/*
 * Musical Links component styles. Every class is prefixed `.musical-`.
 * Design direction lives in DESIGN.md (Impeccable) - see docs/architecture.md
 * → "Design system": style against it, no generic/templated patterns.
 */

/* ==========================================================================
   0. Rem base and Bricks layout reset
   ========================================================================== */

/*
 * Bricks ships a `html { font-size: 62.5% }` reset, which makes 1rem = 10px.
 * DESIGN.md and .bricks-dev-mcp.json both specify a 16px base, so restore it
 * here - otherwise every size in the type and spacing scales lands at 62.5%
 * of its documented value.
 */
html {
	font-size: 100%;
}

body {
	font-family: var(--musical-font-body);
	font-size: 1rem;
	line-height: 1.6;
	color: var(--musical-text-primary);
	background: #fff;
}

/*
 * Bricks renders sections as `display:flex; align-items:center`, so a child
 * shrinks to its content width, and caps element width at its own container
 * default. These layout roots are meant to span the full section, so opt them
 * out. Compound selectors are deliberate: they need to beat Bricks' own
 * single-class element rules.
 */
.brxe-section > .musical-header,
.brxe-section > .musical-footer,
.brxe-musical-site-header.musical-header,
.brxe-musical-site-footer.musical-footer,
.musical-hero,
.musical-section,
.musical-dashboard,
.musical-player-wrap,
.musical-track-grid,
.musical-gallery,
.musical-steps,
.musical-artist-header,
.musical-shell {
	width: 100%;
	max-width: none;
	align-self: stretch;
}

/* Re-apply the measured maximums that the reset above just cleared. */
.musical-shell {
	max-width: 75rem;
	margin-inline: auto;
}

.musical-artist-header {
	max-width: 50rem;
	margin-inline: auto;
}

/* ==========================================================================
   1. Tokens
   ========================================================================== */

:root {
	/* Saturated hues. These are FILL colours - they own regions, not details. */
	--musical-primary: #00d9d9;
	--musical-secondary: #e61d9b;
	--musical-tertiary: #ffa500;

	/*
	 * Ink variants for text and icons on light surfaces. DESIGN.md asks for
	 * link text in the primary hue AND for WCAG AA; #00d9d9 on off-white is
	 * 1.76:1, so it cannot carry text. These are the same hues darkened to
	 * 4.9:1 (teal) and 6.2:1 (magenta) against --musical-bg-light.
	 */
	--musical-primary-ink: #007a7a;
	--musical-secondary-ink: #b01379;

	--musical-bg-light: #fafaf9;
	--musical-bg-dark: #1a1a1a;
	--musical-text-primary: #1d1d1d;
	--musical-text-secondary: #6b6b6b;
	/*
	 * Placeholders only. 3.03:1 on the white input background - under AA, and
	 * deliberately so: these are illustrative examples, and every instruction
	 * they replaced now sits in a .musical-field__hint at full contrast.
	 */
	--musical-text-placeholder: #949494;
	--musical-text-light: #f5f5f5;
	--musical-border: #e5e5e5;
	--musical-border-dark: #2a2a2a;

	--musical-success: #00d084;
	--musical-warning: #ffb800;
	--musical-error: #ff5555;
	/* --musical-error is tuned for the dark ground and fails AA on white. This
	   is its light-ground counterpart, with headroom over 4.5:1. */
	--musical-error-ink: #a51f1f;
	--musical-info: #00a8e8;

	--musical-font-display: "Outfit", "DM Sans", system-ui, -apple-system, sans-serif;
	--musical-font-body: "Inter", system-ui, -apple-system, sans-serif;
	/* Chord charts only line up in a fixed-width face. */
	--musical-font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;

	--musical-space-xs: 0.25rem;
	--musical-space-sm: 0.5rem;
	--musical-space-md: 1rem;
	--musical-space-lg: 1.5rem;
	--musical-space-xl: 2rem;
	--musical-space-2xl: 3rem;
	--musical-space-3xl: 4rem;
	--musical-space-4xl: 6rem;

	--musical-radius-sm: 6px;
	--musical-radius-md: 8px;
	--musical-radius-lg: 12px;
	--musical-radius-pill: 999px;

	--musical-shadow-card: 0 2px 8px rgb(0 0 0 / 8%);
	--musical-shadow-card-hover: 0 4px 16px rgb(0 0 0 / 12%);
	--musical-shadow-lift: 0 6px 20px rgb(0 0 0 / 14%);

	--musical-duration-quick: 0.2s;
	--musical-duration-smooth: 0.4s;
	--musical-duration-luxe: 0.6s;
	--musical-easing-out: cubic-bezier(0.2, 0, 0.38, 0.92);
	--musical-easing-luxe: cubic-bezier(0.16, 1, 0.3, 1);

	/* Editorial content measures. */
	--musical-measure: 45rem; /* ~720px, 50-75 characters */
	--musical-player-width: 44rem; /* ~700px, inside the 600-800px band */
}

/* ==========================================================================
   2. Typography scale
   ========================================================================== */

.musical-h1,
.musical-h2,
.musical-h3,
.musical-h4 {
	font-family: var(--musical-font-display);
	color: var(--musical-text-primary);
	margin: 0;
	text-wrap: balance;
}

.musical-h1 {
	font-size: clamp(2.5rem, 6vw, 4rem);
	line-height: 1.1;
	letter-spacing: -0.01em;
	font-weight: 700;
}

.musical-h2 {
	font-size: clamp(1.875rem, 4vw, 2.5rem);
	line-height: 1.2;
	letter-spacing: -0.005em;
	font-weight: 700;
}

.musical-h3 {
	font-size: 1.75rem;
	line-height: 1.3;
	font-weight: 600;
}

.musical-h4 {
	font-size: 1.25rem;
	line-height: 1.4;
	font-weight: 600;
}

.musical-body-l {
	font-family: var(--musical-font-body);
	font-size: 1.125rem;
	line-height: 1.6;
}

.musical-body {
	font-family: var(--musical-font-body);
	font-size: 1rem;
	line-height: 1.6;
}

.musical-body-s {
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	line-height: 1.5;
}

.musical-label {
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	line-height: 1.4;
	letter-spacing: 0.05em;
	font-weight: 600;
}

.musical-caption {
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	line-height: 1.4;
	letter-spacing: 0.08em;
	color: var(--musical-text-secondary);
}

.musical-measure {
	max-width: var(--musical-measure);
}

/* Text link. Uses the ink variant so it clears AA on light surfaces. */
.musical-link {
	color: var(--musical-primary-ink);
	text-decoration-thickness: 1px;
	text-underline-offset: 0.2em;
	transition: color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-link:hover,
.musical-link:focus-visible {
	color: var(--musical-secondary-ink);
}

/* ==========================================================================
   3. Focus, motion and skip link
   ========================================================================== */

.musical-skip-link {
	position: absolute;
	left: var(--musical-space-md);
	top: var(--musical-space-md);
	z-index: 999;
	padding: var(--musical-space-sm) var(--musical-space-md);
	background: var(--musical-text-primary);
	color: var(--musical-text-light);
	border-radius: var(--musical-radius-md);
	transform: translateY(-200%);
	transition: transform var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-skip-link:focus {
	transform: translateY(0);
}

/* One visible focus treatment for everything interactive. */
.musical-btn:focus-visible,
.musical-link:focus-visible,
.musical-input:focus-visible,
.musical-toggle:focus-visible,
.musical-icon-btn:focus-visible,
.musical-seek:focus-visible,
.musical-track-card__art-link:focus-visible,
.musical-track-card__link:focus-visible,
.musical-nav__link:focus-visible {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 3px;
}

/* On dark surfaces the ink teal is too low-contrast for a focus ring. */
.musical-player .musical-icon-btn:focus-visible,
.musical-player .musical-seek:focus-visible,
.musical-footer .musical-link:focus-visible {
	outline-color: var(--musical-primary);
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/*
 * Scroll reveal. The hidden start state is scoped to `.musical-js`, which the
 * scripts stamp on <html>. Without JS the content is simply visible - never
 * stranded at opacity 0.
 */
.musical-js .musical-reveal {
	opacity: 0;
	transform: translateY(30px);
	transition:
		opacity var(--musical-duration-smooth) var(--musical-easing-out),
		transform var(--musical-duration-smooth) var(--musical-easing-out);
}

.musical-js .musical-reveal.is-revealed {
	opacity: 1;
	transform: none;
}

@media (prefers-reduced-motion: reduce) {
	.musical-js .musical-reveal {
		opacity: 1;
		transform: none;
	}
}

/* ==========================================================================
   4. Buttons
   ========================================================================== */

.musical-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--musical-space-sm);
	min-height: 56px;
	padding: var(--musical-space-md) var(--musical-space-xl);
	border: 0;
	border-radius: var(--musical-radius-md);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	letter-spacing: 0.05em;
	line-height: 1;
	text-decoration: none;
	cursor: pointer;
	transition:
		background-color var(--musical-duration-quick) var(--musical-easing-out),
		box-shadow var(--musical-duration-quick) var(--musical-easing-out),
		transform var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-btn--primary {
	background: var(--musical-tertiary);
	color: var(--musical-text-primary);
}

.musical-btn--primary:hover {
	background: #ffb733;
	box-shadow: var(--musical-shadow-lift);
}

.musical-btn--primary:active {
	background: #e08e00;
	transform: scale(0.98);
}

.musical-btn--secondary {
	background: var(--musical-bg-light);
	color: var(--musical-text-primary);
	box-shadow: inset 0 0 0 1px var(--musical-border);
}

.musical-btn--secondary:hover {
	background: var(--musical-border);
}

.musical-btn--secondary:active {
	transform: scale(0.98);
	box-shadow: inset 0 0 0 1px var(--musical-text-secondary);
}

.musical-btn--ghost {
	background: transparent;
	color: var(--musical-primary-ink);
	padding-inline: var(--musical-space-sm);
}

.musical-btn--ghost:hover {
	color: var(--musical-secondary-ink);
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.musical-btn--ghost:active {
	transform: scale(0.98);
}

.musical-btn--danger {
	background: var(--musical-error);
	color: var(--musical-text-light);
}

.musical-btn--danger:hover {
	background: #ff6a6a;
	box-shadow: var(--musical-shadow-lift);
}

.musical-btn--danger:active {
	background: #e04343;
	transform: scale(0.98);
}

/* Ghost buttons sitting on dark regions. */
.musical-btn--on-dark {
	color: var(--musical-text-light);
	box-shadow: inset 0 0 0 1px rgb(245 245 245 / 35%);
}

.musical-btn--on-dark:hover {
	background: rgb(245 245 245 / 12%);
	color: var(--musical-text-light);
	text-decoration: none;
}

.musical-btn[disabled],
.musical-btn[aria-disabled="true"] {
	opacity: 0.5;
	cursor: not-allowed;
	transform: none;
	box-shadow: none;
}

.musical-btn[hidden] {
	display: none;
}

.musical-icon-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	padding: 0;
	border: 0;
	border-radius: var(--musical-radius-pill);
	background: transparent;
	color: currentcolor;
	cursor: pointer;
	transition:
		background-color var(--musical-duration-quick) var(--musical-easing-out),
		transform var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-icon-btn:hover {
	background: rgb(255 255 255 / 10%);
}

.musical-icon-btn:active {
	transform: scale(0.95);
}

.musical-icon-btn svg {
	width: 24px;
	height: 24px;
	fill: currentcolor;
	pointer-events: none;
}

/* ==========================================================================
   5. Form elements
   ========================================================================== */

.musical-field {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-xs);
}

.musical-field__label {
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.05em;
	color: var(--musical-text-secondary);
	text-transform: uppercase;
}

.musical-input {
	width: 100%;
	min-height: 48px;
	padding: var(--musical-space-md);
	font-family: var(--musical-font-body);
	font-size: 1rem;
	line-height: 1.5;
	color: var(--musical-text-primary);
	background: #fff;
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-sm);
	transition:
		border-color var(--musical-duration-quick) var(--musical-easing-out),
		box-shadow var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-input::placeholder {
	color: var(--musical-text-placeholder);
}

.musical-input:focus {
	border-color: var(--musical-primary-ink);
	box-shadow: 0 0 0 3px rgb(0 122 122 / 15%);
	outline: none;
}

textarea.musical-input {
	min-height: 8rem;
	resize: vertical;
}

/*
 * Chord charts are entered and displayed in the same face, so what the author
 * lines up in the field is what a visitor sees. Soft wrap stays on - a long
 * line should fold rather than hide off the right edge of a phone.
 */
.musical-input--mono {
	font-family: var(--musical-font-mono);
	font-size: 0.9375rem;
	line-height: 1.7;
	tab-size: 4;
}

.musical-field__hint {
	font-family: var(--musical-font-body);
	font-size: 0.8125rem;
	line-height: 1.4;
	color: var(--musical-text-secondary);
}

.musical-field__error {
	display: flex;
	align-items: center;
	gap: var(--musical-space-xs);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: #d13030; /* --musical-error darkened to 4.5:1 on light */
}

/* Toggle switch. Built on a real checkbox so it is keyboard-operable. */
.musical-toggle {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: var(--musical-space-sm);
	cursor: pointer;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-text-primary);
}

.musical-toggle__input {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
	pointer-events: none;
}

.musical-toggle__track {
	position: relative;
	flex: 0 0 auto;
	width: 48px;
	height: 28px;
	border-radius: var(--musical-radius-pill);
	background: var(--musical-text-secondary);
	transition: background-color var(--musical-duration-smooth) var(--musical-easing-out);
}

.musical-toggle__track::after {
	content: "";
	position: absolute;
	inset-block-start: 2px;
	inset-inline-start: 2px;
	width: 24px;
	height: 24px;
	border-radius: 50%;
	background: #fff;
	box-shadow: 0 1px 3px rgb(0 0 0 / 25%);
	transition: transform var(--musical-duration-smooth) var(--musical-easing-out);
}

.musical-toggle__input:checked + .musical-toggle__track {
	background: var(--musical-primary-ink);
}

.musical-toggle__input:checked + .musical-toggle__track::after {
	transform: translateX(20px);
}

.musical-toggle__input:focus-visible + .musical-toggle__track {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 3px;
}

/* Checkbox for share options (autoplay toggle, etc.) */
.musical-checkbox {
	display: inline-flex;
	align-items: center;
	gap: var(--musical-space-sm);
	cursor: pointer;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-text-primary);
}

.musical-checkbox__input {
	position: relative;
	width: 18px;
	height: 18px;
	cursor: pointer;
	accent-color: var(--musical-primary-ink);
}

.musical-checkbox__input:focus-visible {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 2px;
}

/* Share options container */
.musical-share__options {
	margin-block-start: var(--musical-space-md);
	padding-block: var(--musical-space-sm);
	border-top: 1px solid var(--musical-border);
}

.musical-share__options .musical-checkbox {
	font-size: 0.8rem;
	color: var(--musical-text-secondary);
}

/* Reduce cover art when accessed via public link with autoplay enabled */
@media (prefers-reduced-motion: no-preference) {
	/* Check for autoplay query param via body data attribute or JS-applied class */
	body[data-autoplay-active] .musical-player__art,
	.musical-player[data-autoplay="true"] .musical-player__art {
		max-width: 300px;
		margin-inline: auto;
		margin-block-end: var(--musical-space-md);
	}

	/* On mobile, keep cover art smaller for better UX when autoplay is active */
	@media (max-width: 640px) {
		body[data-autoplay-active] .musical-player__art,
		.musical-player[data-autoplay="true"] .musical-player__art {
			max-width: 240px;
		}
	}
}

/* ==========================================================================
   6. Layout scaffolding
   ========================================================================== */

.musical-section {
	padding-block: var(--musical-space-3xl);
	padding-inline: var(--musical-space-lg);
}

.musical-section--tight {
	padding-block: var(--musical-space-2xl);
}

.musical-section--dark {
	background: var(--musical-bg-dark);
	color: var(--musical-text-light);
}

.musical-section--dark .musical-h1,
.musical-section--dark .musical-h2,
.musical-section--dark .musical-h3,
.musical-section--dark .musical-h4 {
	color: var(--musical-text-light);
}

.musical-shell {
	width: 100%;
	max-width: 75rem; /* 1200px */
	margin-inline: auto;
}

.musical-stack {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
}

.musical-section__head {
	display: flex;
	flex-wrap: wrap;
	align-items: end;
	justify-content: space-between;
	gap: var(--musical-space-md);
	margin-block-end: var(--musical-space-xl);
}

.musical-eyebrow {
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--musical-secondary-ink);
}

/*
 * On dark ground the ink magenta is far too low-contrast; the bright teal hits
 * ~9.7:1 on charcoal. The hero counts as dark ground even though it does not
 * carry the --dark modifier.
 */
.musical-section--dark .musical-eyebrow,
.musical-hero .musical-eyebrow {
	color: var(--musical-primary);
}

/* Editorial two-column: wide content + sticky sidebar. */
.musical-editorial {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--musical-space-2xl);
}

@media (min-width: 64rem) {
	.musical-editorial {
		grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
	}

	.musical-editorial__aside {
		position: sticky;
		top: var(--musical-space-2xl);
		align-self: start;
	}
}

/* Numbered steps row: 3 across on desktop, stacked below tablet. */
.musical-steps {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--musical-space-xl);
}

@media (min-width: 64rem) {
	.musical-steps {
		grid-template-columns: repeat(3, minmax(0, 1fr));
		gap: var(--musical-space-2xl);
	}
}

.musical-step__number {
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.14em;
	color: var(--musical-primary);
}

/* Gallery grid: 1 / 2 / 3 columns. */
.musical-gallery {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--musical-space-lg);
	list-style: none;
	margin: 0;
	padding: 0;
}

@media (min-width: 48rem) {
	.musical-gallery {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (min-width: 64rem) {
	.musical-gallery {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	/*
	 * Inside the narrower editorial column three cards get cramped, and the
	 * cover art stops reading. Two is the right count for that measure.
	 */
	.musical-editorial .musical-gallery {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

/*
 * Studio list: one track per row.
 *
 * The gallery tile is a listener-facing object - big square art, three up. The
 * owner's list is a management surface, so it drops to a single column and the
 * art shrinks to an identifier. That is what gives the inline editor the full
 * container width instead of a 280px sliver of it. Declared after the gallery
 * breakpoints above so it wins at every size without a specificity bump.
 */
.musical-gallery--rows {
	grid-template-columns: minmax(0, 1fr);
	gap: var(--musical-space-md);
}

/*
 * Section media: a photographic band behind a page header.
 *
 * Same layering as the hero (photo at -3, scrim at -1, content in flow above)
 * but sized for a page header rather than a full viewport. Applied on top of
 * .musical-section--dark, so the section still has its charcoal ground if the
 * image is slow, fails, or is removed - the header never depends on the photo.
 */
.musical-section--media {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	padding-block: var(--musical-space-4xl);
}

.musical-section__media {
	position: absolute;
	inset: 0;
	z-index: -3;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center;
	opacity: 0.85;
}

/*
 * The headline sits left, so the scrim is heaviest there and thins out to the
 * right where the photograph is allowed to read.
 *
 * The stops are not eyeballed: text runs to roughly 56% of the viewport, so the
 * scrim holds ~70% opacity until then and only opens up past it. Sampled against
 * the brightest pixels under the text on all three left-aligned images, the
 * lightest result is ~10:1 - comfortably past the 7:1 the design system asks of
 * body copy. Lighten these stops further and that guarantee goes with them.
 */
.musical-section--media::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background:
		linear-gradient(90deg,
			rgb(26 26 26 / 92%) 0%,
			rgb(26 26 26 / 86%) 34%,
			rgb(26 26 26 / 70%) 52%,
			rgb(26 26 26 / 18%) 100%),
		linear-gradient(180deg, rgb(26 26 26 / 45%) 0%, transparent 55%);
}

/*
 * The artist header is a centred composition, so its scrim has to protect the
 * middle of the band instead of the left edge.
 */
/*
 * The centred artist header is already tall on its own (avatar, name, bio, stats,
 * share row), so it keeps the standard section rhythm instead of the roomier
 * padding the left-aligned headers use - otherwise the share button drops below
 * the fold on a laptop.
 */
.musical-section--media-center {
	padding-block: var(--musical-space-3xl);
}

.musical-section--media-center::after {
	background:
		radial-gradient(68% 78% at 50% 50%, rgb(26 26 26 / 82%) 0%, rgb(26 26 26 / 62%) 62%, rgb(26 26 26 / 30%) 100%),
		linear-gradient(180deg, rgb(26 26 26 / 45%) 0%, transparent 45%);
}

/*
 * Below the tablet breakpoint the text spans the full width, so a left-weighted
 * scrim would leave the end of the lede sitting on open photograph. Flatten it.
 */
@media (max-width: 47.9375rem) {
	.musical-section--media::after {
		background:
			linear-gradient(180deg, rgb(26 26 26 / 78%) 0%, rgb(26 26 26 / 90%) 100%);
	}

	.musical-section--media .musical-section__media {
		opacity: 0.4;
	}
}

/*
 * The artist header's supporting text defaults to the medium grey used on light
 * ground, which is nowhere near readable on the dark band. Scoped to the media
 * band only, so the same element keeps its light-ground styling on the song page.
 */
.musical-section--media .musical-artist-header__bio,
.musical-section--media .musical-artist-header__details,
.musical-section--media .musical-artist-header__stats {
	color: rgb(245 245 245 / 82%);
}

.musical-section--media .musical-artist-header__links a {
	color: var(--musical-primary);
}

.musical-section--media .musical-share__url {
	color: rgb(245 245 245 / 78%);
	background: rgb(255 255 255 / 6%);
	border-color: var(--musical-border-dark);
}

/*
 * Same problem as the bio text above: the "start playing automatically"
 * checkbox label was rendering at --musical-text-secondary (#6b6b6b), which is
 * ~3.3:1 on the charcoal band and fails AA. The "copied!" feedback text has
 * the same issue with the ink teal, so it gets the same dark-ground swap the
 * eyebrow already uses elsewhere in this file (raw teal reads ~9.7:1 here).
 */
.musical-section--media .musical-share__options .musical-checkbox {
	color: rgb(245 245 245 / 82%);
}

.musical-section--media .musical-checkbox__input {
	accent-color: var(--musical-primary);
}

.musical-section--media .musical-share__feedback {
	color: var(--musical-primary);
}

/* ==========================================================================
   7. Hero
   ========================================================================== */

.musical-hero {
	position: relative;
	display: grid;
	align-content: center;
	min-height: min(88vh, 46rem);
	padding: var(--musical-space-4xl) var(--musical-space-lg);
	overflow: hidden;
	background: var(--musical-bg-dark);
	color: var(--musical-text-light);
	isolation: isolate;
}

/* Colour owns the region: a large saturated field, not scattered accents. */
.musical-hero::before {
	content: "";
	position: absolute;
	inset: -20%;
	z-index: -2;
	background:
		radial-gradient(60% 55% at 18% 22%, rgb(0 217 217 / 55%) 0%, transparent 62%),
		radial-gradient(52% 50% at 82% 72%, rgb(230 29 155 / 52%) 0%, transparent 60%),
		radial-gradient(40% 40% at 62% 12%, rgb(255 165 0 / 32%) 0%, transparent 60%);
}

.musical-hero__media {
	position: absolute;
	inset: 0;
	z-index: -3;
	width: 100%;
	height: 100%;
	object-fit: cover;
	opacity: 0.45;
}

.musical-hero::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	background: linear-gradient(180deg, rgb(26 26 26 / 25%) 0%, rgb(26 26 26 / 78%) 100%);
}

.musical-hero__inner {
	position: relative;
	width: 100%;
	max-width: 75rem;
	margin-inline: auto;
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
	align-items: start;
}

.musical-hero__title {
	color: var(--musical-text-light);
	max-width: 20ch;
}

.musical-hero__lede {
	color: rgb(245 245 245 / 88%);
	max-width: 48ch;
}

.musical-hero__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-md);
	margin-block-start: var(--musical-space-sm);
}

/*
 * Staggered entrance. Kept deliberately tight: the h1 is the LCP element, so
 * it gets no delay at all and the rest follow in short 80ms steps. A long
 * luxe stagger here reads as a slow page, not a choreographed one.
 */
.musical-hero__inner > * {
	animation: musical-rise var(--musical-duration-smooth) var(--musical-easing-luxe) both;
}

.musical-hero__inner > :nth-child(1) { animation-delay: 0s; }
.musical-hero__inner > :nth-child(2) { animation-delay: 0s; }
.musical-hero__inner > :nth-child(3) { animation-delay: 0.08s; }
.musical-hero__inner > :nth-child(4) { animation-delay: 0.16s; }

@keyframes musical-rise {
	from {
		opacity: 0;
		transform: translateY(20px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

/* ==========================================================================
   8. Track card
   ========================================================================== */

.musical-track-card {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-md);
	padding: var(--musical-space-md);
	background: #fff;
	border-radius: var(--musical-radius-lg);
	box-shadow: var(--musical-shadow-card);
	/* Clears the sticky header when the studio scrolls to a card. */
	scroll-margin-top: calc(64px + var(--musical-space-lg));
	transition:
		box-shadow var(--musical-duration-smooth) var(--musical-easing-out),
		transform var(--musical-duration-smooth) var(--musical-easing-out);
}

.musical-track-card:hover,
.musical-track-card:focus-within {
	box-shadow: var(--musical-shadow-card-hover);
	transform: translateY(-4px);
}

/* The track the studio just reloaded onto, after an upload. */
.musical-track-card--fresh {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 3px;
}

.musical-track-card__fresh {
	margin: 0;
	display: flex;
	align-items: center;
	gap: var(--musical-space-sm);
	padding: var(--musical-space-sm) var(--musical-space-md);
	border-radius: var(--musical-radius-md);
	background: rgb(0 122 122 / 10%);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	line-height: 1.5;
	color: var(--musical-primary-ink);
}

.musical-track-card__art {
	position: relative;
	aspect-ratio: 1 / 1;
	border-radius: var(--musical-radius-md);
	overflow: hidden;
	/* Sits behind an uploaded cover while it decodes. Generated art (see
	   inc/cover-art.php) paints its own ground and covers this entirely. */
	background: var(--musical-bg-dark);
}

.musical-track-card__art-link {
	display: block;
	width: 100%;
	height: 100%;
}

/* Keep the focus ring visible inside the art frame's clipped corners. */
.musical-track-card__art-link:focus-visible {
	outline-offset: -3px;
}

.musical-track-card__art img,
.musical-track-card__art .musical-cover {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	transition: transform var(--musical-duration-luxe) var(--musical-easing-out);
}

.musical-track-card:hover .musical-track-card__art img,
.musical-track-card:hover .musical-track-card__art .musical-cover {
	transform: scale(1.04);
}

/* Play affordance. Always present for touch and keyboard, emphasised on hover. */
.musical-track-card__play {
	position: absolute;
	/* Above the card-wide link overlay so it stays independently clickable. */
	z-index: 2;
	inset-block-end: var(--musical-space-sm);
	inset-inline-end: var(--musical-space-sm);
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 48px;
	height: 48px;
	border: 0;
	border-radius: 50%;
	background: var(--musical-tertiary);
	color: var(--musical-text-primary);
	cursor: pointer;
	/* Hairline ring as well as the lift: the button sits over generated art and
	   over uploaded photos, either of which can be orange right under it. */
	box-shadow:
		0 0 0 1px rgb(26 26 26 / 22%),
		var(--musical-shadow-lift);
	transition:
		transform var(--musical-duration-smooth) var(--musical-easing-out),
		background-color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-track-card__play svg {
	width: 20px;
	height: 20px;
	fill: currentcolor;
	pointer-events: none;
}

.musical-track-card:hover .musical-track-card__play,
.musical-track-card__play:focus-visible {
	transform: scale(1.1);
}

.musical-track-card__play:active {
	transform: scale(0.95);
}

.musical-track-card__body {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-xs);
}

.musical-track-card__title {
	font-family: var(--musical-font-display);
	font-size: 1.25rem;
	font-weight: 600;
	line-height: 1.4;
	margin: 0;
}

.musical-track-card__link {
	color: var(--musical-text-primary);
	text-decoration: none;
}

/* Whole-card hit area without nesting interactive elements. */
.musical-track-card__link::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: var(--musical-radius-lg);
}

.musical-track-card__link:hover {
	color: var(--musical-primary-ink);
}

.musical-track-card__meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--musical-space-sm);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-text-secondary);
}

.musical-track-card__meta a {
	position: relative;
	z-index: 2;
	color: var(--musical-text-secondary);
}

.musical-track-card__meta a:hover {
	color: var(--musical-primary-ink);
}

.musical-track-card__duration {
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.04em;
}

.musical-badge {
	display: inline-flex;
	align-items: center;
	gap: var(--musical-space-xs);
	padding: 2px var(--musical-space-sm);
	border-radius: var(--musical-radius-pill);
	font-family: var(--musical-font-body);
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

.musical-badge--private {
	background: var(--musical-border);
	color: #4a4a4a;
}

.musical-badge--public {
	background: rgb(0 122 122 / 12%);
	/* --musical-primary-ink lands at 4.3:1 on this tint, and the badge is 11px
	   uppercase - small text, so it needs the full 4.5:1 and then some. */
	color: #005f5f;
}

/* Reachable, but only by invitation - so neither the open teal nor the
   closed grey. */
.musical-badge--unlisted {
	background: rgb(176 19 121 / 10%);
	color: var(--musical-secondary-ink);
}

/* ==========================================================================
   9. Playlist card
   ========================================================================== */

.musical-playlist-card {
	position: relative;
	display: flex;
	flex-direction: column;
	justify-content: end;
	gap: var(--musical-space-sm);
	min-height: 14rem;
	padding: var(--musical-space-lg);
	border-radius: var(--musical-radius-lg);
	background: linear-gradient(135deg, var(--musical-primary) 0%, var(--musical-secondary) 100%);
	color: var(--musical-text-light);
	overflow: hidden;
	transition:
		filter var(--musical-duration-smooth) var(--musical-easing-out),
		transform var(--musical-duration-smooth) var(--musical-easing-out);
}

.musical-playlist-card:hover {
	filter: brightness(1.05);
	transform: translateY(-4px);
}

.musical-playlist-card__title {
	font-family: var(--musical-font-display);
	font-size: 1.75rem;
	font-weight: 600;
	line-height: 1.3;
	margin: 0;
}

.musical-playlist-card__title a {
	color: var(--musical-text-light);
	text-decoration: none;
}

.musical-playlist-card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.musical-playlist-card__count {
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: rgb(245 245 245 / 80%);
}

/* ==========================================================================
   10. Player
   ========================================================================== */

.musical-player {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
	width: 100%;
	max-width: var(--musical-player-width);
	margin-inline: auto;
	padding: var(--musical-space-xl);
	background: var(--musical-bg-dark);
	border-radius: var(--musical-radius-lg);
	color: var(--musical-text-light);
}

/*
 * Capped, not full-bleed. Left to fill the player's 44rem the square ran to
 * 640px, which on a 900px-tall laptop pushed the play button - and now the
 * lyrics panel - below the fold; the first thing a shared link showed was
 * artwork with no way to start the track. 20rem keeps art, title, transport
 * and the top of the details panel on one screen.
 */
.musical-player__art {
	position: relative;
	width: 100%;
	max-width: 20rem;
	margin-inline: auto;
	aspect-ratio: 1 / 1;
	border-radius: var(--musical-radius-lg);
	overflow: hidden;
	background: var(--musical-bg-dark);
	transition: transform var(--musical-duration-smooth) var(--musical-easing-out);
}

.musical-player__art img,
.musical-player__art .musical-cover {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
	animation: musical-fade var(--musical-duration-smooth) var(--musical-easing-out) both;
}

@keyframes musical-fade {
	from { opacity: 0; }
	to { opacity: 1; }
}

.musical-player.is-playing .musical-player__art {
	transform: scale(1.02);
}

/*
 * Cover art moves in time with the track. The period is `--musical-beat`,
 * written onto the art by `musical_beat_attrs()` from the tempo the analyser
 * measured, so it moves at the speed of the song rather than at some fixed
 * rate that happens to fit nothing.
 *
 * Generated art moves in *parts*: the sun breathes while the hills stay put,
 * the singer bobs while the stage does not, the windows blink while the city
 * stands still. `fill-box` makes each group turn around its own centre rather
 * than the middle of the frame, which is the difference between a lamp
 * flickering and the whole picture rocking.
 *
 * Only under `.is-playing`, which lives on the one player or card currently
 * sounding: a whole grid of covers moving at once is a screensaver.
 */
.musical-cover__beat {
	transform-box: fill-box;
	transform-origin: center;
}

@keyframes musical-beat-pulse {
	0% { transform: scale(1); }
	9% { transform: scale(1.07); }
	62% { transform: scale(1.005); }
	100% { transform: scale(1); }
}

@keyframes musical-beat-bob {
	0% { transform: translateY(0); }
	9% { transform: translateY(-1.6px); }
	62% { transform: translateY(-0.1px); }
	100% { transform: translateY(0); }
}

@keyframes musical-beat-blink {
	0% { opacity: 0.55; }
	9% { opacity: 1; }
	62% { opacity: 0.7; }
	100% { opacity: 0.55; }
}

@keyframes musical-beat-sway {
	0% { transform: rotate(0deg); }
	9% { transform: rotate(1.1deg); }
	55% { transform: rotate(-0.5deg); }
	100% { transform: rotate(0deg); }
}

@media (prefers-reduced-motion: no-preference) {
	.is-playing [data-musical-beat] .musical-cover__beat {
		animation-duration: var(--musical-beat, 0.75s);
		animation-timing-function: var(--musical-easing-out);
		animation-iteration-count: infinite;
	}

	.is-playing [data-musical-beat] .musical-cover__beat--pulse { animation-name: musical-beat-pulse; }
	.is-playing [data-musical-beat] .musical-cover__beat--bob { animation-name: musical-beat-bob; }
	.is-playing [data-musical-beat] .musical-cover__beat--blink { animation-name: musical-beat-blink; }
	.is-playing [data-musical-beat] .musical-cover__beat--sway { animation-name: musical-beat-sway; }

	/* Half a beat late, so a scene does not land every element at once. */
	.is-playing [data-musical-beat] .musical-cover__beat--off {
		animation-delay: calc(var(--musical-beat, 0.75s) / -2);
	}

	/*
	 * Uploaded photography has no parts to move, only the whole frame - and a
	 * photo pulsing full-square to the beat read as a cheap zoom effect, not a
	 * performance. Generated art keeps the parts-based .musical-cover__beat
	 * rules above; a photo just keeps its plain musical-fade mount-in from the
	 * base .musical-player__art img rule, unconditionally, playing or not.
	 */
}

.musical-player__meta {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-xs);
}

.musical-player__artist {
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--musical-primary);
}

.musical-player__artist a {
	color: inherit;
	text-decoration: none;
}

.musical-player__artist a:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.musical-player__title {
	font-family: var(--musical-font-display);
	font-size: clamp(1.75rem, 4vw, 2.5rem);
	font-weight: 700;
	line-height: 1.2;
	letter-spacing: -0.005em;
	color: var(--musical-text-light);
	margin: 0;
}

.musical-player__controls {
	display: flex;
	align-items: center;
	gap: var(--musical-space-md);
	min-height: 56px;
}

.musical-player__play {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: 0 0 auto;
	width: 56px;
	height: 56px;
	border: 0;
	border-radius: 50%;
	background: var(--musical-tertiary);
	color: var(--musical-text-primary);
	cursor: pointer;
	transition:
		transform var(--musical-duration-smooth) var(--musical-easing-out),
		background-color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-player__play svg {
	width: 24px;
	height: 24px;
	fill: currentcolor;
	pointer-events: none;
}

.musical-player__play:hover {
	background: #ffb733;
	transform: scale(1.08);
}

.musical-player__play:active {
	transform: scale(0.95);
}

/*
 * Play/pause glyph swap. Keyed off `.is-playing` on the player or card root, so
 * the same markup serves the big player and the small card buttons.
 */
.musical-player__icon-play {
	display: flex;
}

.musical-player__icon-pause {
	display: none;
}

.is-playing .musical-player__icon-play {
	display: none;
}

.is-playing .musical-player__icon-pause {
	display: flex;
}

.musical-player__timeline {
	display: flex;
	align-items: center;
	gap: var(--musical-space-sm);
	flex: 1 1 auto;
	min-width: 0;
}

.musical-player__time {
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.06em;
	color: rgb(245 245 245 / 75%);
	flex: 0 0 auto;
}

/* Range inputs, restyled but still native (keyboard + AT support intact). */
.musical-seek,
.musical-volume {
	appearance: none;
	width: 100%;
	height: 20px;
	background: transparent;
	cursor: pointer;
	margin: 0;
}

.musical-seek {
	flex: 1 1 auto;
	min-width: 0;
	--musical-progress: 0%;
}

.musical-volume {
	flex: 0 0 6.25rem;
	width: 6.25rem;
	--musical-progress: 100%;
}

/* --------------------------------------------------------------------------
   Measured track traits (key, tempo, replay gain)
   -------------------------------------------------------------------------- */

.musical-traits {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-lg);
	margin: var(--musical-space-lg) 0 0;
	padding-block-start: var(--musical-space-md);
	border-block-start: 1px solid var(--musical-border);
}

.musical-traits__item {
	display: flex;
	flex-direction: column;
	gap: 0.125rem;
}

.musical-traits__label {
	font-family: var(--musical-font-body);
	font-size: 0.6875rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--musical-text-secondary);
}

.musical-traits__value {
	margin: 0;
	font-family: var(--musical-font-body);
	font-size: 1rem;
	font-variant-numeric: tabular-nums;
	color: var(--musical-text-primary);
}

/* --------------------------------------------------------------------------
   Waveform scrubber

   The SVG is a backdrop; the range input above it stays the real control, so
   keyboard, screen readers and touch all keep working untouched.
   -------------------------------------------------------------------------- */

.musical-waveform {
	position: relative;
	flex: 1 1 auto;
	min-width: 0;
	height: 3rem;
	--musical-progress: 0%;
}

.musical-waveform__svg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

.musical-waveform__base {
	/* Translucent white rather than the border token: the player sits on near
	   black, where that token is all but invisible. */
	fill: rgb(245 245 245 / 24%);
}

.musical-waveform__played {
	fill: var(--musical-primary);
	/* An SVG geometry property, so it animates like any other CSS length. */
	width: var(--musical-progress);
	transition: width var(--musical-duration-quick) linear;
}

/* The input keeps its box - and therefore its focus ring - but hands the
   drawing over to the SVG behind it. */
.musical-waveform .musical-seek {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
}

.musical-waveform .musical-seek::-webkit-slider-runnable-track {
	height: 100%;
	background: transparent;
}

.musical-waveform .musical-seek::-moz-range-track,
.musical-waveform .musical-seek::-moz-range-progress {
	height: 100%;
	background: transparent;
}

/* A slim playhead reads better than a dot against bars. */
.musical-waveform .musical-seek::-webkit-slider-thumb {
	appearance: none;
	width: 3px;
	height: 3rem;
	margin-top: 0;
	border-radius: 1px;
	background: var(--musical-tertiary);
	box-shadow: 0 0 6px rgb(0 0 0 / 50%);
}

.musical-waveform .musical-seek::-moz-range-thumb {
	width: 3px;
	height: 3rem;
	border: 0;
	border-radius: 1px;
	background: var(--musical-tertiary);
}

.musical-waveform:hover .musical-waveform__base {
	fill: rgb(245 245 245 / 34%);
}

@media (max-width: 47.9375em) {
	.musical-waveform {
		height: 2.25rem;
	}

	.musical-waveform .musical-seek::-webkit-slider-thumb,
	.musical-waveform .musical-seek::-moz-range-thumb {
		height: 2.25rem;
	}
}

@media (prefers-reduced-motion: reduce) {
	.musical-waveform__played {
		transition: none;
	}
}

.musical-seek::-webkit-slider-runnable-track,
.musical-volume::-webkit-slider-runnable-track {
	height: 4px;
	border-radius: var(--musical-radius-pill);
	background: linear-gradient(
		to right,
		var(--musical-primary) 0 var(--musical-progress),
		var(--musical-border-dark) var(--musical-progress) 100%
	);
	transition: height var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-seek::-moz-range-track,
.musical-volume::-moz-range-track {
	height: 4px;
	border-radius: var(--musical-radius-pill);
	background: var(--musical-border-dark);
}

.musical-seek::-moz-range-progress,
.musical-volume::-moz-range-progress {
	height: 4px;
	border-radius: var(--musical-radius-pill);
	background: var(--musical-primary);
}

.musical-seek::-webkit-slider-thumb,
.musical-volume::-webkit-slider-thumb {
	appearance: none;
	width: 12px;
	height: 12px;
	margin-top: -4px;
	border: 0;
	border-radius: 50%;
	background: var(--musical-tertiary);
	box-shadow: 0 1px 4px rgb(0 0 0 / 40%);
	transition:
		width var(--musical-duration-quick) var(--musical-easing-out),
		height var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-seek::-moz-range-thumb,
.musical-volume::-moz-range-thumb {
	width: 12px;
	height: 12px;
	border: 0;
	border-radius: 50%;
	background: var(--musical-tertiary);
}

.musical-seek:hover::-webkit-slider-runnable-track {
	height: 6px;
}

.musical-seek:hover::-webkit-slider-thumb {
	width: 16px;
	height: 16px;
	margin-top: -5px;
}

.musical-player__volume {
	display: flex;
	align-items: center;
	gap: var(--musical-space-xs);
	flex: 0 0 auto;
}

.musical-player__volume .musical-icon-btn {
	width: 40px;
	height: 40px;
	color: rgb(245 245 245 / 80%);
}

@media (max-width: 47.99rem) {
	/* Volume is an OS-level control on touch devices; reclaim the space. */
	.musical-player__volume {
		display: none;
	}

	.musical-player {
		padding: var(--musical-space-lg);
	}
}

/* ==========================================================================
   11. Artist header
   ========================================================================== */

.musical-artist-header {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--musical-space-md);
	max-width: 50rem;
	margin-inline: auto;
	text-align: center;
}

.musical-artist-header__avatar {
	width: clamp(7.5rem, 18vw, 12.5rem);
	aspect-ratio: 1 / 1;
	border-radius: 50%;
	overflow: hidden;
	background: linear-gradient(135deg, var(--musical-primary) 0%, var(--musical-secondary) 100%);
	box-shadow: var(--musical-shadow-lift);
}

.musical-artist-header__avatar img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.musical-artist-header__bio {
	color: var(--musical-text-secondary);
	max-width: 55ch;
}

.musical-artist-header__details,
.musical-artist-header__links {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: var(--musical-space-sm) var(--musical-space-md);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
}

.musical-artist-header__details {
	color: var(--musical-text-secondary);
}

.musical-artist-header__links a {
	color: var(--musical-primary-ink);
	font-weight: 600;
	text-underline-offset: 0.25em;
}

.musical-artist-header__stats {
	display: flex;
	gap: var(--musical-space-lg);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-text-secondary);
}

/* The centred column shrink-wraps its children, which squeezed the copy button
 * onto two lines. Give the share row a width of its own. */
.musical-artist-header > .musical-stack {
	align-self: stretch;
}

.musical-artist-header .musical-share {
	width: min(100%, 34rem);
	margin-inline: auto;
	justify-content: center;
}

.musical-artist-header .musical-share__social {
	justify-content: center;
}

/* ==========================================================================
   12. Share row
   ========================================================================== */

.musical-share {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--musical-space-sm);
}

/* The button carries the action, so it keeps its label on one line and the
 * URL field gives up the width instead. */
.musical-share .musical-btn {
	flex: 0 0 auto;
	white-space: nowrap;
}

.musical-share__url {
	flex: 1 1 16rem;
	min-width: 0;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-text-secondary);
	background: var(--musical-bg-light);
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-sm);
	padding: var(--musical-space-sm) var(--musical-space-md);
	min-height: 48px;
	text-overflow: ellipsis;
}

.musical-share__feedback {
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-primary-ink);
}

/* The base .musical-icon-btn is styled for the dark player bar; on the light
 * card/section backgrounds the share row sits in, invert to match
 * .musical-btn--secondary instead. */
.musical-share__social {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--musical-space-xs);
}

.musical-share__social .musical-icon-btn {
	width: 44px;
	height: 44px;
	color: var(--musical-text-secondary);
	box-shadow: inset 0 0 0 1px var(--musical-border);
}

.musical-share__social .musical-icon-btn:hover {
	background: var(--musical-bg-light);
	color: var(--musical-text-primary);
}

.musical-share__social .musical-icon-btn svg {
	width: 20px;
	height: 20px;
}

.musical-share__native[hidden] {
	display: none;
}

/* ==========================================================================
   13. Empty and loading states
   ========================================================================== */

.musical-empty {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--musical-space-lg);
	padding: var(--musical-space-3xl) var(--musical-space-lg);
	text-align: center;
}

.musical-empty__mark {
	width: 8rem;
	height: 8rem;
	color: var(--musical-primary);
	opacity: 0.5;
}

.musical-empty__mark svg {
	width: 100%;
	height: 100%;
	fill: currentcolor;
}

.musical-empty__body {
	color: var(--musical-text-secondary);
	max-width: 40ch;
}

.musical-skeleton {
	border-radius: var(--musical-radius-md);
	background: var(--musical-border);
	animation: musical-pulse 1.5s ease-in-out infinite;
}

@keyframes musical-pulse {
	0%, 100% { opacity: 1; }
	50% { opacity: 0.5; }
}

.musical-progress {
	height: 6px;
	border-radius: var(--musical-radius-pill);
	background: var(--musical-border);
	overflow: hidden;
}

.musical-progress__bar {
	height: 100%;
	width: 0;
	background: var(--musical-primary);
	transition: width var(--musical-duration-smooth) linear;
}

/* ==========================================================================
   14. Toast
   ========================================================================== */

.musical-toasts {
	position: fixed;
	inset-block-end: var(--musical-space-lg);
	inset-inline-end: var(--musical-space-lg);
	z-index: 900;
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-sm);
	max-width: min(24rem, calc(100vw - 2 * var(--musical-space-lg)));
	pointer-events: none;
}

.musical-toast {
	display: flex;
	align-items: start;
	gap: var(--musical-space-sm);
	padding: var(--musical-space-md);
	border-radius: var(--musical-radius-md);
	font-family: var(--musical-font-body);
	font-size: 0.9375rem;
	color: var(--musical-text-light);
	background: var(--musical-text-primary);
	box-shadow: var(--musical-shadow-lift);
	pointer-events: auto;
	animation: musical-rise var(--musical-duration-smooth) var(--musical-easing-out) both;
}

.musical-toast--success { background: #057a52; }
.musical-toast--error { background: #b32424; }
.musical-toast--warning { background: #7a5200; }
.musical-toast--info { background: #00688f; }

.musical-toast__close {
	margin-inline-start: auto;
	border: 0;
	background: transparent;
	color: inherit;
	opacity: 0.7;
	cursor: pointer;
	font-size: 1rem;
	line-height: 1;
	padding: var(--musical-space-xs);
}

.musical-toast__close:hover {
	opacity: 1;
}

/* ==========================================================================
   15. Header and footer
   ========================================================================== */

.musical-header {
	position: sticky;
	top: 0;
	z-index: 500;
	background: rgb(250 250 249 / 92%);
	backdrop-filter: blur(10px);
	border-block-end: 1px solid var(--musical-border);
}

.musical-header__inner {
	display: flex;
	align-items: center;
	gap: var(--musical-space-lg);
	min-height: 64px;
	max-width: 75rem;
	margin-inline: auto;
	padding-inline: var(--musical-space-lg);
}

.musical-brand {
	display: inline-flex;
	align-items: center;
	gap: var(--musical-space-sm);
	font-family: var(--musical-font-display);
	font-size: 1.25rem;
	font-weight: 700;
	letter-spacing: -0.01em;
	color: var(--musical-text-primary);
	text-decoration: none;
}

.musical-brand__mark {
	width: 32px;
	height: 32px;
	border-radius: var(--musical-radius-md);
	background: linear-gradient(135deg, var(--musical-primary) 0%, var(--musical-secondary) 100%);
	object-fit: cover;
	flex: 0 0 auto;
}

.musical-nav {
	margin-inline-start: auto;
}

.musical-nav__list {
	display: flex;
	align-items: center;
	gap: var(--musical-space-lg);
	list-style: none;
	margin: 0;
	padding: 0;
}

.musical-nav__link {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font-family: var(--musical-font-body);
	font-size: 1rem;
	color: var(--musical-text-primary);
	text-decoration: none;
	border-block-end: 3px solid transparent;
	transition:
		color var(--musical-duration-quick) var(--musical-easing-out),
		border-color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-nav__link:hover {
	color: var(--musical-primary-ink);
	border-block-end-color: var(--musical-border);
}

.musical-nav__link[aria-current="page"] {
	border-block-end-color: var(--musical-primary-ink);
	font-weight: 600;
}

/* Desktop already shows log-out as `.musical-header__logout`; see mobile below. */
.musical-nav__link--utility {
	display: none;
}

.musical-header__toggle {
	display: none;
	margin-inline-start: auto;
}

.musical-header__toggle-bar {
	transform-origin: 12px 12px;
	transition:
		transform var(--musical-duration-quick) var(--musical-easing-out),
		opacity var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-header__toggle[aria-expanded="true"] .musical-header__toggle-bar--top {
	transform: translateY(6px) rotate(45deg);
}

.musical-header__toggle[aria-expanded="true"] .musical-header__toggle-bar--mid {
	opacity: 0;
}

.musical-header__toggle[aria-expanded="true"] .musical-header__toggle-bar--bottom {
	transform: translateY(-6px) rotate(-45deg);
}

@media (prefers-reduced-motion: reduce) {
	.musical-header__toggle-bar {
		transition: none;
	}
}

@media (max-width: 47.99rem) {
	/*
	 * Brand + hamburger + CTA compete for one 390px row. Desktop's roomy
	 * button padding and header gap push "Musical Links" and "Sign in" each
	 * into a two-line wrap here, so both tighten to the next token down;
	 * the button keeps its 48px+ min-height so the touch target is untouched.
	 */
	.musical-header__inner {
		gap: var(--musical-space-md);
		padding-inline: var(--musical-space-md);
	}

	.musical-brand {
		white-space: nowrap;
	}

	.musical-header__inner > .musical-btn {
		padding-inline: var(--musical-space-md);
		white-space: nowrap;
	}

	/*
	 * Logged in, the bar would otherwise carry brand + toggle + "Upload a
	 * track" + "Log out" - two full-width buttons is the row that never
	 * fits. Log-out moves into the same collapsible menu the toggle opens.
	 */
	.musical-header__logout {
		display: none;
	}

	.musical-nav__link--utility {
		display: flex;
	}

	.musical-header__toggle {
		display: inline-flex;
	}

	.musical-nav {
		position: absolute;
		inset-inline: 0;
		top: 100%;
		margin: 0;
		background: var(--musical-bg-light);
		border-block-end: 1px solid var(--musical-border);
		display: none;
	}

	.musical-nav.is-open {
		display: block;
	}

	.musical-nav__list {
		flex-direction: column;
		align-items: stretch;
		gap: 0;
		padding: var(--musical-space-sm) var(--musical-space-lg) var(--musical-space-lg);
	}

	.musical-nav__link {
		min-height: 48px;
		border-block-end: 1px solid var(--musical-border);
	}
}

.musical-footer {
	background: var(--musical-bg-dark);
	color: var(--musical-text-light);
	padding: var(--musical-space-3xl) var(--musical-space-lg) var(--musical-space-xl);
}

.musical-footer__inner {
	display: grid;
	gap: var(--musical-space-xl);
	max-width: 75rem;
	margin-inline: auto;
}

@media (min-width: 48rem) {
	.musical-footer__inner {
		grid-template-columns: 2fr 1fr 1fr;
	}
}

.musical-footer .musical-link {
	color: rgb(245 245 245 / 85%);
}

.musical-footer .musical-link:hover {
	color: var(--musical-primary);
}

.musical-footer__brand {
	color: var(--musical-text-light);
}

.musical-footer__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-sm);
}

.musical-footer__legal {
	max-width: 75rem;
	margin: var(--musical-space-xl) auto 0;
	padding-block-start: var(--musical-space-lg);
	border-block-start: 1px solid var(--musical-border-dark);
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: rgb(245 245 245 / 65%);
}

/* ==========================================================================
   16. Dashboard
   ========================================================================== */

.musical-dashboard {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--musical-space-xl);
	max-width: 78rem;
	margin-inline: auto;
	padding: var(--musical-space-xl) var(--musical-space-lg) var(--musical-space-3xl);
}

@media (min-width: 64rem) {
	.musical-dashboard {
		grid-template-columns: 10.5rem minmax(0, 1fr);
		gap: var(--musical-space-2xl);
	}
}

.musical-sidebar__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: nowrap;
	gap: var(--musical-space-xs);
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	scrollbar-width: none;
}

.musical-sidebar__list::-webkit-scrollbar {
	display: none;
}

@media (min-width: 64rem) {
	.musical-sidebar {
		position: sticky;
		top: calc(64px + var(--musical-space-lg));
		align-self: start;
	}

	.musical-sidebar__list {
		flex-direction: column;
		overflow-x: visible;
	}
}

.musical-sidebar__link {
	display: flex;
	align-items: center;
	flex: 0 0 auto;
	min-height: 44px;
	padding-inline: var(--musical-space-sm);
	border-block-end: 3px solid transparent;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	color: var(--musical-text-secondary);
	text-decoration: none;
	white-space: nowrap;
	border-radius: var(--musical-radius-sm);
	transition: background-color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-sidebar__link:hover {
	background: var(--musical-border);
}

.musical-sidebar__link[aria-current="page"] {
	font-weight: 600;
	color: var(--musical-text-primary);
	border-block-end-color: var(--musical-primary-ink);
}

@media (min-width: 64rem) {
	.musical-sidebar__link {
		border-block-end: 0;
		border-inline-start: 3px solid transparent;
		white-space: normal;
	}

	.musical-sidebar__link[aria-current="page"] {
		border-inline-start-color: var(--musical-primary-ink);
	}
}

.musical-dashboard__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-md);
	margin-block-end: var(--musical-space-xl);
}

/* The one link that opens a chooser rather than a single track. */
.musical-artist-link {
	padding: var(--musical-space-lg);
	background: #fff;
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-lg);
	box-shadow: var(--musical-shadow-card);
}

/* Owner-view card gets a control row under the metadata. */
.musical-track-card__owner-tools {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--musical-space-md);
	position: relative;
	z-index: 2;
	padding-block-start: var(--musical-space-sm);
	border-block-start: 1px solid var(--musical-border);
}

/* ==========================================================================
   16b. Visibility: public / unlisted / private
   ========================================================================== */

/*
 * A segmented control, not a switch. Three states with genuinely different
 * consequences have to be readable without operating them, and the note under
 * the control says what the selected one actually does.
 */
.musical-visibility {
	margin: 0;
	padding: 0;
	border: 0;
	min-width: 0;
}

.musical-visibility__options {
	display: inline-flex;
	padding: 3px;
	background: var(--musical-bg-light);
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-pill);
}

.musical-visibility__input {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
}

.musical-visibility__option {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 38px;
	padding-inline: var(--musical-space-md);
	border-radius: var(--musical-radius-pill);
	font-family: var(--musical-font-body);
	font-size: 0.8125rem;
	font-weight: 600;
	color: var(--musical-text-secondary);
	cursor: pointer;
	white-space: nowrap;
	transition:
		background-color var(--musical-duration-quick) var(--musical-easing-out),
		color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-visibility__option:hover {
	color: var(--musical-text-primary);
}

.musical-visibility__input:checked + .musical-visibility__option {
	background: #fff;
	color: var(--musical-text-primary);
	box-shadow: var(--musical-shadow-card);
}

/* The input is visually hidden, so the ring has to land on the label. */
.musical-visibility__input:focus-visible + .musical-visibility__option {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 2px;
}

.musical-visibility__input:disabled + .musical-visibility__option {
	cursor: progress;
	opacity: 0.6;
}

.musical-track-card__visibility-note {
	position: relative;
	z-index: 2;
	margin: 0;
	letter-spacing: 0.02em;
}

.musical-track-card__reset-link {
	min-height: 44px;
	padding-inline: var(--musical-space-md);
	flex: 0 0 auto;
	white-space: nowrap;
	color: var(--musical-text-secondary);
}

.musical-track-card__reset-link[hidden] {
	display: none;
}

/* ==========================================================================
   17. Upload form
   ========================================================================== */

/*
 * A tinted, bordered panel. The studio's track rows are white cards on white
 * ground; making the upload form a different surface is half the reason it is
 * no longer mistakable for the editor sitting a few hundred pixels above it.
 * The other half is that it now asks for three things instead of nine.
 */
.musical-upload-panel {
	padding: var(--musical-space-lg);
	background: var(--musical-bg-light);
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-lg);
}

@media (min-width: 48rem) {
	.musical-upload-panel {
		padding: var(--musical-space-xl);
	}
}

.musical-upload {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
}

/* The drop zone is a target, so it takes the panel's full width. The fields
   under it keep a form measure - a 900px text input is not easier to fill. */
.musical-upload__primary,
.musical-upload__submit {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
}

.musical-upload__primary .musical-field,
.musical-upload__primary .musical-toggle {
	max-width: 34rem;
}

/*
 * The file is the subject of this form, so it goes first and it is the biggest
 * thing in it. Title used to sit above it, which asked people to name a track
 * before they had chosen one.
 */
.musical-upload__drop {
	position: relative;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--musical-space-sm);
	min-height: 11rem;
	padding: var(--musical-space-lg);
	text-align: center;
	border: 2px dashed var(--musical-border);
	border-radius: var(--musical-radius-lg);
	background: #fff;
	color: var(--musical-text-secondary);
	cursor: pointer;
	transition:
		border-color var(--musical-duration-quick) var(--musical-easing-out),
		background-color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-upload__drop:hover,
.musical-upload__drop.is-dragging {
	border-color: var(--musical-primary-ink);
	background: rgb(0 122 122 / 5%);
}

.musical-upload__drop:focus-within {
	border-color: var(--musical-primary-ink);
	box-shadow: 0 0 0 3px rgb(0 122 122 / 15%);
}

.musical-upload__drop-icon svg {
	width: 32px;
	height: 32px;
	fill: var(--musical-primary-ink);
}

.musical-upload__drop-lead {
	font-family: var(--musical-font-display);
	font-size: 1.125rem;
	font-weight: 600;
	line-height: 1.3;
	color: var(--musical-text-primary);
}

.musical-upload__drop input[type="file"] {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
}

.musical-upload__filename {
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--musical-primary-ink);
	overflow-wrap: anywhere;
}

/*
 * Everything below here is metadata the track page can live without on day
 * one, and every field of it exists again in the editor. Closed by default,
 * the upload form stops being a second copy of that editor.
 */
.musical-upload__more {
	border-block-start: 1px solid var(--musical-border);
	padding-block-start: var(--musical-space-md);
}

.musical-upload__more-summary {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--musical-primary-ink);
	cursor: pointer;
}

.musical-upload__more-summary:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.musical-upload__more-summary:focus-visible {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 3px;
}

.musical-upload__more-body {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
	padding-block-start: var(--musical-space-md);
}

/* Names the relationship in words, so nobody has to work out why these fields
   look like the ones in the editor. */
.musical-upload__more-note {
	margin: 0;
	font-family: var(--musical-font-body);
	font-size: 0.8125rem;
	color: var(--musical-text-secondary);
}

.musical-upload__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--musical-space-lg);
	align-items: start;
}

@media (min-width: 60rem) {
	.musical-upload__grid {
		grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
		column-gap: var(--musical-space-2xl);
	}
}

.musical-upload__col {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
	min-width: 0;
}

.musical-upload__submit {
	align-items: flex-start;
}

/* The picker's own ground is --musical-bg-light, which is now also the panel's
   ground: without this it dissolves into the panel it sits on. */
.musical-upload-panel .musical-cover-picker {
	background: #fff;
}

/* ==========================================================================
   18. Account: sign in / sign up
   ========================================================================== */

.musical-auth {
	display: grid;
	grid-template-columns: 1fr;
	gap: var(--musical-space-xl);
	align-items: start;
}

@media (min-width: 56rem) {
	.musical-auth {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		gap: var(--musical-space-2xl);
	}
}

.musical-auth__panel {
	padding: var(--musical-space-xl);
	background: #fff;
	border-radius: var(--musical-radius-lg);
	box-shadow: var(--musical-shadow-card);
}

/* Keep signed-in account controls together so password management does not
 * fall below the taller profile editor in the desktop grid. */
.musical-auth__account-actions {
	align-self: start;
}

/* The sign-up side is the one we want chosen, so colour owns it. */
.musical-auth__panel--accent {
	background: linear-gradient(150deg, var(--musical-bg-dark) 0%, #241d2c 100%);
	color: var(--musical-text-light);
	box-shadow: var(--musical-shadow-lift);
}

.musical-auth__panel--accent .musical-h3 {
	color: var(--musical-text-light);
}

.musical-auth__panel--accent .musical-field__label,
.musical-auth__panel--accent .musical-caption {
	color: rgb(245 245 245 / 75%);
}

.musical-auth__panel--accent .musical-body-s {
	color: rgb(245 245 245 / 88%);
}

.musical-auth__panel--accent .musical-field__error {
	color: #ff9d9d; /* readable on the dark panel, unlike --musical-error */
}

.musical-auth__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-md);
}

.musical-profile__details {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
	gap: var(--musical-space-lg);
}

.musical-profile__notice {
	margin: 0;
}

.musical-profile__notice--success {
	color: #006b43;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
}

/* ==========================================================================
   19. Utilities
   ========================================================================== */

/*
 * Anchor targets sit under the 64px sticky header without this, so a jump to
 * #musical-upload lands with the heading hidden behind the bar.
 */
:target,
.musical-anchor,
[id^="musical-"] {
	scroll-margin-top: calc(64px + var(--musical-space-lg));
}

/* Zero-height marker used purely as a scroll target. */
.musical-anchor {
	display: block;
	height: 0;
	overflow: hidden;
}

.musical-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

/* ==========================================================================
   20. Studio row: share link and inline edit
   ========================================================================== */

/*
 * The owner's row. Art drops from a 312px square to a small identifier, which
 * is all it needs to be when you already know your own catalogue, and the
 * width it gives back is what the editor lives on. It stays a row on phones
 * too: three full-bleed album squares put a thousand pixels of artwork
 * between a musician and the track they came to change.
 */
.musical-track-card--row {
	display: grid;
	grid-template-columns: 4rem minmax(0, 1fr);
	grid-template-areas: "art body";
	align-items: start;
	gap: var(--musical-space-md);
	padding: var(--musical-space-md);
}

.musical-track-card--row .musical-track-card__art {
	grid-area: art;
}

.musical-track-card--row .musical-track-card__body {
	grid-area: body;
}

@media (min-width: 40rem) {
	.musical-track-card--row {
		grid-template-columns: 6rem minmax(0, 1fr);
		gap: var(--musical-space-lg);
		padding: var(--musical-space-lg);
	}
}

/*
 * Below the editor's own two-column breakpoint every pixel of row width is
 * needed by the form, and the art column is worth ~80 of them. While the
 * editor is open the thumbnail steps aside - the panel names the track it is
 * editing, and the cover field carries its own preview.
 */
@media (max-width: 59.99rem) {
	.musical-track-card--row:has(.musical-edit[open]) {
		grid-template-columns: minmax(0, 1fr);
		grid-template-areas: "body";
	}

	.musical-track-card--row:has(.musical-edit[open]) .musical-track-card__art {
		display: none;
	}
}

/*
 * The visibility switch and the share link are one job, so at a width that can
 * hold both they sit on one line instead of stacking down the left edge and
 * leaving 250px of the row empty beside them.
 */
@media (min-width: 64rem) {
	.musical-track-card--row .musical-track-card__body {
		display: grid;
		grid-template-columns: auto minmax(0, 1fr);
		align-items: center;
		column-gap: var(--musical-space-lg);
		row-gap: var(--musical-space-sm);
	}

	.musical-track-card--row .musical-track-card__title,
	.musical-track-card--row .musical-track-card__meta,
	.musical-track-card--row .musical-track-card__visibility-note,
	.musical-track-card--row .musical-track-card__fresh,
	.musical-track-card--row .musical-edit {
		grid-column: 1 / -1;
	}

	/* One rule per row is enough separation; the edit disclosure carries it. */
	.musical-track-card--row .musical-track-card__owner-tools {
		border-block-start: 0;
		padding-block-start: 0;
	}
}

/* A full-width row rising off the page on hover is a lot of movement for a
   list you are working inside, and absurd once the editor is open. */
.musical-track-card--row:hover,
.musical-track-card--row:focus-within {
	transform: none;
}

.musical-track-card--row:hover .musical-track-card__art img,
.musical-track-card--row:hover .musical-track-card__art .musical-cover {
	transform: none;
}

/* Scaled to the smaller art, and centred because there is no longer a corner
   big enough to tuck it into. 44px is the floor, not a design choice. */
.musical-track-card--row .musical-track-card__play {
	inset: 50% auto auto 50%;
	translate: -50% -50%;
	width: 44px;
	height: 44px;
}

.musical-track-card--row .musical-track-card__play svg {
	width: 16px;
	height: 16px;
}

.musical-track-card__share {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-sm);
	position: relative;
	z-index: 2;
}

/*
 * `display: flex` outranks the UA's `[hidden] { display: none }`, so private
 * tracks were showing a share link and, right under it, a note saying they do
 * not have one until you make them public.
 */
.musical-track-card__share[hidden] {
	display: none;
}

/* The link is a fixed-length string, not a layout element: let it stop. */
.musical-track-card--row .musical-track-card__share {
	max-width: 34rem;
}

.musical-track-card__share .musical-share__url {
	flex: 1 1 10rem;
	font-size: 0.8125rem;
	min-height: 44px;
}

.musical-track-card__share .musical-btn {
	min-height: 44px;
	padding-inline: var(--musical-space-md);
	flex: 0 0 auto;
	/* "Copy link" broke onto two lines in the narrow card column. */
	white-space: nowrap;
}

.musical-edit {
	position: relative;
	z-index: 2;
	border-block-start: 1px solid var(--musical-border);
	padding-block-start: var(--musical-space-sm);
}

.musical-edit__summary {
	display: inline-flex;
	align-items: center;
	gap: var(--musical-space-sm);
	min-height: 44px;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--musical-primary-ink);
	cursor: pointer;
}

.musical-edit__cue {
	padding: 2px var(--musical-space-sm);
	border-radius: var(--musical-radius-pill);
	background: rgb(0 122 122 / 10%);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.02em;
	white-space: nowrap;
	text-decoration: none;
}

.musical-edit__summary:hover {
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.musical-edit__summary:focus-visible {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 3px;
}

/* The control says what it will do next, not what the panel is. */
.musical-edit__summary-label--open,
.musical-edit[open] .musical-edit__summary-label--closed,
.musical-edit[open] .musical-edit__cue {
	display: none;
}

.musical-edit[open] .musical-edit__summary-label--open {
	display: inline;
}

.musical-edit__form {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
	padding-block-start: var(--musical-space-md);
}

/* Says which track, and says "editing" - the studio also carries an upload
   form with the same field set, and the two used to be indistinguishable. */
.musical-edit__heading {
	margin: 0;
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--musical-text-secondary);
}

.musical-edit__heading-title {
	color: var(--musical-text-primary);
	text-transform: none;
	letter-spacing: 0.01em;
}

.musical-edit__grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: var(--musical-space-lg);
	align-items: start;
}

/*
 * Split by what the fields are, not by how many: the short identity fields on
 * the left, the three long text blocks on the right. Stacked in one column the
 * editor ran to 1500px whatever the screen size, and the monospace chord sheet
 * - the one field that is useless without horizontal room - was the narrowest
 * thing on the page.
 */
@media (min-width: 60rem) {
	.musical-edit__grid {
		grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
		column-gap: var(--musical-space-2xl);
	}
}

.musical-edit__col {
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-lg);
	min-width: 0;
}

/* The three long text blocks are sized by their `rows`; the global 8rem floor
   on textareas only ever added height the editor could not spare. */
.musical-edit__col--words textarea.musical-input {
	min-height: 0;
}

.musical-edit__actions {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--musical-space-md);
	padding-block-start: var(--musical-space-md);
	border-block-start: 1px solid var(--musical-border);
}

.musical-edit__status {
	margin: 0;
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	line-height: 1.5;
}

.musical-edit__status--success {
	color: #006b43;
}

.musical-edit__status--error {
	color: #d13030;
}

/*
 * Destructive, and permanent, but not the reason anyone opened this editor.
 * As a filled red block directly under Save it was the loudest element on the
 * whole page; as a quiet button at the far end of the bar it is still one
 * click away and no longer competing with the action people came for.
 */
.musical-edit__delete {
	margin-inline-start: auto;
	color: var(--musical-error-ink);
}

.musical-edit__delete:hover,
.musical-edit__delete:focus-visible {
	background: rgb(165 31 31 / 8%);
}

/* ==========================================================================
   21. Cover image picker
   ========================================================================== */

/*
 * Deliberately not a second dashed drop zone: one of those already owns the
 * audio field, and two identical targets in one form make the important one
 * (the track itself) stop reading as the primary action. This is a thumbnail
 * plus a link, and the thumbnail always shows what the song will actually
 * look like - the uploaded image, or the generated art it falls back to.
 */
/*
 * Wraps on the space it actually has, not on viewport width: this sits both in
 * the roomy upload form and inside a 312px studio card, and a media query
 * keyed to the window leaves the narrow one squeezed into a 140px column at
 * every desktop size.
 */
.musical-cover-picker {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-start;
	gap: var(--musical-space-md);
	padding: var(--musical-space-md);
	background: var(--musical-bg-light);
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-md);
}

.musical-cover-picker__preview {
	position: relative;
	flex: 0 0 auto;
	display: block;
	width: 5.5rem;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	border-radius: var(--musical-radius-sm);
	background: #fff;
}

.musical-profile-picture__preview {
	border-radius: 50%;
}

.musical-cover-picker__preview img,
.musical-cover-picker__preview .musical-cover {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

.musical-cover-picker__placeholder {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 100%;
	height: 100%;
	color: var(--musical-text-secondary);
}

.musical-cover-picker__placeholder svg {
	width: 40%;
	height: 40%;
	fill: currentcolor;
}

/* Below ~12rem of its own the copy drops under the thumbnail instead. */
.musical-cover-picker__body {
	flex: 1 1 12rem;
	min-width: 12rem;
	display: flex;
	flex-direction: column;
	gap: var(--musical-space-xs);
}

/* A wrapping two-line label must not float its box to the middle. */
.musical-cover-picker .musical-checkbox {
	align-items: flex-start;
}

.musical-cover-picker__choose {
	position: relative; /* contains the visually-hidden file input */
	align-self: flex-start;
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	font-weight: 600;
	color: var(--musical-primary-ink);
	cursor: pointer;
	text-decoration: underline;
	text-underline-offset: 0.25em;
}

.musical-cover-picker__choose input[type="file"] {
	position: absolute;
	width: 1px;
	height: 1px;
	opacity: 0;
}

/* The visually-hidden input still takes focus, so give it a visible ring. */
.musical-cover-picker__choose:focus-within {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 3px;
	border-radius: var(--musical-radius-sm);
}

.musical-cover-picker__filename {
	font-family: var(--musical-font-body);
	font-size: 0.875rem;
	font-weight: 600;
	color: var(--musical-text-primary);
	overflow-wrap: anywhere;
}

.musical-cover-picker__actions {
	margin-block-start: var(--musical-space-xs);
}

/* ==========================================================================
   22. Track details panel (about / lyrics / chords)
   ========================================================================== */

/*
 * Sits directly under the player. Tabs rather than a stack, because all three
 * of these are long and stacking them pushed the artist card and the rest of
 * the catalogue below two screens of scroll - and because a listener wants the
 * words while the track is playing, not after scrolling away from the play
 * button.
 */
.musical-panels {
	max-width: var(--musical-measure);
	margin-inline: auto;
	margin-block-start: var(--musical-space-2xl);
}

.musical-panels__tabs {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-lg);
	border-block-end: 1px solid var(--musical-border);
}

.musical-panels__tab {
	position: relative;
	appearance: none;
	background: none;
	border: 0;
	padding: 0 0 var(--musical-space-sm);
	min-height: 44px;
	font-family: var(--musical-font-body);
	font-size: 0.75rem;
	font-weight: 600;
	letter-spacing: 0.05em;
	text-transform: uppercase;
	color: var(--musical-text-secondary);
	cursor: pointer;
	transition: color var(--musical-duration-quick) var(--musical-easing-out);
}

/*
 * The underline is a pseudo-element rather than a border so switching tabs
 * does not shift the row by a pixel, and so it can slide in from the centre.
 */
.musical-panels__tab::after {
	content: "";
	position: absolute;
	inset-block-end: -1px;
	inset-inline: 0;
	height: 2px;
	background: var(--musical-primary-ink);
	transform: scaleX(0);
	transition: transform var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-panels__tab:hover {
	color: var(--musical-text-primary);
}

.musical-panels__tab[aria-selected="true"] {
	color: var(--musical-text-primary);
}

.musical-panels__tab[aria-selected="true"]::after {
	transform: scaleX(1);
}

.musical-panels__tab:focus-visible {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 4px;
	border-radius: var(--musical-radius-sm);
}

.musical-panels__panel {
	padding-block-start: var(--musical-space-xl);
}

/* The panel is focusable per the ARIA tabs pattern; say so when it is. */
.musical-panels__panel:focus-visible {
	outline: 2px solid var(--musical-primary-ink);
	outline-offset: 4px;
	border-radius: var(--musical-radius-md);
}

.musical-panels__genres {
	margin-block-start: var(--musical-space-md);
	text-transform: uppercase;
}

.musical-prose {
	font-family: var(--musical-font-body);
	font-size: 1.125rem;
	line-height: 1.6;
	color: var(--musical-text-primary);
}

.musical-prose p {
	margin-block: 0 var(--musical-space-md);
}

.musical-prose p:last-child {
	margin-block-end: 0;
}

/*
 * A lyric sheet is not prose: verses are short lines that want a narrower
 * column and more air between them than a paragraph does, and the blank line
 * between verses is doing structural work.
 */
.musical-lyrics {
	max-width: 34rem;
	line-height: 1.75;
}

.musical-lyrics p {
	margin-block-end: var(--musical-space-lg);
}

/*
 * A chord chart is pre-formatted text. Its columns are the content, so it gets
 * its own horizontal scroll rather than wrapping - a folded chart puts the
 * chord over the wrong syllable, which is worse than a scrollbar.
 */
.musical-chords {
	margin: 0;
	padding: var(--musical-space-lg);
	overflow-x: auto;
	background: var(--musical-bg-light);
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-md);
	font-family: var(--musical-font-mono);
	font-size: 0.9375rem;
	line-height: 1.8;
	color: var(--musical-text-primary);
	tab-size: 4;
	white-space: pre;
	overscroll-behavior-x: contain;
}

.musical-chords code {
	font: inherit;
	background: none;
	padding: 0;
}

@media (max-width: 600px) {
	.musical-chords {
		padding: var(--musical-space-md);
		font-size: 0.875rem;
	}
}

/* Genre autocomplete
   ------------------------------------------------------------------------ */

/*
 * The listbox anchors to the whole .musical-field, not the input, so it lands
 * directly under the input only while the field has no hint or error row.
 * Both genre fields are label + input exactly; adding a hint to one means
 * giving it its own positioned wrapper.
 */
.musical-field--combobox {
	position: relative;
}

.musical-genre-suggestions {
	position: absolute;
	z-index: 20;
	inset-inline: 0;
	top: 100%;
	max-height: 15rem;
	margin: var(--musical-space-xs) 0 0;
	padding: var(--musical-space-xs);
	overflow-y: auto;
	list-style: none;
	background: #fff;
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-sm);
	box-shadow: var(--musical-shadow-card);
}

.musical-genre-suggestions__option {
	padding: var(--musical-space-xs) var(--musical-space-sm);
	border-radius: var(--musical-radius-sm);
	color: var(--musical-text-primary);
	cursor: pointer;
}

.musical-genre-suggestions__option:hover,
.musical-genre-suggestions__option.is-active {
	background: var(--musical-bg-light);
	color: var(--musical-primary-ink);
}

.musical-genre-filter {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-sm);
	align-items: baseline;
	margin: 0 0 var(--musical-space-lg);
	color: var(--musical-text-secondary);
}

/* Genre suggestions from the audio
   ------------------------------------------------------------------------ */

/* An upload jumps to its own card by id; clear the sticky header. */
.musical-track-card__title {
	scroll-margin-top: 6rem;
}

/*
 * Sits between the genre field and the save button. The negative top margin
 * eats most of the form's 1.5rem stack gap so this reads as a helper attached
 * to the field above it rather than another thing to fill in.
 */
.musical-genre-ai {
	margin-top: calc(var(--musical-space-md) * -1);
}

.musical-genre-ai__button {
	padding: 0;
	font-family: inherit;
	font-size: 0.875rem;
	color: var(--musical-primary-ink);
	text-decoration: underline;
	text-underline-offset: 3px;
	background: none;
	border: 0;
	cursor: pointer;
}

.musical-genre-ai__button:hover:not(:disabled) {
	color: var(--musical-secondary-ink);
}

.musical-genre-ai__button:disabled {
	color: var(--musical-text-secondary);
	cursor: progress;
}

.musical-genre-ai__status {
	margin: var(--musical-space-sm) 0 0;
	font-size: 0.8125rem;
	color: var(--musical-text-secondary);
}

.musical-genre-ai__list {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-sm);
	margin: var(--musical-space-sm) 0 0;
	padding: 0;
	list-style: none;
}

.musical-genre-ai__chip {
	padding: var(--musical-space-xs) var(--musical-space-md);
	font-family: inherit;
	font-size: 0.8125rem;
	color: var(--musical-text-primary);
	background: var(--musical-bg-light);
	border: 1px solid var(--musical-border);
	border-radius: var(--musical-radius-pill);
	cursor: pointer;
	transition: border-color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-genre-ai__chip::before {
	content: "+ ";
	color: var(--musical-primary-ink);
}

.musical-genre-ai__chip:hover:not(:disabled) {
	border-color: var(--musical-primary-ink);
}

.musical-genre-ai__chip.is-chosen {
	color: var(--musical-text-secondary);
	cursor: default;
	opacity: 0.6;
}

.musical-genre-ai__chip.is-chosen::before {
	content: "✓ ";
}

@media (prefers-reduced-motion: reduce) {
	.musical-genre-ai__chip {
		transition: none;
	}
}

/* Genre cloud
   ------------------------------------------------------------------------ */

.musical-genre-cloud {
	display: flex;
	flex-wrap: wrap;
	gap: var(--musical-space-sm) var(--musical-space-lg);
	align-items: baseline;
	justify-content: center;
	/* .musical-shell is a column flex container with align-items: flex-start,
	   so a direct child shrink-wraps to its content width by default (the
	   same reason .musical-shell itself needs this rule one level up) - with
	   no width to center within, justify-content: center above is a no-op. */
	align-self: stretch;
}

/*
 * Words, not buttons: no background, no border, no pill. The size carries the
 * meaning, so the only other signal needed is the hover colour.
 */
.musical-genre-tag {
	color: var(--musical-text-secondary);
	font-family: var(--musical-font-display);
	line-height: 1.2;
	text-decoration: none;
	transition: color var(--musical-duration-quick) var(--musical-easing-out);
}

.musical-genre-tag:hover,
.musical-genre-tag:focus-visible {
	color: var(--musical-primary-ink);
	text-decoration: underline;
}

/* Five fixed steps on a ~1.22x progression. No clamp() - the flex-wrap above
   already handles narrow widths, and scaling these with the viewport would
   flatten the count differences the sizes exist to show. */
.musical-genre-tag--1 { font-size: 0.875rem; }
.musical-genre-tag--2 { font-size: 1.0625rem; }
.musical-genre-tag--3 { font-size: 1.3125rem; }
.musical-genre-tag--4 { font-size: 1.625rem; }
.musical-genre-tag--5 { font-size: 2rem; }
