/*
Theme Name: Kerikeri Retirement Village
Theme URI:
Description: Child theme of GeneratePress for the Kerikeri Retirement Village website. Holds the accessible design system (WCAG-checked brand palette, warm serif identity, readable type scale for an older audience), component styles and template overrides.
Author: Sean McConnachie
Template: generatepress
Version: 0.18.2
Text Domain: kkrv-child
*/

/* =========================================================
   Self-hosted brand fonts (latin subset, preloaded in functions.php)
   ========================================================= */
@font-face {
	font-family: "Fraunces";
	font-style: normal;
	font-weight: 500 600;
	font-display: swap;
	src: url("assets/fonts/fraunces-latin.woff2") format("woff2");
}
@font-face {
	font-family: "Hanken Grotesk";
	font-style: normal;
	font-weight: 400 700;
	font-display: swap;
	src: url("assets/fonts/hanken-grotesk-latin.woff2") format("woff2");
}

/* =========================================================
   Design tokens — brand palette (WCAG-checked) + warm neutrals
   Contrast ratios below are MEASURED, not assumed, and each one names the surface
   it was measured against. "on paper" means --kkrv-paper #FAF7EF, the page colour
   — NOT white. The two are ~1.5% apart, so the old against-white figures read
   about half a point high; every ratio here was re-taken against paper on -zvj.9
   after the canvas moved (-zvj.3/-zvj.4). Re-take them again if the paper moves,
   and always write down the surface: a ratio with no surface gets trusted against
   whatever the reader assumes. Full tables live in docs/accessibility-audit.md.
   (docs/design-research/styling-plan.md is the original proposal, not current
   values: its warm-neutral hexes were never the ones that shipped, so do not
   read token values back out of it.)
   ========================================================= */
:root {
	/* Brand blues */
	--kkrv-blue: #002C57;         /* PRIMARY — text/UI/fills, 13.10:1 on paper (AAA)   */
	--kkrv-blue-dark: #001D3A;    /* hover / active / deep headings                    */
	--kkrv-blue-link: #002C57;    /* links — navy, underlined for affordance, 13.10:1 on paper */
	--kkrv-blue-accent: #7ECFFC;  /* LIGHT BLUE — large decorative / hero wash ONLY (fails text) */

	/* Warm neutrals — the warmth that de-sterilises the page.
	   The ramp only works while it steps DOWN in lightness without stepping UP in
	   chroma: paper L 97.6 / C .011 -> cream-soft L 96.1 / C .011 -> cream L 93.9 /
	   C .011 -> border L 88.4 / C .016 (oklch). Paper and cream-soft are level on
	   chroma and separated by lightness alone, which is as tight as it goes — a
	   warmer paper inverts the chroma order, so the page reads warmer than the tint
	   that is meant to be the warm one and the ramp reads backwards. That is why
	   paper is #FAF7EF and NOT #FAF6E9 (C .018, above cream-soft), which was the
	   first instinct on -zvj.4. Re-measure both if you touch either. */
	--kkrv-paper: #FAF7EF;        /* page background — warm off-white, oklch C .011      */
	--kkrv-cream: #EDEBE3;        /* primary warm section tint (client cream), C .011    */
	--kkrv-cream-soft: #F5F2EA;   /* lighter cream, C .011 — one step under paper        */
	--kkrv-card: #FFFFFF;         /* cards — pure white to lift off the warm page       */
	/* Cool light-blue tint. KEPT, but its brief shrank on -zvj.7: it is now a
	   BUTTON-HOVER tint only, never a section background. Measured oklch it is
	   L 96.1 / C .018 / H 240 — the same lightness as cream-soft but 60% more
	   chroma and ~150 degrees round the wheel from the warm ramp, so on #FAF7EF
	   paper a panel of it reads near-complementary, not merely "cooler". As a
	   large surface it would undo the epic this token was re-examined for. As
	   the 100-200px patch under a cursor on .kkrv-btn-ghost it reads as
	   "pressed", and it is what keeps the care-centre CTA cool where its homes
	   siblings hover sage (see .kkrv-tabs--homes ... --care below). Contrast is
	   fine either way: blue-dark on it is 15.2:1, ink 13.9:1, ink-soft 6.8:1.
	   Do not reintroduce a section band from it — use cream or green-tint. */
	--kkrv-bg-alt: #E8F4FD;       /* cool tint — .kkrv-btn-ghost:hover ONLY (see above) */

	/* Sage green — the new signature warm accent + brand grey */
	--kkrv-green: #AEBAA8;        /* light sage — section tints / large decorative only */
	--kkrv-green-deep: #4E6152;   /* accessible brand green — icons/indicators/accents, 6.22:1 on paper (6.65:1 on a white card) */
	--kkrv-green-deep-dark: #3D4C41; /* hover/active sibling of green-deep, 8.50:1 on paper (-00r.43) */
	--kkrv-green-tint: #E9EDE6;   /* very light sage — section background band          */
	/* Brand grey is 2.45:1 on paper — under AA at every text size and under the
	   3:1 of 1.4.11 as well. Borders and large decorative only; never text. */
	--kkrv-grey: #A89E99;         /* brand grey — 2.45:1 on paper, decorative only      */
	--kkrv-focus-light: #9FD8FB;  /* focus ring on DARK/navy surfaces (hero, footer)    */

	/* Text */
	--kkrv-ink: #1C2530;          /* body text, 14.46:1 on paper (AAA)                  */
	--kkrv-ink-soft: #57534E;     /* secondary text — warm grey, 7.13:1 on paper, 6.39:1 on cream */

	/* Borders */
	--kkrv-border: #DED8CD;       /* warm hairline (tint of brand grey)                 */
	--kkrv-border-cool: #CBD8E4;  /* cool hairline (blue context)                       */

	/* Accents */
	--kkrv-terracotta: var(--kkrv-green-deep); /* deprecated in navy+sage rebrand — alias kept for any legacy refs */
	--kkrv-focus: #B34700;        /* focus outline — warm, 5.14:1 on paper vs the 3:1 of 1.4.11 */

	/* Page context. Blue is the safe default; the semantic body class added in
	   functions.php switches these to sage on the six general-site pages. Keep
	   typography and structural chrome on the explicit blue tokens above. */
	--kkrv-page-accent: var(--kkrv-blue);
	--kkrv-page-accent-dark: var(--kkrv-blue-dark);
	--kkrv-page-accent-tint: var(--kkrv-bg-alt);
	--kkrv-page-band-accent: var(--kkrv-green);
	--kkrv-footer-bg: var(--kkrv-blue-dark);
	--kkrv-footer-action: var(--kkrv-blue);
	--kkrv-footer-action-hover: var(--kkrv-blue-dark);
	--kkrv-footer-link-hover: var(--kkrv-blue-accent);

	/* Shadows (soft depth instead of flat borders).
	   The shadow colour is --kkrv-ink's lightness and chroma with the hue rotated
	   out of the blues and into the warm-neutral family: oklch L .261 / C .024,
	   H 253.7 -> H 80, which sits beside border H 82.8 and paper H 89.7. Until
	   -zvj.6 these were --kkrv-ink itself, so every card, feature image and tab
	   panel cast a faintly blue shadow onto a warm page — fine while the paper was
	   near-white, wrong once -zvj.4 warmed it. Lightness is deliberately unchanged
	   (composited over paper the two differ by <0.003 relative luminance at every
	   alpha used), so the alphas still land at the depth they were tuned for. What
	   does change, measurably: over paper the old shadow dragged chroma DOWN, oklch
	   C .011 -> .0055 at alpha .24, so the deepest shadows greyed the warmth out of
	   the page they sat on; the warm one holds C ~.013 at hue ~87, i.e. in paper's
	   own family (H 89.7). Only the hue moves; move only the hue if you touch this
	   again. */
	--kkrv-shadow-sm: 0 1px 3px rgba(42, 35, 23, .06), 0 2px 8px rgba(42, 35, 23, .05);
	--kkrv-shadow-md: 0 6px 20px rgba(42, 35, 23, .12);

	/* Type */
	--kkrv-fs-base: 1.125rem;     /* 18px — minimum body for readability                */
	--kkrv-lh-base: 1.7;
	--kkrv-font-head: "Fraunces", "Iowan Old Style", Georgia, "Times New Roman", serif;
	--kkrv-font-body: "Hanken Grotesk", "Segoe UI", system-ui, -apple-system, Roboto, "Helvetica Neue", Arial, sans-serif;

	/* Sizing */
	--kkrv-tap-min: 48px;         /* touch target — comfortable for 65+ (WCAG 2.5.5 is 44) */
	--kkrv-radius: 14px;
	--kkrv-radius-sm: 8px;
	--kkrv-btn-radius: 999px;
	--kkrv-space-section: clamp(3rem, 7vw, 5.5rem);

	/* Light-only site (00r.27): keep the light brand palette even when the OS is
	   in dark mode. Visitors who want dark use the Dark Reader extension, which
	   inverts this light page cleanly (a site-authored dark theme would fight it).
	   'light' also keeps native form controls, scrollbars and UA chrome light. */
	color-scheme: light;
}

/* =========================================================
   Base — readable defaults for an older audience
   ========================================================= */
body {
	font-family: var(--kkrv-font-body);
	font-size: var(--kkrv-fs-base);
	line-height: var(--kkrv-lh-base);
	color: var(--kkrv-ink);
	background: var(--kkrv-paper);
}

body.kkrv-scheme-sage {
	--kkrv-page-accent: var(--kkrv-green-deep);
	--kkrv-page-accent-dark: var(--kkrv-green-deep-dark);
	--kkrv-page-accent-tint: var(--kkrv-green-tint);
	/* Light sage is only 3.29:1 on deep sage. Cream is 5.58:1 and is safe for
	   both decorative rules and small eyebrow text inside the inverse bands. */
	--kkrv-page-band-accent: var(--kkrv-cream);
	--kkrv-footer-bg: var(--kkrv-green-deep);
	--kkrv-footer-action: var(--kkrv-green-deep);
	--kkrv-footer-action-hover: var(--kkrv-green-deep-dark);
	--kkrv-footer-link-hover: var(--kkrv-cream);
}

/* Keep the paper showing through GeneratePress's page containers.
   GP's generated global CSS paints every "separate containers" surface with
   --base-3, which is stock #FFFFFF and lives in the database (customizer global
   colours), not in this repo:
       .separate-containers .inside-article, … { background-color: var(--base-3) }
   The body above is already warm, so the result was a pure-white sheet laid over
   the paper on every inner page — only the home page escaped, via the
   `.home .inside-article` rule further down. Repointing --base-3 itself would put
   the fix in the database, outside version control and outside the provision
   path, so it is countered here instead where the rest of the design lives.
   This is deliberate, not a stray override: delete it and the white comes
   straight back on every inner page (-zvj.3).
   Nothing to cancel besides the colour — GeneratePress free draws no box-shadow
   on .inside-article, so removing the white leaves no floating card outline. */
.separate-containers .inside-article,
.separate-containers .page-header,
.separate-containers .comments-area,
.separate-containers .paging-navigation,
.inside-page-header {
	background-color: var(--kkrv-paper);
}

.entry-content p,
.site-content p,
.site-content li {
	font-size: var(--kkrv-fs-base);
	line-height: var(--kkrv-lh-base);
}

/* Limit line length for comfortable reading */
.entry-content > p,
.entry-content > ul,
.entry-content > ol {
	max-width: 65ch;
}

/* Headings — warm serif in brand blue */
h1, h2, h3, h4, h5, h6 {
	font-family: var(--kkrv-font-head);
	color: var(--kkrv-blue);
	line-height: 1.2;
	font-weight: 600;
	letter-spacing: -0.01em;
}
h1 { font-size: clamp(2.25rem, 5vw, 3.5rem); line-height: 1.1; }
h2 { font-size: clamp(1.75rem, 3.2vw, 2.4rem); }
h3 { font-size: clamp(1.3rem, 2vw, 1.55rem); }
h4 { font-size: clamp(1.15rem, 1.6vw, 1.3rem); }

/* Links — always visible and underlined for clarity */
a {
	color: var(--kkrv-page-accent);
	text-underline-offset: 0.15em;
}
a:hover,
a:focus { color: var(--kkrv-page-accent-dark); }

/* =========================================================
   Accessibility — focus, targets, motion
   ========================================================= */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
	outline: 3px solid var(--kkrv-focus);
	outline-offset: 2px;
	border-radius: 2px;
}

.skip-link:focus,
a.screen-reader-text:focus {
	background: var(--kkrv-blue);
	color: #fff;
	padding: 0.75em 1em;
	z-index: 100000;
}

/* On dark/navy surfaces the warm focus ring fails contrast — use a light ring there */
.kkrv-hero__cta a:focus-visible,
.kkrv-cta-band a:focus-visible,
.kkrv-subbar a:focus-visible,
.kkrv-footer-contact a:focus-visible,
.site-info a:focus-visible {
	outline-color: var(--kkrv-focus-light);
}

/* Respect users who prefer reduced motion */
@media (prefers-reduced-motion: reduce) {
	*, *::before, *::after {
		animation-duration: 0.001ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.001ms !important;
		scroll-behavior: auto !important;
	}
	.kkrv-card:hover { transform: none !important; }
	.kkrv-path-card:hover { transform: none !important; }
	.kkrv-path-card:hover .kkrv-path-card__arrow { transform: none !important; }
}

/* =========================================================
   In-page anchor scrolling (nav submenus link to section headings).
   Reduced-motion users get an instant jump via the rule above.
   ========================================================= */
html { scroll-behavior: smooth; }
/* Full-bleed sections (e.g. the hero) use 100vw, which includes the vertical
   scrollbar and so overflows the content area by the scrollbar width at narrow
   widths — an 8px horizontal scroll at 320px (WCAG 1.4.10 reflow). Contain it at
   the root; no sticky elements depend on the root scroll context. */
html { overflow-x: hidden; }
:target { scroll-margin-top: 2rem; }
.kkrv-tabs { scroll-margin-top: 2rem; margin-bottom: clamp(2.25rem, 5vw, 3.25rem); }

/* =========================================================
   Buttons — big, obvious, pill-shaped
   ========================================================= */
.wp-block-button__link,
button:not(.is-style-link):not(.menu-toggle),
input[type="submit"],
.button {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: var(--kkrv-tap-min);
	padding: 0.7em 1.6em;
	background-color: var(--kkrv-page-accent);
	color: #fff;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	line-height: 1.3;
	border: 2px solid transparent;
	border-radius: var(--kkrv-btn-radius);
	text-decoration: none;
	box-shadow: var(--kkrv-shadow-sm);
	transition: background-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
.wp-block-button__link:hover,
.wp-block-button__link:focus,
button:not(.is-style-link):not(.menu-toggle):hover,
input[type="submit"]:hover,
.button:hover {
	background-color: var(--kkrv-page-accent-dark);
	color: #fff;
	transform: translateY(-2px);
	box-shadow: var(--kkrv-shadow-md);
}

/* Secondary / outline button */
.wp-block-button.is-style-outline .wp-block-button__link {
	background: transparent;
	color: var(--kkrv-page-accent);
	border-color: var(--kkrv-page-accent);
	box-shadow: none;
}
.wp-block-button.is-style-outline .wp-block-button__link:hover {
	background: var(--kkrv-page-accent);
	color: #fff;
}

/* Form fields — large, clear, high-contrast borders */
input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]),
select,
textarea {
	min-height: var(--kkrv-tap-min);
	font-size: var(--kkrv-fs-base);
	border: 2px solid var(--kkrv-border-cool);
	border-radius: var(--kkrv-radius-sm);
	padding: 0.5em 0.7em;
	/* A field is a surface lifted off the page, the same job a card does, so it
	   tracks the card token — otherwise the enquiry form ends up the one
	   clinical patch on a warm page (-zvj.5). */
	background: var(--kkrv-card);
}
input:focus,
select:focus,
textarea:focus { border-color: var(--kkrv-page-accent); }

/* WPForms' modern skin loads after the theme and restates its one-pixel field
   border. Match the plugin wrapper and keep the scheme focus cue visible. */
div.wpforms-container-full input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):focus,
div.wpforms-container-full select:focus,
div.wpforms-container-full textarea:focus {
	border-color: var(--kkrv-page-accent) !important;
	box-shadow: 0 0 0 2px var(--kkrv-page-accent) !important;
}
div.wpforms-container-full input:not([type="submit"]):not([type="checkbox"]):not([type="radio"]):focus-visible,
div.wpforms-container-full select:focus-visible,
div.wpforms-container-full textarea:focus-visible {
	outline: 3px solid var(--kkrv-focus) !important;
	outline-offset: 3px !important;
}
/* The modern skin also restates `outline: none` on its submit button after the
   theme's global focus rule. Match that late selector so keyboard users keep
   the same visible focus cue from the first field through submission. */
div.wpforms-container-full button.wpforms-submit:focus-visible {
	outline: 3px solid var(--kkrv-focus) !important;
	outline-offset: 3px !important;
}

label { font-weight: 600; }

/* WPForms (modern markup) submit button — retheme to the page accent via the
   plugin's own CSS variables. !important beats WPForms' per-form inline vars. */
.wpforms-container {
	--wpforms-button-background-color: var(--kkrv-page-accent) !important;
	--wpforms-button-background-color-hover: var(--kkrv-page-accent-dark) !important;
	--wpforms-button-text-color: #ffffff !important;
	--wpforms-button-text-color-hover: #ffffff !important;
	--wpforms-button-border-radius: 999px !important;
}
.wpforms-container button.wpforms-submit {
	min-height: var(--kkrv-tap-min);
	font-weight: 700;
	box-shadow: var(--kkrv-shadow-sm);
	transition: background-color .2s ease, transform .2s ease, box-shadow .2s ease;
}
/* WPForms sizes fields from its own --wpforms-field-size-input-height (43px),
   and its reset `div.wpforms-container-full *` ties the theme's blanket
   `select { min-height }` on specificity while loading later, so the theme rule
   loses. Every text input still landed on the 48px tap target because WPForms
   styles those separately — leaving the enquiry dropdown the single control in
   the form under the size this site sets for a 65+ audience, and a dropdown is
   the fiddliest thing on the page to hit accurately.
   Set WPForms' own token rather than fight the cascade, the same approach the
   button retheme above takes. */
.wpforms-container {
	--wpforms-field-size-input-height: var(--kkrv-tap-min) !important;
}
.wpforms-container button.wpforms-submit:hover {
	background-color: var(--kkrv-page-accent-dark) !important;
	border-color: var(--kkrv-page-accent-dark) !important;
	transform: translateY(-2px);
	box-shadow: var(--kkrv-shadow-md);
}

/* =========================================================
   Header — brand identity + tagline
   ========================================================= */
.site-header {
	background: var(--kkrv-paper);
	border-bottom: 1px solid var(--kkrv-border);
}
.site-branding .main-title {
	margin: 0;
	line-height: 1.1;
}
.main-title a {
	font-family: var(--kkrv-font-head);
	font-weight: 600;
	font-size: clamp(1.35rem, 2.4vw, 1.95rem);
	color: var(--kkrv-blue);
	text-decoration: none;
	letter-spacing: -0.01em;
}
/* Brand lockup — icon mark + site name & tagline as text */
.main-title.kkrv-brand { margin: 0; line-height: 1.1; }
.kkrv-brand__link {
	display: inline-flex;
	align-items: center;
	gap: 0.7rem;
	text-decoration: none;
}
.kkrv-brand__mark {
	height: clamp(46px, 5vw, 60px);
	width: auto;
	flex: none;
}
.kkrv-brand__text {
	display: flex;
	flex-direction: column;
	line-height: 1.12;
}
.kkrv-brand__name {
	font-family: var(--kkrv-font-head);
	font-weight: 600;
	font-size: clamp(1.25rem, 2.1vw, 1.8rem);
	color: var(--kkrv-blue);
	letter-spacing: -0.01em;
}
.kkrv-brand__tag {
	font-family: var(--kkrv-font-head);
	font-style: italic;
	font-weight: 500;
	font-size: clamp(0.85rem, 1.1vw, 1.02rem);
	color: var(--kkrv-blue-link);
	margin-top: 0.12rem;
}

.kkrv-tagline,
.site-description {
	margin: 0.15rem 0 0;
	font-family: var(--kkrv-font-head);
	font-style: italic;
	font-weight: 500;
	font-size: 1.05rem;
	color: var(--kkrv-blue-link);
}

/* =========================================================
   Navigation — light bar, page-aware links, animated underline
   ========================================================= */
/* The bar sits directly beneath .site-header, which is --kkrv-paper, so a
   literal white here drew a hairline seam across the top of every page — a
   seam already, and worse once the canvas warmed (-zvj.5). Both surfaces read
   the same token now; move the header and the bar follows. */
.main-navigation,
.main-navigation.sub-menu-right {
	background: var(--kkrv-paper);
	border-bottom: 1px solid var(--kkrv-border);
}
.main-navigation .main-nav ul li a {
	color: var(--kkrv-blue-dark);
	font-weight: 600;
	min-height: var(--kkrv-tap-min);
	/* Tighter than GeneratePress's 20px default so the longer item labels
	   (Independent Living / Quality Care and Support) still fit on one row. */
	padding-inline: 14px;
	display: flex;
	align-items: center;
	box-shadow: inset 0 0 0 var(--kkrv-blue);
	transition: box-shadow .18s ease, color .18s ease;
}
.main-navigation .main-nav ul li a:hover,
.main-navigation .main-nav ul li a:focus {
	color: var(--kkrv-page-accent);
	box-shadow: inset 0 -3px 0 var(--kkrv-page-accent);
}
.main-navigation .main-nav ul li.current-menu-item > a {
	color: var(--kkrv-page-accent);
	box-shadow: inset 0 -3px 0 var(--kkrv-page-accent);
}
/* GeneratePress prints its navigation colours in a late inline block. The body
   prefix gives these state rules enough specificity to keep the page scheme. */
body .main-navigation .main-nav ul li:not([class*="current-menu-"]):hover > a,
body .main-navigation .main-nav ul li:not([class*="current-menu-"]):focus > a,
body .main-navigation .main-nav ul li.sfHover:not([class*="current-menu-"]) > a,
body .main-navigation .main-nav ul li[class*="current-menu-"] > a {
	color: var(--kkrv-page-accent);
}

/* Push the phone + CTA to the far right of the bar */
.main-navigation .main-nav ul li.kkrv-phone { margin-left: auto; }
.main-navigation .menu-item.kkrv-phone > a {
	font-weight: 700;
	color: var(--kkrv-page-accent);
	box-shadow: none;
}
.main-navigation .menu-item.kkrv-phone > a:hover { box-shadow: none; color: var(--kkrv-page-accent-dark); }
.main-navigation .menu-item.kkrv-cta > a {
	background: var(--kkrv-page-accent);
	color: #fff;
	font-weight: 700;
	border-radius: var(--kkrv-btn-radius);
	margin: 0.4em 0 0.4em 0.5em;
	padding-inline: 1.3em;
	box-shadow: var(--kkrv-shadow-sm);
}
.main-navigation .menu-item.kkrv-cta > a:hover {
	background: var(--kkrv-page-accent-dark);
	color: #fff;
	box-shadow: inset 0 0 0 99px var(--kkrv-page-accent-dark);
}
body .main-navigation .main-nav .menu-item.kkrv-cta > a:hover,
body .main-navigation .main-nav .menu-item.kkrv-cta > a:focus { color: #fff; }

/* --- Dropdown submenus (each item links to a section on the parent's page) --- */
/* GeneratePress injects its own arrow toggle on parents; its default padding
   (0 20px 0 10px = 45px wide) is too greedy for our contained 1200px bar, so
   tighten it right down while keeping the arrow as the "more underneath" cue. */
.main-navigation .main-nav ul li.menu-item-has-children > a .dropdown-menu-toggle {
	padding-left: 5px;
	padding-right: 4px;
}
.main-navigation .main-nav ul ul.sub-menu {
	/* Paper, not white: the panel hangs off the bar above and a literal here put
	   the same seam back one level down. Its border and shadow do the lifting,
	   so it still reads as a floating panel over the page (-zvj.5). */
	background: var(--kkrv-paper);
	border: 1px solid var(--kkrv-border);
	border-top: 3px solid var(--kkrv-page-accent);
	border-radius: 0 0 var(--kkrv-radius-sm) var(--kkrv-radius-sm);
	box-shadow: var(--kkrv-shadow-md);
	padding: 0.3rem 0;
	width: max-content;
	min-width: 220px;
	max-width: 300px;
}
.main-navigation .main-nav ul ul.sub-menu li a {
	min-height: 0;
	padding: 0.6rem 1.15rem;
	font-weight: 600;
	color: var(--kkrv-blue-dark);
	white-space: normal;
	box-shadow: none;
	border-left: 3px solid transparent;
}
.main-navigation .main-nav ul ul.sub-menu li a:hover,
.main-navigation .main-nav ul ul.sub-menu li a:focus {
	background: var(--kkrv-green-tint);
	color: var(--kkrv-page-accent);
	box-shadow: none;
	border-left-color: var(--kkrv-page-accent);
}
/* Keep the CTA pill legible (white text) when the contact page is current */
.main-navigation .main-nav ul li.kkrv-cta.current-menu-item > a {
	color: #fff;
	box-shadow: var(--kkrv-shadow-sm);
}

/* Mobile toggle — clear and on-brand */
.menu-toggle,
.main-navigation .menu-toggle {
	color: var(--kkrv-page-accent);
	font-family: var(--kkrv-font-body);
	font-weight: 600;
}

/* =========================================================
   Sections — rhythm & warm tint bands
   ========================================================= */
.kkrv-section {
	padding-block: var(--kkrv-space-section);
}
.kkrv-section--cream { background: var(--kkrv-cream); }
.kkrv-section--paper { background: var(--kkrv-paper); }
/* No cool band class here on purpose (-zvj.7). .kkrv-section--blue-tint and the
   legacy .kkrv-section-alt both painted --kkrv-bg-alt and were never applied to a
   single section in the repo's whole history — no page HTML, no theme template, no
   mu-plugin, in any commit. They were the "care / clinical sections" the token
   comment promised and that markup never asked for; the bands that actually ship
   are kkrv-band-navy, kkrv-band-navy--sage and kkrv-band-green. Removed rather
   than rewarmed, so nobody reaches for a near-complementary cold panel on warm
   paper. A care section that wants to feel clinical should use navy, which is on
   the brand's own axis. */

/* =========================================================
   Hero — full-bleed photographic
   ========================================================= */
.kkrv-hero {
	position: relative;
	display: flex;
	align-items: center;
	/* full-bleed: break out of the constrained content container */
	width: 100vw;
	max-width: 100vw;
	left: 50%;
	right: 50%;
	margin-left: -50vw;
	margin-right: -50vw;
	min-height: clamp(420px, 60vh, 600px);
	padding: clamp(2rem, 6vw, 4.5rem) clamp(1.5rem, 6vw, 4rem);
	color: #fff;
	background-color: var(--kkrv-page-accent-dark);
	background-position: center 35%;
	background-size: cover;
	background-repeat: no-repeat;
}
/* --kkrv-hero-photo is declared once per hero and read twice: by the full-bleed
   background here, and by the mobile photo band in the --paths block at the
   foot of this file. Naming the file in one place is what stops the two from
   drifting when a photo is swapped (as the home hero was on 2026-07-27). */
.kkrv-hero--home {
	--kkrv-hero-photo: url("assets/images/home/header.webp");
	background-image:
		linear-gradient(90deg, rgba(0, 42, 84, .82) 0%, rgba(0, 42, 84, .55) 45%, rgba(0, 42, 84, .12) 100%),
		var(--kkrv-hero-photo);
	/* Photo replaced 2026-09-03: residents sharing a meal on an apartment
	   balcony. The group sits through the centre and right, clear of most of the
	   copy in the left third. Each real photo below gets its own vertical
	   framing for the same reason: these bands crop a 3:2 photo hard, so the
	   subject has to be aimed at deliberately. */
	background-position: center 72%;
}
.kkrv-hero__inner {
	max-width: 1100px;
	margin-inline: auto;
	width: 100%;
}
.kkrv-hero__content { max-width: 34rem; }
.kkrv-hero h1 {
	color: #fff;
	margin: 0 0 0.6rem;
	text-shadow: 0 1px 3px rgba(0, 0, 0, .35);
}
.kkrv-hero__sub {
	font-size: clamp(1.15rem, 1.7vw, 1.35rem);
	line-height: 1.5;
	color: #fff;
	max-width: 42ch;
	margin: 0 0 1.5rem;
	text-shadow: 0 1px 3px rgba(0, 0, 0, .35);
}
.kkrv-hero__cta {
	display: flex;
	flex-wrap: wrap;
	gap: 0.85rem;
}
.kkrv-hero__cta .wp-block-button__link,
.kkrv-hero__cta a.kkrv-btn {
	background: #fff;
	color: var(--kkrv-page-accent);
}
.kkrv-hero__cta .wp-block-button__link:hover { background: var(--kkrv-cream); color: var(--kkrv-page-accent-dark); }
.kkrv-hero__cta .is-style-outline .wp-block-button__link,
.kkrv-hero__cta a.kkrv-btn-ghost {
	background: transparent;
	color: #fff;
	border-color: #fff;
}
.kkrv-hero__cta a.kkrv-btn-ghost:hover { background: #fff; color: var(--kkrv-page-accent); }

/* Slim wayfinding / action bar beneath the hero */
.kkrv-subbar {
	background: var(--kkrv-page-accent);
	color: #fff;
}
.kkrv-subbar__inner {
	max-width: 1100px;
	margin-inline: auto;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem 1.5rem;
	padding: 0.6rem 1.25rem;
}
.kkrv-subbar a { color: #fff; font-weight: 600; }
.kkrv-subbar__links { display: flex; flex-wrap: wrap; gap: 0.25rem 1.5rem; }

/* =========================================================
   Front page — drop GeneratePress's article "card" (white bg + 40px padding +
   shadow) so the full-bleed hero and bands sit flush on the warm page
   background, with no white strips / boxes poking through around the hero.
   Inner pages keep the card for comfortable reading.
   ========================================================= */
.home .site-main { margin-top: 0; }
.home .inside-article {
	padding-top: 0;
	padding-bottom: 0;
	background: transparent;
	box-shadow: none;
}

/* =========================================================
   Lead paragraph
   ========================================================= */
/* The one place the warm serif is allowed out of the headings (-zvj.8). Warmth
   on this site has to come from type and photography rather than more colour,
   and a lead in Fraunces changes the texture of a page in a way a background
   tint cannot. Deliberately scoped to .kkrv-lead only — Sean's call over also
   taking the hero decks, which sit over photographs at ~20px where a
   high-contrast serif is the legibility risk we cannot take with a 65+
   audience. Body copy stays in Hanken Grotesk.

   Fraunces is self-hosted as a weight-only variable font (see @font-face at the
   top of this file), so: no italic face — anything asking for italic here gets
   a synthesised oblique — and the declared 500-600 range clamps any lighter
   request up to 500. The weight is therefore stated, not inherited. */
.kkrv-lead {
	font-family: var(--kkrv-font-head);
	font-weight: 500;
	font-size: clamp(1.2rem, 1.7vw, 1.375rem);
	line-height: 1.6;
	/* 39ch, not the 46ch this was while it was set in the sans. `ch` is the
	   width of a zero, and Fraunces draws a wide zero against a narrow
	   lowercase, so the same 46ch grew the rendered measure from 494px to
	   585px — a materially longer line for a reader who is 75. 39ch of
	   Fraunces measures back to ~496px, i.e. the line length is unchanged and
	   only the letterforms are. Re-measure this number if the face changes. */
	max-width: 39ch;
}
/* Reversed out of navy, a serif at lead size reads thinner than the same face
   does on paper — the "Life at the village" lead on the homepage is the one
   instance. Half a step of weight puts it back where the light-background
   leads are; it is not a colour change. */
.kkrv-band-navy .kkrv-lead,
.kkrv-band-green .kkrv-lead { font-weight: 550; }

/* =========================================================
   Cards & wayfinding tiles
   ========================================================= */
.kkrv-card,
.kkrv-tiles .wp-block-column {
	background: var(--kkrv-card);
	border: 1px solid var(--kkrv-border);
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	padding: 1.75rem;
	transition: transform .2s ease, box-shadow .2s ease;
}
.kkrv-card:hover,
.kkrv-tiles .wp-block-column:hover {
	transform: translateY(-3px);
	box-shadow: var(--kkrv-shadow-md);
}
.kkrv-tiles.wp-block-columns { gap: 1.5rem; }
.kkrv-tiles h3 { margin-top: 0; }
/* A boxed component's padding is its spacing — the last child's own
   margin-bottom otherwise stacks inside it and fattens the bottom edge
   (the same defect the navy bands had). */
.kkrv-tiles .wp-block-column > :last-child,
.kkrv-news__events > :last-child { margin-bottom: 0; }
.kkrv-tiles h3 a { text-decoration: none; }
.kkrv-tiles h3 a:hover { text-decoration: underline; }

/* EVERY GRID TRACK IN THIS FILE IS SPELLED minmax(0, ...), NEVER A BARE 1fr.
   This is the one CSS rule on the site that has caused the same visible bug
   three times, so it is written down once, here, at the first grid.

   A bare `1fr` means `minmax(auto, 1fr)`. That `auto` minimum is the item's
   min-content size, and a grid track will NOT shrink below it — so any item
   holding something that cannot get narrower (a third-party iframe with an
   inline width, a long word at large text zoom, a fixed-size media element)
   pushes its track wider than the container and the whole page scrolls
   sideways. `max-width: 100%` further down cannot rescue it: those percentages
   resolve against a parent that is itself already blown out, so the chain
   settles wide and agrees with itself.

   It bites on PHONES and at TEXT ZOOM, never on the developer's screen, and it
   bit at -bne (Village News, the Facebook embed) and -41s (path cards and
   facility cards at 200% zoom). In both cases the desktop track was written
   correctly and a narrow-viewport media query overrode it with a bare 1fr.
   If you add a grid or a breakpoint, carry the minmax(0, ...) into it too. */

/* Alternating photo + text feature rows */
.kkrv-feature {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
	gap: clamp(1.5rem, 4vw, 3rem);
	align-items: center;
}
.kkrv-feature__media img {
	width: 100%;
	height: 100%;
	max-height: 420px;
	object-fit: cover;
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
}
.kkrv-feature--flip .kkrv-feature__media { order: 2; }

/* Team group photo — sixty-odd faces, so it runs the full content width rather
   than sharing a two-column row, where everyone would be thumbnail-sized. */
.kkrv-team-photo { margin-block: 1.5rem; }
.kkrv-team-photo img {
	width: 100%;
	height: auto;
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
}
@media (max-width: 768px) {
	.kkrv-feature { grid-template-columns: minmax(0, 1fr); }
	.kkrv-feature--flip .kkrv-feature__media { order: 0; }
}

/* =========================================================
   Location map — responsive, lazy iframe
   ========================================================= */
.kkrv-map {
	position: relative;
	aspect-ratio: 16 / 10;
	max-width: 900px;
	margin-block: 1rem;
	border: 1px solid var(--kkrv-border);
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	background: var(--kkrv-cream);
	overflow: hidden;
}
.kkrv-map iframe {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	border: 0;
}

/* =========================================================
   Facebook — footer link + click-to-load page-feed facade
   ========================================================= */
.kkrv-footer-contact__social { width: 100%; margin: 0.2rem 0 0; }
.kkrv-footer-contact__social a {
	display: inline-flex;
	align-items: center;
	gap: 0.5rem;
	color: #fff;
	font-weight: 600;
	text-decoration: none;
}
.kkrv-footer-contact__social a:hover { color: var(--kkrv-footer-link-hover); text-decoration: underline; }
.kkrv-footer-contact__social svg { flex: none; }

.kkrv-fb { max-width: 500px; margin: 1.75rem auto; text-align: center; }
.kkrv-fb h2,
.kkrv-fb h3 { margin: 0 0 0.9rem; }
/* These panel headings became h2 for heading-order (they sit directly under
   the page h1). They are section labels beside a feed, not page-level
   headings, so they keep the h3 type scale — the level is about document
   structure, the size is about visual hierarchy, and the two need not match. */
.kkrv-fb h2,
.kkrv-news__events h2 { font-size: clamp(1.3rem, 2vw, 1.55rem); }
.kkrv-fb__alt { margin: 0.9rem 0 0; font-size: 0.95rem; }
.kkrv-fb .fb-page { display: inline-block; max-width: 100%; }
.kkrv-fb .fb-page span,
.kkrv-fb .fb-page iframe { max-width: 100%; }

/* =========================================================
   Virtual tour (Pannellum, lazy-loaded on demand)
   ========================================================= */
.kkrv-tour { margin: 1.75rem 0; }
.kkrv-tour__intro { color: var(--kkrv-ink-soft); max-width: 62ch; }
#virtual-tour { scroll-margin-top: 6rem; }

/* One unified card: viewer on top, controls beneath — no detached button rows. */
.kkrv-tour__card {
	background: var(--kkrv-paper);
	border: 1px solid var(--kkrv-border);
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	overflow: hidden;
}

.kkrv-tour__stage { position: relative; }
.kkrv-tour__viewer {
	width: 100%;
	aspect-ratio: 16 / 9;
	min-height: 320px;
	background: #0b1016;
}
.kkrv-tour__viewer:focus-visible { outline: 3px solid var(--kkrv-focus); outline-offset: -3px; }

/* Loading / data-saver poster over the viewer until the first scene is ready. */
.kkrv-tour__poster {
	position: absolute;
	inset: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 1rem;
	padding: 1.5rem;
	text-align: center;
	background-color: #0b1016;
	background-size: cover;
	background-position: center;
}
.kkrv-tour__poster::before {
	content: "";
	position: absolute;
	inset: 0;
	background: rgba(11, 16, 22, 0.55);
}
.kkrv-tour__poster[hidden] { display: none; }
.kkrv-tour__poster-msg {
	position: relative;
	color: #fff;
	font-family: var(--kkrv-font-head);
	font-size: 1.15rem;
	letter-spacing: 0.01em;
}
.kkrv-tour__load-btn {
	position: relative;
	min-height: var(--kkrv-tap-min);
	padding: 0.6em 1.4em;
	border: 0;
	border-radius: var(--kkrv-btn-radius);
	background: var(--kkrv-page-accent);
	color: #fff;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	cursor: pointer;
}
.kkrv-tour__load-btn:hover { background: var(--kkrv-page-accent-dark); }

/* Controls: look-around first (right under the view it steers, so it's easy
   to find on mobile), then area tabs, then the open area's photo strip. */
.kkrv-tour__controls {
	display: grid;
	gap: 1rem;
	padding: 1rem;
}
/* Grid items default to min-width:auto, which would let the scene strip's
   intrinsic width blow the card out sideways instead of scrolling in place. */
.kkrv-tour__controls > * { min-width: 0; }

/* Area tabs — one per group of scenes (Community Centre, Apartments, …). */
.kkrv-tour__areas {
	display: flex;
	flex-wrap: wrap;
	gap: 0.5rem;
}
/* .kkrv-tour prefix + tag out-specifies the global button rule. */
.kkrv-tour .kkrv-tour__areas button {
	min-height: var(--kkrv-tap-min);
	padding: 0.45em 1.1em;
	border: 2px solid var(--kkrv-page-accent);
	border-radius: var(--kkrv-btn-radius);
	/* These pills sit on .kkrv-tour__card, which is --kkrv-paper, so they are a
	   card surface on the page and not white-on-photo like the hot-spots below
	   — token them so the whole widget warms together (-zvj.5). */
	background: var(--kkrv-card);
	box-shadow: none;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	color: var(--kkrv-page-accent);
	cursor: pointer;
	transition: background-color .18s ease, color .18s ease;
}
.kkrv-tour .kkrv-tour__areas button:hover {
	background: var(--kkrv-page-accent-tint);
	color: var(--kkrv-page-accent-dark);
	box-shadow: none;
	transform: none;
}
.kkrv-tour .kkrv-tour__areas button.is-current,
.kkrv-tour .kkrv-tour__areas button.is-current:hover {
	background: var(--kkrv-page-accent);
	color: #fff;
}

/* Sub-heading inside an area (the two apartment types). */
.kkrv-tour__subhead {
	margin: 0.35rem 0;
	font-weight: 700;
	font-size: 0.95rem;
	color: var(--kkrv-ink-soft);
}
.kkrv-tour__subhead + .kkrv-tour__rooms { margin-bottom: 0.5rem; }

/* Room strip — recognisable photo tiles; scrolls horizontally when an area
   has more scenes than fit (Cottages has seven). */
.kkrv-tour__rooms {
	display: grid;
	grid-auto-flow: column;
	grid-auto-columns: minmax(140px, 1fr);
	gap: 0.6rem;
	overflow-x: auto;
	scroll-snap-type: x proximity;
	scrollbar-width: thin;
	padding-bottom: 0.25rem;
}
@media (max-width: 640px) {
	.kkrv-tour__rooms { grid-auto-columns: 44%; }
}
/* .kkrv-tour prefix out-specifies the global button rule. */
.kkrv-tour .kkrv-tour__rooms button {
	scroll-snap-align: start;
	display: flex;
	flex-direction: column;
	gap: 0.4rem;
	padding: 0 0 0.2rem;
	border: 2px solid transparent;
	border-radius: var(--kkrv-radius);
	background: none;
	box-shadow: none;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	color: var(--kkrv-page-accent);
	cursor: pointer;
	transition: border-color .18s ease, color .18s ease;
}
.kkrv-tour .kkrv-tour__rooms button img {
	display: block;
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: calc(var(--kkrv-radius) - 2px);
	background: var(--kkrv-cream);
}
.kkrv-tour .kkrv-tour__rooms button span { padding: 0 0.35rem 0.35rem; }
/* Set BOTH background and colour so the global button:hover (accent bg + white
   text) can't leak in and make the label illegible. */
.kkrv-tour .kkrv-tour__rooms button:hover {
	background: none;
	color: var(--kkrv-page-accent-dark);
	box-shadow: none;
	transform: none;
}
.kkrv-tour .kkrv-tour__rooms button:hover img { filter: brightness(0.94); }
.kkrv-tour .kkrv-tour__rooms button.is-current {
	border-color: var(--kkrv-page-accent);
	color: var(--kkrv-page-accent-dark);
}
/* Non-colour cue for the current room (doesn't rely on the ring alone). */
.kkrv-tour .kkrv-tour__rooms button.is-current span::after { content: " ✓"; }

/* Look-around — a labelled inline group directly below the viewer; the rule
   under it separates it from the place picker. */
.kkrv-tour__look {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: 0.5rem 0.6rem;
	border-bottom: 1px solid var(--kkrv-border);
	padding-bottom: 1rem;
}
.kkrv-tour__look-label { font-weight: 700; color: var(--kkrv-ink-soft); }
.kkrv-tour__poi { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.kkrv-tour .kkrv-tour__poi button {
	min-height: var(--kkrv-tap-min);
	padding: 0.45em 1em;
	border: 2px solid var(--kkrv-green-deep);
	border-radius: var(--kkrv-btn-radius);
	background: var(--kkrv-card);
	box-shadow: none;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	color: var(--kkrv-green-deep);
	cursor: pointer;
	transition: background-color .18s ease;
}
.kkrv-tour .kkrv-tour__poi button:hover {
	background: var(--kkrv-green-tint);
	color: var(--kkrv-green-deep);
	box-shadow: none;
	transform: none;
}

/* On-panorama "walk to" hot-spots. Pannellum renders custom-class hot-spots
   with no visual of its own, so this IS the marker: a tap-friendly white disc
   with a page-accent arrow. Pannellum shows each spot's "Go to …" text on hover. */
.kkrv-tour__hotspot {
	width: 44px;
	height: 44px;
	border-radius: 50%;
	background-color: rgba(255, 255, 255, 0.92);
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4l7 7h-4v9h-6v-9H5z' fill='%23002C57'/%3E%3C/svg%3E");
	background-repeat: no-repeat;
	background-position: center;
	background-size: 22px 22px;
	border: 3px solid var(--kkrv-page-accent);
	box-shadow: 0 2px 8px rgba(11, 16, 22, 0.4);
	cursor: pointer;
	/* No transform styling here: Pannellum positions each hot-spot with an
	   inline transform every frame, so transforms/transitions would fight it. */
	transition: background-color .15s ease, box-shadow .15s ease;
}
/* The SVG is a data URL, so its fill cannot read a CSS custom property. Keep a
   sage copy beside the semantic page context rather than leaving a blue arrow
   inside an otherwise sage control. */
.kkrv-scheme-sage .kkrv-tour__hotspot {
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4l7 7h-4v9h-6v-9H5z' fill='%234E6152'/%3E%3C/svg%3E");
}
.kkrv-tour__hotspot:hover {
	/* Literal white on purpose: the disc sits on the panorama photo, where the
	   marker has to hold its own against whatever is behind it (-zvj.5). */
	background-color: #fff;
	box-shadow: 0 0 0 4px rgba(126, 207, 252, 0.55), 0 2px 8px rgba(11, 16, 22, 0.4);
}

/* Side padding keeps long lines off the card edges (they were 1px away). */
.kkrv-tour__note { text-align: center; color: var(--kkrv-ink-soft); font-size: 0.95rem; margin-top: 1rem; padding: 0 1.25rem; }

/* =========================================================
   Call-to-action band
   ========================================================= */
.kkrv-cta-band {
	background: var(--kkrv-green-deep);
	color: #fff;
	/* Same section gap as any other section start — see "Section rhythm" at the
	   foot of this file. Was a one-off clamp(2.5rem, 6vw, 4rem). */
	margin-top: var(--kkrv-space-section);
	padding: clamp(2rem, 5vw, 3.25rem) 1.5rem;
	text-align: center;
	border-radius: var(--kkrv-radius);
}
/* The band's padding is the ONLY spacing — zero GeneratePress's stacked inner
   padding and edge child margins, same trio as every band (band-padding skill). */
.kkrv-cta-band > .wp-block-group__inner-container { padding: 0; }
.kkrv-cta-band > :first-child,
.kkrv-cta-band > .wp-block-group__inner-container > :first-child { margin-top: 0; }
.kkrv-cta-band > :last-child,
.kkrv-cta-band > .wp-block-group__inner-container > :last-child { margin-bottom: 0; }
.kkrv-cta-band h2 { color: #fff; }
.kkrv-cta-band .wp-block-button__link { background: #fff; color: var(--kkrv-page-accent); }
.kkrv-cta-band .wp-block-button__link:hover { background: var(--kkrv-cream); color: var(--kkrv-page-accent-dark); }
.kkrv-cta-band .is-style-outline .wp-block-button__link { background: transparent; color: #fff; border-color: #fff; }
.kkrv-cta-band .is-style-outline .wp-block-button__link:hover { background: #fff; color: var(--kkrv-page-accent); }

/* =========================================================
   Inverse colour band — page-aware sage or care-blue sections
   =========================================================
   Solid inverse section with light text, wrapped around every second section
   for contrast and colour. It reads --kkrv-page-accent, so the care page keeps
   navy while the general pages use deep sage. Re-points the design tokens so nested
   components (leads, secondary text, links, focus rings) invert themselves;
   everything explicitly coloured gets its own rule below. White is 14.02:1 on
   navy and 6.65:1 on deep sage; cream is 11.75:1 on navy and 5.58:1 on deep
   sage. The band paints its own background, so the warm canvas underneath does
   not enter into those pairs. */
.kkrv-band-navy {
	background: var(--kkrv-page-accent);
	color: #fff;
	border-radius: var(--kkrv-radius);
	padding: clamp(1.75rem, 4.5vw, 3rem);
	/* A section start in its own right — same reasoning as .kkrv-band-green. */
	margin-block: var(--kkrv-space-section);
	--kkrv-ink: #fff;
	--kkrv-ink-soft: var(--kkrv-cream);
	--kkrv-blue-link: #fff;
	--kkrv-focus: var(--kkrv-focus-light);
}
/* The band's padding is the ONLY spacing: GeneratePress's group inner
   container stacks its own 40px padding on top (zeroed, same trick as
   .kkrv-tabs), and leading/trailing child margins would stack inside it too
   ("too much padding" — Sean, review round 2). */
.kkrv-band-navy > .wp-block-group__inner-container { padding: 0; }
.kkrv-band-navy > :first-child,
.kkrv-band-navy > .wp-block-group__inner-container > :first-child { margin-top: 0; }
.kkrv-band-navy > :last-child,
.kkrv-band-navy > .wp-block-group__inner-container > :last-child { margin-bottom: 0; }
.kkrv-band-navy h2,
.kkrv-band-navy h3 { color: #fff; }
.kkrv-band-navy .kkrv-headline::after { background: var(--kkrv-page-band-accent); }
.kkrv-band-navy .kkrv-eyebrow { color: var(--kkrv-page-band-accent); }
.kkrv-band-navy a { color: #fff; }
.kkrv-band-navy a:hover { color: var(--kkrv-cream); }
.kkrv-band-navy li::marker { color: var(--kkrv-page-band-accent); }
.kkrv-band-navy .kkrv-feature { margin: 0; }
/* Buttons flip exactly like the CTA band's — handled in the button override
   block near the foot of this file, where the !important globals live. */
/* Components that sit on their own LIGHT card inside an inverse band (facility
   cards, the tour card) keep dark-on-light text — the inversion is for the
   band surface, not for white cards on it. Values mirror :root. */
.kkrv-band-navy .kkrv-card-fac,
.kkrv-band-navy .kkrv-howto,
.kkrv-band-navy .kkrv-tour__card {
	color: var(--kkrv-ink);
	--kkrv-ink: #1C2530;
	--kkrv-ink-soft: #57534E;
	--kkrv-blue-link: #002C57;
	--kkrv-focus: #B34700;
}
.kkrv-band-navy .kkrv-card-fac h3,
.kkrv-band-navy .kkrv-howto h3,
.kkrv-band-navy .kkrv-tour__card h2,
.kkrv-band-navy .kkrv-tour__card h3 { color: var(--kkrv-page-accent); }
.kkrv-band-navy .kkrv-card-fac a,
.kkrv-band-navy .kkrv-tour__card a { color: var(--kkrv-page-accent); }
.kkrv-band-navy .kkrv-card-fac a:hover,
.kkrv-band-navy .kkrv-tour__card a:hover { color: var(--kkrv-page-accent-dark); }
/* The band recolours list markers for legibility on its inverse colour; inside the
   white how-to card that leaves pale bullets on white, so put them back. */
.kkrv-band-navy .kkrv-howto li::marker { color: var(--kkrv-green-deep); }
/* Use the band accent on light-card edges, matching the headline rule and eyebrow. */
.kkrv-band-navy .kkrv-card-fac { border-top-color: var(--kkrv-page-band-accent); }

/* --- Legacy sage-band modifier: Independent Living's virtual tour (-00r.43)
   The page scheme now gives every general-site inverse band the same palette.
   Retain this modifier for explicit component rules and old content. Everything
   above still supplies padding, token repointing and the white-card reset.

   THE ACCENT HAD TO CHANGE, NOT JUST THE BACKGROUND. --kkrv-green (light sage)
   is the navy band's accent at 6.9:1, and it is the obvious thing to keep. On
   deep sage it measures 3.29:1 — fine for a decorative rule, a FAIL for any text
   at AA. Cream is 5.6:1 there and reads warm rather than muddy, so the accent
   moves to cream for anything legible. Measure before reusing a token across a
   hue change; it is the whole trap. */
.kkrv-band-navy--sage { background: var(--kkrv-green-deep); }
.kkrv-band-navy--sage .kkrv-headline::after { background: var(--kkrv-cream); }
.kkrv-band-navy--sage .kkrv-eyebrow,
.kkrv-band-navy--sage li::marker { color: var(--kkrv-cream); }
/* The white cards inside take the section's own accent rather than site navy —
   a navy heading on a card sitting in a green band is the one thing that would
   give the game away. */
.kkrv-band-navy--sage .kkrv-howto h3,
.kkrv-band-navy--sage .kkrv-tour__card h2,
.kkrv-band-navy--sage .kkrv-tour__card h3 { color: var(--kkrv-green-deep); }
.kkrv-band-navy--sage .kkrv-card-fac a,
.kkrv-band-navy--sage .kkrv-tour__card a { color: var(--kkrv-green-deep); }
.kkrv-band-navy--sage .kkrv-card-fac a:hover,
.kkrv-band-navy--sage .kkrv-tour__card a:hover { color: var(--kkrv-green-deep-dark); }
.kkrv-band-navy--sage .kkrv-howto li::marker { color: var(--kkrv-green-deep); }
.kkrv-band-navy--sage .kkrv-card-fac { border-top-color: var(--kkrv-cream); }

/* The tour's own controls come too. They are a shared component — the same tour
   renders on /about/, where it must stay navy — so this is scoped through the
   band, not through .kkrv-tour. Without it the panel sits inside a green band
   wearing navy pills and reads as a piece of another page. */
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__areas button,
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__poi button {
	border-color: var(--kkrv-green-deep);
	color: var(--kkrv-green-deep);
}
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__areas button:hover,
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__poi button:hover {
	background: var(--kkrv-green-tint);
	color: var(--kkrv-green-deep-dark);
}
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__areas button.is-current,
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__areas button.is-current:hover {
	background: var(--kkrv-green-deep);
	color: #fff;
}
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__rooms button { color: var(--kkrv-green-deep); }
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__rooms button:hover { color: var(--kkrv-green-deep-dark); }
.kkrv-band-navy--sage .kkrv-tour .kkrv-tour__rooms button.is-current {
	border-color: var(--kkrv-green-deep);
	color: var(--kkrv-green-deep-dark);
}

/* Editorial note (placeholder for client-supplied content) */
.kkrv-note { color: var(--kkrv-ink-soft); }

/* =========================================================
   Footer contact bar (replaces GeneratePress credit)
   ========================================================= */
.site-info {
	background: var(--kkrv-footer-bg);
	color: #fff;
}
.kkrv-footer-contact {
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1.75rem;
	align-items: center;
	justify-content: center;
	text-align: center;
	line-height: 1.55;
}
.kkrv-footer-contact__lead {
	width: 100%;
	font-family: var(--kkrv-font-head);
	font-size: 1.15rem;
}
.kkrv-footer-contact a { color: #fff; }
.kkrv-footer-contact__list {
	list-style: none;
	display: flex;
	flex-wrap: wrap;
	gap: 0.4rem 1.5rem;
	margin: 0;
	padding: 0;
}
.kkrv-footer-contact__cta a {
	display: inline-flex;
	align-items: center;
	min-height: var(--kkrv-tap-min);
	background: #fff;
	color: var(--kkrv-footer-action);
	font-weight: 700;
	padding: 0.4em 1.3em;
	border-radius: var(--kkrv-btn-radius);
	text-decoration: none;
}
.kkrv-footer-contact__cta a:hover { background: var(--kkrv-cream); color: var(--kkrv-footer-action-hover); }
.kkrv-footer-contact__charity {
	width: 100%;
	font-size: 0.95rem;
	opacity: 0.9;
	border-top: 1px solid rgba(255, 255, 255, .15);
	padding-top: 0.75rem;
	margin-top: 0.25rem;
}

/* =========================================================
   Accessible tabs — restyled as a pill segmented control
   (behaviour & ARIA unchanged; see assets/js/tabs.js)
   ========================================================= */
.kkrv-tabs__list {
	display: flex;
	width: fit-content;
	margin-inline: auto;
	flex-wrap: nowrap;
	gap: 0.35rem;
	max-width: 100%;
	overflow-x: auto;
	background: var(--kkrv-cream);
	border: 1px solid var(--kkrv-border);
	padding: 0.4rem;
	border-radius: var(--kkrv-btn-radius);
	margin-bottom: 1.75rem;
}
.kkrv-tabs__tab {
	display: inline-flex;
	align-items: center;
	white-space: nowrap;
	min-height: var(--kkrv-tap-min);
	padding: 0.55em 1.3em;
	font-weight: 700;
	color: var(--kkrv-page-accent);
	text-decoration: none;
	border: none;
	border-radius: var(--kkrv-btn-radius);
	transition: background-color .18s ease, color .18s ease;
}
/* Hover lifts the pill off the cream tablist, so it wants the card surface
   rather than a literal white (-zvj.5). */
.kkrv-tabs__tab:hover { background: var(--kkrv-card); color: var(--kkrv-page-accent-dark); }
.kkrv-tabs__tab[aria-selected="true"] {
	background: var(--kkrv-page-accent);
	color: #fff;
	box-shadow: var(--kkrv-shadow-sm);
}
/* Independent Living's tabs run green (-00r.43). White on --kkrv-green-deep is
   6.7:1, so the selected pill clears AA comfortably. */
.kkrv-tabs--homes .kkrv-tabs__tab { color: var(--kkrv-green-deep); }
.kkrv-tabs--homes .kkrv-tabs__tab:hover { color: var(--kkrv-green-deep-dark); }
.kkrv-tabs--homes .kkrv-tabs__tab[aria-selected="true"] {
	background: var(--kkrv-green-deep);
	color: #fff;
}
.kkrv-tabs__panel {
	background: var(--kkrv-card);
	border: 1px solid var(--kkrv-border);
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	padding: clamp(1.1rem, 2.4vw, 1.6rem);
}
/* GeneratePress wraps group blocks in an .wp-block-group__inner-container that
   carries its own 40px padding; on the block-native home-type panels that doubled
   up with the card padding above (~70px gutter). Zero the inner one so each panel
   has a single, tighter gutter. */
.kkrv-tabs > .wp-block-group__inner-container,
.kkrv-tabs__panel > .wp-block-group__inner-container { padding: 0; }
/* Inset, thinner ring: nav submenus deep-link to a panel, which then receives
   focus — a 3px halo offset 4px outside read as an alarm box. Hug the card edge. */
.kkrv-tabs__panel:focus-visible { outline: 2px solid var(--kkrv-focus); outline-offset: -2px; }
.kkrv-tabs__panel[hidden] { display: none; }
/* Panel headings were h3 until 2026-07-27 and are now h2: they sit directly
   under the page h1, so h3 skipped a level and axe flagged heading-order on the
   first panel. Both are matched so a stray h3 deeper in a panel still behaves. */
.kkrv-tabs__panel h2,
.kkrv-tabs__panel h3 { margin-top: 0; }
/* Same reasoning as .kkrv-fb h2 above: the level moved for structure, the size
   stays where the design put it. */
.kkrv-tabs__panel > .wp-block-group__inner-container > h2,
.kkrv-tabs__panel > h2 { font-size: clamp(1.3rem, 2vw, 1.55rem); }
/* When JS is off, all panels show — separate them clearly */
.kkrv-tabs:not(.kkrv-tabs--enhanced) .kkrv-tabs__list { display: none; }
.kkrv-tabs:not(.kkrv-tabs--enhanced) .kkrv-tabs__panel + .kkrv-tabs__panel { margin-top: 1.5rem; }
/* Button row inside a tab panel or a two-column feature block. Same layout in
   both places, so one rule — .kkrv-feature__cta exists only because calling it
   "tabs" inside the day-programme feature would be a lie to the next reader. */
.kkrv-tabs__cta,
.kkrv-feature__cta { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.5rem; }
.kkrv-btn-ghost { background: transparent; color: var(--kkrv-page-accent); border-color: var(--kkrv-page-accent); }
.kkrv-btn-ghost:hover { background: var(--kkrv-page-accent-tint); color: var(--kkrv-page-accent-dark); }

/* =========================================================
   Override GeneratePress's default grey button colour, which uses
   a.wp-block-button__link:not(.has-background) (specificity 0,2,1) and
   otherwise wins. The page accent is primary; white on photo/inverse bands.
   ========================================================= */
.wp-block-button__link { background-color: var(--kkrv-page-accent) !important; color: #fff !important; }
.wp-block-button__link:hover,
.wp-block-button__link:focus { background-color: var(--kkrv-page-accent-dark) !important; color: #fff !important; }
.wp-block-button.is-style-outline .wp-block-button__link { background-color: transparent !important; color: var(--kkrv-page-accent) !important; }
.wp-block-button.is-style-outline .wp-block-button__link:hover { background-color: var(--kkrv-page-accent) !important; color: #fff !important; }
.kkrv-hero__cta .wp-block-button__link,
.kkrv-cta-band .wp-block-button__link,
.kkrv-band-navy .wp-block-button__link { background-color: #fff !important; color: var(--kkrv-page-accent) !important; }
.kkrv-hero__cta .wp-block-button__link:hover,
.kkrv-cta-band .wp-block-button__link:hover,
.kkrv-band-navy .wp-block-button__link:hover { background-color: var(--kkrv-cream) !important; color: var(--kkrv-page-accent-dark) !important; }
.kkrv-cta-band .is-style-outline .wp-block-button__link,
.kkrv-band-navy .is-style-outline .wp-block-button__link,
.kkrv-hero__cta .kkrv-btn-ghost { background-color: transparent !important; color: #fff !important; border-color: #fff !important; }
.kkrv-cta-band .is-style-outline .wp-block-button__link:hover,
.kkrv-band-navy .is-style-outline .wp-block-button__link:hover,
.kkrv-hero__cta .kkrv-btn-ghost:hover { background-color: #fff !important; color: var(--kkrv-page-accent) !important; }

/* The sage band's white buttons take green text, not navy — same reasoning as
   the white cards above. Placed here so it lands after the .kkrv-band-navy
   button rules it overrides. */
.kkrv-band-navy--sage .wp-block-button__link { color: var(--kkrv-green-deep) !important; }
.kkrv-band-navy--sage .wp-block-button__link:hover { color: var(--kkrv-green-deep-dark) !important; }

/* --- Independent Living wears the green accent (-00r.43) ------------------
   Scoped through .kkrv-tabs--homes, a modifier that was already in the markup
   and styled nowhere. NOT through body.page-id-N, and NOT through .kkrv-tabs:
   the tabs component is shared with /quality-care-and-support/ and nothing here
   may leak onto the care page.

   !important throughout only because the rules above are !important and this has
   to outrank them; the specificity is doing the real work.

   THE CARE CENTRE PANEL IS THE ONE EXCEPTION. Its CTA lives on this page but
   points at /quality-care-and-support/, so it keeps the navy of the section it
   leads to — a green button opening a navy page would contradict the very
   signal this feature exists to send. update-test.sh:268 already guards that
   panel for the same reason. */
.kkrv-tabs--homes .wp-block-button__link:not(.kkrv-btn-ghost) {
	background-color: var(--kkrv-green-deep) !important;
	color: #fff !important;
}
.kkrv-tabs--homes .wp-block-button__link:not(.kkrv-btn-ghost):hover {
	background-color: var(--kkrv-green-deep-dark) !important;
}
.kkrv-tabs--homes .kkrv-btn-ghost {
	background-color: transparent !important;
	color: var(--kkrv-green-deep) !important;
	border-color: var(--kkrv-green-deep) !important;
}
.kkrv-tabs--homes .kkrv-btn-ghost:hover {
	background-color: var(--kkrv-green-tint) !important;
	color: var(--kkrv-green-deep-dark) !important;
}
/* The exception, last so it wins on source order at equal specificity. */
.kkrv-tabs--homes .kkrv-tabs__cta--care .wp-block-button__link:not(.kkrv-btn-ghost) {
	background-color: var(--kkrv-blue) !important;
}
.kkrv-tabs--homes .kkrv-tabs__cta--care .wp-block-button__link:not(.kkrv-btn-ghost):hover {
	background-color: var(--kkrv-blue-dark) !important;
}
.kkrv-tabs--homes .kkrv-tabs__cta--care .kkrv-btn-ghost {
	color: var(--kkrv-blue) !important;
	border-color: var(--kkrv-blue) !important;
}
.kkrv-tabs--homes .kkrv-tabs__cta--care .kkrv-btn-ghost:hover {
	background-color: var(--kkrv-bg-alt) !important;
	color: var(--kkrv-blue-dark) !important;
}

/* =========================================================
   Light-only by design (00r.27) — no prefers-color-scheme:dark theme.
   An auto dark-flip was turning the whole site dark for anyone whose OS is set
   to dark; the brand is a light, airy palette, so light is the default for
   everyone. Visitors who prefer dark can use the Dark Reader extension, which
   cleanly inverts this light page — a site-authored dark theme only fights it.
   See color-scheme:light near the top of this file.
   ========================================================= */


/* =========================================================
   Round 2 — sage-green accents, About redesign, home-type
   galleries + homes tour, wider news layout
   (issues yds / 0t3 / xnt / g2z / akp)
   ========================================================= */

/* --- Sage-green accents, used more widely across the site --- */
/* Subtle green list markers in readable content. */
.entry-content li::marker { color: var(--kkrv-green-deep); }

/* Short green rule under top-level section headings, plus any heading that opts
   in with .kkrv-headline (headings nested in columns / features). */
.entry-content > h2::after,
.kkrv-headline::after {
	content: "";
	display: block;
	width: 2.75rem;
	height: 4px;
	margin-top: 0.6rem;
	border-radius: 2px;
	background: var(--kkrv-green-deep);
}
/* Never draw the rule on the white CTA-band heading. */
.kkrv-cta-band h2::after { display: none; }

/* Eyebrow — small green kicker above a heading. */
.kkrv-eyebrow {
	display: block;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	font-size: 0.82rem;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--kkrv-green-deep);
	margin: 0 0 0.4rem;
}
.kkrv-eyebrow--ondark { color: var(--kkrv-green); }
.kkrv-eyebrow + h2 { margin-top: 0; }


/* --- About: hero banner --- */
.kkrv-hero--about {
	--kkrv-hero-photo: url("assets/images/about/header.webp");
	background-image:
		linear-gradient(90deg, rgba(0, 42, 84, .82) 0%, rgba(0, 42, 84, .5) 48%, rgba(0, 42, 84, .12) 100%),
		var(--kkrv-hero-photo);
	min-height: clamp(320px, 42vh, 440px);
}
/* --- Contact: photographic page header + colour-blocked content --- */
.kkrv-hero--contact {
	--kkrv-hero-photo: url("assets/images/contact/header.webp");
	background-image:
		linear-gradient(90deg, rgba(61, 76, 65, .9) 0%, rgba(61, 76, 65, .72) 48%, rgba(61, 76, 65, .28) 100%),
		var(--kkrv-hero-photo);
	background-position: center 50%;
	min-height: clamp(260px, 34vh, 380px);
}

/* These two panels organise the existing Contact page without changing its
   copy or form/map contract. The white enquiry card lifts off the paper; the
   sage location band creates a separate destination for the map. */
.kkrv-contact-panel {
	border-radius: var(--kkrv-radius);
	padding: clamp(1.5rem, 4vw, 2.75rem);
	margin-block: var(--kkrv-space-section);
}
/* Panel padding is the only padding: constrained WordPress groups can add an
   inner 40px wrapper, and the edge children otherwise stack their margins on
   top of it. Keep the same three-part safeguard as every colour band. */
.kkrv-contact-panel > .wp-block-group__inner-container { padding: 0; }
.kkrv-contact-panel > :first-child,
.kkrv-contact-panel > .wp-block-group__inner-container > :first-child { margin-top: 0; }
.kkrv-contact-panel > :last-child,
.kkrv-contact-panel > .wp-block-group__inner-container > :last-child { margin-bottom: 0; }
.kkrv-contact-panel--enquiry {
	background: var(--kkrv-card);
	border: 1px solid var(--kkrv-border);
	box-shadow: var(--kkrv-shadow-sm);
}
.kkrv-contact-panel--location { background: var(--kkrv-green-tint); }
.kkrv-contact-panel--location .kkrv-map {
	max-width: none;
	margin-bottom: 0;
}
/* Breathing room between a full-bleed hero and the first content section: the
   hero's negative side-margins don't affect vertical flow, so without this the
   first heading butts right up against the hero band (Home, About). */
.kkrv-hero { margin-bottom: clamp(2.25rem, 5vw, 3.5rem); }
/* Let the hero sit flush at the very top of the article on hero pages. */
.kkrv-has-hero .inside-article { padding-top: 0; }

/* --- About: two-column info section + map --- */
.kkrv-info-cols.wp-block-columns { gap: clamp(1.5rem, 4vw, 3rem); align-items: start; }
.kkrv-info-cols .kkrv-map { max-width: none; margin-block: 1.25rem 0; }

/* --- About: green-tint band (Day Programme) --- */
.kkrv-band-green {
	background: var(--kkrv-green-tint);
	border-radius: var(--kkrv-radius);
	padding: clamp(1.5rem, 4vw, 2.75rem);
	/* A tinted band is a section start in its own right, so it takes the section
	   gap rather than the old flat 2rem. Adjacent margins collapse, so a
	   following top-level h2 contributes its own equal gap and the boundary
	   stays one gap wide, not two. */
	margin-block: var(--kkrv-space-section);
}
/* The band's padding is the ONLY spacing — GeneratePress's group inner
   container stacks its own 40px on top, and edge child margins would stack
   inside it too. Same trio as .kkrv-band-navy ("too much padding" — Sean,
   review rounds 2 AND 3: every band class needs this, see the band-padding
   skill). */
.kkrv-band-green > .wp-block-group__inner-container { padding: 0; }
.kkrv-band-green > :first-child,
.kkrv-band-green > .wp-block-group__inner-container > :first-child { margin-top: 0; }
.kkrv-band-green > :last-child,
.kkrv-band-green > .wp-block-group__inner-container > :last-child { margin-bottom: 0; }
.kkrv-band-green .kkrv-feature { margin: 0; }

/* =========================================================
   "How to use this" instruction card
   Sits directly above an interactive widget (the locality
   map, the virtual tour) and says in plain words what to
   do. Our visitors are mostly in their 70s and 80s and have
   no reason to know that a photo can be dragged or that a
   small circle is a button — so the instructions are a
   heading and a list at full body contrast, not a clause
   buried in a muted intro paragraph. Issue 67t.
   ========================================================= */
.kkrv-howto {
	background: var(--kkrv-card);
	border: 1px solid var(--kkrv-border);
	border-left: 4px solid var(--kkrv-green-deep);
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	padding: 1.1rem 1.35rem;
	margin-block: 1.25rem;
	max-width: 62ch;
}
.kkrv-howto__title {
	display: flex;
	align-items: center;
	gap: 0.55rem;
	margin: 0 0 0.6rem;
	font-size: 1.1rem;
	color: var(--kkrv-blue-dark);
}
.kkrv-howto__title svg {
	flex: none;
	width: 26px;
	height: 26px;
	color: var(--kkrv-green-deep);
}
.kkrv-howto ul {
	margin: 0;
	padding-left: 1.25rem;
}
.kkrv-howto li {
	margin-bottom: 0.4rem;
	/* Full body size and full-contrast ink. This is the one place on the page
	   where shrinking the text to look "secondary" would defeat the point. */
	font-size: var(--kkrv-fs-base);
	color: var(--kkrv-ink);
}
.kkrv-howto li:last-child { margin-bottom: 0; }

/* =========================================================
   Locality map — "how close we are to town"
   Real OpenStreetMap road geometry and the village's real
   LINZ title boundary, drawn to scale from the committed
   data in assets/js/locality-data.js. Issue 5ik.
   ========================================================= */
/* Drawing weights are viewBox units, so they shrink with the map. At 1100px wide
   the defaults look right; on a 320px phone the same numbers render pins about
   two pixels across and minor roads at half a pixel — invisible. So every weight
   is a custom property and the small-screen block scales them back up. Set on
   .kkrv-locality (not :root) to keep them scoped to this widget. */
.kkrv-locality {
	margin-block: 1.5rem;
	--loc-road-minor: 1.6;
	--loc-road-major: 3.2;
	--loc-pin: 6.5;
	--loc-pin-halo: 13;
	--loc-pin-current: 9;
	--loc-home: 9;
	--loc-line: 2.5;
	--loc-label: 21px;
	--loc-stroke: 2.5;
}
@media (max-width: 780px) {
	.kkrv-locality {
		--loc-road-minor: 4;
		--loc-road-major: 8;
		--loc-pin: 15;
		--loc-pin-halo: 28;
		--loc-pin-current: 20;
		--loc-home: 20;
		--loc-line: 6;
		--loc-label: 52px;
		--loc-stroke: 6;
	}
}

.kkrv-locality__stage {
	position: relative;
	border: 1px solid var(--kkrv-border);
	border-radius: var(--kkrv-radius);
	background: var(--kkrv-cream-soft);
	box-shadow: var(--kkrv-shadow-sm);
	overflow: hidden;
	padding: 0.5rem;
}
.kkrv-locality__svg { display: block; width: 100%; height: auto; }

/* Two road weights only. The extract is filtered to named through-roads, but
   even so a single weight reads as a net rather than a street layout — the
   contrast between the two is what makes the shape of the town legible. */
.kkrv-locality__roads path { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.kkrv-locality__roads--minor path { stroke: var(--kkrv-grey); stroke-width: var(--loc-road-minor); opacity: .5; }
.kkrv-locality__roads--major path { stroke: var(--kkrv-ink-soft); stroke-width: var(--loc-road-major); opacity: .75; }

.kkrv-locality__village path {
	fill: var(--kkrv-green);
	fill-opacity: .7;
	stroke: var(--kkrv-green-deep);
	stroke-width: var(--loc-stroke);
}

/* Dashed, so it reads as "measured distance" rather than "a road you drive". */
.kkrv-locality__line {
	stroke: var(--kkrv-page-accent);
	stroke-width: var(--loc-line);
	stroke-dasharray: 7 5;
	stroke-linecap: round;
}

/* Every white through the map below is a literal on purpose. These are
   legibility casings drawn over roads, the village fill and open ground, so
   they need maximum contrast against whatever they land on rather than the
   page's warmth — a tokenised near-white would blur the pins (-zvj.5). */
.kkrv-locality__home circle { fill: var(--kkrv-page-accent); stroke: #fff; stroke-width: var(--loc-stroke); r: var(--loc-home); }

/* The selected place's name, drawn over the map. paint-order:stroke puts a white
   casing behind the glyphs so the name stays readable wherever it lands —
   over a road, over the village fill, or over open ground. */
.kkrv-locality__label {
	font-family: var(--kkrv-font-body);
	font-size: var(--loc-label);
	font-weight: 700;
	fill: var(--kkrv-blue-dark);
	stroke: #fff;
	stroke-width: calc(var(--loc-stroke) * 2);
	paint-order: stroke fill;
	stroke-linejoin: round;
}
/* On a phone the map is only ~300px wide and a name like "Community swimming
   pool" spans most of it, crowding the edge whichever way it is anchored. The
   readout immediately below already names the selected place, so the on-map
   label is redundant there rather than merely tight — drop it. */
@media (max-width: 780px) {
	.kkrv-locality__label { display: none; }
}

.kkrv-locality__pin { cursor: pointer; }
.kkrv-locality__pin-halo { fill: var(--kkrv-page-accent); opacity: 0; r: var(--loc-pin-halo); transition: opacity .18s ease; }
.kkrv-locality__pin-dot { fill: #fff; stroke: var(--kkrv-page-accent); stroke-width: var(--loc-stroke); r: var(--loc-pin); }
.kkrv-locality__pin:hover .kkrv-locality__pin-halo { opacity: .18; }
.kkrv-locality__pin.is-current .kkrv-locality__pin-halo { opacity: .28; }
.kkrv-locality__pin.is-current .kkrv-locality__pin-dot {
	fill: var(--kkrv-page-accent);
	stroke: #fff;
	r: var(--loc-pin-current);
}

.kkrv-locality__readout {
	margin: 0.9rem 0 0.6rem;
	font-weight: 700;
	color: var(--kkrv-blue-dark);
	font-size: 1.05rem;
}

/* Same button idiom as the virtual tour's area picker — see .kkrv-tour__areas.
   Two map-like widgets on one site should not have two different controls. */
.kkrv-locality__places { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.kkrv-locality .kkrv-locality__places button {
	display: inline-flex;
	align-items: center;
	/* The place name and its distance sit on one line by default and neither can
	   shrink, so at 200% text zoom "Cornerstone Church 200 m" demanded 305px on a
	   320px screen (-41s). Letting the pair wrap inside the button, and capping
	   the button at the row width, keeps the longest name on screen. */
	flex-wrap: wrap;
	max-width: 100%;
	gap: 0.5rem;
	min-height: var(--kkrv-tap-min);
	padding: 0.4em 1em;
	border: 2px solid var(--kkrv-page-accent);
	border-radius: var(--kkrv-btn-radius);
	/* The card surface, not a literal — an unselected pill lifts off the warm
	   page and should keep lifting by the same amount if it warms (-zvj.5). */
	background: var(--kkrv-card);
	box-shadow: none;
	font-family: var(--kkrv-font-body);
	font-weight: 700;
	font-size: 0.95rem;
	color: var(--kkrv-page-accent);
	cursor: pointer;
	transition: background-color .18s ease, color .18s ease;
}
.kkrv-locality .kkrv-locality__places button:hover {
	background: var(--kkrv-page-accent-tint);
	color: var(--kkrv-page-accent-dark);
	box-shadow: none;
	transform: none;
}
.kkrv-locality .kkrv-locality__places button.is-current,
.kkrv-locality .kkrv-locality__places button.is-current:hover {
	background: var(--kkrv-page-accent);
	color: #fff;
}
.kkrv-locality__btn-dist {
	font-weight: 600;
	font-variant-numeric: tabular-nums;
	/* Do not fade the inherited accent: deep sage at 75% composites below
	   4.5:1 on the light button surface. Weight provides the secondary cue. */
	opacity: 1;
}

.kkrv-locality__caption {
	margin: 0.85rem 0 0;
	font-size: 0.9rem;
	color: var(--kkrv-ink-soft);
}

/* The no-JavaScript view. Kept as a real list rather than a table: it is a set
   of place/distance pairs, and it is the only thing a visitor without SVG or
   JavaScript ever sees, so it has to read as prose. */
.kkrv-locality__list { margin: 0.5rem 0 0; padding-left: 1.2rem; }
.kkrv-locality__list li { margin-bottom: 0.3rem; }

@media (prefers-reduced-motion: reduce) {
	.kkrv-locality__pin-halo,
	.kkrv-locality .kkrv-locality__places button { transition: none; }
}

/* --- Day programme schedule --- */
/* The three named day programmes, as a description list. Each dt/dd pair is
   wrapped in a .kkrv-dayprog__row div, which is valid inside <dl> and is the
   only way to make a pair a single grid/flex item — styling dt and dd directly
   would let a long programme name and its day drift onto separate rows. */
.kkrv-dayprog {
	margin: 1.25rem 0;
	display: grid;
	grid-template-columns: minmax(0, 1fr);
	gap: 0.5rem;
}
/* This feature alone puts the schedule in its media column. Keep that column
   as a vertical stack and let the landscape image retain its intrinsic ratio;
   changing the generic feature media would affect every photo/text row. */
.kkrv-feature--day-programme .kkrv-feature__media {
	display: flex;
	min-width: 0;
	flex-direction: column;
	gap: 1rem;
}
.kkrv-feature--day-programme .kkrv-dayprog { margin: 0; }
.kkrv-feature--day-programme .kkrv-feature__media img { height: auto; }
.kkrv-dayprog__row {
	display: flex;
	flex-wrap: wrap;
	align-items: baseline;
	gap: 0.35rem 0.75rem;
	padding: 0.6rem 0.9rem;
	background: rgba(255, 255, 255, 0.55);
	border-left: 3px solid var(--kkrv-green-deep);
	border-radius: 0 var(--kkrv-radius) var(--kkrv-radius) 0;
}
.kkrv-dayprog dt {
	font-weight: 700;
	color: var(--kkrv-blue-dark);
	/* min() so the alignment column cannot outgrow the row. A flat 6.5em is an
	   em, so it doubles under text zoom — at 200% on a 320px screen it demanded
	   208px for the day name alone and pushed the whole page sideways (-41s).
	   Capped at 100%, the dt gives up its column and the row's flex-wrap drops
	   the day onto its own line, which is the graceful outcome already designed
	   for here. */
	min-width: min(6.5em, 100%);
}
.kkrv-dayprog dd {
	margin: 0;
	color: var(--kkrv-ink-soft);
}

/* --- About: facilities & services cards --- */
/* Fixed three-up (not auto-fit): the card count must divide by three or the
   last row orphans (Sean, 2026-07-28 — five cards had to be forced to 3+2
   rather than the 4+1 auto-fit produced). Now twelve cards, so 3+3+3+3 falls
   out naturally. Collapses 2-up, then 1-up. */
.kkrv-cards {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 1.15rem;
	margin: 1.75rem 0;
}
@media (max-width: 820px) {
	.kkrv-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px) {
	.kkrv-cards { grid-template-columns: minmax(0, 1fr); }
}
.kkrv-card-fac {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
	background: var(--kkrv-card);
	border: 1px solid var(--kkrv-border);
	border-top: 3px solid var(--kkrv-green-deep);
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	padding: 1.6rem 1.25rem;
	transition: transform .2s ease, box-shadow .2s ease;
}
.kkrv-card-fac:hover { transform: translateY(-3px); box-shadow: var(--kkrv-shadow-md); }
.kkrv-card-fac__icon {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 58px;
	height: 58px;
	margin-bottom: 0.9rem;
	border-radius: 50%;
	background: var(--kkrv-green-tint);
	color: var(--kkrv-green-deep);
}
.kkrv-card-fac__icon svg { width: 30px; height: 30px; }
.kkrv-card-fac h3 { margin: 0 0 0.35rem; font-size: 1.15rem; }
.kkrv-card-fac p { margin: 0; font-size: 1rem; color: var(--kkrv-ink-soft); }

/* --- Independent Living: home-type galleries (native Gallery block) --- */
.kkrv-home-gallery { margin-block: 1.25rem; }
.kkrv-home-gallery.wp-block-gallery img {
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
}

/* A phone number sitting in a sentence, where the link text is ONLY the digits.
   Keeps it on one line: "027" / "225 5983" split across two lines is harder to
   read and easier to misdial, and a misdial produces no error anywhere — the
   enquiry simply never arrives (-tcf). This audience is in its seventies and
   eighties and the phone is the primary conversion, so the number is worth the
   rule.

   SCOPED TO A MARKER CLASS ON PURPOSE, not to a[href^="tel:"]. Most tel links on
   this site are button labels reading "Call us on 09 407 0070" — 22 characters
   that MUST stay free to wrap, or they overflow at narrow widths and at large
   text zoom, which is a worse accessibility outcome than the split it fixes.
   Add this class only where the visible text is the number and nothing else. */
.kkrv-tel { white-space: nowrap; }

/* --- Village News: two-column layout so the (Facebook-capped 500px) page feed
   no longer floats narrow and alone in a full-width column. --- */
.kkrv-news {
	display: grid;
	grid-template-columns: minmax(0, 520px) minmax(0, 1fr);
	gap: clamp(1.5rem, 4vw, 2.5rem);
	align-items: start;
	margin: 1.5rem 0;
}
@media (max-width: 860px) {
	/* minmax(0, 1fr), NOT 1fr. A bare 1fr is minmax(auto, 1fr), and that auto
	   minimum is the whole bug: the Facebook SDK writes an inline width:500px
	   on its span and iframe, which becomes the column's intrinsic minimum, so
	   the track refuses to shrink below 500px and blows the page out sideways
	   at every viewport under that. The max-width:100% further down cannot save
	   it — those percentages resolve against a parent that is itself 500px, so
	   the whole chain settles at 500 and agrees with itself. The desktop track
	   above already spells minmax(0, 520px) for exactly this reason. */
	.kkrv-news { grid-template-columns: minmax(0, 1fr); }
}
/* Same guard on the items themselves, so a future change to the track cannot
   quietly bring the overflow back. */
.kkrv-news__feed,
.kkrv-news__events { min-width: 0; }
.kkrv-news .kkrv-fb {
	max-width: 500px;
	margin: 0;
	text-align: left;
}
.kkrv-news .kkrv-fb .fb-page { display: block; }
.kkrv-news__events {
	background: var(--kkrv-cream);
	border: 1px solid var(--kkrv-border);
	border-radius: var(--kkrv-radius);
	padding: clamp(1.25rem, 3vw, 1.75rem);
}
.kkrv-news__events h2,
.kkrv-news__events h3 { margin-top: 0; }
.kkrv-news__events p { font-size: 1rem; }

/* Roomier side gutters for inner-page content on tablet / mid-width viewports.
   Below the desktop container width the article is full-bleed with only GP's
   40px gutter, so bare content (e.g. the care "How to arrange care" section)
   sat too close to the edges. Grows the gutter; heroes/bands break out of this
   container so they are unaffected. */
@media (min-width: 600px) {
	.inside-article {
		padding-left: clamp(48px, 8vw, 80px);
		padding-right: clamp(48px, 8vw, 80px);
	}
}

/* A hidden attribute must always win over the global button/display resets. */
[hidden] { display: none !important; }

/* =========================================================
   Home-type galleries: swipeable carousel + full-screen lightbox
   (progressive enhancement over the native Gallery block; see gallery.js)
   ========================================================= */
.kkrv-gallery-holder { position: relative; margin-block: 1.25rem; }

.kkrv-home-gallery.kkrv-gallery--carousel.wp-block-gallery {
	display: flex !important;
	flex-wrap: nowrap !important;
	justify-content: flex-start;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	gap: 0.75rem;
	margin: 0;
	padding-bottom: 0.35rem;
	scrollbar-width: thin;
}
.kkrv-home-gallery.kkrv-gallery--carousel .wp-block-image {
	flex: 0 0 min(80%, 340px);
	margin: 0;
	scroll-snap-align: center;
}
.kkrv-home-gallery button.kkrv-gallery-open {
	display: block;
	width: 100%;
	padding: 0;
	margin: 0;
	border: 0;
	background: none;
	cursor: zoom-in;
	min-height: 0;
	box-shadow: none;
	border-radius: var(--kkrv-radius);
	overflow: hidden;
}
.kkrv-home-gallery.kkrv-gallery--carousel .wp-block-image img {
	display: block;
	width: 100%;
	aspect-ratio: 3 / 2;
	object-fit: cover;
	border-radius: var(--kkrv-radius);
	box-shadow: var(--kkrv-shadow-sm);
	transition: transform .25s ease;
}
.kkrv-home-gallery button.kkrv-gallery-open:hover img { transform: scale(1.03); }
/* The global button:hover (background-color + translateY(-2px) lift + shadow,
   see line ~285) otherwise wins here too, since a plain <button> matches it.
   Without this override every open button in the strip painted itself solid
   blue on hover — invisible only because the image (with its own box-shadow)
   happened to cover it edge-to-edge; any resize/zoom that broke that coverage
   showed blue through the gap. */
.kkrv-home-gallery button.kkrv-gallery-open:hover {
	background: none;
	transform: none;
	box-shadow: none;
}
.kkrv-home-gallery button.kkrv-gallery-open:focus-visible {
	outline: 3px solid var(--kkrv-focus);
	outline-offset: 2px;
}

/* Carousel prev/next — shared by the strip carousel and the showcase stage */
.kkrv-gallery-holder button.kkrv-gallery-arrow,
.kkrv-showcase__stage button.kkrv-gallery-arrow {
	position: absolute;
	top: calc(50% - 0.2rem);
	transform: translateY(-50%);
	z-index: 2;
	width: 44px;
	height: 44px;
	min-height: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 0;
	border: 2px solid #fff;
	border-radius: 50%;
	background: var(--kkrv-page-accent);
	color: #fff;
	cursor: pointer;
	box-shadow: var(--kkrv-shadow-md);
}
/* Re-assert the centring transform: the global button:hover (line ~285) sets
   transform: translateY(-2px) at the same specificity, which — because it
   loses the base rule's translateY(-50%) — physically slides the 44px circle
   out from under the pointer as soon as :hover engages. On a real click that
   window is enough for the button to move off the cursor between mousedown
   and mouseup, so the click falls through to whatever sits underneath (the
   showcase stage's fullscreen-open button) instead of stepping the photo —
   the "arrow sometimes opens fullscreen instead of skipping" bug. */
.kkrv-gallery-holder button.kkrv-gallery-arrow:hover,
.kkrv-showcase__stage button.kkrv-gallery-arrow:hover {
	background: var(--kkrv-page-accent-dark);
	transform: translateY(-50%);
	box-shadow: var(--kkrv-shadow-md);
}
.kkrv-gallery-arrow--prev { left: 6px; }
.kkrv-gallery-arrow--next { right: 6px; }
.kkrv-gallery-arrow[hidden] { display: none; }

/* =========================================================
   "Life at the village" showcase: one big stage + a thumbnail rail
   (progressive enhancement over the same native Gallery block; see gallery.js)
   ========================================================= */
/* Narrower than the content column: at full width the stage grew to ~750px tall
   and swallowed the viewport, and the wider it gets the more letterbox the
   portrait shots have to fill. */
.kkrv-showcase {
	max-width: 940px;
	margin: 1.5rem auto;
}

/* Sized by height, not aspect-ratio: the photos are a mix of orientations, so
   the frame is a fixed window they are fitted into. (aspect-ratio plus a
   max-height would shrink the box's WIDTH to keep the ratio, leaving the stage
   floating inside its own container.)
   The height tracks the viewport's width AND height: on vh alone a phone got a
   245x416 stage, so a landscape photo sat in a thin band with blur above and
   below; the vw term keeps the frame roughly landscape as the page narrows,
   and the vh term stops it eating a short laptop screen. */
.kkrv-showcase__stage {
	position: relative;
	width: 100%;
	height: min(clamp(200px, 62vw, 520px), 62vh);
	border-radius: var(--kkrv-radius);
	overflow: hidden;
	background: var(--kkrv-cream);
	box-shadow: var(--kkrv-shadow-md);
}
/* Blurred copy of the current photo, filling the letterbox bars left by the
   portrait shots. Scaled up so the blur's soft edge never reaches the frame. */
.kkrv-showcase__bg {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transform: scale(1.18);
	filter: blur(28px) saturate(1.15) brightness(0.82);
}
.kkrv-showcase button.kkrv-showcase__open {
	position: absolute;
	inset: 0;
	display: block;
	width: 100%;
	height: 100%;
	padding: 0;
	margin: 0;
	border: 0;
	min-height: 0;
	background: none;
	box-shadow: none;
	cursor: zoom-in;
}
.kkrv-showcase__img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: contain;
}
/* THE bug this file was chasing: this button has no overflow:hidden (it can't —
   it's the hit target for the whole stage, and the photo inside is
   object-fit:contain so it letterboxes for anything that isn't the frame's
   own ratio). Left to the global button:hover (line ~285), its background
   turns solid --kkrv-blue-dark on hover, and that colour shows through the
   letterbox bars above/below (or beside) portrait or odd-ratio photos —
   "background blue poking through at top of image on hover". Default state
   was already background:none, so only :hover needed the override. */
.kkrv-showcase button.kkrv-showcase__open:hover {
	background: none;
	transform: none;
	box-shadow: none;
}
.kkrv-showcase button.kkrv-showcase__open:focus-visible {
	outline: 3px solid var(--kkrv-focus);
	outline-offset: -5px;
}
/* Loading spinner: the stage image and its blurred backdrop are swapped by
   src assignment (gallery.js), which blanks the <img> until the new file has
   downloaded and decoded. Neighbouring photos are preloaded so this is rare,
   but the current photo is still fetched on demand the first time it's shown,
   and this covers that gap instead of leaving the stage looking frozen/blank. */
.kkrv-showcase__spinner {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 2.5rem;
	height: 2.5rem;
	margin: -1.25rem 0 0 -1.25rem;
	border: 3px solid rgba(255, 255, 255, 0.35);
	border-top-color: #fff;
	border-radius: 50%;
	pointer-events: none;
	opacity: 0;
	transition: opacity .15s ease .1s;
	animation: kkrv-spin 0.8s linear infinite;
}
.kkrv-showcase__stage.is-loading .kkrv-showcase__spinner { opacity: 1; }
@keyframes kkrv-spin { to { transform: rotate(360deg); } }
/* Position counter — sits on the photo, so it needs the dark scrim to stay
   legible whatever the image behind it happens to be. */
.kkrv-showcase__count {
	position: absolute;
	right: 0.75rem;
	bottom: 0.75rem;
	margin: 0;
	padding: 0.25rem 0.7rem;
	border-radius: var(--kkrv-btn-radius);
	background: rgba(0, 29, 58, 0.78);
	color: #fff;
	font-size: 0.95rem;
	font-weight: 600;
	pointer-events: none;
}
/* Thumbnail rail. Core lays gallery items out as a grid of equal shares with
   `figure.wp-block-image:not(#individual-image) { width: calc(50% - gap/2) }` —
   an ID-weighted selector, so shrink-to-fit thumbs need !important to win. */
.kkrv-showcase__rail.wp-block-gallery {
	display: flex !important;
	flex-wrap: nowrap !important;
	justify-content: flex-start;
	gap: 0.5rem !important;
	margin: 0.6rem 0 0;
	padding-bottom: 0.35rem;
	overflow-x: auto;
	scrollbar-width: thin;
}
.kkrv-showcase__rail.wp-block-gallery.has-nested-images figure.wp-block-image {
	display: block;
	flex: 0 0 auto !important;
	width: auto !important;
	margin: 0 !important;
}
.kkrv-showcase button.kkrv-showcase__thumb {
	display: block;
	width: clamp(56px, 6vw, 70px);
	padding: 0;
	margin: 0;
	border: 0;
	min-height: 0;
	background: none;
	box-shadow: none;
	border-radius: var(--kkrv-radius-sm);
	overflow: hidden;
	cursor: pointer;
	opacity: 0.62;
	transition: opacity .18s ease;
}
.kkrv-showcase button.kkrv-showcase__thumb img {
	display: block;
	width: 100%;
	aspect-ratio: 1 / 1;
	object-fit: cover;
	border-radius: var(--kkrv-radius-sm);
}
.kkrv-showcase button.kkrv-showcase__thumb:hover { opacity: 1; background: none; transform: none; box-shadow: none; }
/* The selected thumb is marked by a ring AND full opacity — colour alone would
   fail WCAG 1.4.1, and the ring survives high-contrast modes. */
.kkrv-showcase button.kkrv-showcase__thumb.is-current {
	opacity: 1;
	box-shadow: 0 0 0 3px var(--kkrv-green-deep);
}
.kkrv-showcase button.kkrv-showcase__thumb:focus-visible {
	outline: 3px solid var(--kkrv-focus);
	outline-offset: 2px;
}

/* Full-screen lightbox */
body.kkrv-noscroll { overflow: hidden; }
.kkrv-lightbox {
	position: fixed;
	inset: 0;
	z-index: 9999;
	display: flex;
	align-items: center;
	justify-content: center;
}
.kkrv-lightbox[hidden] { display: none; }
.kkrv-lightbox__backdrop {
	position: absolute;
	inset: 0;
	background: rgba(9, 14, 20, 0.93);
	cursor: zoom-out;
}
.kkrv-lightbox__stage {
	position: relative;
	z-index: 1;
	width: 100%;
	height: 100%;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: clamp(1rem, 4vw, 3rem);
}
.kkrv-lightbox__figure {
	position: relative;
	margin: 0;
	max-width: 100%;
	max-height: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.7rem;
}
.kkrv-lightbox__img {
	max-width: min(1200px, 92vw);
	max-height: 82vh;
	width: auto;
	height: auto;
	object-fit: contain;
	border-radius: var(--kkrv-radius-sm);
	box-shadow: 0 12px 44px rgba(0, 0, 0, .55);
}
/* Same rationale as .kkrv-showcase__spinner: covers the blank gap between
   opening the lightbox (or stepping to a neighbour that wasn't preloaded)
   and the full-resolution photo finishing its download. */
.kkrv-lightbox__spinner {
	position: absolute;
	top: 50%;
	left: 50%;
	width: 2.75rem;
	height: 2.75rem;
	margin: -1.375rem 0 0 -1.375rem;
	border: 3px solid rgba(255, 255, 255, 0.3);
	border-top-color: #fff;
	border-radius: 50%;
	pointer-events: none;
	opacity: 0;
	transition: opacity .15s ease .1s;
	animation: kkrv-spin 0.8s linear infinite;
}
.kkrv-lightbox.is-loading .kkrv-lightbox__spinner { opacity: 1; }
.kkrv-lightbox__caption {
	color: #e8eef4;
	font-size: 0.95rem;
	text-align: center;
	max-width: 60ch;
}
.kkrv-lightbox__caption[hidden] { display: none; }
.kkrv-lightbox button.kkrv-lightbox__btn {
	position: absolute;
	z-index: 2;
	background: rgba(255, 255, 255, 0.14);
	color: #fff;
	border: 2px solid transparent;
	border-radius: 50%;
	width: 52px;
	height: 52px;
	min-height: 0;
	padding: 0;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	cursor: pointer;
	font-size: 2.1rem;
	line-height: 1;
}
/* box-shadow:none and transform:none because these round buttons never had
   either — the global button:hover (line ~285) otherwise adds both, and for
   prev/next its translateY(-2px) beats the base rule's translateY(-50%) at
   equal specificity, sliding the circle away from vertical centre and (as in
   the showcase stage above) out from under the pointer mid-click. */
.kkrv-lightbox button.kkrv-lightbox__btn:hover { background: rgba(255, 255, 255, 0.26); transform: none; box-shadow: none; }
.kkrv-lightbox button.kkrv-lightbox__btn:focus-visible { outline: 3px solid var(--kkrv-focus-light); outline-offset: 2px; }
.kkrv-lightbox__close { top: clamp(0.75rem, 2vw, 1.5rem); right: clamp(0.75rem, 2vw, 1.5rem); }
.kkrv-lightbox__prev { left: clamp(0.5rem, 2vw, 1.75rem); top: 50%; transform: translateY(-50%); }
.kkrv-lightbox__next { right: clamp(0.5rem, 2vw, 1.75rem); top: 50%; transform: translateY(-50%); }
/* Same specificity as the :hover rule above (class + button-type + class +
   :hover), so source order — not a losing specificity fight — decides the
   tie and this wins for `transform`. A plain `.kkrv-lightbox__next:hover`
   selector here is LOWER specificity than that rule and silently loses. */
.kkrv-lightbox button.kkrv-lightbox__prev:hover,
.kkrv-lightbox button.kkrv-lightbox__next:hover { transform: translateY(-50%); }
.kkrv-lightbox__btn[hidden] { display: none; }
.kkrv-lightbox__count {
	position: absolute;
	bottom: clamp(0.6rem, 2vw, 1.4rem);
	left: 50%;
	transform: translateX(-50%);
	color: #cdd6df;
	font-size: 0.9rem;
	margin: 0;
	font-variant-numeric: tabular-nums;
}

/* =========================================================
   Centered page-header heros with a background image
   (Independent Living / Quality Care and Support / Village News)
   ========================================================= */
.kkrv-hero--homes,
.kkrv-hero--care,
.kkrv-hero--news { min-height: clamp(260px, 34vh, 380px); }
/* Independent Living's hero wears the sage wash, not the navy one (-00r.43,
   Sean 2026-08-06) — it is the section's colour and the last navy surface on the
   page. /about/, /care/ and /news/ keep navy below.

   THE ALPHAS ARE HIGHER THAN THE NAVY ONES AND THAT IS THE WHOLE POINT. Sage is
   a much lighter colour than navy, so reusing .74/.8 would have dropped white
   text over this photo to 3.62:1 worst case — under the 4.5:1 the hero sub
   needs, and the exact failure the issue predicted. Values below are the deep
   token #3D4C41 (--kkrv-green-deep-dark) at .84/.88, measured against the real
   photo's brightest pixel behind each piece of text: h1 6.1:1, sub 6.0:1,
   eyebrow 5.1:1. Lighten either stop and the sub-headline fails AA. */
.kkrv-hero--homes { background-image: linear-gradient(rgba(61, 76, 65, .84), rgba(61, 76, 65, .88)), url("assets/images/homes/header.webp"); background-position: center 78%; }
/* The eyebrow CANNOT stay light sage here, and no alpha fixes it. --kkrv-green
   on this wash tops out at 3.31:1 even at .88 — it is sage on sage. It reads
   6.9:1 on the navy heroes, which is exactly why reusing the token looked safe.
   Cream is 5.1:1 and still reads as an accent rather than a second headline. */
.kkrv-hero--homes .kkrv-eyebrow { color: var(--kkrv-cream); }
.kkrv-hero--care  { background-image: linear-gradient(rgba(0, 42, 84, .74), rgba(0, 29, 58, .8)), url("assets/images/care/header.webp"); background-position: center 82%; }
.kkrv-hero--news  {
	background-image: linear-gradient(rgba(0, 42, 84, .74), rgba(0, 29, 58, .8)), url("assets/images/news/header.webp");
	/* Keep the seated resident in frame when the 4:3 photograph is cropped into
	   the shallow desktop hero. The mobile crop retains nearly the full height. */
	background-position: center 62%;
}
/* General-site heroes use the same deep-sage wash as Independent Living. Text
   sits in the opaque portion of the directional Home/About wash; the centred
   News hero uses the fully covered treatment. Against the replacement photos,
   the lowest desktop text ratios are Home 4.62:1 and About 4.98:1. The News
   figure is measured separately against its current photograph below. Care is
   deliberately absent and retains its navy gradient above. */
.kkrv-scheme-sage .kkrv-hero--home,
.kkrv-scheme-sage .kkrv-hero--about {
	background-image:
		linear-gradient(90deg, rgba(61, 76, 65, .88) 0%, rgba(61, 76, 65, .78) 48%, rgba(61, 76, 65, .2) 100%),
		var(--kkrv-hero-photo);
}
.kkrv-scheme-sage .kkrv-hero--news {
	/* DSCF0104, measured after its 2026-09-11 replacement by rasterising the
	   photo plus wash and sampling the worst pixel behind every text run. Across
	   1280, 640, 375 and 320px, the minima are eyebrow 5.04:1, h1 5.94:1 and
	   supporting text 6.30:1. Text shadow receives no credit. */
	background-image:
		linear-gradient(rgba(61, 76, 65, .84), rgba(61, 76, 65, .88)),
		url("assets/images/news/header.webp");
}
.kkrv-scheme-sage .kkrv-hero .kkrv-eyebrow { color: var(--kkrv-cream); }
.kkrv-hero--homes .kkrv-hero__content,
.kkrv-hero--care .kkrv-hero__content,
.kkrv-hero--news .kkrv-hero__content {
	max-width: 48rem;
	margin-inline: auto;
	text-align: center;
}
.kkrv-hero--homes .kkrv-hero__sub,
.kkrv-hero--care .kkrv-hero__sub,
.kkrv-hero--news .kkrv-hero__sub {
	max-width: 54ch;
	margin-inline: auto;
}

/* Even out the tab panel's bottom gutter — the last child's margin stacked on top
   of the panel padding, making the bottom read larger than the top/sides. */
.kkrv-tabs__panel > :last-child,
.kkrv-tabs__panel > .wp-block-group__inner-container > :last-child { margin-bottom: 0; }

/* =========================================================
   Hero path cards — the Independent Living / Quality Care and Support
   choice, straddling the bottom edge of the hero (Home,
   About). Issue 6wt.
   ========================================================= */

/* The overhang is declared once and read three times: to pull the cards down
   past the hero's edge, to add matching clearance below so the next section is
   not overlapped, and to reset both to zero on narrow screens where the cards
   sit inside the band instead. One custom property is what stops those three
   from drifting apart when the padding is next tuned. */
.kkrv-hero--paths {
	--kkrv-paths-overhang: clamp(2.5rem, 5vw, 4rem);
	/* Shorter than a plain hero: the cards add their own height, and the whole
	   point of the change is that both paths are reachable without scrolling.
	   At the old clamp(420px, 60vh, 600px) the cards landed below the fold on a
	   900px-tall window, which would have defeated the exercise. */
	min-height: clamp(360px, 50vh, 500px);
	padding-bottom: clamp(1.75rem, 4vw, 2.5rem);
	margin-bottom: calc(clamp(2.25rem, 5vw, 3.5rem) + var(--kkrv-paths-overhang));
}
/* The text block is tuned down so the cards clear the fold: wider measure and a
   smaller display size on the h1, and the subheading given enough width to sit
   on three lines instead of four. Every line saved here is a line of card that
   becomes visible without scrolling, which is the whole point of the change. */
.kkrv-hero--paths .kkrv-hero__content { max-width: 44rem; }
.kkrv-hero--paths h1 { font-size: clamp(1.9rem, 3.4vw, 2.75rem); }
.kkrv-hero--paths .kkrv-hero__sub {
	max-width: 58ch;
	margin-bottom: 0;
}
.kkrv-hero__paths {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: clamp(0.9rem, 2vw, 1.25rem);
	/* Narrower than the 1100px hero container so the cards stay a comfortable
	   reading width and leave the right of the photo visible. */
	max-width: 46rem;
	margin: clamp(1.5rem, 3vw, 2.25rem) 0 calc(-1 * var(--kkrv-paths-overhang));
	padding: 0;
	list-style: none;
}
.kkrv-path-card {
	position: relative;
	display: flex;
	flex-direction: column;
	background: var(--kkrv-card);
	border: 1px solid var(--kkrv-border);
	/* Colour comes from the --living / --care modifier below, never from here.
	   Until -00r.43 both cards shared one green top border, so the only accent in
	   play was the same on the two things it was meant to tell apart. */
	border-top: 3px solid var(--kkrv-blue);
	border-radius: var(--kkrv-radius);
	/* A heavier shadow than .kkrv-card: these sit half over a photo and need to
	   read as lifted off it, not printed on it. The colour is the warm shadow ink
	   of the --kkrv-shadow-* tokens (-zvj.6); only the alpha is heavier. Cards
	   half over a photo are where a shadow hue shows most, so this pair has to
	   move with the tokens or the home hero is the one cool shadow on the site. */
	box-shadow: 0 8px 24px rgba(42, 35, 23, .18);
	padding: clamp(1.15rem, 2.5vw, 1.6rem);
	transition: transform .2s ease, box-shadow .2s ease;
}
.kkrv-path-card:hover {
	transform: translateY(-3px);
	box-shadow: 0 12px 30px rgba(42, 35, 23, .24);
}
.kkrv-path-card__title {
	font-size: clamp(1.15rem, 2vw, 1.4rem);
	margin: 0 0 0.4rem;
	color: var(--kkrv-blue);
}
.kkrv-path-card__title a {
	color: inherit;
	text-decoration: none;
}
/* The whole card is the click target. The overlay is attached to the LINK, not
   the card, for two reasons: the click event still originates from the anchor
   (analytics.js reads href off it), and the link's accessible name stays just
   the heading text — a screen reader announces "Independent Living, link", not
   the heading plus description plus "explore" run together. */
.kkrv-path-card__title a::after {
	content: "";
	position: absolute;
	inset: 0;
	border-radius: var(--kkrv-radius);
}
.kkrv-path-card__desc {
	margin: 0 0 0.9rem;
	font-size: 0.98rem;
	line-height: 1.5;
	color: var(--kkrv-ink-soft);
}
/* margin-top:auto pins this to the bottom so both cards' arrows line up even
   when the two descriptions wrap to different heights. */
.kkrv-path-card__more {
	display: inline-flex;
	align-items: center;
	gap: 0.4rem;
	margin-top: auto;
	font-weight: 700;
	font-size: 0.95rem;
	color: var(--kkrv-blue);
}
/* THE TWO LIVING OPTIONS ARE TOLD APART BY COLOUR, NOT ONLY BY WORDING
   (-00r.43). Independent Living is sage green, Quality Care and Support is navy,
   and the same pairing repeats on the Independent Living page's tabs and
   buttons. The modifier is written into the markup on both /  and /about/ and
   keyed to the card's own link — :first-child would repaint the wrong card the
   day a third one appears. */
.kkrv-path-card--living { border-top-color: var(--kkrv-green-deep); }
.kkrv-path-card--living .kkrv-path-card__title,
.kkrv-path-card--living .kkrv-path-card__more { color: var(--kkrv-green-deep); }

.kkrv-path-card--care { border-top-color: var(--kkrv-blue); }
.kkrv-path-card--care .kkrv-path-card__title,
.kkrv-path-card--care .kkrv-path-card__more { color: var(--kkrv-blue); }

.kkrv-path-card__arrow {
	flex: none;
	transition: transform .2s ease;
}
.kkrv-path-card:hover .kkrv-path-card__arrow { transform: translateX(4px); }

/* Focus ring is drawn around the whole card, because the whole card is the
   target — a ring hugging just the heading text would point at the wrong
   thing. The link keeps its own default ring wherever :has() is unsupported,
   so focus can never end up invisible. */
.kkrv-path-card:has(a:focus-visible) {
	outline: 3px solid var(--kkrv-focus);
	outline-offset: 3px;
}
@supports selector(:has(*)) {
	.kkrv-path-card__title a:focus-visible { outline: none; }
}

@media (max-width: 860px) {
	.kkrv-hero__paths { max-width: none; }
}

@media (max-width: 640px) {
	/* Stacked, and sitting inside the hero rather than straddling it — at this
	   width an overhang just crowds the next section. */
	.kkrv-hero--paths {
		--kkrv-paths-overhang: 0px;
		margin-bottom: clamp(2.25rem, 5vw, 3.5rem);
	}
	.kkrv-hero__paths { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 480px) {
	/* Cards win above the fold. The photo collapses to a banner and the heading
	   and both cards sit on solid navy beneath it, so nothing competes for the
	   first screen. White on --kkrv-blue is ~14:1, so no scrim is needed under
	   the text and the hero gradient is dropped here entirely.

	   The photo moves to a ::before rather than staying the element's own
	   background, because `cover` sizes against the WHOLE element: on a phone
	   the hero is ~780px tall and 375px wide, so cover would scale the 3:2
	   photo to fill that height and the 180px band would show a narrow vertical
	   sliver of it — roofline and sky, no people. Sizing a fixed 180px box
	   instead crops the way a 180px banner should. */
	.kkrv-hero--paths {
		/* Band height in one property: the element's top padding and the
		   ::before that paints the photo must agree exactly, or the navy panel
		   overlaps the photo or leaves a gap. */
		--kkrv-hero-band: 150px;
		min-height: 0;
		align-items: flex-start;
		padding: var(--kkrv-hero-band) 0 0;
		background-image: none;
		background-color: var(--kkrv-page-accent);
	}
	.kkrv-hero--paths::before {
		content: "";
		position: absolute;
		top: 0;
		left: 0;
		right: 0;
		height: var(--kkrv-hero-band);
		background-image: var(--kkrv-hero-photo);
		background-size: cover;
		background-position: center 55%;
		background-repeat: no-repeat;
	}
	/* Every line saved above the cards is a line of card that clears the fold.
	   The eyebrow is tightened to hold one line, and the heading and subheading
	   step down a size — the first card lands on the fold instead of 170px
	   below it. Both cards cannot fit a 812px phone screen at readable sizes;
	   the second is deliberately left half-visible so it reads as "there is
	   another option here" rather than as the end of the page. */
	.kkrv-hero--paths .kkrv-eyebrow {
		font-size: 0.74rem;
		letter-spacing: 0.06em;
	}
	.kkrv-hero--paths h1 { font-size: 1.75rem; }
	.kkrv-hero--paths .kkrv-hero__sub {
		font-size: 1.02rem;
		line-height: 1.45;
	}
	/* Keeps the solid colour panel above the photo band if the two ever meet. */
	.kkrv-hero--paths .kkrv-hero__inner {
		position: relative;
		background: var(--kkrv-page-accent);
		padding: clamp(1.25rem, 5vw, 1.75rem);
	}
	.kkrv-hero--paths .kkrv-hero__content { max-width: none; }
	.kkrv-hero--paths .kkrv-hero__sub { margin-bottom: 0; }
}

/* =========================================================
   Section rhythm (47v)
   ========================================================= */
/*
   A top-level h2 is what starts a new section on these pages, so the section
   gap hangs off it rather than being re-guessed on each component below.

   Measured before this rule existed (homepage, 1280px): the gaps at section
   BOUNDARIES were 0px, 0px, 20px and 32px, while the gap between a heading and
   its own content was 20px. So "new section" and "next paragraph" were visually
   identical and the page read as one undifferentiated stream — two sections
   literally butted against each other with no gap at all. That is the client's
   "padding is still wrong on the homepage".

   One gap, declared once, from the --kkrv-space-section token that was already
   in :root but used in only one place. Sections now separate at ~3-4x their
   internal spacing, which is what makes the boundary legible.
*/
.entry-content > h2 { margin-top: var(--kkrv-space-section); }

/* A hero already supplies the gap beneath itself — plus the path-card overhang
   on Home and About — so the first section must not stack a second gap on top.
   Same for a page whose content opens on a heading. */
.entry-content > .kkrv-hero + h2,
.entry-content > h2:first-child { margin-top: 0; }

/* An eyebrow is the kicker FOR the heading beneath it. Without these two rules
   the gap lands between the kicker and its own h2, which reads as a stray
   trailing line of the section above (seen on About: "On your doorstep" was cut
   adrift from "Facilities and services"). So the gap moves up onto the eyebrow
   and the heading closes back up under it. */
.entry-content > .kkrv-eyebrow { margin-top: var(--kkrv-space-section); }
.entry-content > .kkrv-eyebrow + h2 { margin-top: 0; }

/* Full-bleed bands set their own top gap (see .kkrv-cta-band and
   .kkrv-band-green) because they are section starts in their own right without
   carrying a top-level h2. */

/* A link wears the colour of its destination. Reset the scheme tokens on the
   link itself so every current and future component rule that reads them —
   prose, buttons, path cards and navigation — gets the care exception without
   knowing where the link happens to sit. The forms below cover root-relative,
   document-relative and absolute internal URLs, with an optional slash or
   fragment. Query strings are intentionally not used for page identity. */
.kkrv-scheme-sage a:is(
	[href="quality-care-and-support"],
	[href="quality-care-and-support/"],
	[href^="quality-care-and-support#"],
	[href^="quality-care-and-support/#"],
	[href="/quality-care-and-support"],
	[href="/quality-care-and-support/"],
	[href^="/quality-care-and-support#"],
	[href^="/quality-care-and-support/#"],
	[href$="/quality-care-and-support"],
	[href$="/quality-care-and-support/"],
	[href*="/quality-care-and-support#"],
	[href*="/quality-care-and-support/#"]
) {
	--kkrv-page-accent: var(--kkrv-blue);
	--kkrv-page-accent-dark: var(--kkrv-blue-dark);
	--kkrv-page-accent-tint: var(--kkrv-bg-alt);
}
