/* Diskurs grid */

/*
 * Tuning parameters. Everything adjusted against the visual draft lives in this
 * one block — gutters, row spacing and the vertical offset of every slot in
 * each of the four patterns. Nothing below this block carries a raw value.
 *
 * Naming: --dg-p<pattern>-<slot>, slots counted from 1.
 */
.diskurs-grid {
	--dg-gap: 24px;
	--dg-row-gap: 96px;

	/* The offset height, and the one value to tune. Every pattern value below is
	   a multiple of it, so raising it scales the whole rhythm without changing
	   its relations. Set it on .diskurs-grid in DevTools to try a value live.
	   The breakpoints below restate the step instead of twelve values. */
	--dg-step: 56px;

	/* Multiples of --dg-step per pattern and slot. Every neighbouring pair differs
	   by exactly 1.5 steps, so the gap between two tiles is the same everywhere
	   and only its direction changes: p0 rises, p1 falls, p2 dips, p3 peaks. That
	   is what keeps the four patterns distinguishable once the differences are
	   equal — the shape carries them, not the amount. */
	--dg-p0-1: calc(0 * var(--dg-step));
	--dg-p0-2: calc(1.5 * var(--dg-step));
	--dg-p0-3: calc(3 * var(--dg-step));

	--dg-p1-1: calc(3 * var(--dg-step));
	--dg-p1-2: calc(1.5 * var(--dg-step));
	--dg-p1-3: calc(0 * var(--dg-step));

	--dg-p2-1: calc(1.5 * var(--dg-step));
	--dg-p2-2: calc(0 * var(--dg-step));
	--dg-p2-3: calc(1.5 * var(--dg-step));

	--dg-p3-1: calc(1.5 * var(--dg-step));
	--dg-p3-2: calc(3 * var(--dg-step));
	--dg-p3-3: calc(1.5 * var(--dg-step));

	/* Phone offsets. The phone block packs tiles by flow, so a pair on one line can
	   come from two different rows — "left" and "right" stop being properties of a
	   slot, and the values above cannot simply be scaled down.
	   Instead each row carries a base by pattern and each slot adds one step.
	   The bases are 0 / 3 / 2 / 1 steps, which is what makes the whole thing hold
	   together: neighbours inside a row differ by one step, and across a row
	   boundary the base difference is +3 or −1 steps — never 0, one or two steps,
	   which are the only values that could cancel out against the slot increment.
	   Because every value is a multiple of the step, the guarantee survives any
	   step, so this is a single knob: raise it and every offset grows with it. */
	--dg-m-step: 16px;
	--dg-m-p0: 0px;
	--dg-m-p1: calc(3 * var(--dg-m-step));
	--dg-m-p2: calc(2 * var(--dg-m-step));
	--dg-m-p3: var(--dg-m-step);

	/* Hover feedback. Set to 1 for no hover state at all. */
	--dg-hover-opacity: .85;

	/* Scroll reveal. Duration and easing are WPBakery's bottom-to-top, which the
	   About page uses, so the grid reads as part of the same site. The lift is a
	   fixed distance rather than WPBakery's 10%: percentages resolve against the
	   element's own height, and tile heights differ widely here (align-self: start
	   plus mixed aspect ratios), so tall tiles would travel much further than flat
	   ones. */
	--dg-anim-lift: 24px;
	--dg-anim-duration: 700ms;
	--dg-anim-ease: cubic-bezier(.175, .885, .32, 1.275);
	--dg-anim-stagger: 90ms;
}

.diskurs-grid__rows {
	display: flex;
	flex-direction: column;
	gap: var(--dg-row-gap);
}

.diskurs-row {
	display: grid;
	grid-template-columns: repeat(12, 1fr);
	gap: var(--dg-gap);
	align-items: start;
}

.diskurs-item {
	grid-column: var(--dg-start) / span var(--dg-span);
	align-self: start;
	margin: 0;
}

/* Vertical offsets. Slot position comes from the DOM, the value from the block above. */
.diskurs-row--p0 > .diskurs-item:nth-child(1) { margin-top: var(--dg-p0-1); }
.diskurs-row--p0 > .diskurs-item:nth-child(2) { margin-top: var(--dg-p0-2); }
.diskurs-row--p0 > .diskurs-item:nth-child(3) { margin-top: var(--dg-p0-3); }

.diskurs-row--p1 > .diskurs-item:nth-child(1) { margin-top: var(--dg-p1-1); }
.diskurs-row--p1 > .diskurs-item:nth-child(2) { margin-top: var(--dg-p1-2); }
.diskurs-row--p1 > .diskurs-item:nth-child(3) { margin-top: var(--dg-p1-3); }

.diskurs-row--p2 > .diskurs-item:nth-child(1) { margin-top: var(--dg-p2-1); }
.diskurs-row--p2 > .diskurs-item:nth-child(2) { margin-top: var(--dg-p2-2); }
.diskurs-row--p2 > .diskurs-item:nth-child(3) { margin-top: var(--dg-p2-3); }

.diskurs-row--p3 > .diskurs-item:nth-child(1) { margin-top: var(--dg-p3-1); }
.diskurs-row--p3 > .diskurs-item:nth-child(2) { margin-top: var(--dg-p3-2); }
.diskurs-row--p3 > .diskurs-item:nth-child(3) { margin-top: var(--dg-p3-3); }

.diskurs-item__link {
	display: block;
	color: inherit;
	text-decoration: none;
}

/* The theme animates an underline in on every link inside .entry-content
   (style.css:3066). Unwanted on a tile whose whole area is the link. */
.entry-content .diskurs-item__link::after {
	content: none;
}

.diskurs-item__link:focus-visible {
	outline: 2px solid currentColor;
	outline-offset: 4px;
}

/* aspect-ratio is set inline from the original image dimensions, so the box is
   reserved before anything loads and nothing jumps. */
.diskurs-item__media {
	overflow: hidden;
	background: #f2f2f2;
}

.diskurs-item__media > img,
.diskurs-item__media > video {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: opacity 200ms ease;
}

/* The theme margins every image inside .entry-content (style.css: figure.size-full,
   img, p > img). Inside a fixed aspect-ratio box that pushes the image down, so the
   box background shows as a grey bar on top and the same amount is clipped below. */
.entry-content .diskurs-item__media > img,
.entry-content .diskurs-item__media > video {
	margin: 0;
}

.diskurs-item__link:hover .diskurs-item__media > img,
.diskurs-item__link:hover .diskurs-item__media > video {
	opacity: var(--dg-hover-opacity);
}

.diskurs-item__title {
	margin: 12px 0 0;
	font-size: 15px;
	font-weight: 600;
	line-height: 1.3;
}

.diskurs-item__line {
	margin: 2px 0 0;
	font-size: 14px;
	line-height: 1.4;
	opacity: .7;
}

.diskurs-grid__more {
	display: block;
	margin: var(--dg-row-gap) auto 0;
	padding: 12px 28px;
	background: none;
	border: 1px solid currentColor;
	font: inherit;
	cursor: pointer;
}

.diskurs-grid__more[aria-busy="true"] {
	opacity: .5;
	cursor: default;
}

.diskurs-grid__notice {
	margin: 12px 0 0;
	text-align: center;
	font-size: 14px;
	opacity: .7;
}

.diskurs-grid__notice:empty {
	display: none;
}

/*
 * Scroll reveal. The hidden start state hangs on --animated, a class diskurs.js
 * sets itself — with JS off the class never appears and every tile is simply
 * visible, which is why the hidden state is not in the base rule.
 *
 * The delay counts slots inside the row, not tiles across the grid. Each row
 * animates when that row enters the viewport, so a running counter would push
 * later rows to delays of several seconds.
 */
.diskurs-grid--animated .diskurs-item {
	--dg-anim-delay: 0ms;
	opacity: 0;
	transform: translateY(var(--dg-anim-lift));
}

.diskurs-grid--animated .diskurs-item:nth-child(2) { --dg-anim-delay: var(--dg-anim-stagger); }
.diskurs-grid--animated .diskurs-item:nth-child(3) { --dg-anim-delay: calc(var(--dg-anim-stagger) * 2); }

.diskurs-grid--animated .diskurs-item--revealed {
	opacity: 1;
	transform: none;
	transition:
		opacity var(--dg-anim-duration) var(--dg-anim-ease) var(--dg-anim-delay),
		transform var(--dg-anim-duration) var(--dg-anim-ease) var(--dg-anim-delay);
}

/*
 * Tablet. The briefing asks for 8 columns with s=3 / m=4 / l=8, which does not
 * work: rows are built server-side for 12 columns, so 12 of 20 rows overflow an
 * 8-track grid (any row with an l plus a second tile) and 6 tiles carry a start
 * column above 8. Keeping 12 columns and only tightening gutters and offsets
 * leaves the row structure intact, which is what the layout depends on.
 */
@media (min-width: 768px) and (max-width: 1023px) {
	.diskurs-grid {
		--dg-gap: 16px;
		--dg-row-gap: 64px;
		--dg-step: 28px;
	}
}

/*
 * Phone: one to two tiles per line, offset against each other. §8 asks for a
 * single column, but that hides that the grid continues — deliberate departure,
 * Ben 2026-08-17.
 *
 * The editorial size keeps its meaning here, so editors steer the phone layout
 * with the field they already have and no mobile-only meta field is needed:
 * large claims the full width, the two smaller sizes share it.
 *
 * For that to work the row containers stop generating boxes and every tile
 * becomes an item of one continuous two-column grid. Only then can m and s pair
 * up *across* row boundaries; with a grid per row the partner of a full-width
 * large tile would be stranded half width on a line of its own, which is the case
 * in 11 of the current 20 rows. The DOM keeps the rows, so row_index, the pattern
 * classes, the offset rules and load-more are untouched — only the boxes go.
 *
 * The cost, accepted knowingly: a pair can now come from two different rows, so a
 * slot no longer maps to a column and the offsets cannot be biased to one side.
 * They come from the base-plus-step formula in the block above instead.
 *
 * --dg-step is unused here: all twelve pattern values are replaced outright,
 * because the flow needs a different distribution, not a smaller one.
 */
@media (max-width: 767px) {
	.diskurs-grid {
		--dg-gap: 16px;
		--dg-row-gap: 40px;

		--dg-p0-1: var(--dg-m-p0);
		--dg-p0-2: calc(var(--dg-m-p0) + var(--dg-m-step));
		--dg-p0-3: calc(var(--dg-m-p0) + 2 * var(--dg-m-step));

		--dg-p1-1: var(--dg-m-p1);
		--dg-p1-2: calc(var(--dg-m-p1) + var(--dg-m-step));
		--dg-p1-3: calc(var(--dg-m-p1) + 2 * var(--dg-m-step));

		--dg-p2-1: var(--dg-m-p2);
		--dg-p2-2: calc(var(--dg-m-p2) + var(--dg-m-step));
		--dg-p2-3: calc(var(--dg-m-p2) + 2 * var(--dg-m-step));

		--dg-p3-1: var(--dg-m-p3);
		--dg-p3-2: calc(var(--dg-m-p3) + var(--dg-m-step));
		--dg-p3-3: calc(var(--dg-m-p3) + 2 * var(--dg-m-step));
	}

	/* Column gap and line gap are set apart here: the flow grid would otherwise
	   use one value for both axes and lines would sit as tight as columns. */
	.diskurs-grid__rows {
		display: grid;
		grid-template-columns: repeat(2, 1fr);
		column-gap: var(--dg-gap);
		row-gap: var(--dg-row-gap);
		align-items: start;
	}

	.diskurs-row {
		display: contents;
	}

	/* Flow placement, which is what lets the packing cross row boundaries.
	   Overrides grid-column from this stylesheet rather than --dg-span and
	   --dg-start, which are inline on the element and would win. */
	.diskurs-item {
		grid-column: auto / span 1;
	}

	.diskurs-item--l {
		grid-column: auto / span 2;
	}
}

@media (prefers-reduced-motion: reduce) {
	.diskurs-item__media > img,
	.diskurs-item__media > video {
		transition: none;
	}

	/* Static grid. diskurs.js additionally leaves the videos unobserved, so with
	   preload="none" they never load and the poster stays. */
	.diskurs-grid--animated .diskurs-item,
	.diskurs-grid--animated .diskurs-item--revealed {
		opacity: 1;
		transform: none;
		transition: none;
	}
}
