/*
Theme Name: Sagelyn
Theme URI: https://github.com/DaisyAI-LLC/sagelyn-wp-theme
Author: Sagelyn
Author URI: https://sagelyn.ai
Description: Visual refresh of the Sagelyn block theme - editorial salon layout, arch imagery, alternating tinted bands. Installs alongside v1 so it can be previewed without touching the live site.
Requires at least: 6.6
Tested up to: 6.7
Requires PHP: 7.4
Version: 1.3.4
License: GNU General Public License v2 or later
License URI: http://www.gnu.org/licenses/gpl-2.0.html
Text Domain: sagelyn
Tags: block-patterns, full-site-editing, blog, business, one-column, custom-colors, custom-logo, custom-menu, editor-style, featured-images, template-editing, wide-blocks
*/

/*
 * Block themes load their styles from theme.json.
 * Only rules that theme.json cannot express belong here.
 *
 * LAYOUT LANGUAGE (the visual direction approved for v2)
 *
 * The arrangement follows an editorial salon reference: generous whitespace,
 * full-bleed tinted bands alternating with white, photographs masked into an
 * arch, flat colour tiles instead of bordered cards, and wide letter-spaced
 * serif headings. Fonts and colours are Vinia's own - Playfair Display and
 * Outfit are the two faces her existing site loads, and the palette is drawn
 * from her logo and her published social creatives.
 *
 * FLAT, NOT FLOATING. The reference has no drop shadows anywhere: surfaces are
 * separated by colour, not by elevation. Shadows are therefore absent by
 * design. Re-adding them is what made the previous pass read as a template.
 */

/* ---------------------------------------------------------------------------
 * PALETTE
 *
 * WHY THIS BLOCK EXISTS - read before deleting it.
 *
 * A theme's theme.json is NOT the last word on colour. WordPress stores a
 * Global Styles record in the database (wp_global_styles, post id 7 on this
 * site) and prints it into the page head AFTER the theme's own presets. The
 * database therefore wins, for whichever theme is being viewed.
 *
 * That record currently holds the v1 salon palette, written there when v1 was
 * set up. Previewing v2 without this block loads v2's layout but v1's colours:
 * the hero band renders #faf7f6 warm grey instead of blush, and the accent
 * rules render #be1e2d crimson instead of rose. The layout looks right and the
 * colour looks untouched, which is a confusing failure to diagnose.
 *
 * Restating the presets here fixes it without touching the database. That
 * matters: Global Styles is SHARED between v1 and v2, so editing it would
 * change the colours on the live site Vinia's customers see. This file is
 * inside the v2 theme folder and is only ever loaded by the v2 preview.
 *
 * ONE SOURCE OF TRUTH: these values must stay identical to the palette in
 * theme.json. theme.json is what the block editor's colour picker shows; this
 * block is what the front end actually paints. If they drift, the editor and
 * the page disagree. Change both together, or neither.
 *
 * AT SIGN-OFF, when this palette moves to v1: write it into Global Styles (or
 * into v1's theme.json and clear the colour section of the Global Styles
 * record) and DELETE this block. It is correct for a preview living beside a
 * live theme; it is not the right permanent shape.
 * ------------------------------------------------------------------------ */

:root {
	--wp--preset--color--base: #FFFFFF !important;
	--wp--preset--color--base-2: #FCEEF3 !important;
	--wp--preset--color--base-3: #F7D7E3 !important;
	--wp--preset--color--cream: #F9F8F5 !important;
	--wp--preset--color--sage: #DDE4DD !important;
	--wp--preset--color--contrast: #5B1230 !important;
	--wp--preset--color--contrast-2: #231F20 !important;
	--wp--preset--color--muted: #6B6560 !important;
	--wp--preset--color--accent: #E7548F !important;
	--wp--preset--color--accent-2: #F06EB0 !important;
	--wp--preset--color--panel: #0E0E0E !important;
	--wp--preset--color--surface: #FFFFFF !important;
	--wp--preset--color--border: #EBDCE2 !important;
}

/*
 * The fonts need the same treatment for the same reason: a Global Styles
 * record that names a font family overrides theme.json's, and v1's record
 * names Inter. Without this the page would render Vinia's layout in the wrong
 * typeface. Both faces are the ones her own site loads.
 */
:root {
	--wp--preset--font-family--heading: "Playfair Display", Georgia, "Times New Roman", serif !important;
	--wp--preset--font-family--body: "Outfit", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif !important;
}

:root {
	/* One easing for everything, so the whole site moves with the same weight. */
	--sg-ease: cubic-bezier( 0.32, 0.72, 0, 1 );
	--sg-dur: 420ms;

	/*
	 * The arch: a photograph with a fully rounded top and square bottom, which
	 * is the single most recognisable shape in the reference. Expressed as one
	 * radius pair so every arch on the site matches.
	 */
	--sg-arch: 50% 50% 0 0 / 34% 34% 0 0;
}

/* ---------------------------------------------------------------------------
 * The hero band
 *
 * A full-bleed tinted band holding two columns: the photograph on one side,
 * the welcome line, headline, lead paragraph and call to action on the other.
 * ------------------------------------------------------------------------ */

/*
 * alignfull strips the root padding, so the band supplies its own - without it
 * the title sits hard against the left edge of the window.
 *
 * The whole of post-content sits inside this wrapper (WordPress will not let
 * the template split it), so a gradient stops the tint at a fixed height:
 * blush down to the end of the hero, white from there on. That gives the
 * alternating surfaces the page needs without a wall of colour, and costs
 * nothing at runtime.
 */
.sg-hero {
	background-color: transparent !important;
	background-image: linear-gradient(
		to bottom,
		var( --wp--preset--color--base-2 ) 0,
		var( --wp--preset--color--base-2 ) var( --sg-hero-band, 36rem ),
		var( --wp--preset--color--base ) var( --sg-hero-band, 36rem )
	);
	padding-inline: var( --wp--style--root--padding-right, var( --wp--preset--spacing--30 ) );
}

@media ( min-width: 900px ) {
	.sg-hero {
		--sg-hero-band: 44rem;
	}
}

/*
 * A page whose opening has no photograph - services, contact - has a much
 * shorter hero than the homepage, and the fixed band height then runs on into
 * the content below and slices a row of cards in half. Where the first block
 * is not an image, the band ends with the opening paragraph instead.
 *
 * :has() is doing real work here: it lets the band measure itself against the
 * page's own shape rather than against a number guessed per page.
 */
.sg-hero:not( :has( .wp-block-post-content > figure.wp-block-image ) ) {
	--sg-hero-band: 20rem;
}

@media ( min-width: 900px ) {
	.sg-hero:not( :has( .wp-block-post-content > figure.wp-block-image ) ) {
		--sg-hero-band: 22rem;
	}
}

/*
 * The page title is the salon's name and sits above the welcome line as a
 * quiet, wide-tracked label rather than as the display headline - in the
 * reference the large type is the invitation, not the business name.
 */
/*
 * The salon's name IS the display line.
 *
 * It was previously set as a small tracked label above a large welcome line,
 * on the reference's logic that the invitation carries the page. That reads
 * well when the business name is already a logo in the header at size - here
 * the header logo is small, so the name needs to be the thing a visitor sees
 * first and the welcome becomes the supporting voice beneath it.
 */
.sg-hero .wp-block-post-title {
	color: var( --wp--preset--color--contrast-2 );
	font-family: var( --wp--preset--font-family--heading );
	font-size: clamp( 1.875rem, 1.2rem + 2.6vw, 3.125rem );
	font-weight: 400;
	letter-spacing: 0.04em;
	line-height: 1.22;
	margin-block: 0 var( --wp--preset--spacing--30 );
	margin-inline: 0;
	max-width: none;
	text-transform: uppercase;
	text-wrap: balance;
}

/*
 * Vinia's own line, from her About copy, is the invitation that opens the
 * page. Set in the display serif, uppercase and widely tracked, it is the
 * largest type on the screen.
 */
/*
 * Vinia's own line, from her About copy, is now the voice under the name
 * rather than the headline itself. Set in the display serif at a size between
 * the name and the body copy, in her plum, and left in sentence case: the
 * name is the shout, this is her speaking.
 */
.sg-hero-line {
	color: var( --wp--preset--color--contrast );
	font-family: var( --wp--preset--font-family--heading );
	font-size: clamp( 1.125rem, 0.95rem + 0.7vw, 1.5rem ) !important;
	font-style: italic;
	font-weight: 400;
	letter-spacing: 0.01em;
	line-height: 1.4;
	margin-block: 0 var( --wp--preset--spacing--40 ) !important;
	max-width: 30ch;
	text-transform: none;
	text-wrap: balance;
}

/*
 * The address sentence is the answer an engine quotes, so it stays on the page
 * - but as supporting detail rather than as the first thing a person reads.
 */
.sg-hero .wp-block-post-content > p {
	color: var( --wp--preset--color--muted );
	font-size: var( --wp--preset--font-size--medium );
	line-height: 1.8;
}

.sg-hero .wp-block-post-content > p strong {
	color: var( --wp--preset--color--contrast-2 );
	font-weight: 500;
}

/* ---------------------------------------------------------------------------
 * Browser surfaces
 *
 * The parts nobody draws - the selection highlight, the caret, the scrollbar,
 * the focus ring - ship with defaults that belong to no design system.
 * ------------------------------------------------------------------------ */

::selection {
	background-color: var( --wp--preset--color--base-3 );
	color: var( --wp--preset--color--contrast-2 );
}

:root {
	accent-color: var( --wp--preset--color--contrast );
	caret-color: var( --wp--preset--color--contrast );
	scrollbar-color: var( --wp--preset--color--base-3 ) var( --wp--preset--color--base-2 );
	scrollbar-width: thin;
}

:focus-visible {
	outline: 2px solid var( --wp--preset--color--contrast );
	outline-offset: 3px;
}

a {
	text-underline-offset: 0.18em;
	text-decoration-thickness: 1px;
}

/*
 * post-content is laid out "default" rather than "constrained" in the template:
 * constrained puts a max-width and auto margins on EVERY child, which silently
 * collapses the hero grid back into one column. The reading width it would
 * have given us is restored here instead.
 */
/*
 * The wide size, restated with !important. post-content carries
 * `has-global-padding` and WordPress's own constrained-layout rule caps it at
 * the CONTENT size (720px) - that cap is what crushed the hero into a narrow
 * centre column and left the grid with no room to form columns. The cap has to
 * be beaten here, not merely matched.
 */
.sg-hero > .wp-block-group,
.sg-hero > .wp-block-post-title,
.sg-hero .wp-block-post-content {
	margin-inline: auto;
	max-width: var( --wp--style--global--wide-size, 1320px ) !important;
	width: 100%;
}

/* The inner group must not add a second layer of padding on top of the band's. */
.sg-hero > .wp-block-group {
	padding-inline: 0;
}

/*
 * !important is required, not lazy. WordPress's constrained layout emits
 *   is-layout-constrained > :where(...) { margin-left: auto !important;
 *                                         margin-right: auto !important; }
 * inline in the document head. No amount of specificity beats an !important
 * declaration, so the only way to hold these blocks on the left edge is to
 * match it. Without this every heading and button narrower than the container
 * centres itself over left-edged content.
 */
/*
 * `body:not( .page-id-18 )` excludes Contact and Book, which is centred.
 *
 * The exclusion belongs HERE rather than in a later override. This selector
 * carries !important and two :not() pseudo-classes, which makes it more
 * specific than any reasonable rule written further down the file - several
 * attempts to centre that page from the bottom of the stylesheet lost to this
 * rule and silently did nothing. Narrowing the rule at source is the only
 * version that works.
 */
body:not( .page-id-18 ) .sg-hero .wp-block-post-content > *:not( .alignfull ):not( .alignwide ) {
	margin-left: 0 !important;
	margin-right: auto !important;
	max-width: var( --wp--style--global--content-size, 64ch );
}

body:not( .page-id-18 ) .sg-hero .wp-block-post-title,
body:not( .page-id-18 ) .sg-hero > .wp-block-group > * {
	margin-left: 0 !important;
	margin-right: auto !important;
}

/*
 * Cards and galleries are exempt from the prose measure and take the full
 * container width. This sits in the same specificity bracket as the rule above
 * on purpose: a lower-specificity override further down the file loses to it.
 */
.sg-hero .wp-block-post-content > *:not( .alignfull ):not( .alignwide ):is(
	.sg-card,
	figure.wp-block-gallery
) {
	max-width: var( --wp--style--global--wide-size, 1320px );
	width: 100%;
}

/* ---------------------------------------------------------------------------
 * THE ONE GRID
 *
 * post-content is a single grid at every width above the phone breakpoint, and
 * everything on the page is placed into it. It has to be one grid rather than
 * two: the hero's two columns and the service row's four columns are the same
 * element's children, so a second `display: grid` further down the file would
 * simply overwrite the first.
 *
 * Four columns is the common denominator - the hero takes 2 + 2, a service
 * card takes 1, and anything else spans all four.
 * ------------------------------------------------------------------------ */

/*
 * Contact and Book is excluded from the grid ENTIRELY, not just from the
 * span rule below.
 *
 * Excluding it from `grid-column: 1 / -1` alone is what broke the page: the
 * grid was still switched on here, so with nothing spanning it every heading
 * and paragraph dropped into one ~246px column and the text wrapped one or two
 * words per line. The page is a centred column of prose, so it must never
 * become a grid in the first place.
 */
@media ( min-width: 700px ) {
	body:not( .page-id-18 ) .sg-hero .wp-block-post-content {
		align-items: start;
		column-gap: var( --wp--preset--spacing--50 );
		display: grid;
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
		/*
		 * The grid supplies the vertical rhythm. WordPress's own blockGap would
		 * otherwise stack on top of the row gap AND the headings' own top
		 * margin, which opened up bands of dead space between a heading and the
		 * paragraph belonging to it.
		 */
		row-gap: var( --wp--preset--spacing--30 );
	}

	/*
	 * A heading keeps its generous space above, but not below: the paragraph
	 * under it is part of the same section and the row gap is enough.
	 */
	.sg-hero .wp-block-post-content > h2 {
		margin-bottom: 0;
	}

	/*
	 * Everything that is not a card spans the whole row. The margin reset
	 * matters: auto side margins centre a grid item inside its track, which
	 * would pull the hero columns back to the middle.
	 *
	 * A gallery is explicitly included: as a grid item it would otherwise be
	 * squeezed into a single 246px track and its own inner columns would
	 * collapse to one image with a column of empty space beside it.
	 */
	/* Contact and Book is excluded: it is a centred column, not a grid page. */
	body:not( .page-id-18 ) .sg-hero .wp-block-post-content > * {
		grid-column: 1 / -1;
		margin-inline: 0 !important;
		max-width: none;
	}

	/*
	 * A card fills its grid row. Without this each card is only as tall as its
	 * own text, so a row of them has ragged bottom edges and the tinted blocks
	 * read as an accident rather than as a band. stretch is the default for a
	 * grid item, but the parent sets align-items: start for the hero - so it
	 * has to be restated here.
	 */
	.sg-hero .wp-block-post-content > .sg-card {
		align-self: stretch;
		grid-column: span 1;
	}

	/*
	 * A gallery keeps its own internal grid across the full width.
	 *
	 * The core gallery block is a flex container and sets an inline
	 * `width: calc(...)` on every child to fake columns. Switching the parent
	 * to grid without neutralising those widths leaves each tile sized for the
	 * old flex maths, which is what scattered them across the row. Both the
	 * flex sizing properties and the inline width have to be overridden.
	 */
	/*
	 * Three across, not five.
	 *
	 * Her galleries hold six and nine photographs. At five per row a six-photo
	 * gallery leaves one orphan sitting alone under a full row, which reads as
	 * a mistake. Three divides both counts exactly - six becomes two clean rows,
	 * nine becomes three - and the larger tiles show her actual work rather
	 * than reducing it to thumbnails.
	 *
	 * The gap is generous because each photograph now carries a colour field
	 * behind it (see the gallery section below) and the fields need air between
	 * them or the row reads as one striped band.
	 */
	.sg-hero .wp-block-post-content > figure.wp-block-gallery {
		display: grid;
		gap: var( --wp--preset--spacing--60 ) var( --wp--preset--spacing--50 );
		grid-column: 1 / -1;
		grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
	}

	.sg-hero .wp-block-post-content > figure.wp-block-gallery > figure.wp-block-image {
		flex-basis: auto !important;
		flex-grow: 0 !important;
		margin: 0 !important;
		max-width: none !important;
		width: 100% !important;
	}
}

@media ( min-width: 900px ) {
	/*
	 * TWELVE columns.
	 *
	 * Twelve divides by 2, 3 and 4, so the same grid carries the hero (6 + 6),
	 * a run of three cards (4 + 4 + 4) and a run of four (3 + 3 + 3 + 3)
	 * without any of them fighting the others.
	 *
	 * Three cards per row rather than four: at four, a 1200px container gives
	 * each card about 260px of inner width, and a sentence of service copy
	 * wraps every four words into a tall thin column. Three cards give roughly
	 * 370px each - a comfortable measure, and the row stops looking cramped.
	 */
	/* Contact and Book is excluded here too - see the 700px grid above. */
	body:not( .page-id-18 ) .sg-hero .wp-block-post-content {
		column-gap: var( --wp--preset--spacing--50 );
		grid-template-columns: repeat( 12, minmax( 0, 1fr ) );
	}

	/*
	 * A card spans two of six columns - three per row - by default.
	 *
	 * The page holds two separate runs of cards: three "what makes this salon
	 * different" points, then four services. They are siblings in one grid with
	 * a heading between them, so there is no wrapper to count within. CSS
	 * cannot know where one run ends, but it CAN count backwards from the end
	 * of a run: a card that is followed by a non-card is the last of its run.
	 *
	 * A run of four therefore has to be detected explicitly, or the fourth card
	 * wraps onto a row of its own and the section looks broken.
	 */
	.sg-hero .wp-block-post-content > .sg-card {
		grid-column: span 4;
	}

	/*
	 * A run of FOUR OR MORE cards goes four to a row; a run of three stays
	 * three. Detected by looking for the first card of a run - one whose
	 * previous sibling is not a card - that has at least three cards after it,
	 * then carrying that width down the run with sibling combinators.
	 *
	 * The chain has to be spelled out rather than expressed as "every card in
	 * this run", because CSS has no way to say that: a sibling combinator only
	 * walks forwards one step at a time. Eight services is the longest run on
	 * the site, so the chain is written to eight.
	 *
	 * :has() makes this possible without touching her page content at all.
	 */
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ),
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card,
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card + .sg-card,
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card + .sg-card + .sg-card,
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card + .sg-card + .sg-card + .sg-card,
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card + .sg-card + .sg-card + .sg-card + .sg-card,
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card + .sg-card + .sg-card + .sg-card + .sg-card + .sg-card,
	.sg-hero .wp-block-post-content > :not( .sg-card ) + .sg-card:has( + .sg-card + .sg-card + .sg-card ) + .sg-card + .sg-card + .sg-card + .sg-card + .sg-card + .sg-card + .sg-card {
		grid-column: span 3;
	}

	/*
	 * The opening rows: welcome line, lead paragraph and call to action on the
	 * left two columns, the photograph beside them on the right two. Grid is
	 * used rather than a float because the image sits AFTER the text in the
	 * page markup, and only grid can place a later sibling alongside an earlier
	 * one without reordering anyone's content.
	 *
	 * A fourth, empty row soaks up whatever height the photo has left over.
	 * Without it the three content rows stretch to fill the photo column and
	 * the hero opens up into wide empty bands.
	 */
	.sg-hero .wp-block-post-content > .sg-hero-line {
		grid-column: 1 / span 6;
		grid-row: 1;
	}

	.sg-hero .wp-block-post-content > .sg-hero-line + p {
		grid-column: 1 / span 6;
		grid-row: 2;
		margin-top: 0;
		max-width: 38ch;
	}

	.sg-hero .wp-block-post-content > .wp-block-buttons:first-of-type {
		align-self: start;
		grid-column: 1 / span 6;
		grid-row: 3;
		margin-top: var( --wp--preset--spacing--40 );
	}

	/*
	 * A page with no welcome line - About, for instance - opens with plain
	 * paragraphs beside the photograph instead.
	 *
	 * The homepage pins its opening blocks to explicit rows because it knows
	 * exactly what they are: welcome line, lead, button. On any other page the
	 * opening is just prose, so the blocks before the first image are placed
	 * into the left half and the image takes the right half of the same rows.
	 * Without this the paragraphs span the full width, get pushed below the
	 * pinned image, and leave a tall empty band beside the photograph.
	 *
	 * :has() on the sibling chain identifies "a paragraph that still has an
	 * image after it" - that is, part of the opening rather than body copy
	 * further down the page.
	 */
	/*
	 * The opening prose sits beside the photograph as ONE continuous column.
	 *
	 * Her About copy is three separate paragraphs. Laid out as grid items they
	 * each land in their own row and the row heights stretch to match the
	 * photograph beside them, which opens gaps between paragraphs that read as
	 * three disconnected statements rather than as one introduction.
	 *
	 * Spanning them all across the same rows and letting them stack naturally
	 * makes them read as a single passage, with normal paragraph spacing.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > p:has( ~ figure.wp-block-image ) {
		align-self: start;
		grid-column: 1 / span 6;
		grid-row: auto;
		margin-block: 0 1em;
	}

	/*
	 * The last paragraph before the photograph closes the passage, so it drops
	 * the trailing margin and the section's own spacing takes over.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > p:has( + figure.wp-block-image ) {
		margin-bottom: 0;
	}

	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > .wp-block-buttons:first-of-type {
		grid-row: auto;
	}

	/*
	 * The photograph takes the right half of the opening rows.
	 *
	 * `grid-row: 1 / -1` rather than a fixed span: the opening prose is one
	 * paragraph on Service Area and three on About, so a fixed span either
	 * leaves the image short on one page or stretches it on the other. Letting
	 * it run to the end of the implicit rows lets each page's own content
	 * decide, and the image simply sits at the top of whatever column it gets.
	 */
	/*
	 * The photograph spans exactly as many rows as there are opening
	 * paragraphs beside it - no more.
	 *
	 * A fixed span is what caused the void on Service Area: the image claimed
	 * four rows, the full-width heading below it could not share any of them,
	 * and the three unused rows opened a 500px gap. Counting the paragraphs
	 * with :has() lets each page size its own hero.
	 */
	/*
	 * The photograph occupies the right column beside the opening prose.
	 *
	 * Its height is capped to the height of the text beside it rather than the
	 * other way round. Left uncapped, a 544px image makes its grid row 544px
	 * tall and the full-width heading below starts under all of it - which left
	 * a 500px void on Service Area, whose opening is a single short paragraph.
	 *
	 * `height: 100%` on the figure plus `object-fit: cover` on the image means
	 * the photograph fills whatever the prose column gives it and crops rather
	 * than stretching the layout. A minimum keeps it from becoming a letterbox
	 * on a page with one line of opening copy.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > figure.wp-block-image:first-of-type {
		align-self: stretch;
		grid-column: 7 / span 6;
		margin-block: 0;
	}

	/*
	 * No min-height. A minimum on the image forces its grid row to that height
	 * whatever the row span says, so a short opening paragraph still pushed the
	 * next heading hundreds of pixels down. The image takes the height the prose
	 * beside it establishes and crops to fill.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > figure.wp-block-image:first-of-type img {
		height: 100%;
		max-height: 34rem;
		object-fit: cover;
	}

	/*
	 * The photograph takes the right half of the opening rows.
	 *
	 * It is left in normal grid flow. Taking it out of flow with absolute
	 * positioning was tried and reverted: it overlapped the section below on
	 * Service Area, where the opening is short. A floating image cannot know how
	 * much room the prose beside it needs, so it stays a grid item and simply
	 * spans the opening.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > figure.wp-block-image:first-of-type {
		align-self: start;
		grid-column: 7 / span 6;
		grid-row: 1 / span 3;
		margin-block: 0;
	}

	/*
	 * A page whose opening is a single paragraph - Service Area - gives the
	 * photograph only that one row, so the section below starts right under the
	 * prose instead of after three empty rows.
	 *
	 * The test counts paragraphs that PRECEDE the figure, because the figure is
	 * not the second child on every page: on Service Area a heading, an address
	 * and a card all sit between the opening paragraph and the image.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ):not( :has( > p ~ p ~ p ~ figure.wp-block-image ) ) > figure.wp-block-image:first-of-type {
		grid-row: 1 / span 1;
	}

	/*
	 * SERVICE AREA: the opening is a matched pair.
	 *
	 * The photograph starts a column further right than the default so there
	 * is a clear gutter between prose and picture, and the prose centres
	 * itself against the image's height so the two line up rather than the
	 * text sitting high against a taller block.
	 */
	/*
	 * `body.page-id-17` is not decoration: it is what makes this rule win.
	 *
	 * Further down, `:has( ... ) > h2 ~ *` pins EVERY sibling after the first
	 * heading to `grid-column: 1 / -1`, and on this page the figure sits after
	 * that heading. That rule is later in the file and of equal specificity,
	 * so it took the image full width and no column placement written here had
	 * any effect at all. The class on the body lifts this above it.
	 */
	body.page-id-17 .sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type {
		align-self: center;
		grid-column: 7 / span 6;
		grid-row: 1;
	}

	/*
	 * The prose ends at column 5 while the picture starts at 7, which keeps a
	 * full empty column between them. Narrowing the text from 6 tracks to 5
	 * buys the photograph the width it needs without crowding the sentence.
	 */
	body.page-id-17 .sg-hero .wp-block-post-content > p:first-of-type {
		align-self: center;
		font-size: var( --wp--preset--font-size--medium );
		grid-column: 1 / span 5;
		grid-row: 1;
		line-height: 1.6;
		margin-block: 0;
	}

	/*
	 * Everything from the first section heading down starts below the opening
	 * band and spans the full width, instead of being hoisted up beside the
	 * photograph - which is what scattered the page left and right.
	 */
	body.page-id-17 .sg-hero .wp-block-post-content > h2,
	body.page-id-17 .sg-hero .wp-block-post-content > h2 ~ *:not( figure ) {
		grid-column: 1 / -1;
		grid-row: auto;
	}

	/*
	 * The image is then capped to a height the single row can carry, so it does
	 * not inflate that row and re-open the gap it was meant to close.
	 *
	 * Service Area is excluded. A height cap decides the width of a portrait
	 * image: with `aspect-ratio: 4 / 5`, 22rem of height forces 17.6rem of
	 * width, so the picture sized itself from this cap and sat at 282px inside
	 * a 618px column - which read as "the image is too small" and survived
	 * three attempts to fix it by moving grid columns that were never wrong.
	 */
	body:not( .page-id-17 ) .sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ):not( :has( > p ~ p ~ p ~ figure.wp-block-image ) ) > figure.wp-block-image:first-of-type img {
		max-height: 22rem;
	}

	/*
	 * "Where the salon is": heading, address and Towns-served card stack in one
	 * centred column, each directly under the one above it.
	 *
	 * The card used to sit at `5 / span 4` - a centre track four columns wide.
	 * Against a full-width heading and a full-width address that read as a
	 * third alignment on the same section: the eye saw the heading centred,
	 * the address centred, and the card starting somewhere else again. All
	 * three now span the grid and centre their own contents, so the section
	 * reads as one block rather than three pieces.
	 */
	body.page-id-17 .sg-hero .wp-block-post-content > h2 + p:has( br ) + .sg-card {
		grid-column: 1 / -1;
		margin-inline: auto;
		max-width: 34rem;
		text-align: center;
	}

	/*
	 * The address paragraph spans the full grid width and centres its own text
	 * (see the details-block rule further down). It must NOT be narrowed to a
	 * centre track: a narrow track plus centred text reads as an indented
	 * block sitting left of the heading, which is the mismatch that made this
	 * section look broken.
	 */
	.sg-hero .wp-block-post-content > h2 + p:has( br ) {
		grid-column: 1 / -1;
	}

	/*
	 * ...and it has to beat the opening-prose rule to do it.
	 *
	 * Further up, `> p:has( ~ figure.wp-block-image )` puts every paragraph
	 * that PRECEDES the photograph into the left six columns. The general
	 * sibling combinator does not care how far apart they are, so on this page
	 * it also caught the address under "Where the salon is": the block sat in
	 * the left half and centred its text inside that half, which read as
	 * left-aligned under a full-width centred heading. `grid-area` there is a
	 * shorthand and outranks a plain `grid-column`, so the override has to be
	 * scoped to win.
	 */
	body.page-id-17 .sg-hero .wp-block-post-content > h2 + p:has( br ) {
		grid-column: 1 / -1 !important;
		margin-inline: auto !important;
		max-width: none !important;
		text-align: center;
		width: 100%;
	}

	/*
	 * A section heading after the opening keeps its own full-width row and a
	 * generous space above, so the page reads as opening-then-section rather
	 * than as one long column.
	 */
	.sg-hero .wp-block-post-content:not( :has( > .sg-hero-line ) ) > figure.wp-block-image:first-of-type ~ h2 {
		grid-column: 1 / -1;
		margin-top: var( --wp--preset--spacing--50 );
	}

	.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type {
		align-self: start;
		grid-column: 7 / span 6;
		grid-row: 1 / span 4;
		margin-block: 0;
	}

	/*
	 * Her storefront is a tall portrait, and the arch wants a portrait crop:
	 * a wide image inside an arch reads as a tunnel mouth rather than a window.
	 */
	.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type img {
		aspect-ratio: 4 / 5;
		max-height: 34rem;
		object-fit: cover;
		object-position: 50% 20%;
		width: 100%;
	}

	/*
	 * SERVICE AREA matches the portrait arch on the home page.
	 *
	 * This used to be a 5/4 landscape capped at 22rem, which made the image
	 * render smaller than the column holding it - it floated centred in its
	 * own track with dead space either side, which read as "the picture is
	 * too small" rather than as a deliberate crop.
	 *
	 * Same 4/5 portrait and 34rem cap as the home page, so the two pages open
	 * with the same shape.
	 */
	body.page-id-17 .sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type img {
		aspect-ratio: 4 / 5;
		max-height: 34rem;
		object-fit: cover;
		object-position: 50% 20%;
		width: 100%;
	}

	/*
	 * Section headings are centred over the full grid width.
	 *
	 * max-width needs !important here. The earlier rule that gives every
	 * non-aligned child the 64ch reading measure also carries !important (it
	 * has to, to beat WordPress's constrained-layout margins), so a plain
	 * `max-width: none` loses to it and the heading centres itself inside a
	 * 720px box sitting at the left of a 1200px grid - which reads as
	 * left-aligned, not centred.
	 */
	.sg-hero .wp-block-post-content > h2 {
		max-width: none !important;
		text-align: center;
		/*
		 * justify-self: stretch is needed as well as the width. A grid item
		 * shrink-wraps to its content by default, so the heading box was only
		 * as wide as its own text and sat at the left of the grid - centred
		 * inside itself, which looks identical to left-aligned on the page.
		 */
		justify-self: stretch;
		width: 100%;
	}

	.sg-hero .wp-block-post-content > h2 + p {
		margin-inline: auto !important;
		max-width: 68rem !important;
		text-align: center;
	}

	/* The closing section spans the grid so its centring reads against the page. */
	.sg-hero .wp-block-post-content > h2:last-of-type,
	.sg-hero .wp-block-post-content > h2:last-of-type + p {
		grid-column: 1 / -1;
		justify-self: stretch;
		width: 100%;
	}

	/*
	 * A details list (phone / email / address, separated by <br>) is centred as
	 * a block but its lines stay left-aligned, so the labels line up.
	 *
	 * justify-self, not auto margins. The grid's own margin reset carries
	 * !important and sits in the same specificity bracket, so an auto margin
	 * here is a coin toss decided by source order; justify-self is the grid's
	 * own centring mechanism and is not competing with it. grid-column must be
	 * restated too, or the paragraph centres inside column 1 of four.
	 */
	/*
	 * A details block sits centred under its centred heading, but its own lines
	 * stay left-aligned so the labels line up. Centring the text itself centres
	 * each line independently and an address reads as ragged steps.
	 */
	/*
	 * Inside the grid the details block spans the full width so its centred
	 * text centres against the page rather than against one 12th of it. The
	 * text-align does the centring; see the details-block section below for why
	 * an auto-margin approach cannot win here.
	 */
	.sg-hero .wp-block-post-content > h2 + p:has( br ) {
		grid-column: 1 / -1;
		text-align: center;
	}

	/*
	 * Anything else following that details block - the opening hours line after
	 * an address, for instance - is centred with it rather than left on the
	 * page edge, so the whole section reads as one centred group.
	 */
	.sg-hero .wp-block-post-content > h2 + p:has( br ) + p {
		grid-column: 1 / -1;
		text-align: center;
	}

	/*
	 * A section whose heading is centred keeps its prose centred with it: a
	 * centred heading sitting over a left-edged paragraph reads as a mistake
	 * rather than as a choice. Cards, galleries and the hero are excluded -
	 * they carry their own alignment.
	 */
	.sg-hero .wp-block-post-content > h2 ~ p:not( :has( br ) ):not( .sg-hero-line ) {
		justify-self: center;
		max-width: 68rem;
		text-align: center;
	}
}

/*
 * THE ARCH. The hero photograph is masked to a rounded top and square bottom.
 * This is the signature shape of the direction and is applied to the hero
 * image and to the alternating band images below, but never to gallery tiles -
 * a grid of arches reads as decoration rather than as photography.
 *
 * !important and the extra selectors are both required. A figure saved with a
 * border radius in the editor carries `has-custom-border`, and WordPress then
 * emits an inline radius on the image itself; an inline style beats any
 * stylesheet selector, so the arch has to be forced. The figure is targeted as
 * well as the img because the inline radius can land on either.
 */
.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type,
.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type img,
.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type.has-custom-border img {
	border-radius: var( --sg-arch ) !important;
	box-shadow: none;
}

.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type {
	overflow: hidden;
}

.sg-hero .wp-block-post-content > figure.wp-block-image:first-of-type img {
	width: 100%;
}

/* ---------------------------------------------------------------------------
 * Typography polish theme.json cannot express
 * ------------------------------------------------------------------------ */

/* Stop single words dropping onto their own line under a big headline. */
h1,
h2,
h3 {
	text-wrap: balance;
}

p {
	text-wrap: pretty;
}

/*
 * The opening paragraph of a page is the answer an engine quotes, so it gets
 * the lead size. Only the first one - every paragraph at lead size is just a
 * bigger wall of text.
 */
.wp-block-post-content > p:first-of-type {
	color: var( --wp--preset--color--muted );
	font-size: var( --wp--preset--font-size--lead );
	line-height: 1.7;
}

/* ---------------------------------------------------------------------------
 * Section rhythm
 *
 * In the reference, a section heading is centred over a single wide paragraph
 * with a great deal of air above it. The rule underneath a heading is gone:
 * the reference separates sections with whitespace and background colour, not
 * with drawn lines.
 * ------------------------------------------------------------------------ */

.wp-block-post-content > h2 {
	margin-top: var( --wp--preset--spacing--70 );
	margin-bottom: var( --wp--preset--spacing--40 );
	text-align: center;
}

/*
 * The intro paragraph that follows a section heading is centred with it and
 * given a wider measure than body prose, matching the reference's single
 * centred block of introduction under each section title.
 *
 * Only the paragraph DIRECTLY after the heading. In the reference every
 * section opens with one centred line of introduction and then returns to
 * left-aligned prose; centring every paragraph is what makes a page read like
 * a certificate rather than like something written to be read.
 */
.wp-block-post-content > h2 + p {
	margin-inline: auto !important;
	max-width: 68rem !important;
	text-align: center;
}

/* Body prose stays left-aligned. */
.wp-block-post-content > p,
.sg-card p {
	text-align: left;
}

.wp-block-post-content > h2 + p {
	text-align: center;
}

/*
 * A details block - a single paragraph broken with <br> into phone, email and
 * address lines - is LEFT-aligned and centred as a block. Centring the text
 * itself centres every line independently, and a list of labelled values then
 * reads as ragged steps rather than as a list. Only genuine prose after a
 * heading gets centred text; anything with line breaks in it is a list.
 */
/* ---------------------------------------------------------------------------
 * The details block - name, address, phone, hours
 *
 * Centred TEXT, not a centred box.
 *
 * The obvious approach - shrink the block to its content and give it auto side
 * margins - cannot win here: several rules set `margin-left: 0 !important` on
 * every child of post-content, one of them inside a media query, and a tie on
 * specificity is decided by source order. Centring the text itself sidesteps
 * the whole fight, and for an address it reads better anyway: a short stack of
 * lines centred under a centred heading is how a business card sets its
 * details.
 *
 * The lines are given room to breathe and the name is lifted into the display
 * serif, so the block reads as the salon's card rather than as a leftover
 * paragraph.
 * ------------------------------------------------------------------------ */

.wp-block-post-content > h2 + p:has( br ) {
	color: var( --wp--preset--color--muted );
	line-height: 2.1;
	text-align: center;
	/*
	 * The width has to be forced as well as the alignment. An earlier rule caps
	 * every child of post-content at the reading measure, which leaves this
	 * block about 285px wide sitting at the left edge - the text then centres
	 * inside that narrow box and the section still looks left-aligned. Filling
	 * the container is what makes the centring visible.
	 */
	max-width: none !important;
	width: 100%;
}

/*
 * Bold text inside a details block is a LABEL - "Phone:", "Email:",
 * "Address:" - not a title. It stays at body size and simply carries a little
 * more weight than the value beside it.
 *
 * An earlier version of this rule promoted the first bold to a large display
 * serif on the assumption it was the salon's name. That is true on the
 * homepage and wrong on the contact page, where it turned "Phone:" into a
 * heading larger than the section title above it. Styling by position is a
 * guess about content; styling every label the same way is not.
 */
.wp-block-post-content > h2 + p:has( br ) strong {
	color: var( --wp--preset--color--contrast-2 );
	font-weight: 500;
}

/* The line that follows a details block - opening hours - is centred with it. */
.wp-block-post-content > h2 + p:has( br ) + p {
	color: var( --wp--preset--color--muted );
	max-width: none !important;
	text-align: center;
	width: 100%;
}

/* ---------------------------------------------------------------------------
 * The closing section of a page
 *
 * The last heading on a page - "Opening hours" on Service Area - is the one a
 * visitor scrolls to deliberately, so it is set larger than the section
 * headings above it and its line is centred directly beneath it rather than
 * left on the page edge. It reads as a closing statement rather than as a
 * footnote.
 *
 * `:last-of-type` identifies it without hard-coding any wording, so the same
 * treatment applies on any page whose final section is a single fact.
 * ------------------------------------------------------------------------ */

.wp-block-post-content > h2:last-of-type {
	font-size: var( --wp--preset--font-size--x-large );
	margin-top: var( --wp--preset--spacing--60 );
}

.wp-block-post-content > h2:last-of-type + p {
	margin-inline: auto;
	max-width: none !important;
	text-align: center;
	width: 100%;
}


/* ---------------------------------------------------------------------------
 * Service cards
 *
 * Flat tiles, not floating cards. In the reference a service is a photograph
 * with a centred serif name beneath it and left-aligned body copy - no border,
 * no shadow, no fill. Each service is a real group block (.sg-card) in the
 * page content, so the tile is one element.
 * ------------------------------------------------------------------------ */

/*
 * A card is a tinted surface, not floating text.
 *
 * Bare headings and paragraphs sitting in grid columns read as a spreadsheet:
 * nothing holds a service together, and the eye has no edge to rest on. The
 * reference solves this with solid blocks of colour - no borders, no shadows,
 * just a field of tint that contains its content. That is what makes it look
 * composed rather than typed.
 *
 * The tints rotate through three of her surface colours (blush, cream, sage)
 * so a row reads as one designed system rather than three copies of the same
 * card. The rotation is by position, so it adapts to rows of three or four
 * without anyone tagging the markup.
 */
.sg-card {
	background-color: var( --wp--preset--color--base-2 );
	border: 0;
	border-radius: 2px;
	box-sizing: border-box;
	margin-block: var( --wp--preset--spacing--30 );
	padding: var( --wp--preset--spacing--50 ) var( --wp--preset--spacing--40 );
	/*
	 * The lift on hover is 1px and the tint deepens slightly. Anything more
	 * turns a calm page into a bouncing one; anything less and the card does
	 * not acknowledge the pointer at all.
	 */
	transition: background-color var( --sg-dur ) var( --sg-ease ),
		transform var( --sg-dur ) var( --sg-ease );
}

/*
 * ONE surface, not a rotation.
 *
 * Rotating three tints across a row was the wrong instinct: the reference uses
 * three colours because it has exactly three tiles, each linking somewhere
 * different. A row of four services is one set of equivalent things, and
 * giving them different colours implies a distinction that does not exist -
 * it reads as arbitrary rather than considered.
 *
 * The warm cream carries every card. It is the quietest surface in the
 * palette, so the blush hero stays the only strong colour on the page and the
 * cards read as calm, not as a second hero.
 */
.sg-card {
	background-color: var( --wp--preset--color--cream );
}

.sg-card:hover {
	background-color: var( --wp--preset--color--base-2 );
	transform: translateY( -1px );
}

/*
 * A hairline in the rose accent sits above each service name. It is 24px of
 * 1px rule - just enough to give the card a starting edge and to carry a trace
 * of her brand pink into a section that is otherwise all neutrals. This is the
 * one place the pink earns its keep: it is decoration, never text, so its poor
 * contrast on a tint cannot hurt legibility.
 */
.sg-card h3::before {
	background-color: var( --wp--preset--color--accent );
	content: "";
	display: block;
	height: 1px;
	margin: 0 auto var( --wp--preset--spacing--30 );
	width: 24px;
}

/*
 * The card is a constrained group, so WordPress centres its children at the
 * content size and leaves a wide indent inside a full-width card.
 */
.sg-card > * {
	margin-inline: 0;
	max-width: none;
}

.sg-card > :first-child {
	margin-top: 0;
}

.sg-card > :last-child {
	margin-bottom: 0;
}

/*
 * The service name: centred serif, slightly smaller than a section heading and
 * widely tracked. Centring the name over centred body copy is what makes the
 * card read as a composed unit - the previous version centred the name over
 * left-aligned prose, which is what made the section look misaligned.
 */
.sg-card h3 {
	color: var( --wp--preset--color--contrast-2 );
	font-size: var( --wp--preset--font-size--large );
	letter-spacing: 0.05em;
	margin-block: 0 var( --wp--preset--spacing--30 );
	text-align: center;
}

.sg-card p {
	color: var( --wp--preset--color--muted );
	font-size: var( --wp--preset--font-size--small );
	line-height: 1.8;
	margin-block: 0;
	text-align: center;
	text-wrap: pretty;
}

/*
 * A photograph inside a service tile is a plain square with a soft radius -
 * the arch is reserved for the hero and the feature bands.
 */
.sg-card figure.wp-block-image img {
	aspect-ratio: 1 / 1;
	border-radius: 6px;
	box-shadow: none;
	object-fit: cover;
	width: 100%;
}

/*
 * The cards are flat siblings inside post-content - there is no wrapper element
 * around each run of them, and adding one would mean editing her page content
 * again. They are placed into the page grid above (see THE ONE GRID): a card
 * takes one column, everything else spans all four.
 */

/* ---------------------------------------------------------------------------
 * Flat colour tiles
 *
 * The reference's three quick links - team, services, gallery - are flat
 * blocks of colour with a small caps label over a bold name, and nothing else:
 * no icon, no border, no shadow, no image. Applied to a row of buttons or a
 * columns block marked .sg-tiles.
 * ------------------------------------------------------------------------ */

.sg-tiles {
	margin-block: var( --wp--preset--spacing--60 );
}

.sg-tiles .wp-block-column {
	padding: var( --wp--preset--spacing--60 ) var( --wp--preset--spacing--40 );
	text-align: center;
}

/* Each tile takes one of the three tints, in the reference's order. */
.sg-tiles .wp-block-column:nth-child( 3n + 1 ) {
	background-color: var( --wp--preset--color--base-2 );
}

.sg-tiles .wp-block-column:nth-child( 3n + 2 ) {
	background-color: var( --wp--preset--color--base-3 );
}

.sg-tiles .wp-block-column:nth-child( 3n + 3 ) {
	background-color: var( --wp--preset--color--sage );
}

.sg-tiles .wp-block-column p {
	color: var( --wp--preset--color--muted );
	font-size: var( --wp--preset--font-size--small );
	letter-spacing: 0.18em;
	margin-block: 0;
	text-transform: uppercase;
}

.sg-tiles .wp-block-column h3 {
	color: var( --wp--preset--color--contrast-2 );
	margin-block: var( --wp--preset--spacing--20 ) 0;
	text-align: center;
}

/* ---------------------------------------------------------------------------
 * Feature bands
 *
 * The reference alternates full-bleed tinted bands holding an arch photograph
 * beside a block of text and a button. A band is a group marked .sg-band.
 * ------------------------------------------------------------------------ */

.sg-band {
	margin-block: var( --wp--preset--spacing--70 );
	padding-block: var( --wp--preset--spacing--70 );
	padding-inline: var( --wp--style--root--padding-right, var( --wp--preset--spacing--30 ) );
}

.sg-band > * {
	margin-inline: auto;
	max-width: var( --wp--style--global--wide-size, 1320px );
}

.sg-band--cream {
	background-color: var( --wp--preset--color--cream );
}

.sg-band--blush {
	background-color: var( --wp--preset--color--base-2 );
}

.sg-band--sage {
	background-color: var( --wp--preset--color--sage );
}

.sg-band .wp-block-image img {
	border-radius: var( --sg-arch );
	box-shadow: none;
}

.sg-band h2 {
	text-align: left;
}

/* ---------------------------------------------------------------------------
 * Testimonials
 *
 * Centred italic quotes on a tinted ground, side by side at desktop. No
 * quotation marks are drawn and no card is used: the reference lets the italic
 * and the colour do the work.
 * ------------------------------------------------------------------------ */

.sg-quotes {
	background-color: var( --wp--preset--color--sage );
	margin-block: var( --wp--preset--spacing--70 );
	padding-block: var( --wp--preset--spacing--70 );
	padding-inline: var( --wp--style--root--padding-right, var( --wp--preset--spacing--30 ) );
}

.sg-quotes blockquote,
.sg-quotes .wp-block-quote {
	border: 0;
	color: var( --wp--preset--color--contrast-2 );
	font-size: var( --wp--preset--font-size--medium );
	font-style: italic;
	line-height: 1.75;
	margin: 0;
	padding: 0;
	text-align: center;
}

.sg-quotes cite {
	color: var( --wp--preset--color--muted );
	display: block;
	font-size: var( --wp--preset--font-size--small );
	font-style: normal;
	letter-spacing: 0.12em;
	margin-top: var( --wp--preset--spacing--30 );
	text-transform: uppercase;
}

/* ---------------------------------------------------------------------------
 * Buttons
 *
 * Solid rectangles with wide-tracked uppercase labels. The reference's buttons
 * do not lift, glow or round: the hover is a colour change only. Structure,
 * destination and wording are untouched - this is the surface treatment.
 * ------------------------------------------------------------------------ */

.wp-element-button,
.wp-block-button__link {
	box-shadow: none;
	transition: background-color var( --sg-dur ) var( --sg-ease ),
		color var( --sg-dur ) var( --sg-ease );
}

.wp-element-button:hover,
.wp-block-button__link:hover {
	box-shadow: none;
	transform: none;
}

/* ---------------------------------------------------------------------------
 * Repeated calls to action
 *
 * Every page already carries a "Book" button in the header, and the navigation
 * carries the same links. A second button at the foot of a section repeats a
 * journey the visitor can already make and leaves an odd stub hanging under
 * otherwise tidy content.
 *
 * The Contact page keeps its button - that page exists to convert, so the call
 * to action belongs there. Everywhere else the in-page duplicates are hidden.
 *
 * Hidden in CSS, not removed from her pages: the blocks stay in the content, so
 * the links survive for anyone reading without this stylesheet, and restoring
 * one is deleting a rule rather than re-editing her content.
 * ------------------------------------------------------------------------ */

.sg-hero .wp-block-post-content > .wp-block-buttons:has( a[ href*="/services-prices/" ] ) {
	display: none;
}

/*
 * The "Book an appointment" buttons on About and Service Area.
 *
 * WordPress does not emit a slug class on the body - pages are identified by
 * id - so the Contact page is excluded by its id, 18. If her pages are ever
 * rebuilt from scratch the ids change and this needs revisiting; the comment
 * is here so that is findable.
 */
body:not( .page-id-18 ) .sg-hero .wp-block-post-content > .wp-block-buttons:has( a[ href*="/contact-book/" ] ) {
	display: none;
}

/* The outline button is the quieter of the pair, so it gets no fill. */
.is-style-outline .wp-block-button__link {
	background-color: transparent;
	border: 1px solid var( --wp--preset--color--contrast-2 );
	box-shadow: none;
	color: var( --wp--preset--color--contrast-2 );
}

.is-style-outline .wp-block-button__link:hover {
	background-color: var( --wp--preset--color--contrast-2 );
	color: var( --wp--preset--color--surface );
}

/* ---------------------------------------------------------------------------
 * Images
 *
 * Square photographs with a soft radius, flat on the page. Gallery tiles are
 * uniform squares, as in the reference's Instagram row.
 * ------------------------------------------------------------------------ */

.wp-block-image img,
.wp-block-gallery .wp-block-image img {
	border-radius: 6px;
	box-shadow: none;
}

/* ---------------------------------------------------------------------------
 * Gallery photographs on colour fields
 *
 * Each photograph sits slightly inset over a block of colour that extends past
 * it on two sides, the way the reference sets its hero image: the picture is
 * not a tile on a white page, it is a picture ON something. That offset field
 * is what gives the section depth without a single shadow.
 *
 * The fields rotate through five of her surface colours rather than repeating
 * one. Here the rotation is right - unlike the service cards, these are not
 * equivalent items in a set, they are a wall of her work, and the varied
 * grounds read as an arrangement rather than as a grid of sameness.
 * ------------------------------------------------------------------------ */

/*
 * The figure is the frame the field and the photograph are positioned inside.
 *
 * Core makes a gallery figure `display: flex` so the image fills it exactly;
 * with no slack there is nowhere for an offset field to show. Switching to
 * block and padding the two sides the field overhangs gives the composition
 * its room, and the photograph then sits inset on its ground.
 */
.wp-block-gallery .wp-block-image {
	/* One distance governs the whole construction: the field's shift and the
	   padding that makes room for it are always the same number. */
	--sg-field-shift: 1.25rem;

	display: block;
	padding-bottom: var( --sg-field-shift );
	padding-left: var( --sg-field-shift );
	position: relative;
}

/*
 * The colour field. Inset on two sides and overhanging on the other two, so
 * the photograph sits off-centre on its ground - a centred field behind a
 * centred photo just looks like a border.
 */
/*
 * `content` needs !important. The core gallery stylesheet sets
 * `content: none` on gallery figures' pseudo-elements (it uses them for
 * caption gradients and turns them off when there is no caption), and that
 * declaration wins here - the field gets its colour and its box but is never
 * generated, so the treatment silently does nothing.
 */
.wp-block-gallery .wp-block-image::before {
	background-color: var( --sg-field, var( --wp--preset--color--base-2 ) );
	border-radius: 2px;
	/*
	 * The field is the photograph's box shifted down and left by an equal
	 * amount on all four sides. Offsetting by a single distance keeps the two
	 * rectangles parallel, so the overhang reads as one deliberate shift
	 * rather than as a frame that has slipped.
	 */
	bottom: calc( -1 * var( --sg-field-shift ) );
	content: "" !important;
	display: block;
	left: calc( -1 * var( --sg-field-shift ) );
	position: absolute;
	right: var( --sg-field-shift );
	top: var( --sg-field-shift );
	transition: background-color var( --sg-dur ) var( --sg-ease );
	z-index: 0;
}

/* Five grounds, cycling. Every row of three lands on a different combination. */
.wp-block-gallery .wp-block-image:nth-child( 5n + 1 ) { --sg-field: #F7D7E3; }
.wp-block-gallery .wp-block-image:nth-child( 5n + 2 ) { --sg-field: #DDE4DD; }
.wp-block-gallery .wp-block-image:nth-child( 5n + 3 ) { --sg-field: #F3E4D7; }
.wp-block-gallery .wp-block-image:nth-child( 5n + 4 ) { --sg-field: #E6DCE8; }
.wp-block-gallery .wp-block-image:nth-child( 5n + 5 ) { --sg-field: #FCEEF3; }

/*
 * The photograph itself sits above its field. A portrait crop rather than a
 * square: hair is vertical, and a square crop cuts the length off every style
 * she has done.
 */
.wp-block-gallery .wp-block-image img {
	aspect-ratio: 4 / 5;
	object-fit: cover;
	position: relative;
	transition: transform var( --sg-dur ) var( --sg-ease );
	width: 100%;
	z-index: 1;
}

/*
 * On hover the photograph eases towards the centre of its field rather than
 * scaling. Scaling a photograph enlarges the grain; a small shift keeps the
 * image crisp and makes the layered construction legible.
 */
.wp-block-gallery .wp-block-image:hover img {
	transform: translate( calc( -0.5 * var( --wp--preset--spacing--20 ) ),
		calc( 0.5 * var( --wp--preset--spacing--20 ) ) );
}

/* ---------------------------------------------------------------------------
 * Header and footer
 * ------------------------------------------------------------------------ */

/*
 * The navigation is set as small, wide-tracked uppercase labels, matching the
 * reference. The links themselves are untouched.
 */
header.wp-block-group .wp-block-navigation {
	font-family: var( --wp--preset--font-family--body );
	font-size: var( --wp--preset--font-size--small );
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

header.wp-block-group .wp-block-navigation a {
	text-decoration: none;
}

header.wp-block-group .wp-block-navigation a:hover {
	text-decoration: underline;
}

/*
 * theme.json colours every heading with the logo black, which is invisible on
 * the near-black footer panel, so the footer's own headings are re-stated.
 */
footer.wp-block-group h1,
footer.wp-block-group h2,
footer.wp-block-group h3,
footer.wp-block-group .wp-block-site-title {
	color: var( --wp--preset--color--surface );
}

/*
 * The footer panel is near-black and its body text is set to `muted`, which is
 * a mid grey chosen for readability on WHITE. On the panel it drops to roughly
 * 3.4:1 and fails AA for body text, so the footer re-states it as a light warm
 * grey that clears AA against #0E0E0E.
 */
footer.wp-block-group .has-muted-color {
	color: #C9C4BF !important;
}

/* Footer column headings are small caps labels, as in the reference. */
footer.wp-block-group h2,
footer.wp-block-group h3 {
	font-family: var( --wp--preset--font-family--body );
	font-size: var( --wp--preset--font-size--small );
	letter-spacing: 0.18em;
	text-transform: uppercase;
}

footer.wp-block-group a {
	text-underline-offset: 0.2em;
}

footer.wp-block-group a:hover {
	color: var( --wp--preset--color--base-3 );
}

/*
 * The three footer columns share the full width evenly.
 *
 * The block's own grid used `minimumColumnWidth: 16rem`, which is an auto-fit:
 * it packs as many 16rem tracks as fit and leaves the remainder as empty space
 * at the right. On a wide screen that read as three columns crowded into the
 * left two-thirds of a near-black panel.
 *
 * Three explicit equal tracks spread the columns across the whole width, so
 * the contact block, the hours and the page list sit at even intervals.
 */
.sg-footer-columns {
	gap: var( --wp--preset--spacing--50 );
	grid-template-columns: repeat( 3, minmax( 0, 1fr ) );
}

/* One column on a phone: three tracks would give each about 100px. */
@media ( max-width: 781px ) {
	.sg-footer-columns {
		grid-template-columns: 1fr;
	}
}

/* ---------------------------------------------------------------------------
 * Scroll reveal
 *
 * Animation-timeline does this natively where it is supported, with no
 * JavaScript and no layout thrash. Where it is not, content is simply visible:
 * the @supports guard means nothing is ever hidden without the means to
 * reveal it, which is the usual way scroll reveals break.
 * ------------------------------------------------------------------------ */

@supports ( animation-timeline: view() ) {
	@media ( prefers-reduced-motion: no-preference ) {
		@keyframes sg-reveal {
			from {
				opacity: 0;
				transform: translateY( 20px );
			}

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

		/*
		 * The tiles and the galleries only. Putting the same entrance on every
		 * heading, button and figure makes the whole page twitch on the way
		 * down; the reveal is worth having where there is a row of things that
		 * can arrive in sequence, and nowhere else.
		 */
		.sg-card,
		.sg-tiles .wp-block-column,
		.wp-block-post-content > figure.wp-block-gallery {
			animation: sg-reveal var( --sg-ease ) both;
			animation-range: entry 0% cover 18%;
			animation-timeline: view();
		}
	}
}

/* Visually hidden, still read aloud and still focusable. */
.screen-reader-text {
	border: 0;
	clip-path: inset(50%);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
	word-wrap: normal !important;
}

/* Skip link: visible only once focused by keyboard. */
.skip-link:focus {
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--contrast);
	clip: auto !important;
	clip-path: none;
	display: block;
	font-size: var(--wp--preset--font-size--medium);
	font-weight: 600;
	height: auto;
	left: 6px;
	line-height: normal;
	padding: 14px 22px;
	text-decoration: none;
	top: 6px;
	width: auto;
	z-index: 100000;
}

/* The header logo keeps its aspect ratio at every width. */
.wp-block-site-logo img {
	height: auto;
	max-width: 100%;
}

/*
 * The GHL booking widget is an iframe. Without these it either collapses
 * to nothing or forces a horizontal scrollbar on narrow phones.
 *
 * The min-height matters: an iframe has no intrinsic height, so without one
 * the widget is clipped to a sliver. See the frame rule below for why that
 * height is 40rem and not the service list's full height.
 */
.sagelyn-booking-embed {
	margin-inline: auto;
	max-width: 64rem;
	width: 100%;
}

/*
 * The frame is sized to the widget's own content, NOT to the service list.
 *
 * 125rem/108rem was an attempt to show all eight services without an inner
 * scrollbar. It does not work and cannot work: the GHL widget is a fixed-height
 * scrolling app inside the iframe, so it renders its own scrollbar no matter
 * how tall we make the frame. All the extra height did was add ~1400px of blank
 * page between the widget and the footer - two empty screens on a desktop.
 *
 * 40rem fits the widget's rendered content. The inner scrollbar stays either
 * way; this way it does not cost a screenful of nothing underneath.
 *
 * If this ever needs to grow, measure the widget's real rendered height first
 * (its content is ~300px) rather than estimating from the service count.
 */
.sagelyn-booking-embed iframe {
	border: 0;
	display: block;
	max-width: 100%;
	min-height: 40rem;
	width: 100%;
}

/*
 * Shown until a real calendar URL replaces the placeholder. It reads as part
 * of the salon rather than as a developer warning.
 */
.sagelyn-booking-embed__todo {
	background-color: var( --wp--preset--color--base-2 );
	border: 0;
	border-radius: 0;
	color: var( --wp--preset--color--contrast-2 );
	padding: var( --wp--preset--spacing--40 );
	text-align: center;
}

/* Respect a visitor's reduced-motion setting. */
@media ( prefers-reduced-motion: reduce ) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		scroll-behavior: auto !important;
		transition-duration: 0.01ms !important;
	}
}

/* ---------------------------------------------------------------------------
 * The booking widget
 *
 * The GHL service menu is an iframe, and an iframe has no intrinsic width in a
 * grid track - it rendered in a narrow column with the row empty beside it. It
 * takes the full content width and a height that suits the service list, so
 * the list does not scroll inside an already scrolling page.
 * ------------------------------------------------------------------------ */

@media ( min-width: 700px ) {
	.sg-hero .wp-block-post-content > .sagelyn-booking-embed,
	.sg-hero .wp-block-post-content > *:has( > .sagelyn-booking-embed ) {
		grid-column: 1 / -1;
	}
}

/* ---------------------------------------------------------------------------
 * The booking link in the navigation
 *
 * The header used to carry a separate "Book" button beside the menu, which
 * duplicated the "Contact & Book" item next to it - two controls, one
 * destination. The button is gone and the nav item itself now carries the
 * emphasis, so there is one obvious way to book from the header.
 *
 * The last item in the navigation is the booking link. Matching on position
 * rather than on wording keeps this working if the label is ever reworded.
 * ------------------------------------------------------------------------ */

/*
 * The colour needs !important. WordPress prints its own navigation link
 * colour from Global Styles into the page head, and that selector beats this
 * one - without the override the label rendered near-black on the plum field
 * and was unreadable.
 */
header .wp-block-navigation__container > li:last-child > a,
header .wp-block-navigation__container > li:last-child > a.wp-block-navigation-item__content {
	background-color: var( --wp--preset--color--contrast );
	color: var( --wp--preset--color--base ) !important;
	padding: 0.7em 1.4em;
	transition: background-color var( --sg-dur ) var( --sg-ease );
}

header .wp-block-navigation__container > li:last-child > a:hover,
header .wp-block-navigation__container > li:last-child > a:focus-visible,
header .wp-block-navigation__container > li:last-child > a.wp-block-navigation-item__content:hover {
	background-color: var( --wp--preset--color--panel );
	color: var( --wp--preset--color--base ) !important;
}

/*
 * Inside the mobile overlay the item returns to a plain link: the overlay is
 * a list of destinations on a solid background, and a filled block there
 * reads as a misplaced button rather than as emphasis.
 */
header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container > li:last-child > a {
	background-color: transparent;
	color: inherit;
	padding: 0;
}

/* ---------------------------------------------------------------------------
 * CONTACT AND BOOK - centred column
 *
 * The blocks that used to pin every child of the hero to the left edge now
 * exclude this page at source (search `page-id-18` above). That was the only
 * approach that worked: those rules carry !important AND two :not() pseudo-
 * classes, so nothing written at the bottom of this file could outrank them,
 * and several attempts to centre this page from here lost silently.
 *
 * With the competition removed these rules are ordinary and need no
 * !important of their own.
 *
 * The page is a short list of facts - phone, address, hours, then the booking
 * widget - so the whole column is centred rather than individual blocks.
 * ------------------------------------------------------------------------ */

body.page-id-18 .sg-hero .wp-block-post-content,
body.page-id-18 .sg-hero > .wp-block-group {
	margin-inline: auto;
	max-width: var( --wp--style--global--wide-size, 1320px );
	width: 100%;
}

body.page-id-18 .sg-hero .wp-block-post-content > *,
body.page-id-18 .sg-hero .wp-block-post-title {
	margin-inline: auto;
	max-width: 46rem;
	text-align: center;
}

/* Inline content follows the column. */
body.page-id-18 .sg-hero .wp-block-post-content > * > * {
	text-align: center;
}

/* The widget is an interface, not prose, so it takes more room. */
body.page-id-18 .sagelyn-booking-embed {
	margin-inline: auto;
	max-width: 64rem;
}
