/*--------------------------------------------------------------
wknz-base — main.css

Base theme stylesheet. Generic/CPT-agnostic — no brand values here.
Token VALUES below (colours, scale numbers) are neutral/functional
placeholder defaults for the base theme, matching the same pattern
already used for fonts (system stack until a child theme supplies a
brand font). Child themes override tokens, not structure. Real
overrides at runtime come from the Customizer (theme_mod, registered
in the theme — see docs/theme-architecture.md), output as an
*unlayered* <style> block so they win over the @layer defaults below
without needing !important.

Full decision record: docs/css-checklist.md (testable items) and
docs/css-architecture.md (reasoning). Do not add rules here that
aren't in the checklist without updating it first.

RTL: handled via a companion main-rtl.css + wp_style_add_data('rtl',
'replace') — not inline in this file. Logical properties are used
throughout below specifically so main-rtl.css only has to cover what
logical properties can't (background-image position, icon mirroring).

Fonts: self-hosted, not Google Fonts CDN (see CLAUDE.md project
principle). Open Sans (variable, wght 300-800, verified from the
font's own fvar table) is both --wknz-font-family-heading and
-body (2026-09-24 decision: same font for both). Atkinson
Hyperlegible (a low-vision/dyslexia-friendly accessibility font)
is registered as --wknz-font-family-accessible but not applied
anywhere yet - reserved for the planned font-size/contrast
accessibility widget (see CLAUDE.md dark mode notes). @font-face
declarations are deliberately unlayered (not inside @layer reset/
tokens/etc.) - font loading isn't part of the cascade-priority
concern @layer solves, and leaving @font-face out of any layer
means it can never be accidentally shadowed by a later layer.
--------------------------------------------------------------*/

@font-face {
	font-family: 'Open Sans';
	src: url('../fonts/open-sans/OpenSans-Variable.woff2') format('woff2-variations'),
		url('../fonts/open-sans/OpenSans-Variable.woff2') format('woff2');
	font-weight: 300 800;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: 'Open Sans';
	src: url('../fonts/open-sans/OpenSans-Variable-Italic.woff2') format('woff2-variations'),
		url('../fonts/open-sans/OpenSans-Variable-Italic.woff2') format('woff2');
	font-weight: 300 800;
	font-style: italic;
	font-display: swap;
}

/* Registered but not applied anywhere by default - see file header. */
@font-face {
	font-family: 'Atkinson Hyperlegible';
	src: url('../fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Regular.woff2') format('woff2');
	font-weight: 400;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: 'Atkinson Hyperlegible';
	src: url('../fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Bold.woff2') format('woff2');
	font-weight: 700;
	font-style: normal;
	font-display: swap;
}

@font-face {
	font-family: 'Atkinson Hyperlegible';
	src: url('../fonts/atkinson-hyperlegible/AtkinsonHyperlegible-Italic.woff2') format('woff2');
	font-weight: 400;
	font-style: italic;
	font-display: swap;
}

@font-face {
	font-family: 'Atkinson Hyperlegible';
	src: url('../fonts/atkinson-hyperlegible/AtkinsonHyperlegible-BoldItalic.woff2') format('woff2');
	font-weight: 700;
	font-style: italic;
	font-display: swap;
}

@layer reset, wp-core, tokens, base, components, utilities;

/*--------------------------------------------------------------
# Tokens — --wknz-*
--------------------------------------------------------------*/
@layer tokens {
	:root {
		/* color — semantic (Bootstrap-aligned) */
		--wknz-color-primary: #404040;
		--wknz-color-primary-hover: #262626;
		--wknz-color-primary-active: #171717;
		--wknz-color-secondary: #6b6b6b;
		--wknz-color-secondary-hover: #545454;
		--wknz-color-secondary-active: #3d3d3d;
		--wknz-color-success: #15803d;
		--wknz-color-success-hover: #166534;
		--wknz-color-success-active: #14532d;
		--wknz-color-danger: #b91c1c;
		--wknz-color-danger-hover: #991b1b;
		--wknz-color-danger-active: #7f1d1d;
		--wknz-color-warning: #b45309;
		--wknz-color-warning-hover: #92400e;
		--wknz-color-warning-active: #78350f;
		--wknz-color-info: #0369a1;
		--wknz-color-info-hover: #075985;
		--wknz-color-info-active: #0c4a6e;
		--wknz-color-light: #fafafa; /* deliberately distinct from -surface, was coincidentally identical */
		--wknz-color-dark: #171717; /* Bootstrap-style neutral swatch — NOT the data-theme="dark" toggle, see architecture notes */

		/* color — decorative only, never interactive (no hover/active) */
		--wknz-color-accent: #7c3aed;

		/* color — structural */
		--wknz-color-text: #1a1a1a;
		--wknz-color-text-muted: #6b6b6b;
		--wknz-color-heading: #0d0d0d;
		--wknz-color-background: #ffffff;
		--wknz-color-surface: #f5f5f5;
		/* Dedicated, not a reuse of -disabled-bg (visually similar but a
		   different concept - "disabled" vs "hovered/interactive") or
		   -surface (needs to read as a step darker for the hover state to
		   be visible when combined with striped rows). */
		--wknz-color-surface-hover: #ececec;
		--wknz-color-border: #d4d4d4;
		/* Dedicated, not a reuse of -border: UI component boundaries (form
		   fields, dropdown panels) need >=3:1 against their background per
		   WCAG 1.4.11 — -border alone (~1.5:1 on white) fails that and stays
		   reserved for decorative dividers (hr, table rules) where 1.4.11
		   doesn't apply. #767676 on white ~4.55:1. */
		--wknz-color-border-strong: #767676;
		--wknz-color-link: #1d4ed8;
		--wknz-color-link-hover: #1e40af;
		--wknz-color-link-active: #1e3a8a;
		--wknz-color-link-visited: #6d28d9;
		--wknz-color-focus: #2563eb;
		--wknz-color-disabled: #a3a3a3;
		--wknz-color-disabled-bg: #e5e5e5;

		/* space */
		--wknz-space-3xs: 0.25rem;
		--wknz-space-2xs: 0.5rem;
		--wknz-space-xs: 0.75rem;
		--wknz-space-sm: 1rem;
		--wknz-space-md: 1.5rem;
		--wknz-space-lg: 2rem;
		--wknz-space-xl: 3rem;
		--wknz-space-2xl: 4rem;
		--wknz-space-3xl: 6rem;

		/* font */
		--wknz-font-family-heading: "Open Sans", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
		--wknz-font-family-body: "Open Sans", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
		--wknz-font-family-mono: ui-monospace, "Cascadia Code", "Source Code Pro", Menlo, Consolas, "DejaVu Sans Mono", monospace;
		/* Registered, not applied by default - see file header. */
		--wknz-font-family-accessible: "Atkinson Hyperlegible", -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
		--wknz-font-size-h1: clamp(2.25rem, 1.9rem + 1.75vw, 3rem);
		--wknz-font-size-h2: clamp(1.875rem, 1.6rem + 1.375vw, 2.5rem);
		--wknz-font-size-h3: clamp(1.5rem, 1.3rem + 1vw, 1.875rem);
		--wknz-font-size-h4: clamp(1.25rem, 1.15rem + 0.5vw, 1.5rem);
		--wknz-font-size-h5: clamp(1.125rem, 1.05rem + 0.375vw, 1.25rem);
		--wknz-font-size-h6: clamp(1rem, 0.95rem + 0.25vw, 1.125rem);
		--wknz-font-size-body: 1rem;
		--wknz-font-size-sm: 0.875rem;
		--wknz-font-size-lg: 1.125rem;
		--wknz-font-weight-regular: 400;
		--wknz-font-weight-medium: 500;
		--wknz-font-weight-bold: 700;
		--wknz-line-height-heading: 1.2;
		--wknz-line-height-body: 1.6;
		--wknz-letter-spacing-heading: -0.01em;

		/* radius */
		--wknz-radius-sm: 0.25rem;
		--wknz-radius-md: 0.5rem;
		--wknz-radius-lg: 1rem;
		--wknz-radius-full: 9999px;

		/* shadow */
		--wknz-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
		--wknz-shadow-md: 0 4px 8px rgba(0, 0, 0, 0.08);
		--wknz-shadow-lg: 0 12px 24px rgba(0, 0, 0, 0.12);

		/* z-index */
		--wknz-z-header: 100;
		--wknz-z-dropdown: 200;
		--wknz-z-modal: 300;
		--wknz-z-toggle: 400; /* reserved for the future accessibility widget — mobile menu panel uses -dropdown, not this */
		--wknz-z-skiplink: 100000;

		/* transition */
		--wknz-transition-fast: 150ms;
		--wknz-transition-base: 250ms;
		--wknz-transition-slow: 400ms;
		--wknz-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);

		/* container */
		--wknz-container-max: 80rem; /* 1280px */
		--wknz-container-max-wide: 90rem;
		--wknz-container-gutter: 1.5rem;
		--wknz-content-max: 42.5rem; /* 680px — reading line length for .entry-content, see docs/css-checklist.md */
	}

	/* Dark scheme — OS preference fallback (only when no manual choice made) */
	@media (prefers-color-scheme: dark) {
		:root:not([data-theme="light"]) {
			/* Deliberately distinct from -dark (#171717, a fixed neutral
			   swatch used for component variants regardless of scheme) —
			   was coincidentally identical, a maintenance trap if one gets
			   retuned without the other. */
			--wknz-color-background: #18181b;
			--wknz-color-surface: #262626;
			--wknz-color-surface-hover: #333333;
			--wknz-color-border: #404040;
			--wknz-color-text: #f5f5f5;
			--wknz-color-text-muted: #a3a3a3;
			--wknz-color-heading: #ffffff;
			--wknz-color-link: #60a5fa;
			--wknz-color-link-hover: #93c5fd;
			--wknz-color-link-active: #bfdbfe;
			--wknz-color-link-visited: #c4b5fd;
			--wknz-color-focus: #60a5fa;
			--wknz-color-disabled: #737373;
			--wknz-color-disabled-bg: #404040;
			/* ~3.12:1 on #171717 */
			--wknz-color-border-strong: #666666;
			/* Status colours need their own dark-mode values too — the
			   light-mode values drop below 3:1 against a dark background
			   (e.g. -danger #b91c1c ~2.8:1 on #171717), which matters
			   wherever they're used as borders/text, not just button fills.
			   All four below clear 3:1 with comfortable margin (~6-10:1). */
			--wknz-color-success: #4ade80;
			--wknz-color-success-hover: #22c55e;
			--wknz-color-success-active: #16a34a;
			--wknz-color-danger: #f87171;
			--wknz-color-danger-hover: #ef4444;
			--wknz-color-danger-active: #dc2626;
			--wknz-color-warning: #fbbf24;
			--wknz-color-warning-hover: #f59e0b;
			--wknz-color-warning-active: #d97706;
			--wknz-color-info: #38bdf8;
			--wknz-color-info-hover: #0ea5e9;
			--wknz-color-info-active: #0284c7;
		}
	}

	/* Dark scheme — manual toggle (data-theme="dark" on <html>, set via JS) */
	:root[data-theme="dark"] {
		--wknz-color-background: #18181b;
		--wknz-color-surface: #262626;
		--wknz-color-surface-hover: #333333;
		--wknz-color-border: #404040;
		--wknz-color-text: #f5f5f5;
		--wknz-color-text-muted: #a3a3a3;
		--wknz-color-heading: #ffffff;
		--wknz-color-link: #60a5fa;
		--wknz-color-link-hover: #93c5fd;
		--wknz-color-link-active: #bfdbfe;
		--wknz-color-link-visited: #c4b5fd;
		--wknz-color-focus: #60a5fa;
		--wknz-color-disabled: #737373;
		--wknz-color-disabled-bg: #404040;
		--wknz-color-border-strong: #666666;
		--wknz-color-success: #4ade80;
		--wknz-color-success-hover: #22c55e;
		--wknz-color-success-active: #16a34a;
		--wknz-color-danger: #f87171;
		--wknz-color-danger-hover: #ef4444;
		--wknz-color-danger-active: #dc2626;
		--wknz-color-warning: #fbbf24;
		--wknz-color-warning-hover: #f59e0b;
		--wknz-color-warning-active: #d97706;
		--wknz-color-info: #38bdf8;
		--wknz-color-info-hover: #0ea5e9;
		--wknz-color-info-active: #0284c7;
	}
}

/*--------------------------------------------------------------
# Reset
--------------------------------------------------------------*/
@layer reset {
	*,
	*::before,
	*::after {
		box-sizing: border-box;
	}

	html {
		-webkit-text-size-adjust: 100%;
		/* .alignfull uses width:100vw, which ignores scrollbar width on
		   platforms with visible (non-overlay) scrollbars and can cause
		   horizontal overflow. scrollbar-gutter reserves the space
		   consistently instead - not overflow-x:hidden on body/html, which
		   would disable position:sticky on any descendant in that axis
		   (the sticky header uses position:sticky). */
		scrollbar-gutter: stable;
	}

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

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

	ul[role="list"],
	ol[role="list"] {
		/* list-style removal only ever paired with role="list" in markup —
		   see the Navigation/Comments watch item in docs/css-checklist.md */
		list-style: none;
	}

	@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;
		}
	}
}

/*--------------------------------------------------------------
# WP-core — screen-reader-text, skip link, focus-visible, alignments,
# captions, galleries, pagination, sticky, comment-list base,
# .wp-block-* baseline
--------------------------------------------------------------*/
@layer wp-core {
	/* Accessibility: screen-reader-text (WP-standard pattern) */
	.screen-reader-text {
		border: 0;
		clip: rect(1px, 1px, 1px, 1px);
		clip-path: inset(50%);
		height: 1px;
		margin: -1px;
		overflow: hidden;
		padding: 0;
		position: absolute !important;
		width: 1px;
		word-wrap: normal !important;
	}

	.screen-reader-text:focus {
		background-color: var(--wknz-color-surface);
		border-radius: var(--wknz-radius-sm);
		box-shadow: var(--wknz-shadow-md);
		clip: auto !important;
		clip-path: none;
		color: var(--wknz-color-text);
		display: block;
		font-size: var(--wknz-font-size-sm);
		font-weight: var(--wknz-font-weight-bold);
		height: auto;
		inset-inline-start: var(--wknz-space-3xs);
		inset-block-start: var(--wknz-space-3xs);
		line-height: normal;
		padding: var(--wknz-space-sm) var(--wknz-space-md);
		text-decoration: none;
		width: auto;
		z-index: var(--wknz-z-skiplink);
	}

	/* Accessibility: skip-link target — id="primary" tabindex="-1" on the
	   main-content wrapper, see docs/css-architecture.md.
	   Deliberate, documented exception to "never remove outline without a
	   replacement" (WCAG 2.4.7): #primary is only ever reached
	   programmatically via the skip link, never through normal Tab order
	   (tabindex="-1" removes it from the tab sequence), so there is no
	   keyboard path where this element receives focus without the skip
	   link itself already having shown a visible focus indicator first. */
	#primary[tabindex="-1"]:focus {
		outline: 0;
	}

	/* Accessibility: single centralized focus-visible rule (WCAG 2.4.7 / 1.4.11) */
	:focus-visible {
		outline: max(2px, 0.125em) solid var(--wknz-color-focus);
		outline-offset: max(2px, 0.125em);
	}

	/* Alignments (WP core) */
	.alignleft {
		float: inline-start;
		margin-inline-end: var(--wknz-space-md);
		margin-block-end: var(--wknz-space-sm);
	}

	.alignright {
		float: inline-end;
		margin-inline-start: var(--wknz-space-md);
		margin-block-end: var(--wknz-space-sm);
	}

	.aligncenter {
		display: block;
		margin-inline: auto;
	}

	.alignwide {
		max-width: var(--wknz-container-max-wide);
		margin-inline: auto;
	}

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

	/* Captions / galleries (classic-editor [caption] shortcode output —
	   WYSIWYG fields are client-editable, see docs/css-checklist.md) */
	.wp-caption {
		max-width: 100%;
	}

	.wp-caption-text {
		color: var(--wknz-color-text-muted);
		font-size: var(--wknz-font-size-sm);
		margin-block-start: var(--wknz-space-2xs);
		text-align: center;
	}

	.gallery {
		display: grid;
		gap: var(--wknz-space-sm);
		grid-template-columns: repeat(var(--gallery-columns, 3), 1fr);
		margin-block-end: var(--wknz-space-md);
	}

	.gallery-caption {
		color: var(--wknz-color-text-muted);
		font-size: var(--wknz-font-size-sm);
	}

	.wp-embed-responsive .wp-embed-aspect-16-9 .wp-block-embed__wrapper {
		aspect-ratio: 16 / 9;
	}

	.wp-embed-responsive .wp-embed-aspect-16-9 .wp-block-embed__wrapper iframe {
		width: 100%;
		height: 100%;
	}

	/* Sticky posts — visual treatment TBD, structural hook only for now */
	.sticky {
		/* badge/ribbon treatment: pending values pass, see docs/css-checklist.md */
	}

	/* Post navigation (the_posts_navigation()) */
	.nav-links {
		display: flex;
		justify-content: space-between;
		gap: var(--wknz-space-md);
		margin-block: var(--wknz-space-lg);
	}

	/* Pagination (the_posts_pagination()) */
	.page-numbers {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-width: 1.5rem;
		min-height: 1.5rem;
		padding: var(--wknz-space-3xs) var(--wknz-space-2xs);
		border-radius: var(--wknz-radius-sm);
		color: var(--wknz-color-text);
		text-decoration: none;
	}

	.page-numbers.current {
		background-color: var(--wknz-color-primary);
		color: var(--wknz-color-light);
		font-weight: var(--wknz-font-weight-bold);
	}

	.page-numbers.dots {
		/* ellipsis is not interactive — no hover/focus treatment */
		color: var(--wknz-color-text-muted);
	}

	/* Comments area.
	   comments_template() renders outside any .container wrapper (see
	   single.php/page.php), so the constraint is applied directly to the
	   content element itself — same pattern as .site-header/.site-info.
	   Uses --wknz-container-max (not --wknz-content-max): matches the page
	   container width, not the narrower article reading-width column. */
	.comments-area {
		margin-inline: auto;
		max-width: var(--wknz-container-max);
		padding-inline: var(--wknz-container-gutter);
	}

	/* Comments — nested/threaded list base.
	   TEMPLATE TODO: this bare list-style:none bypasses the role="list"
	   gate set up in Reset (which only protects ul[role="list"]
	   selectors) — add role="list" to the <ol>/<ul> markup for
	   .comment-list in the comments template, or Safari/VoiceOver may
	   stop announcing it as a list. */
	.comment-list,
	.comment-list .children {
		list-style: none;
		margin: 0;
		padding: 0;
	}

	.comment-list .children {
		margin-inline-start: var(--wknz-space-lg);
	}

	/* .wp-block-* baseline — defensive fallback only; widgets are
	   classic/plugin-built per docs/css-checklist.md, this covers any
	   block markup that shows up regardless */
	.wp-block-group,
	.wp-block-columns {
		display: block;
	}
}

/*--------------------------------------------------------------
# Elements / Typography / Links / Tables / Forms (base)
--------------------------------------------------------------*/
@layer base {
	body {
		background-color: var(--wknz-color-background);
		color: var(--wknz-color-text);
		font-family: var(--wknz-font-family-body);
		font-size: var(--wknz-font-size-body);
		font-weight: var(--wknz-font-weight-regular);
		line-height: var(--wknz-line-height-body);
	}

	h1, h2, h3, h4, h5, h6 {
		color: var(--wknz-color-heading);
		font-family: var(--wknz-font-family-heading);
		font-weight: var(--wknz-font-weight-bold);
		line-height: var(--wknz-line-height-heading);
		letter-spacing: var(--wknz-letter-spacing-heading);
		margin-block-end: var(--wknz-space-md);
	}

	h1 { font-size: var(--wknz-font-size-h1); }
	h2 { font-size: var(--wknz-font-size-h2); }
	h3 { font-size: var(--wknz-font-size-h3); }
	h4 { font-size: var(--wknz-font-size-h4); }
	h5 { font-size: var(--wknz-font-size-h5); }
	h6 { font-size: var(--wknz-font-size-h6); }

	p {
		margin-block-end: var(--wknz-space-md);
	}

	ul, ol {
		margin-block-end: var(--wknz-space-md);
		padding-inline-start: var(--wknz-space-lg);
	}

	li > ul,
	li > ol {
		margin-block-end: 0;
	}

	dt {
		font-weight: var(--wknz-font-weight-bold);
	}

	dd {
		margin-inline-start: var(--wknz-space-md);
		margin-block-end: var(--wknz-space-md);
	}

	blockquote {
		border-inline-start: var(--wknz-space-3xs) solid var(--wknz-color-border);
		color: var(--wknz-color-text-muted);
		font-size: var(--wknz-font-size-lg);
		font-style: italic;
		margin-block-end: var(--wknz-space-md);
		margin-inline: 0;
		padding-inline-start: var(--wknz-space-md);
	}

	blockquote p:last-child {
		margin-block-end: 0;
	}

	pre {
		background-color: var(--wknz-color-surface);
		border-radius: var(--wknz-radius-sm);
		font-family: var(--wknz-font-family-mono);
		font-size: var(--wknz-font-size-sm);
		line-height: normal;
		margin-block-end: var(--wknz-space-md);
		max-width: 100%;
		overflow: auto;
		padding: var(--wknz-space-md);
	}

	code, kbd, samp {
		background-color: var(--wknz-color-surface);
		border-radius: var(--wknz-radius-sm);
		font-family: var(--wknz-font-family-mono);
		font-size: 0.9em;
		padding: 0.125em 0.375em;
	}

	pre code {
		background: none;
		padding: 0;
	}

	hr {
		background-color: var(--wknz-color-border);
		border: 0;
		height: 1px;
		margin-block: var(--wknz-space-xl);
	}

	address {
		font-style: normal;
		margin-block-end: var(--wknz-space-md);
	}

	details {
		border: 1px solid var(--wknz-color-border-strong);
		border-radius: var(--wknz-radius-sm);
		margin-block-end: var(--wknz-space-md);
		padding: var(--wknz-space-sm) var(--wknz-space-md);
	}

	summary {
		cursor: pointer;
		font-weight: var(--wknz-font-weight-medium);
	}

	details[open] summary {
		margin-block-end: var(--wknz-space-sm);
	}

	dialog {
		background-color: var(--wknz-color-background);
		border: 1px solid var(--wknz-color-border-strong);
		border-radius: var(--wknz-radius-md);
		box-shadow: var(--wknz-shadow-lg);
		color: var(--wknz-color-text);
		margin: auto;
		max-width: var(--wknz-content-max);
		padding: var(--wknz-space-lg);
	}

	dialog::backdrop {
		background-color: rgba(0, 0, 0, 0.5);
	}

	/* meter has no standardized styling API - only vendor pseudo-elements
	   (::-webkit-meter-*, :-moz-meter-*), no --wknz-* token passthrough
	   possible for the bar/value colors. Baseline sizing only; status
	   colors hardcoded to match --wknz-color-success/-warning/-danger at
	   time of writing since custom properties can't cross into these
	   pseudo-elements. */
	meter {
		block-size: var(--wknz-space-sm);
		display: block;
		inline-size: 100%;
		margin-block-end: var(--wknz-space-md);
	}

	meter::-webkit-meter-bar {
		background: var(--wknz-color-surface);
		border: none;
		border-radius: var(--wknz-radius-full);
	}

	meter::-webkit-meter-optimum-value {
		background: #15803d;
		border-radius: var(--wknz-radius-full);
	}

	meter::-webkit-meter-suboptimum-value {
		background: #b45309;
		border-radius: var(--wknz-radius-full);
	}

	meter::-webkit-meter-even-less-good-value {
		background: #b91c1c;
		border-radius: var(--wknz-radius-full);
	}

	meter:-moz-meter-optimum::-moz-meter-bar {
		background: #15803d;
	}

	meter:-moz-meter-sub-optimum::-moz-meter-bar {
		background: #b45309;
	}

	meter:-moz-meter-sub-sub-optimum::-moz-meter-bar {
		background: #b91c1c;
	}

	b, strong {
		font-weight: var(--wknz-font-weight-bold);
	}

	dfn, cite, em, i {
		font-style: italic;
	}

	small {
		font-size: var(--wknz-font-size-sm);
	}

	mark {
		background-color: var(--wknz-color-accent);
		color: var(--wknz-color-light);
		padding: 0.05em 0.25em;
	}

	sub, sup {
		font-size: 0.75em;
		line-height: 0;
		position: relative;
		vertical-align: baseline;
	}

	sup { inset-block-start: -0.5em; }
	sub { inset-block-end: -0.25em; }

	abbr[title] {
		border-block-end: 1px dotted var(--wknz-color-text-muted);
		cursor: help;
		text-decoration: none;
	}

	figure {
		margin: 0;
	}

	figcaption {
		color: var(--wknz-color-text-muted);
		font-size: var(--wknz-font-size-sm);
		margin-block-start: var(--wknz-space-2xs);
	}

	/* Links */
	a {
		color: var(--wknz-color-link);
	}

	/* Inline prose links: underline required (WCAG 1.4.1). Nav/button/card
	   links opt out via .components layer — see docs/css-checklist.md */
	p a, li a, dd a, blockquote a, figcaption a, .entry-content a {
		text-decoration: underline;
		text-underline-offset: 0.15em;
		text-decoration-thickness: max(1px, 0.08em);
	}

	a:hover {
		color: var(--wknz-color-link-hover);
	}

	a:active {
		color: var(--wknz-color-link-active);
	}

	a:visited {
		color: var(--wknz-color-link-visited);
	}

	/* Content wrapper contains legacy floated .alignleft/.alignright images
	   without a separate clearfix utility class */
	/* Title/meta/image + .entry-content share one reading-width column */
	.article {
		margin-inline: auto;
		max-width: var(--wknz-content-max);
	}

	/* Templates where .comments-area is rendered outside the grid (see
	   single.php, page-templates/page-left-sidebar.php,
	   page-right-sidebar.php): left-align instead of center, so .article
	   lines up with the main content column's left edge, matching
	   .comments-area's left edge below it. Centering left a visible gap,
	   making comments look offset/messy underneath. Not applied to
	   .article generally (page.php/archive teasers stay centered - they
	   don't sit above a misaligned .comments-area the same way). */
	.article--left {
		margin-inline: 0;
	}

	.entry-content {
		display: flow-root;
	}

	/* Tables */
	table {
		border-collapse: collapse;
		margin-block-end: var(--wknz-space-md);
		width: 100%;
	}

	/* Horizontal-scroll wrapper for narrow viewports — wrap <table> in
	   .table-scroll in templates, not a JS card-collapse reflow */
	.table-scroll {
		overflow-x: auto;
	}

	caption {
		caption-side: bottom;
		color: var(--wknz-color-text-muted);
		font-size: var(--wknz-font-size-sm);
		padding-block-start: var(--wknz-space-2xs);
		text-align: start;
	}

	th, td {
		border-block-end: 1px solid var(--wknz-color-border);
		padding: var(--wknz-space-2xs) var(--wknz-space-sm);
		text-align: start;
	}

	th {
		font-weight: var(--wknz-font-weight-bold);
	}

	/* Opt-in only - no striping/hover by default. Author adds
	   data-visual-aid="striped", "hover", or "striped hover" (space-
	   separated, both can combine) directly on the <table>. */
	table[data-visual-aid~="striped"] tbody tr:nth-child(odd) {
		background-color: var(--wknz-color-surface);
	}

	table[data-visual-aid~="hover"] tbody tr:hover {
		background-color: var(--wknz-color-surface-hover);
	}

	/* Forms (base fields — button styling lives in components) */
	label {
		display: inline-block;
		font-weight: var(--wknz-font-weight-medium);
		margin-block-end: var(--wknz-space-3xs);
	}

	/* Persistent, visible "required" text on the label itself - not a
	   placeholder (WCAG 3.3.2 - placeholder content disappears on input,
	   fails "presented to all users"). font-weight: normal so it doesn't
	   compete with the bold label text as the more important element. */
	.required-hint {
		color: var(--wknz-color-text-muted);
		font-weight: var(--wknz-font-weight-regular);
	}

	input, textarea, select {
		background-color: var(--wknz-color-background);
		border: 1px solid var(--wknz-color-border-strong);
		border-radius: var(--wknz-radius-sm);
		color: var(--wknz-color-text);
		font-family: inherit;
		font-size: var(--wknz-font-size-body);
		padding: var(--wknz-space-2xs) var(--wknz-space-sm);
	}

	input[type="checkbox"],
	input[type="radio"] {
		min-width: 1.5rem;
		min-height: 1.5rem;
	}

	input:focus-visible,
	textarea:focus-visible,
	select:focus-visible {
		border-color: var(--wknz-color-focus);
	}

	input:invalid,
	textarea:invalid {
		border-color: var(--wknz-color-danger);
	}

	input:disabled,
	textarea:disabled,
	select:disabled {
		background-color: var(--wknz-color-disabled-bg);
		border-color: var(--wknz-color-disabled);
		color: var(--wknz-color-disabled);
	}

	fieldset {
		border: 1px solid var(--wknz-color-border-strong);
		border-radius: var(--wknz-radius-sm);
		padding: var(--wknz-space-md);
	}

	legend {
		font-weight: var(--wknz-font-weight-bold);
		padding-inline: var(--wknz-space-2xs);
	}
}

/*--------------------------------------------------------------
# Components — Buttons, Navigation, Header, Top Bar, Footer,
# Content Layout, Featured Images, Icons, Widgets, Compatibility (CF7)
--------------------------------------------------------------*/
@layer components {
	/* Buttons — one component, three possible elements underneath.
	   .cta is a deliberate alias of .btn (checklist locks "button,
	   input[...], and the .btn/.cta BEM class render identically") -
	   not a separate visual style. */
	.btn,
	.cta,
	button,
	input[type="submit"],
	input[type="button"],
	input[type="reset"] {
		background-color: var(--wknz-color-primary);
		border: 1px solid transparent;
		border-radius: var(--wknz-radius-sm);
		color: var(--wknz-color-light);
		cursor: pointer;
		display: inline-flex;
		align-items: center;
		justify-content: center;
		font-family: inherit;
		font-size: var(--wknz-font-size-body);
		font-weight: var(--wknz-font-weight-medium);
		/* 1.5rem = 24px at the default root size (WCAG 2.5.8 minimum) but
		   tracks the root-font-size accessibility toggle, unlike a fixed px
		   value would. */
		min-height: 1.5rem;
		padding: var(--wknz-space-2xs) var(--wknz-space-md);
		text-decoration: none;
		transition: background-color var(--wknz-transition-fast) var(--wknz-ease-standard);
	}

	.btn:hover,
	.cta:hover,
	button:hover,
	input[type="submit"]:hover,
	input[type="button"]:hover {
		background-color: var(--wknz-color-primary-hover);
	}

	.btn:active,
	.cta:active,
	button:active,
	input[type="submit"]:active,
	input[type="button"]:active {
		background-color: var(--wknz-color-primary-active);
	}

	.btn:disabled,
	.cta:disabled,
	button:disabled,
	input[type="submit"]:disabled,
	input[type="button"]:disabled {
		background-color: var(--wknz-color-disabled-bg);
		color: var(--wknz-color-disabled);
		cursor: not-allowed;
	}

	.btn--secondary,
	.cta--secondary {
		background-color: var(--wknz-color-secondary);
	}

	.btn--secondary:hover,
	.cta--secondary:hover {
		background-color: var(--wknz-color-secondary-hover);
	}

	.btn--secondary:active,
	.cta--secondary:active {
		background-color: var(--wknz-color-secondary-active);
	}

	/* Navigation.
	   Primary breakpoint: 48em (768px) — below it, mobile toggle/panel;
	   at/above it, the desktop nav. Chosen because a 20rem fixed sidebar
	   plus readable main content stops being comfortable below ~48em.
	   Kept as a single shared value (not per-component) for predictability. */
	.site-navigation {
		display: none;
		position: relative;
	}

	/* display set here (mobile-first default), not on the later
	   .mobile-menu-toggle rule below — that rule coming after this
	   @media block in source order would otherwise win the cascade
	   (equal specificity, later source position) and defeat the
	   desktop override regardless of the media condition. */
	.mobile-menu-toggle {
		display: inline-flex;
	}

	@media (min-width: 48em) {
		.site-navigation {
			display: block;
		}

		.mobile-menu-toggle,
		.mobile-menu-panel {
			display: none;
		}
	}

	/* TEMPLATE TODO: bare list-style:none bypasses the role="list" gate
	   from Reset — add role="list" to this <ul> in the nav-menu walker
	   markup, or Safari/VoiceOver may stop announcing it as a list. */
	.site-navigation ul {
		display: flex;
		list-style: none;
		margin: 0;
		padding: 0;
	}

	.site-navigation a {
		display: inline-flex;
		align-items: center;
		min-height: 1.5rem;
		padding: var(--wknz-space-2xs) var(--wknz-space-sm);
		text-decoration: none;
	}

	.current-menu-item > a {
		font-weight: var(--wknz-font-weight-bold);
	}

	/* Dropdown menus — plain nested list + aria-expanded, never role="menu" */
	.menu-item-has-children {
		position: relative;
	}

	.menu-item-has-children > .sub-menu {
		display: none;
		position: absolute;
		inset-inline-start: 0;
		background-color: var(--wknz-color-background);
		border: 1px solid var(--wknz-color-border-strong);
		box-shadow: var(--wknz-shadow-md);
		min-width: 12rem;
		z-index: var(--wknz-z-dropdown);
	}

	/* Nested (3rd level+) submenus fly out to the side of their parent
	   item instead of dropping below it - the default drop-below/
	   flush-left positioning above, applied to a submenu that's already
	   inside another submenu, landed the flyout on top of its own
	   sibling items in the parent list (confirmed bug, 2026-09-23).
	   .sub-menu .sub-menu (not >) so this also holds at 4+ levels. */
	.sub-menu .sub-menu {
		inset-inline-start: 100%;
		inset-block-start: 0;
	}

	/* Applied by assets/js/dropdown-click.js when a flyout would overflow
	   the right edge of the viewport - opens leftward instead. JS-only
	   enhancement: without it, flyouts just keep the default right-side
	   behavior above (matches pre-fix behavior, never worse). */
	.sub-menu .sub-menu.sub-menu--flip {
		inset-inline-start: auto;
		inset-inline-end: 100%;
	}

	.menu-item-has-children:hover > .sub-menu,
	.menu-item-has-children:focus-within > .sub-menu,
	.menu-item-has-children > [aria-expanded="true"] + .sub-menu {
		display: block;
	}

	/* Mobile menu — partial panel, not a full-screen modal (no focus trap).
	   display is set earlier (with the mobile-first defaults, above) so
	   it can't out-order the desktop media-query override. */
	.mobile-menu-toggle {
		min-width: 1.5rem;
		min-height: 1.5rem;
	}

	/* position:absolute (not static) so the open panel is taken out of
	   .site-header\'s flex flow — otherwise it becomes a third flex item
	   under justify-content:space-between and visibly shifts the toggle
	   button\'s position when opened. .site-header--sticky already
	   establishes the positioning context (position:sticky). */
	.mobile-menu-panel {
		position: absolute;
		inset-inline: 0;
		inset-block-start: 100%;
		background-color: var(--wknz-color-background);
		box-shadow: var(--wknz-shadow-lg);
		z-index: var(--wknz-z-dropdown);
		transition: transform var(--wknz-transition-base) var(--wknz-ease-standard);
	}

	/* Mobile panel's own nav/submenu styling — deliberately not reusing
	   .site-navigation (that class is display:none below 48em, which
	   would hide this too) or .site-navigation's flex-row list (wrong
	   direction for a narrow panel). Submenu reveal itself (:hover/
	   :focus-within/[aria-expanded]) is shared with desktop via
	   .menu-item-has-children/.sub-menu — only positioning differs here:
	   inline/expanding, not an absolutely-positioned flyout. */
	.mobile-menu-panel nav > ul {
		list-style: none;
		margin: 0;
		padding: 0;
	}

	.mobile-menu-panel nav a {
		display: inline-flex;
		align-items: center;
		min-height: 1.5rem;
		padding: var(--wknz-space-2xs) var(--wknz-space-sm);
		text-decoration: none;
	}

	.mobile-menu-panel .sub-menu {
		position: static;
		border: 0;
		box-shadow: none;
		margin-inline-start: var(--wknz-space-md);
		min-width: 0;
	}

	/* Sidebar navigation.
	   TEMPLATE TODO: bare list-style:none bypasses the role="list" gate
	   from Reset — add role="list" to this <ul> in the template markup. */
	.sidebar-navigation ul {
		list-style: none;
		margin: 0;
		padding: 0;
	}

	/* Header.
	   Renders outside any .container wrapper (background can span full
	   width), so the content itself carries the max-width/centering —
	   same pattern used for .top-bar__inner, .footer-widgets and
	   .footer-bottom below. */
	/* position:relative is the mobile panel's positioning context when
	   the sticky option is off (Customizer); --sticky overrides it. */
	.site-header {
		position: relative;
		background-color: var(--wknz-color-background);
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: var(--wknz-space-md);
		max-width: var(--wknz-container-max);
		margin-inline: auto;
		padding-inline: var(--wknz-container-gutter);
		padding-block: var(--wknz-space-sm);
	}

	.site-header--sticky {
		position: sticky;
		inset-block-start: 0;
		z-index: var(--wknz-z-header);
	}

	/* margin-inline-end:auto packs everything after the title (nav,
	   header actions, mobile toggle) against the far edge, instead of
	   space-between spreading three items across the bar. */
	.site-branding__title {
		font-size: var(--wknz-font-size-h4);
		margin: 0;
		margin-inline-end: auto;
	}

	/* Customizer logo - replaces the text title inside the same element. */
	.site-branding__title--logo {
		line-height: 0;
	}

	.custom-logo {
		max-height: 3rem;
		width: auto;
	}

	/* Header actions - 'header-actions' widget area (button, social
	   links). Stays in the header bar at every width (2026-09-27). */
	.header-actions {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--wknz-space-sm);
	}

	/* Header actions + mobile toggle (inc/structure/navigation.php).
	   Below 48em the auto start margin right-aligns the group when the
	   header wraps it onto its own row; at desktop width the title's
	   auto end margin already packs nav + group to the far edge, and an
	   extra auto margin here would split the space and strand the nav
	   mid-bar. */
	.site-header__end {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--wknz-space-sm);
		margin-inline-start: auto;
	}

	@media (min-width: 48em) {
		.site-header__end {
			margin-inline-start: 0;
		}
	}

	/* Top bar — 'top-bar' widget area (contact info, social links), per
	   decision in docs/css-checklist.md. Only rendered when it has widgets. */
	.top-bar {
		background-color: var(--wknz-color-dark);
		color: var(--wknz-color-light);
		font-size: var(--wknz-font-size-sm);
		padding-block: var(--wknz-space-2xs);
	}

	.top-bar a {
		color: inherit;
		text-decoration: none;
	}

	.top-bar__inner {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		gap: var(--wknz-space-md);
		margin-inline: auto;
		max-width: var(--wknz-container-max);
		padding-inline: var(--wknz-container-gutter);
	}

	/* Compact widget areas: widgets sit inline, so no stacked-widget
	   spacing, and no paragraph margins from Text widgets. */
	:is(.top-bar, .header-actions, .footer-bottom) .widget {
		margin-block-end: 0;
	}

	:is(.top-bar, .header-actions, .footer-bottom) .widget p {
		margin-block: 0;
	}

	/* Social links - whichever menu is assigned to the 'social' location,
	   wherever it's placed (inc/structure/navigation.php). 1.5rem minimum
	   target, same WCAG 2.5.8 reasoning as buttons. */
	.social-links {
		display: flex;
		flex-wrap: wrap;
		gap: var(--wknz-space-2xs);
		list-style: none;
		margin: 0;
		padding: 0;
	}

	.social-links a {
		display: inline-flex;
		align-items: center;
		justify-content: center;
		min-width: 1.5rem;
		min-height: 1.5rem;
	}

	/* Icon only - a text fallback link (e.g. mailto:) stays at the
	   surrounding text size. */
	.social-links .icon {
		width: 1.25em;
		height: 1.25em;
	}

	/* Footer */
	.site-footer {
		background-color: var(--wknz-color-surface);
		padding-block: var(--wknz-space-xl);
	}

	/* Footer columns - only active 'footer-N' areas are output, auto-fit
	   sizes the grid to however many there are (1-4), stacking on narrow
	   screens without a breakpoint. */
	.footer-widgets {
		display: grid;
		gap: var(--wknz-space-lg);
		grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr));
		margin-block-end: var(--wknz-space-xl);
		margin-inline: auto;
		max-width: var(--wknz-container-max);
		padding-inline: var(--wknz-container-gutter);
	}

	.footer-widgets__column > .widget:last-child {
		margin-block-end: 0;
	}

	.footer-bottom {
		display: flex;
		flex-wrap: wrap;
		align-items: center;
		justify-content: space-between;
		gap: var(--wknz-space-sm) var(--wknz-space-md);
		color: var(--wknz-color-text-muted);
		font-size: var(--wknz-font-size-sm);
		margin-inline: auto;
		max-width: var(--wknz-container-max);
		padding-inline: var(--wknz-container-gutter);
	}

	.site-info {
		margin: 0;
	}

	.footer-navigation ul {
		display: flex;
		flex-wrap: wrap;
		gap: var(--wknz-space-md);
		list-style: none;
		margin: 0;
		padding: 0;
	}

	/* Content Layout — Grid for page regions, flex row/col for editor
	   content columns (see boundary decision in docs/css-checklist.md) */
	.page-layout {
		display: grid;
		gap: var(--wknz-container-gutter);
		grid-template-columns: 1fr;
	}

	.page-layout--with-sidebar {
		grid-template-columns: minmax(0, 1fr) 20rem;
	}

	.page-layout--with-sidebar-left {
		grid-template-columns: 20rem minmax(0, 1fr);
	}

	.page-layout--with-two-sidebars {
		grid-template-columns: 16rem minmax(0, 1fr) 16rem;
	}

	/* Below 48em, all sidebar-having layouts collapse to a single stacked
	   column. Main content is forced ahead of any <aside> via `order`
	   regardless of which side the sidebar sits on at desktop width, so
	   mobile users always reach content before a sidebar. */
	@media (max-width: 47.9375em) {
		.page-layout--with-sidebar,
		.page-layout--with-sidebar-left,
		.page-layout--with-two-sidebars {
			grid-template-columns: 1fr;
		}

		.page-layout > aside {
			order: 2;
		}
	}

	.row {
		display: flex;
		flex-wrap: wrap;
		gap: var(--wknz-container-gutter);
	}

	.row > * {
		flex: 1 1 0;
	}

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

	/* Featured images */
	.post-thumbnail img {
		aspect-ratio: 16 / 9;
		object-fit: cover;
		width: 100%;
	}

	/* Icons — sized via font-size context (1em), not a token category */
	.icon {
		display: inline-block;
		width: 1em;
		height: 1em;
		vertical-align: -0.125em;
	}

	.icon[aria-hidden="true"] {
		pointer-events: none;
	}

	/* Widgets */
	.widget {
		margin-block-end: var(--wknz-space-lg);
	}

	.widget-title {
		font-size: var(--wknz-font-size-h5);
		margin-block-end: var(--wknz-space-sm);
	}

	/* Compatibility — Contact Form 7 styled here, not left at plugin defaults */
	.wpcf7-form {
		display: grid;
		gap: var(--wknz-space-sm);
	}

	.wpcf7-form-control {
		width: 100%;
	}

	.wpcf7-not-valid {
		border-color: var(--wknz-color-danger) !important;
	}

	.wpcf7-not-valid-tip {
		color: var(--wknz-color-danger);
		font-size: var(--wknz-font-size-sm);
	}

	.wpcf7-response-output {
		border-radius: var(--wknz-radius-sm);
		padding: var(--wknz-space-sm);
	}

	.wpcf7-validation-errors {
		border: 1px solid var(--wknz-color-danger);
	}

	.wpcf7-mail-sent-ok {
		border: 1px solid var(--wknz-color-success);
	}
}

/*--------------------------------------------------------------
# Print
--------------------------------------------------------------*/
@media print {
	.site-navigation,
	.mobile-menu-toggle,
	.top-bar,
	.header-actions,
	.widget,
	.social-links,
	.footer-navigation,
	form,
	.btn,
	button {
		display: none !important;
	}

	a[href]::after {
		content: " (" attr(href) ")";
	}

	* {
		background: transparent !important;
		color: #000 !important;
		box-shadow: none !important;
	}

	h1, h2, h3, h4, h5, h6 {
		break-after: avoid;
	}

	img {
		break-inside: avoid;
	}
}
