/*
 * Theme layer. Everything visual lives in tokens/ and components.css, which are
 * copied verbatim from the design system. This file holds only what the design
 * system expressed outside its component CSS — the UI kit's own inline rules and
 * the handful of WordPress-specific affordances (admin bar, alignment, skip
 * link) that a prototype never needs.
 *
 * Rule: no new colours, no new spacing values, no radii, no shadows. Anything
 * added here must resolve to an existing token.
 */

@import "tokens/fonts.css";
@import "tokens/colors.css";
@import "tokens/typography.css";
@import "tokens/spacing.css";
@import "tokens/borders.css";
@import "tokens/motion.css";
@import "tokens/base.css";
@import "components.css";

/* --------------------------------------------------- From the UI kit's index.html
   The process list and the inquiry form sit outside a Band (their introducing
   Band drops its bottom padding via .milos-band:has(+ .milos-form-wrap)), so
   they carry the band's closing padding themselves. */
.milos-process-wrap,
.milos-form-wrap { padding-bottom: var(--space-70); }

/* --------------------------------------------------------------- Skip link
   Keyboard affordance the prototype had no need for. Uses the button tokens
   unchanged so it cannot introduce a new visual idea. */
.milos-skip-link {
	position: absolute;
	left: var(--gutter);
	top: -100%;
	z-index: 300;
	padding: 1rem 2rem;
	background: var(--milos-espresso);
	color: var(--milos-ivory);
	font-size: var(--text-eyebrow);
	font-weight: var(--weight-medium);
	letter-spacing: var(--tracking-button);
	text-transform: uppercase;
	transition: top var(--duration-hover) var(--ease);
}

.milos-skip-link:focus {
	top: var(--space-20);
	color: var(--milos-ivory);
}

/* ------------------------------------------------------------ Mobile menu
   The header's nav collapses under 860px. The burger is three 1px CSS rules
   (components.css); this is only the panel it opens. Espresso ground because
   the header itself is transparent in every state and the nav would otherwise
   fall across the hero painting. */
@media (max-width: 859px) {

	.milos-burger { display: block; }

	.milos-nav {
		position: absolute;
		inset: var(--header-height) 0 auto;
		display: none;
		flex-direction: column;
		align-items: flex-start;
		gap: var(--space-30);
		padding: var(--space-40) var(--gutter) var(--space-50);
		background: var(--milos-espresso);
		color: var(--milos-ivory);
	}

	.milos-nav.is-open { display: flex; }

	.milos-nav.is-open a,
	.milos-nav.is-open .milos-lang__link { color: var(--milos-ivory); }

	.milos-nav__list {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--space-30);
	}

	/* The header's own text-shadow is for ivory type over a painting; inside the
	   opened panel the ground is solid, so it is not needed. */
	.milos-header.is-open { text-shadow: none; }
}

/* ------------------------------------------------------- WordPress plumbing */
.admin-bar .milos-header--fixed { top: 32px; }

@media screen and (max-width: 782px) {
	.admin-bar .milos-header--fixed { top: 46px; }
}

/* The editor emits these on images and galleries. Map them onto the system's
   own layout widths rather than letting WordPress introduce its own. */
.milos-prose .alignwide {
	max-width: var(--wide-width);
	margin-inline: auto;
}

.milos-prose .alignfull {
	width: 100vw;
	max-width: 100vw;
	margin-inline: calc(50% - 50vw);
}

.milos-prose .aligncenter { margin-inline: auto; }

.milos-prose img,
.milos-prose iframe { max-width: 100%; }

.milos-prose ul,
.milos-prose ol { padding-left: 1.25rem; }

.milos-prose li + li { margin-top: 0.5rem; }

.milos-prose a {
	border-bottom: 1px solid var(--milos-champagne);
	transition: border-color var(--duration-hover) var(--ease), color var(--duration-hover) var(--ease);
}

.milos-prose a:hover {
	border-bottom-color: var(--milos-gold);
	color: var(--milos-bronze);
}

/* --------------------------------------------------------- 404 and no-results
   No design was authored for these. They reuse PageHead and a button row
   rather than inventing a layout. */
.milos-notice {
	max-width: var(--measure-prose);
	padding-bottom: var(--space-70);
}

.milos-notice .milos-btn-row { margin-top: var(--space-40); }

/* --------------------------------------------------------------- Form errors
   The design system defines .has-error and .milos-field__error but the
   prototype never submitted to a server, so it never needed a summary. This
   is a Field error's tokens applied to a block-level list. */
.milos-form__errors {
	max-width: var(--measure-lede);
	margin-bottom: var(--space-40);
	padding: var(--space-20) var(--space-30);
	border-left: 1px solid var(--milos-bronze);
	color: var(--milos-bronze);
	font-size: var(--text-small);
}

.milos-form__errors ul {
	margin: var(--space-10) 0 0;
	padding-left: 1.25rem;
}

.milos-form__honeypot {
	position: absolute !important;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}

/* ------------------------------------------------- Content-driven pages
   A page built from blocks renders the same design as the template, but
   WordPress wraps every group block's children in an extra
   .wp-block-group__inner-container. That wrapper breaks every rule written
   against direct children: .milos-commission-split is a two-column grid and
   would see one child, so the text collapsed into the first column and the
   second stood empty.

   display:contents removes the wrapper from the box tree while keeping its
   children, so the grid, the bands and the measure rules all see the elements
   they were written for. The wrapper carries no background, padding or border
   of its own, so nothing is lost with it. */
.milos-page-content .wp-block-group__inner-container { display: contents; }

/* The band and inner wrappers own their spacing through the milos- classes.
   Neutralise the block layout classes so they cannot add a second set. */
.milos-page-content .is-layout-flow > *,
.milos-page-content .is-layout-constrained > * { margin-block: 0; }

.milos-page-content .wp-block-group.milos-inner {
	max-width: var(--content-width);
	margin-inline: auto;
	padding-inline: var(--gutter);
}

/* Core adds .wp-block-heading; the design styles headings by element and by
   its own classes, so the block class must not introduce a second set of
   margins. */
.milos-page-content .wp-block-heading { margin: 0; }

/* Prose paragraphs keep the measure and rhythm the design gives them, unless
   they are one of its own typographic roles (eyebrow, lede, statement, quote). */
.milos-page-content .milos-inner > p:not([class]),
.milos-page-content .milos-inner > p.milos-body {
	max-width: var(--measure-prose);
}

.milos-page-content .milos-inner > p:not([class]) + p:not([class]) { margin-top: 1.25em; }

.milos-contact-aside { padding-bottom: var(--space-70); }

/* The core image block wraps the painting in its own <figure>, so the
   statement-band sizing has to reach the img inside it rather than sit on
   the img itself as it does in the template. */
.milos-commission-media.wp-block-image { margin: 0; }

.milos-commission-media.wp-block-image img {
	display: block;
	width: auto;
	max-width: 100%;
	max-height: 26rem;
	object-fit: contain;
}

/* The byline photograph, when it comes from an image block rather than the
   template's bare <img>. The size is the design's: a 6.5rem square signature,
   arrived at after the artist rejected anything larger. */
.milos-about-byline .milos-about-photo.wp-block-image { margin: 0; }

.milos-about-byline .milos-about-photo.wp-block-image img {
	display: block;
	width: 6.5rem;
	height: 6.5rem;
	object-fit: cover;
	object-position: 50% 30%;
}

/* ------------------------------------------------------------- Spacing fixes

   The process list carries a full band's closing padding, and the band that
   follows it opens with a full band's top padding — so the two stack into
   roughly 16rem of empty ivory between the last step and "Commission a
   Painting". components.css already collapses the band *before* a process or
   form wrap for the same reason; this is the missing other half. */
.milos-process-wrap:has( + .milos-band ),
.milos-form-wrap:has( + .milos-band ) { padding-bottom: var(--space-40); }

/* The inquiry form was capped at 46rem, which left it occupying a little over
   half the content column with the rest of the row empty. It now fills the
   column: the two-field rows keep their split, each field simply gets the room
   the page already had. A deliberate widening of the design system's value,
   at the artist's request. */
.milos-form { max-width: none; }

/* The upload hint and the submit button sit under a much wider grid now, so
   hold them to the reading measure rather than letting them stretch. */
.milos-form__grid > .milos-field--full > textarea { max-width: 100%; }

/* The design's rules are written against direct children — .milos-prose > * + *
   for the paragraph rhythm, and so on. WordPress puts .wp-block-group__inner-
   container between them in the DOM, and display:contents does not change that:
   it affects layout, never selector matching. So the same rules have to be
   restated one level down for content-driven pages. */
.milos-page-content .milos-prose > .wp-block-group__inner-container > * + * { margin-top: 1.25em; }

.milos-page-content .milos-inner > .wp-block-group__inner-container > p:not([class]) {
	max-width: var(--measure-prose);
}

.milos-page-content .milos-inner > .wp-block-group__inner-container > p:not([class]) + p:not([class]) {
	margin-top: 1.25em;
}

/* ------------------------------------------------------- Mobile header
   The header is fixed and transparent, which works over the hero and over the
   generous top padding a page head gives it on a wide screen. On a phone the
   page is narrower, the type wraps taller, and content scrolls straight under
   an invisible bar — the wordmark and the burger end up sitting on top of the
   page's own words. Give it the page's ground below the breakpoint, everywhere
   except over the hero, where the painting is the point. */
@media (max-width: 859px) {

	.milos-header:not(.milos-header--over-hero) {
		background: var(--milos-ivory);
		border-bottom: 1px solid var(--milos-champagne);
	}

	/* Open, the header and its panel are one espresso block, so the bar has to
	   match the panel rather than stay ivory above it. */
	.milos-header.is-open,
	.milos-header.is-open:not(.milos-header--over-hero) {
		background: var(--milos-espresso);
		border-bottom-color: transparent;
		color: var(--milos-ivory);
	}

	.milos-header.is-open .milos-header__brand a { color: var(--milos-ivory); }

	.milos-nav.is-open {
		border-top: 1px solid var(--milos-ivory-28);
	}
}

/* ------------------------------------------------------------ Mobile hero
   The copy block used to be pulled up over the painting by a negative margin,
   which cut into the image and left the two overlapping awkwardly. On a narrow
   screen there is no need to overlap: the painting ends, the copy follows on
   the artwork's own ground. */
@media (max-width: 899px) {

	.milos-cover-hero__copy {
		margin-top: 0;
		width: 100%;
		max-width: none;
		padding: var(--space-50) var(--gutter) var(--space-40);
		backdrop-filter: none;
		-webkit-backdrop-filter: none;
		background: transparent;
		mask-image: none;
		-webkit-mask-image: none;
	}

	.milos-cover-hero__caption { margin-top: var(--space-30); }
}

/* -------------------------------------------------- About at full width
   The biography normally sits at the 65ch reading measure. The artist asked for
   the page to run the full content column instead, so the prose takes the width
   the band gives it. A deliberate departure from the design system's measure,
   scoped to this page only. */
.milos-about-page .milos-prose,
.milos-about-page .milos-about-byline { max-width: none; }

/* --------------------------------------------- At the artist's request, 1.8.0
   Four sizing changes to the design system's values, each a stated percentage
   or a named placement. They override components.css by loading after it under
   the same selectors; the mobile rules there are left alone by scoping the hero
   change to the desktop range it applies to. */

/* The hero's frosted copy box, one fifth larger. It is scaled from its right
   edge (components.css), so the bigger box still hangs from the same gutter. */
@media (min-width: 900px) {
	.milos-cover-hero__copy { transform: translateY(-50%) scale(0.84); }
}

/* Selected Works, 15% taller: 76vh → 87.4vh. Still never above the painting's
   own pixel width, still never cropped. */
.milos-work__img,
.milos-work--landscape .milos-work__img { max-height: 87.4vh; }

/* The portfolio's two-up gallery, 15% taller: 46vh → 52.9vh. A landscape
   painting is bounded by its column before it reaches that, which is fine. */
.milos-strip__img { max-height: 52.9vh; }

/* The portfolio opens with its eyebrow alone — the eyebrow IS the h1 there, so
   the bottom margin it carries as a lead-in to a title is not wanted. */
.milos-page-head--eyebrow-only > .milos-eyebrow:last-child { margin-bottom: 0; }

/* The process numbers were 13px sans, raised to the top of the line; they were
   easy to miss. Now Playfair at the medium heading size, sitting on the same
   baseline as the step's title. Tabular lining figures so 01–05 keep one
   width and the titles line up beneath each other. */
.milos-process__step { align-items: baseline; }

.milos-process__num {
	min-width: 2ch;
	font-family: var(--font-display);
	font-size: var(--text-heading-m);
	font-weight: var(--weight-regular);
	letter-spacing: 0;
	line-height: var(--leading-heading-s);
	font-variant-numeric: lining-nums tabular-nums;
}

/* ------------------------------------------------------- Scrolled header
   The design kept the fixed header transparent in every state, which works at
   the top of a page. Scrolled, the nav landed on the paintings and their
   captions. site.js marks the header stuck once the page has moved under it;
   past the hero it takes the page's ivory ground and the champagne hairline,
   over the hero it darkens the painting behind it just enough to keep the
   ivory type readable. The opened mobile panel keeps its own espresso block. */
.milos-header.is-stuck:not(.milos-header--over-hero):not(.is-open) {
	background: var(--milos-ivory);
	border-bottom: 1px solid var(--milos-champagne);
}

.milos-header.is-stuck.milos-header--over-hero:not(.is-open) {
	background: var(--milos-espresso-62);
	backdrop-filter: blur(14px);
	-webkit-backdrop-filter: blur(14px);
}

/* The process steps run down the left column first, then down the right — 01,
   02, 03 / 04, 05 — rather than across. The row count comes from the template
   (--process-rows) so the flow survives a change in the number of steps. Below
   the two-column breakpoint the list is a single column and reads in order. */
@media (min-width: 900px) {
	.milos-process {
		grid-auto-flow: column;
		grid-template-rows: repeat(var(--process-rows, 3), auto);
	}
}

/* Anchors land under the fixed header otherwise: a form that re-renders with
   errors jumps to #inquiry and the first line of the notice sits behind the
   bar — visibly so, now that the bar has a ground when scrolled. */
html { scroll-padding-top: calc(var(--header-height) + var(--space-20)); }

/* scroll-padding lives on the scroll container, and .admin-bar is on body;
   components.css already relies on :has(), so it is fine to use here too. */
html:has(> body.admin-bar) { scroll-padding-top: calc(var(--header-height) + var(--space-20) + 32px); }

@media screen and (max-width: 782px) {
	html:has(> body.admin-bar) { scroll-padding-top: calc(var(--header-height) + var(--space-20) + 46px); }
}
