/*
 * Reset, the type scale, the 1100 px container and the button base.
 *
 * Everything here consumes tokens.css and declares no colour of its own: a bare
 * hex in this file is a finding (qa-grep.sh, G4). What lives here is the layer
 * every page shares before a single component exists - the document defaults, the
 * grid, the two button variants and the focus ring. Components arrive in
 * components.css from WPS-012 on.
 *
 * There is no width media query in this file yet, and when one arrives it is
 * mobile-first (min-width) - the opposite direction from the mockups, which are
 * authored desktop-first with `max-width: 920px`. The two are the same
 * breakpoint read from opposite ends: a rule the mockup applies below 921 px is
 * a rule this file simply does not apply until 921 px. The direction is fixed by
 * config/review-rules.md rule 7; the number is the canon 920/921 px, where the
 * header folds into a burger.
 */

/* ---------------------------------------------------------------------------
 * Reset
 *
 * Small on purpose. A large reset undoes browser defaults that are correct and
 * then has to reinstate them one by one, which is how a theme ends up with two
 * competing type scales.
 */

*,
*::before,
*::after {
	box-sizing: border-box;
}

html {
	scroll-behavior: smooth;
	/*
	 * Never let a fixed header cover the heading an anchor jumps to. While a
	 * logged-in preview user's admin toolbar is fixed, the sticky header sits
	 * below it (components.css), so the anchor padding grows by the same height.
	 */
	scroll-padding-top: calc( var( --space-16 ) + var( --admin-bar-fixed-height, 0px ) );
	-webkit-text-size-adjust: 100%;
}

/*
 * The height of WordPress' admin toolbar while it is FIXED to the viewport - the
 * one number the sticky header, the open phone navigation and the anchor padding
 * all have to clear. Core publishes --wp-admin--admin-bar--height on :root only
 * while the toolbar is shown (46 px up to 782 px, 32 px above), but up to 600 px
 * core makes the toolbar position: absolute and it scrolls away with the page, so
 * nothing sticky needs to clear it there. 601 px is core's toolbar breakpoint, not
 * a design one. A public visitor never has the core property and reads 0.
 */
@media screen and ( min-width: 601px ) {

	:root {
		--admin-bar-fixed-height: var( --wp-admin--admin-bar--height, 0px );
	}
}

body {
	margin: 0;
	background: var( --surface-page );
	color: var( --text-body );
	font-family: var( --font-sans );
	font-size: var( --fs-body );
	font-weight: var( --fw-regular );
	line-height: var( --lh-body );
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

img,
picture,
video,
canvas,
svg {
	display: block;
	max-width: 100%;
	height: auto;
}

/* Form controls do not inherit the document font on their own, and a select
 * rendering in the system UI font is the one element that gives a custom theme
 * away. */
button,
input,
select,
textarea {
	font: inherit;
	color: inherit;
}

/*
 * Motion is restrained by design, and for a visitor who asks the operating
 * system to reduce it there is none. The smooth scroll above is the main thing
 * this switches off; the rest is a floor for the components still to come.
 */
@media ( prefers-reduced-motion: reduce ) {
	html {
		scroll-behavior: auto;
	}

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

/* ---------------------------------------------------------------------------
 * Type scale
 *
 * The sizes are measured off the current mockups rather than read off the token
 * scale alone: the tokens carry the desktop end (--fs-display 56px, --fs-h2
 * 38px) and the design reaches it through a clamp, so a phone gets 36px and 26px
 * instead of a heading that pushes the page sideways. The lower bound and the
 * vw slope are those measured values; the upper bound is the token.
 */

h1,
h2,
h3,
h4,
h5,
h6 {
	margin: 0 0 var( --space-4 );
	color: var( --text-heading );
	font-weight: var( --fw-black );
	/* Balance the last line instead of leaving one orphaned word. Ignored by
	 * browsers that do not know it, which is the correct outcome. */
	text-wrap: pretty;
}

h1 {
	font-size: clamp( 36px, 5.4vw, var( --fs-display ) );
	line-height: var( --lh-tight );
	letter-spacing: var( --ls-display );
}

h2 {
	font-size: clamp( 26px, 3.6vw, var( --fs-h2 ) );
	line-height: var( --lh-heading );
}

h3 {
	font-size: var( --fs-h3 );
	font-weight: var( --fw-bold );
	line-height: var( --lh-relaxed );
}

h4,
h5,
h6 {
	font-size: var( --fs-lead );
	font-weight: var( --fw-bold );
	line-height: var( --lh-relaxed );
}

p,
ul,
ol,
figure,
blockquote {
	margin: 0 0 var( --space-4 );
}

blockquote {
	font-style: italic;
	line-height: var( --lh-snug );
}

/* The lead paragraph under a heading. */
.lead {
	font-size: var( --fs-lead );
	line-height: var( --lh-relaxed );
}

/* Meta lines: dates, captions, the fine print under a price. */
.meta {
	color: var( --text-meta );
	font-size: var( --fs-meta );
}

/* Short uppercase label above a heading - the one place the canon allows
 * capitals, and only with wide tracking. */
.eyebrow {
	color: var( --text-link );
	font-size: var( --fs-eyebrow );
	font-weight: var( --fw-black );
	letter-spacing: var( --ls-eyebrow );
	text-transform: uppercase;
}

.handwritten {
	font-family: var( --font-accent );
	font-weight: 600;
}

a {
	color: var( --text-link );
}

/* ---------------------------------------------------------------------------
 * Layout
 *
 * One grid for the whole site: the header, the footer and every content section
 * use this class, so their content edges line up to the pixel. Two containers
 * that declare the same max-width and measure different edges are invariant
 * I11.1 and a blocking finding.
 */

.container {
	width: 100%;
	max-width: var( --container );
	margin-inline: auto;
	padding-inline: var( --gutter );
}

/* ---------------------------------------------------------------------------
 * Buttons
 *
 * Both variants are fully pill. Primary is ink black and turns accessible blue
 * on hover; secondary is white with a hairline border that picks up the accent.
 * They are sized so the touch target clears 44 px without a helper: 15px text at
 * the body line-height plus 13px of padding measures about 52 px tall.
 *
 * The white on the primary button comes from --color-surface because that is the
 * only white the palette has. It reads as a surface token in a text position,
 * and it is still the right call: inventing a --text-on-inverse token here would
 * put a value in tokens.css that the design system never wrote down.
 */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var( --space-2 );
	border: 1px solid transparent;
	border-radius: var( --radius-pill );
	padding: 13px 24px;
	font-family: var( --font-sans );
	font-size: var( --fs-sm );
	font-weight: var( --fw-bold );
	line-height: var( --lh-body );
	text-decoration: none;
	white-space: nowrap;
	cursor: pointer;
	transition:
		background var( --dur ) var( --ease ),
		border-color var( --dur ) var( --ease ),
		color var( --dur ) var( --ease );
}

.btn--sm {
	padding: 11px 22px;
	font-size: var( --fs-caption );
}

.btn--lg {
	padding: 15px 32px;
	font-size: var( --fs-body );
}

.btn--primary {
	background: var( --action-primary );
	color: var( --color-surface );
}

.btn--primary:hover {
	background: var( --action-primary-hover );
}

.btn--secondary {
	background: var( --surface-card );
	border-color: var( --border-control );
	color: var( --text-heading );
}

/*
 * Hover on the secondary button borrows the accent for the BORDER and the darker
 * accent for the TEXT. The design system's own Button component paints both in
 * --color-accent, which its own palette file forbids in the same breath: that
 * token measures 3.27:1 and fails the 4.5:1 floor for text, which is exactly why
 * --color-accent-text exists. The mockups already do it this way; the component
 * is the one that drifted.
 *
 * Hover only, deliberately. Focus already has its own indicator - the ring at
 * the bottom of this file - and the design system describes no focus colour for
 * a button. Borrowing the hover styling for :focus-visible would be a design
 * decision taken in a stylesheet rather than in the design, and on the secondary
 * button it would paint the border in the same accent the ring is already using.
 */
.btn--secondary:hover {
	border-color: var( --color-accent );
	color: var( --text-link );
}

/* ---------------------------------------------------------------------------
 * Icons
 *
 * Material Symbols is loaded as a font and the glyph names are written as text,
 * so `<span class="material-symbols-outlined">water_drop</span>` renders one
 * icon through a ligature. Every decorative glyph needs aria-hidden="true" in
 * the markup, otherwise a screen reader reads the ligature name out loud
 * (qa-a11y.mjs, A15.3).
 *
 * font-variation-settings pins the axes the canon fixes: FILL 0 for the outlined
 * style, GRAD 0, optical size 24. Note that pinning `wght` here means
 * font-weight no longer moves the icon - a component that wants the lighter 300
 * end of the canon's 300-400 range overrides font-variation-settings, not
 * font-weight. Without this the glyph inherits whatever weight its parent has,
 * which is how icons next to an 800 heading come out heavier than the set allows.
 */

.material-symbols-outlined {
	font-family: var( --font-icon );
	font-weight: normal;
	font-style: normal;
	font-size: 24px;
	line-height: 1;
	letter-spacing: normal;
	text-transform: none;
	display: inline-block;

	/*
	 * Every glyph is a 1 em square. Until the font arrives the ligature is drawn
	 * as its word ("schedule", "arrow_forward"), and without a fixed box that word
	 * pushed the text beside it: measured on dev 2026-09-27 (WPS-062) the front
	 * page's hero shifted 0.078 CLS at the moment the icon font landed. The box
	 * keeps the word clipped in the space the glyph will fill.
	 */
	width: 1em;
	overflow: hidden;

	/* overflow: hidden lets a flex parent shrink the box below 1 em; a glyph never gives way. */
	flex-shrink: 0;
	white-space: nowrap;
	word-wrap: normal;
	direction: ltr;
	font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
	-webkit-font-feature-settings: 'liga';
	-webkit-font-smoothing: antialiased;
}

/* ---------------------------------------------------------------------------
 * Focus and skip link
 *
 * WCAG 2.4.7: a keyboard user has to be able to see where they are. The ring is
 * the brand accent, which is exactly what that colour is for - 3.27:1 against
 * white clears the 3:1 a UI component needs, and it is the reason the palette
 * keeps a separate darker blue for text.
 *
 * The design system's rule also sets `border-radius: 6px` on the focused
 * element. That is left out here for two reasons: it would square off a 999 px
 * pill button the moment it takes focus, and 6 px sits outside the shape scale
 * that qa-tokens.mjs enforces (12-16 icon boxes, 20-28 cards, 999 pills). Every
 * browser that supports :focus-visible already draws the outline along the
 * element's own corners, so the declaration buys nothing and costs a visible
 * jump.
 */

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
label:focus-visible,
summary:focus-visible,
[role="button"]:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var( --focus-ring );
	outline-offset: 2px;
}

/*
 * The WordPress screen-reader-text pattern. header.php has carried a skip link
 * since WPS-010, and until this file existed it was hidden only by the block
 * library stylesheet WordPress happens to enqueue - which is to say, by luck.
 * The clip is what tells a measurer this is deliberately invisible rather than a
 * control somebody made too small (qa-measure.mjs, I8.2).
 */

.screen-reader-text {
	position: absolute;
	width: 1px;
	height: 1px;
	margin: -1px;
	padding: 0;
	overflow: hidden;
	clip: rect( 1px, 1px, 1px, 1px );
	clip-path: inset( 50% );
	border: 0;
	word-wrap: normal;
}

/*
 * On focus it becomes a real, reachable control again: a skip link nobody can
 * see is a skip link nobody can use.
 *
 * :focus rather than :focus-visible, which is the WordPress convention and the
 * safer one here. A clipped 1x1 element cannot be clicked, so there is no mouse
 * focus to guard against, and focus moved programmatically by assistive
 * technology does not always satisfy the focus-visible heuristic.
 */
.screen-reader-text:focus {
	position: fixed;
	top: var( --space-4 );
	left: var( --space-4 );
	z-index: 100;
	width: auto;
	height: auto;
	margin: 0;
	padding: var( --space-3 ) var( --space-6 );
	overflow: visible;
	clip: auto;
	clip-path: none;
	background: var( --surface-card );
	border-radius: var( --radius-md );
	box-shadow: var( --shadow-floating );
	color: var( --text-heading );
	font-weight: var( --fw-bold );
	text-decoration: none;
}
