/* =========================================================================
   AFFINITY FORMATIONS — BASE
   Reset, token aliases, element defaults, accessibility, layout primitives.

   CASCADE STRATEGY — read before editing
   -------------------------------------
   Only the reset is placed in a cascade layer. Everything else is unlayered.

   WordPress prints theme.json global styles into an *unlayered*
   <style id="global-styles-inline-css"> block. In the CSS cascade, any
   unlayered rule beats every layered rule regardless of layer order. So if
   component styles lived in @layer, theme.json's :where() defaults would
   silently win and components would appear "almost styled".

   Putting only the reset in a layer gives us exactly what we want:
     reset (layered)  <  theme.json (unlayered)  <  our CSS (unlayered, later)
   ========================================================================= */

@layer af-reset {

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

	html {
		-webkit-text-size-adjust: 100%;
		text-size-adjust: 100%;
		-moz-tab-size: 4;
		tab-size: 4;
	}

	body,
	h1, h2, h3, h4, h5, h6,
	p, figure, blockquote, dl, dd,
	ul, ol {
		margin: 0;
	}

	ul[role="list"],
	ol[role="list"] {
		list-style: none;
		padding: 0;
	}

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

	img {
		height: auto;
		font-style: italic; /* styles the alt text if the image fails */
	}

	input,
	button,
	textarea,
	select {
		font: inherit;
		color: inherit;
	}

	button {
		background: none;
		border: 0;
		cursor: pointer;
	}

	p, h1, h2, h3, h4, h5, h6, li {
		overflow-wrap: break-word;
	}

	table {
		border-collapse: collapse;
		width: 100%;
	}

	:target {
		scroll-margin-block: 6rem;
	}
}

/* =========================================================================
   TOKEN ALIASES
   theme.json is the single source of truth. These short aliases exist only
   so component CSS stays readable. Never hard-code a value here — every
   right-hand side must reference a --wp--preset--* or --wp--custom--* var.
   ========================================================================= */

:root {
	/* Colour */
	--af-ink:            var(--wp--preset--color--ink);
	--af-ink-800:        var(--wp--preset--color--ink-800);
	--af-ink-700:        var(--wp--preset--color--ink-700);
	--af-crimson:        var(--wp--preset--color--crimson);
	--af-crimson-deep:   var(--wp--preset--color--crimson-deep);
	--af-gold:           var(--wp--preset--color--gold);
	--af-gold-soft:      var(--wp--preset--color--gold-soft);
	--af-bone:           var(--wp--preset--color--bone);
	--af-surface:        var(--wp--preset--color--surface);
	--af-surface-alt:    var(--wp--preset--color--surface-alt);
	--af-slate:          var(--wp--preset--color--slate);
	--af-line:           var(--wp--preset--color--line);
	--af-on-dark:        var(--wp--preset--color--on-dark);
	--af-on-dark-muted:  var(--wp--preset--color--on-dark-muted);
	--af-success:        var(--wp--preset--color--success);
	--af-warning:        var(--wp--preset--color--warning);
	--af-error:          var(--wp--preset--color--error);
	--af-info:           var(--wp--preset--color--info);

	/* Type */
	--af-font-display:   var(--wp--preset--font-family--display);
	--af-font-body:      var(--wp--preset--font-family--body);
	--af-t-micro:        var(--wp--preset--font-size--micro);
	--af-t-small:        var(--wp--preset--font-size--small);
	--af-t-body:         var(--wp--preset--font-size--body);
	--af-t-lead:         var(--wp--preset--font-size--lead);
	--af-t-h3:           var(--wp--preset--font-size--h3);
	--af-t-h2:           var(--wp--preset--font-size--h2);
	--af-t-h1:           var(--wp--preset--font-size--h1);
	--af-t-display:      var(--wp--preset--font-size--display);

	/* Space */
	--af-s-3xs:  var(--wp--preset--spacing--3xs);
	--af-s-2xs:  var(--wp--preset--spacing--2xs);
	--af-s-xs:   var(--wp--preset--spacing--xs);
	--af-s-sm:   var(--wp--preset--spacing--sm);
	--af-s-md:   var(--wp--preset--spacing--md);
	--af-s-lg:   var(--wp--preset--spacing--lg);
	--af-s-xl:   var(--wp--preset--spacing--xl);
	--af-s-2xl:  var(--wp--preset--spacing--2xl);
	--af-s-3xl:  var(--wp--preset--spacing--3xl);
	--af-s-4xl:  var(--wp--preset--spacing--4xl);
	--af-section: var(--wp--preset--spacing--section);

	/* Shape, depth, motion */
	--af-r-sm:    var(--wp--custom--radius--sm);
	--af-r-md:    var(--wp--custom--radius--md);
	--af-r-lg:    var(--wp--custom--radius--lg);
	--af-r-pill:  var(--wp--custom--radius--pill);

	--af-shadow-1: var(--wp--preset--shadow--1);
	--af-shadow-2: var(--wp--preset--shadow--2);
	--af-shadow-3: var(--wp--preset--shadow--3);
	--af-shadow-4: var(--wp--preset--shadow--4);

	--af-dur-fast: var(--wp--custom--duration--fast);
	--af-dur-base: var(--wp--custom--duration--base);
	--af-dur-slow: var(--wp--custom--duration--slow);
	--af-ease-out:    var(--wp--custom--easing--out);
	--af-ease-in-out: var(--wp--custom--easing--in-out);

	/* Measure & width */
	--af-measure-prose: var(--wp--custom--measure--prose);
	--af-measure-lead:  var(--wp--custom--measure--lead);
	--af-w-narrow:  var(--wp--custom--width--narrow);
	--af-w-content: var(--wp--custom--width--content);
	--af-w-wide:    var(--wp--custom--width--wide);

	/* Controls */
	--af-control-h: var(--wp--custom--control--height);
	--af-btn-h:     var(--wp--custom--control--button-height);
	--af-touch:     var(--wp--custom--control--touch-target);

	/* Header offset, updated by navigation.js when the bar is sticky */
	--af-header-h: 76px;
}

/* =========================================================================
   ELEMENT DEFAULTS
   ========================================================================= */

/*
 * Scrolling is deliberately left at the browser default.
 *
 * `scroll-behavior: smooth` was removed: it makes the page glide on after
 * the user stops scrolling, which reads as the page moving by itself rather
 * than sitting still. Jump-to-anchor is instant and the page stops when the
 * reader stops.
 */
html,
html:focus-within,
body {
	scroll-behavior: auto !important;
	scroll-snap-type: none !important;
}

body {
	background-color: var(--af-bone);
	color: var(--af-ink);
	font-family: var(--af-font-body);
	font-size: var(--af-t-body);
	line-height: 1.65;
	font-synthesis-weight: none;
	text-rendering: optimizeLegibility;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	min-height: 100svh;
}

/*
 * Fraunces ships expressive SOFT and WONK axes. Left at their defaults the
 * face reads quirky; dialled to zero it reads refined. This single
 * declaration is most of the difference between "craft blog" and "premium".
 */
h1, h2, h3, h4, h5, h6,
.af-display,
.has-display-font-family {
	font-variation-settings: var(--wp--custom--font-variation--display);
	text-wrap: balance;
}

h3, h4, h5, h6 {
	/* These use Inter, which has no SOFT/WONK axes. */
	font-variation-settings: normal;
}

p {
	text-wrap: pretty;
}

/* Numerals: tabular in UI, proportional in prose. Prices must align. */
.af-tabular,
.price,
.woocommerce-Price-amount,
time {
	font-variant-numeric: tabular-nums;
}

hr,
.wp-block-separator {
	border: 0;
	border-top: 1px solid var(--af-line);
	margin-block: var(--af-s-xl);
}

::selection {
	background-color: var(--af-gold-soft);
	color: var(--af-ink);
}

/* =========================================================================
   ACCESSIBILITY
   ========================================================================= */

/*
 * Visible focus is non-negotiable (WCAG 2.2 AA, brief §43).
 * :focus-visible keeps it off for mouse users without ever removing it
 * for keyboard users. There is no `outline: none` anywhere in this build.
 */
:focus-visible {
	outline: 3px solid var(--af-info);
	outline-offset: 2px;
	border-radius: 2px;
}

/* Focus ring flips to gold on dark fields, where blue lacks contrast. */
.af-section--dark :focus-visible,
.af-footer :focus-visible {
	outline-color: var(--af-gold);
}

.screen-reader-text,
.af-sr-only {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.af-skip-link {
	position: absolute;
	top: 0;
	left: 50%;
	translate: -50% -120%;
	z-index: 9999;
	padding: var(--af-s-xs) var(--af-s-md);
	background-color: var(--af-ink);
	color: var(--af-on-dark);
	font-size: var(--af-t-small);
	font-weight: 600;
	text-decoration: none;
	border-radius: 0 0 var(--af-r-md) var(--af-r-md);
	transition: translate var(--af-dur-fast) var(--af-ease-out);
}

.af-skip-link:focus {
	translate: -50% 0;
}

/*
 * Honour the OS "reduce motion" setting everywhere. Every animated element
 * in this theme must remain fully usable with animation removed.
 */
@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;
		scroll-behavior: auto !important;
	}
}

/* =========================================================================
   LAYOUT PRIMITIVES
   ========================================================================= */

.af-section {
	padding-block: var(--af-section);
}

.af-section--tight {
	padding-block: var(--af-s-2xl);
}

.af-section--alt {
	background-color: var(--af-surface-alt);
}

.af-section--dark {
	background-color: var(--af-ink);
	color: var(--af-on-dark);
}

.af-section--dark :is(h1, h2, h3, h4, h5, h6) {
	color: var(--af-on-dark);
}

.af-section--dark .af-eyebrow {
	color: var(--af-gold);
}

.af-section--dark p {
	color: var(--af-on-dark-muted);
}

.af-wrap {
	width: min(100% - (var(--af-s-md) * 2), var(--af-w-content));
	margin-inline: auto;
}

.af-wrap--wide {
	width: min(100% - (var(--af-s-md) * 2), var(--af-w-wide));
}

.af-wrap--narrow {
	width: min(100% - (var(--af-s-md) * 2), var(--af-w-narrow));
}

.af-prose {
	max-width: var(--af-measure-prose);
}

.af-lead {
	max-width: var(--af-measure-lead);
	font-size: var(--af-t-lead);
	line-height: 1.55;
	color: var(--af-slate);
}

.af-section--dark .af-lead {
	color: var(--af-on-dark-muted);
}

/* Stack: consistent vertical rhythm without margin collapsing surprises. */
.af-stack {
	display: flex;
	flex-direction: column;
	gap: var(--af-s-md);
}

.af-stack--sm { gap: var(--af-s-sm); }
.af-stack--lg { gap: var(--af-s-lg); }
.af-stack--xl { gap: var(--af-s-xl); }

/*
 * Auto grid. Most layouts in this theme need no media query at all —
 * the column count falls out of the available width.
 */
.af-grid {
	display: grid;
	gap: var(--af-s-lg);
	grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}

.af-grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(420px, 100%), 1fr)); }
.af-grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr)); }

.af-cluster {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: var(--af-s-sm);
}

/*
 * Cancel WordPress's flow-layout margins inside our own layouts.
 *
 * A block group carries both our layout class and WordPress's
 * `is-layout-flow`, which emits
 *     .wp-block-group-is-layout-flow > :not(:first-child) { margin-block-start: 24px }
 * That rule is meant for stacked blocks. Inside a grid or flex container it
 * pushes every child except the first down by 24px, so a row of three cards
 * sits with the first one higher than the other two.
 *
 * Spacing here comes from `gap`, never from child margins. The
 * `.wp-block-group` prefix raises specificity above WordPress's rule without
 * resorting to !important.
 */
.af-grid > *,
.af-grid--2 > *,
.af-grid--4 > *,
.af-steps > *,
.af-cluster > *,
.af-split > *,
.af-stack > *,
.af-stack--sm > *,
.af-stack--lg > *,
.af-stack--xl > *,
.af-trust > *,
.af-header__inner > *,
.af-header__actions > *,
.af-footer__grid > *,
.af-footer__bottom > *,
.af-megapanel__grid > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/*
 * The rule above needs to outrank WordPress's own
 *     .wp-block-group-is-layout-flow > :where(:not(:first-child))
 * which scores one class. Repeating the layout class alongside
 * `.wp-block-group` lifts these to two, without reaching for !important.
 *
 * Every container listed here spaces its children with `gap`. A stray
 * child margin inside a grid does not collapse or centre — it simply pushes
 * that one item out of line, which is how the footer ended up with its first
 * column sitting 24px above the other three.
 */
.wp-block-group.af-grid > *,
.wp-block-group.af-steps > *,
.wp-block-group.af-cluster > *,
.wp-block-group.af-split > *,
.wp-block-group.af-stack > *,
.wp-block-group.af-stack--sm > *,
.wp-block-group.af-stack--lg > *,
.wp-block-group.af-stack--xl > *,
.wp-block-group.af-trust > *,
.wp-block-group.af-header__inner > *,
.wp-block-group.af-header__actions > *,
.wp-block-group.af-footer__grid > *,
.wp-block-group.af-footer__bottom > *,
.wp-block-group.af-megapanel__grid > * {
	margin-block-start: 0;
	margin-block-end: 0;
}

/* Editorial split: image beside text, stacking below the lg breakpoint. */
.af-split {
	display: grid;
	gap: var(--af-s-xl);
	align-items: center;
	grid-template-columns: 1fr;
}

@media (min-width: 1024px) {
	.af-split {
		grid-template-columns: 1fr 1fr;
		gap: var(--af-s-3xl);
	}

	.af-split--reverse > :first-child {
		order: 2;
	}
}

/* =========================================================================
   TYPOGRAPHIC UTILITIES
   ========================================================================= */

.af-eyebrow {
	display: block;
	font-family: var(--af-font-body);
	font-size: var(--af-t-micro);
	font-weight: 600;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var(--af-crimson);
	margin-bottom: var(--af-s-xs);
}

.af-display {
	font-family: var(--af-font-display);
	font-size: var(--af-t-display);
	font-weight: 400;
	line-height: 0.98;
	letter-spacing: -0.02em;
}

.af-muted { color: var(--af-slate); }
.af-center { text-align: center; }

.af-center .af-lead,
.af-center .af-prose {
	margin-inline: auto;
}

/* =========================================================================
   SCROLL REVEAL — DISABLED

   Sections used to fade and lift into place as they entered the viewport.
   Removed at the client's request: the page is meant to sit still, not
   animate itself while being read.

   The `.af-reveal` class is intentionally left on the markup. It now does
   nothing, costs nothing, and means the effect can be restored by putting
   this rule back rather than re-editing a dozen template files.

   The matching script is no longer enqueued — see inc/assets.php.
   ========================================================================= */

.af-reveal {
	opacity: 1;
	translate: none;
}
