/*
Theme Name: ZAVEL
Description: The ZAVEL MIRRORS presentation layer. Presentation only: collections, editions, designers and their fields belong to the ZAVEL Core plugin, so this theme can be replaced without touching the content architecture.
Version: 0.1.0
Requires at least: 6.7
Tested up to: 7.0
Requires PHP: 8.1
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: zavel
*/

/* Both web fonts load with `font-display: swap`, so the first paint sets in a
   local face and the swap reflows whatever the difference in advance width
   costs. Each fallback is scaled to the web font's own measure, from a mixed
   sample string rendered at 100 pixels in each family, so the line count before
   the swap is the line count after it. Ported unchanged from the previous
   application, where the ratios were measured.

   These two figures survived the display face changing, and that is the point
   of the `size-adjust` on Source Serif 4 in `theme.json`: it is normalised to
   Newsreader's own advance, so everything downstream that was measured against
   Newsreader, these ratios included, is still measured against the same width. */
@font-face {
	font-family: "Source Serif Iowan";
	font-weight: 100 900;
	src: local("Iowan Old Style");
	size-adjust: 94.5%;
}

@font-face {
	font-family: "Source Serif Times";
	font-weight: 100 900;
	src: local("Times New Roman");
	size-adjust: 105.25%;
}

@font-face {
	font-family: "Manrope Helvetica";
	font-weight: 100 900;
	src: local("Helvetica Neue");
	size-adjust: 102%;
}

@font-face {
	font-family: "Manrope Arial";
	font-weight: 100 900;
	src: local("Arial");
	size-adjust: 102.7%;
}

/* Gallery is the default edition. Nocturne overrides the same custom properties
   below, so every palette entry in theme.json resolves through one token set and
   both editions stay in step by construction rather than by discipline. */
:root {
	--zavel-paper: #f5f1e8;
	--zavel-paper-soft: #faf8f2;
	--zavel-limestone: #e8e0d3;
	--zavel-taupe: #c7bbae;
	/* Clay is the brand's own hand: the drawn geometry and the reasoning beside
	   it. Only the deep step clears AA as text, and the focus ring resolves
	   through it so the ring and clay text can never drift apart. */
	--zavel-clay: #9d5931;
	--zavel-clay-deep: #854011;
	--zavel-focus: var(--zavel-clay-deep);
	--zavel-charcoal: #292825;
	--zavel-charcoal-soft: #45413b;
	--zavel-black: #161513;
	--zavel-ivory: #f8f3e8;
	/* Gold is light: the rays in the study drawing, and the state the system
	   reports or the visitor chose. Nocturne overrides it, because no single
	   value clears the 3:1 graphic floor on cream and stays quiet on near-black.
	   Only the deep step clears AA as text, so a gold label reaches for it the
	   way a clay one reaches for clay-deep. */
	--zavel-gold: #866617;
	--zavel-gold-deep: #654a0e;
	--zavel-logo-day-display: inline;
	--zavel-logo-night-display: none;
	--zavel-film-copy-scrim: rgba(245, 241, 232, 0.88);
	--zavel-film-copy-scrim-clear: rgba(245, 241, 232, 0);
	--zavel-line: rgba(41, 40, 37, 0.18);
	--zavel-surface-muted: #ddd2c3;
	--zavel-surface-interactive: #d9d0c4;
	--zavel-surface-detail: #ded4c5;
	--zavel-button-text: #f8f3e8;
	--zavel-error-text: #8d3f31;
	--zavel-header-height: 6.5rem;
	/* The lockup is the same drawing at the same size scrolled as it is at rest,
	   so the solid bar is the height of the lockup's own box: the artwork sits in
	   it with the air it was drawn with rather than overhanging a shorter bar. */
	--zavel-header-height-solid: calc(var(--zavel-lockup-width) * 164 / 467);
	/* What an in-page destination reserves above itself: the masthead until
	   edition.js has had its first second, because a fragment the browser jumps
	   to before that lands under a bar the script has not yet collapsed, and
	   without scripts never will; the solid height after, when the bar has. */
	--zavel-anchor-reserve: var(--zavel-header-height);
	/* The masthead. The primary lockup's width sets the brand column and the
	   reveal line's height, so the three cannot drift apart. */
	--zavel-lockup-width: 16.5rem;
	--zavel-brand-width: 18.5rem;
	/* The lockup's ink sits below the middle of its own viewBox, so a box
	   centred on the bar reads low. At this size that left 25 pixels of air
	   above the artwork and 11 below it; this raises the artwork rather than the
	   box, and the reveal line rides with it. */
	--zavel-lockup-lift: 0.5rem;
	--zavel-content-max: 100rem;
	/* The page gutter. Below the cap it is the page padding unchanged; above it
	   the surplus goes to the gutter, so a 1920 screen stops laying six cards
	   across 1824 pixels. Percentages resolve against the element's own
	   containing block, which for every user here is the full page width. */
	--zavel-page-inset: max(var(--wp--preset--spacing--page-padding), (100% - var(--zavel-content-max)) / 2);
}

.zavel-header-live {
	--zavel-anchor-reserve: var(--zavel-header-height-solid);
}

[data-theme="nocturne"] {
	--zavel-paper: #171411;
	--zavel-paper-soft: #1f1a16;
	--zavel-limestone: #2d251f;
	--zavel-taupe: #594b40;
	--zavel-clay: #ae6c45;
	--zavel-clay-deep: #d49978;
	--zavel-charcoal: #f3ede3;
	--zavel-charcoal-soft: #c5bbae;
	--zavel-black: #0e0c0a;
	--zavel-ivory: #f8f3e8;
	--zavel-gold: #ac8b42;
	--zavel-gold-deep: #ddbb79;
	--zavel-logo-day-display: none;
	--zavel-logo-night-display: inline;
	--zavel-film-copy-scrim: rgba(14, 12, 10, 0.86);
	--zavel-film-copy-scrim-clear: rgba(14, 12, 10, 0);
	--zavel-line: rgba(248, 243, 232, 0.17);
	--zavel-surface-muted: #29211c;
	--zavel-surface-interactive: #241d18;
	--zavel-surface-detail: #302720;
	--zavel-button-text: #181411;
	--zavel-error-text: #efa693;
}

/* Every measurement ported from the reference was taken against a border-box
   layout, because its build ships a reset and this theme did not. Without this
   line a padded element is its padding wider and taller than the figure it was
   given, and a min-height is the floor of the content rather than of the box:
   the primary button came out 87 pixels tall against a measured 54.4. */
*,
*::before,
*::after {
	box-sizing: border-box;
}

/* The floor is 0.75rem at any viewport, on any route, in either edition. The
   weight and tracking are measured from the reference implementation rather
   than chosen: Manrope at 650 with 0.08em is what a ZAVEL label is. */
.zavel-micro-label {
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.75rem;
	font-weight: 650;
	letter-spacing: 0.08em;
	line-height: 1.55;
	text-transform: uppercase;
}

/* The label tier carries two weights in the reference and only the heavier one
   was ported. A label that is an action or a section eyebrow is 650; a label
   that captions something already on screen is 400, which is what keeps a
   photograph's credit from reading as loudly as the button beside it. */
.zavel-composer-alternatives small,
.zavel-composer-back,
.zavel-composer-progress li,
.zavel-composer-recommendation-grid dt,
.zavel-composer-room-context,
.zavel-composer-saved-resume-label,
.zavel-composer-selection-status,
.zavel-composer-step-kicker,
.zavel-composer-study-figures dt,
.zavel-footer-bottom span,
.zavel-hero-product-label,
.zavel-index-badge small,
.zavel-light-calendar figcaption,
.zavel-light-coordinates label,
.zavel-light-depth label,
.zavel-light-dial-label,
.zavel-light-figure figcaption,
.zavel-light-figures dt,
.zavel-light-hours span,
.zavel-light-legend span,
.zavel-light-months span,
.zavel-light-place > label,
.zavel-light-sizes label,
.zavel-light-time-label,
.zavel-light-when > label,
.zavel-numbered-edition,
.zavel-placement-note,
.zavel-placement-option-number,
.zavel-portrait-caption,
.zavel-provenance,
.zavel-saved-room-study dt,
.zavel-saved-study-alternatives small,
.zavel-saved-study-status,
.zavel-tile-where,
.zavel-wall-choices > label,
.zavel-wall-figures dt,
.zavel-wall-inputs > label,
.zavel-wall-opening label,
.zavel-wall-sizes label {
	font-weight: 400;
}

/* The interactive tier, which the floor permits above itself and which this
   theme already used once, on the represented-designers line. A label that is
   acted on is read before it is pressed, so navigation, buttons, text actions,
   breadcrumbs and the terms of a specification sit at 0.85rem, 13.6 pixels; a
   label that is read from rather than acted on keeps the floor, which is what
   still tells an eyebrow, a caption and an identifier apart from a control.
   The size lives here alone: the rules below carry the family, the weight and
   the tracking of each control and none of them restates a size. */
.zavel-action-label,
.zavel-breadcrumb,
.zavel-button,
.zavel-collection-shelf-heading a,
.zavel-composer-back,
.zavel-composer-goal,
.zavel-composer-room-option,
.zavel-designer-card-cta,
.zavel-designer-represented,
.zavel-light-city,
.zavel-light-day,
.zavel-light-dial-value,
.zavel-light-link,
.zavel-light-time-value,
.zavel-light-where label,
.zavel-nav,
.zavel-row dt,
.zavel-scroll-cue,
.zavel-section-link,
.zavel-text-link,
.zavel-wall-choices select,
.zavel-wall-reference label,
.edition-switch button {
	font-size: 0.85rem;
}

.zavel-secondary-prose {
	font-size: var(--wp--preset--font-size--secondary);
}

/* Structured record surfaces. The terms sit at the label tier and the values at
   the prose tier, which the legibility floor requires even inside one row. */
.zavel-specification,
.zavel-collection-copy,
.zavel-designer {
	margin-top: 2.5rem;
	max-width: 44rem;
}

.zavel-quickfacts,
.zavel-reflection-detail {
	border-top: 1px solid var(--zavel-line);
	margin: 1.5rem 0;
}

.zavel-row {
	border-bottom: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.25rem 1.5rem;
	padding: 0.7rem 0;
}

@media (min-width: 40rem) {
	.zavel-row {
		grid-template-columns: 12rem 1fr;
	}
}

.zavel-row dt {
	color: var(--zavel-charcoal-soft);
}

.zavel-row dd {
	margin: 0;
}

.zavel-reflection,
.zavel-placement {
	margin-top: 3rem;
}

.zavel-ri-code {
	color: var(--zavel-clay);
}

.zavel-reflection-summary,
.zavel-statement {
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.45;
	margin: 0.75rem 0 0;
}

.zavel-quote {
	border-left: 2px solid var(--zavel-clay);
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: var(--wp--preset--font-size--intro);
	line-height: 1.3;
	margin: 2rem 0;
	padding-left: 1.25rem;
}

.zavel-provenance,
.zavel-edition-list {
	list-style: none;
	margin: 1.5rem 0 0;
	padding: 0;
}

.zavel-provenance {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.25rem;
}

.zavel-provenance li {
	color: var(--zavel-charcoal-soft);
}

.zavel-edition-list li {
	border-bottom: 1px solid var(--zavel-line);
	padding: 0.6rem 0;
}

/* Collection hero. The photograph runs edge to edge and the caption sits on it,
   naming the edition and its designer, because the image is of a specific
   mirror rather than a mood. */
.zavel-hero-image {
	position: relative;
}

.zavel-hero-image img {
	aspect-ratio: 16 / 10;
	display: block;
	height: auto;
	object-fit: cover;
	width: 100%;
}

/* The photograph stops short of the viewport, so the eyebrow and the H1 share
   the first screen with it rather than following a full-height image. The
   designer portrait keeps its own proportion beside the copy. */
.zavel-hero:not(.zavel-designer-hero) .zavel-hero-image img {
	max-height: 62svh;
	min-height: 22rem;
}

.zavel-hero-caption {
	background: var(--zavel-paper);
	bottom: 0;
	color: var(--zavel-charcoal);
	left: 0;
	padding: 0.75rem 1.1rem;
	position: absolute;
}

/* The gutter is inside this box, so it is two gutters wider than the 44rem
   record body below it; otherwise the copy sits a gutter further in than the
   notes and the specification. Left-aligned, on the same edge as the body. */
.zavel-hero-copy {
	margin: 0;
	max-width: calc(44rem + 2 * var(--wp--preset--spacing--page-padding));
	padding: clamp(2.5rem, 6vw, 5rem) var(--wp--preset--spacing--page-padding) 0;
}

.zavel-hero-title {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--page-title);
	font-weight: 400;
	letter-spacing: -0.045em;
	line-height: 0.96;
	margin: 0.4rem 0 0;
}

/* An eyebrow tracks wider than the rest of the label tier. Measured from the
   reference, where .eyebrow is 0.16em against 0.07em to 0.08em everywhere else,
   because it sits alone above a display heading rather than in a row of peers. */
.zavel-eyebrow {
	color: var(--zavel-charcoal-soft);
	letter-spacing: 0.16em;
	line-height: 1.3;
	margin: 0;
}

.zavel-hero-copy .zavel-secondary-prose {
	color: var(--zavel-charcoal-soft);
	max-width: 34rem;
}

/* A portrait is not a room. It keeps its own proportion rather than the hero's
   landscape crop, and sits beside the copy on a wide screen. */
@media (min-width: 60rem) {
	.zavel-designer-hero {
		align-items: end;
		display: grid;
		gap: 3rem;
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		padding-right: var(--wp--preset--spacing--page-padding);
	}

	.zavel-designer-hero .zavel-hero-copy {
		margin: 0;
		padding-left: 0;
		padding-bottom: 2rem;
	}
}

.zavel-designer-hero .zavel-hero-image img {
	aspect-ratio: 4 / 5;
}

.zavel-designer-hero .zavel-quote {
	margin-top: 1.5rem;
}

.zavel-designer-process .zavel-notes-copy p {
	font-size: var(--wp--preset--font-size--lead);
}

/* Reflection Index badge */
.zavel-index-badge {
	align-items: center;
	border-top: 1px solid var(--zavel-line);
	display: flex;
	gap: 1rem;
	margin-top: 2.5rem;
	max-width: 22rem;
	padding-top: 1rem;
}

.zavel-index-badge small {
	color: var(--zavel-charcoal-soft);
	display: block;
}

/* Two lines are reserved because the behaviour name is the part that wraps
   differently per card once it is translated: in Bulgarian three of the six
   take a second line and three do not, which moved the badge's rule and its
   mark by exactly one line of this type against the other three. The card
   above already gives its slack to the meta so the six rules agree, and that
   only holds while the badges are one height. */
.zavel-index-badge strong {
	display: block;
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.05rem;
	font-weight: 400;
	min-block-size: 2lh;
}

/* The reference's primary button, including the border that only shows once the
   fill is dropped on hover. Without it the hover state loses the button's
   outline instead of inverting it. */
.zavel-button {
	align-items: center;
	background: var(--zavel-charcoal);
	border: 1px solid var(--zavel-charcoal);
	color: var(--zavel-button-text);
	display: inline-flex;
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 650;
	justify-content: center;
	letter-spacing: 0.08em;
	margin-top: 2rem;
	min-height: 3.4rem;
	padding: 0.95rem 1.5rem;
	text-decoration: none;
	text-transform: uppercase;
	transition: background-color 0.22s, color 0.22s;
}

.zavel-button:hover {
	background: transparent;
	color: var(--zavel-charcoal);
}

.zavel-button:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

/* The record body: the group the three record templates put their sections in,
   on the gallery's left edge at the editor's 44rem measure rather than centred
   on the page. WordPress zeroes a first child's block margin, so the space
   above the opening section is the body's own padding, not the section's. */
.zavel-record-body {
	padding: var(--wp--preset--spacing--section-space) var(--wp--preset--spacing--page-padding);
}

.zavel-record-body > * {
	max-width: 44rem;
}

/* From 70rem the record body composes in two columns. One column left the right
   45 percent of the content width empty for the length of the body: measured at
   1440 before this, a run of 1,953 pixels on the collection page and 1,669 on
   the designer page. The tracks are the edition gallery's, so the rail carries
   on where the purchase panel above it stops and the two columns line up down
   the page. Below 70rem none of this applies and the document order is the
   reading order, which is what the phone layout depends on.

   The page is told apart by the body class WordPress already prints, rather
   than by a modifier the templates would have to carry, so the composition is a
   stylesheet change and the harness can measure it before it costs a deploy. */
@media (min-width: 70rem) {
	.zavel-record-body {
		align-items: start;
		column-gap: 3rem;
		display: grid;
		grid-template-columns: minmax(0, 1.6fr) minmax(20rem, 1fr);
	}

	/* The 44rem measure belonged to the single column. The track sets the width
	   now, and the sentence keeps its own measure through the prose rules. */
	.zavel-record-body > * {
		max-width: none;
	}

	/* A card in this composition is a tile: the photograph over the name rather
	   than beside it, because neither the rail nor a third of a tile row is wide
	   enough to hold both and still print a legible name. */
	.zavel-record-body .zavel-edition-card {
		grid-template-columns: minmax(0, 1fr);
	}

	/* The edition page: the idea and the reflection profile read down the left,
	   the practical details are a specification panel in the rail. It is sticky
	   for the same reason the purchase panel is, that the left column is long
	   and the dimensions should not scroll away from the piece they describe. */
	.single-zavel_edition .zavel-story,
	.single-zavel_edition .zavel-profile {
		grid-column: 1;
	}

	.single-zavel_edition .zavel-practical {
		grid-column: 2;
		grid-row: 1 / span 2;
		margin-top: 0;
		position: sticky;
		top: calc(var(--zavel-header-height) + 1.5rem);
	}

	/* The collection page: the notes on the left, the signature edition beside
	   them. The section around the card is dropped to a `contents` box so the
	   card can take the rail while the continuation stays under the notes,
	   which is where the sentence that names the next collection belongs.

	   The rail is one card wide, so a collection presenting more than one edition
	   takes the row composition at the end of this block instead. */
	.single-zavel_collection .zavel-editions:not(.zavel-editions-row) {
		display: contents;
	}

	/* The rail stops at 26rem here, where the edition page lets it take the whole
	   share, because this one carries a photograph and the track's width is what
	   the photograph has to pay for: an open rail at 1920 puts a 683 pixel box
	   under a portrait crop of a 1672 pixel landscape plate, 1.10 source pixels
	   per CSS pixel at a device ratio of 2. At 26rem it is 1.81, and the width
	   the notes do not need falls to the reading column.

	   The rows: a spanning item hands its extra height to the rows it spans, and
	   the card is taller than the three boxes beside it. A flexible last row
	   takes all of it, so the notes, the continuation and the collection links
	   keep their own spacing instead of drifting apart by whatever the
	   photograph happens to measure. */
	.single-zavel_collection .zavel-record-body {
		grid-template-columns: minmax(0, 1fr) minmax(20rem, 26rem);
		grid-template-rows: min-content min-content 1fr;
	}

	.single-zavel_collection .zavel-notes {
		grid-column: 1;
		grid-row: 1;
	}

	.single-zavel_collection .zavel-editions:not(.zavel-editions-row) > .zavel-edition-card {
		grid-column: 2;
		grid-row: 1 / span 3;
	}

	.single-zavel_collection .zavel-editions:not(.zavel-editions-row) > .zavel-continuation {
		grid-column: 1;
		grid-row: 2;
	}

	.single-zavel_collection .zavel-editions:not(.zavel-editions-row) > .zavel-continuation-links {
		grid-column: 1;
		grid-row: 3;
	}

	/* More than one edition: the rail cannot hold them, so the section keeps its
	   box and becomes a row of tiles under the notes, on the designer page's
	   three tracks and for the same reason, that a pair should read as a row
	   with a gap at its end rather than as two tiles stretched to half the page
	   each. The signature edition leads the row through its eyebrow, its badge
	   and its enquiry link rather than through a place in the composition. */
	.single-zavel_collection .zavel-editions-row {
		column-gap: var(--wp--preset--spacing--page-padding);
		display: grid;
		grid-column: 1 / -1;
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.single-zavel_collection .zavel-editions-row > .zavel-continuation,
	.single-zavel_collection .zavel-editions-row > .zavel-continuation-links {
		grid-column: 1 / -1;
	}

	.single-zavel_collection .zavel-editions-row .zavel-edition-card-image img {
		aspect-ratio: 16 / 9;
	}

	/* The designer page: the process copy keeps the left column and the editions
	   are a row of tiles across the full width under it. Three tracks whatever
	   the count, so a designer with two editions reads as a row with a gap at
	   its end rather than as two tiles stretched to half the page each. */
	.single-zavel_designer .zavel-designer-process {
		grid-column: 1;
	}

	/* No row gap: a second row of tiles is separated by the rule and padding the
	   card already carries, which is what separated them when they were a list. */
	.single-zavel_designer .zavel-editions {
		column-gap: var(--wp--preset--spacing--page-padding);
		display: grid;
		grid-column: 1 / -1;
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	.single-zavel_designer .zavel-editions > .zavel-eyebrow {
		grid-column: 1 / -1;
		margin-bottom: 1.5rem;
	}

	/* Keep a common tile height without cropping taller sources such as TRACE.
	   The complete photograph must survive the desktop cover rule below. */
	.single-zavel_designer .zavel-edition-card-image img {
		aspect-ratio: 16 / 9;
		object-fit: contain;
	}
}

/* Collection notes */
.zavel-notes h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--display);
	font-weight: 400;
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0.4rem 0 0;
}

.zavel-notes-copy {
	border-top: 1px solid var(--zavel-line);
	margin-top: 2.5rem;
	padding-top: 2rem;
}

.zavel-notes-copy p {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.45;
	margin: 0 0 1.25rem;
	max-width: 40rem;
}

/* Editions */
.zavel-editions {
	margin-top: var(--wp--preset--spacing--section-space);
}

/* A card in a row of tiles is stretched to the tallest card's height. Its rows
   are auto, so the spare height would be shared between them and the shorter
   card would carry it inside the photograph's box, dropping its name out of
   line with the name beside it. The spare height belongs under the card. */
.zavel-edition-card {
	align-content: start;
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 1.5rem 2.5rem;
	padding-top: 2rem;
}

@media (min-width: 48rem) {
	.zavel-edition-card {
		grid-template-columns: 1fr 1fr;
	}
}

.zavel-edition-card-image img {
	aspect-ratio: 16 / 9;
	display: block;
	height: auto;
	object-fit: contain;
	width: 100%;
}

/* Small-screen cards keep the full scene; the desktop rail keeps its crop. */
@media (min-width: 70rem) {
	.zavel-edition-card-image img {
		aspect-ratio: 4 / 5;
		object-fit: cover;
	}
}

.zavel-edition-card-copy h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--title);
	font-weight: 400;
	margin: 0.3rem 0 0.5rem;
}

.zavel-edition-card-copy h2 a {
	display: inline-block;
	text-decoration: none;
}

.zavel-continuation {
	color: var(--zavel-charcoal-soft);
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.45;
	margin-top: 3rem;
	max-width: 40rem;
}

/* Edition page. The gallery and the panel sit side by side on a wide screen,
   with the panel sticky, because the gallery is long and the price and lead
   time should not scroll away from the photographs they describe.
   The gallery is placed as two blocks, the room view and the rest, so that on
   a phone the panel follows the first photograph rather than all of them. On
   a wide screen the two blocks stack in the first column with the gallery's
   own gap between them, and the panel spans both rows, so nothing moves. */
.zavel-breadcrumb {
	align-items: center;
	color: var(--zavel-charcoal-soft);
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
	padding: calc(var(--zavel-header-height) + 1.5rem) var(--wp--preset--spacing--page-padding) 1.5rem;
}

/* The collection page's crumb follows a full-bleed hero rather than opening the
   document, so the header reserve the edition page's needs above it would be a
   void here. It sits close under the hero because it belongs to it, and the
   record body's own section space is what separates it from the notes. Scoped
   by the body class WordPress already prints, the way the record composition
   is. */
.single-zavel_collection .zavel-breadcrumb {
	padding-block: 2rem 0;
}

.zavel-breadcrumb a {
	align-items: center;
	display: inline-flex;
	min-block-size: 1.5rem;
	text-decoration: none;
}

.zavel-edition-layout {
	display: grid;
	gap: 2rem;
	padding: 0 var(--wp--preset--spacing--page-padding);
}

@media (min-width: 60rem) {
	.zavel-edition-layout {
		align-items: start;
		gap: 0 3rem;
		grid-template-columns: minmax(0, 1.6fr) minmax(20rem, 1fr);
		grid-template-rows: auto 1fr;
	}

	.zavel-gallery-lead {
		grid-column: 1;
		grid-row: 1;
	}

	/* The margin rather than a row gap, so an edition with one photograph does
	   not end its first column a gap below the room view. */
	.zavel-gallery-rest {
		grid-column: 1;
		grid-row: 2;
		margin-block-start: 1rem;
	}

	.zavel-panel {
		grid-column: 2;
		grid-row: 1 / span 2;
		position: sticky;
		top: calc(var(--zavel-header-height) + 1.5rem);
	}
}

.zavel-gallery {
	display: grid;
	gap: 1rem;
}

@media (min-width: 40rem) {
	.zavel-gallery {
		grid-template-columns: 1fr 1fr;
	}

	.zavel-gallery-figure-room {
		grid-column: 1 / -1;
	}
}

.zavel-gallery-figure {
	margin: 0;
}

.zavel-gallery-figure img {
	display: block;
	height: auto;
	width: 100%;
}

.zavel-gallery-figure-room img {
	aspect-ratio: 16 / 10;
	object-fit: cover;
}

.zavel-gallery-figure figcaption {
	color: var(--zavel-charcoal-soft);
	padding-top: 0.6rem;
}

.zavel-panel-title {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--page-title);
	font-weight: 400;
	letter-spacing: -0.045em;
	line-height: 0.96;
	margin: 0.3rem 0 0.4rem;
}

.zavel-price {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--title);
	margin: 1.25rem 0 0.75rem;
}

/* The designer credit is a link on its own line, so it is a 24 pixel target. */
.zavel-panel .zavel-secondary-prose a {
	align-items: center;
	display: inline-flex;
	min-block-size: 1.5rem;
}

.zavel-profile,
.zavel-practical {
	margin-top: var(--wp--preset--spacing--section-space);
}

.zavel-story h2,
.zavel-profile-heading h2,
.zavel-practical h2,
.zavel-closing h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--display);
	font-weight: 400;
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0.4rem 0 1.5rem;
}

.zavel-story-prose {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.45;
	margin: 0 0 1.25rem;
	max-width: 40rem;
}

.zavel-section-link {
	align-items: center;
	color: var(--zavel-charcoal-soft);
	display: inline-flex;
	margin-top: 0.5rem;
	min-block-size: 1.5rem;
}

/* The Reflection Index gets the large mark and its own layout, because it is
   the system the catalog is organised around rather than another fact. */
.zavel-profile-primary {
	align-items: start;
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 1.5rem 2.5rem;
	padding-top: 2rem;
}

@media (min-width: 40rem) {
	.zavel-profile-primary {
		grid-template-columns: auto 1fr;
	}
}

.zavel-profile-primary h3 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--title);
	font-weight: 400;
	margin: 0.25rem 0 0.75rem;
}

.zavel-profile-summary {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--lead);
	line-height: 1.45;
	margin: 0;
	max-width: 34rem;
}

.zavel-practical h3 {
	color: var(--zavel-charcoal-soft);
	margin: 2rem 0 0.5rem;
}

/* The Reflection Index mark, ported from the reference implementation. The
   frame's border radius is the organic curve the silhouettes are drawn from,
   the axis is the viewing line, and the signal is what the mirror does with
   light. Each behavior restyles the signal rather than redrawing the mark. */
.zavel-glyph {
	--glyph-size: 4.5rem;
	color: currentcolor;
	display: inline-block;
	flex: 0 0 auto;
	height: var(--glyph-size);
	position: relative;
	width: var(--glyph-size);
}

.zavel-glyph-small {
	--glyph-size: 2.35rem;
}

/* The size the mark is drawn at when it leads a section rather than labelling a
   card. Named so a caller asks for a size rather than relying on the default. */
.zavel-glyph-large {
	--glyph-size: clamp(7rem, 12vw, 11rem);
}

.zavel-glyph-frame,
.zavel-glyph-axis,
.zavel-glyph-signal {
	display: block;
	position: absolute;
}

.zavel-glyph-frame {
	border: 1.5px solid;
	border-radius: 47% 53% 56% 44% / 42% 46% 54% 58%;
	inset: 12%;
}

.zavel-glyph-axis {
	background: currentcolor;
	height: 1px;
	left: 17%;
	top: 50%;
	transform: rotate(-35deg);
	transform-origin: 50% center;
	width: 66%;
}

.zavel-glyph-signal {
	border-top: 2px solid var(--zavel-clay);
	left: 2%;
	top: 49%;
	width: 30%;
}

.zavel-glyph-carries-light .zavel-glyph-signal {
	box-shadow: 0 -0.42rem 0 -0.5px var(--zavel-clay), 0 0.42rem 0 -0.5px var(--zavel-clay);
}

.zavel-glyph-opens-threshold .zavel-glyph-frame {
	border-radius: 48% 48% 3% 3% / 34% 34% 3% 3%;
	inset: 7% 24%;
}

.zavel-glyph-opens-threshold .zavel-glyph-axis {
	left: 26%;
	top: 52%;
	transform: rotate(-52deg);
	width: 50%;
}

.zavel-glyph-opens-threshold .zavel-glyph-signal {
	border-left: 2px solid var(--zavel-clay);
	border-top: 0;
	height: 78%;
	left: 49%;
	top: 10%;
	width: 0;
}

.zavel-glyph-creates-focal-point .zavel-glyph-frame {
	border-radius: 50%;
	inset: 13%;
}

.zavel-glyph-creates-focal-point .zavel-glyph-signal {
	border: 2px solid var(--zavel-clay);
	border-radius: 50%;
	height: 31%;
	inset: 34.5%;
	width: 31%;
}

.zavel-glyph-softens-architecture .zavel-glyph-frame {
	border-radius: 66% 34% 62% 38% / 38% 61% 39% 62%;
	inset: 8% 20%;
}

.zavel-glyph-softens-architecture .zavel-glyph-axis {
	transform: rotate(-24deg);
}

.zavel-glyph-softens-architecture .zavel-glyph-signal {
	border-left: 0;
	border-radius: 0 100% 100% 0;
	height: 45%;
	left: 52%;
	top: 27%;
	width: 25%;
}

.zavel-glyph-adds-material-weight .zavel-glyph-frame {
	border-bottom-width: 5px;
	border-radius: 43% 57% 49% 51% / 45% 40% 60% 55%;
	border-right-width: 4px;
}

.zavel-glyph-adds-material-weight .zavel-glyph-signal {
	border-bottom: 2px solid var(--zavel-clay);
	border-top: 0;
	bottom: 9%;
	left: 25%;
	top: auto;
	width: 62%;
}

/* Site header. Fixed and transparent over a hero, solid once the hero is nearly
   past, which is why templates without a hero add their own top padding rather
   than the header reserving space it does not always need. Over a hero it is a
   masthead, taller by the air above and below the lockup; the lockup itself and
   the brand column are the same in both states, so nothing beside it moves.

   The height between those two states is animated, so containment keeps the
   frames it costs inside this subtree instead of leaving the engine to prove
   each one changes nothing further down. */
.zavel-header {
	align-items: center;
	background: none;
	color: var(--zavel-charcoal);
	contain: layout;
	display: grid;
	grid-template-columns: var(--zavel-brand-width) 1fr auto auto;
	height: var(--zavel-header-height);
	left: 0;
	padding: 0 var(--zavel-page-inset);
	position: fixed;
	right: 0;
	top: 0;
	transition: background-color 0.24s, height 0.24s, box-shadow 0.24s;
	z-index: 100;
}

/* The veil is drawn on a layer taller than the bar rather than as the bar's own
   background, because bound to that height the fade is half gone by the row
   that carries the ink, and a room photographed behind it is not reliably
   darker, or lighter, than the ink up there. */
.zavel-header::before {
	background: linear-gradient(to bottom, rgba(245, 241, 232, 0.92), rgba(245, 241, 232, 0));
	content: "";
	height: 210%;
	left: 0;
	pointer-events: none;
	position: absolute;
	right: 0;
	top: 0;
	transition: opacity 0.24s;
	z-index: -1;
}

/* Nocturne's veil is a deeper black than its own paper, for the same reason its
   ground is: the wordmark reads against the photograph, not against the page. */
[data-theme="nocturne"] .zavel-header::before {
	background: linear-gradient(to bottom, rgba(17, 14, 12, 0.92), rgba(17, 14, 12, 0));
}

/* The header is fixed, so every in-page destination has to reserve its height or
   the jump parks the section's heading underneath it. Measured before this
   existed: #collections landed flush at the viewport top and the whole "Shop by
   collection" line sat behind the header. */
#collections,
#editions,
#designer {
	scroll-margin-top: var(--zavel-anchor-reserve);
}

/* The band's three groups begin at their eyebrow rather than at a padding of
   their own, so the reserve alone lands the eyebrow flush against the header
   and the group opens with no air above it. */
#reflection-index,
#silhouettes,
#rooms {
	scroll-margin-top: calc(var(--zavel-anchor-reserve) + 2rem);
}

/* The group is a block, so its children carry the editor's flow margin into the
   grid and every cell but the first lands below centre. */
.zavel-header > *,
.zavel-mobile-panel > * {
	margin-block-start: 0;
}

/* A template with no hero opens solid, which is the scrolled treatment without
   the scroll. The alpha is what the blur behind it is for. */
.zavel-header.is-scrolled,
.zavel-no-hero .zavel-header {
	backdrop-filter: blur(12px);
	background: rgba(245, 241, 232, 0.96);
	box-shadow: 0 1px 0 var(--zavel-line);
	height: var(--zavel-header-height-solid);
}

[data-theme="nocturne"] .zavel-header.is-scrolled,
[data-theme="nocturne"] .zavel-no-hero .zavel-header {
	background: rgba(23, 20, 17, 0.96);
}

/* A solid bar owns its own ground, so the veil fades out rather than sitting on
   top of it and thickening the state it was never for. */
.zavel-header.is-scrolled::before,
.zavel-no-hero .zavel-header::before {
	opacity: 0;
}

/* A full-bleed hero starts at the top of the viewport, under the fixed header,
   rather than below the editor's flow margin. */
.zavel-has-hero main {
	margin-block-start: 0;
}

/* WordPress pushes the document down for the admin bar but not a fixed element,
   so above this width the bar covered the top 32 pixels of the header for every
   signed-in editor. Below it the bar is absolute and scrolls away by itself. */
@media (min-width: 783px) {
	.admin-bar .zavel-header {
		top: 32px;
	}
}

/* The lockup symbols, printed once at the top of the body by functions.php and
   drawn wherever a `use` points at one. Kept out of the layout rather than
   display:none, so no browser is asked whether an undisplayed symbol renders. */
.zavel-lockups {
	height: 0;
	overflow: hidden;
	position: absolute;
	width: 0;
}

/* The arrival. Once per session, the lockup is uncovered left to right behind a
   hairline the height of the primary lockup, and the line leaves as the last
   stroke appears; the artwork itself never moves. The head's bootstrap marks a
   session that has already arrived, so a second page or a reload draws the
   composition at rest, and reduced motion is that state from the start. Only
   the start state is held, so once the animation ends no clip is left on the
   box. */
.zavel-brand {
	align-items: center;
	animation: zavel-arrival 640ms cubic-bezier(0.2, 0.7, 0.2, 1) 120ms backwards;
	display: flex;
	height: 100%;
	position: relative;
	width: var(--zavel-brand-width);
}

/* One lockup, the same drawing at the same size whatever the bar is doing: the
   emblem stays with the wordmark once the page is scrolled and on a template
   with no hero, so nothing about the signature changes as the reader moves. */
.zavel-logo {
	height: auto;
	left: 0;
	overflow: visible;
	position: absolute;
}

.zavel-logo-primary {
	transform: translateY(calc(0px - var(--zavel-lockup-lift)));
	width: var(--zavel-lockup-width);
}

.zavel-brand:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-brand::after {
	animation: zavel-arrival-line 640ms cubic-bezier(0.2, 0.7, 0.2, 1) 120ms both;
	background: currentcolor;
	content: "";
	height: calc(var(--zavel-lockup-width) * 164 / 467);
	left: 0;
	pointer-events: none;
	position: absolute;
	top: calc(50% - var(--zavel-lockup-lift));
	width: 1px;
}

.zavel-arrived .zavel-brand {
	animation: none;
}

.zavel-arrived .zavel-brand::after {
	content: none;
}

@keyframes zavel-arrival {
	from {
		clip-path: inset(0 100% 0 0);
		opacity: 0;
	}

	35% {
		opacity: 1;
	}

	to {
		clip-path: inset(0 0 0 0);
		opacity: 1;
	}
}

@keyframes zavel-arrival-line {
	from {
		opacity: 0.55;
		transform: translate(0, -50%);
	}

	80% {
		opacity: 0.55;
	}

	to {
		opacity: 0;
		transform: translate(var(--zavel-brand-width), -50%);
	}
}

/* Any sync in the first second after load, in edition.js: a page opened at a
   fragment lands already scrolled, and the header takes that state at once. */
.zavel-header.is-snapping {
	transition: none;
}

/* The header's motion is a change of state, not a decoration, but a reader who
   asked for less of it gets each state without the passage between them. */
@media (prefers-reduced-motion: reduce) {
	.zavel-header,
	.zavel-nav a::after,
	.zavel-menu-toggle span,
	.zavel-mobile-panel {
		transition: none;
	}

	.zavel-brand {
		animation: none;
	}

	.zavel-brand::after {
		content: none;
	}
}

/* The navigation is a block, so its list is what carries the layout and the
   theme only supplies the type. */
.zavel-nav,
.zavel-mobile-nav {
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 650;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.zavel-nav {
	align-items: center;
	display: flex;
	justify-content: center;
}

.zavel-nav ul {
	align-items: center;
	display: flex;
	gap: clamp(0.85rem, 1.35vw, 1.55rem);
	list-style: none;
	margin: 0;
	padding: 0;
}

.zavel-nav a {
	padding: 0.75rem 0;
	position: relative;
	text-decoration: none;
}

/* The underline grows from the leading edge on hover and retracts to the
   trailing one, which is the reference's own transition rather than a fade. */
.zavel-nav a::after {
	background: currentcolor;
	bottom: 0.4rem;
	content: "";
	height: 1px;
	left: 0;
	position: absolute;
	transform: scaleX(0);
	transform-origin: 100% center;
	transition: transform 0.22s;
	width: 100%;
}

.zavel-nav a:hover::after,
.zavel-nav a:focus-visible::after {
	transform: scaleX(1);
	transform-origin: 0 center;
}

.zavel-nav a:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

/* Mobile navigation. The colour is restated because a button takes the user
   agent's buttontext rather than the header's, which left the bars black on
   Nocturne's near-black bar and so invisible. */
.zavel-menu-toggle {
	align-items: center;
	background: none;
	border: 0;
	color: inherit;
	cursor: pointer;
	display: none;
	flex-direction: column;
	font: inherit;
	gap: 6px;
	justify-content: center;
	justify-self: end;
	min-height: 2.8rem;
	min-width: 2.8rem;
	padding: 0;
	position: relative;
	z-index: 2;
}

.zavel-menu-toggle span {
	background: currentcolor;
	height: 1px;
	transition: transform 0.22s;
	width: 1.5rem;
}

/* Half the gap plus half a bar, so the two bars meet on the box's centre line. */
.zavel-menu-toggle[aria-expanded="true"] span:first-child {
	transform: translateY(3.5px) rotate(45deg);
}

.zavel-menu-toggle[aria-expanded="true"] span:last-child {
	transform: translateY(-3.5px) rotate(-45deg);
}

.zavel-menu-toggle:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 2px;
}

/* The panel covers the whole viewport and the header floats over it, so the
   brand and the toggle stay put while it opens. It is display:none above the
   breakpoint and hidden rather than removed below it, because visibility takes
   it out of the accessibility tree and still allows the fade. */
.zavel-mobile-panel {
	background: var(--zavel-paper);
	display: none;
	left: 0;
	min-height: 100svh;
	opacity: 0;
	padding: 7rem var(--wp--preset--spacing--page-padding) 3rem;
	pointer-events: none;
	overflow-y: auto;
	position: fixed;
	right: 0;
	top: 0;
	transform: translateY(-1rem);
	transition: opacity 0.22s, transform 0.22s;
	visibility: hidden;
	z-index: 99;
}

.zavel-mobile-panel.is-open {
	opacity: 1;
	pointer-events: auto;
	transform: translateY(0);
	visibility: visible;
}

.zavel-mobile-panel > .edition-switch {
	margin: 0 0 2.5rem;
}

.zavel-mobile-nav ul {
	align-items: stretch;
	flex-direction: column;
	gap: 0;
}

/* The panel's own items are a serif menu rather than the label tier the closed
   header uses, so every property the wrapper sets for the label tier has to be
   unset here. The figures are the reference's: untracked, sentence case, and
   sized off the viewport so a phone and a small tablet both fill the column.
   flex, because the block's list item is a flex container and the anchor would
   otherwise be as wide as its own word, leaving a ragged stack of rules. */
.zavel-mobile-nav a {
	border-bottom: 1px solid var(--zavel-line);
	flex: 1;
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(2.5rem, 10vw, 4.5rem);
	font-weight: 400;
	letter-spacing: normal;
	line-height: 1;
	padding: 0.7rem 0;
	text-decoration: none;
	text-transform: none;
}

@media (max-width: 70rem) {
	:root {
		--zavel-header-height: 6rem;
		/* The bar carries the list on one line from 1024 pixels up, which is where the
		   phone composition below now takes over, and this size is what that
		   figure was measured against. */
		--zavel-lockup-width: 11rem;
		--zavel-brand-width: 12.25rem;
		--zavel-lockup-lift: 0.35rem;
	}

	.zavel-nav ul {
		gap: 1.2rem;
	}
}

/* The band where the bar carries the language switch and has to be asked to.
   `WP-35` left the list setting on one line at 1024 with 34 pixels to spare and
   said that the next thing added to the bar would spend them; the switch costs
   46.4 including its air, so this is that bill.

   From 1056 pixels down the list's gap returns to the site's floor. The
   edition orbit retains its full targets at every width. */
@media (max-width: 66rem) {
	.zavel-nav ul {
		gap: 0.85rem;
	}
}

/* Where the bar hands its navigation to the panel. The
   boundary is where the bar's own contents stop fitting rather than where a
   phone begins: the brand column is 196 pixels, the list 527, the switch 191
   and the two page insets 3vw each, which needs 990 pixels of window and had
   been asked to work in 900. Below that the list wrapped to a second line and
   grew the bar to 109 pixels inside a 96 pixel one, measured on the live site
   between 900 and 970.

   It sat at 56.25rem because the reference implementation's bar sets on one
   line there, and that stayed true here until the list grew: `Guided
   consultation` is 176 pixels where the reference's `Journal` is 61, and the
   label tier rose a step in the same week. The reference's list is 377 wide
   and this one is 527, so the figure it came with could not come with it.

   Anything added to the list, or any lockup wider than 11rem, moves this
   number again: measured at the narrowest window that now takes the bar, on a
   desktop scrollbar, the list sets on one line with 34 pixels to spare. */
@media (max-width: 63.99rem) {
	.zavel-header {
		display: flex;
		gap: 0.5rem;
	}

	.zavel-header .zavel-nav,
	.zavel-mobile-panel > .zavel-language-switch-panel,
	.zavel-mobile-panel > .edition-switch {
		display: none;
	}

	.zavel-header .zavel-brand {
		flex: 1 1 var(--zavel-brand-width);
		margin-right: auto;
		max-width: var(--zavel-brand-width);
		min-width: 0;
	}

	.zavel-header .zavel-logo {
		max-width: 100%;
	}

	.zavel-header .zavel-switch-desktop {
		flex-shrink: 0;
	}

	.zavel-header .zavel-switch-desktop button {
		min-height: 2.75rem;
		min-width: 2.75rem;
	}

	/* The button owns its full touch area here, including beside the menu. */
	.zavel-header .zavel-switch-desktop button::before {
		content: none;
	}

	/* The bar returns to its masthead height over an open panel, whatever the
	   scroll, so the navigation opens against the composition it was drawn in. */
	.zavel-header.is-menu-open {
		height: var(--zavel-header-height);
	}

	.zavel-menu-toggle {
		display: flex;
	}

	.zavel-mobile-panel {
		display: block;
	}
}

/* The bar's own scale, which is a separate question from what it carries and
   stays where the hero copy starts meeting it. */
@media (max-width: 56.25rem) {
	:root {
		--zavel-header-height: 5rem;
		--zavel-lockup-width: 11.5rem;
		--zavel-brand-width: 12rem;
	}

	/* The gradient reads as a veil only over a hero that is taller than it, and
	   below this width the copy comes up to meet the bar, so it goes opaque.
	   Scoped to the hero templates so the solid rules above still own the rest. */
	.zavel-has-hero .zavel-header {
		backdrop-filter: blur(10px);
		background: rgba(245, 241, 232, 0.88);
	}

	.zavel-has-hero .zavel-header::before {
		opacity: 0;
	}

	[data-theme="nocturne"] .zavel-has-hero .zavel-header {
		background: rgba(23, 20, 17, 0.9);
	}
}

/* Templates that do not open with a full-bleed image need the header's height
   back, because the header is fixed and sits outside the flow. The editor's
   block gap rides above main as well, and under a solid header it drew a band
   of the body's paper between the bar and the section's own ground: measured
   at 1440 on the designers index, 24 pixels of it. The reserve is the header's
   height and nothing else. */
.zavel-no-hero main {
	margin-block-start: 0;
	padding-top: var(--zavel-header-height-solid);
}

/* The fallback template answers search, 404 and an empty archive. It runs on the
   page gutter the way the designers archive does rather than in the editor's
   centred 44rem column, which is a measure nothing else on the site is set in.
   The state carries the space below it, the way every other last section on the
   site does, rather than borrowing a margin from the footer. */
.zavel-fallback-main .wp-block-query {
	padding: 0 var(--zavel-page-inset);
}

.zavel-empty-state {
	max-width: 58rem;
	padding: clamp(5rem, 9vw, 8rem) 0 var(--wp--preset--spacing--section-space);
}

.zavel-empty-state h1 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(3.4rem, 6vw, 6.2rem);
	font-weight: 400;
	letter-spacing: -0.045em;
	line-height: 0.96;
	margin: 1rem 0 1.5rem;
}

.zavel-empty-state .zavel-text-link {
	margin-top: 2.25rem;
}

/* A route whose content is shorter than the viewport, which search and 404 both
   are, would otherwise leave the footer floating mid-page. The header is fixed
   and so out of flow, which is why only main has to grow. svh rather than dvh,
   the way the hero and the mobile panel are measured, so a retracting phone
   toolbar cannot grow the page past the screen it was fitted to. */
.wp-site-blocks {
	display: flex;
	flex-direction: column;
	min-height: 100svh;
}

.wp-site-blocks > main {
	flex: 1 0 auto;
}

/* Footer. The space above it is the last section's own bottom padding, which is
   the section rhythm every other boundary on the page runs on. A margin here as
   well put a band of paper between the numbered photograph and the footer's
   rule that belonged to neither: measured at 1440, 86 pixels of it after a
   full-bleed section that ends at its own edge. */
.wp-site-blocks > footer {
	margin-block-start: 0;
}

.zavel-footer {
	background: var(--zavel-limestone);
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 3rem;
	margin-top: 0;
	padding: clamp(3rem, 5vw, 5rem) var(--zavel-page-inset) 2rem;
}

.zavel-footer > * {
	margin-block: 0;
}

/* The footer draws the full lockup once, at the masthead's size, as the closing
   signature: it has its own pair of classes rather than the header's, whose
   absolute positioning exists only to stack two lockups in one box. overflow is
   visible for the header's reason: the L overhangs its own viewBox. */
.zavel-footer-brand-link {
	display: inline-block;
}

.zavel-footer-brand-link:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-footer-logo {
	display: block;
	height: auto;
	margin-bottom: 0;
	overflow: visible;
	width: var(--zavel-lockup-width);
}

@media (min-width: 64rem) {
	.zavel-footer {
		align-items: start;
		column-gap: clamp(3rem, 5vw, 6rem);
		grid-template-columns: minmax(0, 1fr) minmax(35rem, 1.15fr);
	}

	.zavel-footer-bottom {
		grid-column: 1 / -1;
	}
}

.zavel-footer-brand p {
	color: var(--zavel-charcoal-soft);
	font-size: 1rem;
	line-height: 1.7;
	margin: 1.25rem 0 0;
	max-width: 30ch;
}

.zavel-footer-nav ul {
	display: flex;
	flex-wrap: wrap;
	gap: 1.25rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.zavel-footer-nav a {
	font-size: var(--wp--preset--font-size--secondary);
	text-decoration: none;
}

.zavel-footer-bottom {
	align-items: center;
	border-top: 1px solid var(--zavel-line);
	color: var(--zavel-charcoal-soft);
	display: flex;
	flex-wrap: wrap;
	gap: 1rem;
	justify-content: space-between;
	padding-top: 1.5rem;
}

.zavel-footer-bottom a {
	text-decoration: none;
}

/* The chosen light rests at the left end of the ellipse. Only a deliberate
   selection changes the edition and moves the controls; the orbit has no timer. */
.edition-switch {
	display: inline-block;
	height: 62px;
	position: relative;
	width: 120px;
}

.zavel-edition-orbit {
	fill: none;
	height: 100%;
	left: 0;
	opacity: 0.3;
	pointer-events: none;
	position: absolute;
	stroke: currentcolor;
	stroke-width: 0.75;
	top: 0;
	width: 100%;
}

.edition-switch button {
	background: none;
	border: 0;
	border-radius: 999px;
	color: inherit;
	cursor: pointer;
	display: grid;
	font-family: var(--wp--preset--font-family--sans);
	height: 44px;
	left: 74px;
	padding: 0;
	place-items: center;
	position: absolute;
	top: 2px;
	width: 44px;
}

.edition-switch button[aria-pressed="true"] {
	left: 2px;
	top: 16px;
}

.zavel-edition-glyph {
	background: var(--zavel-paper);
	border-radius: 50%;
	display: block;
	height: 32px;
	transform: scale(0.76);
	transition: transform 0.5s ease;
	width: 32px;
}

.zavel-edition-glyph svg {
	animation: zavel-edition-breathe 3.2s ease-in-out infinite;
	display: block;
	fill: none;
	height: 100%;
	stroke: currentcolor;
	stroke-linecap: round;
	stroke-linejoin: round;
	stroke-width: 1.5;
	transform-origin: center;
	width: 100%;
}

.edition-switch button[data-edition="nocturne"] .zavel-edition-glyph svg {
	animation-delay: -1.1s;
	animation-duration: 4.4s;
}

@keyframes zavel-edition-breathe {
	0%, 100% { transform: scale(0.9); }
	50% { transform: scale(1.06); }
}

.edition-switch button[aria-pressed="true"] .zavel-edition-glyph {
	transform: scale(1);
}

.edition-switch button[aria-pressed="true"]::after {
	background: currentcolor;
	border-radius: 50%;
	bottom: 0;
	content: "";
	height: 3px;
	left: calc(50% - 1.5px);
	position: absolute;
	width: 3px;
}

@supports (offset-path: path("M0 0L1 1")) {
	.edition-switch button,
	.edition-switch button[aria-pressed="true"] {
		left: 0;
		offset-anchor: 50% 50%;
		offset-distance: 0%;
		offset-path: path("M96 24 C100 30 87 39 67 43 C47 47 28 44 24 38 C20 32 33 23 53 19 C73 15 92 18 96 24Z");
		offset-rotate: 0deg;
		top: 0;
		transition: offset-distance 0.7s cubic-bezier(0.4, 0, 0.2, 1);
	}

	.edition-switch button[data-edition="gallery"],
	[data-theme="nocturne"] .edition-switch button[data-edition="nocturne"] {
		offset-distance: 50%;
	}

	[data-theme="nocturne"] .edition-switch button[data-edition="gallery"] {
		offset-distance: 100%;
	}
}

@media (prefers-reduced-motion: reduce) {
	.zavel-edition-glyph svg {
		animation: none;
	}

	.edition-switch button,
	.edition-switch button[aria-pressed="true"],
	.zavel-edition-glyph {
		transition: none;
	}
}

.edition-switch button:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 2px;
}

/* The language switch, which is a link and is drawn as one. The edition beside
   it is a preference this device keeps, so it uses buttons; a language
   is another address, so this is bare text at the label tier and the two do not
   read as the same control.

   The margins are the whole design decision. `БГ` is 18.3 pixels wide at this
   tier, and the box is 24 because that is the target-size floor, so the switch
   costs the bar 46.4 pixels including the air on either side of it. That air is
   what stops it reading as a fifth navigation item. */
.zavel-language-switch {
	align-items: center;
	display: inline-flex;
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 650;
	letter-spacing: 0.08em;
	margin: 0 0.7rem;
	text-transform: uppercase;
}

.zavel-language-switch a {
	align-items: center;
	color: inherit;
	display: inline-flex;
	font-size: 0.85rem;
	justify-content: center;
	line-height: 1;
	min-height: 1.5rem;
	min-width: 1.5rem;
	text-decoration: none;
	text-underline-offset: 0.3em;
}

.zavel-language-switch a:hover {
	text-decoration: underline;
}

.zavel-language-switch a:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 2px;
}

/* In the panel it is a row of its own above the edition switch, which is the
   same order the bar reads in. */
.zavel-language-switch-panel {
	display: flex;
	margin: 0 0 1.25rem;
}

@media (max-width: 63.99rem) {
	.zavel-header .zavel-language-switch-bar {
		flex-shrink: 0;
		margin: 0;
	}

	.zavel-header .zavel-language-switch-bar a {
		min-height: 2.75rem;
		min-width: 2.75rem;
	}
}

/* The language and menu share one column on narrow phones so the wordmark and
   the orbit can retain their readable size and full touch targets. */
@media (max-width: 28rem) {
	html:root[data-zavel-design] {
		--zavel-header-height: 6rem;
		--zavel-header-height-solid: 6rem;
	}

	.zavel-header {
		display: grid;
		grid-template-columns: minmax(0, 1fr) 7.5rem 2.75rem;
		grid-template-rows: repeat(2, 2.75rem);
		column-gap: 0.25rem;
		row-gap: 0.125rem;
		padding-inline: 0.75rem;
		align-content: center;
	}

	.zavel-header .zavel-brand {
		grid-area: 1 / 1 / 3 / 2;
		width: 100%;
	}

	.zavel-header .zavel-switch-desktop { grid-area: 1 / 2 / 3 / 3; }
	.zavel-header .zavel-language-switch-bar { grid-area: 1 / 3; }
	.zavel-header .zavel-menu-toggle { grid-area: 2 / 3; }
}

/* ============================================================================
   The homepage.

   Ported from the reference implementation by reading its computed styles and
   its own rules rather than by describing them, so the clamps, ratios and
   breakpoints below are the reference's own figures expressed against this
   theme's tokens. Its breakpoints are 1120, 900 and 680 pixels, which are
   70rem, 56.25rem and 42.5rem here.
   ============================================================================ */

/* The whole photograph sits below the fixed masthead. Copy shares its row on
   wide screens, and the credit has its own row so neither clips the mirror. */
.zavel-home-hero {
	background: var(--zavel-limestone);
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	overflow: hidden;
	padding-top: var(--zavel-header-height);
	position: relative;
}

.zavel-home-hero-media {
	align-self: center;
	display: grid;
	grid-area: 1 / 1;
	min-width: 0;
}

.zavel-home-hero-media .zavel-hero-variant {
	grid-area: 1 / 1;
	inset: auto;
	min-width: 0;
	position: relative;
}

.zavel-home-hero-media .zavel-hero-photo {
	--zavel-hero-painted-width: min(100%, calc(max(16rem, 90svh - var(--zavel-header-height) - 6rem) * var(--zavel-hero-aspect, 1.77778)));
	display: block;
	height: auto;
	max-height: max(16rem, calc(90svh - var(--zavel-header-height) - 6rem));
	object-fit: contain;
	object-position: right center;
	position: static;
	width: 100%;
}

/* Follow the fitted photograph's edge, which can be far inside a wide screen.
   The feather ends before either mirror; the remaining source stays opaque. */
.zavel-home-hero-media .zavel-hero-photo {
	-webkit-mask-image: linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, 0.1) 7%, rgba(0, 0, 0, 0.35) 14%, rgba(0, 0, 0, 0.65) 21%, rgba(0, 0, 0, 0.9) 28%, #000 35%);
	mask-image: linear-gradient(90deg, transparent 0%, rgba(0, 0, 0, 0.1) 7%, rgba(0, 0, 0, 0.35) 14%, rgba(0, 0, 0, 0.65) 21%, rgba(0, 0, 0, 0.9) 28%, #000 35%);
	-webkit-mask-position: right center;
	mask-position: right center;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-size: var(--zavel-hero-painted-width) 100%;
	mask-size: var(--zavel-hero-painted-width) 100%;
}

.zavel-home-hero .zavel-hero-content {
	align-self: center;
	grid-area: 1 / 1;
	inset: auto;
	margin: 2rem 0 2rem var(--zavel-page-inset);
	position: relative;
}

.zavel-home-hero .zavel-hero-product-label {
	grid-area: 2 / 1;
	inset: auto;
	justify-self: end;
	margin: 1rem var(--zavel-page-inset) 1.5rem;
	max-width: calc(100% - 2 * var(--zavel-page-inset));
	position: static;
}

.zavel-home-hero .zavel-scroll-cue {
	align-self: center;
	grid-area: 2 / 1;
	inset: auto;
	justify-self: start;
	margin: 1rem var(--zavel-page-inset) 1.5rem;
	position: static;
}

/* At tablet widths the copy needs the mirror's space, so it follows the image. */
@media (max-width: 68.75rem) {
	.zavel-home-hero .zavel-hero-content {
		grid-area: 2 / 1;
		margin: 1.25rem var(--wp--preset--spacing--page-padding) 0;
		max-width: none;
		width: auto;
	}

	.zavel-home-hero-media .zavel-hero-photo {
		max-height: none;
		-webkit-mask-image: none;
		mask-image: none;
	}

	.zavel-home-hero-media .zavel-hero-wash {
		display: none;
	}

	.zavel-home-hero .zavel-hero-product-label {
		grid-area: 3 / 1;
		justify-self: start;
		margin: 1rem var(--wp--preset--spacing--page-padding);
		text-align: left;
	}

	.zavel-home-hero .zavel-scroll-cue {
		display: none;
	}
}

/* Crop only the room's sides on a phone. These positions retain the complete
   padded mirror bounds in both source frames; home-hero.spec.ts projects them. */
@media (max-width: 37.5rem) {
	.zavel-home-hero-media .zavel-hero-photo {
		aspect-ratio: 1 / 1;
		object-fit: cover;
		object-position: 62% center;
	}
}

.zavel-hero-variant {
	inset: 0;
	position: absolute;
	transition: opacity 0.44s, visibility 0.44s;
}

/* Both variants are in the document so the switch is a paint rather than a
   fetch, and the one not showing leaves the accessibility tree and the tab
   order rather than merely turning transparent. The rules are scoped to the
   dual class: an edition with no night photograph renders one variant, and
   hiding it in Nocturne would leave an empty hero. */
.zavel-home-hero-dual .zavel-hero-variant-nocturne,
[data-theme="nocturne"] .zavel-home-hero-dual .zavel-hero-variant-gallery {
	opacity: 0;
	pointer-events: none;
	visibility: hidden;
}

.zavel-home-hero-dual .zavel-hero-variant-gallery,
[data-theme="nocturne"] .zavel-home-hero-dual .zavel-hero-variant-nocturne {
	opacity: 1;
	pointer-events: auto;
	visibility: visible;
}

/* The homepage film. Scenes, each an edition in its room, that dissolve into
   one another on a timer, every plate settling from a slow zoom and every
   scene's copy drifting into place; film.js keeps the timer. The film takes
   the edition's own photographs and tokens, so Gallery opens on daylight and
   Nocturne on the night frames, and it sits in the page at the hero's height:
   the page scrolls as a page. On a session's first arrival the first plate
   comes up from the section's own ground. */
.zavel-film {
	background: var(--zavel-limestone);
	height: 74svh;
	max-height: 54rem;
	min-height: 40rem;
	overflow: hidden;
	position: relative;
}

.zavel-film-stage {
	height: 100%;
	position: relative;
}

.zavel-film-scene {
	inset: 0;
	opacity: 0;
	position: absolute;
	transition: opacity 1s ease, visibility 0s 1s;
	visibility: hidden;
}

.zavel-film-scene.is-current {
	opacity: 1;
	transition: opacity 1s ease;
	visibility: visible;
	z-index: 1;
}

.zavel-film-plate {
	inset: 0;
	overflow: hidden;
	position: absolute;
}

.zavel-film-plate-form {
	background: #d8d0c4;
}

.zavel-film-plate-light {
	background: #80654a;
}

.zavel-film-plate-reflection {
	background: #4c3d31;
}

.zavel-film-plate::after {
	background: linear-gradient(90deg, rgba(239, 233, 223, 0.95) 0%, rgba(239, 233, 223, 0.65) 25%, rgba(0, 0, 0, 0) 58%);
	content: "";
	inset: 0;
	pointer-events: none;
	position: absolute;
}

.zavel-film-plate-nocturne::after {
	background:
		radial-gradient(circle at 67% 39%, rgba(187, 151, 93, 0.08), rgba(0, 0, 0, 0) 25%),
		linear-gradient(90deg, rgba(14, 12, 10, 0.52) 0%, rgba(14, 12, 10, 0.2) 39%, rgba(14, 12, 10, 0.03) 70%);
}

.zavel-film-picture,
.zavel-film-photo {
	display: block;
	height: 100%;
	width: 100%;
}

.zavel-film-photo {
	object-fit: contain;
	object-position: right center;
	transform: scale(0.965);
	transform-origin: right center;
	will-change: transform;
}

.zavel-film-scene.is-current .zavel-film-photo {
	animation: zavel-film-settle 7s cubic-bezier(0.25, 0.5, 0.2, 1) both;
}

.zavel-film-copy {
	bottom: clamp(5rem, 10vh, 7.5rem);
	left: var(--zavel-page-inset);
	max-width: min(clamp(30rem, 33.3vw, 36.2rem), 42vw);
	position: absolute;
	z-index: 2;
}

.zavel-film-scene.is-current .zavel-film-copy {
	animation: zavel-film-copy 800ms cubic-bezier(0.2, 0.7, 0.2, 1) 350ms both;
}

:root:not(.zavel-arrived) .zavel-film-scene[data-scene="0"].is-current .zavel-film-plate {
	animation: zavel-film-open 1200ms ease-out 300ms both;
}

:root:not(.zavel-arrived) .zavel-film-scene[data-scene="0"].is-current .zavel-film-copy {
	animation-delay: 800ms;
}

.zavel-film .zavel-eyebrow {
	color: var(--zavel-gold-deep);
	letter-spacing: 0.17em;
	margin: 0 0 1.5rem;
}

.zavel-film h1,
.zavel-film h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(3.2rem, 4.8vw, 5.2rem);
	font-weight: 400;
	letter-spacing: -0.045em;
	line-height: 0.98;
	margin: 0 0 1.35rem;
}

.zavel-film-lead {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(1.2rem, 1.5vw, 1.5rem);
	line-height: 1.35;
	margin: 0 0 2rem;
	max-width: 32rem;
}

.zavel-film-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem 2.25rem;
}

[data-theme="nocturne"] .zavel-film,
[data-theme="nocturne"] .zavel-film .zavel-scroll-cue {
	color: var(--zavel-ivory);
}

[data-theme="nocturne"] .zavel-film .zavel-button {
	background: var(--zavel-ivory);
	border-color: var(--zavel-ivory);
	color: #171411;
}

[data-theme="nocturne"] .zavel-film .zavel-button:hover {
	background: transparent;
	color: var(--zavel-ivory);
}

@keyframes zavel-film-settle {
	from {
		transform: scale(0.965);
	}

	to {
		transform: scale(1);
	}
}

@keyframes zavel-film-copy {
	from {
		opacity: 0;
		transform: translateY(-20px);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes zavel-film-open {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

@media (prefers-reduced-motion: reduce) {
	.zavel-film-scene,
	.zavel-film-scene.is-current {
		transition: none;
	}

	.zavel-film-scene.is-current .zavel-film-photo,
	.zavel-film-scene.is-current .zavel-film-copy,
	:root:not(.zavel-arrived) .zavel-film-scene[data-scene="0"].is-current .zavel-film-plate {
		animation: none;
	}

	.zavel-film-photo {
		transform: none;
	}
}

@media (max-width: 56.25rem) {
	.zavel-film {
		height: 76svh;
		min-height: 43rem;
	}

	.zavel-film-plate::after {
		background: linear-gradient(rgba(0, 0, 0, 0) 28%, rgba(239, 233, 223, 0.72) 56%, rgba(239, 233, 223, 0.97) 100%);
	}

	.zavel-film-plate-nocturne::after {
		background: linear-gradient(rgba(14, 12, 10, 0.04) 24%, rgba(14, 12, 10, 0.55) 58%, rgba(14, 12, 10, 0.9) 100%);
	}

	.zavel-film-copy {
		bottom: 5.5rem;
		left: var(--wp--preset--spacing--page-padding);
		max-width: none;
		right: var(--wp--preset--spacing--page-padding);
	}

	.zavel-film h1,
	.zavel-film h2 {
		font-size: clamp(2.7rem, 11vw, 4.2rem);
	}

	.zavel-film-photo {
		object-fit: contain;
		object-position: right top;
		transform-origin: right top;
	}
}

/* The opening film is a three-part editorial proposition, not a product
   carousel. Its title and actions stay still while the photograph and the
   chapter thought dissolve together, so the change reads as one unfolding
   idea rather than three competing hero slides. */
.zavel-film-scenes {
	inset: 0;
	position: absolute;
}

/* The wash holds to the far edge of the copy before it feathers. It used to
   begin falling at 30%, which put the tail of every label on raw photograph,
   and the chapter that runs darkest under it decided whether a label could be
   read. The mirror bleeds off the right, well clear of where this reaches. */
.zavel-film-plate::after {
	background: linear-gradient(90deg, rgba(245, 241, 232, 0.97) 0%, rgba(245, 241, 232, 0.86) 26%, rgba(245, 241, 232, 0.68) 47%, rgba(245, 241, 232, 0.24) 63%, rgba(245, 241, 232, 0) 78%);
}

[data-theme="nocturne"] .zavel-film-plate::after {
	background:
		radial-gradient(circle at 70% 40%, rgba(187, 151, 93, 0.08), transparent 25%),
		linear-gradient(90deg, rgba(14, 12, 10, 0.94) 0%, rgba(14, 12, 10, 0.84) 26%, rgba(14, 12, 10, 0.7) 47%, rgba(14, 12, 10, 0.22) 65%, rgba(14, 12, 10, 0.02) 80%);
}

.zavel-film-copy {
	bottom: clamp(6.5rem, 12vh, 8rem);
	max-width: min(50rem, 46vw);
}

/* Above the mobile breakpoint the copy sits in the film's flow rather than
   hanging off its bottom edge, so the block's own height is what decides how
   tall the hero is. The Bulgarian headline wraps to three lines where the
   English one takes two, and while the copy was positioned that third line
   grew upward into the masthead: 64px straight through the wordmark at 1536
   by 864, and through it at 1366 by 768, 1440 by 700 and 1440 by 900 too. In
   flow the hero grows instead, which costs English nothing, because a two-line
   copy still fits inside the height the film already had. The stage's top
   padding is the floor no copy can rise above, whatever a translation or a
   later headline does to the line count. */
@media (min-width: 56.251rem) {
	.zavel-film {
		display: flex;
		flex-direction: column;
		height: auto;
		max-height: none;
		min-height: clamp(40rem, 74svh, 54rem);
	}

	.zavel-film-stage {
		display: flex;
		flex: 1;
		flex-direction: column;
		height: auto;
		justify-content: flex-end;
		padding-block: calc(var(--zavel-header-height) + 1.5rem) clamp(6.5rem, 12vh, 8rem);
	}

	.zavel-film-copy {
		bottom: auto;
		left: auto;
		margin-left: var(--zavel-page-inset);
		position: relative;
	}
}

:root:not(.zavel-arrived) .zavel-film-copy {
	animation: zavel-film-copy 800ms cubic-bezier(0.2, 0.7, 0.2, 1) 800ms both;
}

.zavel-film h1 {
	font-size: clamp(3.5rem, 5vw, 5.7rem);
	margin-bottom: 1.8rem;
}

.zavel-film-chapters {
	min-height: 7.2rem;
}

.zavel-film-chapter.is-current {
	animation: zavel-film-copy 700ms cubic-bezier(0.2, 0.7, 0.2, 1) 180ms both;
}

.zavel-film-chapter-label {
	color: var(--zavel-gold-deep);
	margin: 0 0 0.55rem;
}

.zavel-film-lead {
	margin-bottom: 1.7rem;
}

.zavel-film-controls {
	background: rgba(245, 241, 232, 0.8);
	bottom: 1.55rem;
	display: flex;
	gap: clamp(1rem, 2.2vw, 2.25rem);
	padding: 0 0.65rem;
	position: absolute;
	right: var(--zavel-page-inset);
	z-index: 3;
}

[data-theme="nocturne"] .zavel-film-controls {
	background: rgba(23, 20, 17, 0.78);
}

/* The state is the rule above the chapter, solid on the one showing and faint
   on the others, and the text keeps a colour that clears AA on its own: an
   opacity dimmed the text below the floor on the Gallery ground. */
.zavel-film-controls button {
	background: transparent;
	border: 0;
	border-top: 1px solid var(--zavel-line);
	color: var(--zavel-charcoal-soft);
	cursor: pointer;
	font: inherit;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.75rem;
	font-weight: 650;
	letter-spacing: 0.08em;
	min-block-size: 2.75rem;
	padding: 0.65rem 0 0;
	text-transform: uppercase;
	transition: border-color 0.3s, color 0.3s;
	white-space: nowrap;
}

.zavel-film-controls button span {
	display: inline-block;
	margin-right: 0.55rem;
}

.zavel-film-controls button:hover,
.zavel-film-controls button[aria-pressed="true"] {
	border-top-color: currentcolor;
	color: var(--zavel-charcoal);
}

/* The glyph only: the word beside it is a label and keeps the floor. */
.zavel-film-pause span[aria-hidden] {
	font-size: 0.6rem;
	letter-spacing: 0.1em;
}

.zavel-film-controls button:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
	:root:not(.zavel-arrived) .zavel-film-copy,
	.zavel-film-chapter.is-current {
		animation: none;
	}
}

/* Below 900 the film stacks instead of overlaying. The copy used to hang over
   the lower half of the portrait plate under a wash, which left the mirror a
   band about 140 pixels tall at 390 and a ghost behind the headline at 768.
   Now the plate takes the upper half of the viewport unwashed and the copy sits
   on the film's own ground beneath it, in flow, with the chapter controls
   after it. The photograph covers its box rather than fitting inside it, held
   at the point every plate keeps its mirror, and it settles down from a slight
   zoom rather than up, because a cover crop has no edge to reveal. */
@media (max-width: 56.25rem) {
	.zavel-film {
		display: flex;
		flex-direction: column;
		height: auto;
		max-height: none;
		min-height: 0;
	}

	.zavel-film-stage {
		display: flex;
		flex-direction: column;
		height: auto;
		padding-top: var(--zavel-header-height);
	}

	.zavel-film-scenes {
		height: clamp(17rem, 52svh, 30rem);
		inset: auto;
		position: relative;
	}

	.zavel-film-plate::after,
	.zavel-film-plate-nocturne::after,
	[data-theme="nocturne"] .zavel-film-plate::after {
		background: none;
	}

	.zavel-film-photo {
		object-fit: cover;
		object-position: 50% 30%;
		transform: scale(1.035);
		transform-origin: 50% 30%;
	}

	.zavel-film-scene.is-current .zavel-film-photo {
		animation-name: zavel-film-settle-cover;
	}

	.zavel-film-copy {
		bottom: auto;
		left: auto;
		max-width: none;
		padding: 1.5rem var(--wp--preset--spacing--page-padding) 0;
		position: relative;
		right: auto;
	}

	.zavel-film h1 {
		font-size: clamp(2.65rem, 11vw, 4.2rem);
		margin-bottom: 1.25rem;
	}

	.zavel-film-chapters {
		min-height: 6.2rem;
	}

	.zavel-film .zavel-eyebrow {
		margin-bottom: 1rem;
	}

	.zavel-film-lead {
		font-size: clamp(1.05rem, 4.6vw, 1.3rem);
		margin-bottom: 1.3rem;
	}

	.zavel-film-actions {
		gap: 0.8rem 1.4rem;
	}

	.zavel-film-controls,
	[data-theme="nocturne"] .zavel-film-controls {
		background: transparent;
		bottom: auto;
		display: grid;
		gap: 0.5rem;
		grid-template-columns: repeat(3, minmax(0, 1fr)) auto;
		left: auto;
		margin: 1.6rem var(--wp--preset--spacing--page-padding) 0;
		padding: 0 0.25rem 1.5rem;
		position: relative;
		right: auto;
	}

	.zavel-film-controls button {
		letter-spacing: 0.04em;
		text-align: left;
	}

	.zavel-film-controls button span {
		display: block;
		margin: 0 0 0.1rem;
	}
}

/* Between a phone and the desktop composition the landscape plate is the whole
   scene at the viewport's width, so nothing is cropped; the portrait crop below
   600 would have covered a 768 box with a third of the plate. */
@media (min-width: 37.501rem) and (max-width: 56.25rem) {
	.zavel-film-scenes {
		height: min(calc(100vw * 942 / 1672), 62svh);
	}

	.zavel-film-photo {
		object-position: right center;
		transform-origin: right center;
	}
}

@keyframes zavel-film-settle-cover {
	from {
		transform: scale(1.035);
	}

	to {
		transform: scale(1);
	}
}

@media (prefers-reduced-motion: reduce) and (max-width: 56.25rem) {
	.zavel-film-photo {
		transform: none;
	}
}

/* A 320 column has 280 pixels for the row, and Reflection alone wants 76 of
   them, so the pause keeps its glyph and gives its word to the tree only. */
@media (max-width: 22.5rem) {
	.zavel-film-controls {
		gap: 0.25rem;
		grid-template-columns: repeat(3, minmax(0, 1fr)) 2.75rem;
	}

	.zavel-film-controls button {
		letter-spacing: 0;
	}

	.zavel-film-pause {
		text-align: center;
	}

	.zavel-film-pause-label {
		clip-path: inset(50%);
		height: 1px;
		overflow: hidden;
		position: absolute;
		white-space: nowrap;
		width: 1px;
	}
}

/* Short desktop windows otherwise hit the film's 40rem floor and make a
   720px preview read almost full-screen. The compact composition preserves
   the same hierarchy while letting the shelf below remain visibly in reach. */
@media (min-width: 56.251rem) and (max-height: 53rem) {
	.zavel-film {
		min-height: 36rem;
	}

	.zavel-film-stage {
		padding-bottom: 3.75rem;
	}

	.zavel-film h1 {
		font-size: clamp(3.2rem, 4.4vw, 4.4rem);
		margin-bottom: 1.3rem;
	}

	.zavel-film-chapters {
		min-height: 6.4rem;
	}
}

.zavel-hero-photo {
	height: 100%;
	inset: 0;
	object-fit: cover;
	object-position: center center;
	position: absolute;
	width: 100%;
}

/* The wash runs across on a wide screen, because the copy sits in the left
   third and the mirror is to the right of it. */
.zavel-hero-wash {
	background: linear-gradient(90deg, rgba(239, 233, 223, 0.95) 0%, rgba(239, 233, 223, 0.65) 25%, rgba(0, 0, 0, 0) 58%);
	inset: 0;
	pointer-events: none;
	position: absolute;
}

.zavel-hero-variant-nocturne .zavel-hero-wash {
	background:
		radial-gradient(circle at 67% 39%, rgba(187, 151, 93, 0.08), rgba(0, 0, 0, 0) 25%),
		linear-gradient(90deg, rgba(14, 12, 10, 0.52) 0%, rgba(14, 12, 10, 0.2) 39%, rgba(14, 12, 10, 0.03) 70%);
}

/* Bottom-anchored, but inset from the header so the copy cannot ride up under
   it on a tall screen. `safe` drops the box back to the top when the copy is
   taller than the space, which is the case the eyebrow was lost in.
   The heading column grows with the viewport rather than staying at 30rem, or
   the type scales and the measure does not and the h1 gains a fourth line.
   The masthead's own space below the lockup is the gap, so nothing is added to
   its height: at 1920 by 900 the copy already fills the hero to the pixel. */
.zavel-hero-content {
	bottom: clamp(5rem, 10vh, 7.5rem);
	display: flex;
	flex-direction: column;
	justify-content: safe flex-end;
	left: var(--zavel-page-inset);
	max-width: min(clamp(30rem, 33.3vw, 36.2rem), 40vw);
	position: absolute;
	top: var(--zavel-header-height);
	z-index: 2;
}

.zavel-hero-kicker {
	letter-spacing: 0.17em;
	margin: 0 0 1.5rem;
}

.zavel-home-hero h1 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(3.6rem, 5.2vw, 5.65rem);
	font-weight: 400;
	letter-spacing: -0.045em;
	line-height: 0.96;
	margin: 0 0 1.35rem;
}

.zavel-hero-lead {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(1.25rem, 1.65vw, 1.65rem);
	line-height: 1.32;
	margin: 0 0 2rem;
	max-width: 35rem;
}

.zavel-hero-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 1.5rem 2.25rem;
}

.zavel-hero-actions .zavel-button {
	margin-top: 0;
}

.zavel-hero-product-label,
.zavel-numbered-edition {
	bottom: 2rem;
	display: flex;
	flex-direction: column;
	position: absolute;
	right: var(--zavel-page-inset);
	text-align: right;
	z-index: 2;
}

/* The credit now takes the designer story's chip so 12 pixel Manrope has a
   ground over a pale photograph, and that chip owns the bottom left of its own
   picture. The hero has to say again where its own corner is, and it has to
   outrank the chip to do it. */
.zavel-home-hero .zavel-hero-product-label {
	bottom: 2rem;
	left: auto;
	right: var(--zavel-page-inset);
}

.zavel-scroll-cue {
	align-items: center;
	bottom: 2rem;
	display: flex;
	gap: 1rem;
	left: var(--zavel-page-inset);
	letter-spacing: 0.1em;
	min-block-size: 1.5rem;
	position: absolute;
	text-decoration: none;
	z-index: 2;
}

/* On a wide, short screen the copy already fills the hero to its floor and the
   cue lands on the actions. Measured at 1920 by 800: the actions end at 585 and
   the cue began at 584. It is a prompt to do what the fold already invites.
   From 1600 wide the h1 is at its cap and three lines of it, the lead and the
   actions stand 481 tall, so up to 912 tall the copy is also given the cue's
   room, or it is pinned to the top with the eyebrow 19 pixels under the lockup. */
@media (max-height: 53rem) {
	.zavel-scroll-cue {
		display: none;
	}
}

@media (min-width: 100rem) and (max-height: 57rem) {
	.zavel-scroll-cue {
		display: none;
	}

	.zavel-hero-content {
		bottom: 3rem;
	}
}

[data-theme="nocturne"] .zavel-home-hero-dual,
[data-theme="nocturne"] .zavel-home-hero-dual .zavel-hero-product-label,
[data-theme="nocturne"] .zavel-home-hero-dual .zavel-scroll-cue {
	color: var(--zavel-ivory);
}

[data-theme="nocturne"] .zavel-home-hero-dual .zavel-button {
	background: var(--zavel-ivory);
	border-color: var(--zavel-ivory);
	color: #171411;
}

[data-theme="nocturne"] .zavel-home-hero-dual .zavel-button:hover {
	background: transparent;
	color: var(--zavel-ivory);
}

/* The shelf sits directly under the hero rather than a section space below it,
   so the first scroll reaches the whole catalog. */
.zavel-collection-shelf {
	background: var(--zavel-paper-soft);
	border-top: 1px solid var(--zavel-line);
	padding: 2.35rem var(--zavel-page-inset) 2.65rem;
	position: relative;
}

.zavel-collection-shelf-heading {
	align-items: center;
	display: flex;
	justify-content: space-between;
	letter-spacing: 0.11em;
	margin-bottom: 1.35rem;
}

.zavel-collection-shelf-heading p {
	margin: 0;
}

.zavel-collection-shelf-heading a {
	align-items: center;
	border-bottom: 1px solid;
	display: inline-flex;
	min-block-size: 1.5rem;
	padding-bottom: 0.15rem;
	text-decoration: none;
}

/* One column per collection. Five left the sixth alone on a second row, and the
   catalog is meant to read as one shelf. */
.zavel-collection-shelf-grid {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(6, minmax(0, 1fr));
}

/* A column, and the name block takes the slack, so the six rule lines agree:
   TRACE and LITHOS name their founding edition after the collection, so their
   meta carries a name where the others carry a name and an edition, and a
   badge that follows the text lands higher on two cards of six. */
.zavel-collection-shelf-grid > a {
	display: flex;
	flex-direction: column;
	text-decoration: none;
}

.zavel-collection-card-meta {
	flex: 1 0 auto;
}

.zavel-collection-card-image {
	aspect-ratio: 16 / 9;
	background: var(--zavel-limestone);
	overflow: hidden;
	position: relative;
}

.zavel-collection-card-image img {
	display: block;
	height: 100%;
	object-fit: contain;
	object-position: center;
	transition: filter 0.36s;
	width: 100%;
}

/* A dedicated night photograph carries its own exposure. A modest fallback
   keeps future daylight-only records readable against the dark ground. */
[data-theme="nocturne"] .zavel-collection-card-image img {
	filter: brightness(0.8);
}

.zavel-collection-card-image-dual .zavel-collection-photo-nocturne {
	display: none;
}

[data-theme="nocturne"] .zavel-collection-card-image-dual img {
	display: none;
}

[data-theme="nocturne"] .zavel-collection-card-image-dual .zavel-collection-photo-nocturne {
	display: block;
	filter: none;
}

[data-theme="nocturne"] .zavel-designer-card-image img,
[data-theme="nocturne"] .zavel-designer-portrait img {
	filter: brightness(0.85);
}

[data-theme="nocturne"] .zavel-tile-image img,
[data-theme="nocturne"] .zavel-edition-card-image:not(.zavel-edition-card-image-dual) img,
[data-theme="nocturne"] .zavel-hero:not(.zavel-designer-hero) .zavel-hero-image:not(.zavel-hero-image-dual) img {
	filter: brightness(0.8);
}

/* An edition with a night photograph of its own shows it in Nocturne instead
   of the dimmed daylight frame, the hero's rule carried to the grid. One image
   is in flow at a time, so the box never moves, and the hidden one is a lazy
   image that display: none keeps from ever being fetched. A night frame keeps
   its own warmth rather than taking the dim, per the photography brief. */
.zavel-tile-image-dual .zavel-tile-photo-nocturne {
	display: none;
}

[data-theme="nocturne"] .zavel-tile-image-dual img {
	display: none;
}

[data-theme="nocturne"] .zavel-tile-image-dual .zavel-tile-photo-nocturne {
	display: block;
	filter: none;
}

/* The collection page swaps by the same rule, in both places it prints a
   photograph: the hero and the signature edition's card. Without it the one
   page whose premise is light after dark opened on a daylight frame at full
   brightness against a near-black ground. A collection whose founding edition
   has no night frame keeps its daylight one, which is why the class is
   conditional rather than the selector. */
.zavel-hero-image-dual .zavel-hero-photo-nocturne,
.zavel-edition-card-image-dual .zavel-edition-photo-nocturne {
	display: none;
}

[data-theme="nocturne"] .zavel-hero-image-dual img,
[data-theme="nocturne"] .zavel-edition-card-image-dual img {
	display: none;
}

[data-theme="nocturne"] .zavel-hero-image-dual .zavel-hero-photo-nocturne,
[data-theme="nocturne"] .zavel-edition-card-image-dual .zavel-edition-photo-nocturne {
	display: block;
	filter: none;
}

/* The record page's room view swaps by the same rule. The edition page stays
   undimmed in both editions, so the photograph and its caption are the only
   things the edition changes here. */
.zavel-gallery-figure-dual .zavel-photo-nocturne,
.zavel-gallery-figure-dual .zavel-caption-nocturne {
	display: none;
}

[data-theme="nocturne"] .zavel-gallery-figure-dual img,
[data-theme="nocturne"] .zavel-gallery-figure-dual .zavel-caption-day {
	display: none;
}

[data-theme="nocturne"] .zavel-gallery-figure-dual .zavel-photo-nocturne {
	display: block;
}

[data-theme="nocturne"] .zavel-gallery-figure-dual .zavel-caption-nocturne {
	display: inline;
}

.zavel-collection-card-meta {
	align-items: start;
	display: flex;
	justify-content: space-between;
	padding: 0.7rem 0.1rem 0;
}

.zavel-collection-card-meta h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(1rem, 1.3vw, 1.35rem);
	font-weight: 400;
	letter-spacing: -0.02em;
	line-height: 1.05;
	margin: 0 0 0.2rem;
}

.zavel-collection-card-meta p {
	color: var(--zavel-charcoal-soft);
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	margin: 0;
	text-transform: uppercase;
}

.zavel-collection-card-meta > span {
	font-size: 0.75rem;
}

/* The compact Reflection Index mark on a card is a different object from the
   one on an edition panel: it rules off both edges and sits tight under the
   name rather than opening a block of its own. */
.zavel-collection-shelf-grid .zavel-index-badge {
	align-items: center;
	border-bottom: 1px solid var(--zavel-line);
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.75rem;
	grid-template-columns: auto 1fr;
	margin-top: 0.65rem;
	max-width: none;
	padding: 0.65rem 0;
}

.zavel-collection-shelf-grid .zavel-index-badge > span:last-child {
	display: grid;
	gap: 0.12rem;
}

/* Six across, the kicker has the tile minus the mark to fit one line in, which
   at 1440 is 163 pixels against 165 of text at the label tier's tracking;
   0.06em brings the text to 154. Balanced, so if it still breaks it breaks
   before the code rather than inside it. */
.zavel-collection-shelf-grid .zavel-index-badge small {
	letter-spacing: 0.06em;
	text-wrap: balance;
}

.zavel-collection-shelf-grid .zavel-index-badge strong {
	font-size: 1rem;
	font-weight: 450;
	line-height: 1.1;
}

/* Between six across and the width where a tile is 207 pixels the kicker does
   not fit beside the mark at any legal tracking, so the mark sits above it. */
@media (min-width: 70.0625rem) and (max-width: 88rem) {
	.zavel-collection-shelf-grid .zavel-index-badge {
		gap: 0.5rem;
		grid-template-columns: 1fr;
	}
}

/* The sections carry their own spacing, so the editor's block gap between them,
   a strip of paper under the hero and between two grounds, is dropped. */
.wp-site-blocks > main > section,
.wp-site-blocks > main > .zavel-depth-band {
	margin-block: 0;
}

/* Section framing shared by the homepage's full-width sections. */
.zavel-featured-section {
	background: var(--zavel-paper);
	padding: var(--wp--preset--spacing--section-space) var(--zavel-page-inset);
}

.zavel-section-heading {
	margin-bottom: clamp(2.5rem, 4.5vw, 4.5rem);
}

.zavel-split-heading {
	align-items: end;
	display: grid;
	gap: 3rem;
	grid-template-columns: minmax(0, 1.3fr) minmax(18rem, 0.7fr);
}

.zavel-split-heading .zavel-eyebrow {
	margin-bottom: 1.25rem;
}

.zavel-split-heading h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--display);
	font-weight: 400;
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0;
	text-wrap: balance;
}

.zavel-section-intro {
	color: var(--zavel-charcoal-soft);
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--intro);
	line-height: 1.3;
	max-width: 31rem;
}

/* The underline is drawn the whole width and faint, and comes to full strength
   on hover, which is the reason these links carry no text decoration of their
   own. The designer card's action is the same object, and its hover is the
   card's, since the card is the link.

   It used to be a fifth drawn and to grow. A fifth is a proportion, so the mark
   measured 50 pixels under a 248 pixel link and 18 under a 92 pixel one, and at
   every width it stopped mid-phrase: it read as an underline that had failed to
   render rather than as a mark. Nine links on the homepage carried it. Opacity
   also costs no layout, where growing a rule under a line of text did. */
.zavel-text-link,
.zavel-light-link,
.zavel-designer-card-cta {
	align-items: center;
	display: inline-flex;
	gap: 1.5rem;
	letter-spacing: 0.07em;
	min-block-size: 1.5rem;
	padding-bottom: 0.35rem;
	position: relative;
	text-decoration: none;
}

.zavel-text-link::after,
.zavel-light-link::after,
.zavel-designer-card-cta::after {
	background: currentcolor;
	bottom: 0;
	content: "";
	height: 1px;
	left: 0;
	opacity: 0.3;
	position: absolute;
	transition: opacity 0.26s;
	width: 100%;
}

.zavel-text-link:hover::after,
.zavel-light-link:hover::after,
.zavel-designer-card:hover .zavel-designer-card-cta::after {
	opacity: 1;
}

.zavel-text-link-spaced {
	margin-top: clamp(2.5rem, 5vw, 5rem);
}

/* The depth tier. It held three sections that were three ways into the same six
   records, laid out in three columns so they cost one band of the page rather
   than a viewport each. Those three are three pivots inside one section since
   `WP-39`, so the band holds one child and lays it out in one column.

   What survives the change is the reason the band exists: everything inside it
   gives up its own section framing, so the ground and the padding are the
   band's and what it holds reads as one tier rather than as a stack. */
.zavel-depth-band {
	background: var(--zavel-paper-soft);
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: clamp(2.25rem, 5vw, 4rem);
	padding: var(--wp--preset--spacing--section-space) var(--zavel-page-inset);
}

/* The group is a block, so the editor's block gap rides on every child but the
   first and is added to the grid's own gap. Stacked that put 24 pixels under
   two of the three groups and nothing under the third. */
.zavel-depth-band > * {
	margin-block: 0;
}

.zavel-depth-band > section {
	background: none;
	border: 0;
	min-width: 0;
	padding: 0;
}

/* The band held three groups side by side and shared its rows with them through
   subgrid, so their three rules opened on one line. It holds one section since
   the three became three pivots inside it, and a single column is the whole
   layout: the section divides its own width, and giving it a third of the band
   crushed every card in it to one word per line.

   Nothing replaces the subgrid, because there is no second column to align to. */

/* The band's own heading tier. The heading shares the band with the pivot under
   it, so the display size the sections carried alone would take a third of the
   height before naming a single behaviour. */
.zavel-depth-band .zavel-classification-intro {
	display: block;
	margin-bottom: clamp(1.5rem, 2.5vw, 2.25rem);
}

.zavel-depth-band .zavel-classification-intro h2 {
	font-size: var(--wp--preset--font-size--title);
	letter-spacing: -0.02em;
	line-height: 1.1;
	margin: 0 0 0.75rem;
	max-width: none;
}

.zavel-depth-band .zavel-classification-intro .zavel-eyebrow {
	margin-bottom: 0.6rem;
}

.zavel-depth-band .zavel-section-intro {
	font-family: var(--wp--preset--font-family--sans);
	font-size: var(--wp--preset--font-size--secondary);
	line-height: 1.55;
	margin: 0;
	max-width: 34rem;
}

.zavel-depth-band .zavel-text-link-spaced {
	margin-top: 2rem;
}

/* The classification. One section where there were three, and the pivot is the
   whole point: the Reflection Index, the silhouettes and the rooms were three
   parallel readings of the same six pieces, so they are three views of one list
   rather than three lists.

   The panels are not floored at a common height, and the first build of this
   section was. The reasoning was that the form panel is shorter than the other
   two by more than a viewport, so switching to it pulls everything below the
   section up the page. What the floor did instead was hold that panel open at
   the tallest one's height: measured on the deployed page, 567 pixels of empty
   ground at 1440 and 1,024 at 900, where six cards in two rows sat above a
   blank screen and a reader had no way to tell the difference between that and
   a page that had failed to load.

   A page that reflows when the reader asks it to is ordinary. A blank viewport
   is not, so the reflow is the one to keep. */
.zavel-classification-intro {
	margin-bottom: clamp(2rem, 3.5vw, 3.2rem);
	max-width: 46rem;
}

.zavel-classification-pivot {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem;
	margin-bottom: 0.5rem;
}

.zavel-classification-pivot[hidden] {
	display: none;
}

/* The tabs take the edition switch's idiom rather than an underline. Tracked
   caps over a full-width rule read as a caption row above a divider, which is
   what the review found: a reader who did not recognise the strip as a control
   saw only the first of the three readings, and two thirds of the section was
   invisible to them. The site already has one control that says "these are
   choices and one of them is on", and this is the same object, so it is drawn
   the same way.

   The label sits at the interactive tier the legibility floor names for a label
   that is acted on, and the box clears 44 pixels rather than the 34 it had. */
.zavel-classification-pivot button {
	background: none;
	border: 1px solid var(--zavel-line);
	border-radius: 999px;
	color: var(--zavel-charcoal-soft);
	cursor: pointer;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.85rem;
	font-weight: 650;
	letter-spacing: 0.09em;
	min-block-size: 2.75rem;
	padding: 0 1.15rem;
	text-transform: uppercase;
	transition: background-color 0.2s, border-color 0.2s, color 0.2s;
}

.zavel-classification-pivot button:hover {
	border-color: var(--zavel-charcoal-soft);
	color: var(--zavel-charcoal);
}

.zavel-classification-pivot button[aria-selected="true"] {
	background: var(--zavel-charcoal);
	border-color: var(--zavel-charcoal);
	color: var(--zavel-paper);
}

.zavel-classification-pivot button:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-classification-panel {
	padding-top: 2.2rem;
}

.zavel-classification-panel[hidden] {
	display: none;
}

/* Each panel names itself until the tab strip does it instead. */
.is-pivoted .zavel-classification-panel-title {
	display: none;
}

.zavel-classification-panel-title {
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.5rem;
	font-weight: 400;
	margin: 0 0 1.4rem;
}

/* The classification on the left, the pieces it holds on the right. A row per
   group across the whole measure left two thirds of the line empty wherever a
   behaviour holds one edition, which four of the five do. */
.zavel-classification-group {
	display: grid;
	gap: 2.5rem;
	grid-template-columns: 18rem minmax(0, 1fr);
}

.zavel-classification-group + .zavel-classification-group {
	border-top: 1px solid var(--zavel-line);
	margin-top: 1.8rem;
	padding-top: 1.8rem;
}

.zavel-classification-group-head {
	display: grid;
	gap: 0.75rem;
	grid-template-columns: auto minmax(0, 1fr);
}

.zavel-classification-group-head-room {
	display: block;
}

.zavel-classification-group-head h4 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.35rem;
	font-weight: 400;
	margin: 0;
}

.zavel-classification-group-head p {
	color: var(--zavel-charcoal-soft);
	font-size: 0.9rem;
	margin: 0.3rem 0 0;
}

.zavel-classification-group-head .zavel-text-link {
	margin-top: 0.9rem;
}

/* auto-fit rather than two fixed columns, because four of the five behaviours
   hold one edition and a fixed second column reserved half the row for nothing.
   An empty track collapses, so a lone card sits at its own width beside the
   classification that heads it rather than stretched across half the measure. */
.zavel-classification-grid {
	display: grid;
	gap: 1.2rem 2rem;
	grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 22rem));
	justify-content: start;
}

.zavel-classification-grid-wide {
	gap: 1.6rem 2rem;
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.zavel-classification-card a {
	align-items: center;
	color: inherit;
	display: grid;
	gap: 1.1rem;
	grid-template-columns: 4.5rem minmax(0, 1fr);
	text-decoration: none;
}

/* The outline at a size that reads. At the 38 pixels the silhouette cards gave
   it, a raw-edge horizontal and an architectural full-length were both a small
   rectangle, and the drawing is the most specific thing the brand owns. */
.zavel-classification-draw {
	align-items: center;
	aspect-ratio: 0.72 / 1;
	color: var(--zavel-clay);
	display: flex;
	justify-content: center;
}

.zavel-classification-draw svg {
	display: block;
	height: 100%;
	transition: transform 0.28s;
	width: 100%;
}

.zavel-classification-card a:hover .zavel-classification-draw {
	color: var(--zavel-charcoal);
}

.zavel-classification-card a:hover .zavel-classification-draw svg {
	transform: scale(1.06);
}

.zavel-classification-card a:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-classification-lead {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

.zavel-classification-card h4 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.25rem;
	font-weight: 400;
	margin: 0.15rem 0 0.2rem;
}

.zavel-classification-meta {
	margin: 0;
}

.zavel-classification-scale {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	margin: 0.25rem 0 0;
}

/* Below the two-column measure the classification sits above the pieces it
   holds rather than beside them, which is the order it is read in anyway. */
@media (max-width: 70rem) {
	.zavel-classification-group {
		gap: 1.6rem;
		grid-template-columns: minmax(0, 1fr);
	}

}

@media (max-width: 42.5rem) {
	.zavel-classification-grid,
	.zavel-classification-grid-wide {
		grid-template-columns: minmax(0, 1fr);
	}

	/* Three tabs do not fit the measure on a phone, so the strip scrolls out to
	   the page inset on both sides rather than wrapping into two rows. */
	.zavel-classification-pivot {
		gap: 1.4rem;
		margin-inline: calc(0px - var(--zavel-page-inset));
		overflow-x: auto;
		padding-inline: var(--zavel-page-inset);
		scrollbar-width: none;
	}

	.zavel-classification-pivot button {
		white-space: nowrap;
	}

}

/* The editorial grid. Ten columns and two rows: the lead edition and the piece
   the catalog can say most about take the first row six and four columns wide,
   and the other five take two columns each in the second. It used to be twelve
   columns of alternating five and seven over four rows, which read as a spread
   and cost three screens; the tier this section now opens has to end before the
   consultation, so the spread is one plate and a row rather than four.

   The rule the rows keep is unchanged: every tile in a row shares its top edge
   and its image height. What sets the row's height is whichever tile has more
   to say under its photograph, which is the study plate and its prose. */
.zavel-editorial-grid {
	display: grid;
	gap: var(--wp--preset--spacing--page-padding);
	grid-template-columns: repeat(10, minmax(0, 1fr));
}

.zavel-tile {
	display: block;
	text-decoration: none;
}

.zavel-tile-main {
	grid-column: span 6;
}

.zavel-tile-detail {
	grid-column: span 4;
}

.zavel-tile-small {
	grid-column: span 2;
}

.zavel-tile-image {
	background: var(--zavel-limestone);
	overflow: hidden;
	position: relative;
}

.zavel-tile-image img {
	display: block;
	height: 100%;
	object-fit: cover;
	transition: filter 0.36s, transform 0.5s cubic-bezier(0.2, 0.7, 0.2, 1);
	width: 100%;
}

/* The lead takes the photograph's own frame, so the plate that opens the page
   is the frame as shot and crops nothing. The study keeps the 1.35 the grid
   has always given a tile of this width.

   The two are drawn to different heights and the tiles still end together,
   because the row is set by the study's prose and the lead's caption is two
   lines shorter. Drawing them to one height was tried and it is what the
   photography cannot pay for: a square study box asks `aster-front.webp` for
   1,032 device pixels of height from a 460 pixel frame, and it measured 0.89
   source pixels per CSS pixel against 1.20 here. */
.zavel-tile-main .zavel-tile-image {
	aspect-ratio: 1.78 / 1;
}

.zavel-tile-detail .zavel-tile-image {
	aspect-ratio: 1.35 / 1;
}

/* Square, which is what separates the row from the collection shelf above it:
   the shelf is six landscape plates of the same six records, and the same crop
   twice on one page reads as one list printed twice. It is also the study
   plate's frame, so the section's two rows are one set of proportions. */
.zavel-tile-small .zavel-tile-image {
	aspect-ratio: 1 / 1;
}

.zavel-tile:hover .zavel-tile-image img {
	transform: scale(1.025);
}

.zavel-tile-meta {
	display: flex;
	justify-content: space-between;
	padding-top: 1.15rem;
}

.zavel-tile-meta h3 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.6rem;
	font-weight: 400;
	margin: 0 0 0.2rem;
}

.zavel-tile-meta p {
	color: var(--zavel-charcoal-soft);
	font-size: var(--wp--preset--font-size--secondary);
	letter-spacing: 0.04em;
	margin: 0.12rem 0;
}

.zavel-tile-meta > div:last-child {
	text-align: right;
}

/* A two-column caption inside a two-column tile leaves the name two words a
   line and gives the price the rest, which is the reason the phone widths gave
   it up already. The row of five is the same width by another route. */
.zavel-tile-small .zavel-tile-meta {
	flex-direction: column;
	gap: 0.6rem;
}

.zavel-tile-small .zavel-tile-meta h3 {
	font-size: 1.25rem;
}

.zavel-tile-small .zavel-tile-meta > div:last-child {
	text-align: left;
}

/* The third line of every card, carrying the collection where it adds a name
   and the run where it does not. It sits at the caption tier rather than the
   eyebrow tier the class list would otherwise give it: .zavel-tile-meta p
   outranks the label tier on specificity and the eyebrow's tighter line height
   comes with it. */
.zavel-tile-meta .zavel-tile-where {
	color: var(--zavel-charcoal-soft);
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	margin-top: 0.45rem;
}

/* A name and a lead time are each one unit and are read once. Broken across
   lines they are read twice: the row of five gave TRACE `Maria` over
   `Velichkova` and `6–8` over `weeks` at 1440. Both are short enough that
   holding them together cannot widen the card past its column. */
.zavel-tile-designer,
.zavel-tile-lead {
	white-space: nowrap;
}

.zavel-detail-caption {
	padding-top: 1.25rem;
}

.zavel-detail-caption > p:not(.zavel-eyebrow) {
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.25rem;
	line-height: 1.35;
	max-width: 28rem;
}

.zavel-detail-caption .zavel-text-link {
	margin-top: 0.5rem;
}

/* The designer story. The portrait takes the wider column, because a face at
   this scale is the section's argument and the prose is its evidence. */
.zavel-designer-section {
	background: var(--zavel-surface-muted);
	display: grid;
	grid-template-columns: minmax(0, min(52.63vw, 56rem)) minmax(24rem, 1fr);
	min-height: 52rem;
}

.zavel-designer-portrait {
	min-height: 48rem;
	overflow: hidden;
	position: relative;
}

.zavel-designer-portrait img {
	display: block;
	height: 100%;
	object-fit: cover;
	transition: filter 0.36s;
	width: 100%;
}

.zavel-portrait-caption {
	background: rgba(245, 241, 232, 0.92);
	bottom: 1.25rem;
	color: var(--zavel-charcoal);
	left: 1.25rem;
	padding: 0.6rem 0.75rem;
	position: absolute;
}

[data-theme="nocturne"] .zavel-portrait-caption {
	background: rgba(23, 20, 17, 0.92);
}

.zavel-designer-story {
	align-self: center;
	padding: clamp(3rem, 5.5vw, 6rem);
}

.zavel-designer-story h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--display);
	font-weight: 400;
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0 0 2rem;
}

.zavel-designer-story .zavel-eyebrow {
	margin-bottom: 1.5rem;
}

.zavel-designer-story blockquote {
	border-left: 1px solid var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(1.4rem, 2vw, 2rem);
	line-height: 1.3;
	margin: 0 0 2rem;
	padding-left: 1.5rem;
}

.zavel-designer-story blockquote p {
	margin: 0;
}

.zavel-designer-story .zavel-provenance {
	border-bottom: 1px solid var(--zavel-line);
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.75rem;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	letter-spacing: 0.07em;
	list-style: none;
	margin: 3rem 0 0;
	padding: 1.25rem 0;
}

.zavel-designer-represented {
	color: var(--zavel-charcoal-soft);
	margin-top: 1.5rem;
}

.zavel-designer-represented a {
	text-decoration: underline 1px;
	text-underline-offset: 0.25em;
}

/* The designer index. Four portraits in a row is the reference's composition and
   the reason the cards are narrow: the face carries the card and the prose sits
   under it, rather than the two competing for width the way the story section
   above lets them. Ported from the reference's `.designer-index`. */
.zavel-designer-index {
	background: var(--zavel-paper-soft);
}

.zavel-designer-index-hero {
	padding: clamp(10rem, 16vw, 15rem) var(--zavel-page-inset) clamp(4rem, 7vw, 7rem);
}

.zavel-designer-index-hero h1 {
	font-size: clamp(4.2rem, 7vw, 7.6rem);
	margin: 1rem 0 1.5rem;
	max-width: 58rem;
}

.zavel-designer-index-empty {
	padding: 0 var(--zavel-page-inset) var(--wp--preset--spacing--section-space);
}

.zavel-designer-index-grid {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	padding: 0 var(--zavel-page-inset) var(--wp--preset--spacing--section-space);
}

.zavel-designer-card {
	display: flex;
	flex-direction: column;
	text-decoration: none;
}

.zavel-designer-card-image {
	aspect-ratio: 0.86;
	background: var(--zavel-limestone);
	margin-bottom: 1.5rem;
	overflow: hidden;
	position: relative;
}

/* The plate a designer with no portrait of their own gets, until `WP-04`
   photographs one. It says it is a name rather than a face, which the workshop
   photograph that stood here could not: on a row of four it read as two people
   and two objects. The letters are the display face at the card's own width, so
   the plate is typography rather than a placeholder. */
.zavel-designer-card-monogram {
	align-items: center;
	background: var(--zavel-surface-muted);
	color: var(--zavel-charcoal-soft);
	display: flex;
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(4.5rem, 9vw, 8rem);
	font-weight: 400;
	height: 100%;
	justify-content: center;
	letter-spacing: -0.04em;
	line-height: 1;
	margin: 0;
}

/* The portraits are framed for a face near the top, which is why this holds the
   upper third rather than the centre. `cover` keeps a frame that is not shaped
   for the box from distorting in it. */
.zavel-designer-card-image img {
	display: block;
	height: 100%;
	object-fit: cover;
	object-position: 50% 30%;
	transition: filter 0.36s, transform 0.6s cubic-bezier(0.2, 0.7, 0.2, 1);
	width: 100%;
}

.zavel-designer-card:hover .zavel-designer-card-image img {
	transform: scale(1.025);
}

/* The grid stretches every card to the tallest, so a designer whose discipline
   and studio fit on one line leaves slack under their card. The CTA's
   `margin-top: auto` is what absorbs it, and an auto margin does nothing in a
   block box, so this column has to be a flex one that grows. The reference
   carries the same rule on a block parent and the same stranded underline. */
.zavel-designer-card-meta {
	display: flex;
	flex: 1;
	flex-direction: column;
}

.zavel-designer-card-meta h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(2.2rem, 3vw, 3.4rem);
	font-weight: 400;
	letter-spacing: -0.02em;
	margin: 0 0 0.5rem;
}

/* Two lines' room whether the studio wraps or not, so the statements start on
   one baseline across the row. */
.zavel-designer-card-studio {
	color: var(--zavel-charcoal-soft);
	letter-spacing: 0.08em;
	margin: 0 0 1rem;
	min-height: 3.1em;
}

.zavel-designer-card-statement {
	color: var(--zavel-charcoal-soft);
	font-family: var(--wp--preset--font-family--serif);
	font-size: 1.15rem;
	line-height: 1.4;
	margin: 0 0 1.5rem;
	max-width: 24rem;
}

.zavel-designer-card-cta {
	align-self: flex-start;
	margin-top: auto;
}

/* One studio is a record rather than a card in a row of four. Left in the grid
   it took 326 pixels of a 1,354 pixel line at 1440 and read as a page waiting
   for the other three, so it takes the whole line and the prose takes the width
   the card was denying it, which is the pairing the designer page already uses.
   Bounded to one pixel above the width where the grid stacks and the portrait
   turns landscape, so the rules below never have to undo it and the record
   never runs at the frame it was not composed for. */
@media (min-width: 56.3125rem) {
	.zavel-designer-card:only-child {
		align-items: center;
		column-gap: clamp(2.5rem, 5vw, 5rem);
		display: grid;
		grid-column: 1 / -1;
		grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
	}

	.zavel-designer-card:only-child .zavel-designer-card-image {
		margin-bottom: 0;
	}

	/* The reserved studio line and the stranded call to action both exist to
	   hold a row to one baseline, and a record has no row to hold. */
	.zavel-designer-card:only-child .zavel-designer-card-studio {
		min-height: 0;
	}

	.zavel-designer-card:only-child .zavel-designer-card-cta {
		margin-top: 1rem;
	}

	.zavel-designer-card:only-child .zavel-designer-card-meta h2 {
		font-size: clamp(3.4rem, 5vw, 5.2rem);
	}

	.zavel-designer-card:only-child .zavel-designer-card-statement {
		font-size: 1.4rem;
		max-width: 32rem;
	}
}

/* The numbered collection, over the night photograph. The image is darkened in
   both editions, because the copy is ivory on it either way; the wash is
   heaviest under the copy and lifts where the mirror is, so the piece reads. */
.zavel-numbered-section {
	color: var(--zavel-ivory);
	min-height: min(50rem, 80svh);
	overflow: hidden;
	position: relative;
}

/* The panel is dark in both editions, so everything in it reads the panel's own
   foreground. A link otherwise takes the page's, which is black on black here. */
.zavel-numbered-section a {
	color: var(--zavel-ivory);
}

/* In Nocturne the panel and the page are nearly one tone, and the edge is all
   that still says panel. */
[data-theme="nocturne"] .zavel-numbered-section {
	border-top: 1px solid var(--zavel-line);
}

.zavel-numbered-section > img {
	display: block;
	filter: brightness(0.6) saturate(0.85);
	height: 100%;
	inset: 0;
	object-fit: cover;
	object-position: center center;
	position: absolute;
	width: 100%;
}

/* The wash darkens the photograph for the ivory copy and lifts where the mirror
   is. It carried a champagne radial over the mirror as well, at 0.12, which was
   a metallic gradient on a brand whose principles name metallic gradients among
   the things it does not use. The photograph's own light is what should lift
   there, so the radial is gone rather than dimmed. */
.zavel-numbered-overlay {
	background: linear-gradient(90deg, rgba(15, 14, 12, 0.86), rgba(15, 14, 12, 0.62) 40%, rgba(15, 14, 12, 0.14) 62%, rgba(15, 14, 12, 0.72));
	inset: 0;
	position: absolute;
}

/* The end inset belongs in the max-width, not in a right: a right stretches the
   box to both insets and 53rem then clamps it wider than the shrink-to-fit was,
   which moves the copy on the widths this is not meant to touch. */
.zavel-numbered-copy {
	left: var(--zavel-page-inset);
	max-width: min(53rem, calc(100% - var(--zavel-page-inset) * 2));
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	z-index: 2;
}

.zavel-numbered-copy .zavel-eyebrow {
	color: var(--zavel-ivory);
}

.zavel-numbered-copy h2 {
	font-family: var(--wp--preset--font-family--serif);
	font-size: var(--wp--preset--font-size--display-large);
	font-weight: 400;
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 1.25rem 0 1.75rem;
	text-wrap: balance;
}

.zavel-numbered-copy > p:not(.zavel-eyebrow) {
	color: rgba(248, 243, 232, 0.76);
	font-family: var(--wp--preset--font-family--serif);
	font-size: clamp(1.25rem, 1.8vw, 1.75rem);
	max-width: 33rem;
}

.zavel-numbered-copy .zavel-light-link {
	margin-top: 1.5rem;
}

.zavel-numbered-edition {
	letter-spacing: 0.1em;
}

/* Six is the whole catalog, so the counts below it are its divisors: three, then
   two. Any other count leaves one card alone on a row of its own. */
@media (max-width: 70rem) {
	.zavel-collection-shelf-grid {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}

	/* Six columns rather than ten: two columns of ten is 140 pixels here, and a
	   price under a designer's name does not set in it. The two plates of the
	   first row are the same width now, so they are also the same ratio. */
	.zavel-editorial-grid {
		grid-template-columns: repeat(6, minmax(0, 1fr));
	}

	.zavel-tile-main,
	.zavel-tile-detail {
		grid-column: span 3;
	}

	.zavel-tile-detail .zavel-tile-image {
		aspect-ratio: 1.78 / 1;
	}

	.zavel-designer-story .zavel-provenance {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}

@media (max-width: 56.25rem) {
	/* A landscape plate at 16:10 on a phone is a strip that crops the mirror
	   out. The crop follows the founding edition's shape, with the record's
	   focal position: tall mirrors take a portrait, circles a square, and the
	   horizontal one keeps the strip because it is the only crop that holds it.
	   The designer portrait is already 4:5 and is left alone. */
	.zavel-hero:not(.zavel-designer-hero) .zavel-hero-image img {
		aspect-ratio: 4 / 5;
	}

	.zavel-hero.zavel-hero-shape-circular .zavel-hero-image img,
	.zavel-hero.zavel-hero-shape-drawn-light .zavel-hero-image img {
		aspect-ratio: 1 / 1;
	}

	.zavel-hero.zavel-hero-shape-horizontal .zavel-hero-image img {
		aspect-ratio: 16 / 10;
	}

	.zavel-hero-photo {
		object-position: 62% center;
	}

	/* Stacked, the copy sits over the bottom of the photograph rather than
	   beside it, so the wash has to run down instead of across. */
	.zavel-hero-wash {
		background: linear-gradient(rgba(0, 0, 0, 0) 28%, rgba(239, 233, 223, 0.72) 56%, rgba(239, 233, 223, 0.97) 100%);
	}

	.zavel-hero-variant-nocturne .zavel-hero-wash {
		background: linear-gradient(rgba(14, 12, 10, 0.04) 24%, rgba(14, 12, 10, 0.55) 58%, rgba(14, 12, 10, 0.9) 100%);
	}

	.zavel-hero-content {
		bottom: 6.8rem;
		left: var(--wp--preset--spacing--page-padding);
		max-width: none;
		right: var(--wp--preset--spacing--page-padding);
		width: auto;
	}

	.zavel-home-hero h1 {
		font-size: clamp(2.9rem, 12vw, 4.7rem);
		max-width: 100%;
	}

	.zavel-hero-lead {
		max-width: 30rem;
	}

	.zavel-scroll-cue {
		display: none;
	}

	.zavel-home-hero .zavel-hero-product-label {
		bottom: 1.2rem;
		left: var(--wp--preset--spacing--page-padding);
		max-width: calc(100% - 2 * var(--wp--preset--spacing--page-padding));
		right: auto;
		text-align: left;
	}

	/* The shelf becomes a snapping rail rather than a grid, because six cards at
	   a legible size do not fit a phone and stacking them buries the rest of the
	   page. It bleeds to the right edge only, so the first card starts on the
	   page gutter under the label, and the trailing padding is what lets the
	   last card clear the edge. A leading padding would sit outside the
	   snapport, and the mandatory snap would scroll the gutter away again. */
	.zavel-collection-shelf-grid {
		gap: 0.8rem;
		grid-template-columns: repeat(6, minmax(17rem, 72vw));
		margin-right: calc(var(--wp--preset--spacing--page-padding) * -1);
		overflow-x: auto;
		padding: 0 var(--wp--preset--spacing--page-padding) 0.7rem 0;
		scroll-snap-type: x mandatory;
		scrollbar-width: none;
	}

	.zavel-collection-shelf-grid::-webkit-scrollbar {
		display: none;
	}

	.zavel-collection-shelf-grid > a {
		scroll-snap-align: start;
	}

	.zavel-split-heading {
		align-items: start;
		grid-template-columns: 1fr;
	}

	/* The hero h1 scales at 12vw below this width, and every section heading
	   has to stay under 0.85 of it, so the two heading tiers scale with it here
	   rather than sitting on their desktop minimums. */
	.zavel-classification-intro h2,
	.zavel-numbered-copy h2 {
		font-size: clamp(2.3rem, 10vw, 3.9rem);
	}

	.zavel-split-heading h2,
	.zavel-designer-story h2 {
		font-size: clamp(2.1rem, 9vw, 3.3rem);
	}

	/* The lead and the study take the width; the other five are pairs, because
	   five plates at full width is the screen and a half this tier gave back. */
	.zavel-editorial-grid {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.zavel-tile-main,
	.zavel-tile-detail {
		grid-column: 1 / -1;
	}

	.zavel-tile-small {
		grid-column: span 1;
	}

	/* Alone across the width there is no row to match, and a 1.54 plate is a
	   strip at phone width; the lead keeps the near-square frame it had, and the
	   study goes back to a landscape one rather than filling the fold. */
	.zavel-tile-main .zavel-tile-image {
		aspect-ratio: 1.06 / 1;
	}

	.zavel-tile-detail .zavel-tile-image {
		aspect-ratio: 1.35 / 1;
	}

	.zavel-designer-section {
		grid-template-columns: 1fr;
	}

	.zavel-designer-portrait {
		height: clamp(30rem, 96vw, 56rem);
		min-height: 0;
	}

	.zavel-designer-portrait img {
		object-position: center 46%;
	}

	/* One card per row, and the portrait turns landscape, because a 0.86 frame
	   at full width is taller than the viewport. The reference does the same. */
	.zavel-designer-index-grid {
		gap: 4rem;
		grid-template-columns: 1fr;
	}

	.zavel-designer-card-image {
		aspect-ratio: 1.05;
	}

	/* Stacked, the copy sits over the whole photograph, mirror included, so the
	   wash runs down and stays heavy enough for the copy, and the crop follows
	   the mirror the way the hero's does. */
	.zavel-numbered-section > img {
		object-position: 62% center;
	}

	.zavel-numbered-overlay {
		background: linear-gradient(rgba(15, 14, 12, 0.6), rgba(15, 14, 12, 0.8));
	}
}

@media (max-width: 42.5rem) {
	/* The label and the consultation link both wrap on a phone, and
	   space-between then has no space to distribute, so the two sat against
	   each other with the link's rule running under both. Stacked, the link is
	   its own row and reads as the door it is. */
	.zavel-collection-shelf-heading {
		align-items: flex-start;
		flex-direction: column;
		gap: 0.75rem;
	}

	.zavel-hero-actions {
		align-items: stretch;
		flex-direction: column;
	}

	.zavel-hero-actions .zavel-text-link {
		align-self: flex-start;
	}

	.zavel-hero-kicker {
		margin-bottom: 1rem;
	}

	.zavel-hero-lead {
		font-size: 1.15rem;
	}

	.zavel-designer-index-hero h1 {
		font-size: clamp(3.4rem, 15vw, 4.8rem);
	}

	/* The meta stops being two columns. Side by side the name column was down to
	   two words a line, "Edition of / 60" and "Mara / Saldanha", and the price
	   column had taken two thirds of the row. */
	.zavel-tile-meta {
		flex-direction: column;
		gap: 0.75rem;
	}

	.zavel-tile-meta > div:last-child {
		text-align: left;
	}

	.zavel-designer-story .zavel-provenance {
		grid-template-columns: 1fr;
	}

	.zavel-designer-story {
		padding: 3rem var(--wp--preset--spacing--page-padding);
	}

	.zavel-numbered-section {
		min-height: 40rem;
	}

	.zavel-numbered-edition {
		left: var(--wp--preset--spacing--page-padding);
		right: auto;
		text-align: left;
	}
}

/* Enquiry and footer */

/* The enquiry closes the panel the way the badge opens its last section: a
   rule, then the copy, the action, and the address as text so it can be copied. */
.zavel-enquiry {
	border-top: 1px solid var(--zavel-line);
	margin-top: 2.5rem;
	padding-top: 1.5rem;
}

.zavel-enquiry .zavel-secondary-prose {
	margin: 0.75rem 0 0;
	max-width: 26rem;
}

.zavel-enquiry .zavel-button {
	margin-top: 1.25rem;
}

.zavel-enquiry-address {
	color: var(--zavel-charcoal-soft);
	overflow-wrap: anywhere;
}

/* The edition alerts page's list: one hairline row per edition, the edition
   and its lead time at the prose tier and the follow action at the label tier,
   the way an edition card pairs its copy with its continuation. */
.zavel-alerts-list {
	border-top: 1px solid var(--zavel-line);
	list-style: none;
	margin: 1.5rem 0 0;
	padding: 0;
}

.zavel-alerts-row {
	align-items: baseline;
	border-bottom: 1px solid var(--zavel-line);
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	justify-content: space-between;
	margin: 0;
	padding: 0.85rem 0;
}

.zavel-alerts-edition {
	flex: 1 1 18rem;
}

.zavel-alerts-edition a {
	color: inherit;
	text-underline-offset: 0.18em;
}

/* The row's rhythm is the text's, but the target is the theme's 44 pixels: the
   padding is taken back by the margin so the rule spacing does not move. */
.zavel-alerts-follow {
	margin-block: -0.9rem;
	padding-block: 0.9rem;
	white-space: nowrap;
}

.zavel-alerts-collection {
	margin-top: 1.5rem;
}

.zavel-alerts-collection .zavel-secondary-prose {
	margin: 0.75rem 0 0;
	max-width: 32rem;
}

.zavel-edition-card-copy .zavel-text-link {
	margin-top: 0.5rem;
}

/* The edition page's closing act, after the record body: a hairline inset to
   the page padding, the enquiry beside the consultation, and the authored
   lateral as its own beat. The prose measure matches the profile summary's. */
.zavel-closing {
	border-top: 1px solid var(--zavel-line);
	margin: 0 var(--wp--preset--spacing--page-padding);
	padding: var(--wp--preset--spacing--section-space) 0;
}

.zavel-closing .zavel-secondary-prose {
	margin: 0;
	max-width: 34rem;
}

.zavel-closing-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 1rem 2.5rem;
	margin-top: 1.75rem;
}

.zavel-closing .zavel-enquiry-address {
	margin-top: 0.75rem;
}

.zavel-closing-note {
	margin-top: 2.5rem;
}

.zavel-closing-note .zavel-secondary-prose {
	margin-bottom: 0.5rem;
}

.zavel-numbered-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem 2.5rem;
	margin-top: 1.5rem;
}

.zavel-numbered-actions .zavel-light-link {
	margin-top: 0;
}

/* The three headings and first actions share a baseline. On phones the two
   navigation groups sit above the full-width contact group. */
.zavel-footer-groups {
	display: grid;
	gap: 2rem 1.5rem;
	grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.3fr);
}

.zavel-footer-group {
	align-items: flex-start;
	display: flex;
	flex-direction: column;
	gap: 1.25rem;
	min-width: 0;
}

/* Core's flow margins otherwise push the navigation below the other lists. */
.zavel-footer-groups > *,
.zavel-footer-group > *,
.zavel-footer-discover-links > * {
	margin-block: 0;
}

.zavel-footer-discover-links {
	display: grid;
	gap: 0.5rem;
}

.zavel-footer-groups .zavel-footer-nav ul,
.zavel-footer-links {
	align-items: flex-start;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.zavel-footer-group a {
	font-size: clamp(0.875rem, 0.82rem + 0.2vw, 1rem);
	line-height: 1.5;
	text-decoration: none;
}

.zavel-footer-contact {
	border-top: 1px solid var(--zavel-line);
	grid-column: 1 / -1;
	padding-top: 1.5rem;
}

.zavel-footer-group .zavel-footer-contact-list {
	gap: 1.25rem;
}

.zavel-footer .zavel-footer-contact .zavel-footer-contact-list a {
	align-items: flex-start;
	flex-direction: column;
	gap: 0.125rem;
}

.zavel-footer-contact-name {
	color: var(--zavel-charcoal-soft);
}

.zavel-footer-contact-value {
	font-variant-numeric: tabular-nums;
}

@media (min-width: 48rem) {
	.zavel-footer-groups {
		column-gap: clamp(1.5rem, 3vw, 3rem);
		grid-template-columns: repeat(3, minmax(0, 1fr));
		justify-self: stretch;
	}

	.zavel-footer-contact {
		border-top: 0;
		grid-column: auto;
		padding-top: 0;
	}
}

/* Every footer link is a 24 pixel target at least, at its tier's own size; the
   review measured them at 18 to 20. Specific enough to win against the
   navigation block's own item rule. */
.zavel-footer .zavel-footer-group a,
.zavel-footer .zavel-footer-bottom a {
	align-items: center;
	display: inline-flex;
	min-block-size: 1.5rem;
}

.zavel-footer .zavel-footer-group a {
	align-items: flex-start;
}

.zavel-footer .zavel-footer-contact .zavel-footer-form-link {
	align-items: center;
	justify-content: space-between;
	gap: 1rem;
	min-block-size: 3rem;
	width: 100%;
	max-width: 18rem;
	padding: 0.75rem 1rem;
	border: 1px solid var(--zavel-charcoal-soft);
	color: var(--zavel-charcoal);
	text-decoration: none;
}

.zavel-footer .zavel-footer-contact .zavel-footer-form-link:hover {
	background: var(--zavel-paper-soft);
}

.zavel-footer .zavel-footer-contact .zavel-footer-form-link:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 4px;
}

/* WCAG 2.5.8 is met everywhere on the site and its minimum is 24 pixels, which
   is what a text action, a footer link and a breadcrumb crumb measure. On a
   phone the same visitor meets 63 pixels in the menu panel and 24 everywhere
   else, so below the width at which the header becomes that menu every one of
   them reaches 44 with its type and the rhythm around it unmoved.

   Two mechanisms, because the two kinds of control fail differently. A link
   that draws nothing against its own box takes the height itself and the
   column it sits in simply grows. A link that draws its own underline cannot:
   the rule is positioned against the box and would strand itself below the
   words, so the reach is a pseudo element and the box stays the size the
   composition was measured at. The percentage resolves against the link's own
   height, so the area is 44 whichever tier the link is set in. */
@media (max-width: 56.25rem) {
	.zavel-breadcrumb a,
	.zavel-footer .zavel-footer-bottom a,
	.zavel-footer .zavel-footer-group a {
		min-block-size: 2.75rem;
	}

	.zavel-collection-shelf-heading a,
	.zavel-light-link,
	.zavel-section-link,
	.zavel-text-link {
		position: relative;
	}

	.zavel-collection-shelf-heading a::before,
	.zavel-light-link::before,
	.zavel-section-link::before,
	.zavel-text-link::before {
		content: "";
		inset: calc((2.75rem - 100%) / -2) 0;
		position: absolute;
	}

	/* Extend the language link's touch target without changing its text layout.
	   The edition buttons already have full 44px boxes. */
	.zavel-language-switch a {
		position: relative;
	}

	.zavel-language-switch a::before {
		content: "";
		inset: calc((2.75rem - 100%) / -2) min(0px, calc((2.75rem - 100%) / -2));
		position: absolute;
	}
}

/* Pages. The template renders the content alone, so a page opens with the
   page-hero pattern's label and title rather than a title the template prints,
   and the editor's constrained column is the measure. */
.zavel-page-main {
	padding-bottom: var(--wp--preset--spacing--section-space);
}

.zavel-page-main .has-page-title-font-size {
	letter-spacing: -0.045em;
	line-height: 0.96;
	margin: 0.75rem 0 0;
}

.zavel-page-main .has-display-font-size {
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0.75rem 0 0;
}

.zavel-page-main .has-title-font-size {
	margin: 0 0 0.5rem;
}

.zavel-page-main ol,
.zavel-page-main ul {
	padding-left: 1.25rem;
}

.zavel-page-main li + li {
	margin-top: 0.5rem;
}

/* Catalog copy and cards */
.zavel-edition-card-detail {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

.zavel-edition-card-copy .zavel-index-badge {
	margin-top: 1.5rem;
}

.zavel-continuation-links {
	display: flex;
	flex-wrap: wrap;
	gap: 1rem 2.5rem;
	margin-top: 3rem;
}

.zavel-continuation + .zavel-continuation-links {
	margin-top: 1.5rem;
}

/* The Guided Consultation: the room launchers and Step 01.
   Measured from the reference implementation's `.rooms-section` and
   `.composer-section` at 1440 by 900 rather than described from them. Two things
   are deliberately not carried across. The display sizes are this theme's, which
   already runs a quieter type scale than the reference: the ratios between a
   room name, a step heading and a section heading are the reference's, the
   absolute sizes are the preset scale's. And the label tier is this theme's one
   tier, 650 at 0.08em, where the reference tracks the same labels between 0.05em
   and 0.14em depending on where they sit. */

/* A control the keyboard needs and the layout does not. The objective radios
   are the first of these; the module's announcement regions are the next. */
.zavel-visually-hidden {
	clip-path: inset(50%);
	height: 1px;
	overflow: hidden;
	position: absolute;
	white-space: nowrap;
	width: 1px;
}

/* The consultation. The composition stops at the content cap and centres,
   because a preview column whose width follows the viewport outgrows the height
   it shares with the controls. */
.zavel-composer-section {
	--zavel-anchor-offset: calc(var(--zavel-anchor-reserve) + 1rem);

	background: var(--zavel-surface-interactive);
	display: grid;
	grid-template-columns: minmax(28rem, 1.06fr) minmax(0, 0.94fr);
	padding-inline: max(0px, calc((100% - var(--zavel-content-max)) / 2));
}

/* The fixed header would otherwise park the open step underneath itself, and a
   step is landed on rather than scrolled to: every launcher addresses it. */
#composer {
	scroll-margin-top: var(--zavel-anchor-offset);
}

.zavel-composer-copy {
	padding: clamp(4rem, 6vw, 7rem) var(--wp--preset--spacing--page-padding);
}

/* The display measure is expressed in em rather than ch: a ch is the width of
   the current font's zero, so a fallback serif resolves a different measure and
   the section reflows by a line when the web font swaps in. It is 5.3em rather
   than the reference's 4.53em because this theme tracks a display heading at
   -0.03em where the reference tracks it at -0.045em, and the same measure took
   the heading to five lines and one word each. */
.zavel-composer-copy h2 {
	font-size: var(--wp--preset--font-size--display);
	letter-spacing: -0.03em;
	line-height: 1;
	margin: 0.9rem 0 1.5rem;
	max-width: 5.3em;
}

.zavel-composer-introduction {
	max-width: 42rem;
}

.zavel-composer-room-context {
	color: var(--zavel-charcoal-soft);
	margin: 0.75rem 0 0;
}

/* Aligned to the block width of the introduction above it. */
.zavel-composer-entry-note {
	border-left: 1px solid var(--zavel-line);
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.65;
	margin: 1.4rem 0 0;
	max-width: 31rem;
	padding-left: 1rem;
}

/* A wrapping sequence rather than five columns: a legible step label is wider
   than a fifth of the control column at every desktop width below about 1500
   pixels, and a column that narrow can only hold it by breaking the word.

   Equal columns rather than a flex row, because each step's rule is its own
   width: content-sized columns gave five rules of five different lengths and a
   sequence that reads as five rules of five lengths does not read as progress.
   Two columns wrap five steps 2, 2, 1; three wrap them 3, 2. */
.zavel-composer-progress {
	border-bottom: 1px solid var(--zavel-line);
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.55rem 1.3rem;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	list-style: none;
	margin: clamp(2rem, 4vw, 4rem) 0 1.5rem;
	padding: 0.8rem 0 0.6rem;
}

/* Three columns from the width at which they fit, because a wrapping sequence
   wraps where the words run out rather than where the sequence divides: at 1440
   the five labels and their gaps want 752 pixels of a 669 pixel column, so the
   row broke four and one and the fifth step read as one added late. Three
   columns of content width take 508 there, which is why the rule opens at 70rem
   rather than at the width two columns stop being the honest division. */
@media (min-width: 70rem) {
	.zavel-composer-progress {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}

/* The rule sits above the label so a wrapped line reads as its own row of steps
   rather than as an underline pressed against the line beneath it. */
.zavel-composer-progress li {
	border-top: 2px solid var(--zavel-line);
	color: var(--zavel-charcoal-soft);
	padding-top: 0.45rem;
	transition: border-top-color 0.18s ease;
}

.zavel-composer-progress li[aria-current="step"] {
	border-top-color: var(--zavel-gold);
	color: var(--zavel-charcoal);
	font-weight: 650;
}

.zavel-composer-progress li span {
	margin-right: 0.3rem;
}

.zavel-composer-step-kicker {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

/* Two columns keep the study beside the step, so the echo below has nothing
   to add here. */
.zavel-composer-summary {
	display: none;
}

.zavel-composer-panel h3 {
	font-size: clamp(1.7rem, 2.6vw, 2.6rem);
	margin: 0.6rem 0 1.6rem;
	max-width: 6.8em;
}

.zavel-composer-form {
	margin: 0;
}

/* The room, which qualifies the ranking rather than deciding it, so it is a row
   of six compact options above the objectives rather than a sixth objective
   among them. It carries no rule of its own: the objectives open on one
   directly beneath, and two rules a third of a viewport apart would read as two
   sections rather than as one step. */
.zavel-composer-rooms {
	border: 0;
	margin: 0.4rem 0 0;
	min-inline-size: 0;
	padding: 0;
}

.zavel-composer-rooms legend {
	color: var(--zavel-charcoal-soft);
	padding: 0;
}

/* Three equal columns rather than a wrapping row: six labels of six lengths
   wrap five and one, and a sixth option that reads as an afterthought is the
   wrong thing to say about a bathroom. The cells share their borders the way
   the light picker's do, because it is the same kind of answer. */
.zavel-composer-room-options {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	margin-top: 0.7rem;
}

/* The radio stays in the document for the state, the keyboard and the
   announcement, exactly as the objectives' does, and only its own box leaves
   the layout. */
.zavel-composer-room-option {
	align-items: center;
	border: 1px solid var(--zavel-line);
	cursor: pointer;
	display: flex;
	margin: 0 -1px -1px 0;
	min-height: 2.75rem;
	padding: 0 0.9rem;
	position: relative;
	transition: background-color 0.18s ease, border-color 0.18s ease;
}

.zavel-composer-room-options input {
	block-size: 1px;
	inline-size: 1px;
	margin: 0;
	opacity: 0;
	position: absolute;
}

/* Marked the way the objective rows beneath are marked rather than inverted the
   way the light picker is. The group opens on an option, so inversion would put
   the loudest element on the step on the answer the visitor has not given yet,
   above the decision the ranking actually depends on. Three signals carry the
   selection and none of them is colour alone: the mark, the weight, and the
   darker edge. */
.zavel-composer-room-option:has(input:checked) {
	border-color: var(--zavel-charcoal);
	font-weight: 650;
	padding-left: 1.6rem;
	z-index: 1;
}

.zavel-composer-room-option:has(input:checked)::before {
	animation: zavel-goal-mark 0.2s cubic-bezier(0.2, 0.7, 0.2, 1) both;
	background: var(--zavel-gold);
	content: "";
	height: 0.42rem;
	left: 0.9rem;
	position: absolute;
	top: calc(50% - 0.21rem);
	width: 0.42rem;
}

.zavel-composer-room-option:has(input:focus-visible) {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

/* A fieldset defaults to a min-content minimum width, which a grid or flex
   parent then refuses to shrink below. */
.zavel-composer-goals {
	border: 0;
	border-top: 1px solid var(--zavel-line);
	margin: 1.8rem 0 0;
	min-inline-size: 0;
	padding: 0;
}

.zavel-composer-goal {
	align-items: center;
	border-bottom: 1px solid var(--zavel-line);
	cursor: pointer;
	display: flex;
	gap: 0.85rem;
	min-height: 3.5rem;
	padding: 0 0.3rem;
	position: relative;
}

/* The radio carries the state, the keyboard and the announcement, so it stays
   in the document and only its own box leaves the layout. The reference draws
   this control as a pressed button, which needs scripts to mean anything; a
   radio in a GET form means the same thing without them. */
.zavel-composer-goals input {
	block-size: 1px;
	inline-size: 1px;
	margin: 0;
	opacity: 0;
	position: absolute;
}

.zavel-composer-goal:has(input:checked) {
	font-weight: 650;
	padding-left: 1rem;
}

.zavel-composer-goal:has(input:checked)::before {
	animation: zavel-goal-mark 0.2s cubic-bezier(0.2, 0.7, 0.2, 1) both;
	background: var(--zavel-gold);
	content: "";
	height: 0.42rem;
	left: 0.29rem;
	position: absolute;
	top: calc(50% - 0.21rem);
	width: 0.42rem;
}

@keyframes zavel-goal-mark {
	from {
		opacity: 0;
		transform: scale(0.4);
	}

	to {
		opacity: 1;
		transform: scale(1);
	}
}

.zavel-composer-goal:has(input:focus-visible) {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

/* Drawn in the emblem's language so the objectives stop reading as plain rows.
   The label always carries the meaning, so the mark is decorative reinforcement. */
.zavel-objective-mark {
	flex: none;
	height: 2.2em;
	width: 2.2em;
}

.zavel-composer-objective-note {
	border-left: 1px solid var(--zavel-clay);
	margin-top: 1.4rem;
	padding-left: 1rem;
}

.zavel-composer-objective-note p,
.zavel-composer-study-behavior p {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.55;
	margin: 0.35rem 0 0;
	max-width: 34rem;
}

.zavel-composer-step-actions {
	align-items: center;
	display: flex;
	gap: 1rem;
	justify-content: flex-end;
	margin-top: 2rem;
}

.zavel-composer-step-actions .zavel-button {
	margin-top: 0;
	min-width: 12rem;
}

/* What the disabled action is waiting for, on the row's leading edge so the
   sentence and the control it explains are read in that order. It takes the
   whole row once the row wraps, which is what keeps `Back` beside the action
   rather than under the sentence. */
.zavel-composer-step-hint {
	color: var(--zavel-charcoal-soft);
	flex: 1 1 14rem;
	font-size: var(--wp--preset--font-size--secondary);
	line-height: 1.55;
	margin: 0;
	max-width: 24rem;
}

/* The way back to an interrupted draft, under the entry step's heading. One
   sentence and one action; it leaves with the visitor's first move. */
.zavel-composer-draft-offer {
	align-items: baseline;
	display: flex;
	flex-wrap: wrap;
	gap: 0.35rem 1.5rem;
	margin-top: 1.25rem;
}

.zavel-composer-draft-offer .zavel-secondary-prose {
	margin: 0;
}

/* Evidence rather than decoration, so it stays with the control that changes
   it. The inset is the reference's own, small, because the recommended
   edition's photograph is what fills the difference: phase 2 carried the copy
   column's larger padding here only while nothing ranked and there was no
   photograph to put in it. */
.zavel-composer-preview {
	align-content: start;
	align-self: start;
	display: grid;
	gap: clamp(0.9rem, 1.4vw, 1.5rem);
	/* The photograph carries its height from an aspect ratio and its plates are
	   absolute, so it offers the row almost no content to measure. Against this
	   panel's max-height the row then collapsed to a third of the frame while the
	   photograph kept painting its full height over the study card beneath it, and
	   the grid reported that it fitted, so the panel never scrolled either. */
	grid-auto-rows: max-content;
	max-height: calc(100svh - var(--zavel-anchor-offset));
	overflow-y: auto;
	overscroll-behavior: contain;
	padding: clamp(1.25rem, 1.8vw, 1.75rem) var(--wp--preset--spacing--page-padding) clamp(1.25rem, 1.8vw, 1.75rem) 0;
	position: sticky;
	scrollbar-width: thin;
	top: var(--zavel-anchor-offset);
}

.zavel-composer-study {
	background: color-mix(in srgb, var(--zavel-paper) 40%, transparent);
	border: 1px solid var(--zavel-line);
	display: grid;
	gap: clamp(0.9rem, 1.4vw, 1.4rem);
	padding: clamp(1rem, 1.6vw, 1.5rem);
}

.zavel-composer-study-label {
	display: flex;
	gap: 1rem;
	justify-content: space-between;
	margin: 0;
}

.zavel-composer-study-label span + span {
	color: var(--zavel-charcoal-soft);
	font-weight: 400;
}

/* Equal halves, because the drawing's height follows its width and the column
   has a viewport-bounded height to keep. */
.zavel-composer-study-body {
	align-items: center;
	display: grid;
	gap: clamp(1rem, 1.8vw, 1.8rem);
	grid-template-columns: minmax(0, 1fr) minmax(8.5rem, 1fr);
}

/* Both modes share the figure's footprint, so entering a wall replaces the
   behaviour mark with the elevation without resizing the panel. */
.zavel-composer-study-figure {
	align-items: center;
	aspect-ratio: 200 / 132;
	display: flex;
	justify-content: center;
}

.zavel-composer-study-mark {
	height: auto;
	width: min(70%, 12rem);
}

/* What the catalog measures, which is what the section can answer when nothing
   ranks. It spans both columns because six records need the width, and it is
   one element so the module can put it away in one line once it boots. */
.zavel-composer-static {
	border-top: 1px solid var(--zavel-line);
	grid-column: 1 / -1;
	padding: clamp(2.5rem, 4vw, 4rem) var(--wp--preset--spacing--page-padding) clamp(3.5rem, 6vw, 6rem);
}

.zavel-composer-static h3 {
	font-size: var(--wp--preset--font-size--title);
	margin: 0;
}

.zavel-composer-static-note {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.55;
	margin: 0.5rem 0 0;
	max-width: 34rem;
}

/* Six is the whole catalog, so three across leaves two full rows and no card
   alone at the end. */
.zavel-composer-catalog {
	border-top: 1px solid var(--zavel-line);
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	list-style: none;
	margin: 2rem 0 0;
	padding: 0;
}

.zavel-composer-catalog-entry {
	border-bottom: 1px solid var(--zavel-line);
	border-right: 1px solid var(--zavel-line);
	padding: 1.5rem;
}

.zavel-composer-catalog-entry:nth-child(3n) {
	border-right: 0;
}

.zavel-composer-catalog-entry a {
	color: inherit;
	text-decoration: none;
}

.zavel-composer-catalog-entry a:hover h4,
.zavel-composer-catalog-entry a:focus-visible h4 {
	text-decoration: underline 1px;
	text-underline-offset: 0.25em;
}

.zavel-composer-catalog-entry h4 {
	font-size: clamp(1.25rem, 1.6vw, 1.7rem);
	margin: 0;
}

.zavel-composer-catalog .zavel-quickfacts {
	margin: 1.25rem 0 0;
}

/* -----------------------------------------------------------------------------
   The consultation once the module runs.

   Everything above is the shell `includes/consultation.php` prints, which is
   Step 01 and the measured catalog. Everything below belongs to a step the
   shell never reaches, so none of it renders without scripts. Every figure is
   measured from the live reference rather than described from it.
   -------------------------------------------------------------------------- */

/* `hidden` is a display of none in the user agent sheet, which any display in a
   class rule outranks, and the module puts a step, a placeholder, a save row and
   a figure list away with it. Measured: the saved study rendered under the
   placeholder it replaces, because `.zavel-room-study-placeholder` is a grid.
   This is one rule rather than a `display: none` per element so a state added
   later cannot be the one that forgets it. */
.zavel-composer-section [hidden] {
	display: none;
}

/* A step change is a change of state and reads as one, so the step that opens
   rises into place. Only a change: the reference animates every panel it mounts,
   which fades the entry step in on arrival as well, and that is a flash nobody
   asked for on a page they have just landed on. Measured: it also left the
   section's own contrast unmeasurable for the length of the fade, because
   opacity multiplies down onto the glyphs. The module adds the class. */
.zavel-composer-panel.is-entering {
	animation: zavel-composer-panel-in 260ms ease both;
}

@media (prefers-reduced-motion: reduce) {
	.zavel-composer-panel.is-entering {
		animation: none;
	}
}

@keyframes zavel-composer-panel-in {
	from {
		opacity: 0;
		transform: translateY(0.45rem);
	}

	to {
		opacity: 1;
		transform: translateY(0);
	}
}

/* The anchor focuses the open step's heading. A step change driven from the
   keyboard still matches :focus-visible, because the browser's heuristic
   carries the keyboard context through a scripted focus; one driven by a
   pointer does not, and a pointer reader watching the step move gains nothing
   from a ring around its heading. */
.zavel-composer-panel h3:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 5px;
}

/* 1024 pixels of width and 880 of height are what it takes to land the progress
   list above the step without pushing the step's own action out of view, so the
   anchor clears the list only there. Between 901 and 1023 the control column is
   under 430 pixels wide, where a legible placement option needs the whole
   viewport the way the shortest ones do.

   The lead is 7.5rem rather than the reference's 6rem because it is this
   theme's own block that has to clear the header, not the reference's: the
   progress list and its closing margin measure 119 pixels above the step at
   1024 and at 1440, where the reference's measure 96, and 6rem here landed the
   list seven pixels under the header rather than below it. */
@media (min-width: 64rem) and (min-height: 55.0625rem) {
	#composer {
		scroll-margin-top: calc(var(--zavel-anchor-offset) + 7.5rem);
	}
}

.zavel-composer-progress li.is-complete {
	border-top-color: var(--zavel-gold);
}

/* Resuming and starting again are separate doors, so the record names itself
   above them rather than being implied by whichever one is pressed. */
.zavel-composer-saved-resume {
	border-top: 1px solid var(--zavel-line);
	margin-top: 1.5rem;
	padding-top: 0.8rem;
}

.zavel-composer-saved-resume-label {
	margin: 0;
}

.zavel-composer-saved-resume-summary {
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 0.35rem 0 0;
}

.zavel-composer-saved-resume-note {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 0.35rem 0 0;
	max-width: 28rem;
}

/* The row gap clears the focus ring, so a wrapped pair cannot ring one control
   across the box of the one below it. */
.zavel-composer-saved-resume-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem 0.75rem;
	margin-top: 0.4rem;
}

/* A control the layout does not carry, so it states its own face: a button
   inherits neither the family nor the weight of the copy around it. */
.zavel-composer-back {
	background: transparent;
	border: 0;
	color: inherit;
	cursor: pointer;
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 400;
	letter-spacing: 0.08em;
	min-height: 2.8rem;
	padding: 0.5rem 0.75rem;
	text-decoration: underline;
	text-transform: uppercase;
	text-underline-offset: 0.35rem;
}

.zavel-composer-back:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-composer-back:disabled {
	cursor: not-allowed;
	opacity: 0.45;
}

.zavel-composer-step-actions .zavel-button:disabled {
	cursor: not-allowed;
	opacity: 0.45;
}

/* The note and the whole action group wrap against each other, so the buttons
   are never split across lines by the sentence that qualifies them. */
.zavel-composer-save-row {
	align-items: end;
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem 1.5rem;
	margin-top: 2rem;
}

.zavel-composer-save-row .zavel-composer-step-actions {
	flex: 1 1 auto;
	margin-top: 0;
}

.zavel-composer-save-note {
	color: var(--zavel-charcoal-soft);
	flex: 1 1 18rem;
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 0;
}

/* Step 02, the wall and the light. */

.zavel-wall-inputs {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(2, 1fr);
	margin-top: 2rem;
}

.zavel-wall-inputs > label {
	display: grid;
	gap: 0.7rem;
}

.zavel-dimension-input {
	align-items: center;
	border-bottom: 1px solid var(--zavel-charcoal);
	display: grid;
	grid-template-columns: 1fr auto;
}

/* The field is the number and its unit together, so the ring goes around both.
   On the input alone it crossed the `cm` label sitting beside it. */
.zavel-dimension-input:focus-within {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 5px;
}

.zavel-dimension-input input:focus-visible {
	outline: 0;
}

.zavel-dimension-input input {
	appearance: textfield;
	background: transparent;
	border: 0;
	color: var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 2.2rem;
	min-width: 0;
	padding: 0.3rem 0;
	text-transform: none;
	width: 100%;
}

.zavel-dimension-input input::-webkit-inner-spin-button,
.zavel-dimension-input input::-webkit-outer-spin-button {
	appearance: none;
}

.zavel-dimension-input > span {
	color: var(--zavel-charcoal-soft);
}

.zavel-composer-field-note,
.zavel-composer-error {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 0.75rem 0 0;
}

.zavel-composer-error {
	color: var(--zavel-error-text);
}

/* A wall no mirror fits gets advice and a next step rather than a dead control. */
.zavel-composer-advice {
	background: var(--zavel-paper-soft);
	border-left: 1px solid var(--zavel-clay);
	margin-top: 1.25rem;
	padding: 1rem 1.1rem;
}

.zavel-composer-advice p {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.55;
	margin: 0.45rem 0 0;
	max-width: 34rem;
}

.zavel-composer-advice p:first-of-type {
	color: var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 1rem;
}

.zavel-light-picker {
	border: 0;
	margin: 2rem 0 0;
	min-inline-size: 0;
	padding: 0;
}

.zavel-light-picker legend {
	margin-bottom: 0.75rem;
	padding: 0;
}

.zavel-light-picker > div {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
}

.zavel-light-picker button {
	background: transparent;
	border: 1px solid var(--zavel-line);
	color: inherit;
	cursor: pointer;
	display: grid;
	font-family: var(--wp--preset--font-family--sans);
	gap: 0.2rem;
	margin: 0 -1px -1px 0;
	min-height: 4.3rem;
	padding: 0.8rem;
	position: relative;
	text-align: left;
}

.zavel-light-picker button[aria-pressed="true"] {
	background: var(--zavel-charcoal);
	color: var(--zavel-button-text);
}

.zavel-light-picker button:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: -4px;
}

.zavel-light-picker button span {
	font-size: 0.8rem;
	font-weight: 650;
}

/* Inherited rather than coloured, because the selected cell inverts, so opacity
   is what makes the note quieter than the label. 0.8 is where it clears AA
   against the consultation surface; 0.7 measured 4.47:1. */
.zavel-light-picker button small {
	color: inherit;
	font-size: 0.75rem;
	opacity: 0.8;
}

/* Step 03, the three placements. */

.zavel-placement-options {
	border-top: 1px solid var(--zavel-line);
}

.zavel-placement-options > button {
	align-items: center;
	background: transparent;
	border: 0;
	border-bottom: 1px solid var(--zavel-line);
	color: inherit;
	cursor: pointer;
	display: grid;
	font-family: var(--wp--preset--font-family--sans);
	gap: 0.3rem 0.9rem;
	grid-template-columns: 1.5rem 4.5rem minmax(0, 1fr);
	padding: 0.75rem 0.5rem;
	position: relative;
	text-align: left;
	transition: background-color 0.18s ease;
	width: 100%;
}

.zavel-placement-options > button[aria-pressed="true"] {
	background: color-mix(in srgb, var(--zavel-gold) 15%, transparent);
}

.zavel-placement-options > button:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: -4px;
}

.zavel-composer-selection-status {
	border: 1px solid currentcolor;
	padding: 0.18rem 0.34rem;
	position: absolute;
	right: 0.5rem;
	top: 0.45rem;
}

/* Every text row is placed in the third column, so nothing auto-flows back
   under the number when a row is added. */
.zavel-placement-options strong,
.zavel-placement-options small,
.zavel-placement-rank,
.zavel-placement-rationale,
.zavel-placement-options .zavel-composer-selection-status {
	grid-column: 3;
}

/* The marker keeps its corner, and every label gives up the width it occupies,
   selected or not. Without that the two shared the same pixels as soon as a
   label ran past the middle of the row, and reserving the space only on the
   selected option would re-wrap that label at the moment of selection. */
.zavel-placement-options strong {
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 1.05rem;
	font-weight: 450;
	padding-right: 6rem;
}

.zavel-placement-option-number {
	color: var(--zavel-charcoal-soft);
	grid-row: 1 / span 4;
}

.zavel-placement-miniature {
	border: 1px solid var(--zavel-line);
	display: block;
	grid-row: 1 / span 4;
	height: 4.4rem;
	position: relative;
	width: 4.2rem;
}

/* 1.45rem centres the mirror in the 4.2rem miniature. The module supplies the
   offset from the same ratio the study drawing uses, so the two can never
   contradict each other. */
.zavel-placement-miniature::before {
	background: var(--zavel-charcoal);
	border: 1px solid var(--zavel-clay);
	border-radius: 44% 56% 49% 51% / 37% 46% 54% 63%;
	content: "";
	height: 2.8rem;
	left: 1.45rem;
	position: absolute;
	top: 0.75rem;
	transform: translateX(var(--zavel-placement-offset, 0rem));
	transition: transform 0.36s cubic-bezier(0.2, 0.7, 0.2, 1);
	width: 1.25rem;
}

.zavel-placement-miniature.zavel-placement-counterpoint::before {
	top: 1.15rem;
}

.zavel-placement-options small {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
}

.zavel-placement-rank,
.zavel-placement-rationale {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.45;
	margin: 0;
}

/* A measurement rather than a caption, so it is set at full contrast. */
.zavel-placement-options small.zavel-placement-measure {
	color: var(--zavel-charcoal);
}

.zavel-placement-rank > span,
.zavel-placement-rationale > span,
.zavel-composer-alternatives p > span,
.zavel-saved-study-alternatives p > span {
	color: var(--zavel-charcoal);
	margin-right: 0.4rem;
}

/* Only the drawing recedes, so the label and its reason keep full contrast and
   the Unavailable line states the condition. */
.zavel-placement-options > button[data-possible="false"] {
	cursor: not-allowed;
}

.zavel-placement-options > button[data-possible="false"] .zavel-placement-miniature {
	opacity: 0.4;
}

/* Step 04, the recommendation. */

.zavel-composer-curatorial-note {
	color: var(--zavel-charcoal-soft);
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 1rem;
	line-height: 1.5;
	max-width: 38rem;
}

.zavel-composer-recommendation-grid {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	margin: 1.5rem 0 0;
}

.zavel-composer-recommendation-grid > div {
	border-bottom: 1px solid var(--zavel-line);
	min-height: 5.8rem;
	padding: 0.9rem 0.8rem 0.9rem 0;
}

.zavel-composer-recommendation-grid > div:nth-child(odd) {
	border-right: 1px solid var(--zavel-line);
}

.zavel-composer-recommendation-grid > div:nth-child(even) {
	padding-left: 0.8rem;
}

.zavel-composer-recommendation-grid dt,
.zavel-saved-room-study dt {
	color: var(--zavel-charcoal-soft);
}

.zavel-composer-recommendation-grid dd {
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 1rem;
	line-height: 1.3;
	margin: 1rem 0 0;
}

.zavel-composer-position-summary {
	border-left: 1px solid var(--zavel-clay);
	margin-top: 1.4rem;
	padding-left: 1rem;
}

.zavel-composer-position-summary p {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.55;
	margin: 0.35rem 0 0;
	max-width: 34rem;
}

.zavel-composer-ranking {
	border-top: 1px solid var(--zavel-line);
	margin-top: 1.75rem;
}

.zavel-composer-ranking summary {
	cursor: pointer;
	min-height: 2.8rem;
	padding: 0.9rem 0 0.55rem;
}

.zavel-composer-ranking-factors {
	display: grid;
	gap: 0.7rem;
	margin: 0.4rem 0 0;
}

.zavel-composer-ranking-factors dd {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 0.2rem 0 0;
	max-width: 34rem;
}

.zavel-composer-ranking-note {
	border-left: 1px solid var(--zavel-clay);
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 1.1rem 0 0;
	max-width: 34rem;
	padding-left: 0.9rem;
}

/* Each alternative carries the gap and the condition that would close it, so
   the two clauses stay separable rather than running together as one sentence. */
.zavel-composer-alternatives {
	margin-top: 1.4rem;
}

.zavel-composer-alternatives h4 {
	margin: 0;
}

.zavel-composer-alternatives ul,
.zavel-saved-study-alternatives {
	display: grid;
	gap: 1.1rem;
	list-style: none;
	margin: 1rem 0 0;
	padding: 0;
}

.zavel-composer-alternatives strong,
.zavel-saved-study-alternatives strong {
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 1.05rem;
	font-weight: 450;
	margin-right: 0.6rem;
}

.zavel-composer-alternatives p,
.zavel-saved-study-alternatives p {
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.5;
	margin: 0.4rem 0 0;
	max-width: 34rem;
}

/* Step 05, the record. */

.zavel-saved-room-study {
	border: 1px solid var(--zavel-line);
	padding: clamp(1.2rem, 3vw, 2rem);
}

.zavel-saved-study-heading {
	align-items: flex-start;
	border-bottom: 1px solid var(--zavel-line);
	display: flex;
	justify-content: space-between;
	padding-bottom: 1.2rem;
}

.zavel-saved-study-emblem {
	flex: none;
	height: 2.6rem;
	width: 2.2rem;
}

.zavel-saved-room-study h3 {
	font-size: clamp(1.8rem, 3vw, 2.8rem);
	margin: 0.5rem 0 0;
}

.zavel-saved-study-status {
	color: var(--zavel-charcoal-soft);
	margin: 1rem 0;
}

.zavel-saved-study-restated {
	border-left: 1px solid var(--zavel-clay);
	color: var(--zavel-charcoal-soft);
	font-size: 0.8rem;
	line-height: 1.65;
	margin: 0 0 1.4rem;
	max-width: 34rem;
	padding-left: 1rem;
}

.zavel-saved-room-study dl,
.zavel-room-study-placeholder {
	display: grid;
	grid-template-columns: repeat(2, 1fr);
	margin: 0;
}

.zavel-saved-room-study dl > div,
.zavel-room-study-placeholder > div {
	border-top: 1px solid var(--zavel-line);
	min-height: 5.7rem;
	padding: 0.8rem 0.8rem 0.8rem 0;
}

.zavel-saved-room-study dl > div:nth-child(even),
.zavel-room-study-placeholder > div:nth-child(even) {
	border-left: 1px solid var(--zavel-line);
	padding-left: 0.8rem;
}

/* The closing two rows are prose rather than a figure, so they take the full
   width instead of leaving a dead cell beside them. */
.zavel-saved-room-study dl > div:nth-last-child(-n + 2) {
	border-left: 0;
	grid-column: 1 / -1;
	padding-left: 0;
}

.zavel-saved-room-study dd,
.zavel-room-study-placeholder dd {
	font-family: var(--wp--preset--font-family--serif, serif);
	font-size: 0.86rem;
	line-height: 1.4;
	margin: 0.65rem 0 0;
}

/* The decision the study ends in, kept above its revision control: the studio
   and the mirror it chose open here, and editing or starting again is the row
   below. The two rules are the reference's own composition rather than one
   border repeated. */
.zavel-saved-study-handoff {
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 1rem;
	justify-items: start;
	margin-top: 1.75rem;
	padding-top: 1.5rem;
}

/* Both handoffs on one line where there is room for it, wrapping rather than
   shrinking when there is not. The button's own top margin is the air it takes
   when it stands under a rule by itself; here the block's padding is that air,
   and leaving the margin on opens the row 32 pixels taller than the button and
   throws the text link beside it off the button's centre. */
.zavel-saved-study-handoff-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 1.4rem;
	width: 100%;
}

.zavel-saved-study-handoff-actions .zavel-button {
	margin-top: 0;
}

.zavel-saved-study-handoff .zavel-button {
	min-width: 12rem;
}

.zavel-saved-study-handoff-note {
	margin: 0;
	max-width: 34rem;
}

/* The alternatives name editions that are published, so each name is the way
   into its page. The underline is the card's own, rather than the navigation's
   travelling rule, because these sit inside running text. */
.zavel-saved-study-alternatives a {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.22em;
}

.zavel-saved-study-alternatives a:hover {
	text-decoration-color: var(--zavel-clay-deep);
}

.zavel-saved-study-alternatives a:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-saved-study-actions {
	align-items: center;
	border-top: 1px solid var(--zavel-line);
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem 0.75rem;
	margin-top: 1.5rem;
	padding-top: 1rem;
}

/* The preview's own plate. A landscape frame at a fixed ratio: every edition
   photograph is roughly 1.78, so the column height never depends on which
   edition is recommended. */
.zavel-composer-hero {
	aspect-ratio: 16 / 9;
	background: var(--zavel-surface-muted);
	overflow: hidden;
	position: relative;
}

.zavel-composer-hero-plate {
	height: 100%;
	inset: 0;
	object-fit: cover;
	position: absolute;
	width: 100%;
}

.zavel-composer-hero-plate.is-incoming {
	opacity: 0;
	transition: opacity 240ms ease;
}

.zavel-composer-hero-plate.is-incoming[data-revealed="true"] {
	opacity: 1;
}

.zavel-composer-hero-shade {
	background: linear-gradient(
		to bottom,
		color-mix(in srgb, var(--zavel-paper) 14%, transparent),
		color-mix(in srgb, var(--zavel-paper) 4%, transparent)
	);
	inset: 0;
	position: absolute;
}

/* Most of the photography is daylit in both editions, so Nocturne dims the
   plate and keeps the centre band lightest, where the mirror and its reflection
   sit. */
[data-theme="nocturne"] .zavel-composer-hero-shade {
	background: linear-gradient(
		to bottom,
		color-mix(in srgb, var(--zavel-black) 58%, transparent),
		color-mix(in srgb, var(--zavel-black) 34%, transparent) 52%,
		color-mix(in srgb, var(--zavel-black) 62%, transparent)
	);
}

/* Where the edition has a night photograph the preview draws that instead, and
   the wash is there to bring a daylit frame down to the page rather than to
   darken one that was shot dark. It keeps the same shape at roughly a third of
   the weight, so the plate still sits under the copy beside it. */
[data-theme="nocturne"] .zavel-composer-hero[data-plate="nocturne"] .zavel-composer-hero-shade {
	background: linear-gradient(
		to bottom,
		color-mix(in srgb, var(--zavel-black) 20%, transparent),
		color-mix(in srgb, var(--zavel-black) 10%, transparent) 52%,
		color-mix(in srgb, var(--zavel-black) 22%, transparent)
	);
}

/* A solid chip rather than text on the plate, so contrast holds in both
   editions whatever the photograph does behind it. */
/* The Reflection Index over the plate, in the two-line shape the edition
   record's badge already gives it: the system and its code above, the behaviour
   below. */
.zavel-composer-hero-index {
	background: color-mix(in srgb, var(--zavel-paper) 92%, transparent);
	bottom: 0;
	display: grid;
	gap: 0.15rem;
	left: 0;
	margin: 0;
	padding: 0.55rem 0.8rem;
	position: absolute;
}

.zavel-composer-hero-index small {
	color: var(--zavel-charcoal-soft);
	font-weight: 400;
}

/* The elevation, and the figure list that is its text. */

.zavel-composer-study-drawing {
	display: block;
	height: auto;
	width: 100%;
}

/* The module rewrites this drawing's geometry in place rather than rebuilding
   it, so the structure settles into the new wall and the mirror travels to its
   place along it. The mirror is given the longer duration on purpose: it
   arrives last, because where it sits is the measurement the drawing states and
   the rest is the room it is measured against. */
.zavel-study-wall,
.zavel-study-context,
.zavel-study-floor,
.zavel-study-axis,
.zavel-study-eye-level,
g.zavel-study-light line {
	transition: x 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		y 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		width 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		height 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		x1 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		x2 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		y1 0.3s cubic-bezier(0.2, 0.7, 0.2, 1),
		y2 0.3s cubic-bezier(0.2, 0.7, 0.2, 1);
}

.zavel-study-wall {
	fill: none;
	stroke: var(--zavel-charcoal-soft);
	stroke-width: 1;
}

/* Every height in the drawing is measured from this line, so it is the one
   stroke that runs the full frame. */
.zavel-study-floor {
	stroke: var(--zavel-charcoal-soft);
	stroke-width: 1.2;
}

/* The room's own fixture, at the wall's scale, so it reads as a scale reference
   rather than as part of the measured wall. */
.zavel-study-context {
	fill: none;
	stroke: color-mix(in srgb, var(--zavel-charcoal) 34%, transparent);
	stroke-linejoin: miter;
	stroke-width: 1;
}

.zavel-study-axis {
	stroke: color-mix(in srgb, var(--zavel-charcoal) 28%, transparent);
	stroke-dasharray: 3 4;
	stroke-width: 1;
}

/* A finer dash than the wall axis, so the two datums never read as one line. */
.zavel-study-eye-level {
	stroke: color-mix(in srgb, var(--zavel-charcoal) 40%, transparent);
	stroke-dasharray: 1 4;
	stroke-linecap: round;
	stroke-width: 1;
}

/* The element is named because the class is also the placement study page's
   light section, and a bare class selector would paint that section's calendar
   grid gold. The two ray groups are both `g` inside a drawing and always were. */
g.zavel-study-light line {
	stroke: var(--zavel-gold);
	stroke-linecap: square;
	stroke-width: 1.4;
}

.zavel-study-light-ambient {
	opacity: 0.45;
}

.zavel-study-mirror {
	fill: color-mix(in srgb, var(--zavel-ivory) 66%, transparent);
	stroke: var(--zavel-clay);
	stroke-width: 1.6;
	transition: x 0.42s cubic-bezier(0.2, 0.7, 0.2, 1),
		y 0.42s cubic-bezier(0.2, 0.7, 0.2, 1),
		width 0.42s cubic-bezier(0.2, 0.7, 0.2, 1),
		height 0.42s cubic-bezier(0.2, 0.7, 0.2, 1);
}

/* Reduced motion keeps every state cue and drops every journey. The mirror
   still lands where the answer put it and the marks still report themselves;
   nothing travels to get there, and the photographs hold their frame. */
@media (prefers-reduced-motion: reduce) {
	.zavel-study-wall,
	.zavel-study-context,
	.zavel-study-floor,
	.zavel-study-axis,
	.zavel-study-eye-level,
	g.zavel-study-light line,
	.zavel-study-mirror,
	.zavel-placement-miniature::before,
	.zavel-wall-mark::before {
		transition: none;
	}

	.zavel-composer-goal:has(input:checked)::before,
	.zavel-composer-room-option:has(input:checked)::before {
		animation: none;
	}

	.zavel-collection-card-image img,
	.zavel-tile-image img,
	.zavel-designer-card-image img,
	.zavel-classification-draw svg {
		transition: filter 0.36s;
	}

	.zavel-collection-shelf-grid a:hover .zavel-collection-card-image img,
	.zavel-tile:hover .zavel-tile-image img,
	.zavel-designer-card:hover .zavel-designer-card-image img,
	.zavel-classification-card a:hover .zavel-classification-draw svg {
		transform: none;
	}
}

[data-theme="nocturne"] .zavel-study-mirror {
	fill: color-mix(in srgb, var(--zavel-ivory) 20%, transparent);
}

.zavel-composer-study-figures {
	display: grid;
	gap: 0.55rem;
	margin: 0;
}

.zavel-composer-study-figures > div {
	border-bottom: 1px solid var(--zavel-line);
	display: flex;
	gap: 0.6rem;
	justify-content: space-between;
	padding-bottom: 0.4rem;
}

.zavel-composer-study-figures > div:last-child {
	border-bottom: 0;
	padding-bottom: 0;
}

.zavel-composer-study-figures dt {
	color: var(--zavel-charcoal-soft);
}

.zavel-composer-study-figures dd {
	font-size: 0.8rem;
	margin: 0;
	text-align: right;
}

/* What the preview is currently stating, under the card that states it. */
.zavel-placement-note {
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.35rem;
	margin: 0;
	padding-top: 0.85rem;
}

.zavel-placement-note span:last-child {
	color: var(--zavel-charcoal-soft);
}

/* -----------------------------------------------------------------------------
   The wall step, which opens from the recommendation rather than following it.

   The photograph is the visitor's and is never regraded, so nothing here paints
   over it: the chrome takes the edition's tokens and the drawing's own ink is
   fixed in `wall-study.js`, a dark line inside a light one, because a token
   colour would be legible on a pale wall and gone on a dark one.
   -------------------------------------------------------------------------- */

/* A grid rather than flow, so the margins each block carries are its own and
   nothing collapses into the block above it. */
.zavel-wall-study {
	display: grid;
}

/* The active instruction stays with the photograph, then leaves with it. */
.zavel-wall-workspace {
	margin-top: 1.25rem;
	scroll-margin-top: calc(var(--zavel-anchor-offset) + 0.5rem);
}

.zavel-wall-guide {
	align-items: center;
	background: var(--zavel-limestone);
	border: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.65rem 1rem;
	grid-template-columns: 4.5rem minmax(0, 1fr);
	padding: 0.85rem;
	position: sticky;
	top: var(--zavel-anchor-offset);
	z-index: 3;
}

.zavel-wall-guide:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-wall-guide-copy { min-width: 0; }
.zavel-wall-progress { margin: 0; }
.zavel-wall-guide .zavel-wall-status {
	color: var(--zavel-charcoal);
	font-size: 1rem;
	line-height: 1.4;
	margin: 0.3rem 0 0;
}
.zavel-wall-guide-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1rem;
	grid-column: 1 / -1;
}
.zavel-wall-guide-actions:has(> :not([hidden])) { min-height: 2.75rem; }
.zavel-wall-guide-actions .zavel-button { margin: 0; }
.zavel-wall-guide-copy:first-child { grid-column: 1 / -1; }
.zavel-wall-guide:has(.zavel-wall-corner-guide[hidden]) .zavel-wall-guide-copy {
	grid-column: 1 / -1;
}
.zavel-wall-corner-guide {
	border: 1px solid var(--zavel-charcoal-soft);
	height: 3.4rem;
	margin: 0.5rem;
	position: relative;
}
.zavel-wall-corner-number {
	align-items: center;
	background: var(--zavel-limestone);
	border: 1px solid var(--zavel-charcoal-soft);
	border-radius: 50%;
	color: var(--zavel-charcoal);
	display: flex;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.75rem;
	height: 1.5rem;
	justify-content: center;
	position: absolute;
	width: 1.5rem;
}
.zavel-wall-corner-number:nth-child(1) { left: -0.65rem; top: -0.65rem; }
.zavel-wall-corner-number:nth-child(2) { right: -0.65rem; top: -0.65rem; }
.zavel-wall-corner-number:nth-child(3) { right: -0.65rem; bottom: -0.65rem; }
.zavel-wall-corner-number:nth-child(4) { left: -0.65rem; bottom: -0.65rem; }
.zavel-wall-corner-number.is-current {
	background: var(--zavel-charcoal);
	color: var(--zavel-button-text);
	outline: 2px solid var(--zavel-charcoal);
	outline-offset: 2px;
	font-weight: 700;
}
.zavel-wall-corner-number.is-complete { border-width: 2px; }
.zavel-wall-workspace .zavel-wall-stage { margin-top: 0; }
.zavel-wall-tools {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1rem;
	margin-top: 0.5rem;
}
.zavel-wall-size-note { margin: 1.2rem 0 0; }
.zavel-wall-confirm { justify-self: start; margin-top: 1rem; }
.zavel-wall-result-title {
	font-family: var(--wp--preset--font-family--serif);
	font-size: 2rem;
	font-weight: 400;
	margin: 1.5rem 0 0;
}
.zavel-wall-sizes { scroll-margin-top: calc(var(--zavel-anchor-offset) + 1rem); }

.zavel-wall-intro {
	color: var(--zavel-charcoal-soft);
	line-height: 1.55;
	margin: 0;
	max-width: 38rem;
}

.zavel-field-privacy,
.zavel-wall-privacy {
	color: var(--zavel-charcoal-soft);
	line-height: 1.55;
	margin: 0.5rem 0 0;
	max-width: 38rem;
}

/* The row gap clears the focus ring, so a wrapped pair cannot ring one control
   across the box of the one below it. */
.zavel-field-actions,
.zavel-wall-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.6rem 0.75rem;
	margin-top: 1.4rem;
}

/* The file input stays in the document for the keyboard and the announcement,
   exactly as the objectives' radios do, and only its own box leaves the layout. */
.zavel-wall-file {
	cursor: pointer;
	margin-top: 0;
	position: relative;
}

.zavel-wall-file input {
	block-size: 1px;
	inline-size: 1px;
	margin: 0;
	opacity: 0;
	position: absolute;
}

.zavel-wall-file:focus-within {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

/* Two solid buttons side by side would put the same weight on taking a
   photograph and finding one, and the camera is the step's own instruction. */
.zavel-wall-file-quiet {
	background: transparent;
	color: var(--zavel-charcoal);
}

.zavel-wall-file-quiet:hover {
	background: var(--zavel-charcoal);
	color: var(--zavel-button-text);
}

/* The aspect is rewritten from the working copy before the first paint, so the
   photograph arriving never moves the controls under it. */
/* The visitor's room owns the wall step; the stock preview returns on exit. */
.zavel-composer-section:has(.zavel-wall-panel:not([hidden])) {
	grid-template-columns: minmax(0, 1fr);
}
.zavel-composer-section:has(.zavel-wall-panel:not([hidden])) .zavel-composer-preview {
	display: none;
}
.zavel-composer-section:has(.zavel-wall-panel:not([hidden])) .zavel-composer-copy {
	margin-inline: auto;
	max-width: 58rem;
	width: 100%;
}
.zavel-wall-panel h3 { max-width: none; }
.zavel-wall-result-actions {
	align-items: center;
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.3rem;
	margin: 1rem 0;
}
.zavel-wall-result-actions .zavel-button { margin: 0; }
.zavel-wall-details { border-block: 1px solid var(--zavel-line); margin-top: 1.5rem; }
.zavel-wall-details summary {
	cursor: pointer;
	font-size: 0.85rem;
	min-height: 2.75rem;
	padding: 1rem 0;
}
.zavel-wall-details summary:focus-visible,
.zavel-wall-result-title:focus-visible { outline: 2px solid var(--zavel-focus); outline-offset: 3px; }
.zavel-wall-preview-note { color: var(--zavel-charcoal-soft); line-height: 1.6; margin: 0.5rem 0; }
.zavel-wall-stage[data-preview="true"],
.zavel-wall-stage[data-preview="true"] .zavel-wall-canvas { touch-action: pan-y; }
.zavel-wall-mirror-handle {
	background: transparent;
	border: 0;
	cursor: grab;
	min-height: 2.75rem;
	min-width: 2.75rem;
	padding: 0;
	position: absolute;
	touch-action: none;
}
.zavel-wall-mirror-handle:active { cursor: grabbing; }
.zavel-wall-mirror-handle:focus-visible { outline: 2px solid var(--zavel-focus); outline-offset: 5px; border-radius: 1rem; }

.zavel-wall-stage {
	aspect-ratio: 3 / 2;
	background: var(--zavel-limestone);
	margin-top: 1.1rem;
	overflow: hidden;
	position: relative;
	touch-action: none;
	width: 100%;
}

.zavel-wall-canvas {
	display: block;
	height: 100%;
	touch-action: none;
	width: 100%;
}

/* The stage owns every pointer, because a mark is dragged from wherever the
   finger lands rather than from the mark's own box. The keyboard still reaches
   each one: a button with no pointer events is still in the tab order. */
.zavel-wall-mark {
	background: transparent;
	border: 0;
	height: 2.75rem;
	padding: 0;
	pointer-events: none;
	position: absolute;
	transform: translate(-50%, -50%);
	width: 2.75rem;
}

.zavel-wall-mark::before {
	background: var(--zavel-ivory);
	border: 2px solid var(--zavel-black);
	border-radius: 50%;
	content: attr(data-number);
	color: var(--zavel-black);
	display: grid;
	font-family: var(--wp--preset--font-family--sans);
	font-size: 0.75rem;
	font-weight: 700;
	place-items: center;
	height: 1.5rem;
	left: 50%;
	position: absolute;
	top: 50%;
	transform: translate(-50%, -50%);
	transition: height 0.18s ease, width 0.18s ease;
	width: 1.5rem;
}

.zavel-wall-mark:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: -3px;
}

.zavel-wall-mark:focus-visible::before {
	height: 1.75rem;
	width: 1.75rem;
}

.zavel-wall-empty {
	align-items: center;
	color: var(--zavel-charcoal-soft);
	display: flex;
	inset: 0;
	justify-content: center;
	margin: 0;
	padding: 1.5rem;
	pointer-events: none;
	position: absolute;
	text-align: center;
}

.zavel-wall-hint {
	color: var(--zavel-charcoal-soft);
	line-height: 1.5;
	margin: 0.7rem 0 0;
}

/* One line is reserved so the prompts that follow the marks do not move the
   figure list under them on every tap. The reflected field's own status sits
   under the same rule, and under its own class: one selector matching both
   would make either of them ambiguous to address. */
.zavel-field-status,
.zavel-wall-status {
	line-height: 1.5;
	margin: 0.35rem 0 0;
	min-height: 1.5em;
}

.zavel-wall-reference {
	border: 0;
	margin: 1.5rem 0 0;
	min-inline-size: 0;
	padding: 0;
}

.zavel-wall-reference legend {
	color: var(--zavel-charcoal-soft);
	margin-bottom: 0.5rem;
	padding: 0;
}

.zavel-wall-reference > div {
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem 1.5rem;
}

.zavel-wall-reference label {
	align-items: center;
	cursor: pointer;
	display: flex;
	font-family: var(--wp--preset--font-family--sans);
	gap: 0.55rem;
	min-height: 2.75rem;
}

.zavel-wall-reference input {
	accent-color: var(--zavel-gold);
	block-size: 1.1rem;
	inline-size: 1.1rem;
	margin: 0;
}

.zavel-wall-reference label:has(input:focus-visible) {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-wall-sizes {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(2, 1fr);
	margin-top: 1.25rem;
}

.zavel-wall-sizes label {
	display: grid;
	gap: 0.7rem;
}

/* The door's own size only exists while a door is the reference, and it sits
   under the wall it is standing against rather than beside it. */
.zavel-wall-door {
	display: grid;
	gap: 1rem;
	grid-column: 1 / -1;
	grid-template-columns: repeat(2, 1fr);
}

.zavel-wall-choices {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(2, 1fr);
	margin-top: 1.5rem;
}

.zavel-wall-choices > label {
	display: grid;
	gap: 0.7rem;
	margin: 0;
}

/* A select inherits neither the family nor the weight of the copy around it,
   which is the same thing a button does not inherit. */
.zavel-wall-choices select {
	background: transparent;
	border: 0;
	border-bottom: 1px solid var(--zavel-charcoal);
	color: var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--sans);
	min-height: 2.75rem;
	padding: 0.4rem 0;
	width: 100%;
}

.zavel-wall-choices select:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 4px;
}

/* The opening exists only while a pair flanks one, and it belongs to the
   composition that asks for it, so it runs across the choices rather than
   standing apart from them. The two figures and the mark they can be taken
   from are one thing to enter, so they are one row. */
.zavel-wall-opening {
	align-items: end;
	display: grid;
	gap: 1rem;
	grid-column: 1 / -1;
	grid-template-columns: repeat(2, minmax(0, 1fr)) auto;
}

.zavel-wall-opening label {
	display: grid;
	gap: 0.7rem;
	margin: 0;
}

/* The button sits on the same line the two fields are underlined at, rather
   than on the baseline of the labels above them. */
.zavel-wall-opening-mark {
	justify-self: start;
	padding-left: 0;
	white-space: nowrap;
}

/* Every drawing in this step is hidden from assistive technology, so its own
   list is the whole text carrier for the figures it asserts. The light study
   states its findings in the same shape, so the two share the rule rather than
   drifting apart under two copies of it. */
.zavel-light-figures,
.zavel-wall-figures {
	border-top: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.55rem;
	margin: 1.75rem 0 0;
	padding-top: 0.9rem;
}

.zavel-light-figures > div,
.zavel-wall-figures > div {
	border-bottom: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.2rem 1rem;
	grid-template-columns: 8rem minmax(0, 1fr);
	padding-bottom: 0.5rem;
}

.zavel-light-figures > div:last-child,
.zavel-wall-figures > div:last-child {
	border-bottom: 0;
	padding-bottom: 0;
}

.zavel-light-figures dt,
.zavel-wall-figures dt {
	color: var(--zavel-charcoal-soft);
	padding-top: 0.2rem;
}

.zavel-light-figures dd,
.zavel-wall-figures dd {
	font-family: var(--wp--preset--font-family--serif, serif);
	font-variant-numeric: tabular-nums;
	line-height: 1.35;
	margin: 0;
}

.zavel-light-caption,
.zavel-wall-caption {
	border-top: 1px solid var(--zavel-line);
	color: var(--zavel-charcoal-soft);
	margin: 1.2rem 0 0;
	max-width: 40rem;
	padding-top: 0.85rem;
}

.zavel-wall-study .zavel-composer-step-actions {
	justify-content: space-between;
}

/* -----------------------------------------------------------------------------
   The reflected field, which asks for a second photograph after the drawing is
   standing. It is a new action rather than more of the caption, so it opens on
   its own rule under the caption's.
   -------------------------------------------------------------------------- */

.zavel-field-study {
	border-top: 1px solid var(--zavel-line);
	display: grid;
	margin-top: 1.2rem;
	padding-top: 1rem;
}

.zavel-field-kicker {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

/* The plan sits beside the sentence it illustrates and drops above it once the
   two no longer fit, which on a phone is immediately. */
.zavel-field-instruction {
	align-items: start;
	display: flex;
	flex-wrap: wrap;
	gap: 0.9rem 1.25rem;
	margin-top: 0.8rem;
}

/* One user unit to one CSS pixel, the way the light study's rose is fixed, so
   the strokes the study inset sets in pixels read at the weight they were
   drawn at. */
.zavel-field-diagram {
	flex: none;
	height: auto;
	width: 8.25rem;
}

.zavel-field-note {
	flex: 1 1 16rem;
	line-height: 1.55;
	margin: 0;
	max-width: 34rem;
}

/* -----------------------------------------------------------------------------
   The light study, opened from inside the wall step.

   It draws on the panel's own ground rather than over the photograph, so unlike
   the wall's canvas it takes the edition's tokens throughout. The two warm fills
   are the one exception the study inset does not already carry: a sun patch and
   the part of the glass it crosses, mixed from the gold so both editions read
   them as light rather than as another line.
   -------------------------------------------------------------------------- */

.zavel-light-open {
	justify-self: start;
	margin-top: 1.1rem;
	padding-left: 0;
}

.zavel-light-loading {
	color: var(--zavel-charcoal-soft);
	margin: 1rem 0 0;
}

.zavel-light-study {
	border-top: 1px solid var(--zavel-line);
	display: grid;
	margin-top: 0.4rem;
	padding-top: 1.3rem;
}

.zavel-light-heading {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

.zavel-light-status {
	color: var(--zavel-charcoal-soft);
	line-height: 1.5;
	margin: 0.6rem 0 0;
}

.zavel-light-controls {
	display: grid;
	gap: 1.6rem;
	margin-top: 1.3rem;
}

.zavel-light-where {
	border: 0;
	margin: 0;
	min-inline-size: 0;
	padding: 0;
}

.zavel-light-where legend {
	color: var(--zavel-charcoal-soft);
	margin-bottom: 0.35rem;
	padding: 0;
}

.zavel-light-where label {
	align-items: center;
	cursor: pointer;
	display: flex;
	font-family: var(--wp--preset--font-family--sans);
	gap: 0.55rem;
	min-height: 2.75rem;
}

.zavel-light-where input {
	accent-color: var(--zavel-gold);
	block-size: 1.1rem;
	inline-size: 1.1rem;
	margin: 0;
}

.zavel-light-where label:has(input:focus-visible) {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

.zavel-light-coordinates,
.zavel-light-sizes,
.zavel-light-when {
	display: grid;
	gap: 1rem;
	grid-template-columns: repeat(2, minmax(0, 1fr));
}

.zavel-light-coordinates label,
.zavel-light-depth label,
.zavel-light-place > label,
.zavel-light-sizes label,
.zavel-light-time-field,
.zavel-light-when > label {
	display: grid;
	gap: 0.55rem;
	margin: 0;
}

.zavel-light-depth,
.zavel-light-place {
	display: grid;
	gap: 0.7rem;
}

.zavel-light-hint {
	color: var(--zavel-charcoal-soft);
	line-height: 1.5;
	margin: 0;
	max-width: 34rem;
}

.zavel-light-coordinates .zavel-light-hint {
	grid-column: 1 / -1;
}

.zavel-light-compass {
	display: grid;
	gap: 0.7rem;
}

/* The reading and its dial sit on one line, so the point of the compass is read
   beside the control that sets it rather than under the hint below both. */
.zavel-light-dial-row {
	align-items: center;
	display: grid;
	gap: 0.75rem 1rem;
	grid-template-columns: minmax(0, 1fr) auto;
}

.zavel-light-dial-value,
.zavel-light-time-value {
	font-family: var(--wp--preset--font-family--sans);
	font-variant-numeric: tabular-nums;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	white-space: nowrap;
}

/* A range is a full tap target in its own right, which is the height rather
   than the thumb: the box is what a finger lands in. */
.zavel-light-dial,
.zavel-light-time {
	accent-color: var(--zavel-gold);
	background: transparent;
	block-size: 2.75rem;
	inline-size: 100%;
	margin: 0;
}

.zavel-light-dial:focus-visible,
.zavel-light-time:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 4px;
}

.zavel-light-compass-read {
	justify-self: start;
	padding-left: 0;
}

.zavel-light-compass-note {
	color: var(--zavel-charcoal-soft);
	line-height: 1.5;
	margin: 0;
}

.zavel-light-city,
.zavel-light-day {
	background: transparent;
	border: 0;
	border-bottom: 1px solid var(--zavel-charcoal);
	color: var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--sans);
	min-height: 2.75rem;
	padding: 0.4rem 0;
	width: 100%;
}

.zavel-light-city:focus-visible,
.zavel-light-day:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 4px;
}

.zavel-light-drawings {
	display: grid;
	gap: 1.3rem;
	grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
	margin-top: 1.8rem;
}

.zavel-light-figure {
	display: grid;
	gap: 0.5rem;
	margin: 0;
}

.zavel-light-figure figcaption,
.zavel-light-calendar figcaption {
	color: var(--zavel-charcoal-soft);
}

.zavel-light-frame {
	background: var(--zavel-limestone);
	position: relative;
}

.zavel-light-drawing {
	display: block;
	height: auto;
	width: 100%;
}

/* Three rem square with a matching viewBox, so one user unit is one CSS pixel
   and the only glyph inside a drawing here is drawn at the floor exactly. */
.zavel-light-rose {
	block-size: 3rem;
	inline-size: 3rem;
	inset-block-start: 0.4rem;
	inset-inline-end: 0.4rem;
	position: absolute;
}

.zavel-light-needle line {
	stroke: var(--zavel-charcoal-soft);
	stroke-width: 1.2;
}

.zavel-light-needle polygon {
	fill: var(--zavel-charcoal-soft);
}

.zavel-light-north {
	fill: var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--sans);
	font-size: 12px;
	font-weight: 650;
	letter-spacing: 0.08em;
}

.zavel-light-window {
	stroke: var(--zavel-gold);
	stroke-linecap: butt;
	stroke-width: 3;
}

/* The rays follow a slider, so they track it rather than easing after it; the
   study inset's own transition would leave them a third of a second behind. */
g.zavel-study-light line.zavel-light-ray {
	transition: none;
}

.zavel-light-footprint {
	stroke: color-mix(in srgb, var(--zavel-gold) 70%, transparent);
	stroke-linecap: butt;
	stroke-width: 4;
}

.zavel-light-bounce {
	stroke: var(--zavel-clay);
	stroke-dasharray: 2 3;
	stroke-width: 1.2;
}

.zavel-light-reflected {
	fill: var(--zavel-clay);
}

.zavel-light-in-room,
.zavel-light-patch {
	fill: color-mix(in srgb, var(--zavel-gold) 28%, transparent);
	stroke: none;
}

.zavel-light-on-glass {
	fill: color-mix(in srgb, var(--zavel-gold) 55%, transparent);
	stroke: none;
}

/* Both mixes sit on a dark ground in Nocturne, where the same share of gold
   reads as a smudge rather than as light. */
[data-theme="nocturne"] .zavel-light-in-room,
[data-theme="nocturne"] .zavel-light-patch {
	fill: color-mix(in srgb, var(--zavel-gold) 42%, transparent);
}

[data-theme="nocturne"] .zavel-light-on-glass {
	fill: color-mix(in srgb, var(--zavel-gold) 78%, transparent);
}

.zavel-light-calendar {
	display: grid;
	gap: 0.7rem;
	margin: 1.8rem 0 0;
}

/* The hours run down the gutter and the months along the foot, both as real
   text outside the drawing: an SVG label would scale with the strip and fall
   under the floor on a phone. */
.zavel-light-calendar-frame {
	padding: 0 0 1.5rem 3.2rem;
	position: relative;
}

.zavel-light-grid {
	background: var(--zavel-limestone);
	block-size: 11rem;
	display: block;
	inline-size: 100%;
}

.zavel-light-hours {
	inset: 0 auto 1.5rem 0;
	position: absolute;
	width: 2.9rem;
}

.zavel-light-hours span {
	color: var(--zavel-charcoal-soft);
	font-variant-numeric: tabular-nums;
	position: absolute;
	transform: translateY(-50%);
}

.zavel-light-months {
	bottom: 0;
	height: 1.5rem;
	left: 3.2rem;
	overflow: hidden;
	position: absolute;
	right: 0;
}

.zavel-light-months span {
	color: var(--zavel-charcoal-soft);
	position: absolute;
	top: 0.3rem;
}

.zavel-light-hour-line {
	stroke: color-mix(in srgb, var(--zavel-charcoal) 28%, transparent);
	stroke-dasharray: 3 4;
	stroke-width: 1;
	vector-effect: non-scaling-stroke;
}

.zavel-light-tick {
	stroke: color-mix(in srgb, var(--zavel-charcoal) 28%, transparent);
	stroke-width: 1;
	vector-effect: non-scaling-stroke;
}

.zavel-light-marker {
	stroke: var(--zavel-clay);
	stroke-width: 1.5;
	vector-effect: non-scaling-stroke;
}

.zavel-light-legend {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1.4rem;
	list-style: none;
	margin: 0;
	padding: 0;
}

.zavel-light-legend li {
	align-items: center;
	display: flex;
	gap: 0.5rem;
}

.zavel-light-swatch {
	block-size: 0.95rem;
	border: 1px solid var(--zavel-line);
	display: inline-block;
	inline-size: 1.7rem;
}

.zavel-light-swatch-glass {
	background: color-mix(in srgb, var(--zavel-gold) 55%, transparent);
}

.zavel-light-swatch-room {
	background: color-mix(in srgb, var(--zavel-gold) 28%, transparent);
}

[data-theme="nocturne"] .zavel-light-swatch-glass {
	background: color-mix(in srgb, var(--zavel-gold) 78%, transparent);
}

[data-theme="nocturne"] .zavel-light-swatch-room {
	background: color-mix(in srgb, var(--zavel-gold) 42%, transparent);
}

.zavel-light-note {
	color: var(--zavel-charcoal-soft);
	line-height: 1.5;
	margin: 0;
	max-width: 40rem;
}

.zavel-light-overrule {
	align-items: center;
	border: 1px solid var(--zavel-line);
	display: grid;
	gap: 0.8rem;
	margin-top: 1.3rem;
	padding: 1rem;
}

.zavel-light-overrule p {
	line-height: 1.5;
	margin: 0;
}

.zavel-light-restore {
	justify-self: start;
}

/* The way onto the visitor's own wall, under the position it checks. A button
   inherits neither the family nor the weight of the copy around it, and the
   text link's own rule under the words is what the padding keeps close while
   the box reaches a full tap target. */
.zavel-composer-wall-open {
	background: transparent;
	border: 0;
	color: inherit;
	cursor: pointer;
	font-family: var(--wp--preset--font-family--sans);
	font-weight: 650;
	margin-top: 1.1rem;
	padding: 0.85rem 0 0.4rem;
	text-transform: uppercase;
}

.zavel-composer-wall-open:focus-visible {
	outline: 2px solid var(--zavel-focus);
	outline-offset: 3px;
}

/* The photograph is not in the record, so this row is a sentence rather than a
   figure and takes the whole width, which keeps the measured rows above paired. */
.zavel-saved-room-study dl > div.zavel-saved-study-wall {
	border-left: 0;
	grid-column: 1 / -1;
	padding-left: 0;
}

@media (max-width: 70rem) {
	/* The control column gives up its floor first, because the preview column
	   is what the drawing's own aspect ratio holds. */
	.zavel-composer-section {
		grid-template-columns: minmax(20rem, 1.06fr) minmax(0, 0.94fr);
	}

	.zavel-composer-catalog {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}

	.zavel-composer-catalog-entry:nth-child(3n) {
		border-right: 1px solid var(--zavel-line);
	}

	.zavel-composer-catalog-entry:nth-child(2n) {
		border-right: 0;
	}
}

/* Single column keeps the step, its controls and its action ahead of the study,
   so no full-width panel precedes the action and the study scrolls with the
   step rather than sticking beside it. */
@media (max-width: 56.25rem) {
	.zavel-composer-section {
		grid-template-columns: 1fr;
	}

	.zavel-composer-copy {
		max-width: 46rem;
		padding-bottom: clamp(1.15rem, 3vw, 2rem);
	}

	.zavel-composer-preview {
		gap: clamp(1.1rem, 1.7vw, 1.9rem);
		max-height: none;
		max-width: 46rem;
		overflow-y: visible;
		padding: 0 var(--wp--preset--spacing--page-padding) clamp(3.5rem, 8vw, 5rem);
		position: static;
	}

	.zavel-composer-static {
		padding-inline: var(--wp--preset--spacing--page-padding);
	}

	/* The echo of the study while the study is below the step: one line of
	   wall, mirror and light held under the bar, so a figure typed into the
	   wall step is seen to land without scrolling to the drawing. */
	.zavel-composer-summary {
		background: var(--zavel-surface-interactive);
		border-bottom: 1px solid var(--zavel-line);
		color: var(--zavel-charcoal);
		display: block;
		margin: 0 calc(-1 * var(--wp--preset--spacing--page-padding)) 1.25rem;
		padding: 0.8rem var(--wp--preset--spacing--page-padding);
		position: sticky;
		top: var(--zavel-anchor-reserve);
		z-index: 4;
	}

	.zavel-composer-summary[hidden] {
		display: none;
	}

	/* Single column stacks the preview under the step, so these seams close up
	   to keep the compact preview in the same view as the control that changes
	   it. Step 04 carries the reason, the grid, the position and the ranking
	   disclosure, so its cells give back what the type takes rather than pushing
	   the preview out of the view. */
	.zavel-composer-goals {
		margin-top: 1.1rem;
	}

	/* Two columns wrap six rooms 2, 2, 2 where three would break a label. */
	.zavel-composer-room-options {
		grid-template-columns: repeat(2, minmax(0, 1fr));
		margin-top: 0.55rem;
	}

	.zavel-composer-objective-note,
	.zavel-composer-position-summary {
		margin-top: 1rem;
	}

	.zavel-light-picker,
	.zavel-wall-inputs {
		margin-top: 1.3rem;
	}

	.zavel-composer-step-actions,
	.zavel-composer-save-row {
		margin-top: 1.15rem;
	}

	.zavel-composer-recommendation-grid {
		margin-top: 0.8rem;
	}

	.zavel-composer-recommendation-grid > div {
		min-height: 3.6rem;
		padding: 0.6rem 0.7rem 0.6rem 0;
	}

	.zavel-composer-recommendation-grid > div:nth-child(even) {
		padding-left: 0.7rem;
	}

	.zavel-composer-recommendation-grid dd {
		font-size: 0.86rem;
		margin-top: 0.4rem;
	}

	.zavel-composer-curatorial-note {
		line-height: 1.4;
	}

	.zavel-composer-objective-note p,
	.zavel-composer-position-summary p {
		line-height: 1.45;
	}

	.zavel-composer-ranking {
		margin-top: 0.8rem;
	}

	/* The study's behaviour copy is the drawing's caption and repeats Step 01's
	   own objective note, which is why it is hidden from assistive technology
	   already. Once the two columns stack it repeats it a screen apart, so the
	   mark and the panel's own label carry the card on their own. The general
	   entry is the exception: it starts with nothing chosen, so there is no
	   mark, and without the open state's sentence the card was a frame around
	   two labels that read as a drawing that failed to load. */
	.zavel-composer-study-behavior {
		display: none;
	}

	.zavel-composer-study.is-open .zavel-composer-study-behavior {
		display: block;
	}

	.zavel-composer-study.is-open .zavel-composer-study-figure {
		display: none;
	}
}

@media (max-width: 42.5rem) {
	.zavel-composer-study-body {
		grid-template-columns: 1fr;
	}

	/* One column gives the figure the whole card, and a 200 by 132 box that wide
	   is mostly empty around a mark this size. The cap is the width the drawing
	   is composed at on a desktop, so the study reads the same on both. */
	.zavel-composer-study-figure {
		margin-inline: auto;
		max-width: 20rem;
		width: 100%;
	}

	.zavel-composer-catalog {
		grid-template-columns: 1fr;
	}

	.zavel-composer-catalog-entry,
	.zavel-composer-catalog-entry:nth-child(3n) {
		border-right: 0;
	}

	/* A full-width button beside a Back link has about 206 pixels at 320, and
	   1.5rem of side padding sent the longest label to a second line. */
	.zavel-composer-step-actions .zavel-button {
		min-width: 0;
		padding-inline: 1rem;
		width: 100%;
	}

	/* Two columns leave the Selected marker sitting on top of the option label. */
	.zavel-light-picker > div {
		grid-template-columns: 1fr;
	}

	/* A legible term and a measured sentence do not both fit across a phone, so
	   the row stacks and the type does not shrink. */
	.zavel-light-coordinates,
	.zavel-light-figures > div,
	.zavel-light-sizes,
	.zavel-light-when,
	.zavel-wall-choices,
	.zavel-wall-door,
	.zavel-wall-figures > div,
	.zavel-wall-opening,
	.zavel-wall-sizes {
		grid-template-columns: 1fr;
	}

	/* Twelve three-letter ticks across a phone's calendar overlap, so every
	   other month carries the strip and the type stays at the floor. */
	.zavel-light-months span:nth-child(even) {
		display: none;
	}

	/* Two full-width buttons stack, so the row reads as one column. */
	.zavel-wall-study .zavel-composer-step-actions {
		flex-wrap: wrap;
		justify-content: flex-start;
	}

	/* The narrow column is already a display measure, so a capped measure only
	   buys a third line. */
	.zavel-composer-panel h3 {
		margin-bottom: 0.7rem;
		margin-top: 0.3rem;
		max-width: none;
	}

	/* Step 04 carries the longest panel, and a decisive wall clause can add two
	   lines to the reason, so its seams close a little further. */
	.zavel-composer-curatorial-note {
		line-height: 1.32;
	}

	.zavel-composer-recommendation-grid {
		margin-top: 0.5rem;
	}

	.zavel-composer-recommendation-grid > div {
		padding-bottom: 0.45rem;
		padding-top: 0.45rem;
	}

	.zavel-composer-recommendation-grid dd {
		margin-top: 0.3rem;
	}

	.zavel-composer-position-summary {
		margin-top: 0.6rem;
	}

	.zavel-composer-ranking {
		margin-top: 0.5rem;
	}

	.zavel-composer-step-actions {
		margin-top: 0.75rem;
	}

	/* The ranked order adds a line to each option, so the option's own padding
	   closes to keep the compact preview in the same view as the controls. */
	.zavel-placement-options > button {
		gap: 0.25rem 0.9rem;
		grid-template-columns: 1.2rem minmax(0, 1fr);
		padding: 0.4rem;
	}

	/* Every row reads across the whole option, which is what pays for legible
	   type here. The miniature is where that width comes from: it is a
	   decorative diagram with no accessible name, the row states its geometry in
	   words, and the study inset below draws the selected placement to scale, so
	   it is what gives way when the option runs out of width. */
	.zavel-placement-miniature {
		display: none;
	}

	.zavel-placement-option-number {
		grid-row: 1;
	}

	/* The number hangs beside the label and everything under it runs flush, so
	   the option keeps one left edge instead of two. */
	.zavel-placement-options strong {
		grid-column: 2;
		padding-right: 0;
	}

	.zavel-placement-options small,
	.zavel-placement-rank,
	.zavel-placement-rationale,
	.zavel-placement-options .zavel-composer-selection-status {
		grid-column: 1 / -1;
	}

	/* Here the label needs the whole row, so the marker takes a place in the
	   stack instead of a corner over the label. */
	.zavel-placement-options .zavel-composer-selection-status {
		justify-self: end;
		position: static;
	}

	.zavel-saved-room-study dl,
	.zavel-room-study-placeholder {
		grid-template-columns: 1fr;
	}

	.zavel-saved-room-study dl > div:nth-child(even),
	.zavel-room-study-placeholder > div:nth-child(even) {
		border-left: 0;
		padding-left: 0;
	}

	.zavel-saved-room-study dl > div:nth-last-child(-n + 2) {
		grid-column: auto;
	}
}

/* -----------------------------------------------------------------------------
   The specification sheet, which is the one page here written to leave the
   screen.

   The study is on the device, so the block prints a shell and `specification.js`
   fills it. The rows are the record surfaces the edition and collection pages
   already state facts in, so the sheet inherits the label tier for its terms and
   the prose tier for its values without a type rule of its own; the values take
   the serif here rather than the sans, because this reads as a document a fixer
   works from rather than as an interface.
   -------------------------------------------------------------------------- */

.zavel-specification-sheet {
	display: grid;
}

/* The state a device with no study lands in. The one action it can take stands
   on its own line under the sentence that explains why it is the only one. */
.zavel-specification-empty {
	margin-top: 2rem;
}

.zavel-specification-empty .zavel-text-link {
	margin-top: 1rem;
}

.zavel-specification-head {
	align-items: end;
	border-top: 1px solid var(--zavel-line);
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem 1.5rem;
	justify-content: space-between;
	margin-top: 2rem;
	padding-top: 1.5rem;
}

.zavel-specification-subject {
	font-size: var(--wp--preset--font-size--title);
	margin: 0;
}

/* The subject names the record the way every other sentence about it does,
   which is lowercase inside one. Only its first letter changes, because
   capitalising the phrase would title-case a room's name in English and leave
   Bulgarian, which does not capitalise one, looking like a mistake. */
.zavel-specification-subject::first-letter {
	text-transform: uppercase;
}

.zavel-specification-head p {
	color: var(--zavel-charcoal-soft);
	margin: 0.45rem 0 0;
}

.zavel-specification-print {
	margin-top: 0;
}

.zavel-specification-block {
	margin-top: 2.25rem;
}

.zavel-specification-block > h2,
.zavel-specification-placement > h3 {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

.zavel-specification-placement > h3 {
	color: var(--zavel-clay-deep);
}

.zavel-specification-block .zavel-quickfacts {
	margin: 0.7rem 0 0;
}

.zavel-specification-block dd {
	font-family: var(--wp--preset--font-family--serif, serif);
}

/* A value stands on its own line here, where several of its sentences are
   written to sit inside one elsewhere and share that msgid with the wall step.
   The sheet opens each of them rather than the catalogue carrying a second
   entry that differs by one letter. */
.zavel-specification-sheet dd::first-letter {
	text-transform: uppercase;
}

.zavel-specification-placement {
	margin-top: 1.4rem;
}

.zavel-specification-drawing {
	margin: 0.9rem 0 0;
}

.zavel-specification-drawing svg {
	display: block;
	height: auto;
	max-width: 100%;
}

.zavel-specification-drawing figcaption {
	color: var(--zavel-charcoal-soft);
	margin-top: 0.7rem;
}

/* The drawing's measurements, drawn the way a sheet of drawings draws them: a
   thin line with a tick across each end and the value written on it. The value
   carries a halo of the page's own ground, because a dimension is worth nothing
   where it crosses the outline it measures and cannot be read. */
.zavel-specification-dimension line {
	stroke: var(--zavel-clay);
	stroke-width: 1;
}

.zavel-specification-dimension text {
	fill: var(--zavel-charcoal);
	font-family: var(--wp--preset--font-family--sans);
	/* A figure a fixer reads off the drawing, so it sits on the legibility floor
	   like every other value on the sheet rather than below it. */
	font-size: 12px;
	letter-spacing: 0.03em;
	paint-order: stroke;
	stroke: var(--zavel-paper);
	stroke-linejoin: round;
	/* Wider than the space in `215 cm`, which measures 3.7 pixels of ink at this
	   size, so the pockets either side of it meet and a crossing line does not
	   reappear between the number and its unit. The halo is the ground's own
	   colour, so its width shows nowhere but where it clears something. */
	stroke-width: 5px;
}

.zavel-specification-foot {
	border-top: 1px solid var(--zavel-line);
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem 1.5rem;
	justify-content: space-between;
	margin-top: 2.5rem;
	padding-top: 1rem;
}

.zavel-specification-foot p {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

/* The trade page's way into the sheet. */
.zavel-specification-link {
	border-top: 1px solid var(--zavel-line);
	margin-top: 2.5rem;
	padding-top: 1.5rem;
}

/* -----------------------------------------------------------------------------
   The placement study, which is a page the studio delivers to one client.

   The template puts the block in a constrained group, so the editor's 44rem
   measure and the page gutter are already the page's and nothing here restates
   either: the composite is the width of that column, which is the width its own
   `sizes` is written for, and every section under it is a record surface spaced
   and ruled the way the edition and collection pages space theirs.
   -------------------------------------------------------------------------- */

.zavel-study-page {
	margin-top: 2.5rem;
}

.zavel-study-page > h1 {
	font-size: var(--wp--preset--font-size--display);
	margin: 0.6rem 0 0;
}

.zavel-study-delivered {
	color: var(--zavel-charcoal-soft);
	margin: 1.1rem 0 0;
}

/* The one sentence the studio writes to this client. The section intro is
   written for the top of a page and carries no margin of its own. */
.zavel-study-page > .zavel-section-intro {
	margin: 1.2rem 0 0;
}

.zavel-study-composite {
	margin: 2.5rem 0 0;
}

.zavel-study-photo {
	display: block;
	height: auto;
	width: 100%;
}

.zavel-study-composite figcaption {
	color: var(--zavel-charcoal-soft);
	line-height: 1.5;
	margin-top: 0.9rem;
}

/* The measured sections, the alternatives and the reply: four record surfaces
   under the composite, each opening on a rule under a label. */
.zavel-study-record > section,
.zavel-study-alternatives,
.zavel-study-enquiry {
	border-top: 1px solid var(--zavel-line);
	margin-top: 2.5rem;
	padding-top: 1.5rem;
}

.zavel-study-record > section > h2,
.zavel-study-alternatives > h2,
.zavel-study-enquiry > h2 {
	color: var(--zavel-charcoal-soft);
	margin: 0;
}

/* The sheet opens under a heading here rather than under the page's own title,
   so its own rule would be a second line under a label. */
.zavel-study-record .zavel-specification-head {
	border-top: 0;
	margin-top: 1.1rem;
	padding-top: 0;
}

.zavel-study-light-body {
	display: grid;
	margin-top: 0.6rem;
}

/* Named twice over, because the page template's own list rules indent a list
   and space a row, and this is a record surface rather than prose. */
.zavel-study-alternatives .zavel-study-alternative-list {
	list-style: none;
	margin: 1.2rem 0 0;
	padding: 0;
}

.zavel-study-alternatives .zavel-study-alternative {
	align-items: baseline;
	border-bottom: 1px solid var(--zavel-line);
	display: flex;
	flex-wrap: wrap;
	gap: 0.3rem 1.5rem;
	margin: 0;
	padding: 0.85rem 0;
}

.zavel-study-alternative h3 {
	font-size: var(--wp--preset--font-size--lead);
	margin: 0;
}

.zavel-study-alternative p {
	color: var(--zavel-charcoal-soft);
	font-variant-numeric: tabular-nums;
	margin: 0;
}

/* The action stands at the end of its own row only where the row has the width
   for it; below that it takes the line under the size it belongs to. */
@media (min-width: 40rem) {
	.zavel-study-alternative a {
		margin-left: auto;
	}
}

.zavel-study-enquiry > p {
	line-height: 1.55;
	margin: 1.1rem 0 0;
}

.zavel-study-enquiry .zavel-enquiry-address {
	margin-top: 0.75rem;
}

/* -----------------------------------------------------------------------------
   The sheet on paper, which is what the page is for.

   Either way round: the blocks stand in two columns in landscape and one in
   portrait, and the rows pair up inside a block. A single mirror's fifteen
   figures and its elevation fit one page either way round. A composition's
   twenty-two take two either way round: its five blocks stand 1249 pixels tall
   against the 1220 that two columns of an A4 landscape page hold, and the sheet
   runs on rather than shrinking the drawing everyone reads off a wall.

   The page box states its margin and not its size, because a `size` naming the
   paper pins the orientation with it: `size: A4` answered a landscape request
   with a portrait sheet, and the two-column layout was then printed down a page
   it was not laid out for. The dialog owns the paper; the sheet answers to it.
   -------------------------------------------------------------------------- */

@media print {
	@page {
		margin: 12mm;
	}

	/* Paper is paper. The tokens are redefined rather than the elements
	   recoloured, so the drawing's strokes and the sheet's rules turn with the
	   text and Nocturne cannot follow the page onto the sheet. */
	:root,
	:root[data-theme="nocturne"] {
		--zavel-paper: #fff;
		--zavel-paper-soft: #fff;
		--zavel-charcoal: #000;
		--zavel-charcoal-soft: #333;
		--zavel-clay: #000;
		--zavel-clay-deep: #000;
		--zavel-line: rgba(0, 0, 0, 0.4);
		--zavel-surface-muted: #fff;
	}

	/* Everything the page carries around the sheet is furniture for a screen,
	   so it goes by ancestry rather than by name and a block added to this page
	   later is off the paper without anyone remembering to say so. The named
	   rule under it is the same statement for a browser without `:has()`.

	   A placement study prints whole, composite and all, so on that page the
	   sheet is not the region and the page is: the same statement is made about
	   it, and the sheet's own is held off the page it is one section of. */
	body:not(:has(.zavel-study-page)) *:not(:has(.zavel-specification)):not(.zavel-specification):not(.zavel-specification *) {
		display: none !important;
	}

	body:has(.zavel-study-page) *:not(:has(.zavel-study-page)):not(.zavel-study-page):not(.zavel-study-page *) {
		display: none !important;
	}

	/* The study page's reply is a `mailto:`, which is furniture for a screen the
	   same way the sheet's print button is; the address printed under it is the
	   part of that section paper can use. */
	.zavel-header,
	.zavel-header-rule,
	.zavel-mobile-panel,
	.zavel-footer,
	.zavel-specification-print,
	.zavel-study-enquiry .zavel-button {
		display: none !important;
	}

	/* The kicker and the introduction say what this page is to someone who
	   arrived on it. On paper the sheet says that for itself. */
	.zavel-specification > p {
		display: none;
	}

	/* The reserve under the fixed header, the editor's 44rem measure and the
	   global gutter are all the screen's, and each of them counts against the
	   one page the sheet has to fit. On paper the page margin is the margin, so
	   the sheet runs the full width of it. `.zavel-no-hero main` is named
	   because that is the selector the reserve is written under, and a rule of
	   lower specificity leaves 4rem of blank paper above the heading. */
	body,
	.wp-site-blocks,
	.zavel-no-hero main,
	.zavel-page-main,
	.entry-content,
	.zavel-specification,
	.zavel-study-page {
		background: #fff;
		color: #000;
		margin: 0;
		max-width: none;
		padding: 0;
		width: auto;
	}

	/* The page's own wrapper is an editor group rather than the post content, so
	   the measure and the gutter it carries are taken off by ancestry. */
	:has(> .zavel-study-page) {
		max-width: none;
		padding: 0;
		width: auto;
	}

	/* The composite is the reason this page prints, and a plate that took a
	   whole sheet on its own would push every figure onto a second one. */
	.zavel-study-composite {
		break-inside: avoid;
		margin-top: 4mm;
	}

	.zavel-study-photo {
		margin: 0 auto;
		max-height: 92mm;
		max-width: 100%;
		width: auto;
	}

	/* The column that holds the footer down on a short screen. The footer is not
	   on the paper, and a column floored at the height of the page cannot print
	   shorter than one. */
	.wp-site-blocks {
		display: block;
		min-height: 0;
	}

	.zavel-specification,
	.zavel-study-page {
		font-size: 10pt;
		line-height: 1.35;
	}

	.zavel-specification h1,
	.zavel-study-page > h1 {
		font-size: 15pt;
		margin: 0;
	}

	.zavel-specification .zavel-micro-label,
	.zavel-study-page .zavel-micro-label {
		font-size: 8.5pt;
	}

	.zavel-study-record > section,
	.zavel-study-alternatives,
	.zavel-study-enquiry {
		break-inside: avoid;
		margin-top: 4mm;
		padding-top: 2mm;
	}

	.zavel-specification-head {
		border-top: 0;
		margin-top: 3mm;
		padding-top: 0;
	}

	.zavel-specification-subject {
		font-size: 13pt;
	}

	.zavel-specification-block {
		break-inside: avoid;
		margin-top: 3mm;
	}

	/* Paired, because a sheet of fifteen figures reads down two short columns
	   and a composition's twenty-two would not otherwise fit the page at all. */
	.zavel-specification-block .zavel-quickfacts {
		column-gap: 8mm;
		display: grid;
		grid-template-columns: 1fr 1fr;
		margin-top: 2mm;
	}

	/* The installation notes are a paragraph rather than a figure, and a list
	   holding one row has nothing to pair it with in any case. */
	.zavel-specification-block .zavel-quickfacts:has(> .zavel-row:only-child) {
		grid-template-columns: 1fr;
	}

	.zavel-specification-block .zavel-row {
		gap: 0 3mm;
		grid-template-columns: 22mm 1fr;
		padding: 1mm 0;
	}

	.zavel-specification-placement {
		margin-top: 3mm;
	}

	.zavel-specification-drawing {
		break-inside: avoid;
		margin-top: 3mm;
	}

	.zavel-specification-drawing svg {
		margin: 0 auto;
		max-height: 84mm;
		width: 100%;
	}

	.zavel-specification-drawing figcaption {
		font-size: 10pt;
		margin-top: 2mm;
	}

	/* The drawing is fitted into the print box rather than filling it: the box is
	   capped at 84mm, the frame's own ratio wants more, and `preserveAspectRatio`
	   answers by painting one drawing unit at about 0.699 of a CSS pixel. A value
	   written at the size it is read at would land at 0.699 of that size on the
	   paper, so it is written larger by the reciprocal instead: 17 by 0.699 is
	   11.9 pixels, 8.9 points, the floor the sheet's own labels sit on. */
	.zavel-specification-dimension text {
		font-size: 17px;
		stroke: #fff;
	}

	.zavel-specification-foot {
		margin-top: 3mm;
		padding-top: 2mm;
	}
}

@media print and (orientation: landscape) {
	/* Columns rather than a grid, because the blocks are five of very different
	   heights and a grid would leave a row as tall as its tallest cell. Flowing
	   them lets the drawing sit beside the figures instead of under them.

	   These two figures also decide what the drawing dimensions: a column is 497
	   pixels here, under the width `specification.js` states a mirror's two
	   edges above, so the landscape elevation leaves those two to the rows and
	   states every other figure itself. */
	.zavel-specification-sheet {
		column-count: 2;
		column-gap: 10mm;
		display: block;
	}

	.zavel-specification-head,
	.zavel-specification-foot {
		column-span: all;
	}

	/* Half the page is already the second column, so the rows inside a block
	   stand one under the other rather than pairing up again. */
	.zavel-specification-block .zavel-quickfacts,
	.zavel-specification-block .zavel-quickfacts:has(> .zavel-row:only-child) {
		grid-template-columns: 1fr;
	}

	.zavel-specification-drawing svg {
		max-height: 74mm;
	}
}
