/*
 * LEAFLET.CSS
 * .jm-leaflet: the mix view (pop-up and page). Three pages: Article panel | blocks + rating bar | Comments panel.
 * Desktop (1000px and wider) shows all three as one neat rectangle; narrower screens show one page at a time with a pager.
 * Blocks use the mix's cover colours (--jm-tone-bg / --jm-tone-ink); the two panels use them swapped.
 */


/* ============================================================
 * 1. SIZES (one square block = --jm-block)
 * The leaflet is 4 blocks wide; the side panels are 1 block wide
 * and the stream strip + 2 blocks + the rating bar tall, so everything lines up.
 * ============================================================ */

.jm-leaflet {
	--jm-rating-height: 56px;
	--jm-strip-height: 34px;
	--jm-block: max(var(--jm-block-unit-min), min(calc((92vh - var(--jm-rating-height) - var(--jm-strip-height)) / 2), calc(96vw / 4), var(--jm-block-unit-max)));

	position: relative;
	background: var(--jm-tone-bg);
	color: var(--jm-tone-ink);
}


/* ============================================================
 * 2. CLOSE BUTTON (top-right corner) AND PAGER BAR (phones)
 * ============================================================ */

.jm-leaflet__close {
	position: absolute;
	top: var(--jm-space-2);
	right: var(--jm-space-3);
	z-index: 3;
	background: none;
	border: 0;
	padding: 0 var(--jm-space-1);
	color: var(--jm-tone-bg);            /* sits on the Comments panel (swapped colours) */
	font-size: 34px;
	font-weight: 300;
	line-height: 1;
	text-decoration: none;
	cursor: pointer;
}

.jm-leaflet__pager {
	display: none;                        /* desktop: no pager, all pages visible */
}

/* The wizard's wrapper round Article + Front: on desktop it steps aside, so the three columns are unchanged
   (section 10 makes it one page on phones). */
.jm-leaflet__stack {
	display: contents;
}


/* ============================================================
 * 3. THE THREE PAGES (desktop: side by side)
 * ============================================================ */

.jm-leaflet__pages {
	display: grid;
	grid-template-columns: var(--jm-block) calc(var(--jm-block) * 2) var(--jm-block);
	height: calc(var(--jm-strip-height) + var(--jm-block) * 2 + var(--jm-rating-height));
}

/* A mix being made in the wizard has no Comments page: two columns. */
.jm-leaflet--no-comments .jm-leaflet__pages {
	grid-template-columns: var(--jm-block) calc(var(--jm-block) * 2);
}

.jm-leaflet__main {
	display: flex;
	flex-direction: column;
}


/* ============================================================
 * 4. THE BLOCK GRID AND THE BLOCK COMPONENT
 * Every block: .jm-block + .jm-block--{type}; square.
 * Flavour blocks (parts/flavour.php): Front .jm-block .jm-block--flavour .jm-block--{type};
 * Article and Tray .jm-piece .jm-piece--{type} (type key with "-" for "_", e.g. fav-track).
 * ============================================================ */

.jm-leaflet__grid {
	display: grid;
	grid-template-columns: var(--jm-block) var(--jm-block);
	grid-template-rows: var(--jm-strip-height) var(--jm-block) var(--jm-block);   /* strip, then the 2x2 */
}

/* ---------- The stream strip (Nick, 19 Oct): tiny service buttons and a "+" ---------- */
.jm-strip {
	grid-column: 1 / -1;
	display: flex;
	align-items: center;
	gap: var(--jm-space-2);
	height: var(--jm-strip-height);
	padding: 0 var(--jm-space-3);
	background: color-mix(in srgb, var(--jm-tone-ink) 10%, var(--jm-tone-bg));
	color: var(--jm-tone-ink);
	cursor: pointer;
}

.jm-strip .jm-service {                    /* the same badge as on the cover, but in a row */
	position: static;
	width: 22px;
	height: 22px;
	font-size: 10px;
}

.jm-strip__service { display: block; line-height: 0; }
.jm-strip__none { font-size: var(--jm-text-xs); opacity: 0.7; }

.jm-strip__more {
	margin-left: auto;
	font-size: 20px;
	line-height: 1;
	opacity: 0.8;
}

/* Put on shelf (Stage 7, Brief D4): a shared .jm-btn (button.css); only its place is set here. */
.jm-strip__shelf { max-width: 9em; }
.jm-strip .jm-btn--secondary { color: inherit; }   /* outline in the strip's own ink */

.jm-block--cover[data-jm-cover-open] { cursor: zoom-in; }

.jm-block {
	position: relative;
	overflow: hidden;
	background: var(--jm-tone-bg);
	color: var(--jm-tone-ink);
}

/* (The entrance animation lives in section 10.) */

/* The words in a Front flavour square fit it at any size (Nick, 30-31 Oct). The square is a container, so its words
   are sized from its width (--jm-block-text-*, 00-tokens.css); they step down as the block says more
   (jm-block--len-m / -l, parts/flavour.php). Spacing is a share of the square too (padding % = of its width). */
.jm-block--flavour {
	container-type: inline-size;
	--jm-block-text: var(--jm-block-text-s);
}

.jm-block--len-m { --jm-block-text: var(--jm-block-text-m); }
.jm-block--len-l { --jm-block-text: var(--jm-block-text-l); }
.jm-block--flavour.jm-block--len-l:not(.jm-block--text-bottom.jm-block--framed) { padding: var(--jm-block-pad-l); }

.jm-block--flavour .jm-quote,
.jm-block--flavour .jm-tagline,
.jm-block--flavour .jm-occasion,
.jm-block--flavour .jm-fav,
.jm-block--flavour .jm-vibe-one { font-size: var(--jm-block-text); }

.jm-block--flavour .jm-occasion__text,
.jm-block--flavour .jm-fav__song { font-size: 1em; }

.jm-block--flavour .jm-lead,
.jm-block--flavour .jm-quote cite { font-size: var(--jm-block-text-small); }   /* the small lines: one size, whatever the length */


/* ============================================================
 * 5. BLOCK TYPES
 * ============================================================ */

/* ---------- 5a. Cover ---------- */
.jm-block__img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/* ---------- 5b. Vibes (the site's fill for an empty Leaflet A) ---------- */
.jm-block--vibes {
	display: flex;
	padding: var(--jm-block-pad);
}

.jm-vibes {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--jm-space-2);
	margin: 0;
	padding: 0;
	list-style: none;
}

/* Favourite track (8.4a): "featuring {song} by {artist}". PLACEHOLDER look ("Flavour block styling", styling phase). */
.jm-block--fav {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--jm-block-pad);
	text-align: center;
}

.jm-fav {
	margin: 0;
	line-height: 1.3;
}

/* The lead line: the small uppercase words before a block's main text ("featuring", "by", "Good for").
   One look for every block that has one (Flavour Blocks spec, T1). */
.jm-lead {
	font-size: var(--jm-text-xs);
	font-style: normal;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	opacity: 0.75;
}

.jm-fav__song {
	display: block;
	margin: var(--jm-space-1) 0;
	font-family: var(--jm-font-display);
	font-size: var(--jm-text-l);
	font-weight: 700;
}

.jm-fav--line { margin: var(--jm-space-3) 0; text-align: center; }
.jm-fav--line .jm-fav__song { display: inline; margin: 0; font-size: var(--jm-text-m); }

/* Occasion (Flavour Blocks spec, section 1): the small lead line ("Good for", .jm-lead) over one short sentence.
   Front: floats in the middle of the square with generous space round it. Article: sized like every Article piece
   (7a2), with a little less side padding so the sentence sits in fewer lines. */
.jm-block--occasion {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--jm-block-pad);
	text-align: center;
}

.jm-occasion {
	margin: 0;
	line-height: 1.35;
}

.jm-occasion__lead {
	display: block;
	margin-bottom: var(--jm-space-2);
}

.jm-occasion__text {
	font-family: var(--jm-font-display);
	font-size: var(--jm-text-l);
	font-weight: 600;
}

/* Media (spec section 4): a small description (.jm-helper) over one button, centred. Front: in the middle of the
   square with generous space; Article: the standard piece (7a2). The pair is one unit, so a frame hugs both. */
.jm-block--media {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--jm-block-pad);
	text-align: center;
}

.jm-media {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: var(--jm-space-3);
	min-width: 0;              /* never wider than the square: a long button shortens with "…" instead */
}

.jm-media__desc { margin: 0; }
.jm-media__btn {
	max-width: 100%;
	overflow: hidden;
	text-overflow: ellipsis;   /* the words stay on one line in the pill */
	white-space: nowrap;
}

.jm-piece--occasion { text-align: center; }
.jm-piece--occasion .jm-occasion__text { font-size: var(--jm-text-m); }

/* Real Humans badge on the tracklist (Brief D4), ported from the old site's "AI free" sticker:
 * two small lines in a soft tinted box, pinned to the block's bottom-right corner. It sits OUTSIDE
 * the scrolling list (.jm-tracklist-scroll), so it never scrolls with the tracks. */
.jm-humans {
	position: absolute;
	right: var(--jm-space-2);
	bottom: var(--jm-space-2);
	z-index: 2;
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: var(--jm-space-1) var(--jm-space-2);
	border-radius: var(--jm-radius-s);
	/* Frosted glass, so tracks scrolling underneath don't clash with the words (Nick, 21 Oct). */
	background: color-mix(in srgb, var(--jm-tone-bg) 55%, transparent);
	-webkit-backdrop-filter: blur(var(--jm-glass-blur));
	backdrop-filter: blur(var(--jm-glass-blur));
	color: inherit;
	font-size: var(--jm-text-xxs);
	line-height: 1.2;
	letter-spacing: 0.03em;
	text-transform: uppercase;
	pointer-events: none;
	transform: scale(0.8);              /* 0.8 of its size (Nick, 21 Oct), shrinking into the corner */
	transform-origin: bottom right;
}

.jm-humans__line1 { font-weight: 400; }
.jm-humans__line2 { font-weight: 700; }


/* One vibe on its own: a single styled word (PLACEHOLDER look, to tweak in the styling pass). */
.jm-vibe-one {
	margin: auto;
	font-family: var(--jm-font-display);
	font-size: var(--jm-text-l);
	font-weight: 700;
	letter-spacing: 0.14em;
	text-align: center;
	text-transform: uppercase;
}

.jm-vibe-one--line { margin: var(--jm-space-3) 0; }

/* Vibe tags in the article (or the Tray): one centred, wrapping row. */
.jm-vibes-line { margin: var(--jm-space-3) 0; }

.jm-vibes--line {
	flex-direction: row;
	flex-wrap: wrap;
	gap: var(--jm-space-2) var(--jm-space-4);
}

.jm-tag--vibe {
	font-size: var(--jm-text-s);
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
}

/* ---------- 5c. Tracklist ----------
 * The block holds still; the list scrolls inside .jm-tracklist-scroll, so the Real Humans badge stays in the corner. */
.jm-block--tracklist {
	display: flex;
	flex-direction: column;
	overflow: hidden;
	padding: 0;
}

.jm-tracklist-scroll {
	flex: 1;
	min-height: 0;
	overflow-y: auto;
	padding: var(--jm-space-2) var(--jm-space-4);
	touch-action: pan-y;
}

/* With the badge: room at the bottom, so the last track scrolls clear of it. */
.jm-block--humans .jm-tracklist-scroll { padding-bottom: calc(var(--jm-space-2) * 6); }

.jm-tracklist {
	margin: 0;
	padding: 0;
	list-style: none;
}

.jm-track {
	display: grid;
	grid-template-columns: 2.25rem 1fr auto;
	align-items: center;
	gap: var(--jm-space-2);
	padding: var(--jm-space-3) 0;
	border-bottom: 1px solid color-mix(in srgb, var(--jm-tone-ink) 16%, transparent);
	font-size: var(--jm-text-s);
	line-height: 1.35;
}

.jm-track__number {
	font-size: var(--jm-text-xs);
	opacity: 0.65;
}

.jm-track__artist {
	font-weight: 700;
}

.jm-track__heart {
	background: none;
	border: 0;
	padding: 0;
	color: inherit;
	opacity: 0.85;
	cursor: pointer;
}

.jm-track__heart:disabled {
	cursor: default;
	opacity: 0.35;
}

/* Hearted: the heart fills, with a tiny pop as it does. */
.jm-track__heart[aria-pressed="true"] { opacity: 1; }
.jm-track__heart[aria-pressed="true"] svg path { fill: currentColor; }
.jm-track__heart.is-popping svg { animation: jm-heart-pop 280ms var(--jm-ease-out); }

@keyframes jm-heart-pop {
	50% { transform: scale(1.3); }
}

@media (prefers-reduced-motion: reduce) {
	.jm-track__heart.is-popping svg { animation: none; }
}

/* ---------- 5d. Play button and service badge on the cover (the Play block retired, 19 Oct) ---------- */
.jm-service {
	position: absolute;
	top: var(--jm-space-3);
	right: var(--jm-space-3);
	z-index: 1;
	display: grid;
	place-items: center;
	width: 26px;
	height: 26px;
	border-radius: 50%;
	background: var(--jm-colour-chip);
	color: var(--jm-colour-dark-1);
	font-size: var(--jm-text-xs);
	font-weight: 700;
}

/* A real logo (assets/icons/{service}.svg) instead of the letter: one colour, sized to the badge. */
.jm-service--logo svg {
	width: 58%;
	height: 58%;
	display: block;
}

.jm-cover__play {
	position: absolute;
	right: var(--jm-space-3);
	bottom: var(--jm-space-3);
	z-index: 1;
	box-shadow: var(--jm-shadow-2);
}

/* ---------- 5e. Flavour blocks in the main leaflet (squares) ---------- */

/* A block's background (parts/flavour.php; Nick, 29-31 Oct): a texture filling the square, the words on top in a
   frame. Front squares only. Strengths are tokens (00-tokens.css section 7).
     .jm-block__bg           a picture filling the square (the Image block's own picture: as it is)
     .jm-block__bg--texture  a text block's background, faded
     .jm-block__bg--cover    the cover art in its own colours, zoomed so Front A and B show the two quarters beside
                             the cover block and meet at its centre: A (top right) the top-right quarter, B (bottom
                             left) the bottom-left; stacked on phones, A above B, both centred
     .jm-block__bg--image    a picture, greyscale and toned into the block's colour (like the panels' texture) */
.jm-block__bg {
	position: absolute;
	inset: 0;
	background-size: cover;
	background-position: center;
}

.jm-block--backdrop { isolation: isolate; }   /* the toned picture blends with its own block only */

.jm-block__bg--cover {
	--zoom: var(--jm-block-bg-cover-zoom);
	--near: calc((var(--zoom) / 2 - 1) / (var(--zoom) - 1) * 100%);   /* the cover's centre at the block's edge */
	--far:  calc((var(--zoom) / 2) / (var(--zoom) - 1) * 100%);       /* ... at its other edge */
	opacity: var(--jm-block-bg-cover-opacity);
	background-size: calc(var(--zoom) * 100%);
}

.jm-block__bg--a { background-position: var(--far) var(--near); }    /* centre at the bottom-left corner */
.jm-block__bg--b { background-position: var(--near) var(--far); }    /* centre at the top-right corner */

.jm-block__bg--image {
	opacity: var(--jm-block-bg-image-opacity);
	filter: grayscale(1);
	mix-blend-mode: var(--jm-panel-texture-blend);
}

/* The text over a picture: the mix's own colour, pushed out of the midtones so it reads (an inverted leaflet's text
   is the cover's average colour, often a midtone). Plain blocks keep the mix's colours as they are. */
.jm-block--tint-light {
	color: color-mix(in srgb, var(--jm-tone-ink), #000 var(--jm-block-bg-ink-darken));
}

.jm-block--tint-dark {
	color: color-mix(in srgb, var(--jm-tone-ink), #fff var(--jm-block-bg-ink-lighten));
}

/* The frame (always, over a picture): a solid panel behind the words, the opposite extreme to the text: the block's
   own colour pushed light under dark text, pushed dark under light text, at --jm-block-bg-frame. Square corners
   follow --jm-radius-block. */
.jm-block--framed {
	--jm-frame: color-mix(in srgb, var(--jm-tone-bg), #fff var(--jm-block-bg-ink-lighten));
}

.jm-block--framed.jm-block--tint-dark {
	--jm-frame: color-mix(in srgb, var(--jm-tone-bg), #000 var(--jm-block-bg-ink-darken));
}

.jm-block--framed > :not(.jm-block__bg):not(.jm-swap) {
	flex: 0 1 auto;                     /* hug the words, not the whole square (the vibe list would stretch) */
	align-self: center;
	max-width: 100%;
	margin: auto;
	padding: var(--jm-block-frame-pad);
	border-radius: var(--jm-radius-block);
	background: color-mix(in srgb, var(--jm-frame) var(--jm-block-bg-frame), transparent);
}

/* Style text: bottom (the block's editor). Over a picture the frame becomes a full-width banner along the bottom;
   on a plain block the words simply sit at the bottom. */
.jm-block--text-bottom { align-items: flex-end; }
.jm-block--text-bottom .jm-vibes { justify-content: flex-end; }

.jm-block--text-bottom.jm-block--framed { padding: 0; }

.jm-block--text-bottom.jm-block--framed > :not(.jm-block__bg):not(.jm-swap) {
	flex: 1 1 100%;
	align-self: flex-end;
	margin: 0;
	border-radius: 0;
	padding: var(--jm-block-frame-pad);
}

/* The block's content sits above the picture and tint (the swap icon has its own place). */
.jm-block--backdrop > :not(.jm-block__bg):not(.jm-swap) {
	position: relative;
	z-index: 1;
}

/* Small print inside a leaflet (.jm-helper, 10-base.css): the mix's own ink, softened, not the site's grey,
   so it reads on any cover colour. */
.jm-leaflet .jm-helper,
.jm-tray__item .jm-helper {
	color: inherit;
	opacity: 0.75;
}

/* Quote: small bold italic text between big quotation marks. */
.jm-block--quote,
.jm-block--tagline {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--jm-block-pad);
	text-align: center;
}


.jm-quote {
	position: relative;
	z-index: 1;
	margin: 0;
	font-size: var(--jm-text-m);
	font-style: italic;
	font-weight: 700;
	line-height: 1.4;
}

.jm-quote p { margin: 0; }

.jm-quote p::before,
.jm-quote p::after {
	display: block;
	height: 0.5em;
	font-family: Georgia, serif;
	font-size: 3em;
	line-height: 1;
	opacity: 0.5;
}

.jm-quote p::before { content: "\201C"; margin-bottom: 0.15em; }
.jm-quote p::after  { content: "\201D"; margin-top: 0.35em; }

.jm-quote cite {
	display: block;
	margin-top: var(--jm-space-3);
	font-size: var(--jm-text-xs);
	font-style: normal;
	font-weight: 500;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	opacity: 0.8;
}

/* Tagline: one big line. */
.jm-tagline {
	margin: 0;
	font-family: var(--jm-font-display);
	font-size: var(--jm-text-l);
	font-weight: 600;
	line-height: 1.3;
}

/* Picture (Image or Back cover, parts/flavour.php): the picture fills the square as it is (no fade, no tone). The
   Image's caption is a small line (.jm-lead, bold) in the shared frame (5e), along the bottom by default or in the
   middle; Invert this block swaps the frame's colours (Nick, 31 Oct). */
.jm-block--image,
.jm-block--back-cover {
	display: flex;
	align-items: center;
	justify-content: center;
	padding: var(--jm-block-pad);
	text-align: center;
}

.jm-block__caption {
	position: relative;
	z-index: 1;
	margin: 0;
	font-weight: 700;
}

/* ============================================================
 * 6. RATING BAR (under the blocks)
 * ============================================================ */

.jm-rating--bar {
	display: flex;
	align-items: center;
	gap: var(--jm-space-4);
	height: var(--jm-rating-height);
	padding: 0 var(--jm-space-4);
	background: var(--jm-colour-light-1);
	color: var(--jm-colour-dark-1);
}

.jm-rating__label {
	font-size: var(--jm-text-s);
	font-weight: 600;
	white-space: nowrap;
}

.jm-rating__slider {
	flex: 1;
	accent-color: var(--jm-colour-rating-0);
	cursor: pointer;
}

.jm-rating__slider:disabled { cursor: default; opacity: 0.5; }

/* The rating name sits at a fixed width, so the slider doesn't jump as the words change. */
.jm-rating--bar .jm-rating__label {
	min-width: 11em;
	text-align: left;
}

/* The slider takes the colour of the rating it's on (0 = not rated). */
.jm-rating--bar[data-rating="1"] .jm-rating__slider { accent-color: var(--jm-colour-rating-1); }
.jm-rating--bar[data-rating="2"] .jm-rating__slider { accent-color: var(--jm-colour-rating-2); }
.jm-rating--bar[data-rating="3"] .jm-rating__slider { accent-color: var(--jm-colour-rating-3); }
.jm-rating--bar[data-rating="4"] .jm-rating__slider { accent-color: var(--jm-colour-rating-4); }
.jm-rating--bar[data-rating="5"] .jm-rating__slider { accent-color: var(--jm-colour-rating-5); }
.jm-rating--bar[data-rating="6"] .jm-rating__slider { accent-color: var(--jm-colour-rating-6); }
.jm-rating--bar[data-rating="7"] .jm-rating__slider { accent-color: var(--jm-colour-rating-7); }

.jm-rating--bar.is-saving .jm-rating__label { opacity: 0.6; }
.jm-rating--bar.is-error .jm-rating__label  { color: var(--jm-colour-scale-1);   /* the same red as error notices */ }

/* Phones: the name above, the slider full width under it would cost height, so the name just shrinks. */
@media (max-width: 480px) {
	.jm-rating--bar { gap: var(--jm-space-2); padding: 0 var(--jm-space-3); }
	.jm-rating--bar .jm-rating__label { min-width: 8.5em; font-size: var(--jm-text-xs); }
}


/* ============================================================
 * 7. THE TWO PANELS (Article left, Comments right)
 * Opposite colours to the blocks: the cover colours swapped.
 * ============================================================ */

/* A panel is a column: a pinned head, then a body that scrolls on its own. */
.jm-panel {
	display: flex;
	flex-direction: column;
	height: 100%;
	min-height: 0;
	background: var(--jm-tone-ink);
	color: var(--jm-tone-bg);
}

.jm-panel__head {
	flex-shrink: 0;
	padding: var(--jm-space-5) var(--jm-space-4) 0;
}

.jm-panel__body {
	flex: 1;
	min-height: 0;
	display: flex;
	flex-direction: column;
	overflow-y: auto;
	padding: 0 var(--jm-space-4) var(--jm-space-5);
}

.jm-panel__empty,
.jm-panel__note {
	font-size: var(--jm-text-s);
	opacity: 0.7;
}

/* ---------- 7a. Article: title, vibes, round photo, the write-up ---------- */
.jm-panel__title {
	margin: 0 0 var(--jm-space-2);
	color: inherit;
	font-size: var(--jm-text-l);
	font-weight: 600;
	line-height: 1.15;
}

.jm-panel__vibes {
	margin: 0 0 var(--jm-space-4);
	font-size: var(--jm-text-xs);
	font-style: italic;
	letter-spacing: 0.04em;
}

.jm-panel__maker {
	display: flex;
	align-items: center;
	gap: var(--jm-space-3);
	margin: 0 0 var(--jm-space-4);
}

.jm-panel__photo {
	display: block;
	width: 64px;
	height: 64px;
	border-radius: 50%;
	object-fit: cover;
	box-shadow: var(--jm-shadow-2);
	background: var(--jm-colour-accent-1);
}

.jm-panel__by {
	font-size: var(--jm-text-s);
	font-style: italic;
}

.jm-article {
	font-size: var(--jm-text-s);
	line-height: 1.6;
}

.jm-article p {
	margin: 0 0 var(--jm-space-3);
}

/* The large first capital (part of the Article template). */
.jm-article > p:first-child::first-letter {
	float: left;
	margin: 0.08em var(--jm-space-2) 0 0;
	font-family: var(--jm-font-display);
	font-size: 3.4em;
	font-weight: 700;
	line-height: 0.85;
}

/* A very short write-up sits centred in the space, like a quote.
   (margin: auto centres it; if text ever overflows, it still scrolls normally.) */
.jm-article--short {
	margin: auto 0;
	text-align: center;
	font-size: var(--jm-text-m);
	font-style: italic;
}

.jm-article--short > p:first-child::first-letter {
	float: none;
	margin: 0;
	font-size: 2em;
	line-height: 1;
}

/* ---------- 7a2. The Article's two spaces (Nick, 29 Oct) ----------
 * parts/leaflet.php draws Article A, a short divider, Article B. Every flavour block there is a .jm-piece (a centred
 * box); the write-up is .jm-piece--write-up (text, top-aligned when long).
 *  - One on its own floats in the middle: a flavour block fills the space, centred; a short write-up centres itself.
 *  - Two flavour blocks share the space evenly, one each side of the divider.
 *  - Beside a write-up, a flavour block is a third of the height (--jm-piece-height), and the two spread evenly so
 *    no dead space is left; a long write-up just scrolls. */
.jm-panel__body {
	--jm-piece-height: calc(var(--jm-block) * 2 / 3);   /* a third of the leaflet's height (two squares) */
}

.jm-panel__body > .jm-piece:not(.jm-piece--write-up) {
	position: relative;
	display: flex;
	flex: 0 0 auto;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	min-height: var(--jm-piece-height);
	margin: 0;
	padding: var(--jm-space-3) var(--jm-space-2);
	text-align: center;
}

.jm-panel__body:not(:has(> .jm-piece--write-up)) > .jm-piece { flex: 1 1 auto; }    /* no write-up: share the space */
.jm-panel__body:has(> .jm-piece-divider) > .jm-piece { margin-block: auto; }         /* two: spread evenly */

.jm-piece > .jm-tagline--line,
.jm-piece > .jm-fav--line { margin: 0; }

.jm-piece > .jm-fav--line .jm-fav__song { display: block; margin: var(--jm-space-1) 0; }   /* the song on its own line, as on the Front */

.jm-piece-divider {
	flex: none;
	width: 3rem;
	height: 0;
	margin: var(--jm-space-3) auto;
	border: 0;
	border-top: 1px solid currentColor;
	opacity: 0.3;
}

@media (max-width: 999px) {
	.jm-panel__body { --jm-piece-height: 30vh; }   /* phones: the Article is a page of its own */
}

.jm-quote--line {
	margin: var(--jm-space-3) 0;
	text-align: center;
	font-size: var(--jm-text-m);
}

.jm-quote--line p::before,
.jm-quote--line p::after { font-size: 2em; }

.jm-tagline--line {
	margin: var(--jm-space-3) 0;
	text-align: center;
	font-size: var(--jm-text-m);
}

/* A picture in the Article (Image or Back cover; Nick, 31 Oct): the panel's full width, edge to edge, twice as wide
   as it is tall, with its caption centred underneath as a small bold line (.jm-lead). */
.jm-figure {
	position: relative;
	margin: var(--jm-space-3) 0;
}

.jm-figure img {
	display: block;
	width: 100%;
	aspect-ratio: 2 / 1;
	object-fit: cover;
}

.jm-panel__body > .jm-piece.jm-figure {
	align-self: stretch;
	margin-inline: calc(var(--jm-space-4) * -1);   /* out to the panel's edges (its body's side padding) */
	padding: 0;
}

.jm-figure__caption {
	display: block;
	margin-top: var(--jm-space-2);
	padding: 0 var(--jm-space-4);
	font-weight: 700;
	text-align: center;
}

/* Empty article: the maker, large and centred; the small "by" in the head steps aside. */
.jm-panel--bare .jm-panel__maker { display: none; }

.jm-panel__fill {
	margin: auto 0;
	text-align: center;
}

.jm-panel__photo--large {
	width: 120px;
	height: 120px;
	margin: 0 auto var(--jm-space-3);
}

.jm-panel__by--large {
	margin: 0;
	font-size: var(--jm-text-l);
	font-style: normal;
	font-weight: 600;
}

/* ---------- 7d. The panels' texture (Flavour Blocks spec, section 2; parts/leaflet.php) ----------
 * A background set on a block in the Article: a faint picture behind the Article and Comments panels, still while
 * the words scroll over it. Desktop: the layer is twice a panel's width, anchored left in the Article and right in
 * the Comments, so the picture reads as one image cut down the middle with the leaflet between. Phones: one panel at
 * a time, the picture centred.
 *  --texture-cover  the cover art in its own colours
 *  --texture-image  the maker's picture, greyscale, toned into the panel's colour (the luminosity blend keeps the
 *                   panel's hue: --jm-panel-texture-blend: normal for plain greyscale)
 * Strength: --jm-panel-texture-opacity (00-tokens.css). */
.jm-panel--textured { isolation: isolate; }

.jm-panel--textured::before {
	content: "";
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	z-index: 0;
	width: 200%;
	background: var(--jm-panel-texture) center / cover no-repeat;
	opacity: var(--jm-panel-texture-opacity);
	pointer-events: none;
}

.jm-panel--comments.jm-panel--textured::before { left: auto; right: 0; }

.jm-panel--texture-image::before {
	filter: grayscale(1);
	mix-blend-mode: var(--jm-panel-texture-blend);
}

.jm-panel--textured > * { position: relative; z-index: 1; }

@media (min-width: 1000px) {
	.jm-panel--textured { overflow: hidden; }   /* the double-width layer stays inside its panel */
}

@media (max-width: 999px) {
	.jm-panel--textured::before { width: 100%; }

	/* The Article page scrolls as a whole on phones (its head scrolls away): the picture is one screen tall and
	   sticks, so the words move over a still texture. In the wizard's stacked page it sticks while the Article is in
	   view and leaves with it (overflow: clip keeps it inside the panel without making the panel scroll). */
	.jm-panel--article.jm-panel--textured::before {
		position: sticky;
		top: 0;
		flex: none;
		height: 100dvh;
		margin-bottom: -100dvh;
	}

	.jm-leaflet__stack > .jm-panel--textured { overflow: clip; }
}

/* ---------- 7b. Comments ---------- */
.jm-panel__heading {
	margin: 0 0 var(--jm-space-4);
	padding-right: var(--jm-space-5);    /* room for the close button */
	color: inherit;
	font-size: var(--jm-text-s);
	letter-spacing: 0.1em;
}

.jm-panel__count {
	opacity: 0.6;
}

.jm-comments {
	margin: 0 0 var(--jm-space-4);
	padding: 0;
	list-style: none;
}

.jm-comment {
	display: grid;
	grid-template-columns: 36px 1fr;
	gap: var(--jm-space-3);
	padding: var(--jm-space-3) 0;
	border-bottom: 1px solid color-mix(in srgb, var(--jm-tone-bg) 15%, transparent);
	font-size: var(--jm-text-s);
}

.jm-comment__photo {
	display: block;
	width: 36px;
	height: 36px;
	border-radius: 50%;
	object-fit: cover;
	background: var(--jm-colour-accent-1);
}

.jm-comment__author {
	margin: 0;
	font-weight: 700;
}

.jm-comment__date {
	font-weight: 400;
	font-size: var(--jm-text-xs);
	opacity: 0.6;
}

.jm-comment__body p {
	margin: var(--jm-space-1) 0 0;
}

.jm-comment__body a { color: inherit; text-decoration: underline; word-break: break-all; }  /* long playlist links wrap */

.jm-comment__reply,
.jm-comment__delete {
	margin-left: var(--jm-space-2);
	font-size: var(--jm-text-xs);
	font-weight: 400;
	opacity: 0.6;
}

/* ---------- 7c. Writing a comment (Stage 6.3): a chat-style bar at the bottom of the panel ----------
   It sits outside the scrolling list (the panel is a column: head, list, bar), so it's always in view.
   Box and Send button share --jm-control-size and the button shape token: pill now, square if that changes. */
.jm-comment-form {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	gap: var(--jm-space-2);
	flex-shrink: 0;
	margin: 0;
	padding: var(--jm-space-3) var(--jm-space-4);
	border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent);
}

.jm-comment-form textarea {
	flex: 1;
	min-width: 0;
	min-height: var(--jm-control-size);
	max-height: 8.5em;                       /* grows with the text (site.js) up to about five lines */
	padding: calc((var(--jm-control-size) - 1.5em) / 2) var(--jm-space-4);
	border: 1px solid color-mix(in srgb, currentColor 30%, transparent);
	border-radius: min(var(--jm-radius-button), calc(var(--jm-control-size) / 2));
	background: transparent;
	color: inherit;
	font: inherit;
	font-size: var(--jm-text-s);
	line-height: 1.5;
	resize: none;
	overflow-y: hidden;                      /* no scroll bar; site.js turns it on only past the max height */
	white-space: pre-wrap;
}

.jm-comment-form textarea:focus {
	outline: none;
	border-color: var(--jm-colour-action);
}

.jm-comment-form__error {
	flex-basis: 100%;
	margin: 0;
	color: var(--jm-colour-scale-1);
	font-size: var(--jm-text-xs);
}


/* ============================================================
 * 8. THE LEAFLET AS A PAGE (a shared link)
 * ============================================================ */

.jm-page--leaflet {
	display: flex;
	justify-content: center;
	max-width: none;
	padding-top: var(--jm-space-5);
}

.jm-leaflet--page {
	box-shadow: var(--jm-shadow-3);
}


/* ============================================================
 * 9. THE ENTRANCE (Pop-ups and Motion doc)
 * The middle scales in a touch and glides to a stop. The two panels
 * start tucked a quarter of the way behind it, already moving, and
 * slide out while fading in, settling at the same moment.
 * Inside, the blocks fade up one after another (order set by --i).
 * Replays each time a leaflet opens (site.js toggles .is-open).
 * ============================================================ */

/* On desktop each part carries its own background and shadow, so nothing
   appears at full size before the parts arrive (the outer leaflet is see-through). */
@media (min-width: 1000px) {
	.jm-leaflet--popup {
		background: transparent;
	}

	.jm-leaflet__main,
	.jm-panel {
		box-shadow: var(--jm-shadow-3);
	}
}

.jm-leaflet__main     { position: relative; z-index: 2; background: var(--jm-tone-bg); }
.jm-panel--article,
.jm-panel--comments   { position: relative; z-index: 1; }

.jm-modal.is-open .jm-leaflet__main,
.jm-leaflet--page .jm-leaflet__main {
	animation: jm-main-in var(--jm-motion-time-leaflet) var(--jm-ease-silk) both;
}

.jm-modal.is-open .jm-panel--article,
.jm-leaflet--page .jm-panel--article {
	animation: jm-panel-left-in var(--jm-motion-time-leaflet) var(--jm-ease-silk) 40ms both;
}

.jm-modal.is-open .jm-panel--comments,
.jm-leaflet--page .jm-panel--comments {
	animation: jm-panel-right-in var(--jm-motion-time-leaflet) var(--jm-ease-silk) 40ms both;
}

.jm-modal.is-open .jm-block,
.jm-leaflet--page .jm-block {
	animation: jm-block-in var(--jm-motion-time) var(--jm-ease-silk) both;
	animation-delay: calc(60ms + var(--i, 0) * var(--jm-motion-stagger));
}

/* The close button fades in as everything settles. */
.jm-modal.is-open .jm-leaflet__close {
	animation: jm-block-in var(--jm-motion-time-leaflet) var(--jm-ease-silk) 120ms both;
}

@keyframes jm-main-in {
	from { opacity: 0; transform: scale(0.94); }
	to   { opacity: 1; transform: none; }
}

@keyframes jm-panel-left-in {               /* starts a quarter tucked behind the middle */
	from { opacity: 0; transform: translateX(25%) scale(0.94); }
	to   { opacity: 1; transform: none; }
}

@keyframes jm-panel-right-in {
	from { opacity: 0; transform: translateX(-25%) scale(0.94); }
	to   { opacity: 1; transform: none; }
}

@keyframes jm-block-in {
	from { opacity: 0; }
	to   { opacity: 1; }
}


/* ============================================================
 * 10. NARROWER SCREENS: one page at a time, Cat's pager
 * Swipe sideways (or tap ‹ › or a dot) between Article, Mix and
 * Comments. Each page scrolls up and down on its own.
 * ============================================================ */

@media (max-width: 999px) {
	/* Never wider than a phone (Nick, 31 Oct): on a tablet or a narrow window the stacked leaflet stays this wide,
	   centred, so it looks as it does on a phone (--jm-leaflet-stacked-width, 00-tokens.css). */
	.jm-leaflet {
		display: flex;
		flex-direction: column;
		width: 100%;
		max-width: var(--jm-leaflet-stacked-width);
		height: 100%;
		margin-inline: auto;
	}

	/* A mix's own page (a shared link) looks like the pop-up: no site header or menu,
	   just the pager bar; its X goes to the home page (Nick, 19 Oct). */
	.single-jmalbum .jm-header {
		display: none;
	}

	.jm-leaflet--page {
		height: 100dvh;
		box-shadow: none;
	}

	/* Staff only: the admin bar takes the top of the screen (see modal.css section 4). */
	body.admin-bar .jm-leaflet--page {
		height: calc(100dvh - var(--wp-admin--admin-bar--height, 46px));
	}

	.jm-page--leaflet {
		padding: 0;
	}

	/* Page switcher: one icon per page, always all of them, centred; close at the right (N6).
	   The page you're on is larger and in the accent colour (site.js marks it is-active). */
	.jm-leaflet__pager {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: var(--jm-space-4);
		height: 44px;
		flex-shrink: 0;
		background: var(--jm-colour-header);
		color: var(--jm-colour-text);
	}

	.jm-leaflet__go {
		position: relative;
		display: grid;
		place-items: center;
		width: 44px;                       /* a comfortable tap area around a 22px icon */
		height: 44px;
		padding: 0;
		border: 0;
		background: none;
		color: inherit;
		opacity: 0.6;
		cursor: pointer;
		transition: color var(--jm-motion-time), opacity var(--jm-motion-time);
	}

	.jm-leaflet__go svg {
		transition: transform var(--jm-motion-time) var(--jm-ease-out);
	}

	.jm-leaflet__go:hover,
	.jm-leaflet__go:focus-visible { opacity: 1; }

	.jm-leaflet__go.is-active {
		opacity: 1;
		color: var(--jm-colour-action);
	}

	.jm-leaflet__go.is-active svg {
		transform: scale(1.3);
	}

	/* The comment count: a small dot on the bubble's corner. */
	.jm-leaflet__count {
		position: absolute;
		top: 6px;
		right: 4px;
		min-width: 16px;
		height: 16px;
		padding: 0 4px;
		border-radius: 8px;
		background: var(--jm-colour-heading);
		color: var(--jm-colour-dark-1);
		font-size: 10px;
		font-weight: 700;
		line-height: 16px;
		text-align: center;
	}

	.jm-leaflet__close {
		top: 10px;
		color: var(--jm-colour-text);
	}

	/* The pages sit side by side and snap into place when swiped. */
	.jm-leaflet__pages {
		display: flex;
		flex: 1;
		height: auto;
		min-height: 0;
		overflow-x: auto;
		overflow-y: hidden;
		scroll-snap-type: x mandatory;
		scrollbar-width: none;
	}

	.jm-leaflet__pages::-webkit-scrollbar {
		display: none;
	}

	.jm-leaflet__page {
		flex: 0 0 100%;
		height: 100%;
		overflow-y: auto;
		scroll-snap-align: start;
		scroll-snap-stop: always;   /* a fast swipe stops at the next page instead of flying past the Front (Nick's phone, Firefox) */
	}

	/* Comments: only the list scrolls, so the chat bar stays at the bottom of the screen. */
	.jm-leaflet__page.jm-panel--comments { overflow-y: hidden; }

	/* Middle page: blocks stacked in one column, full width; the strip sits under the cover. */
	.jm-leaflet__grid {
		grid-template-columns: 1fr;
		grid-template-rows: none;
		grid-auto-rows: auto;
	}

	.jm-block--cover { order: -1; }

	/* Stacked, Front A sits above Front B: the cover's centre falls on the edge they share. */
	.jm-block__bg--a { background-position: 50% var(--near); }
	.jm-block__bg--b { background-position: 50% var(--far); }

	.jm-block {
		aspect-ratio: 1 / 1;
	}

	.jm-block--tracklist {
		aspect-ratio: auto;
		min-height: 200px;
		overflow: visible;
	}

	.jm-tracklist-scroll { overflow: visible; }   /* phones: the whole list shows; the page scrolls */

	.jm-rating--bar {
		position: sticky;
		bottom: 0;
		z-index: 2;
		flex-shrink: 0;
	}

	/* The wizard (Launch Tasks 10): Article sits above the Front on one page, so every block space is in view.
	   The wrapper is the page; the two sections inside just stack and the whole page scrolls. */
	.jm-leaflet--builder .jm-leaflet__stack {
		display: flex;
		flex-direction: column;
		flex: 0 0 100%;
		height: 100%;
		overflow-y: auto;
		scroll-snap-align: start;
		scroll-snap-stop: always;
	}

	.jm-leaflet__stack > .jm-leaflet__page {
		flex: none;
		height: auto;
		overflow: visible;
	}

	.jm-leaflet__stack > .jm-panel--article .jm-panel__body { overflow: visible; }

	/* Side pages are off-screen here, so they simply appear; the middle still scales in. */
	.jm-modal.is-open .jm-panel--article,
	.jm-modal.is-open .jm-panel--comments,
	.jm-leaflet--page .jm-panel--article,
	.jm-leaflet--page .jm-panel--comments {
		animation: none;
	}
}



/* ============================================================
 * 11. THE COVER POP-UP (the cover block's expanded view, second layer)
 * The full, clean cover large, with the play button and every link
 * beside it (desktop) or under it (phones).
 * ============================================================ */

.jm-coverpop {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr);
	align-items: center;
}

/* Flush to the pop-up's edges (no margin, square: Nick, 24 Oct); the info panel carries the padding. */
.jm-coverpop__cover {
	display: block;
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
}

.jm-coverpop__side {
	padding: var(--jm-space-5);
}

.jm-coverpop__title { margin: 0; }

.jm-coverpop__by {
	margin: var(--jm-space-1) 0 var(--jm-space-4);
	color: var(--jm-colour-text-soft);
	font-style: italic;
}

.jm-coverpop__play,
.jm-coverpop__shelf { width: 100%; }
.jm-coverpop__play svg { width: 18px; height: 18px; }

.jm-coverpop__links {
	margin: var(--jm-space-4) 0;
	padding: 0;
	list-style: none;
}

.jm-coverpop__links a {
	display: flex;
	align-items: center;
	gap: var(--jm-space-2);
	padding: var(--jm-space-2) 0;
	border-bottom: 1px solid var(--jm-colour-line);
	color: var(--jm-colour-text);
	text-decoration: none;
}

.jm-coverpop__links .jm-service { position: static; }

.jm-coverpop__note {
	color: var(--jm-colour-text-soft);
	font-size: var(--jm-text-xs);
}

@media (max-width: 699px) {
	.jm-coverpop {
		grid-template-columns: 1fr;
	}
	.jm-coverpop__side {
		padding: var(--jm-space-4) var(--jm-space-3);
	}
}

/* The X sits over the cover on phones (and over the panel on desktop): a soft dark disc so it reads on any cover. */
.jm-coverpop .jm-auth__close {
	z-index: 1;
	top: var(--jm-space-2);
	right: var(--jm-space-2);
	width: 40px;
	height: 40px;
	border-radius: 50%;
	background: rgba(0, 0, 0, 0.35);
	backdrop-filter: blur(6px);
	color: #fff;
}

.jm-comment-form--login { display: block; }

/* The mix's maker in the comments ("OP"): a gold ring around the photo and a small tag by the name. */
.jm-comment--op .jm-comment__photo {
	box-shadow: 0 0 0 2px var(--jm-tone-ink), 0 0 0 4px var(--jm-colour-action);
}

.jm-comment__op {
	margin-left: var(--jm-space-1);
	padding: 1px 6px;
	border-radius: var(--jm-radius-button);
	background: var(--jm-colour-action);
	color: var(--jm-colour-action-text);
	font-size: var(--jm-text-xxs);
	font-weight: 600;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	vertical-align: 2px;
}
