/* ---------------------------------------------------------------------------
 * shanmp3 music entity styles — page-level layout for song/artist/album/
 * playlist/genre pages and the home/discover/library/search shells.
 *
 * Built on the design-system tokens + component classes in shanmp3-design.css.
 * ------------------------------------------------------------------------- */

/* =========================================================================
   Entity hero (album / artist / playlist header)
   ========================================================================= */
.shanmp3-hero {
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
	padding: 1.5rem 0 1rem;
}
.shanmp3-hero__cover {
	width: min(220px, 60vw);
	height: min(220px, 60vw);
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
	background: var(--shanmp3-surface-2);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--shanmp3-muted);
	flex: 0 0 auto;
	box-shadow: var(--shanmp3-shadow-md);
}
.shanmp3-hero__cover img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.shanmp3-hero__cover--circle {
	border-radius: 50%;
}
.shanmp3-hero__eyebrow {
	margin: 0;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--shanmp3-muted);
}
.shanmp3-hero__title {
	margin: 0.25rem 0;
	font-size: clamp(1.75rem, 5vw, 2.75rem);
	font-weight: 800;
	line-height: 1.1;
	color: var(--shanmp3-fg);
}
.shanmp3-hero__meta {
	margin: 0;
	color: var(--shanmp3-muted);
	font-size: 0.95rem;
}
.shanmp3-hero__meta a {
	color: var(--shanmp3-fg);
	text-decoration: none;
}
.shanmp3-hero__meta a:hover {
	color: var(--shanmp3-accent);
}
.shanmp3-hero__actions {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	flex-wrap: wrap;
	margin-top: 0.5rem;
}
/* On phones the hero stacks cover-above-body. Center the cover image on its
   own line (align-self) so the body text stays left-aligned and full-width. */
@media ( max-width: 767px ) {
	.shanmp3-hero__cover {
		align-self: center;
	}
	.shanmp3-hero__actions {
		justify-content: center;
	}
}
/* Uniform icon chips: every action (play/like/add/follow/share/comment) renders
   as an equal-height chip with a visible surface and bright foreground, so the
   thin stroke glyphs (heart, share, comment) read clearly instead of fading into
   the hero. Auto-width with a touch-size min so count badges fit alongside icons. */
.shanmp3-hero__actions .shanmp3-btn--icon {
	box-sizing: border-box;
	width: auto;
	min-width: var(--shanmp3-touch);
	height: var(--shanmp3-touch);
	padding: 0 0.6em;
	border-radius: var(--shanmp3-radius-pill);
	background: var(--shanmp3-surface-2, rgba(255, 255, 255, 0.06));
	border: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.1));
	color: var(--shanmp3-fg);
}
.shanmp3-hero__actions .shanmp3-btn--icon:hover {
	background: var(--shanmp3-surface, rgba(255, 255, 255, 0.12));
	border-color: var(--shanmp3-border, rgba(255, 255, 255, 0.2));
	color: var(--shanmp3-fg);
	transform: none;
}
.shanmp3-hero__actions .shanmp3-btn--icon[aria-pressed="true"] {
	color: var(--shanmp3-accent);
	border-color: var(--shanmp3-accent);
}
.shanmp3-hero__actions .shanmp3-btn--icon:focus-visible {
	outline: none;
	box-shadow: var(--shanmp3-shadow-focus);
}
.shanmp3-hero__bio {
	margin: 0.5rem 0 0;
	max-width: 70ch;
	color: var(--shanmp3-fg);
	line-height: 1.6;
}

@media (min-width: 768px) {
	.shanmp3-hero {
		flex-direction: row;
		align-items: flex-end;
		gap: 2rem;
		padding: 2.5rem 0 1.5rem;
	}
	.shanmp3-hero__body {
		flex: 1 1 auto;
		min-width: 0;
	}
}

/* =========================================================================
   Artist profile layout (artist page only)
   =========================================================================
   Two-column profile: a 1/4 left aside (photo + info card + follow) and a
   3/4 right main (eyebrow, title, bio, songs). Albums render full-width below
   the wrapper. Stacks to a single column under 768px. Plain surface — no
   gradient banner — so the info card and song list read on the page bg.
   ------------------------------------------------------------------------ */
.shanmp3-artist-profile {
	display: grid;
	gap: 1.5rem;
	padding: 1.5rem 0 1rem;
}
.shanmp3-artist-profile__aside {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	min-width: 0;
}
.shanmp3-artist-profile__cover {
	width: 100%;
	max-width: 260px;
	aspect-ratio: 1 / 1;
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
	background: var(--shanmp3-surface-2);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--shanmp3-muted);
	box-shadow: var(--shanmp3-shadow-md);
}
.shanmp3-artist-profile__cover img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
/* Info card surface wrapping the artist-meta meta-grid. */
.shanmp3-artist-profile__card {
	padding: 1rem 1.25rem;
	background: var(--shanmp3-surface);
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-lg);
}
/* The meta grid auto-fills 180px columns; in the narrow aside force a single
   column so labels/values stack cleanly. */
.shanmp3-artist-profile__card .shanmp3-meta-grid {
	grid-template-columns: 1fr;
	margin: 0;
}
.shanmp3-artist-profile__main {
	min-width: 0;
}
.shanmp3-artist-profile__main .shanmp3-hero__bio {
	margin: 0.75rem 0 0;
}
.shanmp3-artist-profile__main .shanmp3-section {
	gap: 0.75rem;
}
.shanmp3-artist-profile__aside .shanmp3-hero__actions {
	margin-top: 0.25rem;
}
@media (min-width: 768px) {
	.shanmp3-artist-profile {
		grid-template-columns: minmax(180px, 25%) 1fr;
		align-items: start;
		gap: 2rem;
		padding: 2.5rem 0 1.5rem;
	}
	/* Let the cover fill the aside column width on desktop. */
	.shanmp3-artist-profile__cover {
		max-width: none;
	}
}

/* =========================================================================
   Label single page (shanmp3_label)
   Mirrors the artist-profile grid: a cover + meta card aside, a main column
   with the eyebrow/title/bio + Songs list, and Albums/Artists sections below.
   The top-right ⓘ info button (label-info block, .shanmp3-song-credits) is
   absolutely positioned, so the profile grid must be its positioned ancestor.
   ------------------------------------------------------------------------ */
.shanmp3-label-profile {
	display: grid;
	gap: 1.5rem;
	padding: 1.5rem 0 1rem;
}
.shanmp3-label-profile__aside {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	min-width: 0;
}
.shanmp3-label-profile__cover {
	width: 100%;
	max-width: 260px;
	aspect-ratio: 1 / 1;
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
	background: var(--shanmp3-surface-2);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--shanmp3-muted);
	box-shadow: var(--shanmp3-shadow-md);
}
.shanmp3-label-profile__cover img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
/* Info card surface wrapping the label-meta meta-grid. */
.shanmp3-label-profile__card {
	padding: 1rem 1.25rem;
	background: var(--shanmp3-surface);
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-lg);
}
.shanmp3-label-profile__card .shanmp3-meta-grid {
	grid-template-columns: 1fr;
	margin: 0;
}
.shanmp3-label-profile__main {
	min-width: 0;
}
.shanmp3-label-profile__main .shanmp3-hero__bio {
	margin: 0.75rem 0 0;
}
.shanmp3-label-profile__main .shanmp3-section {
	gap: 0.75rem;
}
.shanmp3-label-profile__aside .shanmp3-hero__actions {
	margin-top: 0.25rem;
}
.single-shanmp3_label .shanmp3-label-profile {
	position: relative;
}
@media (min-width: 768px) {
	.shanmp3-label-profile {
		grid-template-columns: minmax(180px, 25%) 1fr;
		align-items: start;
		gap: 2rem;
		padding: 2.5rem 0 1.5rem;
	}
	.shanmp3-label-profile__cover {
		max-width: none;
	}
	/* Reserve space on the right of the title row so a long label name never
	   runs under the top-right ⓘ button. */
	.single-shanmp3_label .shanmp3-label-profile__title-row {
		padding-right: 2.75rem;
	}
}
@media ( max-width: 767px ) {
	.shanmp3-label-profile {
		gap: 1.25rem;
		padding: 1rem 0 0.5rem;
	}
	.shanmp3-label-profile__aside {
		align-items: center;
		text-align: center;
	}
	.shanmp3-label-profile__cover {
		max-width: clamp( 140px, 45vw, 200px );
		margin-inline: auto;
	}
	/* Hide the detailed meta card on phones — the cover + actions are enough;
	   the card reappears in the two-column desktop layout. (Mirrors artist.) */
	.shanmp3-label-profile__card {
		display: none;
	}
}
/* Mobile-only: the ⓘ wrapper (.shanmp3-song-credits) is a non-first child of the
   label-profile, so core's global-styles inline rule stamps a 24px top margin on
   it, dropping the info button below the back button. Qualify to (0,2,0) to
   reset, mirroring the artist-profile rule (see comment there for full detail). */
@media ( max-width: 1023px ) {
	.single-shanmp3_label .shanmp3-label-profile .shanmp3-song-credits {
		margin-block-start: 0;
	}
}

/* =========================================================================
   Credit single page (Composer / Studio / Producer / Band)
   One generic class set serves all four credit CPTs (the templates all use
   shanmp3-credit-profile). Mirrors the label-profile layout above. The cover
   shape is set per-template via the post-featured-image inline border-radius
   (50% for the circular people entities, --shanmp3-radius-lg for studio).
   ========================================================================= */
.shanmp3-credit-profile {
	display: grid;
	gap: 1.5rem;
	padding: 1.5rem 0 1rem;
}
.shanmp3-credit-profile__aside {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	min-width: 0;
}
.shanmp3-credit-profile__cover {
	width: 100%;
	max-width: 260px;
	aspect-ratio: 1 / 1;
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
	background: var(--shanmp3-surface-2);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--shanmp3-muted);
	box-shadow: var(--shanmp3-shadow-md);
}
.shanmp3-credit-profile__cover img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.shanmp3-credit-profile__card {
	padding: 1rem 1.25rem;
	background: var(--shanmp3-surface);
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-lg);
}
.shanmp3-credit-profile__card .shanmp3-meta-grid {
	grid-template-columns: 1fr;
	margin: 0;
}
.shanmp3-credit-profile__main {
	min-width: 0;
}
.shanmp3-credit-profile__main .shanmp3-hero__bio {
	margin: 0.75rem 0 0;
}
.shanmp3-credit-profile__main .shanmp3-section {
	gap: 0.75rem;
}
.shanmp3-credit-profile__aside .shanmp3-hero__actions {
	margin-top: 0.25rem;
}
/* The info/back buttons are absolutely positioned, so the profile grid is the
   positioned ancestor. Applies to all four credit CPT single templates. */
.single-shanmp3_composer .shanmp3-credit-profile,
.single-shanmp3_studio .shanmp3-credit-profile,
.single-shanmp3_producer .shanmp3-credit-profile,
.single-shanmp3_band .shanmp3-credit-profile {
	position: relative;
}
@media (min-width: 768px) {
	.shanmp3-credit-profile {
		grid-template-columns: minmax(180px, 25%) 1fr;
		align-items: start;
		gap: 2rem;
		padding: 2.5rem 0 1.5rem;
	}
	.shanmp3-credit-profile__cover {
		max-width: none;
	}
	/* Reserve space on the right of the title row so a long name never runs
	   under the top-right ⓘ button (mirrors the label rule). */
	.single-shanmp3_composer .shanmp3-credit-profile__title-row,
	.single-shanmp3_studio .shanmp3-credit-profile__title-row,
	.single-shanmp3_producer .shanmp3-credit-profile__title-row,
	.single-shanmp3_band .shanmp3-credit-profile__title-row {
		padding-right: 2.75rem;
	}
}
@media ( max-width: 767px ) {
	.shanmp3-credit-profile {
		gap: 1.25rem;
		padding: 1rem 0 0.5rem;
	}
	.shanmp3-credit-profile__aside {
		align-items: center;
		text-align: center;
	}
	.shanmp3-credit-profile__cover {
		max-width: clamp( 140px, 45vw, 200px );
		margin-inline: auto;
	}
	.shanmp3-credit-profile__card {
		display: none;
	}
}
/* Mobile-only: the ⓘ wrapper (.shanmp3-song-credits) is a non-first child of
   the credit-profile, so core's global-styles inline rule stamps a 24px top
   margin on it, dropping the info button below the back button. Qualify to
   (0,2,0) to reset (mirrors the label rule). */
@media ( max-width: 1023px ) {
	.single-shanmp3_composer .shanmp3-credit-profile .shanmp3-song-credits,
	.single-shanmp3_studio .shanmp3-credit-profile .shanmp3-song-credits,
	.single-shanmp3_producer .shanmp3-credit-profile .shanmp3-song-credits,
	.single-shanmp3_band .shanmp3-credit-profile .shanmp3-song-credits {
		margin-block-start: 0;
	}
}

/* =========================================================================
   Home hero (front-page gradient banner)
   ========================================================================= */
.shanmp3-home-hero {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.5rem;
	margin: 1.5rem 0 2.5rem;
	padding: clamp(2rem, 6vw, 4rem) clamp(1.5rem, 5vw, 3.5rem);
	border-radius: var(--shanmp3-radius-lg);
	background: linear-gradient(135deg, var(--shanmp3-accent-fill) 0%, var(--shanmp3-accent-2) 100%);
	color: #0b0c10;
	overflow: hidden;
	box-shadow: var(--shanmp3-shadow-lg);
}
/* Soft radial highlight for depth, layered over the gradient. */
.shanmp3-home-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background: radial-gradient(120% 100% at 0% 0%, rgba(255, 255, 255, 0.18), transparent 55%);
}
.shanmp3-home-hero > * {
	position: relative;
	z-index: 1;
}
.shanmp3-home-hero__eyebrow {
	margin: 0 0 0.25rem;
	font-size: 0.8rem;
	font-weight: 700;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(11, 12, 16, 0.72);
}
.shanmp3-home-hero__title {
	margin: 0 0 0.5rem;
	font-size: clamp(2rem, 6vw, 3.5rem);
	font-weight: 800;
	line-height: 1.05;
	color: #0b0c10;
}
.shanmp3-home-hero__tagline {
	margin: 0 0 1.25rem;
	max-width: 60ch;
	font-size: clamp(1rem, 2vw, 1.25rem);
	line-height: 1.5;
	color: rgba(11, 12, 16, 0.85);
}
.shanmp3-home-hero__actions {
	margin-top: 0.25rem;
}
/* Buttons inside the bright gradient need dark-on-light styling so they don't
   blend with the accent background. Override the theme's default button look
   only within the hero. */
.shanmp3-home-hero .wp-block-button__link {
	border-radius: var(--shanmp3-radius-pill);
	font-weight: 600;
}
.shanmp3-home-hero .shanmp3-home-hero__cta .wp-block-button__link {
	background: #0b0c10;
	color: var(--shanmp3-accent-fill);
}
.shanmp3-home-hero .shanmp3-home-hero__cta .wp-block-button__link:hover {
	background: #15171f;
	color: var(--shanmp3-accent-fill);
}
.shanmp3-home-hero .shanmp3-home-hero__cta-alt .wp-block-button__link {
	background: transparent;
	color: #0b0c10;
	border-color: #0b0c10;
}
.shanmp3-home-hero .shanmp3-home-hero__cta-alt .wp-block-button__link:hover {
	background: rgba(11, 12, 16, 0.08);
	color: #0b0c10;
	border-color: #0b0c10;
}
@media (max-width: 600px) {
	.shanmp3-home-hero__actions .wp-block-button {
		margin-bottom: 0.5rem;
		flex: 0 0 auto;
		width: auto;
	}
	/* Compact auto-width CTA pill — mobile only. The hero button is too heavy
	   on a narrow screen, so shrink the font + padding and size it to its label
	   (not stretched). Desktop keeps the full hero button. (0,3,0) beats
	   theme.json's .wp-element-button (0,1,0) and core's :where() (0,0,0). */
	.shanmp3-home-hero .shanmp3-home-hero__cta .wp-block-button__link {
		display: inline-block;
		width: auto;
		font-size: 0.85rem;
		padding: 0.45rem 0.9rem;
	}
}

/* =========================================================================
   Home hero slider (backend-managed carousel replacing the static hero)
   =========================================================================
   Each slide panel reuses .shanmp3-home-hero so the size and look match the
   original static hero exactly. The track is a horizontal flex row of the
   panels; it slides with a GPU-friendly translateX driven by the --i index
   custom property (set by the slider island). Because every slide stays in
   flow (no absolute stacking, no opacity crossfade) and the row height equals
   the tallest slide, switching slides never reflows the track — the slide is
   smooth. No JS = first slide visible (--i defaults to 0).
   */
.shanmp3-slider {
	position: relative;
	margin: 1.5rem 0 2.5rem;
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
	box-shadow: var(--shanmp3-shadow-lg);
}
.shanmp3-slider__track {
	display: flex;
	/* Slide the row by --i slides. --slide-w is the exact pixel width of one
	   slide, measured by the slider island. Translating in whole pixels (not
	   -100%) avoids the subpixel rounding gap: a percentage translate resolves
	   against the track's border-box while each slide's flex-basis 100%
	   resolves against the content box, and at fractional slider widths the
	   browser rounds the two differently — leaving a hairline sliver of the
	   previous slide visible at the edge. Matching the translate to the
	   measured slide width fixes it. Falls back to -100% (= one slide) before
	   JS measures, so the no-JS first paint still works. */
	transform: translateX(calc(var(--i, 0) * -1 * var(--slide-w, 100%)));
	transition: transform 0.5s ease;
	will-change: transform;
}
/* Slides sit side by side, each one viewport wide. They stretch to the row's
   height (the tallest slide), so the track height is stable across switches.
   overflow:hidden makes each slide its own clipping context so a background
   image or content can never bleed into the neighbour's edge. */
.shanmp3-slider__slide {
	flex: 0 0 100%;
	min-width: 100%;
	position: relative;
	overflow: hidden;
}
/* The hero's own margin/radius/shadow belong on the root, not each slide. */
.shanmp3-slider__slide.shanmp3-home-hero {
	margin: 0;
	border-radius: 0;
	box-shadow: none;
}
/* Featured image as a clean cover background — no dark overlay. Sits behind
   the content (the hero's > * z-index:1 lifts the text above it). */
.shanmp3-slider__bg {
	position: absolute;
	inset: 0;
	z-index: 0;
	background-size: cover;
	background-position: center;
	background-repeat: no-repeat;
}
/* Over a photo, flip the hero text to light + soft shadow for legibility
   (no full overlay — keeps the image clean). The bg div precedes the text
   siblings, so ~ * targets the content that follows it. */
.shanmp3-slider__slide--has-image .shanmp3-slider__bg ~ * {
	color: #fff;
	text-shadow: 0 1px 8px rgba(0, 0, 0, 0.55);
}
.shanmp3-slider__slide--has-image .shanmp3-slider__bg ~ .shanmp3-home-hero__eyebrow {
	color: rgba(255, 255, 255, 0.85);
}
.shanmp3-slider__slide--has-image .shanmp3-slider__bg ~ .shanmp3-home-hero__tagline {
	color: rgba(255, 255, 255, 0.9);
}
/* Drop the hero's decorative radial highlight over a photo so the image stays clean. */
.shanmp3-slider__slide--has-image::after {
	display: none;
}
@media (prefers-reduced-motion: reduce) {
	/* No animated slide for reduced-motion users — instant swap. */
	.shanmp3-slider__track {
		transition: none;
	}
}
/* Arrows — bare chevrons on the edge. No background pill/circle: just the
   chevron icon with a soft shadow for legibility, dark to match the hero text
   on the gradient banner. */
.shanmp3-slider__btn {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 3;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	min-height: 44px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #0b0c10;
	cursor: pointer;
	transition: opacity 0.2s ease, transform 0.2s ease;
	filter: drop-shadow(0 1px 2px rgba(255, 255, 255, 0.25));
}
.shanmp3-slider__btn:hover {
	color: var(--shanmp3-accent-2);
	transform: translateY(-50%) scale(1.12);
}
.shanmp3-slider__btn:focus-visible {
	outline: 2px solid var(--shanmp3-accent-fill);
	outline-offset: 2px;
	border-radius: var(--shanmp3-radius-pill);
}
.shanmp3-slider__btn--prev {
	left: clamp(0.4rem, 1.5vw, 0.9rem);
}
.shanmp3-slider__btn--next {
	right: clamp(0.4rem, 1.5vw, 0.9rem);
}
.shanmp3-slider__btn-icon {
	width: 28px;
	height: 28px;
}
/* Dots. */
.shanmp3-slider__dots {
	position: absolute;
	left: 0;
	right: 0;
	bottom: clamp(0.6rem, 2vw, 1rem);
	z-index: 3;
	display: flex;
	justify-content: center;
	gap: 0.5rem;
}
.shanmp3-slider__dot {
	width: 10px;
	height: 10px;
	padding: 0;
	border: 0;
	border-radius: 50%;
	background: rgba(11, 12, 16, 0.35);
	cursor: pointer;
	transition: background 0.2s ease, transform 0.2s ease;
}
.shanmp3-slider__dot:hover {
	background: rgba(11, 12, 16, 0.55);
}
.shanmp3-slider__dot.is-active {
	background: #0b0c10;
	transform: scale(1.15);
}
/* Over a photo (active slide has an image) the bare chevrons and dots flip to
   light so they stay visible regardless of the image's brightness. */
.shanmp3-slider:has(.shanmp3-slider__slide.is-active.shanmp3-slider__slide--has-image) .shanmp3-slider__btn {
	color: #fff;
	filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.6));
}
.shanmp3-slider:has(.shanmp3-slider__slide.is-active.shanmp3-slider__slide--has-image) .shanmp3-slider__dot {
	background: rgba(255, 255, 255, 0.7);
}
.shanmp3-slider:has(.shanmp3-slider__slide.is-active.shanmp3-slider__slide--has-image) .shanmp3-slider__dot:hover {
	background: rgba(255, 255, 255, 0.9);
}
.shanmp3-slider:has(.shanmp3-slider__slide.is-active.shanmp3-slider__slide--has-image) .shanmp3-slider__dot.is-active {
	background: #fff;
}
@media (max-width: 600px) {
	/* Edge-disc arrows — mobile only. A small translucent circular button
	   flush at the slide edge (left:0 / right:0), vertically centered on the
	   border. The frosted dark disc with a white chevron reads over both the
	   bright gradient hero and photo slides; nothing is clipped (overflow
	   hidden on the root keeps the track contained, the disc sits inside).
	   Desktop keeps the bare-chevron look. */
	.shanmp3-slider__btn {
		width: 30px;
		height: 30px;
		min-height: 30px;
		border-radius: 50%;
		background: rgba(11, 12, 16, 0.45);
		color: #fff;
		filter: none;
		-webkit-backdrop-filter: blur(4px);
		backdrop-filter: blur(4px);
	}
	.shanmp3-slider__btn:hover {
		background: rgba(11, 12, 16, 0.65);
		color: #fff;
		transform: translateY(-50%) scale(1.08);
	}
	.shanmp3-slider__btn--prev {
		left: 0;
	}
	.shanmp3-slider__btn--next {
		right: 0;
	}
	.shanmp3-slider__btn-icon {
		width: 18px;
		height: 18px;
	}
}

/* =========================================================================
   Song list (track lists, album tracks, playlist tracks, history)
   =========================================================================
   Minimalist tracklist: a flat list on the page background — no card chrome,
   no shadows, no banded header. A quiet label row (# / Title / Time) sits on
   a hairline divider, rows are separated by hairlines, and a number → play
   swap fires on hover. The forward-compatible .is-playing hook turns the
   title accent and swaps the number for a filled accent disc.
   ========================================================================= */
.shanmp3-song-table {
	display: block;
}
.shanmp3-song-list {
	display: flex;
	flex-direction: column;
	list-style: none;
	margin: 0;
	padding: 0;
	background: transparent;
	border: 0;
	border-radius: 0;
	box-shadow: none;
}

/* Quiet header: muted labels on a hairline divider (no band). The art track is
   an empty spacer matching the row's cover, and the last (actions) track is
   fixed at 4.25rem to fit the row's queue + favorite buttons, so the head and
   row — separate grids — share the same column edges and "Title" lines up over
   the title text (not the cover) and "Time" over the duration. */
.shanmp3-song-list__head {
	display: grid;
	grid-template-columns: 2rem 2.5rem 1fr auto 4.25rem;
	gap: 0.75rem;
	padding: 0 0.5rem 0.5rem;
	border-bottom: 1px solid var(--shanmp3-border);
	color: var(--shanmp3-muted);
	font-size: 0.7rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}
.shanmp3-song-list__head span:nth-child(4),
.shanmp3-song-list__head span:nth-child(5) {
	text-align: right;
}

/* Row: hairline divider, flat (no radius, no shadow). Five tracks mirror the
   header: index | cover | title | duration | actions. */
.shanmp3-song-list__row {
	position: relative;
	display: grid;
	grid-template-columns: 2rem 2.5rem 1fr auto 4.25rem;
	align-items: center;
	gap: 0.75rem;
	padding: 0.55rem 0.5rem;
	border-bottom: 1px solid var(--shanmp3-border);
	color: var(--shanmp3-fg);
	transition: background-color var(--shanmp3-transition-fast);
}
.shanmp3-song-list__row:last-child {
	border-bottom: 0;
}
.shanmp3-song-list__row:hover,
.shanmp3-song-list__row:focus-within {
	background: var(--shanmp3-surface-2);
}

/* Index column: a play button that is ALWAYS visible (not just on hover) so the
   row reads as playable on touch devices with no hover state. Filled accent
   disc only while playing; otherwise a quiet fg glyph that accents on hover. */
.shanmp3-song-list__index {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
}
.shanmp3-song-list__num {
	display: none;
}
.shanmp3-song-list__play {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2rem;
	height: 2rem;
	border: 0;
	margin: 0;
	padding: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
	cursor: pointer;
	transition: color var(--shanmp3-transition-fast), background-color var(--shanmp3-transition-fast);
}
.shanmp3-song-list__play svg {
	width: 1.1rem;
	height: 1.1rem;
}
.shanmp3-song-list__row:hover .shanmp3-song-list__play,
.shanmp3-song-list__row:focus-within .shanmp3-song-list__play {
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__play:hover {
	background: var(--shanmp3-surface-2);
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__play:focus-visible {
	outline: none;
	box-shadow: var(--shanmp3-shadow-focus);
}

/* Cover art: small square thumbnail at the left of the title column. Holds the
   song's featured image, or a muted music glyph when the song has no art. */
.shanmp3-song-list__art {
	width: 2.5rem;
	height: 2.5rem;
	flex: 0 0 auto;
	border-radius: var(--shanmp3-radius-sm);
	overflow: hidden;
	background: var(--shanmp3-surface-2);
}
.shanmp3-song-list__art img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* Title + meta column. */
.shanmp3-song-list__main {
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
}
/* History rows (render_me_history) render without a cover-art slot, so their
   main column would auto-place into the 2.5rem art track and the title would be
   clipped to nothing (white-space:nowrap + ellipsis in 2.5rem). Span main across
   the art + title tracks so the title lands in the wide 1fr column. Scoped to
   art-less rows via :has() so normal cover-bearing rows are untouched. */
.shanmp3-song-list__row:not(:has(.shanmp3-song-list__art)) .shanmp3-song-list__main {
	grid-column: 2 / 4;
}
.shanmp3-song-list__titleline {
	display: flex;
	align-items: center;
	gap: 0.45rem;
	min-width: 0;
}
.shanmp3-song-list__title {
	margin: 0;
	flex: 1 1 auto;
	min-width: 0;
	font-size: 0.95rem;
	font-weight: 500;
	color: var(--shanmp3-fg);
	line-height: 1.8;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	text-decoration: none;
	transition: color var(--shanmp3-transition-fast);
}
/* Now-playing equalizer: three animated bars shown in the title line only while
   the row is playing. Hidden at rest so it takes no layout space. */
.shanmp3-song-list__eq {
	display: none;
	align-items: flex-end;
	gap: 2px;
	height: 0.85rem;
	flex: 0 0 auto;
}
.shanmp3-song-list__eq i {
	width: 2px;
	height: 100%;
	background: var(--shanmp3-accent);
	border-radius: 1px;
	transform-origin: bottom;
}
.shanmp3-song-list__row.is-playing .shanmp3-song-list__eq {
	display: inline-flex;
}
.shanmp3-song-list__row.is-playing .shanmp3-song-list__eq i {
	animation: shanmp3-eq 900ms ease-in-out infinite;
}
.shanmp3-song-list__row.is-playing .shanmp3-song-list__eq i:nth-child(2) {
	animation-delay: 150ms;
}
.shanmp3-song-list__row.is-playing .shanmp3-song-list__eq i:nth-child(3) {
	animation-delay: 300ms;
}
@keyframes shanmp3-eq {
	0%, 100% { transform: scaleY(0.35); }
	50%      { transform: scaleY(1); }
}
/* Irregular variant for the cover ring: uneven peaks so bars don't breathe in
   unison even before the island's per-bar randomization is applied. */
@keyframes shanmp3-eq-ring {
	0%   { transform: scaleY(0.25); }
	15%  { transform: scaleY(0.9); }
	25%  { transform: scaleY(0.4); }
	40%  { transform: scaleY(1); }
	55%  { transform: scaleY(0.3); }
	70%  { transform: scaleY(0.85); }
	85%  { transform: scaleY(0.45); }
	100% { transform: scaleY(0.25); }
}
.shanmp3-song-list__row:hover .shanmp3-song-list__title,
.shanmp3-song-list__title:hover {
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__meta {
	margin: 0;
	display: flex;
	align-items: center;
	gap: 0.35rem;
	font-size: 0.8rem;
	color: var(--shanmp3-muted);
	line-height: 1.6;
	min-width: 0;
}
/* Artist names take the available space and truncate; badges sit inline after
   them and never shrink, so the premium/explicit pills keep their natural size
   on one compact line instead of stacking under the artists or stretching. */
.shanmp3-song-list__artists {
	min-width: 0;
	flex: 1 1 auto;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.shanmp3-song-list__meta > .shanmp3-badge {
	flex: 0 0 auto;
}
/* Icon-only yellow premium lock inline in a song row (no "PREMIUM" text, no
   background pill) — matches the lock on the card covers. */
.shanmp3-song-list__premium {
	display: inline-flex;
	align-items: center;
	flex: 0 0 auto;
	color: #f5c451;
}
.shanmp3-song-list__premium .shanmp3-icon {
	width: 14px;
	height: 14px;
	filter: drop-shadow( 0 1px 2px rgba( 0, 0, 0, 0.5 ) );
}
.shanmp3-song-list__meta a {
	color: var(--shanmp3-muted);
	text-decoration: none;
}
.shanmp3-song-list__meta a:hover {
	color: var(--shanmp3-accent);
}

/* Duration + actions (right-aligned for a clean right edge). */
.shanmp3-song-list__dur {
	color: var(--shanmp3-muted);
	font-variant-numeric: tabular-nums;
	font-size: 0.82rem;
	text-align: right;
}
.shanmp3-song-list__actions {
	display: flex;
	align-items: center;
	justify-content: flex-end;
	gap: 0.2rem;
}
/* Favorite button inside a row: clearly visible at rest (fg, not muted), accent
   on hover/active. box-sizing:border-box so the 2rem width holds with its 1px
   border. The actions track (4.25rem) fits this plus the queue button. */
.shanmp3-song-list__actions .shanmp3-inline-like {
	box-sizing: border-box;
	width: 2rem;
	height: 2rem;
	min-height: 0;
	padding: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
}
.shanmp3-song-list__actions .shanmp3-inline-like svg {
	width: 1.25rem;
	height: 1.25rem;
}
.shanmp3-song-list__actions .shanmp3-inline-like:hover {
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__actions .shanmp3-inline-like[aria-pressed="true"] {
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__actions .shanmp3-inline-like:focus-visible {
	outline: none;
	box-shadow: var(--shanmp3-shadow-focus);
}
/* Add-to-queue button inside a row: mirrors the favorite button so the two sit
   together at the right edge. Quiet fg at rest, accent on hover. */
.shanmp3-song-list__actions .shanmp3-inline-queue {
	box-sizing: border-box;
	width: 2rem;
	height: 2rem;
	min-height: 0;
	padding: 0;
	border-radius: var(--shanmp3-radius-pill);
	background: transparent;
	color: var(--shanmp3-fg);
}
.shanmp3-song-list__actions .shanmp3-inline-queue svg {
	width: 1.25rem;
	height: 1.25rem;
}
.shanmp3-song-list__actions .shanmp3-inline-queue:hover {
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__actions .shanmp3-inline-queue:focus-visible {
	outline: none;
	box-shadow: var(--shanmp3-shadow-focus);
}

/* Now-playing state: the player adds .is-playing to the row matching the
   currently playing track. Accent title + animated equalizer in the title line
   + the index play button becomes a filled accent disc. */
.shanmp3-song-list__row.is-playing .shanmp3-song-list__title {
	color: var(--shanmp3-accent);
}
.shanmp3-song-list__row.is-playing .shanmp3-song-list__play {
	background: var(--shanmp3-accent-fill);
	color: #0b0c10;
}

/* -------------------------------------------------------------------------
   Mobile (≤ 767px): the artist page is a single column. Center the cover,
   stretch the follow button, and tighten the song-list columns so the title
   keeps room on narrow screens. The # index hides on the smallest phones.
   ------------------------------------------------------------------------- */
@media ( max-width: 767px ) {
	.shanmp3-artist-profile {
		gap: 1.25rem;
		padding: 1rem 0 0.5rem;
	}
	/* Centered, smaller cover; the aside is a single centered column. */
	.shanmp3-artist-profile__aside {
		align-items: center;
		text-align: center;
	}
	.shanmp3-artist-profile__cover {
		max-width: clamp( 140px, 45vw, 200px );
		margin-inline: auto;
	}
	/* Hide the detailed info card (Birth Place / Country / Gender / Genres) on
	   phones — the cover + Follow button are enough; the card reappears on the
	   two-column desktop layout. */
	.shanmp3-artist-profile__card {
		display: none;
	}
	.shanmp3-artist-profile__aside .shanmp3-hero__actions {
		width: 100%;
		margin-top: 0;
		justify-content: center;
	}
	/* Title sits flush to the page edge (no left offset vs the centered cover). */
	.shanmp3-artist-profile__main .shanmp3-hero__title {
		font-size: clamp( 1.6rem, 7vw, 2rem );
	}

	/* Song list: tighten the columns on phones. The art shrinks to 2rem and the
	   actions track stays 4.25rem (queue + favorite) so Time still lines up over
	   the duration. The play button stays visible at every width. */
	.shanmp3-song-list__head {
		grid-template-columns: 1.75rem 2rem 1fr auto 4.25rem;
		gap: 0.5rem;
		padding-inline: 0.25rem;
	}
	.shanmp3-song-list__row {
		grid-template-columns: 1.75rem 2rem 1fr auto 4.25rem;
		gap: 0.5rem;
		padding-inline: 0.25rem;
	}
	.shanmp3-song-list__art {
		width: 2rem;
		height: 2rem;
	}
}

/* =========================================================================
   Meta grid (song/album details)
   ========================================================================= */
.shanmp3-meta-grid {
	display: grid;
	gap: 0.75rem 1.5rem;
	grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
	margin: 1rem 0;
}
.shanmp3-meta-grid__item {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}
.shanmp3-meta-grid__label {
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--shanmp3-muted);
}
.shanmp3-meta-grid__value {
	color: var(--shanmp3-fg);
	font-size: 0.95rem;
}

/* =========================================================================
   Lyrics
   ========================================================================= */
.shanmp3-lyrics {
	max-width: 60ch;
	margin: 1.5rem 0;
	padding: 1rem 1.25rem;
	background: var(--shanmp3-surface);
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-lg);
	color: var(--shanmp3-fg);
	white-space: pre-wrap;
	line-height: 1.7;
	font-size: 1rem;
}

/* =========================================================================
   Song single page layout
   ========================================================================= */
/* Two-column "stage": a 1/4 left aside (circular cover + title + actions +
   meta) and a 3/4 right panel (karaoke lyrics, or a tracklist fallback). Stacks
   to a single centered column on phones. */
.shanmp3-song-single {
	display: grid;
	gap: 1.5rem;
	position: relative;
}
@media (min-width: 768px) {
	.shanmp3-song-single {
		grid-template-columns: 1fr 3fr;
		align-items: start;
		gap: 2rem;
	}
}

/* -------------------------------------------------------------------------
   Info popup wrapper: "i" info button (top-right) + popup dialog. Shared by
   the single-song "Track Info" popup (render_track_info) and the album
   "Album info" popup (render_album_meta). The .shanmp3-credit-* primitives
   below are reused by both.
   ------------------------------------------------------------------------- */
.shanmp3-song-credits {
	position: absolute;
	top: 0;
	right: 0;
	z-index: 5;
}

.shanmp3-credit-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 36px;
	height: 36px;
	padding: 0;
	border: 1px solid var( --shanmp3-border );
	border-radius: 50%;
	background: var( --shanmp3-surface );
	color: var( --shanmp3-muted );
	cursor: pointer;
	transition: color var( --shanmp3-transition-fast ), border-color var( --shanmp3-transition-fast ), background var( --shanmp3-transition-fast );
}

.shanmp3-credit-btn:hover {
	color: var( --shanmp3-accent );
	border-color: var( --shanmp3-accent );
}

.shanmp3-credit-btn .shanmp3-icon {
	width: 18px;
	height: 18px;
}

/* -------------------------------------------------------------------------
   Mobile back button (shanmp3/back-button block) — a top-left arrow that
   mirrors the top-right info button on the single entity pages, so mobile
   users can pop back without opening the menu. Mobile-only; the anchor's href
   is the post-type archive (no-JS / no-history fallback) and an inline script
   calls history.back() when there is a page to return to.
   ------------------------------------------------------------------------- */
.shanmp3-back-btn {
	display: none; /* shown only on mobile (max-width: 1023px) below */
}
@media ( max-width: 1023px ) {
	/* Establish the positioned ancestor for the absolute back button. The
	   song single and album hero are already position:relative; the playlist
	   hero and artist profile are not. */
	.single-shanmp3_playlist .shanmp3-hero,
	.single-shanmp3_artist .shanmp3-artist-profile {
		position: relative;
	}
	/* The ⓘ wrapper (.shanmp3-song-credits) is the 2nd element child of the
	   hero/song-single/artist-profile. Core's global-styles-inline emits
	   `:root :where(.is-layout-flow) > * { margin-block-start: 24px }` (0,1,0)
	   — it stamps a 24px top margin on every non-first-child, dropping the info
	   button ~24px below the back arrow (which IS :first-child, so core's
	   `> :first-child { margin-block-start:0 }` (0,2,0) zeroes it). A bare
	   `.shanmp3-song-credits` reset is only (0,1,0) and ties, losing by source
	   order (global-styles prints after the theme sheet). Qualify to (0,2,0)
	   so the two buttons sit at the same top:0 level. Mobile-only: desktop
	   keeps its long-standing 24px offset, so no visual change there. */
	.shanmp3-hero .shanmp3-song-credits,
	.shanmp3-song-single .shanmp3-song-credits,
	.single-shanmp3_artist .shanmp3-artist-profile .shanmp3-song-credits {
		margin-block-start: 0;
	}
	.shanmp3-back-btn {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		position: absolute;
		top: 0;
		inset-inline-start: 0;
		z-index: 5;
		/* The info button (.shanmp3-credit-btn, a <button>) is border-box, so
		   its 40/36px includes the 1px border. The back <a> defaults to
		   content-box → 42/38px total, 2px bigger. Match the info button's
		   box model so the two circles are identical at every breakpoint. */
		box-sizing: border-box;
		width: 36px;
		height: 36px;
		padding: 0;
		border: 1px solid var( --shanmp3-border );
		border-radius: 50%;
		background: var( --shanmp3-surface );
		color: var( --shanmp3-muted );
		text-decoration: none;
		cursor: pointer;
		-webkit-tap-highlight-color: transparent;
		transition: color var( --shanmp3-transition-fast ),
			border-color var( --shanmp3-transition-fast ),
			background var( --shanmp3-transition-fast );
	}
	.shanmp3-back-btn:hover,
	.shanmp3-back-btn:focus-visible {
		color: var( --shanmp3-accent );
		border-color: var( --shanmp3-accent );
	}
	.shanmp3-back-btn .shanmp3-icon {
		width: 18px;
		height: 18px;
	}
}

/* Match the info button's phone touch size (40px @ ≤767px) so the back arrow
   and the ⓘ are an identical pair at the same level — not 36px vs 40px. */
@media ( max-width: 767px ) {
	.shanmp3-back-btn {
		width: 40px;
		height: 40px;
	}
	.shanmp3-back-btn .shanmp3-icon {
		width: 20px;
		height: 20px;
	}
}

/* The popup (native <dialog>, top layer when open). */
.shanmp3-credit-dialog {
	width: min( 420px, 92vw );
	max-width: 92vw;
	max-height: 85vh;
	padding: 0;
	border: 1px solid var( --shanmp3-border );
	border-radius: var( --shanmp3-radius-lg );
	background: var( --shanmp3-surface );
	color: var( --shanmp3-fg );
	box-shadow: var( --shanmp3-shadow-lg );
	/* Clip full-width item hover rects to the dialog's rounded corners — same
	   trick .shanmp3-dropdown__menu uses (see its comment). Without this the
	   "Open Song" / "View artist" rows (width:100% + content-box padding) are
	   wider than the body content box and their hover bg pokes past the 20px
	   corner radius ("hover outside the card"). overflow-y:auto also lets tall
	   Track Info content scroll on desktop. Mobile re-asserts hidden auto at
	   (0,1,1) for the bottom-sheet. box-shadow / ::backdrop are not clipped by
	   the element's own overflow. */
	overflow: hidden auto;
}

.shanmp3-credit-dialog::backdrop {
	background: rgba( 0, 0, 0, 0.55 );
}

/* Mobile: bottom-sheet idiom for EVERY credit-style info popup — the song-card
   "Song info" popup, the single-song "Track Info" popup, and the album "Album
   info" popup. The dialog is in the top layer once open via showModal(), so
   position:fixed resolves against the viewport (NOT a transformed ancestor),
   which is exactly the case that broke the old position:fixed sheet on in-app
   WebViews. `dialog.` prefix keeps these (0,1,1) above any later base rule. The
   desktop card-scoped width override in shanmp3-design.css still wins at
   (0,1,1) for the song-card popup's narrower 30rem panel. */
@media ( max-width: 767px ) {
	dialog.shanmp3-credit-dialog {
		box-sizing: border-box; /* 100vw is content-box by default → border would push width past viewport → horizontal scroll */
		width: 100vw;
		max-width: 100vw;
		margin: 0;
		border-radius: var( --shanmp3-radius-lg ) var( --shanmp3-radius-lg ) 0 0;
		border-bottom: 0;
		position: fixed;
		top: auto; /* beat the UA dialog sheet's `inset:0` (top:0) so only bottom anchors */
		left: 0;
		right: 0;
		bottom: 0;
		max-height: 85vh;
		overflow: hidden auto; /* clip horizontal (prevents the bottom side-scroll bar), keep vertical scroll */
		padding-bottom: max( env( safe-area-inset-bottom ), 0.75rem );
		animation: shanmp3-dialog-slide-up 0.22s cubic-bezier( 0.16, 1, 0.3, 1 );
	}
}
@keyframes shanmp3-dialog-slide-up {
	from { transform: translateY( 100% ); }
	to   { transform: translateY( 0 ); }
}
@media ( prefers-reduced-motion: reduce ) {
	dialog.shanmp3-credit-dialog {
		animation: none;
	}
}

.shanmp3-credit-dialog__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	padding: 14px 16px;
	border-bottom: 1px solid var( --shanmp3-border );
}

.shanmp3-credit-dialog__title {
	margin: 0;
	font-size: 1rem;
	font-weight: 700;
}

.shanmp3-credit-dialog__body {
	padding: 12px 16px 16px;
	display: flex;
	flex-direction: column;
	gap: 10px;
}

.shanmp3-credit-row {
	display: flex;
	flex-direction: row;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
}

.shanmp3-credit-row__label {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	flex: 0 0 auto;
	font-size: 0.7rem;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var( --shanmp3-muted );
}

.shanmp3-credit-row__iconwrap {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	color: var( --shanmp3-accent );
}

.shanmp3-credit-row__icon {
	width: 0.95rem;
	height: 0.95rem;
}

.shanmp3-credit-row__value {
	flex: 1 1 auto;
	max-width: 72%;
	text-align: right;
	font-size: 0.95rem;
	font-weight: 600;
	color: var( --shanmp3-fg );
	word-break: break-word;
}

/* Mobile: keep the button top-right and a touch target. */
@media ( max-width: 767px ) {
	.shanmp3-credit-btn {
		width: 40px;
		height: 40px;
	}
	.shanmp3-credit-btn .shanmp3-icon {
		width: 20px;
		height: 20px;
	}
}

/* Left aside: the cover disc (with the centered play/pause overlay). The title,
   artists, actions, and meta now live in the right-hand main column. */
.shanmp3-song-single__aside {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
	min-width: 0;
}
/* On phones the aside stays a centered column. */
@media (max-width: 767px) {
	.shanmp3-song-single__aside {
		text-align: center;
	}
}
/* Right-hand main column: title + artists up top, then actions, meta, stage. */
.shanmp3-song-single__main {
	display: flex;
	flex-direction: column;
	min-width: 0;
}

/* Circular "vinyl" cover with an orbiting accent ring. overflow: visible so the
   ring (::before, inset negative) renders outside the disc; the <img> clips
   itself to the circle via its own border-radius. Spins while this song is
   playing (the song-stage island toggles .is-playing on the cover). Reuses the
   shanmp3-disc-spin / shanmp3-ring-spin keyframes from shanmp3-player.css. */
.shanmp3-song-single__cover {
	width: 100%;
	max-width: 240px;
	aspect-ratio: 1 / 1;
	border-radius: 50%;
	overflow: visible;
	background: var(--shanmp3-surface-2);
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--shanmp3-muted);
	position: relative;
}
@media (max-width: 767px) {
	.shanmp3-song-single__cover {
		max-width: clamp(180px, 60vw, 260px);
	}
}
/* The featured-image block wraps the <img> in a <figure>; let it fill the disc. */
.shanmp3-song-single__cover figure,
.shanmp3-song-single__cover .wp-block-post-featured-image {
	margin: 0;
	width: 100%;
	height: 100%;
	display: flex;
}
.shanmp3-song-single__cover img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	border-radius: 50%;
}

/* Equalizer ring around the cover disc: a circle of thin colorful bars
   sitting just outside the disc, each growing outward (radially). The
   song-stage island builds the bars (.shanmp3-song-single__eq-bar > i) in JS —
   hue + randomized timing per bar — so they read as a random audio meter.
   Sizes are in % of the disc so they track the responsive cover. Bars are
   quiet and static while paused, animate only while .is-playing. Nudged up a
   touch so the ring sits slightly above the disc rather than dead-centered. */
.shanmp3-song-single__eq {
	position: absolute;
	inset: -10px;
	transform: translateY( -12px );
	border-radius: 50%;
	pointer-events: none;
	z-index: 1;
}
.shanmp3-song-single__eq-bar {
	position: absolute;
	left: 50%;
	top: 50%;
	width: 3px;
	height: 50%;
	margin-left: -1.5px;
	/* The arm hangs from the disc center; rotating it sweeps the bar around
	   the circle. transform (rotate) is set inline per bar by the island. */
	transform-origin: top center;
}
.shanmp3-song-single__eq-bar i {
	position: absolute;
	left: 0;
	right: 0;
	top: 100%;
	height: 12px;
	border-radius: 2px;
	background: var(--shanmp3-accent); /* overridden per-bar by the island (rainbow hsl). */
	/* Grow outward from the disc edge. */
	transform-origin: top center;
	transform: scaleY( 0.35 );
	opacity: 0;
	transition: opacity 0.3s ease;
	/* Irregular multi-step keyframe + per-bar randomized delay/duration (set
	   inline by the island) so the ring reads as a random audio meter, not a
	   synced pulse. */
	animation: shanmp3-eq-ring 900ms ease-in-out infinite;
	animation-play-state: paused;
}
.shanmp3-song-single__cover.is-playing .shanmp3-song-single__eq-bar i {
	animation-play-state: running;
	opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
	.shanmp3-song-single__cover img {
		animation: none;
	}
	.shanmp3-song-single__eq-bar i {
		animation: none;
		transform: scaleY( 0.5 );
	}
}

/* Centered play/pause overlay on the cover disc — shown on all viewports (the
   action row's play button is hidden in favor of this overlay). On desktop it
   sits dead-center over the spinning cover; on mobile it doubles as the
   thumb-sized transport control. The song-stage island swaps the play/pause
   glyph from live player state and wires toggle-vs-start click semantics. */
.shanmp3-song-cover__play {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: 64px;
	height: 64px;
	border: 0;
	border-radius: 50%;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: rgba(0, 0, 0, 0.5);
	color: #fff;
	cursor: pointer;
	z-index: 2;
	-webkit-backdrop-filter: blur(2px);
	backdrop-filter: blur(2px);
	transition: transform 0.15s ease, background 0.15s ease;
}
.shanmp3-song-cover__play svg {
	width: 30px;
	height: 30px;
}
.shanmp3-song-cover__play:active {
	transform: translate(-50%, -50%) scale(0.94);
}
.shanmp3-song-cover__play:hover {
	background: rgba(0, 0, 0, 0.62);
}
/* On desktop, nudge the overlay a little above dead-center on the cover. */
@media (min-width: 768px) {
	.shanmp3-song-cover__play {
		top: 42%;
	}
}
/* On mobile, sit the overlay a little above dead-center (matches the original
   thumb-sized transport position). */
@media (max-width: 767px) {
	.shanmp3-song-cover__play {
		top: calc(50% - 28px);
	}
}
@media (max-width: 360px) {
	.shanmp3-song-cover__play {
		width: 54px;
		height: 54px;
	}
	.shanmp3-song-cover__play svg {
		width: 26px;
		height: 26px;
	}
}
/* The cover-center overlay is the transport control on all viewports, so hide
   the redundant play button in the action row. Other actions (like, share, …) stay. */
.shanmp3-song-single .shanmp3-hero__actions [data-shanmp3-play] {
	display: none;
}

/* Main column title + artists — they sit at the top of the right column. */
.shanmp3-song-single__main .wp-block-post-title,
.shanmp3-song-single__main h1 {
	margin: 0;
	font-size: clamp(1.6rem, 3vw, 2.25rem);
	font-weight: 800;
	line-height: 1.1;
	color: var(--shanmp3-fg);
}
.shanmp3-song-single__main .shanmp3-song-artists {
	margin: 0;
	padding-top: 10px;
	color: var(--shanmp3-muted);
	font-size: 1rem;
}
.shanmp3-song-single__main .shanmp3-song-artists a {
	color: var(--shanmp3-fg);
	text-decoration: none;
}
.shanmp3-song-single__main .shanmp3-song-artists a:hover {
	color: var(--shanmp3-accent);
}
/* On phones the header (title + artists) centers, mirroring the original aside. */
@media (max-width: 767px) {
	.shanmp3-song-single__main .wp-block-post-title,
	.shanmp3-song-single__main h1,
	.shanmp3-song-single__main .shanmp3-song-artists {
		text-align: center;
	}
}
/* Action chips sit under the artists. On phones they center. */
.shanmp3-song-single__main .shanmp3-hero__actions {
	margin-top: 0.5rem;
}
@media (max-width: 767px) {
	.shanmp3-song-single__main .shanmp3-hero__actions {
		justify-content: center;
	}
}

/* Icons for the three key stats live inside the meta items and replace their
   text labels on the single song page (both desktop and mobile). */
.shanmp3-meta-grid__iconwrap {
	display: none;
}
.shanmp3-meta-grid__icon {
	width: 18px;
	height: 18px;
	color: var(--shanmp3-accent);
}

/* Song-single meta: a single quiet inline line — icon + value separated by
   middots — shown on DESKTOP only. Only Duration / Genre / Plays are shown; the
   rest of the meta (released, language, ISRC, copyright) is hidden to keep the
   header minimal. On mobile (≤767px) the whole grid is hidden so the "Track
   Info" ⓘ popup (render_track_info) is the single track-info source, mirroring
   the album page which has only the album-meta popup. */
.shanmp3-song-single .shanmp3-meta-grid {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	align-items: center;
	gap: 0;
	margin: 0.4rem 0 0;
	padding: 0;
}
.shanmp3-song-single .shanmp3-meta-grid__item:not([data-shanmp3-key="duration"]):not([data-shanmp3-key="genre"]):not([data-shanmp3-key="plays"]) {
	display: none;
}
.shanmp3-song-single .shanmp3-meta-grid__item {
	display: inline-flex;
	flex-direction: row;
	align-items: center;
	gap: 0.3rem;
	padding: 0;
	border: 0;
	color: var(--shanmp3-muted);
}
/* Middot separators between the three stats (not after the last). */
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="duration"]::after,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"]::after {
	content: "·";
	margin: 0 0.5rem;
	color: var(--shanmp3-muted);
}
/* Key stats: show the icon, hide the text label. */
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="duration"] .shanmp3-meta-grid__iconwrap,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"] .shanmp3-meta-grid__iconwrap,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="plays"] .shanmp3-meta-grid__iconwrap {
	display: inline-flex;
}
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="duration"] .shanmp3-meta-grid__label,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"] .shanmp3-meta-grid__label,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="plays"] .shanmp3-meta-grid__label {
	display: none;
}
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="duration"] .shanmp3-meta-grid__icon,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"] .shanmp3-meta-grid__icon,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="plays"] .shanmp3-meta-grid__icon {
	color: var(--shanmp3-muted);
}
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="duration"] .shanmp3-meta-grid__value,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"] .shanmp3-meta-grid__value,
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="plays"] .shanmp3-meta-grid__value {
	font-size: 0.85rem;
	font-weight: 500;
	color: var(--shanmp3-muted);
	line-height: 1.2;
}
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"] .shanmp3-meta-grid__value a {
	color: inherit;
	text-decoration: none;
}
.shanmp3-song-single .shanmp3-meta-grid__item[data-shanmp3-key="genre"] .shanmp3-meta-grid__value a:hover {
	color: var(--shanmp3-accent);
}
/* Center the stat line on phones (the main header centers on mobile). On
   mobile the grid is hidden entirely — the "Track Info" ⓘ popup takes over as
   the single source of song metadata (matches the album page, which has only
   the album-meta popup). */
@media (max-width: 767px) {
	.shanmp3-song-single .shanmp3-meta-grid {
		justify-content: center;
		display: none;
	}
}

/* -------------------------------------------------------------------------
   Song stage: the right-hand panel (karaoke lyrics + tracklist fallback).
   ------------------------------------------------------------------------- */
.shanmp3-song-stage {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	min-width: 0;
}
/* On desktop the panel sticks while the page scrolls so the lyrics stay in view. */
@media (min-width: 768px) {
	.shanmp3-song-stage {
		position: sticky;
		top: 1rem;
	}
}
.shanmp3-song-stage__lyrics,
.shanmp3-song-stage__list {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	min-width: 0;
}
.shanmp3-song-stage__lyrics.is-hidden,
.shanmp3-song-stage__list.is-hidden {
	display: none;
}
.shanmp3-song-stage__head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
}
.shanmp3-song-stage__title {
	margin: 0;
	font-size: 1rem;
	font-weight: 700;
	color: var(--shanmp3-fg);
}
/* Scroll box shared by lyrics and tracklist. The top/bottom fade mask gives the
   karaoke "lines emerge from below / vanish above" feel. position:relative so
   line.offsetTop is measured relative to this box (used by the island). */
.shanmp3-song-stage__scroll,
.shanmp3-song-stage__list-body {
	position: relative;
	overflow-y: auto;
	height: clamp(360px, 60vh, 620px);
	padding: 1rem 0.5rem;
	text-align: center;
	-webkit-mask-image: linear-gradient( to bottom, transparent, #000 10%, #000 90%, transparent );
	mask-image: linear-gradient( to bottom, transparent, #000 10%, #000 90%, transparent );
	scrollbar-width: thin;
}
/* Karaoke lines: dim at rest; the active (matching) line is blue + magnified.
   Scoped under .shanmp3-song-stage so it beats the player's gold .is-active.
   Magnification is done with transform: scale() only — NOT font-size — so
   activating a line never reflows the column (which would shift every line's
   position and make the smooth-scroll target stale/janky). */
.shanmp3-song-stage .shanmp3-lyrics-line {
	position: relative;
	margin: 0.6rem auto;
	padding: 0 0.5rem;
	max-width: 52ch;
	color: var(--shanmp3-muted);
	font-size: 1rem;
	line-height: 1.8;
	transition: color 0.3s ease, transform 0.3s ease, opacity 0.3s ease;
	opacity: 0.55;
	will-change: transform, opacity;
}
.shanmp3-song-stage .shanmp3-lyrics-line.is-active {
	color: var(--shanmp3-accent-2);
	font-weight: 700;
	transform: scale(1.12);
	opacity: 1;
}
/* Plain (unsynced) lyrics: static text, no magnification. */
.shanmp3-song-stage .shanmp3-lyrics-plain {
	color: var(--shanmp3-fg);
	font-size: 1rem;
	line-height: 1.7;
	white-space: pre-wrap;
	text-align: center;
	max-width: 52ch;
	margin: 0 auto;
}
/* Tracklist body reuses the .shanmp3-song-list row styles; left-align it. */
.shanmp3-song-stage__list-body .shanmp3-song-list {
	text-align: left;
}
/* Mini karaoke header (small cover + title + dismiss) is mobile-only: it's shown
   inside the fixed .is-karaoke panel (see the mobile block below). Hidden
   everywhere else — including desktop, where the full cover + title are already
   visible in the page and the mini header would just duplicate them unstyled. */
.shanmp3-song-stage__mini {
	display: none;
}
/* Mobile: the panel stacks below the aside; drop sticky and keep the scroll box. */
@media (max-width: 767px) {
	.shanmp3-song-stage {
		position: static;
	}
	.shanmp3-song-stage__scroll,
	.shanmp3-song-stage__list-body {
		height: clamp(320px, 55vh, 520px);
	}
	/* Lyrics flow: the active line is pinned near the top and the column rises
	   continuously (song-stage.js), so hide the scrollbar for a clean karaoke
	   read. Scrolling still works (touch / auto-scroll) — only the gutter is hidden. */
	.shanmp3-song-stage__scroll {
		scrollbar-width: none;
	}
	.shanmp3-song-stage__scroll::-webkit-scrollbar {
		display: none;
	}

	/* Karaoke mode (.is-karaoke added by song-stage.js while this song is the
	   current track on mobile): the panel goes fixed between the site header and
	   the persistent player, so the active lyric stays at the top of the screen
	   for the whole song. The mini header keeps the cover + title visible. */
	.shanmp3-song-stage.is-karaoke {
		position: fixed;
		/* Start at the vertical midpoint so the upper half of the screen stays
		   clear and the cover photo shows through behind the lyrics panel. */
		top: 40vh;
		bottom: var( --shanmp3-player-h, 80px );
		left: 0;
		right: 0;
		z-index: 30;
		display: flex;
		flex-direction: column;
		gap: 0;
		background: var( --shanmp3-bg );
		box-shadow: 0 -2px 18px rgba( 0, 0, 0, 0.35 );
		border-top-left-radius: 18px;
		border-top-right-radius: 18px;
		overflow: hidden;
	}
	.shanmp3-song-stage.is-karaoke .shanmp3-song-stage__mini {
		display: flex;
		align-items: center;
		gap: 0.6rem;
		padding: 0.6rem 1rem;
		flex: 0 0 auto;
		border-bottom: 1px solid var( --shanmp3-border );
	}
	.shanmp3-song-stage__mini-cover {
		width: 40px;
		height: 40px;
		border-radius: 8px;
		object-fit: cover;
		flex: 0 0 auto;
		display: block;
	}
	.shanmp3-song-stage__mini-title {
		flex: 1 1 auto;
		min-width: 0;
		font-weight: 700;
		font-size: 0.95rem;
		color: var( --shanmp3-fg );
		white-space: nowrap;
		overflow: hidden;
		text-overflow: ellipsis;
	}
	.shanmp3-song-stage__mini-close {
		flex: 0 0 auto;
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: 32px;
		height: 32px;
		border: 0;
		border-radius: 50%;
		background: transparent;
		color: var( --shanmp3-muted );
		cursor: pointer;
	}
	.shanmp3-song-stage__mini-close:hover {
		color: var( --shanmp3-fg );
		background: var( --shanmp3-surface-2, rgba( 255, 255, 255, 0.08 ) );
	}
	/* In karaoke mode only the lyrics panel shows; the section header and the
	   tracklist are hidden — the mini header replaces the section header. */
	.shanmp3-song-stage.is-karaoke .shanmp3-song-stage__list {
		display: none;
	}
	.shanmp3-song-stage.is-karaoke .shanmp3-song-stage__lyrics {
		flex: 1 1 0;
		min-height: 0;
		display: flex;
		flex-direction: column;
		gap: 0;
	}
	.shanmp3-song-stage.is-karaoke .shanmp3-song-stage__head {
		display: none;
	}
	.shanmp3-song-stage.is-karaoke .shanmp3-song-stage__scroll {
		flex: 1 1 0;
		min-height: 0;
		height: auto;
	}
}

/* =========================================================================
   Library shell
   ========================================================================= */
.shanmp3-library {
	display: flex;
	flex-direction: column;
	gap: 2rem;
}
/* Logged-out visitors: the me-profile block at the top already shows a single
   login hero, so hide the per-section login prompts (Playlists/Favorites/
   History/Following) to avoid a stack of repeated "Log in" cards. */
body:not( .logged-in ) .shanmp3-library {
	display: none;
}

/* Login prompt (logged-out library / profile). A centered hero card with a
   prominent "Log in" button. */
.shanmp3-library__login {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
	max-width: 460px;
	margin: 1rem auto;
	padding: 3rem 1.5rem;
	text-align: center;
	background: var( --shanmp3-surface );
	border: 1px solid var( --shanmp3-border );
	border-radius: var( --shanmp3-radius-lg );
	box-shadow: var( --shanmp3-shadow-md );
}
.shanmp3-library__login-icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 72px;
	height: 72px;
	border-radius: 50%;
	background: color-mix( in srgb, var( --shanmp3-accent ) 14%, transparent );
	color: var( --shanmp3-accent );
}
.shanmp3-library__login-icon .shanmp3-icon {
	width: 34px;
	height: 34px;
}
.shanmp3-library__login-title {
	margin: 0;
	font-size: 1.5rem;
	font-weight: 800;
	color: var( --shanmp3-fg );
}
.shanmp3-library__login-text {
	margin: 0;
	max-width: 38ch;
	font-size: 0.975rem;
	line-height: 1.55;
	color: var( --shanmp3-muted );
}
.shanmp3-library__login-btn {
	min-width: 200px;
}
.shanmp3-library__login-btn-icon {
	width: 20px;
	height: 20px;
}

/* Library sections rendered as surface panels (cards) for a clearer grouping
   than the bare stacked rows. Scoped to the library so other .shanmp3-section
   uses on Home/Discover keep their open layout. */
.shanmp3-library .shanmp3-section {
	background: var(--shanmp3-surface, #111);
	border: 1px solid var(--shanmp3-border, #222);
	border-radius: var(--shanmp3-radius-lg, 1rem);
	padding: clamp(1.25rem, 3vw, 1.75rem);
}
/* Iconified section title (inline glyph + label). */
.shanmp3-library .shanmp3-section__title {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
}
.shanmp3-section__title-icon {
	display: inline-flex;
	align-items: center;
	color: var(--shanmp3-accent, #6366f1);
}
.shanmp3-section__title-icon .shanmp3-icon {
	width: 20px;
	height: 20px;
}

/* =========================================================================
   Search results + suggestions (Phase 11)
   ========================================================================= */
.shanmp3-search-results {
	display: flex;
	flex-direction: column;
	gap: 2rem;
}
.shanmp3-search-results__query {
	font-size: var(--shanmp3-text-lg, 1.125rem);
	color: var(--shanmp3-muted, #888);
	margin: 0;
}
.shanmp3-search-tabs {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	border-bottom: 1px solid var(--shanmp3-border, #222);
	padding-bottom: 0.75rem;
}
.shanmp3-search-tabs__tab {
	padding: 0.4rem 0.85rem;
	border-radius: var(--shanmp3-radius-pill, 999px);
	text-decoration: none;
	color: var(--shanmp3-muted, #888);
	font-size: var(--shanmp3-text-sm, 0.875rem);
	background: var(--shanmp3-surface-2, #1c1c1c);
}
.shanmp3-search-tabs__tab:hover {
	color: var(--shanmp3-text, #fff);
}
.shanmp3-search-tabs__tab.is-active {
	background: var(--shanmp3-accent-fill, #ca8a04);
	color: #000;
	font-weight: 600;
}
.shanmp3-search-group {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}
.shanmp3-section__head {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 1rem;
}
.shanmp3-section__link {
	font-size: var(--shanmp3-text-sm, 0.875rem);
	color: var(--shanmp3-accent, #a16207);
	text-decoration: none;
}
.shanmp3-section__link:hover {
	text-decoration: underline;
}
.shanmp3-genre-list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
	gap: 0.5rem;
}
.shanmp3-genre-list__item {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 0.5rem 0.75rem;
	background: var(--shanmp3-surface-2, #1c1c1c);
	border-radius: var(--shanmp3-radius-sm, 0.375rem);
}
.shanmp3-genre-list__item a {
	color: inherit;
	text-decoration: none;
}
.shanmp3-genre-list__item a:hover {
	text-decoration: underline;
}
.shanmp3-genre-list__count {
	color: var(--shanmp3-muted, #888);
	font-size: var(--shanmp3-text-xs, 0.75rem);
}
.shanmp3-pagination {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 1rem;
	padding-top: 1rem;
}
.shanmp3-pagination__link {
	color: var(--shanmp3-accent, #a16207);
	text-decoration: none;
}
.shanmp3-pagination__link:hover {
	text-decoration: underline;
}
.shanmp3-pagination__info {
	color: var(--shanmp3-muted, #888);
	font-size: var(--shanmp3-text-sm, 0.875rem);
}

/* Suggestions dropdown (hydrated island). Grouped by entity, with cover thumbs,
   loading/empty states, and recent searches. */
.shanmp3-search-bar {
	position: relative;
}
.shanmp3-search-suggest {
	position: absolute;
	left: 0;
	right: 0;
	top: 100%;
	margin-top: 0.25rem;
	z-index: 30;
	max-height: min(60vh, 460px);
	overflow-y: auto;
	overscroll-behavior: contain;
	background: var(--shanmp3-surface-2, #1c1c1c);
	border: 1px solid var(--shanmp3-border, #222);
	border-radius: var(--shanmp3-radius-md, 0.5rem);
	box-shadow: var(--shanmp3-shadow-md, 0 6px 24px rgba(0, 0, 0, 0.35));
}
.shanmp3-search-suggest[hidden] {
	display: none;
}
/* Entity group header (Songs / Artists / … / Recent). */
.shanmp3-search-suggest__group {
	padding: 0.5rem 0.85rem 0.25rem;
	font-size: var(--shanmp3-text-xs, 0.75rem);
	font-weight: 700;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: var(--shanmp3-muted, #888);
}
.shanmp3-search-suggest__group:first-child {
	padding-top: 0.35rem;
}
.shanmp3-search-suggest__item,
.shanmp3-search-suggest__all {
	display: flex;
	align-items: center;
	gap: 0.75rem;
	padding: 0.55rem 0.85rem;
	color: var(--shanmp3-text, #fff);
	text-decoration: none;
}
.shanmp3-search-suggest__item:hover,
.shanmp3-search-suggest__item.is-active,
.shanmp3-search-suggest__all:hover {
	background: var(--shanmp3-surface, #111);
}
/* Cover thumbnail (lazy <img>) or the type-icon SVG fallback. Both are 40×40 so the
   row never reflows as images decode. */
.shanmp3-search-suggest__cover,
.shanmp3-search-suggest__icon {
	flex: 0 0 auto;
	width: 40px;
	height: 40px;
	border-radius: var(--shanmp3-radius-sm, 0.375rem);
	object-fit: cover;
	background: var(--shanmp3-surface, #111);
}
.shanmp3-search-suggest__icon {
	padding: 8px;
	color: var(--shanmp3-muted, #888);
	box-sizing: content-box;
	width: 24px;
	height: 24px;
}
.shanmp3-search-suggest__text {
	display: flex;
	flex-direction: column;
	gap: 0.1rem;
	min-width: 0;
}
.shanmp3-search-suggest__title {
	font-size: var(--shanmp3-text-sm, 0.875rem);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.shanmp3-search-suggest__sub {
	font-size: var(--shanmp3-text-xs, 0.75rem);
	color: var(--shanmp3-muted, #888);
	text-transform: capitalize;
}
.shanmp3-search-suggest__all {
	color: var(--shanmp3-accent, #a16207);
	font-size: var(--shanmp3-text-sm, 0.875rem);
	font-weight: 600;
	border-top: 1px solid var(--shanmp3-border, #222);
	margin-top: 0.25rem;
}
/* Loading / empty state row. No role="option" → keyboard nav skips it. */
.shanmp3-search-suggest__state {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	padding: 0.85rem;
	color: var(--shanmp3-muted, #888);
	font-size: var(--shanmp3-text-sm, 0.875rem);
}
.shanmp3-search-suggest__spinner {
	width: 16px;
	height: 16px;
	border: 2px solid var(--shanmp3-border, #333);
	border-top-color: var(--shanmp3-accent, #a16207);
	border-radius: 50%;
	animation: shanmp3-search-spin 0.7s linear infinite;
}
@keyframes shanmp3-search-spin {
	to {
		transform: rotate(360deg);
	}
}
/* Recent-search rows reuse __item; the --recent modifier drops the thumb. */
.shanmp3-search-suggest__item--recent {
	padding-inline-start: 0.85rem;
}
/* Visually-hidden aria-live status region (announces results/empty to SRs). */
.shanmp3-search-status {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}
@media (prefers-reduced-motion: reduce) {
	.shanmp3-search-suggest__spinner {
		animation: none;
	}
	.shanmp3-search-suggest {
		transition: none;
	}
}
/* Mobile: larger 48px touch targets inside the dropdown. */
@media (max-width: 600px) {
	.shanmp3-search-suggest__item,
	.shanmp3-search-suggest__all,
	.shanmp3-search-suggest__state {
		min-height: 48px;
		padding: 0.65rem 0.85rem;
	}
}
/* Profile hero banner — a gold-range gradient with dark ink. Unlike the home
   hero (gold → indigo), the profile text spans the full width so it can't sit
   on the gold half only; a two-tone gradient leaves dark text unreadable on the
   indigo half (~2.8:1). Keeping both ends in the gold family (accent-fill → a
   lighter tint of it) preserves the hero-like banner + brand accent while
   keeping dark ink at AA contrast across the whole panel. */
.shanmp3-profile {
	position: relative;
	overflow: hidden;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 1.5rem;
	padding: clamp(1.5rem, 4vw, 2.5rem);
	background: linear-gradient(135deg, var(--shanmp3-accent-fill, #ca8a04) 0%, color-mix(in srgb, var(--shanmp3-accent-fill, #ca8a04) 84%, #fff 16%) 100%);
	border-radius: var(--shanmp3-radius-lg, 1rem);
	color: #0b0c10;
}
/* Soft top-right highlight for depth, sitting behind the content (z-index:1). */
.shanmp3-profile::after {
	content: "";
	position: absolute;
	inset: 0;
	background: radial-gradient(circle at 85% 12%, rgba(255, 255, 255, 0.3), transparent 55%);
	pointer-events: none;
}
.shanmp3-profile__avatar {
	position: relative;
	z-index: 1;
	flex: 0 0 auto;
	width: 5.5rem;
	height: 5.5rem;
	border-radius: 50%;
	overflow: hidden;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	background: rgba(255, 255, 255, 0.28);
	box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.9);
	font-size: 2rem;
	line-height: 1;
	color: #0b0c10;
}
.shanmp3-profile__avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.shanmp3-profile__body {
	position: relative;
	z-index: 1;
	flex: 1 1 240px;
	min-width: 0;
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0.6rem;
}
.shanmp3-profile__eyebrow {
	font-size: 0.7rem;
	font-weight: 800;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: rgba(11, 12, 16, 0.62);
}
.shanmp3-profile__name {
	font-size: clamp(1.5rem, 3.5vw, 2rem);
	font-weight: 800;
	margin: 0;
	color: #0b0c10;
}
/* Stats become inline pill chips on the gradient (value + label side by side). */
.shanmp3-profile .shanmp3-meta-grid {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin: 0.25rem 0 0;
}
.shanmp3-profile .shanmp3-meta-grid__item {
	flex-direction: row;
	align-items: baseline;
	gap: 0.4rem;
	padding: 0.3rem 0.7rem;
	background: rgba(11, 12, 16, 0.12);
	border-radius: var(--shanmp3-radius-pill, 999px);
}
.shanmp3-profile .shanmp3-meta-grid__value {
	font-weight: 800;
	font-size: 0.95rem;
	color: #0b0c10;
}
.shanmp3-profile .shanmp3-meta-grid__label {
	font-size: 0.68rem;
	letter-spacing: 0.04em;
	text-transform: uppercase;
	color: rgba(11, 12, 16, 0.7);
}
/* Outline-style Log out button that reads on the gradient. */
.shanmp3-profile .shanmp3-btn--secondary {
	align-self: flex-start;
	margin-top: 0.25rem;
	background: rgba(11, 12, 16, 0.14);
	color: #0b0c10;
	border: 1px solid rgba(11, 12, 16, 0.3);
}
.shanmp3-profile .shanmp3-btn--secondary:hover {
	background: rgba(11, 12, 16, 0.26);
}
@media (max-width: 600px) {
	.shanmp3-profile {
		gap: 1rem;
	}
	.shanmp3-profile__avatar {
		width: 4.25rem;
		height: 4.25rem;
	}
}

/* =========================================================================
   Playlists manager (Phase 10)
   ========================================================================= */
.shanmp3-library__playlists {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}
.shanmp3-card--playlist {
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}
/* Podcast card = a playlist flagged as a podcast. Inherits the playlist card
   chrome via .shanmp3-card--playlist; this only adds the mic "Podcast" eyebrow
   badge and shifts the premium lock to the top-right corner so it never sits on
   top of the mic badge. */
.shanmp3-badge--podcast {
	gap: 0.25em;
	background: var(--shanmp3-surface-2, rgba(255, 255, 255, 0.08));
	color: var(--shanmp3-fg);
	border: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.14));
}
/* Top-left is the default card-badge position; --start makes that explicit so
   the mic pill always claims the top-left corner. */
.shanmp3-card__badge--start {
	top: 8px;
	left: 8px;
}
/* On a podcast card, move the icon-only premium lock to top-right so it doesn't
   overlap the top-left mic badge. Featured (top-right via --end) and promoted
   (bottom-left via --bottom) keep their corners. */
.shanmp3-card--podcast .shanmp3-card__badge--icon {
	left: auto;
	right: 8px;
}
.shanmp3-card__ops {
	display: flex;
	gap: 0.25rem;
	margin-top: 0.25rem;
}
.shanmp3-playlist-edit {
	max-width: 24rem;
	width: calc(100vw - 2rem);
}
.shanmp3-form__row--actions {
	display: flex;
	justify-content: flex-end;
	gap: 0.5rem;
}

/* =========================================================================
   Search results
   ========================================================================= */
.shanmp3-search-results {
	display: flex;
	flex-direction: column;
	gap: 2rem;
}
.shanmp3-search-bar {
	display: flex;
	gap: 0.5rem;
	margin-bottom: 1.5rem;
}
.shanmp3-search-bar .shanmp3-input {
	flex: 1 1 auto;
}

/* Inline like/follow/share/comment buttons keep inline-flex sizing. */
.shanmp3-inline-like,
.shanmp3-inline-follow,
.shanmp3-inline-share,
.shanmp3-inline-comment,
.shanmp3-inline-add {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 0.35rem;
}
/* Count badges sit on the icon's top-right border as a small notch — the
   standard corner-badge style — so like + comment keep the uniform square
   chip shape while still showing their number. Scoped to the hero row so
   song-list rows keep their own layout. */
.shanmp3-hero__actions .shanmp3-inline-like,
.shanmp3-hero__actions .shanmp3-inline-comment {
	position: relative;
}
.shanmp3-hero__actions .shanmp3-like-count,
.shanmp3-hero__actions .shanmp3-comment-count {
	position: absolute;
	top: -0.4rem;
	right: -0.4rem;
	min-width: 1.05rem;
	height: 1.05rem;
	padding: 0 0.22rem;
	border-radius: var(--shanmp3-radius-pill);
	background: var(--shanmp3-surface-2, rgba(255, 255, 255, 0.06));
	border: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.12));
	color: var(--shanmp3-fg);
	font-size: 0.62rem;
	font-weight: 600;
	line-height: 1;
	font-variant-numeric: tabular-nums;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	z-index: 1;
}
.shanmp3-hero__actions .shanmp3-inline-like[aria-pressed="true"] .shanmp3-like-count {
	background: var(--shanmp3-accent);
	border-color: var(--shanmp3-accent);
	color: #fff;
}
/* Share button "Copied!" flash state. */
.shanmp3-inline-share.is-copied {
	color: var(--shanmp3-accent);
}

/* ------------------------------------------------------------------
 * Comments section
 * --------------------------------------------------------------- */
.shanmp3-comments {
	margin-top: 2rem;
	padding-top: 1.5rem;
	border-top: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.1));
}
.shanmp3-comments__title {
	font-size: var(--shanmp3-font-lg, 1.25rem);
	margin: 0 0 1rem;
}
.shanmp3-comments__list {
	list-style: none;
	margin: 0 0 1.5rem;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 1rem;
}
.shanmp3-comments__empty {
	color: var(--shanmp3-color-muted, #b3b3b3);
	margin: 0 0 1.5rem;
}
.shanmp3-comment {
	display: block;
}
.shanmp3-comment__row {
	display: flex;
	gap: 0.75rem;
}
.shanmp3-comment__avatar {
	flex: 0 0 auto;
}
.shanmp3-comment__img {
	border-radius: 50%;
	display: block;
	width: 40px;
	height: 40px;
}
.shanmp3-comment__body {
	flex: 1 1 auto;
	min-width: 0;
	background: var(--shanmp3-surface, rgba(255, 255, 255, 0.04));
	border: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.08));
	border-radius: var(--shanmp3-radius-md, 0.6rem);
	padding: 0.75rem 0.9rem;
}
.shanmp3-comment__head {
	display: flex;
	align-items: baseline;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin-bottom: 0.55rem;
}
.shanmp3-comment__author {
	font-weight: 600;
	font-size: 0.9rem;
	color: var(--shanmp3-accent);
}
.shanmp3-comment__time {
	font-size: 0.72rem;
	color: var(--shanmp3-muted, #9aa0b4);
}
.shanmp3-comment__time::before {
	content: "·";
	margin-right: 0.4rem;
	color: var(--shanmp3-muted, #9aa0b4);
}
.shanmp3-comment__text {
	color: color-mix(in srgb, var(--shanmp3-fg) 82%, var(--shanmp3-muted, #9aa0b4));
	font-size: 0.9rem;
	line-height: 1.55;
	word-wrap: break-word;
}
.shanmp3-comment__text p {
	margin: 0;
}

/* Reply link (core emits <a class="comment-reply-link">). Small, muted, gold on
   hover — reads as a secondary action, not a loud button. */
.shanmp3-comment__reply {
	margin-top: 0.5rem;
}
.shanmp3-comment .comment-reply-link {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
	font-size: 0.75rem;
	font-weight: 600;
	color: var(--shanmp3-muted, #9aa0b4);
	text-decoration: none;
	transition: color var(--shanmp3-transition-fast);
}
.shanmp3-comment .comment-reply-link .shanmp3-icon {
	width: 0.85rem;
	height: 0.85rem;
	flex: 0 0 auto;
}
.shanmp3-comment .comment-reply-link:hover {
	color: var(--shanmp3-accent);
}

/* Threaded replies: the walker nests child comments in <ol class="children">
   inside the parent <li>. Indent them under the comment body (avatar width +
   gap) and draw a left thread line so the nesting is scannable. */
.shanmp3-comment > .children {
	list-style: none;
	margin: 0.5rem 0 0;
	padding-left: 0.75rem;
	border-left: 2px solid var(--shanmp3-border, rgba(255, 255, 255, 0.1));
}
.shanmp3-comment > .children .shanmp3-comment__row {
	/* Shift the whole reply under the parent's body (avatar width + gap). */
	margin-left: calc(40px + 0.75rem);
}
@media ( max-width: 600px ) {
	.shanmp3-comment > .children {
		padding-left: 0.5rem;
	}
	.shanmp3-comment > .children .shanmp3-comment__row {
		margin-left: 1.75rem;
	}
}

/* Themed comment form (scoped so WP core classes don't leak globally). */
.shanmp3-comment-form {
	margin-top: 1.5rem;
}
.shanmp3-comment-form .comment-form-comment {
	margin: 0 0 0.75rem;
}
.shanmp3-comment-form textarea {
	box-sizing: border-box;
	width: 100%;
	border: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.12));
	border-radius: var(--shanmp3-radius-md, 0.6rem);
	background: var(--shanmp3-surface, rgba(255, 255, 255, 0.04));
	color: var(--shanmp3-fg);
	padding: 0.7rem 0.85rem;
	font: inherit;
	resize: vertical;
}
.shanmp3-comment-form textarea:focus {
	outline: none;
	border-color: var(--shanmp3-accent);
	box-shadow: var(--shanmp3-shadow-focus);
}
.shanmp3-comment-form .form-submit {
	margin: 0;
}
.shanmp3-comment-form .comment-reply-title {
	font-size: var(--shanmp3-font-md, 1rem);
	margin: 0 0 0.75rem;
}
.shanmp3-comment-form #cancel-comment-reply-link {
	margin-left: 0.5rem;
	font-size: var(--shanmp3-font-xs, 0.75rem);
}

/* "Log in to comment" prompt — a slim accent-tinted pill bar with a small
   gold CTA. One line on desktop, wraps cleanly on mobile. */
.shanmp3-comments__login {
	box-sizing: border-box;
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.45rem 0.7rem;
	margin-top: 1rem;
	padding: 0.5rem 0.85rem;
	border: 1px solid var(--shanmp3-border, rgba(255, 255, 255, 0.1));
	border-left: 2px solid var(--shanmp3-accent);
	border-radius: var(--shanmp3-radius-pill, 999px);
	background: color-mix(in srgb, var(--shanmp3-accent) 8%, var(--shanmp3-surface, rgba(255, 255, 255, 0.04)));
}
.shanmp3-comments__login-icon {
	flex: 0 0 auto;
	display: inline-flex;
	color: var(--shanmp3-accent);
}
.shanmp3-comments__login-icon svg {
	width: 1rem;
	height: 1rem;
}
.shanmp3-comments__login p {
	margin: 0;
	min-width: 0;
	color: var(--shanmp3-muted, #9aa0b4);
	font-size: 0.85rem;
}
.shanmp3-comments__login-btn {
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	margin-left: auto;
	padding: 0.32em 0.95em;
	border-radius: var(--shanmp3-radius-pill, 999px);
	background: var(--shanmp3-accent);
	color: #fff;
	font-size: 0.78rem;
	font-weight: 600;
	line-height: 1.4;
	text-decoration: none;
	white-space: nowrap;
	transition: background var(--shanmp3-transition-fast),
		transform var(--shanmp3-transition-fast),
		box-shadow var(--shanmp3-transition-fast);
}
.shanmp3-comments__login-btn:hover {
	background: linear-gradient(135deg, var(--shanmp3-accent) 0%, var(--shanmp3-accent-2) 100%);
	color: #fff;
	transform: translateY(-1px);
	box-shadow: 0 4px 14px color-mix(in srgb, var(--shanmp3-accent) 35%, transparent);
}
/* Breadcrumbs (Phase 13). Visible nav; the BreadcrumbList JSON-LD is emitted
   in <head>. Hidden on the smallest screens to save vertical space. */
.shanmp3-breadcrumbs {
	font-size: var(--shanmp3-font-xs, 0.8125rem);
	color: var(--shanmp3-color-muted, #b3b3b3);
	padding: 0.5rem 0 0;
}
.shanmp3-breadcrumbs__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem;
	align-items: center;
}
.shanmp3-breadcrumbs__item {
	display: inline-flex;
	align-items: center;
}
.shanmp3-breadcrumbs__item:not(:last-child)::after {
	content: "/";
	margin-left: 0.25rem;
	color: var(--shanmp3-color-muted, #6a6a6a);
}
.shanmp3-breadcrumbs__link {
	color: var(--shanmp3-color-muted, #b3b3b3);
	text-decoration: none;
}
.shanmp3-breadcrumbs__link:hover,
.shanmp3-breadcrumbs__link:focus {
	color: var(--shanmp3-color-text, #fff);
	text-decoration: underline;
}
.shanmp3-breadcrumbs__current {
	color: var(--shanmp3-color-text, #fff);
}
@media (max-width: 480px) {
	.shanmp3-breadcrumbs {
		display: none;
	}
}
/* The visible breadcrumb nav is kept in the markup for SEO (the BreadcrumbList
   JSON-LD is also emitted in <head>), but hidden from the album page UI by
   request — collapsed to a screen-reader-only block so assistive tech still
   announces the trail. Scoped to the album single template only; other
   entities keep their visible breadcrumb. */
.single-shanmp3_album .shanmp3-breadcrumbs {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	border: 0;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	clip-path: inset(50%);
	white-space: nowrap;
}
/* The 480px display:none above is overridden for album pages so the SR-only
   rule wins at every breakpoint (it already takes the nav out of flow). */

/* =========================================================================
   Album info popup (album-meta block)
   =========================================================================
   Reuses the Song Credit popup primitives (shanmp3-credit-btn +
   shanmp3-credit-dialog + shanmp3-credit-row) so the album info dialog is
   visually identical to the song credit one. The block renders the same ⓘ
   button (pinned top-right via .shanmp3-song-credits) and a native <dialog>
   with label+value rows. The album hero just needs to be the positioned
   ancestor for that absolute button. */
.single-shanmp3_album .shanmp3-hero {
	position: relative;
}
/* Reserve space on the right of the hero body (desktop) so the large album
   title never runs under the top-right ⓘ button. */
@media (min-width: 768px) {
	.single-shanmp3_album .shanmp3-hero__body {
		padding-right: 2.75rem;
	}
}

/* Artist info popup (shanmp3/artist-info block) — same top-right ⓘ pattern as
   the album/song info popups. The artist-profile grid just needs to be the
   positioned ancestor for that absolute button. (The back-button's mobile-only
   rule already sets this under max-width:1023px; this makes it apply on desktop
   too.) On desktop the button sits in the 2.5rem top padding gap, clear of the
   title; on mobile it overlaps the cover's top-right corner, matching album. */
.single-shanmp3_artist .shanmp3-artist-profile {
	position: relative;
}
@media (min-width: 768px) {
	/* Reserve space on the right of the title row so a long artist name never
	   runs under the top-right ⓘ button. */
	.single-shanmp3_artist .shanmp3-artist-profile__title-row {
		padding-right: 2.75rem;
	}
}
/* Album info rows can contain links (Artist, Genre); song credit values are
   plain text, so style links here for the shared credit-row value. */
.shanmp3-credit-row__value a {
	color: inherit;
	text-decoration: none;
}
.shanmp3-credit-row__value a:hover,
.shanmp3-credit-row__value a:focus {
	color: var(--shanmp3-accent, #f5c518);
	text-decoration: underline;
}

/* Artist info popup — the "About" block sits at the top of the dialog body,
   above the label+value rows. Richer than a credit_row can hold (multi-paragraph
   bio rendered via the_content). Only present when the artist has a bio. */
.shanmp3-artist-info__about {
	margin: 0 0 0.25rem;
}
.shanmp3-artist-info__about-title {
	margin: 0 0 0.5rem;
	font-size: 0.7rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var( --shanmp3-muted, #8b8f99 );
}
.shanmp3-artist-info__about-body {
	font-size: 0.875rem;
	line-height: 1.55;
	color: var( --shanmp3-text, #e8e9ee );
}
.shanmp3-artist-info__about-body p {
	margin: 0 0 0.6rem;
}
.shanmp3-artist-info__about-body p:last-child {
	margin-bottom: 0;
}
.shanmp3-artist-info__about-body a {
	color: var( --shanmp3-accent, #f5c518 );
	text-decoration: none;
}
.shanmp3-artist-info__about-body a:hover,
.shanmp3-artist-info__about-body a:focus {
	text-decoration: underline;
}

/* =========================================================================
   Artist archive (post-type archive grid)
   =========================================================================
   The archive reuses the .shanmp3-card--artist glyph but renders each card
   as a square (rounded) cover with the artist name below — a rounded-square
   tile on a subtle surface, matching the song/album card rhythm. The
   .shanmp3-card__cover--circle class (added by artist_card()) is overridden
   back to a rounded square here, scoped to the archive so the circular
   avatars used elsewhere keep their shape.
   ------------------------------------------------------------------------ */
.shanmp3-artist-archive {
	gap: 1.1rem;
	grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.shanmp3-artist-archive .shanmp3-card--artist {
	box-sizing: border-box;
	align-items: stretch;
	gap: 0.4rem;
	padding: 0;
	background: transparent;
	border: 0;
	border-radius: var(--shanmp3-radius-lg);
	transition: transform var(--shanmp3-transition),
		box-shadow var(--shanmp3-transition);
}
/* Rounded-square cover fills the card width (overrides the circular variant). */
.shanmp3-artist-archive .shanmp3-card__cover--circle {
	border-radius: var(--shanmp3-radius-md, 0.5rem);
}
.shanmp3-artist-archive .shanmp3-card__cover {
	width: 100%;
	height: auto;
	margin: 0;
}
.shanmp3-artist-archive .shanmp3-card__title {
	font-size: 0.95rem;
	line-height: 1.8;
	white-space: normal;
	text-align: center;
}
.shanmp3-artist-archive .shanmp3-card__meta {
	/* The "Artist" label is redundant on the artist archive — hide it. */
	display: none;
}
.shanmp3-artist-archive .shanmp3-card--artist:hover {
	transform: translateY(-4px);
}

@media (max-width: 600px) {
	.shanmp3-artist-archive {
		grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
		gap: 0.85rem;
	}
	.shanmp3-artist-archive .shanmp3-card--artist {
		padding: 0.6rem;
	}
}

/* -------------------------------------------------------------------------
   Artist archive — list view (.is-list on the grid)
   -------------------------------------------------------------------------
   Flipped on by the archive-view island (or the inline boot script) when the
   user picks the list toggle. The grid becomes a single column of horizontal
   rows: a small circular avatar on the left, the artist name on the right —
   a compact, scannable list for users who don't want the cover grid. No markup
   changes; the same .shanmp3-card--artist glyph is re-laid via CSS only, so
   pagination + the gender filter are untouched. Selectors are qualified to
   (0,3,0) to beat the archive's (0,2,0) grid rules above.
   ---------------------------------------------------------------------- */
.shanmp3-artist-archive.is-list {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}
.shanmp3-artist-archive.is-list .shanmp3-card--artist {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 0.85rem;
	padding: 0.55rem 0.6rem;
	background: transparent;
	border: 0;
	border-radius: var(--shanmp3-radius-md, 0.5rem);
	transition: background var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast);
}
/* Restore the circular avatar at a fixed thumbnail size (the archive forces a
   rounded-square full-width cover; list view wants a small round avatar).
   The cover sits inside the .shanmp3-card__avatar wrapper (added v0.8.105 so
   the featured/promoted seals aren't clipped by the circular mask). That
   wrapper is the real flex child and defaults to width:100%, so it must be
   pinned to the thumbnail size here or it expands and shoves the name to the
   far edge of the row. */
.shanmp3-artist-archive.is-list .shanmp3-card__avatar {
	width: 48px;
	height: 48px;
	flex: 0 0 auto;
}
.shanmp3-artist-archive.is-list .shanmp3-card__cover {
	width: 100%;
	height: 100%;
	flex: 0 0 auto;
	margin: 0;
}
.shanmp3-artist-archive.is-list .shanmp3-card__cover--circle {
	border-radius: 50%;
}
/* The featured/promoted seals are sized relative to the avatar (clamp 26%),
   which is right for the large grid tiles but reads as a huge blob on the
   48px list-row avatar (floors at 22px ≈ half the circle). Shrink them and
   thin the ring for list view only. Scoped to (0,3,0) to beat the base
   .shanmp3-card--artist .shanmp3-card__badge--seal at (0,2,0). */
.shanmp3-artist-archive.is-list .shanmp3-card__badge--seal {
	width: 13px;
	height: 13px;
	border-width: 1px;
	bottom: 0;
}
.shanmp3-artist-archive.is-list .shanmp3-card__badge--seal .shanmp3-icon {
	width: 60%;
	height: 60%;
}
.shanmp3-artist-archive.is-list .shanmp3-card__title {
	flex: 1 1 auto;
	text-align: left;
	font-size: 1rem;
	line-height: 1.4;
	white-space: nowrap;
}
/* Rows get a subtle surface on hover/focus instead of the grid's lift. */
.shanmp3-artist-archive.is-list .shanmp3-card--artist:hover {
	transform: none;
	background: var(--shanmp3-surface-2, var(--shanmp3-surface));
}
@media (max-width: 600px) {
	.shanmp3-artist-archive.is-list .shanmp3-card--artist {
		padding: 0.6rem 0.4rem;
	}
	.shanmp3-artist-archive.is-list .shanmp3-card__avatar {
		width: 44px;
		height: 44px;
	}
}

/* =========================================================================
   Responsive swap utilities — render two variants and toggle by breakpoint.
   Used by the front-page "Popular songs" section: a card grid on desktop, a
   ranked chart table on mobile (the grid gets cramped at phone width). Both
   variants stay in the markup; only one is ever shown. The breakpoint matches
   the chart's own mobile cutoff (≤600px) so the table and its hidden-plays
   rule kick in together.
   ========================================================================= */
.shanmp3-only-mobile {
	display: none;
}
@media (max-width: 600px) {
	.shanmp3-only-desktop {
		display: none;
	}
	.shanmp3-only-mobile {
		display: block;
	}
}

/* =========================================================================
   Top chart (ranked table — Weekly / Monthly top chart on Discover)
   =========================================================================
   Reuses the song-list row classes so the player's queue/playing hooks work
   unchanged. The chart's own column grid is rank | cover | main | plays | play | more
   (6 tracks). The trailing "more" column holds the 3-dot song-info sheet toggle
   that sits behind the play button. Scoped as `.shanmp3-chart .shanmp3-song-list__row`
   (0,2,0) to override the base `.shanmp3-song-list__row` (0,1,0) grid. Most-played
   is always #1 at the top (analytics returns rows ordered plays DESC). */
.shanmp3-chart {
	width: 100%;
}
.shanmp3-chart__head {
	display: grid;
	grid-template-columns: 2.5rem 2.5rem 1fr auto 2.5rem 2.5rem;
	gap: 0.75rem;
	padding: 0 0.5rem 0.5rem;
	border-bottom: 1px solid var(--shanmp3-border);
	color: var(--shanmp3-muted);
	font-size: 0.7rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}
.shanmp3-chart__head span:nth-child(4),
.shanmp3-chart__head span:nth-child(5),
.shanmp3-chart__head span:nth-child(6) {
	text-align: right;
}
.shanmp3-chart .shanmp3-song-list__row {
	grid-template-columns: 2.5rem 2.5rem 1fr auto 2.5rem 2.5rem;
}
/* 3-dot song-info toggle in a chart row: it is a direct grid item (the dialog
   it opens is a separate top-layer element, not a wrapper child), so align it
   end/center so the dot sits at the row's right edge, right behind the play
   button. The toggle reuses .shanmp3-song-list__play so it matches the play
   trigger's 2rem disc + accent-on-hover look. The card-scoped overlay
   positioning (.shanmp3-card--song .shanmp3-card__more-toggle) never matches a
   chart row, so the toggle flows inline here. */
.shanmp3-chart .shanmp3-chart__more-toggle {
	justify-self: end;
	align-self: center;
}
/* Rank number — bold, tabular so the digits line up. #1 gets the accent color. */
.shanmp3-chart__rank {
	display: flex;
	align-items: center;
	justify-content: center;
	font-weight: 700;
	font-variant-numeric: tabular-nums;
	color: var(--shanmp3-fg);
}
.shanmp3-chart__rank--top {
	color: var(--shanmp3-accent);
}
/* Play count column — muted, right-aligned, hidden on mobile to keep rows
   scannable (rank + cover + title + play). */
.shanmp3-chart__plays {
	text-align: right;
	color: var(--shanmp3-muted);
	font-size: 0.85rem;
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}
.shanmp3-chart__play {
	justify-self: end;
}
@media (max-width: 600px) {
	.shanmp3-chart__head {
		grid-template-columns: 2rem 2.5rem 1fr 2.25rem 2.25rem;
	}
	.shanmp3-chart__head .shanmp3-chart__head-plays {
		display: none;
	}
	.shanmp3-chart .shanmp3-song-list__row {
		grid-template-columns: 2rem 2.5rem 1fr 2.25rem 2.25rem;
	}
	.shanmp3-chart__plays {
		display: none;
	}
}

/* =========================================================================
   Album archive (post-type archive grid)
   =========================================================================
   Same clean treatment as the artist archive: borderless, background-less
   cards — just a square rounded cover with the album title + artist meta
   below. The album card already renders a rounded-square cover with a play
   overlay and the artist name as meta (unlike artists, that meta is useful
   here, so it is kept). Hover lifts the card; the cover keeps its own shadow.
   ------------------------------------------------------------------------ */
.shanmp3-album-archive {
	gap: 1.25rem;
	grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.shanmp3-album-archive .shanmp3-card--album {
	box-sizing: border-box;
	padding: 0;
	background: transparent;
	border: 0;
	gap: 0.4rem;
	transition: transform var(--shanmp3-transition);
}
.shanmp3-album-archive .shanmp3-card__title {
	font-size: 0.92rem;
	line-height: 1.3;
	white-space: normal;
}
.shanmp3-album-archive .shanmp3-card__meta {
	font-size: 0.78rem;
}
.shanmp3-album-archive .shanmp3-card--album:hover {
	transform: translateY(-4px);
}

@media (max-width: 600px) {
	.shanmp3-album-archive {
		grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
		gap: 0.9rem;
	}
}

/* =========================================================================
   Label archive
   Labels render as square-cover cards (like albums, not the artist circle),
   distinguished by a "Record Label" meta line. The grid sits inside the
   .shanmp3-label-archive section wrapper (mirrors the playlist archive), so
   only the card surface needs scoping here — the header/empty styles are
   shared with the playlist + song archives above.
   ========================================================================= */
.shanmp3-label-archive .shanmp3-card--label {
	box-sizing: border-box;
	padding: 0;
	background: transparent;
	border: 0;
	gap: 0.4rem;
	transition: transform var(--shanmp3-transition);
}
.shanmp3-label-archive .shanmp3-card--label .shanmp3-card__cover {
	border-radius: var(--shanmp3-radius-md);
	overflow: hidden;
}
.shanmp3-label-archive .shanmp3-card__title {
	font-size: 0.92rem;
	line-height: 1.6;
	white-space: normal;
}
.shanmp3-label-archive .shanmp3-card__meta {
	font-size: 0.78rem;
}
.shanmp3-label-archive .shanmp3-card--label:hover {
	transform: translateY(-4px);
}

/* Credit archive card surface (Composer/Studio/Producer/Band). Mirrors the
   label-archive card block above; the circle/square cover shape comes from
   .shanmp3-card--credit-circle / --credit-square in design.css. */
.shanmp3-credit-archive .shanmp3-card--credit {
	box-sizing: border-box;
	padding: 0;
	background: transparent;
	border: 0;
	gap: 0.4rem;
	transition: transform var(--shanmp3-transition);
}
.shanmp3-credit-archive .shanmp3-card--credit .shanmp3-card__cover {
	border-radius: var(--shanmp3-radius-md);
	overflow: hidden;
}
.shanmp3-credit-archive .shanmp3-card__title {
	font-size: 0.92rem;
	line-height: 1.6;
	white-space: normal;
}
.shanmp3-credit-archive .shanmp3-card__meta {
	font-size: 0.78rem;
}
.shanmp3-credit-archive .shanmp3-card--credit:hover {
	transform: translateY(-4px);
}

/* =========================================================================
   News archive
   The news archive is a magazine: a lead-story hero (page 1 / unfiltered only)
   above a landscape 16:9 card grid. The card surface mirrors the label/credit
   archive blocks; the lead hero is mobile-first (stacked) and becomes a
   two-column row on desktop.
   ========================================================================= */
.shanmp3-news-archive .shanmp3-card--news {
	box-sizing: border-box;
	padding: 0;
	background: transparent;
	border: 0;
	gap: 0.5rem;
	transition: transform var(--shanmp3-transition);
}
.shanmp3-news-archive .shanmp3-card--news .shanmp3-card__cover {
	border-radius: var(--shanmp3-radius-md);
	overflow: hidden;
}
.shanmp3-news-archive .shanmp3-card__title {
	font-size: 0.95rem;
	line-height: 1.35;
	white-space: normal;
}
.shanmp3-news-archive .shanmp3-card__meta {
	font-size: 0.76rem;
	color: var(--shanmp3-muted);
}
.shanmp3-news-archive .shanmp3-card--news:hover {
	transform: translateY(-4px);
}

/* The archive grid: 2 columns on mobile, a breathable 3-column magazine grid
   on desktop. (0,2,0) beats the base .shanmp3-grid auto-fill (0,1,0). */
.shanmp3-news-archive .shanmp3-grid {
	grid-template-columns: repeat(2, 1fr);
	gap: 1.25rem;
}
@media (min-width: 1024px) {
	.shanmp3-news-archive .shanmp3-grid {
		grid-template-columns: repeat(3, 1fr);
		gap: 2rem;
	}
	.shanmp3-news-archive .shanmp3-card__title {
		font-size: 1.05rem;
	}
}

/* Lead-story hero. Mobile: media stacked on top of the body. Desktop: a
   two-column row with a larger 58% media, a bigger headline, and a
   "Read story" pill CTA. Page 1 of the post-type archive only. */
.shanmp3-news__lead {
	display: flex;
	flex-direction: column;
	gap: 1rem;
	margin-bottom: 2.5rem;
	padding-bottom: 2.5rem;
	border-bottom: 1px solid var(--shanmp3-border);
}
.shanmp3-news__lead-media {
	position: relative;
	display: block;
	aspect-ratio: 16 / 9;
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
}
.shanmp3-news__lead-media .shanmp3-news__cat,
.shanmp3-news__lead-media .shanmp3-news__lead-cat {
	position: absolute;
	top: 12px;
	left: 12px;
	z-index: 1;
	padding: 0.3em 0.75em;
	font-size: 0.7rem;
	font-weight: 700;
	line-height: 1;
	text-transform: uppercase;
	letter-spacing: 0.04em;
	color: var(--shanmp3-surface, #fff);
	background: var(--shanmp3-accent, #6366f1);
	border-radius: var(--shanmp3-radius-pill, 999px);
}
.shanmp3-news__lead-body {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
}
.shanmp3-news__lead-cat {
	font-size: 0.72rem;
	font-weight: 800;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--shanmp3-accent);
}
.shanmp3-news__lead-title {
	margin: 0;
	font-size: clamp(1.5rem, 5vw, 2rem);
	font-weight: 800;
	line-height: 1.12;
}
.shanmp3-news__lead-title a {
	color: var(--shanmp3-fg);
	text-decoration: none;
}
.shanmp3-news__lead-title a:hover {
	color: var(--shanmp3-accent);
}
.shanmp3-news__lead-excerpt {
	margin: 0;
	display: -webkit-box;
	-webkit-box-orient: vertical;
	-webkit-line-clamp: 3;
	overflow: hidden;
	font-size: 1rem;
	line-height: 1.6;
	color: var(--shanmp3-muted);
}
.shanmp3-news__lead-meta {
	font-size: 0.82rem;
	color: var(--shanmp3-muted);
}
.shanmp3-news__lead-cta {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	align-self: flex-start;
	margin-top: 0.4rem;
	padding: 0.5em 1.1em;
	font-size: 0.85rem;
	font-weight: 700;
	color: var(--shanmp3-surface, #fff);
	background: var(--shanmp3-accent, #6366f1);
	border-radius: var(--shanmp3-radius-pill, 999px);
	text-decoration: none;
	-webkit-tap-highlight-color: transparent;
	transition: transform var(--shanmp3-transition), opacity var(--shanmp3-transition);
}
.shanmp3-news__lead-cta:hover,
.shanmp3-news__lead-cta:focus-visible {
	transform: translateY(-1px);
	opacity: 0.92;
}
@media (min-width: 1024px) {
	.shanmp3-news__lead {
		flex-direction: row;
		align-items: center;
		gap: 3rem;
		margin-bottom: 3rem;
		padding-bottom: 3rem;
	}
	.shanmp3-news__lead-media {
		flex: 0 0 48%;
	}
	.shanmp3-news__lead-body {
		flex: 1;
		max-width: 38rem;
	}
	.shanmp3-news__lead-title {
		font-size: clamp(2.25rem, 3.2vw, 3rem);
	}
	.shanmp3-news__lead-excerpt {
		-webkit-line-clamp: 4;
		font-size: 1.05rem;
	}
}

/* =========================================================================
   Single news article — two-column meta rail + content
   A magazine article laid out as a narrow left "rail" (back link, category
   eyebrow, byline) beside a wide reading column (title, 16:9 cover, prose
   body, tags). Mobile stacks the rail above the content as one column;
   desktop (>=900px) puts them side by side with the rail sticky on scroll.

   The three wrappers are core FLEX groups (layout:{"type":"flex"}), so core's
   flow-layout rule `:root :where(.is-layout-flow) > * { margin-block-start:
   24px }` never applies — the old single-column version was a flow group and
   that 24px margin stacked on top of the flex gap, doubling the spacing
   between every piece (the "big gap" the owner flagged). Here the only
   vertical spacing is our own gap, set at (0,2,0) via the .shanmp3-single-news
   qualifier so it beats core's inline `.is-layout-flex { gap:
   var(--wp--style--block-gap) }` (24px, (0,1,0), printed after the stylesheet
   — same trap as the archive grids; see wp-core-flex-block-gap-override).

   GOTCHA — `align-items`: core's base `.is-layout-flex { align-items: center }`
   (0,1,0) applies to the split, and its per-instance container rule only sets
   `flex-wrap`, NOT align-items. With `flex-direction: column` (mobile) and
   align-items left at center, the rail + content shrink to content-width and
   center horizontally — indented from the left, misaligned with each other,
   and the title (content's per-instance rule is align-items:flex-start) becomes
   max-content wide and stops wrapping. So every column explicitly sets
   `align-items: stretch` at (0,2,0): rail + content fill the full width and
   line up flush-left; the back link + eyebrow keep their explicit
   `align-self: flex-start` so they stay compact at the left. Desktop overrides
   the split to `align-items: flex-start` (so the rail stays top-aligned, not
   stretched to the content height — which would break the sticky rail).
   ========================================================================= */
.shanmp3-single-news .shanmp3-article--split {
	flex-direction: column;
	align-items: stretch;
	gap: 1.25rem;
}
.shanmp3-single-news .shanmp3-article__rail {
	flex-direction: column;
	align-items: stretch;
	gap: 0.85rem;
}
.shanmp3-single-news .shanmp3-article__content {
	flex-direction: column;
	align-items: stretch;
	gap: 1.25rem;
}
.shanmp3-article__back {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	align-self: flex-start;
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--shanmp3-muted);
	text-decoration: none;
	-webkit-tap-highlight-color: transparent;
	transition: color var(--shanmp3-transition);
}
.shanmp3-article__back:hover,
.shanmp3-article__back:focus-visible {
	color: var(--shanmp3-accent);
}
.shanmp3-article__back .shanmp3-icon {
	width: 18px;
	height: 18px;
}
.shanmp3-article__eyebrow {
	align-self: flex-start;
	padding: 0.3em 0.8em;
	font-size: 0.7rem;
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--shanmp3-accent);
	background: var(--shanmp3-surface-2, rgba(99, 102, 241, 0.12));
	border-radius: var(--shanmp3-radius-pill, 999px);
	text-decoration: none;
}
.shanmp3-article__title {
	margin: 0;
	font-size: clamp(1.85rem, 5vw, 2.85rem);
	font-weight: 800;
	line-height: 1.1;
	color: var(--shanmp3-fg);
}
.shanmp3-article__byline {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.4rem;
	font-size: 0.86rem;
	color: var(--shanmp3-muted);
}
.shanmp3-article__cover {
	width: 100%;
	aspect-ratio: 16 / 9;
	border-radius: var(--shanmp3-radius-lg);
	overflow: hidden;
}
/* The figure above is a responsive 16:9 box (aspect-ratio + width:100%). The
   <img> inside carries width="640" height="360" HTML attrs + loading="lazy".
   Core's block-library rule gives it `width:100%; height:auto` — but
   `height:auto` only resolves against the image's INTRINSIC ratio, which a
   lazily-loaded image inserted via soft-nav (DOMParser + replaceWith) does
   not expose until it actually loads. Until then the img falls back to its
   640x360 attribute box → overflows the figure → clipped by overflow:hidden →
   the cover looks non-responsive right after a soft-nav swap, only fitting
   once a hard refresh forces a real load. Pin the img to the figure's definite
   box with width/height:100% + object-fit:cover so it fills deterministically
   regardless of load state. (0,1,1) beats core's `.wp-block-post-featured-image
   :where(img)` (0,1,0, :where is zero-specificity). Mirrors the song-single
   cover disc rule below. */
.shanmp3-article__cover img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}
.shanmp3-article__body {
	font-size: 1.0625rem;
	line-height: 1.75;
	color: var(--shanmp3-fg);
}
.shanmp3-article__body > * + * {
	margin-top: 1.35rem;
}
/* The post-content body is a core FLOW group (is-layout-flow), so core's
   `:root :where(.is-layout-flow) > * { margin-block-start: 24px }` still stamps
   a 24px top margin on the FIRST body child — doubling the content column's
   gap right under the cover. Zero it (physical margin-top wins over core's
   logical margin-block-start); the `> * + *` rule above keeps sibling spacing. */
.shanmp3-article__body > :first-child {
	margin-top: 0;
}
.shanmp3-article__body h2,
.shanmp3-article__body h3 {
	margin-top: 2.25rem;
	line-height: 1.25;
}
.shanmp3-article__body img {
	max-width: 100%;
	height: auto;
	border-radius: var(--shanmp3-radius-md);
}
.shanmp3-article__body blockquote {
	margin: 1.75rem 0;
	padding: 0.5rem 0 0.5rem 1.25rem;
	border-left: 3px solid var(--shanmp3-accent);
	font-style: italic;
	color: var(--shanmp3-muted);
}
.shanmp3-article__tags {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}
@media (min-width: 900px) {
	.shanmp3-single-news .shanmp3-article--split {
		flex-direction: row;
		align-items: flex-start;
		gap: 3rem;
		max-width: 1000px;
		margin-inline: auto;
	}
	.shanmp3-single-news .shanmp3-article__rail {
		flex: 0 0 220px;
		position: sticky;
		top: calc(var(--shanmp3-header-h, 64px) + 1rem);
		align-self: flex-start;
		gap: 1rem;
	}
	/* Logged-in admins/managers keep the admin bar (32px desktop), so the
	   sticky rail must clear the header the same way the header itself does
	   (style.css `body.admin-bar header.wp-block-template-part { top: 32px }`).
	   Regular members have the bar hidden — the base offset above is enough. */
	body.admin-bar .shanmp3-single-news .shanmp3-article__rail {
		top: calc(var(--shanmp3-header-h, 64px) + 32px + 1rem);
	}
	.shanmp3-single-news .shanmp3-article__content {
		flex: 1 1 0;
		min-width: 0;
	}
	.shanmp3-article__title {
		font-size: clamp(2.25rem, 3vw, 3rem);
	}
}

/* =========================================================================
   Artist archive type filters (chips above the grid)
   ========================================================================= */
.shanmp3-archive__filters {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	margin-bottom: 1.25rem;
}
.shanmp3-archive__filter {
	box-sizing: border-box;
	padding: 0.4em 0.95em;
	font-size: 0.82rem;
	font-weight: 600;
}
.shanmp3-archive__filter:hover {
	border-color: var(--shanmp3-accent);
	color: var(--shanmp3-accent);
}
.shanmp3-archive__filter.is-active {
	background: var(--shanmp3-accent);
	border-color: var(--shanmp3-accent);
	color: #fff;
}
.shanmp3-archive__filter.is-active:hover {
	color: #fff;
}

/*
 * Mobile filter dropdown — the native <select> counterpart to the chip row.
 * Hidden by default (desktop shows chips); swapped in at <=600px where a long
 * chip list (genres) would wrap into many rows. Both controls are rendered by
 * archive_filter() and carry the same option set; the island navigates on change.
 *
 * Styled as a deliberate filter control (not a bare OS select): a funnel glyph
 * on the left signals "filter", a chevron on the right signals "dropdown", the
 * surface-2 fill lifts it off the page, and the border turns accent when a
 * filter is applied (.is-active) or focused — mirroring the chips above.
 */
.shanmp3-archive__select-label {
	display: none;
	position: relative;
}
.shanmp3-archive__select {
	box-sizing: border-box;
	width: 100%;
	min-height: var(--shanmp3-touch, 44px);
	/* Room for the funnel (left) + chevron (right) glyphs. */
	padding: 0.6em 2.5em 0.6em 2.6em;
	border-radius: var(--shanmp3-radius-md, 12px);
	border: 1px solid var(--shanmp3-border);
	background-color: var(--shanmp3-surface-2, var(--shanmp3-surface));
	color: var(--shanmp3-fg);
	font-family: inherit;
	font-size: 0.92rem;
	font-weight: 600;
	letter-spacing: 0.01em;
	appearance: none;
	-webkit-appearance: none;
	-moz-appearance: none;
	cursor: pointer;
	/*
	 * Two glyphs: funnel (left) + chevron-down (right). Stroke colors are
	 * hardcoded per theme because `currentColor` inside a data-URI background
	 * image does NOT resolve against the host element — it falls back to the SVG
	 * default (black), which is invisible on the dark surface. Dark mode is the
	 * default here; the light-mode blocks below re-point both strokes. %23 = '#'.
	 */
	background-image:
		url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239aa0b4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E"),
		url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%239aa0b4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
	background-position: left 0.95em center, right 0.95em center;
	background-repeat: no-repeat, no-repeat;
	transition: border-color var(--shanmp3-transition-fast),
		box-shadow var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast);
}
.shanmp3-archive__select:hover {
	border-color: var(--shanmp3-accent);
}
.shanmp3-archive__select:focus {
	outline: none;
	border-color: var(--shanmp3-accent);
	box-shadow: var(--shanmp3-shadow-focus);
}
/* A filter is applied (not "All") — accent border + text signal it, mirroring
 * the active chip. The glyphs stay muted (they're affordances, not status). */
.shanmp3-archive__select.is-active {
	border-color: var(--shanmp3-accent);
	color: var(--shanmp3-accent);
}

/* Light theme: re-point both glyphs to a dark stroke so they show on the light
 * surface. Mirrors the theme's own dark/light token selectors in style.css. */
:root[data-theme="light"] .shanmp3-archive__select {
	background-image:
		url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235a6072' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E"),
		url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235a6072' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
}
@media (prefers-color-scheme: light) {
	:root:not([data-theme]) .shanmp3-archive__select {
		background-image:
			url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235a6072' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolygon points='22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3'/%3E%3C/svg%3E"),
			url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235a6072' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
	}
}

@media (max-width: 600px) {
	/* Swap chips for the compact native dropdown on phones. */
	.shanmp3-archive__filters {
		display: none;
	}
	.shanmp3-archive__select-label {
		display: block;
		margin-bottom: 1.25rem;
	}
}

/* Native posts pagination (get_the_posts_pagination) themed to match. */
.shanmp3-archive__pagination {
	margin-top: 1.5rem;
}
.shanmp3-archive__pagination .pagination {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.35rem;
}
.shanmp3-archive__pagination .page-numbers {
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 2rem;
	height: 2rem;
	padding: 0 0.6rem;
	border-radius: var(--shanmp3-radius-pill);
	border: 1px solid var(--shanmp3-border);
	background: var(--shanmp3-surface);
	color: var(--shanmp3-fg);
	font-size: 0.8rem;
	font-weight: 600;
	text-decoration: none;
	transition: background var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast),
		border-color var(--shanmp3-transition-fast);
}
.shanmp3-archive__pagination .page-numbers:hover {
	border-color: var(--shanmp3-accent);
	color: var(--shanmp3-accent);
}
.shanmp3-archive__pagination .page-numbers.current {
	background: var(--shanmp3-accent);
	border-color: var(--shanmp3-accent);
	color: #fff;
}
.shanmp3-archive__pagination .page-numbers.dots {
	border: 0;
	background: transparent;
	color: var(--shanmp3-muted);
}
.shanmp3-archive__pagination .screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}

/* Empty state for the archive (no artists yet). */
.shanmp3-archive__empty {
	margin-top: 1.5rem;
	color: var(--shanmp3-muted);
	font-size: 0.95rem;
}

/* =========================================================================
   Designed archive header (playlists + songs)
   Unlike the artist (gender) and album (genre) archives, playlists have no
   taxonomy facet to drive filter chips, so the playlist archive opens with a
   designed typographic header — eyebrow, the post-type label as h1, and a
   public-count subtitle — followed by the card grid + pagination. The song
   archive reuses the same header (above its genre chips + sort control).
   ========================================================================= */
.shanmp3-playlist-archive .shanmp3-archive__header,
.shanmp3-song-archive .shanmp3-archive__header,
.shanmp3-label-archive .shanmp3-archive__header,
.shanmp3-credit-archive .shanmp3-archive__header,
.shanmp3-news-archive .shanmp3-archive__header {
	margin-bottom: 1.5rem;
	padding-bottom: 1.25rem;
	border-bottom: 1px solid var(--shanmp3-border);
}
.shanmp3-playlist-archive .shanmp3-archive__eyebrow,
.shanmp3-song-archive .shanmp3-archive__eyebrow,
.shanmp3-label-archive .shanmp3-archive__eyebrow,
.shanmp3-credit-archive .shanmp3-archive__eyebrow,
.shanmp3-news-archive .shanmp3-archive__eyebrow {
	display: block;
	margin-bottom: 0.4rem;
	font-size: 0.72rem;
	font-weight: 800;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--shanmp3-accent);
}
.shanmp3-playlist-archive .shanmp3-archive__title,
.shanmp3-song-archive .shanmp3-archive__title,
.shanmp3-label-archive .shanmp3-archive__title,
.shanmp3-credit-archive .shanmp3-archive__title,
.shanmp3-news-archive .shanmp3-archive__title {
	margin: 0 0 0.35rem;
	font-size: clamp(1.75rem, 4vw, 2.5rem);
	font-weight: 800;
	line-height: 1.1;
	color: var(--shanmp3-fg);
}
.shanmp3-playlist-archive .shanmp3-archive__subtitle,
.shanmp3-song-archive .shanmp3-archive__subtitle,
.shanmp3-label-archive .shanmp3-archive__subtitle,
.shanmp3-credit-archive .shanmp3-archive__subtitle,
.shanmp3-news-archive .shanmp3-archive__subtitle {
	margin: 0;
	font-size: 0.9rem;
	color: var(--shanmp3-muted);
}
/* The empty state already carries its own spacing; align it under the header. */
.shanmp3-playlist-archive .shanmp3-empty,
.shanmp3-song-archive .shanmp3-empty,
.shanmp3-label-archive .shanmp3-empty,
.shanmp3-credit-archive .shanmp3-empty,
.shanmp3-news-archive .shanmp3-empty {
	margin-top: 0;
}

/* News archive RSS link in the header (top-right of the header row). Rendered
   as a labelled "Subscribe" pill so it reads as an action, not a bare icon. */
.shanmp3-archive__rss {
	margin-left: auto;
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	padding: 0.4em 0.9em;
	font-size: 0.78rem;
	font-weight: 600;
	color: var(--shanmp3-muted);
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-pill, 999px);
	text-decoration: none;
	transition: color var(--shanmp3-transition), border-color var(--shanmp3-transition);
}
.shanmp3-archive__rss:hover {
	color: var(--shanmp3-accent);
	border-color: var(--shanmp3-accent);
}
.shanmp3-archive__rss .shanmp3-icon {
	width: 15px;
	height: 15px;
}
/* The news header is a flex row so the RSS link can sit at the end. */
.shanmp3-news-archive .shanmp3-archive__header {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.75rem;
}
.shanmp3-news-archive .shanmp3-archive__eyebrow {
	flex-basis: 100%;
}
.shanmp3-news-archive .shanmp3-archive__title {
	margin-bottom: 0;
}
/* Category filter chips sit between the header and the grid. */
.shanmp3-news-archive .shanmp3-archive__filters {
	margin-bottom: 1.5rem;
}
/* Magazine masthead: a larger headline on desktop. (0,2,0) beats the grouped
   archive title clamp (0,1,0). */
@media (min-width: 1024px) {
	.shanmp3-news-archive .shanmp3-archive__title {
		font-size: clamp(2.5rem, 4vw, 3.25rem);
	}
}

/* =========================================================================
   Song archive toolbar (genre filter + sort control)
   The song archive stacks two facets in one row: the genre chip row (desktop)
   / native <select> (mobile) from archive_filter(), and a sort <select>
   (Newest / Most played / Title A–Z). The sort control reuses the
   .shanmp3-archive__select surface but is always visible (it is not a
   mobile-only chip swap), anchored to the right on desktop and full-width on
   mobile. Each facet's URLs preserve the other query var.
   ========================================================================= */
.shanmp3-archive__toolbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.75rem 1rem;
	margin-bottom: 1.5rem;
}
/* Neutralize the filter row's own bottom margin inside the toolbar. */
.shanmp3-archive__toolbar .shanmp3-archive__filters,
.shanmp3-archive__toolbar .shanmp3-archive__select-label {
	margin-bottom: 0;
}
.shanmp3-archive__sort-label {
	display: block;
	margin-left: auto;
	width: auto;
	max-width: 13rem;
}
@media (max-width: 600px) {
	.shanmp3-archive__sort-label {
		margin-left: 0;
		max-width: none;
	}
}

/*
 * Artist archive grid/list view toggle — a two-button segmented control that
 * sits at the right of the toolbar (margin-left:auto). It mirrors the archive
 * filter select surface (border + surface-2 fill + accent when active) so the
 * two controls read as one family. Icon-only; titles + aria-pressed carry the
 * label for AT. The active button takes the accent fill like an active chip.
 */
.shanmp3-archive__view-toggle {
	display: inline-flex;
	align-items: center;
	gap: 0;
	margin-left: auto;
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-md, 12px);
	overflow: hidden;
	background-color: var(--shanmp3-surface-2, var(--shanmp3-surface));
}
.shanmp3-archive__view-btn {
	box-sizing: border-box;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	min-height: var(--shanmp3-touch, 44px);
	padding: 0;
	border: 0;
	border-radius: 0;
	background: transparent;
	color: var(--shanmp3-muted);
	cursor: pointer;
	transition: background var(--shanmp3-transition-fast),
		color var(--shanmp3-transition-fast);
}
.shanmp3-archive__view-btn + .shanmp3-archive__view-btn {
	border-left: 1px solid var(--shanmp3-border);
}
.shanmp3-archive__view-btn:hover {
	color: var(--shanmp3-fg);
	background: var(--shanmp3-surface-3, var(--shanmp3-surface));
}
.shanmp3-archive__view-btn:focus {
	outline: none;
	box-shadow: var(--shanmp3-shadow-focus);
}
.shanmp3-archive__view-btn.is-active {
	background: var(--shanmp3-accent);
	color: #fff;
}
.shanmp3-archive__view-btn.is-active:hover {
	color: #fff;
}
@media (max-width: 600px) {
	/* On phones the filter select is a full-width block above; the toggle wraps
	 * to its own row and hugs the right edge. */
	.shanmp3-archive__view-toggle {
		margin-left: auto;
	}
}

/* =========================================================================
   Membership page + comparison card (Phase 11)
   ========================================================================= */
.shanmp3-membership {
	max-width: var(--shanmp3-content-width, 1100px);
	margin: 0 auto;
	padding: 2rem 1.25rem 4rem;
}
.shanmp3-membership__hero {
	text-align: center;
	max-width: 640px;
	margin: 0 auto 2.5rem;
}
.shanmp3-membership__eyebrow {
	display: inline-block;
	font-size: 0.75rem;
	font-weight: 700;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--shanmp3-accent);
	margin-bottom: 0.5rem;
}
.shanmp3-membership__title {
	font-size: clamp(1.75rem, 4vw, 2.5rem);
	margin: 0 0 0.75rem;
}
.shanmp3-membership__lead {
	color: var(--shanmp3-muted);
	font-size: 1.05rem;
	margin: 0;
}

.shanmp3-membership-card {
	display: grid;
	grid-template-columns: 1fr 1fr;
	gap: 1.5rem;
	align-items: start;
}
.shanmp3-membership-card__tile {
	position: relative;
	border: 1px solid var(--shanmp3-border);
	border-radius: var(--shanmp3-radius-lg, 16px);
	background: var(--shanmp3-surface);
	padding: 1.75rem 1.5rem;
}
.shanmp3-membership-card__tile--premium {
	border-color: rgba(245, 196, 81, 0.45);
	background: linear-gradient(180deg, rgba(245, 196, 81, 0.08), var(--shanmp3-surface));
	box-shadow: 0 8px 30px rgba(0, 0, 0, 0.25);
}
.shanmp3-membership-card__ribbon {
	position: absolute;
	top: -0.75rem;
	right: 1.25rem;
	background: linear-gradient(135deg, #f5c451, #e0a328);
	color: #2a1c00;
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	padding: 0.25em 0.6em;
	border-radius: var(--shanmp3-radius-sm);
}
.shanmp3-membership-card__name {
	display: flex;
	align-items: center;
	gap: 0.4rem;
	font-size: 1.4rem;
	margin: 0 0 0.5rem;
}
.shanmp3-membership-card__price {
	font-size: 1.1rem;
	font-weight: 700;
	color: var(--shanmp3-text);
	margin: 0 0 1.25rem;
}
.shanmp3-membership-card__list {
	list-style: none;
	margin: 0 0 1.5rem;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: 0.65rem;
}
.shanmp3-membership-card__list li {
	display: flex;
	align-items: center;
	gap: 0.5rem;
	font-size: 0.95rem;
}
.shanmp3-membership-card__check {
	color: var(--shanmp3-accent);
	flex-shrink: 0;
}
.shanmp3-membership-card__current {
	display: inline-block;
	font-size: 0.85rem;
	color: var(--shanmp3-muted);
}
.shanmp3-membership-card__cta {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	width: 100%;
	justify-content: center;
}
.shanmp3-membership-card__cta--active,
.shanmp3-membership-card__cta--soon {
	background: var(--shanmp3-surface-2);
	color: var(--shanmp3-muted);
	border: 1px dashed var(--shanmp3-border);
	padding: 0.7rem 1rem;
	border-radius: var(--shanmp3-radius-md, 10px);
}
.shanmp3-membership-card__cta--active {
	color: #f5c451;
	border-style: solid;
	border-color: rgba(245, 196, 81, 0.45);
}

@media (max-width: 720px) {
	.shanmp3-membership-card {
		grid-template-columns: 1fr;
	}
}
