/* ==========================================================================
   The Waarom stream
   --------------------------------------------------------------------------
   Three vertical columns, each drifting at its own speed, each with its own
   card treatment. One design system: every colour below is an existing theme
   token, and the three columns are separated by tone and by how much of an
   article they show, never by a new palette.

   Scoped entirely to .nsn-stream, so nothing here can reach the Journal index
   at /wanneer/ or any other route.
   ========================================================================== */

.nsn-stream {
	/*
	 * The three grounds. Ink, then two barely-lifted tones from the bone
	 * alpha scale the rest of the site already uses - enough to read as three
	 * distinct columns on a dark page, not enough to read as three websites.
	 */
	--nsn-stream-c1: transparent;
	--nsn-stream-c2: var(--nsn-bone-08);
	--nsn-stream-c3: var(--nsn-bone-14);

	/*
	 * Where the band starts, and how tall it is.
	 *
	 * Declared here on the section rather than on the columns, because the
	 * runway is the columns' parent and has to see it too - a custom property
	 * only inherits downward, and an undefined one invalidates the whole
	 * declaration it appears in. Held on .nsn-stream, both read it.
	 *
	 * --nsn-header-h is the header's type band; the header paints a slightly
	 * taller gradient than that, so the extra clamp keeps the first photograph
	 * from running up under it.
	 */
	--nsn-stream-top: calc(var(--nsn-header-h) + clamp(1rem, 2.2vh, 2rem));

	/* Card rhythm. One value sets the gaps between and inside the cards. */
	--nsn-stream-pad: clamp(1rem, 1.6vw, 2rem);

	/*
	 * Type per column. Column 1 is the reading column and stays at the
	 * Journal's index size; 2 and 3 drop the description, so their titles take
	 * that space back and carry the column instead.
	 */
	--nsn-stream-title-1: clamp(1.0625rem, 0.85rem + 0.6vw, 1.375rem);
	--nsn-stream-title-2: clamp(1.375rem, 0.95rem + 1.35vw, 2.25rem);
	--nsn-stream-title-3: clamp(1.5rem, 1rem + 1.7vw, 2.625rem);

	position: relative;
	background: var(--nsn-ink);
	color: var(--nsn-bone);

	/*
	 * Room between the end of the stream and the top of the footer, so the
	 * last cards finish against space rather than against the footer's edge.
	 * The band itself also leaves air under its final card - see TAIL in
	 * journal-stream.js - so the two together give the ending somewhere to
	 * breathe.
	 */
	padding-bottom: clamp(2.5rem, 7vh, 6rem);

	/*
	 * Deliberately NOT overflow: hidden.
	 *
	 * The columns are sticky, and an ancestor with a clipping overflow becomes
	 * their scroll container - which would pin them to this box instead of to
	 * the viewport and stop the effect dead. Each column clips its own track,
	 * so nothing escapes sideways anyway.
	 */
}

/*
 * Same reason, one level up: base.css sets overflow-x: hidden on the body,
 * which makes the body a scroll container and disables sticky throughout the
 * page. clip does the same job without that side effect. Scoped to this
 * page's own body class, exactly as the About page does it, so no other route
 * changes.
 */
body.nsn-stream-page {
	overflow-x: clip;
}

/*
 * The scroll runway. Its height is the scroll distance the columns are driven
 * by, handed over from the script once all three have been measured: enough
 * for the most demanding of them to bring its own last card fully into view.
 * Without the script the custom property is never set and this collapses to
 * the height of its contents.
 */
.nsn-stream__runway {
	position: relative;
}

.nsn-stream.is-running .nsn-stream__runway {
	height: calc(100svh - var(--nsn-stream-top) + var(--nsn-stream-runway, 0px));
}

/* --------------------------------------------------------------------------
   The three columns

   A viewport-height band. The tracks inside it are taller than the screen and
   are clipped to it, so the document is bounded by the runway rather than by
   the content - and each track stops once its own last card has arrived, so
   nothing is clipped away permanently.
   -------------------------------------------------------------------------- */
.nsn-stream__cols {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));

	/*
	 * Below the fixed header, with a little air under it.
	 *
	 * --nsn-header-h is the header's type band; the header paints a slightly
	 * taller gradient than that, so starting exactly at the token would let
	 * the first photograph run up under it. The offset is added to the top and
	 * taken off the height, so the band still ends at the foot of the screen.
	 */
	height: calc(100svh - var(--nsn-stream-top));
	margin-top: var(--nsn-stream-top);
}

/*
 * Held against the top of the screen while the runway scrolls past beneath it.
 * That is what turns page scroll into column travel: the band stays put, the
 * tracks inside it move by a fraction of the distance scrolled.
 */
.nsn-stream.is-running .nsn-stream__cols {
	position: sticky;
	top: var(--nsn-stream-top);
	margin-top: 0;
}

.nsn-stream__col {
	position: relative;
	overflow: hidden;
	min-width: 0;
}

/* Thin separators, drawn between the columns only. */
.nsn-stream__col + .nsn-stream__col {
	border-left: 1px solid var(--nsn-rule);
}

.nsn-stream__col--1 {
	background: var(--nsn-stream-c1);
}

.nsn-stream__col--2 {
	background: var(--nsn-stream-c2);
}

.nsn-stream__col--3 {
	background: var(--nsn-stream-c3);
}

/*
 * The moving part. Transform only - no top, no margin - so a frame costs a
 * composite and never a layout.
 */
.nsn-stream__track {
	display: flex;
	flex-direction: column;
	will-change: transform;
}

/* --------------------------------------------------------------------------
   Cards
   -------------------------------------------------------------------------- */
.nsn-stream__card {
	border-bottom: 1px solid var(--nsn-rule);
}

.nsn-stream__link {
	display: block;
	padding: var(--nsn-stream-pad);
	color: inherit;
	text-decoration: none;
	transition: opacity var(--nsn-dur-fast) var(--nsn-ease);
}

.nsn-stream__media {
	margin: 0 0 var(--nsn-stream-pad);
	overflow: hidden;

	/* A steady frame, so a portrait and a landscape photograph occupy the same
	   space and the column's rhythm does not change with the picture. */
	aspect-ratio: 4 / 3;
}

.nsn-stream__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

.nsn-stream__body {
	display: flex;
	flex-direction: column;
	gap: 0.5em;
}

.nsn-stream__title {
	margin: 0;
	font-weight: 700;
	line-height: 1.08;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

.nsn-stream__excerpt {
	margin: 0;
	font-size: var(--nsn-step-sm);
	line-height: 1.5;
	color: var(--nsn-bone-72);
}

.nsn-stream__date {
	font-size: var(--nsn-step-xs);
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--nsn-bone-46);
}

/* --- per-column treatment --- */
.nsn-stream__col--1 .nsn-stream__title {
	font-size: var(--nsn-stream-title-1);
}

.nsn-stream__col--2 .nsn-stream__title {
	font-size: var(--nsn-stream-title-2);
}

.nsn-stream__col--3 .nsn-stream__title {
	font-size: var(--nsn-stream-title-3);
	/* The quietest column carries the loudest type, so it is set a shade back
	   from full bone to keep the three columns in balance. */
	color: var(--nsn-bone);
}

/*
 * Hover is deliberately almost nothing: the card lifts its own contrast and
 * that is all. No scale, no shadow, no movement - the card must not shift
 * under a cursor that is about to click it, and nothing here may move the
 * column, which answers to the scroll position alone.
 */
.nsn-stream__link:hover .nsn-stream__excerpt,
.nsn-stream__link:focus-visible .nsn-stream__excerpt {
	color: var(--nsn-bone);
}

.nsn-stream__link:focus-visible {
	outline: 2px solid var(--nsn-bone);
	outline-offset: -4px;
}

.nsn-stream__empty {
	padding: calc(var(--nsn-header-h) + var(--nsn-space-5)) var(--nsn-gutter);
	color: var(--nsn-bone-72);
}

/*
 * Static fallback - no JavaScript, or the animation declined to run. The band
 * stops being a fixed-height window and simply grows with its content, so
 * every article is reachable by ordinary scrolling.
 */
.nsn-stream:not(.is-running) .nsn-stream__cols {
	height: auto;
	min-height: calc(100svh - var(--nsn-stream-top));
}

/* --------------------------------------------------------------------------
   Tablet: the three columns hold, the type steps down to fit them.
   -------------------------------------------------------------------------- */
@media (max-width: 1100px) {
	.nsn-stream {
		--nsn-stream-pad: clamp(0.75rem, 1.4vw, 1.25rem);
		--nsn-stream-title-1: clamp(0.9375rem, 0.8rem + 0.5vw, 1.125rem);
		--nsn-stream-title-2: clamp(1.125rem, 0.85rem + 1vw, 1.625rem);
		--nsn-stream-title-3: clamp(1.25rem, 0.9rem + 1.2vw, 1.875rem);
	}

	.nsn-stream__excerpt {
		font-size: var(--nsn-step-xs);
	}
}

/* --------------------------------------------------------------------------
   Phone

   One column, standing still. Three animated columns on a phone would be
   three unreadable ones, so the layout stacks, the loop's duplicate pass is
   gone, and the page scrolls the way every other page on the site does.
   -------------------------------------------------------------------------- */
@media (max-width: 760px) {
	.nsn-stream {
		--nsn-stream-pad: var(--nsn-gutter);
		--nsn-stream-title-1: clamp(1.25rem, 5.2vw, 1.625rem);
		--nsn-stream-title-2: clamp(1.25rem, 5.2vw, 1.625rem);
		--nsn-stream-title-3: clamp(1.25rem, 5.2vw, 1.625rem);
	}

	.nsn-stream__cols,
	.nsn-stream.is-running .nsn-stream__cols {
		grid-template-columns: minmax(0, 1fr);
		height: auto;
	}

	.nsn-stream__col + .nsn-stream__col {
		border-left: 0;
	}

	/*
	 * One column, and only the first one.
	 *
	 * Every column carries every article, so stacking all three on a phone
	 * would hand the reader each article three times in a row, in three
	 * treatments - which reads as duplicated content rather than as a design.
	 * Column 1 is the complete card, so it is the one that survives: each
	 * article appears exactly once, with its picture, title, description and
	 * date. Nothing is lost, because columns 2 and 3 hold the same posts.
	 */
	.nsn-stream__col--2,
	.nsn-stream__col--3 {
		display: none;
	}

	.nsn-stream__track {
		/* Whatever the script last set is irrelevant at this width. */
		transform: none !important;
		will-change: auto;
	}

	.nsn-stream__media {
		aspect-ratio: 16 / 10;
	}
}

/* --------------------------------------------------------------------------
   Reduced motion: the same static page the no-JavaScript reader gets.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
	.nsn-stream__cols,
	.nsn-stream.is-running .nsn-stream__cols {
		height: auto;
		min-height: 0;
	}

	.nsn-stream__track {
		transform: none !important;
		will-change: auto;
	}

	.nsn-stream__link {
		transition: none;
	}
}
