/*
Theme Name:   YUAN
Theme URI:    https://yuan-living.com/
Author:       YUAN
Description:  A block theme for YUAN, a curated collection brand rooted in artistic research. Editorial, quiet and image-led, in the manner of a gallery publication.
Version:      1.7.1
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.0
License:      GNU General Public License v2 or later
License URI:  http://www.gnu.org/licenses/gpl-2.0.html
Text Domain:  yuan
Tags:         full-site-editing, blog, portfolio, one-column, block-patterns, custom-colors, custom-menu, editor-style, featured-images, wide-blocks
*/

/* -------------------------------------------------------------------------
 * Foundations
 * ---------------------------------------------------------------------- */

:root {
	--yuan-rule: 1px solid var(--wp--preset--color--line);
	--yuan-ease: cubic-bezier(0.16, 0.68, 0.28, 1);
	--yuan-duration: 0.5s;
	--yuan-header-height: 5.5rem;
}

@media (prefers-reduced-motion: reduce) {
	:root {
		--yuan-duration: 0.01ms;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

body {
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	font-variant-numeric: oldstyle-nums;
}

img {
	max-width: 100%;
	height: auto;
}

::selection {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

:where(a):focus-visible,
:where(button):focus-visible,
:where(summary):focus-visible,
:where(input):focus-visible,
:where(textarea):focus-visible {
	outline: 1px solid var(--wp--preset--color--cinnabar);
	outline-offset: 3px;
}

/* Skip link. */
.yuan-skip {
	position: absolute;
	left: -9999px;
	top: 0;
	z-index: 999;
	padding: 1rem 1.5rem;
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--micro);
	letter-spacing: 0.16em;
	text-transform: uppercase;
}

.yuan-skip:focus {
	left: 0;
}

/* -------------------------------------------------------------------------
 * Type utilities
 * ---------------------------------------------------------------------- */

/* The small tracked capitals used for every label on the site. */
.yuan-eyebrow,
.yuan-specs dt,
.yuan-card__meta,
.yuan-collection__count,
.yuan-lang,
.yuan-index__meta {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	line-height: 1.4;
}

.yuan-eyebrow {
	color: var(--wp--preset--color--stone);
	margin: 0 0 var(--wp--preset--spacing--30);
}

/* Caps a block to a comfortable reading measure while staying flush left,
   which a constrained layout cannot do (it centres). */
.yuan-measure {
	max-width: 46rem;
}

/* A lead paragraph, set in the display face. */
.yuan-lead {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 400;
	line-height: 1.45;
	letter-spacing: -0.005em;
}

.has-display-font-family {
	letter-spacing: -0.01em;
}

/* -------------------------------------------------------------------------
 * Header
 * ---------------------------------------------------------------------- */

.yuan-header {
	position: sticky;
	top: 0;
	z-index: 100;
	background: var(--wp--preset--color--paper);
	border-bottom: var(--yuan-rule);
}

/*
 * While the header is fixed, its template part collapses to zero height — but
 * the root layout still puts a block gap between it and <main>. That margin
 * collapses out through the wrapper and shows as a strip of page background
 * above the hero.
 */
.has-full-bleed-hero .wp-site-blocks > main {
	margin-block-start: 0;
}

/* Over a full-bleed hero the header floats, inverted, until the page scrolls. */
.yuan-header.is-over-hero {
	position: fixed;
	inset: 0 0 auto 0;
	background: transparent;
	border-bottom-color: transparent;
	color: var(--wp--preset--color--paper);
	transition: background var(--yuan-duration) var(--yuan-ease),
		color var(--yuan-duration) var(--yuan-ease),
		border-color var(--yuan-duration) var(--yuan-ease);
}

.yuan-header.is-over-hero .wp-block-site-title a,
.yuan-header.is-over-hero .wp-block-navigation a,
.yuan-header.is-over-hero .yuan-lang__item {
	color: var(--wp--preset--color--paper);
}

.yuan-header.is-over-hero .wp-block-site-logo img {
	filter: none;
}

.yuan-header.is-pinned {
	position: fixed;
	background: var(--wp--preset--color--paper);
	color: var(--wp--preset--color--ink);
	border-bottom-color: var(--wp--preset--color--line);
}

.yuan-header.is-pinned .wp-block-site-title a,
.yuan-header.is-pinned .wp-block-navigation a,
.yuan-header.is-pinned .yuan-lang__item {
	color: var(--wp--preset--color--ink);
}

.yuan-header.is-pinned .wp-block-site-logo img {
	filter: invert(1);
}

/* Underline that draws in from the left on hover — used across all nav. */
.wp-block-navigation .wp-block-navigation-item__content,
.yuan-lang__item {
	position: relative;
	padding-block: 0.25em;
}

.wp-block-navigation .wp-block-navigation-item__content::after,
.yuan-lang__item::after {
	content: "";
	position: absolute;
	left: 0;
	bottom: 0;
	width: 100%;
	height: 1px;
	background: currentColor;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform var(--yuan-duration) var(--yuan-ease);
}

.wp-block-navigation .wp-block-navigation-item__content:hover::after,
.wp-block-navigation .current-menu-item .wp-block-navigation-item__content::after,
.yuan-lang__item:hover::after,
.yuan-lang__item.is-current::after {
	transform: scaleX(1);
}

/*
 * Submenus. The dropdown arrives with an opaque card behind it: core paints it
 * white, and the navigation block copies its overlay colours onto the submenu
 * container too (see navigation-submenu.php), so it renders as paper-on-ink.
 * Over the hero that card reads as a foreign panel and swallows the header's
 * own white links. Dropping the panel lets the submenu take the header's colour
 * in every state — black over paper, paper over the hero.
 *
 * The !important is not optional: those overlay colours land as preset utility
 * classes, and WordPress declares every preset colour class !important.
 */
.yuan-header .wp-block-navigation .has-child > .wp-block-navigation__submenu-container {
	background-color: transparent !important;
	color: inherit !important;
	border: 0;
	box-shadow: none;
	min-width: max-content;
	padding-block: var(--wp--preset--spacing--20);
	/* Nothing but the hero behind the labels now, so soften what shows through. */
	backdrop-filter: blur(10px);
}

/* Without a card to sit inside, the labels align under the parent item. */
.yuan-header .wp-block-navigation .has-child > .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	padding-inline: 0;
	padding-block: 0.35em;
}

/* The overlay is already paper-on-ink; it needs no blur behind its own items. */
.yuan-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__submenu-container {
	backdrop-filter: none;
}

.yuan-lang {
	display: flex;
	gap: 0.9rem;
	align-items: center;
}

.yuan-lang__item.is-current {
	color: var(--wp--preset--color--ink);
}

.yuan-lang__item:not(.is-current) {
	color: var(--wp--preset--color--stone);
}

/*
 * A language this page has not been written in. The switcher still shows all
 * three — the site has three, and hiding one says otherwise — but an entry
 * with nowhere to lead is rendered as a span, so it should not invite a click.
 */
.yuan-lang__item.is-unavailable {
	opacity: 0.4;
	cursor: default;
}

.yuan-lang__item.is-unavailable::after {
	content: none;
}

/*
 * Leads somewhere, but to another language than the one on the label. Carries
 * the hover underline permanently, faintly: enough to look unlike its
 * neighbours and prompt the title that explains it.
 */
.yuan-lang__item.is-fallback::after {
	transform: scaleX(1);
	opacity: 0.35;
}

/* -------------------------------------------------------------------------
 * Header — narrow screens
 *
 * Up to 899px the bar carries the logo and the menu toggle and nothing else.
 * That is what puts the toggle hard right: the row is justified space-between,
 * so a third item — the language switcher — was leaving it stranded in the
 * middle.
 *
 * The languages are not dropped, they move into the overlay, where the menu
 * already has room for them. functions.php emits a second copy of the switcher
 * inside the overlay; the two rules below show exactly one of the two, so the
 * duplicate is never both visible at once.
 *
 * 899px rather than core's 600px because between the two the menu did not fit
 * on one line and wrapped onto a second. Measured across the three languages,
 * the last to fit is French at 880px — the labels are longest there — so the
 * overlay has to hold until past it.
 * ---------------------------------------------------------------------- */

.yuan-nav-lang {
	display: none;
}

/*
 * Core hands the navigation back to the bar at 600px. Between there and the
 * width where it actually fits, keep it in the overlay: hide the inline list
 * and show the toggle core would have hidden. Each selector carries one class
 * more than core's, which is what settles it without !important.
 */
@media (min-width: 600px) and (max-width: 899px) {
	.yuan-header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
		display: none;
	}

	.yuan-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}
}

@media (max-width: 899px) {
	/* The bar's own copy, distinguished from the overlay's by where it sits. */
	.yuan-header > .wp-block-group > .yuan-lang {
		display: none;
	}

	.yuan-nav-lang {
		display: block;
		width: 100%;
		/* Pushed to the floor of the overlay, under the menu. */
		margin-top: auto;
		padding-top: var(--wp--preset--spacing--30);
		/* A divider, not a line to read: faint, and following the overlay's
		   own colour so it holds up whatever shows through behind it. */
		border-top: 1px solid currentColor;
		border-top-color: color-mix(in srgb, currentColor 15%, transparent);
	}

	.yuan-nav-lang .yuan-lang {
		gap: 1.5rem;
		font-size: var(--wp--preset--font-size--small);
	}

	/*
	 * An overlay that shows the page through itself. Core paints the container
	 * with the block's overlay colour as a preset class, and every preset colour
	 * class is declared !important — so unseating it takes the same.
	 *
	 * What replaces it is a wash rather than clear glass. The overlay's links
	 * are ink on whatever the page happened to be showing, and ink over an
	 * unblurred photograph is not readable.
	 */
	.yuan-header .wp-block-navigation__responsive-container.is-menu-open {
		background-color: rgb(247 245 240 / 72%) !important;
		-webkit-backdrop-filter: blur(24px) saturate(140%);
		backdrop-filter: blur(24px) saturate(140%);
	}

	/* Without a blur to soften it, the wash carries the legibility alone. */
	@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
		.yuan-header .wp-block-navigation__responsive-container.is-menu-open {
			background-color: rgb(247 245 240 / 95%) !important;
		}
	}

	/*
	 * Core stacks the overlay's wrappers but lets them shrink to their contents,
	 * which leaves nothing for the switcher's auto margin to push against.
	 */
	.yuan-header .is-menu-open .wp-block-navigation__responsive-close,
	.yuan-header .is-menu-open .wp-block-navigation__responsive-dialog {
		display: flex;
		flex: 1 1 auto;
		flex-direction: column;
	}

	.yuan-header .is-menu-open .wp-block-navigation__responsive-container-content {
		flex: 1 1 auto;
	}

	/*
	 * Over a hero the header inverts its links to paper so they read against the
	 * image. The overlay is not over the image — it is a surface of its own, and
	 * it carries the block's own ink colour — so the inversion has to stop at
	 * its edge, or the menu is paper on paper. The extra class outweighs the
	 * .yuan-header.is-over-hero rule that would otherwise win on the anchor.
	 */
	.yuan-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content,
	.yuan-header .wp-block-navigation__responsive-container.is-menu-open .yuan-lang__item.is-current {
		color: var(--wp--preset--color--ink);
	}

	.yuan-header .wp-block-navigation__responsive-container.is-menu-open .yuan-lang__item:not(.is-current) {
		color: var(--wp--preset--color--stone);
	}

	/* The toggle would otherwise show through its own overlay, under the close
	   button. Hidden rather than removed, so the bar keeps its shape. */
	.has-modal-open .yuan-header .wp-block-navigation__responsive-container-open {
		visibility: hidden;
	}

	/*
	 * Submenu entries. Core insets them by 2rem, which leaves them hanging
	 * short of the parent they belong under; setting them flush with Collection
	 * and marking each with a rule says "these are its children" without
	 * spending width on an indent. Matching core's selector class for class
	 * outranks it without reaching for !important.
	 */
	.yuan-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content .has-child .wp-block-navigation__submenu-container {
		padding-left: 0;
		padding-right: 0;
	}

	/* Drawn rather than written: a dash typed as content is text a screen
	   reader would announce before every label.
	   Core lays the link out as a flex row, so the rule is centred with
	   align-self — vertical-align has no say inside a flex container, and left
	   to itself a one-pixel box stretches to the top of the line. */
	.yuan-header .is-menu-open .wp-block-navigation__submenu-container .wp-block-navigation-item__content::before {
		content: "";
		flex: none;
		align-self: center;
		width: 0.8em;
		height: 1px;
		margin-right: 0.6em;
		background: currentColor;
		opacity: 0.45;
	}
}

/* -------------------------------------------------------------------------
 * Hero
 * ---------------------------------------------------------------------- */

.yuan-hero {
	position: relative;
	min-height: 100svh;
	display: grid;
	align-items: end;
	overflow: clip;
}

/*
 * A scrim rather than a heavier flat dim: the hero image can be bright at the
 * top (where the inverted header sits) and at the bottom (where the statement
 * sits), and a flat overlay dark enough for both would grey out the artwork.
 */
.yuan-hero::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: 1;
	pointer-events: none;
	background: linear-gradient(
		to bottom,
		rgba(20, 17, 15, 0.5) 0%,
		rgba(20, 17, 15, 0) 26%,
		rgba(20, 17, 15, 0) 42%,
		rgba(20, 17, 15, 0.7) 100%
	);
}

/* Hero copy sits bottom-left on the wide grid, not centred in the text column. */
/*
 * Core lays the cover out as a grid with justify-content:center, and its single
 * column track is content-sized — so width:100% below resolves against a track
 * that has already shrunk to fit the text, and the whole block ends up centred
 * on its own contents. The hero then starts at a different place in every
 * language: "源于艺术" is short, "la vie quotidienne" is long, and neither lines
 * up with the logo above it. Giving the track a definite size fixes the left
 * edge for all three.
 */
.yuan-hero {
	grid-template-columns: minmax(0, 1fr);
	justify-content: stretch;
}

.yuan-hero > .wp-block-cover__inner-container {
	position: relative;
	z-index: 2;
	width: 100%;
	max-width: var(--wp--style--global--wide-size);
	margin-inline: auto;
}

/* The cover's inner container is a constrained layout, which would re-centre
   its children inside the text column — release them. */
.yuan-hero > .wp-block-cover__inner-container > * {
	max-width: none;
	margin-inline: 0;
}

.yuan-hero .wp-block-cover__image-background,
.yuan-hero img {
	animation: yuan-hero-drift 24s var(--yuan-ease) forwards;
}

@keyframes yuan-hero-drift {
	from { transform: scale(1.06); }
	to   { transform: scale(1); }
}

/*
 * The hero images are landscape but the hero itself is a full-height panel, so
 * on a narrow screen what shows is a tall slice rather than the photograph. Cut
 * from the middle that slice lands on the empty wall a gallery shot leaves
 * behind its subject; these frames carry their subject on the right, so that is
 * where the slice is taken. Wide screens show the whole frame and need none of
 * this.
 */
@media (max-width: 899px) {
	.yuan-hero .wp-block-cover__image-background,
	.yuan-hero img {
		object-position: right center;
	}
}

.yuan-hero__statement {
	font-family: var(--wp--preset--font-family--display);
	font-weight: 400;
	line-height: 1.05;
	letter-spacing: -0.02em;
	text-wrap: balance;
}

/* -------------------------------------------------------------------------
 * Grids and cards
 * ---------------------------------------------------------------------- */

.yuan-grid {
	display: grid;
	gap: var(--wp--preset--spacing--40) var(--wp--preset--spacing--30);
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

@media (min-width: 700px) {
	.yuan-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
	.yuan-grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/*
 * A grid of one. On a narrow screen the grid is two columns wide, so a section
 * holding a single card filled the left half and left the right empty — which
 * reads as a card that failed to load rather than as a set with one member.
 * With nothing to sit beside it, it takes the row.
 *
 * Only the lone case: an odd card at the end of a longer list is plainly the
 * tail of a set, and stretching that one would break the rhythm of the rest.
 */
@media (max-width: 699px) {
	.yuan-grid > .yuan-card:only-child {
		grid-column: 1 / -1;
	}
}

.yuan-card {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	text-decoration: none;
	color: inherit;
}

/* -------------------------------------------------------------------------
 * Gallery
 *
 * A mosaic rather than a uniform grid: every fifth image spans two columns, so
 * the page reads as a wall of images instead of a product listing — which is
 * the distinction the brief draws.
 * ---------------------------------------------------------------------- */

.yuan-gallery {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: var(--wp--preset--spacing--30);
}

@media (min-width: 700px) {
	.yuan-gallery {
		grid-template-columns: repeat(4, minmax(0, 1fr));
	}

	.yuan-gallery__item.is-wide {
		grid-column: span 2;
	}
}

.yuan-gallery__item {
	position: relative;
	display: block;
	overflow: clip;
	background: var(--wp--preset--color--parchment);
	aspect-ratio: 4 / 5;
	text-decoration: none;
	color: inherit;
}

/* Only once a tile can actually span two columns; below that the landscape crop
   in a two-column grid just staggers the rows. */
@media (min-width: 700px) {
	.yuan-gallery__item.is-wide {
		aspect-ratio: 8 / 5;
	}
}

.yuan-gallery__item img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.2s var(--yuan-ease);
}

.yuan-gallery__item:hover img {
	transform: scale(1.03);
}

/* The caption sits over the image, so it needs its own ground to stay legible
   whatever the photograph does underneath it. */
.yuan-gallery__caption {
	position: absolute;
	inset: auto 0 0 0;
	display: grid;
	gap: 0.2rem;
	padding: var(--wp--preset--spacing--40) var(--wp--preset--spacing--20) var(--wp--preset--spacing--20);
	background: linear-gradient( to top, rgb(20 17 15 / 72%), transparent );
	color: var(--wp--preset--color--paper);
	opacity: 0;
	transform: translateY(0.4rem);
	transition: opacity var(--yuan-duration) var(--yuan-ease), transform var(--yuan-duration) var(--yuan-ease);
}

.yuan-gallery__item:hover .yuan-gallery__caption,
.yuan-gallery__item:focus-visible .yuan-gallery__caption {
	opacity: 1;
	transform: none;
}

/* Hover is not available on touch, so the captions are simply always on. */
@media (hover: none) {
	.yuan-gallery__caption {
		opacity: 1;
		transform: none;
	}
}

.yuan-gallery__title {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	line-height: 1.2;
}

.yuan-gallery__meta {
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	opacity: 0.8;
}

.yuan-card__media {
	display: block;
	overflow: clip;
	background: var(--wp--preset--color--parchment);
	aspect-ratio: 4 / 5;
}

.yuan-card__media img,
.yuan-card__placeholder {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.2s var(--yuan-ease), filter var(--yuan-duration) var(--yuan-ease);
}

.yuan-card:hover .yuan-card__media img {
	transform: scale(1.03);
}

.yuan-card__body {
	display: grid;
	gap: 0.35rem;
}

.yuan-card__title {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 400;
	line-height: 1.3;
}

.yuan-card__meta {
	color: var(--wp--preset--color--stone);
}

/* Query-loop posts styled as cards without extra markup. */
.yuan-loop .wp-block-post-featured-image {
	margin-bottom: var(--wp--preset--spacing--20);
	background: var(--wp--preset--color--parchment);
	overflow: clip;
}

.yuan-loop .wp-block-post-featured-image img {
	transition: transform 1.2s var(--yuan-ease);
}

.yuan-loop li:hover .wp-block-post-featured-image img {
	transform: scale(1.03);
}

.yuan-loop .wp-block-post-title {
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 400;
	letter-spacing: 0;
	margin: 0;
}

/* -------------------------------------------------------------------------
 * Index list — the "see all" rows used for artists and projects
 * ---------------------------------------------------------------------- */

.yuan-index {
	border-top: var(--yuan-rule);
}

.yuan-index__row {
	display: grid;
	grid-template-columns: 1fr auto;
	gap: var(--wp--preset--spacing--20);
	align-items: baseline;
	padding: var(--wp--preset--spacing--30) 0;
	border-bottom: var(--yuan-rule);
	text-decoration: none;
	color: inherit;
	transition: padding-left var(--yuan-duration) var(--yuan-ease);
}

.yuan-index__row:hover {
	padding-left: var(--wp--preset--spacing--20);
}

.yuan-index__title {
	font-family: var(--wp--preset--font-family--display);
	font-size: var(--wp--preset--font-size--large);
	font-weight: 400;
	margin: 0;
}

.yuan-index__meta {
	color: var(--wp--preset--color--stone);
}

/* -------------------------------------------------------------------------
 * Specs, price, enquiry
 * ---------------------------------------------------------------------- */

.yuan-specs__list {
	margin: 0;
	border-top: var(--yuan-rule);
}

.yuan-specs__row {
	display: grid;
	grid-template-columns: minmax(7rem, 30%) 1fr;
	gap: var(--wp--preset--spacing--20);
	padding: 0.85rem 0;
	border-bottom: var(--yuan-rule);
}

.yuan-specs dt {
	margin: 0;
	color: var(--wp--preset--color--stone);
}

.yuan-specs dd {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
}

.yuan-price {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--medium);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.02em;
}

.yuan-button {
	display: inline-block;
	border: 1px solid currentColor;
	padding: 0.9em 2em;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	cursor: pointer;
	background: transparent;
	color: inherit;
	transition: background var(--yuan-duration) var(--yuan-ease), color var(--yuan-duration) var(--yuan-ease);
	list-style: none;
}

.yuan-button::-webkit-details-marker {
	display: none;
}

.yuan-button:hover {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.yuan-enquire__wrap[open] .yuan-button {
	background: var(--wp--preset--color--ink);
	color: var(--wp--preset--color--paper);
}

.yuan-enquire__form {
	display: grid;
	gap: var(--wp--preset--spacing--20);
	margin-top: var(--wp--preset--spacing--30);
	max-width: 26rem;
}

.yuan-enquire__intro {
	margin: 0;
	font-size: var(--wp--preset--font-size--small);
	color: var(--wp--preset--color--stone);
}

.yuan-enquire__thanks {
	font-family: var(--wp--preset--font-family--display);
	border-left: 2px solid var(--wp--preset--color--cinnabar);
	padding-left: var(--wp--preset--spacing--20);
}

.yuan-field {
	display: grid;
	gap: 0.4rem;
}

.yuan-field > span {
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--micro);
	font-weight: 500;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var(--wp--preset--color--stone);
}

.yuan-field input,
.yuan-field textarea,
.yuan-field select {
	width: 100%;
	border: 0;
	border-bottom: var(--yuan-rule);
	background: transparent;
	padding: 0.5rem 0;
	font: inherit;
	color: inherit;
	border-radius: 0;
}

.yuan-field input:focus,
.yuan-field textarea:focus,
.yuan-field select:focus {
	border-bottom-color: var(--wp--preset--color--ink);
}

/* The native arrow sits on a control the browser paints its own background
   behind; drawing our own keeps the field flush with the rules above and below. */
.yuan-field select {
	appearance: none;
	background-image: linear-gradient( 45deg, transparent 50%, currentColor 50% ),
	                  linear-gradient( 135deg, currentColor 50%, transparent 50% );
	background-position: right 0.55rem center, right 0.2rem center;
	background-size: 0.35rem 0.35rem;
	background-repeat: no-repeat;
	padding-right: 1.5rem;
}

/* The contact page's form is the point of the page, so it is wider and open
   rather than folded behind a summary. */
.yuan-enquire--contact .yuan-enquire__form {
	max-width: 34rem;
	margin-top: 0;
	gap: var(--wp--preset--spacing--30);
}

.yuan-enquire--contact .yuan-button {
	justify-self: start;
}

.yuan-enquire__note {
	margin: 0;
	font-size: var(--wp--preset--font-size--micro);
	color: var(--wp--preset--color--stone);
}

/* Honeypot — off-screen rather than display:none, which some bots detect. */
.yuan-hp {
	position: absolute;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* -------------------------------------------------------------------------
 * Collection introduction
 *
 * The prose written for one collection, shown on its own archive between the
 * description and the works. It renders nothing when a collection has no
 * introduction, so the spacing below is only ever paid when there is copy.
 * ---------------------------------------------------------------------- */

.yuan-collection-intro {
	margin-bottom: var(--wp--preset--spacing--50);
}

/* -------------------------------------------------------------------------
 * Collection index
 * ---------------------------------------------------------------------- */

.yuan-collection-index {
	display: grid;
	gap: var(--wp--preset--spacing--40);
}

.yuan-collection {
	border-top: var(--yuan-rule);
	padding-top: var(--wp--preset--spacing--30);
}

.yuan-collection__head {
	display: grid;
	grid-template-columns: minmax(0, 14rem) 1fr;
	gap: var(--wp--preset--spacing--30);
	align-items: start;
	text-decoration: none;
	color: inherit;
}

@media (max-width: 600px) {
	.yuan-collection__head {
		grid-template-columns: minmax(0, 8rem) 1fr;
	}
}

.yuan-collection__media {
	display: block;
	overflow: clip;
	background: var(--wp--preset--color--parchment);
	aspect-ratio: 4 / 5;
}

.yuan-collection__media img,
.yuan-collection__placeholder {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 1.2s var(--yuan-ease);
}

.yuan-collection__head:hover .yuan-collection__media img {
	transform: scale(1.03);
}

.yuan-collection__text {
	display: block;
}

.yuan-collection__row {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--wp--preset--spacing--20);
}

.yuan-collection__name {
	margin: 0;
	font-size: var(--wp--preset--font-size--x-large);
	font-weight: 400;
}

.yuan-collection__count {
	color: var(--wp--preset--color--stone);
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

.yuan-collection__desc {
	display: block;
	max-width: 42rem;
	margin: var(--wp--preset--spacing--20) 0 0;
	color: var(--wp--preset--color--stone);
	font-size: var(--wp--preset--font-size--small);
}

.yuan-collection__children {
	display: flex;
	flex-wrap: wrap;
	gap: var(--wp--preset--spacing--30);
	margin-top: var(--wp--preset--spacing--30);
}

.yuan-collection__child {
	display: flex;
	align-items: baseline;
	gap: 0.6rem;
	text-decoration: none;
	color: inherit;
	border-bottom: var(--yuan-rule);
	padding-bottom: 0.35rem;
	font-family: var(--wp--preset--font-family--body);
	font-size: var(--wp--preset--font-size--small);
	transition: border-color var(--yuan-duration) var(--yuan-ease);
}

.yuan-collection__child:hover {
	border-bottom-color: var(--wp--preset--color--ink);
}

/* -------------------------------------------------------------------------
 * The mark
 * ---------------------------------------------------------------------- */

/* Sized in em so a block-level font-size override rescales the whole mark. */
.yuan-mark {
	font-size: 4rem;
	line-height: 0;
}

/*
 * The traced ensō is closed outlines, not a stroked path — so it is filled with
 * currentColor and carries no stroke of its own.
 */
.yuan-mark__svg {
	display: block;
	width: 1em;
	height: 1em;
	fill: currentColor;
	stroke: none;
}

/*
 * The logo is stored white, because that is how it has to look while the header
 * floats over a hero. It is an image, so it cannot follow the header's
 * currentColor the way the nav links do — on the paper header it is inverted
 * back to black instead. Blending stays off: the PNG is already transparent,
 * and multiply would sink it into the hero photograph.
 */
.wp-block-site-logo img {
	mix-blend-mode: normal;
	filter: invert(1);
	transition: filter var(--yuan-duration) var(--yuan-ease);
}

/* -------------------------------------------------------------------------
 * Related works
 * ---------------------------------------------------------------------- */

.yuan-related {
	margin-top: var(--wp--preset--spacing--60);
	padding-top: var(--wp--preset--spacing--40);
	border-top: var(--yuan-rule);
}

/* -------------------------------------------------------------------------
 * Editorial body copy
 * ---------------------------------------------------------------------- */

.yuan-prose > * + * {
	margin-top: var(--wp--preset--spacing--30);
}

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

.yuan-prose p {
	max-width: 40rem;
}

/*
 * Research entries are the one place where the body copy is the page rather
 * than a note beside an object, and they already run in a column narrowed by
 * the specs beside them. Capping the line a second time left the text short of
 * its own column, so here it takes the width it is given.
 */
.yuan-prose--full p {
	max-width: none;
}

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

/*
 * The footer's parchment background is set on the block itself, in
 * parts/footer.html, so it stays editable in the site editor — WordPress marks
 * preset background classes !important, so declaring it here would only be dead
 * code that silently outranked nothing.
 *
 * It carried a hairline along its top edge as well; against the page's paper
 * the tonal step already separates it, and doing both read as a seam.
 */

.yuan-footer a {
	color: inherit;
}

/* The footer lists are navigation and label groups, not prose, so they carry no
   markers. */
.yuan-footer ul {
	list-style: none;
	padding-left: 0;
	margin: 0;
}

/* -------------------------------------------------------------------------
 * Narrow screens
 *
 * 781px is where core stops laying a columns block out side by side and
 * stacks it. That is the width at which these sections stop being a row and
 * become one reading column, and everything below is about what the stacking
 * leaves behind.
 * ---------------------------------------------------------------------- */

@media (max-width: 781px) {
	/*
	 * Stacked, the dates read as a timeline running down the page, and a
	 * timeline holds together centred. Left-aligned each year trails most of a
	 * line of empty paper beside it.
	 */
	.yuan-timeline {
		text-align: center;
	}

	/*
	 * The brand block closes the footer on a phone instead of opening a row, so
	 * the mark and the line beneath it are centred together with the sentence
	 * that belongs to them — centring only part of the group reads as a mistake.
	 */
	.yuan-footer .wp-block-columns > .wp-block-column:first-child {
		text-align: center;
	}

	/* The mark is a block-level SVG of its own fixed width, which text-align
	   cannot move. */
	.yuan-footer .wp-block-columns > .wp-block-column:first-child .yuan-mark__svg {
		margin-inline: auto;
	}

	/*
	 * A blockquote carries the browser's own 40px side margins. On a phone that
	 * is a quarter of the measure spent on nothing, and it was breaking the
	 * pull quote into six short lines inside a section that had width to spare.
	 */
	.wp-block-quote {
		margin-inline: 0;
	}

}

/* -------------------------------------------------------------------------
 * Enquiry routes
 *
 * The three ways of writing to YUAN, framed. Stacked on a phone they ran
 * together as one column of text with no telling where one ended; side by side
 * they were three headings adrift in white space. A frame around each makes
 * them countable at a glance, which is the whole job of that section, and the
 * columns block stretches its children to equal height so the boxes line up.
 * ---------------------------------------------------------------------- */

.yuan-enquiries > .wp-block-column {
	padding: var(--wp--preset--spacing--30);
	border: var(--yuan-rule);
}

/* -------------------------------------------------------------------------
 * Reveal on scroll — progressive, and inert when JS or motion is off
 *
 * assets/js/yuan.js finds its own targets by walking the page, so this applies
 * site-wide without a template or a pattern asking for it. Every rule is gated
 * on .js and switched off under reduced motion, so a failed script or a stalled
 * observer can never leave content permanently invisible.
 *
 * Nothing here keys off .yuan-reveal, which content authors write by hand, or
 * off the block style. Those mark what the script should pick up; the class that
 * hides an element is .yuan-revealing, which only the script applies, and only
 * to an element it is at that moment beginning to observe. Hiding therefore
 * cannot outlive the code responsible for undoing it.
 *
 * The distance and the pace are held in custom properties rather than repeated
 * per variant, so a section, a photograph and an eyebrow can differ in how they
 * arrive while sharing one transition.
 * ---------------------------------------------------------------------- */

.js .yuan-revealing {
	--yuan-reveal-shift: 1.25rem;
	--yuan-reveal-scale: 1;
	--yuan-reveal-duration: 0.9s;

	opacity: 0;
	transform: translate3d(0, var(--yuan-reveal-shift), 0) scale(var(--yuan-reveal-scale));
	transition:
		opacity var(--yuan-reveal-duration) var(--yuan-ease),
		transform var(--yuan-reveal-duration) var(--yuan-ease);
	/* Two delays, composed: where the element sits in its grid row, and — on the
	   first screen, which has no scroll to trigger it — where it sits in the
	   order the page reads. */
	transition-delay: calc(var(--yuan-reveal-enter, 0ms) + var(--yuan-reveal-delay, 0ms));
}

/* Landing on none rather than on an identity transform: a transform that stays
   put makes a containing block and can soften text rendering for good. */
.js .yuan-revealing.is-visible {
	opacity: 1;
	transform: none;
}

/*
 * Photographs settle rather than slide: a shorter move over a longer time, with
 * a trace of scale coming off. Reading it as an image coming to rest is the
 * point — a picture that slides in reads as an advertisement.
 */
.js .yuan-revealing:is(
	figure,
	.wp-block-image,
	.wp-block-cover,
	.wp-block-post-featured-image,
	.yuan-gallery__item
) {
	--yuan-reveal-shift: 0.75rem;
	--yuan-reveal-scale: 1.03;
	--yuan-reveal-duration: 1.2s;
}

/* A dozen cards each travelling a full step is a lot of motion at once. */
.js :is(
	.wp-block-post-template,
	.wp-block-gallery,
	.yuan-gallery,
	.yuan-grid
) > .yuan-revealing {
	--yuan-reveal-shift: 1rem;
}

/* Columns arrive from the side they sit on, which suits a spread better than
   four blocks rising in parallel. */
.js .wp-block-columns > .yuan-revealing {
	--yuan-reveal-shift: 0.85rem;
	--yuan-reveal-duration: 1s;
}

/* Set in small caps at micro sizes, a full step of travel reads as a twitch
   rather than as movement. */
.js .yuan-revealing:is(
	.yuan-eyebrow,
	.wp-block-post-terms,
	.wp-block-post-date,
	.wp-block-query-pagination
) {
	--yuan-reveal-shift: 0.4rem;
	--yuan-reveal-duration: 0.7s;
}

/* A rule has no mass to move, so it draws itself in from the left instead —
   the same gesture the navigation underline makes. */
.js .yuan-revealing.wp-block-separator {
	opacity: 1;
	transform: scaleX(0);
	transform-origin: left;
	transition: transform 1s var(--yuan-ease);
}

.js .yuan-revealing.wp-block-separator.is-visible {
	transform: scaleX(1);
}

@media (prefers-reduced-motion: reduce) {
	.js .yuan-revealing,
	.js .yuan-revealing.wp-block-separator {
		opacity: 1;
		transform: none;
	}
}

/* A print stylesheet has no viewport to scroll, so nothing would ever be told
   to appear. */
@media print {
	.js .yuan-revealing,
	.js .yuan-revealing.wp-block-separator {
		opacity: 1 !important;
		transform: none !important;
	}
}
