/*
Theme Name: Tenant Site Management
Description: A professional theme for tenant subsites in the allotment management multisite platform. Works dynamically with any combination of installed plugin modules.
Version: 1.12.3
Author: Your Company
Text Domain: tenant-saas
*/
/* @quality-factory-reviewed 2026-03-19 19:24:21
 * @quality-factory-tag      QF-PASS-v1.0.0
 * @quality-factory-run      4
 * @quality-factory-agents    accessibility-reviewer, code-fixer, css-visual-reviewer, root-cause-analyst
 * @quality-factory-findings  19 found, 19 fixed */

/* ==========================================================================
	Global Utility Classes
	========================================================================== */

.is-hidden {
	display: none !important;
}

/* ==========================================================================
	CSS Reset and Base Styles
	========================================================================== */

/* Modern CSS Reset */
*,
*::before,
*::after {
	box-sizing: border-box;
	margin: 0;
	padding: 0;
}

/* Remove default list styles for navigation lists only.
	Global list-style:none breaks VoiceOver on Safari which
	removes list semantics when list-style is none. */
nav ul,
nav ol,
.main-navigation ul,
.main-navigation ol,
#footer-menu,
.breadcrumbs {
	list-style: none;
}

/* Remove default button styles */
button {
	background: none;
	border: none;
	cursor: pointer;
	font: inherit;
}

/* Remove default link styles */
a {
	color: inherit;
	text-decoration: none;
}

/* ROOT CAUSE FIX: Remove any pseudo-elements from styled links/buttons
	WordPress block styles and themes sometimes add arrows/decorations via ::before/::after
	This ensures our inline-styled buttons remain clean */
a[style*="background"]::before,
a[style*="background"]::after,
.entry-content a[style*="background"]::before,
.entry-content a[style*="background"]::after {
	display: none !important;
	content: none !important;
}

/* ==========================================================================
	CSS Custom Properties (Variables)
	========================================================================== */

:root {
	/*
	 * Green palette — single source of truth.
	 *
	 * #2e7d32 on #ffffff = 5.13:1 (WCAG AA pass for normal text).
	 * #1b5e20 on #ffffff = 7.87:1 (hover / dark variant).
	 *
	 * --color-primary-green is the canonical token. Module CSS should use it
	 * directly. --primary-color is kept as a backwards-compatible alias so
	 * existing var(--primary-color) references continue to resolve correctly.
	 * Do NOT reintroduce hard-coded green hex values (#28a745, #4caf50,
	 * #5e9732 etc.) — the stylelint colour-no-hex rule blocks them.
	 */
	--color-primary-green: #2e7d32;
	--color-primary-green-dark: #1b5e20;
	/*
	 * Accent tokens — use these whenever a module needs a non-green accent.
	 * Never hard-code a hex for buttons/links/badges. All values AA-tested
	 * against white. Blue #1d4ed8 = 6.70:1, darker blue #1565c0 = 5.75:1,
	 * indigo #4338ca = 7.90:1. The stylelint/pre-commit guard will block
	 * #667eea, #3498db, and the other known-bad shades.
	 */
	--color-accent-blue: #1d4ed8;
	--color-accent-blue-dark: #1565c0;
	--color-accent-indigo: #4338ca;
	--color-overlay-dark: rgb(0 0 0 / 0.25); /* darkens a control on a coloured chip; white on indigo under it is about 10:1 */
	/* On-tint pair: use inside components with a tinted background (pale green,
	   pale red, pale yellow) where the usual primary token fails contrast on
	   the tint. Pattern P3 from UAT handover v4. */
	--color-primary-on-tint: var(--color-primary-green-dark);

	/*
	 * Alert / status families. Each pair is AA-tested for 4.5:1 minimum
	 * (text on bg). Bootstrap-style naming so existing CSS can migrate
	 * one hex at a time. Do not hard-code these shades anywhere in module
	 * CSS — use the tokens. The stylelint gate enforces this.
	 */
	--color-alert-success-bg: #d4edda;
	--color-alert-success-text: #155724;    /* 6.99:1 on #d4edda */
	--color-alert-success-border: #16a34a;  /* decorative, not text */

	--color-alert-warning-bg: #fff3cd;
	--color-alert-warning-text: #664d03;    /* 7.21:1 on #fff3cd (darkened from #856404 for 7.0+) */
	--color-alert-warning-border: #ffc107;

	--color-alert-danger-bg: #f8d7da;
	--color-alert-danger-text: #721c24;     /* 8.25:1 on #f8d7da */
	--color-alert-danger-border: #dc3545;

	--color-alert-info-bg: #d1ecf1;
	--color-alert-info-text: #0c5460;       /* 6.92:1 on #d1ecf1 */
	--color-alert-info-border: #17a2b8;

	/*
	 * Hover companions for the four alert grounds above.
	 *
	 * A status table row needs a base and a hover, and platform-all-pages had
	 * been building both itself out of `rgba(22, 163, 74, 0.08)` / `0.12` — the
	 * theme's green at two opacities, arrived at independently, matching nothing.
	 * One step darker than the base, same hue.
	 */
	--color-alert-success-bg-hover: #c3e6cb;
	--color-alert-warning-bg-hover: #ffeeba;
	--color-alert-danger-bg-hover: #f5c6cb;
	--color-alert-info-bg-hover: #bee5eb;

	/*
	 * Four more semantic grounds, same family and same naming as the four above.
	 *
	 * 39 of the 51 modules define their own badge palette — 505 token
	 * definitions across 54 files — and they nearly all land on the same
	 * Material pastels, because four grounds are not enough for what this
	 * platform actually shows. An incident register needs risk low / medium /
	 * high / critical to stay apart, and a workflow needs reported /
	 * investigating / review / report / hse / closed to stay apart. Collapsing
	 * those onto success-warning-danger-info destroys distinctions that carry
	 * meaning.
	 *
	 * These extend that family rather than starting a `--badge-*` one beside
	 * it: one naming scheme, one place to look. The original four are unchanged,
	 * so nothing already converted moves.
	 *
	 * Text colours are darkened from the values the modules use where those did
	 * not clear 4.5:1 — the cyan pair every module copies is 4.06:1.
	 */
	--color-alert-neutral-bg: #f5f5f5;
	--color-alert-neutral-text: #4b5563;      /* 6.93:1 on the ground above */
	--color-alert-neutral-border: #d1d5db;

	--color-alert-accent-bg: #e0f7fa;
	--color-alert-accent-text: #00636d;       /* 6.27:1; the modules' #00838f is 4.06:1 */
	--color-alert-accent-border: #4dd0e1;

	--color-alert-notable-bg: #e8eaf6;
	--color-alert-notable-text: #303f9f;      /* 7.50:1 */
	--color-alert-notable-border: #7986cb;

	--color-alert-critical-bg: #880e4f;
	--color-alert-critical-text: #ffffff;     /* 9.45:1 — a dark ground, white on it */
	--color-alert-critical-border: #4a148c;

	/*
	 * Crop families.
	 *
	 * This is an allotment platform, so the botanical family of a crop is a
	 * first-class thing it shows, and two modules badge it: the Crop Library and
	 * the Plot Editor. They disagreed. Five of the six families they share were
	 * a different colour in each file — brassicas #e3f2fd against #bbdefb,
	 * cucurbits #e8f5e9 against #c8e6c9 — so a member met one crop's family in
	 * one colour on one page and another colour on the next.
	 *
	 * The Plot Editor's set is the complete one (13 families to the Library's 6)
	 * so it is the one kept. Every ground is light enough to carry
	 * --text-primary at 8.89:1 or better, which is why there is no per-family
	 * text token: one readable text colour on all of them.
	 *
	 * Note for whoever revisits this: soft_fruit and perennial_veg are close
	 * enough to be hard to tell apart side by side, as are flowers and salads.
	 * That is inherited, not introduced, and the badges carry their name as text
	 * so colour is not the only cue (WCAG 1.4.1). Worth a look if the palette is
	 * ever redesigned.
	 */
	--color-crop-family-brassicas: #bbdefb;
	--color-crop-family-legumes: #e1bee7;
	--color-crop-family-alliums: #ffe0b2;
	--color-crop-family-roots: #f8bbd0;
	--color-crop-family-solanaceae: #fff9c4;
	--color-crop-family-cucurbits: #c8e6c9;
	--color-crop-family-herbs: #dcedc8;
	--color-crop-family-fruit-trees: #d7ccc8;
	--color-crop-family-soft-fruit: #f3e5f5;
	--color-crop-family-flowers: #fff3e0;
	--color-crop-family-green-manures: #e0f7fa;
	--color-crop-family-perennial-veg: #e8eaf6;
	--color-crop-family-salads: #f1f8e9;

	/*
	 * Illustration colours.
	 *
	 * The setup wizard draws a little allotment — soil, grass, sun — and those
	 * are pictures, not chrome. Mapping them onto the alert grounds would make
	 * the soil green. They belong to the theme like everything else, but as
	 * their own set, because nothing else on the site should reach for them.
	 */
	--color-illustration-soil: #8b4513;
	--color-illustration-soil-dark: #654321;
	--color-illustration-soil-deep: #4a3728;
	--color-illustration-grass: #228b22;
	--color-illustration-grass-light: #32cd32;
	--color-illustration-sun: #ffd700;
	--color-illustration-sun-deep: #ffa500;

	/* Surface scale. subtle < pale < row-hover, lightest to darkest(-ish). */
	--color-surface-subtle: #f5f5f5;
	--color-surface-subtle-hover: #e8e8e8;
	--color-surface-pale: #f9fafb;
	--color-surface-row-hover: #f0f6fc;

	/*
	 * Document colours. Owned here, not by the module that prints them.
	 *
	 * The rent invoice hardcoded these — 2c3e50 as a hex string and
	 * SetFillColor(209, 236, 241) as raw numbers — so the society could not
	 * change how its own invoice looks without a developer, and a second
	 * document would have copied the values rather than shared them.
	 *
	 * They are not the screen palette and deliberately do not alias it: an
	 * invoice is printed, often in mono, and its header bar has to stay legible
	 * on paper. Kept as their own named pair so a change to the site's greens
	 * cannot silently restyle a financial document.
	 */
	--color-document-header: #2c3e50;
	--color-document-header-text: #ffffff;
	--color-document-panel: #d1ecf1;
	--color-document-panel-alt: #ecf0f1;
	--color-document-muted: #666666;
	--color-document-reference: #e74c3c;
	--color-document-notice-text: #856404;
	--color-document-panel-border: #bee5eb;

	/* Border scale. */
	--color-border-light: #e5e7eb;
	/*
	 * Muted body-text token. 4b5563 meets 4.5:1 on both #ffffff (7.56:1)
	 * and #f3f4f6 (6.87:1). Use for secondary body text only — icons,
	 * borders, and decorative greys should keep their own values.
	 */
	--color-text-muted: #4b5563;

	/* Color Palette (aliases — resolve to the canonical tokens above) */
	--primary-color: var(--color-primary-green);
	--primary-dark: var(--color-primary-green-dark);
	--primary-light: var(--color-primary-green);
	--secondary-color: #2c5530;
	--secondary-dark: #1e3a22;
	--secondary-light: #3a6b3e;
	--accent-color: #f59e0b;
	--accent-dark: #d97706;
	--accent-light: #fbbf24;

	/* Neutral Colors */
	--text-primary: #1f2937;
	/* FIND-A18: #4b5563 on #f5f5f5 = 6.93:1 (AA pass). Previous #6b7280 was 4.43:1 (fail). */
	--text-secondary: var(--color-text-muted);
	--text-muted: var(--color-text-muted);
	--background-primary: #ffffff;
	--background-secondary: #f8f9fa;
	--background-tertiary: #f1f5f9;
	--border-color: #e5e7eb;
	--border-light: #f3f4f6;

	/* Status Colors */
	--success-color: #10b981;
	--success-light: #d1fae5;
	--success-dark: #0d9970;
	/* White-on-this is 5.02:1; --success-dark is only 3.62:1 and is a tint. */
	--success-dark-accessible: #15803d;
	--warning-color: #f59e0b;
	--warning-light: #fef3c7;
	/*
	 * `.btn-warning:hover` has always said `background: var(--warning-dark)`
	 * and nothing has ever defined it, so the whole declaration was void and
	 * the warning button had no hover state at all. Found by
	 * ThemeTokensResolveTest once the modules stopped supplying stray
	 * definitions by accident. --text-primary on it is 4.61:1, over the 4.5:1 line but not by much.
	 */
	--warning-dark: #d97706;
	--error-color: #ef4444;
	--error-dark: #c81e1e;
	/* Hover step for .btn-error, which now sits on --error-dark. */
	--error-darker: #a11616;
	--error-light: #fee2e2;
	--info-color: #3b82f6;
	--info-light: #dbeafe;

	/* Footer colors */
	--footer-heading-color: #fcd34d;
	--footer-link-color: #e5e7eb;
	--footer-copyright-color: #d1d5db;

	/* Demo banner colors */
	--demo-banner-bg: #2d6a4f;
	--demo-banner-link-hover: #d4edda;

	/* PWA banner colors */
	--pwa-text-strong: #2c3e50;
	--pwa-text-muted: #545b62;
	--pwa-icon-border: #adb5bd;
	--pwa-step-color: #495057;

	/* Shared light border gray */
	--border-mid: #d1d5db;
	/*
	 * The edge of a form field: input, select, textarea, .form-control. 6b7280
	 * is 4.83:1 on white, past the 3:1 WCAG 2.2 AA asks of a control's edge
	 * (1.4.11). --border-color (e5e7eb, about 1.2:1) left members with low
	 * vision unable to see where to type, on every form (#6648).
	 */
	--border-field: #6b7280;

	/* Typography */
	--font-family-primary: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
	--font-family-mono: 'SF Mono', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
	--font-size-xs: 0.75rem;
	--font-size-sm: 0.875rem;
	--font-size-base: 1rem;
	--font-size-lg: 1.125rem;
	--font-size-xl: 1.25rem;
	--font-size-2xl: 1.5rem;
	--font-size-3xl: 1.875rem;
	--font-size-4xl: 2.25rem;
	--line-height-tight: 1.25;
	--line-height-normal: 1.5;
	--line-height-relaxed: 1.75;

	/* Spacing */
	--spacing-xs: 0.25rem;
	--spacing-sm: 0.5rem;
	--spacing-md: 1rem;
	--spacing-lg: 1.5rem;
	--spacing-xl: 2rem;
	--spacing-2xl: 3rem;
	--spacing-3xl: 4rem;

	/*
	 * Table cell padding.
	 *
	 * Its own token rather than a step on the spacing scale, because the value
	 * is decided by the row height it produces, not by rhythm. At
	 * --font-size-sm on a 1.5 line box, 0.75rem top and bottom gives a 45px
	 * row: over the 44px touch target the platform's users need (WCAG 2.5.8),
	 * where 0.5rem gives 37px and 0.625rem gives 41px.
	 *
	 * It is also what the tables already wanted. The theme said 1rem and only
	 * 6% of tables used it; 76% had overridden it to somewhere between 0.5rem
	 * and 0.75rem, because these are data tables and 1rem is too loose. 47
	 * different values were in use.
	 */
	--table-cell-padding: 0.75rem;

	/* Border Radius */
	--radius-sm: 0.25rem;
	--radius-md: 0.375rem;
	--radius-lg: 0.5rem;
	--radius-xl: 0.75rem;
	--radius-2xl: 1rem;
	--radius-full: 9999px;

	/* Shadows */
	--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
	--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
	--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
	--shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1);

	/*
	 * Overlays and scrims.
	 *
	 * Black at an opacity, over a photo or behind a modal. Eight files were each
	 * picking their own strength — 0.5, 0.6, 0.7 and 0.9 — for what is one idea.
	 * The three lighter ones are all modal backdrops with no text on them, so
	 * they are one token now; the 0.9 is a media lightbox, where the point IS
	 * that everything else disappears, so it keeps its own.
	 */
	/* The dark ring outside a white focus outline, so focus reads on any ground. */
	--color-focus-halo: #1b1b1b;
	--color-overlay: rgb(0 0 0 / 0.6);
	--color-overlay-soft: rgb(0 0 0 / 0.2);       /* top of a scrim gradient */
	--color-overlay-strong: rgb(0 0 0 / 0.9);     /* media lightbox */

	/* A panel floating over a photograph, where the image should still read. */
	--color-surface-translucent: rgb(255 255 255 / 0.95);
	--color-surface-translucent-soft: rgb(255 255 255 / 0.8);
	--color-surface-translucent-faint: rgb(255 255 255 / 0.15);  /* a hover lift on a dark ground */

	/*
	 * Focus rings (WCAG 2.2 AA, 2.4.7).
	 *
	 * `--focus-ring-color` is referenced by five module stylesheets that the
	 * theme never defined it for, so their focus ring resolved to nothing at
	 * all. Defining it here is the fix for those five as well as the name for
	 * what the theme was already drawing inline.
	 */
	--focus-ring-color: rgb(46 125 50 / 0.1);  /* --color-primary-green at 10% */
	--focus-ring: 0 0 0 3px var(--focus-ring-color);
	--focus-ring-error: 0 0 0 3px rgb(239 68 68 / 0.1);
	--focus-ring-success: 0 0 0 3px rgb(16 185 129 / 0.1);

	/* Text sitting directly on a photograph. */
	--text-shadow-on-image: 0 2px 4px rgb(0 0 0 / 0.3);

	/*
	 * Disabled controls.
	 *
	 * Eight stylesheets disable a control, between them using five different
	 * greys — #ccc, #9ca3af, #5a6268, and two that reach for an alert colour.
	 * A disabled button should read as inert, and read the same way everywhere,
	 * so a member learns it once. Text on this ground is 5.13:1.
	 */
	--color-disabled-bg: #d1d5db;
	--color-disabled-text: #4b5563;

	/* An inner shadow, for a recessed input. Used by eight stylesheets. */
	--shadow-inset: inset 0 1px 2px rgb(0 0 0 / 0.075);

	/*
	 * A dark neutral ground — a tooltip, or a table's section header row.
	 * White on it is 17.9:1. Only three stylesheets want one, but the
	 * alternative they reached for was `background: var(--text-primary)`,
	 * a text token used as a surface, which reads as a mistake to whoever
	 * finds it next.
	 */
	--color-surface-inverse: #1f2937;

	/* Transitions */
	--transition-fast: 150ms ease-in-out;
	--transition-normal: 250ms ease-in-out;
	--transition-slow: 350ms ease-in-out;

	/* Z-Index Scale */
	--z-dropdown: 1000;
	--z-sticky: 1020;
	/*
	 * Event category colours.
	 *
	 * The `category` column is a fixed enum (events/module.json schema), so the
	 * seven colours are tokens, not arbitrary values. Single source of truth for
	 * both the CSS and Event_Model::get_category_colours().
	 *
	 * These were hardcoded hex values in an inline style= attribute emitted from
	 * PHP (C3-001). Moving them out of the markup meant they had to become tokens
	 * — stylelint (correctly) refuses raw hex in a colour property.
	 */
	--color-event-working-party: #2e7d32;
	--color-event-social: #1565c0;
	--color-event-committee-meeting: #616161;
	--color-event-open-day: #e65100;
	--color-event-maintenance: #f9a825;
	--color-event-seed-swap: #6a1b9a;
	--color-event-other: #455a64;

	/* Layering */
	--z-fixed: 1030;
	--z-modal-backdrop: 1040;
	--z-modal: 1050;
	--z-popover: 1060;
	--z-tooltip: 1070;
	--z-toast: 1080;
}

/* ==========================================================================
	Accessibility and Focus Management
	========================================================================== */

/*
 * The global focus indicator (WCAG 2.2 AA, 2.4.7 and 1.4.11) — #592, #297.
 *
 * The tenant theme styled focus for eleven named components — .btn,
 * .modal-close, .social-link and so on — and for nothing else. A plain link,
 * input, select or textarea got whatever the browser drew. So 137 module
 * stylesheets each wrote this rule for themselves, between them naming about
 * sixty different tokens for the colour (--color-focus, --rent-focus-outline,
 * --pp-color-focus-ring, --bank-tx-focus-outline ...) at two widths. 36 of them
 * simply used WordPress admin blue, #0073aa, which appears nowhere else here.
 *
 * That is not a formatting inconsistency. Focus is how a keyboard user knows
 * where they are, and it was arriving in a different colour on every page.
 *
 * The treatment is not a new one. It is what this theme already draws for
 * `.btn:focus-visible`, and what platform-theme has applied universally since
 * #592/#297 — a white outline inside a dark halo, which clears 3:1 on light,
 * dark AND the brand green. Green-on-green measured 1.67:1, which is why
 * `2px solid var(--primary-color)` is NOT what goes here, however many of the
 * component rules below still use it.
 *
 * Module copies of this rule are deleted as each module is converted (#2639).
 */
:focus-visible {
	outline: 3px solid #ffffff;
	outline-offset: 2px;
	box-shadow: 0 0 0 5px var(--color-focus-halo);
}

/* Fallback for browsers without :focus-visible — keep a visible ring. */
*:focus {
	outline: 3px solid var(--primary-color);
	outline-offset: 2px;
}

*:focus:not(:focus-visible) {
	outline: none;
	box-shadow: none;
}

/*
 * Eleven component `:focus-visible` overrides stood here (.modal-close,
 * .notification-close, .social-link, .action-card, .back-to-feed, .btn-text,
 * th[data-sort], the three .pwa-banner-* buttons, .error-404-btn, .offline-btn,
 * .sitemap-links a, .terms-btn). Each redrew the ring in the green or accent
 * the block above says must not be used, and each won on specificity — so the
 * one component set most likely to sit ON the green (a card, a modal close, a
 * banner button) was the one set getting the 1.67:1 ring. They are deleted, not
 * recoloured: the global rule is the only focus indicator this theme draws.
 */

/* Skip to main content link */
.skip-link {
	position: absolute;
	top: -40px;
	left: 6px;
	background: var(--primary-color);
	color: white;
	padding: 8px;
	text-decoration: none;
	border-radius: var(--radius-md);
	z-index: var(--z-toast);
	transition: top var(--transition-normal);
}

.skip-link:focus {
	top: 6px;
}

/* Screen reader only text */
.sr-only {
	position: absolute;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect(0, 0, 0, 0);
	white-space: nowrap;
	border: 0;
}

/* High contrast mode support */
@media (prefers-contrast: high) {
	:root {
		--border-color: #000000;
		--border-field: #000000;
		--text-secondary: #000000;
	}
}

/* Reduced motion support */
@media (prefers-reduced-motion: reduce) {
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
	}

	html {
		scroll-behavior: auto;
	}
}

/* ==========================================================================
	Base Typography and Layout
	========================================================================== */

html {
	font-size: 16px;
	scroll-behavior: smooth;
	/*
	 * #494 (WCAG 2.4.11 Focus Not Obscured): the site header (#masthead) is
	 * position:sticky, so an element focused near the top of the viewport is
	 * covered by it. scroll-padding-top keeps focused/anchored targets clear of
	 * the sticky header (value ≥ masthead height, ~5rem/80px).
	 */
	scroll-padding-top: 5rem;
	/*
	 * Same problem, the other edge: #pwa-install-banner is fixed at the
	 * bottom while visible. body.pwa-banner-open's padding-bottom keeps a
	 * SCROLLED-to target clear of it, but scroll-padding only affects the
	 * browser's own focus-scroll behaviour when it is on the scrolling
	 * element itself — a Tab landing on the last control on a page could
	 * still be scrolled to just inside the raw viewport edge, under the
	 * banner, while this stayed unset (WCAG 2.4.11, found reviewing
	 * BUG-2609-0098). pwa-register.js sets --pwa-banner-height on this
	 * element as well as on body.
	 */
	scroll-padding-bottom: var( --pwa-banner-height, 0px );
}

body {
	font-family: var(--font-family-primary);
	font-size: var(--font-size-base);
	line-height: var(--line-height-normal);
	color: var(--text-primary);
	background: var(--background-secondary);
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	text-rendering: optimizeLegibility;
	transition: padding-bottom var(--transition-normal);
}

/*
 * #pwa-install-banner is position:fixed at the bottom of the viewport,
 * z-index 9999, with nothing reserving space for it — so it sits on top
 * of whatever control happens to be at the bottom of the page underneath
 * it. On My Profile that was the Delete Profile button, reported as
 * hidden "behind stuff" on mobile (BUG-2609-0098). pwa-register.js sets
 * --pwa-banner-height to the banner's real rendered height (the iOS
 * instructions banner and the Android install banner differ) and toggles
 * this class while the banner is visible.
 */
body.pwa-banner-open {
	padding-bottom: var(--pwa-banner-height, 0px);
}

/* Typography scale */
h1, h2, h3, h4, h5, h6 {
	font-weight: 600;
	line-height: var(--line-height-tight);
	margin-bottom: var(--spacing-md);
	color: var(--text-primary);
}

h1 { font-size: var(--font-size-4xl); }
h2 { font-size: var(--font-size-3xl); }
h3 { font-size: var(--font-size-2xl); }
h4 { font-size: var(--font-size-xl); }
h5 { font-size: var(--font-size-lg); }
h6 { font-size: var(--font-size-base); }

p {
	margin-bottom: var(--spacing-md);
	line-height: var(--line-height-relaxed);
}

/* ==========================================================================
	Header Styles
	========================================================================== */

.site-header {
	background: var(--background-primary);
	box-shadow: var(--shadow-sm);
	position: sticky;
	top: 0;
	z-index: var(--z-sticky);
	border-bottom: 1px solid var(--border-color);
}

.header-content {
	max-width: 1400px;
	margin: 0 auto;
	padding: var(--spacing-sm) var(--spacing-xl);
	display: flex;
	justify-content: space-between;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--spacing-md);
}

.site-branding {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: var(--spacing-xs);
}

.site-logo {
	font-size: var(--font-size-2xl);
	font-weight: 700;
	color: var(--primary-color);
	text-decoration: none;
	transition: color var(--transition-normal);
}

.site-logo:hover,
.site-logo:focus {
	color: var(--primary-dark);
}

.site-description {
	font-size: var(--font-size-sm);
	color: var(--text-secondary);
	margin: 0;
}

.header-right {
	display: flex;
	align-items: center;
	gap: var(--spacing-lg);
	flex-wrap: wrap;
}

/* ==========================================================================
	User Status and Site Switcher
	========================================================================== */

.user-status {
	display: flex;
	align-items: center;
	gap: var(--spacing-sm);
	font-size: var(--font-size-sm);
	background: var(--background-secondary);
	padding: var(--spacing-sm) var(--spacing-md);
	border-radius: var(--radius-lg);
	border: 1px solid var(--border-color);
	transition: all var(--transition-normal);
}

.user-status:hover {
	background: var(--background-tertiary);
	border-color: var(--primary-color);
}

.user-name {
	font-weight: 500;
	color: var(--primary-dark);
}

.user-role {
	color: var(--text-secondary);
	font-size: var(--font-size-xs);
	background: var(--background-primary);
	padding: 2px var(--spacing-xs);
	border-radius: var(--radius-sm);
}

.logout-link,
.login-link {
	color: var(--secondary-color);
	text-decoration: none;
	font-weight: 500;
	padding: var(--spacing-xs) var(--spacing-sm);
	border-radius: var(--radius-sm);
	transition: all var(--transition-normal);
}

.logout-link:hover,
.login-link:hover,
.logout-link:focus,
.login-link:focus {
	background: var(--secondary-color);
	color: white;
	text-decoration: none;
}

.site-switcher {
	position: relative;
}

.site-switcher select {
	padding: var(--spacing-sm) var(--spacing-md);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-md);
	background: var(--background-primary);
	font-size: var(--font-size-sm);
	cursor: pointer;
	transition: all var(--transition-normal);
	min-width: 150px;
}

.site-switcher select:focus {
	border-color: var(--primary-color);
}

/* ==========================================================================
	Navigation Styles
	========================================================================== */

.main-navigation {
	display: flex;
	align-items: center;
}

.main-navigation ul {
	list-style: none;
	display: flex;
	gap: var(--spacing-lg);
	margin: 0;
	padding: 0;
}

.main-navigation li {
	position: relative;
}

.main-navigation a {
	text-decoration: none;
	color: var(--text-primary);
	font-weight: 500;
	padding: var(--spacing-sm) var(--spacing-md);
	border-radius: var(--radius-md);
	transition: all var(--transition-normal);
	font-size: var(--font-size-sm);
	display: block;
}

.main-navigation a:hover,
.main-navigation a:focus {
	background: var(--primary-color);
	color: white;
	transform: translateY(-1px);
}

/*
 * Which page you are on (#2542).
 *
 * WordPress already marks the current item — `aria-current="page"` is in the
 * delivered HTML and exactly one item carries it per page — so a screen reader
 * has always been told. Nothing was ever drawn for it, which left every member
 * who navigates by looking with no location cue at all (WCAG 2.2 AA 2.4.8).
 *
 * The cue is an underline and weight, not a fill, because hover and focus above
 * already own the fill: three states that all filled the item would be three
 * states nobody could tell apart. It is also not colour alone (1.4.1) — the
 * weight changes too.
 *
 * --color-primary-green on the page ground is 5.13:1, clearing the 3:1 that
 * 1.4.11 asks of a non-text indicator. The second rule repaints the underline
 * white when the current item is hovered or focused, because at that moment the
 * item's background has become that same green and a green marker on green is
 * no marker.
 *
 * A pseudo-element rather than border-bottom: a border would add 3px to the
 * item's height and shift the whole bar the moment a page became current.
 *
 * It was an inset box-shadow until #2777. `box-shadow` is one property, not a
 * list you add to, so at 0,2,0 this rule was also replacing the global focus
 * halo — the current item was the one item in the bar that could not draw the
 * theme's ring. An `::after` occupies no property the focus indicator needs.
 */
.main-navigation .current-menu-item > a,
.main-navigation .current_page_item > a,
.main-navigation .current-menu-ancestor > a,
.main-navigation [aria-current="page"] {
	font-weight: 700;
	position: relative;
}

.main-navigation .current-menu-item > a::after,
.main-navigation .current_page_item > a::after,
.main-navigation .current-menu-ancestor > a::after,
.main-navigation [aria-current="page"]::after {
	content: "";
	position: absolute;
	inset: auto 0 0 0;
	height: 3px;
	background: var(--color-primary-green);
	pointer-events: none;
}

.main-navigation .current-menu-item > a:hover::after,
.main-navigation .current-menu-item > a:focus::after,
.main-navigation .current_page_item > a:hover::after,
.main-navigation .current_page_item > a:focus::after,
.main-navigation .current-menu-ancestor > a:hover::after,
.main-navigation .current-menu-ancestor > a:focus::after,
.main-navigation [aria-current="page"]:hover::after,
.main-navigation [aria-current="page"]:focus::after {
	background: var(--background-primary);
}

/* Dropdown Styles */
.main-navigation ul ul {
	display: none;
	position: absolute;
	top: 100%;
	left: 0;
	background: var(--background-primary);
	box-shadow: var(--shadow-lg);
	border-radius: var(--radius-lg);
	min-width: 200px;
	flex-direction: column;
	gap: 0;
	border: 1px solid var(--border-color);
	z-index: var(--z-dropdown);
}

.main-navigation ul li:hover > ul,
.main-navigation ul li:focus-within > ul {
	display: flex;
}

.main-navigation ul ul a {
	padding: var(--spacing-md);
	border-radius: 0;
	border-bottom: 1px solid var(--border-light);
}

.main-navigation ul ul a:last-child {
	border-bottom: none;
}

.main-navigation ul ul a:hover,
.main-navigation ul ul a:focus {
	background: var(--background-secondary);
	color: var(--primary-color);
	transform: none;
}

/* ==========================================================================
	Breadcrumbs
	========================================================================== */

.breadcrumbs {
	background: var(--background-primary);
	padding: var(--spacing-sm) var(--spacing-lg);
	border-radius: var(--radius-lg);
	margin-bottom: var(--spacing-md);
	font-size: var(--font-size-sm);
	border: 1px solid var(--border-color);
}

.breadcrumbs a {
	color: var(--primary-color);
	text-decoration: underline;
	transition: color var(--transition-normal);
}

.breadcrumbs a:hover,
.breadcrumbs a:focus {
	color: var(--primary-dark);
	text-decoration: underline;
}

.breadcrumbs span {
	color: var(--text-secondary);
	font-weight: 500;
}

/* ==========================================================================
	Container and Layout
	========================================================================== */

.container {
	max-width: 1400px;
	margin: 0 auto;
	padding: var(--spacing-lg) var(--spacing-xl);
}

main {
	min-height: 70vh;
	background: var(--background-primary);
	margin: var(--spacing-md) auto;
	max-width: 1400px;
	border-radius: var(--radius-2xl);
	box-shadow: var(--shadow-lg);
	overflow: hidden;
	border: 1px solid var(--border-color);
}

/* ==========================================================================
	Content Styles
	========================================================================== */

.entry-content {
	padding: 0;
}

.entry-title {
	color: var(--primary-color);
	margin-bottom: var(--spacing-lg);
	font-size: var(--font-size-3xl);
}

/* ==========================================================================
	Button Styles
	========================================================================== */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: var(--spacing-sm);
	padding: var(--spacing-sm) var(--spacing-lg);
	background: var(--primary-color);
	color: white;
	text-decoration: none;
	border-radius: var(--radius-md);
	border: none;
	cursor: pointer;
	font-size: var(--font-size-base);
	font-weight: 500;
	transition: all var(--transition-normal);
	line-height: 1;
	min-height: 44px; /* Accessibility: minimum touch target size */
	min-width: 44px; /* Accessibility: 2.5.8 target size, for icon-only buttons */
}

.btn:hover,
.btn:focus {
	background: var(--primary-dark);
	color: white;
	transform: translateY(-1px);
}

/*
 * The lift shadow is for the mouse only. On keyboard focus it would replace
 * the global :focus-visible halo, leaving a thin white outline (#4758).
 */
.btn:hover:not(:focus-visible) {
	box-shadow: var(--shadow-md);
}

.btn:active {
	transform: translateY(0);
}

/*
 * Disabled reads as a button that is unavailable, not as a smudge.
 *
 * This was `opacity: 0.6`, which over white composites the brand green to
 * #82b184 and leaves the white label at 2.45:1 — legible to nobody who needs
 * to know what the unavailable control would have done. WCAG 1.4.3 exempts
 * inactive controls so it broke no rule, but the members here are elderly
 * volunteers and "I can't read what that greyed-out button says" is a support
 * call.
 *
 * --text-secondary carries the white label at 7.56:1. plot-list had already
 * worked this out and fixed it for its own Assign button; this is that fix,
 * for every button.
 *
 * At 0,2,0 this outranks the role variants, so a disabled button is grey
 * whatever it does — which is right: disabled has no role.
 */
.btn:disabled,
.btn[aria-disabled="true"] {
	background: var(--text-secondary);
	color: var(--background-primary);
	cursor: not-allowed;
	transform: none;
}

/*
 * A toggle button that is switched on (aria-pressed="true"), such as the job
 * board's List view: bold, underlined label, so "on" shows without relying
 * on colour (WCAG 1.4.1, #5711). Not a box-shadow: that would replace the
 * focus halo.
 */
.btn[aria-pressed="true"] {
	font-weight: 700;
	text-decoration: underline;
	text-decoration-thickness: 3px;
	text-underline-offset: 0.3em;
}

/*
 * The shared photo step's status line (mu-plugins/media _upload.js): placed
 * before a form's Submit button while a photo is prepared, read out by screen
 * readers. Hidden when empty, so it takes no space in the button row.
 */
.allotment-upload-status {
	margin: 0.5rem 0;
	font-size: 1rem;
	color: var(--text-primary);
}

.allotment-upload-status:empty {
	display: none;
}

/*
 * Why a chosen photo cannot be used, beside its field (_upload.js problem()).
 * Never display:none, which would hide it from screen readers; takes no space
 * while empty.
 */
.allotment-upload-problem {
	margin: 0.25rem 0 0;
	font-size: 1rem;
	font-weight: 600;
	color: var(--error-dark);
}

.allotment-upload-problem:empty {
	margin: 0;
}

/*
 * Low-emphasis button: a light surface with dark text, so it reads as the quiet
 * alternative beside a green primary rather than competing with it. It was solid
 * slate with white text, which gave a card with an Edit button two heavy controls
 * and no visual hierarchy between them.
 *
 * `.btn` sets `color: white` and `border: none`, and `.btn:hover` sets white
 * again — so both are re-stated here. Dropping either leaves white text on a
 * light grey button, invisible, on hover only.
 *
 * #1f2937 on #f5f5f5 is 13.4:1, well past WCAG 2.2 AA. That matters: this is the
 * Edit control on every card of My Profile, read by the members this platform is
 * built for.
 */
.btn-secondary {
	background: var(--color-surface-subtle);
	color: var(--text-primary);
	border: 1px solid var(--border-mid);
}

.btn-secondary:hover,
.btn-secondary:focus {
	background: var(--color-surface-subtle-hover);
	color: var(--text-primary);
}

/*
 * Grid page controls (Tabulator). The shared helper (estate-management
 * _tabulator-a11y.js) renders them just below each grid, not inside it, so
 * screen readers read the grid as a grid (PIPE-014/015/018/019). The theme owns
 * their look, the same on every grid: each page control is given the theme's
 * own .btn (R16) — green, 44px, the standard hover and disabled look — and the
 * current page is also darker, bold and underlined, so colour is not the only
 * sign of it.
 */
.tabulator-pagination {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: flex-end;
	gap: var(--spacing-sm);
	padding: var(--spacing-sm) 0;
}

.tabulator-pagination .tabulator-pages {
	display: inline-flex;
	flex-wrap: wrap;
	gap: var(--spacing-sm);
}

.tabulator-pagination .tabulator-page.active {
	background: var(--primary-dark);
	font-weight: 700;
	text-decoration: underline;
}

/*
 * The grid's scroll box stays in the tab order (it is the grid's row group),
 * and the grid library's stylesheet removes its focus outline. The ring is
 * drawn inside the box (it clips anything outside) and in the dark halo colour,
 * as an outline: an inset shadow would be painted under the rows and hidden.
 */
.tabulator .tabulator-tableholder:focus-visible {
	outline: 3px solid var(--color-focus-halo);
	outline-offset: -3px;
}

.tabulator-pagination select {
	min-height: 44px;
	font-size: var(--font-size-base);
}

/*
 * `--success-color` (#10b981) and `--warning-color` (#f59e0b) are tints. White
 * text on them is 2.54:1 and 2.15:1, against the 4.5:1 WCAG 2.2 AA requires —
 * and `.btn` sets `color: white`, so every button using them inherited a label
 * that could not be read.
 *
 * Success takes a green dark enough to carry white. Warning keeps its amber,
 * which no member would recognise in any other colour, and takes dark text
 * instead: `--text-primary` on `--warning-color` is 6.83:1.
 */
.btn-success {
	background: var(--success-dark-accessible);
}

.btn-success:hover,
.btn-success:focus {
	background: var(--success-dark);
}

.btn-warning {
	background: var(--warning-color);
	color: var(--text-primary);
}

.btn-warning:hover,
.btn-warning:focus {
	background: var(--warning-dark);
}

/*
 * `--error-color` (#ef4444) is the right red for a border or an icon, but white
 * text on it is 3.76:1 — under the 4.5:1 WCAG 2.2 AA asks for text this size, so
 * it was never a safe button background. `--error-dark` is 5.74:1.
 *
 * This is the destructive control: "Delete my record", "Delete Profile". It has
 * to be legible to the members least able to recover from clicking it by mistake.
 */
.btn-error {
	background: var(--error-dark);
}

.btn-error:hover,
.btn-error:focus {
	background: var(--error-darker);
}

.btn-small {
	padding: var(--spacing-xs) var(--spacing-md);
	font-size: var(--font-size-sm);
	min-height: 44px; /* The project's minimum touch target, as .btn: small changes the text, not the target. */
}

.btn-large {
	padding: var(--spacing-md) var(--spacing-xl);
	font-size: var(--font-size-lg);
	min-height: 52px;
}

/* Loading state */
/* The label stays visible and the spinner sits beside it. Hiding the label
   with color: transparent also hid the spinner (it draws in currentColor),
   and with reduced motion on a spinner alone says nothing: members saw a
   blank button (#5717). Only on a .btn: some forms use .btn-loading for a
   hidden "Sending..." span inside their button. */
.btn.btn-loading {
	cursor: progress;
}

.btn.btn-loading::after {
	content: '';
	flex: none;
	width: 1em;
	height: 1em;
	border: 2px solid transparent;
	border-top-color: currentColor;
	border-radius: 50%;
	animation: spin 1s linear infinite;
}

/* ==========================================================================
	Buttons on a coloured band
	==========================================================================

	A button on a coloured ground, where the default green .btn disappears.
	Mirrored from platform-theme, which needed all three for the marketing
	pages; on this side the marketplace's "Select" button is an .btn-outline
	and had been carrying its own indigo copy.

	Three designs. Fifteen implementations, under nine names, across this file
	and two module stylesheets: .btn-hero, .btn-cta, .btn-pricing-card,
	.cta-buttons .btn-primary, .story-cta .btn-primary, .tech-cta .btn-primary
	(which reached for --secondary-color where its two siblings used
	--primary-color), .hero-cta .btn:not(.btn-primary), .features-cta .btn, and
	.contact-cta .btn-secondary.

	Here they are once. Contrast is measured against #2e7d32, the green those
	bands are built from:

	  .btn-inverse          green label on white          5.13:1
	  .btn-outline          green label and rule on white 5.13:1 (1.4.11 wants 3:1 of the rule)
	  .btn-outline-inverse  white label and rule on green 5.13:1

	Each overrides colour as well as background, because .btn and .btn:hover
	set `color: white` and would otherwise leave a white label on white.
	========================================================================== */

.btn-inverse {
	background: var(--background-primary);
	color: var(--color-primary-green);
}

/* Resting shadow, but not over the keyboard focus halo (#4758). */
.btn-inverse:not(:focus-visible) {
	box-shadow: var(--shadow-md);
}

.btn-inverse:hover,
.btn-inverse:focus {
	background: var(--color-surface-subtle);
	color: var(--color-primary-green);
}

.btn-outline {
	background: transparent;
	color: var(--color-primary-green);
	border: 2px solid var(--color-primary-green);
}

.btn-outline:hover,
.btn-outline:focus {
	background: var(--color-primary-green);
	color: var(--background-primary);
}

.btn-outline-inverse {
	/* No fill: the faint white wash lifted the green behind the label to
	   #4d9151, 3.82:1 with white — below 4.5:1 (PIPE-033/034). Transparent
	   keeps the 5.13:1 measured above. */
	background: transparent;
	color: var(--background-primary);
	border: 2px solid var(--background-primary);
}

.btn-outline-inverse:hover,
.btn-outline-inverse:focus {
	background: var(--background-primary);
	color: var(--color-primary-green);
}

/*
 * The gradient button.
 *
 * The contact form and the login form each grew one, and they were not the
 * same gradient: contact ran --secondary-color -> --secondary-light, login ran
 * --secondary-light -> --color-primary-green. One idea, two answers, on the
 * two most prominent public forms on the platform.
 *
 * This is the one, spanning the brand's darkest green to its primary at the
 * 135deg the rest of the site uses. White clears 4.5:1 against both ends:
 *
 *   --secondary-color      #2c5530   8.57:1
 *   --color-primary-green  #2e7d32   5.13:1
 *
 * Hover darkens rather than lifting only. Neither original changed colour on
 * hover at all -- both restated their own gradient -- so the pointer told you
 * nothing beyond the 1px lift .btn already gives.
 */
.btn-gradient {
	background: linear-gradient(135deg, var(--secondary-color) 0%, var(--color-primary-green) 100%);
	color: var(--background-primary);
}

.btn-gradient:hover,
.btn-gradient:focus {
	background: linear-gradient(135deg, var(--secondary-dark) 0%, var(--secondary-color) 100%);
	color: var(--background-primary);
}

@keyframes spin {
	to { transform: rotate(360deg); }
}

/* ==========================================================================
	Form Styles
	========================================================================== */

.form-group {
	margin-bottom: var(--spacing-lg);
}

.form-group label {
	display: block;
	margin-bottom: var(--spacing-sm);
	font-weight: 500;
	color: var(--text-primary);
	font-size: var(--font-size-sm);
}

.form-group label.required::after {
	content: ' *';
	color: var(--error-color);
}

.form-control {
	width: 100%;
	padding: var(--spacing-sm) var(--spacing-md);
	border: 1px solid var(--border-field);
	border-radius: var(--radius-md);
	font-size: var(--font-size-base);
	transition: all var(--transition-normal);
	background: var(--background-primary);
	min-height: 44px; /* Accessibility: minimum touch target size */
}

/*
 * The border colour is the affordance; the ring is the global rule's. Neither
 * `outline` nor `box-shadow` is set here — either would beat the global
 * indicator on specificity and leave a form field with a 1.67:1 green ring, or
 * with the 10% tint and no ring at all.
 */
.form-control:focus {
	border-color: var(--primary-color);
}

.form-control.error {
	border-color: var(--error-color);
}

/* The shadow is not shown over the keyboard focus halo (#4761). */
.form-control.error:not(:focus-visible) {
	box-shadow: var(--focus-ring-error);
}

.form-control.success {
	border-color: var(--success-color);
}

.form-control.success:not(:focus-visible) {
	box-shadow: var(--focus-ring-success);
}

.form-control:disabled {
	background: var(--background-secondary);
	cursor: not-allowed;
	opacity: 0.6;
}

/*
 * THE FORM FIELD ITSELF — the floor under every input, select and textarea.
 *
 * The theme styled `.form-control` and nothing else. Of the 1,429 visible form
 * fields in this tree, 34 carry that class. 817 carry no class at all, so they
 * were drawn entirely by the browser: whatever padding, border and font the UA
 * happened to use, and no minimum touch target on a platform whose users are
 * elderly. The remaining 578 carry one of the module's own names, which is why
 * 131 module stylesheets hold 450 rules re-deciding what a field looks like —
 * padding 148 times, border 137, border-radius 135, font-size 132, and
 * `min-height` only 62.
 *
 * This is styled on the ELEMENT, for the same reason the tab component is
 * styled on the ARIA role: it is the one thing every implementation already
 * shares. A class would mean editing 1,429 fields; the element means editing
 * none.
 *
 * SPECIFICITY IS THE WHOLE DESIGN. `input` is 0,0,1 — below every class rule
 * in the tree — and `:where()` contributes nothing, so the exclusion list adds
 * no weight. So this is a FLOOR, not an override: a module that already styles
 * its fields keeps winning, and only the fields nobody styled change. Nothing
 * regresses; the 817 gain a field that looks like the rest of the platform.
 *
 * Width is deliberately absent. `.form-control` sets `width: 100%` and that is
 * right for a stacked form, but forcing it on every bare input would reflow
 * every inline filter and search box in the tree. Appearance and touch target
 * here; layout stays where it was.
 */
input:not(:where(
	[type="hidden"], [type="submit"], [type="button"], [type="reset"],
	[type="image"], [type="checkbox"], [type="radio"], [type="range"],
	[type="file"], [type="color"]
)),
select,
textarea {
	padding: var(--spacing-sm) var(--spacing-md);
	border: 1px solid var(--border-field);
	border-radius: var(--radius-md);
	background: var(--background-primary);
	color: var(--text-primary);
	font-family: inherit;
	font-size: var(--font-size-base);
	min-height: 44px;  /* WCAG 2.2 AA 2.5.8, and the theme's own button height */
	transition: border-color var(--transition-normal);
}

/*
 * The border colour is the affordance; the ring is the global focus rule's.
 * Neither `outline` nor `box-shadow` is set here — see the note on
 * `.form-control:focus`, which this mirrors.
 */
input:focus,
select:focus,
textarea:focus {
	border-color: var(--primary-color);
}

input:disabled,
select:disabled,
textarea:disabled {
	background: var(--background-secondary);
	cursor: not-allowed;
	opacity: 0.6;
}

/*
 * The error state is `aria-invalid`, not a class.
 *
 * Modules had four names for it — `.error` (41 rules), `.has-error` (13),
 * `.is-error` (9), `.invalid` (1) — and three stylesheets in the whole tree
 * looked at `aria-invalid`. So the state a screen reader announces and the
 * state a sighted user sees were separate facts maintained separately, which
 * is the same split that let a tab be drawn as selected while being announced
 * as not (#2610).
 *
 * Colour is not the only cue (WCAG 1.4.1): the border thickens to 2px as well
 * as changing colour, and `aria-invalid` is itself the announcement. The
 * message beside the field is `.form-error`, below.
 */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"] {
	border: 2px solid var(--error-color);
}

/*
 * Checkboxes and radios are targets before they are decoration. 24px is the
 * WCAG 2.2 AA 2.5.8 minimum, and this audience is the reason not to shave it.
 * `accent-color` tints the native control, which keeps the platform's own
 * focus, hover and high-contrast behaviour rather than replacing it with a
 * hand-drawn box.
 */
input[type="checkbox"],
input[type="radio"] {
	width: 1.5rem;
	height: 1.5rem;
	accent-color: var(--color-primary-green);
}

/* Form validation messages */
.form-error {
	color: var(--error-color);
	font-size: var(--font-size-sm);
	margin-top: var(--spacing-xs);
}

.form-success {
	color: var(--success-color);
	font-size: var(--font-size-sm);
	margin-top: var(--spacing-xs);
}

/* Form row for side-by-side fields */
.form-row {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
	gap: var(--spacing-md);
}

/* ==========================================================================
	Table Styles
	========================================================================== */

table {
	width: 100%;
	border-collapse: collapse;
	margin: var(--spacing-lg) 0;
	background: var(--background-primary);
	border-radius: var(--radius-lg);
	overflow: hidden;
	box-shadow: var(--shadow-sm);
	border: 1px solid var(--border-color);
}

th, td {
	padding: var(--table-cell-padding);
	font-size: var(--font-size-sm);
	text-align: left;
	border-bottom: 1px solid var(--border-color);
}

th {
	background: var(--primary-color);
	color: white;
	font-weight: 600;
	font-size: var(--font-size-sm);
	text-transform: uppercase;
	letter-spacing: 0.05em;
}

/*
 * ONE row hover, for every table on the platform.
 *
 * 66 module rules each decided what a hovered row looks like, between them
 * naming 24 different values — --color-surface-pale (32), --background-secondary
 * (11), --color-surface-row-hover (6), and a tail that reached for the ALERT
 * colours, so a hovered row could read as an error row. Most of those values
 * sit about 1% off white, which is a hover you cannot see.
 *
 * --color-surface-row-hover is the token this palette already has for the job
 * — its own comment reads "subtle < pale < row-hover" — and it is the only one
 * of the three that is actually visible against a white row. Body text on it
 * measures 13.49:1.
 *
 * A row that is already coloured by its state keeps its own hover: those 14
 * rules qualify the row (`tr.unreconciled-row:hover`) and are deliberate.
 */
tr:hover {
	background: var(--color-surface-row-hover);
}

tr:last-child td {
	border-bottom: none;
}

/* Sortable table headers */
th[data-sort] {
	cursor: pointer;
	-webkit-user-select: none;
	user-select: none;
	position: relative;
	padding-right: var(--spacing-xl);
}

th[data-sort]::after {
	content: '↕';
	position: absolute;
	right: var(--spacing-sm);
	opacity: 0.5;
	transition: opacity var(--transition-normal);
}

th[data-sort]:hover::after {
	opacity: 1;
}

th.sort-asc::after {
	content: '↑';
	opacity: 1;
}

th.sort-desc::after {
	content: '↓';
	opacity: 1;
}

/* Responsive Table Wrapper */
.table-responsive {
	width: 100%;
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
}

/* ==========================================================================
	Tabs
	========================================================================== */

/*
 * Sixteen modules had invented their own tab component — .tab-nav-item,
 * .tab-button, .form-tab-button, .tab-btn, .shop-dashboard__tab,
 * .usage-dashboard__tab, .am-login-tab-btn, .mailchimp-sync-tab,
 * .pp-potting-bench-tab, .allotment-action-board__tab and more — with
 * thirteen different names for "the selected one" and two different accent
 * colours. The theme had none, which is why (#2610).
 *
 * This is styled on the ARIA contract, not on a class, and that is deliberate.
 *
 * A tab strip is `role="tablist"`, a tab is `role="tab"` with
 * `aria-selected`, a panel is `role="tabpanel"` — a module cannot build an
 * accessible tab without them, so they are the one name every implementation
 * must already share. Thirteen of the sixteen carried the roles already.
 * Styling the role rather than a class means those thirteen need no markup
 * change at all, and the three that skipped the roles get no tab styling
 * until they add them — which is the accessibility defect they had anyway.
 *
 * It also puts the visual state and the announced state on ONE fact.
 * `.active` and `aria-selected="true"` were maintained separately, so a tab
 * could look selected and be announced as not, or the reverse. The selected
 * look now follows `aria-selected` and nothing else.
 *
 * Specificity is 0,1,0 — the same as a bare class — and the Asset Manager
 * enqueues module CSS at priority 5 against this theme's 10, so the theme
 * prints last and wins any tie. Module rules with a descendant selector
 * (`.risk-tabs .tab-nav-item`, 0,2,0) still beat it, so those were deleted
 * rather than left to lose.
 */

[role="tablist"] {
	display: flex;
	flex-wrap: wrap;
	gap: 0;
	margin: 0;
	padding: 0;
	list-style: none;
	background-color: var(--color-surface-pale);
	border-bottom: 1px solid var(--border-color);
}

/*
 * Some tab strips are a <ul> with <li role="presentation"> between the list
 * and the button. The li is structural only, so it must not size the tab.
 */
[role="tablist"] > li {
	display: flex;
}

/*
 * min-height 44px matches the theme's buttons and clears WCAG 2.2 2.5.8.
 * The 3px bottom border is transparent here and coloured when selected, so
 * the tab does not change size on selection.
 */
[role="tab"] {
	display: inline-flex;
	align-items: center;
	gap: var(--spacing-sm);
	min-height: 44px;
	padding: var(--spacing-sm) var(--spacing-md);
	background: transparent;
	border: none;
	border-bottom: 3px solid transparent;
	color: var(--text-secondary);       /* 7.15:1 on --color-surface-pale */
	font-family: inherit;
	font-size: var(--font-size-sm);
	font-weight: 500;
	text-align: center;
	text-decoration: none;
	cursor: pointer;
	transition: background-color var(--transition-normal), color var(--transition-normal);
}

[role="tab"]:hover {
	background-color: var(--color-surface-subtle-hover);
	color: var(--text-primary);
}

/*
 * Selected state. Colour is not the only cue (WCAG 1.4.1): the ground
 * changes, the weight changes, and `aria-selected` carries it to a screen
 * reader. The underline is --color-primary-green at 5.17:1 on white, well
 * over the 3:1 that 1.4.11 asks of a non-text indicator.
 */
[role="tab"][aria-selected="true"] {
	background-color: var(--background-primary);
	border-bottom-color: var(--color-primary-green);
	color: var(--text-primary);         /* 14.5:1 */
	font-weight: 600;
}

[role="tab"]:disabled,
[role="tab"][aria-disabled="true"] {
	color: var(--color-disabled-text);
	cursor: not-allowed;
}

/*
 * There is deliberately no `[role="tabpanel"]` rule here. The tab component is
 * the strip and the tabs; a panel is just the container for whatever the module
 * puts in it, and every module already sets its own padding, including mobile
 * overrides. Claiming the panel in the theme would silently beat all of those
 * (same specificity, theme prints last) for no gain.
 */

/* An emoji or icon glyph inside a tab. */
.tab-icon {
	font-size: 1.125rem;
	line-height: 1;
}

/*
 * A count on a tab. The two modules that had this both used a solid blue
 * pill, which is the one accent this palette does not otherwise use; the
 * neutral alert pair reads as a count rather than an alert, and the border
 * keeps the pill visible on the selected tab's white ground.
 */
.tab-badge {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 1.5rem;
	padding: 0 var(--spacing-xs);
	border: 1px solid var(--border-mid);
	border-radius: var(--radius-full);
	background-color: var(--color-alert-neutral-bg);
	color: var(--color-alert-neutral-text);   /* 6.93:1 */
	font-size: var(--font-size-xs);
	font-weight: 600;
	line-height: 1.5;
}

/* ==========================================================================
	Status Badges
	========================================================================== */

.status-badge {
	display: inline-flex;
	align-items: center;
	padding: var(--spacing-xs) var(--spacing-sm);
	border-radius: var(--radius-full);
	font-size: var(--font-size-xs);
	font-weight: 500;
	text-transform: uppercase;
	letter-spacing: 0.05em;
}

/*
 * These read a member's standing, so they have to be legible.
 *
 * They used `--success-light` behind `--success-color` and the two were never
 * measured together: 2.24:1 approved, 1.93:1 pending, 3.08:1 suspended, against
 * the 4.5:1 WCAG 2.2 AA requires. `--success-color` and its siblings are chosen
 * to carry white text ON them, not to be read against their own tint.
 *
 * The theme already had a set built for exactly this and measured when it was
 * written — `--color-alert-*-bg` with its matching `-text`. Use the pair, never
 * a background from one set and a colour from another. That is the same slip
 * that put `--color-primary-green` on `--color-alert-success-bg` at 4.13:1 in
 * membership-management.
 */
.status-approved {
	background: var(--color-alert-success-bg);
	color: var(--color-alert-success-text);
}

.status-pending {
	background: var(--color-alert-warning-bg);
	color: var(--color-alert-warning-text);
}

.status-suspended {
	background: var(--color-alert-danger-bg);
	color: var(--color-alert-danger-text);
}

/* ==========================================================================
	Footer Styles
	========================================================================== */

.site-footer {
	background: var(--secondary-color);
	color: white;
	margin-top: var(--spacing-3xl);
}

.footer-content {
	max-width: 1400px;
	margin: 0 auto;
	padding: var(--spacing-2xl) var(--spacing-xl);
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
	gap: var(--spacing-2xl);
}

.footer-info h2 {
	color: var(--background-primary);
}

.footer-section h3,
.footer-section h4 {
	color: var(--footer-heading-color);
	margin-bottom: var(--spacing-lg);
	font-size: var(--font-size-lg);
}

.footer-section p {
	margin-bottom: var(--spacing-sm);
	font-size: var(--font-size-sm);
	line-height: var(--line-height-relaxed);
}

.footer-section a {
	color: var(--footer-link-color);
	text-decoration: none;
	transition: color var(--transition-normal);
	font-size: var(--font-size-sm);
}

.footer-section a:hover,
.footer-section a:focus {
	color: var(--footer-heading-color);
}

#footer-menu {
	list-style: none;
	margin: 0;
	padding: 0;
}

#footer-menu li {
	margin-bottom: var(--spacing-sm);
}

.social-links {
	display: flex;
	gap: var(--spacing-md);
}

.social-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 40px;
	height: 40px;
	background: var(--primary-color);
	color: white;
	text-decoration: none;
	border-radius: var(--radius-full);
	font-size: var(--font-size-sm);
	transition: all var(--transition-normal);
}

.social-link:hover,
.social-link:focus {
	background: var(--primary-dark);
	color: white;
	transform: translateY(-2px);
}

.footer-bottom {
	background: var(--secondary-dark);
	padding: var(--spacing-lg) var(--spacing-xl);
	text-align: center;
}

.footer-bottom-content {
	max-width: 1400px;
	margin: 0 auto;
	display: flex;
	justify-content: space-between;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--spacing-md);
}

.footer-bottom p {
	margin: 0;
	font-size: var(--font-size-sm);
	color: var(--footer-copyright-color);
}

/* ==========================================================================
	Dashboard and Component Styles
	========================================================================== */

.dashboard-container {
	padding: var(--spacing-xl);
}

.dashboard-header {
	text-align: center;
	margin-bottom: var(--spacing-2xl);
}

.dashboard-title {
	color: var(--primary-color);
	margin-bottom: var(--spacing-sm);
}

.dashboard-subtitle {
	color: var(--text-secondary);
	font-size: var(--font-size-lg);
}

.dashboard-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
	gap: var(--spacing-xl);
	margin-bottom: var(--spacing-2xl);
}

.dashboard-section {
	background: var(--background-primary);
	padding: var(--spacing-xl);
	border-radius: var(--radius-xl);
	box-shadow: var(--shadow-sm);
	border: 1px solid var(--border-color);
}

.dashboard-section h2 {
	color: var(--primary-color);
	margin-bottom: var(--spacing-lg);
	font-size: var(--font-size-xl);
}

/* Stats Grid */
.stats-grid {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
	gap: var(--spacing-lg);
}

.stat-card {
	text-align: center;
	padding: var(--spacing-lg);
	background: var(--background-secondary);
	border-radius: var(--radius-lg);
	border: 1px solid var(--border-color);
	transition: all var(--transition-normal);
}

.stat-card:hover {
	transform: translateY(-2px);
}

/* The shadow is not shown over the keyboard focus halo (#4761). */
.stat-card:hover:not(:focus-visible) {
	box-shadow: var(--shadow-md);
}

/*
 * A stat card that is a link.
 *
 * plot-list renders four of them as <a> and had to restate colour and
 * text-decoration itself, because the theme styled the card and never the
 * anchor. `a.stat-card` is 0,1,1, so it also beats a module's bare class.
 */
a.stat-card {
	color: inherit;
	text-decoration: none;
}

.stat-number {
	font-size: var(--font-size-3xl);
	font-weight: 700;
	color: var(--primary-color);
	margin-bottom: var(--spacing-xs);
}

.stat-label {
	font-size: var(--font-size-sm);
	color: var(--text-secondary);
	font-weight: 500;
}

/* Quick Actions */
.quick-actions {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
	gap: var(--spacing-md);
}

.action-card {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: var(--spacing-lg);
	background: var(--background-secondary);
	border-radius: var(--radius-lg);
	border: 1px solid var(--border-color);
	transition: all var(--transition-normal);
	text-decoration: none;
	color: var(--text-primary);
}

.action-card:hover,
.action-card:focus {
	background: var(--primary-color);
	color: white;
	transform: translateY(-2px);
}

/* The shadow is not shown over the keyboard focus halo (#4761). */
.action-card:hover:not(:focus-visible) {
	box-shadow: var(--shadow-md);
}

.action-icon {
	font-size: var(--font-size-3xl);
	margin-bottom: var(--spacing-sm);
}

.action-title {
	font-weight: 600;
	margin-bottom: var(--spacing-xs);
	text-align: center;
}

.action-description {
	font-size: var(--font-size-sm);
	text-align: center;
	opacity: 0.8;
}

/* Activity Feed */
.activity-feed {
	max-height: 400px;
	overflow-y: auto;
}

.activity-item {
	display: flex;
	align-items: flex-start;
	gap: var(--spacing-md);
	padding: var(--spacing-md);
	border-bottom: 1px solid var(--border-color);
	transition: background var(--transition-normal);
}

.activity-item:hover {
	background: var(--background-secondary);
}

.activity-item:last-child {
	border-bottom: none;
}

.activity-icon {
	font-size: var(--font-size-lg);
	flex-shrink: 0;
}

.activity-content {
	flex: 1;
}

.activity-title {
	font-weight: 500;
	margin-bottom: var(--spacing-xs);
}

.activity-time {
	font-size: var(--font-size-sm);
	color: var(--text-secondary);
}

/* Notifications */
.notifications-list {
	max-height: 400px;
	overflow-y: auto;
}

.notification-item {
	display: flex;
	align-items: flex-start;
	gap: var(--spacing-md);
	padding: var(--spacing-md);
	border-radius: var(--radius-md);
	margin-bottom: var(--spacing-sm);
	border-left: 4px solid;
}

.notification-info {
	background: var(--info-light);
	border-left-color: var(--info-color);
}

.notification-warning {
	background: var(--warning-light);
	border-left-color: var(--warning-color);
}

.notification-error {
	background: var(--error-light);
	border-left-color: var(--error-color);
}

.notification-success {
	background: var(--success-light);
	border-left-color: var(--success-color);
}

.notification-icon {
	font-size: var(--font-size-lg);
	flex-shrink: 0;
}

.notification-content {
	flex: 1;
}

.notification-title {
	font-weight: 500;
	margin-bottom: var(--spacing-xs);
}

.notification-message {
	font-size: var(--font-size-sm);
	color: var(--text-secondary);
}

/*
 * An inline notice on the page - what an action just did, or something the
 * member should know. Printed by more than one module (the shop's rent-sale
 * list, its Shop Sync result on My Purchases), so it lives here, not in any one
 * module's stylesheet.
 */
.allotment-notice {
	padding: 1rem 1.25rem;
	border-radius: var(--radius-md);
	margin-bottom: 1.5rem;
	border-left: 4px solid;
}

.allotment-notice--success {
	background: var(--color-alert-success-bg);
	border-color: var(--color-primary-green);
	color: var(--color-primary-green-dark);
}

.allotment-notice--error {
	background: var(--color-alert-danger-bg);
	border-color: var(--color-alert-danger-border);
	color: var(--error-darker);
}

.allotment-notice--warning {
	background: var(--color-alert-warning-bg);
	border-color: var(--color-alert-warning-border);
	color: var(--color-alert-warning-text);
}

.allotment-notice--info {
	background: var(--color-alert-info-bg);
	border-color: var(--color-alert-info-border);
	color: var(--color-alert-info-text);
}

/* The theme strips link underlines site-wide; inside a notice a link would
   then look like the sentence around it (WCAG 1.4.1). Underline it and keep
   the notice's own text colour, so no new contrast pair is introduced.
   Buttons (.btn) are left out: they keep their own colours, or their label
   took the notice's dark text on a green button (1.66:1, PIPE-021). */
.allotment-notice a:not(.btn) {
	color: inherit;
	text-decoration: underline;
	text-underline-offset: 0.15em;
}

.allotment-notice a:not(.btn):hover {
	text-decoration-thickness: 0.125rem;
}

/* ==========================================================================
	Loading and State Indicators
	========================================================================== */

.loading-indicator {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	padding: var(--spacing-3xl);
	color: var(--text-secondary);
}

.spinner {
	width: 40px;
	height: 40px;
	border: 4px solid var(--border-color);
	border-top: 4px solid var(--primary-color);
	border-radius: 50%;
	animation: spin 1s linear infinite;
	margin-bottom: var(--spacing-md);
}

.no-results {
	text-align: center;
	padding: var(--spacing-3xl);
	color: var(--text-secondary);
}

/* ==========================================================================
	Modal Styles
	========================================================================== */

.modal {
	display: none;
	position: fixed;
	top: 0;
	left: 0;
	width: 100%;
	height: 100%;
	background: var(--color-overlay);
	z-index: var(--z-modal-backdrop);
	opacity: 0;
	transition: opacity var(--transition-normal);
}

.modal.active {
	display: flex;
	align-items: center;
	justify-content: center;
	opacity: 1;
}

.modal-content {
	background: var(--background-primary);
	border-radius: var(--radius-xl);
	box-shadow: var(--shadow-xl);
	max-width: 90vw;
	max-height: 90vh;
	overflow: hidden;
	transform: scale(0.9);
	transition: transform var(--transition-normal);
}

.modal.active .modal-content {
	transform: scale(1);
}

.modal-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: var(--spacing-lg) var(--spacing-xl);
	border-bottom: 1px solid var(--border-color);
	background: var(--background-secondary);
}

.modal-header h3 {
	margin: 0;
	color: var(--text-primary);
}

.modal-close {
	background: none;
	border: none;
	font-size: var(--font-size-2xl);
	cursor: pointer;
	color: var(--text-secondary);
	padding: var(--spacing-xs);
	border-radius: var(--radius-sm);
	transition: all var(--transition-normal);
}

.modal-close:hover,
.modal-close:focus {
	background: var(--error-dark);
	color: white;
}

.modal-body {
	padding: var(--spacing-xl);
	overflow-y: auto;
	max-height: calc(90vh - 120px);
}

/*
 * The row of buttons at the foot of a modal.
 *
 * The theme owned every other part of the modal and not this one, so fourteen
 * modules wrote it for themselves and each arrived at the same shape: flex,
 * pushed right, a gap, a top rule. Two names are in use — `.modal-footer` and
 * `.modal-actions` — and both are styled here rather than renamed in forty
 * templates, because a rename buys nothing a second selector does not.
 */
.modal-footer,
.modal-actions {
	display: flex;
	justify-content: flex-end;
	gap: var(--spacing-md);
	padding: var(--spacing-lg) var(--spacing-xl);
	border-top: 1px solid var(--border-color);
	background: var(--background-secondary);
}

/*
 * On a narrow screen the buttons stack, and the primary action goes to the
 * bottom where a thumb reaches it.
 */
@media (max-width: 768px) {
	.modal-footer,
	.modal-actions {
		flex-direction: column-reverse;
	}

	.modal-footer > .btn,
	.modal-actions > .btn {
		width: 100%;
	}
}

/* ==========================================================================
	Toast Notifications
	========================================================================== */

.notification {
	position: fixed;
	top: var(--spacing-lg);
	right: var(--spacing-lg);
	background: var(--background-primary);
	border-radius: var(--radius-lg);
	box-shadow: var(--shadow-lg);
	padding: var(--spacing-md) var(--spacing-lg);
	border-left: 4px solid;
	z-index: var(--z-toast);
	max-width: 400px;
	display: flex;
	align-items: center;
	gap: var(--spacing-md);
	transform: translateX(100%);
	transition: transform var(--transition-normal);
}

.notification.show {
	transform: translateX(0);
}

.notification-info {
	border-left-color: var(--info-color);
}

.notification-success {
	border-left-color: var(--success-color);
}

.notification-warning {
	border-left-color: var(--warning-color);
}

.notification-error {
	border-left-color: var(--error-color);
}

.notification-message {
	flex: 1;
	font-size: var(--font-size-sm);
}

.notification-close {
	background: none;
	border: none;
	font-size: var(--font-size-lg);
	cursor: pointer;
	color: var(--text-secondary);
	padding: 0;
	width: 20px;
	height: 20px;
	display: flex;
	align-items: center;
	justify-content: center;
	border-radius: var(--radius-sm);
	transition: all var(--transition-normal);
}

.notification-close:hover,
.notification-close:focus {
	background: var(--text-secondary);
	color: white;
}

/* ==========================================================================
	Mobile Menu Toggle (Hamburger)
	========================================================================== */

.mobile-menu-toggle {
	display: none;
	background: none;
	border: none;
	cursor: pointer;
	padding: var(--spacing-sm);
	border-radius: var(--radius-md);
	transition: background var(--transition-normal);
}

.mobile-menu-toggle:hover,
.mobile-menu-toggle:focus {
	background: var(--background-secondary);
}

.hamburger-icon {
	display: flex;
	flex-direction: column;
	justify-content: space-between;
	width: 24px;
	height: 18px;
}

.hamburger-line {
	display: block;
	width: 100%;
	height: 3px;
	background: var(--text-primary);
	border-radius: 2px;
	transition: all var(--transition-normal);
}

/* Hamburger animation when menu is open */
.mobile-menu-toggle[aria-expanded="true"] .hamburger-line:nth-child(1) {
	transform: translateY(7.5px) rotate(45deg);
}

.mobile-menu-toggle[aria-expanded="true"] .hamburger-line:nth-child(2) {
	opacity: 0;
	transform: scaleX(0);
}

.mobile-menu-toggle[aria-expanded="true"] .hamburger-line:nth-child(3) {
	transform: translateY(-7.5px) rotate(-45deg);
}

/* ==========================================================================
	Responsive Design
	========================================================================== */

@media (max-width: 768px) {
	.header-content {
		flex-direction: row;
		flex-wrap: wrap;
		justify-content: space-between;
		align-items: center;
		padding: var(--spacing-md);
	}

	.site-branding {
		flex: 1;
		align-items: flex-start;
	}

	.header-right {
		flex-direction: row;
		align-items: center;
		gap: var(--spacing-sm);
		order: 2;
	}

	/* Show hamburger button on mobile */
	.mobile-menu-toggle {
		display: flex;
		align-items: center;
		justify-content: center;
		min-width: 44px;
		min-height: 44px;
	}

	/* Hide navigation by default on mobile */
	.main-navigation {
		display: none;
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		background: var(--background-primary);
		box-shadow: var(--shadow-lg);
		border-top: 1px solid var(--border-color);
		z-index: var(--z-dropdown);
		max-height: calc(100vh - 80px);
		overflow-y: auto;
	}

	/* Show navigation when toggled */
	.main-navigation.is-open {
		display: block;
	}

	.main-navigation ul {
		flex-direction: column;
		width: 100%;
		gap: 0;
	}

	.main-navigation li {
		border-bottom: 1px solid var(--border-color);
	}

	.main-navigation li:last-child {
		border-bottom: none;
	}

	.main-navigation a {
		display: block;
		border-radius: 0;
		padding: var(--spacing-md) var(--spacing-lg);
		font-size: var(--font-size-base);
	}

	.main-navigation a:hover,
	.main-navigation a:focus {
		transform: none;
		background: var(--primary-color);
		color: white;
	}

	/* Dropdown menus on mobile */
	.main-navigation ul ul {
		position: static;
		box-shadow: none;
		background: var(--background-secondary);
		border: none;
		border-radius: 0;
		min-width: 100%;
		display: none;
	}

	.main-navigation ul li.menu-item-has-children.is-open > ul {
		display: flex;
	}

	.main-navigation ul ul a {
		padding-left: var(--spacing-2xl);
		background: var(--background-secondary);
	}

	.main-navigation ul ul a:hover,
	.main-navigation ul ul a:focus {
		background: var(--primary-light);
	}

	/* Hide verbose logged-in status and site switcher on smaller mobiles */
	/* Login link (.user-status-logged-out) stays visible — it's compact and critical */
	.user-status-logged-in,
	.site-switcher {
		display: none;
	}

	/* Make header position relative for absolute nav positioning */
	.site-header {
		position: relative;
	}

	.footer-content {
		grid-template-columns: 1fr;
		text-align: center;
		gap: var(--spacing-xl);
	}

	.footer-bottom-content {
		flex-direction: column;
		text-align: center;
	}

	.container {
		padding: var(--spacing-md);
	}

	.dashboard-grid {
		grid-template-columns: 1fr;
		gap: var(--spacing-lg);
	}

	.stats-grid {
		grid-template-columns: repeat(2, 1fr);
	}

	.quick-actions {
		grid-template-columns: 1fr;
	}

	.form-row {
		grid-template-columns: 1fr;
	}

	.modal-content {
		margin: var(--spacing-md);
		max-width: calc(100vw - 2rem);
	}

	.notification {
		right: var(--spacing-md);
		left: var(--spacing-md);
		max-width: none;
	}

	/* Responsive Table Styles */
	.table-responsive {
		margin-bottom: var(--spacing-lg);
	}

	.table-responsive table {
		min-width: 600px;
	}

	/* Make table cells more compact on mobile */
	table th,
	table td {
		padding: var(--spacing-sm);
		font-size: var(--font-size-sm);
	}

	/* Ensure action buttons are always accessible */
	table .btn,
	table button {
		white-space: nowrap;
		min-width: auto;
		padding: var(--spacing-xs) var(--spacing-sm);
		font-size: var(--font-size-xs);
	}
}

/* Tablet - show logged-in user status but keep hamburger */
@media (min-width: 481px) and (max-width: 768px) {
	.user-status-logged-in {
		display: flex;
	}
}

@media (max-width: 480px) {
	.stats-grid {
		grid-template-columns: 1fr;
	}

	.dashboard-section {
		padding: var(--spacing-md);
	}

	.modal-body {
		padding: var(--spacing-md);
	}

	.site-logo {
		font-size: var(--font-size-xl);
	}

	.site-description {
		display: none;
	}
}

/* ==========================================================================
	Utility Classes
	========================================================================== */

/* Text alignment */
.text-center { text-align: center; }
.text-right { text-align: right; }
.text-left { text-align: left; }

/* Margins */
.mb-1 { margin-bottom: var(--spacing-xs); }
.mb-2 { margin-bottom: var(--spacing-sm); }
.mb-3 { margin-bottom: var(--spacing-md); }
.mb-4 { margin-bottom: var(--spacing-lg); }
.mb-5 { margin-bottom: var(--spacing-xl); }

.mt-1 { margin-top: var(--spacing-xs); }
.mt-2 { margin-top: var(--spacing-sm); }
.mt-3 { margin-top: var(--spacing-md); }
.mt-4 { margin-top: var(--spacing-lg); }
.mt-5 { margin-top: var(--spacing-xl); }

/* Padding */
.p-1 { padding: var(--spacing-xs); }
.p-2 { padding: var(--spacing-sm); }
.p-3 { padding: var(--spacing-md); }
.p-4 { padding: var(--spacing-lg); }
.p-5 { padding: var(--spacing-xl); }

/* Display */
.d-none { display: none; }
.d-block { display: block; }
.d-flex { display: flex; }
.d-grid { display: grid; }
.d-inline { display: inline; }
.d-inline-block { display: inline-block; }

/* Flexbox utilities */
.justify-center { justify-content: center; }
.justify-between { justify-content: space-between; }
.justify-around { justify-content: space-around; }
.justify-end { justify-content: flex-end; }

.align-center { align-items: center; }
.align-start { align-items: flex-start; }
.align-end { align-items: flex-end; }

.flex-column { flex-direction: column; }
.flex-wrap { flex-wrap: wrap; }

/* Width and height */
.w-100 { width: 100%; }
.h-100 { height: 100%; }
.w-auto { width: auto; }
.h-auto { height: auto; }

/* Border radius */
.rounded { border-radius: var(--radius-md); }
.rounded-sm { border-radius: var(--radius-sm); }
.rounded-lg { border-radius: var(--radius-lg); }
.rounded-xl { border-radius: var(--radius-xl); }
.rounded-full { border-radius: var(--radius-full); }

/* Shadows */
.shadow { box-shadow: var(--shadow-sm); }
.shadow-md { box-shadow: var(--shadow-md); }
.shadow-lg { box-shadow: var(--shadow-lg); }
.shadow-xl { box-shadow: var(--shadow-xl); }

/* Colors */
.text-primary { color: var(--text-primary); }
.text-secondary { color: var(--text-secondary); }
.text-muted { color: var(--text-muted); }
.text-success { color: var(--success-color); }
.text-warning { color: var(--warning-color); }
.text-error { color: var(--error-color); }
.text-info { color: var(--info-color); }

.bg-primary { background: var(--primary-color); }
.bg-secondary { background: var(--secondary-color); }
.bg-success { background: var(--success-color); }
.bg-warning { background: var(--warning-color); }
.bg-error { background: var(--error-color); }
.bg-info { background: var(--info-color); }

/* Position */
.relative { position: relative; }
.absolute { position: absolute; }
.fixed { position: fixed; }
.sticky { position: sticky; }

/* Overflow */
.overflow-hidden { overflow: hidden; }
.overflow-auto { overflow: auto; }
.overflow-scroll { overflow: scroll; }

/* Cursor */
.cursor-pointer { cursor: pointer; }
.cursor-not-allowed { cursor: not-allowed; }

/* User select */
.select-none {
	-webkit-user-select: none;
	user-select: none;
}
.select-text {
	-webkit-user-select: text;
	user-select: text;
}
.select-all {
	-webkit-user-select: all;
	user-select: all;
}

/* Onboarding Wizard Styles */
.allotment-onboarding-wizard-container {
	max-width: 800px;
	margin: 40px auto;
	padding: 20px 40px;
	background: var(--background-primary);
	border-radius: 8px;
	box-shadow: var(--shadow-md);
}

.allotment-wizard-steps {
	list-style: none;
	padding: 0;
	margin: 0 0 40px 0;
	display: flex;
	justify-content: space-between;
	border-bottom: 1px solid var(--border-color);
	padding-bottom: 20px;
}

.allotment-wizard-steps li {
	flex: 1;
	text-align: center;
	color: var(--text-muted);
	font-weight: 600;
	position: relative;
}

/* The number circle */
.allotment-wizard-steps li::before {
	content: counter(step);
	counter-increment: step;
	width: 30px;
	height: 30px;
	line-height: 30px;
	border: 2px solid var(--border-color);
	display: block;
	margin: 0 auto 10px auto;
	border-radius: 50%;
	background-color: white;
}

.allotment-wizard-steps li.active {
	color: var(--info-color);
}

.allotment-wizard-steps li.active::before {
	border-color: var(--color-accent-blue);
	background-color: var(--color-accent-blue);
	color: white;
}

.allotment-wizard-steps li.completed {
	color: var(--success-color);
}

.allotment-wizard-steps li.completed::before {
	content: '\\2713'; /* Checkmark */
	border-color: var(--color-primary-green);
	background-color: var(--color-primary-green);
	color: white;
}

.wizard-step-content h2 {
	margin-top: 0;
}

.wizard-step-content .form-table {
	width: 100%;
}

.wizard-step-content .button-primary {
	background: var(--info-color);
	border-color: var(--info-color);
	padding: 10px 20px;
	height: auto;
	font-size: 1rem;
}

.site-logo .custom-logo {
	max-width: 250px !important;
	height: auto !important;
}
/* ==========================================================================
	Accessibility Improvements (v1.2.0)
	========================================================================== */

/* Screen Reader Text - visible only to screen readers */
.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;
	white-space: nowrap;
	width: 1px;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	background-color: var(--background-secondary);
	border-radius: 3px;
	clip: auto !important;
	clip-path: none;
	color: var(--color-accent-blue);
	display: block;
	font-size: 0.875rem;
	font-weight: bold;
	height: auto;
	left: 5px;
	line-height: normal;
	padding: 15px 23px 14px;
	text-decoration: none;
	top: 5px;
	width: auto;
	z-index: 100000;
}

/* The shadow is not shown over the keyboard focus halo (#4761). */
.screen-reader-text:focus:not(:focus-visible) {
	box-shadow: 0 0 2px 2px var(--color-overlay);
}

/* Skip link styling */
.skip-link {
	background: var(--primary-color);
	color: var(--background-primary);
	font-weight: bold;
}

.skip-link:focus {
	background: var(--primary-dark);
	/* .screen-reader-text:focus sets blue text, unreadable on this green (#4764). */
	color: var(--background-primary);
}

/* ==========================================================================
	Mobile Menu Login/Logout Styles
	========================================================================== */

/*
 * Login/Logout menu items are added to the nav menu for mobile accessibility.
 * On desktop, the user-status area in the header shows login/logout.
 * On mobile, user-status is hidden, so we show these in the hamburger menu.
 */

/* Hide menu login/logout on desktop - user-status area handles this */
.menu-item-login,
.menu-item-logout {
	display: none;
}

/* Mobile-specific styling for login/logout items */
@media (max-width: 768px) {
	/* Show login/logout in mobile menu */
	.menu-item-login,
	.menu-item-logout {
		display: list-item;
		border-top: 2px solid var(--border-color);
		margin-top: var(--spacing-sm);
	}

	.menu-item-login a,
	.menu-item-logout a {
		font-weight: 600;
	}

	.menu-item-login a {
		color: var(--primary-color);
	}

	.menu-item-logout a {
		color: var(--error-color);
	}

	.menu-item-login a,
	.menu-item-logout a {
		display: flex;
		align-items: center;
		gap: var(--spacing-sm);
	}

	.menu-item-login a::before {
		content: "→";
	}

	.menu-item-logout a::before {
		content: "←";
	}

	.menu-item-login a:hover,
	.menu-item-login a:focus {
		background: var(--primary-color);
		color: white;
	}

	.menu-item-logout a:hover,
	.menu-item-logout a:focus {
		background: var(--error-dark);
		color: white;
	}
}

/* ==========================================================================
	Demo Site Banner
	========================================================================== */

.demo-site-banner {
	position: sticky;
	top: 0;
	z-index: 10000;
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 1rem;
	padding: 0.625rem 1rem;
	background: var(--demo-banner-bg);
	color: var(--background-primary);
	font-size: 0.9rem;
	text-align: center;
}

.demo-site-banner a {
	color: var(--background-primary);
	font-weight: 600;
	text-decoration: underline;
	text-underline-offset: 2px;
}

.demo-site-banner a:hover,
.demo-site-banner a:focus {
	color: var(--demo-banner-link-hover);
}

@media (max-width: 600px) {
	.demo-site-banner {
		flex-direction: column;
		gap: 0.25rem;
		font-size: 0.8rem;
		padding: 0.5rem;
	}
}

/* ==========================================================================
	Single Community Post
	========================================================================== */

.community-blog-single-wrapper {
	max-width: 720px;
	margin: 0 auto;
	padding: var(--spacing-lg) var(--spacing-md);
}

.community-post-single {
	background: var(--background-primary);
	border-radius: var(--radius-2xl);
	border: 1px solid var(--border-color);
	padding: var(--spacing-2xl);
	box-shadow: var(--shadow-sm);
}

/* Author row — reuse feed card patterns */
.community-post-single .post-author-row {
	display: flex;
	align-items: center;
	gap: var(--spacing-sm);
	margin-bottom: var(--spacing-lg);
	flex-wrap: wrap;
}

.community-post-single .author-avatar {
	width: 44px;
	height: 44px;
	border-radius: var(--radius-full);
	flex-shrink: 0;
	object-fit: cover;
}

.community-post-single .author-details {
	display: flex;
	align-items: center;
	gap: var(--spacing-xs);
	flex-wrap: wrap;
}

.community-post-single .author-name {
	font-weight: 600;
	color: var(--text-primary);
	font-size: var(--font-size-sm);
}

.community-post-single .post-meta-separator {
	color: var(--text-muted);
}

.community-post-single .post-date {
	color: var(--text-muted);
	font-size: var(--font-size-xs);
}

.community-post-single .post-topics {
	display: flex;
	gap: var(--spacing-xs);
	flex-wrap: wrap;
	margin-left: auto;
}

.community-post-single .topic-badge {
	display: inline-flex;
	align-items: center;
	padding: 2px 10px;
	background: var(--background-tertiary);
	color: var(--text-secondary);
	font-size: 0.875rem;
	font-weight: 600;
	border-radius: var(--radius-full);
	letter-spacing: 0.03em;
	text-transform: uppercase;
	position: relative;
}

.community-post-single .topic-badge::before {
	content: '';
	position: absolute;
	left: 4px;
	top: 50%;
	transform: translateY(-50%);
	width: 6px;
	height: 6px;
	border-radius: 50%;
	background: currentColor;
}

.community-post-single .topic-badge.topic-help {
	background: var(--color-alert-warning-bg);
	color: var(--color-alert-warning-text);
}

.community-post-single .topic-badge.topic-help::before {
	content: '?';
	width: auto;
	height: auto;
	border-radius: 0;
	background: none;
	font-weight: 700;
	font-size: 0.75rem;
	left: 6px;
}

.community-post-single .topic-badge.topic-announcement {
	background: var(--color-alert-info-bg);
	color: var(--color-alert-info-text);
}

.community-post-single .topic-badge.topic-announcement::before {
	content: '!';
	width: auto;
	height: auto;
	border-radius: 0;
	background: none;
	font-weight: 700;
	font-size: 0.75rem;
	left: 6px;
}

.community-post-single .topic-badge.topic-lost-found {
	background: var(--color-alert-danger-bg);
	color: var(--color-alert-danger-text);
}

.community-post-single .topic-badge.topic-lost-found::before {
	content: '⚠';
	width: auto;
	height: auto;
	border-radius: 0;
	background: none;
	font-size: 0.75rem;
	left: 6px;
}

.community-post-single .topic-badge.topic-for-sale {
	background: var(--color-alert-success-bg);
	color: var(--color-alert-success-text);
}

.community-post-single .topic-badge.topic-for-sale::before {
	content: '$';
	width: auto;
	height: auto;
	border-radius: 0;
	background: none;
	font-weight: 700;
	font-size: 0.75rem;
	left: 6px;
}

/* Adjust padding to accommodate icons */
.community-post-single .topic-badge.topic-help,
.community-post-single .topic-badge.topic-announcement,
.community-post-single .topic-badge.topic-lost-found,
.community-post-single .topic-badge.topic-for-sale {
	padding-left: 18px;
}

/* Title */
.post-single-title {
	font-size: var(--font-size-3xl);
	font-weight: 700;
	color: var(--text-primary);
	line-height: var(--line-height-tight);
	margin: 0 0 var(--spacing-xl) 0;
}

/* Images */
.post-single-images {
	display: flex;
	flex-wrap: wrap;
	gap: var(--spacing-md);
	margin-bottom: var(--spacing-xl);
}

.post-single-image {
	border-radius: var(--radius-xl);
	overflow: hidden;
	border: 1px solid var(--border-color);
}

.post-single-image img {
	display: block;
	max-width: 100%;
	height: auto;
	border-radius: var(--radius-xl);
}

/* Content */
.post-single-content {
	color: var(--text-primary);
	line-height: var(--line-height-relaxed);
	font-size: var(--font-size-base);
	margin-bottom: var(--spacing-xl);
}

.post-single-content p {
	margin-bottom: var(--spacing-md);
}

.post-single-content a {
	color: var(--primary-color);
	text-decoration: underline;
}

.post-single-content a:hover {
	color: var(--primary-dark);
}

/* Footer */
.post-single-footer {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding-top: var(--spacing-lg);
	border-top: 1px solid var(--border-light);
}

.community-post-single .post-actions {
	display: flex;
	gap: 2px;
}

.community-post-single .btn-text {
	background: transparent;
	color: var(--text-muted);
	border: none;
	padding: var(--spacing-xs) var(--spacing-sm);
	font-size: var(--font-size-xs);
	font-weight: 500;
	cursor: pointer;
	border-radius: var(--radius-lg);
	transition: color 0.15s, background 0.15s;
	min-height: 44px;
	display: inline-flex;
	align-items: center;
	gap: 4px;
	font-family: var(--font-family-primary);
	text-decoration: none;
}

.community-post-single .btn-text:hover {
	color: var(--primary-color);
	background: var(--background-secondary);
}

.back-to-feed {
	display: inline-flex;
	align-items: center;
	gap: var(--spacing-xs);
	color: var(--primary-color);
	font-size: var(--font-size-sm);
	font-weight: 600;
	text-decoration: none;
	min-height: 44px;
	padding: var(--spacing-xs) var(--spacing-sm);
	border-radius: var(--radius-lg);
	transition: color 0.15s, background 0.15s;
}

.back-to-feed:hover {
	color: var(--primary-dark);
	background: var(--background-secondary);
}

/* Comments on single community post */
.community-blog-single-wrapper .comments-area {
	margin-top: var(--spacing-xl);
	background: var(--background-primary);
	border-radius: var(--radius-2xl);
	border: 1px solid var(--border-color);
	padding: var(--spacing-xl);
}

.community-blog-single-wrapper .comments-title {
	font-size: var(--font-size-xl);
	font-weight: 700;
	color: var(--text-primary);
	margin-bottom: var(--spacing-lg);
}

.community-blog-single-wrapper .comment-list {
	list-style: none;
	padding: 0;
	margin: 0;
}

.community-blog-single-wrapper .comment {
	padding: var(--spacing-md) 0;
	border-bottom: 1px solid var(--border-light);
}

.community-blog-single-wrapper .comment:last-child {
	border-bottom: none;
}

.community-blog-single-wrapper .comment-author {
	font-weight: 600;
	color: var(--text-primary);
	font-size: var(--font-size-sm);
}

.community-blog-single-wrapper .comment-metadata {
	font-size: var(--font-size-xs);
	color: var(--text-muted);
	margin-bottom: var(--spacing-sm);
}

.community-blog-single-wrapper .comment-content {
	color: var(--text-secondary);
	font-size: var(--font-size-sm);
	line-height: var(--line-height-relaxed);
}

.community-blog-single-wrapper .comment-respond {
	margin-top: var(--spacing-lg);
	padding-top: var(--spacing-lg);
	border-top: 1px solid var(--border-light);
}

.community-blog-single-wrapper .comment-reply-title {
	font-size: var(--font-size-lg);
	font-weight: 700;
	color: var(--text-primary);
	margin-bottom: var(--spacing-md);
}

.community-blog-single-wrapper .comment-form textarea {
	width: 100%;
	padding: var(--spacing-sm) var(--spacing-md);
	border: 1px solid var(--border-color);
	border-radius: var(--radius-lg);
	font-size: var(--font-size-base);
	font-family: var(--font-family-primary);
	line-height: var(--line-height-normal);
	color: var(--text-primary);
	background: var(--background-primary);
	min-height: 100px;
	resize: vertical;
	box-sizing: border-box;
}

.community-blog-single-wrapper .comment-form textarea:focus {
	border-color: var(--primary-color);
}

.community-blog-single-wrapper .comment-form .submit {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: var(--spacing-sm) var(--spacing-lg);
	background: var(--primary-color);
	color: var(--background-primary);
	border: 1px solid var(--primary-color);
	border-radius: var(--radius-full);
	font-size: var(--font-size-sm);
	font-weight: 600;
	font-family: var(--font-family-primary);
	cursor: pointer;
	min-height: 44px;
	margin-top: var(--spacing-sm);
	transition: background 0.15s;
}

.community-blog-single-wrapper .comment-form .submit:hover {
	background: var(--primary-dark);
	border-color: var(--primary-dark);
}

/* Responsive */
@media (max-width: 768px) {
	.community-blog-single-wrapper {
		padding: var(--spacing-md) var(--spacing-sm);
	}

	.community-post-single {
		padding: var(--spacing-lg) var(--spacing-md);
		border-radius: var(--radius-xl);
	}

	.post-single-title {
		font-size: var(--font-size-2xl);
	}

	.community-post-single .post-topics {
		margin-left: 0;
		margin-top: var(--spacing-xs);
		width: 100%;
	}

	.post-single-footer {
		flex-direction: column;
		align-items: flex-start;
		gap: var(--spacing-sm);
	}

	.community-blog-single-wrapper .comments-area {
		padding: var(--spacing-lg) var(--spacing-md);
	}
}

/* =====================================================================
	PWA Install Banner
	===================================================================== */
#pwa-install-banner {
	position: fixed;
	bottom: -100px;
	left: 0;
	right: 0;
	z-index: 9999;
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 12px 20px;
	background: var(--background-primary);
	border-top: 2px solid var(--primary-color);
	box-shadow: var(--shadow-lg);
	transition: bottom 0.4s ease;
}

#pwa-install-banner.pwa-banner-visible {
	bottom: 0;
}

.pwa-banner-content {
	display: flex;
	align-items: center;
	gap: 12px;
}

.pwa-banner-icon {
	font-size: 1.75rem;
	line-height: 1;
}

.pwa-banner-text {
	display: flex;
	flex-direction: column;
	gap: 2px;
}

.pwa-banner-text strong {
	font-size: 0.9375rem;
	color: var(--pwa-text-strong);
}

.pwa-banner-text span {
	font-size: 0.875rem;
	color: var(--pwa-text-muted);
}

.pwa-banner-actions {
	display: flex;
	align-items: center;
	gap: 8px;
}

.pwa-banner-install {
	padding: 8px 20px;
	background: var(--primary-color);
	color: var(--background-primary);
	border: none;
	border-radius: 6px;
	font-size: 0.875rem;
	font-weight: 600;
	cursor: pointer;
}

.pwa-banner-dismiss {
	padding: 4px 8px;
	background: none;
	border: none;
	font-size: 1.5rem;
	color: var(--pwa-icon-border);
	cursor: pointer;
	line-height: 1;
}

.pwa-banner-dismiss:hover {
	color: var(--pwa-text-muted);
}

@media (max-width: 480px) {
	#pwa-install-banner {
		flex-direction: column;
		gap: 10px;
		padding: 14px 16px;
	}

	.pwa-banner-actions {
		width: 100%;
	}

	.pwa-banner-install {
		flex: 1;
	}
}

/* iOS Safari Install Banner */
.pwa-ios-banner .pwa-banner-content {
	align-items: flex-start;
}

.pwa-ios-steps {
	display: flex;
	flex-direction: column;
	gap: 6px;
	margin-top: 6px;
}

.pwa-ios-step {
	display: flex;
	align-items: center;
	gap: 8px;
	font-size: 0.875rem;
	color: var(--pwa-step-color);
}

.pwa-ios-num {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 22px;
	height: 22px;
	border-radius: 50%;
	background: var(--primary-color);
	color: var(--background-primary);
	font-size: 0.875rem;
	font-weight: 700;
	flex-shrink: 0;
}

.pwa-ios-share-icon {
	display: inline-block;
	padding: 2px 6px;
	border: 1px solid var(--pwa-icon-border);
	border-radius: 4px;
	font-size: 0.875rem;
	line-height: 1;
}

.pwa-banner-dismiss-ios {
	padding: 8px 20px;
	background: var(--primary-color);
	color: var(--background-primary);
	border: none;
	border-radius: 6px;
	font-size: 0.875rem;
	font-weight: 600;
	cursor: pointer;
}

@media (max-width: 480px) {
	.pwa-ios-banner {
		flex-direction: column;
		gap: 10px;
		padding: 16px;
	}

	.pwa-ios-banner .pwa-banner-actions {
		width: 100%;
	}

	.pwa-banner-dismiss-ios {
		width: 100%;
	}
}

/* ==========================================================================
	404 Error Page — Allotment Garden Theme
	========================================================================== */

.error-404-container {
	text-align: center;
	padding: 0 1rem 3rem;
	max-width: 800px;
	margin: 0 auto;
}

.error-404-scene {
	margin: -1rem -1rem 0;
	overflow: hidden;
	border-radius: 0 0 1rem 1rem;
}

.error-404-illustration {
	width: 100%;
	height: auto;
	display: block;
}

.error-404-content {
	padding: 2rem 1rem 0;
}

.error-404-title {
	font-size: 2rem;
	font-weight: 700;
	color: var(--primary-color);
	margin-bottom: 0.75rem;
	line-height: 1.2;
}

.error-404-message {
	font-size: 1.125rem;
	color: var(--text-primary);
	max-width: 540px;
	margin: 0 auto 2rem;
	line-height: 1.6;
}

.error-404-actions {
	display: flex;
	justify-content: center;
	gap: 1rem;
	flex-wrap: wrap;
	margin-bottom: 2.5rem;
}

.error-404-btn {
	display: inline-block;
	padding: 0.875rem 1.75rem;
	border-radius: 0.5rem;
	font-size: 1rem;
	font-weight: 600;
	text-decoration: none;
	transition: background-color 0.2s ease, transform 0.1s ease;
}

.error-404-btn:hover {
	transform: translateY(-1px);
}

.error-404-btn-primary {
	background-color: var(--primary-color);
	color: var(--background-primary);
}

.error-404-btn-primary:hover {
	background-color: var(--secondary-color);
	color: var(--background-primary);
}

.error-404-btn-secondary {
	background-color: transparent;
	color: var(--primary-color);
	border: 2px solid var(--primary-color);
}

.error-404-btn-secondary:hover {
	background-color: var(--primary-color);
	color: var(--background-primary);
}

.error-404-suggestions {
	margin-bottom: 2rem;
}

.error-404-suggestions h2 {
	font-size: 1.125rem;
	color: var(--text-primary);
	margin-bottom: 0.75rem;
}

.error-404-suggestions ul {
	display: flex;
	justify-content: center;
	gap: 1.5rem;
	flex-wrap: wrap;
	padding: 0;
}

.error-404-suggestions li {
	list-style: none;
}

.error-404-suggestions a {
	color: var(--primary-color);
	font-weight: 500;
	text-decoration: underline;
	text-underline-offset: 2px;
}

.error-404-suggestions a:hover {
	color: var(--secondary-color);
}

.error-404-search {
	max-width: 400px;
	margin: 0 auto;
}

.error-404-search h2 {
	font-size: 1.125rem;
	color: var(--text-primary);
	margin-bottom: 0.75rem;
}

@media (max-width: 600px) {
	.error-404-title {
		font-size: 1.5rem;
	}

	.error-404-message {
		font-size: 1rem;
	}

	.error-404-actions {
		flex-direction: column;
		align-items: center;
	}

	.error-404-btn {
		width: 100%;
		max-width: 280px;
		text-align: center;
	}

	.error-404-suggestions ul {
		flex-direction: column;
		gap: 0.75rem;
	}
}

/* ==========================================================================
	Offline / Maintenance Page
	========================================================================== */

.offline-container {
	text-align: center;
	padding: 0 1rem 3rem;
	max-width: 800px;
	margin: 0 auto;
}

.offline-scene {
	margin: -1rem -1rem 0;
	overflow: hidden;
	border-radius: 0 0 1rem 1rem;
}

.offline-illustration {
	width: 100%;
	height: auto;
	display: block;
}

.offline-content {
	padding: 2rem 1rem 0;
}

.offline-title {
	font-size: 2rem;
	font-weight: 700;
	color: var(--primary-color);
	margin-bottom: 0.75rem;
	line-height: 1.2;
}

.offline-message {
	font-size: 1.125rem;
	color: var(--text-primary);
	max-width: 540px;
	margin: 0 auto 1rem;
	line-height: 1.6;
}

.offline-reassurance {
	font-size: 1rem;
	color: var(--text-secondary);
	margin-bottom: 2rem;
}

.offline-actions {
	margin-bottom: 2rem;
}

.offline-btn {
	display: inline-block;
	padding: 0.875rem 1.75rem;
	border-radius: 0.5rem;
	font-size: 1rem;
	font-weight: 600;
	text-decoration: none;
	transition: background-color 0.2s ease, transform 0.1s ease;
}

.offline-btn:hover {
	transform: translateY(-1px);
}

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

.offline-btn-primary:hover {
	background-color: var(--secondary-color);
	color: var(--background-primary);
}

@media (max-width: 600px) {
	.offline-title {
		font-size: 1.5rem;
	}

	.offline-message {
		font-size: 1rem;
	}
}

/* ==========================================================================
	Site Map Page
	========================================================================== */

.sitemap-container {
	max-width: 800px;
	margin: 0 auto;
	padding: 0 1rem 3rem;
}

.sitemap-header {
	text-align: center;
	margin-bottom: 2.5rem;
}

.sitemap-header-icon {
	margin-bottom: 1rem;
}

.sitemap-title {
	font-size: 2rem;
	font-weight: 700;
	color: var(--primary-color);
	margin-bottom: 0.5rem;
}

.sitemap-description {
	font-size: 1.125rem;
	color: var(--text-secondary);
	max-width: 480px;
	margin: 0 auto;
	line-height: 1.5;
}

.sitemap-sections {
	display: grid;
	gap: 1.5rem;
}

.sitemap-section {
	background: var(--background-primary);
	border: 1px solid var(--border-color);
	border-radius: 0.75rem;
	padding: 1.5rem;
	transition: box-shadow 0.2s ease;
}

.sitemap-section:hover {
	box-shadow: var(--shadow-sm);
}

.sitemap-section-title {
	font-size: 1.25rem;
	font-weight: 600;
	margin-bottom: 0.75rem;
	padding-bottom: 0.5rem;
	border-bottom: 2px solid var(--primary-color);
}

.sitemap-section-title a {
	color: var(--primary-color);
	text-decoration: none;
}

.sitemap-section-title a:hover {
	color: var(--secondary-color);
	text-decoration: underline;
	text-underline-offset: 2px;
}

.sitemap-links {
	padding-left: 1.25rem;
}

.sitemap-links li {
	margin-bottom: 0.5rem;
	line-height: 1.5;
}

.sitemap-links a {
	color: var(--text-primary);
	text-decoration: underline;
	text-underline-offset: 2px;
	text-decoration-color: var(--border-mid);
}

.sitemap-links a:hover {
	color: var(--primary-color);
	text-decoration-color: var(--primary-color);
}

.sitemap-empty {
	text-align: center;
	color: var(--text-secondary);
	font-size: 1.125rem;
	padding: 3rem 0;
}

@media (max-width: 600px) {
	.sitemap-title {
		font-size: 1.5rem;
	}

	.sitemap-section {
		padding: 1rem;
	}
}

/* ==========================================================================
	Terms of Use Page
	========================================================================== */

.terms-container {
	max-width: 760px;
	margin: 0 auto;
	padding: 0 1rem 3rem;
}

.terms-header {
	text-align: center;
	margin-bottom: 2.5rem;
	padding-bottom: 1.5rem;
	border-bottom: 2px solid var(--border-color);
}

.terms-header-icon {
	margin-bottom: 1rem;
}

.terms-title {
	font-size: 2rem;
	font-weight: 700;
	color: var(--primary-color);
	margin-bottom: 0.5rem;
}

.terms-last-updated {
	font-size: 0.9rem;
	color: var(--text-secondary);
}

.terms-content {
	line-height: 1.8;
	color: var(--text-primary);
	margin-bottom: 2.5rem;
}

.terms-content h2 {
	font-size: 1.375rem;
	font-weight: 600;
	color: var(--secondary-color);
	margin-top: 2rem;
	margin-bottom: 0.75rem;
	padding-bottom: 0.375rem;
	border-bottom: 1px solid var(--border-color);
}

.terms-content h3 {
	font-size: 1.125rem;
	font-weight: 600;
	color: var(--text-primary);
	margin-top: 1.5rem;
	margin-bottom: 0.5rem;
}

.terms-content p {
	margin-bottom: 1rem;
}

.terms-content ul,
.terms-content ol {
	margin-bottom: 1rem;
	padding-left: 1.5rem;
}

.terms-content li {
	margin-bottom: 0.375rem;
}

.terms-footer-nav {
	display: flex;
	justify-content: center;
	gap: 1rem;
	flex-wrap: wrap;
	padding-top: 2rem;
	border-top: 2px solid var(--border-color);
}

.terms-btn {
	display: inline-block;
	padding: 0.75rem 1.5rem;
	border-radius: 0.5rem;
	font-size: 1rem;
	font-weight: 600;
	text-decoration: none;
	background-color: var(--primary-color);
	color: var(--background-primary);
	transition: background-color 0.2s ease, transform 0.1s ease;
}

.terms-btn:hover {
	background-color: var(--secondary-color);
	color: var(--background-primary);
	transform: translateY(-1px);
}

.terms-btn-secondary {
	background-color: transparent;
	color: var(--primary-color);
	border: 2px solid var(--primary-color);
}

.terms-btn-secondary:hover {
	background-color: var(--primary-color);
	color: var(--background-primary);
}

@media (max-width: 600px) {
	.terms-title {
		font-size: 1.5rem;
	}

	.terms-footer-nav {
		flex-direction: column;
		align-items: center;
	}

	.terms-btn {
		width: 100%;
		max-width: 280px;
		text-align: center;
	}
}
