/* ============================================================
   1st Brabazon Scout Group — shared stylesheet
   Palette: Scouts Navy #003982 | Scouts Yellow #FFE627 | cream #F7F5F1, plus the five
   Scouts section colours (see "Section branding")
   Type: Nunito Sans (Scouts brand typeface, all weights)
   ============================================================ */

/* --- Self-hosted web font (latin subset, variable) -----------------------
   Nunito Sans is the Scouts brand typeface (brand guidelines v3.3, p34). It is a
   free Google font, but it is self-hosted deliberately: that drops the third-party
   call (visitor IPs stay off Google) and removes the render-blocking request to
   fonts.googleapis.com. One variable file covers the whole brand weight range —
   Light 300, Regular 400, Bold 700, Extra Bold 800, Black 900 — for 31KB, replacing
   the 68KB of Bricolage Grotesque + Public Sans it succeeded. */
@font-face {
	font-family: "Nunito Sans";
	src: url("fonts/nunito-sans.woff2") format("woff2");
	font-weight: 300 900;
	font-style: normal;
	font-display: swap;
}

:root {
	--navy: #003982;
	--navy-2: #0a4d9e;
	/* --gold/--gold-soft keep their names to stay in step with the .btn-gold and
	   .tag-* classes in the HTML; the value is Scouts Yellow. */
	--gold: #ffe627;
	--gold-soft: #fff5a9;
	--cream: #f7f5f1;
	--white: #ffffff;
	--ink: #003982;
	--muted: #565c77;
	--line: #e3ded6;
	--ok: #1b7f4d;
	--danger: #b3261e;
	/* ---- Accent: the colour a page leads with -------------------------------
	   Everything below the header and above the footer paints from these tokens
	   rather than naming a colour directly, so a page can re-point them at its own
	   section colour (see "Section branding" below) and the whole body of the page
	   follows. The defaults are Scouts Navy, the 1st Brabazon colour, which is what
	   group-wide pages — home, join, parents, trustees, news, contact — use.

	   The header and footer deliberately do NOT read these: they are Scouts Navy and
	   Scouts Yellow on every page, so the 1st Brabazon frame is constant while the
	   content inside it changes colour. On a group-wide page the two now agree, which
	   is the point — the whole page is the group's own colour.

	   --accent-2 is lighter than --accent under the group theme and darker under a
	   section theme. That is deliberate: it has to stay visible against BOTH --accent
	   and the navy body text, and navy is already the darkest ink on the page.

	   --accent      marks and text on cream/white, and fills behind white text
	   --accent-2    the second shade: links, hovers, and button hover fills
	   --accent-soft a 10% tint for icon plates and panels
	   --accent-ring the focus glow on form fields (rgba, so it can sit under 20%) */
	--accent: var(--navy);
	--accent-2: var(--navy-2);
	--accent-soft: #e6ebf3;
	--accent-ring: rgba(0, 57, 130, 0.18);
	/* The flat block behind a hero. Scouts Navy leads on group-wide pages; a section
	   theme swaps in its own colour. It is a separate token from --accent because a
	   hero also has to carry Scouts Yellow (.text-gold) at 4.5:1, which is a
	   darker ceiling than merely reading as text on cream.

	   Flat, and not a gradient: the Scouts palette is ten solid hexes, the guidelines
	   only ever describe text "on a solid colour background", and nothing in them
	   sanctions blending two colours into one another. The hero used to fade Navy into
	   Purple, which looked well enough but was not the brand. */
	--hero-bg: var(--navy);
	--radius: 18px;
	--radius-sm: 12px;
	--shadow: 0 10px 30px rgba(0, 57, 130, 0.1);
	--shadow-lift: 0 16px 34px rgba(0, 57, 130, 0.22);
	--ease: cubic-bezier(0.2, 0.7, 0.3, 1);
	--font-head:
		"Nunito Sans", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
	--font-body:
		"Nunito Sans", system-ui, -apple-system, "Segoe UI", Arial, sans-serif;
}

/* ---------- Section branding --------------------------------------------------
   Put `data-section="squirrels"` (or beavers / cubs / scouts / explorers) on the
   <body> of a section page and the accent tokens re-point, so the hero block,
   kickers, ticks, links, tabs and buttons all pick up that section's colour. The
   header and footer never read these tokens, so they stay Scouts Navy and Scouts
   Yellow throughout and the page still reads as 1st Brabazon.

   Group-wide pages — index, join, parents, trustees, news, contact, support,
   volunteer — carry no attribute and keep the Scouts Navy defaults.

   The attribute also works on a single element: beyond.html puts it on each of
   the three District cards so a Cubs card is green without colouring the page.

   ---- Why these are not the raw brand hexes ----
   The section hues come from the Scouts palette (brand/brand-guidelines.md), but
   most are too light to carry white or yellow text at the sizes used here, so
   each one is darkened to clear WCAG 2.2 SC 1.4.3. Same trade-off, and the same
   reasoning, as --ok and --danger. Measured against the surface each token
   actually lands on:

     section    brand hex   --accent on cream   --hero-bg under Scouts Yellow
     Beavers    #006ddf     4.60:1              4.62:1
     Cubs       #25b755     4.66:1              4.63:1
     Scouts     #205b41     7.32:1              6.30:1   (dark enough as-is)
     Explorers  #088486     4.66:1              4.65:1

   Forest Green, the Scouts section's colour, already clears both bars, so it is
   the one used unmodified.

   Squirrels is a deliberate exception, not an oversight: it runs on the true,
   undarkened #ed3f23 (white text on it measures 3.94:1 — under the 4.5:1 normal-
   text floor, though still clear of the 3:1 floor for large text and graphics).
   Kept anyway on a direct, explicit group decision to match the brand hex
   scouts.org.uk itself shows for Squirrels rather than a locally-darkened tone.
   See "Known deviations" in brand/brand-guidelines.md. */
[data-section="squirrels"] {
	/* Squirrels Red #ed3f23, used true rather than darkened — see "Why these are
	   not the raw brand hexes" above and "Known deviations" in
	   brand/brand-guidelines.md. --accent-2 keeps the previously-darkened tone as
	   a hover/pressed shade, so interactive states still read as a step darker. */
	--accent: #ed3f23;
	--accent-2: #ce371e;
	--accent-soft: #fdece9;
	--accent-ring: rgba(237, 63, 35, 0.18);
	--hero-bg: #ed3f23;
}
[data-section="beavers"] {
	/* Scouts Blue #006ddf */
	--accent: #006cdd;
	--accent-2: #004389;
	--accent-soft: #e6f0fc;
	--accent-ring: rgba(0, 108, 221, 0.18);
	--hero-bg: #0062c9;
}
[data-section="cubs"] {
	/* Scouts Green #25b755 */
	--accent: #1a7f3b;
	--accent-2: #104f25;
	--accent-soft: #e9f8ee;
	--accent-ring: rgba(26, 127, 59, 0.18);
	--hero-bg: #177436;
}
[data-section="scouts"] {
	/* Scouts Forest Green #205b41 — used at full strength */
	--accent: #205b41;
	--accent-2: #143828;
	--accent-soft: #e9efec;
	--accent-ring: rgba(32, 91, 65, 0.18);
	--hero-bg: #205b41;
}
[data-section="explorers"] {
	/* Scouts Teal #088486 */
	--accent: #077b7d;
	--accent-2: #054d4e;
	--accent-soft: #e6f3f3;
	--accent-ring: rgba(7, 123, 125, 0.18);
	--hero-bg: #077072;
}
[data-section="network"] {
	/* Black #000000 (Process Black C), used at full strength like Scouts Forest
	   Green above – it needs no darkening for contrast, since nothing is darker.
	   --accent-2 (the hover/pressed shade every other section reaches by going
	   darker) instead lightens one step, reusing the exact grey already established
	   for a black hover elsewhere on this site (.contact-form.is-safeguarding
	   .btn-accent:hover). --accent-soft is an independently-judged 10% tint for
	   this UI's own use (icon plates, panel washes – see the --accent-soft
	   definition further up), not one of the brand's own 20/40/60/80% tint steps,
	   which all land too dark for that role. Never paired with Scouts Yellow: that
	   combination is reserved for safeguarding messaging (brand-guidelines.md). */
	--accent: #000000;
	--accent-2: #262626;
	--accent-soft: #e6e6e6;
	--accent-ring: rgba(0, 0, 0, 0.18);
	--hero-bg: #000000;
}
* {
	box-sizing: border-box;
}
/* The `hidden` attribute only sets display:none in the browser's own stylesheet, so
   ANY author rule that gives an element a display value silently wins and the
   element stays visible. That trap has been hit four separate times in this file
   (.tag on the news hero, .show-more-btn, .prog-panel, .drive-block), each time
   needing its own opt-out. This one rule covers all of them at once, so setting
   el.hidden = true now always hides the element. */
[hidden] {
	display: none !important;
}
html {
	scroll-behavior: smooth;
	/* Anchor targets must clear the sticky header (~108px) or headings land underneath it. */
	scroll-padding-top: 124px;
}
body {
	margin: 0;
	font-family: var(--font-body);
	color: var(--ink);
	background: var(--cream);
	line-height: 1.6;
	font-size: 17px;
	-webkit-font-smoothing: antialiased;
}
img {
	max-width: 100%;
	height: auto;
	display: block;
}
picture {
	display: block;
}
h1,
h2,
h3,
h4 {
	/* Black (900) — the brand guidelines specify Nunito Sans Black for headlines. */
	font-weight: 900;
	font-family: var(--font-head);
	line-height: 1.12;
	margin: 0 0 0.4em;
	color: var(--navy);
	letter-spacing: -0.01em;
}
/* Tighter tracking as size grows — the biggest weight (900) reads best a touch
   condensed at display sizes, where the default -0.01em is barely noticeable. */
h1 {
	letter-spacing: -0.03em;
}
h2 {
	letter-spacing: -0.02em;
}
p {
	margin: 0 0 1em;
}
a {
	color: var(--accent-2);
}
a:hover {
	text-decoration-thickness: 2px;
}
ul {
	margin: 0 0 1em;
	padding-left: 1.1em;
}
/* Gold only reaches 1.6:1 on cream/white, well under the 3:1 WCAG 2.2 SC 1.4.11 floor.
   Navy is the default ring; gold is swapped in only over dark backgrounds. */
:focus-visible {
	outline: 3px solid var(--navy);
	outline-offset: 2px;
	border-radius: 4px;
}
.hero :focus-visible,
.page-hero :focus-visible,
.section-navy :focus-visible,
.site-header :focus-visible,
.site-footer :focus-visible,
.mobile-cta-bar :focus-visible {
	outline-color: var(--gold);
}
.visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	white-space: nowrap;
}
.skip-link {
	position: absolute;
	left: 8px;
	top: -60px;
	z-index: 200;
	background: var(--gold);
	color: var(--navy);
	padding: 10px 16px;
	border-radius: 8px;
	font-weight: 700;
	transition: top 0.15s;
}
.skip-link:focus {
	top: 8px;
}
.wrap {
	max-width: 1180px;
	margin: 0 auto;
	padding: 0 22px;
}

/* ---------- Buttons ---------- */
.btn {
	display: inline-flex;
	align-items: center;
	gap: 0.45em;
	padding: 0.85em 1.6em;
	border-radius: 999px;
	border: 2px solid transparent;
	font: 700 1rem / 1 var(--font-body);
	text-decoration: none;
	cursor: pointer;
	transition:
		transform 0.12s ease,
		box-shadow 0.12s ease,
		background 0.12s ease;
}
.btn:hover {
	transform: translateY(-2px);
}
.btn:active {
	transform: translateY(0);
}
.btn-gold {
	background: var(--gold);
	color: var(--navy);
}
.btn-gold:hover {
	background: #fff05c;
	box-shadow: 0 8px 18px rgba(255, 230, 39, 0.35);
}
/* The page's own colour as a solid button: navy on a group page, red on a Squirrels
   page, blue on a Beavers one. Hover moves to --accent-2 rather than a fixed second
   hex, which would stay one colour under every theme, and rather than a translucent
   wash over the fill, which is a gradient by another name. */
.btn-accent {
	background: var(--accent);
	color: #fff;
}
.btn-accent:hover {
	background: var(--accent-2);
	box-shadow: 0 8px 18px rgba(0, 0, 0, 0.22);
}
/* .ext-link's arrow is coloured with var(--accent) (see further down), same as
   this button's own fill — invisible on any page where the two match (e.g. a
   red-accent section page). Matching the button's own text colour instead
   keeps it visible under every theme. */
.btn-accent .ext-link::after {
	color: currentColor;
}
/* The page's own colour as an outline pill: transparent fill, accent border and
   text, a lighter-weight sibling to the solid .btn-accent above for links that
   shouldn't all compete for attention on the same card. */
.btn-accent-outline {
	background: transparent;
	color: var(--accent);
	border-color: var(--accent);
}
.btn-accent-outline:hover {
	background: var(--accent-soft);
}
.btn-outline {
	background: transparent;
	color: #fff;
	border-color: rgba(255, 255, 255, 0.65);
}
.btn-outline:hover {
	background: rgba(255, 255, 255, 0.12);
}
.btn-navy {
	background: var(--navy);
	color: #fff;
}
.btn-navy:hover {
	background: var(--navy-2);
}
/* Black on Scouts Yellow, inverted from .panel-safeguarding's yellow-on-black
   panel so a pill button still reads as a distinct, clickable shape rather
   than disappearing into the panel it sits on — same reserved safeguarding
   pairing (see .section-safeguarding), just the two colours swapped. */
.btn-safeguarding {
	background: #000;
	color: var(--gold);
}
.btn-safeguarding:hover {
	background: #262626;
}
/* Same fix as .btn-accent above: .ext-link's arrow defaults to var(--accent)
   (Navy on this group page), which would render as a near-invisible navy
   arrow on this button's black fill. Match the button's own text colour. */
.btn-safeguarding .ext-link::after {
	color: currentColor;
}
.btn-ghost {
	background: transparent;
	color: var(--navy);
	border-color: var(--navy);
}
.btn-ghost:hover {
	background: var(--navy);
	color: #fff;
}
.btn-sm {
	padding: 0.55em 1.1em;
	font-size: 0.9rem;
}
/* A "Moving up" link rendered as the NEXT section's own logo and colour rather
   than this page's accent and a text label — a deliberate break from the
   usual .btn-accent pattern, since the point is to recognise the section
   you're heading to before you even read the word. Colours are the other
   section's own --accent hex, hard-coded rather than read from a variable:
   this button lives on a page whose --accent is a different section's colour
   entirely (e.g. Squirrels' own red, for a button that must be Beavers' blue). */
.btn-section-link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	padding: 1em 2.4em;
	border-radius: 999px;
	transition:
		transform 0.12s ease,
		box-shadow 0.12s ease,
		filter 0.12s ease;
}
.btn-section-link:hover {
	transform: translateY(-2px);
	filter: brightness(0.92);
}
.btn-section-link-logo {
	display: inline-block;
	height: 1.7em;
	background: #fff;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-size: contain;
	mask-size: contain;
}
.btn-section-link-beavers {
	background: #006cdd; /* Scouts Blue — [data-section="beavers"] --accent */
}
.btn-section-link-beavers .btn-section-link-logo {
	aspect-ratio: 166 / 46;
	-webkit-mask-image: url("logos/beavers.svg");
	mask-image: url("logos/beavers.svg");
}
.btn-section-link-cubs {
	background: #1a7f3b; /* Scouts Green — [data-section="cubs"] --accent */
}
.btn-section-link-cubs .btn-section-link-logo {
	aspect-ratio: 110 / 43;
	-webkit-mask-image: url("logos/cubs.svg");
	mask-image: url("logos/cubs.svg");
}

/* ---------- Header ---------- */
.site-header {
	position: -webkit-sticky;
	position: sticky;
	top: 0;
	z-index: 100;
	/* Solid --navy, not rgba(…, 0.96). The header is sticky, so at 96% whatever
	   scrolled beneath it tinted the bar — and with it the fleur-de-lis and the
	   Brabazon wordmark, which are CSS masks painted in currentColor directly onto
	   this background. The logos must render clean and untouched (POR 2e.2), which
	   they cannot do over a surface that shifts colour as the page moves. */
	background: var(--navy);
	color: #fff;
	border-bottom: 3px solid var(--gold);
}
.site-header.scrolled {
	box-shadow: 0 4px 18px rgba(0, 57, 130, 0.35);
}
/* Same 1180px box as .wrap so the logo lines up with page content at every width. */
.header-inner {
	display: flex;
	align-items: center;
	gap: 14px;
	padding: 10px 22px;
	max-width: 1180px;
	margin: 0 auto;
}
.brand {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	color: var(--gold);
	text-decoration: none;
	flex: 0 1 auto;
	min-width: 0;
}
/* The fleur-de-lis and the Brabazon wordmark are painted as CSS masks rather than inlined
   or dropped in an <img>. An <img> renders the SVG in its own document, where the file's
   `currentColor` cannot see this stylesheet, so it would come out black; inlining both would
   repeat ~19KB of path data in all 11 pages. As masks they stay one cached file each and take
   their colour from `background`, so they follow the palette tokens like everything else. */
.brand-fleur,
.brand-wordmark {
	flex: none;
	background: currentColor;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-size: contain;
	mask-size: contain;
}
.brand-fleur {
	/* Artwork is 2067 x 1884. */
	/* Scouts Yellow, not white — a deliberate departure from the guidelines (2026-09-12), which
	   call for white on a palette-colour background and don't list yellow as a permitted logo
	   colourway. Tracked in brand/brand-guidelines.md → Known deviations. 8.70:1 against the
	   navy bar, well past the 3:1 WCAG 2.2 SC 1.4.11 floor for graphical objects. */
	background: var(--gold);
	width: 48px;
	height: 44px;
	-webkit-mask-image: url("logos/fleur-de-lis.svg");
	mask-image: url("logos/fleur-de-lis.svg");
}
.brand-wordmark {
	/* Artwork is 1794 x 350. */
	width: 92px;
	height: 18px;
	-webkit-mask-image: url("logos/brabazon.svg");
	mask-image: url("logos/brabazon.svg");
}
.brand-1st {
	font-weight: 800;
	font-size: 1.4rem;
	line-height: 1;
	letter-spacing: -0.01em;
}
/* The header keeps the brand and the Menu button on one row, so the lock-up has to give
   ground on narrow phones or it pushes the button off-screen. */
@media (max-width: 700px) {
	.brand {
		gap: 7px;
	}
	.brand-fleur {
		width: 39px;
		height: 36px;
	}
	.brand-wordmark {
		width: 77px;
		height: 15px;
	}
	.brand-1st {
		font-size: 1.15rem;
	}
}
.nav-toggle {
	display: none;
	margin-left: auto;
	background: none;
	border: 2px solid rgba(255, 255, 255, 0.5);
	color: #fff;
	font: 700 0.95rem var(--font-body);
	padding: 0.45em 0.9em;
	border-radius: 10px;
	cursor: pointer;
}
.site-nav {
	margin-left: auto;
	min-width: 0;
}
/* Sized so the 10 links stay on one row at every width above the 1300px collapse point;
   a 1180px header only has ~764px to give them, and wrapping looked accidental. */
.nav {
	display: flex;
	list-style: none;
	margin: 0;
	padding: 0;
	gap: 0;
	align-items: center;
	flex-wrap: wrap;
}
.nav a {
	display: block;
	color: #e4eefb;
	text-decoration: none;
	padding: 0.55em 0.45em;
	border-radius: 10px;
	font-size: 0.88rem;
	font-weight: 500;
	white-space: nowrap;
}
.nav a:hover {
	background: rgba(255, 255, 255, 0.08);
	color: var(--gold);
}
.nav a.active {
	background: rgba(255, 230, 39, 0.22);
	color: var(--gold);
	font-weight: 700;
}
/* Group headings are a drawer-only affordance. Hidden inside the max-width:1300px block
   they stayed visible on laptops, reading as clickable nav links. */
.nav-group-label {
	display: none;
}
/* No margin-left here: .header-inner already supplies a 14px flex gap, and the duplicate
   was the difference between the 10 nav links fitting on one row and wrapping. */
.header-cta {
	flex: 0 0 auto;
}
.header-cta .btn {
	padding: 0.62em 1.25em;
	font-size: 0.95rem;
}

/* ---------- Hero (home) ---------- */
.hero {
	background: var(--hero-bg);
	color: #fff;
	padding: 96px 0 104px;
	position: relative;
	overflow: hidden;
}
.hero-inner {
	position: relative;
	z-index: 1;
	max-width: 640px;
}
/* The fleur-de-lis, huge and nearly invisible, bled off the right edge — a flat
   brand device rather than a stock photo or a gradient wash, and the one thing in
   the hero that isn't already said in words somewhere else on the page. Inlined
   (not a background-image) because currentColor only works on an inline SVG — see
   the logos note in README.md. */
.hero-mark {
	position: absolute;
	top: 50%;
	right: -8%;
	transform: translateY(-50%);
	width: clamp(440px, 48vw, 780px);
	height: auto;
	color: #fff;
	opacity: 0.06;
	pointer-events: none;
	z-index: 0;
}
@media (max-width: 700px) {
	.hero-mark {
		display: none;
	}
}
.hero h1 {
	color: #fff;
	font-size: clamp(2.7rem, 7.2vw, 5.6rem);
	letter-spacing: -0.04em;
	margin-bottom: 0.25em;
}
.hero .h-sub {
	font-size: clamp(1.05rem, 2.2vw, 1.3rem);
	color: #e8e4f6;
	max-width: 30em;
	margin-bottom: 24px;
}
/* The two section panels, linked to their own pages and carrying their own colour —
   a stripe above the logo, a 10% wash behind the card, and the accent on hover —
   the same device as .card[data-section] on beyond.html and .js-card on the journey
   rail below. White rather than a tint of navy: the Squirrels and Beavers logos are
   Scouts Red and Scouts Blue, which fall to 2.8:1 and 2.2:1 against navy and must sit
   on white, so the wash sits UNDER the white card as its own background, and the
   card itself stays var(--white) until a theme's --accent-soft overrides it. */
.hero-secs {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
	gap: 16px;
	margin: 0 0 30px;
	padding: 0;
	list-style: none;
	max-width: 34em;
}
.hero-sec {
	display: block;
	background: var(--white);
	color: var(--ink);
	text-decoration: none;
	border: 2px solid transparent;
	border-radius: var(--radius);
	padding: 18px 20px 16px;
	transition:
		transform 0.12s ease,
		box-shadow 0.12s ease,
		border-color 0.12s;
}
.hero-sec[data-section] {
	background: var(--accent-soft);
	border-top: 4px solid var(--accent);
}
/* Squirrels and Beavers specifically – the two sections 1st Brabazon runs
   itself, not District – get the fuller "own section" treatment introduced
   by .journey-stop--own .js-card further down: a full accent-colour border
   rather than just the top stripe above. No shadow added to match it,
   though: --shadow-lift is a low-opacity navy tint, invisible against this
   hero's own navy background – the same reason its :hover state below
   already reaches for a bespoke dark shadow instead of --shadow. */
.hero-sec[data-section="squirrels"],
.hero-sec[data-section="beavers"] {
	border: 2px solid var(--accent);
}
.hero-sec:hover,
.hero-sec:focus-visible {
	transform: translateY(-4px);
	border-color: var(--accent);
	/* --shadow is a 10% navy, which is invisible on the navy hero. */
	box-shadow: 0 14px 30px rgba(8, 10, 35, 0.38);
}
.hero-sec .logo {
	height: 34px;
	width: auto;
	margin-bottom: 12px;
}
.hero-sec .row {
	display: flex;
	align-items: baseline;
	gap: 8px;
	font-size: 1rem;
}
.hero-sec .row + .row {
	margin-top: 2px;
}
.hero-sec .k {
	font-weight: 800;
}
.hero-sec .where {
	margin: 9px 0 0;
	padding-top: 9px;
	border-top: 1px solid var(--line);
	font-size: 0.85rem;
	color: var(--muted);
}
.hero-sec:hover .where,
.hero-sec:focus-visible .where {
	color: var(--accent);
}
.hero-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 14px;
}
/* ---------- Hero entrance ----------
   Four elements, 70ms apart, once on load — not on every scroll. Only transform and
   opacity animate, so it stays on the compositor. prefers-reduced-motion (below)
   collapses the animation-duration to near-zero but keeps the forwards fill, so
   reduced-motion visitors land straight on the resting state instead of stuck at
   opacity:0. */
.hero-inner > * {
	opacity: 0;
	transform: translateY(14px);
	animation: hero-rise 0.5s cubic-bezier(0.2, 0.7, 0.3, 1) forwards;
}
.hero-inner > *:nth-child(1) {
	animation-delay: 0s;
}
.hero-inner > *:nth-child(2) {
	animation-delay: 0.07s;
}
.hero-inner > *:nth-child(3) {
	animation-delay: 0.14s;
}
.hero-inner > *:nth-child(4) {
	animation-delay: 0.21s;
}
@keyframes hero-rise {
	to {
		opacity: 1;
		transform: none;
	}
}

/* Interior page hero */
.page-hero {
	background: var(--hero-bg);
	color: #fff;
	padding: 58px 0 54px;
}
.page-hero .wrap {
	position: relative;
}
.page-hero h1 {
	color: #fff;
	font-size: clamp(2rem, 4.5vw, 3rem);
	margin-bottom: 0.15em;
}
/* The Brabazon wordmark set inline in running heading text, e.g. "Join <mark>Brabazon</mark>".
   Painted as a CSS mask (see .brand-wordmark above) so it takes Scouts Yellow from `background`
   rather than needing an <img>. 0.8em is the header lock-up's own ratio for pairing this
   wordmark with "1st" (see .brand-wordmark comment) — reused here so the two "1st Brabazon"
   treatments on the site (header, hero) read as the same lock-up at different sizes. Height is
   set and width left to `aspect-ratio`, so it scales cleanly with the h1's clamp() font-size. */
.hero-wordmark {
	display: inline-block;
	vertical-align: middle;
	height: 0.8em;
	aspect-ratio: 1794 / 350;
	background: var(--gold);
	-webkit-mask: url("logos/brabazon.svg") center / contain no-repeat;
	mask: url("logos/brabazon.svg") center / contain no-repeat;
	margin-left: 0.12em;
	/* The script capital B in the Brabazon wordmark is deliberately oversized —
	   part of its own branding — and sits both above and below the rest of the
	   lettering, so the mask's flat bounding box reads slightly low next to plain
	   text. Nudged up so "rabazon" lines up with the bottom of "1st". */
	transform: translateY(-0.08em);
}
/* join.html's hero sits on navy, so Scouts Yellow is what separates the
   wordmark from the rest of the white heading. beyond.html's "Beyond 1st
   Brabazon" sits on a light section background as ordinary heading text —
   there it should read as one navy heading, not a mid-word colour change. */
.hero-wordmark-navy {
	background: var(--navy);
}
/* A section's own logo standing in for its name as the hero h1 (Squirrels
   first) — same CSS-mask technique as .hero-wordmark above, so it can render
   white on the section's coloured --hero-bg, which a plain <img> can't do. A
   logo can read clearly at a size running text can't, so this clamp() runs
   larger than the h1 text it replaces rather than matching it exactly;
   aspect-ratio comes from each logo's real viewBox. */
.hero-section-logo {
	display: inline-block;
	vertical-align: middle;
	height: clamp(2.4rem, 6vw, 4.5rem);
	background: #fff;
}
.hero-section-logo-squirrels {
	aspect-ratio: 174 / 39;
	-webkit-mask: url("logos/squirrels.svg") center / contain no-repeat;
	mask: url("logos/squirrels.svg") center / contain no-repeat;
}
.hero-section-logo-beavers {
	aspect-ratio: 166 / 46;
	-webkit-mask: url("logos/beavers.svg") center / contain no-repeat;
	mask: url("logos/beavers.svg") center / contain no-repeat;
}
.page-hero p {
	color: #e6e1f6;
	max-width: 46em;
	font-size: 1.08rem;
	margin-bottom: 0;
}
/* ---------- Sections ---------- */
section {
	padding: 74px 0;
}
.section-alt {
	background: var(--white);
}
/* Scouts Navy, as the name says. It reads --navy rather than --hero-bg so that a
   section page keeps its dark bands in the group's navy instead of restating the
   section colour a third time; on a group page the two are the same navy anyway. */
.section-navy {
	background: var(--navy);
	color: #fff;
}
.section-navy h2,
.section-navy h3 {
	color: #fff;
}
/* Flat Scouts Yellow, used once — on the site's single most important call to
   action, so the brightest thing on the page is also the thing that matters most.
   Navy on Yellow is 8.7:1 (AAA), same pairing as the Brabazon wordmark itself. */
.section-gold {
	background: var(--gold);
	color: var(--navy);
}
.section-gold h2,
.section-gold h3 {
	color: var(--navy);
}
.section-gold .text-soft {
	color: #1d4d8f;
}
.section-gold .text-gold {
	color: var(--navy);
	text-decoration: underline;
}
/* Black text on Scouts Yellow, not Navy on Yellow — deliberately the one place
   on the site that breaks the .section-gold rule above. Per brand/
   brand-guidelines.md, "Black text on a yellow background is reserved for
   safeguarding messaging in Scouts": everywhere else this site uses Navy
   instead so that reserved pairing stays meaningful, and this section is the
   reason it's reserved. Black on Scouts Yellow measures 16.6:1 (AAA). */
.section-safeguarding {
	background: var(--gold);
	color: #000;
}
.section-safeguarding h2,
.section-safeguarding h3 {
	color: #000;
}
/* The fleur-de-lis beside "Safeguarding" / "If you need help right away" —
   same CSS-mask technique as .brand-fleur in the header, but in black (the
   reserved safeguarding colour, see .section-safeguarding above) rather than
   Scouts Yellow, and clamp()-sized to roughly track both heading rows'
   combined height responsively (see .sec-head-fleur-icon below for why this
   isn't a literal height:100% match). */
.sec-head-fleur {
	display: flex;
	align-items: center;
	gap: 16px;
}
/* Overrides .sec-head's own max-width: 46em (a deliberate readable-line-length
   cap used all over the site for a plain intro heading) rather than fighting
   it — that cap is what was forcing this specific heading into a narrow,
   flush-left column with a lot of empty yellow to its right once its subtext
   grew into a full sentence. Combined selector for specificity (0,2,0) rather
   than relying on being declared after .sec-head in source order. */
.sec-head.sec-head-fleur {
	max-width: none;
}
.sec-head-fleur-icon {
	flex: none;
	/* A definite length, not height:100% of the flex container — that relied on
	   the stretch algorithm handing aspect-ratio a resolved cross size, which
	   didn't render (the icon came out zero-width) rather than actually
	   matching both rows exactly. clamp() tracks the .sec-title/h3 pairing's
	   own responsive sizing closely enough to read as "the same height". */
	height: clamp(3.4rem, 4.5rem + 2vw, 4.6rem);
	aspect-ratio: 2067 / 1884;
	background: #000;
	-webkit-mask: url("logos/fleur-de-lis.svg") center / contain no-repeat;
	mask: url("logos/fleur-de-lis.svg") center / contain no-repeat;
}
.sec-head {
	max-width: 46em;
	margin-bottom: 34px;
}
.sec-head.center {
	margin-left: auto;
	margin-right: auto;
	text-align: center;
}
/* No text-transform: uppercase (removed 2026-09-13) — this used to render every
   .kicker in full capitals, which both fought the brand guidelines' "don't
   capitalise whole words" rule and, wherever a kicker sat beside a real
   heading, meant the section's actual topic was rendered as decoration while
   a less important line next to it held the real <h2>. Full story and the
   site-wide fix in brand/brand-guidelines.md → Known deviations. Letter-spacing
   is reduced accordingly: 0.14em was tuned for tracking out small capitals and
   reads as loose, oddly-spaced gaps on the mixed-case text it renders now. */
.kicker {
	display: block;
	font-size: 0.82rem;
	letter-spacing: 0.02em;
	font-weight: 700;
	color: var(--accent);
	margin-bottom: 10px;
}
.kicker.gold {
	color: var(--gold);
}
.banner-gold {
	display: inline-block;
	background: var(--gold);
	color: var(--navy);
	font-weight: 800;
	font-size: 0.9rem;
	padding: 0.45em 1.1em;
	border-radius: 999px;
	margin-bottom: 14px;
}
h2.sec-title {
	font-size: clamp(1.7rem, 3.6vw, 2.5rem);
}
/* A real h3 subheading directly under a .sec-title h2 — e.g. join.html's "Got a
   question?" / "Ask us anything" — rather than the decorative, non-heading
   .kicker most sections use above their h2. Sized between the two so the
   hierarchy still reads visually, not just in the markup. */
.sec-head h3 {
	font-size: 1.3rem;
	margin-top: -0.2em;
}
.lede {
	color: var(--muted);
	font-weight: 300;
	font-size: 1.18rem;
	line-height: 1.55;
}
/* Regular (400), not the base Light (300): the brand guidelines' typography page
   sanctions Light only for body text on a white background, and Regular for body
   text on a solid colour one. No .lede currently lives inside a .section-navy
   block, but the rule stays correct for the next one that does. */
.section-navy .lede {
	color: #dcd6ef;
	font-weight: 400;
}
/* A solid hex, not the usual rgba mute: translucent navy over this much yellow
   shifts toward olive under simultaneous contrast, which reads as muddy rather
   than muted. Weight bumped off the usual Light 300 for the same reason — thin
   strokes on a saturated ground lose definition. */
.section-gold .lede {
	color: #123a6b;
	font-weight: 400;
}

/* ---------- The Scouting journey (index.html) ----------
   Age 4 through 25 along one rail, in order — an <ol> because the order is real
   information here, not decoration. Each stop can carry its own data-section
   (the same attribute beyond.html puts on its District cards), so the dot, the
   heading and the "Run by us" tag all pick up that section's colour with no
   colour named in this file. Network carries data-section="network" (Black,
   see [data-section="network"] above) rather than staying unthemed like this
   comment once said – every stop on the rail now has a real theme. */
.journey-stops {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(6, minmax(0, 1fr));
	gap: 14px;
	align-items: start;
}
@media (max-width: 980px) {
	.journey-stops {
		grid-template-columns: repeat(3, minmax(0, 1fr));
	}
}
@media (max-width: 700px) {
	.journey-stops {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
.journey-stop {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}
.js-age {
	font-weight: 800;
	font-size: 0.74rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--muted);
	margin-bottom: 10px;
}
.journey-stop[data-section] .js-age {
	color: var(--accent);
}
/* The connecting line is drawn per stop rather than as one long absolutely
   positioned bar, so it always meets the dot on either side of it exactly —
   no separate element to keep in sync as the grid reflows at each breakpoint. */
.js-dot-wrap {
	position: relative;
	width: 100%;
	display: flex;
	justify-content: center;
	margin-bottom: 14px;
}
.js-dot-wrap::before {
	content: "";
	position: absolute;
	left: -50%;
	right: -50%;
	top: 50%;
	height: 3px;
	margin-top: -1.5px;
	border-radius: 2px;
	background: var(--line);
}
.journey-stops > li:first-child .js-dot-wrap::before {
	left: 50%;
}
.journey-stops > li:last-child .js-dot-wrap::before {
	right: 50%;
}
@media (max-width: 980px) {
	/* The rail only reads left-to-right on one row; once stops wrap onto several
	   rows the connecting line no longer means anything, so it is dropped rather
	   than drawn between unrelated neighbours. */
	.js-dot-wrap::before {
		display: none;
	}
}
.js-dot {
	width: 16px;
	height: 16px;
	border-radius: 50%;
	background: var(--white);
	border: 3px solid var(--line);
	position: relative;
	z-index: 1;
	flex: none;
}
.journey-stop[data-section] .js-dot {
	border-color: var(--accent);
}
.journey-stop--own .js-dot {
	background: var(--accent);
	box-shadow: 0 0 0 5px var(--accent-soft);
}
.js-card {
	width: 100%;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 4px;
	text-decoration: none;
	color: var(--ink);
	background: var(--white);
	border: 2px solid var(--line);
	border-radius: var(--radius);
	padding: 18px 14px;
	transition:
		transform 0.12s ease,
		box-shadow 0.12s ease,
		border-color 0.12s ease;
}
/* The same treatment as .hero-sec and .card[data-section] on beyond.html: a
   wash of the stop's own colour rather than only carrying it on the dot and
   the age label, a full accent-colour border rather than .js-card's plain
   one, and a raised shadow at rest, so the section reads at a glance. Every
   stop carries a data-section now, Network included (see [data-section="network"]
   above) – .journey-stop--own below layers the extra lift that marks out the
   two 1st Brabazon actually runs, on top of this shared base. */
.journey-stop[data-section] .js-card {
	background: var(--accent-soft);
	border-color: var(--accent);
	box-shadow: var(--shadow-lift);
}
.js-card:hover {
	transform: translateY(-4px);
	box-shadow: var(--shadow);
	border-color: var(--accent);
}
.journey-stop[data-section] .js-card:hover {
	box-shadow: var(--shadow-lift);
}
.journey-stop--own .js-card {
	transform: translateY(-6px);
}
.journey-stop--own .js-card:hover {
	transform: translateY(-9px);
}
.js-name {
	font-weight: 900;
	font-family: var(--font-head);
	font-size: 1.05rem;
	line-height: 1.15;
	color: var(--ink);
}
.journey-stop--own .js-name {
	font-size: 1.16rem;
	color: var(--accent);
}
.js-meta {
	font-size: 0.82rem;
	color: var(--muted);
}
.js-card .tag {
	margin-top: 4px;
	white-space: nowrap;
	font-size: 0.63rem;
	padding: 0.3em 0.65em;
}
/* ---------- Journey reveal ----------
   Rests fully visible with no JS and no motion by default — the .run class (added
   once, by IntersectionObserver, the first time the rail scrolls into view) is
   what turns this on, never a precondition for seeing the content. Six stops,
   120ms apart; the connecting line draws alongside each one. */
.journey-rail.run .journey-stop {
	animation: journey-rise 0.4s var(--ease) both;
}
.journey-rail.run .js-dot-wrap::after {
	content: "";
	position: absolute;
	left: -50%;
	right: -50%;
	top: 50%;
	height: 3px;
	margin-top: -1.5px;
	border-radius: 2px;
	background: var(--gold);
	transform-origin: left center;
	transform: scaleX(0);
	animation: journey-draw 0.5s var(--ease) both;
}
.journey-stops > li:first-child .js-dot-wrap::after {
	left: 50%;
}
.journey-stops > li:last-child .js-dot-wrap::after {
	right: 50%;
}
@media (max-width: 980px) {
	.journey-rail.run .js-dot-wrap::after {
		display: none;
	}
}
@keyframes journey-rise {
	from {
		opacity: 0;
		transform: translateY(10px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}
@keyframes journey-draw {
	to {
		transform: scaleX(1);
	}
}
.journey-rail.run .journey-stops > li:nth-child(1),
.journey-rail.run .journey-stops > li:nth-child(1) .js-dot-wrap::after {
	animation-delay: 0.05s;
}
.journey-rail.run .journey-stops > li:nth-child(2),
.journey-rail.run .journey-stops > li:nth-child(2) .js-dot-wrap::after {
	animation-delay: 0.17s;
}
.journey-rail.run .journey-stops > li:nth-child(3),
.journey-rail.run .journey-stops > li:nth-child(3) .js-dot-wrap::after {
	animation-delay: 0.29s;
}
.journey-rail.run .journey-stops > li:nth-child(4),
.journey-rail.run .journey-stops > li:nth-child(4) .js-dot-wrap::after {
	animation-delay: 0.41s;
}
.journey-rail.run .journey-stops > li:nth-child(5),
.journey-rail.run .journey-stops > li:nth-child(5) .js-dot-wrap::after {
	animation-delay: 0.53s;
}
.journey-rail.run .journey-stops > li:nth-child(6),
.journey-rail.run .journey-stops > li:nth-child(6) .js-dot-wrap::after {
	animation-delay: 0.65s;
}

/* ---------- Numbered step timeline (join.html "How joining works") ----------
   Same rail device as .journey-stops above — a connecting line drawn per stop
   rather than one long absolutely-positioned bar, so it always meets the dot
   either side of it — but there's no separate label (like the journey's age)
   to sit above a blank dot, so the dot itself carries the step number. Colour
   treatment matches .journey-stop--own .js-dot (solid accent fill, soft ring)
   for the same reason: these are "our" steps, same as the group's own sections. */
.step-stops {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(4, minmax(0, 1fr));
	gap: 14px;
	/* Stretch (the grid default), not align-items: start like .journey-stops —
	   the panels should match the tallest one in their row rather than each
	   hugging its own text. .step-card below grows to fill that stretched
	   height while .step-dot-wrap stays a fixed size at the top. */
}
@media (max-width: 980px) {
	.step-stops {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
@media (max-width: 700px) {
	.step-stops {
		grid-template-columns: minmax(0, 1fr);
	}
}
.step-stop {
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}
.step-dot-wrap {
	position: relative;
	width: 100%;
	display: flex;
	justify-content: center;
	margin-bottom: 16px;
}
.step-dot-wrap::before {
	content: "";
	position: absolute;
	left: -50%;
	right: -50%;
	top: 50%;
	height: 3px;
	margin-top: -1.5px;
	border-radius: 2px;
	/* Scouts Yellow, not the neutral --line grey the journey rail uses by default —
	   this line has no scroll-reveal gold overlay to draw in later, so it's gold
	   from the start. */
	background: var(--gold);
}
.step-stops > li:first-child .step-dot-wrap::before {
	left: 50%;
}
.step-stops > li:last-child .step-dot-wrap::before {
	right: 50%;
}
@media (max-width: 980px) {
	/* Same reasoning as .js-dot-wrap::before: once stops wrap onto several rows
	   the connecting line no longer means anything between unrelated neighbours. */
	.step-dot-wrap::before {
		display: none;
	}
}
.step-dot {
	width: 34px;
	height: 34px;
	border-radius: 50%;
	background: var(--accent);
	color: #fff;
	display: grid;
	place-items: center;
	font-family: var(--font-head);
	font-weight: 900;
	font-size: 1rem;
	position: relative;
	z-index: 1;
	flex: none;
	box-shadow: 0 0 0 5px var(--accent-soft);
}
/* .step-card also carries the standard .card.pad classes in the HTML, for the
   same white-panel treatment (background, border, radius, shadow, padding)
   every other card on the site uses — this rule only adds the layout and
   typography specific to a step panel. */
.step-card {
	width: 100%;
	max-width: 24em;
	flex: 1;
}
.step-card h3 {
	font-size: 1.05rem;
	margin-bottom: 0.3em;
}
.step-card p {
	color: var(--muted);
	font-size: 0.95rem;
	margin: 0;
}

.tag {
	display: inline-block;
	font-size: 0.68rem;
	font-weight: 800;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	border-radius: 999px;
	padding: 0.25em 0.8em;
}
.tag-own {
	background: var(--accent);
	color: #fff;
}
.tag-district {
	background: var(--gold-soft);
	color: #003982;
}
.tag-example {
	background: #ffe9e7;
	color: var(--danger);
	border: 1px dashed var(--danger);
}

/* Facts band */
.facts {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 16px;
}
@media (max-width: 700px) {
	.facts {
		grid-template-columns: 1fr;
	}
}
.fact {
	background: rgba(255, 255, 255, 0.08);
	border: 1px solid rgba(255, 255, 255, 0.2);
	border-radius: var(--radius);
	padding: 22px 20px;
}
.fact-label {
	display: block;
	font-size: 0.72rem;
	font-weight: 800;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: rgba(255, 255, 255, 0.65);
	margin-bottom: 4px;
}
.fact b {
	display: block;
	font-family: var(--font-head);
	font-size: 1.5rem;
	color: var(--gold);
	font-variant-numeric: tabular-nums;
}
.fact span {
	color: #e4e0f2;
	font-size: 0.95rem;
}

/* Generic cards */
.card {
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	box-shadow: var(--shadow);
}
/* A card can carry its own data-section (beyond.html gives the three District
   cards theirs; a squirrels/beavers-scoped news story on news.html/index.html
   gets one too, see newsCard() in app.js). It picks up the fuller "own
   section" card style introduced by .journey-stop--own .js-card further
   down: a wash of the section's colour at 14% behind the whole card, a full
   accent-colour border rather than just .card's plain one, and a raised
   shadow at rest so the theme reads at a glance rather than only in a thin
   stripe. Both are on a page that is otherwise 1st Brabazon navy or cream. */
.card[data-section] {
	background: var(--accent-soft);
	border: 2px solid var(--accent);
	box-shadow: var(--shadow-lift);
}
/* Same .card.pad:hover specificity fix as .card-safeguarding and friends
   elsewhere in this file: without this, hovering one of these would drop the
   shadow from --shadow-lift back down to the plain --shadow every other card
   gets on hover – a downgrade on the one interaction meant to feel raised. */
.card.pad[data-section]:hover {
	box-shadow: var(--shadow-lift);
}
.grid {
	display: grid;
	gap: 22px;
}
/* minmax(0, …) everywhere: a bare 1fr track is `minmax(auto, 1fr)`, so any
   unbreakable child (a long email, a nowrap tag) widens the track and overflows the page. */
.grid-2 {
	grid-template-columns: repeat(2, minmax(0, 1fr));
}
.grid-3 {
	grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-4 {
	grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 980px) {
	.grid-3,
	.grid-4 {
		grid-template-columns: repeat(2, minmax(0, 1fr));
	}
}
@media (max-width: 700px) {
	.grid-2,
	.grid-3,
	.grid-4 {
		grid-template-columns: minmax(0, 1fr);
	}
}
.pad {
	padding: 26px;
}
.card h3 {
	margin-top: 0.2em;
}
/* A border-and-shadow acknowledgement only — no lift. Eight activity cards all
   bouncing at once on hover is noise; a colour shift on the edge is enough to
   say "this is a thing", and it costs nothing on touch devices that never hover. */
.card.pad {
	transition:
		border-color 0.15s ease,
		box-shadow 0.15s ease;
}
.card.pad:hover {
	border-color: var(--accent);
	box-shadow: var(--shadow);
}
/* ---------------------------------------------------------------------------
   Was emoji. The Scouts brand guidelines explicitly rule emoji out — "Please
   don't use emojis or smiley faces in any website content" (v3.3, Digital
   accessibility, p52) — and they rendered differently on Windows, macOS and
   Android besides. Each icon is now a small inline SVG sprite defined once near
   the top of <body>, drawn in the brand palette and referenced with <use>, so it
   is one element per page rather than a duplicated block per icon. Still
   aria-hidden, since every icon here is decorative next to a text heading.
   --------------------------------------------------------------------------- */
.emoji-ico {
	display: grid;
	place-items: center;
	width: 56px;
	height: 56px;
	border-radius: 16px;
	background: var(--accent-soft);
}
.emoji-ico .ico {
	width: 28px;
	height: 28px;
	color: var(--accent);
	fill: none;
	stroke: currentColor;
	stroke-width: 1.75;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.card .emoji-ico {
	margin-bottom: 12px;
}
ul.tick {
	list-style: none;
	padding-left: 0;
}
ul.tick li {
	padding-left: 1.8em;
	position: relative;
	margin-bottom: 0.55em;
}
ul.tick li::before {
	content: "\2713";
	position: absolute;
	left: 0;
	color: var(--accent);
	font-weight: 800;
}

/* ---------- Forms (contact.html) ---------- */
.field {
	margin-bottom: 18px;
}
.field label {
	display: block;
	font-weight: 700;
	margin-bottom: 6px;
}
.field input,
.field select,
.field textarea {
	width: 100%;
	font: 400 1rem/1.4 var(--font-body);
	color: var(--ink);
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	padding: 0.7em 0.9em;
}
.field textarea {
	min-height: 140px;
	resize: vertical;
}
/* Kept in the document and in tab order (not display:none) so bot/screen-
   reader heuristics that check for a genuinely hidden field still catch it,
   while a sighted keyboard user never lands on it. */
.contact-form input[name="botcheck"] {
	position: absolute;
	width: 1px;
	height: 1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
}
/* Shown only when Enquiry type = Safeguarding (toggled by initContactForm()
   in app.js, same moment .is-safeguarding switches the form's colours), so
   it always renders on the yellow background below — plain black text reads
   fine there without its own fill, same reasoning as .card-safeguarding. */
.safeguarding-note {
	font-weight: 700;
	border-left: 4px solid #000;
	padding: 2px 0 2px 16px;
	margin: 0 0 18px;
}
/* Reserved black-on-yellow safeguarding pairing (see .section-safeguarding),
   applied to the form itself rather than a whole page section — switched on
   by initContactForm() in app.js when Enquiry type = Safeguarding. */
.contact-form.is-safeguarding {
	background: var(--gold);
	border: 3px solid #000;
	color: #000;
}
.contact-form.is-safeguarding label {
	color: #000;
}
.contact-form.is-safeguarding .btn-accent {
	background: #000;
	color: var(--gold);
}
.contact-form.is-safeguarding .btn-accent:hover {
	background: #262626;
}
/* Same .card.pad:hover specificity fix as .card-safeguarding/.panel-safeguarding
   elsewhere: without this, hovering the form while it's in the safeguarding
   theme would still flip the border to Navy. */
.card.pad.contact-form.is-safeguarding:hover {
	border-color: #000;
}
/* Squirrels/Beavers theming, switched on the same way as is-safeguarding but a
   lighter touch: the ordinary section-page device (.hero-sec[data-section]
   above) of an --accent-soft wash plus an --accent border, not the reserved
   black-on-yellow pairing. Re-pointing --accent/--accent-2/--accent-soft also
   recolours the submit button and hover border for free, since .btn-accent and
   .card.pad:hover already read those custom properties rather than a fixed hex. */
.contact-form.is-squirrels {
	--accent: #ed3f23;
	--accent-2: #ce371e;
	--accent-soft: #fdece9;
	--accent-ring: rgba(237, 63, 35, 0.18);
	background: var(--accent-soft);
	border-color: var(--accent);
}
.contact-form.is-beavers {
	--accent: #006cdd;
	--accent-2: #004389;
	--accent-soft: #e6f0fc;
	--accent-ring: rgba(0, 108, 221, 0.18);
	background: var(--accent-soft);
	border-color: var(--accent);
}
/* .field label has no colour of its own to inherit, so unlike the button and
   border above it does not pick up --accent for free — same gap .is-safeguarding
   closes with its own "label { color: #000 }" rule just above. */
.contact-form.is-squirrels label,
.contact-form.is-beavers label {
	color: var(--accent);
}

/* Photo placeholders */
.ph {
	position: relative;
	border-radius: var(--radius);
	overflow: hidden;
	border: 2px dashed var(--accent-soft);
	border: 2px dashed color-mix(in srgb, var(--accent) 40%, transparent);
	background: var(--accent-soft);
	background:
		repeating-linear-gradient(
			-45deg,
			color-mix(in srgb, var(--accent) 5%, transparent) 0 12px,
			transparent 12px 24px
		),
		var(--accent-soft);
	display: grid;
	place-items: center;
	min-height: 200px;
	text-align: center;
	margin-bottom: 18px;
}
.ph-wide {
	min-height: 260px;
}
.ph-tall {
	min-height: 380px;
}
/* A true portrait placeholder: narrower than its column and taller than
   .ph-tall, rather than just stretching to the column's own (landscape)
   width. Centred within whatever column it sits in. */
.ph-portrait {
	max-width: 420px;
	min-height: 520px;
	margin-left: auto;
	margin-right: auto;
}
.ph-note {
	padding: 18px;
	color: var(--accent-2);
	font-size: 0.95rem;
}
.ph-note b {
	display: block;
	font-family: var(--font-head);
	font-size: 1.05rem;
	margin-bottom: 2px;
}

/* Link cards & list rows */
.linklist {
	list-style: none;
	padding: 0;
	margin: 0;
}
.linklist li {
	border-bottom: 1px solid var(--line);
}
.linklist li:last-child {
	border-bottom: 0;
}
.linklist a {
	display: flex;
	justify-content: space-between;
	gap: 12px;
	align-items: baseline;
	padding: 14px 4px;
	text-decoration: none;
	color: var(--navy);
	font-weight: 600;
}
/* --accent-2, not --accent: the rest state is already var(--navy), which --accent
   also is under the group theme, so --accent here would be no hover at all. */
.linklist a:hover {
	color: var(--accent-2);
}
.linklist small {
	color: var(--muted);
	font-weight: 400;
	white-space: nowrap;
}
.ext-link::after {
	content: " ↗";
	color: var(--accent);
	font-weight: 700;
}
/* .linklist a is flex with justify-content:space-between, expecting exactly two
   items: the link text and the trailing <small>. ::after on .ext-link generates a
   third, separate flex item, so space-between pries the arrow away from "Scouts
   UK" instead of keeping them together at the right edge. Moving the arrow onto
   <small> itself folds it back into that same second item, so every row's arrow
   lands flush with the others regardless of how long its <small> text is. */
.linklist a.ext-link::after {
	content: none;
}
.linklist a.ext-link small::after {
	content: " ↗";
	color: var(--accent);
	font-weight: 700;
}

/* Programme table */
.tbl {
	width: 100%;
	border-collapse: collapse;
	background: var(--white);
	border-radius: var(--radius);
	overflow: hidden;
	box-shadow: var(--shadow);
}
.tbl th,
.tbl td {
	text-align: left;
	padding: 14px 18px;
	border-bottom: 1px solid var(--line);
}
.tbl th {
	background: var(--navy);
	color: #fff;
	font-family: var(--font-head);
	font-size: 0.95rem;
	letter-spacing: 0.02em;
}
.tbl tr:last-child td {
	border-bottom: 0;
}
.tbl td {
	font-size: 0.97rem;
	font-variant-numeric: tabular-nums;
}

/* News */
.news-item {
	display: grid;
	grid-template-columns: 150px minmax(0, 1fr);
	gap: 22px;
	align-items: start;
}
@media (max-width: 700px) {
	.news-item {
		grid-template-columns: minmax(0, 1fr);
	}
}
.news-item .date {
	background: var(--navy);
	color: var(--gold);
	border-radius: var(--radius-sm);
	padding: 10px 6px;
	text-align: center;
	font-family: var(--font-head);
}
/* Only the headline picks up the section's colour – the summary, and every
   other piece of text on the card, stays the normal navy --ink, same as a
   general story. */
.news-item[data-section] h2,
.news-item[data-section] h3 {
	color: var(--accent);
}
/* A squirrels/beavers-scoped story's date badge swaps navy/gold for that
   section's own accent, white reading clearly on every section colour here
   (same pairing as .btn-accent) – including Squirrels Red, whose white-text
   contrast trade-off is already an accepted, documented deviation (see
   "Known deviations" in brand/brand-guidelines.md), not a new one. */
.news-item[data-section] .date {
	background: var(--accent);
	color: #fff;
}
.news-item .date b {
	display: block;
	font-size: 1.6rem;
	line-height: 1;
}
.news-item .date span {
	font-size: 0.75rem;
	letter-spacing: 0.02em;
}
/* Sits above the headline, the same device as .card-logo on beyond.html's
   District cards, so which section(s) a story is about still reads even for
   a reader who can't see the date badge's colour or the card's border – and
   for a multi-tagged general story, which has no colour of its own at all. */
.news-logos {
	display: flex;
	align-items: center;
	gap: 12px;
	margin-bottom: 8px;
}
.news-logo {
	display: block;
	height: 26px;
	width: auto;
}
.news-summary {
	margin-bottom: 0.4em;
}
/* When the Sheet loads and replaces the written-in items (assets/app.js,
   initNews), fade the swap in rather than let the new cards pop in place —
   a pop reads as a glitch, a fade reads as an update. */
[data-news-mode] {
	transition: opacity 0.3s ease;
}
[data-news-mode].news-loading {
	opacity: 0;
}
/* Hides the "these are examples" note the instant a browser can run JS at all —
   .news-pending is added by the inline bootstrap script in <head>, before <body>
   even exists, so this is what stops a visitor ever seeing the note appear and
   then vanish a moment later once the Sheet turns out to have real news.
   initNews() (assets/app.js) removes the class again on every path where the
   note is still true: no Sheet configured, the fetch failed, or it returned no
   usable rows — so it only ever stays hidden when there is real news to show.
   With JavaScript disabled the class is never added, and the note is exactly as
   visible as it always was. */
.news-pending [data-news-example] {
	display: none;
}
/* A photo added from the news Sheet. width:100% with height:auto keeps the photo's
   own proportions, and the max-height only bites on a portrait shot; object-fit
   then crops that one rather than squashing it. */
.news-item .news-img {
	display: block;
	width: 100%;
	height: auto;
	max-height: 420px;
	object-fit: cover;
	margin-top: 0.9rem;
	border-radius: var(--radius-sm);
	background: var(--cream);
}

/* FAQ */
details.faq {
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	margin-bottom: 12px;
	padding: 4px 18px;
}
details.faq summary {
	cursor: pointer;
	font-weight: 700;
	padding: 12px 0;
	color: var(--navy);
	list-style-position: outside;
}
/* Same reason as .linklist a:hover — summary's rest state is already var(--navy). */
details.faq[open] summary {
	color: var(--accent-2);
}
details.faq p {
	margin-top: 0;
}

/* Promise carousel (squirrels.html, beavers.html) — see initPromiseCarousels()
   in app.js. Before JS runs, .promise-slide elements are a plain stacked list
   (no CSS here hides them), so a no-JS visitor still gets every wording. JS
   adds .carousel-ready and the controls, and from then on .carousel-viewport
   stacks every slide in the same grid cell — sizing the panel to the tallest
   one — and only toggles which is visible, so the page never reflows as it
   cycles between a short promise and a longer one. */
.promise-carousel {
	margin-top: 18px;
}
/* One button per faith, above the panel — a direct jump to that wording
   rather than only stepping through with prev/next. The current one is a
   solid accent fill; the rest sit on the lighter --accent-soft tint. Icons
   are currentColor (mask-based) or real script text, so both automatically
   pick up the button's own white-on-accent / accent-on-soft colour. */
.promise-nav {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 10px;
	margin-bottom: 16px;
}
.promise-nav-btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: 999px;
	border: none;
	background: var(--accent-soft);
	color: var(--accent);
	cursor: pointer;
}
.promise-nav-btn.is-active {
	background: var(--accent);
	color: #fff;
}
.promise-icon {
	display: inline-block;
	width: 22px;
	height: 22px;
	background: currentColor;
	-webkit-mask-position: center;
	mask-position: center;
	-webkit-mask-repeat: no-repeat;
	mask-repeat: no-repeat;
	-webkit-mask-size: contain;
	mask-size: contain;
}
.promise-icon-cross {
	-webkit-mask-image: url("icons/cross.svg");
	mask-image: url("icons/cross.svg");
}
.promise-icon-star-of-david {
	-webkit-mask-image: url("icons/star-of-david.svg");
	mask-image: url("icons/star-of-david.svg");
}
.promise-icon-crescent {
	-webkit-mask-image: url("icons/crescent.svg");
	mask-image: url("icons/crescent.svg");
}
.promise-icon-wheel {
	-webkit-mask-image: url("icons/wheel.svg");
	mask-image: url("icons/wheel.svg");
}
.promise-icon-humanist {
	-webkit-mask-image: url("icons/humanist.svg");
	mask-image: url("icons/humanist.svg");
}
.promise-icon-om {
	-webkit-mask-image: url("icons/om.svg");
	mask-image: url("icons/om.svg");
}
.promise-icon-khanda {
	-webkit-mask-image: url("icons/khanda.svg");
	mask-image: url("icons/khanda.svg");
}
.promise-slide {
	background: var(--white);
	border: 1px solid var(--line);
	border-radius: var(--radius);
	box-shadow: var(--shadow);
	padding: 28px 26px;
	margin-bottom: 12px;
}
.promise-slide h3 {
	margin-top: 0;
}
.promise-slide p {
	margin-bottom: 0;
	font-size: 1.1rem;
}
.carousel-viewport {
	display: grid;
}
.carousel-viewport .promise-slide {
	grid-area: 1 / 1;
	margin-bottom: 0;
	text-align: center;
	visibility: hidden;
	opacity: 0;
	transition: opacity 0.2s ease;
}
.carousel-viewport .promise-slide.is-active {
	visibility: visible;
	opacity: 1;
}
.carousel-controls {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 14px;
	margin-top: 16px;
}
.carousel-nav {
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: 999px;
	border: 2px solid var(--accent);
	background: transparent;
	color: var(--accent);
	font-size: 1.4rem;
	line-height: 1;
	cursor: pointer;
}
.carousel-nav:hover {
	background: var(--accent-soft);
}
/* The one solid-fill control in the row — deliberately, so play/pause (the
   control that changes the auto-advance itself) reads as the primary action
   next to the two outline step buttons either side of it. */
.carousel-pause {
	flex: none;
	display: inline-flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border-radius: 999px;
	border: none;
	background: var(--accent);
	color: #fff;
	font-size: 1.1rem;
	line-height: 1;
	cursor: pointer;
}
.carousel-pause:hover {
	background: var(--accent-2);
}
.carousel-status {
	text-align: center;
	color: var(--muted);
	font-size: 0.9rem;
	margin: 10px 0 0;
}

/* QR cards (join page) */
.qr-grid {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 22px;
}
@media (max-width: 980px) {
	.qr-grid {
		grid-template-columns: minmax(0, 1fr);
	}
}
.qr-card {
	text-align: center;
	padding: 24px 20px;
	display: flex;
	flex-direction: column;
	gap: 12px;
}
.qr-card h3 {
	margin: 0;
	font-size: 1.15rem;
}
.qr-wrap {
	background: #fff;
	border: 1px solid var(--line);
	border-radius: var(--radius-sm);
	padding: 12px;
	display: grid;
	place-items: center;
	min-height: 190px;
}
.qr-wrap svg {
	width: 100%;
	max-width: 168px;
	height: auto;
}
.qr-pending {
	font-size: 0.9rem;
	color: var(--muted);
	display: grid;
	gap: 6px;
}
.qr-pending strong {
	color: var(--danger);
}
.qr-text {
	font-size: 0.8rem;
	color: var(--muted);
	word-break: break-all;
}
.qr-text a {
	color: var(--accent-2);
}
.cfg-missing {
	display: inline-block;
	margin-top: 10px;
	background: #fffad4;
	color: #003982;
	border: 1px dashed #a69619;
	border-radius: 8px;
	font-size: 0.85rem;
	padding: 0.5em 0.9em;
}

/* Tabs + form */
.tabs {
	display: flex;
	gap: 8px;
	flex-wrap: wrap;
	margin-bottom: 22px;
}
/* Keyed off the class, not the element, so the same component works for the
   enquiry form's <button> tabs and the document section's <a> tabs. */
.tabs .tab-btn {
	display: inline-flex;
	align-items: center;
	border: 2px solid var(--navy);
	background: #fff;
	color: var(--navy);
	font: 700 0.95rem var(--font-body);
	padding: 0.55em 1.25em;
	border-radius: 999px;
	cursor: pointer;
	text-decoration: none;
}
/* Same reason as .linklist a:hover — .tab-btn's rest label is already var(--navy). */
.tabs .tab-btn:hover {
	border-color: var(--accent-2);
	color: var(--accent-2);
}
.tabs .tab-btn.tab-on {
	background: var(--accent);
	border-color: var(--accent);
	color: #fff;
}
/* Squirrels/Beavers programme tabs (parents.html #progTabs): the Scouts-red and
   Scouts-blue logos are solid brand-colour wordmarks (see the .hero-sec comment
   above), so unlike a plain text tab-btn this one can never fill its own
   background with --accent — the logo would vanish into it. It stays white/
   tinted at all times and borrows the "own section" card treatment used
   elsewhere on the site (full accent border + --shadow-lift) to mark which tab
   is current instead. */
.tabs .tab-btn-logo {
	border-color: var(--line);
	background: var(--white);
	padding: 0.5em 1.3em;
}
.tabs .tab-btn-logo:hover {
	border-color: var(--accent);
}
.tabs .tab-btn-logo.tab-on {
	background: var(--accent-soft);
	border-color: var(--accent);
	box-shadow: var(--shadow-lift);
}
.tab-logo {
	height: 20px;
	width: auto;
	margin: 0;
}
/* Key facts + chips */
.chip-row {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin: 0 0 24px;
}
.chip {
	background: var(--gold-soft);
	color: #003982;
	border-radius: 999px;
	padding: 0.5em 1.1em;
	font-weight: 600;
	font-size: 0.95rem;
}

/* Contact list */
dl.contact {
	display: grid;
	grid-template-columns: auto 1fr;
	gap: 8px 26px;
	margin: 0;
}
dl.contact dt {
	font-weight: 700;
	color: var(--accent);
}
dl.contact dd {
	margin: 0;
}
/* Two columns squeeze the values into an awkward ribbon on small phones — stack instead. */
@media (max-width: 560px) {
	dl.contact {
		grid-template-columns: minmax(0, 1fr);
		gap: 0;
	}
	dl.contact dt {
		margin-top: 14px;
	}
	dl.contact dd {
		margin-bottom: 2px;
	}
}

/* Footer */
.site-footer {
	background: var(--navy);
	color: #c0d7ef;
	margin-top: 0;
}
/* Down to two columns — the "Explore" and "Parents and volunteers" link lists
   were dropped (they only repeated the main nav, already on every page). */
.footer-grid {
	display: grid;
	grid-template-columns: 1.3fr 1fr;
	gap: 36px;
	padding: 56px 0 34px;
}
@media (max-width: 560px) {
	.footer-grid {
		grid-template-columns: minmax(0, 1fr);
	}
}
.site-footer h3 {
	color: var(--gold);
	font-size: 1rem;
	letter-spacing: 0.02em;
}
.site-footer ul {
	list-style: none;
	padding: 0;
	margin: 0;
}
.site-footer li {
	margin-bottom: 0.55em;
}
.site-footer a {
	color: #c8dbf2;
	text-decoration: none;
}
.site-footer a:hover {
	color: var(--gold);
	text-decoration: underline;
}
/* The default ↗ is the page accent, which on a group page IS the footer's own navy and
   on a section page is a dark section shade — 1:1 and about 1.5:1 respectively, i.e.
   invisible either way. Inherit the link colour here instead (7.8:1). */
.site-footer .ext-link::after {
	color: inherit;
}
.footer-bottom {
	border-top: 1px solid rgba(255, 255, 255, 0.15);
	padding: 18px 0 26px;
	font-size: 0.88rem;
	color: #a3c1e4;
}
.footer-bottom p {
	margin: 0.3em 0;
}

/* Two-column content */
.split {
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	gap: 44px;
	/* start, not center: when the two columns are close in height this makes no visible
	   difference, but when they are not (a short intro beside a tall card, e.g. the
	   section pages) `center` floats the short column in the middle of the tall one and
	   leaves dead space above and below it. `.split.balanced` opts back into center for
	   the few pairs that are genuinely close in height. */
	align-items: start;
}
.split.balanced {
	align-items: center;
}
@media (max-width: 980px) {
	.split {
		grid-template-columns: minmax(0, 1fr);
	}
}
.callout {
	border-left: 5px solid var(--gold);
	background: var(--white);
	border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
	padding: 18px 22px;
	box-shadow: var(--shadow);
	margin: 0 0 24px;
}

/* Misc */
.note {
	font-size: 0.9rem;
	color: var(--muted);
}
.center {
	text-align: center;
}
/* .mw-820 on its own has no auto margins — it just caps the width of a column
   that still sits flush against the left edge of the wider .wrap around it.
   That's invisible for ordinary left-aligned copy, but paired with .center it
   read as a lopsided, off-page column: text centred inside a box that was
   itself still pinned left rather than centred on the page. */
.mw-820.center {
	margin-left: auto;
	margin-right: auto;
}
/* A numbered/bulleted list inside a centred narrow column: browsers hang a
   list's markers off the block's own edge regardless of text-align, so a
   centred <ol>/<ul> otherwise reads as text drifting away from a
   left-pinned number. Moving the marker inside keeps it with its text. */
.mw-820.center ol,
.mw-820.center ul:not(.tick) {
	list-style-position: inside;
}
.mt-1 {
	margin-top: 18px;
}
.mt-2 {
	margin-top: 34px;
}
.mb-0 {
	margin-bottom: 0;
}

/* --- Utility helpers ----------------------------------------------------
   These replace the ~40 ad-hoc style="" attributes that used to be scattered
   through the pages, which bypassed every design token in this file. */
.m-0 {
	margin: 0;
}
.mx-auto {
	margin-left: auto;
	margin-right: auto;
}
.mb-12 {
	margin-bottom: 12px;
}
.mb-18 {
	margin-bottom: 18px;
}
.mb-20 {
	margin-bottom: 20px;
}
.mb-26 {
	margin-bottom: 26px;
}
.mt-6 {
	margin-top: 6px;
}
.ms-6 {
	margin-left: 6px;
}
.ms-8 {
	margin-left: 8px;
}
.mw-240 {
	max-width: 240px;
}
.mw-820 {
	max-width: 820px;
}
.mw-860 {
	max-width: 860px;
}
.mw-900 {
	max-width: 900px;
}
.mw-lede {
	max-width: 34em;
}
.text-accent {
	color: var(--accent);
}
.text-gold {
	color: var(--gold);
}
.text-soft {
	color: #c8dbf2;
}
.text-white {
	color: #fff;
}
.text-danger {
	color: var(--danger);
}
.bg-cream {
	background: var(--cream);
}
.panel-navy {
	background: var(--navy);
	color: #fff;
}
/* Same reserved black-on-yellow pairing as .section-safeguarding
   (contact.html), as a .card panel rather than a full-width section — for
   safeguarding content that sits alongside other content on a page instead
   of getting its own section. */
.panel-safeguarding {
	background: var(--gold);
	border: 3px solid #000;
	color: #000;
	transition: box-shadow 0.12s ease;
}
.panel-safeguarding h2,
.panel-safeguarding h3 {
	color: #000;
}
/* .card h3 { margin-top: 0.2em } elsewhere in this file (specificity 0,1,1)
   otherwise beats the plain .mt-1 utility (0,1,0) on this particular h3,
   quietly shrinking its intended gap down to ~3px. This selector matches it
   for specificity so the utility actually wins. */
.panel-safeguarding h3.mt-1 {
	margin-top: 18px;
}
/* Same reasoning as .btn-safeguarding's .ext-link::after fix: the default
   link colour (var(--accent-2), Navy-2 on this group page) would stand out
   as an off-theme blue inside an otherwise all-black panel. Underline still
   carries "this is a link" on its own, same as body text links anywhere
   else on the site. :not(.btn) so this doesn't fight .btn-safeguarding's own
   (higher-specificity-needing) gold text colour on the pill buttons above. */
.panel-safeguarding a:not(.btn) {
	color: #000;
}
/* Same override as .card.pad.card-safeguarding:hover above, and for the same
   reason: .card.pad:hover otherwise wins on border-color by specificity and
   turns this Navy on hover too. */
.card.pad.panel-safeguarding:hover {
	border-color: #000;
	box-shadow: var(--shadow-lift);
}
/* The three info cards inside .section-safeguarding (contact.html): a black
   border makes each one read as its own distinct panel even though its fill
   is the same yellow as the section behind it — the border and shadow carry
   the separation instead of a colour change. Declared after the base .card
   rule above (same specificity, so source order decides) rather than up by
   .section-safeguarding, where .card's later background/border would have
   silently won the cascade. */
.card-safeguarding {
	background: var(--gold);
	border: 3px solid #000;
	color: #000;
	transition: box-shadow 0.12s ease;
}
.card-safeguarding h3 {
	color: #000;
}
/* Shadow only on hover — no lift, these panels should stay put. Border colour
   and weight are also deliberately untouched, so it stays the same solid
   black rather than picking up var(--accent) (Navy on this group-wide page)
   the way .card.pad:hover normally does. Selector is .card.pad.card-safeguarding,
   not just .card-safeguarding, to out-specificity that sitewide .card.pad:hover
   rule — border-color is repeated here too, since a higher-specificity rule
   only wins per property it actually sets, and .card.pad:hover's border-color
   would otherwise still win by itself. */
.card.pad.card-safeguarding:hover {
	border-color: #000;
	box-shadow: var(--shadow-lift);
}
.border-0 {
	border: 0;
}
.rounded-sm {
	border-radius: var(--radius-sm);
}
.no-bullets {
	list-style: none;
	padding-left: 0;
}
.center-actions {
	justify-content: center;
}
.ph-sm {
	min-height: 150px;
}
.quote {
	margin: 0;
	font-family: var(--font-head);
	font-size: 1.35rem;
	line-height: 1.4;
}
/* Respect the OS "reduce motion" preference */
@media (prefers-reduced-motion: reduce) {
	html {
		scroll-behavior: auto;
	}
	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-delay: 0s !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		transition-delay: 0s !important;
		scroll-behavior: auto !important;
	}
	.btn:hover,
	.js-card:hover,
	.journey-stop--own .js-card,
	.journey-stop--own .js-card:hover {
		transform: none;
	}
}

@media print {
	.site-header,
	.site-footer,
	.mobile-cta-bar,
	.page-toc,
	.btn {
		display: none;
	}
	body {
		background: #fff;
	}
	a[href^="http"]::after {
		content: " (" attr(href) ")";
		font-size: 0.85em;
	}
}

/* Nav below 1300px: progressive enhancement.
   The CSS shows a plain wrapped link list by default, so the site still navigates
   with JavaScript disabled or broken — it used to have no navigation at all.
   `html.js` (set by a one-line inline script in <head>) switches it to the drawer.
   The drawer is the .site-nav element itself rather than a descendant: `display: contents`
   on a <nav> can drop the landmark from the accessibility tree, so it is avoided entirely.
   `calc(100dvh - 100%)` is the viewport minus the header (100% resolves against the sticky
   header, which is the containing block) — it keeps the drawer scrollable on short screens,
   where the 11 links otherwise ran off the bottom with no way to reach them.

   This used to sit inside @media (max-width: 1300px), with the ten links laid out flat
   above that. The flat row needed ~709px and the header could only spare ~619px once a
   second button joined the CTA, so the links wrapped onto a second row and the header
   grew from 70px to 99px. Rather than shrink the navigation text or shorten the buttons,
   the drawer is now the navigation at every width. That also means the three group
   labels below finally get used on desktop, where they had always been hidden. */
/* --- no-JS baseline --- */
.site-nav {
	position: static;
	width: 100%;
	box-shadow: none;
	border-top: 0;
	max-height: none;
	overflow: visible;
}
.header-inner {
	flex-wrap: wrap;
}
.nav {
	flex-direction: row;
	flex-wrap: wrap;
	gap: 2px;
	padding: 6px 0 4px;
}
.nav a {
	padding: 0.45em 0.6em;
	border-bottom: 0;
	font-size: 0.9rem;
}
.nav-toggle {
	display: none;
}
.header-cta {
	margin-left: 0;
}

/* --- with JS: the drawer takes over --- */
.js .header-inner {
	flex-wrap: nowrap;
}
.js .nav-toggle {
	display: inline-flex;
}
/* Was display:none/block. Opacity+transform read as an intentional opening rather
   than a pop, and cost nothing extra: visibility carries the same "not in the
   accessibility tree, not tabbable while closed" job display used to do, just
   delayed until the close transition finishes so it doesn't cut the motion off
   mid-flight. prefers-reduced-motion (below) collapses both to instant either way. */
.js .site-nav {
	position: absolute;
	top: 100%;
	left: 0;
	right: 0;
	background: var(--navy);
	border-top: 1px solid rgba(255, 255, 255, 0.15);
	box-shadow: 0 18px 30px rgba(0, 57, 130, 0.4);
	max-height: calc(100vh - 100%);
	max-height: calc(100dvh - 100%);
	overflow-y: auto;
	overscroll-behavior: contain;
	-webkit-overflow-scrolling: touch;
	opacity: 0;
	visibility: hidden;
	transform: translateY(-14px) scaleY(0.96);
	transform-origin: top center;
	transition:
		opacity 0.26s var(--ease),
		transform 0.26s var(--ease),
		visibility 0s linear 0.26s;
}
.js .site-nav.open {
	opacity: 1;
	visibility: visible;
	transform: none;
	transition:
		opacity 0.26s var(--ease),
		transform 0.26s var(--ease);
}
/* A light stagger on the links themselves as the drawer opens. */
.js .nav a {
	opacity: 0;
	transform: translateY(-8px);
	transition:
		opacity 0.22s var(--ease),
		transform 0.22s var(--ease);
}
.js .site-nav.open .nav a {
	opacity: 1;
	transform: none;
}
.js .site-nav.open .nav li:nth-child(1) > a {
	transition-delay: 0.03s;
}
.js .site-nav.open .nav li:nth-child(3) > a {
	transition-delay: 0.07s;
}
.js .site-nav.open .nav li:nth-child(4) > a {
	transition-delay: 0.11s;
}
.js .site-nav.open .nav li:nth-child(5) > a {
	transition-delay: 0.15s;
}
.js .site-nav.open .nav li:nth-child(7) > a {
	transition-delay: 0.19s;
}
.js .site-nav.open .nav li:nth-child(8) > a {
	transition-delay: 0.23s;
}
.js .site-nav.open .nav li:nth-child(10) > a {
	transition-delay: 0.27s;
}
.js .site-nav.open .nav li:nth-child(11) > a {
	transition-delay: 0.31s;
}
.js .site-nav.open .nav li:nth-child(12) > a {
	transition-delay: 0.35s;
}
.js .site-nav.open .nav li:nth-child(13) > a {
	transition-delay: 0.39s;
}
.js .nav {
	flex-direction: column;
	align-items: stretch;
	gap: 0;
	padding: 10px 0 16px;
}
.js .nav a {
	padding: 0.8em 22px;
	border-radius: 0;
	border-bottom: 1px solid rgba(255, 255, 255, 0.08);
	font-size: 1.02rem;
}
.js .site-nav.open .nav-group-label {
	display: block;
	padding: 14px 22px 4px;
	font-size: 0.72rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var(--gold);
	font-weight: 700;
	opacity: 0.85;
}
@media (min-width: 701px) {
	.js .site-nav.open .nav {
		display: grid;
		grid-template-columns: 1fr 1fr;
		/* The panel spans the whole header, but its contents line up with the same 1180px
		   grid as the rest of the page, so the columns start where the logo does. */
		max-width: 1180px;
		margin: 0 auto;
		padding-left: 22px;
		padding-right: 22px;
	}
	.js .site-nav.open .nav-group-label {
		grid-column: 1 / -1;
	}
}

/* Stop the page scrolling behind an open drawer */
body.nav-open {
	overflow: hidden;
}

/* With the navigation out of the flex flow, the CTA pair carries the push to the right
   edge instead of the nav doing it. Both rules have to sit after the no-JS baseline
   above, which zeroes every .header-cta margin. Below 701px both CTAs are display:none,
   so their auto margin stops mattering and the menu button takes the push over. */
.header-cta-lead {
	margin-left: auto;
}
@media (min-width: 701px) {
	.nav-toggle {
		margin-left: 0;
	}
}

/* Table overflow on narrow screens */
.tbl-wrap {
	overflow-x: auto;
	-webkit-overflow-scrolling: touch;
	border-radius: var(--radius);
	box-shadow: var(--shadow);
}
.tbl-wrap .tbl {
	box-shadow: none;
	min-width: 480px;
}
/* parents.html's programme tables list every upcoming session (index.html's home
   preview only ever shows 6), which can run to 30+ rows — tall enough to push
   everything below it a long way down the page. A fixed height plus scroll keeps
   the section compact; the header stays pinned so a long scroll never loses track
   of which column is which. */
.tbl-wrap-scroll {
	max-height: 420px;
	overflow-y: auto;
}
.tbl-wrap-scroll .tbl thead th {
	position: sticky;
	top: 0;
	z-index: 1;
}

/* Hero on mobile */
@media (max-width: 980px) {
	.hero {
		padding: 52px 0 64px;
	}
}

/* 74px per section stacks up to ~900px of dead space down a phone screen. */
@media (max-width: 700px) {
	main section {
		padding: 46px 0;
	}
	main section.hero {
		padding: 40px 0 56px;
	}
	/* The fixed bottom bar already carries this CTA. Keeping it in the header pushed the
     page 104px wide, which made mobile browsers shrink the whole site to ~79% scale. */
	.header-cta {
		display: none;
	}
}

/* Sticky mobile join bar */
.mobile-cta-bar {
	display: none;
}
@media (max-width: 700px) {
	.mobile-cta-bar {
		display: flex;
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		z-index: 150;
		background: var(--navy);
		border-top: 3px solid var(--gold);
		padding: 10px 16px calc(10px + env(safe-area-inset-bottom, 0px));
		box-shadow: 0 -8px 24px rgba(0, 57, 130, 0.25);
	}
	.mobile-cta-bar .btn {
		flex: 1;
		justify-content: center;
	}
	body {
		padding-bottom: 78px;
	}
	/* The drawer is position:absolute off the header, so its own max-height has no
	   idea the fixed bar above sits over its bottom ~78px — without this, the last
	   link (Contact) opens underneath the bar and never becomes reachable, worst on
	   an iPhone where the dynamic toolbar eats into 100dvh further still. Padding
	   the scrollable list itself, rather than raising the drawer's max-height,
	   means the fix travels with the same 78px body already reserves. */
	.js .nav {
		padding-bottom: calc(16px + 78px + env(safe-area-inset-bottom, 0px));
	}
}

/* "Show more" activities collapse on mobile */
.act-more {
	display: contents;
}
.show-more-btn {
	display: none;
}
@media (max-width: 700px) {
	.act-more:not(.show) {
		display: none;
	}
	.show-more-btn {
		display: inline-flex;
		margin-top: 16px;
	}
}

/* Bigger touch targets on mobile */
@media (max-width: 700px) {
	.nav a {
		padding: 0.95em 22px;
		font-size: 1.02rem;
		min-height: 44px;
		display: flex;
		align-items: center;
	}
	.nav-toggle {
		min-height: 44px;
		padding: 0.6em 1em;
	}
	.tabs .tab-btn {
		padding: 0.75em 1.3em;
		min-height: 44px;
	}
	.qr-card .btn,
	.btn-sm {
		min-height: 44px;
	}
	.site-footer li {
		margin-bottom: 0.2em;
	}
	.site-footer a {
		display: inline-block;
		padding: 0.5em 0;
	}
	/* .site-footer a above is (0,1,1) and wins over .social-fb's own (0,1,0)
	   inline-flex regardless of source order, which knocked the icon back into
	   normal inline flow — and since .social-fb span is display:grid (block-level),
	   a block box inside inline content forces a line break, dropping "Follow us
	   on Facebook" onto its own line under the icon instead of beside it. */
	.site-footer .social-fb,
	.site-footer .social-ig {
		display: inline-flex;
		padding: 0.5em 0;
	}
	.linklist a {
		padding: 16px 4px;
	}
}

/* ---- Official Scout logo lockups (POR 2e.2 — assets from scouts.org.uk, unaltered) ---- */
.sec-chip {
	display: inline-flex;
	align-items: center;
	gap: 12px;
	background: #fff;
	border-radius: 14px;
	padding: 9px 16px 9px 12px;
	margin-top: 16px;
	box-shadow: 0 10px 24px rgba(8, 10, 35, 0.25);
}
.sec-chip img {
	height: 34px;
	width: auto;
}
.sec-chip span {
	font-family: var(--font-head);
	font-weight: 700;
	color: var(--navy);
	font-size: 0.98rem;
}
/* Fixed-height band + object-fit so logos of differing aspect ratios occupy the same
   vertical space and the card headings line up across the row. */
.t-logo {
	height: 54px;
	width: auto;
	max-width: 100%;
	object-fit: contain;
	margin: 2px auto 6px;
	display: block;
}
.card-logo {
	height: 44px;
	width: auto;
	margin-bottom: 12px;
}
.official-card {
	background: #fff;
	display: inline-block;
	padding: 16px 20px 14px;
	border-radius: 16px;
	text-align: center;
	margin-bottom: 14px;
	max-width: 100%;
}
.official-card .hl-logo {
	height: 46px;
	width: auto;
	margin: 0 auto;
}
/* The Brabazon half of the lock-up, built the same way as the header's: "1st" set in
   Nunito Sans Extra Bold, as the brand guidelines require, beside the wordmark itself.
   Both in black, which is the wordmark's sanctioned form on white and matches the black
   Scouts logo above it.

   The wordmark is a plain <img>, not the header's CSS mask. The artwork is
   fill="currentColor", which in an <img> renders in its own document and comes out
   black — exactly what is wanted here, so it needs no mask and no second asset.

   The <img> carries brabazon.svg's own 1794 x 350 as its width/height — the convention
   squirrels.svg and the rest follow — so the intrinsic ratio stays exact however large
   CSS renders it.

   The wordmark is sized in em, against the "1st" beside it, and that is the point. Its
   artwork height includes the capital B, the b's ascender and the script's descenders,
   so only about a third of it is lowercase — scaling it to the type's own height, or to
   fit a given width, sets the lowercase far too small.

   0.97em is a compromise between two things that pull against each other. Matching the
   flowing lowercase to the x-height of the "st" exactly wants about 1.17em, but the
   script's capital B is tall, so at that size the B towers over the "1" and "Brabazon"
   swamps "1st". At 0.97em the lowercase sits just under the "st" and the two halves
   carry equal weight. The header lock-up's 0.804em is the other extreme: the B lines up
   with the "1" and the lowercase is visibly small.

   Because everything here is em, the whole lock-up resizes from the one font-size on
   .oc-lockup and the ratio cannot drift. Change that number, nothing else.

   The Scouts logo above is then set to land on roughly the same width as the lock-up
   (~170px at these sizes). Leaving it smaller made the wordmark line wider than the
   mark above it and the card looked bottom-heavy. */
.official-card .oc-lockup {
	display: flex;
	align-items: center;
	justify-content: center;
	/* The one number that sizes the whole lock-up. */
	font-size: 1.6rem;
	gap: 0.35em;
	margin: 0.48em 0 0;
	color: #000;
}
.official-card .oc-1st {
	font-family: var(--font-head);
	font-weight: 800;
	font-size: 1em;
	line-height: 1;
	letter-spacing: -0.01em;
}
.official-card .oc-wordmark {
	height: 0.97em;
	width: auto;
}
.oc-note {
	font-size: 0.8rem;
	color: #a3c1e4;
	margin-top: 8px !important;
}
.actions {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	align-items: center;
}

.map-embed {
	border-radius: var(--radius);
	overflow: hidden;
	min-height: 260px;
	background: var(--cream);
	border: 1px solid var(--line);
}
.map-embed iframe {
	display: block;
	width: 100%;
	height: 260px;
	border: 0;
}

/* ---------- Programme panels (index.html, parents.html) ----------
   Two hand-kept programme tables with a tab strip above them. Without JS both
   panels show, stacked, each under its own heading — so nothing is hidden from a
   visitor whose script failed. */
.prog-panel-title {
	margin: 0 0 12px;
	font-size: 1.05rem;
}
.prog-panel + .prog-panel {
	margin-top: 30px;
}
/* Once the tabs are built, the panel heading just repeats the active tab. */
.prog-ready .prog-panel-title {
	display: none;
}
.prog-ready .prog-panel + .prog-panel {
	margin-top: 0;
}
/* A tab switch swaps which panel carries the `hidden` attribute. Removing that
   attribute changes the panel's display from none to block, and a CSS animation
   on an element restarts the moment that happens — so this needs no JS beyond
   the hidden-toggle initProgrammeTabs already does. */
.prog-panel:not([hidden]) {
	animation: panel-fade 0.22s var(--ease);
}
@keyframes panel-fade {
	from {
		opacity: 0;
		transform: translateY(4px);
	}
	to {
		opacity: 1;
		transform: none;
	}
}

/* ---------- Google Drive document library (parents.html) ---------- */
/* The inline folder list uses Google's undocumented embeddedfolderview endpoint, so it
   is treated as an enhancement: the Open-in-Drive button always works, and the frame
   collapses to a readable panel if it never loads. The frame scrolls internally, so it
   gets a fixed height rather than growing with the folder. */
.drive-block {
	margin-top: 36px;
}
/* The category tabs sit directly above the frame, so they need less bottom
   margin than the enquiry form's tabs. */
.drive-tabs {
	margin-bottom: 14px;
}
.drive-block-head {
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 12px 20px;
	flex-wrap: wrap;
	margin-bottom: 14px;
}
.drive-block-head h3 {
	margin: 0 0 2px;
}
.drive-embed {
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--white);
	overflow: hidden;
}
.drive-loading,
.drive-empty {
	margin: 0;
	padding: 26px;
	text-align: center;
}
/* One row per PDF: name (links out to Drive) and last-updated date only –
   never an uploader/editor name, since initDriveEmbed() in app.js never
   asks the Drive API for that field in the first place. */
.drive-files {
	list-style: none;
	margin: 0;
	padding: 0;
}
.drive-file {
	display: flex;
	align-items: baseline;
	justify-content: space-between;
	gap: 8px 20px;
	padding: 14px 22px;
	border-bottom: 1px solid var(--line);
}
.drive-file:last-child {
	border-bottom: 0;
}
.drive-file a {
	font-weight: 700;
	color: var(--accent);
}
.drive-file-date {
	flex: none;
	color: var(--muted);
	font-size: 0.9rem;
}
.drive-fallback {
	display: none;
	padding: 30px 26px;
	text-align: center;
}
.drive-slot:empty {
	display: none;
}
.drive-embed.drive-failed .drive-slot {
	display: none;
}
.drive-embed.drive-failed {
	border-style: dashed;
	border-color: var(--accent);
}
.drive-embed.drive-failed .drive-fallback {
	display: block;
}
@media (max-width: 700px) {
	.drive-file {
		flex-direction: column;
		align-items: flex-start;
		gap: 2px;
	}
	.drive-fallback {
		padding: 22px 18px;
		text-align: left;
	}
}
/* Sticky, and highlights the section in view (assets/app.js, initTocScrollspy).
   --header-h is measured on load rather than hard-coded, since header height can
   shift a little with font loading. Falls back to a sane flat value so the strip
   still sits just under the header before that JS runs, or if it never does. */
.page-toc {
	background: var(--white);
	border-bottom: 1px solid var(--line);
	padding: 14px 0;
	position: sticky;
	top: var(--header-h, 70px);
	z-index: 90;
}
/* The header + toc are both sticky, so an in-page anchor needs extra clearance on
   top of the site-wide 124px or its target lands under the toc as well. */
html:has(.page-toc) {
	scroll-padding-top: calc(124px + var(--toc-h, 52px));
}
.page-toc a.active {
	color: var(--accent-2);
	text-decoration: underline;
	text-decoration-thickness: 2px;
	text-underline-offset: 3px;
}
.page-toc .wrap {
	display: flex;
	align-items: center;
	gap: 18px 22px;
	flex-wrap: wrap;
}
.page-toc .toc-label {
	font-size: 0.75rem;
	text-transform: uppercase;
	letter-spacing: 0.08em;
	color: var(--muted);
	font-weight: 700;
	flex: 0 0 auto;
}
.page-toc a {
	color: var(--navy);
	font-weight: 600;
	font-size: 0.92rem;
	text-decoration: none;
}
/* Same reason as .linklist a:hover — the rest state is already var(--navy). */
.page-toc a:hover {
	color: var(--accent-2);
	text-decoration: underline;
}
/* Wrap rather than scroll: a clipped horizontal strip gives no hint that more links exist. */
@media (max-width: 700px) {
	.page-toc .wrap {
		flex-wrap: wrap;
		gap: 6px 18px;
	}
	.page-toc .toc-label {
		flex: 0 0 100%;
	}
	.page-toc a {
		white-space: nowrap;
	}
}
.social-fb,
.social-ig {
	display: inline-flex;
	align-items: center;
	gap: 10px;
	color: #c8dbf2;
	text-decoration: none;
	font-weight: 600;
}
.social-fb span,
.social-ig span {
	display: grid;
	place-items: center;
	width: 34px;
	height: 34px;
	border-radius: 50%;
	color: #fff;
	flex: 0 0 auto;
}
.social-fb span {
	background: #1877f2;
	font-family: var(--font-head);
	font-weight: 800;
	font-size: 1.1rem;
}
/* Instagram's own mark is a gradient; this is the flat single-tone treatment the
   Facebook badge above already uses, not the official logo artwork. */
.social-ig span {
	background: #c1305a;
}
.social-ig svg {
	width: 18px;
	height: 18px;
	fill: none;
	stroke: currentColor;
	stroke-width: 1.8;
	stroke-linecap: round;
	stroke-linejoin: round;
}
.social-fb:hover,
.social-ig:hover {
	color: var(--gold);
}
.social-fb:hover span {
	background: #3b8cf5;
}
.social-ig:hover span {
	background: #d34873;
}
