/*!
 * Archivo del Desierto — components
 */

@layer components {

	/* ══════════════════════════════════════════════════════════════════════
	   Site header
	   ══════════════════════════════════════════════════════════════════════ */

	.site-header {
		position: fixed;
		inset-block-start: 0;
		inset-inline: 0;
		z-index: 100;
		min-height: var(--header-height);
		display: flex;
		/* Stretch, so the mega tab can reach the bar's bottom edge; see the note there. */
		align-items: stretch;
		transition: background-color var(--motion-slow) var(--ease-standard),
			box-shadow var(--motion-slow) var(--ease-standard),
			backdrop-filter var(--motion-slow) var(--ease-standard);
	}

	/* Over the hero photograph the bar is a gradient scrim; once scrolled it becomes solid so
	   the labels never sit on an unpredictable image. */
	.site-header::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: -1;
		background: linear-gradient(
			180deg,
			rgb(11 13 16 / 0.82) 0%,
			rgb(11 13 16 / 0.42) 60%,
			rgb(11 13 16 / 0) 100%
		);
		opacity: 1;
		transition: opacity var(--motion-slow) var(--ease-standard);
	}

	.is-scrolled .site-header {
		background-color: color-mix(in oklab, var(--color-night) 94%, transparent);
		box-shadow: 0 1px 0 color-mix(in oklab, var(--color-brass) 30%, transparent),
			0 10px 30px -18px rgb(0 0 0 / 0.8);
		-webkit-backdrop-filter: saturate(150%) blur(12px);
		backdrop-filter: saturate(150%) blur(12px);
	}

	.is-scrolled .site-header::before {
		opacity: 0;
	}

	/* Pages without a photographic hero need the solid bar from the start. */
	.add--page .site-header,
	.add--contact .site-header,
	.add--search .site-header,
	.add--notfound .site-header {
		background-color: var(--color-night);
	}

	/*
	 * Stretched, not centred, all the way down to the nav item: the mega tab has to reach the
	 * bottom edge of the bar so that the pointer never crosses bare header on its way into the
	 * panel. Anything that should stay optically centred does it for itself.
	 */
	.site-header__inner {
		display: flex;
		align-items: stretch;
		justify-content: space-between;
		gap: var(--space-m);
		width: 100%;
	}

	.brand {
		display: inline-flex;
		flex-direction: column;
		justify-content: center;
		gap: 0.15rem;
		text-decoration: none;
		color: var(--color-paper);
		padding-block: 0.4rem;
	}

	.brand__name {
		font-family: var(--font-display);
		font-size: clamp(1.05rem, 2.1vw, 1.3rem);
		font-weight: 700;
		letter-spacing: 0.01em;
		line-height: 1;
		color: var(--color-paper);
	}

	.brand__name em {
		font-style: italic;
		font-weight: 600;
		color: var(--color-sand);
	}

	.brand__tag {
		font-family: var(--font-mono);
		font-size: 0.625rem;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: color-mix(in oklab, var(--color-brass) 85%, white);
		white-space: nowrap;
	}

	/* Below ~420px the tagline wraps onto a second line and collides with the menu button. */
	@media (max-width: 26.5em) {
		.brand__tag { display: none; }
	}

	/* ── Primary navigation ─────────────────────────────────────────────── */

	.nav {
		display: flex;
		align-items: stretch;
		gap: clamp(0.75rem, 2vw, 1.75rem);
	}

	.nav__list {
		display: flex;
		align-items: stretch;
		gap: clamp(0.5rem, 1.6vw, 1.5rem);
		margin: 0;
		padding: 0;
		list-style: none;
	}

	.nav__item {
		position: relative;
		display: flex;
		align-items: stretch;
	}

	/* The link and chevron together. Full height, so the item ends where the panel begins. */
	.nav__tab {
		display: flex;
		align-self: stretch;
		align-items: center;
		gap: 0.1rem;
		padding-inline: 0.5rem;
		border: 1px solid transparent;
		border-bottom: 0;
		border-radius: var(--radius-m) var(--radius-m) 0 0;
	}

	.nav__link {
		display: inline-block;
		padding: 0.6rem 0.15rem;
		font-size: 0.75rem;
		font-weight: 500;
		letter-spacing: var(--tracking-wider);
		text-transform: uppercase;
		text-decoration: none;
		color: color-mix(in oklab, var(--color-paper) 88%, transparent);
		white-space: nowrap;
	}

	.nav__link:hover,
	.nav__link:focus-visible {
		color: var(--color-paper);
	}

	/* An ink rule that draws from the centre. */
	.nav__link::after {
		content: "";
		position: absolute;
		inset-inline: 50%;
		inset-block-end: 0.35rem;
		height: 1px;
		background-color: var(--color-brass);
		transition: inset-inline var(--motion-normal) var(--ease-cinematic);
	}

	.nav__link:hover::after,
	.nav__link:focus-visible::after,
	.nav__item--current > .nav__link::after {
		inset-inline: 0.15rem;
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Mega panel
	   ══════════════════════════════════════════════════════════════════════

	   Opens on hover and on focus-within, in CSS, so it works with JavaScript off. The script
	   adds only what CSS cannot do: close on Escape, close on a click outside, and a real
	   toggle for touch, where "hover" does not exist.

	   The item goes `position: static` on purpose — the panel is positioned against the fixed
	   header instead, which is what lets it span the full width of the bar. */

	/*
	 * Static, not relative: the panel is positioned against the fixed header instead, which is
	 * what lets it span the whole bar. That is also why the tab decoration lives on the inner
	 * `.nav__tab` rather than on the item itself.
	 */
	.nav__item--mega { position: static; }

	/*
	 * The folder tab. Brass on the top and the sides, nothing along the bottom, and three
	 * pixels of overshoot so the tab's own paper covers the panel's brass rule underneath —
	 * which is what makes the two read as one piece of card rather than as a button sitting
	 * above a drawer.
	 */
	.nav__item--mega:hover .nav__tab,
	.nav__item--mega:focus-within .nav__tab,
	.nav__item--mega.is-open .nav__tab {
		position: relative;
		z-index: 95;
		/* Inset at the top so it reads as a tab; three pixels past the bottom so its paper
		   covers the panel's brass rule and the two become one piece of card. */
		margin-block: 0.5rem -3px;
		background-color: var(--color-paper);
		border-color: var(--color-brass);
		border-block-start-width: 3px;
		box-shadow: 0 -6px 18px -10px rgb(11 13 16 / 0.5);
	}

	.nav__item--mega:hover .nav__link,
	.nav__item--mega:focus-within .nav__link,
	.nav__item--mega.is-open .nav__link {
		color: var(--color-ink);
	}

	.nav__item--mega:hover .nav__link::after,
	.nav__item--mega:focus-within .nav__link::after,
	.nav__item--mega.is-open .nav__link::after {
		display: none;
	}

	.nav__item--mega:hover .nav__disclose,
	.nav__item--mega:focus-within .nav__disclose,
	.nav__item--mega.is-open .nav__disclose {
		color: var(--accent-text);
	}

	/*
	 * El rótulo y su pestaña tienen que cambiar en el MISMO fotograma.
	 *
	 * El fondo de `.nav__tab` salta a papel de golpe —no lleva transición—, pero el color del
	 * enlace heredaba `a { transition: color 140ms }` y el de la flecha el suyo propio. Durante
	 * esos 140 ms el texto viajaba de blanco roto a tinta *por encima del papel ya pintado*: dos
	 * tonos casi iguales, o sea, texto invisible.
	 *
	 * En la primera apertura eso no dura 140 ms. El hilo principal está rasterizando el panel
	 * (medido: 83 ms de fotograma con la CPU a 1/4, y ninguno en la segunda apertura), así que
	 * no llega ningún fotograma nuevo y el intermedio se queda congelado hasta que el panel
	 * termina. De ahí que el rótulo «desapareciera» un par de segundos y volviera justo cuando
	 * el megamenú aparecía.
	 *
	 * Sin transición sólo existen dos estados, y los dos se leen: si el fotograma se retrasa, lo
	 * que se ve es el anterior —texto claro sobre la barra oscura—, nunca un estado intermedio.
	 * Va sin `:hover` para que valga también al salir, que es la misma trampa al revés.
	 */
	.nav__item--mega .nav__link { transition: none; }

	/* La flecha conserva su giro; lo que no puede fundirse es el color. */
	.nav__item--mega .nav__disclose {
		transition: rotate var(--motion-normal) var(--ease-standard);
	}

	.nav__disclose {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		width: 1.5rem;
		height: 1.5rem;
		padding: 0;
		color: color-mix(in oklab, var(--color-paper) 62%, transparent);
		background: none;
		border: 0;
		cursor: pointer;
		transition: color var(--motion-fast) var(--ease-standard),
			rotate var(--motion-normal) var(--ease-standard);
	}

	.nav__disclose svg { width: 10px; height: 6px; }

	.nav__disclose:hover,
	.nav__disclose:focus-visible { color: var(--color-paper); }

	.nav__item--mega:hover .nav__disclose,
	.nav__item--mega:focus-within .nav__disclose,
	.nav__item--mega.is-open .nav__disclose { rotate: 180deg; }

	.mega {
		position: absolute;
		inset-inline: 0;
		inset-block-start: 100%;
		z-index: 90;
		padding-inline: var(--space-gutter);
		opacity: 0;
		visibility: hidden;
		translate: 0 -10px;
		transition: opacity var(--motion-normal) var(--ease-standard),
			translate var(--motion-normal) var(--ease-cinematic),
			visibility var(--motion-normal);
	}

	.nav__item--mega:hover > .mega,
	.nav__item--mega:focus-within > .mega,
	.nav__item--mega.is-open > .mega {
		opacity: 1;
		visibility: visible;
		translate: 0;
	}

	.mega__sheet {
		position: relative;
		max-width: var(--width-full);
		margin-inline: auto;
		padding-block: clamp(1.75rem, 3vw, 2.5rem) 0;
		background-color: var(--color-paper);
		border: 1px solid var(--color-border);
		border-block-start: 3px solid var(--color-brass);
		border-radius: 0 0 var(--radius-l) var(--radius-l);
		box-shadow: 0 30px 70px -26px rgb(11 13 16 / 0.6);
	}

	/*
	 * The panel is a sheet of card, so it is scuffed like one: a warm wash falling from the
	 * brass rule, and scratches — long, shallow, slightly wandering strokes, displaced by
	 * fractal noise so none of them is straight. Generated, like every other texture here; a
	 * photograph of scratched paper would weigh more than the panel it sits under.
	 */
	.mega__sheet::before {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 0;
		pointer-events: none;
		background-image:
			linear-gradient(180deg, color-mix(in oklab, var(--color-brass) 11%, transparent) 0, transparent 9rem),
			url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='600'%3E%3Cfilter id='s'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.02' numOctaves='3' seed='9' result='n'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='8' xChannelSelector='R' yChannelSelector='G'/%3E%3C/filter%3E%3Cg filter='url(%23s)' fill='none' stroke-linecap='round'%3E%3Cpath d='M294 484 l15 330' stroke='%23fffaf0' stroke-width='0.57' opacity='0.19'/%3E%3Cpath d='M206 448 l40 148' stroke='%235a4526' stroke-width='0.58' opacity='0.36'/%3E%3Cpath d='M50 475 l137 26' stroke='%235a4526' stroke-width='0.7' opacity='0.22'/%3E%3Cpath d='M418 42 l192 1' stroke='%235a4526' stroke-width='0.91' opacity='0.31'/%3E%3Cpath d='M284 202 l-4 198' stroke='%23fffaf0' stroke-width='0.53' opacity='0.33'/%3E%3Cpath d='M331 3 l188 -36' stroke='%235a4526' stroke-width='0.82' opacity='0.3'/%3E%3Cpath d='M131 472 l138 7' stroke='%235a4526' stroke-width='0.65' opacity='0.28'/%3E%3Cpath d='M183 102 l4 113' stroke='%235a4526' stroke-width='0.51' opacity='0.42'/%3E%3Cpath d='M183 280 l10 158' stroke='%23fffaf0' stroke-width='0.65' opacity='0.42'/%3E%3Cpath d='M418 291 l84 230' stroke='%235a4526' stroke-width='0.94' opacity='0.49'/%3E%3Cpath d='M338 235 l138 -17' stroke='%235a4526' stroke-width='1.04' opacity='0.2'/%3E%3Cpath d='M583 183 l311 -28' stroke='%235a4526' stroke-width='1.06' opacity='0.21'/%3E%3Cpath d='M453 503 l254 -12' stroke='%23fffaf0' stroke-width='0.83' opacity='0.49'/%3E%3Cpath d='M104 575 l90 216' stroke='%235a4526' stroke-width='0.85' opacity='0.44'/%3E%3Cpath d='M102 245 l241 -51' stroke='%235a4526' stroke-width='0.64' opacity='0.28'/%3E%3Cpath d='M81 218 l14 96' stroke='%235a4526' stroke-width='0.53' opacity='0.45'/%3E%3Cpath d='M-20 523 Q 300 503 620 541' stroke='%235a4526' stroke-width='0.7' opacity='0.22'/%3E%3Cpath d='M-20 171 Q 300 160 620 158' stroke='%235a4526' stroke-width='0.7' opacity='0.22'/%3E%3Cpath d='M-20 527 Q 300 509 620 524' stroke='%235a4526' stroke-width='0.7' opacity='0.22'/%3E%3C/g%3E%3C/svg%3E");
		background-size: 100% 100%, 600px 600px;
		background-repeat: no-repeat, repeat;
		mix-blend-mode: multiply;
		opacity: 0.38;
	}

	/* Above the scuffing. */
	.mega__inner,
	.mega__foot {
		position: relative;
		z-index: 1;
	}

	.mega__inner {
		display: flex;
		flex-wrap: wrap;
		align-items: flex-start;
		gap: clamp(1.5rem, 3vw, 3rem);
		padding-bottom: clamp(1.25rem, 2vw, 1.75rem);
	}

	.mega__inner--three > * { flex: 1 1 min(18rem, 100%); min-width: 0; }

	.mega__label {
		font-family: var(--font-mono);
		font-size: 0.625rem;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	.mega__lede { flex: 1 1 100%; }

	.mega__lede-text {
		max-width: 62ch;
		margin-top: var(--space-2xs);
		font-family: var(--font-display);
		font-size: var(--text-lg);
		line-height: var(--leading-snug);
		color: var(--color-ink);
	}

	/* The shelf gets a touch more room above it: three books need somewhere to stand. */
	.mega__sheet--shelf { padding-block-start: clamp(2rem, 3.4vw, 2.75rem); }

	/* ── The shelf ──────────────────────────────────────────────────────── */

	.shelf {
		display: flex;
		flex-wrap: wrap;
		gap: clamp(1rem, 2.5vw, 2.25rem);
		flex: 1 1 100%;
	}

	.shelf-book {
		display: flex;
		align-items: flex-start;
		gap: clamp(0.9rem, 1.6vw, 1.4rem);
		flex: 1 1 min(20rem, 100%);
		min-width: 0;
		padding: clamp(0.75rem, 1.4vw, 1.1rem);
		text-decoration: none;
		border: 1px solid transparent;
		border-radius: var(--radius-m);
		transition: background-color var(--motion-normal) var(--ease-standard),
			border-color var(--motion-normal) var(--ease-standard);
	}

	.shelf-book:hover,
	.shelf-book:focus-visible {
		background-color: color-mix(in oklab, var(--accent) 7%, var(--color-paper));
		border-color: color-mix(in oklab, var(--accent) 34%, transparent);
	}

	/*
	 * The stage gives the book somewhere to stand. Explicit width, and two classes of
	 * specificity: `.book3d-link { width: 100% }` is declared later in this file and would
	 * otherwise win at equal specificity — which is how the covers once opened at three
	 * hundred pixels each and crushed the text beside them.
	 */
	.shelf-book__stage {
		flex: 0 0 auto;
		display: block;
		width: clamp(5.5rem, 8vw, 7.75rem);
		padding-block: 0.35rem;
	}

	/*
	 * La estantería sólo fija el ángulo de reposo; quien lo anima es `.book3d__inner`. Con la
	 * transición aquí, el valor heredado cambiaba de forma continua y la del interior perseguía
	 * a un objetivo en movimiento: dos curvas para el mismo giro, que es exactamente como se
	 * consigue que un movimiento se sienta tosco.
	 */
	.shelf-book .shelf-book__object {
		display: block;
		width: 100%;
		--book-rot: 22deg;
	}

	.shelf-book:hover .shelf-book__object,
	.shelf-book:focus-visible .shelf-book__object {
		--book-rot: 12deg;
	}

	.shelf-book__body {
		display: flex;
		flex-direction: column;
		min-width: 0;
	}

	.shelf-book__numeral {
		font-family: var(--font-display);
		font-size: 1.5rem;
		font-weight: 600;
		line-height: 1;
		color: color-mix(in oklab, var(--accent) 55%, transparent);
	}

	.shelf-book__kicker {
		margin-top: 0.3rem;
		font-family: var(--font-mono);
		font-size: 0.5625rem;
		letter-spacing: var(--tracking-wider);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	.shelf-book__title {
		margin-top: 0.35rem;
		font-family: var(--font-display);
		font-size: 1.125rem;
		font-weight: 700;
		line-height: 1.15;
		color: var(--color-ink);
		text-wrap: balance;
	}

	.shelf-book__subtitle {
		margin-top: 0.2rem;
		font-size: 0.8125rem;
		font-style: italic;
		line-height: 1.35;
		color: var(--color-muted);
	}

	.shelf-book__meta {
		margin-top: 0.5rem;
		font-family: var(--font-mono);
		font-size: 0.5625rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--color-muted);
	}

	.shelf-book__cta {
		margin-top: 0.7rem;
		font-size: 0.75rem;
		font-weight: 600;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	.shelf-book:hover .shelf-book__cta span,
	.shelf-book:focus-visible .shelf-book__cta span {
		display: inline-block;
		translate: 4px 0;
		transition: translate var(--motion-fast) var(--ease-standard);
	}

	/* ── The preview cards ──────────────────────────────────────────────── */

	/* ── El panel del contexto: mitad mapa, mitad lo demás ──────────────── */

	/*
	 * Top-aligned, not stretched. Stretching made the two tiles as tall as the map card and
	 * left a hand's width of empty paper under each of them.
	 */
	.mega__inner--split {
		align-items: flex-start;
	}

	.mega__inner--split > .mega-hero { flex: 5 1 26rem; }
	.mega__inner--split > .mega__stack { flex: 4 1 22rem; }

	.mega__stack {
		display: flex;
		flex-direction: column;
		gap: clamp(0.75rem, 1.4vw, 1.1rem);
		min-width: 0;
	}

	/* The map card. Its preview is the point, so it gets the height. */
	/*
	 * The caption sits on the sheet rather than under it. Stacked, the card ran to seven
	 * hundred and sixty pixels and left the two tiles beside it floating in empty paper; laid
	 * over the map behind a scrim, the panel is no taller than the preview.
	 */
	.mega-hero {
		position: relative;
		display: block;
		min-width: 0;
		padding: 0.75rem;
		text-decoration: none;
		border: 1px solid transparent;
		border-radius: var(--radius-m);
		transition: background-color var(--motion-normal) var(--ease-standard),
			border-color var(--motion-normal) var(--ease-standard);
	}

	.mega-hero:hover,
	.mega-hero:focus-visible {
		background-color: var(--color-paper-warm);
		border-color: var(--color-border);
	}

	/*
	 * The sheet the map is printed on: aged paper, a neatline and a vignette, the same
	 * treatment as the real map so the preview reads as a smaller copy of it rather than as an
	 * illustration of one. The ratio is enforced by taking the SVG out of flow — an SVG with a
	 * squarish viewBox has a min-content height that `aspect-ratio` yields to.
	 */
	/*
	 * A sheet, not a thumbnail. Everything the full-size map carries, scaled down: a deckle
	 * edge cut by a displaced rectangle, the creases of a sheet that lived folded in four, a
	 * printed neatline, foxing and fibre. No border-radius — torn paper does not have one —
	 * and the shadow is a drop-shadow so it follows the torn outline instead of a rectangle.
	 */
	.mega-hero__sheet {
		position: relative;
		display: block;
		aspect-ratio: 16 / 12;
		overflow: clip;
		background-color: #e7dcc4;
		-webkit-mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='450' preserveAspectRatio='none'%3E%3Cfilter id='d'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.022 0.032' numOctaves='4' seed='23' result='n'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='11' xChannelSelector='R' yChannelSelector='G'/%3E%3C/filter%3E%3Crect x='7' y='7' width='586' height='436' fill='%23fff' filter='url(%23d)'/%3E%3C/svg%3E");
		mask-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='600' height='450' preserveAspectRatio='none'%3E%3Cfilter id='d'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.022 0.032' numOctaves='4' seed='23' result='n'/%3E%3CfeDisplacementMap in='SourceGraphic' in2='n' scale='11' xChannelSelector='R' yChannelSelector='G'/%3E%3C/filter%3E%3Crect x='7' y='7' width='586' height='436' fill='%23fff' filter='url(%23d)'/%3E%3C/svg%3E");
		-webkit-mask-size: 100% 100%;
		mask-size: 100% 100%;
		-webkit-mask-repeat: no-repeat;
		mask-repeat: no-repeat;
		filter: drop-shadow(0 1px 1px rgb(28 22 12 / 0.16)) drop-shadow(0 8px 14px rgb(28 22 12 / 0.16));
	}

	/* The neatline, inside the torn margin where a printed sheet puts it. */
	.mega-hero__sheet::before {
		content: "";
		position: absolute;
		inset: 9px;
		z-index: 2;
		pointer-events: none;
		border: 1px solid rgb(96 72 38 / 0.45);
		box-shadow:
			inset 0 0 0 2px rgb(231 220 196 / 0.4),
			inset 0 0 0 3px rgb(96 72 38 / 0.24),
			inset 0 0 34px 6px rgb(86 62 26 / 0.15);
	}

	.mega-hero__sheet > * {
		position: absolute;
		inset: 0;
	}

	/*
	 * The ageing, on ::after rather than on a child because the rule above only matches real
	 * elements — a pseudo-element is not selected by `>`. Two creases, corner staining, foxing
	 * and fibre, in that order.
	 */
	.mega-hero__sheet::after {
		content: "";
		position: absolute;
		inset: 0;
		z-index: 1;
		pointer-events: none;
		background-image:
			/* the vertical and horizontal folds of a sheet kept folded in four: a shadowed
			   valley with a burnished highlight along one side of it */
			/* Off dead centre on purpose: a fold that lands exactly at 50% in both axes reads as
			   a mirror line rather than as a crease. */
			linear-gradient(90deg, transparent 45.4%, rgb(90 70 36 / 0.17) 46.9%, rgb(255 250 235 / 0.30) 47.7%, transparent 49.4%),
			linear-gradient(0deg, transparent 51.2%, rgb(90 70 36 / 0.13) 52.6%, rgb(255 250 235 / 0.24) 53.4%, transparent 55%),
			radial-gradient(56% 44% at 2% 4%, rgb(120 88 40 / 0.16), transparent 72%),
			radial-gradient(60% 46% at 98% 98%, rgb(104 74 32 / 0.18), transparent 74%),
			url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='380' height='380'%3E%3Cfilter id='mf'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.014' numOctaves='3' seed='5'/%3E%3CfeColorMatrix type='matrix' values='0 0 0 0 0.44 0 0 0 0 0.31 0 0 0 0 0.11 0 0 0 -1.5 0.62'/%3E%3C/filter%3E%3Crect width='380' height='380' filter='url(%23mf)'/%3E%3C/svg%3E"),
			url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='mg'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23mg)' opacity='0.5'/%3E%3C/svg%3E");
		background-size: 100% 100%, 100% 100%, auto, auto, 380px 380px, 180px 180px;
		mix-blend-mode: multiply;
		opacity: 0.52;
	}

	/*
	 * A cartouche, in the corner where the sheet is empty desert — which is how a printed map
	 * carries its title. The first attempt was a full-width scrim across the foot of the frame,
	 * and it buried Sidi Ifni, El Aaiún and Hausa: the half of the route the panel exists to
	 * show.
	 */
	.mega-hero__body {
		position: absolute;
		inset: auto 1.5rem 1.5rem auto;
		display: block;
		width: min(17.5rem, 54%);
		padding: 0.8rem 1rem 0.9rem;
		background-color: color-mix(in oklab, #efe6d0 95%, transparent);
		border: 1px solid rgb(96 72 38 / 0.34);
		border-radius: var(--radius-xs);
		box-shadow: 0 8px 20px -10px rgb(60 44 18 / 0.5);
	}

	.mega-hero__label {
		display: block;
		font-family: var(--font-mono);
		font-size: 0.5625rem;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	.mega-hero__title {
		display: block;
		margin-top: 0.25rem;
		font-family: var(--font-display);
		font-size: clamp(1.0625rem, 1.4vw, 1.25rem);
		font-weight: 700;
		line-height: 1.15;
		color: var(--color-ink);
	}

	.mega-hero__text {
		display: block;
		max-width: 52ch;
		margin-top: 0.3rem;
		font-size: 0.8125rem;
		line-height: 1.5;
		color: var(--color-charcoal);
	}

	.mega-hero__cta,
	.mega-tile__cta {
		display: block;
		margin-top: 0.6rem;
		font-family: var(--font-mono);
		font-size: 0.625rem;
		letter-spacing: var(--tracking-wider);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	.mega-hero:hover .mega-hero__cta span,
	.mega-hero:focus-visible .mega-hero__cta span,
	.mega-tile:hover .mega-tile__cta span,
	.mega-tile:focus-visible .mega-tile__cta span {
		display: inline-block;
		translate: 4px 0;
		transition: translate var(--motion-fast) var(--ease-standard);
	}

	/* The two tiles beside it. */
	.mega-tile {
		display: flex;
		flex-direction: column;
		gap: 0.85rem;
		flex: 0 0 auto;
		min-width: 0;
		padding: 0.85rem;
		text-decoration: none;
		border: 1px solid var(--color-border);
		border-radius: var(--radius-m);
		transition: background-color var(--motion-normal) var(--ease-standard),
			border-color var(--motion-normal) var(--ease-standard);
	}

	.mega-tile:hover,
	.mega-tile:focus-visible {
		background-color: var(--color-paper-warm);
		border-color: color-mix(in oklab, var(--accent) 40%, transparent);
	}

	.mega-tile__title {
		display: block;
		font-family: var(--font-display);
		font-size: 1.0625rem;
		font-weight: 700;
		color: var(--color-ink);
	}

	.mega-tile__text {
		display: block;
		margin-top: 0.2rem;
		font-size: 0.8125rem;
		line-height: 1.5;
		color: var(--color-muted);
	}

	/* Five plates hung in a row, as they are on the wall. */
	.mega-tile__strip {
		display: flex;
		gap: 3px;
		height: clamp(4.5rem, 7vw, 6rem);
	}

	.mega-tile__strip img {
		display: block;
		flex: 1 1 0;
		min-width: 0;
		height: 100%;
		object-fit: cover;
		filter: grayscale(1) contrast(1.06);
		border: 1px solid var(--color-border);
		transition: filter var(--motion-normal) var(--ease-standard);
	}

	.mega-tile:hover .mega-tile__strip img,
	.mega-tile:focus-visible .mega-tile__strip img { filter: grayscale(0.2) contrast(1.06); }

	/* The chronology, drawn as a rail rather than listed as rows. */
	.date-rail {
		position: relative;
		display: flex;
		justify-content: space-between;
		gap: 0.35rem;
		padding-top: 1.1rem;
	}

	/* The same rule as the chronology, laid on its side: a line with a tick above each stop. */
	.date-rail::before {
		content: "";
		position: absolute;
		inset-block-start: 0.16rem;
		inset-inline: 0.4rem;
		height: 7px;
		background-image:
			linear-gradient(90deg, var(--color-border-strong) 50%, transparent 50%),
			repeating-linear-gradient(90deg, color-mix(in oklab, var(--accent) 26%, transparent) 0 1px, transparent 1px 11px);
		background-size: 6px 1px, 100% 4px;
		background-position: 0 5px, 0 0;
		background-repeat: repeat-x, repeat-x;
	}

	.date-rail__step {
		position: relative;
		display: flex;
		flex-direction: column;
		align-items: center;
		gap: 0.15rem;
		text-align: center;
	}

	/* Benchmarks again, at panel scale: core, paper ring, hairline ring. */
	.date-rail__dot {
		position: absolute;
		inset-block-start: -0.86rem;
		width: 5px;
		height: 5px;
		border-radius: 50%;
		background-color: color-mix(in oklab, var(--accent) 62%, var(--color-paper));
		box-shadow:
			0 0 0 2px var(--color-paper),
			0 0 0 3px color-mix(in oklab, var(--accent) 40%, transparent),
			0 0 0 5px var(--color-paper);
	}

	.date-rail__step--mark .date-rail__dot {
		background-color: var(--accent-deep);
		box-shadow:
			0 0 0 2px var(--color-paper),
			0 0 0 3.5px var(--accent),
			0 0 0 6px var(--color-paper),
			0 0 12px 4px color-mix(in oklab, var(--accent) 32%, transparent);
	}

	.date-rail__year {
		font-family: var(--font-mono);
		font-size: 0.625rem;
		letter-spacing: 0.02em;
		color: var(--color-charcoal);
	}

	.date-rail__step--mark .date-rail__year { color: var(--accent-text); font-weight: 600; }

	.date-rail__text {
		font-family: var(--font-mono);
		font-size: 0.5rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--color-muted);
	}

	/* The map miniature, drawn from the same geometry as the real map. */
	.mini-map {
		display: block;
		width: 100%;
		height: 100%;
	}

	.mini-map :where(path, circle, rect) { vector-effect: non-scaling-stroke; }
	.mini-map__water { fill: #d7e2e0; }

	.mini-map__shore {
		fill: #f2ead7;
		stroke: #9a8a68;
		stroke-width: 1;
	}

	.mini-map__line {
		stroke: var(--color-rust);
		stroke-width: 2;
		stroke-dasharray: 2 7;
		stroke-linecap: round;
		transition: stroke-width var(--motion-normal) var(--ease-standard);
	}

	.mega-hero:hover .mini-map__line,
	.mega-hero:focus-visible .mini-map__line { stroke-width: 3.2; }

	.mini-map__dot {
		fill: var(--color-ink);
		stroke: #f2ead7;
		stroke-width: 1.5;
	}

	.mini-map__label {
		font-family: var(--font-mono);
		font-size: 34px;
		letter-spacing: 0.04em;
		fill: var(--color-ink);
		paint-order: stroke;
		stroke: #f2ead7;
		stroke-width: 4px;
		stroke-linejoin: round;
	}

	.mega__foot {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: 0.75rem 2rem;
		padding: 0.9rem var(--space-gutter);
		font-size: 0.8125rem;
		color: var(--color-charcoal);
		background-color: var(--color-paper-warm);
		border-block-start: 1px solid var(--color-border);
		border-radius: 0 0 var(--radius-l) var(--radius-l);
	}

	/*
	 * The cards arrive in sequence when the panel opens. Scoped under .js so that with the
	 * script blocked — where the panel is still a working hover menu — nothing starts life at
	 * zero opacity waiting for an animation that may never run.
	 */
	.js .shelf-book,
	.js .mega-hero,
	.js .mega-tile { opacity: 0; }

	.js .nav__item--mega:hover .shelf-book,
	.js .nav__item--mega:focus-within .shelf-book,
	.js .nav__item--mega.is-open .shelf-book,
	.js .nav__item--mega:hover :is(.mega-hero, .mega-tile),
	.js .nav__item--mega:focus-within :is(.mega-hero, .mega-tile),
	.js .nav__item--mega.is-open :is(.mega-hero, .mega-tile) {
		animation: mega-in 460ms var(--ease-cinematic) both;
		animation-delay: calc(90ms + var(--i, 0) * 80ms);
	}

	@keyframes mega-in {
		from { opacity: 0; translate: 0 14px; }
		to { opacity: 1; translate: none; }
	}

	@media (prefers-reduced-motion: reduce) {
		.mega { transition: none; }
		.shelf-book .shelf-book__object { transition: none; }
		.js .shelf-book,
		.js .mega-hero,
		.js .mega-tile { opacity: 1; }
		.js .nav__item--mega:hover .shelf-book,
		.js .nav__item--mega:focus-within .shelf-book,
		.js .nav__item--mega.is-open .shelf-book,
		.js .nav__item--mega:hover :is(.mega-hero, .mega-tile),
		.js .nav__item--mega:focus-within :is(.mega-hero, .mega-tile),
		.js .nav__item--mega.is-open :is(.mega-hero, .mega-tile) { animation: none; }
	}

	/* ── Mobile navigation ──────────────────────────────────────────────── */

	.nav-toggle {
		align-self: center;
		display: none;
		align-items: center;
		gap: 0.6rem;
		padding: 0.6rem 0.35rem;
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-wider);
		text-transform: uppercase;
		color: var(--color-paper);
	}

	.nav-toggle__bars {
		position: relative;
		width: 22px;
		height: 12px;
	}

	.nav-toggle__bars span {
		position: absolute;
		inset-inline: 0;
		height: 1.5px;
		background-color: currentColor;
		transition: transform var(--motion-normal) var(--ease-cinematic),
			opacity var(--motion-fast) var(--ease-standard);
	}

	.nav-toggle__bars span:nth-child(1) { top: 0; }
	.nav-toggle__bars span:nth-child(2) { top: 5px; }
	.nav-toggle__bars span:nth-child(3) { top: 10px; }

	.is-nav-open .nav-toggle__bars span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
	.is-nav-open .nav-toggle__bars span:nth-child(2) { opacity: 0; }
	.is-nav-open .nav-toggle__bars span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

	.nav-drawer {
		position: fixed;
		inset: 0;
		z-index: 99;
		display: flex;
		flex-direction: column;
		justify-content: center;
		padding: calc(var(--header-height) + var(--space-l)) var(--space-gutter) var(--space-2xl);
		background-color: var(--color-night);
		overflow-y: auto;
		opacity: 0;
		visibility: hidden;
		transition: opacity var(--motion-normal) var(--ease-standard), visibility var(--motion-normal);
	}

	.is-nav-open .nav-drawer {
		opacity: 1;
		visibility: visible;
	}

	.nav-drawer__list {
		display: flex;
		flex-direction: column;
		gap: 0.35rem;
		margin: 0;
		padding: 0;
		list-style: none;
		max-width: 32rem;
	}

	.nav-drawer__link {
		display: flex;
		align-items: baseline;
		gap: 1rem;
		padding: 0.7rem 0;
		font-family: var(--font-display);
		font-size: clamp(1.6rem, 7vw, 2.4rem);
		font-weight: 600;
		line-height: 1.15;
		color: var(--color-paper);
		text-decoration: none;
		border-bottom: 1px solid color-mix(in oklab, var(--color-paper) 12%, transparent);
		opacity: 0;
		transform: translateY(14px);
	}

	.is-nav-open .nav-drawer__link {
		animation: nav-in var(--motion-slow) var(--ease-cinematic) forwards;
	}

	.nav-drawer__item:nth-child(1) .nav-drawer__link { animation-delay: 40ms; }
	.nav-drawer__item:nth-child(2) .nav-drawer__link { animation-delay: 80ms; }
	.nav-drawer__item:nth-child(3) .nav-drawer__link { animation-delay: 120ms; }
	.nav-drawer__item:nth-child(4) .nav-drawer__link { animation-delay: 160ms; }
	.nav-drawer__item:nth-child(5) .nav-drawer__link { animation-delay: 200ms; }
	.nav-drawer__item:nth-child(6) .nav-drawer__link { animation-delay: 240ms; }
	.nav-drawer__item:nth-child(7) .nav-drawer__link { animation-delay: 280ms; }
	.nav-drawer__item:nth-child(8) .nav-drawer__link { animation-delay: 320ms; }

	@keyframes nav-in {
		to { opacity: 1; transform: none; }
	}

	.nav-drawer__link:hover,
	.nav-drawer__link:focus-visible {
		color: var(--color-sand);
	}

	.nav-drawer__numeral {
		font-family: var(--font-mono);
		font-size: 0.75rem;
		font-weight: 400;
		color: var(--color-brass);
	}

	.nav-drawer__sub {
		margin: 0 0 0 1.5rem;
		padding: 0;
		list-style: none;
	}

	.nav-drawer__sub .nav-drawer__link {
		font-size: clamp(1.05rem, 4.4vw, 1.4rem);
		font-family: var(--font-sans);
		font-weight: 400;
		color: color-mix(in oklab, var(--color-paper) 78%, transparent);
		border-bottom-color: color-mix(in oklab, var(--color-paper) 8%, transparent);
	}

	/*
	 * The drawer takes over below 1080px. It was 1024 until the bar carried seven destinations
	 * of uppercase tracked type and they were clipped off the right edge — silently, because
	 * the header clips rather than scrolls. Five fit again, with the gaps closed a little
	 * between 1080 and 1400 rather than an item dropped.
	 */
	@media (max-width: 67.49em) {
		.nav__list { display: none; }
		.nav-toggle { display: inline-flex; }
	}

	@media (min-width: 67.5em) {
		.nav-drawer { display: none; }
	}

	@media (min-width: 67.5em) and (max-width: 87.49em) {
		.nav__list { gap: 0.85rem; }
		.nav__link { font-size: 0.6875rem; letter-spacing: 0.1em; }
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Section heading + eyebrow + archival label
	   ══════════════════════════════════════════════════════════════════════ */

	.section-head {
		max-width: var(--measure-wide);
		margin-bottom: clamp(2.5rem, 5vw, 4rem);
	}

	.section-head--center {
		margin-inline: auto;
		text-align: center;
	}

	.eyebrow {
		display: inline-flex;
		align-items: center;
		gap: 0.85rem;
		margin-bottom: var(--space-s);
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		font-weight: 500;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	/* Centred variant, so a centred section head does not need an inline justify-content. */
	.eyebrow--centred {
		display: flex;
		justify-content: center;
	}

	.eyebrow__rule {
		width: clamp(24px, 5vw, 48px);
		height: 1px;
		background: linear-gradient(90deg, transparent, currentColor);
	}

	.section-head--center .eyebrow {
		justify-content: center;
	}

	.section-head__title {
		font-size: var(--text-3xl);
	}

	.section-head__standfirst {
		max-width: var(--measure);
		margin-top: var(--space-m);
		font-size: var(--text-lg);
		line-height: var(--leading-relaxed);
		color: var(--on-surface-muted);
	}

	.section-head--center .section-head__standfirst {
		margin-inline: auto;
	}

	.section--dark .section-head__standfirst {
		color: var(--on-dark-muted);
	}

	.archive-label {
		display: inline-block;
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		font-weight: 500;
		letter-spacing: var(--tracking-wider);
		text-transform: uppercase;
		color: var(--on-surface-muted);
	}

	/* ── On dark surfaces ───────────────────────────────────────────────── */
	/*
	 * --accent-text and --color-muted are tuned for paper. Reused unchanged on the night
	 * sections they measure ~3.3:1, so every label that can appear on both surfaces gets an
	 * explicit dark-surface value here. Brass itself is legible on night (6.1:1); it is only
	 * on paper that it needs darkening.
	 */
	.section--dark .eyebrow,
	.page-intro .eyebrow,
	.book-hero .eyebrow,
	.section--dark .plate__ref,
	.page-intro .plate__ref {
		color: var(--color-brass);
	}

	.section--dark .plate__caption,
	.section--dark .plate__title,
	.page-intro .plate__caption,
	.page-intro .plate__title,
	.section--dark .archive-label,
	.page-intro .archive-label {
		color: var(--on-dark-muted);
	}

	/*
	 * El pie manuscrito es tinta sobre papel, así que su color por defecto es el de la tinta.
	 * Sobre fondo oscuro hay que invertirlo o desaparece: aquí se escribe con la luz.
	 */
	.section--dark .plate__hand,
	.page-intro .plate__hand {
		color: var(--on-dark);
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Buttons
	   ══════════════════════════════════════════════════════════════════════ */

	.actions {
		display: flex;
		flex-wrap: wrap;
		gap: var(--space-s);
	}

	.btn {
		display: inline-flex;
		flex-direction: column;
		align-items: flex-start;
		gap: 0.1rem;
		padding: 0.85rem 1.6rem;
		min-height: 44px;
		justify-content: center;
		font-family: var(--font-sans);
		text-decoration: none;
		border: 1px solid transparent;
		border-radius: var(--radius-s);
		transition: transform var(--motion-fast) var(--ease-standard),
			background-color var(--motion-fast) var(--ease-standard),
			border-color var(--motion-fast) var(--ease-standard),
			color var(--motion-fast) var(--ease-standard),
			box-shadow var(--motion-fast) var(--ease-standard);
	}

	.btn__label {
		font-size: 0.8125rem;
		font-weight: 600;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		line-height: 1.2;
	}

	.btn__meta {
		font-family: var(--font-mono);
		font-size: 0.625rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		opacity: 0.72;
		line-height: 1.3;
	}

	/* The deep tone, not the bright one: white on #b08544 is 3.04:1, on #8a6a33 it is 5.0:1. */
	.btn--primary {
		color: #fff;
		background-color: var(--accent-deep);
		border-color: var(--accent-deep);
	}

	.btn--primary:hover,
	.btn--primary:focus-visible {
		color: #fff;
		background-color: color-mix(in oklab, var(--accent-deep) 84%, black);
		border-color: color-mix(in oklab, var(--accent-deep) 84%, black);
		transform: translateY(-1px);
		box-shadow: 0 10px 22px -12px color-mix(in oklab, var(--accent) 90%, black);
	}

	.btn--quiet {
		color: var(--color-ink);
		background-color: transparent;
		border-color: var(--color-border-strong);
	}

	.btn--quiet:hover,
	.btn--quiet:focus-visible {
		color: var(--accent-deep);
		border-color: var(--accent);
		transform: translateY(-1px);
	}

	/* On night surfaces the quiet button inverts. Miss one of these and the button turns
	   into dark-on-dark: invisible, but still focusable and still clickable. */
	.section--dark .btn--quiet,
	.hero .btn--quiet,
	.book-hero .btn--quiet,
	.page-intro .btn--quiet,
	.add--reader .btn--quiet {
		color: var(--color-paper);
		border-color: color-mix(in oklab, var(--color-paper) 34%, transparent);
		-webkit-backdrop-filter: blur(6px);
		backdrop-filter: blur(6px);
		background-color: rgb(255 255 255 / 0.06);
	}

	.section--dark .btn--quiet:hover,
	.hero .btn--quiet:hover,
	.book-hero .btn--quiet:hover,
	.page-intro .btn--quiet:hover,
	.add--reader .btn--quiet:hover {
		color: var(--color-paper);
		border-color: var(--color-paper);
		background-color: rgb(255 255 255 / 0.14);
	}

	/* A text link that draws its rule on hover. */
	.link-draw {
		position: relative;
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
		font-size: 0.8125rem;
		font-weight: 600;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		text-decoration: none;
		color: var(--accent-text);
		padding-block: 0.35rem;
	}

	.link-draw::after {
		content: "";
		position: absolute;
		inset-inline: 0 100%;
		inset-block-end: 0;
		height: 1px;
		background-color: currentColor;
		transition: inset-inline var(--motion-normal) var(--ease-cinematic);
	}

	.link-draw:hover::after,
	.link-draw:focus-visible::after {
		inset-inline: 0 0;
	}

	.link-draw__arrow {
		transition: translate var(--motion-normal) var(--ease-cinematic);
	}

	.link-draw:hover .link-draw__arrow {
		translate: 4px 0;
	}

	.section--dark .link-draw {
		color: var(--color-sand);
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Book cover as a physical object
	   ══════════════════════════════════════════════════════════════════════ */

	/* ══════════════════════════════════════════════════════════════════════
	   The book, as an object
	   ══════════════════════════════════════════════════════════════════════

	   The artwork is a flat 2:3 cover, so the volume is built here: five faces around a
	   central plane, plus the two details that actually sell a printed book — the joint
	   where the board meets the spine, and the contact shadow on the ground.

	   Depth is expressed in container query units, so one component serves the 320px cover
	   on a book page and the 88px thumbnail in the "next volume" card without a single
	   breakpoint. `container-type: inline-size` is set on the outer element only; the 3D
	   work happens one level in, where containment cannot flatten it.
	*/

	/*
	 * The wrapper must be a block. `container-type: inline-size` resolves against the
	 * containing block's inline size, and an inline <a> or <span> has none — the container
	 * measures 0, `--book-depth` in cqw becomes 0, the 2:3 aspect ratio collapses, and the
	 * book vanishes entirely. This bit us on the home page.
	 */
	.book3d-link {
		display: block;
		text-decoration: none;
		width: 100%;
	}

	.book3d {
		--book-turn: 460ms;   /* el giro al acercarse */
		--book-back: 780ms;   /* y la vuelta, más calmada */
		--ease-book: cubic-bezier(0.22, 0.68, 0.24, 1);
		--ease-book-back: cubic-bezier(0.38, 0.02, 0.3, 1);
		/* La subida remata por encima y se asienta: es lo que le da peso. */
		--ease-book-lift: cubic-bezier(0.2, 0.92, 0.28, 1.14);

		container-type: inline-size;
		position: relative;
		width: 100%;
		max-width: 22rem;
		/*
		 * La perspectiva tiene que guardar proporción con el tamaño al que se dibuja el libro:
		 * 1800 px sobre una portada de 100 px es prácticamente una proyección ortográfica, y
		 * por eso los libros pequeños se veían planos. No se puede expresar en `cqw` —dentro
		 * del propio contenedor esas unidades no resuelven contra él mismo—, así que cada
		 * contexto declara la suya, en torno a tres veces el ancho al que se pinta.
		 */
		perspective: var(--book-persp, 1000px);
		perspective-origin: 58% 44%;
	}

	.book3d__inner {
		position: relative;
		aspect-ratio: 2 / 3;
		transform-style: preserve-3d;
		/*
		 * Positive rotation brings the left edge forward, which is what puts the spine in
		 * view — the way a book is normally photographed.
		 *
		 * El orden importa: primero el giro y después la inclinación. Al revés, la inclinación
		 * se aplica en el sistema ya girado y el libro no se ve desde arriba, sino escorado,
		 * como si estuviera cayéndose hacia un lado.
		 */
		transform: rotateX(var(--book-tilt, -8deg)) rotateY(var(--book-rot, 24deg));
		/*
		 * Se animan los ángulos, no la matriz. `transition: transform` interpola entre dos
		 * matrices, y el camino que sigue una interpolación de matrices no es el de un giro:
		 * el libro se deformaba por el medio. Como `--book-rot` y `--book-tilt` están
		 * registrados con sintaxis `<angle>`, interpolan como ángulos y el `transform` se
		 * recalcula en cada fotograma a partir de ellos.
		 *
		 * Ida y vuelta no duran lo mismo. Al acercarse, el gesto tiene que responder; al
		 * apartarse, el libro vuelve solo, y volver deprisa se lee como un tirón.
		 */
		transition:
			--book-rot var(--book-back) var(--ease-book-back),
			--book-tilt var(--book-back) var(--ease-book-back),
			translate var(--book-back) var(--ease-book-back);
	}

	.book3d__inner > * {
		position: absolute;
	}

	/* ── Front board ────────────────────────────────────────────────────── */

	.book3d__front {
		inset: 0;
		overflow: hidden;
		border-radius: 1px 3px 3px 1px;
		transform: translateZ(calc(var(--book-depth) / 2));
		box-shadow:
			0 0 0 1px rgb(0 0 0 / 0.16) inset,
			/* Rim light along the fore-edge of the board, where it catches the room. */
			-1px 0 0 rgb(255 255 255 / 0.16) inset;
	}

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

	/* The joint: the hinge where the board folds onto the spine. Without it the cover reads
	   as a printed picture rather than as a bound board. */
	.book3d__joint {
		position: absolute;
		inset-block: 0;
		inset-inline-start: 0;
		width: 7%;
		max-width: 22px;
		pointer-events: none;
		background: linear-gradient(
			90deg,
			rgb(0 0 0 / 0.42) 0%,
			rgb(0 0 0 / 0.16) 34%,
			rgb(0 0 0 / 0.04) 64%,
			rgb(255 255 255 / 0.08) 88%,
			rgb(0 0 0 / 0) 100%
		);
	}

	/* A single raking highlight, as if a window were off to the right. */
	.book3d__sheen {
		position: absolute;
		inset: 0;
		pointer-events: none;
		background-image: linear-gradient(
			104deg,
			rgb(255 255 255 / 0) 34%,
			rgb(255 255 255 / 0.20) 50%,
			rgb(255 255 255 / 0) 64%
		);
		/* Más ancho que la tapa: es lo que deja sitio para que el reflejo la recorra. */
		background-size: 260% 100%;
		background-position: 22% 0;
		background-repeat: no-repeat;
		opacity: 0.72;
		transition: opacity var(--book-back) var(--ease-book-back),
			background-position var(--book-back) var(--ease-book-back);
	}

	/* ── Back board ─────────────────────────────────────────────────────── */

	.book3d__back {
		inset: 0;
		border-radius: 3px 1px 1px 3px;
		transform: translateZ(calc(var(--book-depth) / -2));
		background: linear-gradient(
			100deg,
			color-mix(in oklab, var(--book-spine) 88%, black) 0%,
			color-mix(in oklab, var(--book-spine) 62%, black) 100%
		);
	}

	/* ── Spine ──────────────────────────────────────────────────────────── */
	/* Centred on x = 0 (left: -depth/2, width: depth), then swung into that plane. */

	.book3d__spine {
		inset-block: 0;
		inset-inline-start: calc(var(--book-depth) / -2);
		width: var(--book-depth);
		transform: rotateY(-90deg);
		display: flex;
		flex-direction: column;
		align-items: center;
		justify-content: space-between;
		padding-block: 6%;
		overflow: hidden;
		/*
		 * El lomo de un libro encuadernado no es una cara plana: es un cilindro. El degradado
		 * lleva dos cantos oscuros, un lomo de luz descentrado hacia la tapa —de donde viene la
		 * ventana— y una caída suave hacia el otro extremo. Es lo que hace que a este ángulo,
		 * en el que la cara superior no se ve, el libro siga leyéndose como un volumen.
		 */
		background:
			linear-gradient(
				90deg,
				rgb(0 0 0 / 0.62) 0%,
				rgb(0 0 0 / 0.30) 7%,
				rgb(255 255 255 / 0.14) 26%,
				rgb(255 255 255 / 0.06) 44%,
				rgb(0 0 0 / 0.10) 62%,
				rgb(0 0 0 / 0.30) 84%,
				rgb(0 0 0 / 0.58) 100%
			),
			linear-gradient(180deg,
				color-mix(in oklab, var(--book-spine) 92%, white 8%) 0%,
				var(--book-spine) 18%,
				var(--book-spine) 82%,
				color-mix(in oklab, var(--book-spine) 92%, white 8%) 100%
			);
	}

	/* La ranura de la bisagra: el surco entre el lomo y la tapa, marcado a fuego en la tela. */
	.book3d__spine {
		box-shadow:
			inset -1px 0 0 rgb(0 0 0 / 0.35),
			inset 1px 0 0 rgb(0 0 0 / 0.3);
	}

	/* Head and tail bands, the coloured threads at the top and bottom of a bound spine. */
	.book3d__spine::before,
	.book3d__spine::after {
		content: "";
		position: absolute;
		inset-inline: 0;
		height: 2.5%;
		background: repeating-linear-gradient(
			90deg,
			color-mix(in oklab, var(--color-sand) 90%, transparent) 0 2px,
			color-mix(in oklab, var(--book-spine) 60%, black) 2px 4px
		);
		opacity: 0.85;
	}

	.book3d__spine::before { inset-block-start: 1.5%; }
	.book3d__spine::after { inset-block-end: 1.5%; }

	.book3d__spine-title {
		writing-mode: vertical-rl;
		text-orientation: mixed;
		font-family: var(--font-display);
		font-size: 3.5cqw;
		font-weight: 600;
		line-height: 1;
		letter-spacing: 0.02em;
		color: color-mix(in oklab, var(--color-sand) 88%, white);
		text-shadow: 0 1px 1px rgb(0 0 0 / 0.5);
		white-space: nowrap;
		overflow: hidden;
		max-height: 74%;
		margin-block: auto;
	}

	.book3d__spine-mark {
		font-family: var(--font-mono);
		font-size: 2.9cqw;
		line-height: 1;
		color: color-mix(in oklab, var(--color-sand) 70%, transparent);
	}

	/* Below roughly a 130px-wide book the spine is a few pixels across; lettering there is
	   noise, so only the object remains. */
	@container (max-width: 130px) {
		.book3d__spine-title,
		.book3d__spine-mark { display: none; }
	}

	/* ── Fore-edge: the block of pages ──────────────────────────────────── */

	.book3d__edge {
		inset-block: 1.4%;
		inset-inline-start: calc(100% - var(--book-depth) / 2);
		width: var(--book-depth);
		transform: rotateY(90deg);
		background:
			/* El bloque de páginas de un libro cerrado no es plano: abulta por el centro. */
			linear-gradient(
				90deg,
				rgb(0 0 0 / 0.38) 0%,
				rgb(0 0 0 / 0.06) 16%,
				rgb(255 255 255 / 0.12) 46%,
				rgb(0 0 0 / 0.04) 68%,
				rgb(0 0 0 / 0.26) 100%
			),
			repeating-linear-gradient(
				90deg,
				#e9e0ca 0 1px,
				#bfb296 1px 2px,
				#ded4bd 2px 3px
			);
	}

	/* ── Head: the page block seen from above ───────────────────────────── */
	/*
	 * La cara que faltaba, y la que de verdad da el grosor: sin ella el libro era una portada
	 * y un lomo, y el canto delantero se leía como un borde pintado. Se centra en y = 0 —el
	 * canto superior— y se abate al plano horizontal, igual que el lomo se abate al vertical.
	 *
	 * Las páginas se apilan en profundidad, así que vistas desde arriba sus cantos son rayas
	 * perpendiculares al lomo: la trama repite a lo largo del alto del elemento, que tras el
	 * giro es la profundidad. Va metida un pelo por los lados porque las tapas vuelan sobre el
	 * bloque —la «ceja» de un libro encuadernado—.
	 */
	.book3d__head {
		inset-inline: 1.4%;
		inset-block-start: calc(var(--book-depth) / -2);
		height: var(--book-depth);
		transform: rotateX(90deg);
		/*
		 * A esta inclinación la cara superior se proyecta en uno o dos píxeles: la perspectiva
		 * la comprime casi del todo porque cae muy por encima del origen de fuga. No se ve el
		 * bloque de páginas, y no hay ángulo razonable en el que se vea sin deformar la tapa;
		 * lo que sí se ve, y es lo que cuenta, es la línea de sombra bajo el canto de la tapa,
		 * el «cuadradillo» que separa el cartón del papel. Por eso el degradado carga el
		 * contraste en los extremos y no en el centro.
		 */
		background:
			linear-gradient(
				180deg,
				rgb(0 0 0 / 0.5) 0%,
				rgb(0 0 0 / 0.14) 12%,
				rgb(255 255 255 / 0.14) 44%,
				rgb(0 0 0 / 0.10) 74%,
				rgb(0 0 0 / 0.46) 92%,
				rgb(0 0 0 / 0.62) 100%
			),
			/*
			 * El canto tiene que ser más oscuro que el papel del sitio, o desaparece contra el
			 * fondo: un bloque de páginas visto de canto es un gris cálido, nunca blanco.
			 */
			repeating-linear-gradient(
				180deg,
				#e7ddc7 0 1px,
				#bdb094 1px 2px,
				#ddd3bc 2px 3px
			);
	}

	/* ── Ground shadow ──────────────────────────────────────────────────── */

	.book3d__shadow {
		position: absolute;
		inset-inline: -10%;
		inset-block-end: -4%;
		height: 11%;
		border-radius: 50%;
		/*
		 * Dos sombras en una: el núcleo duro justo bajo el canto —el contacto con la mesa, que
		 * es lo que ancla el objeto— y la penumbra ancha que lo rodea.
		 */
		background:
			radial-gradient(
				closest-side,
				rgb(0 0 0 / 0.7) 0%,
				rgb(0 0 0 / 0.4) 42%,
				rgb(0 0 0 / 0) 100%
			);
		filter: blur(9px);
		transform: translateZ(0) scaleX(0.92) skewX(-9deg);
		transition: opacity var(--book-back) var(--ease-book-back),
			transform var(--book-back) var(--ease-book-back),
			filter var(--book-back) var(--ease-book-back);
		z-index: -1;
	}

	/* ── Sizes ──────────────────────────────────────────────────────────── */
	/* One knob per context. 8% of the cover width is a ~24mm spine on a 15cm book: right for
	   a 180-page paperback, and it stays proportional as the component scales. */

	.book3d { --book-depth: 11cqw; }

	@supports not (width: 1cqw) {
		.book3d { --book-depth: 30px; }
	}

	/*
	 * Una perspectiva por contexto, en torno a tres veces el ancho al que se pinta el libro.
	 * Con un valor único, el mismo componente salía escorzado en la portada y plano en el
	 * pie de página, que es donde más falta le hace parecer un objeto.
	 */
	.volume__object { --book-persp: 1000px; }
	.book-hero__object { --book-persp: 950px; }
	.companion__object { --book-persp: 400px; }
	.companion--third .companion__object { --book-persp: 330px; }
	.next-volume__object { --book-persp: 280px; }
	.shelf-book__stage { --book-persp: 360px; }
	.mega-book__stage { --book-persp: 420px; }

	@media (max-width: 47.99em) {
		.volume__object { --book-persp: 460px; }
		.book-hero__object { --book-persp: 650px; }
	}

	/* ── States ─────────────────────────────────────────────────────────── */

	/*
	 * Al acercarse, el libro se gira hacia el lector y se levanta un poco de la mesa. Es un
	 * solo gesto: el giro, la inclinación, el levantamiento, la sombra que se abre y se
	 * aclara —porque el objeto se aleja del suelo— y el brillo que barre la tapa. Todo con la
	 * misma duración y la misma curva, que es lo que hace que se lea como un movimiento y no
	 * como cuatro transiciones a la vez.
	 */
	/*
	 * `@media (hover: hover)`: en una pantalla táctil el `:hover` se queda pegado después del
	 * toque, y el libro se quedaba girado hasta que tocabas otra cosa.
	 */
	@media (hover: hover) {
		a:hover .book3d__inner,
		a:focus-visible .book3d__inner,
		.volume:hover .book3d__inner,
		.next-volume:hover .book3d__inner {
			/* Se gira hacia el lector, pero sin llegar a ponerse de frente: a menos de unos
			   catorce grados el lomo desaparece y el libro deja de ser un objeto. */
			--book-rot: 14deg;
			--book-tilt: -5deg;
			translate: 0 -10px;

			/*
			 * Las tres cosas no empiezan a la vez. Primero gira, la inclinación sigue al giro
			 * con noventa milisegundos de retraso y la subida va por delante y remata por
			 * encima. Un objeto real no cambia de postura en bloque, y es ese bloque lo que
			 * hacía que el gesto pareciera un interruptor.
			 */
			transition:
				--book-rot var(--book-turn) var(--ease-book),
				--book-tilt calc(var(--book-turn) + 140ms) var(--ease-book) 90ms,
				translate 400ms var(--ease-book-lift);
		}
	}

	a:hover .book3d__shadow,
	a:focus-visible .book3d__shadow,
	.volume:hover .book3d__shadow,
	.next-volume:hover .book3d__shadow {
		opacity: 0.6;
		transform: translateZ(0) scaleX(1.06) skewX(-3deg);
		filter: blur(13px);
		/* La sombra va un pelo por detrás del libro: el suelo se entera después. */
		transition-duration: 560ms;
		transition-delay: 70ms;
	}

	/* El barrido del brillo: la tapa gira, y la luz de la ventana la recorre. */
	a:hover .book3d__sheen,
	a:focus-visible .book3d__sheen,
	.volume:hover .book3d__sheen {
		opacity: 1;
		/* Hasta el 76 %, no hasta el final: pasado ese punto el reflejo se sale de la tapa y
		   el barrido termina en nada. */
		background-position: 76% 0;
		transition-duration: 700ms;
		transition-delay: 40ms;
	}

	/*
	 * Entrada: el libro llega girado y se asienta. Sólo se declara el estado de partida —el de
	 * llegada son los valores por defecto—, porque una regla `.is-visible` tendría más
	 * especificidad que `a:hover` y dejaría el libro clavado al pasar por encima.
	 */
	.js .reveal:not(.is-visible) .book3d__inner,
	.js .reveal--stagger:not(.is-visible) .book3d__inner {
		--book-rot: 42deg;
		--book-tilt: -14deg;
	}

	@media (prefers-reduced-motion: reduce) {
		.book3d__inner,
		.book3d__shadow,
		.book3d__sheen {
			transition: none;
		}

		.js .reveal:not(.is-visible) .book3d__inner,
		.js .reveal--stagger:not(.is-visible) .book3d__inner {
			--book-rot: 24deg;
			--book-tilt: -8deg;
		}
	}

	/* Per-volume spine colour, from the same family as the page accent. The unqualified
	   default is declared first: at equal specificity the last rule wins, so putting it
	   after the variants would silently paint every spine the same. */
	.book3d { --book-spine: #4a4034; }
	.book3d--brass { --book-spine: #6a5228; }
	.book3d--olive { --book-spine: #3f4331; }
	.book3d--rust { --book-spine: #6b3220; }

	/* ══════════════════════════════════════════════════════════════════════
	   Volume — one book in the index
	   ══════════════════════════════════════════════════════════════════════ */

	.volumes {
		display: flex;
		flex-direction: column;
		gap: clamp(3rem, 8vw, 7rem);
	}

	.volume {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: clamp(2rem, 5vw, 5rem);
	}

	.volume:nth-child(even) {
		flex-direction: row-reverse;
	}

	.volume__object {
		flex: 0 1 20rem;
		display: flex;
		justify-content: center;
		min-width: 0;
	}

	.volume__body {
		flex: 1 1 24rem;
		min-width: 0;
	}

	/* The volume numeral: a large, quiet piece of typography behind the title. */
	.volume__numeral {
		display: block;
		font-family: var(--font-display);
		font-size: clamp(3rem, 9vw, 5.5rem);
		font-weight: 500;
		line-height: 0.8;
		letter-spacing: var(--tracking-tight);
		color: color-mix(in oklab, var(--accent) 34%, transparent);
		margin-bottom: 0.35rem;
	}

	.volume__kicker {
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: var(--accent-text);
		margin-bottom: var(--space-xs);
	}

	.volume__title {
		font-size: var(--text-2xl);
		margin-bottom: 0.25rem;
	}

	.volume__title a {
		text-decoration: none;
		background-image: linear-gradient(currentColor, currentColor);
		background-size: 0% 1px;
		background-repeat: no-repeat;
		background-position: 0 100%;
		transition: background-size var(--motion-normal) var(--ease-cinematic);
	}

	.volume__title a:hover,
	.volume__title a:focus-visible {
		background-size: 100% 1px;
	}

	.volume__subtitle {
		font-family: var(--font-display);
		font-style: italic;
		font-size: var(--text-lg);
		color: var(--accent-deep);
		margin-bottom: var(--space-m);
	}

	.volume__excerpt {
		max-width: var(--measure);
		color: var(--on-surface-muted);
		margin-bottom: var(--space-m);
	}

	.meta-row {
		display: flex;
		flex-wrap: wrap;
		gap: 0 var(--space-m);
		margin-bottom: var(--space-l);
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--on-surface-muted);
	}

	.meta-row__item {
		display: inline-flex;
		align-items: center;
		gap: 0.5rem;
	}

	.meta-row__item + .meta-row__item::before {
		content: "";
		width: 1px;
		height: 0.75em;
		margin-right: 0.5rem;
		background-color: var(--color-border-strong);
	}

	.section--dark .meta-row {
		color: var(--on-dark-muted);
	}

	/*
	 * En móvil el volumen se invierte en vez de apilarse: el texto a la izquierda y la portada
	 * arriba a la derecha, junto al número y al título a los que pertenece. Apilado, el libro
	 * ocupaba media pantalla antes de que empezara a leerse nada.
	 */
	@media (max-width: 47.99em) {
		/*
		 * La portada flota a la derecha en vez de apilarse encima. Con dos columnas rígidas el
		 * texto se quedaba en media pantalla y el título salía en tres líneas; flotando, el
		 * número, el título y el subtítulo van al lado del libro y el resumen sigue a todo lo
		 * ancho por debajo, que es como se maqueta una ficha de libro en papel.
		 */
		.volume,
		.volume:nth-child(even) {
			display: block;
		}

		.volume::after {
			content: "";
			display: block;
			clear: both;
		}

		/*
		 * An explicit width, not `align-self: flex-start` alone. The book sizes itself from
		 * its container (container queries drive the spine depth and the 2:3 ratio), so a
		 * shrink-to-fit parent and a width:100% child resolve to zero and the book disappears.
		 */
		.volume__object {
			float: right;
			width: min(9rem, 35%);
			margin: 0.35rem 0 clamp(0.75rem, 3vw, 1.15rem) clamp(1.1rem, 4.5vw, 1.75rem);
		}

		.volume__numeral { font-size: clamp(2.25rem, 11vw, 3.25rem); }
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Quote / opening excerpt
	   ══════════════════════════════════════════════════════════════════════ */

	.opening {
		position: relative;
		max-width: var(--measure);
		padding-left: clamp(1.25rem, 4vw, 2.75rem);
		border-left: 1px solid color-mix(in oklab, var(--accent) 45%, transparent);
	}

	.opening__label {
		display: block;
		margin-bottom: var(--space-m);
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: var(--accent-text);
	}

	.opening__text {
		font-family: var(--font-display);
		font-size: clamp(1.15rem, 1.05rem + 0.6vw, 1.5rem);
		line-height: var(--leading-relaxed);
		color: var(--color-charcoal);
	}

	.opening__text p + p {
		margin-top: 1em;
	}

	/* A drop cap, set in the display face, only on the first paragraph. */
	.opening__text > p:first-child::first-letter {
		float: left;
		font-size: 3.6em;
		line-height: 0.78;
		font-weight: 700;
		margin: 0.04em 0.1em 0 0;
		color: var(--accent-deep);
	}

	.opening__attribution {
		margin-top: var(--space-m);
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--on-surface-muted);
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Plate — one archive photograph
	   ══════════════════════════════════════════════════════════════════════ */

	.plate {
		margin: 0;
		display: flex;
		flex-direction: column;
	}

	.plate__open {
		display: block;
		width: 100%;
		padding: 0;
		cursor: zoom-in;
		border-radius: var(--radius-xs);
	}

	/*
	 * The mount: warm board behind the print, exactly as the album sheets were. The image
	 * carries its own aspect ratio, so `contain` never has anything left over to letterbox —
	 * a portrait print gets a portrait mount and a panorama a panoramic one. The old fixed
	 * 4:3 mount padded half the album with empty board.
	 */
	.plate__mount {
		/* Un solo número manda: el ancho de la cartulina alrededor de la copia. De él salen el
		   relleno, la ventana recortada y dónde se apoyan las esquineras. */
		--plate-pad: clamp(9px, 1.7vw, 18px);

		position: relative;
		display: flex;
		align-items: center;
		justify-content: center;
		padding: var(--plate-pad);
		background-color: var(--color-paper-warm);
		border: 1px solid var(--color-border);
		border-radius: var(--radius-xs);
		box-shadow: var(--shadow-paper);
		transition: box-shadow var(--motion-normal) var(--ease-standard),
			transform var(--motion-normal) var(--ease-standard),
			border-color var(--motion-normal) var(--ease-standard);
	}

	.plate__mount img {
		width: 100%;
		aspect-ratio: var(--ar, 4 / 3);
		object-fit: contain;
		filter: saturate(0.62) contrast(1.04);
		transition: filter var(--motion-slow) var(--ease-standard);
	}

	/*
	 * La ventana. La copia no va pegada sobre la cartulina: va metida en un hueco recortado en
	 * ella, que es lo que explica que las esquineras la pisen por las puntas. Todo el efecto
	 * está aquí, en sombras interiores sobre el área exacta de la imagen:
	 *
	 *   · el canto superior de la cartulina vuela sobre la copia y le echa sombra encima —la
	 *     más marcada, porque la luz de este sitio viene de arriba y de la derecha—;
	 *   · el canto derecho, otra más corta;
	 *   · el filo del recorte, una línea de un píxel;
	 *   · y abajo, donde la copia sale del hueco, un hilo de luz.
	 */
	.plate__mount::after {
		content: "";
		position: absolute;
		inset: var(--plate-pad);
		z-index: 1;
		border-radius: 1px;
		pointer-events: none;
		box-shadow:
			inset 0 7px 9px -3px rgb(0 0 0 / 0.42),
			inset -5px 0 8px -4px rgb(0 0 0 / 0.28),
			inset 4px 0 6px -4px rgb(0 0 0 / 0.13),
			inset 0 -3px 4px -2px rgb(255 255 255 / 0.38),
			inset 0 0 0 1px rgb(0 0 0 / 0.18);
	}

	/*
	 * Las esquineras. Una esquinera de álbum es un bolsillito de papel en el que se mete la
	 * punta de la copia, así que va SOBRE la copia y no sobre la cartulina: el ángulo recto
	 * coincide con la esquina de la foto y el triángulo la tapa un poco. Antes estaban a tres
	 * píxeles del borde de la cartulina, es decir, sujetando el aire.
	 *
	 * Un píxel de más hacia fuera para que monten también sobre el filo del recorte, que es
	 * donde se apoyan de verdad.
	 */
	.plate__corner {
		position: absolute;
		z-index: 2;
		width: clamp(13px, 2.1vw, 21px);
		aspect-ratio: 1;
		/*
		 * El degradado corre perpendicular a la hipotenusa: oscuro en el vértice, donde la
		 * esquinera se pega al fondo del hueco, y con un filo claro al final, que es el doblez
		 * del papel cogiendo luz. La sombra proyectada la levanta sobre la copia; `drop-shadow`
		 * y no `box-shadow` porque sigue la forma recortada y no la caja.
		 */
		background-image: linear-gradient(135deg,
			color-mix(in oklab, var(--color-sand-dark) 92%, var(--color-ink)) 0%,
			color-mix(in oklab, var(--color-sand-dark) 74%, var(--color-ink)) 58%,
			color-mix(in oklab, var(--color-sand) 88%, white) 93%,
			color-mix(in oklab, var(--color-sand) 70%, white) 100%);
		filter: drop-shadow(0 1px 1.5px rgb(0 0 0 / 0.4));
		opacity: 0.9;
		pointer-events: none;
		transition: opacity var(--motion-normal) var(--ease-standard),
			width var(--motion-normal) var(--ease-standard);
	}

	.plate__corner--tl {
		top: calc(var(--plate-pad) - 1px);
		left: calc(var(--plate-pad) - 1px);
		clip-path: polygon(0 0, 100% 0, 0 100%);
	}

	.plate__corner--tr {
		top: calc(var(--plate-pad) - 1px);
		right: calc(var(--plate-pad) - 1px);
		clip-path: polygon(100% 0, 100% 100%, 0 0);
		background-image: linear-gradient(-135deg,
			color-mix(in oklab, var(--color-sand-dark) 92%, var(--color-ink)) 0%,
			color-mix(in oklab, var(--color-sand-dark) 74%, var(--color-ink)) 58%,
			color-mix(in oklab, var(--color-sand) 88%, white) 93%,
			color-mix(in oklab, var(--color-sand) 70%, white) 100%);
	}

	.plate__corner--bl {
		bottom: calc(var(--plate-pad) - 1px);
		left: calc(var(--plate-pad) - 1px);
		clip-path: polygon(0 0, 0 100%, 100% 100%);
		background-image: linear-gradient(45deg,
			color-mix(in oklab, var(--color-sand-dark) 92%, var(--color-ink)) 0%,
			color-mix(in oklab, var(--color-sand-dark) 74%, var(--color-ink)) 58%,
			color-mix(in oklab, var(--color-sand) 88%, white) 93%,
			color-mix(in oklab, var(--color-sand) 70%, white) 100%);
	}

	.plate__corner--br {
		bottom: calc(var(--plate-pad) - 1px);
		right: calc(var(--plate-pad) - 1px);
		clip-path: polygon(100% 0, 100% 100%, 0 100%);
		background-image: linear-gradient(-45deg,
			color-mix(in oklab, var(--color-sand-dark) 92%, var(--color-ink)) 0%,
			color-mix(in oklab, var(--color-sand-dark) 74%, var(--color-ink)) 58%,
			color-mix(in oklab, var(--color-sand) 88%, white) 93%,
			color-mix(in oklab, var(--color-sand) 70%, white) 100%);
	}

	.plate:hover .plate__mount,
	.plate__open:focus-visible .plate__mount {
		transform: translateY(-3px);
		box-shadow: var(--shadow-photograph);
		border-color: color-mix(in oklab, var(--accent) 45%, transparent);
	}

	.plate:hover .plate__mount img,
	.plate__open:focus-visible .plate__mount img {
		filter: saturate(0.85) contrast(1.07);
	}

	/* Al pasar por encima, las esquineras aflojan un poco: como si la copia fuera a salir. */
	.plate:hover .plate__corner,
	.plate__open:focus-visible .plate__corner {
		opacity: 0.94;
		width: clamp(14px, 2.3vw, 23px);
	}

	.plate__caption {
		display: flex;
		flex-direction: column;
		gap: 0.25rem;
		padding-top: 0.55rem;
		font-size: 0.8125rem;
		line-height: 1.4;
		color: var(--on-surface-muted);
	}

	/* What he wrote on the print, in his own letters. It reads as a caption, not as a label:
	   slightly larger than the reference line and in the ink colour, because it is ink. */
	.plate__hand {
		font-size: clamp(0.9375rem, 0.85rem + 0.4vw, 1.125rem);
		line-height: 1.18;
		color: color-mix(in oklab, var(--color-ink) 82%, transparent);
		text-wrap: balance;
		overflow-wrap: anywhere;
	}

	/*
	 * La referencia y el título envuelven. Sin `wrap`, el ancho mínimo de la línea es la
	 * signatura más la palabra más larga del título, y en una lámina vertical estrecha eso
	 * empujaba la retícula entera fuera de la pantalla a 320 px.
	 */
	.plate__line {
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: 0.15rem 0.55rem;
		min-width: 0;
	}

	.plate__ref {
		flex: 0 0 auto;
		font-family: var(--font-mono);
		font-size: 0.625rem;
		letter-spacing: var(--tracking-wide);
		color: var(--accent-text);
	}

	.plate__title {
		min-width: 0;
		overflow-wrap: anywhere;
	}

	/* On a plate with a handwritten caption the typed title is secondary: it is the archive's
	   description, not the document. */
	.plate__hand + .plate__line .plate__title {
		font-size: 0.75rem;
		opacity: 0.8;
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Timeline / chronology
	   ══════════════════════════════════════════════════════════════════════ */

	.timeline {
		position: relative;
		max-width: var(--width-text);
		margin-inline: auto;
		padding-left: clamp(2rem, 6vw, 3.5rem);
	}

	/*
	 * The spine is a surveyor's rule, not a hairline: a fine vertical line with a tick every
	 * sixteen pixels, drawn from two backgrounds on one element. It still draws itself when the
	 * section arrives.
	 */
	.timeline::before {
		content: "";
		position: absolute;
		inset-block: 0.5rem 1rem;
		inset-inline-start: -10px;
		width: 12px;
		background-image:
			/* the rule */
			linear-gradient(
				180deg,
				color-mix(in oklab, var(--accent) 70%, transparent),
				color-mix(in oklab, var(--accent) 22%, transparent)
			),
			/* a major tick every four */
			repeating-linear-gradient(
				180deg,
				color-mix(in oklab, var(--accent) 42%, transparent) 0 1px,
				transparent 1px 64px
			),
			/* and a minor one every sixteen pixels */
			repeating-linear-gradient(
				180deg,
				color-mix(in oklab, var(--accent) 26%, transparent) 0 1px,
				transparent 1px 16px
			);
		background-size: 1.5px 100%, 8px 100%, 4px 100%;
		background-position: 10px 0, 0 0, 4px 0;
		background-repeat: no-repeat, repeat-y, repeat-y;
		transform-origin: top;
		scale: 1 var(--timeline-draw, 1);
		transition: scale 1.4s var(--ease-cinematic);
	}

	/*
	 * The second rail: the distance already read, filling behind the reader. Its height comes
	 * from --timeline-progress, which the script updates on scroll; with no script it stays at
	 * zero and the timeline is exactly the rule above, which is a complete design on its own.
	 */
	.timeline::after {
		content: "";
		position: absolute;
		inset-block-start: 0.5rem;
		inset-inline-start: -0.25px;
		width: 2px;
		height: calc((100% - 1.5rem) * var(--timeline-progress, 0));
		background: linear-gradient(
			180deg,
			color-mix(in oklab, var(--accent-deep) 20%, transparent),
			var(--accent-deep) 12%,
			var(--accent-deep)
		);
		box-shadow: 0 0 10px -2px color-mix(in oklab, var(--accent) 55%, transparent);
		pointer-events: none;
	}

	.js .timeline:not(.is-visible)::before {
		--timeline-draw: 0;
	}

	.timeline__entry {
		position: relative;
		padding-block: clamp(1.25rem, 3vw, 2.25rem);
	}

	/*
	 * A benchmark, the way a survey sheet marks one: a filled core, a ring of paper around it,
	 * then a hairline ring — all of it built from box-shadow spreads on a single 7px dot, so
	 * there is one element and no extra markup. The paper ring is what makes the marker sit on
	 * the rule rather than under it.
	 */
	.timeline__entry::before {
		content: "";
		position: absolute;
		inset-block-start: calc(clamp(1.25rem, 3vw, 2.25rem) + 0.5em);
		inset-inline-start: calc(clamp(2rem, 6vw, 3.5rem) * -1);
		width: 7px;
		height: 7px;
		border-radius: 50%;
		background-color: color-mix(in oklab, var(--accent) 70%, var(--surface));
		box-shadow:
			0 0 0 3px var(--tl-paper, var(--surface)),
			0 0 0 4px color-mix(in oklab, var(--accent) 42%, transparent),
			0 0 0 7px var(--tl-paper, var(--surface));
		translate: -3px 0;
	}

	/* The milestones the books themselves sit inside get a surveyed point: brass core, two
	   rings and a halo. */
	.timeline__entry--accent::before {
		width: 9px;
		height: 9px;
		background-color: var(--accent-deep);
		box-shadow:
			0 0 0 3px var(--tl-paper, var(--surface)),
			0 0 0 4.5px var(--accent),
			0 0 0 8px var(--tl-paper, var(--surface)),
			0 0 0 9px color-mix(in oklab, var(--accent) 34%, transparent),
			0 0 18px 6px color-mix(in oklab, var(--accent) 26%, transparent);
		translate: -4px 0;
	}

	/*
	 * The rings are holes punched in whatever paper the timeline is lying on — the chronology
	 * sits on the warm surface, the author's life on the plain one — so the colour comes from
	 * a variable rather than being assumed.
	 */
	.section--alt .timeline { --tl-paper: var(--surface-alt); }

	/* The markers are set one after another as the timeline arrives. */
	.js .timeline.is-visible .timeline__entry::before {
		animation: tl-pin 520ms var(--ease-cinematic) both;
		animation-delay: calc(120ms + var(--i, 0) * 55ms);
	}

	@keyframes tl-pin {
		from { opacity: 0; scale: 0.3; }
		60% { scale: 1.18; }
		to { opacity: 1; scale: 1; }
	}

	@media (prefers-reduced-motion: reduce) {
		.timeline::before { transition: none; }
		.timeline::after { box-shadow: none; }
		.js .timeline.is-visible .timeline__entry::before { animation: none; }
	}

	.timeline__year {
		font-family: var(--font-mono);
		font-size: 0.8125rem;
		font-weight: 500;
		letter-spacing: var(--tracking-wider);
		color: var(--accent-text);
		margin-bottom: 0.35rem;
	}

	.timeline__date {
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--on-surface-muted);
		margin-bottom: 0.5rem;
	}

	.timeline__label {
		font-size: var(--text-xl);
		margin-bottom: var(--space-2xs);
	}

	.timeline__text {
		max-width: var(--measure);
		color: var(--on-surface-muted);
	}

	.section--dark .timeline__text,
	.section--dark .timeline__date {
		color: var(--on-dark-muted);
	}

	.section--dark .timeline__entry::before {
		background-color: var(--color-night);
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Question list (FAQ)
	   ══════════════════════════════════════════════════════════════════════ */

	.questions {
		max-width: var(--width-text);
		margin-inline: auto;
	}

	/* Under a left-aligned section head the centred block reads as a mistake, so the flush
	   variant drops the auto margins and lines up with the heading above it. */
	.questions--flush {
		margin-inline: 0;
		margin-top: var(--space-xl);
	}

	.question {
		border-bottom: 1px solid var(--color-border);
	}

	.question__q {
		display: flex;
		align-items: flex-start;
		gap: var(--space-s);
		padding: clamp(1rem, 2.2vw, 1.5rem) 2.5rem clamp(1rem, 2.2vw, 1.5rem) 0;
		list-style: none;
		cursor: pointer;
		font-family: var(--font-display);
		font-size: var(--text-lg);
		font-weight: 600;
		color: var(--color-ink);
		position: relative;
		transition: color var(--motion-fast) var(--ease-standard);
	}

	.question__q::-webkit-details-marker { display: none; }

	.question__q:hover { color: var(--accent-deep); }

	.question__q::after {
		content: "";
		position: absolute;
		inset-inline-end: 0.35rem;
		inset-block-start: calc(clamp(1rem, 2.2vw, 1.5rem) + 0.5em);
		width: 10px;
		height: 10px;
		border-right: 1.5px solid var(--accent);
		border-bottom: 1.5px solid var(--accent);
		rotate: 45deg;
		transition: rotate var(--motion-normal) var(--ease-cinematic);
	}

	.question[open] .question__q::after { rotate: -135deg; }

	.question__a {
		padding: 0 2.5rem clamp(1rem, 2.2vw, 1.5rem) 0;
		max-width: var(--measure);
		color: var(--on-surface-muted);
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Breadcrumbs
	   ══════════════════════════════════════════════════════════════════════ */

	.breadcrumbs__list {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 0.5rem;
		margin: 0;
		padding: 0;
		list-style: none;
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
	}

	.breadcrumbs__item + .breadcrumbs__item::before {
		content: "/";
		margin-right: 0.5rem;
		opacity: 0.4;
	}

	.breadcrumbs a {
		text-decoration: none;
		opacity: 0.75;
	}

	.breadcrumbs a:hover { opacity: 1; }

	/* ══════════════════════════════════════════════════════════════════════
	   Site footer
	   ══════════════════════════════════════════════════════════════════════ */

	.site-footer {
		background-color: var(--color-night);
		color: var(--on-dark-muted);
		border-top: 1px solid color-mix(in oklab, var(--color-brass) 28%, transparent);
		padding-block: clamp(3rem, 7vw, 5rem) var(--space-l);
	}

	.site-footer__grid {
		display: flex;
		flex-wrap: wrap;
		gap: clamp(2rem, 5vw, 4rem);
		padding-bottom: var(--space-l);
		border-bottom: 1px solid color-mix(in oklab, var(--color-paper) 10%, transparent);
	}

	.site-footer__col { flex: 1 1 13rem; min-width: 0; }
	.site-footer__col--brand { flex: 1.6 1 18rem; }

	.site-footer__name {
		font-family: var(--font-display);
		font-size: var(--text-xl);
		font-weight: 700;
		color: var(--color-paper);
		margin-bottom: var(--space-2xs);
	}

	.site-footer__blurb {
		max-width: 34ch;
		font-size: 0.9375rem;
		line-height: var(--leading-normal);
	}

	.site-footer__heading {
		margin-bottom: var(--space-s);
		font-family: var(--font-mono);
		font-size: 0.625rem;
		font-weight: 500;
		letter-spacing: var(--tracking-widest);
		text-transform: uppercase;
		color: var(--color-brass);
	}

	.site-footer__list {
		display: flex;
		flex-direction: column;
		gap: 0.55rem;
		margin: 0;
		padding: 0;
		list-style: none;
	}

	.site-footer__list a {
		font-size: 0.9375rem;
		text-decoration: none;
		color: var(--on-dark-muted);
		transition: color var(--motion-fast) var(--ease-standard),
			padding-inline-start var(--motion-fast) var(--ease-standard);
	}

	.site-footer__list a:hover,
	.site-footer__list a:focus-visible {
		color: var(--color-sand);
		padding-inline-start: 4px;
	}

	/*
	 * The donation line sits above the copyright and carries slightly more weight than it:
	 * the studio's name is the only thing in this footer that is not about the books, and
	 * burying it inside the legal line would be both illegible and ungrateful.
	 */
	.site-footer__patron {
		display: flex;
		flex-wrap: wrap;
		align-items: baseline;
		gap: 0.5rem 1.1rem;
		margin-top: var(--space-l);
		padding-top: var(--space-m);
		border-top: 1px solid var(--color-border-on-dark);
		font-size: 0.875rem;
		color: var(--on-dark-muted);
	}

	.site-footer__patron-more {
		display: inline-flex;
		align-items: baseline;
		gap: 0.4rem;
		font-family: var(--font-mono);
		font-size: 0.6875rem;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		text-decoration: none;
		color: color-mix(in oklab, var(--color-brass) 62%, white);
		border-bottom: 1px solid transparent;
		transition: border-color var(--motion-fast) var(--ease-standard);
	}

	.site-footer__patron-more:hover,
	.site-footer__patron-more:focus-visible {
		border-color: currentColor;
	}

	.site-footer__legal {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: 0.5rem;
		margin-top: var(--space-s);
		font-size: 0.8125rem;
		color: color-mix(in oklab, var(--on-dark-muted) 85%, transparent);
	}

	.site-footer__sep { opacity: 0.4; }

	/* La fila de documentos legales, debajo del copyright y con su mismo peso: información
	   obligatoria, no letra pequeña escondida. */
	.site-footer__legal-nav { margin-top: var(--space-2xs); }

	.site-footer__legal-list {
		display: flex;
		flex-wrap: wrap;
		gap: 0.4rem 1.4rem;
		margin: 0;
		padding: 0;
		list-style: none;
		font-size: 0.8125rem;
		color: color-mix(in oklab, var(--on-dark-muted) 85%, transparent);
	}

	.site-footer__brand {
		font-weight: 600;
		letter-spacing: 0.03em;
		text-decoration: none;
		color: var(--color-brass);
		border-bottom: 1px solid transparent;
		transition: color var(--motion-fast) var(--ease-standard),
			border-color var(--motion-fast) var(--ease-standard);
	}

	.site-footer__brand:hover,
	.site-footer__brand:focus-visible {
		color: var(--color-sand);
		border-bottom-color: currentColor;
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Contact form (WPForms) — brought into the design system
	   ══════════════════════════════════════════════════════════════════════ */

	.wpforms-container { max-width: var(--width-text); margin-inline: 0 !important; }

	.wpforms-container .wpforms-form .wpforms-field { padding: 0 0 var(--space-m) !important; }

	.wpforms-container .wpforms-form .wpforms-field-label {
		font-family: var(--font-sans) !important;
		font-size: var(--text-sm) !important;
		font-weight: 500 !important;
		letter-spacing: var(--tracking-wide);
		text-transform: uppercase;
		color: var(--color-charcoal) !important;
	}

	.wpforms-container .wpforms-form input[type="text"],
	.wpforms-container .wpforms-form input[type="email"],
	.wpforms-container .wpforms-form textarea {
		max-width: 100% !important;
		border: 1px solid var(--color-border-strong) !important;
		border-radius: var(--radius-s) !important;
		background-color: #fff !important;
		font-size: var(--text-base) !important;
	}

	.wpforms-container .wpforms-form button[type="submit"] {
		padding: 0.95rem 1.9rem !important;
		font-family: var(--font-sans) !important;
		font-size: 0.8125rem !important;
		font-weight: 600 !important;
		letter-spacing: var(--tracking-wide) !important;
		text-transform: uppercase !important;
		color: #fff !important;
		background-color: var(--accent-deep) !important;
		border: 1px solid var(--accent-deep) !important;
		border-radius: var(--radius-s) !important;
		transition: background-color var(--motion-fast) var(--ease-standard),
			transform var(--motion-fast) var(--ease-standard) !important;
	}

	.wpforms-container .wpforms-form button[type="submit"]:hover {
		background-color: color-mix(in oklab, var(--accent-deep) 84%, black) !important;
		border-color: color-mix(in oklab, var(--accent-deep) 84%, black) !important;
		transform: translateY(-1px);
	}

	/* WPForms ships a light red for the required marker that measures 3.64:1 here. */
	.wpforms-container .wpforms-required-label {
		color: var(--color-blood-earth) !important;
	}

	/* ══════════════════════════════════════════════════════════════════════
	   Aviso de cookies
	   ══════════════════════════════════════════════════════════════════════

	   Quién lo enseña es `data-consent` en <html>, que el plugin escribe antes del primer
	   pintado. Aquí no hay estado: oculto por defecto, visible sólo mientras no se ha decidido.
	   Ese «por defecto» es también la respuesta correcta sin JavaScript —no hay atributo, no
	   hay aviso— porque sin JavaScript tampoco se carga nada opcional.

	   No atrapa el foco ni tapa la página. La guía de cookies de la AEPD admite el aviso no
	   modal si rechazar cuesta lo mismo que aceptar, y aquí los dos botones son el mismo botón:
	   mismo tamaño, mismo peso, mismo borde. El «sí» se distingue por color, no por jerarquía. */

	.consent { display: none; }

	:root[data-consent="pending"] .consent {
		display: block;
		position: fixed;
		inset-block-end: 0;
		inset-inline: 0;
		z-index: 200;
		padding: var(--space-gutter);
		padding-block-start: 0;
		/* Sin `pointer-events: none` en el contenedor: el hueco de arriba es aire, y el aire
		   tiene que dejar seguir leyendo la página que hay debajo. */
		pointer-events: none;
	}

	.consent__sheet {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: clamp(1rem, 2.5vw, 2rem);
		max-width: var(--width-full);
		margin-inline: auto;
		padding: clamp(1.1rem, 2.2vw, 1.6rem) clamp(1.2rem, 2.6vw, 2rem);
		pointer-events: auto;
		background-color: var(--color-paper);
		border: 1px solid var(--color-border);
		border-block-start: 3px solid var(--color-brass);
		border-radius: var(--radius-l) var(--radius-l) 0 0;
		box-shadow: 0 -24px 60px -28px rgb(11 13 16 / 0.55);
	}

	.consent__body { flex: 1 1 22rem; min-width: 0; }

	.consent__title {
		margin: 0 0 0.35rem;
		font-family: var(--font-display);
		font-size: 1.15rem;
		font-weight: 600;
		line-height: 1.2;
		color: var(--color-ink);
	}

	/* El cuerpo del sitio arranca en 19 px y aquí no se baja: esto es justo lo que no puede
	   quedar en letra pequeña. */
	.consent__text {
		margin: 0;
		max-width: 62ch;
		font-size: 1rem;
		line-height: 1.55;
		color: var(--color-charcoal);
	}

	.consent__actions {
		display: flex;
		flex: 0 1 auto;
		flex-wrap: wrap;
		gap: 0.75rem;
	}

	.consent__btn {
		flex: 1 1 auto;
		min-width: 10rem;
		min-height: 52px;          /* la medida de campo del sitio: dedos de ochenta años */
		padding: 0.85rem 1.75rem;
		font-family: var(--font-sans);
		font-size: 0.9375rem;
		font-weight: 600;
		letter-spacing: var(--tracking-wide);
		color: var(--color-ink);
		background-color: transparent;
		border: 1px solid var(--color-border-strong);
		border-radius: var(--radius-s);
		cursor: pointer;
		transition: background-color var(--motion-fast) var(--ease-standard),
			border-color var(--motion-fast) var(--ease-standard),
			color var(--motion-fast) var(--ease-standard);
	}

	.consent__btn:hover,
	.consent__btn:focus-visible {
		color: var(--accent-deep);
		border-color: var(--accent);
	}

	.consent__btn--yes {
		color: #fff;
		background-color: var(--accent-deep);
		border-color: var(--accent-deep);
	}

	.consent__btn--yes:hover,
	.consent__btn--yes:focus-visible {
		color: #fff;
		background-color: color-mix(in oklab, var(--accent-deep) 84%, black);
		border-color: color-mix(in oklab, var(--accent-deep) 84%, black);
	}

	/* Reabrir la decisión desde el pie o desde la política. Mismo botón, sin ocupar la fila. */
	.consent__btn--inline { flex: 0 0 auto; min-width: 0; }

	.consent:focus { outline: none; }

	.consent:focus-visible .consent__sheet {
		outline: 2px solid var(--color-brass);
		outline-offset: 3px;
	}

	@media (max-width: 40em) {
		/* En móvil el aviso ocupa el ancho y los botones van a lo ancho también: dos objetivos
		   grandes y separados valen más que dos botones pequeños en fila. */
		.consent__actions { flex: 1 1 100%; }
		.consent__btn { flex: 1 1 100%; }
	}

	/* El pie: el enlace que devuelve la decisión. Es un botón porque no lleva a ninguna parte. */
	.site-footer__consent {
		font: inherit;
		color: inherit;
		background: none;
		border: 0;
		padding: 0;
		text-decoration: underline;
		text-decoration-color: color-mix(in oklab, var(--color-brass) 55%, transparent);
		text-underline-offset: 0.2em;
		cursor: pointer;
	}

	.site-footer__consent:hover,
	.site-footer__consent:focus-visible { color: var(--color-sand); }
}
