/*
Theme Name: VC Defensa — Dos Tintas
Theme URI: https://vcdefensa.org
Author: VC Defensa
Description: Risograph child theme of Ollie for vcdefensa.org. Two inks on cheap paper — safety yellow and black, printed slightly out of register, halftoned, stamped. Built for a community that needs one phone number to be impossible to miss. ¡El pueblo se defiende!
Template: ollie
Version: 1.7.3
License: GNU General Public License v3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html
Text Domain: vcdefensa-riso
Tags: full-site-editing, block-patterns, translation-ready, accessibility-ready
*/

/* ---------------------------------------------------------------------------
   Design tokens live in theme.json. This file holds the print primitives that
   theme.json has no vocabulary for: paper grain, ink misregistration, halftone
   screens, registration marks.

   The governing fiction: this page was run through a two-drum Risograph. One
   drum holds safety yellow, one holds black, and the paper went through twice.
   Everything below is a consequence of that.
   --------------------------------------------------------------------------- */


/* --- Ink and register ------------------------------------------------------ */

:root {
	/* How far the second plate sits out of register. Small enough to read as a
	   printing artifact, large enough to be unmistakably deliberate. */
	/* One curve for the whole theme: a weighted settle, never a linear ramp. */
	--riso-ease: cubic-bezier(0.2, 0.8, 0.3, 1);

	--riso-shift: 4px;
	--riso-shift-lg: 7px;

	/* The ghost ink behind display type, and the ink an offset plate is printed
	   in. Both are redefined per surface further down, because what counts as
	   "the other ink" depends on what you are printing on. */
	--riso-ghost: var(--wp--preset--color--primary);
	--riso-plate-ink: var(--wp--preset--color--main);

	/* Stacking order, named rather than guessed at. */
	--z-grain: 5;
	--z-skiplink: 100;
}

/* On a black plate the paper is gone, so yellow can no longer be the ghost —
   it is doing the work of the text. Red takes the ghost role. */
.has-primary-alt-background-color,
.has-primary-alt-accent-background-color {
	--riso-ghost: var(--wp--preset--color--alert);
	/* Not yellow: the buttons on this plate are themselves yellow, so a yellow
	   offset behind them would be invisible. Red is the third drum. */
	--riso-plate-ink: var(--wp--preset--color--alert);
}

/* On a yellow plate the text is already black, so a black ghost would simply
   thicken it. Paper shows through instead, like a knockout printed shy. */
.has-primary-background-color {
	--riso-ghost: var(--wp--preset--color--base);
	--riso-plate-ink: var(--wp--preset--color--main);
}


/* --- Utility --------------------------------------------------------------- */

/* WP core's standard visually-hidden-but-accessible recipe. Front-end themes
   must supply this themselves — it isn't auto-included outside wp-admin. */
.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	word-wrap: normal !important;
}

html {
	scroll-behavior: smooth;
}


/* --- Paper ----------------------------------------------------------------- */

/* Riso paper is never white and never flat. The grain is a fixed overlay rather
   than a background on each section, so it reads as one sheet the whole page is
   printed on instead of a texture that restarts at every band. */
.riso-grain {
	position: fixed;
	inset: 0;
	z-index: var(--z-grain);
	pointer-events: none;
	mix-blend-mode: multiply;
	opacity: 0.55;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.42'/%3E%3C/svg%3E");
	background-size: 140px 140px;
}

body {
	background-color: var(--wp--preset--color--base);
}


/* --- Site skeleton --------------------------------------------------------- */

/* Header, main and footer are siblings in .wp-site-blocks, and WP's global
   styles put the theme's default blockGap between them — a visible gap between
   bands that are meant to butt straight up against each other. Each band owns
   its own internal padding, so the gap between them is always zero. */
.wp-site-blocks > * {
	margin-block-start: 0;
}

/* Long words in two languages, set in a condensed face at poster sizes, will
   otherwise push a phone viewport sideways. */
body {
	overflow-x: hidden;
}


/* --- Hazard strip ---------------------------------------------------------- */

/* A printer's trim strip, and the one place the two inks meet at full strength.
   Used to close a band rather than to decorate one. */
.riso-hazard {
	height: 14px;
	background-image: repeating-linear-gradient(
		-45deg,
		var(--wp--preset--color--primary) 0,
		var(--wp--preset--color--primary) 11px,
		var(--wp--preset--color--main) 11px,
		var(--wp--preset--color--main) 22px
	);
}


/* --- Masthead -------------------------------------------------------------- */

/* The logo is yellow with a white knockout, so it only survives on ink. The
   masthead stays a solid black plate for that reason — not for contrast alone
   but because the mark is unreadable on paper. */
.riso-masthead {
	column-gap: clamp(1rem, 3vw, 2.5rem);
}

.riso-masthead .wp-block-navigation__container {
	flex-wrap: nowrap;
	column-gap: clamp(0.75rem, 1.8vw, 1.6rem);
}

.riso-masthead .wp-block-navigation-item__label {
	white-space: nowrap;
	font-family: var(--wp--preset--font-family--big-shoulders);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.06em;
}

/* Ollie marks the current item with text-decoration:underline at a
   four-class specificity, so a shorter override loses and the theme's own
   marker ends up sitting under a stray underline. These selectors carry one
   more class than Ollie's and win on specificity rather than !important. */
.riso-masthead .wp-block-navigation__responsive-container .wp-block-navigation__container .current-menu-item > a,
.riso-masthead .wp-block-navigation__responsive-container .wp-block-navigation__container .current-menu-item > .wp-block-navigation-item__content {
	box-shadow: inset 0 -0.42em 0 -0.06em var(--wp--preset--color--primary);
	text-decoration: none;
}

/* Logo and phone button are fixed points — never candidates for shrinking.
   Without this, a flex item with no protected minimum can be squeezed below its
   own content width and the browser will break its text mid-digit to make it
   fit, which is what the phone number does here when the nav's nowrap makes it
   claim space first. */
.riso-masthead .wp-block-site-logo,
.riso-masthead .wp-block-buttons {
	flex: 0 0 auto;
}

.riso-masthead .wp-block-site-logo {
	width: 180px;
}

.riso-masthead .wp-block-site-logo img {
	display: block;
	width: 180px;
}

/* Donate leads, the hotline follows. Both are always present: the number never
   falls further than one tap away, it only trades its digits for a receiver
   when the band genuinely runs out of room.

   All of the sizing lives here rather than in the block markup, so these rules
   no longer have to out-shout an inline style attribute with !important. */
.riso-masthead__actions {
	gap: 0.5rem;
}

.riso-masthead__actions .wp-block-button__link {
	white-space: nowrap;
	line-height: 1;
	padding: 0.55rem 1rem 0.47rem;
	font-size: 1.05rem;
}

/* The primary ask: larger than its neighbour, and the only filled plate in the
   band apart from the logo itself. */
.riso-donate-cta .wp-block-button__link {
	font-size: 1.25rem;
	padding-inline: 1.25rem;
	letter-spacing: 0.02em;
}

/* Icon is the exception, not the rule — hidden until the band gets too narrow
   to hold ten digits. */
/* The hotline should read as a call, not as a string of digits, so the handset
   is always on. The digits are what give way when the band runs short. */
.riso-phone-cta {
	display: inline-flex;
	align-items: center;
	gap: 0.42em;
}

.riso-phone-cta__icon {
	display: inline-flex;
	flex: 0 0 auto;
	width: 1.05em;
	height: 1.05em;
}

.riso-phone-cta__glyph {
	display: block;
	width: 100%;
	height: 100%;
}

/* Ollie styles the mobile menu toggle as a tertiary-coloured chip with a 3px
   radius. On this masthead that lands as a pale rounded rectangle sitting on a
   black band, in a theme where nothing else has a soft corner. The control
   should be the icon alone, in whatever ink the surface it sits on is using.

   Two classes beats Ollie's one, so this wins on specificity regardless of
   which stylesheet the browser sees last. */
.riso-masthead .wp-block-navigation__responsive-container-open,
.riso-masthead .wp-block-navigation__responsive-container-close {
	background: transparent;
	border-radius: 0;
	color: inherit;
	/* The toggle is the one control a phone user has to hit, so it gets the
	   full 44px target even though the glyph inside is half that. */
	min-width: 44px;
	min-height: 44px;
	align-items: center;
	justify-content: center;
	padding: 0;
	/* Deliberately no display here. Core hides this button above 600px with a
	   two-class selector, and any display declared at this level ties on
	   specificity, wins on order, and leaves a hamburger sitting next to the
	   full desktop navigation. Display is set only in the narrow-band media
	   query below, where the button is actually meant to be seen. */
}

/* Nav labels are nowrap, which makes the nav's CONTENT width rigid — it cannot
   shrink below the sum of its labels. Letting the nav's BOX shrink smaller than
   that creates a contradiction: the container shrinks, the content doesn't, and
   with justify-content:flex-end the overflow leaves by the left edge. There's
   headroom for the full row at 880px and up; below that and down to the block's
   own 600px overlay breakpoint the row is tightened directly rather than left
   to fight over space on its own. */
/* The masthead now carries two calls to action, not one, so the band runs out
   of room far earlier than it used to. Three stages, widest first.

   Stage one: tighten everything that can be tightened while the full nav is
   still on show. */
@media (max-width: 1100px) {
	header.wp-block-group.has-global-padding {
		padding-left: 0.85rem;
		padding-right: 0.85rem;
	}

	.riso-masthead {
		column-gap: clamp(0.5rem, 2vw, 1rem);
	}

	.riso-masthead .wp-block-site-logo,
	.riso-masthead .wp-block-site-logo img {
		width: 124px;
	}

	.riso-masthead .wp-block-navigation__container {
		column-gap: clamp(0.4rem, 1vw, 0.7rem);
	}

	.riso-masthead nav.wp-block-navigation {
		font-size: 0.78rem;
	}

	.riso-masthead__actions {
		gap: 0.4rem;
	}

	.riso-masthead__actions .wp-block-button__link {
		font-size: 0.9rem;
		padding-inline: 0.6rem;
	}

	.riso-donate-cta .wp-block-button__link {
		font-size: 1rem;
		padding-inline: 0.8rem;
	}
}

/* Stage two: the hotline trades its digits for a receiver. It stays a single
   tap throughout; only the label changes. This happens before the navigation
   collapses, because giving up ten digits buys back roughly 90px and that is
   usually enough to keep the full nav on show a little longer. */
@media (max-width: 900px) {
	.riso-phone-cta__number {
		display: none;
	}

	.riso-phone-cta__icon {
		width: 1.3em;
		height: 1.3em;
	}

	.riso-masthead .wp-block-site-logo,
	.riso-masthead .wp-block-site-logo img {
		width: 132px;
	}
}

/* Stage two and a half: below this the row genuinely cannot hold five nav
   labels, a logo and two buttons. Measured, not estimated: it still fits at
   860px and breaks by 800px, so the switch sits above both. The navigation block only swaps itself for
   its overlay at its own 600px breakpoint, which would leave a band where
   everything collides, so the overlay is brought forward to meet it. This
   mirrors what core already does under 600px rather than inventing a second
   mechanism. */
@media (max-width: 880px) {
	.riso-masthead .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}

	.riso-masthead .wp-block-navigation__responsive-container-open {
		display: flex;
	}
}

/* On phones the call button goes altogether. The hotline number is still one
   tap away in the hotline band and the footer. */
@media (max-width: 600px) {
	.riso-phone-cta-wrap {
		display: none;
	}
}

/* Stage three: the narrowest phones. */
@media (max-width: 420px) {
	header.wp-block-group.has-global-padding {
		padding-left: 0.6rem;
		padding-right: 0.6rem;
	}

	.riso-masthead {
		column-gap: 0.4rem;
	}

	.riso-langswitch__cell {
		min-width: 2.1em;
		font-size: 0.62rem;
	}

	.riso-masthead .wp-block-site-logo,
	.riso-masthead .wp-block-site-logo img {
		width: 104px;
	}

	.riso-masthead__actions .wp-block-button__link {
		padding-inline: 0.55rem;
	}
}


/* --- Display type ---------------------------------------------------------- */

/* Misregistration. The yellow plate landed a few thousandths off, so every
   display line carries a ghost of itself in the other ink.

   text-shadow rather than a duplicated element on purpose: the ghost is an
   artifact of printing, not content, and a screen reader should never meet it.
   The real glyphs stay solid ink on paper, so contrast is unaffected. */
.riso-offset,
.is-style-riso-offset {
	text-shadow: 0.038em 0.034em 0 var(--riso-ghost);
}

/* Stencil is the loud voice and gets used sparingly: the hotline, the section
   numerals, the 404. Registered as a block style so editors can reach it. */
.riso-stencil,
.is-style-riso-stencil {
	font-family: var(--wp--preset--font-family--stencil);
	font-weight: 800;
	line-height: 0.9;
	text-transform: uppercase;
	letter-spacing: -0.01em;
}

/* Headlines set at poster scale strand single words on their own line more
   often than not. Balance the rag instead of leaving orphans. */
h1, h2, h3,
.riso-offset {
	text-wrap: balance;
}

p {
	text-wrap: pretty;
}

/* A running head — the small mono line that labels a section, carrying a
   printer's registration mark. The mark is drawn rather than typed so it holds
   its weight at any size. */
.riso-label {
	font-family: var(--wp--preset--font-family--monospace);
	font-size: var(--wp--preset--font-size--x-small);
	font-weight: 600;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	font-variant-numeric: tabular-nums;
	display: flex;
	align-items: center;
	gap: 0.7em;
}

/* The rule that runs from the label to the edge of the measure. Print uses a
   rule where the web reaches for a border on a box. */
.riso-label::after {
	content: "";
	flex: 1 1 auto;
	height: 1px;
	background: currentColor;
	opacity: 0.45;
}

.riso-label--mark::before {
	content: "";
	flex: 0 0 auto;
	width: 0.95em;
	height: 0.95em;
	background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23B3301C' stroke-width='1.6'%3E%3Ccircle cx='12' cy='12' r='6.5'/%3E%3Cpath d='M12 0v7M12 17v7M0 12h7M17 12h7'/%3E%3C/svg%3E") center / contain no-repeat;
}


/* --- Plates ---------------------------------------------------------------- */

/* A plate is a block of ink that didn't quite land where the other plate did.
   The offset is a box-shadow rather than a second element, so the plate costs
   nothing structurally and collapses cleanly on narrow screens. */
.riso-plate {
	box-shadow: var(--riso-shift-lg) var(--riso-shift-lg) 0 0 var(--riso-plate-ink);
}

.riso-plate--tight {
	box-shadow: var(--riso-shift) var(--riso-shift) 0 0 var(--riso-plate-ink);
}

/* A stamp: hit hard, slightly crooked, the way a rubber stamp lands. The
   rotation is small enough to read as a hand rather than a broken layout.

   The width is capped here rather than through the block's own contentSize,
   because a constrained layout caps a group's CHILDREN and leaves the box
   itself full width — which stretches the stamp across the whole measure and
   leaves it looking like an empty table. */
.riso-stamp {
	border: 3px solid currentColor;
	transform: rotate(-1.1deg);
	transform-origin: left center;
	max-width: 42rem;
	margin-right: auto;
}


/* --- The hotline ----------------------------------------------------------- */

/* This is the one element on the site allowed to shout, and the only reason
   most people will ever load the page. Poster scale, flush left, tabular
   figures so the digits hold a steady rhythm, never wrapped mid-number. */
.riso-hotline__number,
.riso-hotline__number a {
	font-family: var(--wp--preset--font-family--stencil);
	font-weight: 800;
	font-variant-numeric: tabular-nums;
	line-height: 0.82;
	letter-spacing: -0.015em;
	white-space: nowrap;
	text-decoration: none;
	display: block;
	color: inherit;
}

.riso-hotline__number a:hover,
.riso-hotline__number a:focus-visible {
	text-decoration: underline;
	text-decoration-thickness: 0.055em;
	text-underline-offset: 0.06em;
}

/* Digits at this size need their own optical alignment — the stencil face
   carries a little left side bearing that makes a flush-left number look
   indented next to the label above it. */
.riso-hotline__number {
	margin-left: -0.035em;
}


/* --- Ruled rows ------------------------------------------------------------ */

/* Four parallel actions are a list, not a sequence — so they get rules rather
   than boxes. The rule carries the structure a card border would otherwise
   carry, without boxing content into ragged-bottomed columns. */
.riso-rows {
	border-top: 3px solid currentColor;
}

.riso-row {
	display: grid;
	grid-template-columns: 4.25rem minmax(min(11rem, 100%), 19rem) 1fr;
	column-gap: clamp(1.25rem, 3.5vw, 3rem);
	row-gap: 0.35rem;
	align-items: start;
	padding-block: clamp(1.25rem, 2.8vw, 1.9rem);
	border-bottom: 1px solid var(--wp--preset--color--border-light);
}

/* Kill the default block margins inside a row so the grid controls the rhythm. */
.riso-row > * {
	margin-block: 0;
}

.riso-row__title {
	line-height: 0.98;
}

/* The only numerals on the page. "What happens when you call" is a genuine
   sequence, so the figure carries information; the parallel action list gets
   rules and no numbers, because those are choices rather than steps. */
.riso-row__num {
	font-family: var(--wp--preset--font-family--stencil);
	font-weight: 800;
	font-size: clamp(2.1rem, 4.5vw, 3.1rem);
	line-height: 0.74;
	color: var(--wp--preset--color--alert);
	font-variant-numeric: tabular-nums;
	letter-spacing: -0.02em;
}

.riso-row__body {
	max-width: 46ch;
}

@media (max-width: 52rem) {
	.riso-row {
		grid-template-columns: 3rem 1fr;
	}

	.riso-row__body {
		grid-column: 2;
	}
}


/* --- Halftone photography -------------------------------------------------- */

/* Colour separation is handled by WP's own duotone filter (theme.json ships a
   yellow/black preset), which is a real SVG filter and far better than anything
   a blend mode would manage. What's left to CSS is the dot screen the image was
   printed through, and the edge of the yellow plate showing past the black. */
.riso-halftone {
	position: relative;
	isolation: isolate;
}

.riso-halftone img {
	display: block;
	width: 100%;
	height: auto;
}

/* The dot screen. Fine enough to read as texture at arm's length, coarse enough
   to be visible as dots up close — which is the whole point of a halftone. */
.riso-halftone::after {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-image: radial-gradient(circle at center, var(--wp--preset--color--main) 30%, transparent 31%);
	background-size: 4px 4px;
	mix-blend-mode: multiply;
	opacity: 0.3;
}

/* The yellow plate, printed a hair proud of the black one. Only the sliver that
   misses shows, along two edges. */
.riso-halftone::before {
	content: "";
	position: absolute;
	inset: 0;
	pointer-events: none;
	z-index: -1;
	background: var(--wp--preset--color--primary);
	transform: translate(calc(var(--riso-shift-lg) * -1), var(--riso-shift-lg));
}

/* A portrait source dropped into a half-width column runs to a thousand pixels
   tall and swallows the ask sitting next to it. Crop to landscape so the two
   halves of the band stay in conversation. */
.riso-halftone--crop img {
	aspect-ratio: 4 / 3;
	object-fit: cover;
	object-position: 50% 35%;
}

/* Core pulls an alignfull block out to the edges with negative margins equal to
   the root padding. A figure also inherits max-width:100%, which resolves
   against the PADDED container — so the cap (1384px at a 1440px viewport) wins
   and the negative margins do nothing on the right. The band lands one gutter
   short. Releasing the cap lets the margins do their job. */
.riso-bleed {
	max-width: none;
}

/* A raster image never stretches past its own native width on its own — core
   CSS caps it there and centres it, which on any screen wider than the image
   reads as a band that is "almost" full width rather than actually full width.
   These bands are meant to run edge to edge regardless of the source file. */
.riso-bleed img {
	display: block;
	width: 100%;
	height: auto;
}

/* useRootPaddingAwareAlignments (theme.json) inserts the theme's global side
   padding into every alignfull block via .has-global-padding — right for text,
   wrong here, where the photograph is meant to touch both edges. */
.riso-bleed.has-global-padding {
	padding-left: 0;
	padding-right: 0;
}


/* --- Buttons --------------------------------------------------------------- */

/* Every button is printed out of register, and hovering brings it back in. The
   plate snaps home and the button moves into the space it was already casting,
   so nothing around it shifts — the motion is entirely within the element's own
   footprint. */
.wp-block-button__link,
.wp-block-search__button {
	box-shadow: var(--riso-shift) var(--riso-shift) 0 0 var(--riso-plate-ink);
	transition: transform 220ms var(--riso-ease),
		box-shadow 220ms var(--riso-ease),
		background-color 180ms ease,
		color 180ms ease;
}

.wp-block-button__link:hover,
.wp-block-search__button:hover {
	transform: translate(var(--riso-shift), var(--riso-shift));
	box-shadow: 0 0 0 0 var(--riso-plate-ink);
}

.wp-block-button__link:active,
.wp-block-search__button:active {
	transform: translate(var(--riso-shift), var(--riso-shift)) scale(0.985);
}

/* The outline variant is the second voice: paper showing through, ink only at
   the edge. On a black plate it inverts to paper-on-ink automatically because
   both colours are inherited from the surface. */
.wp-block-button.is-style-outline > .wp-block-button__link {
	background-color: transparent;
	border-color: currentColor;
	color: inherit;
}

.wp-block-button.is-style-outline > .wp-block-button__link:hover {
	background-color: var(--wp--preset--color--primary);
	border-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--main);
}


/* --- Editorial index ------------------------------------------------------- */

/* Posts are set as a broadsheet index rather than a row of equal cards: one
   lead story with a picture, then a ruled list where the date does the work the
   thumbnail was doing badly. */
.riso-lead {
	display: grid;
	grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
	column-gap: clamp(1.5rem, 4vw, 3.5rem);
	row-gap: clamp(1rem, 3vw, 1.75rem);
	align-items: start;
	padding-bottom: clamp(1.75rem, 4vw, 2.75rem);
	border-bottom: 3px solid currentColor;
}

.riso-lead > * {
	margin-block: 0;
}

@media (max-width: 50rem) {
	.riso-lead {
		grid-template-columns: 1fr;
	}
}

.riso-index .wp-block-post {
	display: grid;
	grid-template-columns: 7.5rem 1fr;
	column-gap: clamp(1rem, 3vw, 2.5rem);
	row-gap: 0.25rem;
	align-items: baseline;
	padding-block: clamp(0.9rem, 2.2vw, 1.35rem);
	border-bottom: 1px solid var(--wp--preset--color--border-light);
}

.riso-index .wp-block-post > * {
	margin-block: 0;
}

.riso-index .wp-block-post-date {
	font-family: var(--wp--preset--font-family--monospace);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.06em;
	text-transform: uppercase;
}

/* The highlight sweeps in across the text itself.

   A positioned pseudo-element would be cheaper to animate, but it can only
   draw one box — so on a headline that wraps to three lines it highlights the
   last one and reads as an underline. A background on the inline element is
   drawn per line fragment, which is the actual design. The repaint is the size
   of the link's own text; the rule against animating non-composited properties
   is there to prevent layout thrash and full-screen repaints, not this. */
.riso-lead .wp-block-post-title a,
.riso-index .wp-block-post-title a {
	text-decoration: none;
	background-image: linear-gradient(var(--wp--preset--color--primary), var(--wp--preset--color--primary));
	background-repeat: no-repeat;
	background-position: 0 88%;
	background-size: 0 0.36em;
	transition: background-size 280ms var(--riso-ease);
}

.riso-lead .wp-block-post-title a:hover,
.riso-lead .wp-block-post-title a:focus-visible,
.riso-index .wp-block-post-title a:hover,
.riso-index .wp-block-post-title a:focus-visible {
	background-size: 100% 0.36em;
}

.riso-index .wp-block-post-excerpt {
	grid-column: 2;
	max-width: 62ch;
}

@media (max-width: 40rem) {
	.riso-index .wp-block-post {
		grid-template-columns: 1fr;
	}

	.riso-index .wp-block-post-excerpt {
		grid-column: 1;
	}
}

/* Pagination as printed page numbers, not as pill buttons. */
.wp-block-query-pagination {
	font-family: var(--wp--preset--font-family--monospace);
	font-size: var(--wp--preset--font-size--small);
	letter-spacing: 0.08em;
	text-transform: uppercase;
	border-top: 1px solid var(--wp--preset--color--border-light);
	padding-top: var(--wp--preset--spacing--medium);
}

.wp-block-query-pagination .page-numbers.current {
	background: var(--wp--preset--color--primary);
	padding: 0.1em 0.45em;
	font-weight: 700;
}


/* --- Long-form content ----------------------------------------------------- */

/* Body copy keeps to a measure that can actually be read — but only the body
   copy. Capping every child instead squeezes columns, covers and galleries into
   the text column and leaves half the page empty, which is exactly what the
   donate page did: two donation columns crushed into 360px each with 700px of
   blank paper beside them.

   Layout blocks are deliberately absent from this list. They get the full
   measure and manage their own internal widths. */
.riso-prose > p,
.riso-prose > ul,
.riso-prose > ol,
.riso-prose > .wp-block-paragraph,
.riso-prose > .wp-block-heading,
.riso-prose > .wp-block-list,
.riso-prose > .wp-block-quote,
.riso-prose > .wp-block-pullquote,
.riso-prose > .wp-block-preformatted,
.riso-prose > h1,
.riso-prose > h2,
.riso-prose > h3,
.riso-prose > h4,
.riso-prose > h5,
.riso-prose > h6 {
	max-width: 68ch;
}

.riso-prose h2,
.riso-prose h3 {
	margin-top: var(--wp--preset--spacing--large);
}

/* Lists in body copy get a printer's square rather than a browser bullet. */
.riso-prose ul:not(.wp-block-social-links):not(.wp-block-navigation__container) {
	list-style: none;
	padding-left: 0;
}

.riso-prose ul:not(.wp-block-social-links):not(.wp-block-navigation__container) > li {
	position: relative;
	padding-left: 1.5rem;
	margin-bottom: 0.4rem;
}

.riso-prose ul:not(.wp-block-social-links):not(.wp-block-navigation__container) > li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.62em;
	width: 0.5rem;
	height: 0.5rem;
	background: var(--wp--preset--color--primary);
	outline: 1px solid var(--wp--preset--color--main);
}


/* --- Boundaries plate ------------------------------------------------------ */

/* The "does not" list. A stamped plate rather than a full-bleed band: this is
   one boundary being drawn, not a poster moment. */
.riso-dontnot__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: 0.7rem;
	max-width: 48ch;
}

.riso-dontnot__list li {
	padding-left: 1.6rem;
	position: relative;
}

.riso-dontnot__list li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 0.5em;
	width: 0.7rem;
	height: 0.16rem;
	background: var(--wp--preset--color--alert);
}


/* --- Footer ---------------------------------------------------------------- */

.riso-footer-nav .wp-block-navigation-item__label {
	font-family: var(--wp--preset--font-family--big-shoulders);
	font-weight: 700;
	text-transform: uppercase;
	letter-spacing: 0.05em;
	font-size: 1.15rem;
}

.riso-colophon {
	font-family: var(--wp--preset--font-family--monospace);
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}


/* --- Entry motion ---------------------------------------------------------- */

/* Sections arrive a beat apart rather than all at once. Transform and opacity
   only, so it stays on the compositor. The no-JS and reduced-motion paths both
   land on "already visible" — nothing is ever hidden behind an animation that
   might not run. */
@media (prefers-reduced-motion: no-preference) {
	.js .riso-reveal {
		opacity: 0;
		transform: translateY(1.5rem);
		transition: opacity 620ms var(--riso-ease),
			transform 620ms var(--riso-ease);
		transition-delay: calc(var(--riso-reveal-index, 0) * 90ms);
	}

	.js .riso-reveal.is-revealed {
		opacity: 1;
		transform: none;
	}
}


/* --- Third-party embeds ---------------------------------------------------- */

/* Google Forms is a cross-origin iframe: nothing in here can style what is
   inside it, and its height cannot be measured from this side. So the width is
   made fluid and the height is set explicitly, then raised on narrow screens
   where the fields wrap and the form grows taller.

   The iframe carries an inline min-height as well, so that if this stylesheet
   is ever missing the embed is still a usable box rather than the browser
   default of 150px. */
.vcd-embed {
	max-width: 46rem;
}

.vcd-embed iframe {
	height: 2200px;
}

@media (max-width: 40rem) {
	.vcd-embed iframe {
		height: 3000px;
	}
}

/* An embed that fails to load leaves no trace, so the way out is always
   printed underneath it. */
.vcd-embed__fallback {
	margin-top: 0.75rem;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--secondary);
}


/* --- Language switch ------------------------------------------------------- */

/* Two cells sharing one box: the language you are reading is filled, the other
   is an empty cell you can press. It is a switch rather than a pair of links
   because there are exactly two states and you are always in one of them.

   Built from two anchors rather than a checkbox, because this navigates to a
   different URL. A real form switch would promise something it cannot do:
   flip without leaving the page. */
.riso-langswitch {
	display: inline-flex;
	flex: 0 0 auto;
	border: 1px solid currentColor;
	line-height: 1;
}

.riso-langswitch__cell {
	display: flex;
	align-items: center;
	justify-content: center;
	/* Two digits of mono at this size, so the cells stay equal whichever
	   language is filled and the box never changes width. */
	min-width: 2.4em;
	padding: 0.42em 0.1em;
	font-family: var(--wp--preset--font-family--monospace);
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.1em;
	text-decoration: none;
	color: inherit;
	transition: background-color 160ms var(--riso-ease), color 160ms var(--riso-ease);
}

.riso-langswitch__cell:hover {
	background-color: currentColor;
}

/* The filled cell inherits its text colour from the surface, so the label has
   to come back the other way or it would be ink on ink. */
.riso-langswitch__cell:hover span[aria-hidden] {
	color: var(--wp--preset--color--primary-alt);
}

.riso-langswitch__cell.is-current {
	background-color: var(--wp--preset--color--primary);
	color: var(--wp--preset--color--primary-alt);
	cursor: default;
}

.riso-langswitch__cell.is-current:hover {
	background-color: var(--wp--preset--color--primary);
}

.riso-langswitch__cell.is-current:hover span[aria-hidden] {
	color: var(--wp--preset--color--primary-alt);
}

.riso-langswitch__cell + .riso-langswitch__cell {
	border-left: 1px solid currentColor;
}

.riso-langswitch__cell:focus-visible {
	outline: 3px solid var(--wp--preset--color--primary);
	outline-offset: 2px;
}


/* --- Resources page -------------------------------------------------------- */

/* The downloads grid. These rules live here rather than in the block markup on
   purpose: styling a block through its own attributes means hand-writing the
   exact HTML Gutenberg's save function would have produced, and any difference
   makes the editor refuse the block with "unexpected or invalid content". A
   class name is a first-class block attribute and always survives that round
   trip, so the page stays editable. */
.vcd-res-card {
	border-top: 3px solid var(--wp--preset--color--main);
	padding-top: var(--wp--preset--spacing--medium);
}

/* Document previews are all different shapes. A fixed box with contain keeps
   the grid tidy while showing each one whole. */
.vcd-res-card img {
	aspect-ratio: 4 / 3;
	object-fit: contain;
}

.vcd-res-notice {
	border: 2px solid var(--wp--preset--color--alert);
	padding: var(--wp--preset--spacing--large);
	max-width: 46rem;
}


/* --- Guards ---------------------------------------------------------------- */

/* Safety yellow scores 13.7:1 on ink and 1.3:1 on paper. It is a plate, a ghost
   or a large accent on a dark ground — never small text on a light one. If it
   ever lands there by mistake, fall back to ink rather than ship something
   unreadable to someone who needs to read it. */
.has-base-background-color .has-primary-color:not(.has-background),
.has-tertiary-background-color .has-primary-color:not(.has-background),
body:not([class*="background-color"]) .has-primary-color:not(.has-background) {
	color: var(--wp--preset--color--main);
}

/* Print has no soft corners. */
.wp-block-button__link,
.wp-block-search__button,
.wp-block-search__input,
.wp-block-image img,
.wp-block-post-featured-image img {
	border-radius: 0;
}

:where(a, button, input, select, textarea, summary):focus-visible {
	outline: 3px solid currentColor;
	outline-offset: 2px;
}

.skip-link:focus {
	z-index: var(--z-skiplink);
}

/* Tap targets in the masthead and footer never drop below the 44px floor. */
.riso-masthead .wp-block-navigation-item__content,
.riso-footer-nav .wp-block-navigation-item__content {
	min-height: 44px;
	display: flex;
	align-items: center;
}

@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/* Grain and offsets are screen artifacts. On paper they are noise on top of
   noise, and they cost ink. */
@media print {
	.riso-grain,
	.riso-hazard {
		display: none;
	}

	.riso-offset,
	.is-style-riso-offset {
		text-shadow: none;
	}

	.riso-plate,
	.riso-plate--tight,
	.wp-block-button__link {
		box-shadow: none;
	}

	.riso-stamp {
		transform: none;
	}
}
