/*
Theme Name: Blackpool North Shore Golf Club
Theme URI: https://github.com/martinjacksonuk/bnsgc-site
Author: DiGenie
Description: Clean, semantic, GEO-optimised block theme. No page-builder bloat. All design tokens live in theme.json.
Version: 0.2.124
Requires at least: 6.5
Requires PHP: 8.1
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: digenie
*/

/*
 * Minimal utility + inherited-component layer. The DESIGN SYSTEM lives in theme.json.
 *
 * Palette and fonts here are NEUTRAL PLACEHOLDERS (role slugs: brand/accent/ink/surface…,
 * system font stacks). They are deliberately un-locked, discover the real palette and
 * fonts by building the pilot page, then set them in theme.json at Lock (see the
 * digenie-uiux-process skill's Explore → Lock → Apply). Do NOT treat these values as final.
 *
 * Colours are referenced via var(--wp--preset--color--<role>); never hardcode a brand hex
 * here. Self-hosted WOFF2 fonts are declared in theme.json fontFace at Lock. Never here.
 * `button` deliberately carries no fontFace of its own (it reuses the body faces).
 */

/* Header brand lockup: see patterns/site-brand.php.
   Sits on the navy header band (navy since 2026-07-16, per home-v2), so it uses the
   white-circle/white-letter variant.
   Height 58px = the design direction's 48px +20% (client call, 2026-07-15); the doc's
   stated 44-48px range is superseded by that. Source art is 2495x792 (3.15:1), so 58px
   renders ~183px wide. Still well inside the 2495px of source, so no retina softness. */
.bns-site-brand {
	margin: 0;
}
.bns-site-brand img {
	height: 58px;
	width: auto;
	display: block;
}
@media (max-width: 599px) {
	.bns-site-brand img {
		height: 48px; /* 40px +20% */
	}
}

/* Footer brand lockup. See patterns/footer-brand.php.
   Sits on the white footer band, so it uses the blue-letter variant (the header's
   white-circle lockup would disappear on white). Sized by HEIGHT only: source art is
   2495x792 (3.15:1), so a width rule would render it a few px tall. 44px ≈ 139px wide. */
.bns-footer-brand {
	margin: 0;
}
.bns-footer-brand img {
	height: 44px;
	width: auto;
	display: block;
}

/* Widen the prominent footer share band to the shared site width
   token (wideSize) so its content lines up with the header, home and products
   listing. The full-bleed navy band stays full width; only its inner content
   follows. The lower fine-print section keeps the narrow reading measure
   (contentSize). A centred disclaimer at the full site width reads too wide. */
.bns-footer-share {
	--wp--style--global--content-size: var(--wp--style--global--wide-size);
}

/* Footer share band: centre everything on mobile,
   heading, intro, and the social icon row. Left-aligned on larger screens.
   `ul.wp-block-social-links` carries element specificity so it beats the block's own
   is-content-justification-left rule without !important. */
@media (max-width: 599px) {
	.bns-footer-share {
		text-align: center;
	}
	.bns-footer-share ul.wp-block-social-links {
		justify-content: center;
	}
}

/* Sticky header. The masthead floats at the top of the viewport on scroll.
   Targets the template-part wrapper (front-end class), not the inner .site-header,
   so the whole navy band sticks. z-index keeps it above page content; the mobile
   navigation overlay sets its own higher stacking context.
   2026-10-06: the part's wrapper is a <div> now (html-validate: a <header> inside a <header>), so
   the rule finds it by what it holds. Same box, same behaviour. */
.wp-block-template-part:has(> .masthead) {
	position: sticky;
	top: 0;
	z-index: 999;
}

/* ── Mobile navigation ──────────────────────────────────────────────────────
   (1) Push the hamburger breakpoint from WordPress's default 600px up to 768px.
   Our six uppercase items (Home · Carers Help · Shopping Cart · Blog · FAQ / Gen
   Help · Replica Dentures) don't fit on one line until ~768px, so between 600 and
   767px the inline menu wrapped under the logo. Keep the hamburger across that
   band; the full menu returns at 768px, where it sits on one clean line. Selectors
   are scoped under .site-header and carry an extra class so they out-specify core's
   `@media (min-width:600px)` rules without !important. */
@media (min-width: 600px) and (max-width: 767.98px) {
	.site-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
		display: flex;
	}
	.site-header .wp-block-navigation.is-responsive .wp-block-navigation__responsive-container:not(.is-menu-open) {
		display: none;
	}
}

/* (2) Give the opened overlay breathing room from the edges, core opens it
   edge-to-edge, so the right-aligned items and the close button hugged the right
   edge. Applies wherever the overlay is used (below 768px, per rule 1). */
@media (max-width: 767.98px) {
	.site-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
		padding-inline: var(--wp--preset--spacing--50);
	}
	.site-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-close {
		right: var(--wp--preset--spacing--50);
	}
}

/* Accessible skip link (core injects the anchor for block themes). */
.skip-link.screen-reader-text {
	background-color: var(--wp--preset--color--base);
	color: var(--wp--preset--color--brand);
	left: 6px;
	top: 6px;
	padding: 12px 18px;
	z-index: 100000;
}

/* Visually-hidden text for screen readers. */
.screen-reader-text {
	border: 0;
	clip: rect(1px, 1px, 1px, 1px);
	clip-path: inset(50%);
	height: 1px;
	width: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute !important;
	word-wrap: normal !important;
}

.screen-reader-text:focus {
	background-color: var(--wp--preset--color--base);
	clip: auto !important;
	clip-path: none;
	display: block;
	height: auto;
	width: auto;
	left: 6px;
	top: 6px;
	padding: 12px 18px;
	z-index: 100000;
}

/* Cards/patterns lean on this hover affordance. */
.bns-card {
	transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.bns-card:hover {
	box-shadow: 0 6px 20px rgba(42, 42, 42, 0.08);
}

/* Hero subject cut-out: replaces the separate drop-shadow raster the old CMS loads
   beneath it (pngtree-round-gradient-black-shadow. See docs/image-map.json).
   Must be filter:drop-shadow, NOT box-shadow: the source is a transparent PNG, so
   box-shadow renders a rectangle around the image box, while drop-shadow follows the
   alpha channel and shadows the subject itself.
   Client question pending: docs/client-report.md Home Q9. */
.bns-cutout-hero img {
	filter: drop-shadow(0 14px 10px rgba(21, 48, 71, 0.28));
}

/* ============================================================================
   HOME v2 utility layer (2026-07-17). The client-approved prototype's
   signatures that block attributes cannot express. Everything else (colour,
   type, spacing) comes from theme.json tokens. Source of truth:
   bnsgc-working/docs/mockups/home-v2/home.html.
   ========================================================================= */

/* Sticky masthead: anchor jumps must land clear of it. */
html {
	scroll-padding-top: 96px;
}

/* Buttons. The v2 "Google-style" interaction: subtle top-light gradient,
   elevation, lift on hover, press on active. Colour/radius live in theme.json. */
.wp-element-button {
	background-image: linear-gradient(180deg, var(--wp--preset--color--ink-soft), var(--wp--preset--color--ink));
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22);
	transition: transform 0.12s ease, box-shadow 0.12s ease, background-color 0.12s ease;
	/* ⚠️ 44px, same target-size reason as .bns-btn. This is CORE's button, the one the club gets
	   when they add a Button block themselves, so it has to carry the floor too or every button
	   they make in the editor lands under it. The audit measured "Find out more" at 133x39px
	   (2026-09-16). inline-flex so the label centres in the taller box. */
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-height: 44px;
}
.wp-element-button:hover {
	background-image: linear-gradient(180deg, var(--wp--preset--color--brand-deep), var(--wp--preset--color--ink-soft));
	transform: translateY(-2px);
	box-shadow: 0 6px 16px rgba(0, 0, 0, 0.26);
}
.wp-element-button:active {
	transform: translateY(0);
	box-shadow: 0 1px 3px rgba(0, 0, 0, 0.22);
}
/* A button given its own background colour (white-on-teal etc.) drops the navy gradient. */
.wp-block-button .wp-element-button.has-background {
	background-image: none;
}
@media (prefers-reduced-motion: reduce) {
	.wp-element-button,
	.bns-service img,
	.bns-res-card,
	.bns-pod-card {
		transition: none !important;
	}
}

/* ⚠️ REMOVED 2026-09-16: `.bns-hero { overflow: clip }` used to sit here.
   Found by the FIRST CLEAN RUN of tools/check-selector-collisions.mjs, and it is a real trap
   rather than tool noise. It belongs to the INHERITED SKELETON LAYER and was written for that
   build's cut-out hero (`.bns-hero-art`, which no template in this theme uses). THIS site's hero
   sets its own `overflow:hidden` in the hero band ~1,400 lines below, and being later it already
   won, so the page was correct BY SOURCE ORDER ALONE. Reorder the file, or lift the skeleton layer
   out, and the hero silently changes clipping mode with nothing to show for it.
   Two authors setting one property on one element, that far apart, is exactly what the
   "Never redefine a shared element" rule in CLAUDE.md exists to stop. */

/* Hero artwork, brand radial glow behind the cut-out subject. */
.bns-hero-art {
	position: relative;
	display: grid;
	place-items: center;
}
.bns-hero-art::before {
	content: "";
	position: absolute;
	inset: -12%;
	border-radius: 50%;
	background: radial-gradient(circle at 50% 45%, rgba(58, 74, 90, 0.3), rgba(58, 74, 90, 0) 68%);
}
.bns-hero-art img {
	position: relative;
	width: min(100%, 400px);
	height: auto;
	filter: drop-shadow(0 26px 34px rgba(4, 90, 79, 0.24));
}

/* The teal chapter band. The poster template's own gradient extended into the
   page, plus one echoed blob so the artwork edges read as page, not image. */
.bns-chapter {
	position: relative;
	isolation: isolate;
	background:
		radial-gradient(120% 90% at 12% 0%, var(--wp--preset--color--accent) 0%, rgba(58, 74, 90, 0) 58%),
		linear-gradient(158deg, var(--wp--preset--color--brand) 0%, var(--wp--preset--color--brand-deep) 55%, var(--wp--preset--color--brand-deep) 100%);
}
.bns-chapter::before {
	content: "";
	position: absolute;
	z-index: -1;
	border-radius: 50%;
	background: rgba(58, 74, 90, 0.16);
	width: 46vw;
	height: 26vw;
	left: -8vw;
	top: 14%;
}

/* Service poster cards. Lifted off the gradient with a white ring and deep
   double shadow; gentle grow on hover. The image link is the card. */
.bns-service {
	text-align: center;
}
.bns-service img {
	width: 100%;
	height: auto;
	border-radius: 14px;
	border: 2px solid rgba(255, 255, 255, 0.45);
	box-shadow: 0 10px 22px rgba(0, 0, 0, 0.32), 0 30px 60px rgba(0, 0, 0, 0.38);
	transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.bns-service:hover img {
	transform: scale(1.02);
	box-shadow: 0 14px 28px rgba(0, 0, 0, 0.38), 0 38px 74px rgba(0, 0, 0, 0.46);
}

/* Chapter closing prose. Hairline above, constrained measure. */
.bns-chapter-foot {
	border-top: 1px solid rgba(255, 255, 255, 0.22);
	max-width: 64ch;
}

/* Ora champion. Avatar in a soft teal circle; the flat-vector file ships on an
   opaque white square, multiply melts it into the field. */
.bns-champion-art {
	position: relative;
	display: grid;
	place-items: center;
	aspect-ratio: 1;
	border-radius: 50%;
	background: radial-gradient(circle at 50% 45%, var(--wp--preset--color--surface-2) 0%, var(--wp--preset--color--surface-2) 70%);
}
.bns-champion-art img {
	width: 76%;
	height: auto;
	mix-blend-mode: multiply;
}

/* Callout note (help-us-improve). */
.bns-note {
	border: 1px solid var(--wp--preset--color--line);
	border-left: 4px solid var(--wp--preset--color--brand);
	border-radius: 14px;
}
.bns-note p {
	max-width: 70ch;
}

/* Two click-through tiles. */
.bns-duo-tile img {
	border-radius: 14px;
	border: 1px solid var(--wp--preset--color--line);
	box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14);
	transition: box-shadow 0.18s ease, transform 0.18s ease;
}
.bns-duo-tile a:hover img {
	transform: translateY(-4px);
	box-shadow: 0 18px 40px rgba(0, 0, 0, 0.22);
}

/* Constrained lede under a stacked heading. On alignwide groups the core layout
   rule out-specifies a group-level cap, so cap the paragraphs inside too. */
.bns-lede,
.bns-lede p {
	max-width: 68ch;
}

/* Watch/listen/ask. Three invisible link zones over the artwork's panels. */
.bns-tri {
	position: relative;
}
.bns-tri img {
	width: 100%;
	height: auto;
	border-radius: 14px;
	display: block;
}
.bns-tri a {
	position: absolute;
	border-radius: 14px;
}
.bns-tri a:hover,
.bns-tri a:focus-visible {
	box-shadow: inset 0 0 0 3px #fff, 0 0 0 3px var(--wp--preset--color--brand);
}

/* Lightbox: any .bns-zoom link opens its href full-size (assets/js/home.js
   builds the dialog). Hover/focus shows the enlarge hint. */
.bns-zoom {
	cursor: zoom-in;
	display: block;
	position: relative;
}
.bns-zoom::after {
	content: "Click to enlarge ⊕";
	position: absolute;
	right: 0.75rem;
	bottom: 0.75rem;
	background: rgba(0, 0, 0, 0.85);
	color: #fff;
	font: 600 0.8rem/1 var(--wp--preset--font-family--body);
	padding: 0.45rem 0.75rem;
	border-radius: 6px;
	opacity: 0;
	transition: opacity 0.15s ease;
	pointer-events: none;
}
.bns-zoom:hover::after,
.bns-zoom:focus-visible::after {
	opacity: 1;
}
dialog.bns-lightbox {
	border: 0;
	padding: 0;
	background: transparent;
	overflow: visible;
}
dialog.bns-lightbox::backdrop {
	background: rgba(0, 0, 0, 0.85);
}
dialog.bns-lightbox img {
	max-width: 92vw;
	max-height: 88vh;
	width: auto;
	height: auto;
	border-radius: 10px;
}
dialog.bns-lightbox .bns-lightbox-close {
	position: absolute;
	top: 0.6rem;
	right: 0.6rem;
	background: #fff;
	border: 0;
	border-radius: 999px;
	width: 2.3rem;
	height: 2.3rem;
	font-size: 1.25rem;
	line-height: 1;
	cursor: pointer;
	font-family: var(--wp--preset--font-family--body);
}

/* Click-to-load video facade, YouTube markup only enters the page on demand. */
.bns-frame {
	aspect-ratio: 16 / 9;
	border-radius: 14px;
	overflow: hidden;
	background: #000;
}
.bns-frame iframe {
	width: 100%;
	height: 100%;
	border: 0;
	display: block;
}
.bns-yt-lite {
	position: relative;
	display: block;
	width: 100%;
	height: 100%;
	padding: 0;
	border: 0;
	background: #000;
	cursor: pointer;
}
.bns-yt-lite img {
	width: 100%;
	height: 100%;
	object-fit: cover;
}
.bns-yt-play {
	position: absolute;
	inset: 0;
	margin: auto;
	width: 72px;
	height: 50px;
	border-radius: 14px;
	background: rgba(0, 0, 0, 0.85);
	display: grid;
	place-items: center;
	transition: background-color 0.15s ease;
}
.bns-yt-play::before {
	content: "";
	border-style: solid;
	border-width: 10px 0 10px 17px;
	border-color: transparent transparent transparent #fff;
	margin-left: 3px;
}
.bns-yt-lite:hover .bns-yt-play,
.bns-yt-lite:focus-visible .bns-yt-play {
	background: var(--wp--preset--color--brand);
}

/* Deep teal media band (the problem, in video or podcast). */
.bns-deepband {
	background: linear-gradient(158deg, var(--wp--preset--color--brand) 0%, var(--wp--preset--color--brand-deep) 58%, var(--wp--preset--color--brand-deep) 100%);
}

/* Spotify episode card. */
.bns-pod-card img {
	border-radius: 14px;
	border: 1px solid rgba(255, 255, 255, 0.28);
	box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
	transition: transform 0.18s ease;
}
.bns-pod-card a:hover img {
	transform: translateY(-3px);
}

/* Microphone glyph inside the Spotify button (CSS mask, no markup needed). */
.bns-btn-mic .wp-element-button::before {
	content: "";
	display: inline-block;
	width: 1em;
	height: 1em;
	vertical-align: -0.12em;
	margin-right: 0.45rem;
	background: currentColor;
	-webkit-mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 15a4 4 0 0 0 4-4V6a4 4 0 1 0-8 0v5a4 4 0 0 0 4 4Zm6-4a6 6 0 0 1-12 0H4a8 8 0 0 0 7 7.94V22h2v-3.06A8 8 0 0 0 20 11h-2Z"/></svg>') center / contain no-repeat;
	mask: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 15a4 4 0 0 0 4-4V6a4 4 0 1 0-8 0v5a4 4 0 0 0 4 4Zm6-4a6 6 0 0 1-12 0H4a8 8 0 0 0 7 7.94V22h2v-3.06A8 8 0 0 0 20 11h-2Z"/></svg>') center / contain no-repeat;
}

/* Teal-dot list (what's in my bag, committee roles). */
ul.bns-dotlist {
	list-style: none;
	padding: 0;
	margin: 0;
}
ul.bns-dotlist li {
	padding: 0.7rem 0 0.7rem 1.9rem;
	border-bottom: 1px solid var(--wp--preset--color--line);
	position: relative;
	font-weight: 600;
}
ul.bns-dotlist li::before {
	content: "";
	position: absolute;
	left: 0;
	top: 1.15rem;
	width: 10px;
	height: 10px;
	border-radius: 50%;
	background: var(--wp--preset--color--brand);
}
ul.bns-dotlist.bns-dotlist-plain li {
	border-bottom: 0;
	font-weight: 400;
	padding-block: 0.55rem;
}

/* Numbered steps with teal counters. */
ol.bns-steps {
	list-style: none;
	padding: 0;
	margin: 0;
	counter-reset: bns-s;
}
ol.bns-steps li {
	counter-increment: bns-s;
	position: relative;
	padding: 0.65rem 0 0.65rem 2.6rem;
	font-weight: 600;
	overflow-wrap: anywhere;
}
ol.bns-steps li::before {
	content: counter(bns-s);
	position: absolute;
	left: 0;
	top: 0.6rem;
	width: 1.7rem;
	height: 1.7rem;
	border-radius: 50%;
	background: var(--wp--preset--color--brand);
	color: #fff;
	font-family: var(--wp--preset--font-family--display);
	font-weight: 800;
	font-size: 0.85rem;
	display: grid;
	place-items: center;
}

/* Dictation steps card. */
.bns-steps-card {
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--line);
	border-left: 4px solid var(--wp--preset--color--brand);
	border-radius: 14px;
}

/* Video-resource tiles. */
.bns-res-card {
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 14px;
	overflow: hidden;
	transition: transform 0.18s ease, box-shadow 0.18s ease;
}
.bns-res-card:hover {
	transform: translateY(-4px);
	box-shadow: 0 16px 36px rgba(0, 0, 0, 0.14);
}
.bns-res-card img {
	display: block;
	width: 100%;
	height: auto;
}
/* Card title links must clear the 24px target floor (SC 2.5.8). */
.bns-res-card h3 a {
	display: inline-block;
	padding-block: 0.4rem;
}

/* Feedback form (G7: markup only. No backend yet; posts nowhere). */
.digenie-form {
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 14px;
	padding: 2rem;
}
.digenie-form label {
	display: block;
	font-weight: 700;
	font-size: 0.92rem;
	margin-bottom: 0.35rem;
}
.digenie-form input,
.digenie-form textarea {
	width: 100%;
	font-family: var(--wp--preset--font-family--body);
	font-size: 1rem;
	padding: 0.75rem 0.9rem;
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 8px;
	background: var(--wp--preset--color--surface-2);
	color: var(--wp--preset--color--ink);
	box-sizing: border-box;
}
.digenie-form input:focus,
.digenie-form textarea:focus {
	border-color: var(--wp--preset--color--brand);
	background: var(--wp--preset--color--base);
}
.digenie-form p {
	margin: 0 0 1.25rem;
}
.digenie-form p:last-child {
	margin-bottom: 0;
}
/* Form delivery (bnsgc-forms mu-plugin): honeypot + submit status. */
.digenie-hp {
	position: absolute !important;
	left: -9999px;
	width: 1px;
	height: 1px;
	overflow: hidden;
}
.digenie-form-status {
	font-weight: 600;
}
.digenie-form-status.is-ok {
	color: var(--wp--preset--color--brand-deep);
}
.digenie-form-status.is-error {
	color: var(--wp--preset--color--accent-deep);
}
/* Consent tick-box + privacy note (injected from Settings → Form Delivery). */
.bns-consent {
	font-size: 0.95rem;
}
.bns-consent label {
	display: flex;
	gap: 0.5rem;
	align-items: flex-start;
	font-weight: 400;
	margin: 0;
	cursor: pointer;
}
.bns-consent input[type="checkbox"] {
	margin-top: 0.28rem;
	flex: 0 0 auto;
}
.digenie-form-note {
	font-size: 0.85rem;
	color: var(--wp--preset--color--ink-soft);
}
.digenie-form-note a,
.bns-consent a {
	color: var(--wp--preset--color--brand);
}

/* ============================================================================
   Product listing (the recommended-products CPT). The card frame + hover come
   from .bns-card above; these rules lay out the product-card block's parts and
   keep every tile the same shape regardless of blurb length.
   ========================================================================= */

/* Header prose and the product grid share one ~1040px column so their left
   edges line up (the intro is no longer a narrow box floating above a wider
   grid). Overriding the constrained content-size on the section widens the h1
   and the query alike; the intro paragraphs are re-capped to a readable measure
   below. At 1040px the 18rem min-column naturally lands 3 across, dropping to
   2 then 1 as it narrows. No media queries needed. */
.bns-products-archive {
	/* Track the site-wide width token (theme.json wideSize) so the header, home,
	   footer and this listing all share one content width. */
	--wp--style--global--content-size: var(--wp--style--global--wide-size);
}
/* The intro group fills the 1040px column (left edge on the grid); its own
   flow layout left-aligns the h1 and paragraphs, and the prose is re-capped to
   a readable measure so it doesn't run the full width. */
.bns-products-intro > p {
	max-width: 68ch;
}

/* Each grid cell (the post-template <li>) is a flex container so the card fills
   its height WITHOUT height:100%. height:100% on a card that contains an
   aspect-ratio image window mis-sizes the grid track. The row computes too
   short and the card overflows into the row below (buttons then look sliced by
   the next row's border). Letting the flex cell size to content fixes it. */
.bns-products-archive .wp-block-post-template.is-layout-grid > li {
	display: flex;
}

/* Card = vertical stack that fills its (flex) cell; actions pinned to the bottom
   so buttons line up across a row even when blurbs differ in length. A visible
   box (border + padding + surface) makes each product read as its own tile at
   rest, not only on hover. */
.bns-product-card {
	display: flex;
	flex-direction: column;
	width: 100%;
	padding: var(--wp--preset--spacing--50);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 14px;
	background: var(--wp--preset--color--surface);
}
.bns-product-card > .bns-product-actions {
	margin-top: auto;
}

/* Uniform image window at the top of each tile. */
.bns-product-image {
	margin: 0 0 var(--wp--preset--spacing--30);
	border-radius: 8px;
	overflow: hidden;
	background: var(--wp--preset--color--surface-2);
	aspect-ratio: 4 / 3;
}
.bns-product-image img {
	width: 100%;
	height: 100%;
	object-fit: contain;
	display: block;
}

/* No photo yet: a subtle framed placeholder holds the window open so titles,
   blurbs and buttons stay aligned across the row. And it reads as "photo to
   come", nudging the gap to be filled, rather than a broken card. */
.bns-product-image--empty {
	display: flex;
	align-items: center;
	justify-content: center;
	border: 1px dashed var(--wp--preset--color--line);
}
.bns-product-image__placeholder {
	display: flex;
	width: 34%;
	max-width: 84px;
	color: var(--wp--preset--color--brand);
	opacity: 0.4;
}
.bns-product-image__placeholder svg {
	width: 100%;
	height: auto;
}

.bns-product-name {
	margin: 0 0 var(--wp--preset--spacing--20);
	font-size: var(--wp--preset--font-size--large);
}
.bns-product-name a {
	display: inline-block;
	padding-block: 0.35rem; /* clears the 24px target floor (SC 2.5.8) */
	text-decoration: none;
	color: var(--wp--preset--color--ink);
}
.bns-product-name a:hover,
.bns-product-name a:focus-visible {
	color: var(--wp--preset--color--brand);
	text-decoration: underline;
}

.bns-product-blurb {
	font-size: 0.95rem;
	margin: 0 0 var(--wp--preset--spacing--30);
}

/* Discount pill, teal, matches the site's teal accent family. */
.bns-product-discount {
	display: inline-block;
	margin: 0 0 var(--wp--preset--spacing--30);
	padding: 0.3rem 0.7rem;
	border-radius: 999px;
	background: var(--wp--preset--color--surface-2);
	border: 1px solid var(--wp--preset--color--brand);
	color: var(--wp--preset--color--brand-deep);
	font-size: 0.8rem;
}

/* Actions stack (pinned to the card bottom via margin-top:auto above): the
   "Watch video" link then the buy button, evenly spaced, so the button is the
   bottom-most element and buy buttons line up across a row. */
.bns-product-actions {
	display: flex;
	flex-direction: column;
	gap: var(--wp--preset--spacing--30);
}
.bns-product-actions .wp-block-buttons {
	margin: 0;
}
.bns-product-video-link-wrap {
	margin: 0;
}
.bns-product-video-link {
	display: inline-block;
	padding-block: 0.35rem; /* clears the 24px target floor (SC 2.5.8) */
	font-size: 0.9rem;
	font-weight: 600;
	color: var(--wp--preset--color--brand);
}

/* ── Single product page ─────────────────────────────────────────────────────────────────────
   Source order is title → media → body, so the product name is the first thing a screen reader
   (and a phone) meets. On desktop the grid lifts the media into a left column spanning both rows,
   putting the photo beside the name and buy action rather than above them. Previously a portrait
   shot rendered ~860px tall in the 680 column and pushed the h1 below the fold.
   The page sits at the wide 1040 edge (see docs/design-system-lock.md §2): as a 680 constrained
   column it started ~180px inward of the archive and every other band. */
.bns-product-layout {
	display: grid;
	gap: var(--wp--preset--spacing--40);
}
@media (min-width: 901px) {
	.bns-product-layout {
		grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
		align-items: start;
		column-gap: var(--wp--preset--spacing--50);
	}
	.bns-product-media {
		grid-column: 1;
		grid-row: 1 / span 2;
	}
	.bns-product-title {
		grid-column: 2;
		grid-row: 1;
	}
	.bns-product-body {
		grid-column: 2;
		grid-row: 2;
	}
}

/* Same treatment as the post hero below, and for the same reason: NO forced aspect ratio. Product
   shots arrive portrait, landscape and letterboxed (several are stills lifted from video, with
   baked-in text), so a fixed crop loses the words and a fixed `contain` window pads the short ones
   with dead space. The image keeps its own proportions, capped in height so a tall one can't
   dominate the column, and the frame hugs the image itself. */
.bns-product-media .wp-block-post-featured-image {
	margin: 0;
}
.bns-product-media img {
	max-width: 100%;
	max-height: 460px;
	width: auto;
	height: auto;
	display: block;
	margin-inline: auto;
	border: 1px solid var(--wp--preset--color--line);
}
.bns-product-title .wp-block-post-title {
	margin: 0;
}
.bns-product-body > * + * {
	margin-top: var(--wp--preset--spacing--40);
}

/* Single-product detail block: discount, buy button, embedded video. */
.bns-product-detail > * + * {
	margin-top: var(--wp--preset--spacing--40);
}
/* margin-top is left to the `> * + *` rule above. A `margin: 0` shorthand here would out-specify
   it (same weight, later in the file) and pull the video up flush against the buy button. */
.bns-product-video {
	margin-inline: 0;
	margin-bottom: 0;
	max-width: 720px;
}


/* ===== Ported page components. From docs/mockups/_shared/system.css (Lock 2026-07-18).
   Un-prefixed classes: no collision with the theme's bns-* home classes. Video facades in
   the ported patterns use .bns-frame/.bns-yt-lite so assets/js/home.js drives them. ===== */
/* ═══ THE PORTABLE LAYER ═══════════════════════════════════════════════════════════════
   This component library is REUSED ACROSS PROJECTS. What makes that possible is that every
   component below reads a ROLE, base, ink, surface, brand, accent. And never a colour name.
   The roles are the contract; theme.json supplies the values, and only the values change per
   project. Re-skinning a site is then a palette swap, not a rewrite.

   ⚠️ NEVER introduce a project-specific colour name into a component rule. `var(--brand)` is
   portable; `var(--olive)` is a one-club dead end, and the next site inherits a stylesheet
   describing a palette it does not have.

   The short aliases below exist only so component rules stay readable. They resolve to the
   role tokens, which resolve to this project's values. Three names for one colour is one too
   many, prefer the role name in anything new.
   ═══════════════════════════════════════════════════════════════════════════════════════ */
:root{
  /* roles → short aliases used by the component rules */
  --brand:var(--wp--preset--color--brand); --brand-deep:var(--wp--preset--color--brand-deep);
  --brand-soft:var(--wp--preset--color--brand-soft);
  --accent:var(--wp--preset--color--accent); --accent-deep:var(--wp--preset--color--accent-deep);
  --ink:var(--wp--preset--color--ink); --ink-soft:var(--wp--preset--color--ink-soft);
  --paper:var(--wp--preset--color--base); --surface:var(--wp--preset--color--surface);
  --mist:var(--wp--preset--color--surface-2); --line:var(--wp--preset--color--line);
  --shell:var(--wp--preset--color--shell);

  /* legacy aliases from the inherited components, kept so nothing breaks, all pointing at
     roles. Do not add to this list; retire entries as the components are touched. */
  --teal:var(--brand); --teal-deep:var(--accent-deep); --teal-bright:var(--accent);
  --teal-abyss:var(--brand-deep); --navy:var(--brand-deep); --navy-lift:var(--brand);
  --heart:var(--accent);

  --measure:var(--wp--style--global--content-size); --wide:var(--wp--style--global--wide-size);
  --prose:var(--wp--style--global--content-size);
  --radius:10px;            /* cards, measured across the pilot, not the inherited 14 */
  --radius-btn:6px;         /* buttons */
  --gut:clamp(20px,5vw,56px);
  --display:var(--wp--preset--font-family--display); --body:var(--wp--preset--font-family--body);
  --sans:var(--body); --disp:var(--display);
  --voice:var(--wp--preset--font-family--voice);
  /* Measured onto :root at runtime by assets/js/home.js. Declared here so the no-JS path is
     real rather than merely claimed: home.js's own header says these carry :root defaults, and
     until now they did not. A bare var(--hdr) with JS off would collapse the page head under
     the fixed masthead. Values are the measured desktop defaults. */
  /* ⚠️ --hdr REDUCED 93px -> 82px, 2026-09-16 (Martin: the header sat too heavily over the hero
     photograph). It is the DEFAULT only: assets/js/home.js measures the real header at runtime and
     overwrites it, so this and the wrap's min-height must move together or the bar keeps its old
     height and only the crest shrinks. Full before-values and the revert are logged at --crest. */
  --hdr:82px; --cue:62px;
  --s3:.75rem; --s4:1.25rem; --s5:2rem; --s6:3rem; --s7:4.25rem; --s8:5.75rem;
}
/* video caption used by the ported gallery/rows */
.vcap{font-size:.9rem;color:var(--ink-soft);margin-top:.75rem;display:flex;gap:.5rem;align-items:baseline}
.vcap::before{content:"\25B6";color:var(--teal);font-size:.7rem}
/* ============================================================================
   bnsgc, shared component system (Lock, 2026-07-18)
   One source of truth for the six pilot mockups. Spec: docs/design-system-lock.md
   ⚠️ RE-LOCKED FOR BNSGC 2026-09-14. The values below were inherited from a sibling build and
   are now WRONG for this project. Kept only as a record of where the components came from.
   CURRENT: wide band 1200 · prose 680 · card radius 10 · button radius 6 · accent = emphasis.
   Fonts are self-hosted in ./assets/fonts and declared in theme.json fontFace.
   WAS (sibling build): wide 1040 · radius 14 · navy = stat/emphasis · fonts in ../home-v2/.
   ============================================================================ */

/* ─── Faces ─────────────────────────────────────────────────────────────── */

/* ─── Tokens (atoms) ────────────────────────────────────────────────────── */

*,*::before,*::after{box-sizing:border-box}
/* Body/headings match shared.css, which is what the four pilot pages were signed off on:
   Inter 400 17px/1.6, Fraunces 600 with -0.015em tracking. The inherited 800/-0.025em was the
   other project's display face and reads far too tight on Fraunces. */
body{margin:0;font-family:var(--body);font-size:17px;line-height:1.6;color:var(--ink);background:var(--paper);
     font-feature-settings:"cv05","ss01";-webkit-font-smoothing:antialiased}
img{max-width:100%;height:auto;display:block}
a{color:var(--accent-deep)}
:focus-visible{outline:3px solid var(--accent);outline-offset:3px;border-radius:2px}
h1,h2,h3{font-family:var(--display);font-weight:600;letter-spacing:-.015em;line-height:1.08;margin:0}
p{margin:0 0 1rem}p:last-child{margin-bottom:0}
#main,section[id]{scroll-margin-top:96px}
.skip{position:absolute;left:-9999px}
/* The audit reports the skip link at 164x27px, but it measures the element while it is parked
   off-screen: this rule is what applies when it is actually usable, and it is the only state a
   visitor can reach. Given an explicit 44px box so the reported figure and the real one agree. */
.skip:focus{left:1rem;top:1rem;z-index:99;background:var(--paper);padding:.75rem 1rem;
  border-radius:6px;display:inline-flex;align-items:center;min-height:44px}

/* ─── Shell ─────────────────────────────────────────────────────────────── */
.wrap{max-width:var(--measure);margin-inline:auto;padding-inline:clamp(1.5rem,4vw,3.5rem)}
.wrap-wide{max-width:var(--wide);margin-inline:auto;padding-inline:clamp(1.5rem,4vw,3.5rem)}
.band{padding-block:var(--s7)}
.eyebrow{font-family:var(--body);font-size:12px;font-weight:600;letter-spacing:.19em;text-transform:uppercase;margin:0 0 var(--s4);color:var(--accent-deep)}
.mist{background:var(--mist)}

/* ─── Buttons ───────────────────────────────────────────────────────────── */
.btn{display:inline-block;font-family:var(--body);font-weight:700;font-size:1rem;padding:.8rem 1.5rem;border-radius:8px;text-decoration:none;border:2px solid transparent;box-shadow:0 1px 3px rgba(0, 0, 0,.22);transition:transform .12s ease, background-color .12s ease, box-shadow .12s ease, border-color .12s ease, color .12s ease}
.btn:hover{transform:translateY(-2px);box-shadow:0 6px 16px rgba(0, 0, 0,.26)}
.btn:active{transform:translateY(0);box-shadow:0 1px 3px rgba(0, 0, 0,.22)}
.btn-primary{background:linear-gradient(180deg,var(--navy-lift),var(--navy));color:#fff}
.btn-primary:hover{background:linear-gradient(180deg,var(--wp--preset--color--brand-deep),var(--navy-lift))}
.btn-ghost{background:#fff;color:var(--navy);border-color:var(--navy);box-shadow:none}
.btn-ghost:hover{background:var(--navy);color:#fff;box-shadow:0 6px 16px rgba(0, 0, 0,.26)}
.btn-onteal{background:#fff;color:var(--teal-abyss);box-shadow:0 2px 6px rgba(0, 0, 0,.35)}
.btn-onteal:hover{background:var(--mist);box-shadow:0 8px 20px rgba(0, 0, 0,.4)}
.btn-onteal-ghost{background:transparent;color:#fff;border-color:rgba(255,255,255,.55);box-shadow:none}
.btn-onteal-ghost:hover{border-color:#fff;background:rgba(255,255,255,.12)}
.btn-onnavy{background:#fff;color:var(--navy);box-shadow:0 2px 6px rgba(0,0,0,.3)}
.btn-onnavy:hover{background:var(--mist)}
.btn-onnavy-ghost{background:transparent;color:#fff;border-color:rgba(255,255,255,.55);box-shadow:none}
.btn-onnavy-ghost:hover{border-color:#fff;background:rgba(255,255,255,.12)}
.btn-row{display:flex;flex-wrap:wrap;gap:var(--s4);margin-top:var(--s5)}

/* ─── Header ────────────────────────────────────────────────────────────── */
.site-head{background:var(--navy);color:#fff;position:sticky;top:0;z-index:999}
.site-head .wrap-wide{display:flex;align-items:center;justify-content:space-between;gap:var(--s4);padding-block:.9rem;flex-wrap:wrap}
.lockup{display:flex;align-items:center;text-decoration:none;color:#fff}
.lockup img{height:58px;width:auto}
.site-nav{display:flex;gap:1.4rem;flex-wrap:wrap}
.site-nav a{color:#fff;text-decoration:none;font-size:.9rem;font-weight:600;opacity:.85;text-transform:uppercase;display:inline-block;padding-block:.55rem}
.site-nav a:hover{opacity:1;text-decoration:underline;text-underline-offset:4px}
.site-nav a[aria-current]{opacity:1;text-decoration:underline;text-underline-offset:4px;text-decoration-color:var(--teal-bright)}

/* ─── Hero, type-led (.hero .wrap) and image 2-col (.hero .wrap-wide) ────── */
.hero{background:var(--mist);border-bottom:1px solid var(--wp--preset--color--surface-2);overflow:hidden}
.hero .wrap{padding-block:var(--s8);max-width:var(--wide)}
.hero .wrap-wide{display:grid;grid-template-columns:1.1fr .9fr;gap:var(--s6);align-items:center;padding-block:var(--s8)}
.hero h1{font-size:clamp(2.5rem,5.2vw,4.15rem);line-height:1.02;letter-spacing:-.035em;max-width:18ch}
.hero .tagline{font-family:var(--display);font-weight:600;font-size:clamp(1.3rem,2.4vw,1.6rem);letter-spacing:-.015em;color:var(--teal-deep);margin-top:var(--s4)}
.hero .lede{font-size:1.35rem;color:var(--ink-soft);margin-top:var(--s5);max-width:60ch}
.hero-art a{display:block;border-radius:16px;transition:transform .18s ease, box-shadow .18s ease}
.hero-art a:hover{transform:translateY(-3px)}
.hero-art img{width:100%;border-radius:16px;border:1px solid var(--line);box-shadow:0 18px 40px rgba(0, 0, 0,.18)}
.hero-art a:hover img{box-shadow:0 24px 50px rgba(0, 0, 0,.26)}

/* Teal hero. For a teal-gradient poster (SDF). Image goes edgeless on matching band. */
.hero-teal{position:relative;color:#fff;isolation:isolate;overflow:hidden;
  background:radial-gradient(120% 90% at 12% 0%, var(--wp--preset--color--accent) 0%, rgba(58, 74, 90,0) 58%),linear-gradient(158deg, var(--wp--preset--color--brand) 0%, var(--wp--preset--color--brand-deep) 55%, var(--wp--preset--color--brand-deep) 100%)}
.hero-teal::before{content:"";position:absolute;z-index:-1;border-radius:50%;background:rgba(58, 74, 90,.16);width:46vw;height:26vw;left:-8vw;top:8%}
.hero-teal .wrap-wide{display:grid;grid-template-columns:1.08fr .92fr;gap:var(--s6);align-items:center;padding-block:var(--s8)}
.hero-teal .eyebrow{color:rgba(255,255,255,.82)}
.hero-teal h1{color:#fff;font-size:clamp(2.5rem,5.2vw,4.15rem);line-height:1.01;letter-spacing:-.035em}
.hero-teal .tagline{font-family:var(--display);font-weight:600;font-size:clamp(1.3rem,2.4vw,1.6rem);letter-spacing:-.015em;margin-top:var(--s4);color:var(--teal-bright)}
.hero-teal .lede{font-size:1.2rem;color:rgba(255,255,255,.9);max-width:46ch;margin-top:var(--s4)}
.hero-teal .poster img{width:100%;border-radius:16px;border:2px solid rgba(255,255,255,.45);box-shadow:0 14px 30px rgba(0, 0, 0,.4), 0 40px 76px rgba(0, 0, 0,.46)}

/* ─── Article prose ────────────────────────────────────────────────────── */
.article{max-width:var(--measure)}
.article h2{font-size:clamp(1.9rem,3.4vw,2.5rem)}
.article .kicker{font-size:1.3rem;color:var(--ink-soft);margin-top:var(--s4)}
.article h3{font-size:1.375rem;letter-spacing:-.015em;margin-top:var(--s6)}
.article h3+p{margin-top:var(--s3)}
.article p{margin-top:var(--s4)}
.article p:first-of-type{margin-top:var(--s5)}
.article strong{font-weight:700}
.sec-head h2{font-size:clamp(1.9rem,3.6vw,2.6rem)}
.sec-head p{color:var(--ink-soft);font-size:1.15rem;margin-top:var(--s4);max-width:64ch}

/* ─── Navy feature bands: stat · statement · pull (data & emphasis) ──────── */
.stat{background:var(--navy);color:#fff}
.stat .wrap-wide{display:grid;grid-template-columns:auto 1fr;gap:var(--s6);align-items:center}
.stat .big{font-family:var(--display);font-weight:800;letter-spacing:-.03em;line-height:.9;font-size:clamp(4rem,11vw,7.5rem);color:var(--teal-bright)}
.stat .big small{display:block;font-size:.9rem;font-weight:700;letter-spacing:.14em;text-transform:uppercase;color:rgba(255,255,255,.7);margin-top:.6rem}
.stat h2{color:#fff;font-size:clamp(1.5rem,2.8vw,2rem);max-width:20ch}
.stat p{color:rgba(255,255,255,.85);margin-top:var(--s4);font-size:1.05rem;max-width:56ch}

.callout{background:var(--navy);color:#fff}                 /* LOCKED navy (was teal on one page) */
.callout .wrap{max-width:900px;text-align:center}
.callout .big{font-family:var(--display);font-weight:800;letter-spacing:-.03em;line-height:1;font-size:clamp(3.5rem,9vw,6rem);color:var(--teal-bright)}
.callout p.lead{font-family:var(--display);font-weight:700;letter-spacing:-.015em;line-height:1.25;font-size:clamp(1.4rem,2.6vw,1.9rem);color:#fff;max-width:26ch;margin:var(--s4) auto 0}
.callout .wrap>p:not(.big):not(.lead):not(.src){font-family:var(--display);font-weight:700;letter-spacing:-.015em;line-height:1.25;font-size:clamp(1.5rem,3vw,2.1rem);color:#fff;max-width:24ch;margin-inline:auto}
.callout .num{color:var(--teal-bright)}
.callout p.src{margin-top:var(--s5);font-size:1.05rem;color:rgba(255,255,255,.82);max-width:60ch;margin-inline:auto;font-family:var(--body);font-weight:400;letter-spacing:0}

.statement{background:var(--navy);color:#fff}
.statement .wrap{max-width:960px;text-align:center}
.statement blockquote{margin:0}
.statement blockquote p{font-family:var(--display);font-weight:800;letter-spacing:-.02em;line-height:1.14;font-size:clamp(1.8rem,4.2vw,3rem);color:#fff}
.statement blockquote p .hl{color:var(--heart)}
.statement cite{display:block;margin-top:var(--s5);font-style:normal;font-family:var(--body);font-weight:700;font-size:.9rem;letter-spacing:.12em;text-transform:uppercase;color:var(--teal-bright)}
.statement .after{margin-top:var(--s5);font-size:1.2rem;color:rgba(255,255,255,.82);max-width:60ch;margin-inline:auto}

.pull{background:var(--navy);color:#fff}
.pull .wrap{text-align:center}
.pull p{font-family:var(--display);font-weight:600;font-size:clamp(1.5rem,3vw,2.1rem);line-height:1.32;letter-spacing:-.02em;color:#fff;max-width:24ch;margin-inline:auto}
.pull em{font-style:normal;color:var(--teal-bright)}

/* ─── Teal-gradient action bands: cta · register ────────────────────────── */
.cta,.register{color:#fff;background:linear-gradient(158deg,var(--wp--preset--color--brand) 0%,var(--wp--preset--color--brand-deep) 55%,var(--wp--preset--color--brand-deep) 100%)}
.cta .wrap,.register .wrap{max-width:820px;text-align:center}
.cta h2,.register h2{color:#fff;font-size:clamp(1.9rem,3.6vw,2.6rem)}
.cta p,.register p{margin-top:var(--s4);color:rgba(255,255,255,.9);font-size:1.15rem}
.cta .btn-row,.register .btn-row{justify-content:center}

/* ─── Deep-teal media band (single featured video) ──────────────────────── */
.deepband{color:#fff;background:linear-gradient(158deg,var(--wp--preset--color--brand) 0%,var(--wp--preset--color--brand-deep) 58%,var(--wp--preset--color--brand-deep) 100%)}
.deepband h2{color:#fff}
.video-wrap{max-width:900px;margin:var(--s6) auto 0}
.video-wrap figcaption{color:rgba(255,255,255,.85);font-size:.98rem;margin-top:var(--s4);text-align:center}

/* ─── Video facade (shared) ─────────────────────────────────────────────── */
.vcap{font-size:.9rem;color:var(--ink-soft);margin-top:.75rem;display:flex;gap:.5rem;align-items:baseline}
.vcap::before{content:"\25B6";color:var(--teal);font-size:.7rem}

/* ─── Alternating media row (canonical), vsec/split/chapter are aliases ── */
.vsec,.split,.chapter{display:grid;grid-template-columns:1.05fr .95fr;gap:var(--s6);align-items:center}
.vsec + .vsec{margin-top:var(--s7)}
.chapter + .chapter{margin-top:var(--s8)}
.vsec .txt h2,.split .txt h2{font-size:clamp(1.7rem,3vw,2.2rem)}
.chapter h2{font-size:clamp(1.8rem,3.2vw,2.35rem);margin-top:.5rem}
.vsec .txt p,.split .txt p,.chapter .txt>p{margin-top:var(--s4);color:var(--ink);font-size:1.05rem}
.vsec .txt p.muted,.split .txt p.muted,.chapter .txt>p.muted{color:var(--ink-soft)}
.split .txt h2{font-size:clamp(1.8rem,3.2vw,2.4rem)}
.vsec--flip .media,.split--flip .media,.chapter--flip .media{order:-1}
@media (min-width:901px){
  .vsec--flip .media,.split--flip .media,.chapter--flip .media{order:0}
  .vsec--flip .txt,.split--flip .txt,.chapter--flip .txt{order:2}
}
.chapter .num{font-family:var(--display);font-weight:800;font-size:1rem;color:var(--teal-deep);letter-spacing:.02em}
.chapter .num::before{counter-increment:innov;content:"0" counter(innov) " \00B7 "}
.chapters{counter-reset:innov}
.epigraph{margin:var(--s5) 0 0;padding-left:var(--s4);border-left:3px solid var(--heart)}
.epigraph p{font-family:var(--voice);font-style:italic;font-size:1.2rem;line-height:1.4;color:var(--ink)}
.epigraph cite{display:block;margin-top:.5rem;font-style:normal;font-family:var(--body);font-weight:700;font-size:.85rem;letter-spacing:.03em;color:var(--ink-soft)}

/* ─── Facts / stat cards ────────────────────────────────────────────────── */
.facts{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:var(--s5);margin-top:var(--s6)}
.fact{background:#fff;border:1px solid var(--line);border-top:4px solid var(--teal);border-radius:var(--radius);padding:var(--s5) var(--s4);box-shadow:0 10px 24px rgba(0, 0, 0,.06)}
.fact b{display:block;font-family:var(--display);font-weight:800;font-size:2.1rem;letter-spacing:-.03em;color:var(--teal-deep);line-height:1}
.fact span{display:block;margin-top:.65rem;color:var(--ink-soft);font-size:.96rem;line-height:1.4}

/* ─── PDF library ───────────────────────────────────────────────────────── */
.pdf-lib{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:var(--s5);margin-top:var(--s6)}
.pdf-card{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:var(--s5);text-decoration:none;color:var(--ink);transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease}
.pdf-card:hover{transform:translateY(-4px);box-shadow:0 16px 36px rgba(0, 0, 0,.14);border-color:var(--wp--preset--color--line)}
.pdf-ico{width:2.6rem;height:2.6rem;border-radius:10px;background:var(--surface);display:grid;place-items:center;color:var(--teal-deep);flex:0 0 auto}
.pdf-ico svg{width:1.4rem;height:1.4rem;fill:currentColor}
.pdf-card h3{font-size:1.2rem;letter-spacing:-.015em;margin-top:var(--s4)}
.pdf-card p{font-size:.96rem;color:var(--ink-soft);margin-top:.5rem}
.pdf-dl{margin-top:auto;padding-top:var(--s4);font-weight:700;color:var(--teal-deep);font-size:.95rem;display:inline-flex;align-items:center;gap:.4rem}
.pdf-card:hover .pdf-dl{text-decoration:underline;text-underline-offset:3px}
.pdf-meta{font-size:.8rem;color:var(--ink-soft);font-weight:400;text-transform:uppercase;letter-spacing:.08em}

/* ─── Resource-link grid (external link cards), LOCKED component, first use 2026-07-18 ── */
.rlinks{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--s5);margin-top:var(--s6)}
.rlink{display:flex;flex-direction:column;background:#fff;border:1px solid var(--line);border-top:4px solid var(--teal);border-radius:var(--radius);padding:var(--s5);text-decoration:none;color:var(--ink);transition:transform .18s ease, box-shadow .18s ease, border-color .18s ease}
.rlink:hover{transform:translateY(-4px);box-shadow:0 16px 36px rgba(0, 0, 0,.14);border-color:var(--wp--preset--color--line)}
.rlink .kind{font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--teal-deep)}
.rlink h3{font-size:1.2rem;letter-spacing:-.015em;margin-top:.5rem}
.rlink p{font-size:.96rem;color:var(--ink-soft);margin-top:.5rem}
.rlink .go{margin-top:auto;padding-top:var(--s4);font-weight:700;color:var(--teal-deep);font-size:.95rem}
.rlink .go::after{content:" \2197"}
.rlink:hover .go{text-decoration:underline;text-underline-offset:3px}

/* ─── Prose bullet list (bns-dotlist), LOCKED component, first use 2026-07-18 ─────────── */
.bns-list{max-width:var(--measure);margin-top:var(--s5);padding-left:1.3rem;color:var(--ink-soft);font-size:1.05rem}
.bns-list li{margin-bottom:.65rem;padding-left:.25rem}
.bns-list li::marker{color:var(--teal)}
.bns-list strong{color:var(--ink)}

/* ─── FAQ accordion (native <details>, no JS). LOCKED component, first use 2026-07-18 ── */
.faq{max-width:var(--measure);margin-top:var(--s6)}
.faq details{border-bottom:1px solid var(--line)}
.faq details:first-of-type{border-top:1px solid var(--line)}
.faq summary{font-family:var(--display);font-weight:700;font-size:1.15rem;letter-spacing:-.01em;color:var(--ink);padding:var(--s4) 2.5rem var(--s4) 0;cursor:pointer;list-style:none;position:relative}
.faq summary::-webkit-details-marker{display:none}
.faq summary::after{content:"+";position:absolute;right:.25rem;top:50%;transform:translateY(-50%);font-family:var(--body);font-weight:400;font-size:1.7rem;line-height:1;color:var(--teal-deep)}
.faq details[open] summary::after{content:"\2013"}
.faq summary:hover{color:var(--teal-deep)}
.faq details>*:not(summary){margin-top:0}
.faq details>p{color:var(--ink-soft);max-width:68ch;padding-bottom:var(--s4);margin-top:0}
.faq details>p:first-of-type{margin-top:-.25rem}


/* ─── Routes / choice cards ─────────────────────────────────────────────── */
.routes{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:var(--s5);margin-top:var(--s6)}
.route{background:#fff;border:1px solid var(--line);border-radius:var(--radius);padding:var(--s5);border-top:4px solid var(--teal)}
.route h3{font-size:1.2rem;letter-spacing:-.015em}
.route p{margin-top:.6rem;color:var(--ink-soft);font-size:.98rem}
.route .tag{display:inline-block;margin-bottom:.8rem;font-size:.72rem;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--teal-deep)}

/* ─── Video gallery grid ────────────────────────────────────────────────── */
.vgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--s6) var(--s5);margin-top:var(--s6)}
.vitem,.vcard{display:flex;flex-direction:column}
.vitem .frame,.vcard .frame{box-shadow:0 10px 24px rgba(0, 0, 0,.14)}
.vcard .num{font-family:var(--body);font-weight:700;font-size:.72rem;letter-spacing:.12em;text-transform:uppercase;color:var(--teal-deep);margin-top:var(--s4)}
.vitem h3,.vcard h3{font-size:1.05rem;margin-top:.85rem;letter-spacing:-.01em}
.vcard h3{margin-top:.3rem;font-size:1.2rem}
.vcard p{font-size:.96rem;color:var(--ink-soft);margin-top:.5rem}

/* ─── Founder testimony ─────────────────────────────────────────────────── */
.founder{background:var(--navy);color:#fff}
.founder .wrap-wide{display:grid;grid-template-columns:.32fr 1fr;gap:var(--s6);align-items:center;max-width:1000px}
.founder-art{aspect-ratio:1;border-radius:50%;overflow:hidden;background:radial-gradient(circle at 50% 40%, var(--wp--preset--color--ink-soft), var(--wp--preset--color--ink));border:2px solid rgba(255,255,255,.15)}
.founder-art img{width:100%;height:100%;object-fit:cover}
.founder blockquote{margin:0}
.founder blockquote p{font-family:var(--voice);font-style:italic;font-weight:400;font-size:clamp(1.35rem,2.4vw,1.7rem);line-height:1.5;color:#fff}
.founder cite{display:block;margin-top:var(--s4);font-style:normal;font-family:var(--body);font-weight:700;font-size:.95rem;letter-spacing:.02em;color:var(--teal-bright)}
.founder .support{margin-top:var(--s5);color:rgba(255,255,255,.82);font-size:1rem}
.founder .support a{color:#fff;text-decoration:underline;text-underline-offset:3px}

/* ─── Numbered steps ────────────────────────────────────────────────────── */
.steps{max-width:var(--measure);margin-top:var(--s6);padding:0;list-style:none;counter-reset:s}
.steps li{counter-increment:s;position:relative;padding:.5rem 0 1.1rem 3.2rem;border-bottom:1px solid var(--line)}
.steps li:last-child{border-bottom:0}
.steps li::before{content:counter(s);position:absolute;left:0;top:.35rem;width:2.1rem;height:2.1rem;border-radius:50%;background:var(--teal);color:#fff;font-family:var(--display);font-weight:800;font-size:1rem;display:grid;place-items:center}
.steps b{display:block;font-family:var(--display);font-weight:700;font-size:1.1rem;letter-spacing:-.01em}
.steps p{margin-top:.35rem;color:var(--ink-soft);font-size:1rem}

/* ─── Callout note · tip · chip · note ──────────────────────────────────── */
.tip{margin-top:var(--s6);background:#fff;border:1px solid var(--line);border-left:4px solid var(--teal);border-radius:var(--radius);padding:var(--s5);max-width:var(--wide)}
.tip b{font-family:var(--display);font-weight:800;display:block;margin-bottom:.4rem}
.tip p{color:var(--ink-soft);max-width:68ch}
.note{margin-top:var(--s5);background:var(--surface);border-radius:12px;padding:1rem 1.3rem;font-size:.95rem;color:var(--ink-soft);max-width:68ch}
.note strong{color:var(--ink)}
.chip{display:inline-block;font-family:var(--body);font-weight:700;font-size:.9rem;text-decoration:none;color:var(--navy);background:#fff;border:1px solid var(--line);border-radius:999px;padding:.5rem 1.1rem;transition:background-color .15s ease, color .15s ease}
.chip:hover{background:var(--navy);color:#fff}

/* ─── Footer ────────────────────────────────────────────────────────────── */
.share{background:var(--navy);color:#fff}
.share h2{color:#fff}
.share p{color:rgba(255,255,255,.85);margin-top:var(--s4);font-size:1.05rem}
.share .socials{display:flex;gap:1.1rem;margin:var(--s5) 0 0;padding:0;list-style:none;flex-wrap:wrap}
.share .socials a{display:grid;place-items:center;width:2.4rem;height:2.4rem;color:#fff}
.share .socials a:hover{color:var(--mist);opacity:.85}
.share .socials svg{width:1.5rem;height:1.5rem;fill:currentColor}
.site-foot{background:#fff;border-top:1px solid var(--line);padding-block:var(--s6) var(--s5);font-size:.9rem;color:var(--ink-soft);text-align:center}
.site-foot a{color:var(--ink-soft)}
.foot-brand{display:inline-block}.foot-brand img{height:44px;width:auto}
.foot-tag{margin-top:var(--s4)}
.foot-disclaimer{max-width:640px;margin:var(--s4) auto 0;background:var(--mist);border-radius:6px;padding:.8rem 1.2rem;font-size:.85rem;text-align:left}
.foot-links{margin-top:var(--s4);font-size:.85rem}
.foot-links a{display:inline-block;padding:.3rem .15rem}
.foot-copy{margin-top:.6rem;font-size:.8rem}

/* ─── Responsive ────────────────────────────────────────────────────────── */
@media (max-width:900px){
  .hero .wrap-wide,.hero-teal .wrap-wide{grid-template-columns:1fr;gap:var(--s5);padding-block:var(--s6)}
  .hero .wrap{padding-block:var(--s6)}
  .hero-art,.hero-teal .poster{order:-1}
  .vsec,.split,.chapter{grid-template-columns:1fr;gap:var(--s5)}
  .vsec .media,.split .media,.chapter .media{order:-1}
  .stat .wrap-wide{grid-template-columns:1fr;gap:var(--s4)}
  .founder .wrap-wide{grid-template-columns:1fr;gap:var(--s5);text-align:center}
  .founder-art{width:160px;margin-inline:auto}
  .band{padding-block:var(--s6)}
  .site-nav{gap:1rem}
}
@media (max-width:560px){ .lockup img{height:48px} .share{text-align:center} .share .socials{justify-content:center} }

/* ─── Blog cards, WCAG 2.2 target-size (post-card title + "Read more" links were 22 to 23px) ─── */
.wp-block-query .wp-block-post-title a{display:inline-block;padding-block:.15rem}
.wp-block-post-excerpt__more-link{display:inline-block;padding-block:.25rem;font-weight:700;text-underline-offset:3px}
/* Post meta (category) link + comment-form checkboxes were under 24px */
.wp-block-post-terms a{display:inline-block;padding-block:.3rem}
#wp-comment-cookies-consent,.comment-form input[type="checkbox"]{width:1.5rem;height:1.5rem;flex:none}
/* Long raw-URL link text (some imported posts) must wrap, not overflow narrow screens */
.wp-block-post-content{overflow-wrap:break-word}
.wp-block-post-content a{word-break:break-word}

/* ─── Featured images, one framed treatment, hero + archive cards ──────────────────────────
   Deliberately NOT a full-bleed image with text over it: that fails on light/busy/badly-cropped
   images. The image is always framed in its own box (never behind text), cover-cropped to a fixed
   ratio so ANY source image lands consistently, and it renders nothing at all when a post has no
   featured image (so image-less posts are unaffected). Hero sits at 860: a touch wider than the
   680 reading column, centred, so it reads as a hero without breaking the column's symmetry. */
/* HERO: deliberately NO forced aspect ratio. A fixed crop butchers the images a client
   actually sends, banners with baked-in text lose the words, portraits lose heads. So the
   image keeps its own proportions, is capped in height so a tall one can't dominate the page,
   and the frame hugs the image itself (no letterbox bars, no empty box). */
.bns-post-hero-img{margin-inline:auto}
.bns-post-hero-img img{
	max-width:100%;
	max-height:520px;
	width:auto;
	height:auto;
	display:block;
	margin-inline:auto;
	border:1px solid var(--wp--preset--color--line);
	box-shadow:0 18px 40px rgba(0, 0, 0,.16);
}
/* ARCHIVE CARDS: here a fixed 16:9 cover IS right. A grid needs consistent card heights. */
.wp-block-query .wp-block-post-featured-image img{
	border:1px solid var(--wp--preset--color--line);
	object-fit:cover;
}
.wp-block-query .wp-block-post-featured-image{margin-bottom:var(--wp--preset--spacing--30)}

/* ─────────────────────────────────────────────────────────────────────────
   REVIEW WALL, blocks/review-wall/render.php
   Added 2026-09-14. The block shipped registered, rendering and deployed with
   NO stylesheet at all: render.php emitted six bns-review* classes and style.css
   contained none of them, so a club member who found the block got unstyled
   blockquotes. product-card (31 rules here) is the house pattern; this was simply
   missing its half.
   ───────────────────────────────────────────────────────────────────────── */

/* A SCROLLING TRACK, not a grid. With more reviews than fit a row, a grid wraps to a second
   row of two and the section stops reading as a wall and starts reading as a leftover. A track
   holds one row however many there are, and the partly-visible next card is what tells a reader
   there IS more. No arrows, no dots, no JavaScript.
   scroll-snap so it always comes to rest on a card edge rather than mid-quote. */
.bns-review-wall {
	display: flex;
	gap: var(--wp--preset--spacing--30, 22px);
	align-items: stretch;
	overflow-x: auto;
	scroll-snap-type: x mandatory;
	scroll-padding-left: 2px;
	padding-bottom: 16px;   /* room for the scrollbar, so it never sits on the cards */
	/* stops a horizontal flick from triggering the browser's back-swipe gesture */
	overscroll-behavior-x: contain;
	scroll-behavior: smooth;
}

/* Cards size themselves; they do not divide the row. A third of the width would make a
   two-review wall into two enormous cards. */
.bns-review-wall > .bns-review {
	flex: 0 0 clamp(262px, 28vw, 336px);
	scroll-snap-align: start;
}

/* A visible but quiet scrollbar. Hiding it entirely is the common move and it is wrong here:
   with no scrollbar and no arrows, a mouse user on a trackpad-less machine has no way to know
   the row scrolls at all. */
.bns-review-wall {
	scrollbar-width: thin;
	scrollbar-color: var(--wp--preset--color--line) transparent;
}

.bns-review-wall::-webkit-scrollbar {
	height: 8px;
}

.bns-review-wall::-webkit-scrollbar-track {
	background: transparent;
}

.bns-review-wall::-webkit-scrollbar-thumb {
	background: var(--wp--preset--color--line);
	border-radius: 4px;
}

/* The track takes keyboard focus (see render.php), so it must show that it has it. */
.bns-review-wall:focus-visible {
	outline: 3px solid var(--wp--preset--color--accent);
	outline-offset: 4px;
}

@media ( prefers-reduced-motion: reduce ) {
	.bns-review-wall {
		scroll-behavior: auto;
	}
}

/* Quotes are never the same length. The card is a column with the attribution pushed
   to the foot by margin-top:auto, so footers line up across a row regardless. Which is
   the difference between a wall of testimonials reading as a set and reading as a mess. */
.bns-review {
	margin: 0;
	display: flex;
	flex-direction: column;
	position: relative;
	padding: 26px 24px 22px;
	background: var(--wp--preset--color--base);
	border: 1px solid var(--wp--preset--color--line);
	border-radius: 10px;
}

/* The quote mark is DECORATION, not content. A pseudo-element so it is never read
   aloud by a screen reader, never selected, and never copied with the quote.
   It sits in its own space above the text rather than behind it: overlapping a 62px glyph
   with the first line made both harder to read for no gain. */
.bns-review::before {
	content: "\201C";
	position: absolute;
	top: 14px;
	left: 24px;
	font-family: var(--wp--preset--font-family--display, serif);
	font-size: 54px;
	font-weight: 600;
	line-height: 1;
	color: var(--wp--preset--color--accent);
	opacity: .3;
	pointer-events: none;
}

/* Stars (2026-10-07): top right of the card, level with the quote mark. The accent gold, which
   theme.json reserves for rules and large display, is right for a small glyph row too: it is the
   crest's own gold and the card is on the base colour. An unlit star is the outline only. */
.bns-review__stars { position: absolute; top: 24px; right: 24px; display: inline-flex; gap: 2px; z-index: 1; }
.bns-review__star { fill: none; stroke: var(--wp--preset--color--accent); stroke-width: 1.4; opacity: .55; }
.bns-review__star.is-on { fill: var(--wp--preset--color--accent); opacity: 1; }

/* the padding is what gives the mark its room. See .bns-review::before above */
.bns-review__quote {
	margin: 0;
	padding-top: 34px;
	position: relative;
	z-index: 1;
}

.bns-review__quote p {
	font-size: 16.5px;
	line-height: 1.62;
	margin: 0;
}

/* Photo beside the name, so this row is a FLEX ROW. And the identity lines inside it are a
   nested block, not siblings of the photo. Three flex siblings would put name, club and source
   in a row beside the picture instead of stacked against it. */
.bns-review__by {
	margin-top: auto;    /* pins the attribution to the foot. See the card comment above */
	padding-top: 18px;
	display: flex;
	align-items: center;
	gap: 12px;
}

/* A circle, and `flex-shrink:0` because a long club name would otherwise squash it into an
   oval. The one deformation people notice instantly on a face. */
.bns-review__photo {
	width: 46px;
	height: 46px;
	flex: 0 0 46px;
	border-radius: 50%;
	object-fit: cover;
	background: var(--wp--preset--color--surface);
	border: 1px solid var(--wp--preset--color--line);
}

/* No photo: initials, so the row never has a blank hole in it, aria-hidden in the markup:
   the name is right there in text, and "DW" read aloud before it helps nobody. */
.bns-review__photo--initials {
	display: grid;
	place-items: center;
	font-family: var(--wp--preset--font-family--display, serif);
	font-size: 16px;
	font-weight: 600;
	letter-spacing: .02em;
	color: var(--wp--preset--color--brand);
	background: var(--wp--preset--color--surface);
}

.bns-review__id {
	display: flex;
	flex-direction: column;
	min-width: 0;        /* lets a long club name wrap instead of stretching the card */
}

.bns-review__who {
	font-weight: 600;
	font-size: 14.5px;
	line-height: 1.3;
}

/* Club and source are both quiet metadata under the name. They are separate elements rather
   than one line, because either may be absent and a joined string would need a separator that
   then has to know which half is missing. Two elements, each simply not rendered. */
.bns-review__club,
.bns-review__source {
	font-size: 12.5px;
	line-height: 1.45;
	color: var(--wp--preset--color--ink-soft);
}

.bns-review__club {
	font-weight: 500;
}

.bns-review__source {
	opacity: .8;
}

/* ═══════════════════════════════════════════════════════════════════════════════════════
   BNSGC PAGE COMPONENTS, ported from the agreed prototypes, 2026-09-14 (Lock → Apply).
   Source: bnsgc-working/docs/prototypes/{shared.css, home.html}.

   ⚠️ EVERY CLASS IS `bns-` PREFIXED, and that is not tidiness. The prototype's unprefixed
   names collided with NINETEEN selectors already in this file, .hero (21 rules, a
   two-column image hero), .article (8 rules), .band, .wrap-wide, .eyebrow, .btn, .lede,
   .skip. Appending unprefixed would have double-defined all of them, last-one-wins, and
   the breakage would have been SILENT. `design-system-lock.md` already mandates one
   prefix; this is it, applied.

   ⚠️ Colours are ROLES, never project names. See the portable-layer note above.
   ⚠️ The review wall is NOT here: .bns-review-wall is already in this file (22 rules) and
   matches the prototype. Do not add a second copy.
   ═══════════════════════════════════════════════════════════════════════════════════════ */

/* ⚠️ TWO DELIBERATE OVERLAPS WITH THE INHERITED LAYER ABOVE, both checked, both left alone:
   .bns-card. The inherited rule adds only a hover transition + shadow. Complementary to
                 the card box below, and the affordance is wanted. Not a conflict.
   .bns-hero: the inherited rule sets `overflow:clip`; mine sets `overflow:hidden` and wins
                 by source order. Same intent, so no rename.
   .bns-lede: WAS a real conflict: the inherited rule caps max-width:68ch on the element and
                 its paragraphs, which silently narrowed every ported lede. Mine is renamed
                 `.bns-band__lede`. ⚠️ PREFIXING DOES NOT PREVENT COLLISIONS HERE. The inherited
                 library uses the SAME bns- prefix because it is the same module system. Only
                 checking finds these; run tools/check-tokens.mjs and the collision sweep. */


/* ── shell ──────────────────────────────────────────────────────────────── */
.bns-band{padding-block:clamp(48px,7vw,96px);padding-inline:var(--gut)}
.bns-wrap{max-width:var(--wide);margin-inline:auto}
.bns-prose,.bns-head{max-width:var(--prose)}
.bns-eyebrow{font:600 12px/1 var(--body);letter-spacing:.19em;text-transform:uppercase;color:var(--accent-deep)}
.bns-band__lede{font-size:clamp(18px,2vw,21px);color:var(--ink-soft);margin-top:14px}
.bns-head h2{font-size:clamp(28px,3.6vw,42px);margin-top:10px}
.bns-grid > *{min-width:0}

/* ── buttons ────────────────────────────────────────────────────────────── */
/* ⚠️ 44px MINIMUM. THIS IS A TARGET-SIZE FIX, NOT A STYLE TWEAK. The site-wide audit of all
   23 pages (2026-09-16) measured every .bns-btn at 37px tall. That CLEARS WCAG 2.2 SC 2.5.8,
   which asks only 24px, and falls short of the 44 to 48px every platform guideline uses for a
   thumb. These are the most-tapped things on the site, and Martin's ask was that it work on a
   phone, so the platform bar is the one worth meeting.
   inline-flex, not inline-block: a bare min-height on an inline-block leaves the label sitting
   at the top of a taller box instead of centred in it.
   ⚠️ RE-RUN tools/sweep-header.mjs AFTER TOUCHING THIS. Two of these live in the masthead,
   whose height is measured at runtime into --hdr, so a taller button could push the bar and
   drag scroll-padding and the hero with it. It does fit inside both the 92px and the 70px bar,
   but that is something to verify, never to assume. */
.bns-btn{display:inline-flex;align-items:center;justify-content:center;min-height:44px;
  padding:11px 20px;border-radius:var(--radius-btn);font:600 15px/1.2 var(--body);
  text-decoration:none;border:1.5px solid transparent;white-space:nowrap}
/* A .bns-btn that is a <button> (the contact form, Cookie settings on the cookies policy) gets the
   pointer a link has by default. */
button.bns-btn{cursor:pointer}
.bns-btn--primary{background:var(--brand);color:var(--paper)}
.bns-btn--primary:hover{background:var(--brand-deep)}
.bns-book__short{display:none}
/* 2026-10-01 (Martin: "make it a bit more obvious there is a button there"). The outline was
   half-transparent PAPER, written for the dark masthead, so on a light band it was a button with
   no visible edge. It now follows the text colour: identical on the masthead (paper at 50%), and a
   real outline on a light ground (ink at 50%). The first line is the fallback where color-mix is
   not supported. Border WIDTH is unchanged, so the masthead's measured height is too. */
.bns-btn--ghost{border-color:rgba(251,249,245,.5);border-color:color-mix(in srgb,currentColor 50%,transparent);color:inherit}
.bns-btn--ghost:hover{border-color:currentColor}
.bns-btn--light{background:var(--paper);color:var(--brand-deep)}
.bns-btn--outline-light{border-color:rgba(251,249,245,.55);color:var(--paper)}
.bns-btn--outline-light:hover{border-color:var(--paper);background:rgba(251,249,245,.1)}
.bns-actions{display:flex;gap:10px;flex:0 0 auto;flex-wrap:wrap}

/* ── figures / cards / holes ────────────────────────────────────────────── */
.bns-figures{display:flex;gap:30px;margin-top:26px;flex-wrap:wrap}
.bns-figures div{border-left:2px solid var(--accent);padding-left:13px}
.bns-figures b{display:block;font-family:var(--display);font-size:30px;font-weight:600;line-height:1.05;color:var(--brand)}
.bns-figures span{font-size:13px;color:var(--ink-soft)}

.bns-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:22px;margin-top:38px}
/* Five cards (home audiences, 2026-10-01): three across then two, never four and a stray. A NEW
   modifier; plain .bns-cards is untouched everywhere else. */
.bns-cards--five{grid-template-columns:repeat(6,1fr)}
.bns-cards--five>*{grid-column:span 2}
.bns-cards--five>:nth-child(n+4){grid-column:span 3}
.bns-card{border:1px solid var(--line);border-radius:var(--radius);overflow:hidden;background:var(--paper);
  display:flex;flex-direction:column}
.bns-card__media{aspect-ratio:4/3;background:var(--surface)}
.bns-card__media img{width:100%;height:100%;object-fit:cover}
.bns-card__txt{padding:22px 22px 24px;display:flex;flex-direction:column;flex:1}
.bns-card h3{font-size:21px}
.bns-card p{font-size:15.5px;color:var(--ink-soft);margin-top:9px}
/* 44px, same target-size reason as .bns-btn. Measured at 289x40px by the site-wide audit
   (2026-09-16). inline-flex keeps the label centred; `margin-top:auto` still pins the link to the
   foot of the card, because that is the CARD's flex column doing the work, not this element's. */
.bns-card__more{margin-top:auto;padding-top:16px;font-weight:600;font-size:15px;text-decoration:none;
  color:var(--accent-deep);display:inline-flex;align-items:center;gap:8px;min-height:44px}
/* 2026-10-16 (Martin, from a two-version comparison): the card link carries an arrow and the WHOLE
   card is its click target. The link's ::before is stretched over the card (.bns-card is the
   containing block), so the accessible name stays the link text and the card body is the hit area;
   the title, the underline and the arrow move together on hover, and keyboard focus shows on the
   card. Any other link inside a card sits above the stretched layer (z-index) and still works.
   Deliberately not a button: five identical buttons a few lines above a band's real calls to action
   flatten the hierarchy. Used by eleven patterns (grepped 2026-10-16); none has two card links. */
.bns-card{position:relative}
.bns-card__more::after{content:"\2192";transition:transform .15s ease}
.bns-card__more::before{content:"";position:absolute;inset:0}
.bns-card:hover .bns-card__more{text-decoration:underline}
.bns-card:hover .bns-card__more::after{transform:translateX(4px)}
.bns-card:has(.bns-card__more):hover h3{color:var(--brand)}
.bns-card:focus-within{outline:2px solid var(--brand);outline-offset:2px}
.bns-card a:not(.bns-card__more){position:relative;z-index:1}
@media (prefers-reduced-motion:reduce){.bns-card__more::after{transition:none}}

/* material we do not have yet, drawn as a labelled hole, never filled with a stand-in */
.bns-hole{min-width:0;overflow-wrap:anywhere;padding:clamp(16px,4vw,26px);border:2px dashed var(--accent);
  border-radius:8px;display:grid;place-content:center;text-align:center;gap:7px;min-height:190px;
  background:repeating-linear-gradient(135deg,rgba(168,136,72,.05),rgba(168,136,72,.05) 9px,transparent 9px,transparent 18px)}
.bns-hole b{font:600 11px/1 var(--body);letter-spacing:.16em;text-transform:uppercase;color:var(--accent-deep)}
.bns-hole span{font-size:13.5px;color:var(--ink-soft);max-width:34ch;line-height:1.5}
/* ⛔ HIDDEN FOR LAUNCH (Martin, 2026-10-16: "To Confirm: hide all"). The labelled holes stay in the markup,
   each one a question the club has not yet answered, so that an answer can replace its box. Delete this
   rule to see them again on staging. !important because a hole can carry a component's own display
   (a card's media slot is a grid). */
.bns-hole{display:none !important}
.bns-card__media.bns-hole{border:none;border-bottom:2px dashed var(--accent);border-radius:0;min-height:0}

/* ── hero ───────────────────────────────────────────────────────────────── */
/* svh, not vh. On iOS/Android vh is the LARGEST viewport, so 100vh cuts the hero's foot
   off behind the URL bar on first paint. */
.bns-hero{
  /* Scrim variables, SWEPT against 16 pinned frames of the clip per viewport class.
     Declared HERE, never on ::after: custom properties set on a pseudo-element shadow
     anything inherited from its host, which silently defeats varying them. */
  /* ⚠️ RAISED 2026-10-06 (--l2 .36 to .50, --b2 .26 to .34) when the home line's backing chip came off
     at the club's request: the line alone read 3.12:1 over the 1963 picture at desk and 3.90:1 over
     the aerial on a tablet with the old values. PREVIOUS: --l1:.62; --l2:.36; --b1:.56; --b2:.26 */
  --l1:.62; --l2:.50;                       /* wide: left column, full height */
  --b1:.56; --b2:.34;                       /* wide: bottom band */
  --m1:.78; --m2:.70; --m3:.48; --m4:.15;   /* narrow: full-width, bottom-up */
  --t1:.52;                                 /* both: band behind the header */
  /* One strength multiplier on the left, bottom and narrow alphas (never --t1, which protects
     the menu). Set per page from measurement: inc/page-head.php, BNSGC_HEAD_SHADE_KEY. */
  --bns-full-scrim:1;
  /* ⚠️ HALVED 2026-09-28 (the club: "reduce the text margin by 50% to the left to encroach less
     on to the image"). The copy used to be centred at --wide, so at 1920 it started 360px in; the
     space either side of the column is now split 1:3 instead of 1:1, so it starts 180px in. Below
     about 1310px the column already sits on the gutter and nothing changes. The copy's own
     margin in .bns-hero__body .bns-wrap is the same arithmetic, and the two MOVE TOGETHER: this
     is what anchors the scrim, and a scrim left where the text used to be strands the text.
     PREVIOUS: max(var(--gut), calc(50% - var(--wide)/2)) */
  --cl:max(var(--gut), calc(var(--gut) + (100% - 2 * var(--gut) - var(--wide)) / 4));
  position:relative;height:100vh;height:100svh;min-height:360px;overflow:hidden;
  background:var(--brand-deep);container-type:size;display:flex;align-items:flex-end}

.bns-hero__media,.bns-hero__media img,.bns-hero iframe{position:absolute;inset:0;width:100%;height:100%;border:0}
.bns-hero__media{z-index:0}
/* 45%, matching .bns-kb__f below, NOT 50%: the poster IS slide 1 until the layer fades in over it,
   and a 5% disagreement showed as a jolt on a sideways-on phone. Both axes come from the picture's
   own meta, set in inc/page-head.php. */
.bns-hero__media img{object-fit:cover;object-position:var(--bns-focus-x,50%) var(--bns-focus-y,45%)}
.bns-hero iframe{z-index:1;opacity:0;transition:opacity .6s ease;filter:saturate(1.10) contrast(1.05)}
.bns-hero iframe.is-ready{opacity:1}
/* `inset` is shorthand for top/right/bottom/left, declaring it AFTER top/left wiped both
   back to auto and the translate() shoved the video up and left. Longhand only here. */
.bns-hero iframe{right:auto;bottom:auto;top:50%;left:50%;transform:translate(-50%,-50%);
  width:max(100cqw,177.7778cqh);height:max(100cqh,56.25cqw)}

/* The copy is a LEFT COLUMN, so the scrim is one too. Strong at the left edge, gone by
   ~55% across, leaving sky and horizon completely clear. Anchored to the CONTENT column
   via --cl, not the viewport edge: at 1920 the copy starts 360px in, and a
   viewport-relative gradient would strand it in the fade. */
.bns-hero::after{content:"";position:absolute;inset:0;z-index:2;pointer-events:none;
  background:
    linear-gradient(to right,
      rgba(6,10,14,calc(var(--l1) * var(--bns-full-scrim))) 0px,
      rgba(6,10,14,calc(var(--l2) * var(--bns-full-scrim))) calc(var(--cl) + 640px),
      rgba(6,10,14,0)         calc(var(--cl) + 1160px)),
    linear-gradient(to top,
      rgba(6,10,14,calc(var(--b1) * var(--bns-full-scrim))) 0%, rgba(6,10,14,calc(var(--b2) * var(--bns-full-scrim))) 38%, rgba(6,10,14,0) 70%),
    /* a ~130px band BEHIND the header: the glass alone could not carry white text over the
       brightest frame (the button measured 255), and raising the tint would have made it
       opaque rather than glass. */
    linear-gradient(to bottom,
      rgba(6,10,14,var(--t1)) 0px, rgba(6,10,14,calc(var(--t1) * .55)) 96px, rgba(6,10,14,0) 150px)}

.bns-hero__body{position:relative;z-index:3;width:100%;
  /* the cue's lane is reserved from its MEASURED height, hand-tuned numbers went stale
     the moment the chevron became a mouse */
  padding:0 var(--gut) calc(clamp(20px,3vw,34px) + var(--cue,62px))}
.bns-hero__body .bns-wrap{max-width:var(--wide);
  /* a quarter of the spare width on the left instead of half: see --cl on .bns-hero */
  margin-left:max(0px, calc((100% - var(--wide)) / 4))}
/* ⚠️ REDUCED 2026-09-16 (Martin: "reduce the font size of the main hero header slightly").
   PREVIOUS: clamp(38px,6.2vw,74px), which rendered at its 74px ceiling from 1194px up.
   NOW: 64px at that ceiling, so the change is visible rather than theoretical.
   The narrow override further down moved with it; revert both together. */
.bns-hero h1{color:#fff;font-size:clamp(35px,5.4vw,64px);max-width:15ch;margin-top:12px;
  text-shadow:0 2px 26px rgba(0,0,0,.42)}

/* ⚠️ The eyebrow carries its OWN backing, and that is what lets the scrim stay light.
   It sits 52% down the hero: past where the bottom band has faded. So only the left
   column protected it, and the left column is exactly what was asked to be brightened.
   Against the measured worst frame (199/255) a pale cream is 1.35:1 and even PURE WHITE
   is 1.69:1: no colour choice fixes it. A chip at alpha .62 measures 6.29:1. */
.bns-hero .bns-eyebrow{color:#F7E4BC;display:inline-block;
  background:rgba(6,10,14,.62);padding:7px 13px;border-radius:4px;
  -webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);
  text-shadow:0 1px 10px rgba(0,0,0,.6)}
.bns-hero__kicker{color:rgba(251,249,245,.93);font-size:clamp(16px,1.7vw,19px);margin-top:16px;
  max-width:46ch;text-shadow:0 1px 14px rgba(0,0,0,.5)}
.bns-hero .bns-actions{margin-top:26px;flex-wrap:wrap}

.bns-cue{position:absolute;z-index:3;left:50%;transform:translateX(-50%);bottom:20px;
  display:flex;align-items:center;justify-content:center;padding:6px 12px;
  color:rgba(251,249,245,.9);text-decoration:none;
  font:600 11px/1 var(--body);letter-spacing:.16em;text-transform:uppercase;white-space:nowrap;
  text-shadow:0 1px 10px rgba(0,0,0,.7)}
.bns-cue:hover{color:#fff}
/* The slideshow's pause button, beside the cue. band-video.js adds it only where pictures rotate. */
.bns-pause{position:absolute;z-index:3;right:var(--gut);bottom:22px;width:36px;height:36px;
  display:grid;place-items:center;padding:0;border-radius:999px;cursor:pointer;
  color:rgba(251,249,245,.9);background:rgba(6,10,14,.45);border:1px solid rgba(251,249,245,.4)}
.bns-pause:hover{color:#fff;background:rgba(6,10,14,.65)}
/* On a letterbox the band is short: smaller, and closer to the edge. */
body:not(.bns-head-full) .bns-page-head .bns-pause{bottom:14px;width:30px;height:30px}
.bns-pause:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.bns-pause .bns-pause__play{display:none}
.is-paused .bns-pause .bns-pause__bar{display:none}
.is-paused .bns-pause .bns-pause__play{display:block}
/* .is-drift on the layer too: the drift rule is a shorthand of equal weight further down, and a
   tie goes to it. Measured: the layer stayed "running" after pause until this carried one more class. */
body.bns-head-full .bns-page-head.is-paused .bns-kb__f.is-drift,
.bns-hero.is-paused .bns-kb__f.is-drift,
.is-paused .bns-cue .bns-mouse,.is-paused .bns-cue .bns-wheel,
.bns-page-head.is-paused::before{animation-play-state:paused}
.bns-cue .bns-mouse{animation:bns-float 2.6s ease-in-out infinite}
.bns-cue .bns-wheel{animation:bns-wheel 2.6s cubic-bezier(.45,0,.25,1) infinite}
/* The cue bobs twice and stops (4.8s): WCAG 2.2.2 gives five seconds to anything that cannot be
   paused. AFTER the two shorthands above, which would otherwise reset these. */
.bns-cue .bns-mouse,.bns-cue .bns-wheel{animation-duration:2.4s;animation-iteration-count:2}
@keyframes bns-float{0%,100%{transform:translateY(0)}50%{transform:translateY(4px)}}
@keyframes bns-wheel{
  0%{transform:translateY(0);opacity:0} 12%{transform:translateY(0);opacity:1}
  55%{transform:translateY(15px);opacity:1} 78%{transform:translateY(19px);opacity:0}
  100%{transform:translateY(0);opacity:0}}

/* ── course status strip ────────────────────────────────────────────────── */
/* ── course status strip ───────────────────────────────────────────────────────────────────
   ⚠️ TIDIED 2026-09-16 (Martin: "can we tidy this up a little so it lines up nicely").
   It used three loose flex children with `margin-left:auto` on the disclosure, which flung
   "Full course status" to the far edge of a 1440px bar and left a lake of dead space in the
   middle. On a phone the row wrapped into three ragged left-aligned lines with the disclosure
   adrift below them.
   Now: the state and its detail are ONE group that stays together, the disclosure sits at the
   end, and a separator rule appears between them only when they are actually side by side. The
   dot, the label and the flags share a baseline instead of each finding their own. */
.bns-status{background:var(--brand-deep);color:var(--paper);padding-block:0;padding-inline:var(--gut)}
.bns-status .bns-wrap{
	display:flex;align-items:center;gap:10px 18px;flex-wrap:wrap;min-height:54px;padding-block:9px;
}
.bns-status p{font-size:15px;margin:0;color:var(--brand-soft)}
/* The live state and what it means, kept as one unit so they never split across a wrap. */
.bns-status__state{display:flex;align-items:center;gap:10px 14px;flex-wrap:wrap;min-width:0}
.bns-status__state p{position:relative;padding-left:15px}
.bns-status__state p::before{
	content:"";position:absolute;left:0;top:50%;width:1px;height:14px;margin-top:-7px;
	background:rgba(158,175,197,.32);
}
.bns-status__lbl{color:var(--paper);font-weight:600;display:inline-flex;align-items:center;white-space:nowrap}
.bns-status__lbl::before{content:"";display:inline-block;width:9px;height:9px;border-radius:50%;
  background:#7BC47F;margin-right:10px;vertical-align:middle;box-shadow:0 0 0 3px rgba(123,196,127,.22)}
/* ⚠️ `margin-left:auto` USED TO LIVE HERE and it is what made the bar look untidy: it pushed the
   disclosure to the far right of a 1440px strip, leaving a lake of dead space in the middle. The
   row is now a normal flex line, so the control sits just after the state it belongs to and the
   strip reads as one sentence. It still moves to its own full-width line when the row wraps. */
.bns-status details{margin-left:0}
@media (min-width:861px){
	.bns-status details{margin-left:auto}
	.bns-status .bns-wrap{gap:10px 26px}
}
@media (max-width:860px){
	.bns-status details{width:100%;border-top:1px solid rgba(158,175,197,.2);margin-top:2px}
	/* stacked, the separator rule before the detail line reads as a stray mark */
	.bns-status__state p::before{content:none}
	.bns-status__state p{padding-left:0}
	.bns-status__state{gap:2px}
	.bns-status__state p{font-size:14px}
}
/* ⚠️ 44px, RAISED FROM 24px. The 24 was the WCAG 2.2 SC 2.5.8 floor, and it passed. The audit
   measured it at 120x38px and the platform bar is 44 to 48. This is the control that opens the
   course status, which is one of the few things a golfer checks from a phone before setting off.
   The strip around it has min-height:54px, so a 44px control fits without growing the row. */
.bns-status summary{cursor:pointer;font-size:14px;color:var(--brand-soft);list-style:none;
  padding:8px 2px;min-height:44px;display:inline-flex;align-items:center}
.bns-status summary::-webkit-details-marker{display:none}
.bns-status summary:hover{color:var(--paper)}
.bns-flags{display:flex;gap:8px;flex-wrap:wrap;padding:12px 0 4px;width:100%}
.bns-flag{border:1px solid rgba(158,175,197,.4);border-radius:5px;padding:5px 10px;font-size:13px;color:var(--brand-soft)}
.bns-flag b{color:var(--paper);font-family:var(--body);font-weight:600}
/* The live strip (2026-10-16): the dot says the state at a glance, the words say it properly. Green, open
   with nothing in force; amber, open with a restriction (preferred lies, mats, no trolleys...); red, not
   open. A flag in force is picked out; the time is when the club last changed it in ClubV1. */
.bns-status.is-restricted .bns-status__lbl::before{background:#E8B04A;box-shadow:0 0 0 3px rgba(232,176,74,.24)}
.bns-status.is-closed .bns-status__lbl::before{background:#E5675A;box-shadow:0 0 0 3px rgba(229,103,90,.24)}
.bns-flag.is-on{border-color:var(--accent);color:var(--paper)}
.bns-status .bns-status__when{width:100%;font-size:13px;padding:2px 0 10px}

/* ── heritage ───────────────────────────────────────────────────────────── */
.bns-heritage{background:var(--surface);border-bottom:1px solid var(--line)}
.bns-heritage .bns-grid{display:grid;grid-template-columns:1.05fr .95fr;gap:clamp(28px,4.5vw,64px);align-items:center}
/* Breathing room around the headings: the eyebrow sat 10px off the h2 and the h2 10px off
   the lede, so the three read as one block rather than label / headline / copy. Set on this
   band only: widening it to every .bns-head would be a system change made in passing. */
.bns-heritage .bns-eyebrow{margin-bottom:18px}
.bns-heritage h2{font-size:clamp(30px,3.8vw,44px);line-height:1.06;max-width:18ch}
.bns-heritage .bns-band__lede{margin-top:22px}
.bns-heritage .bns-figures{margin-top:34px}
.bns-heritage .bns-hole{align-self:stretch;min-height:0}

/* ── legends, 1963. Names set as TYPE: no imagery needed, and none exists ─ */
.bns-legends{border-bottom:1px solid var(--line)}
.bns-legends h2{font-size:clamp(28px,3.6vw,42px);margin-top:10px}
.bns-legends .bns-grid{display:grid;grid-template-columns:1.1fr .9fr;gap:clamp(28px,4.5vw,64px);align-items:center}
/* ⚠️ SCOPED TO THIS BAND. `.bns-names` is also used by page-1904.php, where the same four names are
   a footnote inside a feature card and are set as small pills. That block used to be unscoped and
   beat this one everywhere, which is how the home band lost its typography (fixed 2026-09-16).
   Here the names ARE the band, so they are set as display type. Do not un-scope either block. */
.bns-legends .bns-names{list-style:none;margin:0;padding:0;border-top:1px solid var(--line)}
/* The names and the 1963 photograph share the right-hand column (2026-09-29). */
.bns-legends__side{min-width:0;display:grid;gap:28px}
.bns-legends .bns-names li{font-family:var(--display);font-weight:600;font-size:clamp(26px,3vw,38px);line-height:1.1;
  letter-spacing:-.015em;color:var(--brand);padding:14px 0;border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:16px}
.bns-legends .bns-names li::before{content:"";flex:0 0 18px;height:2px;background:var(--accent)}

/* ── promotion banner. THE CLUB EDITS THIS ─────────────────────────────── */
/* Text NEVER sits on the image: the club will upload arbitrary pictures and legibility
   must not depend on which one they choose. */
.bns-promo{background:var(--brand-deep);color:var(--paper)}
.bns-promo h2{color:#fff;font-size:clamp(28px,3.4vw,40px);margin-top:10px}
.bns-promo .bns-eyebrow{color:#F0D9A8}
.bns-promo p{color:rgba(251,249,245,.86)}
.bns-promo .bns-grid{display:grid;grid-template-columns:1fr 1fr;gap:clamp(28px,4.5vw,64px);align-items:center}
.bns-promo__media{border-radius:var(--radius);overflow:hidden;aspect-ratio:16/10}
.bns-promo__media img{width:100%;height:100%;object-fit:cover}
.bns-promo__tag{display:inline-block;margin-top:20px;font:600 11px/1 var(--body);letter-spacing:.14em;
  text-transform:uppercase;color:var(--brand-soft);border:1px dashed rgba(158,175,197,.5);
  padding:6px 9px;border-radius:4px}

/* What's on, as a PAIR (2026-10-13, Martin for John Gibson: Christmas and winter society "promoted clearly"): two offers given equal weight, side by side, the picture
   on top of each. Text never on the picture, as before. Stacks on a phone, first item first. */
.bns-promo__pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(22px, 3vw, 40px); margin-top: 30px; }
.bns-promo__item {
	display: flex;
	flex-direction: column;
	background: rgba(251, 249, 245, .06);
	border: 1px solid rgba(251, 249, 245, .14);
	border-radius: var(--radius);
	overflow: hidden;
}
.bns-promo__item .bns-promo__media { border-radius: 0; }
.bns-promo__item h3 { color: #fff; font-size: clamp(22px, 2.3vw, 28px); margin: 24px 26px 0; }
.bns-promo__item p { margin: 10px 26px 0; line-height: 1.6; }
.bns-promo__item .wp-block-buttons { margin: auto 26px 0; padding: 22px 0 26px; }
/* The block layout's flow spacing puts a top margin on every block after the first, which dropped the
   second card 24px below the first. The grid gap does the spacing here. */
.bns-promo__pair > .bns-promo__item { margin-block-start: 0; }
@media (max-width: 760px) { .bns-promo__pair { grid-template-columns: 1fr; } }
/* Light buttons on the dark band, as the banner's "Make an enquiry": the dark default all but disappears here. */
.bns-promo__item .wp-block-button__link { background: var(--paper); color: var(--brand-deep); box-shadow: none; }
.bns-promo__item .wp-block-button__link:hover,
.bns-promo__item .wp-block-button__link:focus-visible { background: #fff; color: var(--brand-deep); }

/* ── accreditations ─────────────────────────────────────────────────────── */
.bns-accred{border-top:1px solid var(--line);background:var(--paper)}
.bns-accred__row{display:flex;gap:clamp(26px,3.4vw,46px);align-items:center;flex-wrap:wrap;margin-top:22px}
/* Sized by OPTICAL WEIGHT, not one shared box. The marks are wildly different shapes,
   England Golf 113x144 portrait, SafeGolf 484x144 at 3.4:1, CASC a 2.67:1 lockup. So a
   single fixed slot either crushes the portrait one or lets the wide one own the row.
   ⚠️ Other organisations' trade marks: scaled only. Never recoloured, cropped, or set on a
   tint that changes how they read. */
.bns-accred__logo{height:46px;width:auto;max-width:200px;object-fit:contain;flex:0 0 auto}
.bns-accred__logo[src*="england-golf"]{height:62px}
.bns-accred__logo[src*="safegolf"]{height:40px}
.bns-accred__logo[src*="casc"]{height:44px}
.bns-accred__logo[src*="lancashire"]{height:58px}
.bns-logo-slot{width:132px;height:56px;border:1px dashed var(--line);border-radius:5px;display:grid;
  place-items:center;gap:3px;text-align:center;font-size:11px;color:var(--ink-soft);letter-spacing:.06em}
.bns-logo-slot.is-ask{border-color:var(--accent)}
.bns-logo-slot.is-ask b{font:600 9px/1 var(--body);letter-spacing:.12em;text-transform:uppercase;color:var(--accent-deep)}

/* ── responsive ─────────────────────────────────────────────────────────── */
@media(max-width:1100px){
  .bns-heritage .bns-grid,.bns-legends .bns-grid,.bns-promo .bns-grid{grid-template-columns:1fr;gap:34px}
  .bns-cards{grid-template-columns:repeat(2,1fr);gap:20px}
  .bns-cards--five>*,.bns-cards--five>:nth-child(n+4){grid-column:auto}
  .bns-cards--five>:last-child{grid-column:1/-1}
}
@media(max-width:620px){
  .bns-cards{grid-template-columns:1fr}
  .bns-cards--five>:last-child{grid-column:auto}
  .bns-accred__row{gap:22px 26px}
  .bns-accred__logo{height:40px}
  .bns-accred__logo[src*="england-golf"]{height:52px}
  .bns-accred__logo[src*="safegolf"]{height:34px}
  .bns-accred__logo[src*="casc"]{height:38px}
  .bns-cue{font-size:10px;letter-spacing:.11em}
}
/* Landscape phone/tablet: the hero fits the viewport, min-height must not win. */
@media(orientation:landscape) and (max-height:620px){
  .bns-hero{min-height:0}
  .bns-hero__body{padding-bottom:18px}
}
@media(max-height:620px) and (min-width:621px){
  /* moved with the desktop size above, 2026-09-16. PREVIOUS: clamp(30px,4.6vw,46px) */
  .bns-hero h1{font-size:clamp(28px,4.2vw,42px)}
  .bns-hero__kicker{font-size:16px;margin-top:10px}
  .bns-hero .bns-actions{margin-top:16px}
  .bns-hero__body{padding-bottom:24px}
  .bns-cue{display:none}
}
/* Below 900 the copy spans nearly the full width, so a left-column scrim leaves the right
   end of every line unprotected. Keeping the right of the frame clear is a wide-screen
   idea; on a phone the video is cropped hard and there is no "rest of frame" to save. */
@media(max-width:900px){
  .bns-hero::after{background:
    linear-gradient(to top,
      rgba(6,10,14,calc(var(--m1) * var(--bns-full-scrim))) 0%, rgba(6,10,14,calc(var(--m2) * var(--bns-full-scrim))) 28%,
      rgba(6,10,14,calc(var(--m3) * var(--bns-full-scrim))) 56%, rgba(6,10,14,calc(var(--m4) * var(--bns-full-scrim))) 78%, rgba(6,10,14,0) 100%),
    linear-gradient(to bottom,
      rgba(6,10,14,var(--t1)) 0px, rgba(6,10,14,calc(var(--t1) * .55)) 96px, rgba(6,10,14,0) 150px)}
}
@media(prefers-reduced-motion:reduce){
  /* the cue holds still: both loops ran forever under reduce until the review gate caught it, 2026-10-06 */
  .bns-cue .bns-mouse,.bns-cue .bns-wheel{animation:none}
  .bns-cue .bns-wheel{opacity:1}
}

/* ═══ MASTHEAD ═══════════════════════════════════════════════════════════════════════════
   Ported from the prototype 2026-09-14. Names kept unprefixed (.masthead/.brand/.crest/
   .burger/.actions), checked with word-boundary matching, all five are FREE in this file.
   ⚠️ An earlier substring grep reported 5 hits on `.brand`; every one was PROSE IN A COMMENT.
   Match on a word boundary or a collision check invents work.

   ⚠️ The old .site-header rules above (6, scoped to core navigation) belong to the SKELETON
   header this replaces. They become dead CSS once parts/header.html is rebuilt, left in
   place for now rather than deleted blind.
   ═══════════════════════════════════════════════════════════════════════════════════════ */
.masthead{position:fixed;top:0;left:0;right:0;z-index:50;padding-inline:var(--gut);color:var(--paper);
  /* ⚠️ REDUCED 2026-09-16 (Martin: "make the header slightly smaller so less imposing on the
     images"). PREVIOUS VALUES, MEASURED ON THE LIVE PAGE BEFORE THE CHANGE, FOR A CLEAN REVERT:
       wide  (1440): header 93px, wrap min-height 92px, crest 105x140, --crest 140px, --crest-drop 33px
       phone (390):  header 71px, wrap min-height 70px, crest  66x88,  --crest  88px, --crest-drop 15px
       solid (past the hero): --crest 60px, and 42px below 1100px. Those are UNCHANGED: the bar is
       only imposing where it sits over a photograph, which is the glass state.
     Revert by restoring --crest:140px/--crest-drop:33px here, --hdr:93px, and min-height:92px. */
  --crest:118px; --crest-drop:26px;          /* over the hero: big, and hanging below the bar */
  background:rgba(10,15,21,.40);
  -webkit-backdrop-filter:blur(16px) saturate(150%);backdrop-filter:blur(16px) saturate(150%);
  border-bottom:1px solid rgba(251,249,245,.16);
  transition:background .32s ease,border-color .32s ease,color .32s ease}

/* No backdrop-filter (older Firefox, some Android): a 40% wash with no blur is not a legible
   ground for white text, so fall back to a solid-enough tint. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .masthead{background:rgba(10,15,21,.72)}
}

/* Past the hero it stops being glass and becomes the page's own header. OLIVE: it keeps the
   one property that made the dark bar work (white text passes at 5.67:1), so the SAME white
   crest serves both states: no second asset, no swap at the fold. Being the paler of the two
   it costs elsewhere, gold-bright is 1.78:1 on olive, which is why the CTA and the nav
   underline both change below. */
.masthead.is-solid{--crest:60px; --crest-drop:0px;
  background:var(--shell);color:var(--paper);border-bottom-color:rgba(251,249,245,.20);
  -webkit-backdrop-filter:none;backdrop-filter:none;box-shadow:0 2px 18px rgba(27,30,20,.22)}

/* ⚠️ The bar height is SET FROM THE CREST, not chosen. The top gap and the overhang split
   whatever (crest − bar) comes to, so a bar that does not grow with the crest pushes the
   artwork off its own top edge. --hdr is measured at runtime, so nothing downstream needs
   telling when this changes. */
/* min-height 92px -> 81px, 2026-09-16. Moves with --hdr above; see the revert note at --crest. */
.masthead .bns-wrap{display:flex;align-items:center;gap:22px;min-height:81px;flex-wrap:nowrap}

.brand{position:relative;display:flex;align-items:center;gap:12px;text-decoration:none;color:inherit;
  flex:0 0 auto;padding-left:calc(var(--crest) * .75 + 22px);transition:padding-left .34s ease}

/* ⚠️ OUT OF FLOW, and that is not a style preference. --hdr is measured from the header's REAL
   box; a 140px crest left in flow would inflate that box and drag scroll-padding-top and the
   hero's height with it. Absolute keeps the bar at its own height however large the crest
   grows. .75 is the artwork's own aspect (1793/2393, the white mark). */
.crest{position:absolute;left:0;top:50%;height:var(--crest);width:auto;max-width:none;
  transform:translateY(-50%) translateY(var(--crest-drop));
  transition:height .34s ease,transform .34s ease;
  filter:drop-shadow(0 3px 14px rgba(6,10,14,.45))}

.brand b{font-family:var(--display);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  font-size:clamp(14px,2.4vw,17px);font-weight:600;letter-spacing:-.01em;line-height:1.15;display:block}
.brand span{font-size:11px;letter-spacing:.13em;text-transform:uppercase;opacity:.72}

.masthead nav{margin-left:auto;display:flex;gap:clamp(14px,1.6vw,26px);align-items:center}
.masthead nav a{color:inherit;text-decoration:none;font-size:15px;font-weight:500;white-space:nowrap}

/* Gold TEXT was the hover while the bar was pale (5.42:1). It fails on every dark bar, so the
   state is an UNDERLINE and the label keeps full contrast. The underline colour is measured per
   ground: accent reads on the dark glass but is 1.78:1 on the olive, below even the 3:1 a
   non-text indicator needs. So past the fold it becomes the label's own colour. */
.masthead nav a:hover{opacity:1;text-decoration:underline;text-decoration-color:var(--accent);
  text-underline-offset:7px;text-decoration-thickness:2px}
.masthead.is-solid nav a:hover{text-decoration-color:currentColor}

.actions{display:flex;gap:10px;flex:0 0 auto;flex-wrap:wrap}

/* Forced by the bar change, not a separate idea: brand-on-brand-deep is 1.4:1. The CTA would
   have vanished the instant the header solidified. Accent carries ink at 5.05:1 and stands
   4.02:1 clear of the glass. Header only; the page's own buttons are unchanged. */
.masthead .bns-btn--primary{background:var(--accent);color:var(--ink)}
.masthead .bns-btn--primary:hover{background:#C0A05E}
/* ...and on the olive the accent CTA dissolves for the same reason one colour along, so it
   flips to paper: 5.67:1 at the button's edge, carrying ink at 16.07:1. */
.masthead.is-solid .bns-btn--primary{background:var(--paper);color:var(--ink)}
.masthead.is-solid .bns-btn--primary:hover{background:#FFFFFF}

/* ⚠️ 44px MINIMUM, AND THIS IS THE ONE THAT MATTERS MOST. The burger is the ONLY route to the
   navigation below 1100px, so it is the single most important target on every phone. The audit
   measured it at 60x35px (2026-09-16). min-width as well as min-height, because at 620px down
   the padding shrinks to 8px and a narrow label would otherwise take the box back under 44.
   `display:none` stays: the media query at the 1100px breakpoint is what reveals it, and it
   switches to inline-flex so the label centres in the taller box. */
.burger{display:none;align-items:center;justify-content:center;min-height:44px;min-width:44px;
  margin-left:auto;background:none;border:1px solid rgba(251,249,245,.5);
  border-radius:var(--radius-btn);padding:9px 12px;font:600 15px var(--body);color:inherit}

/* ⚠️ 1101 to 1373px. The nav shows but the row does not fit. SWEPT, not sampled: the header
   passed at seven sampled widths and was meanwhile overflowing by up to 222px across this
   whole range, CTA sliced off, because the range fell between two samples.
   THE WORDMARK GOES, NOT THE NAV: at this size the crest is 140px and carries the brand on its
   own, whereas losing a nav link or a CTA costs the visitor something. Visually hidden, NOT
   display:none. The crest is aria-hidden, so this text is the home link's only accessible name.

   ⚠️ THE CEILING MOVED FROM 1343 TO 1373 ON 2026-09-16, AND IT WAS FOUND THE SAME WAY THE FIRST
   ONE WAS. Raising the tap targets to 44px widened the header row, and the sweep reported
   "✗ 1344 to 1372px overflows by up to 14px". The 23-page audit could not have seen it: it samples
   320/375/390/768/1024/1280 and that whole range sits between two of those samples. The boundary
   is the measured last-bad width plus one, not a guess, and it is re-swept after changing.
   ⚠️ ANY CHANGE TO THE HEADER'S CONTENTS MOVES THIS NUMBER. Re-run tools/sweep-header.mjs, which
   until 2026-09-16 could not even address the theme (it queried the prototype's .wrap-wide). */
/* 2026-09-30: re-swept on the solid-header pages (Contact us, Green fees) and they overflowed
   again at 1374 to 1402px by up to 14px, with or without the section bar, which lives on its own
   row and is not measured here. Boundary moved to the last bad width plus one. */
/* 1403 to 1455 (2026-10-06): sweep-header found the wordmark back at 1404 and 22px over until 1454,
   on inner pages. The crest-size arithmetic below explains the hero pages' own, longer range. */
@media(min-width:1101px) and (max-width:1455px){
  .brand > span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
  .masthead nav{gap:clamp(12px,1.2vw,20px)}
  .masthead .bns-wrap{gap:16px}
}

/* 1101 to 1130 on a big-crest page (2026-10-06): the sweep found 14px over at 1102 to 1124 on home.
   The crest reserves 39px more than on a letterbox page, so the gaps give it back here. */
@media(min-width:1101px) and (max-width:1130px){
  body:has(.bns-hero) .masthead:not(.is-solid) nav,
  body.bns-head-full .masthead:not(.is-solid) nav{gap:9px}
  body:has(.bns-hero) .masthead:not(.is-solid) .bns-wrap,
  body.bns-head-full .masthead:not(.is-solid) .bns-wrap{gap:10px}
}

/* 1100, not 1080. The old value was set when the crest was 42px and left a 20px hole the sweep found. */
@media(max-width:1100px){
  .bns-js .masthead nav,.masthead .actions .bns-btn--ghost{display:none}
  /* inline-FLEX, not inline-block: the base rule centres the label with align-items, and an
     inline-block here would silently drop that and leave "Menu" at the top of a 44px box. */
  .burger{display:inline-flex}
  .masthead .actions{margin-left:12px}
  .brand{flex:0 1 auto;min-width:0}
  .brand > span{min-width:0}
}

@media(max-width:620px){
  /* Overhang is what reads, not size. A 58px crest dropped 10px cleared a 63px bar by SEVEN
     pixels, measured, not judged. Which is a rounding error, not an effect. Drop does the
     work here: the bar is shorter on a phone so the crest sits lower in it, not just smaller.
     Target is ~a third of the bar's height proud of it, as on the desktop. */
  .masthead{--crest:88px; --crest-drop:15px}
  .masthead.is-solid{--crest:42px; --crest-drop:0px}
  .masthead .bns-wrap{gap:12px;min-height:70px}
  /* The crest IS the brand at this width. Beside it the wordmark had nowhere to go and
     rendered "BLACKPOOL NORTH SHO…". The crest alone reads better than a truncation. */
  .brand > span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}
  .bns-btn{padding:9px 13px;font-size:14px}
  .burger{padding:8px 10px;font-size:14px}
  /* "Book" in place of "Book a Tee Time" at this width (2026-10-16). Two real spans, swapped by display.
     It used to be font-size:0 with "Book" drawn by ::after, and text at 0px cannot grow with browser
     zoom: the one FAIL on every page of the audit (WCAG 1.4.4). The link's aria-label keeps the full
     name, which begins with the visible word (2.5.3, label in name). */
  .masthead .bns-btn--primary{padding:9px 12px}
  .masthead .bns-book__full{display:none}
  .masthead .bns-book__short{display:inline}
}

@media(max-width:400px){
  /* The burger STAYS here. It used to be hidden to give the CTA room. But nav is already
     hidden from 1100 down, so below 400px the page had NO route to the navigation at all.
     With the wordmark visually hidden from 620 down there is room for both.
     Deliberately NO crest override: one tuned rule from 620 down, not two fighting. */
  .masthead .bns-wrap{gap:10px}
  .brand b{font-size:13px;line-height:1.2}
}

/* skip link + visually-hidden, needed by the header markup */
.bns-vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0;text-transform:none;letter-spacing:normal}

/* ⚠️ Core's post-content layout gives the content wrapper a top margin, which pushed the hero
   24px down the page and left a sliver of the fixed header's own background above the video.
   Found by rendering the ported page, not by reading the template. MainTop measured 24px with
   main's computed margin-top at 24px and body/html both at 0.
   The front page's first band is always full-bleed and sits UNDER the fixed header by design,
   so the wrapper must not introduce leading space of its own. */
.home main > .wp-block-post-content > :first-child,
.home main > :first-child{margin-block-start:0}
.home main{margin-block-start:0}

/* ── site footer ─────────────────────────────────────────────────────────────
   ⚠️ PREFIXED, though the prototype styled a bare `footer` element. A bare rule in a
   shared theme layer reaches every <footer> on the site, including any a block pattern
   introduces later. Same discipline as scoping `nav` under .masthead. */
.bns-footer{background:var(--ink);color:rgba(251,249,245,.78);font-size:15px}
.bns-footer .bns-wrap{display:grid;grid-template-columns:2fr 1fr 1fr;gap:34px}
/* h2, not h3 (2026-10-16): on a short page (the thank-you page) h1 was followed straight by the
   footer, a heading jump. The footer is its own landmark; its column titles are second level. */
.bns-footer h2{color:var(--paper);font-size:16px;font-family:var(--body);font-weight:600;letter-spacing:.02em}
/* ⚠️ 44px, and these are not decorative links. The audit measured the footer's phone number and
   email address at 335x32px (2026-09-16). On a phone they are TAP-TO-CALL and TAP-TO-EMAIL, which
   makes them among the most likely things anyone touches on the whole site, and they were the
   shortest targets left on it. padding-block does the growing rather than min-height, so the
   column's rhythm stays even rather than one link standing taller than its neighbours. */
.bns-footer a{color:rgba(251,249,245,.78);text-decoration:none;display:flex;align-items:center;
  min-height:44px;padding:4px 0}
.bns-footer a:hover{color:var(--paper);text-decoration:underline}
/* The crest beside the club's details (2026-10-01). Width is set and height follows the file's own
   ratio (419x560), so the box is reserved before the image loads. */
.bns-footer__club{display:flex;align-items:flex-start;gap:24px}
.bns-footer__crest{flex:none;width:88px;height:auto}
@media (max-width:480px){.bns-footer__club{gap:18px}.bns-footer__crest{width:68px}}
.bns-footer__addr{margin-top:10px}
.bns-footer__contact{margin-top:14px}
/* The footer's Contact us button (2026-10-16). Its own class, because `.bns-footer a` (0,1,1) outranks
   every .bns-btn modifier and would strip the button's padding and colour. Gold on the dark ground, as
   the masthead's primary button. */
.bns-footer a.bns-footer__cta{display:inline-flex;padding:11px 20px;background:var(--accent);color:var(--ink)}
.bns-footer a.bns-footer__cta:hover{background:#C0A05E;color:var(--ink);text-decoration:none}
/* The legal row spans every column and sits under a hairline. It is a footnote to the
   whole footer, not a fourth column of links. */
/* The affiliation logos, small, above the legal line (Martin, 2026-10-08). Reversed to white for the
   dark ground: the files are dark-lettered marks for light grounds, and recolouring a trade mark is
   not allowed, so a brightness filter is NOT used; a pale tile behind each keeps the marks as drawn. */
.bns-footer__accred{grid-column:1/-1;display:flex;flex-wrap:wrap;gap:12px 18px;align-items:center;border-top:1px solid rgba(251,249,245,.16);padding-top:20px}
.bns-footer__accred img{height:34px;width:auto;background:var(--paper);border-radius:6px;padding:5px 8px;box-sizing:content-box}
.bns-footer__legal{grid-column:1/-1;border-top:1px solid rgba(251,249,245,.16);padding-top:20px;
  display:flex;align-items:center;column-gap:20px;flex-wrap:wrap;font-size:13.5px;line-height:1.4;
  color:rgba(251,249,245,.6)}
/* ONE BOX FOR EVERY ITEM IN THE ROW (2026-10-12, Martin: "needs formatting so it all lines up").
   The row held three shapes: the links inherited .bns-footer a's 44px min-height with the text at
   the top of it, the copyright was a bare span, and the Cookie settings button had neither, so the
   four baselines sat at three heights. Now each is a 44px inline-flex box, text centred, no padding.
   ⚠️ The 44px is the target size, and it is why the links are not padding:0 bare text: the first
   version of this row did that and took the hit areas to 22px tall, under WCAG 2.2 2.5.8's 24px
   floor, the only failure in the audit of the ported page. */
.bns-footer .bns-footer__legal > *{display:inline-flex;align-items:center;min-height:44px;padding:0;margin:0}
/* Cookie settings (2026-10-12): a button in the legal row, drawn as one of its links. Its own
   class: .bns-footer a would not reach a button, and a button must not pretend to be a link. */
.bns-footer__consent{border:0;background:none;font:inherit;line-height:inherit;
  color:rgba(251,249,245,.78);cursor:pointer;text-align:left}
.bns-footer__consent:hover{color:var(--paper);text-decoration:underline}
/* Credits (2026-10-16): a line under the legal row, smaller and quieter. Its own class: .bns-footer a is
   a 44px flex box, which would put each credit's link on a line of its own. Each credit is one 44px
   inline box, as the legal row's items are, so the link keeps a full target. */
.bns-footer__credits{grid-column:1/-1;margin:-26px 0 0;display:flex;flex-wrap:wrap;column-gap:20px;
  font-size:12.5px;line-height:1.4;color:rgba(251,249,245,.5)}
.bns-footer .bns-footer__credits > span{display:inline-flex;align-items:center;gap:.3em;min-height:44px}
.bns-footer .bns-footer__credits a{display:inline-flex;align-items:center;min-height:44px;padding:0;color:rgba(251,249,245,.72)}

@media(max-width:1100px){
  .bns-footer .bns-wrap{grid-template-columns:1fr}
}

/* ═══ PAGE: CONTACT ═══════════════════════════════════════════════════════════════════════
   Ported from docs/prototypes/contact.html (2026-09-15).

   ⚠️ EVERY PAGE-SPECIFIC NAME IS PREFIXED, including the ones that did not appear to clash.
   The collision check found eight shared names across the three pages, and only two were safe
   to share (.bns-btn, .bns-eyebrow). Three were real conflicts: the inherited layer defines an
   unscoped .routes grid, an unscoped .route card, and a .cta that is a full-width dark gradient
   BAND, while these pages use .cta for a plain row of two buttons. Porting unprefixed would
   have painted a dark slab behind every page's call to action.
   ⚠️ .lede is the same trap that already cost us once: the inherited .bns-lede caps
   max-width:68ch, which is why .bns-band__lede exists. Page heads use .bns-band__lede.

   ⚠️ VARIABLE NAMES ARE THE THEME'S, NOT THE PROTOTYPE'S. The prototype's palette vocabulary
   (--slate-deep, --slate-soft, --paper-2, --gold, --gold-bright) does not exist here. A var()
   naming a property that was never declared resolves to NOTHING and the rule silently stops
   applying: no background, no border, no colour, and no error anywhere. Roles are the contract.
   --hdr is measured onto :root at runtime by assets/js/home.js and carries a default here. */

/* A page head for pages with no hero. Not a hero: a hero is a video and a viewport, this is a
   title and a sentence. It sits UNDER the fixed masthead rather than behind it, so it needs the
   header's measured height as padding. */
.bns-page-head {
	/* The image comes from the page's FEATURED IMAGE, injected as --bns-head-img by
	   functions.php. No featured image means no property: the band falls back to flat
	   brand-deep and the scrim stays at 0, so a page without a photograph is not darkened
	   for no reason. The club swaps the picture in the editor; nothing here changes. */
	--bns-head-img: none;
	--bns-head-scrim: 0;
	position: relative;
	isolation: isolate;
	overflow: hidden;              /* clips the zoom layer to the band */
	background-color: var(--brand-deep);
	color: var(--paper);
	padding-block: calc(var(--hdr, 93px) + clamp(34px, 5vw, 58px)) clamp(34px, 5vw, 58px);
	padding-inline: var(--gut);
}

/* THE PICTURE IS ITS OWN LAYER, and that is not tidiness: it is the whole reason the slow
   zoom is affordable. A background-image CANNOT be transformed, so animating background-size
   or background-position repaints the band on every frame, which is the juddering version of
   this effect everybody has seen. A layer can be moved with `transform`, which stays on the
   compositor. Hence the picture at -2, the scrim at -1, and overflow:hidden above.
   No markup changed: the page head is static wp:html in about twenty patterns. */
.bns-page-head::before {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -2;
	pointer-events: none;
	background-image: var(--bns-head-img);
	background-size: cover;
	background-position: var(--bns-focus-x, 50%) var(--bns-focus-y, 40%);   /* 40% fallback: skies are usually the top third, bias to the horizon. bnsgc_focus_x() / bnsgc_focus_y() */
	transform: scale(1);
	will-change: transform;
}

/* ⚠️ THE SCALE NEVER DROPS BELOW 1. At 0.99 the band would show its own flat colour at the
   edges for the whole cycle. Both directions run 1.00 to 1.06 and differ only in which end
   they start from. `alternate` so it eases back rather than snapping to its first frame.
   ⚠️ SCALE ONLY, NEVER PAN: docs/image-guidance.md asks the club to frame the subject right
   of centre because the title sits over the left, and a drift would carry that subject under
   the title. A centred scale leaves the composition exactly as it was framed. It also keeps
   the SAME pixels behind the heading, which is what makes the measured scrim contrast still
   true while the picture is moving. */
@keyframes bns-kb-in  { from { transform: scale(1); }    to { transform: scale(1.06); } }
@keyframes bns-kb-out { from { transform: scale(1.06); } to { transform: scale(1); } }

/* Motion is an enhancement, never the content. Anyone who has asked for less of it gets the
   photograph held still. */
@media (prefers-reduced-motion: reduce) {
	.bns-page-head::before { animation: none !important; transform: scale(1) !important; }
}

/* A DEEPER PAGE HEAD, for a page whose title IS the point. 1904 is a year, not a sentence: set
   at the shared size it reads as a label, and the prototype Martin approved on 2026-09-15 had
   it far larger over a deeper band.
   ⚠️ A MODIFIER, NOT A CHANGE TO .bns-page-head. That band is shared by about twenty pages, and
   "Open competitions" or "Terms and conditions" at 104px would be shouting. Opt in per page. */
.bns-page-head--display {
	padding-block: calc(var(--hdr, 93px) + clamp(44px, 7vw, 86px)) clamp(44px, 7vw, 86px);
}
.bns-page-head--display h1 { font-size: clamp(46px, 8vw, 104px); letter-spacing: -.03em; }
.bns-page-head--display .bns-band__lede { font-size: clamp(18px, 2.1vw, 22px); max-width: 50ch; }
/* The scrim is a LEFT COLUMN, like the hero's: strong where the text is, clear on the right so
   the photograph still reads. Sized in the same proportions the hero sweep was measured at. */
.bns-page-head::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	pointer-events: none;
	background: linear-gradient(
		to right,
		rgba(12, 18, 26, var(--bns-head-scrim)) 0%,
		rgba(12, 18, 26, calc(var(--bns-head-scrim) * .72)) 46%,
		rgba(12, 18, 26, calc(var(--bns-head-scrim) * .28)) 100%
	);
}
/* ⚠️ BELOW 900 THE LEDE RUNS THE FULL WIDTH, so a left column scrim leaves the right end of every
   line on bare photograph. Found 2026-09-18 re-measuring after the photo grade: at 390px the lede
   measured 4.24:1 on Winter Society Golf BEFORE the grade (a latent failure) and the grade tipped
   Join and Society Rates under 4.5 too. The full screen banner already had this override; the
   letterbox never did. .8 / .6 is the lightest tested that holds (tightest 5.35:1). The full
   screen rule (body.bns-head-full ...) is more specific and still wins on those pages. */
@media (max-width: 900px) {
	.bns-page-head::after {
		background: linear-gradient(
			to right,
			rgba(12, 18, 26, var(--bns-head-scrim)) 0%,
			rgba(12, 18, 26, calc(var(--bns-head-scrim) * .8)) 55%,
			rgba(12, 18, 26, calc(var(--bns-head-scrim) * .6)) 100%
		);
	}
}
.bns-page-head h1 { font-size: clamp(34px, 5vw, 58px); max-width: 16ch; }
/* ⚠️ THE EYEBROW CARRIES ITS OWN BACKING, and this is measured, not chosen.
   Over a photograph it measured 2.05:1 against a 4.5 requirement: --brand-soft
   rgb(158,175,197) on a 117/255 background. The h1 (6.67:1) and lede (6.37:1) pass
   comfortably on the same scrim, so the scrim is right and only this element was wrong.
   The hero hit exactly this and was fixed the same way: a chip at alpha .62 measured 6.29:1.
   A pale colour cannot win on a bright frame, so the text stops depending on the scrim and
   brings its own ground. Re-run tools/measure-band-contrast.mjs when the picture changes. */
.bns-page-head .bns-eyebrow {
	color: #F7E4BC;
	display: inline-block;
	background: rgba(6, 10, 14, .62);
	padding: 7px 13px;
	border-radius: 4px;
	-webkit-backdrop-filter: blur(5px);
	backdrop-filter: blur(5px);
}
.bns-page-head .bns-band__lede { color: rgba(251, 249, 245, .88); max-width: 54ch; }

/* ═══ THE FULL SCREEN BANNER: VERSION 1 OF TWO ═════════════════════════════════════════════
   Martin, 2026-09-16, relaying the club: "for each of the internal pages we need two versions
   of the hero section", one that "duplicates the home page full viewport" and the existing
   letterbox, with "a toggle in the backend to select version 1 or 2".

   ⚠️ THE LETTERBOX ABOVE IS VERSION 2 AND REMAINS THE DEFAULT. Nothing here reaches a page
   until somebody switches that page over, so the twenty five pages carrying this band render
   exactly as they did.

   ⚠️ SCOPED TO A BODY CLASS RATHER THAN WRITTEN ONTO .bns-page-head. The band is static
   `wp:html` in twenty five patterns, so the shape cannot come from the markup without editing
   every one of them, and it would STILL be wrong on the first page the club builds by hand.
   inc/page-head.php puts `bns-head-full` on <body> from the per page setting.

   ⚠️ NOT A COPY OF .bns-hero, AND THE DIFFERENCE IS EVIDENCE. The hero's scrim variables were
   swept against sixteen pinned frames of ONE specific clip. Those numbers are a measurement of
   that video, not a house style, and they do not transfer to a montage nobody has shot yet.
   The values below are a deliberately conservative starting point, and every page switched to
   this shape has to be measured against its own film:
       node tools/measure-band-contrast.mjs <url> --band .bns-page-head
   ⚠️ A NEW FILM VOIDS THE MEASUREMENT, exactly as a new clip voids the hero's.
   ──────────────────────────────────────────────────────────────────────────────────────── */
body.bns-head-full .bns-page-head {
	/* svh, not vh. On iOS and Android vh is the LARGEST viewport, so 100vh hides the foot of
	   the band behind the URL bar on first paint. Same reason .bns-hero uses it. */
	min-height: 100svh;
	display: flex;
	align-items: flex-end;
	/* The copy sits at the FOOT like the hero's, so the top padding only has to clear the
	   fixed bar rather than position anything.
	   ⚠️ THE CUE'S LANE IS A LITERAL 62px AND MUST NOT BECOME var(--cue). home.js measures
	   that shared property once at load, BEFORE band-video.js injects the cue, so it would
	   read 0px and the cue would land on the buttons. Reasoning in full in band-video.js. */
	padding-block: calc(var(--hdr, 82px) + clamp(34px, 5vw, 58px)) calc(clamp(20px, 3vw, 34px) + 62px);
	/* ⚠️ THE SCRIM IS NOT CONDITIONAL HERE. The letterbox leaves it at 0 when a page has no
	   photograph, which is right for a shallow band on flat colour and wrong for white text
	   over a moving picture. PHP sets this same value when a featured image exists; this
	   guarantees it when one does not. */
	--bns-head-scrim: .66;
	/* The strength of the text shading below, as ONE multiplier on every alpha in the bottom
	   band and the left column (desktop) and the bottom band (phone). The header strip is not
	   scaled: it protects the menu, which this band's measurement does not cover. */
	--bns-full-scrim: 1;
}

/* ⚠️ THE WHOLE STACK MOVES INTO POSITIVE z-index, and it has to. The letterbox keeps its
   picture at -2 and its scrim at -1 beneath an `isolation:isolate` parent, and THERE IS NO
   INTEGER BETWEEN THOSE TWO for a film to sit in. Mirrors .bns-hero's order exactly:
   photograph 0, film 1, scrim 2, words 3. */
body.bns-head-full .bns-page-head::before { z-index: 0; }
body.bns-head-full .bns-page-head iframe  { z-index: 1; }
body.bns-head-full .bns-page-head::after  { z-index: 2; }
/* ⚠️ `width:100%` IS LOAD BEARING, AND IT IS NOT TIDINESS. Measured 2026-09-16 at 1440px: the
   band's title sat at x=444 while the page's own content sat at x=120, and the wrap measured
   551px instead of filling its parent. Making the band `display:flex` turns .bns-wrap into a
   FLEX ITEM, which shrinks it to its content, and .bns-wrap's own `margin-inline:auto` then
   centres that shrunken box. The result is a heading indented a third of the way across the
   page while every band below it starts at the left margin.
   .bns-hero never had this because .bns-hero__body already declares `width:100%`; this is the
   same declaration doing the same job.
   ⚠️ IT ONLY SHOWS ON DESKTOP. At 390px the wrap fills anyway, so the phone capture looked
   perfect and the defect was visible only in the wide one. Re-measure both, never one. */
body.bns-head-full .bns-page-head > .bns-wrap { position: relative; z-index: 3; width: 100%; }

/* ⚠️ SIZED IN VIEWPORT UNITS, NOT CONTAINER UNITS, and that is a deliberate difference from
   the hero. The hero carries `container-type:size` for its cqw/cqh sizing, but size
   containment makes an element's height independent of its CONTENTS: safe for a hero whose
   copy is three lines, not safe for a band that also carries a lede and whatever else a page
   puts in it, which would be clipped. This band is the viewport's size anyway, so vw and svh
   cover it identically with nothing to clip.
   ⚠️ pointer-events:none: a tap must never reach the frame. That is what lets a tap freeze
   the home page when the wrong embed parameters are used. */
body.bns-head-full .bns-page-head iframe {
	position: absolute;
	top: 50%;
	left: 50%;
	transform: translate(-50%, -50%);
	width: max(100vw, 177.7778svh);
	height: max(100svh, 56.25vw);
	border: 0;
	pointer-events: none;
	opacity: 0;
	transition: opacity 1s ease;     /* 1s: it now appears on a moving frame, so it can arrive gently */
	filter: saturate(1.10) contrast(1.05);
}
body.bns-head-full .bns-page-head iframe.is-ready { opacity: 1; }
/* Paused (2026-10-16): the film fades back to the still photograph and is then hidden outright, so a
   pressed pause leaves nothing moving even before the player confirms it has stopped (WCAG 2.2.2). */
body.bns-head-full .bns-page-head.is-paused iframe { opacity: 0; visibility: hidden; transition: opacity .6s ease, visibility 0s linear .6s; }

/* ═══ THE SLIDESHOW: FIVE OR SIX PICTURES THAT DRIFT AND CROSS FADE ════════════════════════
   Martin, 2026-09-16, once the montages turned out to be months away: *"unless you can build
   burns effect panning and zoom, cross dissolve between a set of 5 to 6 images"*. The layers are
   injected by assets/js/band-video.js, because the band is static wp:html in twenty five patterns
   and six layers of markup cannot come from PHP.

   ⚠️ THIS PANS, AND THE LETTERBOX BAND DELIBERATELY DOES NOT. inc/page-head.php carries the
   reasoning for that older decision and it still stands where it was made: a drift moves different
   pixels behind the title every second, and the letterbox scrim was measured against a STILL
   frame, so a heading that passes at rest can fail mid-motion with nobody watching.
   Three things make it affordable HERE and they are conditions, not opinions:
     1. The amplitude is still bounded: a 4% pan and a 12% zoom, raised from 2.5% and 6% on
        2026-09-16 when the effect read as static, and re-measured on the real page afterwards.
     2. The scrim on this band is NOT conditional and NOT measured per photograph: the rule above
        pins --bns-head-scrim for every full screen band whether or not a picture exists.
     3. ⚠️ It must be measured ACROSS THE ROTATION, not once. Every slide has its own brightness,
        so one frame is not evidence about six:
          node tools/measure-band-contrast.mjs <url> --band .bns-page-head --frames 19 --interval 2000
        ⚠️ FRAMES TIMES INTERVAL MUST EXCEED THE WHOLE CYCLE, and the first version of this note
        got its own arithmetic wrong: it said 12 frames at 2000ms, which is 24s against a six
        picture cycle of 36s, so it would have told the next person to sample two thirds of the
        rotation and call it covered. Six slides at 6s each is 36s, so 19 frames at 2000ms.
        Change the slide count and this number changes with it.
   ⚠️ NEVER RAISE THE AMPLITUDE WITHOUT RE-MEASURING. That is the whole trade.

   ⚠️ TRANSFORM AND OPACITY ONLY. Both stay on the compositor, so six full screen photographs
   cross fading cost no layout and no repaint. Animating background-position instead, which is the
   obvious way to pan, repaints the whole band every frame and is the juddering version of this
   effect everybody has seen.
   ──────────────────────────────────────────────────────────────────────────────────────────── */
/* ⚠️ THE HOME HERO USES THIS SAME SLIDESHOW (2026-09-18), which is why every rule below names
   `.bns-hero` alongside the full screen page head. Same component, same behaviour, two hosts: in
   the hero it stacks above the poster (.bns-hero__media, also z 0, earlier in the DOM) and below
   the scrim (::after, z 2). */
body.bns-head-full .bns-page-head .bns-kb,
.bns-hero .bns-kb {
	position: absolute;
	inset: 0;
	z-index: 0;
	overflow: hidden;
	pointer-events: none;
}

/* ⚠️ Each layer is its own element with its own background, NOT one element whose image is
   swapped. A swap cannot cross fade with itself: you need both pictures on screen at once. */
body.bns-head-full .bns-page-head .bns-kb__f,
.bns-hero .bns-kb__f {
	position: absolute;
	inset: 0;
	background-size: cover;
	/* ⚠️ BOTH AXES ARE THE PICTURE'S OWN, and only one of them ever bites: upright the band is
	   narrower than the photograph so the crop takes the sides (x), turned sideways it is WIDER so
	   the crop takes top and bottom (y) and x does nothing. inc/page-head.php, bnsgc_focus_y(). */
	background-position: var(--bns-focus-x, 50%) var(--bns-focus-y, 45%);
	opacity: 0;
	transition: opacity 1.5s ease-in-out;
	backface-visibility: hidden;
}
body.bns-head-full .bns-page-head .bns-kb__f.is-on,
.bns-hero .bns-kb__f.is-on { opacity: 1; z-index: 2; }

/* ⚠️ A CROSS-DISSOLVE IS ONE PICTURE FADING IN OVER A SOLID ONE, NOT TWO PICTURES FADING AT ONCE
   (2026-10-08, Martin: "they look jumpy"). Until now the outgoing layer faded out while the
   incoming faded in, so at the midpoint each was at half strength and a quarter of whatever lay
   beneath showed through: the featured image, the SAME photograph as slide one, running its own
   26s zoom at a different scale and position. Measured on /est-1904/: underlayer at scale 1.057,
   the live slide at 1.061 panned 28px. A third, moving copy of a picture ghosting through every
   fade is what the eye reports as a jump. NOW: the outgoing layer keeps `.is-under` (solid, below)
   until the incoming has finished fading in above it, then is dropped out of sight beneath an
   opaque layer. Nothing under the slideshow is ever seen after the first picture is up.
   ⚠️ `transition: none` here is load-bearing: the class is added at the instant `.is-on` is
   removed, and the layer must not begin a fade-out it would otherwise start that frame. */
body.bns-head-full .bns-page-head .bns-kb__f.is-under,
.bns-hero .bns-kb__f.is-under { opacity: 1; z-index: 1; transition: none; }

/* ═══ THE AGED TINT (a comparison, 2026-10-08) ═════════════════════════════════════════════════
   inc/sepia.php: on a page with the switch on (body.bns-sepia) the black and white photographs,
   and only those, carry a 35% sepia. Three targets, one strength. A slideshow layer the script
   marked; a letterbox head whose featured image is black and white (the picture is ::before's
   background, so the filter goes on the pseudo-element: its scrim is in the same layer and a
   sepia on a dark gradient is nothing); an inline picture the content filter marked.
   ⚠️ The filter lands on the compositor like opacity does, so the drift and the fade are
   unaffected; measured, not assumed, on the war page's three slides. */
:root { --bns-sepia: .35; }
body.bns-sepia .bns-kb__f--mono,
body.bns-sepia img.bns-mono { filter: sepia(var(--bns-sepia)); }
body.bns-sepia.bns-sepia-head .bns-page-head::before { filter: sepia(var(--bns-sepia)); }

/* ⚠️ THE DRIFT IS ONE-WAY, LINEAR, AND STARTS AS THE PICTURE STARTS TO FADE IN (2026-09-18).
   Martin, relaying the club: "a little stuttery at the start and on one or two clips, and they
   don't start until the transition finishes". The previous version ran a 14s ease-in-out
   ALTERNATE loop on every layer all the time. Two faults followed from that, both by design:
     - EASE-IN-OUT STOPS AT EACH END. With `alternate`, every layer is motionless at its turnaround
       once every 14s, and a 6s slide lands on one of those moments often. That slide fades in
       looking parked and only gets going afterwards: exactly "doesn't start until the transition
       finishes".
     - The layer's position in its loop was wherever the clock happened to be, so no two slides
       moved alike and some barely moved at all while visible.
   NOW: band-video.js adds `.is-drift` at the moment it adds `.is-on`, which restarts this one-shot
   animation from its first frame. It runs LINEAR, so the speed is the same from the first visible
   frame to the last, and it lasts 8s: the 1.5s fade in, the 6s on screen and the 1.5s fade out
   (7.5s) with a little over, so the picture is still moving as it disappears.
   ⚠️ `.is-drift` IS REMOVED ONLY AFTER THE FADE OUT HAS FINISHED, never together with `.is-on`.
   That is the whole point of it being a separate class: dropping the animation while the layer is
   still visible would snap the transform back mid-fade, which is the jolt the old comment here
   warned about. `both` holds the last frame in the gap, so nothing moves while it is unseen.
   ⚠️ will-change ONLY ON THE LAYERS IN PLAY. Six full screen layers each promoted at 112% is a
   lot of video memory on a phone for pictures nobody can see; only the incoming and outgoing layer
   need it.
   Alternating direction by position (in on odd, out on even) stops six slides all sliding the same
   way, which reads as a camera fault rather than as a composition.
   ⚠️ If the slide interval in band-video.js changes, this 8s has to move with it: it must cover
   fade in + interval + fade out, or the picture stops before it has gone. */
body.bns-head-full .bns-page-head .bns-kb__f.is-drift,
.bns-hero .bns-kb__f.is-drift {
	animation: bns-kb-drift-a 8s linear both;
	will-change: transform, opacity;
}
body.bns-head-full .bns-page-head .bns-kb__f.is-drift:nth-child(even),
.bns-hero .bns-kb__f.is-drift:nth-child(even) {
	animation-name: bns-kb-drift-b;
}

/* ⚠️ THE SCALE NEVER DROPS BELOW 1, the same rule the letterbox zoom already obeys: at 0.99 the
   layer would show the band's own flat colour at its edges for the whole cycle. The translate is
   what makes it a pan rather than a zoom, and 2.5% is the measured ceiling described above. */
/* ⚠️ THE PAN MUST STAY INSIDE THE OVERHANG THE ZOOM CREATES, and this is arithmetic, not taste.
   scale(1.12) makes the layer 112% of the band, so there is 6% spare at each edge. Transform
   functions apply in the order written, so the translate happens in the SCALED coordinate space:
   a 4% translate is really 4 x 1.12 = 4.48% of the band. 4.48 against 6 leaves about 1.5% in
   hand. Push the translate to 5% and it becomes 5.6% against 6, which is a quarter of a percent
   from showing the band's flat colour along one edge for part of every cycle.
   ⚠️ SO THE TWO NUMBERS MOVE TOGETHER. Raising the translate without raising the scale is how
   this breaks, and it breaks intermittently, on one edge, mid-animation, which is the hardest
   kind of fault to catch by looking. */
@keyframes bns-kb-drift-a {
	from { transform: scale(1.00) translate3d(0, 0, 0); }
	to   { transform: scale(1.12) translate3d(-4%, -2%, 0); }
}
@keyframes bns-kb-drift-b {
	from { transform: scale(1.12) translate3d(4%, 2%, 0); }
	to   { transform: scale(1.00) translate3d(0, 0, 0); }
}

/* ⚠️ Motion is an enhancement, never the content. With reduced motion the script shows the FIRST
   slide and never rotates, so this only has to stop the drift. The band is then exactly what it
   would have been with a single featured image, which is a complete page and not a broken one. */
@media (prefers-reduced-motion: reduce) {
	body.bns-head-full .bns-page-head .bns-kb__f,
.bns-hero .bns-kb__f {
		transition: none;
		animation: none !important;
		transform: none !important;
	}
}

/* A line per picture under the title (2026-09-28). band-video.js adds `.has-lines` only when at
   least one picture in the slideshow has a caption, so a page without captions never matches.
   ⚠️ STACKED IN ONE GRID CELL: the box is as tall as the longest line, and only opacity moves,
   so nothing below the line shifts as the pictures change. The fade matches the slides' 1.5s.
   ⚠️ NEW CLASSES ON PURPOSE. `.bns-hero__kicker` and `.bns-band__lede` are shared with every page
   head, and this only ever adds to them through `.has-lines`, never redefines them. */
.bns-hero .has-lines,
body.bns-head-full .bns-page-head .has-lines {
	display: grid;
}
/* ⚠️ OUT, THEN IN (2026-10-16, the club: the text transition "wasn't 100% fluid"). Both lines used to
   fade over the same 1.5s, so for most of it two sentences sat on top of each other at half strength.
   Now the outgoing line goes in .6s and the incoming one starts as it finishes, over .9s: still 1.5s
   in all, matching the pictures, and never two lines legible at once. The removed class takes the
   base rule (no delay); the added class takes the .is-on rule (with the delay). */
.has-lines > .bns-line {
	grid-area: 1 / 1;
	opacity: 0;
	transition: opacity .6s ease;
}
.has-lines > .bns-line.is-on { opacity: 1; transition: opacity .9s ease .6s; }
@media (prefers-reduced-motion: reduce) {
	.has-lines > .bns-line { transition: none; }
}
/* The home line stays on ONE line (2026-10-05, the club: "make sure all one liners are on the same
   text line rather than rolling onto a second"). From 700px a line of up to about 60 characters
   fits beside the gutter at this size; the five in use are 52 to 59. Below that no readable size
   fits a phone, so the line wraps and `balance` makes the two halves even.
   ⚠️ A CAPTION MUCH LONGER THAN 60 CHARACTERS WILL RUN OFF A 700px SCREEN. Captions are the club's
   to edit in the media library, so re-check the narrow end if one grows. */
/* ⚠️ ONE LINE REACHES PAST THE SHADING. The scrim is darkest at the left and fades by mid-screen;
   a 46ch line stayed inside it and a full line does not. Measured on staging 2026-10-05, the line
   alone read 2.41:1 over the 1963 photograph and 3.09:1 over the aerial on a tablet. It carried a
   backing chip for a day; the club asked for it to go (2026-10-06, "remove the darker background
   on the white lettering"), so the LEFT SHADING now reaches further right instead: see .bns-hero
   --cl stops. Re-measure every home slide when a picture changes. */
.bns-hero__kicker { text-wrap: balance; }
@media (min-width: 700px) {
	.bns-hero__kicker { max-width: none; white-space: nowrap; }
}

/* The words sit at the bottom now, so the scrim is a BOTTOM band first and a left column
   second, where the letterbox is a left column only. The third gradient is the ~130px band
   behind the fixed header: the glass alone cannot carry white text over a bright frame. */
body.bns-head-full .bns-page-head::after {
	background:
		linear-gradient(to top,
			rgba(6, 10, 14, calc(.62 * var(--bns-full-scrim))) 0%,
			rgba(6, 10, 14, calc(.34 * var(--bns-full-scrim))) 38%, rgba(6, 10, 14, 0) 72%),
		linear-gradient(to right,
			rgba(6, 10, 14, calc(.52 * var(--bns-full-scrim))) 0%,
			rgba(6, 10, 14, calc(.22 * var(--bns-full-scrim))) 52%, rgba(6, 10, 14, 0) 88%),
		linear-gradient(to bottom,
			rgba(6, 10, 14, .52) 0px, rgba(6, 10, 14, .29) 96px, rgba(6, 10, 14, 0) 150px);
}

/* Type at hero scale. ⚠️ These track `.bns-hero h1` and were reduced with it on 2026-09-16;
   if that one moves again, move this one too or the two shapes stop matching. */
body.bns-head-full .bns-page-head h1 {
	font-size: clamp(35px, 5.4vw, 64px);
	max-width: 15ch;
	text-shadow: 0 2px 26px rgba(0, 0, 0, .42);
}
body.bns-head-full .bns-page-head .bns-band__lede {
	font-size: clamp(16px, 1.7vw, 19px);
	max-width: 46ch;
	text-shadow: 0 1px 14px rgba(0, 0, 0, .5);
}
/* ⚠️ THIS BEATS .bns-page-head--display, which is what we want: 1904's oversized title is a
   LETTERBOX treatment, and a page set to full screen is asking for the hero's proportions. */

/* Landscape phone and tablet: the band fits the viewport, min-height must not win. Mirrors
   the identical rule on .bns-hero. */
@media (orientation: landscape) and (max-height: 620px) {
	body.bns-head-full .bns-page-head { min-height: 0; }
}
@media (max-height: 620px) and (min-width: 621px) {
	body.bns-head-full .bns-page-head h1 { font-size: clamp(28px, 4.2vw, 42px); }
	body.bns-head-full .bns-page-head .bns-band__lede { font-size: 16px; }
	body.bns-head-full .bns-page-head .bns-cue { display: none; }
	/* the cue is gone, so its reserved lane goes with it */
	body.bns-head-full .bns-page-head { padding-bottom: clamp(20px, 3vw, 34px); }
}
/* Below 900 the copy spans nearly the full width, so a left column scrim leaves the right end
   of every line unprotected. Keeping the right of the frame clear is a wide screen idea: on a
   phone the picture is cropped hard and there is no "rest of frame" to save. Same reasoning,
   and the same breakpoint, as .bns-hero. */
@media (max-width: 900px) {
	body.bns-head-full .bns-page-head::after {
		background:
			linear-gradient(to top,
				rgba(6, 10, 14, calc(.78 * var(--bns-full-scrim))) 0%,
				rgba(6, 10, 14, calc(.70 * var(--bns-full-scrim))) 28%,
				rgba(6, 10, 14, calc(.48 * var(--bns-full-scrim))) 56%,
				rgba(6, 10, 14, calc(.15 * var(--bns-full-scrim))) 78%, rgba(6, 10, 14, 0) 100%),
			linear-gradient(to bottom,
				rgba(6, 10, 14, .52) 0px, rgba(6, 10, 14, .29) 96px, rgba(6, 10, 14, 0) 150px);
	}
}

/* Four routes, because there are four ways in. The live site funnels all of them into one form
   that emails three people at once. */
.bns-routes {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(238px, 1fr));
	gap: 20px;
	margin-top: 34px;
}
.bns-route {
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--paper);
	padding: 24px 22px;
	display: flex;
	flex-direction: column;
}
.bns-route h3 { font-size: 19px; }
.bns-route p { font-size: 15px; color: var(--ink-soft); margin-top: 8px; }
.bns-route__lines { margin-top: auto; padding-top: 16px; display: flex; flex-direction: column; gap: 5px; }
.bns-route a { font-weight: 500; font-size: 15px; overflow-wrap: anywhere; }
/* The phone option is the useful bit: "option 1" is what gets you to the right person, and it
   is the one thing the current site buries inside paragraphs on other pages entirely. */
.bns-route__opt {
	display: inline-block;
	margin-top: 2px;
	font: 600 11px/1 var(--body);
	letter-spacing: .13em;
	text-transform: uppercase;
	color: var(--accent-deep);
	background: var(--surface);
	border: 1px solid var(--line);
	border-radius: 999px;
	padding: 6px 10px;
	align-self: flex-start;
}

/* Details beside the form. Collapses to one column early: a form squeezed into half a tablet is
   worse than a form with the width to itself. */
.bns-contact-grid {
	display: grid;
	grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
	gap: clamp(28px, 4.5vw, 64px);
	align-items: start;
	margin-top: 34px;
}
.bns-detail { margin: 0; }
.bns-detail dt {
	font: 600 11px/1 var(--body);
	letter-spacing: .14em;
	text-transform: uppercase;
	color: var(--accent-deep);
	margin-top: 22px;
}
.bns-detail dt:first-child { margin-top: 0; }
.bns-detail dd { margin: 7px 0 0; font-size: 16.5px; line-height: 1.55; }
.bns-detail dd a { font-weight: 500; }
.bns-detail__sub { margin-top: 34px; }

/* Opening hours as a real description list, not a table: these are label to value pairs, and a
   table would promise columns that do not exist. Today's row is marked so the commonest
   question, "are they open now", is answerable at a glance. Marked by JS, see home.js. */
.bns-hours { margin: 12px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 0 18px; font-size: 16px; }
.bns-hours dt { font-weight: 500; padding: 7px 0; border-bottom: 1px solid var(--line); }
.bns-hours dd { margin: 0; padding: 7px 0; border-bottom: 1px solid var(--line); color: var(--ink-soft); text-align: right; }
.bns-hours .is-today dt,
.bns-hours .is-today dd { color: var(--ink); font-weight: 600; }
.bns-hours > div { display: contents; }
.bns-hours__note { margin-top: 16px; font-size: 14px; color: var(--ink-soft); }

/* Form. Posts to the digenie-forms endpoint: same-origin, honeypot and rate limit server-side,
   destination set on the host and never in the page. */
.bns-form-card {
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--paper);
	padding: clamp(22px, 3vw, 32px);
}
.bns-form-card__h { font-size: clamp(24px, 3vw, 32px); margin-top: 8px; }
.bns-field { margin-top: 18px; }
.bns-field:first-of-type { margin-top: 0; }
/* The event-details group on Contact us (2026-10-16). Its first field is the first div in the GROUP, so
   the rule above would take its margin; it follows the field before it like any other. */
.bns-field-group > .bns-field:first-of-type { margin-top: 18px; }
.bns-field label { display: block; font: 600 13px/1.3 var(--body); letter-spacing: .02em; color: var(--ink); }
.bns-field__opt { font-weight: 400; color: var(--ink-soft); }
.bns-field input,
.bns-field select,
.bns-field textarea {
	width: 100%;
	margin-top: 7px;
	padding: 12px 13px;
	font: 400 16px/1.45 var(--body);
	color: var(--ink);
	background: var(--paper);
	border: 1px solid var(--line);
	border-radius: 7px;
}
.bns-field input:focus-visible,
.bns-field select:focus-visible,
.bns-field textarea:focus-visible {
	outline: 3px solid var(--accent);
	outline-offset: 2px;
	border-color: var(--accent);
}
.bns-field__hint { display: block; margin-top: 6px; font-size: 13px; color: var(--ink-soft); }
/* The honeypot must be unreachable, not merely invisible: display:none would hide it from a bot
   reading the DOM too, and off-screen keeps it fillable by the bots this is meant to catch,
   while tabindex="-1" and aria-hidden keep real users and screen readers out of it. */
.bns-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }
.bns-form-card .bns-btn { margin-top: 22px; }
.bns-form-status { margin-top: 14px; font-size: 15px; color: var(--ink-soft); min-height: 1.5em; }

/* Map. aspect-ratio rather than a fixed height, so it never letterboxes on a phone. */
.bns-map {
	margin-top: 34px;
	border: 1px solid var(--line);
	border-radius: var(--radius);
	overflow: hidden;
	aspect-ratio: 16/7;
	background: var(--surface);
}
/* The map is a keyboard stop (a third-party frame), so it shows where focus is like every other one
   (2026-10-16: the go-live audit's one focus-visible failure, on Contact us). */
.bns-map iframe:focus-visible, .bns-map iframe:focus { outline: 3px solid var(--accent); outline-offset: -3px; }   /* inside: .bns-map clips its overflow */
/* Chrome does not apply :focus to a cross-site frame while focus is inside it, so nav.js marks the
   container instead, and the ring is drawn round the map from outside. */
.bns-map.is-focused { outline: 3px solid var(--accent); outline-offset: 3px; }
.bns-map iframe { width: 100%; height: 100%; border: 0; display: block; }

@media (max-width: 900px) {
	.bns-contact-grid { grid-template-columns: 1fr; gap: 34px; }
	.bns-map { aspect-ratio: 4/3; }
}
@media (max-width: 620px) {
	.bns-routes { grid-template-columns: 1fr; }
}

/* ═══ PAGE: GREEN FEES ════════════════════════════════════════════════════════════════════
   Ported from docs/prototypes/green-fees.html (2026-09-15). Page-specific names prefixed, for
   the reason recorded on the contact block: the inherited layer owns an unscoped .cta that is a
   full-width dark gradient band, and these pages use it for a plain row of two buttons. */

/* Seasons side by side. The club's base rate card went in on 2026-10-07 (loop A4), condensed to
   day-and-time bands; the labelled hole that stood here until then (.bns-rate-hole) is gone with
   it. The label is allowed to wrap, the price never is: "Monday to Friday, tee times to 3.59pm" is
   two lines at 390px and its £45 stays on the first. */
.bns-seasons { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 22px; margin-top: 30px; }
.bns-season { border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper); padding: 26px 24px; }
.bns-season .bns-eyebrow { color: var(--accent-deep); }
.bns-season h3 { font-size: 21px; margin-top: 8px; }
.bns-season__when { font-size: 14px; color: var(--ink-soft); margin-top: 6px; }
.bns-season ul { list-style: none; padding: 0; margin: 18px 0 0; border-top: 1px solid var(--line); }
.bns-season li {
	display: flex;
	justify-content: space-between;
	gap: 14px;
	align-items: baseline;
	padding: 10px 0;
	border-bottom: 1px solid var(--line);
	font-size: 15.5px;
}
.bns-season li span:first-child { flex: 1 1 auto; }
.bns-season li span:last-child { color: var(--ink-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Rules that apply whatever the season. ⚠️ The live site repeats all six TWICE, once under each
   season's table. Said once, above both, they stop being noise, and there is then one place to
   change them. */
.bns-rules { display: grid; grid-template-columns: repeat(auto-fit, minmax(248px, 1fr)); gap: 20px; margin-top: 30px; }
.bns-rule { border-left: 3px solid var(--accent); padding: 4px 0 4px 16px; }
.bns-rule h3 { font-size: 16.5px; }
.bns-rule p { font-size: 15px; color: var(--ink-soft); margin-top: 7px; line-height: 1.6; }

/* Restrictions read as a timetable, because that is what they are. */
.bns-restrict { margin: 26px 0 0; display: grid; grid-template-columns: auto 1fr; gap: 0 20px; max-width: 560px; }
.bns-restrict dt { font-weight: 600; font-size: 15.5px; padding: 11px 0; border-bottom: 1px solid var(--line); }
.bns-restrict dd {
	margin: 0;
	padding: 11px 0;
	border-bottom: 1px solid var(--line);
	color: var(--ink-soft);
	font-size: 15.5px;
	text-align: right;
	font-variant-numeric: tabular-nums;
}
.bns-restrict > div { display: contents; }
.bns-restrict__note { margin-top: 16px; font-size: 14.5px; color: var(--ink-soft); max-width: var(--prose); }

.bns-hire__h { margin-top: 38px; font-size: 19px; }
.bns-hire { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }
.bns-hire span { border: 1px solid var(--line); border-radius: 999px; padding: 9px 16px; font-size: 14.5px; background: var(--paper); }

/* Shared by green fees and events: a plain row of two buttons. NOT the inherited .cta band. */
.bns-cta { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 30px; }

@media (max-width: 620px) {
	.bns-restrict { grid-template-columns: 1fr; gap: 0; }
	.bns-restrict dd { text-align: left; padding-top: 0; border-bottom: none; }
	.bns-restrict dt { border-bottom: none; padding-bottom: 2px; }
	.bns-restrict > div { display: block; padding: 10px 0; border-bottom: 1px solid var(--line); }
}

/* ═══ PAGE: YOUR EVENT VENUE ══════════════════════════════════════════════════════════════
   Ported from docs/prototypes/events.html (2026-09-15).

   ⚠️ CAPACITIES ARE THE CLUB'S OWN ANSWER (loop A2, 2026-09-13): three rooms, 100 / 40 / 20.
   The live site contradicts itself four ways about this. No number here is invented. */
.bns-rooms { display: grid; grid-template-columns: repeat(auto-fit, minmax(272px, 1fr)); gap: 22px; margin-top: 32px; }
.bns-room {
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--paper);
	display: flex;
	flex-direction: column;
	overflow: hidden;
}
/* ⚠️ Two of these three pictures DO NOT EXIST (the lounge has the club's own photograph). The
   missing two are drawn as labelled holes so the gap is visible rather than papered over. See
   docs/image-guidance.md. A slot holding a real photograph takes --photo. */
.bns-room__media {
	aspect-ratio: 4/3;
	background: var(--surface);
	border-bottom: 2px dashed var(--accent);
	display: grid;
	place-content: center;
	text-align: center;
	gap: 6px;
	padding: 20px;
}
.bns-room__media b { font: 600 10px/1 var(--body); letter-spacing: .16em; text-transform: uppercase; color: var(--accent-deep); }
.bns-room__media span { font-size: 13px; color: var(--ink-soft); max-width: 30ch; line-height: 1.5; }
/* overflow:hidden (2026-10-16): aspect-ratio only sets a MINIMUM height, so an upright photograph (the
   chef box's plate of food) grew the box to 3:4. Clipping makes the 4:3 hold; the three 4:3 room
   photographs are unchanged. */
.bns-room__media--photo { display: block; padding: 0; border-bottom: 0; background: none; overflow: hidden; }
.bns-room__media--photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* A room box that is one link as a whole (the chef box on Food and events, 2026-10-16). The same
   behaviour as the cards' (.bns-card__more), on its own class because .bns-room is not a card: the
   primary link's ::before is stretched over the box, the arrow and title move on hover, focus shows on
   the box, and any other link in it sits above the stretched layer and still works. */
.bns-room--link { position: relative; }
.bns-room--link .bns-room__more { font-weight: 600; color: var(--accent-deep); text-decoration: none; display: inline-flex; align-items: center; gap: 8px; min-height: 44px; }
.bns-room--link .bns-room__more::before { content: ""; position: absolute; inset: 0; }
.bns-room--link .bns-room__more::after { content: "\2192"; transition: transform .15s ease; }
.bns-room--link:hover .bns-room__more { text-decoration: underline; }
.bns-room--link:hover .bns-room__more::after { transform: translateX(4px); }
.bns-room--link:hover h3 { color: var(--brand); }
.bns-room--link:focus-within { outline: 2px solid var(--brand); outline-offset: 2px; }
.bns-room--link a:not(.bns-room__more) { position: relative; z-index: 1; }
@media (prefers-reduced-motion: reduce) { .bns-room--link .bns-room__more::after { transition: none; } }
.bns-room__txt { padding: 22px 22px 24px; display: flex; flex-direction: column; flex: 1; }
.bns-room h3 { font-size: 20px; }
.bns-room__cap { margin-top: 8px; font: 600 13px/1 var(--body); letter-spacing: .06em; color: var(--accent-deep); }
.bns-room p { font-size: 15px; color: var(--ink-soft); margin-top: 11px; line-height: 1.6; }
.bns-room ul { list-style: none; padding: 0; margin: 14px 0 0; }
.bns-room li { font-size: 14px; color: var(--ink-soft); padding-left: 18px; position: relative; margin-top: 6px; }
.bns-room li::before {
	content: "";
	position: absolute;
	left: 0;
	top: .55em;
	width: 7px;
	height: 7px;
	border-radius: 50%;
	background: var(--accent);
}

/* ═══ PAGE: OUR CHEF (2026-10-13, loop R60) ════════════════════════════════════════════════
   Matt's portrait beside his own words. The portrait stays in view while the letter scrolls on a
   wide screen, so the face and the words are read together; on a phone it comes first, held to a
   column so it does not fill the screen. */
.bns-meet {
	display: grid;
	grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
	gap: clamp(28px, 5vw, 72px);
	align-items: start;
}
.bns-meet__portrait { position: sticky; top: calc(var(--hdr) + 24px); }
.bns-meet__letter { max-width: 60ch; }
.bns-meet__letter h2 { margin-top: 10px; }
.bns-meet__letter p:not(.bns-eyebrow) { margin-top: 1.05em; line-height: 1.7; }
.bns-meet__letter .bns-meet__lede {
	margin-top: 22px;
	font-family: var(--display);
	font-size: clamp(20px, 2.2vw, 24px);
	line-height: 1.45;
	color: var(--ink);
}
.bns-meet__sign {
	font-family: var(--display);
	font-size: clamp(26px, 3vw, 32px);
	font-style: italic;
	color: var(--accent-deep);
}
@media (max-width: 860px) {
	.bns-meet { grid-template-columns: 1fr; }
	.bns-meet__portrait { position: static; max-width: 420px; }
}

/* The Christmas menu: the words as text, the club's card beside them as the picture it is. */
.bns-xmas {
	display: grid;
	grid-template-columns: minmax(0, 7fr) minmax(0, 5fr);
	gap: clamp(28px, 5vw, 72px);
	align-items: start;
}
.bns-xmas__menu h2 { margin-top: 10px; }
.bns-xmas__price { margin-top: 12px; font: 600 clamp(18px, 2vw, 21px)/1.3 var(--body); letter-spacing: .02em; color: var(--accent-deep); }
.bns-xmas__menu h3 { margin-top: 34px; padding-bottom: 8px; border-bottom: 1px solid var(--line); font-size: 21px; }
.bns-xmas__list { list-style: none; padding: 0; margin: 4px 0 0; }
.bns-xmas__list li { padding: 12px 0; border-bottom: 1px solid var(--line); }
.bns-xmas__list b { display: block; font-weight: 600; color: var(--ink); }
.bns-xmas__list span { display: block; margin-top: 3px; font-size: 15px; font-style: italic; color: var(--ink-soft); }
.bns-xmas__note { margin-top: 12px; font-size: 15px; font-style: italic; color: var(--ink-soft); }
.bns-xmas__card { margin: 0; position: sticky; top: calc(var(--hdr) + 24px); }
.bns-xmas__card .bns-zoom { display: block; border-radius: var(--radius); overflow: hidden; }
.bns-xmas__card .bns-zoom::after { content: "Enlarge"; }
.bns-xmas__card img { display: block; width: 100%; height: auto; }
.bns-xmas__card .bns-zoom:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
@media (max-width: 860px) {
	.bns-xmas { grid-template-columns: 1fr; }
	.bns-xmas__card { position: static; max-width: 420px; }
}

.bns-occasions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 26px; }
.bns-occasions span { border: 1px solid var(--line); border-radius: 999px; padding: 9px 16px; font-size: 14.5px; background: var(--paper); }

/* Accessibility is a FACT about the building, not a footnote. The source mentions the stair-lift
   in passing, mid-paragraph, in a sentence about which floor the rooms are on. */
.bns-access { margin-top: 30px; border-left: 3px solid var(--accent); padding: 6px 0 6px 18px; max-width: var(--prose); }
.bns-access h3 { font-size: 17px; }
.bns-access p { font-size: 15px; color: var(--ink-soft); margin-top: 7px; line-height: 1.6; }

.bns-catering { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 22px; margin-top: 30px; }
.bns-cater { border-left: 3px solid var(--accent); padding: 4px 0 4px 16px; }
.bns-cater h3 { font-size: 16.5px; }
.bns-cater p { font-size: 15px; color: var(--ink-soft); margin-top: 7px; line-height: 1.6; }

/* ═══ PAGE: HERITAGE / PROSE ══════════════════════════════════════════════════════════════
   .bns-prose existed as a WIDTH only (max-width:var(--prose)) and set no rhythm, so ported
   prose sections rendered as paragraphs jammed together. Spacing lives here rather than on a
   bare `p` rule: a bare rule would reach every paragraph in every pattern on the site. */
.bns-prose > * + * { margin-top: 1.05em; }
.bns-prose p { font-size: 16.5px; color: var(--ink-soft); line-height: 1.7; }
.bns-prose strong { color: var(--ink); font-weight: 600; }
.bns-prose + .bns-figures,
.bns-prose + .bns-hole { margin-top: 34px; }

/* ═══ PAGE: SCORECARD ═════════════════════════════════════════════════════════════════════
   A scorecard is genuinely tabular data, so it is a <table> with real <th scope> and a
   <caption>. That is not a style choice: a screen reader announcing "hole 5, white, 432,
   par 4, stroke index 1" depends entirely on the header association being declared.

   ⚠️ THE WRAPPER IS FOCUSABLE ON PURPOSE. A table wider than a phone scrolls horizontally,
   and a scroll container that only a mouse can reach fails WCAG 2.1.1. tabindex="0" on the
   wrapper is what lets a keyboard user scroll it, and it therefore needs a visible focus ring.
   The table is allowed to overflow its band; nothing else on these pages is. */
.bns-tbl-wrap { margin-top: 28px; overflow-x: auto; border-radius: var(--radius); border: 1px solid var(--line); }
.bns-tbl-wrap:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: 2px; }
.bns-tbl { width: 100%; min-width: 420px; border-collapse: collapse; background: var(--paper); font-size: 15px; }
.bns-tbl th,
.bns-tbl td {
	padding: 9px 14px;
	border-bottom: 1px solid var(--line);
	text-align: right;
	font-variant-numeric: tabular-nums;
}
.bns-tbl thead th {
	position: sticky;
	top: 0;
	background: var(--surface);
	font: 600 12px/1.2 var(--body);
	letter-spacing: .1em;
	text-transform: uppercase;
	color: var(--accent-deep);
	white-space: nowrap;
}
.bns-tbl th[scope="row"] { text-align: left; font-weight: 600; color: var(--ink); white-space: nowrap; }
.bns-tbl tbody tr:last-child th,
.bns-tbl tbody tr:last-child td { border-bottom: 0; }
/* Out and In are subtotals, the Total is the answer. Two weights, so the eye lands on the
   right row without reading the labels. */
.bns-tbl tbody tr.is-total { background: var(--surface); }
.bns-tbl tbody tr.is-total th[scope="row"] { color: var(--accent-deep); }
.bns-tbl tbody tr.is-grand { background: var(--brand-deep); }
.bns-tbl tbody tr.is-grand th,
.bns-tbl tbody tr.is-grand td { color: var(--paper); font-weight: 600; border-bottom: 0; }
.bns-tbl--card { min-width: 360px; }
/* A table of sentences, not figures (the cookies policy): every column reads from the left, and a
   long description wraps at the top of its row. Doubled class so it beats .bns-tbl thead th. */
.bns-tbl.bns-tbl--text th,
.bns-tbl.bns-tbl--text td { text-align: left; vertical-align: top; }

/* The tee's colour, as a disc beside its name (Martin, 2026-10-07: "colour indicators next to the tee
   description for white, yellow, red etc", on the planner and the scorecard). The name stays: the disc
   is a cue for the golfer who knows the course by its markers, never the only carrier, so it is
   aria-hidden everywhere it appears. One class per colour, used on the planner card rows, the
   scorecard rating rows, the tab buttons and the tab titles. White gets a ring so it shows on paper;
   Gold is the deeper tone so it reads apart from Yellow at 12px. */
.bns-tee {
	display: inline-block;
	width: .8em;
	height: .8em;
	margin-right: .45em;
	border-radius: 50%;
	vertical-align: -.05em;
	border: 1px solid rgba(0, 0, 0, .28);
	box-sizing: border-box;
}
.bns-tee--white { background: #fff; border-color: #7a7a7a; }
.bns-tee--yellow { background: #f2d335; }
.bns-tee--black { background: #1c1c1c; border-color: #1c1c1c; }
.bns-tee--gold { background: #c8962e; }
.bns-tee--red { background: #c62828; border-color: #a31f1f; }
.bns-tbl thead th .bns-tee { vertical-align: -.1em; }
/* The tab is a one-cell grid (place-items: center), which stacks each disc above the words. Flex, on
   the same centre line, keeps them in the row. */
.bns-tabs__nav a:has(.bns-tee) { display: inline-flex; align-items: center; justify-content: center; }
.bns-tabs__nav a .bns-tee { width: .7em; height: .7em; margin-right: .4em; }
.bns-tabs__nav a.is-current .bns-tee--black { border-color: rgba(255, 255, 255, .6); }
.bns-tbl tbody tr.is-grand .bns-tee { border-color: rgba(255, 255, 255, .5); }

@media (max-width: 600px) {
	.bns-tbl th,
	.bns-tbl td { padding: 8px 10px; font-size: 14px; }
}

/* ═══ MASTHEAD OVER A PAGE HEAD ═══════════════════════════════════════════════════════════
   Martin, 2026-09-15: "the page headers should be glass and match how the home page header
   works". The STATE logic is in assets/js/home.js, which used to query '.bns-hero' alone and
   therefore returned early on every inner page, leaving them all solid. It now accepts a page
   head as a glass band too. The LAYOUT consequences are here.

   ⚠️ THE GLASS CREST IS RESIZED, AND THIS IS A COLLISION FIX, NOT A PREFERENCE.
   In the glass state the crest is 140px hanging 33px below a 92px bar, which puts its foot at
   roughly y=149. Over the hero that is free space: a hero is a whole viewport tall and its text
   sits near the bottom. A PAGE HEAD IS ABOUT 360px AND ITS EYEBROW STARTS AROUND y=141, so the
   hero-sized crest lands on the first line of the page. 88px with a 15px drop puts the foot at
   about y=105 and clears it. Those are not new numbers: they are what the tablet breakpoint
   below already uses, so the transition keeps its proportions.

   :has() tests the real condition, a page head being present, rather than inferring it from a
   body class. Verify with tools/check-overlap.mjs, not by eye. */
/* ⚠️ EXCLUDES THE FULL SCREEN BANNER, 2026-09-16, AND THE EXCLUSION IS THE WHOLE POINT OF THE
   RULE. Everything above reasons from "a page head is about 360px", which is what makes the
   big crest land on the page title. A full screen banner is a whole viewport, exactly like the
   hero, so the condition this rule tests for is no longer true there and shrinking the crest
   would be cargo-culting the fix onto the case it was protecting against.
   ⚠️ NARROWED, NOT REDEFINED: the letterbox band keeps this behaviour byte for byte. */
body:not(.bns-head-full):has(.bns-page-head) .masthead:not(.is-solid) { --crest: 88px; --crest-drop: 15px; }

/* ⚠️ THE HOME PAGE'S HERO CREST IS 140px AND IT OVERFLOWS THE BAR. MEASURED, NOT ASSUMED.
   Only the home page failed the 320 to 1600 sweep: the course, event venue, contact and membership
   pages were all clean, and their header markup is byte-identical. The cause is the crest.
   Over a HERO the crest is 140px, and `.brand` reserves calc(crest * .75 + 22px) to sit beside it,
   so the brand is 127px of padding. Over a PAGE HEAD the rule above drops the crest to 88px, and
   the brand to 88px. Measured at 1400px:

     home      brand 369px   row needs 1229 in a 1200 wrap   OVER BY 29
     est-1904  brand 330px   row needs 1190 in a 1200 wrap   fits

   That 39px is precisely the crest difference. So the wordmark has to keep hiding further up the
   range on the hero page, and ONLY there: extending the shared rule to 1464 would strip the
   wordmark from five pages that fit perfectly well.

   ⚠️ SCOPED WITH :has(), the same mechanism the rule above already uses. Keyed to the BIG-CREST
   STATE, not to the home page as such: any future page that opens with a hero inherits the fix.
   ⚠️ Re-swept after changing. A boundary of this kind is measured, never estimated. */
@media (min-width: 1101px) and (max-width: 1507px) {
	/* 1472 to 1507 (2026-10-06): the sweep found 16px over at 1474 to 1506 on the home page. */
	body:has(.bns-hero) .masthead:not(.is-solid) .brand > span {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
		border: 0;
	}
	body.bns-head-full .masthead:not(.is-solid) .brand > span {
		position: absolute;
		width: 1px;
		height: 1px;
		padding: 0;
		margin: -1px;
		overflow: hidden;
		clip-path: inset(50%);
		white-space: nowrap;
		border: 0;
	}
	body:has(.bns-hero) .masthead:not(.is-solid) nav { gap: clamp(12px, 1.2vw, 20px); }
	body:has(.bns-hero) .masthead:not(.is-solid) .bns-wrap { gap: 16px; }
	body.bns-head-full .masthead:not(.is-solid) nav { gap: clamp(12px, 1.2vw, 20px); }
	body.bns-head-full .masthead:not(.is-solid) .bns-wrap { gap: 16px; }
}

/* ⚠️ THE LAST 4px, AND IT IS A SEVEN-PIXEL DEAD BAND. The rule above cleared the hero page's
   1374 to 1464px overflow, and the sweep then reported what was left: `✗ 1102 to 1104px overflows
   by up to 4px`, with "first fit cleanly at: 1108px". The nav is revealed from 1101px (the
   max-width:1100px rule stops there), but on the hero page the 140px crest means the row does not
   actually FIT until 1108. Seven pixels where the nav is shown and does not fit.

   ⚠️ THE GLOBAL 1100 BREAKPOINT IS DELIBERATELY NOT MOVED. assets/js/nav.js carries
   `var MOBILE = '(max-width: 1100px)'` and its own comment says it must match this stylesheet.
   Moving the number here and not there splits the burger's behaviour from the nav's visibility,
   which is how the navigation broke on this site once already. Tightening the gaps costs nothing
   and touches one page.

   4px needed; this frees far more, and only across seven pixels of width on one page. */
@media (min-width: 1101px) and (max-width: 1107px) {
	body:has(.bns-hero) .masthead:not(.is-solid) nav { gap: 10px; }
	body:has(.bns-hero) .masthead:not(.is-solid) .bns-wrap { gap: 10px; }
	body.bns-head-full .masthead:not(.is-solid) nav { gap: 10px; }
	body.bns-head-full .masthead:not(.is-solid) .bns-wrap { gap: 10px; }
}

/* YOUR EVENT VENUE'S CHEVRON (2026-10-13). The venue item became a dropdown for the chef's page, and
   its toggle widened the menu row. sweep-header then reported, on EVERY page type alike: 1102 to
   1146px over by up to 36px, and 1508 to 1554px over by up to 21px. The space between the top-level
   items (1.6vw, about 18px and 24px at those widths) gives it back, inside those two ranges only.
   Proven both ways with the same sweep: the control reproduced both ranges, this cleared them on
   home, a full banner page and a letterbox page. Re-sweep after any change to the menu. */
@media (min-width: 1101px) and (max-width: 1150px) { .masthead .bns-nav { gap: 10px; } }
@media (min-width: 1456px) and (max-width: 1555px) { .masthead .bns-nav { gap: 18px; } }

/* ⚠️ THE BAND MUST REACH y=0, or the glass blurs page background rather than the photograph
   and the top of every inner page shows a pale strip under a transparent bar. Core's
   post-content wrapper carries a top margin; .home already resets it (see the rule above the
   footer block) and this is the same fix for every page that has a page head instead of a hero. */
main:has(.bns-page-head) { margin-block-start: 0; }
main:has(.bns-page-head) > .wp-block-post-content { margin-block-start: 0; }
.bns-page-head:first-child { margin-block-start: 0; }

/* ═══ PRIMARY NAVIGATION ══════════════════════════════════════════════════════════════════
   ⚠️ WHY THIS EXISTS. Until 2026-09-15 the theme shipped a `.burger` with aria-expanded and NO
   HANDLER. Measured on staging at 390 / 768 / 1024px: nav computed display:none, 0 of 6 links
   reachable, burger present, clicking it did nothing. Every phone and tablet visitor had no
   navigation at all, on all fifteen pages. axe-core passed throughout, because a button with
   valid ARIA is all it can see.

   ⚠️ THE `.bns-js` GATE IS THE POINT, NOT A DETAIL. The rule at the 1100px breakpoint above now
   reads `.bns-js .masthead nav{display:none}`. functions.php stamps that class from an inline
   script in the head, so the nav only collapses into the burger WHEN SCRIPTS ARE RUNNING. With
   no JS the links render as a plain stacked list and all six still work. The failure being
   repaired here is exactly what happens when the no-JS state is the broken one. */

.masthead nav ul { list-style: none; margin: 0; padding: 0; }
.bns-nav { display: flex; gap: clamp(14px, 1.6vw, 26px); align-items: center; }
.bns-nav__item { position: relative; display: flex; align-items: center; gap: 2px; }

/* The chevron. A button, not a pseudo-element on the link, because it does a different job from
   the link beside it and needs its own accessible name and its own focus ring. */
.bns-nav__toggle {
	background: none;
	border: 0;
	color: inherit;
	cursor: pointer;
	padding: 10px 6px;
	line-height: 0;
	border-radius: 4px;
}
.bns-nav__toggle::after {
	content: "";
	display: block;
	width: 6px;
	height: 6px;
	border-right: 2px solid currentColor;
	border-bottom: 2px solid currentColor;
	transform: rotate(45deg) translate(-1px, -2px);
	opacity: .75;
	transition: transform .2s ease;
}
.bns-nav__toggle[aria-expanded="true"]::after { transform: rotate(-135deg) translate(-2px, -1px); }
.bns-nav__toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* The dropdown. IT NOW MATCHES THE BAR: glass over a hero or a page head, olive past it
   (Martin, 2026-09-16: "should match the status of the bar - glass or olive").
   ⚠️ THIS REVERSES AN EARLIER DELIBERATE CHOICE, and the reason it was made still stands: this
   panel floats over page content of unknown colour, and a weak translucent panel over a
   photograph is where legible menus go to die. So the glass here is NOT the bar's 40%. The bar
   can be light because it sits on a scrim that was measured; a menu can open over anything. It
   uses a heavy tint plus the same blur, and it keeps its shadow and border so the edges read
   against a busy photograph. Contrast of the link text on it is measured, not assumed. */
.bns-nav__sub {
	position: absolute;
	top: calc(100% + 12px);
	left: -12px;
	min-width: 214px;
	background: var(--shell);
	border: 1px solid rgba(251, 249, 245, .18);
	border-radius: var(--radius);
	padding: 8px;
	box-shadow: 0 16px 38px rgba(12, 18, 26, .38);
	display: none;
	z-index: 60;
	transition: background .32s ease, border-color .32s ease;
}

/* Glass, while the bar is glass. */
.masthead:not(.is-solid) .bns-nav__sub {
	background: rgba(10, 15, 21, .82);
	border-color: rgba(251, 249, 245, .22);
	-webkit-backdrop-filter: blur(16px) saturate(150%);
	backdrop-filter: blur(16px) saturate(150%);
}
/* No backdrop-filter: go nearly solid rather than leave a wash over a photograph. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
	.masthead:not(.is-solid) .bns-nav__sub { background: rgba(10, 15, 21, .95); }
}
/* Olive, past the fold, matching the solid bar. */
.masthead.is-solid .bns-nav__sub { background: var(--shell); }

.bns-nav__sub.is-open { display: block; }
.masthead .bns-nav__sub a {
	display: block;
	padding: 10px 12px;
	border-radius: 5px;
	font-size: 14.5px;
	white-space: nowrap;
	opacity: 1;
}
.masthead .bns-nav__sub a:hover,
.masthead .bns-nav__sub a:focus-visible {
	background: rgba(251, 249, 245, .13);
	text-decoration: none;
}
/* The landing page, first in every menu: "start here". Bolder, an arrow in the crest gold (a mark,
   not text, so the gold's contrast on the olive does not apply), and a rule under it. */
.bns-nav__hub {
	border-bottom: 1px solid rgba(251, 249, 245, .18);
	margin-bottom: 6px;
	padding-bottom: 6px;
}
.masthead .bns-nav__sub .bns-nav__hub a { font-weight: 600; }
.masthead .bns-nav__sub .bns-nav__hub a::after {
	content: "\2192";
	margin-left: 8px;
	color: var(--accent);
}
/* The Visitor information chapters WERE a nested list here (.bns-nav__sub2, 2026-10-07, with a
   phone chevron added 2026-10-08 morning). Removed the same afternoon: the club does not want a
   dropdown inside the dropdown (John Gibson, loop R51: "I just want it to be its own page"). The
   rules are in git before this commit if a third level is ever wanted again. */

/* ── Desktop: the lists open on CLICK, never on hover ──────────────────────────────────────
   Martin, 2026-09-30: clicking a label loads its page AND the list is open when it arrives
   (nav.js remembers which one for exactly one page load). The chevron button beside each label
   opens its list in place. Nothing opens on hover: reverses 2026-09-16's "the drop down should be
   auto not a click".

   ⚠️ WITHOUT SCRIPTS the chevron cannot do anything, so the old hover and focus rules stay for the
   no-JS case only, gated on html:not(.bns-js), and the chevron is drawn on the link instead. Every
   link stays reachable when nav.js fails, the rule this file has held since 2026-09-15. */
@media (min-width: 1101px) {
	html:not(.bns-js) .bns-nav__item--has-sub:hover > .bns-nav__sub,
	html:not(.bns-js) .bns-nav__item--has-sub:focus-within > .bns-nav__sub { display: block; }

	html:not(.bns-js) .bns-nav__toggle { display: none; }
	html:not(.bns-js) .bns-nav__item--has-sub > a::after {
		content: "";
		display: inline-block;
		width: 6px;
		height: 6px;
		margin-left: 7px;
		vertical-align: 2px;
		border-right: 2px solid currentColor;
		border-bottom: 2px solid currentColor;
		transform: rotate(45deg) translate(-1px, -2px);
		opacity: .75;
	}
	/* A hover bridge for the no-JS case, across the 12px gap under the label. */
	html:not(.bns-js) .bns-nav__item--has-sub::after {
		content: "";
		position: absolute;
		top: 100%;
		left: 0;
		right: -12px;
		height: 14px;
	}

	/* With scripts: the label of an open list keeps the hover underline, so it is clear which
	   list is showing. */
	.bns-nav__item--has-sub:has(> .bns-nav__toggle[aria-expanded="true"]) > a {
		opacity: 1;
		text-decoration: underline;
		text-decoration-color: var(--accent);
		text-underline-offset: 7px;
		text-decoration-thickness: 2px;
	}
	.masthead.is-solid .bns-nav__item--has-sub:has(> .bns-nav__toggle[aria-expanded="true"]) > a { text-decoration-color: currentColor; }
}

/* ── The mobile panel ──────────────────────────────────────────────────────────────────── */
@media (max-width: 1100px) {
	.bns-js .masthead nav.is-open {
		display: block;
		position: absolute;
		top: 100%;
		left: 0;
		right: 0;
		background: var(--shell);
		border-top: 1px solid rgba(251, 249, 245, .18);
		padding: 8px var(--gut) 20px;
		/* dvh, not vh: on a phone the browser chrome moves and vh would put the last item
		   under it, which is the one nobody can reach. */
		max-height: calc(100dvh - var(--hdr, 93px));
		overflow-y: auto;
		box-shadow: 0 18px 40px rgba(12, 18, 26, .4);
	}
	.bns-js .masthead nav.is-open .bns-nav { flex-direction: column; align-items: stretch; gap: 0; }
	.bns-js .masthead nav.is-open .bns-nav__item {
		flex-wrap: wrap;
		justify-content: space-between;
		border-bottom: 1px solid rgba(251, 249, 245, .12);
	}
	.bns-js .masthead nav.is-open .bns-nav__item > a { flex: 1; padding: 14px 0; font-size: 16px; }
	.bns-js .masthead nav.is-open .bns-nav__toggle { padding: 14px 10px; }

	/* The sub-list is a full-width accordion here, not a floating panel. */
	.bns-js .masthead nav.is-open .bns-nav__sub {
		position: static;
		width: 100%;
		min-width: 0;
		border: 0;
		box-shadow: none;
		background: rgba(0, 0, 0, .16);
		border-radius: 6px;
		margin: 0 0 12px;
		padding: 4px;
	}
	.bns-js .masthead nav.is-open .bns-nav__sub a { white-space: normal; padding: 11px 12px; }

	/* Scroll lock while the panel is open, so the page behind does not move under a thumb. */
	body.bns-nav-open { overflow: hidden; }
}

/* No JS: the nav is a plain stacked list under the bar rather than a hidden one. Not elegant,
   and deliberately so: every link works, which is the whole requirement. */
@media (max-width: 1100px) {
	.masthead nav { width: 100%; }
	.masthead nav .bns-nav { flex-wrap: wrap; gap: 4px 16px; padding-bottom: 8px; }
	.masthead nav .bns-nav__sub { position: static; display: block; background: none; border: 0;
		box-shadow: none; padding: 0; min-width: 0; }
	.masthead nav .bns-nav__toggle { display: none; }
	.bns-js .masthead nav .bns-nav__toggle { display: block; }
	.bns-js .masthead nav .bns-nav__sub { display: none; }
	.bns-js .masthead nav .bns-nav__sub.is-open { display: block; }
}

/* ═══ THE SECTION BAR ═══════════════════════════════════════════════════════════════════════
   A second row in the masthead on every page of Golf, 1904 or Membership (inc/section-nav.php,
   Martin 2026-09-30). It is part of the header, so --hdr measures it and the page below is padded
   for it. ⚠️ ITS START IS SET FROM THE CREST, like .brand's: the crest hangs below the bar over a
   hero, and a list starting at the wrap's edge would run underneath it. On a phone it is one row
   that scrolls sideways. */
.bns-secnav { border-top: 1px solid rgba(251, 249, 245, .14); }
.bns-secnav__inner {
	max-width: var(--wide);
	margin-inline: auto;
	padding-left: calc(var(--crest) * .75 + 22px);
	transition: padding-left .34s ease;
}
.bns-secnav__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	gap: clamp(16px, 2vw, 26px);
	overflow-x: auto;
	scrollbar-width: none;
	-webkit-overflow-scrolling: touch;
}
.bns-secnav__list::-webkit-scrollbar { display: none; }
.bns-secnav__list li { flex: 0 0 auto; }
/* Where it scrolls, the right edge fades so the row reads as "more this way". */
@media (max-width: 1100px) {
	.bns-secnav__list {
		-webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
		mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
	}
	/* A spacer, not padding-right: a scrolling flex row ignores its end padding, so the last link
	   could never scroll clear of the fade. */
	.bns-secnav__list::after { content: ""; flex: 0 0 36px; }
}
.masthead .bns-secnav a {
	display: block;
	color: inherit;
	text-decoration: none;
	padding: 10px 0 9px;
	font-size: 13.5px;
	font-weight: 500;
	white-space: nowrap;
	opacity: .82;
	text-underline-offset: 6px;
	text-decoration-thickness: 2px;
}
.masthead .bns-secnav a:hover,
.masthead .bns-secnav a[aria-current="page"] {
	opacity: 1;
	text-decoration: underline;
	text-decoration-color: var(--accent);
}
.masthead.is-solid .bns-secnav a:hover,
.masthead.is-solid .bns-secnav a[aria-current="page"] { text-decoration-color: currentColor; }
.masthead .bns-secnav a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; }

/* ═══ THE CLOSING PANEL ═══════════════════════════════════════════════════════════════════
   One panel holding the ask, the buttons and the footnote (Martin, 2026-09-16: "tidy up
   please"). On the CASC page these were three separate blocks stacked under a four-up grid of
   cards, so the ask landed alone on its own line and read as something left over rather than as
   the point of the page.

   Deliberately NOT a variant of .bns-access: this is the END of a page, and it carries a call to
   action. Paper on the surface band so it lifts off the tint rather than dissolving into it. */
.bns-close {
	margin-top: 34px;
	padding: clamp(22px, 3vw, 34px);
	background: var(--paper);
	border: 1px solid var(--line);
	border-left: 3px solid var(--accent);
	border-radius: var(--radius);
	max-width: 74ch;
}
.bns-close h3 { font-size: clamp(20px, 2.4vw, 26px); }
.bns-close p { margin-top: 12px; color: var(--ink-soft); line-height: 1.7; }
.bns-close .bns-cta { margin-top: 22px; }
.bns-close__note { font-size: 14.5px; }

/* ═══ CARD TABS ═══════════════════════════════════════════════════════════════════════════
   The scorecard's four tee cards, as tabs instead of four stacked bands (Martin, 2026-09-16:
   "convert to tabls rather than a long scroll"). The page was around 2,600px of near-identical
   tables, and a reader who wanted one tee scrolled past three they did not.

   ⚠️ EVERY PANEL IS VISIBLE UNTIL assets/js/tabs.js ADDS .is-enhanced. The no-JS page is a long
   scorecard, which is worse-looking and completely readable. The alternative, hiding panels in
   the stylesheet, is a page of four invisible tables the day the script fails. */

/* The tee selector and the units switch share a row: tees left, units right (Martin, 2026-09-16,
   asked for the switch to be repeated down here so the card can be read without scrolling back up).
   ⚠️ THEY SIT SIDE BY SIDE RATHER THAN STACKED ON PURPOSE. Both are rounded pill controls, so one
   row above the other reads as a single group and the units pair looks like a fifth tee.
   They wrap to two lines when there is no room, which is the right failure: the nav scrolls
   horizontally below 560px and needs the full width to do it. */
.bns-tabs__controls {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: space-between;
	gap: 10px 18px;
	margin-bottom: 26px;
}
.bns-tabs__controls .bns-tabs__nav { flex: 1 1 320px; min-width: 0; }
.bns-tabs__controls .bns-tabs__nav ul { margin-bottom: 0; }
.bns-tabs__controls .bns-units { margin: 0; }

.bns-tabs__nav ul {
	list-style: none;
	margin: 0 0 26px;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}
.bns-tabs__nav a {
	display: grid;
	place-items: center;
	min-height: 44px;              /* WCAG 2.2 2.5.8: the primary control on this page. */
	padding: 0 18px;
	border: 1px solid var(--line);
	border-radius: 999px;
	background: var(--paper);
	color: var(--ink);
	text-decoration: none;
	font: 600 15px/1 var(--body);
	white-space: nowrap;
}
.bns-tabs__nav a:hover { border-color: var(--accent); }
.bns-tabs__nav a.is-current {
	background: var(--brand-deep);
	border-color: var(--brand-deep);
	color: var(--paper);
}
.bns-tabs__nav a:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }

.bns-tabs__panel { padding-block: 26px; border-top: 1px solid var(--line); }
.bns-tabs__panel:first-of-type { border-top: 0; padding-top: 0; }
.bns-tabs.is-enhanced .bns-tabs__panel { display: none; border-top: 0; padding-top: 0; }
.bns-tabs.is-enhanced .bns-tabs__panel.is-current { display: block; }

.bns-tabs__title { font-size: clamp(22px, 2.8vw, 30px); margin-top: 6px; }
.bns-tabs__title:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: 4px; }
.bns-tabs__lede { color: var(--ink-soft); line-height: 1.7; margin: 10px 0 20px; max-width: 60ch; }
.bns-tabs .bns-cta { margin-top: 30px; }

/* ⚠️ On a phone the four tees must not wrap into a four-line stack above the card. A single
   scrolling row keeps the table in view, which is the whole point of tabbing this page. */
@media (max-width: 560px) {
	.bns-tabs__nav ul {
		flex-wrap: nowrap;
		overflow-x: auto;
		scroll-snap-type: x proximity;
		padding-bottom: 6px;
		-webkit-overflow-scrolling: touch;
	}
	.bns-tabs__nav li { scroll-snap-align: start; }
	.bns-tabs__nav a { padding: 0 14px; font-size: 14.5px; }
}

/* ═══ COURSE PLANNER ══════════════════════════════════════════════════════════════════════
   The hole-by-hole planner (blocks/course-planner). Reference: Manchester's MGC Pro Planner,
   which Martin pointed at on 2026-09-15.

   ⚠️ ALL EIGHTEEN HOLES ARE IN THE PAGE AND VISIBLE BY DEFAULT. Only `.is-enhanced`, which
   assets/js/planner.js adds, collapses it to one at a time. So a visitor with no JavaScript
   reads a long page rather than an empty one, and a planner meant for use on the course still
   works once loaded, with no connection and no round trip per hole. */

/* ═══ YARDS OR METRES ═════════════════════════════════════════════════════════════════════
   A segmented pair, above the hole picker on the planner and above the ratings table on the
   scorecard. Built on real radio inputs: the input itself is visually hidden but NOT
   display:none, so it keeps its place in the tab order and its focus ring is drawn on the
   label around it.
   ⚠️ The fieldset ships `hidden` and assets/js/units.js reveals it. Without the script the page
   is already in yards, which is the default, so there is nothing for the control to do. */
.bns-units {
	border: 0;
	margin: 0 0 18px;
	padding: 0;
	display: inline-flex;
	gap: 0;
	border-radius: 999px;
	overflow: hidden;
	outline: 1px solid var(--line);
}
.bns-units label {
	position: relative;
	display: grid;
	place-items: center;
	min-height: 44px;              /* the same 44px floor as every other control on the site */
	padding: 0 18px;
	font: 600 14.5px/1 var(--body);
	color: var(--ink-soft);
	cursor: pointer;
	background: var(--paper);
}
.bns-units input {
	position: absolute;
	opacity: 0;
	width: 1px;
	height: 1px;
	margin: 0;
}
.bns-units label:has( input:checked ) {
	background: var(--brand-deep);
	color: var(--paper);
}
.bns-units label:has( input:focus-visible ) {
	outline: 3px solid var(--accent);
	outline-offset: -3px;
}

/* On the scorecard the control sits between the heading and the ratings table, so it governs
   everything below it: a reader meets the switch before the first number it changes. */
.bns-units { margin: 20px 0 0; }
.bns-units + .bns-tbl-wrap { margin-top: 14px; }
.bns-planner .bns-units { margin: 0 0 18px; }

/* The unit, under a heading that names something else: "Out" and "White" are a stretch of holes
   and a tee, not a measurement. ⚠️ Without this the scorecard could swap its numbers to metres
   under a heading that still said nothing, which publishes a wrong distance to every reader. */
.bns-tbl__unit {
	display: block;
	margin-top: 3px;
	font-size: 9.5px;
	font-weight: 600;
	letter-spacing: .12em;
	text-transform: uppercase;
	/* Full strength (2026-10-16): at .72 opacity this 9.5px label failed WCAG contrast (axe, serious)
	   on the scorecard. Its size and spacing already set it apart from the heading above it. */
}

.bns-planner__picker ul {
	list-style: none;
	margin: 0 0 30px;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: 7px;
}
.bns-planner__picker a {
	display: grid;
	place-items: center;
	min-width: 44px;
	min-height: 44px;              /* WCAG 2.2 2.5.8: these are the primary control here. */
	padding: 0 6px;
	border: 1px solid var(--line);
	border-radius: 6px;
	background: var(--paper);
	color: var(--ink);
	text-decoration: none;
	font: 600 15px/1 var(--body);
	font-variant-numeric: tabular-nums;
}
.bns-planner__picker a:hover { border-color: var(--accent); }
.bns-planner__picker a.is-current {
	background: var(--brand-deep);
	border-color: var(--brand-deep);
	color: var(--paper);
}

.bns-planner__hole { padding-block: 34px; border-top: 1px solid var(--line); }
.bns-planner__hole:first-of-type { border-top: 0; padding-top: 0; }
/* Enhanced: one at a time, and the borders that separated a long list stop making sense. */
.bns-planner.is-enhanced .bns-planner__hole { display: none; border-top: 0; padding-top: 0; }
.bns-planner.is-enhanced .bns-planner__hole.is-current { display: block; }

.bns-planner__head h3 { font-size: clamp(24px, 3vw, 34px); margin-top: 0; }
.bns-planner__head h3:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: 4px; }

.bns-planner__body {
	display: grid;
	grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
	gap: clamp(24px, 3.5vw, 48px);
	margin-top: 22px;
	align-items: start;
}
.bns-planner__main > * + * { margin-top: 26px; }
.bns-planner__main h4 {
	font: 600 12px/1 var(--body);
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--accent-deep);
	margin-bottom: 10px;
}
.bns-planner__main p { color: var(--ink-soft); line-height: 1.7; }
.bns-planner__main p + p { margin-top: .9em; }
.bns-planner__story { border-left: 3px solid var(--accent); padding-left: 18px; }

.bns-planner__photos { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 12px; }
.bns-planner__photos img { width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius); display: block; }
/* Each photograph is a lightbox link (.bns-zoom). The generic badge reads "Click to enlarge ⊕",
   too long for a 190px tile, so it is shortened HERE only, as the gallery page does for its own. */
.bns-planner__photos .bns-zoom { border-radius: var(--radius); overflow: hidden; }
.bns-planner__photos .bns-zoom::after { content: "Enlarge"; }
.bns-planner__photos .bns-zoom:focus-visible { outline: 3px solid var(--wp--preset--color--accent); outline-offset: 3px; }

.bns-planner__aside > * + * { margin-top: 20px; }
.bns-planner__diagram { margin: 0; }
.bns-planner__diagram img { width: 100%; height: auto; border-radius: var(--radius); display: block; }

/* ── The four things a hole can carry, each with a place whether it is filled or not ──────────
   Martin, 2026-09-16: "there needs to be somewhere for the flyover video and hole pictures, as
   well as a hole graphic and sponsor". They were always rendered when populated, and nothing is
   populated, so the provision was invisible. An empty slot naming what belongs in it is the same
   convention the rest of this build uses for material the club has not sent.
   ⚠️ The slots are SMALLER than a page-level .bns-hole: four full-size dashed boxes in one panel
   would shout louder than the hole they describe. */
.bns-planner__media h4 {
	font: 600 12px/1 var(--body);
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--accent-deep);
	margin-bottom: 10px;
}
/* ── Picture-shaped placeholders ──────────────────────────────────────────────────────────────
   Martin, 2026-09-16: "can you add a spacer or a image place holder if blank - the same goes for
   video and images". The slots used to be text in a dashed box, so a hole with nothing supplied
   read as a paragraph rather than as a missing picture, and the page RESHAPED when a real image
   finally landed.
   ⚠️ EACH ONE RESERVES THE SHAPE THE REAL THING WILL TAKE, which is why the photographs slot is
   three boxes in the real grid and not one tall box: a single full-width 3:2 box would reserve
   about three times the height the grid actually uses, and over-reserving is its own kind of
   wrong. The film box is capped so a 16:9 frame does not run the full 662px column.
   ⚠️ THE BOXES ARE aria-hidden AND CARRY NO TEXT. The note beneath each one is what names it, so a
   screen reader hears the photographs instruction once rather than three times. The flyover and the
   photographs also have an <h4> above them; the plan and the sponsor do not, which is why the note
   has to name the thing rather than merely describe it.
   ⚠️ THESE MUST NOT SURVIVE GO-LIVE UNFILLED. Honest in a preview, clutter on a published page.
   Martin, 2026-09-16: keep them in place for now. */
.bns-ph {
	border: 2px dashed var(--accent);
	border-radius: 8px;
	min-width: 0;
	background-color: transparent;
	background-repeat: no-repeat, repeat;
	background-position: center, 0 0;
	background-size: 44px 44px, auto;
	background-image:
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Crect x='4' y='9' width='40' height='30' rx='3' fill='none' stroke='%23a88848' stroke-width='2'/%3E%3Ccircle cx='15' cy='19' r='3.5' fill='%23a88848'/%3E%3Cpath d='M8 35l10-11 8 8 5-5 9 8' fill='none' stroke='%23a88848' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E"),
		repeating-linear-gradient(135deg, rgba(168, 136, 72, .05), rgba(168, 136, 72, .05) 9px, transparent 9px, transparent 18px);
}
/* A hole's flyover, playing in the panel. Same 16:9 and the same cap as the empty slot above it
   (.bns-ph--film), so adding a film does not reshape the panel. New class, used only here. */
.bns-planner__film {
	position: relative;
	aspect-ratio: 16 / 9;
	max-width: 560px;
	border-radius: var(--radius);
	overflow: hidden;
	background: var(--wp--preset--color--ink);
}
.bns-planner__film iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
/* "Watch larger": a quiet text control under the film, not a second big button competing with it. */
.bns-planner__enlarge { margin: 8px 0 0; }
.bns-planner__enlarge-btn {
	font: 600 14px/1.2 var(--body);
	color: var(--wp--preset--color--accent-deep);
	background: none;
	border: 0;
	padding: 6px 0;
	min-height: 24px;
	cursor: pointer;
	text-decoration: underline;
	text-underline-offset: 3px;
}
.bns-planner__enlarge-btn:hover { color: var(--wp--preset--color--ink); }
.bns-planner__enlarge-btn:focus-visible { outline: 3px solid var(--wp--preset--color--accent); outline-offset: 2px; }
/* The popped-out player. Its own dialog, NOT .bns-lightbox (photo set, <img>): see planner.js.
   As wide as fits at 16:9 inside 92vw and the screen height LESS room for the close button above it.
   ⚠️ Measured 2026-09-21: sized to 86vh, a phone held sideways (844x390) put the close button at
   y=-21, off the top of the screen, with nothing on screen to close the film. 7rem is the button
   (2.5rem, sitting 3rem above the frame) twice over, so the dialog centres with it visible. */
dialog.bns-filmbox { border: 0; padding: 0; background: transparent; overflow: visible; max-width: none; max-height: none; }
dialog.bns-filmbox::backdrop { background: rgba(0, 0, 0, .88); }
.bns-filmbox__frame {
	position: relative;
	width: min(92vw, calc((100vh - 7rem) * 16 / 9));
	width: min(92vw, calc((100dvh - 7rem) * 16 / 9));
	aspect-ratio: 16 / 9;
	border-radius: var(--radius);
	overflow: hidden;
	background: #000;
}
.bns-filmbox__frame iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }
.bns-filmbox__close {
	position: absolute;
	top: -3rem;
	right: 0;
	width: 2.5rem;
	height: 2.5rem;
	border: 0;
	border-radius: 999px;
	background: #fff;
	color: #000;
	font-size: 1.4rem;
	line-height: 1;
	cursor: pointer;
}
.bns-filmbox__close:focus-visible { outline: 3px solid var(--wp--preset--color--accent); outline-offset: 2px; }
/* A film, not a photograph: the play mark says which of the two is missing. */
.bns-ph--film {
	aspect-ratio: 16 / 9;
	max-width: 560px;
	background-image:
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Ccircle cx='24' cy='24' r='21' fill='none' stroke='%23a88848' stroke-width='2'/%3E%3Cpath d='M20 15l13 9-13 9z' fill='%23a88848'/%3E%3C/svg%3E"),
		repeating-linear-gradient(135deg, rgba(168, 136, 72, .05), rgba(168, 136, 72, .05) 9px, transparent 9px, transparent 18px);
}
.bns-ph--photo { aspect-ratio: 3 / 2; }
/* The drawn plan: a flag on a green, so it is not mistaken for a photograph. */
.bns-ph--plan {
	aspect-ratio: 4 / 3;
	background-image:
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cellipse cx='24' cy='34' rx='16' ry='7' fill='none' stroke='%23a88848' stroke-width='2'/%3E%3Cpath d='M22 33V9l12 5-12 5' fill='none' stroke='%23a88848' stroke-width='2' stroke-linejoin='round'/%3E%3C/svg%3E"),
		repeating-linear-gradient(135deg, rgba(168, 136, 72, .05), rgba(168, 136, 72, .05) 9px, transparent 9px, transparent 18px);
}
/* A sponsor's mark: a logo lockup, so it is not read as a photograph or a drawing.
   ⚠️ 4:1 IS THE SPONSOR LOGO'S OWN SPEC (900x225, docs/image-guidance.md section 3). A placeholder
   that reserves a different shape from the asset it holds space for defeats the point of reserving
   the space at all.
   ⚠️ IT MATCHES THE OTHER SLOTS ON PURPOSE (Martin, 2026-09-16), where it used to be quieter. The
   thing that stops an unsold hole reading as unfinished is the SENTENCE beneath it, which still
   offers the hole rather than reporting a gap, not the colour of the border. */
.bns-ph--logo {
	aspect-ratio: 4 / 1;
	background-image:
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Ccircle cx='13' cy='24' r='9' fill='none' stroke='%23a88848' stroke-width='2'/%3E%3Crect x='27' y='17' width='17' height='4' rx='2' fill='%23a88848'/%3E%3Crect x='27' y='27' width='12' height='4' rx='2' fill='%23a88848'/%3E%3C/svg%3E"),
		repeating-linear-gradient(135deg, rgba(168, 136, 72, .05), rgba(168, 136, 72, .05) 9px, transparent 9px, transparent 18px);
}
.bns-planner__slot > * + * { margin-top: 10px; }
.bns-slot__note {
	font-size: 13px;
	line-height: 1.5;
	color: var(--ink-soft);
	max-width: 52ch;
}

/* Sponsorship, off unless the club turns it on per hole. Quiet by design: it is a credit, not an
   advertisement competing with the hole it sits beside. */
.bns-planner__sponsor {
	border: 1px solid var(--line);
	border-radius: var(--radius);
	padding: 16px 18px;
	background: var(--surface);
	text-align: center;
}
.bns-planner__sponsor-label {
	font: 600 10.5px/1 var(--body);
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--ink-soft);
	margin-bottom: 12px;
}
.bns-planner__sponsor img { max-width: 100%; height: auto; display: block; margin-inline: auto; }
.bns-planner__sponsor-name { font-family: var(--display); font-size: 20px; font-weight: 600; color: var(--ink); }
/* An unsold hole: the stock panel carries its own frame, so no box around it. */
.bns-planner__sponsor--open { border: 0; padding: 0; background: none; }
.bns-planner__sponsor--open a { display: block; border-radius: var(--radius); overflow: hidden; }
.bns-planner__sponsor--open a:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.bns-planner__sponsor--open img { width: 100%; }

/* ⚠️ HIDDEN HERE, BEFORE THE 860px BLOCK, AND IT MUST STAY BEFORE IT. Same specificity as the phone
   rule that shows the dots, so whichever comes LAST wins: written after it, this hid the dots on
   every phone (found 2026-09-21 by driving the page, not by reading the CSS). */
.bns-planner__dots { display: none; }

@media (max-width: 860px) {
	.bns-planner__body { grid-template-columns: 1fr; }
	/* The card outranks the prose on a phone: a golfer standing on the tee wants the yardage,
	   not the history of the claypit. */
	.bns-planner__aside { order: -1; }
	/* ...except "From the tee", which comes first of all (John Gibson, 2026-10-18: the hole's
	   description "before the map of the course" on a phone). The main column dissolves into the
	   body's one-column grid so its first child can be ordered ahead of the card, and the grid gap
	   then does the spacing its children's margins did. */
	.bns-planner__main { display: contents; }
	.bns-planner__main > * + * { margin-top: 0; }
	.bns-planner__tip { order: -2; }
	/* Photographs: ONE at a time, full width, swiped left and right (Martin, 2026-09-21: "on mobile
	   set them to one with swipe left or right"). Stacked, six photographs were ~1200px of scroll.
	   Native scroll-snap, so the swipe is the browser's own and needs no script. The dots under it
	   are built by planner.js; with no script the strip still swipes. Scoped to the REAL grid
	   ([data-zoom-set]), not the empty placeholder boxes, which share .bns-planner__photos. */
	.bns-planner__photos[data-zoom-set] {
		display: flex;
		gap: 12px;
		overflow-x: auto;
		scroll-snap-type: x mandatory;
		overscroll-behavior-x: contain;
		scrollbar-width: none;
	}
	.bns-planner__photos[data-zoom-set]::-webkit-scrollbar { display: none; }
	.bns-planner__photos[data-zoom-set] > .bns-zoom { flex: 0 0 100%; scroll-snap-align: center; aspect-ratio: 16 / 9; }
	.bns-planner__dots { display: flex; justify-content: center; gap: 2px; margin-top: 6px; }
}
/* Dots: phone only. Each is a 24px target (WCAG 2.5.8) drawn as an 8px dot. The phone rule that
   SHOWS them is in the 860px block above. */
.bns-planner__dots button {
	width: 24px;
	height: 24px;
	padding: 0;
	border: 0;
	background: none;
	cursor: pointer;
	display: grid;
	place-items: center;
}
.bns-planner__dots button::before {
	content: "";
	width: 8px;
	height: 8px;
	border-radius: 50%;
	background: var(--wp--preset--color--line);
}
.bns-planner__dots button[aria-current="true"]::before { background: var(--wp--preset--color--accent-deep); }
.bns-planner__dots button:focus-visible { outline: 3px solid var(--wp--preset--color--accent); outline-offset: -3px; border-radius: 50%; }

/* ═══ PLANNER NARROW-VIEWPORT FIX ═════════════════════════════════════════════════════════
   audit-page reported the FIRST failing page in this build: horizontal overflow at 320px and
   375px on /golf/the-course/, with <div>, <h4> and <p> all reaching 382px inside a 375px
   viewport. Measured rather than guessed, and it is one cause with a knock-on.

   ⚠️ (1) GRID CHILDREN DEFAULT TO min-width:auto, WHICH MEANS "DO NOT SHRINK BELOW MY CONTENT".
   .bns-planner__main and .bns-planner__aside both computed min-width:auto, so the widest thing
   inside them (the card table) set the column width and dragged the whole panel past the edge.
   The prose showed up in the failure list for that reason alone: an <h4> and a <p> with no width
   of their own cannot overflow, they were being carried. This stylesheet already carries
   `.bns-grid > * { min-width: 0 }` for exactly this; the planner's grid simply never got it.

   ⚠️ (2) A min-width LARGER THAN THE CONTAINER DEFEATS overflow-x:auto. .bns-tbl-wrap scrolls,
   but .bns-tbl--card asked for 360px while ~362px was available at 375px, and the nowrap header
   cells then pushed the row to 381px, growing the wrapper instead of scrolling inside it. The
   wrapper can only do its job if the table is allowed to be narrower than the viewport.

   ⚠️ THE SCORECARD PAGE USES THE SAME CLASS AND PASSED. It is not immune, it simply has no grid
   around its tables, so only cause (2) applied and its wrapper absorbed it. Fixing the class
   here fixes both. */

.bns-planner__main,
.bns-planner__aside { min-width: 0; }

/* Below the narrowest phone gutter, so the wrapper scrolls rather than the page. */
@media (max-width: 420px) {
	.bns-tbl--card { min-width: 300px; }
	.bns-tbl th,
	.bns-tbl td { padding: 8px 9px; }
}

/* ═══ DOCUMENT LINKS ══════════════════════════════════════════════════════════════════════
   Used by /golf/opens/terms/ and /golf/opens/results/, and by any page whose real content is a
   file the club issues rather than prose we can restate.

   ⚠️ THE WHOLE ROW IS THE LINK, not a "click here" at the end of a sentence. The live site's
   pages are literally "Click here to view our Open Competitions Terms & Conditions", which is
   both a poor target and a link whose text says nothing out of context. A screen-reader user
   listing the links on that page hears "click here" four times on the results page alone.

   ⚠️ THE FORMAT AND SIZE ARE IN THE LINK TEXT ON PURPOSE. A PDF is not an accessible format by
   default and it may open an app rather than a page, so a visitor is told what they are about
   to get before they get it, and the page offers the club office as the other route. */

.bns-docs { display: grid; gap: 12px; margin-top: 28px; max-width: var(--prose); }

.bns-doc {
	display: flex;
	align-items: center;
	gap: 16px;
	padding: 16px 18px;
	border: 1px solid var(--line);
	border-radius: var(--radius);
	background: var(--paper);
	text-decoration: none;
	color: inherit;
	/* 44px minimum comes free from the padding, but state it: these are the page's only targets. */
	min-height: 44px;
}
.bns-doc:hover { border-color: var(--accent); }
.bns-doc:focus-visible { outline: 2px solid var(--accent-deep); outline-offset: 2px; }

.bns-doc__kind {
	flex: 0 0 auto;
	display: grid;
	place-items: center;
	width: 46px;
	height: 46px;
	border-radius: 6px;
	background: var(--brand-deep);
	color: var(--paper);
	font: 600 11px/1 var(--body);
	letter-spacing: .1em;
}
.bns-doc__txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.bns-doc__txt strong { font-size: 16.5px; color: var(--ink); }
.bns-doc:hover .bns-doc__txt strong { text-decoration: underline; text-decoration-color: var(--accent); }
.bns-doc__meta { font-size: 14px; color: var(--ink-soft); }

@media (max-width: 480px) {
	.bns-doc { padding: 14px; gap: 12px; }
	.bns-doc__kind { width: 40px; height: 40px; }
}

/* ═══ HERITAGE TIMELINE ═══════════════════════════════════════════════════════════════════
   The 1904 page, rebuilt as a timeline read top to bottom (Martin, 2026-09-15: "i thought this
   would be built like a time line as you scroll from top to bottom").

   ⚠️ THE RAIL IS DRAWN ON THE LIST, NOT ON EACH ITEM. A per-item border leaves a visible gap at
   every margin collapse, which reads as a broken line rather than a continuous one. One
   pseudo-element on the container, inset to the marker's centre, gives an unbroken spine.

   ⚠️ IT IS AN ORDERED LIST IN THE MARKUP, because that is what it is: dated events in sequence.
   A screen reader announces "list of 9 items" and the position within it, which is exactly the
   information a sighted reader gets from the rail. The numbering itself is suppressed, because
   the YEARS are the enumeration a reader wants, not 1 to 9. */

/* ⚠️ REBUILT 2026-09-15 AS A CENTRE SPINE. The previous version of this block was a single
   left-hand rail with eleven identical entries hanging off it, and Martin rejected the page
   on sight: "it's just a numbered list which is pretty shite". The fault was not in the CSS,
   which applied correctly. It was that the page was never rendered and looked at. What
   changed: the entries alternate either side of a centre spine, which frees the opposite side
   for a picture (Martin: "might be better with the time line in the middle of the page with
   the text alternating left side and right side"); the years are display type again; and one
   entry, 1963, takes the full width so the page changes pace instead of repeating.

   ⚠️ IT IS STILL AN ORDERED LIST, AND THE ALTERNATION IS LAYOUT ONLY. The markup order stays
   1904 to 2004, so a screen reader and a phone both get the sequence in date order. Putting
   the left column before the right column in the DOM would read the page as two interleaved
   half-histories. */

.bns-tl { --bns-spine: 50%; position: relative; margin-top: 48px; }
.bns-tl__list { list-style: none; margin: 0; padding: 0; }

/* TWO RAILS, one behind the other. The base is the full span in pale line colour, so the
   timeline is complete and continuous before a single line of script runs. The fill is the
   scroll state: thicker, and the deep olive of the header bar (Martin, 2026-09-15: "animate
   the time line to change deep olive color and thiker as the user scrolls"). A scaleY, not a
   height: a height change on every scroll frame is a layout pass, a transform is composited. */
.bns-tl__rail {
	position: absolute;
	top: 8px;
	bottom: 8px;
	left: var(--bns-spine);
	width: 2px;
	transform: translateX(-50%);
	background: var(--line);
	border-radius: 2px;
	pointer-events: none;
}
.bns-tl__fill {
	position: absolute;
	top: 0;
	left: 50%;
	width: 6px;
	height: 100%;
	border-radius: 3px;
	background: var(--shell);
	transform: translateX(-50%) scaleY(var(--bns-tl-p, 0));
	transform-origin: top center;
}

.bns-era {
	position: relative;
	display: grid;
	grid-template-columns: 1fr 78px 1fr;
	align-items: start;
	padding-block: clamp(26px, 3.4vw, 44px);
}
.bns-era:first-child { padding-top: 0; }

/* The node sits ON the spine, level with the year rather than with the top of the padding. */
.bns-era__node {
	position: absolute;
	left: var(--bns-spine);
	top: clamp(30px, 3.6vw, 50px);
	width: 19px;
	height: 19px;
	border-radius: 50%;
	background: var(--paper);
	border: 2px solid var(--line);
	transform: translate(-50%, -50%);
	z-index: 2;
	transition: border-color .5s ease;
}
.bns-era:first-child .bns-era__node { top: 26px; }
.bns-era__node::after {
	content: "";
	position: absolute;
	inset: 3px;
	border-radius: 50%;
	background: var(--shell);
	transform: scale(0);
	transition: transform .5s cubic-bezier(.2, .8, .2, 1);
}
.bns-era.is-reached .bns-era__node { border-color: var(--shell); }
.bns-era.is-reached .bns-era__node::after { transform: scale(1); }
/* The major years get a bigger target, so the spine itself carries the emphasis. */
.bns-era--major .bns-era__node { width: 27px; height: 27px; border-width: 3px; }
.bns-era--major .bns-era__node::after { inset: 4px; }

.bns-era__card { grid-column: 1; grid-row: 1; padding-right: clamp(6px, 1.4vw, 18px); }
.bns-era--right .bns-era__card { grid-column: 3; padding-right: 0; padding-left: clamp(6px, 1.4vw, 18px); }
.bns-era__aside { grid-column: 3; grid-row: 1; margin: 0; padding-left: clamp(6px, 1.4vw, 18px); }
.bns-era--right .bns-era__aside { grid-column: 1; padding-left: 0; padding-right: clamp(6px, 1.4vw, 18px); }

/* The tick that ties a card to the spine. Without it the two columns read as two separate
   lists that happen to sit either side of a line. */
.bns-era__card::before {
	content: "";
	position: absolute;
	top: clamp(30px, 3.6vw, 50px);
	width: clamp(14px, 2.4vw, 28px);
	height: 2px;
	background: var(--line);
	transition: background .5s ease;
	right: calc(50% + 9px);
}
.bns-era--right .bns-era__card::before { right: auto; left: calc(50% + 9px); }
.bns-era:first-child .bns-era__card::before { top: 26px; }
.bns-era.is-reached .bns-era__card::before { background: var(--shell); }

/* THE YEAR IS THE DRAW: display type, large, set against the prose rather than inside it. */
.bns-era__year {
	display: block;
	font-family: var(--display);
	font-weight: 600;
	line-height: .92;
	letter-spacing: -.035em;
	font-size: clamp(40px, 5.4vw, 68px);
	color: var(--brand);
	font-variant-numeric: tabular-nums;
	margin: 0;
}
.bns-era--major .bns-era__year { color: var(--shell); }
.bns-era__what {
	display: block;
	font-family: var(--display);
	font-weight: 600;
	font-size: clamp(20px, 2.3vw, 27px);
	line-height: 1.12;
	margin-top: 8px;
	color: var(--ink);
}
.bns-era p { margin-top: 13px; color: var(--ink-soft); line-height: 1.65; max-width: 46ch; }
.bns-era p + p { margin-top: .85em; }
.bns-era strong { color: var(--ink); font-weight: 600; }

/* A quoted line inside an entry: the Gazette, the book, a member. Kept visually distinct from
   the prose so a quotation is never mistaken for the club speaking in its own voice. */
.bns-era blockquote {
	margin: 16px 0 0;
	padding: 16px 0 4px 20px;
	border-left: 3px solid var(--accent);
	font-family: var(--display);
	font-size: clamp(17px, 1.9vw, 21px);
	line-height: 1.42;
	color: var(--ink);
}
.bns-era blockquote cite {
	display: block;
	margin-top: 11px;
	font: 500 12.5px/1.4 var(--body);
	font-style: normal;
	letter-spacing: .06em;
	text-transform: uppercase;
	color: var(--ink-soft);
}

/* THE FEATURE ROW. 1963 is the biggest thing that ever happened here, and it stays in date
   order rather than being lifted out of the sequence. Full width is the change of pace an
   eleven-entry list cannot make for itself. */
.bns-era--feature { grid-template-columns: 1fr; }
.bns-era--feature .bns-era__card { grid-column: 1; padding: 0; }
.bns-era--feature .bns-era__card::before { display: none; }
.bns-era--feature .bns-era__node { top: 34px; }
.bns-feature {
	border-block: 1px solid var(--line);
	background: var(--surface);
	margin-inline: calc(var(--gut) * -1);
	padding: clamp(34px, 5vw, 62px) var(--gut);
}
.bns-feature__inner {
	max-width: var(--wide);
	margin-inline: auto;
	display: grid;
	grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
	gap: clamp(28px, 4vw, 56px);
	align-items: start;
}
.bns-feature .bns-era__year { font-size: clamp(56px, 8vw, 104px); color: var(--shell); }
.bns-feature p { max-width: 54ch; }
/* The 1963 names as small pills, INSIDE THE 1904 FEATURE CARD ONLY.
   ⚠️ THIS WAS UNSCOPED AND IT SILENTLY BROKE THE HOME PAGE (found 2026-09-16, Martin: "what has
   happend to the name formatting"). `.bns-names` is used by two patterns: page-1904.php, where the
   names are a footnote inside a dense feature card and pills are right, and page-home.php, where
   the names ARE the band and are set as large display type. Being written later and at equal
   specificity, this block won everywhere, so the home band lost its typography and the four names
   shrank into pills in the corner of an otherwise empty column.
   ⚠️ WORSE, IT WAS A HALF-OVERRIDE. It never touched `.bns-names li::before`, so the legends band's
   decorative accent rule went on rendering INSIDE each pill: a stray dash before every name.
   ⚠️ BOTH BLOCKS ARE NOW SCOPED TO THEIR OWN BAND. Do not add a bare `.bns-names` rule again. */
.bns-feature .bns-names { list-style: none; margin: 20px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px; }
.bns-feature .bns-names li {
	font: 600 13px/1 var(--body);
	letter-spacing: .05em;
	padding: 9px 13px;
	border: 1px solid var(--line);
	border-radius: 999px;
	background: var(--paper);
	color: var(--ink);
}
/* and no accent rule inside a pill */
.bns-feature .bns-names li::before { content: none; }

/* ── entry motion ──────────────────────────────────────────────────────────────────────
   ⚠️ NO-SCRIPT AND REDUCED-MOTION BOTH GET THE WHOLE PAGE, VISIBLE. The hidden state lives
   only inside `.bns-js`, which functions.php stamps on <html> before the first paint, and
   only where motion is welcome. A reveal that hides content in the stylesheet by default is
   a page that shows nothing the day the script fails to load.
   ⚠️ It must also be stamped BEFORE first paint, not from a deferred file: setting the flag
   late means the browser paints the entries visible and then fades them out in front of the
   reader. Measured on the prototype, 2026-09-15. */
@media (prefers-reduced-motion: no-preference) {
	.bns-js .bns-era__card,
	.bns-js .bns-era__aside {
		opacity: 0;
		transition: opacity .7s ease, transform .7s cubic-bezier(.2, .8, .2, 1);
	}
	/* each side arrives from its own side, which is what makes the alternation read as a
	   rhythm rather than as two columns that happen to be staggered */
	.bns-js .bns-era .bns-era__card { transform: translate(-22px, 16px); }
	.bns-js .bns-era--right .bns-era__card { transform: translate(22px, 16px); }
	.bns-js .bns-era--feature .bns-era__card { transform: translate(0, 20px); }
	.bns-js .bns-era .bns-era__aside { transform: translate(22px, 16px); transition-delay: .14s; }
	.bns-js .bns-era--right .bns-era__aside { transform: translate(-22px, 16px); }
	.bns-js .bns-era.is-reached .bns-era__card,
	.bns-js .bns-era.is-reached .bns-era__aside { opacity: 1; transform: none; }
}

/* On the surface band the nodes need the surface colour, not paper, or they read as holes. */
.has-surface-background-color .bns-era__node { background: var(--surface); }

@media (max-width: 900px) {
	.bns-feature__inner { grid-template-columns: 1fr; gap: 26px; }
}

/* ⚠️ THE SPINE MOVES TO THE LEFT EDGE, IT DOES NOT DISAPPEAR. A centre spine on a 390px
   screen leaves two columns of about 150px, which is four words to a line. Everything stacks
   to the right of a left-hand rail, and the alternation stops meaning anything at that width,
   so it is switched off rather than left to produce a ragged single column. */
@media (max-width: 820px) {
	.bns-tl { --bns-spine: 11px; }
	.bns-era { grid-template-columns: 1fr; padding-left: 42px; padding-block: 30px; }
	.bns-era__card,
	.bns-era--right .bns-era__card,
	.bns-era__aside,
	.bns-era--right .bns-era__aside {
		grid-column: 1;
		grid-row: auto;
		padding-left: 0;
		padding-right: 0;
	}
	.bns-era__aside { margin-top: 20px; }
	.bns-era__card::before,
	.bns-era--right .bns-era__card::before { left: -31px; right: auto; width: 20px; }
	.bns-era__node,
	.bns-era:first-child .bns-era__node { top: 22px; }
	.bns-era--feature { padding-left: 42px; }
	.bns-js .bns-era .bns-era__card,
	.bns-js .bns-era--right .bns-era__card,
	.bns-js .bns-era .bns-era__aside,
	.bns-js .bns-era--right .bns-era__aside { transform: translate(0, 16px); }
}

/* ─────────────────────────────────────────────────────────────────────────────
   2026-09-20: THE CLUB'S EIGHT-POINT NOTE. Course gallery, the 1904 subpages, In the community,
   the pro shop with names, and a fuller Why North Shore.

   ⚠️ EVERY CLASS BELOW IS NEW. None redefines a shared one (CLAUDE.md, "Never redefine a shared
   element"): .bns-gallery, .bns-quote, .bns-plate, .bns-card__role, .bns-prose--after, and the
   two lightbox additions .bns-lightbox-nav and .bns-lightbox-cap. `.bns-prose h3` is the one rule
   that extends an existing component, and .bns-prose had no h3 anywhere before this.
   ───────────────────────────────────────────────────────────────────────────── */

/* THE GALLERY. Every photograph in the club's set is 16:9 off the same drone, so the grid can be
   uniform and the tiles never crop. A masonry layout would be solving a problem these pictures
   do not have. Three across, two on a tablet, one on a phone: at 390px a half-width aerial is a
   green smudge, and the whole point of the page is to see the course. */
.bns-gallery {
	display: grid;
	grid-template-columns: repeat(3, minmax(0, 1fr));
	gap: 14px;
	margin-top: 38px;
	padding: 0;
	list-style: none;
}
.bns-gallery li { margin: 0; }
.bns-gallery .bns-zoom {
	aspect-ratio: 16 / 9;
	border-radius: var(--radius);
	overflow: hidden;
	background: var(--surface);
}
.bns-gallery img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform .5s ease;
}
.bns-gallery .bns-zoom:hover img,
.bns-gallery .bns-zoom:focus-visible img { transform: scale(1.03); }
.bns-gallery .bns-zoom:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
.bns-gallery .bns-zoom::after { content: "Enlarge"; }
@media (max-width: 900px) { .bns-gallery { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .bns-gallery { grid-template-columns: 1fr; gap: 12px; } }
@media (prefers-reduced-motion: reduce) {
	.bns-gallery img { transition: none; }
	.bns-gallery .bns-zoom:hover img,
	.bns-gallery .bns-zoom:focus-visible img { transform: none; }
}

/* Junior golf: the club's own photographs, a mix of portrait phone shots and group pictures, so
   4:3 tiles, four across. The lightbox shows each one whole. */
.bns-gallery--juniors { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 38px; }
.bns-gallery--juniors .bns-zoom { aspect-ratio: 4 / 3; }
@media (max-width: 900px) { .bns-gallery--juniors { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .bns-gallery--juniors { grid-template-columns: 1fr; } }

/* Competitions: the honours boards and the trophies (2026-10-02). Upright phone photographs, so
   3:4 tiles, four across. A NEW modifier; the gallery page and the junior row are untouched. */
.bns-gallery--honours { grid-template-columns: repeat(4, minmax(0, 1fr)); margin-bottom: 30px; }
.bns-gallery--honours .bns-zoom { aspect-ratio: 3 / 4; }
@media (max-width: 900px) { .bns-gallery--honours { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* The chef's food (2026-10-13, loop R60): a mix of upright and landscape phone photographs, so
   SQUARE tiles, the one shape that crops both kinds fairly. Twelve tiles, four across, so the rows
   come out even. Two across on a phone: a plate of food still reads at half width, an aerial did not.
   A NEW modifier; the other galleries are untouched.
   2026-10-16: the function-room picture left the food gallery (Martin), so eleven pictures. "At the
   pass" (landscape) spans two tiles to keep twelve, even at 4, 3 and 2 across; `dense` lets the next
   square fill the hole a wide tile would leave beside the first. Its image is taken out of flow so the
   row height comes from the squares, not from the photograph. */
.bns-gallery--food { grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-flow: dense; }
.bns-gallery--food .bns-gallery__wide { grid-column: span 2; }
.bns-gallery--food .bns-gallery__wide .bns-zoom { aspect-ratio: auto; height: 100%; }
.bns-gallery--food .bns-gallery__wide img { position: absolute; inset: 0; }
.bns-gallery--food .bns-zoom { aspect-ratio: 1; }
@media (max-width: 900px) { .bns-gallery--food { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 560px) {
	.bns-gallery--food { grid-template-columns: repeat(2, minmax(0, 1fr)); }
	/* Two across, the wide tile is a row of its own with no square beside it to set the height, so
	   it takes its own shape (measured 0px tall without this, 2026-10-16). */
	.bns-gallery--food .bns-gallery__wide .bns-zoom { aspect-ratio: 2 / 1; height: auto; }
}

/* Two upright pictures side by side, held to a narrow column (the breakfasts on Winter society golf,
   2026-10-13). Two across at every width: one alone at phone width would run past a whole screen. */
.bns-gallery--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 620px; margin-top: 30px; }
.bns-gallery--pair .bns-zoom { aspect-ratio: 3 / 4; }
@media (max-width: 560px) { .bns-gallery--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

/* Lightbox, as a set. 44px targets, and they sit INSIDE the picture's edge on a phone, where
   there is no margin beside a 92vw image to put them in. */
dialog.bns-lightbox .bns-lightbox-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 2.75rem;
	height: 2.75rem;
	border: 0;
	border-radius: 999px;
	background: #fff;
	color: #111;
	font: 400 1.7rem/1 var(--wp--preset--font-family--body);
	cursor: pointer;
}
dialog.bns-lightbox .bns-lightbox-nav--prev { left: .6rem; }
dialog.bns-lightbox .bns-lightbox-nav--next { right: .6rem; }
dialog.bns-lightbox .bns-lightbox-nav[hidden] { display: none; }
dialog.bns-lightbox .bns-lightbox-nav:focus-visible,
dialog.bns-lightbox .bns-lightbox-close:focus-visible { outline: 3px solid var(--wp--preset--color--accent); outline-offset: 2px; }
dialog.bns-lightbox .bns-lightbox-cap {
	margin: .7rem 0 0;
	text-align: center;
	color: #fff;
	font: 500 .9rem/1.4 var(--wp--preset--font-family--body);
}

/* A role line under a person's name. Its own class: .bns-room__cap looks similar and means a
   room's capacity, and one class that means two things is how this build has been bitten. */
.bns-card .bns-card__role {
	margin-top: 6px;
	font: 600 12px/1.3 var(--body);
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--accent-deep);
}

/* Prose that follows a table or a card grid in the same band, and sub-headings inside prose. */
.bns-prose--after { margin-top: 38px; }
.bns-prose h3 { font-size: 22px; margin-top: 1.7em; }
.bns-prose > h3:first-child { margin-top: 0; }

/* A PULL QUOTE FROM THE RECORD: a minute, a newspaper, a member. The rule is the accent; the
   words are display type because on the heritage pages they ARE the display. */
.bns-quote {
	max-width: var(--prose);
	margin: 34px 0 0;
	padding: 4px 0 4px 22px;
	border-left: 3px solid var(--accent);
}
.bns-quote p {
	font-family: var(--display);
	font-size: clamp(20px, 2.3vw, 25px);
	line-height: 1.42;
	color: var(--ink);
}
.bns-quote footer {
	margin-top: 12px;
	font-size: 14px;
	color: var(--ink-soft);
}
.bns-quote cite { font-style: normal; }

/* A PLATE: one archive picture with its caption, or the labelled gap where one will go. The
   dashed state reuses the look of .bns-hole on purpose (same meaning: waiting on the club) but
   not its class, because a plate holds a 3:2 shape open and a hole does not. */
/* A photograph in a slot that used to be a labelled hole (home legends and heritage, the 1904
   timeline asides and the 1963 feature). Its own class, so the plate's 34px top margin and 760px
   cap never leak into a grid cell (2026-09-29). */
.bns-photo { margin: 0; min-width: 0; }
.bns-photo img { display: block; width: 100%; height: auto; border-radius: var(--radius); }
.bns-photo figcaption { margin-top: 10px; font-size: 14px; line-height: 1.5; color: var(--ink-soft); }

.bns-plate { max-width: 760px; margin: 34px 0 0; }
.bns-plate img { display: block; width: 100%; height: auto; border-radius: var(--radius); }
.bns-plate figcaption { margin-top: 10px; font-size: 14px; line-height: 1.5; color: var(--ink-soft); }
/* The visitors' book on Legends (2026-10-01, the club: "more prominent"): its own modifier, at the
   cleaned scan's width (1100px, was 928 on the book copy) rather than the shared plate's 760, and above
   the names instead of after them. */
.bns-plate--book { max-width: 1100px; margin: 26px 0 30px; }
/* A portrait plate (2026-09-28, the Mabbott Shield). At the 760px landscape width a portrait
   photograph would run past a whole screen, so it is held to a column a reader can take in at once. */
.bns-plate--portrait { max-width: 420px; }
.bns-plate--wanted .bns-plate__gap {
	aspect-ratio: 3 / 2;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 8px;
	padding: 20px;
	text-align: center;
	border: 2px dashed var(--accent);
	border-radius: var(--radius);
	background: var(--surface);
}
.bns-plate--wanted .bns-plate__gap b {
	font: 600 11px/1 var(--body);
	letter-spacing: .16em;
	text-transform: uppercase;
	color: var(--accent-deep);
}
.bns-plate--wanted .bns-plate__gap span { font-size: 13.5px; line-height: 1.5; color: var(--ink-soft); max-width: 40ch; }

/* The way from a timeline entry to its full story. Its own class, not .bns-card__more: that one
   is pushed to the foot of a flex card with margin-top:auto, which does nothing in a timeline
   card and would be a rule that lies about what it does. */
.bns-era__more { margin-top: 16px; }
.bns-era__more a {
	font-weight: 600;
	font-size: 15px;
	color: var(--accent-deep);
	text-decoration: none;
}
.bns-era__more a::after { content: " \2192"; }
.bns-era__more a:hover,
.bns-era__more a:focus-visible { text-decoration: underline; }

/* ═══ COOKIE CHOICES (2026-10-12) ═══════════════════════════════════════════════════════════
   .cookie-bar and .cookie-dialog are built in script by mu-plugins/digenie-consent.php, ported
   from Dale Bathrooms. New classes, used nowhere else. The bar sits on brand-deep at the foot of
   the window, the same ground as the page head and the footer, so the light button pair carries
   it; Accept all takes the accent, as the masthead's Book button does, so the one bright button
   is the one most people want. The dialog is a native <dialog>, so focus stays inside it and
   Escape closes it. The bar is a manual popover where supported, which puts it in the top layer
   above the fixed masthead without moving it in the tab order. */
.cookie-bar{position:fixed;inset:auto 0 0 0;z-index:90;background:var(--brand-deep);color:var(--paper);
  border-top:1px solid rgba(251,249,245,.16);box-shadow:0 -6px 24px rgba(12,18,26,.28)}
.cookie-bar[popover]{inset:auto 0 0 0;width:100%;max-width:none;height:auto;margin:0;padding:0;overflow:visible;
  border:0;border-top:1px solid rgba(251,249,245,.16);background:var(--brand-deep);color:var(--paper)}
.cookie-bar[hidden]{display:none}
.cookie-bar__in{max-width:var(--wide);margin-inline:auto;padding:16px var(--gut);display:grid;gap:14px;align-items:center}
@media (min-width:768px){.cookie-bar__in{grid-template-columns:1fr auto;gap:32px}}
.cookie-bar__text{margin:0;max-width:68ch;font-size:15px;line-height:1.5;color:rgba(251,249,245,.88)}
.cookie-bar__text a{color:var(--paper);text-decoration:underline;text-underline-offset:.15em}
.cookie-bar__actions{display:flex;flex-wrap:wrap;gap:10px}
@media (min-width:768px){.cookie-bar__actions{flex-wrap:nowrap}}
.cookie-bar__actions .bns-btn{flex:1 1 9rem}
/* These are <button>s, and a browser button brings its own grey ground: the outline and ghost
   variants were written for links and never had to clear one. Measured: Customise rendered as
   near-white on light grey. */
.cookie-bar .bns-btn,.cookie-dialog .bns-btn{cursor:pointer}
.cookie-bar .bns-btn--outline-light,.cookie-dialog .bns-btn--ghost{background:transparent}
.cookie-bar .bns-btn--primary{background:var(--accent);color:var(--ink)}
.cookie-bar .bns-btn--primary:hover{background:#C0A05E}
.cookie-dialog{width:min(34rem,calc(100vw - 2rem));max-height:calc(100dvh - 2rem);padding:28px;border:0;
  border-radius:var(--radius);background:var(--paper);color:var(--ink)}
.cookie-dialog::backdrop{background:rgba(12,18,26,.6)}
.cookie-dialog__h{margin:0 0 16px;font-size:clamp(24px,3vw,30px)}
.cookie-dialog__set{margin:0;padding:0;border:0;display:grid;gap:14px}
.cookie-dialog__row{display:grid;grid-template-columns:1.25rem 1fr;gap:12px;align-items:start;padding-bottom:14px;
  border-bottom:1px solid var(--line)}
.cookie-dialog__row input{width:1.25rem;height:1.25rem;margin:.15rem 0 0;accent-color:var(--brand)}
.cookie-dialog__row label strong{display:block;font-family:var(--display);font-weight:600}
.cookie-dialog__row label span{display:block;font-size:14.5px;color:var(--ink-soft)}
.cookie-dialog__actions{display:flex;flex-wrap:wrap;justify-content:flex-end;gap:10px;margin-top:22px}

/* The enquiry thank-you page (patterns/page-contact-thank-you.php): the only page head that
   carries buttons, so this adds just the space above them. */
.bns-page-head__actions{margin-top:26px}
/* A page head that is the whole page (the thank-you page). The theme's block gap above the footer
   is invisible after a pale band and a stripe of paper after a dark one, so this head closes it. */
main:has(.bns-page-head--alone) + *{margin-block-start:0}

/* ═══ PAGE: ABOUT THIS WEBSITE (2026-10-16) ════════════════════════════════════════════════
   New classes only; the figures, cards, meet layout, detail list and slots are the library's own. */

/* Before and after: two screenshots side by side, captured at the same 16:10, one above the other on
   a phone. A NEW component (.bns-gallery tiles carry no captions, and these need them). */
.bns-compare { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(18px, 3vw, 30px); margin-top: 34px; }
.bns-compare figure { margin: 0; }
.bns-compare .bns-zoom { aspect-ratio: 16 / 10; border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; background: var(--paper); }
.bns-compare .bns-zoom::after { content: "Enlarge"; }
.bns-compare img { display: block; width: 100%; height: 100%; object-fit: cover; }
.bns-compare figcaption { margin-top: 12px; font-size: 14.5px; line-height: 1.5; color: var(--ink-soft); }
.bns-compare figcaption b { color: var(--ink); font-weight: 600; }
@media (max-width: 760px) { .bns-compare { grid-template-columns: 1fr; } }

/* The credits sit under the lede in the meet layout; the club's words follow them. */
.bns-about__credits { margin-top: 26px; }
/* Launched text-only, no portrait yet: one column, held to the letter's own measure. */
.bns-meet--text { grid-template-columns: minmax(0, 1fr); }
.bns-meet__letter .bns-about__credits + .bns-ph { margin-top: 30px; }
/* A slot for a short quotation: a wide, low box, the shape a two-line quote will take. Same dashed
   border and pattern as every other slot, with a quotation mark for its icon. */
.bns-ph--quote {
	aspect-ratio: 5 / 1;
	background-image:
		url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath d='M10 30c0-7 4-12 10-14l1 3c-3 1-5 4-5 7h5v10H10zm17 0c0-7 4-12 10-14l1 3c-3 1-5 4-5 7h5v10H27z' fill='%23a88848'/%3E%3C/svg%3E"),
		repeating-linear-gradient(135deg, rgba(168, 136, 72, .05), rgba(168, 136, 72, .05) 9px, transparent 9px, transparent 18px);
}
.bns-meet__portrait .bns-slot__note,
.bns-meet__letter .bns-ph + .bns-slot__note { margin-top: 10px; }
