/*
Theme Name: shanmp3
Theme URI: https://shanmp3.example/
Author: shanmp3
Description: A modern, mobile-first, PWA-oriented block theme for the shanmp3 music discovery & streaming platform. Server-rendered music content with hydrated interactive islands (player, search, library). Requires the shanmp3 plugin for music data.
Version: 0.2.22
Requires at least: 6.4
Requires PHP: 8.2
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: shanmp3
Tags: music, audio, block-patterns, full-site-editing, dark, responsive
*/

/* ---------------------------------------------------------------------------
 * Base styles (design tokens are defined in theme.json and surface as
 * `--wp--preset--*` CSS variables). This file holds only the small amount of
 * CSS that block templates cannot express directly: dark-mode overrides,
 * the app-shell layout, and the persistent player container.
 * ------------------------------------------------------------------------- */

:root {
	/* Layout metrics. */
	--shanmp3-header-h: 64px;
	--shanmp3-player-h: 80px;
	--shanmp3-sidebar-w: 260px;
	/* Horizontal content padding shared by the header and <main> so the navbar
	   brand (logo) and the page content share the same left edge at every
	   breakpoint. Defined on :root so both .shanmp3-header and .shanmp3-main can
	   consume it; widened to 24px on >=1024px below. */
	--shanmp3-main-pad-x: 16px;
	/* The single standard page width — the content column every page, the
	   navbar, and the player bar all align to. One source of truth so the header,
	   <main>, the widened wrappers, and the player can never drift apart. */
	--shanmp3-page-width: 1280px;

	/* Radius scale. */
	--shanmp3-radius-sm: 6px;
	--shanmp3-radius: 12px;
	--shanmp3-radius-md: 12px;
	--shanmp3-radius-lg: 20px;
	--shanmp3-radius-pill: 999px;

	/* Motion. */
	--shanmp3-transition-fast: 120ms ease;
	--shanmp3-transition: 200ms ease;
	--shanmp3-transition-slow: 320ms ease;

	/* Z-index scale. */
	--shanmp3-z-header: 40;
	--shanmp3-z-player: 50;
	--shanmp3-z-dropdown: 60;
	--shanmp3-z-modal: 70;
	--shanmp3-z-toast: 80;

	/* Touch target minimum. */
	--shanmp3-touch: 44px;
}

/* Dark theme is the default for this music application. */
:root,
:root[data-theme="dark"] {
	--shanmp3-bg: #0b0c10;
	--shanmp3-surface: #15171f;
	--shanmp3-surface-2: #1d2030;
	--shanmp3-fg: #e8eaf0;
	--shanmp3-muted: #9aa0b4;
	--shanmp3-border: #2a2e42;
	--shanmp3-accent: #ca8a04;
	--shanmp3-accent-2: #5356ff;
	--shanmp3-success: #ca8a04;
	--shanmp3-danger: #ff5a5f;

	/* Brand identity (the logo): a dark purple field with a yellow glyph.
	   Logo colors are constant across themes, so they live on the base :root
	   only and are inherited by the light-mode block. */
	--shanmp3-brand-purple: #4c1d95;
	--shanmp3-brand-yellow: #facc15;

	/* Bright accent for fills, gradients, focus rings, and any text that sits
	   on a hardcoded dark surface. Constant across themes (always the vivid
	   gold), whereas --shanmp3-accent is the AA-readable text shade per mode
	   (bright gold in dark mode, dark mustard in light mode). Light mode does
	   not redeclare this, so it inherits the bright value here. */
	--shanmp3-accent-fill: #ca8a04;

	/* Shadows: layered for dark surfaces. */
	--shanmp3-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
	--shanmp3-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.45);
	--shanmp3-shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.55);
	--shanmp3-shadow-focus: 0 0 0 3px rgba(202, 138, 4, 0.35);

	/* Skeleton shimmer base. */
	--shanmp3-skeleton-base: #1d2030;
	--shanmp3-skeleton-shine: #2a2e42;
}

:root[data-theme="light"] {
	--shanmp3-bg: #f6f7fb;
	--shanmp3-surface: #ffffff;
	--shanmp3-surface-2: #eef0f6;
	--shanmp3-fg: #16181f;
	--shanmp3-muted: #5a6072;
	--shanmp3-border: #d9dde8;
	--shanmp3-accent: #a16207;
	--shanmp3-accent-2: #3b3fd6;
	--shanmp3-success: #a16207;
	--shanmp3-danger: #e23744;

	--shanmp3-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.08);
	--shanmp3-shadow-md: 0 4px 12px rgba(16, 24, 40, 0.12);
	--shanmp3-shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.16);
	--shanmp3-shadow-focus: 0 0 0 3px rgba(161, 98, 7, 0.30);

	--shanmp3-skeleton-base: #eef0f6;
	--shanmp3-skeleton-shine: #e0e3ec;
}

/* Respect the OS preference when no explicit theme is chosen. */
@media (prefers-color-scheme: light) {
	:root:not([data-theme]) {
		--shanmp3-bg: #f6f7fb;
		--shanmp3-surface: #ffffff;
		--shanmp3-surface-2: #eef0f6;
		--shanmp3-fg: #16181f;
		--shanmp3-muted: #5a6072;
		--shanmp3-border: #d9dde8;
		--shanmp3-accent: #a16207;
		--shanmp3-accent-2: #3b3fd6;
		--shanmp3-success: #a16207;
		--shanmp3-danger: #e23744;

		--shanmp3-shadow-sm: 0 1px 2px rgba(16, 24, 40, 0.08);
		--shanmp3-shadow-md: 0 4px 12px rgba(16, 24, 40, 0.12);
		--shanmp3-shadow-lg: 0 12px 32px rgba(16, 24, 40, 0.16);
		--shanmp3-shadow-focus: 0 0 0 3px rgba(161, 98, 7, 0.30);

		--shanmp3-skeleton-base: #eef0f6;
		--shanmp3-skeleton-shine: #e0e3ec;
	}
}

body {
	background: var(--shanmp3-bg);
	color: var(--shanmp3-fg);
	margin: 0;
	font-family: var(--wp--preset--font-family--shanmp-base, -apple-system, BlinkMacSystemFont, "Noto Sans Myanmar", system-ui, "Segoe UI", Roboto, sans-serif);
	-webkit-font-smoothing: antialiased;
}

/* App shell: the theme stamps `.shanmp3-shell` on <body>.
 *
 * Mobile (<1024px): a single vertical column — sticky header, main, fixed
 * player, minimal footer — exactly as before. The app sidebar is hidden and
 * its nav list moves into the hamburger drawer.
 *
 * Desktop (>=1024px): the header stays a full-width sticky bar (unchanged); a
 * fixed app sidebar (brand + nav + settings) is pinned on the left below the
 * header; main and the fixed player are shifted right to clear it. The body
 * remains the single scroll container, so the sticky header still pins across
 * the whole page. (A CSS grid was avoided: the header is a short `auto` row,
 * and a sticky grid item is confined to its grid area, so the header would
 * scroll away — the classic grid+sticky gotcha. A fixed sidebar sidesteps it
 * with no scroll-model change.) */
.shanmp3-shell {
	min-height: 100vh;
	display: flex;
	flex-direction: column;
}

.shanmp3-main {
	flex: 1 1 auto;
	width: 100%;
	/* The header content is flush to the 1280px column; the main adds horizontal
	   padding, so widen the container by that padding so the actual content
	   aligns edge-to-edge with the header. */
	max-width: calc(var(--shanmp3-page-width) + 2 * var(--shanmp3-main-pad-x, 16px));
	margin-inline: auto;
	box-sizing: border-box;
}

/* WP's useRootPaddingAwareAlignments stamps .has-global-padding on <main> and
   sets its padding-left/right to the root-padding vars — which are 0px because
   theme.json defines no root padding. That zeroing is (0,1,0) and is emitted
   after the theme stylesheet, so it would silently wipe main's horizontal
   gutter (invisible on desktop where the 1280px column centers, but on mobile
   the full-width content would touch the screen edges). Qualify the padding
   to (0,2,0) via the body class so it beats the core override at every width. */
.shanmp3-shell .shanmp3-main {
	/* Bottom clearance keeps the last content from hiding behind the floating
	   player bar (bar height + float gap), including the safe-area inset the
	   bar now reserves on notched devices. */
	padding: 24px var(--shanmp3-main-pad-x, 16px) calc(var(--shanmp3-player-h) + 28px + env(safe-area-inset-bottom, 0));
}

@media (min-width: 1024px) {
	:root {
		--shanmp3-main-pad-x: 24px;
	}
	.shanmp3-shell .shanmp3-main {
		padding: 32px var(--shanmp3-main-pad-x) calc(var(--shanmp3-player-h) + 32px + env(safe-area-inset-bottom, 0));
	}
}

/* Mobile: core's block-gap stamps margin-block-start: 24px on every direct
 * child of .wp-site-blocks (header/main/footer) via `:where(.wp-site-blocks)
 * > *` and the layout `> *` rules. On <main> that 24px margin stacks with main's
 * own 24px top padding into a large gap under the navbar. Drop the margin on
 * mobile so only the padding gutter remains. (0,2,0) via .shanmp3-shell beats
 * core's :where(...)>* (0,0,0) and :root :where(.is-layout-constrained) > * (0,1,0). */
@media (max-width: 600px) {
	.shanmp3-shell .shanmp3-main {
		margin-block-start: 0;
	}
}

/* Site header: sticky, translucent, full-width bar whose content is centered on
   the 1280px column via the max() padding trick (the bar background spans the
   whole viewport; the brand aligns with .shanmp3-main). Brand on the left; the
   responsive menu, search icon and account control cluster on the right.
   --
   The sticky position lives on the TEMPLATE-PART WRAPPER (header.wp-block-
   template-part), NOT on .shanmp3-header itself. WP wraps the header template
   part in <header class="wp-block-template-part">, and that wrapper's parent is
   .wp-site-blocks (the full page height) — so a sticky wrapper stays pinned
   across the whole scroll. .shanmp3-header is the INNER element whose parent is
   that wrapper, which is only the header's own height (~64px); making the inner
   element sticky left it a containing block too short to stick past one header
   height, so it scrolled away. The footer part renders as <footer> and the player
   as <div>, so `header.wp-block-template-part` targets only this wrapper. */
header.wp-block-template-part {
	position: sticky;
	top: 0;
	z-index: var(--shanmp3-z-header);
}
/* WP admin bar coexistence: the fixed #wpadminbar (z-index 99999) sits at
   viewport top:0, so the sticky header must stick BELOW it for logged-in
   admins/managers (regular members have the bar hidden entirely — see
   shanmp3_show_admin_bar()). Core pushes <html> down with margin-top, but
   position:sticky sticks to the scrollport top, not below that margin, so an
   explicit offset is required. 32px desktop; 46px at WP's 782px mobile
   breakpoint where the admin bar grows taller. */
body.admin-bar header.wp-block-template-part {
	top: 32px;
}
@media screen and (max-width: 782px) {
	body.admin-bar header.wp-block-template-part {
		top: 46px;
	}
}
.shanmp3-header {
	min-height: var(--shanmp3-header-h);
	display: flex;
	align-items: center;
	gap: 1rem;
	border-bottom: 1px solid var(--shanmp3-border);
	padding-inline: max(var(--shanmp3-main-pad-x), calc((100vw - var(--shanmp3-page-width)) / 2));
	box-sizing: border-box;
	transition: transform 0.25s ease;
}
/* Auto-hide: the header-scroll island adds .is-hidden when the user scrolls
   down past the header and removes it when they scroll back up or reach the
   top. Safe to transform the sticky header because every overlay (nav drawer,
   search modal) is a native <dialog> opened with showModal() — the top layer
   escapes any containing block the transform would otherwise create. */
.shanmp3-header.is-hidden {
	transform: translateY(-100%);
}
/* The translucent blurred bar background lives on a ::before pseudo-element, NOT
   on the header itself. A `backdrop-filter` on the header would create a
   containing block for `position:fixed` descendants and trap fixed overlays
   inside the 64px-tall header, rendering them behind the page content. The
   nav drawer avoids this by using a native <dialog> (top layer), but we keep
   the header filter-free anyway as a defensive measure. The ::before only
   contains its own (empty) subtree, so it never affects descendants. */
.shanmp3-header::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: color-mix(in srgb, var(--shanmp3-surface) 85%, transparent);
	-webkit-backdrop-filter: blur(10px);
	backdrop-filter: blur(10px);
	pointer-events: none;
}

/* Brand logo: a gradient headphone badge + the "ShanMP3.com" wordmark. Pure
   presentation — wrapped around the core Site Logo block in functions.php so it
   does not depend on the plugin. The home URL comes from the site title's
   blogname; the <title> tag is unaffected (title-tag support + blogname). */
.shanmp3-logo {
	display: inline-flex;
	align-items: center;
	gap: 0.6rem;
	text-decoration: none;
	color: inherit;
	flex: 0 0 auto;
	padding: 0.25rem 0.35rem;
	border-radius: var(--shanmp3-radius);
}
.shanmp3-logo__badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 45px;
	height: 45px;
	border-radius: 50%;
	background: linear-gradient(135deg, var(--shanmp3-brand-purple) 0%, color-mix(in srgb, var(--shanmp3-brand-purple) 60%, #000) 100%);
	color: var(--shanmp3-brand-yellow);
	box-shadow: var(--shanmp3-shadow-sm);
	flex: 0 0 auto;
	position: relative;
}
/* Static headphone glyph centered in the badge. */
.shanmp3-logo__badge svg {
	width: 28px;
	height: 28px;
}
.shanmp3-logo__text {
	font-weight: 800;
	font-size: 1.15rem;
	letter-spacing: -0.02em;
	line-height: 1;
	color: var(--shanmp3-fg);
	white-space: nowrap;
	text-decoration: none;
}
.shanmp3-logo:hover .shanmp3-logo__text {
	color: var(--shanmp3-accent);
}

/* Decorate the wordmark with a sweeping gradient shimmer. Browsers without
   background-clip:text support keep the solid color above. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
	.shanmp3-logo__text {
		background: linear-gradient(
			100deg,
			var(--shanmp3-fg) 0%,
			var(--shanmp3-fg) 35%,
			var(--shanmp3-accent-fill) 50%,
			var(--shanmp3-accent-2) 60%,
			var(--shanmp3-fg) 75%,
			var(--shanmp3-fg) 100%
		);
		background-size: 250% 100%;
		-webkit-background-clip: text;
		background-clip: text;
		-webkit-text-fill-color: transparent;
		animation: shanmp3-wordmark-shimmer 7s linear infinite;
	}
	.shanmp3-logo:hover .shanmp3-logo__text {
		animation-duration: 2.2s;
	}
}
@keyframes shanmp3-wordmark-shimmer {
	0% {
		background-position: 200% 0;
	}
	100% {
		background-position: -200% 0;
	}
}
@media (prefers-reduced-motion: reduce) {
	.shanmp3-logo__text {
		animation: none;
	}
}

/* Custom logo (uploaded via Customizer → Site Identity → Logo). Sized down so
   the image sits in the bar beside the site title, with breathing room.
   Core's `.wp-block-site-logo.is-default-size img { width:120px }` forces a
   120px default; these selectors outrank it (0,3,1 vs core's 0,2,1). */
.shanmp3-header .shanmp3-logo--custom .custom-logo-link {
	display: inline-flex;
	align-items: center;
	flex: 0 0 auto;
	padding: 0.2rem;
	border-radius: var(--shanmp3-radius);
	line-height: 0;
}
.shanmp3-header .wp-block-site-logo img.custom-logo {
	height: 45px;
	width: auto;
	max-width: 220px;
}
@media (max-width: 360px) {
	/* (0,4,1) — outranks the mobile custom-logo reduction in the 1199px block
	   below (0,3,1) regardless of source order, so the tightest size still
	   applies on the narrowest phones. */
	.shanmp3-header .shanmp3-logo.shanmp3-logo--custom img.custom-logo {
		height: 30px;
		max-width: 140px;
	}
}

/* =========================================================================
   Primary navigation (custom, self-contained)
   -------------------------------------------------------------------------
   Plain .shanmp3-nav__* classes — no core Navigation block, no specificity
   battles to maintain. One <ul> of links is shown inline in the bar on desktop
   (>=600px); on mobile the hamburger opens a slide-in <dialog> drawer and a
   tiny island (assets/js/islands/header-nav.js) MOVES that same <ul> into the
   drawer, so there is a single source of truth for the link list.

   The drawer is a native <dialog> opened with showModal(), which renders in the
   top layer. That escapes both the header's stacking context and any containing
   block, so the drawer always paints above page content — no more "drawer
   behind the content". Native <dialog> also gives Esc-to-close and a focus trap.
   ========================================================================= */

/* Primary nav — a self-contained custom nav in the header (NOT core
   wp:navigation): a hamburger toggle (mobile) + an inline icon+label link list
   (desktop) that collapses into the hamburger drawer below 1024px. The drawer
   CSS lives further below. The search button + theme toggle + account control
   follow the nav in the header; the nav's margin-inline-start:auto pushes this
   whole right cluster to the end of the bar. */

/* Nav wrapper: a flex row holding the toggle + the link list. Pushed to the
   right end of the header via margin-inline-start:auto. Qualified to (0,2,0)
   so it beats core's flex-child margin reset (see wp-core-flex-margin-reset),
   which would otherwise zero the auto margin and leave the cluster right after
   the logo. */
.shanmp3-nav {
	display: flex;
	align-items: center;
}
.shanmp3-header .shanmp3-nav {
	margin-inline-start: auto;
}

/* Nav link list — inline pills on desktop; the drawer scope restyles it as a
   vertical stack on mobile (further below). */
.shanmp3-nav__menu {
	display: flex;
	margin: 0;
	padding: 0;
	list-style: none;
}
.shanmp3-nav__link {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	min-height: 34px;
	padding: 0 0.5rem;
	border-radius: var(--shanmp3-radius-pill);
	color: var(--shanmp3-muted);
	font-size: 0.85rem;
	font-weight: 500;
	text-decoration: none;
	transition: color var(--shanmp3-transition-fast),
		background-color var(--shanmp3-transition-fast);
}
.shanmp3-nav__link:hover {
	color: var(--shanmp3-fg);
	background: var(--shanmp3-surface-2);
}
.shanmp3-nav__link[aria-current="page"] {
	color: var(--shanmp3-accent);
	background: var(--shanmp3-surface-2);
}
.shanmp3-nav__icon {
	width: 16px;
	height: 16px;
	flex: 0 0 auto;
	display: block;
}

/* Hamburger toggle — hidden on desktop, shown on mobile. */
.shanmp3-nav__toggle {
	display: none;
	align-items: center;
	justify-content: center;
	width: var(--shanmp3-touch);
	min-height: var(--shanmp3-touch);
	padding: 0;
	border: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
}
.shanmp3-nav__toggle:hover {
	background: var(--shanmp3-surface-2);
}
.shanmp3-nav__toggle svg {
	width: 22px;
	height: 22px;
}

/* Breakpoint switch at 1200px (the site's desktop boundary). Below it the
   inline nav + right-side cluster (search / theme / account) is too wide for
   tablet-portrait viewports (iPad Mini 744, iPad Air 820, Surface Pro 912) and
   — with the News item added (now 7 nav items) — also for 1024–1198px tablet-
   landscape widths, so collapse to the hamburger drawer there — same as
   phones. At >=1200 the full desktop cluster (7 nav items + controls) fits
   with headroom. Mobile: show the hamburger, hide the inline list (it moves
   into the drawer on open). The header gap + hamburger sizing live here
   because their desktop rules are ABOVE this block, so these win by source
   order. The right-side icon controls (search / theme / account) are sized in
   a LATER mobile block — their desktop rules sit below this point and would
   otherwise override equal-specificity mobile rules. */
@media (max-width: 1199px) {
	/* Core inlines its flex-layout `gap: var(--wp--style--block-gap)` (24px here)
	   AFTER the theme stylesheet at equal specificity, so the plain
	   `.shanmp3-header { gap }` rule above is silently overridden. Qualify to
	   (0,2,0) so the tight 0.25rem gap actually applies — otherwise the five
	   header children separated by 24px gaps overflow a 390px viewport
	   (scrollWidth 457 vs clientWidth 390). Trim the side padding too. */
	.wp-block-group.shanmp3-header {
		gap: 0.25rem;
		padding-inline: 0.75rem;
	}
	/* Let the brand shrink on narrow screens instead of forcing overflow: the
	   badge/custom-logo image stays intact while the wordmark truncates. The
	   logo is flex:0 0 auto by default (won't shrink); override min-width + add
	   flex-shrink, and let the text ellipsize. */
	.shanmp3-header .shanmp3-logo {
		min-width: 0;
		flex: 0 1 auto;
		gap: 0.4rem;
		padding-left: 0px !important;
	}
	.shanmp3-header .shanmp3-logo__text {
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		min-width: 0;
		font-size: 0.95rem;
	}
	.shanmp3-nav__toggle {
		display: inline-flex;
		width: 40px;
		min-height: 40px;
	}
	.shanmp3-nav__toggle svg {
		width: 20px;
		height: 20px;
	}
	.shanmp3-nav__menu {
		display: none;
	}
	/* Mobile app-bar order: hamburger left of the brand, action cluster right.
	   The nav wrapper holds only the visible toggle on mobile (the inline list
	   is hidden above and moved into the drawer <dialog> on open), so reordering
	   .shanmp3-nav is equivalent to moving just the hamburger. Zero its auto
	   margin (which on desktop pushes the right cluster to the end) and hand
	   that auto margin to the search button so the action cluster stays right. */
	.shanmp3-header .shanmp3-nav {
		order: -1;
		margin-inline-start: 0;
	}
	/* Push the right-side action cluster (search · theme · account) to the end
	   of the bar. (0,3,0) — the .wp-block-group compound on the header — outranks
	   the bar-scope search margin rule (0,2,0) at line 804 AND the mobile cluster
	   zero-margin rule (0,2,0) further below, both of which would otherwise beat
	   an equal-specificity auto rule by source order. */
	.wp-block-group.shanmp3-header .shanmp3-header__search-btn {
		margin-inline-start: auto;
	}
	/* Hide the settings gear from the header bar on mobile — header-nav.js
	   moves .shanmp3-header__settings into the drawer below the nav list on
	   open. The direct-child selector means this only applies while the gear is
	   a child of the bar; once moved into the slot its parent is the slot, so
	   the gear is visible inside the drawer (see the drawer-scoped rules by the
	   settings section). Desktop keeps the gear in the bar: the toggle is
	   display:none there, open() never fires, the gear never moves. */
	.shanmp3-header > .shanmp3-header__settings {
		display: none;
	}
	/* Shrink the brand badge/image a little on mobile. */
	.shanmp3-header .shanmp3-logo__badge {
		width: 34px;
		height: 34px;
	}
	.shanmp3-header .shanmp3-logo__badge svg {
		width: 22px;
		height: 22px;
	}
	.shanmp3-header .wp-block-site-logo img.custom-logo {
		height: 34px;
		max-width: 160px;
	}
}

/* Mobile drawer (native <dialog>, top layer) — full-screen and theme-aligned.
   The panel IS the screen: a dark surface gradient with the amber accent for the
   active item, so it belongs to the same design system as the rest of the theme
   (no off-theme blue). The dialog's own backdrop is kept dark only as a fallback
   for the brief showModal() paint — the panel covers it entirely. */
.shanmp3-nav__drawer {
	display: none; /* closed; showModal() toggles [open] */
	position: fixed;
	inset: 0;
	margin: 0;
	padding: 0;
	border: 0;
	background: transparent;
	/* Defeat the UA <dialog> default `width/height: fit-content`. With both
	   left+right (and top+bottom) pinned to 0 and margin:0, a fit-content size
	   over-constrains the box and the browser drops right/bottom (LTR), so the
	   dialog would shrink to its content instead of filling the viewport.
	   Auto lets inset:0 stretch it to the full screen. */
	width: auto;
	height: auto;
	max-width: none;
	max-height: none;
	z-index: var(--shanmp3-z-modal);
}
.shanmp3-nav__drawer[open] {
	display: flex;
	justify-content: stretch;
	align-items: stretch;
}
.shanmp3-nav__drawer::backdrop {
	background: rgba(0, 0, 0, 0.6);
}
.shanmp3-nav__panel {
	width: 100%;
	height: 100%;
	display: flex;
	flex-direction: column;
	padding: max(1.25rem, env(safe-area-inset-top)) 1.5rem max(1.25rem, env(safe-area-inset-bottom));
	box-sizing: border-box;
	background: linear-gradient(180deg, var(--shanmp3-surface-2) 0%, var(--shanmp3-surface) 100%);
	color: var(--shanmp3-fg);
	overflow: auto;
	-webkit-overflow-scrolling: touch;
	animation: shanmp3-nav-in 240ms ease;
}
@keyframes shanmp3-nav-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}
.shanmp3-nav__drawer-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	margin-bottom: 1.5rem;
	padding-bottom: 1rem;
	border-bottom: 1px solid var(--shanmp3-border);
}
.shanmp3-nav__drawer-title {
	font-size: 0.8rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--shanmp3-muted);
}
.shanmp3-nav__close {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: var(--shanmp3-touch);
	height: var(--shanmp3-touch);
	padding: 0;
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: background-color var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast),
		border-color var(--shanmp3-transition-fast);
}
.shanmp3-nav__close:hover {
	background: var(--shanmp3-surface-2);
	border-color: var(--shanmp3-accent);
	color: var(--shanmp3-accent);
}
.shanmp3-nav__close svg {
	width: 22px;
	height: 22px;
}

/* When the <ul> is moved into the drawer, restyle it as a vertically-centered
   stack of large touch targets (capped width so it stays elegant on tablets in
   portrait). Active item: amber text + a tinted surface with an accent edge bar.
   Icons inherit the link color, so they go muted→accent with the active item. */
.shanmp3-nav__drawer .shanmp3-nav__menu {
	display: flex;
	flex-direction: column;
	align-items: stretch;
	justify-content: center;
	flex: 1 1 auto;
	gap: 0.5rem;
	width: 100%;
	max-width: 30rem;
	margin-inline: auto;
}
.shanmp3-nav__drawer .shanmp3-nav__link {
	min-height: 56px;
	padding: 0 1rem;
	border-radius: var(--shanmp3-radius-md);
	color: var(--shanmp3-fg);
	font-size: 1.05rem;
	font-weight: 600;
	transition: background-color var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast);
}
.shanmp3-nav__drawer .shanmp3-nav__link:hover {
	background: var(--shanmp3-surface-2);
}
.shanmp3-nav__drawer .shanmp3-nav__link[aria-current="page"] {
	background: var(--shanmp3-surface-2);
	color: var(--shanmp3-accent);
	box-shadow: inset 3px 0 0 var(--shanmp3-accent);
}
.shanmp3-nav__drawer .shanmp3-nav__icon {
	width: 22px;
	height: 22px;
}
/* Account control (profile / log-in) — injected at the right end of the header
   by islands/header-account.js from the SHANMP3 global. Shared positioning for
   both variants; the pill and the dropdown add their own chrome below. */
.shanmp3-account {
	flex: 0 0 auto;
	margin-inline-start: 0.5rem;
	-webkit-tap-highlight-color: transparent;
}

/* Logged-out "Log in" pill. */
.shanmp3-account--login {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.4rem;
	min-height: 34px;
	padding: 0 0.7rem;
	border-radius: var(--shanmp3-radius-pill);
	color: var(--shanmp3-muted);
	font-size: 0.85rem;
	font-weight: 600;
	text-decoration: none;
	transition: color var(--shanmp3-transition-fast),
		background-color var(--shanmp3-transition-fast);
}
.shanmp3-account--login:hover {
	color: var(--shanmp3-fg);
	background: var(--shanmp3-surface-2);
}
.shanmp3-account .shanmp3-icon {
	flex: 0 0 auto;
}
.shanmp3-account__label {
	white-space: nowrap;
}

/* Logged-in profile dropdown. The wrapper is also a .shanmp3-dropdown (the
   design system gives it position:relative + display:inline-block). The toggle
   is a circular gradient disc; the menu anchors to its inline-end edge. */
.shanmp3-account__toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 34px;
	min-height: 34px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	color: #0b0c10;
	background: linear-gradient(135deg, var(--shanmp3-accent-fill) 0%, var(--shanmp3-accent-2) 100%);
	box-shadow: var(--shanmp3-shadow-sm);
	cursor: pointer;
	transition: transform var(--shanmp3-transition-fast),
		box-shadow var(--shanmp3-transition-fast);
}
.shanmp3-account__toggle:hover {
	transform: translateY(-1px);
	box-shadow: var(--shanmp3-shadow-md);
}
/* Anchor the menu to the right edge of the toggle (the core dropdown is
   left-anchored). Qualified to (0,2,0) with .shanmp3-account--profile so it
   beats the base .shanmp3-dropdown__menu rule (0,1,0) in shanmp3-design.css —
   design.css loads AFTER style.css, so an equal-specificity tie would let the
   base `inset-inline-start: 0` win, left-anchoring a 200px menu to the
   rightmost header child and pushing it off the right edge of the viewport
   (invisible on mobile, clipped on narrow desktops). */
.shanmp3-account--profile .shanmp3-account__menu {
	inset-inline-start: auto;
	inset-inline-end: 0;
}
.shanmp3-account__menu .shanmp3-icon {
	flex: 0 0 auto;
	color: var(--shanmp3-muted);
}

/* Header search trigger — a magnifier pill that opens the live-search modal.
   Sized to match the nav/account touch targets. */
.shanmp3-header__search-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 34px;
	width: 34px;
	padding: 0;
	border: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
	cursor: pointer;
	flex: 0 0 auto;
	margin-inline-start: 0.5rem;
	transition: background-color var(--shanmp3-transition-fast);
	-webkit-tap-highlight-color: transparent;
}
/* Core's flex-child margin reset also zeroes the search button's gap; qualify
   to restore it. */
.shanmp3-header .shanmp3-header__search-btn {
	margin-inline-start: 0.5rem;
}
.shanmp3-header__search-btn:hover {
	background: var(--shanmp3-surface-2);
}

/* Dark/light theme toggle. Mirrors the search button's chrome; the sun shows
   in dark mode (click → light), the moon in light mode. Icon swapping is CSS-
   only via :root[data-theme="light"] so there's no flash before the island
   hydrates — the inline <head> script sets data-theme before first paint. */
.shanmp3-theme-toggle {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 34px;
	width: 34px;
	padding: 0;
	border: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
	cursor: pointer;
	flex: 0 0 auto;
	margin-inline-start: 0.5rem;
	transition: background-color var(--shanmp3-transition-fast);
	-webkit-tap-highlight-color: transparent;
}
.shanmp3-header .shanmp3-theme-toggle {
	margin-inline-start: 0.5rem;
}
.shanmp3-theme-toggle:hover {
	background: var(--shanmp3-surface-2);
}
.shanmp3-theme-toggle__moon {
	display: none;
}

/* Settings gear — a dropdown of info/help pages (Privacy, About,
   Announcements, Support). Same chrome as the search/theme icon buttons so the
   right-side cluster reads as a row of equal-size icons; the menu is the
   design-system .shanmp3-dropdown (auto-wired via [data-shanmp3-dropdown]). */
.shanmp3-header__settings {
	flex: 0 0 auto;
	margin-inline-start: 0.5rem;
}
.shanmp3-header .shanmp3-header__settings {
	margin-inline-start: 0.5rem;
}
.shanmp3-header__settings-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 34px;
	width: 34px;
	padding: 0;
	border: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
	cursor: pointer;
	-webkit-tap-highlight-color: transparent;
	transition: background-color var(--shanmp3-transition-fast);
}
.shanmp3-header__settings-btn:hover {
	background: var(--shanmp3-surface-2);
}
/* Right-anchor the menu to the gear. The base .shanmp3-dropdown__menu is
   left-anchored (inset-inline-start:0) at (0,1,0) in shanmp3-design.css, which
   loads AFTER style.css — so an equal-specificity (0,1,0) rule here would lose
   the tie and the menu would left-anchor, extending off the right viewport
   edge on mobile (invisible). Qualified to (0,2,0) so it wins regardless of
   load order. Mirrors the .shanmp3-account--profile .shanmp3-account__menu
   right-anchor fix (see [[header-mobile-three-fixes]]). */
.shanmp3-header__settings .shanmp3-header__settings-menu {
	inset-inline-start: auto;
	inset-inline-end: 0;
}

/* Settings gear relocated into the nav drawer on mobile (header-nav.js moves
   it into the drawer slot below the nav list on open). Rendered as a full-width
   icon+label row that mirrors .shanmp3-nav__link so it reads as part of the menu,
   separated by a hairline. (0,3,0) outranks the bar-scope settings margin rule
   (0,2,0) and the .shanmp3-dropdown inline-block base (0,1,0). */
.shanmp3-nav__drawer .shanmp3-dropdown.shanmp3-header__settings {
	display: block;
	width: 100%;
	max-width: 30rem;
	margin-inline: auto;
	margin-top: 0.75rem;
	padding-top: 0.75rem;
	border-top: 1px solid var(--shanmp3-border);
}
.shanmp3-nav__drawer .shanmp3-header__settings-btn {
	display: flex;
	align-items: center;
	justify-content: flex-start;
	gap: 0.35rem;
	width: 100%;
	min-height: 56px;
	padding: 0 1rem;
	border: 0;
	border-radius: var(--shanmp3-radius-md);
	background: transparent;
	color: var(--shanmp3-fg);
	font-size: 1.05rem;
	font-weight: 600;
	transition: background-color var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast);
}
.shanmp3-nav__drawer .shanmp3-header__settings-btn:hover {
	background: var(--shanmp3-surface-2);
}
.shanmp3-nav__drawer .shanmp3-header__settings-btn .shanmp3-icon {
	width: 22px;
	height: 22px;
}
/* Label span: hidden in the bar (the gear is icon-only there), shown in the
   drawer row. */
.shanmp3-header__settings-label {
	display: none;
}
.shanmp3-nav__drawer .shanmp3-header__settings-label {
	display: inline;
}
/* Submenu: left-anchor to the gear so it opens down-right and stays inside the
   drawer panel. The bar scope right-anchors it (inset-inline-end:0), which
   would push a 200px menu off the left edge of the centered gear here. (0,3,0)
   beats the bar-scope (0,2,0). */
.shanmp3-nav__drawer .shanmp3-header__settings .shanmp3-header__settings-menu {
	inset-inline-start: 0;
	inset-inline-end: auto;
}

/* Size the icons inside the right-side icon buttons (search / theme / settings).
   The SVGs carry width/height presentation attributes; CSS overrides them so
   the glyphs shrink with the buttons (34px → 18px icon). */
.shanmp3-header__search-btn .shanmp3-icon,
.shanmp3-theme-toggle .shanmp3-icon,
.shanmp3-header__settings-btn .shanmp3-icon {
	width: 18px;
	height: 18px;
}
/* Qualify with .shanmp3-theme-toggle (0,2,0 / 0,3,0) so these beat the
   .shanmp3-icon { display:inline-block } rule in shanmp3-design.css, which
   loads after style.css and would otherwise keep the moon visible in dark mode. */
:root[data-theme="light"] .shanmp3-theme-toggle .shanmp3-theme-toggle__sun {
	display: none;
}
:root[data-theme="light"] .shanmp3-theme-toggle .shanmp3-theme-toggle__moon {
	display: inline-block;
}
.shanmp3-theme-toggle .shanmp3-theme-toggle__moon {
	display: none;
}

/* Mobile: shrink the right-side icon controls and drop their margins so the
   bar reads as a tight row of equal-size icons. This block MUST come after the
   desktop `.shanmp3-header__search-btn`, `.shanmp3-theme-toggle`,
   `.shanmp3-header__settings`, `.shanmp3-account--login` and
   `.shanmp3-account__toggle` rules above — they share the same specificity, so
   source order decides, and these mobile overrides have to win. The account
   control becomes icon-only: the "Log in" label is hidden (icon + title/aria-
   label still convey it), so logged-out and logged-in both render as a 32px
   icon button matching search/theme/settings. */
@media (max-width: 1199px) {
	.shanmp3-header .shanmp3-header__search-btn,
	.shanmp3-header .shanmp3-theme-toggle,
	.shanmp3-header .shanmp3-header__settings,
	.shanmp3-account {
		margin-inline-start: 0;
	}
	.shanmp3-header__search-btn,
	.shanmp3-theme-toggle,
	.shanmp3-header__settings-btn {
		width: 32px;
		min-height: 32px;
	}
	.shanmp3-header__search-btn .shanmp3-icon,
	.shanmp3-theme-toggle .shanmp3-icon,
	.shanmp3-header__settings-btn .shanmp3-icon {
		width: 17px;
		height: 17px;
	}
	.shanmp3-account--login {
		width: 32px;
		min-height: 32px;
		padding: 0;
		font-size: 0;
	}
	.shanmp3-account--login .shanmp3-account__label {
		display: none;
	}
	.shanmp3-account--login .shanmp3-icon {
		width: 17px;
		height: 17px;
	}
	.shanmp3-account__toggle {
		width: 32px;
		min-height: 32px;
	}
	.shanmp3-account__toggle .shanmp3-icon {
		width: 17px;
		height: 17px;
	}
}

/* Search field: a magnifier icon inside the input on the left, a clear button
   on the right (shown by the search island once the user types). Shared by the
   search modal (and the archive search bars). */
.shanmp3-search-field {
	position: relative;
	flex: 1 1 auto;
	min-width: 0;
	display: flex;
	align-items: center;
}
.shanmp3-search-field__icon {
	position: absolute;
	left: 0.85rem;
	width: 20px;
	height: 20px;
	color: var(--shanmp3-muted);
	pointer-events: none;
}
.shanmp3-search-field .shanmp3-input {
	width: 100%;
	min-height: 48px;
	padding-left: 2.75rem;
	padding-right: 2.5rem;
	font-size: 1rem;
	border-radius: var(--shanmp3-radius);
	box-sizing: border-box;
}
.shanmp3-search-field__clear {
	position: absolute;
	right: 0.4rem;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 32px;
	height: 32px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: transparent;
	color: var(--shanmp3-muted);
	cursor: pointer;
	transition: color var(--shanmp3-transition-fast),
		background-color var(--shanmp3-transition-fast);
}
.shanmp3-search-field__clear:hover {
	background: var(--shanmp3-surface-2);
	color: var(--shanmp3-fg);
}
.shanmp3-search-field__clear svg {
	width: 16px;
	height: 16px;
}

/* Mobile: drop the "Log in" label so the header stays a tight row of icons; the
   title/aria-label still identifies the control. The profile disc is already
   icon-only. Also slim the inline search input to fit the narrow bar. */
@media (max-width: 600px) {
	.shanmp3-account__label {
		display: none;
	}
	.shanmp3-search-field .shanmp3-input {
		min-height: 40px;
		font-size: 0.95rem;
	}
}

/* On the smallest screens shrink the disc + wordmark to save width. */
@media (max-width: 360px) {
	.shanmp3-logo__badge {
		width: 36px;
		height: 36px;
	}
	.shanmp3-logo__badge svg {
		width: 22px;
		height: 22px;
	}
	.shanmp3-logo__text {
		font-size: 0.95rem;
	}
}

/* Persistent player container (filled by the player island). Fixed full-width
   at the bottom so it stays docked and visible while the page scrolls — the
   reference NetEase-style player is a slim full-width bar, not a floating card.
   Visuals live on .shanmp3-player-bar in shanmp3-player.css. */
.shanmp3-player {
	position: fixed;
	bottom: 0;
	left: 0;
	right: 0;
	z-index: var(--shanmp3-z-player);
	background: var(--shanmp3-surface);
	border-top: 1px solid var(--shanmp3-border);
	box-sizing: border-box;
	/* Push the bar above the home-indicator / gesture bar on notched devices
	   (notably WeChat iOS). The wrapper's background fills the inset strip, so
	   the bar content is never obscured. No effect where the inset is 0. */
	padding-bottom: env(safe-area-inset-bottom, 0);
}

/* Focus visibility for keyboard users. */
a:focus-visible,
button:focus-visible,
input:focus-visible {
	outline: 2px solid var(--shanmp3-accent-fill);
	outline-offset: 2px;
}

/* Respect reduced-motion preference. */
@media (prefers-reduced-motion: reduce) {
	* {
		animation-duration: 0.001ms !important;
		transition-duration: 0.001ms !important;
	}
}