/*
	Second JaR — main stylesheet.

	Structure/mechanics ported from the Zeolutions template (nav toggle,
	section chrome, testimonial carousel, forms/buttons, footer) — but
	authored here as plain CSS with native custom properties instead of
	Sass, since no Sass/Node toolchain is available on this machine. Same
	architecture, zero build step: edit the variables below to re-theme.

	Colour palette and typography (Source Sans Pro, monochrome white/black/
	greyscale, no hue accent) are ported from the original Second JaR site.
*/

@import url("https://fonts.googleapis.com/css2?family=Source+Sans+Pro:ital,wght@0,300;0,400;0,600;1,300;1,400&family=Caveat:wght@500;700&display=swap");

/* LCD Mono (Samuel Reynolds, 1999, freeware — see assets/fonts/LCDMono-LICENSE.txt)
   self-hosted for the vintage hi-fi player's amber readout. */
@font-face {
	font-family: 'LCDMono2';
	src: url('../fonts/LCDMono2-Normal.ttf') format('truetype');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}
@font-face {
	font-family: 'LCDMono2';
	src: url('../fonts/LCDMono2-Bold.ttf') format('truetype');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

/* ==========================================================================
   Variables (ported from Second JaR's original dark/monochrome palette)
   ========================================================================== */

:root {
	--c-bg:            #1b1f22; /* page background */
	--c-bg-alt:        #000000; /* deep black, for gradients/darkest stops */
	--c-surface:       #24282d; /* elevated card surfaces (testimonials, CD gallery) — new role, the original had no card components */
	--c-text:          #e6e6e6; /* primary body text */
	--c-heading:       #ffffff; /* headings */
	--c-muted:         rgba(255, 255, 255, 0.55); /* secondary/muted text */
	--c-band:          #101214; /* nav / header-band / footer background — new dedicated role so band text can stay legible (see note in _main-sections below) */
	--c-band-text:     #ffffff; /* text/icons sitting on top of band backgrounds */
	--c-accent:        #ffffff; /* buttons, links, checkboxes, carousel arrows — the original site's only "accent" is white-on-dark */
	--c-accent-text:   #1b1f22; /* text on solid accent-filled elements (e.g. primary button) */
	--c-hover-fill:    rgba(255, 255, 255, 0.075); /* hover tint — exact value from the original site's button/icon hover */
	--c-active-fill:   rgba(255, 255, 255, 0.175); /* active/pressed tint — exact value from the original site */
	--c-border-light:  rgba(255, 255, 255, 0.075); /* input/box borders */
	--gradient-hero:   linear-gradient(-225deg, rgba(27, 31, 34, 0.85), rgba(0, 0, 0, 0.95), rgba(27, 31, 34, 0.85));
	--shadow-soft:     0 10px 30px rgba(0, 0, 0, 0.45);
	--font-family:     'Source Sans Pro', sans-serif;
	/* Hover "shape burst" for icons: six solid, zero-blur box-shadow rings
	   (offset 0, blur 0, growing spread) around a circular icon chip —
	   like the crisp inset/outset outline already on the album art
	   (.crate-face.front img's box-shadow), not a soft glow. box-shadow
	   traces the ELEMENT's own box/border-radius, never the icon glyph's
	   alpha shape, so unlike filter:drop-shadow it can't bleed into gaps
	   in the icon's own details — the icon stays exactly as it is (white,
	   grey on hover), and the colour sits purely outside it. Listed
	   smallest-spread (red) first so it paints on top, then each larger
	   ring shows only the band beyond the one before it, out to yellow
	   outermost — six equal 0.11rem steps from 0.05rem to 0.6rem. Red
	   starts at 0.05rem rather than exactly 0: a spread of precisely zero
	   is indistinguishable from "no shadow" in practice (it exactly
	   coincides with the icon chip's own edge, with nothing to render),
	   which is why it wasn't showing up at all rather than just being
	   thin. Every colour is a pure 0/F combination per channel
	   (#F00000 etc.), per the brief. */
	--icon-hover-burst:
		0 0 0 0.05rem #FF0000,
		0 0 0 0.16rem #FF00FF,
		0 0 0 0.27rem #0000FF,
		0 0 0 0.38rem #00FFFF,
		0 0 0 0.49rem #00FF00,
		0 0 0 0.6rem  #FFFF00;
}

/* ==========================================================================
   Reset (meyerweb.com/eric/tools/css/reset, public domain)
   ========================================================================== */

html, body, div, span, applet, object,
iframe, h1, h2, h3, h4, h5, h6, p, blockquote,
pre, a, abbr, acronym, address, big, cite,
code, del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var, b,
u, i, center, dl, dt, dd, fieldset,
form, label, legend, table, caption, tbody,
tfoot, thead, tr, th, td, article, aside,
canvas, details, embed, figure, figcaption,
footer, header, hgroup, menu, nav, output, ruby,
section, summary, time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	scroll-behavior: smooth;
	vertical-align: baseline;
}

article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;
}

body {
	line-height: 1;
	-webkit-text-size-adjust: none;
}

blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}

table {
	border-collapse: collapse;
	border-spacing: 0;
}

mark {
	background-color: transparent;
	color: inherit;
}

input::-moz-focus-inner {
	border: 0;
	padding: 0;
}

/* Content lists (bulleted feature lists in About/Music copy). */
ul {
	margin: 0 auto;
	list-style: none;
	display: grid;
	justify-content: center;
}
ul li {
	display: grid;
	grid-template-columns: 1em auto;
	align-items: center;
	column-gap: 0.5em;
	margin-bottom: 0.5em;
	font-weight: 400;
}
ul li .bullet {
	width: 1em;
	height: 1em;
}

/* ==========================================================================
   Base
   ========================================================================== */

html {
	box-sizing: border-box;
}
*, *:before, *:after {
	box-sizing: inherit;
}

body {
	background: var(--c-bg);
	font-family: var(--font-family);
	font-weight: 300;
	font-size: 17pt;
	line-height: 1.75em;
	color: var(--c-text);
}

/* Stops initial animations/transitions until the page has finished loading. */
body.is-preload *,
body.is-preload *:before,
body.is-preload *:after {
	animation: none !important;
	transition: none !important;
	align-content: center;
	align-items: center;
	text-align: center;
}

input, textarea, select {
	font-family: var(--font-family);
	font-weight: 300;
	font-size: 17pt;
	line-height: 1.75em;
	color: #888;
}

h1 { font-size: clamp(2rem, 1.5rem + 2.5vw, 3.5rem); }
h2 { font-size: clamp(1.75rem, 1.4rem + 1.8vw, 2.75rem); font-weight: 400; }
h3 { font-size: clamp(1.4rem, 1.2rem + 1vw, 2rem); font-weight: 300; }
h4 { font-size: clamp(1.15rem, 1.05rem + 0.5vw, 1.4rem); }
h5 { font-size: clamp(1.05rem, 1rem + 0.3vw, 1.2rem); }

h1 {
	color: var(--c-heading);
	margin: 0 0 0.4em 0;
	font-weight: 600;
	line-height: 1.25;
	text-align: center;
}

h2, h3 {
	color: var(--c-heading);
	margin: 0 0 0.4em 0;
	line-height: 1.25;
	text-align: center;
}

h4, h5, h6 {
	color: var(--c-muted);
	margin: 0 0 1em 0;
	font-weight: 300;
	line-height: 1.5em;
	text-align: center;
}

h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
	color: inherit;
	text-decoration: none;
}

strong, b {
	font-weight: 400;
	color: inherit;
}

em, i {
	font-style: italic;
}

a {
	color: inherit;
	text-decoration: none;
}

sub {
	position: relative;
	top: 0.5em;
	font-size: 0.8em;
}
sup {
	position: relative;
	top: -0.5em;
	font-size: 0.8em;
}

hr {
	border: none;
	height: 1px;
	background: linear-gradient(90deg, transparent, var(--c-muted), transparent);
	margin: 0;
	opacity: 0.5;
}

blockquote {
	border-left: solid 0.25em var(--c-border-light);
	padding: 1em 0 1em 2em;
	font-style: italic;
}

p, ul, ol, dl, table {
	margin-bottom: 1em;
}

header {
	display: block;
	margin: 0 0 1em 0;
	padding: 0.25em 0 0.5em;
	text-align: center;
	box-shadow: var(--shadow-soft);
}
header h1, header h2, header h3,
header h4, header h5, header h6 {
	margin: 0;
}

footer {
	padding-top: 1.5em;
}

.featured {
	text-align: center;
}
.featured p {
	text-align: center;
}

@media screen and (max-width: 1680px) {
	body, input, textarea, select { font-size: 15pt; line-height: 1.75em; }
}
@media screen and (max-width: 1280px) {
	body, input, textarea, select { font-size: 13pt; line-height: 1.65em; }
}
@media screen and (max-width: 1000px) {
	header, footer, h2, h3, h4, h5, h6, header > p { text-align: center; }
}
@media screen and (max-width: 736px) {
	body, input, textarea, select { font-size: 11pt; }
}

/* ==========================================================================
   Container / Row
   ========================================================================== */

.container {
	margin: 0 auto;
	max-width: 100%;
	width: 1360px;
}
.container.medium {
	width: 1360px;
}
@media screen and (max-width: 1680px) {
	.container { width: 1200px; }
	.container.medium { width: 1200px; }
}
@media screen and (max-width: 1280px) {
	.container { width: 960px; }
	.container.medium { width: 960px; }
}
@media screen and (max-width: 1000px) {
	.container {
		width: 100% !important;
		padding-left: 1rem;
		padding-right: 1rem;
	}
}

.row {
	display: flex;
	flex-wrap: wrap;
	box-sizing: border-box;
	align-items: stretch;
	margin-top: -50px;
	margin-left: -50px;
}
.row > * {
	box-sizing: border-box;
	padding: 50px 0 0 0;
}
.row > .col-2  { width: 16.66667%; }
.row > .col-3  { width: 25%; }
.row > .col-6  { width: 50%; }
.row > .col-12 { width: 100%; }
.row.gtr-50 {
	margin-top: -25px;
	margin-left: -25px;
}
.row.gtr-50 > * {
	padding: 25px 0 0 25px;
}
@media screen and (max-width: 1680px) {
	.row { margin-top: -40px; margin-left: -40px; }
	.row > * { padding: 40px 0 0 40px; }
	.row.gtr-50 { margin-top: -20px; margin-left: -20px; }
	.row.gtr-50 > * { padding: 20px 0 0 20px; }
}
@media screen and (max-width: 1280px) {
	.row { margin-top: -30px; margin-left: -30px; }
	.row > * { padding: 30px 0 0 30px; }
	.row.gtr-50 { margin-top: -15px; margin-left: -15px; }
	.row.gtr-50 > * { padding: 15px 0 0 15px; }
}
@media screen and (max-width: 1000px) {
	.row { margin-top: -25px; margin-left: -25px; }
	.row > * { padding: 25px 0 0 25px; }
	.row > .col-12-narrow { width: 100%; }
	.row.gtr-50 { margin-top: -12.5px; margin-left: -12.5px; }
	.row.gtr-50 > * { padding: 12.5px 0 0 12.5px; }
}
@media screen and (max-width: 736px) {
	.row { margin-top: -20px; margin-left: -20px; }
	.row > * { padding: 20px 0 0 0; }
	.row > .col-12-mobile { width: 100%; }
	.row.gtr-50 { margin-top: -10px; margin-left: -10px; }
	.row.gtr-50 > * { padding: 10px 0 0 10px; }
}

/* ==========================================================================
   Nav (hamburger circle -> pill menu, pure CSS via checkbox :checked)
   ========================================================================== */

.nav {
	position: fixed;
	top: 0.5em;
	right: 0.5em;
	/* 45px floor (was 34px) so this circle — and .menu's height/right
	   below, which must match it to stay flush against it — is always at
	   least as big as --icon-hover-burst's own worst-case diameter: the
	   ring reaches 2*0.6rem beyond the icon link, and at the smallest
	   viewports the icon (.menu li a, clamp(14px,1.4vw,20px) font *
	   1.8em) sits at its own 14px floor the whole time this circle is at
	   its floor too, working out to ~44.4px — otherwise the ring pokes
	   outside the circle/pill instead of bursting within it. */
	width: clamp(45px, 5vw, 60px);
	height: clamp(45px, 5vw, 60px);
	background-color: var(--c-band);
	border-radius: 50%;
	box-shadow: var(--shadow-soft);
	display: flex;
	justify-content: center;
	align-items: center;
	z-index: 9999;
	overflow: visible;
	cursor: pointer;
}
.nav span {
	position: absolute;
	width: clamp(16px, 3vw, 30px);
	height: clamp(2px, 0.4vw, 4px);
	background-color: var(--c-muted);
	border-radius: 50px;
	pointer-events: none;
	transition: all 0.5s ease;
}
.nav span:nth-child(2) { transform: translateY(-0.3em); }
.nav span:nth-child(3) { transform: translateY(0.3em); }
.nav:hover span,
.nav:active span {
	background-color: var(--c-band-text);
}
.nav input {
	width: 100%;
	height: 100%;
	opacity: 0;
	cursor: pointer;
	position: absolute;
	z-index: 2;
}
.nav input:checked ~ span:nth-child(2) { transform: rotate(-45deg); }
.nav input:checked ~ span:nth-child(3) { transform: rotate(45deg); }
.nav input:checked ~ .menu { transform: scaleX(1); }

.menu {
	position: absolute;
	top: 0;
	right: clamp(45px, 5vw, 60px);
	height: clamp(45px, 5vw, 60px);
	display: flex;
	align-items: center;
	background: var(--c-band);
	padding: 0 clamp(10px, 2.5vw, 24px);
	border-radius: 50px;
	transform-origin: right;
	transform: scaleX(0);
	transition: transform 0.5s ease;
	white-space: nowrap;
}
.menu-list {
	display: contents;
}
.menu li {
	display: block;
	list-style: none;
	margin: 0 clamp(6px, 1.4vw, 14px);
}
.menu li a {
	display: flex;
	align-items: center;
	justify-content: center;
	/* Just big enough to clear the icon plus the ring's own reach (up to
	   0.36rem/~5.8px on each side) without clipping — kept tight rather
	   than a generously-padded circle, since this also has to keep
	   fitting six of these in the pill down to the 320px floor. */
	width: 1.8em; height: 1.8em;
	border-radius: 50%;
	color: var(--c-muted);
	font-size: clamp(14px, 1.4vw, 20px);
	/* Same hover treatment as the footer's social icons (#footer
	   .social-link) — a scale bump, a colour brighten, and the ring
	   burst, nothing else (no underline, no fill background). */
	transition: transform 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
}
.menu li a i {
	line-height: 1;
	font-size: 1em;
}
.menu li a:hover,
.menu li a:active {
	transform: scale(1.35);
	color: var(--c-band-text);
	box-shadow: var(--icon-hover-burst);
}

/* ==========================================================================
   Sections
   ========================================================================== */

section, article {
	margin-bottom: 3em;
}
section > :last-child, article > :last-child,
section:last-child, article:last-child {
	margin-bottom: 0;
}

/* ==========================================================================
   List (prose bullet lists in About/Music copy)
   ========================================================================== */

.content ol, .content ul {
	margin-left: 10%;
	margin-right: 10%;
	padding-left: 0;
}
.content ol {
	list-style: decimal;
}
.content ol > li {
	margin-bottom: 1em;
}
.content ol > li > ul {
	list-style: disc;
	margin-left: 0.5em;
	margin-top: 0.5em;
	margin-bottom: 0.5em;
	padding-left: 0.5em;
}
.content ol > li > ul > li {
	line-height: 1.5em;
	margin-bottom: 0.5em;
	font-size: 0.95em;
}

/* ==========================================================================
   Forms
   ========================================================================== */

form input[type="text"],
form input[type="email"],
form input[type="password"],
form textarea {
	transition: all 0.25s ease-in-out;
	appearance: none;
	display: block;
	background: var(--c-surface);
	color: var(--c-text);
	box-shadow: inset 0 0 0 1px var(--c-border-light);
	width: 100%;
	padding: 0.85em 1em 0.85em 1em;
	border-radius: 0.25em;
	border: 0;
}
form input[type="text"]:focus,
form input[type="email"]:focus,
form input[type="password"]:focus,
form textarea:focus {
	outline: 0;
	box-shadow: inset 0 0 0 1px var(--c-accent);
	background: var(--c-surface);
}
form input[type="text"],
form input[type="email"],
form input[type="password"] {
	line-height: 1.25em;
}
form textarea {
	min-height: 13em;
}
form ::placeholder {
	color: rgba(255, 255, 255, 0.4);
}
form .error {
	color: #ff6b6b;
	font-size: 0.8em;
	margin-top: 0.35em;
	text-align: left;
}
.form-errors {
	background: rgba(255, 107, 107, 0.1);
	box-shadow: inset 0 0 0 1px rgba(255, 107, 107, 0.4);
	border-radius: 0.5em;
	padding: 1em 1.5em;
	color: #ff6b6b;
	text-align: left;
}
.form-errors ul {
	display: block;
	margin: 0;
}
.form-errors li {
	display: list-item;
	margin-left: 1.25em;
	list-style: disc;
}

/* ==========================================================================
   Table
   ========================================================================== */

table {
	width: 100%;
}

/* ==========================================================================
   Buttons (monochrome — outline by default, solid-white .primary)
   ========================================================================== */

input[type="button"],
input[type="submit"],
input[type="reset"],
button,
.button {
	transition: all 0.25s ease-in-out;
	position: relative;
	display: inline-block;
	background: transparent;
	box-shadow: inset 0 0 0 1px var(--c-accent);
	padding: 0.85em 3em 0.85em 3em;
	border-radius: 0.25em;
	cursor: pointer;
	border: 0;
	color: var(--c-accent);
	text-align: center;
	text-decoration: none;
	margin: 0 0.5em;
	text-transform: uppercase;
	letter-spacing: 0.1rem;
	font-size: 0.85rem;
}
input[type="button"]:hover,
input[type="submit"]:hover,
input[type="reset"]:hover,
button:hover,
.button:hover {
	background: var(--c-hover-fill);
}
input[type="button"]:active,
input[type="submit"]:active,
input[type="reset"]:active,
button:active,
.button:active {
	background: var(--c-active-fill);
}
input[type="button"].primary,
input[type="submit"].primary,
input[type="reset"].primary,
button.primary,
.button.primary {
	background: var(--c-accent);
	color: var(--c-accent-text);
	font-weight: 600;
	box-shadow: var(--shadow-soft);
}
input[type="button"].primary:hover,
input[type="submit"].primary:hover,
input[type="reset"].primary:hover,
button.primary:hover,
.button.primary:hover {
	background: #d8d8d8;
}
@media screen and (max-width: 736px) {
	.button {
		padding-left: 0;
		padding-right: 0;
		width: 100%;
		max-width: 24em;
	}
}

/* ==========================================================================
   Custom checkbox
   ========================================================================== */

input[type="checkbox"] {
	appearance: none;
	width: 20px;
	height: 20px;
	border: 2px solid var(--c-accent);
	border-radius: 4px;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	vertical-align: middle;
	background-color: transparent;
}
input[type="checkbox"]:checked {
	background-color: var(--c-accent);
	border-color: var(--c-accent);
}
input[type="checkbox"]:checked::after {
	content: "\2713";
	color: var(--c-accent-text);
	font-size: 14px;
	font-weight: bold;
	line-height: 1;
}

/* ==========================================================================
   Testimonial carousel
   ========================================================================== */

.testimonial-carousel {
	position: relative;
	display: flex;
	align-items: center;
	gap: 1em;
	margin: 1em;
}
.testimonial-track {
	display: flex;
	justify-content: center;
	justify-content: safe center;
	gap: 1.5em;
	flex: 1 1 auto;
	min-width: 0;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-behavior: smooth;
	padding: 0.5em 0.25em;
	scrollbar-width: none;
}
.testimonial-track::-webkit-scrollbar {
	display: none;
}
.carousel-arrow {
	margin: 0;
	padding: 0;
	flex: 0 0 auto;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 2.5em;
	height: 2.5em;
	border: 0;
	border-radius: 50%;
	background: var(--c-accent);
	color: var(--c-accent-text);
	font-size: 1em;
	cursor: pointer;
	box-shadow: var(--shadow-soft);
	transition: background 0.2s ease, opacity 0.2s ease;
}
.carousel-arrow:hover:not(:disabled) {
	background: #d8d8d8;
}
.carousel-arrow:disabled {
	opacity: 0.35;
	cursor: default;
}
@media screen and (max-width: 1000px) {
	.carousel-arrow {
		position: absolute;
		top: 50%;
		transform: translateY(-50%);
		opacity: 0.6;
		z-index: 2;
	}
	.carousel-arrow:hover:not(:disabled),
	.carousel-arrow:focus-visible {
		opacity: 0.9;
	}
	.carousel-prev { left: 0.5rem; }
	.carousel-next { right: 0.5rem; }
}
.testimonial-carousel.is-static .carousel-arrow {
	display: none;
}
.testimonial-card {
	flex: 0 0 auto;
	width: calc((100% - 2 * 1.5em) / 3);
	max-width: 380px;
	scroll-snap-align: center;
	background: var(--c-surface);
	border-radius: 0.75em;
	padding: 2em;
	box-shadow: var(--shadow-soft);
	text-align: center;
}
@media screen and (max-width: 1000px) {
	.testimonial-card { width: calc(100% - 1rem); max-width: none; }
}
.testimonial-card .quote-icon {
	font-size: 1.5em;
	color: var(--c-accent);
	margin-bottom: 0.5em;
}
.testimonial-title {
	font-weight: 600;
	color: var(--c-heading);
	margin-bottom: 0.5em;
}
.testimonial-quote {
	font-style: italic;
	color: var(--c-text);
	margin-bottom: 1em;
}
.testimonial-name {
	font-weight: 600;
	color: var(--c-text);
}
.testimonial-role {
	font-size: 0.85em;
	color: var(--c-muted);
}

/* ==========================================================================
   Header / Hero (#home)
   ========================================================================== */

#home {
	margin: 0;
	background: var(--gradient-hero);
	padding: 4em 1.5em;
	/* Fixed at 16:9 relative to its own full-viewport width — on a 16:9
	   display that makes the computed height equal the viewport height
	   exactly (width * 9/16 = viewport height when the viewport itself is
	   16:9), filling the page with no extra scroll, with no JS needed. On
	   any other aspect ratio it still holds 16:9, just under- or over-
	   filling the actual viewport height instead. */
	aspect-ratio: 16 / 9;
	display: flex;
	align-items: center;
	justify-content: center;
}
.hero {
	text-align: center;
	max-width: 640px;
	margin: 0 auto;
}
.hero-logo-full {
	width: clamp(220px, 30vw, 380px);
	margin: 0 auto 1.5em;
	display: block;
}
.hero-tagline {
	color: rgba(255, 255, 255, 0.75);
	font-style: italic;
	font-size: 1.1em;
	margin: 0;
}

/* ==========================================================================
   Now (latest release)
   ========================================================================== */

.news-releases {
	display: grid;
	grid-template-columns: 1fr;
	max-width: 32em;
	margin: 0 auto;
}
.next-release {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1em;
	background: var(--c-surface);
	border-radius: 0.75em;
	padding: 2em;
	box-shadow: var(--shadow-soft);
	text-align: center;
}
.next-release-cover {
	flex: 0 0 auto;
	width: clamp(200px, 55vw, 320px);
	border-radius: 0.5em;
	box-shadow: var(--shadow-soft);
}
.next-release-tag {
	font-weight: 700;
	font-size: 1.6em;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--c-heading);
	margin: 0;
}
.next-eyebrow {
	letter-spacing: 0.28em;
	font-size: 11px;
	color: var(--c-muted);
	text-transform: uppercase;
	margin: 0.4em 0 0.5em;
}
.next-release-title {
	color: var(--c-heading);
	margin: 0 0 0.5em;
}
.next-release-desc {
	color: var(--c-text);
	margin: 0 0 1em;
}
@media screen and (max-width: 736px) {
	.next-release {
		padding: 1.5em;
	}
}

/* ==========================================================================
   Main sections (.main > header / .content chrome)
   ========================================================================== */

.main {
	position: relative;
	margin: 0;
}
.main > header {
	position: relative;
	z-index: 2;
	text-align: center;
	padding: 2em 0 2em 0;
	margin: 0;
	background: var(--c-band);
	box-shadow: var(--shadow-soft);
}
.main > header h1 {
	color: var(--c-band-text);
}
.main > header > p {
	color: var(--c-band-text);
}
.main > .content.style1 {
	position: relative;
	z-index: 1;
	padding: 2em 0 2em 0;
	background: transparent;
	color: var(--c-text);
}
.main > header .content.style2 {
	padding: 0;
	background: transparent;
	color: var(--c-band-text);
}
.main > header .content.style2 h1,
.main > header .content.style2 h2 {
	font-size: clamp(2.25rem, 1.5rem + 4vw, 4.5rem);
	font-weight: 600;
	margin-bottom: 0;
	color: var(--c-band-text);
	text-align: center;
}
.main > header .content.style2 p {
	color: var(--c-band-text);
}
@media screen and (max-width: 1280px) {
	.main > header { padding: 4em 0 4em 0; }
	.main > .content { padding: 4em 0 4em 0; }
}
@media screen and (max-width: 1000px) {
	.main { margin: 0 !important; }
	.main > header { padding: 3.5em 2em 3.5em 2em; }
	.main > .content { padding: 3.5em 20px 3.5em 20px; }
	.main > .content > .container > :last-child { margin-bottom: 0 !important; }
}
@media screen and (max-width: 736px) {
	.main > header { padding: 3em 20px 3em 20px; }
	.main > .content { padding: 3em 20px 3em 20px; }
}

/* ==========================================================================
   Footer
   ========================================================================== */

#footer {
	position: relative;
	margin: 0;
	text-align: center;
	padding: 4em 0 8em 0;
	background: var(--c-band);
	border-top: 4px solid var(--c-accent);
}
#footer .copyright {
	margin-top: 3em;
	font-size: 0.8em;
	color: var(--c-band-text);
}
#footer .copyright a {
	color: inherit;
}
#footer .social-icons {
	display: flex;
	justify-content: center;
	flex-wrap: wrap;
	gap: 1em;
	color: var(--c-band-text);
	text-align: center;
}
#footer .social-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	/* Icons here are fa-2x (2em) — sized to clear that plus the ring's
	   own reach, same reasoning as the nav's .menu li a. */
	width: 2.9em; height: 2.9em;
	border-radius: 50%;
	color: var(--c-muted);
	text-decoration: none;
	transition: transform 0.2s ease, color 0.2s ease, box-shadow 0.2s ease;
	margin: 1em 0.5em;
}
#footer .social-link:hover,
#footer .social-link:active {
	transform: scale(1.35);
	color: var(--c-band-text);
	text-decoration: none;
	box-shadow: var(--icon-hover-burst);
}
@media screen and (max-width: 1000px) {
	#footer { margin: 0 !important; padding: 3em 0 3em 0; }
	#footer .copyright { margin-top: 2em; }
}

.h-captcha {
	display: flex;
	justify-content: center;
	align-items: center;
	margin: 20px auto;
	padding: 0 !important;
}
.submit-buttons {
	padding: 0 !important;
	margin-top: 2rem;
}

/* ==========================================================================
   CD crate gallery (Discography section)
   ========================================================================== */

.crate-gallery {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.5em;
	padding: 1em 0 2em;
	width: 100%;
}
.crate-eyebrow {
	letter-spacing: 0.28em;
	font-size: 11px;
	color: var(--c-muted);
	text-transform: uppercase;
	display: flex;
	align-items: center;
	gap: 10px;
}
.crate-eyebrow::before, .crate-eyebrow::after {
	content: '';
	width: 28px;
	height: 1px;
	background: rgba(255, 255, 255, 0.25);
}
.crate-stage {
	position: relative;
	container-type: inline-size; /* lets descendants use cqw units so text scales with the crate at any size, not just fixed px */
	width: 100%;
	/* Capped so the resting disc (81.25% of this element, see
	   .crate-disc-wrap below) always renders at exactly its DOCKED size
	   (90% of .crate-player — see .crate-disc-wrap.is-docked) too, at
	   every viewport width, not just above the point where both hit
	   their px caps. That needs .crate-stage's width to stay a CONSTANT
	   multiple of .crate-player's at all times — including in their
	   shared percentage-of-.crate-gallery regime, not just the fixed-px
	   regime — which is why the percentage term below is 104.12% (94% x
	   0.9/0.8125), not a plain copy of .crate-player's own 94%: a plain
	   copy only matches at the exact px-cap crossover point and drifts
	   apart on either side of it, which is what caused the disc to
	   visibly resize when docking. 432px / 0.8125 = the px-cap
	   equivalent, i.e. the widest this can be before the 104.12% term
	   takes over instead. Reduced from 576/709px to 432/532px overall
	   (crate + cases + disc all ~25% smaller) per request. */
	max-width: min(calc(432px / 0.8125), 104.12%);
	aspect-ratio: 1 / 1;
	perspective: 1000px;
	perspective-origin: 50% 85%;
	touch-action: none;
	user-select: none;
}
.crate-deck {
	position: absolute;
	inset: 0;
	transform-style: preserve-3d;
}
.crate-card {
	position: absolute;
	top: 50%; left: 50%;
	/* Widened (height untouched) to fit the jewel case's hinge sliver
	   beside the square window as part of the card's own footprint, rather
	   than overflowing past it — see .crate-face::after below for the
	   916x809 source proportions this is built from. Existing translate
	   -50%/-50% centering (applied via JS, see stageScale()/translate3d
	   below) is relative to the element's own box, so it re-centers on the
	   new width automatically; nothing else needed adjusting for that.
	   Only WIDTH changed because the flip/perspective physics (see
	   PERSPECTIVE_TO_CARD_HEIGHT_RATIO) key off the card's HEIGHT, which
	   this leaves alone. */
	width: 98.35%; height: 87.5%;
	border-radius: 6px;
	transform-origin: 50% 100%;
	box-shadow:
		0 2px 0 rgba(0, 0, 0, 0.4),
		0 30px 60px -20px rgba(0, 0, 0, 0.7),
		inset 0 0 0 1px rgba(255, 255, 255, 0.06);
	will-change: transform, opacity;
	cursor: grab;
	backface-visibility: hidden;
	transform-style: preserve-3d;
}
.crate-card:active { cursor: grabbing; }
.crate-flip-inner {
	position: absolute;
	inset: 0;
	transform-style: preserve-3d;
}
.crate-face {
	position: absolute;
	inset: 0;
	border-radius: 6px;
	overflow: hidden;
	backface-visibility: hidden;
	background: var(--c-surface);
}
/* .crate-card is now wider than its square art (see the comment on
   .crate-card above) so the case's hinge sliver has real room of its own
   — which means the art itself needs confining to just the window portion
   of that wider face (right-anchored, 88.97% of the face's new width, i.e.
   ≈815/916 of it) instead of filling the whole face. It's also inset a
   further few % on all four sides within that window, sitting just inside
   the case's own printed inner edge rather than running flush to it, the
   way a real insert is cut a touch smaller than the case window. */
.crate-face.front img {
position: absolute;
    top: 3%;
    bottom: 3%;
    right: 4.5%;
    width: 84%;
    object-fit: cover;
    display: block;
}
/* Real jewel-case artwork, photographed empty (front: cd case.png; back:
   cd case rear.png, overridden below — real cases only show a hinge on
   the front side). The front source photo (916x809) isn't a plain square
   — its right ~89% (≈815x809, near-square) is the actual case window that
   the art sits behind, and its left ~11% is the empty hinge/spine edge.
   Since .crate-face itself is now sized to that full 916x809 proportion
   (matching the widened .crate-card), this can just fill the face
   directly at inset:0/100% with no distortion. */
.crate-face::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image: url('../../images/cd case.png');
	background-size: 100% 100%;
	background-repeat: no-repeat;
}
.crate-face.back::after {
	/* The rear case cover is a separate photo (cd case rear.png, same
	   916x809 size) rather than a mirrored copy of the front's — the back
	   of a real jewel case has no hinge sliver in view at all, so its
	   window just runs the full width and this needs no scaleX(-1) mirror.
	   This lives directly on .crate-face.back (unpadded, see below) rather
	   than on .crate-back-content (which holds the actual padding) —
	   .crate-back-content also has overflow-y:auto for its scrolling
	   tracklist, and overflow clips AT the padding edge, which would have
	   cut this off right where it most needs to reach past that edge. */
	inset: 0;
	background-image: url('../../images/cd case rear.png');
}
.crate-face.back {
	transform: rotateY(180deg);
	background: linear-gradient(155deg, #2a2e33 0%, #16181b 100%);
}
/* Holds the actual back-of-card text, confined to the rear cover's own
   window (same margin on every side, no hinge to leave clear here) —
   split out from .crate-face.back itself so its overflow-y:auto (for a
   tracklist too long to fit) doesn't also clip the ::after case overlay
   above, which needs to reach .crate-face.back's true edges. */
.crate-back-content {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	justify-content: flex-start;
	/* No scrollbar, ever — the smaller cqw sizes below (and the switch from
	   fixed px/em spacing to cqw for the same reason) are what actually
	   keep this fitting without one, not the overflow behaviour itself. */
	overflow: hidden;
	padding: 2.67% 3%;
}
/* Font sizes AND spacing below use cqw (a % of .crate-stage's own width,
   set via container-type:inline-size) instead of fixed px/em, so the
   whole block — text and the gaps between it — shrinks together as the
   crate does, all the way down to this site's 320px floor, instead of
   fixed spacing eating a growing share of a shrinking box. */
.crate-face.back .crate-side-tag {
	position: absolute; top: 34px; right: 26px;
	z-index: 6;
	font-size: 2.2cqw; letter-spacing: 0.18em;
	color: var(--c-muted);
	text-transform: uppercase;
}
.crate-face.back .crate-back-title {
	font-weight: 600;
	font-size: 4.6cqw;
	line-height: 1.2;
	color: var(--c-heading);
	/* Top margin clears the catalogue number chip (.crate-cat, pinned at
	   top:3%/left:1.5% over this same face) so a long title's first line
	   doesn't run under it. */
	margin: 4cqw 0 0.8cqw;
	text-align: center;
}
.crate-face.back .crate-back-meta {
	/* Pinned to the bottom-left of .crate-back-content's own padding box
	   (the release date/UPC line, like the small print at the foot of a
	   real liner note) rather than flowing after the tracklist. Absolute
	   offsets are measured from the padding box's own edge, not inside it,
	   so left/bottom have to repeat .crate-back-content's padding (2.67%
	   3%) here or this sits flush against the case art's edge instead of
	   lining up with the rest of the inset text above it. */
	position: absolute;
	left: 3%; bottom: 2.67%;
	font-size: 2.4cqw;
	letter-spacing: 0.1em;
	color: var(--c-muted);
	text-align: left;
}
.crate-face.back .crate-back-rule {
	width: 2.4cqw; height: 1px;
	background: rgba(255, 255, 255, 0.3);
	margin: 1cqw 0;
	flex: 0 0 auto;
}
.crate-face.back .crate-back-desc {
	font-size: 2.9cqw;
	line-height: 1.4;
	color: var(--c-text);
	text-align: left;
	margin: 0;
}
.crate-back-tracklist {
	display: block;
	list-style: none;
	columns: 2;
	column-gap: 1.2cqw;
	margin: 0.9cqw 0 0;
	padding: 0;
	counter-reset: crate-track;
}
.crate-back-tracklist li {
	display: block;
	break-inside: avoid;
	counter-increment: crate-track;
	font-size: 2.3cqw;
	line-height: 1.4;
	color: var(--c-text);
	text-align: left;
	white-space: normal;
}
.crate-back-tracklist li::before {
	content: counter(crate-track) '. ';
	color: var(--c-muted);
}
.crate-track-btn {
	display: inline;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	box-shadow: none;
	text-transform: none;
	letter-spacing: normal;
	font: inherit;
	font-size: inherit;
	color: inherit;
	text-align: left;
	cursor: pointer;
	border-bottom: 1px dotted transparent;
}
.crate-track-btn:hover {
	color: var(--c-heading);
	border-bottom-color: rgba(255, 255, 255, 0.4);
}
.crate-track-btn.is-playing {
	color: var(--c-heading);
	font-weight: 600;
}
.crate-track-btn.is-playing::after {
	content: ' ♪';
}
.crate-back-tba {
	font-size: 2.3cqw;
	font-style: italic;
	color: var(--c-muted);
	margin: 0.9cqw 0 0;
	text-align: left;
}
.crate-card .crate-cat {
	/* % of the card's own box (its containing block here), not fixed px
	   — the card has no max-width and can render anywhere from a small
	   mobile size up to well over 600px, so a fixed-px offset would drift
	   off the case artwork's hinge sliver (a fixed % of the card's width)
	   at some sizes instead of always sitting on it. */
	position: absolute; top: 3%; left: 1.5%;
	z-index: 6;
	/* cqw (% of .crate-stage's inline size), not fixed px, so the label
	   itself scales in proportion with the card — same reasoning as its
	   now-percentage position above — all the way up to the site's max
	   width, not just up to some fixed cap. */
	font-size: 3cqw; letter-spacing: 0.15em;
	color: #fff;
	text-shadow: 0 0.3cqw 1.2cqw rgba(0, 0, 0, 0.6);
}
/* The cat label used to sit directly on the (dark) album/rear art; now it
   can land on the light case-panel margin instead, where white text + a
   dark drop-shadow alone isn't enough contrast — give it its own small
   backing chip so it stays legible over either. Applied to both faces so
   the back's catalogue number reads as the same sticker as the front's. */
.crate-face.front .crate-cat,
.crate-face.back .crate-cat {
	padding: 1cqw 2cqw;
	border-radius: 1cqw;
	background: rgba(0, 0, 0, 0.55);
	text-shadow: none;
	/* Slight tilt so it reads as a hand-applied sticker on the hinge, not
	   a perfectly straight printed label. Varied per case below (an
	   8-long repeating cycle, both directions) so they don't all lean
	   the exact same way — :nth-child (not :nth-of-type) because #deck's
	   only non-card child (the disc) is appended after all the cards,
	   so it never throws off this numbering. */
	transform: rotate(-4deg);
}
.crate-card:nth-child(8n+1) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+1) .crate-face.back .crate-cat { transform: rotate(-3deg); }
.crate-card:nth-child(8n+2) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+2) .crate-face.back .crate-cat { transform: rotate(4deg); }
.crate-card:nth-child(8n+3) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+3) .crate-face.back .crate-cat { transform: rotate(-6deg); }
.crate-card:nth-child(8n+4) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+4) .crate-face.back .crate-cat { transform: rotate(2deg); }
.crate-card:nth-child(8n+5) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+5) .crate-face.back .crate-cat { transform: rotate(-2deg); }
.crate-card:nth-child(8n+6) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+6) .crate-face.back .crate-cat { transform: rotate(5deg); }
.crate-card:nth-child(8n+7) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+7) .crate-face.back .crate-cat { transform: rotate(-5deg); }
.crate-card:nth-child(8n+8) .crate-face.front .crate-cat,
.crate-card:nth-child(8n+8) .crate-face.back .crate-cat { transform: rotate(3deg); }
.crate-card .crate-spindle {
	/* Leftover from the original vinyl-sleeve design — no spindle hole on
	   a jewel case front, so hidden now that the crate is CD-themed. */
	display: none;
	position: absolute; top: 50%; left: 50%;
	z-index: 6;
	width: 16px; height: 16px;
	border-radius: 50%;
	transform: translate(-50%, -50%);
	background: radial-gradient(circle at 35% 30%, rgba(255, 255, 255, 0.6), rgba(0, 0, 0, 0.6));
	box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.4);
	opacity: 0.7;
}

.crate-edge-btn {
	position: absolute; left: 0; right: 0;
	height: 48px;
	display: flex; align-items: center; justify-content: center;
	background: none; border: none;
	color: var(--c-muted);
	font-size: 20px;
	cursor: pointer;
	z-index: 250;
	transition: color 0.2s ease, opacity 0.2s ease;
	opacity: 0.5;
	margin: 0;
	padding: 0;
	box-shadow: none;
	text-transform: none;
	letter-spacing: normal;
}
.crate-edge-btn:hover { color: var(--c-heading); opacity: 1; background: none; }
.crate-edge-btn.up { top: -52px; }
.crate-edge-btn.down { bottom: -52px; }

.crate-disc-wrap {
	position: absolute;
	top: 50%; left: 50%;
	width: 81.25%; height: 81.25%;
	z-index: 80;
	opacity: 0;
	pointer-events: none;
	transform: translate(-50%, -50%) translate3d(19%, 3%, 0) rotate(4deg);
	/* 1.4s to match load.wav/Unload.wav (see cd-gallery.js), played over
	   exactly this motion as the disc docks down into the player or
	   undocks back up to the crate. */
	transition: top 1.4s ease, left 1.4s ease, width 1.4s ease, height 1.4s ease;
}
.crate-disc-wrap.animating-in {
	animation: crateDiscIn 1s cubic-bezier(.22, .85, .25, 1.05) forwards;
}
.crate-disc-wrap.animating-out {
	animation: crateDiscOut 1s cubic-bezier(.4, 0, .65, 1) forwards;
}
/* Docked while actually playing, so the cover art crate is uncovered again
   instead of sitting hidden behind the resting disc — it slides down to
   rest over the player instead, like a disc spinning in an open transport.
   top/left/width/height transition normally (plain layout properties,
   untouched by the keyframes above), but transform needs !important: the
   crateDiscIn/Out animation is still "on" the element (kept frozen at its
   last frame by fill-mode:forwards even once finished), and a running/filled
   CSS animation's value for a property outranks a normal-priority rule like
   this one in the cascade — only an !important author rule can override it. */
.crate-disc-wrap.is-docked {
	top: 100%;
	left: 50%;
	/* Needs to render at 90% of .crate-player's width, but this element's
	   actual containing block (for its own % resolution) is .crate-stage,
	   not .crate-player — they're independently-capped siblings. Rather
	   than re-deriving that relationship here (the previous attempt at
	   that, min(576px, 84.6%), assumed a fixed stage:player ratio that
	   only actually held above their shared px-cap crossover, so the
	   disc's size still drifted apart from the resting disc below it),
	   .crate-stage's own max-width is now DEFINED to stay proportional to
	   .crate-player's at every width (see the comment there) — which
	   means plain 81.25%-of-stage, the exact same percentage the resting
	   disc above already uses, is now just as correct here. The 432px cap
	   is 90% of .crate-player's own 480px cap; keep both in sync if
	   either changes. */
	width: min(432px, 81.25%);
	height: min(432px, 81.25%);
	transform: translate(-50%, 0%) rotate(0deg) !important;
}
/* The player's lid — a square panel (not round) in the same dark
   gunmetal material as .crate-player-fascia (so it reads as part of the
   same machine), with a circular transparent window cut into it that
   keeps the docked disc visibly spinning through it, and a dark arm
   sticking up into the window from the bottom.

   Folds down into place rather than sliding up from anywhere — hinged at
   its own bottom edge (transform-origin: 50% 100%) and rotated back
   almost flat (rotateX(-89deg), tipped toward the viewer) when hidden,
   the same "hinge at the bottom, rotateX(negative) tips the top toward
   the viewer" convention render()'s card-fall physics already use (see
   the comment above render() in cd-gallery.js). Folded flat like that,
   its own on-screen height collapses to almost nothing and its (tipped
   closer) top edge briefly reads larger before settling to its correct
   size as it rotates up to rotateX(0deg) — so it stays permanently
   sized/positioned to match the docked disc exactly, and this rotation
   alone is what "opens" and "closes" it, no travel or opacity fade
   needed. perspective() is chained into the transform itself, its own
   tight local value (not the shallower ambient one on .crate-stage,
   tuned for the fanned-card depth, not this) — same technique the card
   flip's own flipTransform() uses. */
.crate-player-lid {
	position: absolute;
	left: 50%;
	/* Anchored by its BOTTOM edge, not centred on the disc — this is what
	   keeps it permanently adjoined to the controls panel below (real
	   screenshots showed a visible gap with an earlier centred-on-disc
	   anchoring, since this box is bigger than the disc). Set by
	   positionPlayerLid() in cd-gallery.js, not a CSS formula — that edge
	   needs to land exactly on .crate-player-fascia's top edge, which
	   depends on the .crate-gallery flex gap + .crate-player's own
	   conditional margin-top + its padding, several different units
	   layered together; a hand-derived calc() here didn't track it
	   correctly in practice, so JS measures the real numbers instead.
	   This value is just an unset-instead-of-jumping fallback for the
	   instant before that first runs. */
	bottom: 0;
	/* 12% larger than the disc overall — enough for a real dark frame
	   margin outside the (also enlarged, see ::before) window, without
	   overhanging .crate-player's own width the way an earlier, much
	   bigger scale did. */
	width: calc(min(432px, 81.25%) * 1.12);
	height: calc(min(432px, 81.25%) * 1.12);
	transform-origin: 50% 100%;
	/* rotateX around transform-origin: 50% 100% rotates about a
	   horizontal axis lying ALONG the box's own bottom edge — every
	   point on that edge (not just the centre) is on the rotation axis
	   itself, so it stays put on screen through the whole rotation,
	   independent of angle; confirmed via a live headless-browser
	   measurement (lidRect.bottom matched the target exactly at a
	   mid-transition frame, not just at rest). -78deg (not -89, which
	   sits right at the perspective projection's mathematical
	   singularity at 90deg) + a longer 3000px perspective keeps a
	   strong "flattens to a sliver, top edge reads larger" illusion
	   without that runaway distortion. */
	transform: translateX(-50%) perspective(3000px) rotateX(-78deg);
	z-index: 600;
	pointer-events: none;
	/* Hidden while resting (disc just popped out but not docked, or back
	   from an eject) — not just folded flat, genuinely invisible. Opacity
	   0s-delayed-1.4s here (this base rule governs the DOCKED→undocked
	   direction, once .is-docked is removed) holds it visible for the
	   full 1.4s of the fold-closed/undock motion, only actually
	   disappearing once that's completely finished — i.e. once the disc
	   is genuinely back resting on the crate, not the instant eject
	   starts. The reverse direction (appearing) is governed by
	   .is-docked's own transition below instead, much faster, so it
	   shows up right as the disc starts moving down, not partway through. */
	opacity: 0;
	/* 1.4s, same as the disc's own dock motion and load.wav/Unload.wav.
	   bottom is included so the lid actually slides down the page WITH
	   the fascia's own margin-top transition (see positionPlayerLid() in
	   cd-gallery.js, which now targets a resting-vs-docked gap and lets
	   this transition carry it between them) instead of sitting already
	   at its destination while only the fold animates and the panel
	   visibly catches up underneath it. */
	transition: transform 1.4s ease, bottom 1.4s ease, opacity 0s linear 1.4s;
	/* No background/mask of its own — that all lives on ::before now (see
	   below) so the -strip sibling, a plain child of THIS element rather
	   than of ::before, is never touched by the mask that punches ::before's
	   own hole. mask-image affects an element's ENTIRE rendered subtree
	   (background, shadow, AND descendants) as one composited unit, so
	   masking this outer element directly would have erased the arm too,
	   everywhere it crossed into the hole. */
}
.crate-player-lid.is-docked {
	transform: translateX(-50%) perspective(3000px) rotateX(0deg);
	opacity: 1;
	/* Governs the undocked→DOCKED direction: opacity appears almost
	   immediately (well inside the 1.4s fold), so it's already visible
	   for the whole fold-open motion rather than only popping in once
	   docked. The slow, delayed hide is the base rule's job instead. */
	transition: transform 1.4s ease, bottom 1.4s ease, opacity 0.15s ease;
}
/* The square dark-gunmetal frame layer, sized to fill .crate-player-lid
   exactly. This is the actual fix for genuine transparency — no PNG
   needed. An overlay with a "transparent" background (the previous
   attempt, back when this rule was .crate-player-lid::before playing
   the *window's* role) only removes ITS OWN tint; it does nothing to a
   dark background painted by a separate element underneath covering the
   same area, so that stayed fully opaque regardless. mask-image instead
   punches an actual hole through THIS element's own rendering —
   background AND box-shadow — letting the docked disc (several
   z-indices further back) genuinely show through. `circle closest-side`
   makes its 100% mean "distance from centre to the box's own edge" —
   i.e. HALF the box's own width, not the full width — so a stop needs
   to be (window-radius / box-half-width)*100, not a plain inset-style
   percentage. With the box now 1.12x the disc's own diameter and a
   window meant to be 1.08x the disc's diameter (comfortably wider than
   the disc, plenty of margin so its full width is visible without being
   clipped): (1.08/1.12)*100 ≈ 96.4%.
   Centred dead-centre (50% 50%) — not nudged, because positionPlayerLid()
   in cd-gallery.js now moves the DISC itself (its docked `top`) so its
   centre coincides with this box's own centre exactly, rather than
   leaving the disc where it naturally docks and approximating the
   window's centre to chase it. */
.crate-player-lid::before {
	content: '';
	position: absolute;
	inset: 0;
	border-radius: 6%;
	background: linear-gradient(180deg, #3d4044 0%, #26282b 14%, #1b1d20 55%, #101113 100%);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.12),
		inset 0 -1px 0 rgba(0, 0, 0, 0.5),
		0 6px 14px rgba(0, 0, 0, 0.45);
	-webkit-mask-image: radial-gradient(circle closest-side at 50% 50%, transparent 0%, transparent 96.4%, black 97.2%, black 100%);
	mask-image: radial-gradient(circle closest-side at 50% 50%, transparent 0%, transparent 96.4%, black 97.2%, black 100%);
}
/* The dark arm sticking up into the window from the bottom — same dark
   gunmetal as the panel/fascia (not the transparent window), rounded off
   at its top like a stadium shape. A sibling of ::before (both direct
   children of .crate-player-lid), not a descendant of it, and later in
   the DOM, so it paints on top of the frame layer without the frame's
   own mask affecting it and without needing its own z-index. height:58%
   reaches comfortably past the disc's own centre (now dead-centre, 50%
   — see ::before above). */
.crate-player-lid-strip {
	position: absolute;
	left: 50%; bottom: 0;
	width: 10.8%; height: 53.4%;
	transform: translateX(-50%);
	border-radius: 999px 999px 0 0;
	background: linear-gradient(180deg, #3d4044 0%, #26282b 14%, #1b1d20 55%, #101113 100%);
	box-shadow:
		inset 0 1px 1px rgba(255, 255, 255, 0.15),
		inset 0 -2px 4px rgba(0, 0, 0, 0.5),
		0 0 0 1px rgba(0, 0, 0, 0.5);
}
@keyframes crateDiscIn {
	0%   { opacity: 0; transform: translate(-50%, -50%) translate3d(19%, 3%, 0) rotate(4deg); z-index: 80; }
	1%   { opacity: 1; transform: translate(-50%, -50%) translate3d(19%, 3%, 0) rotate(4deg); z-index: 80; }
	50%  { opacity: 1; transform: translate(-50%, -50%) translate3d(115%, 1.5%, 0) rotate(20deg); z-index: 80; }
	51%  { opacity: 1; transform: translate(-50%, -50%) translate3d(115%, 1.5%, 0) rotate(20deg); z-index: 520; }
	100% { opacity: 1; transform: translate(-50%, -50%) translate3d(0, 0, 0) rotate(0deg); z-index: 520; }
}
@keyframes crateDiscOut {
	0%   { opacity: 1; transform: translate(-50%, -50%) translate3d(0, 0, 0) rotate(0deg); z-index: 520; }
	49%  { opacity: 1; transform: translate(-50%, -50%) translate3d(115%, 1.5%, 0) rotate(20deg); z-index: 520; }
	50%  { opacity: 1; transform: translate(-50%, -50%) translate3d(115%, 1.5%, 0) rotate(20deg); z-index: 80; }
	99%  { opacity: 1; transform: translate(-50%, -50%) translate3d(19%, 3%, 0) rotate(4deg); z-index: 80; }
	100% { opacity: 0; transform: translate(-50%, -50%) translate3d(19%, 3%, 0) rotate(4deg); z-index: 80; }
}
.crate-disc-face {
	position: absolute;
	inset: 0;
	border-radius: 50%;
	overflow: hidden;
	background-color: #0d0e10;
	/* Blank iridescent disc, sitting under the printed label art so any
	   transparent/unprinted part of a record's cd-labels art (or a record
	   that doesn't have one yet, see .crate-disc-art below) shows real disc
	   foil instead of a flat dark fill. */
	background-image: url('../../images/blank cd background.png');
	background-size: cover;
	background-position: center;
	box-shadow: 0 22px 50px -18px rgba(0, 0, 0, 0.85), inset 0 0 0 1px rgba(255, 255, 255, 0.15);
}
/* Spin rotation itself is applied via JS (requestAnimationFrame), not a CSS
   keyframe animation — accelerating up to speed on play and coasting back
   down on stop needs real angular-velocity control frame by frame, which a
   fixed-duration CSS animation can't ramp smoothly. Lives on this inner
   face (not .crate-disc-wrap, which already has its own slide-in/out
   transform animation) so the two rotations don't fight over the same
   element's transform property. */
.crate-disc-art {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
}
/* A CD's reflective foil surface. Real CD diffraction shows a couple of
   concentrated diagonal rainbow ray-bundles radiating from the hub — not an
   even ring of colour all the way around (a conic-gradient reads as a
   colourful wheel, not a disc) — so this layers two angled spectrum bands
   plus a glossy highlight streak, blended over the printed art like the
   real thing. */
.crate-disc-sheen {
	position: absolute;
	inset: 0;
	border-radius: 50%;
	pointer-events: none;
	background:
		linear-gradient(115deg, transparent 25%, rgba(255, 255, 255, 0.45) 45%, transparent 65%),
		linear-gradient(35deg,
			transparent 0%,
			rgba(0, 160, 255, 0.24) 36%,
			rgba(0, 220, 140, 0.24) 44%,
			rgba(255, 225, 0, 0.24) 52%,
			rgba(255, 110, 180, 0.24) 60%,
			transparent 70%),
		linear-gradient(-30deg,
			transparent 15%,
			rgba(180, 90, 255, 0.18) 42%,
			rgba(255, 210, 90, 0.18) 52%,
			rgba(0, 200, 255, 0.18) 62%,
			transparent 84%);
	mix-blend-mode: overlay;
	opacity: 0.9;
}
/* The unprinted clear/foil ring around a CD's centre hub — the reference
   photo shows two concentric rings (a darker clamp edge, a lighter inset
   ring just inside it) rather than a single flat band. */
.crate-disc-hub {
	position: absolute; top: 50%; left: 50%;
	width: 26%; height: 26%;
	border-radius: 50%;
	transform: translate(-50%, -50%);
	background: radial-gradient(circle at 40% 35%, rgba(255, 255, 255, 0.9), rgba(200, 205, 210, 0.7) 45%, rgba(150, 155, 160, 0.55) 65%, rgba(190, 195, 200, 0.65) 78%, rgba(130, 135, 140, 0.6) 100%);
	box-shadow:
		0 0 0 1px rgba(0, 0, 0, 0.3),
		0 0 0 3px rgba(255, 255, 255, 0.35),
		inset 0 0 6px rgba(0, 0, 0, 0.25);
}
.crate-disc-hub .crate-rec-cat {
	/* Absolutely positioned (against .crate-disc-hub, already the nearest
	   positioned ancestor) rather than flex-aligned, so it lands at a
	   precise spot in the band between the spindle hole and the hub's
	   outer edge — centred there, not sitting over the hole itself. */
	position: absolute;
	top: 80%;
	left: 50%;
	transform: translate(-50%, -50%);
	font-size: 2cqw; /* cqw = % of .crate-stage's inline size, so this scales with the crate itself rather than sitting fixed */
	letter-spacing: 0.1em;
	color: #2a2a2a;
	white-space: nowrap;
}
.crate-disc-hole {
	position: absolute; top: 50%; left: 50%;
	width: 6%; height: 6%;
	border-radius: 50%;
	background: #050505;
	transform: translate(-50%, -50%);
	box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
	z-index: 1;
}

/* =========================
   Vintage hi-fi player
   Appears just under the stage once a disc is slid out. Hidden by default
   via max-height/opacity (not display:none) so it can transition in.

   .crate-player is purely the show/hide animator (max-height/opacity/
   overflow:hidden) — it carries no visuals of its own. .crate-player-fascia
   is the actual brushed-steel housing (background/shadow/radius) with the
   screen and button row stacked inside it at the same width, like a single
   real component front panel. Splitting these two is necessary, not just
   tidy: overflow:hidden on an element also clips that SAME element's own
   box-shadow, so the fascia's drop shadow needs to live one level in from
   the animator, with the animator padded (and negative-margin-compensated)
   to give that shadow room to render before the animator's own edge.
   ========================= */
.crate-player {
	width: min(480px, 94%);
	max-height: 0;
	opacity: 0;
	overflow: hidden;
	visibility: hidden;
	transition: max-height 0.4s ease, opacity 0.3s ease, margin-top 1.4s ease;
	margin-top: 0;
	padding: 10px;
	margin-left: -10px;
	margin-right: -10px;
}
.crate-player.is-visible {
	max-height: 240px;
	opacity: 1;
	visibility: visible;
	margin-top: 1.5em;
}
/* Same size formula as .crate-disc-wrap.is-docked (margin-top's own %
   resolves against the containing block's WIDTH per the CSS spec, which
   for both elements is the same shared-ancestor width .crate-stage's
   height is also equal to, being a square) — so this always pushes the
   fascia exactly clear of the docked disc's actual rendered bottom edge,
   plus a little breathing room, at any viewport size. */
.crate-player.is-visible.is-disc-docked {
	margin-top: calc(min(432px, 81.25%) + 1em);
}
/* Gunmetal fascia modelled on the Cyrus CD-t transport: a dark brushed-metal
   panel with a recessed green LCD and a row of flat rectangular keys
   instead of the old chrome dials. Real half-width hi-fi
   chassis (this one included) read as wide, low boxes — roughly 3:1
   width:height — so every child here is sized to hit that same squat
   proportion rather than stacking to whatever height its text needs.
   Note: body sets line-height in a fixed em (17pt-based), which INHERITS
   as an absolute px value, not a ratio — anything in here that doesn't
   reset line-height explicitly ends up ~40px tall per "line" no matter
   its font-size, which is what was making the old screen (and the fascia
   around it) far taller than the reference unit. */
.crate-player-fascia {
	display: flex;
	flex-direction: column;
	gap: 0;
	padding: 0.7em 0.9em 0.6em;
	border-radius: 0.35em;
	background: linear-gradient(180deg, #3d4044 0%, #26282b 14%, #1b1d20 55%, #101113 100%);
	box-shadow:
		0 14px 28px rgba(0, 0, 0, 0.55),
		inset 0 1px 0 rgba(255, 255, 255, 0.12),
		inset 0 -1px 0 rgba(0, 0, 0, 0.5),
		0 0 0 1px #050505;
}
.crate-player-topbar {
	display: flex;
	align-items: center;
	gap: 0.6em;
	padding-bottom: 0.5em;
	margin-bottom: 0.5em;
	border-bottom: 1px solid rgba(255, 255, 255, 0.09);
}
.crate-player-power {
	flex: 0 0 auto;
	width: 1.7em; height: 1.7em;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 50%;
	background: radial-gradient(circle at 35% 30%, #45484b, #17181a 75%);
	box-shadow:
		inset 0 1px 1px rgba(255, 255, 255, 0.18),
		inset 0 -1px 2px rgba(0, 0, 0, 0.6),
		0 1px 1px rgba(0, 0, 0, 0.4);
	color: rgba(255, 255, 255, 0.6);
	font-size: 0.62em;
	transition: box-shadow 0.2s ease, background 0.2s ease, color 0.2s ease;
}
/* Pressed-in look while the player is "powered" (see playerPowered in
   cd-gallery.js) — the highlight/shadow pair flips (heavy inset shadow at
   top instead of a highlight) so the button itself reads as pushed down,
   not just recolored. */
.crate-player.is-loaded .crate-player-power {
	background: radial-gradient(circle at 35% 30%, #26282b, #0c0d0e 75%);
	box-shadow:
		inset 0 2px 3px rgba(0, 0, 0, 0.75),
		inset 0 -1px 1px rgba(255, 255, 255, 0.1),
		0 0 3px rgba(0, 0, 0, 0.5);
	color: rgba(255, 255, 255, 0.95);
}
.crate-player-sensor {
	flex: 0 0 auto;
	width: 0.6em; height: 0.6em;
	border-radius: 50%;
	background: #040404;
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, 0.15),
		0 0 3px rgba(0, 0, 0, 0.8);
	transition: background 0.2s ease, box-shadow 0.2s ease;
}
/* Lit green while the player is "powered", dark/off otherwise. */
.crate-player.is-loaded .crate-player-sensor {
	background: radial-gradient(circle at 35% 30%, #d9ffb8, #7fdb3a 55%, #3c8f14 100%);
	box-shadow:
		inset 0 0 0 1px rgba(255, 255, 255, 0.5),
		0 0 6px 2px rgba(140, 255, 90, 0.85);
}
.crate-player-readout {
	flex: 1 1 auto;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.7em;
	min-width: 0;
	overflow: hidden;
	line-height: 1.2;
	font-family: 'LCDMono2', 'Courier New', monospace;
	/* Unlit LCD look by default — a dim, barely-legible ghost of the
	   segments rather than the backlit green glass, which only switches
	   on once the player is actually powered (see .is-loaded below). */
	color: rgba(90, 105, 70, 0.45);
	background: #10120d;
	padding: 0.45em 0.8em;
	border-radius: 0.3em;
	/* Recessed glass, then a dark inner bezel edge and a light outer bezel
	   edge — a physical frame built from layered shadows rather than extra
	   markup, sitting flush inside the fascia's own padding. */
	box-shadow:
		inset 0 2px 4px rgba(0, 0, 0, 0.5),
		0 0 0 1px rgba(255, 255, 255, 0.05);
	transition: color 0.3s ease, background 0.3s ease, box-shadow 0.3s ease;
}
.crate-player.is-loaded .crate-player-readout {
	color: #2b2c28;
	background: #9dff57;
	box-shadow:
		inset 0 2px 4px rgba(0, 0, 0, 0.35),
		0 0 6px rgba(157, 255, 87, 0.35),
		0 0 0 1px rgba(255, 255, 255, 0.07);
}
.crate-readout-title {
	flex: 1 1 auto;
	min-width: 0;
	font-weight: 700;
	font-size: 1.05em;
	letter-spacing: 0.08em;
	text-align: left;
	/* pre (not nowrap) so the marquee's gap of consecutive spaces renders at
	   its full width instead of being collapsed to one space — otherwise
	   the crawl jumps unevenly right at the point it loops back around. */
	white-space: pre;
	overflow: hidden;
}
.crate-readout-time {
	flex: 0 0 auto;
	font-size: 0.95em;
	letter-spacing: 0.1em;
	color: inherit;
	white-space: nowrap;
	transition: color 0.3s ease;
}
.crate-player.is-loaded .crate-readout-time {
	color: rgba(43, 44, 40, 0.7);
}
@media (prefers-reduced-motion: no-preference) {
	.crate-readout-time.is-blinking {
		animation: crateTimeBlink 1s steps(1) infinite;
	}
}
@keyframes crateTimeBlink {
	50% { opacity: 0.25; }
}
.crate-player-panel {
	width: 100%;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.35em;
	margin-top: 1.5em;
}
.crate-player-btn {
	position: relative;
	flex: 1 1 0;
	height: auto;
	aspect-ratio: 3 / 1;
	margin: 0;
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border-radius: 0.3em;
	border: 0;
	cursor: pointer;
	background: linear-gradient(180deg, #4b4e51 0%, #303234 45%, #242628 55%, #1a1c1e 100%);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.18),
		inset 0 -1px 1px rgba(0, 0, 0, 0.5),
		0 1px 2px rgba(0, 0, 0, 0.4);
	font-size: 0.6em;
	text-transform: none;
	letter-spacing: normal;
	transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
}
.crate-player-btn i {
	/* Printed as a label above the key, like the CD-t's silkscreened
	   icons sitting on the fascia above each blank button, rather than
	   drawn on the button face itself. */
	position: absolute;
	left: 50%;
	bottom: 100%;
	margin-bottom: 0.4em;
	/* Outline glyphs to match the CD-t's thin white line icons — Font
	   Awesome's free set only ships these as solid (900-weight) shapes, with
	   no lighter/regular version of these particular glyphs available, so
	   the fill is dropped and the thinnest legible stroke traces the same
	   glyph path instead — as light as this trick can go before the icon
	   starts breaking up. */
	color: transparent;
	-webkit-text-stroke: 0.6px rgba(255, 255, 255, 0.9);
	text-stroke: 0.6px rgba(255, 255, 255, 0.9);
	/* Sized up (not stretched — scaleX distorted the glyphs) so each icon
	   still reads clearly above its key at native, correct aspect ratio. */
	font-size: 1.6em;
	transform: translateX(-50%);
	transform-origin: center bottom;
}
.crate-player-btn:hover:not(:disabled) {
	background: linear-gradient(180deg, #56595c 0%, #383a3c 45%, #292b2d 55%, #1e2022 100%);
}
.crate-player-btn:active:not(:disabled) {
	transform: translateY(1px);
	box-shadow: inset 0 2px 3px rgba(0, 0, 0, 0.6);
}
.crate-player-btn:disabled {
	opacity: 0.35;
	cursor: not-allowed;
}
.crate-player-btn.is-active {
	background: linear-gradient(180deg, #3f5c40 0%, #2c4a2d 45%, #223a23 55%, #182a19 100%);
	box-shadow:
		inset 0 1px 0 rgba(255, 255, 255, 0.18),
		inset 0 -1px 1px rgba(0, 0, 0, 0.5),
		0 0 8px rgba(157, 255, 87, 0.35);
}
.crate-player-btn.is-active i {
	-webkit-text-stroke: 0.6px rgba(157, 255, 87, 0.95);
	text-stroke: 0.6px rgba(157, 255, 87, 0.95);
}
/* No wrap breakpoint below this — .crate-player-panel's flex:1 1 0 buttons
   (aspect-ratio-driven height, icon positioned/sized off the button's own
   box) already just keep scaling down together as a single row all the
   way to the ~320px viewport floor this site supports; wrapping them into
   rows here was what caused the buttons to visibly rearrange. */

.crate-details {
	text-align: center;
	max-width: 360px;
}
.crate-details h3 {
	font-weight: 600;
	font-size: 26px;
	margin: 0 0 8px;
	color: var(--c-heading);
	transition: opacity 0.25s ease;
}
.crate-meta {
	display: flex;
	justify-content: center;
	gap: 14px;
	font-size: 11px;
	letter-spacing: 0.08em;
	color: var(--c-muted);
	text-transform: uppercase;
}
.crate-meta span:not(:last-child)::after {
	content: '\00b7';
	margin-left: 14px;
	color: rgba(255, 255, 255, 0.3);
}
.crate-tab-row {
	margin-top: 18px;
	display: flex;
	align-items: center;
	gap: 10px;
	justify-content: center;
}
.crate-tab {
	font-size: 11px;
	letter-spacing: 0.1em;
	color: var(--c-accent-text);
	background: var(--c-accent);
	padding: 5px 12px;
	border-radius: 3px;
	font-weight: 700;
}
.crate-track {
	position: relative;
	width: 140px;
	height: 2px;
	background: rgba(255, 255, 255, 0.12);
	border-radius: 2px;
}
.crate-track-fill {
	position: absolute; left: 0; top: 0; bottom: 0;
	background: var(--c-accent);
	border-radius: 2px;
	transition: width 0.4s ease;
}
.crate-hint {
	font-size: 10px;
	letter-spacing: 0.1em;
	color: var(--c-muted);
	opacity: 0.7;
	text-transform: uppercase;
}
.crate-listen-link {
	display: inline-block;
	margin-top: 0.5em;
}

@media screen and (max-width: 480px) {
	.crate-edge-btn { display: none; }
}

@media (prefers-reduced-motion: reduce) {
	.crate-card { transition: none !important; }
}

/* ==========================================================================
   Liner Notes (lyrics/sleeve-notes notebook)
   ========================================================================== */

.notebook {
	display: flex;
	align-items: stretch;
	justify-content: center;
	width: 100%;
	aspect-ratio: 15 / 21;
	margin: 1.5em auto 0.75em;
}
/* Left (index) is deliberately narrower than right (lyrics) — the index is
   just a short numbered list, while the lyrics page needs the extra width
   for a comfortable line length. Both stretch to the same height (set by
   .notebook's own aspect-ratio above) so they still read as one open book. */
.notebook-page-left,
.notebook-page-wrap {
	height: 100%;
	/* Lets .notebook-index-title/.notebook-title use cqw so they scale
	   with the page itself (same technique as .crate-stage elsewhere),
	   not the viewport. */
	container-type: inline-size;
}
.notebook-page-left {
	flex: 1.5 1 0;
	/* Flex items default to a content-based min-width, which would let
	   an unbreakable long title force this column (and the whole
	   .notebook row) wider than intended instead of actually shrinking. */
	min-width: 0;
}
.notebook-page-wrap {
	flex: 2.5 1 0;
	position: relative;
}
/* Two stacked right-hand pages (see liner-notes.js): the outgoing one
   slides off to the right, revealing the incoming one already sitting
   underneath rather than a 3D page-flip. */
.notebook-page-wrap .notebook-page-right {
	position: absolute;
	inset: 0;
}
/* The spine between the two open pages — a dark grey elastic closure band
   (like the strap built into some notebooks), shared by both pages rather
   than duplicated on each. Fine vertical ribbing simulates the woven
   texture of the elastic; the base gradient is lighter in the middle and
   darker at the edges for a rounded, cylindrical band profile. */
.notebook-spine {
	flex: 0 0 auto;
	width: clamp(20px, 4%, 36px);
	background:
		repeating-linear-gradient(
			to right,
			rgba(255, 255, 255, 0.07) 0, rgba(255, 255, 255, 0.07) 1px,
			rgba(0, 0, 0, 0.15) 1px, rgba(0, 0, 0, 0.15) 2px,
			transparent 2px, transparent 4px
		),
		linear-gradient(
			to right,
			#2b2b2d 0%, #4a4a4d 20%, #5c5c60 50%, #4a4a4d 80%, #2b2b2d 100%
		);
	z-index: 1;
}
/* The page itself: aged paper with handwritten titles/lyrics. Ruled lines
   live on .notebook-lyrics itself (below), sized in em so they line up
   with its own line-height instead of a page-wide fixed spacing that
   wouldn't match the text. */
.notebook-page {
	position: relative;
	width: 100%;
	height: 100%;
	overflow: hidden;
	background: linear-gradient(165deg, #f4ecd8 0%, #e8dfc4 100%);
	box-shadow: 0 18px 40px -12px rgba(0, 0, 0, 0.6);
	backface-visibility: hidden;
}
.notebook-page-left {
	border-radius: 0.3em 0 0 0.3em;
	box-shadow:
		0 18px 40px -12px rgba(0, 0, 0, 0.6),
		inset -10px 0 14px -12px rgba(0, 0, 0, 0.5);
}
.notebook-page-right {
	border-radius: 0 0.3em 0.3em 0;
	box-shadow:
		0 18px 40px -12px rgba(0, 0, 0, 0.6),
		inset 10px 0 14px -12px rgba(0, 0, 0, 0.5);
}
.notebook-page-inner {
	position: absolute;
	inset: 1% 3%;
	display: flex;
	flex-direction: column;
	overflow: hidden;
	/* Overrides the site-wide body line-height (1.75em) that every
	   notebook element would otherwise inherit (titles, heading row,
	   album labels). */
	line-height: 1;
}
/* Left-hand index page — a plain (printed, not handwritten) table of
   contents, one album at a time, scrollable since the full catalogue runs
   well past a single page's height. */
.notebook-index-title {
	font-family: 'Caveat', cursive;
	font-weight: 700;
	/* vw-based clamp (not a fixed size) so this shrinks on narrow
	   viewports instead of crushing/wrapping in the notebook's narrow
	   columns; vw (not cqw) keeps it matching the same-sized title on
	   the right-hand page despite the two pages having different
	   container widths. */
	font-size: clamp(1.1rem, 6vw, 2rem);
	color: #2a2318;
	margin: 0 0 0.5em;
	flex: 0 0 auto;
}
.notebook-index-list {
	flex: 1 1 auto;
	overflow-y: auto;
	/* Explicit, not left to default with overflow-y set (which would
	   otherwise compute to auto and add its own horizontal scrollbar) —
	   long titles should wrap (see overflow-wrap below), never scroll. */
	overflow-x: hidden;
}
.notebook-index-album {
	margin-bottom: 0.4em;
}
.notebook-index-album h4 {
	margin: 0 0 0.5em;
	text-align: left;
}
/* Reset the site-wide button chrome (main.css ~line 604 sets its own
   color/box-shadow directly on <button>, which otherwise wins over the
   inherited ink color and renders these as accent-colored/"white"). */
.notebook-index-notes {
	display: block;
	width: 100%;
	background: none;
	border: 0;
	box-shadow: none;
	padding: 0;
	margin: 0;
	border-radius: 0;
	text-align: left;
	text-transform: none;
	letter-spacing: normal;
	font-family: 'Caveat', cursive;
	font-weight: 700;
	/* vw-based clamp so album titles shrink on narrow viewports instead
	   of crowding the narrow index column — same technique as the
	   index/song titles above. */
	font-size: clamp(0.75rem, 3.5vw, 1.1em);
	line-height: 1;
	color: #332a1c;
	cursor: pointer;
	overflow-wrap: anywhere;
}
.notebook-index-notes::after {
	content: '▸';
	display: inline-block;
	margin-left: 0.4em;
	font-size: 0.8em;
	transition: transform 0.15s ease;
}
.notebook-index-album.is-open .notebook-index-notes::after {
	transform: rotate(90deg);
}
.notebook-index-album ol {
	list-style: decimal;
	margin: 0;
	padding-left: 0.6em;
	display: none;
}
.notebook-index-album.is-open ol {
	display: block;
}
.notebook-index-track {
	display: inline;
	margin: 0;
	padding: 0;
	border: 0;
	background: none;
	box-shadow: none;
	font-family: 'Caveat', cursive;
	font-weight: 500;
	/* vw-based clamp so song titles shrink on narrow viewports instead
	   of crowding the narrow index column — same technique as the
	   album titles above. */
	font-size: clamp(0.75rem, 3.5vw, 1.1em);
	line-height: 1;
	color: #332a1c;
	text-align: left;
	text-transform: none;
	letter-spacing: normal;
	cursor: pointer;
	border-bottom: 1px dotted transparent;
	overflow-wrap: anywhere;
}
.notebook-index-track:hover {
	border-bottom-color: rgba(50, 42, 28, 0.5);
}
.notebook-index-track.is-selected {
	font-weight: 600;
	color: #7a2d1f;
	border-bottom-color: #7a2d1f;
}
.notebook-heading {
	display: flex;
	align-items: baseline;
	gap: 0.6em;
	font-size: 11px;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(50, 42, 28, 0.6);
	flex: 0 0 auto;
}
.notebook-heading .notebook-album,
.notebook-heading .notebook-track-no {
	flex: 0 0 auto;
	white-space: nowrap;
}
.notebook-title {
	font-family: 'Caveat', cursive;
	font-weight: 700;
	/* vw-based clamp (not a fixed size) so this shrinks on narrow
	   viewports instead of crushing/wrapping in the notebook's narrow
	   columns; vw (not cqw) keeps it matching the same-sized title on
	   the right-hand page despite the two pages having different
	   container widths. */
	font-size: clamp(1.1rem, 6vw, 2rem);
	letter-spacing: normal;
	text-transform: none;
	color: #2a2318;
	margin: 0 0 0.5em;
	flex: 1 1 auto;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}
.notebook-lyrics {
	font-family: 'Caveat', cursive;
	font-weight: 500;
	font-size: clamp(1.2em, 4.4cqw, 1.5em);
	line-height: 1;
	color: #332a1c;
	white-space: pre-line;
	overflow-y: auto;
	flex: 1 1 auto;
	/* Ruled lines sized in em, so each rule sits at the bottom of its own
	   line box (line-height: 1 above means a line box is exactly one em
	   tall) — the text reads as actually written on the lines instead of
	   a page-wide pattern that happened not to match. background-attachment:
	   local keeps the lines scrolling with the text, not the viewport. */
	background: repeating-linear-gradient(
		to bottom,
		transparent 0, transparent calc(1em - 1px),
		rgba(70, 60, 40, 0.25) calc(1em - 1px), rgba(70, 60, 40, 0.25) 1em
	);
	background-attachment: local;
}
.notebook-lyrics.is-placeholder {
	font-family: var(--font-family);
	font-style: italic;
	font-size: 0.85em;
	line-height: 1;
	color: rgba(50, 42, 28, 0.65);
}
@media (prefers-reduced-motion: reduce) {
	.notebook-page { transition: none !important; }
}
