/*
	Home page. Dark editorial (mockups/01) with four elements blended in per the G1
	decision:

	  02 newsprint  the segmented tag row, mounted on this direction's edge-running rule
	  03 wire desk  the exclude-a-topic filter bank, grown into the river's topic control
	  04 cover      the full-bleed plate, which all four tracker bands now share

	Palette, type and spacing tokens live in tokens.css. Reset, fonts, skip link and the
	icon convention live in global.css. The masthead, the sign-off and the footer are the
	whole site's now, not this page's, so they live in chrome.css, which loads before this
	file; what is left here is the home page itself, plus the ink for the one lane-chip
	skin this page owns. Nothing below restates a colour literal except the four story art
	screens, which are inked from their own art.duotone values.

	Two flags exist and they never trade treatments. Trending is the orange word and it
	belongs to heavily covered stories. Breaking is the bone word with the accent line
	beneath it. A death notice wears neither.
*/

/* ------------------------------------------------------------------ shell */

.wrap {
	width: 100%;
	max-width: var(--measure);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/* Scoped rather than universal: the one thing the filter toggles, which has a display
   rule that would otherwise outrank the user agent's [hidden]. The menu panel's twin
   of this rule lives with the rest of the masthead in chrome.css. */
.story[hidden] {
	display: none !important;
}

/* global.css sets the ring at zero specificity with :where(), so this plain selector
   takes it over. Sections that change the ground re-point --focus-ring instead of
   restating the rule: the orange band inks it, the obituary row keeps orange out. */
:is(a, button, input, [tabindex]):focus-visible {
	outline: 2px solid var(--focus-ring);
	outline-offset: 3px;
}

.skip-link {
	background-color: var(--accent);
	color: var(--accent-ink);

	&:focus {
		outline-color: var(--text);
	}
}

/* ------------------------------------------------------------- lead story */

.lead {
	position: relative;
	overflow: hidden;
	background-color: var(--lead-canvas);
	border-block-end: 1px solid var(--hairline);
	/* No foot padding below 1200, where the trending band closes the section: the band
	   carries its own and the section's own bottom rule is the one under it. The padding
	   comes back at 1200, where trending stands in the hero as a panel instead.
	   Tightened top (owner's call, 2026-08-16): the hero should open close under the
	   rail, not float in air. */
	padding-block: clamp(1.35rem, 3vw, 2.25rem) 0;
	scroll-margin-block-start: var(--sticky-clearance);
}

.lead-art {
	position: absolute;
	inset: 0;
	pointer-events: none;
	-webkit-mask-image: linear-gradient(102deg, transparent 6%, #000 58%);
	mask-image: linear-gradient(102deg, transparent 6%, #000 58%);
}

.lead-art-canvas {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
}

/* The lead's licensed photo, when its story carries one: full-bleed cover under the
   container's mask (which keeps the headline side dark and readable), cropped
   top-weighted like every photo frame on the site, with the same declared crop bands. */
.lead-art-photo {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	display: block;
	object-fit: cover;
	object-position: 50% 22%;
}

.lead-art-photo[data-focus='top'] { object-position: 50% 0%; }
.lead-art-photo[data-focus='center'] { object-position: 50% 50%; }
.lead-art-photo[data-focus='bottom'] { object-position: 50% 100%; }

/* The print screen over the lead's seed duotone. The colour and the bloom now come from
   the SVG underneath (the same seed art the lead's own story page opens with), so the
   screen is bone ink at a whisper and only supplies the halftone texture. */
.lead-art-screen {
	position: absolute;
	inset: -30%;
	background-image: radial-gradient(circle at 50% 50%, rgb(236 236 240 / 0.6) 0 1.15px, transparent 1.75px);
	background-size: 9px 9px;
	transform: rotate(1deg);
	opacity: 0.16;
}

.lead-inner {
	position: relative;
	z-index: 1;
}

.lead-kicker {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	font-family: var(--font-display);
	font-size: 0.7rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--accent-text);
	margin-block-end: clamp(1rem, 2vw, 1.5rem);

	&::before {
		content: '';
		width: 1.75rem;
		height: 3px;
		background-color: var(--accent);
	}
}

.lead-headline {
	font-family: var(--font-display);
	font-size: clamp(2.6rem, 6vw, 5rem);
	font-weight: 400;
	line-height: 0.95;
	letter-spacing: -0.035em;
	max-width: 20ch;
	text-wrap: balance;

	a {
		color: var(--text);
		text-decoration: none;

		&:hover {
			color: var(--accent-text);
		}
	}
}

.lead-dek {
	margin-block-start: clamp(1.35rem, 2.2vw, 1.85rem);
	font-size: clamp(1rem, 1.5vw, 1.18rem);
	line-height: 1.5;
	color: var(--text);
	max-width: 52ch;
}

/* ------------------------------------------------- trending, docked to the lead */

/*
	Trending docks to the lead (the owner's call, 2026-08-16). One place in the markup,
	two renderings:

	  below 1200   a full-width band closing the lead section, still ahead of the river.
	               It runs edge to edge on the house panel carbon, so no part of the
	               hero picture is under it and there is nothing to overlap.
	  1200 and up  a panel on the right of the hero, over the picture, with the story
	               keeping the left. The two are columns of one grid rather than two
	               boxes holding a width agreement, so the headline and the dek cannot
	               reach under the panel at any width: there is no slot there to reach
	               into, and the 20ch ceiling on the headline is no longer what is
	               keeping them apart.

	THE GROUND. Over a photograph the panel cannot borrow the section's, so it brings
	its own: the panel carbon at 90% with a 3px backdrop blur (owner's call,
	2026-08-16). The blur is what makes 90% hold up: it averages the picture behind the
	panel, so no single hot pixel survives to sit directly under an ink; the ground the
	quietest line reads against is the neighborhood's mean, already dimmed by the scrim
	and the carbon. The band below 1200 has no picture behind it to show through, so it
	takes the flat carbon and every figure on it is the one tokens.css already quotes
	for that ground.

	The hero's mask needs no change for any of this. It runs 102deg from transparent to
	opaque, holding the art off the headline side, so the art is at full strength
	exactly where the panel stands, which is the case the ground above is measured for.

	The row grammar is the one the list has always had: rank in mono at the leading
	edge, name in the body face, then the kind, the count and the engine's delta in mono
	at the trailing edge, ruled by the quiet weight so the list never competes with the
	box holding it.
*/
.lead-trending {
	/* The panel's own tokens, so the list no longer reads the river's cell tokens: it
	   is not a cell on that grid any more. The row rule is drawn as a gradient that
	   dies before the trailing edge; over the glass panel a flat hairline only showed
	   where the photograph behind happened to be bright, so the fade the top rows wore
	   by accident is now the deliberate rule every row wears. */
	--panel-pad: clamp(1rem, 1.9vw, 1.6rem);
	--panel-rule: linear-gradient(90deg, color-mix(in srgb, var(--text) 26%, transparent), transparent 88%);

	display: grid;
	align-content: start;
	gap: 0.75rem;
	margin-block-start: clamp(2rem, 4vw, 3rem);
	/* Full bleed as a band. The gutter is cancelled, and below 1200 the wrap is the
	   width of the window, so the band runs out to both of its edges. */
	margin-inline: calc(var(--gutter) * -1);
	/* No foot: the last row's own breathing room is all the air below the list
	   (owner's call, 2026-08-16). */
	padding: var(--panel-pad) var(--panel-pad) 0;
	background-color: var(--panel);
	/* One rule, at the top. The band closes the section, so the foot is drawn by the
	   lead's own bottom border and never twice. */
	border-block-start: 1px solid var(--hairline-bright);
}

.trending-heading {
	/* The heading carries the family square itself; the panel dropped its slug line
	   (owner's call, 2026-08-16), so the title is the whole nameplate. */
	display: flex;
	align-items: center;
	gap: 0.55rem;
	font-family: var(--font-display);
	font-weight: 400;
	font-size: clamp(1.1rem, 1.5vw, 1.3rem);
	line-height: 1;
	letter-spacing: -0.02em;
	color: var(--text);
}

/* The rows run to the panel's own edges, so the list is ruled by the panel rather than
   floating inside it: the sub-rules terminate on its borders the way a nested box would,
   without nesting a second box. */
.trending-list {
	margin-inline: calc(var(--panel-pad) * -1);
	margin-block-start: 0.25rem;
	background: var(--panel-rule) 0 0 / 100% 1px no-repeat;
	list-style: none;
	padding: 0;
}

.trending-row {
	background: var(--panel-rule) 0 100% / 100% 1px no-repeat;

	&:last-child {
		background: none;
	}
}

.trending-link {
	display: grid;
	grid-template-columns: 1.6rem minmax(0, 1fr) auto;
	align-items: baseline;
	gap: 0.08rem 0.5rem;
	padding: 0.38rem var(--panel-pad);
	text-decoration: none;
	color: inherit;
	transition: background-color 120ms linear;
}

/* The whole row answers the cursor, not just the name: a ground fill plus the accent
   ink, so the hover reads at a glance across the panel's full width. */
a.trending-link:hover,
a.trending-link:focus-visible {
	background-color: color-mix(in srgb, var(--text) 10%, transparent);

	& .trending-name {
		color: var(--accent-text);
	}
}

.trending-rank {
	grid-column: 1;
	grid-row: 1 / span 2;
	align-self: center;
	font-family: var(--font-mono);
	font-size: 0.7rem;
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.04em;
	color: var(--accent-text);
}

.trending-name {
	grid-column: 2;
	grid-row: 1;
	font-size: 0.85rem;
	font-weight: 500;
	line-height: 1.2;
	letter-spacing: -0.012em;
	color: var(--text);
	transition: color 120ms linear;
}

.trending-kind {
	grid-column: 2;
	grid-row: 2;
	font-family: var(--font-mono);
	font-size: 0.6rem;
	line-height: 1.15;
	letter-spacing: 0.1em;
	color: var(--muted-2);
}

/* How many stories the desk filed on this name, said in words so it cannot be mistaken
   for a rating. */
.trending-count {
	grid-column: 3;
	grid-row: 1;
	font-family: var(--font-mono);
	font-size: 0.65rem;
	letter-spacing: 0.06em;
	color: var(--muted);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
	text-align: end;
}

.trending-delta {
	grid-column: 3;
	grid-row: 2;
	font-family: var(--font-mono);
	font-size: 0.6rem;
	letter-spacing: 0.06em;
	text-align: end;
	text-transform: lowercase;
	white-space: nowrap;

	.icon {
		font-size: 0.58rem;
	}

	&.delta-up,
	&.delta-new {
		color: var(--text);
	}

	&.delta-flat {
		color: var(--muted-2);
	}
}

/* ----------------------------------------------------------- the tag row */

/*
	Two grammars, joined. From 02: the row is segmented, each word divided from the
	last by a thin rule, so a story's standing line reads TRENDING | ROCK | RELEASES
	however many tags it carries. From 01: the row is mounted on a rule that runs out
	to the edge of its column, and the words split between the two faces the page
	already uses. A tag is a label, so it is set in the display face; the timestamp is
	a measurement, so it stays in the mono.

	Publishing is rolling, so the date carries the story. A relative time is spent only
	where the clock is still running: the lead and the breaking story.

	No source credits here. That is the G1 decision, and it is why the row ends at the
	timestamp: the outlets that reported a story are named on the story's own page, as
	equal credits, with no ordering claim attached.
*/
.tag-row {
	--meta-rule: var(--hairline-bright);
	--meta-rule-weight: 1px;

	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: 0.55rem;
	row-gap: 0.4rem;
	color: var(--muted);

	/* The divider, with no separator character anywhere in the markup. The pipes
	   bind the tag words into a single unit and stop there: the timestamp is set off
	   by a wider gap instead. That is what keeps a wrapped row honest, because a
	   divider that lands first on the second line has nothing to divide. Note the
	   rule cannot reach ::after, which is not an element. */
	> * + :is(.tag-genre, .tag-type),
	> time + .tag-relative {
		border-inline-start: 1px solid var(--hairline-bright);
		padding-inline-start: 0.55rem;
	}

	> time {
		margin-inline-start: 0.3rem;
	}

	/* The rule runs from the last tag out to the edge of the column. Zero basis, and
	   an outer size of exactly zero: the negative margin cancels the flex gap, and the
	   0.7rem of visible offset (the gap plus a little more) is painted transparent by
	   the gradient instead of held open by layout. A margin here would give the pseudo
	   a few pixels of hypothetical size, enough to wrap it onto a line of its own
	   whenever the tags leave less slack than that, where it would sit a few pixels
	   off the rule that separates one story from the next and read as a mistake. */
	&::after {
		content: '';
		flex: 1 1 0;
		align-self: center;
		height: var(--meta-rule-weight);
		margin-inline-start: -0.55rem;
		background-image: linear-gradient(to right, transparent 0 0.7rem, var(--meta-rule) 0.7rem);
	}

	time,
	.tag-relative {
		font-family: var(--font-mono);
		font-size: 0.74rem;
		letter-spacing: 0.02em;
		font-variant-numeric: tabular-nums;
	}

	.tag-relative {
		color: var(--muted-2);
	}
}

.tag-trending,
.tag-breaking,
.tag-genre,
.tag-type {
	font-family: var(--font-display);
	font-size: 0.7rem;
	line-height: 1.5;
	letter-spacing: 0.11em;
	text-transform: uppercase;
}

/* The orange word. It is the only orange set as text anywhere on carbon, and the
   tint exists so that it clears 4.5:1 where the surface orange would not. */
.tag-trending {
	color: var(--accent-text);
	letter-spacing: 0.13em;
}

/* Bone, with the accent drawn under it. Distinct from Trending by weight of colour
   and by the line, so the two never depend on hue alone to tell them apart. */
.tag-breaking {
	color: var(--text);
	border-block-end: 2px solid var(--accent);
	padding-block-end: 0.1em;
}

/* An anchor since the genre hubs landed: every genre tag is the way into that genre's
   page. It keeps the quiet weight of the row and takes its underline on hover only, so a
   standing line of tags never reads as a row of links. Matches news.css, where the story
   page's genre tag has always been a link. */
.tag-genre {
	color: var(--muted);
	text-decoration: none;

	&:hover {
		color: var(--text);
		text-decoration: underline;
		text-underline-offset: 3px;
	}
}

.tag-type {
	color: var(--muted-2);
}

/* The type word is a link wherever a card or the lead renders it: it goes to that type's
   hub. Element-qualified on purpose. The same class is a plain span inside the hub and
   artist row links, where an anchor cannot nest inside an anchor, and a span must not
   light up under the cursor as though it were clickable. */
a.tag-type {
	text-decoration: none;

	&:hover {
		color: var(--text);
		text-decoration: underline;
		text-underline-offset: 3px;
	}
}

@keyframes rule-draw {
	from {
		transform: scaleX(0);
	}
}

@keyframes meta-settle {
	from {
		transform: translateX(-0.75rem);
		opacity: 0.5;
	}
}

/* The page's one orchestrated entrance: the lead's tag row settles in from the left
   while its accent rule draws out to the column edge. Nothing else on the page
   animates. */
.lead-tags {
	--meta-rule: var(--accent);
	--meta-rule-weight: 3px;

	margin-block-start: clamp(1.15rem, 2.2vw, 1.85rem);
	column-gap: 0.7rem;
	animation: meta-settle 620ms cubic-bezier(0.16, 1, 0.3, 1) 200ms backwards;

	> * + :is(.tag-genre, .tag-type),
	> time + .tag-relative {
		padding-inline-start: 0.7rem;
	}

	> time {
		margin-inline-start: 0.45rem;
	}

	/* Same zero-outer-size trick as the base row, retuned to this row's wider gap:
	   the negative margin cancels the 0.7rem gap and the gradient paints the 1.15rem
	   visible offset (the gap plus the 0.45rem this rule used to hold as margin). */
	&::after {
		margin-inline-start: -0.7rem;
		background-image: linear-gradient(to right, transparent 0 1.15rem, var(--meta-rule) 1.15rem);
		transform-origin: left center;
		animation: rule-draw 820ms cubic-bezier(0.16, 1, 0.3, 1) both;
	}

	.tag-trending,
	.tag-genre,
	.tag-type {
		font-size: 0.78rem;
	}

	time,
	.tag-relative {
		font-size: 0.8rem;
	}
}

/* ------------------------------------------------------------------ river */

/*
	The latest, as a ruled broadsheet. The construction is two declarations: a cluster
	draws its top and left edge, a cell draws its bottom and right edge, so every
	interior rule in the section is drawn exactly once by exactly one element and the
	whole thing reads as one ruled instrument rather than a stack of floating cards.
	There is nothing to undo when a row reflows at a breakpoint, and nothing for a
	filtered row to leave behind: a hidden story takes both of its cells out of the
	grid, and the cells still standing go on drawing their own two edges, so the rules
	close up with no gap and no doubled line wherever the hole was.

	Three cells are chrome (the section slug, the nameplate, the toolbar), each running
	the full width of the grid, and the rest are the river, two cells to a story.

	The two problems this direction answers in the grid rather than in a stylesheet
	trick:

	1. IMAGES. Every story gets the same object: a duotone plate generated from its own
	   seed, under a halftone screen in its family's colour. The stories carrying a
	   photograph lay it on that plate at object-fit: contain, so nothing is ever
	   cropped and no subject is ever beheaded. The plate is not a placeholder standing
	   in for a missing picture; it is the mount every picture sits on, which is why the
	   stories without one do not read as holes. The mount rule is drawn on every art
	   cell either way, so the two kinds are visibly the same cell with and without a
	   print in it.

	2. FILTERS. One ruled toolbar row. The chips are joined at their edges the way the
	   cells are, each carrying a status square in its family's colour: filled is on,
	   hollow is off. No icon and no second row at desktop. The view pair and the live
	   count hold the far end of the same row, joined the same way.

	Trending held a fourth chrome cell here, in a trailing column beside all three rows,
	until the owner moved it into the lead on 2026-08-16. Nothing had to be unpicked to
	let it go: the cell left the grid the way a filtered story leaves it, and the three
	rows that stayed go on drawing their own two edges across the full width.

	The cell system is declared flat, on bare .cluster and .cell, because that flatness
	is the whole technique: every rule that sits inside a cell has to beat exactly one
	class, never a descendant chain. This file is loaded by the home page alone and
	nothing else on it, chrome included, answers to either name.

	Contrast, against the ground each node sits on, taken from tokens.css:

	  #ececf0 text on #0a0a0c canvas .............. 16.79:1
	  #9a9aa4 muted on #0a0a0c canvas ..............  7.09:1
	  #85858f muted-2 on #0a0a0c canvas ............  5.42:1
	  #ff7a42 accent-text on #0a0a0c canvas ........  7.64:1
	  #f0c04e tour accent on carbon ................ 11.63:1
	  #7ef0c1 festival accent on carbon ............ 14.24:1
	  #c99df0 award accent on carbon ...............  9.01:1
	  #f0847e band accent on carbon ................  8.53:1
	  #7ab6f0 industry accent on carbon ............  8.79:1
	  #b8f07e new accent on carbon ................. 13.35:1

	Every square and rule above clears 3:1 as a graphic, and every one of them is also
	set as ink somewhere on the page, where it clears 4.5:1.
*/

/* -------------------------------------------------------- river pagination */
/* Shared by the "Older stories" link that closes page 1's river (index.njk) and the
   prev/next pair on every page after it (river-page.njk). Not .post-back: that class
   belongs to news.css, which pages built on home.css alone never load. */

.page-nav-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding-block: clamp(1.25rem, 3vw, 2rem);
	border-block-end: 1px solid var(--hairline);
}

.river-page-count {
	font-family: var(--font-mono);
	font-size: 0.82rem;
	color: var(--muted);
}

/* The page's real h1 (SEO-037: a second page of the river needs its own heading, not
   zero). Present for a crawler and a screen reader; the "Page N of M" line beside it
   already carries the visible identity this page needs, so the h1 stays off-screen
   rather than duplicating that line in a second, louder voice. */
.river-page-h1 {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

.post-back,
.river-pagination-next {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	font-family: var(--font-display);
	font-size: 0.9rem;
	color: var(--text);
	text-decoration: none;

	&:hover {
		color: var(--accent-text);
	}

	.icon {
		width: 0.85rem;
		height: 0.85rem;
	}
}

.river-pagination {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	padding-block: clamp(1.5rem, 3.5vw, 2.5rem);
}

.river-pagination-next {
	margin-inline-start: auto;
}

.river {
	/* The two rule weights the instrument is drawn in. The bright one is structure
	   (every cell edge); the quiet one rules INSIDE a cell, so a list of rows never
	   competes with the box holding it. */
	--cell-rule: var(--hairline-bright);
	--sub-rule: var(--hairline);
	--cell-pad: clamp(1rem, 1.9vw, 1.6rem);

	/* How far a print is mounted inside its cell. One number, so a photograph and a
	   bare plate hold the same margin and the mount rule lines up across a row. */
	--mount: clamp(0.7rem, 1.3vw, 1.1rem);

	/* The air between a story's rules and its coloured card, so the card reads as an
	   object set into the table rather than as a painted cell. */
	--story-frame: clamp(0.55rem, 1.1vw, 0.8rem);

	padding-block: clamp(2.25rem, 4.5vw, 3.5rem) clamp(2.5rem, 5vw, 4rem);
	scroll-margin-block-start: var(--sticky-clearance);
}

/* ---------------------------------------------------------- the cell system */

/*
	Borders are declared on all four sides at zero width first, so the same class can
	sit on a div, an aside or an article without a user agent border leaking through on
	the two sides it does not own.
*/
.cluster {
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	border: 0 solid var(--cell-rule);
	border-block-start-width: 1px;
	border-inline-start-width: 1px;
}

.cell {
	position: relative;
	min-width: 0;
	border: 0 solid var(--cell-rule);
	border-block-end-width: 1px;
	border-inline-end-width: 1px;
	padding: var(--cell-pad);
}

/* ------------------------------------------------------------ section grammar */

/*
	Every cell that names itself opens the same way: a mono slug with a small square
	status mark in the family's colour. A square rather than a dot, because a square is
	the one shape that stays legible at 8px beside mono type, and it is the same mark
	the chips wear, which is what ties the toolbar to the river.
*/
.slug {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: 0.45rem 0.65rem;
	font-family: var(--font-mono);
	font-size: 0.7rem;
	line-height: 1.4;
	letter-spacing: 0.09em;
	color: var(--muted);
}

.square {
	flex: none;
	width: 0.5rem;
	height: 0.5rem;
	background-color: var(--square-color, var(--accent));
}

.latest-head {
	display: flex;
	padding-block: clamp(1.25rem, 3vw, 2.5rem);
}

/* The nameplate. Held at the lead headline's own ceiling rather than the taller one the
   mock-up used: there the statement was the page's h1 with nothing above it, and here
   the day's story is. The two biggest words on the page match instead of the section
   title outrunning the story it introduces. */
.statement {
	font-family: var(--font-display);
	font-weight: 400;
	font-size: clamp(2.35rem, 6.2vw, 5rem);
	line-height: 0.86;
	letter-spacing: -0.04em;
	text-wrap: balance;
}

/* ------------------------------------------------------------------ toolbar */

/*
	One row. The chips are joined edge to edge with a negative inline margin, the same
	shared-edge rule the cells follow, so ten controls read as one ruled strip instead
	of ten floating pills. A pressed chip lifts its own border above its neighbours'
	with z-index, which is what stops the join from swallowing the state. At the
	narrowest widths the strip wraps, and because every chip is a ruled box on a shared
	grid the wrap reads as more instrument rather than as a second heavy row.

	Off is carried by fill, weight and colour together and never by hue alone: the
	square goes hollow, the label drops to the quiet grey, and aria-pressed is the state
	the CSS selects on, so the picture and the accessibility tree cannot drift apart.
*/
.toolbar-cell {
	display: grid;
	gap: 0.85rem;
	align-content: center;
}

.toolbar {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.85rem 1.5rem;
}

.chips {
	display: flex;
	flex-wrap: wrap;
}

/* The inline padding and the square's gap are a hair under the mock-up's, and the reason
   is arithmetic rather than taste: this site's page measure is 1360px against the
   mock-up's 1440, which leaves the toolbar cell 80px narrower than the one the strip was
   drawn in. At the mock-up's own numbers the nine chips want 910px and the cell offers
   901, so the ninth chip wrapped to a row of its own at every desktop width. Two
   fractions of a rem buy back twenty and keep the one thing the toolbar is for: nine
   topics, the view pair and the live count on one ruled row. Below about 1370 the strip
   still wraps, which is the width the wrap was designed for. */
.chip {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	margin: 0;
	padding: 0.5rem 0.7rem;
	border: 1px solid var(--sub-rule);
	background-color: transparent;
	color: var(--muted);
	font-family: var(--font-mono);
	font-size: 0.7rem;
	letter-spacing: 0.07em;
	line-height: 1.2;
	white-space: nowrap;
	cursor: pointer;
	transition: color 120ms linear, border-color 120ms linear;

	& + & {
		margin-inline-start: -1px;
	}

	&:hover {
		z-index: 2;
		border-color: var(--cell-rule);
		color: var(--text);
	}

	&[aria-pressed='true'] {
		z-index: 1;
		border-color: var(--cell-rule);
		color: var(--text);
	}

	&[aria-pressed='false'] .square {
		background-color: transparent;
		box-shadow: inset 0 0 0 1px var(--muted-2);
	}
}

/* The one thing the bank refuses: a click that would leave the river empty. The refused
   chip flashes its border in the accent and stays on, which says no in the same
   language the pressed state is written in. */
.chip[data-refused='true'] {
	z-index: 4;
	border-color: var(--accent);
	color: var(--accent-text);
}

.toolbar-end {
	display: flex;
	align-items: center;
	gap: 1rem;
	margin-inline-start: auto;
}

.topic-count {
	font-family: var(--font-mono);
	font-size: 0.7rem;
	letter-spacing: 0.07em;
	color: var(--muted-2);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.toolbar-hint {
	font-family: var(--font-mono);
	font-size: 0.68rem;
	letter-spacing: 0.07em;
	color: var(--muted-2);
}

/* --------------------------------------------------------------- view group */

/*
	Cards or the compact index, one pressed at all times, joined the same way the chips
	are so the pair reads as one setting with one choice made rather than as two more
	filters. The pressed one takes the panel fill and an accent cap on its top edge; the
	cap is 2px in both states, with a matching padding correction, so switching the view
	never moves the row the pair sits in.
*/
.view-controls {
	display: flex;
}

.view-toggle {
	position: relative;
	display: inline-flex;
	align-items: center;
	gap: 0.45rem;
	margin: 0;
	padding: 0.5rem 0.75rem;
	border: 1px solid var(--sub-rule);
	background-color: transparent;
	color: var(--muted);
	font-family: var(--font-mono);
	font-size: 0.7rem;
	letter-spacing: 0.07em;
	line-height: 1.2;
	white-space: nowrap;
	cursor: pointer;
	transition: color 120ms linear, background-color 120ms linear;

	.view-icon {
		flex: 0 0 auto;
		font-size: 0.9rem;
	}

	& + & {
		margin-inline-start: -1px;
	}

	&:hover {
		z-index: 2;
		color: var(--text);
	}

	&[aria-pressed='true'] {
		z-index: 1;
		border-color: var(--cell-rule);
		border-block-start-color: var(--accent);
		border-block-start-width: 2px;
		padding-block-start: calc(0.5rem - 1px);
		background-color: var(--panel);
		color: var(--text);
	}
}

/* The chip and view labels carry no case rule of their own. They are set in the mono
   face at the slug's own size, which is what lets nine topics plus the view pair and the
   count hold one row at desktop; upper-casing them is about a fifth more width and buys
   a second heavy row under the toolbar. */

/* The page ring sits outside its target, which on a strip of controls joined at their
   edges would land on top of the neighbour. Inside the border, for these two only. */
:is(.chip, .view-toggle):focus-visible {
	z-index: 3;
	outline-offset: -3px;
}

/* ---------------------------------------------------------------- the story */

/*
	One ruled slot per story, and inside it one coloured card. The story itself is the
	table cell now: it draws the bottom and right rules every cell on the grid draws,
	and holds the card off them by the frame, so the group sits in the table instead of
	painting it. Which side the art takes inside the card is written by the script from
	the story's position among the VISIBLE rows, not its position in the markup, so the
	checkerboard survives filtering instead of going ragged the moment a chip is
	switched off.
*/
.story {
	grid-column: 1 / -1;
	min-width: 0;
	border: 0 solid var(--cell-rule);
	border-block-end-width: 1px;
	border-inline-end-width: 1px;
	padding: var(--story-frame);
	scroll-margin-block-start: var(--sticky-clearance);
}

/* ---- the card */

/*
	The story's one coloured object: the wash under everything, the art window and the
	copy on top of it. The wash and the window are positioned so both paint above the
	in-flow content behind them and below the two positioned siblings that follow in
	the DOM; nothing here needs a z-index.
*/
.story-card {
	position: relative;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	height: 100%;
	/* The card's own screen is an oversized rotated square, like the art window's;
	   the card is what clips it. */
	overflow: hidden;
}

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

/* The halftone across the whole card, in the family's colour at a quieter voice than
   the art window's print screen: texture for the ground the copy sits on, held low
   enough that no dot lifts the wash toward the inks riding it. */
.card-screen {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 200%;
	aspect-ratio: 1;
	translate: -50% -50%;
	background-image: radial-gradient(circle at 50% 50%, var(--card-accent) 0 1px, transparent 1.6px);
	background-size: 6px 6px;
	transform: rotate(18deg);
	opacity: 0.12;
	pointer-events: none;
}

/* ---- the art window */

.art {
	position: relative;
	overflow: hidden;
	min-height: clamp(11rem, 26vw, 15rem);
}

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

/* The screen is a square laid over the frame's diagonal so any rotation still covers
   all four corners. It sits on the generated plate and under the photograph: there is
   nothing to screen on a licensed picture and nothing to licence on the plate. */
.art-screen {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 200%;
	aspect-ratio: 1;
	translate: -50% -50%;
	background-image: radial-gradient(circle at 50% 50%, var(--card-accent) 0 1px, transparent 1.6px);
	background-size: 6px 6px;
	transform: rotate(18deg);
	opacity: 0.22;
	pointer-events: none;
}

/* The plate's type word. A story with no photograph gets a frame the same shape and
   weight as a photographed one, and this is what fills it: the story's own family word,
   set in the display face at plate scale, in the same ink the slug's square already
   wears for this accent. It is what stops a no-photo card reading as a gap beside the
   cards that have one. */
.art-word {
	position: absolute;
	inset-block-end: 0.6rem;
	inset-inline-start: 0.75rem;
	max-width: calc(100% - 1.5rem);
	font-family: var(--font-display);
	font-size: clamp(1.1rem, 2.6vw, 1.6rem);
	line-height: 1;
	letter-spacing: -0.02em;
	text-transform: uppercase;
	color: var(--square-color);
	opacity: 0.62;
	pointer-events: none;
}

/* The mount rule. Drawn on every art cell, photo or plate, which is what makes the two
   kinds read as one object rather than as a picture and its absence. */
.art-mount {
	position: absolute;
	inset: var(--mount);
	border: 1px solid color-mix(in srgb, var(--text) 14%, transparent);
	pointer-events: none;
}

/* Width and height are written out rather than left to the insets: an absolutely
   positioned REPLACED element resolves an auto width to its intrinsic width and drops
   the trailing inset, so an img given four insets alone would lay itself out at its
   natural size and break out of the cell.

   The print is centred in its mount and never cropped, so the story's declared focus
   band decides nothing here and is not read: object-position under contain would only
   shove a whole picture off the mount rule it is meant to sit inside. */
.art-photo {
	position: absolute;
	inset: var(--mount);
	width: calc(100% - var(--mount) * 2);
	height: calc(100% - var(--mount) * 2);
	object-fit: contain;
	object-position: 50% 50%;
}

/* ---- the text cell */

.story-text {
	position: relative;
	display: flex;
	flex-direction: column;
	gap: 0.6rem;
	padding: var(--cell-pad);
}

/*
	The slug hangs in a ruled sub-cell above the copy. The rule is the label row's own
	bottom edge pulled out to the cell's full width and given its padding back, so it
	terminates on the cell's borders exactly as a real sub-cell would.
*/
.story-slug {
	margin-inline: calc(var(--cell-pad) * -1);
	margin-block: calc(var(--cell-pad) * -1) 0.35rem;
	padding: calc(var(--cell-pad) * 0.8) var(--cell-pad);
	border-block-end: 1px solid var(--sub-rule);
}

/* Genre and type as a path, each of them the way into its own hub. The words are the
   site's own labels, set to the lower case the path grammar reads in, which is what
   keeps the two the labels exist for ("R&B", "Lineup change") from arriving at the
   reader as raw slugs. The auto margin here rather than on the marks: two marks would
   otherwise take an auto each and split the slack between them instead of grouping at
   the trailing edge. */
.slug-path {
	min-width: 0;
	margin-inline-end: auto;
	text-transform: lowercase;
	color: var(--muted);
}

.slug-sep {
	color: var(--muted-2);
	padding-inline: 0.1em;
}

.slug-genre,
.slug-type {
	color: var(--muted);
	text-decoration: none;

	&:hover {
		color: var(--text);
		text-decoration: underline;
		text-underline-offset: 3px;
	}
}

/* Two flags and they never trade treatments. Trending is the orange word, the only
   orange set as text anywhere on carbon; Breaking is the bone word with the accent line
   under it, so the two are told apart by weight of colour and by the line and never by
   hue alone. A death notice wears neither. */
.slug-mark {
	flex: none;
	font-family: var(--font-mono);
	font-size: 0.65rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	white-space: nowrap;
}

.slug-mark-trending {
	color: var(--accent-text);
}

.slug-mark-breaking {
	color: var(--text);
	border-block-end: 2px solid var(--accent);
	padding-block-end: 0.1em;
}

.story-headline {
	font-size: clamp(1.05rem, 1.55vw, 1.3rem);
	font-weight: 600;
	line-height: 1.2;
	letter-spacing: -0.018em;
	text-wrap: pretty;

	a {
		color: var(--text);
		text-decoration: none;
		transition: color 120ms linear;

		&:hover {
			color: var(--accent-text);
		}
	}
}

.story-dek {
	max-width: 48ch;
	font-size: 0.9rem;
	line-height: 1.5;
	color: var(--muted);
	text-wrap: pretty;
}

.story-stamp {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	margin-block-start: auto;
	padding-block-start: 0.35rem;
	font-family: var(--font-mono);
	font-size: 0.66rem;
	letter-spacing: 0.08em;
	/* --muted, not --muted-2: the stamp sits on the card wash, and tokens.css gives
	   muted-2 a ceiling that stops at flat carbon. List view hands muted-2 back. */
	color: var(--muted);
	font-variant-numeric: tabular-nums;
}

/* A relative time is spent only where the clock is still running, so it appears on the
   breaking row alone and takes a divider off the timestamp it qualifies. */
.stamp-relative {
	margin-inline-start: 0.5rem;
	padding-inline-start: 0.5rem;
	border-inline-start: 1px solid var(--sub-rule);
}

/* A death notice keeps its place in the checkerboard and loses the volume, not the
   texture. Nothing is drained: the builder already emits a matte story's seed in greys,
   and screening it a second time would leave a black rectangle reading as a picture
   that failed to load rather than as a plate. The neutral square and the grey halftone
   are the whole treatment, and they are set in the family map below with every other
   family. What is left here is the chrome the obituary test also reaches: no accent
   anywhere in the row, the focus ring included, and a headline that never brightens
   under the cursor the way a release does. */
.story-matte {
	--focus-ring: var(--text);

	.story-headline a:hover {
		color: var(--text);
		text-decoration: underline;
		text-decoration-color: var(--muted);
		text-underline-offset: 3px;
	}

	a.slug-type:hover {
		color: var(--type-matte-text);
		text-decoration-color: var(--muted);
	}
}

/* -------------------------------------------------------------- family colours */

/*
	The one place a story's family is turned into ink. Eight names, read here and
	nowhere else, so a chip and the rows it governs are coloured from one decision. The
	*-text variants carry the squares because every one of them is also set as ink
	somewhere on this page, and #ff5c1a is the one orange that cannot be.
*/
.story {
	--card-accent: var(--tracker-release);
	--square-color: var(--tracker-release-text);
}

.story[data-accent='release'],
.chip[data-accent='release'] {
	--card-accent: var(--tracker-release);
	--square-color: var(--tracker-release-text);
}

.story[data-accent='tour'],
.chip[data-accent='tour'] {
	--card-accent: var(--tracker-tour);
	--square-color: var(--tracker-tour-text);
}

.story[data-accent='festival'],
.chip[data-accent='festival'] {
	--card-accent: var(--tracker-festival);
	--square-color: var(--tracker-festival-text);
}

.story[data-accent='award'],
.chip[data-accent='award'] {
	--card-accent: var(--tracker-award);
	--square-color: var(--tracker-award-text);
}

.story[data-accent='band'],
.chip[data-accent='band'] {
	--card-accent: var(--type-band);
	--square-color: var(--type-band-text);
}

.story[data-accent='industry'],
.chip[data-accent='industry'] {
	--card-accent: var(--type-industry);
	--square-color: var(--type-industry-text);
}

.story[data-accent='new'],
.chip[data-accent='new'] {
	--card-accent: var(--type-new);
	--square-color: var(--type-new-text);
}

.story[data-accent='matte'] {
	--card-accent: var(--type-matte);
	--square-color: var(--type-matte-text);
}

/* ------------------------------------------------------------------ list view */

/*
	The same markup at broadsheet index density: one ruled row per story, no art, the
	slug and the stamp holding the outer columns and the headline running between them.
	Nothing is rendered twice and nothing is thrown away; the art cell is the only thing
	that leaves.
*/
.latest-cluster[data-view='list'] {
	& .story {
		grid-column: 1 / -1;
		padding: 0;
	}

	/* The card dissolves: its wash and window leave with the art, and the text runs
	   as the row directly, back on the flat carbon with its own quiet inks. */
	& .story-card {
		display: contents;
	}

	& .card-wash,
	& .card-screen,
	& .art {
		display: none;
	}

	& .story-stamp {
		color: var(--muted-2);
	}

	& .story-text {
		grid-column: 1 / -1;
		grid-row: auto;
		flex-direction: row;
		flex-wrap: wrap;
		align-items: baseline;
		gap: 0.35rem 1.1rem;
		padding-block: 0.75rem;
	}

	& .story-slug {
		flex: none;
		width: 11.5rem;
		margin: 0;
		padding: 0;
		border-block-end-width: 0;
	}

	& .slug-path {
		margin-inline-end: 0;
	}

	& .story-headline {
		flex: 1 1 18rem;
		font-size: 1rem;
		font-weight: 500;
	}

	& .story-dek {
		display: none;
	}

	& .story-stamp {
		flex: none;
		margin-block-start: 0;
		margin-inline-start: auto;
		padding-block-start: 0;
	}
}

/* ------------------------------------------------------------------ 2 columns */

@media (min-width: 700px) {
	.latest-cluster {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	/* The two chrome cells run the full width of the grid at every column count from
	   here up, so this is the only place it is said. */
	.latest-head,
	.toolbar-cell {
		grid-column: 1 / -1;
	}

	/* The card splits into its two columns here; below this line the art stacks over
	   the copy. */
	.story-card {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	/* Both halves pinned to the card's one row. Naming the column is not enough: on a
	   story whose art sits in column two, the text half behind it in the DOM has no slot
	   left to its right, and sparse auto-placement will not walk backwards, so it would
	   drop to a second row and the card would grow to the height of both. */
	.art,
	.story-text {
		grid-row: 1;
	}

	.art {
		grid-column: 1;
	}

	.story-text {
		grid-column: 2;
	}

	.story[data-lean='right'] {
		& .art {
			grid-column: 2;
		}

		& .story-text {
			grid-column: 1;
		}
	}

	/* The trending band is the width of the window here, which is the widest it ever is:
	   rank, name, kind, count and delta all get their own column and each row reads as
	   one ranked strip instead of two stacked lines. */
	.trending-link {
		grid-template-columns: 1.75rem minmax(0, 1fr) minmax(0, 8rem) auto auto;
	}

	.trending-rank {
		grid-row: 1;
	}

	.trending-kind {
		grid-column: 3;
		grid-row: 1;
		align-self: center;
	}

	.trending-count {
		grid-column: 4;
		grid-row: 1;
	}

	.trending-delta {
		grid-column: 5;
		grid-row: 1;
	}
}

/* ------------------------------------- 4 columns, and the hero splits in two */

@media (min-width: 1200px) {
	/*
		THE HERO, SHARED. The story keeps the left and trending stands on the right, over
		the picture. They are two columns of one grid, which is the whole guarantee: the
		headline, the tag row and the dek are laid in a column that stops where the panel
		starts, so none of them can reach under it however long a headline runs. The 20ch
		ceiling on the headline is a typographic measure again rather than the thing
		holding the two apart.

		The panel column is elastic between 17rem and 22rem, so the list keeps its shape
		while the story column takes the whole of the difference as the page widens.
	*/
	.lead {
		padding-block-end: clamp(1.25rem, 2.5vw, 2rem);
	}

	.lead-inner {
		display: grid;
		grid-template-columns: minmax(0, 1fr) minmax(17rem, 22rem);
		column-gap: clamp(2rem, 3.5vw, 3.5rem);
		align-items: start;
	}

	.lead-kicker {
		grid-column: 1;
		grid-row: 1;
	}

	.lead-story {
		grid-column: 1;
		grid-row: 2;
	}

	/* Out of the flow of the section's foot and into the hero beside the story, on its
	   own ground: the carbon at 90% over a 3px backdrop blur, so what shows through is
	   the picture's soft average rather than its pixels. The frame is the bright rule,
	   since here the panel is a box that bounds rather than a band that divides. */
	.lead-trending {
		grid-column: 2;
		grid-row: 1 / span 2;
		margin: 0;
		background-color: color-mix(in srgb, var(--panel) 90%, transparent);
		-webkit-backdrop-filter: blur(3px);
		backdrop-filter: blur(3px);
		border: 1px solid var(--hairline-bright);
	}

	/* Back to two lines a row: the panel is the narrowest the list ever runs, so the kind
	   sits under the name and the delta under the count. */
	.trending-link {
		grid-template-columns: 1.75rem minmax(0, 1fr) auto;
	}

	.trending-rank {
		grid-row: 1 / span 2;
	}

	.trending-kind {
		grid-column: 2;
		grid-row: 2;
		align-self: baseline;
	}

	.trending-count {
		grid-column: 3;
		grid-row: 1;
	}

	.trending-delta {
		grid-column: 3;
		grid-row: 2;
	}

	/* Four columns, and every chrome row still spans all of them: the three keep the
	   grid-column: 1 / -1 they take at two columns, so nothing here has to restate it. */
	.latest-cluster {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	/* Two stories to a row, each holding two of the four columns. The script flips the
	   lean by row as well as by position, so the art falls on the diagonal and the page
	   never grows a column of pictures down one side. */
	.story {
		grid-column: span 2;
	}

	.art {
		min-height: 17rem;
	}
}

/* -------------------------------------------------------- newsletter band */

.band {
	--focus-ring: var(--accent-ink);

	background-color: var(--accent);
	background-image: radial-gradient(circle at 50% 50%, rgb(10 10 12 / 0.14) 0 1.1px, transparent 1.7px);
	background-size: 8px 8px;
	color: var(--accent-ink);
	padding-block: clamp(2.5rem, 5vw, 4.25rem);
	scroll-margin-block-start: var(--sticky-clearance);
}

.band-inner {
	display: grid;
	gap: clamp(1.75rem, 3vw, 2.5rem);
}

.band-kicker {
	font-family: var(--font-mono);
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var(--accent-ink-soft);
	margin-block-end: 0.75rem;
}

.band-heading {
	font-family: var(--font-display);
	font-size: clamp(1.85rem, 3.6vw, 3rem);
	font-weight: 400;
	line-height: 1.02;
	letter-spacing: -0.035em;
	max-width: 18ch;
	text-wrap: balance;
}

.band-body {
	margin-block-start: 1rem;
	font-size: 0.98rem;
	line-height: 1.55;
	color: var(--accent-ink-soft);
	max-width: 46ch;
}

.band-label,
.band-legend {
	display: block;
	font-family: var(--font-mono);
	font-size: 0.72rem;
	font-weight: 700;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--accent-ink-soft);
	margin-block-end: 0.5rem;
}

.band-entry {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem;
}

.band-input {
	flex: 1 1 14rem;
	min-width: 0;
	padding: 0.8rem 0.9rem;
	border: 2px solid var(--accent-ink);
	background-color: transparent;
	color: var(--accent-ink);
	font-size: 0.95rem;

	&::placeholder {
		color: var(--accent-ink-soft);
		opacity: 1;
	}

	/* Light enough that the soft-ink placeholder still clears 4.5:1 over it. */
	&:user-invalid {
		background-color: rgb(10 10 12 / 0.07);
	}
}

.band-submit {
	flex: 0 0 auto;
	padding: 0.8rem 1.35rem;
	border: 2px solid var(--accent-ink);
	background-color: var(--accent-ink);
	color: var(--text);
	font-size: 0.9rem;
	font-weight: 700;
	cursor: pointer;

	&:hover {
		background-color: var(--panel);
		border-color: var(--panel);
	}
}

.band-lanes {
	margin-block-start: 1.35rem;
	border: 0;
	padding: 0;
	margin-inline: 0;
}

.band-fine {
	margin-block-start: 1.15rem;
	font-size: 0.76rem;
	color: var(--accent-ink-soft);
}

/* --------------------------------------------------------- the band's lanes */

/* The chip's shape, its hidden checkbox and its tick all come from chrome.css, which
   every page loads. What belongs here is the ink for this one surface: a chip standing
   on the orange plate is drawn in the plate's dark ink and fills with it when picked. */
.lane-chip-band {
	border: 1.5px solid var(--accent-ink);
	color: var(--accent-ink);

	&:hover {
		background-color: rgb(10 10 12 / 0.12);
	}

	&:has(input:checked) {
		background-color: var(--accent-ink);
		color: var(--text);

		.lane-tick {
			color: var(--accent-text);
		}
	}
}

/* The status line under the band's form. Its show-and-hide comes from chrome.css. */
.band-status {
	font-size: 0.92rem;
	font-weight: 700;
	color: var(--accent-ink);

	&[data-state] {
		margin-block-start: 1.15rem;
		padding: 0.65rem 0.85rem;
		background-color: rgb(10 10 12 / 0.1);
	}

	&[data-state='error'] {
		background-color: var(--accent-ink);
		color: var(--text);
	}
}

/* ----------------------------------------------------------- watch bands */

/*
	The four trackers, as four full-bleed bands: award watch, then the release
	calendar, the tour guide and the festival tracker. One vocabulary, borrowed from
	04's plate and rebuilt in this direction's terms: the panel ground, an orange glow,
	and the same halftone screen the story art uses. Award watch was here first and the
	other three used to be rows in a ruled table under it; nothing below is a copy of
	that section, it is that section's rules with the award names taken off them.

	Each band runs head then body. The head is the same everywhere: kicker, name, angle,
	and a date-led lockup. The body is what differs, and it is the only thing that does:
	award watch has the stage rail, the three trackers have a ruled list.

	The lockup is date-led and quiet on purpose. No flip clock, no hero-metric box: the
	date is the display element and the rest is tabular meta beneath it.

	THE COLOURS ARE NOT HERE. The [data-tracker] map that inks all four is in chrome.css,
	because the rail links that point at these bands wear the same map and the rail is on
	every page. Every accent-inked rule below names --band-accent or --band-accent-text
	and nothing names a hue.

	THE STAGE RAIL IS NOT HERE EITHER, for the same reason and since the same day the four
	trackers got their own pages: /award-watch/ draws the identical rail under its timeline,
	so the whole .stage grammar sits in chrome.css beside the map. The award band's markup
	on this page is unchanged; only the stylesheet it reaches for moved.
*/

.watch {
	/* The plate's four anchors, set here and re-pointed per band below, so the
	   gradients are written once and the variation is data rather than a second
	   copy of the artwork. */
	--plate-glow-x: 82%;
	--plate-glow-y: 6%;
	--plate-wash-angle: 118deg;
	--plate-screen-x: 90%;
	--plate-screen-y: 0%;

	/* The band changes the ground under a ring, so it re-points the ring rather
	   than restating the rule. */
	--focus-ring: var(--band-accent-text);

	position: relative;
	overflow: hidden;
	isolation: isolate;
	background-color: var(--panel);
	border-block: 1px solid var(--hairline);
	padding-block: clamp(2.75rem, 6vw, 5rem);
	scroll-margin-block-start: var(--sticky-clearance);
}

/* Four bands in a row would draw eight hairlines where five belong. A band that
   follows a band drops its own top rule and sits on the one above it. */
.watch + .watch {
	border-block-start: 0;
}

/* The mirrored lean: the lockup crosses to the left edge and the glow crosses with
   it, so the plate always throws its light from the side the date sits on. */
.watch-lockup-left {
	--plate-glow-x: 18%;
	--plate-wash-angle: 242deg;
	--plate-screen-x: 10%;
}

/* Mirroring alone would tile: bands 1 and 3 would be one plate and 2 and 4 another.
   From the third band down the glow drops and the screen follows it, which makes all
   four plates distinct while none of them stops being the same plate. */
.watch ~ .watch ~ .watch {
	--plate-glow-y: 26%;
	--plate-screen-y: 12%;
}

/*
	The glow, the wash and the screen are all inked from the band's own accent and
	scaled together by one number. Scaling the layer rather than each stop is what
	keeps the artwork in one copy: --plate-ink multiplies through both gradients and
	the screen alike, so a band is never a second plate with its own opacities to keep
	in step with this one.
*/
.watch-plate {
	position: absolute;
	inset: 0;
	z-index: 0;
	pointer-events: none;
	opacity: var(--plate-ink);
	background-image:
		radial-gradient(70% 115% at var(--plate-glow-x) var(--plate-glow-y), color-mix(in srgb, var(--band-accent) 30%, transparent) 0%, color-mix(in srgb, var(--band-accent) 10%, transparent) 46%, transparent 80%),
		linear-gradient(var(--plate-wash-angle), color-mix(in srgb, var(--band-accent) 9%, transparent) 0%, transparent 54%);

	/* The dot screen blooms out of the plate's lit corner and dissolves; the mask
	   is radial so the texture has no hard edge anywhere. Unrotated on purpose:
	   a rotated layer's mask tilts with it and slices a dead band across wide
	   viewports, and an 11deg tilt on a uniform grid was invisible anyway. */
	&::before {
		content: '';
		position: absolute;
		inset: 0;
		background-image: radial-gradient(circle at 50% 50%, var(--band-accent) 0 1.15px, transparent 1.75px);
		background-size: 9px 9px;
		opacity: 0.24;
		-webkit-mask-image: radial-gradient(95% 150% at var(--plate-screen-x) var(--plate-screen-y), #000 0%, rgb(0 0 0 / 0.5) 50%, transparent 82%);
		mask-image: radial-gradient(95% 150% at var(--plate-screen-x) var(--plate-screen-y), #000 0%, rgb(0 0 0 / 0.5) 50%, transparent 82%);
	}
}

.watch-inner {
	position: relative;
	z-index: 1;
}

.watch-kicker {
	display: flex;
	align-items: center;
	gap: 0.6rem;
	font-family: var(--font-display);
	font-size: 0.7rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--band-accent-text);
	margin-block-end: clamp(0.9rem, 1.8vw, 1.25rem);

	&::before {
		content: '';
		width: 1.75rem;
		height: 3px;
		background-color: var(--band-accent);
	}
}

.watch-name {
	font-family: var(--font-display);
	font-size: clamp(2.1rem, 5.4vw, 4rem);
	font-weight: 400;
	line-height: 0.97;
	letter-spacing: -0.04em;
	color: var(--text);
	max-width: 16ch;
	text-wrap: balance;
}

.watch-angle {
	margin-block-start: clamp(1rem, 1.8vw, 1.4rem);
	font-size: clamp(1rem, 1.6vw, 1.24rem);
	line-height: 1.5;
	color: var(--text);
	max-width: 54ch;
	text-wrap: pretty;
}

/*
	The way out of a band and into that tracker's own page, added the day the four pages
	landed. Quiet by design and deliberately not the heading: the band is today's news, and
	its page is the reference behind it, so the link sits under the angle at meta scale.
	The arrow steps forward on hover, which is the only motion in the head.
*/
.watch-more {
	margin-block-start: clamp(0.9rem, 1.6vw, 1.15rem);

	& a {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		padding-block-end: 0.15rem;
		font-family: var(--font-mono);
		font-size: 0.78rem;
		letter-spacing: 0.06em;
		color: var(--band-accent-text);
		text-decoration: none;
		border-block-end: 1px solid color-mix(in srgb, var(--band-accent) 45%, transparent);

		&:hover {
			border-block-end-color: var(--band-accent);

			.icon {
				transform: translateX(0.2rem);
			}
		}
	}

	.icon {
		width: 0.85em;
		height: 0.85em;
		transition: transform 0.18s ease;
	}
}

/* Stacked below the angle on small screens, an edge lockup beside the title from
   1024 up. The date leads; one quiet mono line carries the rest. */
.watch-when {
	margin-block-start: clamp(1.75rem, 3.2vw, 2.5rem);
	padding-block-start: clamp(1.5rem, 2.6vw, 2rem);
	border-block-start: 1px solid var(--hairline-bright);
}

/* The date wears the band's color: at display scale it is the loudest carrier of
   the theme on the page, and all four accent inks clear the large-text floor with
   room to spare. */
.watch-date {
	font-family: var(--font-display);
	font-size: clamp(2rem, 4.6vw, 3.2rem);
	line-height: 0.95;
	letter-spacing: -0.035em;
	color: var(--band-accent-text);
}

.watch-meta {
	display: flex;
	flex-wrap: wrap;
	column-gap: 0.6rem;
	margin-block-start: 0.7rem;
	font-family: var(--font-mono);
	font-size: 0.8rem;
	letter-spacing: 0.06em;
	color: var(--muted);
	font-variant-numeric: tabular-nums;

	& span + span::before {
		content: '\00b7';
		margin-inline-end: 0.6rem;
		color: var(--muted);
	}
}

/* ------------------------------------------------------------- watch rows */

/*
	The body of the three tracker bands: what each one is watching, in date order.
	A ruled list, not a table and not four cards. The item carries the row, the dated
	line sits opposite it in mono, and the tag is the quietest thing in the row.

	The dated line is where the band's colour lives in the body: every row's date is set
	in the band accent, so a reader scrolling the list is reading the band rather than
	four lists that happen to sit under different headings. The tag beside it stays
	grey, because the row already carries one colour and the tag is the quietest thing
	in it.

	One row per band can be marked urgent in the data. It takes the accent rule at its
	leading edge and the weight on its dated line, which is the same discipline the rest
	of the page runs: an accent is a rule or it is the ink made for the ground, never a
	highlight painted behind text. Two channels mark it, neither of them hue, which is
	what keeps the mark readable once every date in the list is already coloured.
*/
.watch-rows {
	margin-block-start: clamp(2rem, 3.5vw, 2.75rem);
	border-block-start: 1px solid var(--hairline-bright);
}

.watch-row {
	position: relative;
	display: grid;
	gap: 0.35rem;
	padding-block: clamp(0.95rem, 1.7vw, 1.25rem);
	border-block-end: 1px solid var(--band-row-rule);
}

/* The rule is set outside the text column so the marked row does not indent and
   break the list's leading edge. It stays inside the wrap's smallest gutter. */
.watch-row-urgent {
	&::before {
		content: '';
		position: absolute;
		inset-block: clamp(0.95rem, 1.7vw, 1.25rem);
		inset-inline-start: -0.8rem;
		width: 3px;
		background-color: var(--band-accent);
	}

	.watch-row-meta {
		font-weight: 700;
	}
}

.watch-row-lede {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: 0.7rem;
	row-gap: 0.15rem;
}

.watch-row-primary {
	font-size: clamp(1rem, 1.5vw, 1.15rem);
	font-weight: 600;
	line-height: 1.3;
	color: var(--text);
}

.watch-row-secondary {
	font-size: 0.9rem;
	line-height: 1.4;
	color: var(--muted);
}

.watch-row-when {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	column-gap: 0.75rem;
	font-family: var(--font-mono);
	font-variant-numeric: tabular-nums;
}

.watch-row-meta {
	font-size: 0.82rem;
	letter-spacing: 0.04em;
	color: var(--band-accent-text);
}

.watch-row-tag {
	font-size: 0.68rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var(--muted);
}

/* ---------------------------------------------------------------- podcast */

.podcast {
	padding-block: clamp(3.25rem, 7.5vw, 6rem);
}

.podcast-inner {
	text-align: center;
}

.podcast-heading {
	display: inline-flex;
	flex-direction: column;
	align-items: center;
	gap: 0.85rem;
	font-family: var(--font-mono);
	font-size: 0.72rem;
	font-weight: 400;
	letter-spacing: 0.2em;
	text-transform: uppercase;
	color: var(--muted-2);
	margin-block-end: 1.15rem;

	.icon {
		font-size: 1.5rem;
	}
}

.podcast-line {
	font-size: clamp(1rem, 1.8vw, 1.15rem);
	line-height: 1.5;
	color: var(--muted);
	max-width: 46ch;
	margin-inline: auto;
	text-wrap: balance;
}

/* ------------------------------------------------------------ breakpoints */

/*
	TAP TARGETS AND MICRO-TYPE below the desktop layout (audited 2026-08-28). The topic
	chips, the card tag rows and the trending rail's meta were all sized for a mouse and
	a wide screen: 31px chips, 19px tag words, and 9.6px labels on the trending rows,
	which is under the size a phone can render legibly at all.

	Only the boxes and the two smallest labels move. The chips keep their type scale, the
	tag row keeps its grammar, and nothing here reaches a width where the desktop layout
	is running.
*/
@media (width < 64rem) {
	.chip {
		min-height: 2.5rem;
		padding-block: 0.5rem;
	}

	.lead-tags {
		align-items: center;
		row-gap: 0.1rem;
	}

	a.tag-genre,
	a.tag-type {
		display: inline-flex;
		align-items: center;
		min-height: 2.5rem;
	}

	/* The river card's own genre/type pair, which wears different class names from the
	   lead's tag row but is the same pair of links into the same two hubs. The card is
	   not itself one big link - the headline is - so these are genuinely the only way
	   into a hub from a card and have to be hittable. */
	a.slug-genre,
	a.slug-type {
		display: inline-flex;
		align-items: center;
		min-height: 2.5rem;
	}

	/* The view pair beside the topic bank, and the way back up out of a river page.
	   Both were around 22-32px. */
	.view-toggle {
		min-height: 2.5rem;
	}

	.post-back,
	.river-pagination-next {
		min-height: 2.5rem;
	}

	/* One trending row is one target across the panel's full width; it was 30px tall. */
	.trending-link {
		padding-block: 0.6rem;
	}

	/* The whole trending row is one tap target already; these two labels were simply
	   below the floor a phone can set type at. */
	.trending-kind,
	.trending-delta {
		font-size: 0.68rem;
	}

	.trending-count {
		font-size: 0.7rem;
	}
}

@media (min-width: 768px) {
	/* The tracker row goes two-column here: what is being watched on the left, when
	   it lands on the right edge in mono. The dated line and the tag share a
	   baseline with the item's name rather than sitting under it. */
	.watch-row {
		grid-template-columns: minmax(0, 1fr) auto;
		align-items: baseline;
		column-gap: clamp(1.5rem, 4vw, 3rem);
	}

	.watch-row-when {
		justify-content: flex-end;
		text-align: end;
	}
}

@media (min-width: 1024px) {
	.band-inner {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
		column-gap: clamp(2.5rem, 5vw, 5rem);
		align-items: start;
	}

	/* The band head goes two-column: the name and angle on one side, the date
	   lockup on the opposite edge beside the title. The lockup opens on its own
	   accent dash, mirroring the kicker across the section. */
	.watch-head {
		display: grid;
		grid-template-columns: minmax(0, 1fr) auto;
		column-gap: clamp(2.5rem, 5vw, 5rem);
		align-items: start;
	}

	.watch-when {
		display: flex;
		flex-direction: column;
		align-items: flex-end;
		justify-self: end;
		text-align: right;
		margin-block-start: 0;
		padding-block-start: 0;
		border-block-start: none;

		&::before {
			content: '';
			width: 1.75rem;
			height: 3px;
			background-color: var(--band-accent);
			margin-block-start: 0.3rem;
			margin-block-end: clamp(0.9rem, 1.8vw, 1.25rem);
		}
	}

	.watch-meta {
		justify-content: flex-end;
	}

	/* The mirrored lean, and the whole of it: the two head columns swap places and
	   the lockup aligns to the left edge it now sits on. The title block keeps its
	   own left alignment either way, because a 54ch paragraph set flush right is a
	   mirror nobody can read. */
	.watch-lockup-left {
		.watch-head {
			grid-template-columns: auto minmax(0, 1fr);
		}

		.watch-lede {
			grid-column: 2;
			grid-row: 1;
		}

		.watch-when {
			grid-column: 1;
			grid-row: 1;
			align-items: flex-start;
			justify-self: start;
			text-align: left;
		}

		.watch-meta {
			justify-content: flex-start;
		}
	}

}

/* --------------------------------------------------------- reduced motion */

/* global.css already collapses durations site-wide, but the lead's entrance carries a
   delay and a backwards fill, which would hold its opening frame for a fifth of a
   second before snapping. Removing the animations outright leaves the finished page,
   which is the point. */
@media (prefers-reduced-motion: reduce) {
	.lead-tags,
	.lead-tags::after {
		animation: none !important;
	}

	.chip,
	.view-toggle {
		transition: none !important;
	}
}
