/* ═════════════════════════════════════════════════════════════════════════════
 * THE RESOURCES PAGE — Build-19
 *
 * Five sections: a bleed hero with four ways in, a rail of customer cards, a hairline
 * list, an ink band holding a carousel of press releases, and a table of outbound
 * citations. Bone throughout except the fourth.
 *
 * ── WHY THIS IS ITS OWN SHEET ───────────────────────────────────────────────
 *
 * assets/ds/pages.css loads on roughly twenty pages and is already the largest
 * stylesheet on the site. Three of the four components below exist on this page and
 * nowhere else, and two of them are carousels, which is a lot of rules to put in every
 * page's critical CSS to serve one. So this file is enqueued on page-resources-ds.php
 * alone and depends on fluent-commerce-ds-pages, exactly as partners.css, customers.css
 * and pricing.css do.
 *
 * ONE THING STAYED BEHIND. The knowledge hub's row — .fc-resources__list and its
 * children — is still in pages.css, because it is unchanged from before Build-19 and
 * because blog.css names that block as the original its own /news/ rows are copied from.
 * Moving it would be a rename that updates a cross-reference and changes nothing.
 * See THE RESOURCES ROW there, and THE NEWS LIST in blog.css.
 *
 * ── WHAT THE EXPORT ASKS FOR THAT IS NOT HERE ───────────────────────────────
 *
 * The rail's two 120px edge fades. The export declares .fc-case-rail::before and
 * ::after with a width, a z-index and no background at all, so they paint nothing —
 * and the rail sits inside the ruled column rather than bleeding to the viewport, so
 * there is no page edge for a fade to protect. Adding one would be inventing a device
 * rather than implementing one. Flagged.
 *
 * ── TYPE ────────────────────────────────────────────────────────────────────
 *
 * Every `var(--type-body-18)` in the export means 18px and is written --type-body-16
 * here. In this theme --type-body-18 is the 20px display-adjacent step and
 * --type-body-16 is the paragraph size on every page. See the token table at the head
 * of layout.css, and "body copy is always 18" in the design's own decisions.md.
 * ══════════════════════════════════════════════════════════════════════════ */

/* ═════════════════════════════════════════════════════════════════════════════
 * THE HERO
 *
 * .fc-contact-hero's construction, to the pixel: a bleed section that gives up its own
 * right-hand padding, a copy column that pays the ruled inset itself, a hairline seam
 * column, and artwork absolutely positioned inside it over a 360px floor.
 *
 * FLAG — THIS IS THE FOURTH PAGE DRAWING THIS SHAPE. .fc-kb-hero, .fc-trust-hero and
 * .fc-contact-hero already restate it, and the note above the third of them in pages.css
 * says plainly that "if a third page draws this shape, that is the moment to move them"
 * into layout.css. This is the fourth and it restates them again, because the lift means
 * re-classing and re-seeding three pages that are signed off — a change to three pages
 * nobody asked to change, made in the margin of a fourth. Worth doing deliberately.
 * ══════════════════════════════════════════════════════════════════════════ */

/*
 * The section keeps its top and bottom padding at zero and its right padding at the
 * gutter, so the artwork column ends exactly on the ruled column's right vertical. Only
 * the left is given up, and the copy column pays it back below.
 */
body.fc-ds .fc-section.fc-resources-hero {
	padding: 0 var(--gutter-page) 0 0;
}

body.fc-ds .fc-resources-hero__split {
	gap: 0;
	align-items: stretch;
}

/*
 * --sp-32 where the export says 40. There is no 40 on the spacing scale and adding one
 * for a single gap is a token nobody else would use; .fc-contact-hero made the same
 * substitution for the same reason and said so.
 */
body.fc-ds .fc-resources-hero__copy {
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: var(--sp-32);
	padding: var(--sp-54) var(--sp-54) var(--sp-54) calc(var(--gutter-page) + 40px);
}

body.fc-ds .fc-resources-hero__intro {
	display: flex;
	flex-direction: column;
	gap: var(--sp-24);
}

/* .fc-display-section carries the face, the 62px, the flush ramp and the tracking. */
body.fc-ds .fc-resources-hero__title {
	color: var(--text-on-light);
}

/*
 * 380px, which holds "Everything we know, written down." on two lines beside a headline
 * that is one word. Wider and the sentence outruns the title it belongs to.
 */
body.fc-ds .fc-resources-hero__lede {
	max-width: 380px;
}

/*
 * The four jump links. A shared top border on the list plus a bottom border on every
 * row, which is the same closed-both-ends construction the knowledge hub uses.
 */
body.fc-ds .fc-resources-hero__jumps {
	display: flex;
	flex-direction: column;
	border-top: var(--stroke-1) solid var(--border-on-light);
}

/*
 * space-between with a single child in it, which is the export's rule verbatim. There is
 * nothing on the right of these rows and nothing is meant to be: the affordance is the
 * whole row turning violet, and a corner arrow would say "this leaves the page" about a
 * link that scrolls it. The 20px of vertical padding is the export's and is not on the
 * spacing scale for the same reason the 40 above is not.
 */
body.fc-ds .fc-resources-hero__jump {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: var(--sp-32);
	padding: 20px 0;
	border-bottom: var(--stroke-1) solid var(--border-on-light);
	color: var(--text-on-light);
	text-decoration: none;
	transition: color 160ms var(--ease-out);
}

body.fc-ds .fc-resources-hero__jump:hover,
body.fc-ds .fc-resources-hero__jump:focus-visible {
	color: var(--fc-violet);
}

body.fc-ds .fc-resources-hero__jumplabel {
	font-family: var(--font-core);
	font-weight: var(--fw-semibold);
	font-size: var(--type-h5-24);
	line-height: var(--lh-snug);
}

body.fc-ds .fc-resources-hero__figure {
	position: relative;
	min-height: 360px;
	border-left: var(--stroke-1) solid var(--fc-ink-a20);
}

body.fc-ds .fc-resources-hero__img {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * Stacked. The copy column keeps its ruled inset on the left and takes an ordinary 40px
 * on the right, and the artwork moves below it: its left hairline becomes a top one, and
 * it is indented to the ruled column so the picture starts where the rule does.
 */
@container page (max-width: 1100px) {
	body.fc-ds .fc-resources-hero__copy {
		padding: var(--sp-54) 40px var(--sp-54) calc(var(--gutter-page) + 40px);
	}

	body.fc-ds .fc-resources-hero__figure {
		margin-left: calc(var(--gutter-page) + var(--stroke-1));
		border-left: 0;
		border-top: var(--stroke-1) solid var(--fc-ink-a20);
	}
}

/* The ruled inset halves to 20px below 820 — see THE RULED COLUMN in layout.css. */
@container page (max-width: 820px) {
	body.fc-ds .fc-resources-hero__copy {
		padding: var(--sp-54) 20px var(--sp-54) calc(var(--gutter-page) + 20px);
	}
}

/* ═════════════════════════════════════════════════════════════════════════════
 * THE FOUR BANDS
 *
 * Every section below the hero is the same shell: a heading lockup, then one thing. The
 * scroll margin is what makes the hero's jump links land below the sticky nav instead of
 * behind it.
 * ══════════════════════════════════════════════════════════════════════════ */
body.fc-ds .fc-resources-band {
	scroll-margin-top: var(--nav-height);
}

body.fc-ds .fc-resources-band--dark {
	background: var(--fc-ink-12);
}

/*
 * 680px, which is the measure the export sets on the first of the four and the one the
 * other three want too: these subheads are one line of prose and a full-bleed line of
 * 18px type across 1500px of page is not a line, it is a rule.
 */
body.fc-ds .fc-resources__head {
	display: flex;
	flex-direction: column;
	gap: var(--sp-24);
	max-width: 680px;
}

/* .fc-display-hero carries the face, the 72px, the 1.02 ramp and the tracking. */
body.fc-ds .fc-resources__h2 {
	color: var(--text-on-light);
}

body.fc-ds .fc-resources__head--dark .fc-resources__h2 {
	color: var(--text-on-dark);
}

/* ═════════════════════════════════════════════════════════════════════════════
 * THE LOAD-MORE CONTROLS, AND THE ARCHIVE LINKS
 *
 * Three sections close on a centred button. Two of them are reveal controls that
 * assets/ds/resources.js drives; the third and the media table's are links to an
 * archive. They share this block because they are the same object in the same slot.
 * ══════════════════════════════════════════════════════════════════════════ */
body.fc-ds .fc-resources__more {
	display: flex;
	justify-content: center;
	gap: var(--sp-24);
	flex-wrap: wrap;
	margin: var(--sp-54) 0 0;
}

/*
 * .fc-btn's own 12px gap sits between its direct children, and these buttons wrap their
 * label and glyph in a span so the two states can be swapped as a pair. So the span
 * carries the gap instead.
 */
body.fc-ds .fc-resources__more-face {
	display: inline-flex;
	align-items: center;
	gap: 12px;
}

/*
 * `hidden` on a span whose display is being set has to be restated, or the attribute
 * loses to the class. This is what lets the media control ship as "All media articles"
 * and become "Load more" without a translatable string in the script.
 */
body.fc-ds .fc-resources__more-face[hidden] {
	display: none;
}

/*
 * The knowledge hub's button is gone once the twelfth row is out, and its 54px of margin
 * would be left behind as a gap with nothing in it. The live region stays — it is
 * absolutely positioned and clipped, so it costs the row nothing, and taking it away in
 * the same frame it is written to would lose the announcement.
 */
body.fc-ds .fc-resources__more.is-done {
	margin: 0;
}

/* ═════════════════════════════════════════════════════════════════════════════
 * THE CASE RAIL
 *
 * Nine customer cards in a row that drifts leftwards on its own, wrapping through a
 * duplicate of the same nine.
 *
 * ── IT IS A REAL SCROLL CONTAINER ───────────────────────────────────────────
 *
 * Not a track being transformed inside a mask. assets/ds/resources.js moves
 * rail.scrollLeft, which is the same number the browser writes when a visitor drags,
 * wheels or tabs through it — so grabbing the rail mid-drift does not interrupt an
 * animation, it just moves the number. assets/ds/strip.js makes the argument at length
 * and this is the same mechanism.
 *
 * NO scroll-snap. The export asks for `scroll-snap-type: x mandatory`, which fights a
 * per-frame write to scrollLeft: the browser keeps pulling the rail back to the nearest
 * card while the script is trying to move it a pixel at a time. The two controls scroll
 * to an exact card pitch anyway, which is what the snap was for.
 *
 * THE SCROLLBAR IS ONLY HIDDEN ONCE THE SCRIPT IS RUNNING. .is-grab arrives from
 * JavaScript, so with the script blocked the rail keeps its bar and is an ordinary
 * scroller — the failure state has to be the usable one. assets/ds/rail.js's rule.
 * ══════════════════════════════════════════════════════════════════════════ */
body.fc-ds .fc-case {
	margin: var(--sp-54) 0 0;
}

body.fc-ds .fc-case__rail {
	position: relative;
	overflow-x: auto;
	overflow-y: hidden;
	overscroll-behavior-x: contain;
}

body.fc-ds .fc-case__rail.is-grab {
	scrollbar-width: none;
	-ms-overflow-style: none;
}

body.fc-ds .fc-case__rail.is-grab::-webkit-scrollbar {
	display: none;
}

/*
 * Only where there is a pointer that can grab. On a touch screen the rail already pans
 * with a finger and the cursor would never be seen; assets/ds/strip.js gates its own
 * the same way.
 */
@media (hover: hover) and (pointer: fine) {
	body.fc-ds .fc-case__rail.is-grab {
		cursor: grab;
	}

	body.fc-ds .fc-case__rail.is-dragging {
		cursor: grabbing;
		user-select: none;
	}
}

/*
 * No max-content width. The track's content box IS the rail's viewport, so each card
 * resolves (100% - 64px) / 3 against the visible width and the row overflows sideways.
 * The margin is on every card including the last, which is what makes the scroll width
 * exactly eighteen card pitches and the halfway wrap exact.
 */
body.fc-ds .fc-case__track {
	display: flex;
}

body.fc-ds .fc-case__track > * {
	margin-right: var(--sp-32);
}

/*
 * flex: 0 0 with min-width: 0. Either a wide min-content — a 250px wordmark, the 88px
 * arrow cell — or an unset min-width would override the basis, the card would grow, and
 * both the thirds and the pitch the controls step by would go with it.
 */
body.fc-ds .fc-case-card {
	flex: 0 0 calc((100% - 64px) / 3);
	min-width: 0;
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	min-height: 300px;
	background: var(--fc-white);
	color: var(--text-on-light);
	text-decoration: none;
	box-shadow: inset 0 0 0 var(--stroke-1) var(--fc-ink-a20);
}

/*
 * The duplicated set. It only makes sense while something is driving the scroll: left
 * visible with the script blocked, the rail would hold the same nine cards twice. So it
 * ships display: none and resources.js reveals it by putting .is-live on the rail.
 */
body.fc-ds .fc-case-card--echo {
	display: none;
}

body.fc-ds .fc-case__rail.is-live .fc-case-card--echo {
	display: flex;
}

body.fc-ds .fc-case-card__body {
	display: flex;
	flex-direction: column;
	gap: var(--sp-32);
	padding: var(--sp-32);
}

/*
 * Fraunces at 48, violet, and the one place on this page violet does more than mark a
 * link. Tabular figures so nine numbers of different lengths sit on the same widths, and
 * nowrap because "5 wks" and "1000 → 6" are single objects.
 */
body.fc-ds .fc-case-card__metric {
	font-family: var(--font-quote);
	font-weight: var(--fw-semibold);
	font-size: var(--type-numeral-48);
	line-height: var(--lh-flush);
	letter-spacing: var(--ls-quote);
	color: var(--fc-violet);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/*
 * Five or six characters: "€3.8m", "5 wks", "12 wks". The card is a third of the ruled
 * column, so it has about 236px of measure and 48px Fraunces runs out at four.
 */
body.fc-ds .fc-case-card__metric--tight {
	font-size: calc(var(--type-numeral-48) * 0.8);
}

/* Seven or more: "1000 → 6". */
body.fc-ds .fc-case-card__metric--tightest {
	font-size: calc(var(--type-numeral-48) * 0.65);
}

body.fc-ds .fc-case-card__claim {
	font-size: var(--type-h5-24);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-snug);
	text-wrap: pretty;
}

body.fc-ds .fc-case-card__foot {
	display: flex;
	align-items: stretch;
	border-top: var(--stroke-1) solid var(--fc-ink-a20);
}

body.fc-ds .fc-case-card__logo {
	flex: 1;
	display: flex;
	align-items: center;
	min-width: 0;
	height: 88px;
	padding: 0 var(--sp-16);
}

/*
 * The --mark contract, shared with .fc-storycard__mark and the proof wall's tile: a
 * width and a height derived from the artwork's measured ratio inside a 250 x 44 box,
 * and background-size: contain to do the rest. That is what keeps a 7:1 wordmark and a
 * square badge at one optical weight. See THE MARK BOX in inc/ds-customers.php.
 *
 * Restated rather than shared because .fc-storycard__mark lives in storycard.css, which
 * loads on /customers/ and /pricing/ and not here. The arithmetic IS shared —
 * fluent_commerce_ds_customers_box() is called from this page's renderer.
 */
body.fc-ds .fc-case-card__mark {
	flex: 0 1 auto;
	width: var(--mark-w);
	max-width: 100%;
	height: var(--mark-h);
	background-image: var(--mark);
	background-position: left center;
	background-repeat: no-repeat;
	background-size: contain;
}

/* The documented fallback: no story has been without a mark since Build-18. */
body.fc-ds .fc-case-card__wordmark {
	font-size: var(--type-body-16);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-title);
	letter-spacing: var(--ls-label);
	color: var(--text-on-light);
	text-wrap: balance;
}

/* Square, ruled off the mark beside it, and violet under the pointer. */
body.fc-ds .fc-case-card__arrow {
	flex: none;
	width: 88px;
	height: 88px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-left: var(--stroke-1) solid var(--fc-ink-a20);
	transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}

body.fc-ds .fc-case-card:hover .fc-case-card__arrow,
body.fc-ds .fc-case-card:focus-visible .fc-case-card__arrow {
	background: var(--fc-violet);
	color: var(--fc-white);
}

/*
 * The controls row: the two flicks on the left, the archive on the right. Both buttons
 * ship `hidden` and resources.js unhides them, which is the bargain pulse.js makes with
 * the range inputs on /pricing/ — a control that needs a script to do anything is not
 * drawn until the script is there. The archive link is a real link and is always drawn.
 */
body.fc-ds .fc-case__controls {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: var(--sp-32);
	flex-wrap: wrap;
	margin: var(--sp-32) 0 0;
}

body.fc-ds .fc-case__nav {
	display: flex;
	gap: 12px;
}

body.fc-ds .fc-case__btn {
	width: 54px;
	height: 54px;
	flex: none;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	background: transparent;
	border: var(--stroke-1) solid var(--fc-ink-a20);
	border-radius: var(--radius-0);
	color: var(--text-on-light);
	cursor: pointer;
	transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}

body.fc-ds .fc-case__btn:hover,
body.fc-ds .fc-case__btn:focus-visible {
	background: var(--fc-ink-12);
	color: var(--fc-bone);
}

/* An empty nav row would still take its place in the space-between. */
body.fc-ds .fc-case__nav:empty {
	display: none;
}

/*
 * Two up, then one. The card's whole point is that a metric and a claim are readable at
 * a glance, and a third of 700px is not enough for a 24px claim.
 */
@container page (max-width: 1100px) {
	body.fc-ds .fc-case-card {
		flex-basis: calc((100% - 32px) / 2);
	}
}

@container page (max-width: 680px) {
	body.fc-ds .fc-case-card {
		flex-basis: 85%;
	}

	body.fc-ds .fc-case__controls {
		justify-content: flex-start;
	}
}

/* ═════════════════════════════════════════════════════════════════════════════
 * THE KNOWLEDGE HUB
 *
 * Four squares across the ruled column, each one a hub page's header artwork over its
 * name. It replaced the twelve hairline rows on 2026-08-27; those rules are still in
 * pages.css under THE RESOURCES ROW and are still loaded, because blog.css names that
 * block as the original the /news/ rows are copied from. See inc/ds-resources.php.
 *
 * ── IT IS DRAWN AS A TABLE AND THE BORDERS ARE SHARED ───────────────────────
 *
 * "The table design" is what was asked for, so the grid keeps the row's language: no gaps,
 * one hairline between neighbours, a white plate under the pointer, the same 13px glyph
 * after the label. The construction is the row's own, in two dimensions — top and left on
 * the list, right and bottom on every cell — which gives four tiles five verticals and two
 * horizontals with nothing doubled, and closes itself correctly if a tile drops out
 * because its page is unpublished. No rule has to know which cell is last.
 *
 * ── SQUARE TILE, 16:9 PICTURE ───────────────────────────────────────────────
 *
 * The tile is square and the picture inside it is not, because the four artworks are wide
 * particle fields with something touching the right edge of three of them: a square crop
 * would cut the locomotive's nose off. So the picture keeps its band and the label takes
 * the rest of the square, which is 44% of it — about 112px at the desktop size, enough for
 * two lines of 18px type. aspect-ratio is a preferred height here, not a cap: a label that
 * needs a third line grows the tile rather than spilling out of it.
 *
 * THIS WENT 2x2 AT 24px FOR ONE REVISION AND IS BACK. Andrew asked for the pair of changes
 * on 2026-08-27 and then asked to roll them back, so the numbers here are the first set:
 * four across, an 18px label, and a 112px foot rather than a 245px one. What the round trip
 * settled is that the space under the picture is a consequence of the square, so if the
 * square goes the space goes with it — see the git-less note in inc/ds-resources.php.
 * ══════════════════════════════════════════════════════════════════════════ */
body.fc-ds .fc-hub {
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	margin: var(--sp-54) 0 0;
	padding: 0;
	list-style: none;
	border-top: var(--stroke-1) solid var(--border-on-light);
	border-left: var(--stroke-1) solid var(--border-on-light);
}

body.fc-ds .fc-hub__cell {
	display: flex;
	border-right: var(--stroke-1) solid var(--border-on-light);
	border-bottom: var(--stroke-1) solid var(--border-on-light);
}

/*
 * The plate is on the tile and not the cell, so it stops inside the hairlines rather than
 * painting over them. Same gesture and the same 160ms as .fc-resources__link: on bone,
 * white reads as lifted where a grey would read as disabled.
 */
body.fc-ds .fc-hub__tile {
	flex: 1;
	min-width: 0;
	aspect-ratio: 1;
	display: flex;
	flex-direction: column;
	color: var(--text-on-light);
	text-decoration: none;
	transition: background 160ms ease-out, color 160ms ease-out;
}

body.fc-ds .fc-hub__tile:hover,
body.fc-ds .fc-hub__tile:focus-visible {
	background: var(--surface-lightest);
	color: var(--fc-violet);
}

/*
 * flex: none against the picture's own ratio, so the band is exactly 16:9 of the tile's
 * width and the foot takes what is left. overflow: hidden is the guard for the quarter of
 * a pixel the encode's rounding leaves between the two ratios.
 */
body.fc-ds .fc-hub__figure {
	display: block;
	flex: none;
	aspect-ratio: 880 / 494;
	overflow: hidden;
}

body.fc-ds .fc-hub__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
}

/*
 * The label sits on the picture's baseline edge and fills the rest of the square, centred
 * in it. 16px of side padding is the row's, and for the same reason: it is what the white
 * plate needs to read as a plate rather than as type touching an edge.
 */
body.fc-ds .fc-hub__foot {
	flex: 1;
	min-height: 0;
	display: flex;
	align-items: center;
	padding: var(--sp-24) var(--sp-16);
}

/*
 * .fc-resources__label's type, restated rather than shared. The two are the same object and
 * will drift, but that class is documented in pages.css as the resources ROW's and is copied
 * from there into blog.css for two archives — reusing it here would put a tile inside a
 * cross-sheet contract about hairline rows.
 *
 * NOT inline-flex, which is the one place this parts company with the row. A flex label puts
 * the glyph beside the whole text block, i.e. at the far right of the square, and
 * "Inventory & Fulfillment Optimization" wraps to two lines at every width this grid has —
 * leaving the arrow alone in the corner while the sentence ends mid-line. Here the glyph is
 * inline and follows the last word, so all four tiles read the same way.
 */
body.fc-ds .fc-hub__label {
	font-size: var(--type-body-16);
	font-weight: var(--fw-medium);
	line-height: var(--lh-body);
	text-wrap: pretty;
}

/*
 * 6px of lead-in, and baseline-aligned so it sits on the cap height of the 18px line rather
 * than on the descender. It follows the label's colour, so it turns violet with the tile.
 * white-space: nowrap on the pair is not needed: an SVG cannot be separated from the word
 * before it by a break it has no space in front of, and the 6px is a margin, not a space.
 */
body.fc-ds .fc-hub__arrow {
	display: inline-block;
	vertical-align: baseline;
	margin-left: 6px;
}

/*
 * Two up at the same breakpoint the case cards go two up, and one up before the square
 * gets narrow enough that "Inventory & Fulfillment Optimization" wants four lines. The
 * borders need no rearranging at either step: the shared-edge construction closes a
 * two-column and a one-column table as correctly as a four.
 */
@container page (max-width: 1100px) {
	body.fc-ds .fc-hub {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@container page (max-width: 560px) {
	body.fc-ds .fc-hub {
		grid-template-columns: minmax(0, 1fr);
	}
}

/* ═════════════════════════════════════════════════════════════════════════════
 * THE PRESS RELEASE CAROUSEL
 *
 * Eleven releases on an ink band, one at a time, with its neighbours peeking in from
 * either side.
 *
 * ── THE MECHANISM IS ELEVEN RADIOS AND THEIR LABELS ─────────────────────────
 *
 * Not .fc-story, and inc/ds-resources.php gives the three reasons. The one that matters
 * here is that pages.css declares exactly five :checked rules and this needs eleven.
 *
 * Every slide is in the DOM at once and every slide sits in the same grid cell, so the
 * stage is as tall as the longest release and the page does not move as it advances.
 * Hidden slides are visibility: hidden rather than display: none, because they still
 * have to size the grid — and visibility also takes them out of the accessibility tree,
 * out of the tab order, and takes their four <label> controls out of reach.
 *
 * WITHOUT JAVASCRIPT this is complete: the radios are focusable, they are a real radio
 * group, and arrow keys move through the eleven releases. assets/ds/resources.js adds
 * the 6000ms advance and the drag.
 * ══════════════════════════════════════════════════════════════════════════ */
body.fc-ds .fc-release {
	position: relative;
	margin: var(--sp-54) 0 0;
}

body.fc-ds .fc-release__stage {
	display: grid;
	transition: transform var(--dur-base) var(--ease-out), opacity var(--dur-base) var(--ease-out);
}

/* Drag, on the same terms as .fc-story: the finger keeps the page, the mouse gets the
 * carousel, and the transition comes off mid-drag so the stage tracks the pointer. */
body.fc-ds .fc-release.is-grab .fc-release__stage {
	touch-action: pan-y;
}

@media (hover: hover) and (pointer: fine) {
	body.fc-ds .fc-release.is-grab .fc-release__stage {
		cursor: grab;
	}

	body.fc-ds .fc-release.is-dragging .fc-release__stage {
		cursor: grabbing;
	}
}

body.fc-ds .fc-release.is-dragging .fc-release__stage {
	user-select: none;
	transition: none;
}

body.fc-ds .fc-release__slide {
	grid-area: 1 / 1;
	display: flex;
	flex-direction: column;
	gap: var(--sp-32);
	opacity: 0;
	visibility: hidden;
	transition: opacity var(--dur-base) var(--ease-out), visibility var(--dur-base) var(--ease-out);
}

body.fc-ds .fc-release__radio:nth-of-type(1):checked ~ .fc-release__stage > .fc-release__slide:nth-child(1),
body.fc-ds .fc-release__radio:nth-of-type(2):checked ~ .fc-release__stage > .fc-release__slide:nth-child(2),
body.fc-ds .fc-release__radio:nth-of-type(3):checked ~ .fc-release__stage > .fc-release__slide:nth-child(3),
body.fc-ds .fc-release__radio:nth-of-type(4):checked ~ .fc-release__stage > .fc-release__slide:nth-child(4),
body.fc-ds .fc-release__radio:nth-of-type(5):checked ~ .fc-release__stage > .fc-release__slide:nth-child(5),
body.fc-ds .fc-release__radio:nth-of-type(6):checked ~ .fc-release__stage > .fc-release__slide:nth-child(6),
body.fc-ds .fc-release__radio:nth-of-type(7):checked ~ .fc-release__stage > .fc-release__slide:nth-child(7),
body.fc-ds .fc-release__radio:nth-of-type(8):checked ~ .fc-release__stage > .fc-release__slide:nth-child(8),
body.fc-ds .fc-release__radio:nth-of-type(9):checked ~ .fc-release__stage > .fc-release__slide:nth-child(9),
body.fc-ds .fc-release__radio:nth-of-type(10):checked ~ .fc-release__stage > .fc-release__slide:nth-child(10),
body.fc-ds .fc-release__radio:nth-of-type(11):checked ~ .fc-release__stage > .fc-release__slide:nth-child(11) {
	opacity: 1;
	visibility: visible;
}

/*
 * The focus ring. tokens.css draws one on :focus-visible for everything, but these
 * radios are 1px and clipped, so it has to move onto something the visitor can see. One
 * rule rather than eleven: arrow keys check a radio as they reach it, so the focused
 * radio is always the checked one, and the ten hidden cards cannot paint an outline.
 */
body.fc-ds .fc-release__radio:focus-visible ~ .fc-release__stage .fc-release__card {
	outline: var(--stroke-2) solid var(--fc-violet-light);
	outline-offset: 8px;
}

body.fc-ds .fc-release__row {
	display: grid;
	grid-template-columns: minmax(240px, 0.52fr) 1.6fr minmax(240px, 0.52fr);
	gap: 20px;
	align-items: stretch;
}

/*
 * A peek is a <label> and not a button: it is the affordance for a radio that already
 * carries the state, and a button beside it would be two controls for one fact and a
 * script to keep them in step.
 */
body.fc-ds .fc-release__peek {
	display: flex;
	flex-direction: column;
	gap: var(--sp-16);
	justify-content: center;
	overflow: hidden;
	padding: var(--sp-32);
	background: transparent;
	border: var(--stroke-1) solid var(--fc-bone-a20);
	text-align: left;
	cursor: pointer;
	font-family: var(--font-core);
	color: var(--fc-bone-a50);
	transition: color 160ms var(--ease-out), border-color 160ms var(--ease-out);
}

body.fc-ds .fc-release__peek:hover {
	color: var(--fc-bone);
	border-color: var(--fc-bone-a50);
}

body.fc-ds .fc-release__peekdate {
	color: inherit;
	white-space: nowrap;
}

/* Three lines and then it stops. A peek is a preview, not the release. */
body.fc-ds .fc-release__peektitle {
	display: -webkit-box;
	-webkit-line-clamp: 3;
	-webkit-box-orient: vertical;
	overflow: hidden;
	font-size: var(--type-body-16);
	font-weight: var(--fw-medium);
	line-height: var(--lh-body);
	color: inherit;
	text-wrap: pretty;
}

/* The one 2px edge on the site, and the export is explicit about it: the centre card is
 * the thing being read and a hairline would lose it against the ten hairlines around it. */
body.fc-ds .fc-release__card {
	display: flex;
	flex-direction: column;
	gap: var(--sp-24);
	min-height: 300px;
	padding: var(--sp-54);
	border: var(--stroke-2) solid var(--fc-white);
}

body.fc-ds .fc-release__date {
	color: var(--fc-bone-a60);
}

body.fc-ds .fc-release__title {
	margin: 0;
	font-family: var(--font-core);
	font-weight: var(--fw-semibold);
	font-size: var(--type-h5-24);
	line-height: var(--lh-snug);
	letter-spacing: var(--ls-display);
	color: var(--fc-bone);
	text-wrap: pretty;
}

/*
 * margin-top: auto, so the button sits on the card's floor whatever the headline does —
 * and eleven headlines run from one line to four.
 *
 * The hover is violet rather than .fc-btn--light's bone plate, which is the export's
 * --btn-fill on this one button. Colour only, which is all a page is allowed to set on
 * .fc-btn.
 */
body.fc-ds .fc-release__cta {
	margin-top: auto;
}

body.fc-ds .fc-btn.fc-release__cta:hover,
body.fc-ds .fc-btn.fc-release__cta:focus-visible {
	background: var(--fc-violet);
	border-color: var(--fc-violet);
	color: var(--fc-white);
}

body.fc-ds .fc-release__nav {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: var(--sp-32);
	flex-wrap: wrap;
}

body.fc-ds .fc-release__btn {
	width: 44px;
	height: 44px;
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	border: var(--stroke-1) solid var(--fc-bone-a20);
	border-radius: var(--radius-pill);
	color: var(--fc-bone);
	cursor: pointer;
	transition: background 160ms var(--ease-out), border-color 160ms var(--ease-out), color 160ms var(--ease-out);
}

body.fc-ds .fc-release__btn:hover {
	background: var(--fc-white);
	border-color: var(--fc-white);
	color: var(--fc-ink-12);
}

/*
 * The peeks are a preview and not content, so they go before the centre card loses its
 * measure. The export sets exactly this breakpoint and gives the reason.
 */
@container page (max-width: 1100px) {
	body.fc-ds .fc-release__row {
		grid-template-columns: 1fr;
	}

	body.fc-ds .fc-release__peek {
		display: none;
	}
}

/* 54px of padding inside a card on a 350px screen leaves nothing for the headline. */
@container page (max-width: 440px) {
	body.fc-ds .fc-release__card {
		padding: var(--sp-24);
	}
}

/* ═════════════════════════════════════════════════════════════════════════════
 * THE MEDIA TABLE
 *
 * Publication, date, headline, and a link that leaves the site. Four tracks on the
 * header and on every row, so the columns line up.
 *
 * NOT A <table>, for the reason /media-articles/ is not one either: the rows are links,
 * and a table of one-cell-per-fact links announces as a grid to be navigated rather than
 * as a list of articles. The header row is aria-hidden — it labels four columns for the
 * eye, and a screen reader reads each row's own words in order.
 * ══════════════════════════════════════════════════════════════════════════ */
body.fc-ds .fc-mediatable {
	margin: var(--sp-54) 0 0;
}

/* The list is closed at the bottom; every row draws its own top hairline. */
body.fc-ds .fc-mediatable__grid {
	border-bottom: var(--stroke-1) solid var(--border-on-light);
}

/*
 * THE TRACKS ARE NOT THE EXPORT'S `1fr 0.7fr 2.4fr 0.8fr`, AND THAT IS WHAT MAKES THE
 * EXPORT'S OWN SENTENCE TRUE. Every row is its own grid — thirty-one of them — so an
 * `fr` track is only as narrow as its widest content allows: a row reading "February 25,
 * 2026" sizes its date column wider than one reading "June 4, 2026" and pushes its
 * headline three pixels right of the headline above it. Thirty rows, thirty different
 * left edges. So:
 *
 *   - the date column is a flat 170px, which is the width /news/ and /media-articles/
 *     already give the same dates at the same size (see .fc-newslist in blog.css);
 *   - the other three are minmax(0, …), which takes the automatic minimum off them so
 *     they resolve to the same proportions on every row whatever is in them.
 *
 * The proportions themselves are the export's, untouched.
 */
body.fc-ds .fc-media-row {
	display: grid;
	grid-template-columns: minmax(0, 1fr) 170px minmax(0, 2.4fr) minmax(120px, 0.8fr);
	gap: var(--sp-32);
	align-items: center;
}

/*
 * Restated because `hidden` loses to a class that sets display, and resources.js hides
 * twenty of the thirty rows with the attribute. See THE MEDIA TABLE in that file.
 */
body.fc-ds .fc-media-row[hidden] {
	display: none;
}

/*
 * JetBrains Mono, which is the machine-string face — these are column names, not prose.
 * Ink under bone, so the table reads as having a head rather than a first row.
 */
body.fc-ds .fc-media-head {
	padding: var(--sp-16);
	background: var(--fc-ink-12);
	font-family: var(--font-mono);
	font-size: var(--type-label-12);
	letter-spacing: var(--ls-label);
	text-transform: uppercase;
	color: var(--fc-bone-a80);
}

/*
 * One rule for the anchors and for the one row that has no URL, so a row that goes
 * nowhere sits on the same padding and hairline as one that does. Only the hover differs.
 * The 16px of side padding is what the white hover plate needs to read as a plate.
 */
body.fc-ds a.fc-media-row,
body.fc-ds .fc-media-row--dead {
	padding: var(--sp-24) var(--sp-16);
	border-top: var(--stroke-1) solid var(--border-on-light);
	color: var(--text-on-light);
	text-decoration: none;
	transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}

body.fc-ds a.fc-media-row:hover,
body.fc-ds a.fc-media-row:focus-visible {
	background: var(--surface-lightest);
	color: var(--fc-violet);
}

body.fc-ds .fc-media-row__pub {
	font-size: var(--type-body-16);
	font-weight: var(--fw-semibold);
	line-height: var(--lh-title);
	text-wrap: pretty;
}

/*
 * The date holds its own colour, so the hover turns the headline violet and leaves the
 * timestamp where it was. It is not the thing being clicked.
 */
body.fc-ds .fc-media-row__date {
	font-size: var(--type-body-16);
	font-weight: var(--fw-medium);
	line-height: var(--lh-body);
	color: var(--fc-ink-a60);
	white-space: nowrap;
}

body.fc-ds .fc-media-row__title {
	font-size: var(--type-body-16);
	font-weight: var(--fw-medium);
	line-height: var(--lh-loose);
	text-wrap: pretty;
}

body.fc-ds .fc-media-link {
	display: inline-flex;
	align-items: center;
	gap: var(--sp-8);
	justify-self: end;
	font-size: var(--type-body-16);
	font-weight: var(--fw-medium);
	white-space: nowrap;
}

/*
 * "Read more" is the same two words on all thirty rows, so it appears on the row being
 * pointed at and nowhere else. Collapsed with a zero max-width and no opacity rather
 * than with display: none or `hidden`, because it still has to be read out on every row.
 */
body.fc-ds .fc-media-label {
	max-width: 0;
	overflow: hidden;
	opacity: 0;
	transition: opacity 160ms var(--ease-out);
}

body.fc-ds a.fc-media-row:hover .fc-media-label,
body.fc-ds a.fc-media-row:focus-visible .fc-media-label {
	max-width: 8em;
	opacity: 1;
}

body.fc-ds .fc-media-row__arrow {
	flex: none;
	display: block;
}

/*
 * 1100 is where 1fr + 0.7fr + 0.8fr and three 32px gaps have taken more than half the
 * row and the headline column can no longer hold a readable measure. Stacked is also the
 * touch case, where hover never fires — so "Read more" comes back permanently.
 */
@container page (max-width: 1100px) {
	body.fc-ds .fc-media-row {
		grid-template-columns: 1fr;
		gap: 12px;
		align-items: start;
	}

	body.fc-ds .fc-media-head {
		display: none;
	}

	body.fc-ds .fc-media-link {
		justify-self: start;
	}

	body.fc-ds .fc-media-label {
		max-width: none;
		opacity: 1;
	}

	/*
	 * 31 of the 282 articles have no date and print the element empty, which holds the
	 * column open at full width. In one column there is nothing left to align and the
	 * empty element is only a 12px gap. Hidden here and not above, where display: none
	 * would take it out of the grid and slide the headline into the date's column.
	 */
	body.fc-ds .fc-media-row__date:empty {
		display: none;
	}
}
