/**
 * NW Panthers — component styles
 *
 * Every colour here is a `--nwp-*` role token, so a component follows the mode
 * without branching. Hard-coding a hex breaks the moment the element moves
 * between Club and Match.
 *
 * Reference implementation: design-system/src/index.css
 */

/* ==========================================================================
   1  BASE
   ========================================================================== */

.nwp-visually-hidden {
	position: absolute !important;
	width: 1px;
	height: 1px;
	padding: 0;
	margin: -1px;
	overflow: hidden;
	clip: rect( 0, 0, 0, 0 );
	white-space: nowrap;
	border: 0;
}

/* Skip link. Visible on focus, and one of the few things allowed to move. */
.nwp-skip-link {
	position: absolute;
	inset-block-start: -100%;
	inset-inline-start: var( --nwp-space-md );
	z-index: 999;
	padding: var( --nwp-space-sm ) var( --nwp-space-md );
	background: var( --nwp-maroon );
	color: var( --nwp-fixed-white );
	text-decoration: underline;
}

.nwp-skip-link:focus {
	inset-block-start: var( --nwp-space-md );
}

/* ==========================================================================
   1a  DISPLAY TYPE — the whole show
   Photography is blocked (D-3) and fixtures are unpublished (D-4), so the two
   usual engines of sports-site presence are unavailable. Presence is carried
   by type instead (DEC-057). That only works at genuine poster scale — a
   half-committed version reads as an empty page.
   ========================================================================== */

.nwp-display,
.is-style-nwp-display {
	font-family: var( --nwp-font-display );
	text-transform: uppercase;
	line-height: 0.86;
	letter-spacing: -0.025em;
	/* 🔴 DESCENDER CLEARANCE. A line-height below 1 makes the line box shorter
	   than the font, so the tail of a Q, J, Q or comma escapes it and collides
	   with whatever follows. "OUR SQUADS" was overshooting its own box by 5px
	   and touching the card border beneath it. At poster scale that becomes
	   ~16px. The clearance scales with the type, so it holds at every size. */
	padding-block-end: 0.12em;
	text-wrap: balance;
}

/* The compressed face. Loaded but previously unused — it is the second voice
   the hierarchy was missing, and it belongs to labels, numerals and metadata
   at scale rather than to prose. */
.nwp-compressed {
	font-family: var( --nwp-font-compressed );
	text-transform: uppercase;
	letter-spacing: 0.01em;
	line-height: 0.9;
	padding-block-end: 0.08em;
}

/* Numerals and age labels treated as graphic objects rather than as text. */
.nwp-numeral {
	font-family: var( --nwp-font-compressed );
	font-size: clamp( 3rem, 7vw, 5.5rem );
	line-height: 0.82;
	letter-spacing: -0.01em;
	padding-block-end: 0.08em;
	display: block;
}

/* ==========================================================================
   1b  READING MEASURE
   🔴 Prose gets a measure wherever it lives, not only inside the templates
   that opt in. Body copy was running 122–130 characters in the join panel and
   187 in the footer legal line at 12px — the eye loses its place tracking back
   to the start of the next line, and 12px at 187 characters is the worst
   pairing available.
   ========================================================================== */

.nwp-join p,
.nwp-join ol,
.nwp-join ul,
.nwp-b2n p,
.nwp-chero__sentence,
.nwp-shearpanel__body,
.nwp-alert__body,
.nwp-state__body,
.nwp-safeguarding p,
.nwp-safeguarding__limits,
.nwp-safeguarding__verified,
.nwp-policy p,
.nwp-sponsors__note,
.nwp-footer__legal,
.nwp-footer p {
	max-width: 62ch;
	/* 🔴 A constrained-layout parent centres any child narrower than itself.
	   Capping the measure without this indents every paragraph to the middle
	   of the panel, which reads as broken rather than as a measure. */
	margin-inline: 0;
}

/* 🔴 PROSE CAPS ITSELF, WHEREVER IT IS.
   The earlier caps named specific components, which worked until the page
   container was widened to 70rem for listings — then every ordinary paragraph
   on the values, privacy and kit pages ran to 140 characters. Capping by
   component does not scale; the container is for layout, the measure belongs
   to the text.

   Listings, grids, tables and the finder opt out below, because their width
   is doing a different job. */
/* Specificity note: WordPress's constrained layout emits
   `.wp-container-X > * { max-width: <contentSize> }` at (0,1,0). A rule of
   `main :is(p, li)` is (0,0,2) and silently loses to it — which is why an
   earlier attempt at this changed nothing at all. Matching on the container
   class puts this at (0,1,2), which wins honestly rather than with
   `!important`. */
/* 🔴 NARROW THE COLUMN, NOT THE PARAGRAPH.
   ==========================================================================
   The obvious move — cap `p` at 62ch — is wrong here, and wrong in a way that
   took two attempts to see. WordPress's constrained layout emits, for every
   direct child of the content container:

       > :where(...) { max-width: 70rem; margin-left: auto !important;
                       margin-right: auto !important }

   Capping ONE kind of child makes that child narrower than its siblings, and
   the `auto` margins then centre it. So a 62ch paragraph under a 70rem heading
   does not sit under the heading's left edge — it floats to the middle of the
   column. Headings on one edge, body copy 300px further in.

   The `!important` on those margins means specificity cannot save you: no
   selector, however precise, overrides an important declaration with a normal
   one. Trying to win it with `!important` of my own pinned the container
   itself and threw the entire page against the viewport edge — a worse bug
   than the one being fixed.

   The `max-width`, however, carries NO `!important`. So the fix is to leave
   the centring entirely alone and make every child the SAME width. A uniform
   column, centred as a whole, has exactly one left edge — which is the actual
   goal. Full-bleed and wide blocks opt out by name and keep their reach. */
/* Cap the TEXT elements that sit directly in the content container — and only
   those. Every one of them then has the same width, so the centring WordPress
   applies produces a single shared left edge instead of a ragged one.

   🔴 Two things are deliberately NOT touched:

   Component wrappers (.nwp-sponsors, .nwp-join, the squad grid, a Query block)
   keep the full column. They are layout, not reading, and their width is doing
   a different job.

   Anything NESTED inside those wrappers is left alone too, which is why this
   matches direct children only. An earlier version capped every descendant and
   pulled the Partners section into the middle of the page while Squads stayed
   flush — because the wrapper itself got narrowed. Capping by descendant
   requires maintaining a list of exceptions, and that list is guaranteed to
   fall behind the next component someone adds. Matching the direct children of
   the prose container needs no list at all. */
main .wp-block-post-content > :is( p, h1, h2, h3, h4, h5, h6, ul, ol, dl, blockquote, figcaption, pre ):not( [class*='nwp-'] ),
main .entry-content > :is( p, h1, h2, h3, h4, h5, h6, ul, ol, dl, blockquote, figcaption, pre ):not( [class*='nwp-'] ) {
	/* 🔴 ONE ABSOLUTE WIDTH, NOT `62ch`.

	   `ch` is font-relative, which is exactly right for a reading measure and
	   exactly wrong for aligning a column. 62ch of 16px body text is 535px;
	   62ch of an Oswald heading at 1.875rem is 1023px. Both were capped, both
	   got different widths, and the constrained parent then centred each of
	   them at its own width — putting the heading on one left edge and the
	   paragraph under it 240px further in. Measuring the boxes was the only
	   way to see it; the rule reads as if it makes everything the same.

	   `--nwp-container-reading` (42rem) is close to a 62–66 character line at
	   the body size and, being absolute, is identical for every element that
	   takes it. Identical widths, centred by the same parent, produce one
	   left edge — which is the actual requirement. */
	max-inline-size: var( --nwp-container-reading );
}

/* 🔴 THE PAGE TITLE JOINS THE COLUMN IT INTRODUCES.

   The title sits in its own group above the content, so the rule above does
   not reach it — leaving a full-width h1 on the page's left edge with its
   entire article starting 220px further in. A heading that does not share an
   edge with the text beneath it does not read as its heading.

   Taking the same absolute width puts it on the same centred column. Long
   titles now wrap to two lines, which for display type set at poster scale is
   the correct behaviour rather than a compromise.

   Scoped to `.nwp-prose` so composed pages — the homepage, Squads, the Match
   Centre — keep their full-width titles above full-width components. */
.nwp-prose main .wp-block-post-title,
.nwp-prose main > :is( h1, .wp-block-post-title ) {
	max-inline-size: var( --nwp-container-reading );
}

/* 🔴 `:not([class*='nwp-'])` IS THE WHOLE POINT OF THIS RULE.

   Capping by element type keeps catching components. The squad grid is a
   `<ul>`, so a rule listing `ul` gave it a 62ch reading measure and centred
   it — a two-column card grid squeezed into half the page with a 300px gutter
   beside its own flush-left heading. Before that it was the sponsor strip, and
   before that the whole page.

   The distinction that actually holds is not the tag. It is whether the
   element is PROSE or a COMPONENT, and in this theme every component wrapper
   carries an `nwp-` class while prose from the editor carries none. Selecting
   on that tests the real property instead of a proxy for it, and it needs no
   list of exceptions to fall behind. */

/* Prose that lives outside a post-content container still needs the cap.
 *
 * 🔴 `:not( [class*='nwp-'] )` IS THE POINT, for the same reason it is the
 * point thirty lines above. The opt-out list below names component wrappers
 * one at a time, and a list of exceptions falls behind the moment a component
 * is added: the Match Centre's matchday list arrived, was not on it, and every
 * row was capped to a 62-character reading measure, a results table squeezed
 * into 535px of an 1088px column with the score floating in the middle of the
 * page.
 *
 * A component carries an `nwp-` class. Testing that tests the real property
 * rather than maintaining a register of names. The ancestor opt-outs below
 * stay, because they cover the other case: unclassed prose elements INSIDE a
 * component, which this cannot see. */
main :is( p, li, dd, blockquote ):not( [class*='nwp-'] ) {
	max-inline-size: 62ch;
}

/* Small text needs a SHORTER measure, not the same one — the line is
   physically shorter but the character count is what tires the eye, and a
   14px line at 160 characters is the worst pairing on the site. */
main .wp-block-post-content > .has-small-font-size,
main .wp-block-post-content > .has-meta-font-size,
main .has-small-font-size,
main .has-meta-font-size,
.nwp-footer .has-meta-font-size,
.nwp-sponsors .has-meta-font-size,
.has-meta-font-size,
.nwp-state__meta {
	max-inline-size: 58ch;
	margin-inline: 0;
}

/* Opt-outs: anything whose width is structural rather than textual. */
main :is(
	.nwp-teamgrid, .nwp-fixtures, .nwp-results, .nwp-policylist,
	.nwp-sponsors__grid, .nwp-pathway__rail, .nwp-news__list,
	.nwp-matchday__list, .nwp-teamjump__list,
	.nwp-finder, .wp-block-table, .wp-block-columns, .wp-block-buttons
) :is( p, li, dd ) {
	max-inline-size: none;
}

main :is( .nwp-finder__hint, .nwp-finder__none, .nwp-pathway__intro, .nwp-pathway__foot ),
.nwp-finder__hint,
.nwp-finder__none,
.nwp-chero__sentence {
	max-inline-size: 52ch;
}

/* ==========================================================================
   1-0  ONE LEFT EDGE, EVERYWHERE
   🔴 The single most damaging layout bug in this theme, and it surfaced five
   separate times before it was understood.

   WordPress's constrained layout emits, for every direct child:
       > * { max-width: <contentSize>; margin-left: auto; margin-right: auto }

   So the moment any element is narrower than the content size — a short date,
   a capped measure, a button row — it CENTRES. The result is a column whose
   left edge moves from element to element: the post date indented while its
   title is flush, six different starts inside the join panel, the Back to
   Netball copy floating away from its own heading.

   The container stays centred. Its children do not. Alignment is a decision
   made once, here, rather than re-fought in every component.
   ========================================================================== */

/* 🔴 Pin TEXT to the start edge — never the containers.
   A first attempt pinned every child of `main`, which included the constrained
   70rem group itself: the whole page jumped hard against the viewport edge.
   Group and column wrappers must keep WordPress's centring; only the things
   that carry words get pinned. */
main :is(
	p, ol, ul, dl, blockquote, figcaption, table, figure,
	h1, h2, h3, h4, h5, h6,
	.wp-block-post-date, .wp-block-post-title, .wp-block-post-excerpt,
	.wp-block-buttons, .wp-block-separator
) {
	margin-inline-start: 0;
	margin-inline-end: 0;
}

/* Anything that genuinely wants centring asks for it by name. */
main .aligncenter,
main .has-text-align-center,
main .alignwide,
main .alignfull {
	margin-inline: auto;
}

/* 🔴 No gap between top-level page blocks. The root blockGap was inserting a
   16px strip of page ground between the header and the hero — a white seam
   across a dark fold. Sections own their own spacing; the shell owns none. */
.wp-site-blocks {
	gap: 0;
	/* 🔴 `clip`, not `hidden`. Full-bleed bands reach past the constrained
	   column by design; this stops that becoming a horizontal scrollbar
	   without creating a scroll container, which `hidden` would do and which
	   breaks `position: sticky` for anything inside. */
	overflow-x: clip;
}

.wp-site-blocks > * {
	margin-block: 0;
}

/* Containers. */
.nwp-container-reading {
	max-width: var( --nwp-container-reading );
	margin-inline: auto;
}

.nwp-container-club {
	max-width: var( --nwp-container-club );
	margin-inline: auto;
}

.nwp-container-match {
	max-width: var( --nwp-container-match );
	margin-inline: auto;
}

/* ==========================================================================
   2  IDENTITY
   🔴 The artwork is frozen (DEC-052). Nothing here recolours, redraws,
   simplifies, inverts, outlines, rotates, stretches, shears or shadows either
   asset. The ONLY permitted adaptation is changing what it sits ON.
   ========================================================================== */

.nwp-logo {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	flex: none;
	box-sizing: border-box;
}

.nwp-logo img {
	width: 100%;
	height: 100%;
	object-fit: contain;
}

/* The light plate. Used for the device on a dark ground, and for EITHER mark
   on a maroon SURFACE — the footer, the club statement.

   🔴 The inset is a padding in PIXELS set alongside the size, never a
   percentage. Percentage padding resolves against the containing block, not
   the element, so `padding: 6%` inside a wide parent silently exceeds the
   logo's own width and collapses the artwork to nothing. */
.nwp-logo--plate {
	background: var( --nwp-bone );
}

/* 🔴 Never sheared, tilted or shadowed. This is enforcement, not a reminder. */
.nwp-logo,
.nwp-logo * {
	transform: none !important;
	filter: none !important;
	box-shadow: none !important;
}

/* 🔴 The approved sub-96px treatment: a plain maroon tile. No simplified mark
   is invented — every alternative was considered and rejected (DEC-055). */
.nwp-favicon-fallback {
	display: inline-block;
	flex: none;
	background: var( --nwp-maroon );
	border-radius: var( --nwp-radius-none );
}

/* ==========================================================================
   3  SHEAR — 8°, one direction, never mirrored.
   🔴 Two events per page maximum, never adjacent. Club usually one.
   Governance zero.
   ========================================================================== */

/* 🔴 Panels and heroes shear their EDGE with clip-path, not their box.
   Skewing the box and counter-skewing the content fails here: the prohibition
   rules below force `transform: none` on buttons and tables, which cancels
   their counter-skew while the parent skew still applies — so the child comes
   out LEANING, the exact defect the prohibition exists to prevent. */
.nwp-shear-bottom {
	clip-path: polygon( 0 0, 100% 0, 100% calc( 100% - 3vw ), 0 100% );
	padding-block-end: calc( var( --nwp-space-3xl ) + 3vw );
}

.nwp-shear-top {
	clip-path: polygon( 0 3vw, 100% 0, 100% 100%, 0 100% );
	padding-block-start: calc( var( --nwp-space-3xl ) + 3vw );
}

/* 🔴 Suppressed entirely below 380px — the approved `xs` behaviour. */
@media ( max-width: 379px ) {
	.nwp-shear-bottom,
	.nwp-shear-top {
		clip-path: none;
	}

	.nwp-shear-bottom {
		padding-block-end: var( --nwp-space-3xl );
	}

	.nwp-shear-top {
		padding-block-start: var( --nwp-space-3xl );
	}
}

/* 🔴 Shear is PROHIBITED on all of these. Enforced here, not left to whoever
   composes the page: body copy, safeguarding, policy, tables, sponsor fields,
   form controls, buttons and both identity assets. */
.nwp-safeguarding,
.nwp-safeguarding *,
.nwp-policy,
.nwp-policy *,
.nwp-sponsors,
.nwp-sponsors *,
.wp-block-table,
.wp-block-table *,
.wp-block-button__link,
.nwp-button,
input,
select,
textarea {
	transform: none !important;
}

/* ==========================================================================
   3b  ON-MAROON CONTEXT
   🔴 A mode block redefines custom properties. It does NOT reset an inherited
   `color`, and it cannot beat an explicit colour that theme.json puts on an
   element. Setting the container to white therefore leaves the headings,
   list items and links inside it rendering near-black on maroon — 1.5:1,
   effectively invisible, and exactly the failure the palette work exists to
   prevent.
   ========================================================================== */

.nwp-on-maroon,
.nwp-on-maroon :is( h1, h2, h3, h4, h5, h6, p, li, dt, dd, strong, em, cite, blockquote, figcaption, time ) {
	color: var( --nwp-fixed-white );
}

.nwp-on-maroon a:not( .wp-block-button__link ) {
	color: var( --nwp-fixed-white );
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

/* Subordinate text on maroon: the light tint, which measures 6.9:1. */
.nwp-on-maroon .is-style-nwp-eyebrow,
.nwp-on-maroon .has-meta-font-size {
	color: var( --nwp-maroon-tint40 );
}

/* 🔴 The primary action must not be maroon-on-maroon. Inside a maroon field it
   inverts to white with maroon text. */
.nwp-on-maroon .wp-block-button.is-style-nwp-primary .wp-block-button__link {
	background: var( --nwp-fixed-white );
	color: var( --nwp-maroon );
	border-color: var( --nwp-fixed-white );
}

.nwp-on-maroon .wp-block-button.is-style-nwp-secondary .wp-block-button__link {
	color: var( --nwp-fixed-white );
	border-color: rgba( 255, 255, 255, 0.55 );
}

/* 🔴 The Start here panel sits INSIDE the maroon field but is itself white, so
   it must escape the on-maroon rules above. */
.nwp-on-maroon .nwp-starthere,
.nwp-on-maroon .nwp-starthere :is( h1, h2, h3, h4, p, li, dt, dd, strong, em ) {
	color: var( --nwp-fixed-ink );
}

.nwp-on-maroon .nwp-starthere a:not( .wp-block-button__link ) {
	color: var( --nwp-fixed-ink );
}

.nwp-on-maroon .nwp-starthere .is-style-nwp-eyebrow {
	color: var( --nwp-fixed-subtle );
}

.nwp-on-maroon .nwp-starthere .wp-block-button.is-style-nwp-primary .wp-block-button__link {
	background: var( --nwp-maroon );
	color: var( --nwp-fixed-white );
	border-color: var( --nwp-maroon );
}

/* ==========================================================================
   4  HEADER / FOOTER
   ========================================================================== */

/* 🔴 The header DISSOLVES INTO the surface beneath it. It was a white strip
   with a floating logo tile and five small links pushed right — documentation
   chrome with no relationship to the hero below. It now sits ON the hero's
   ground, sharing its colour, so the fold reads as one block rather than a
   bar and then a picture. */
/* 🔴 INK ON EVERY PAGE. Transparent-over-the-hero was tried and was wrong
   twice over: on interior pages there is no dark hero to sit on, and on the
   homepage the white page ground showed through and rendered the white nav
   links invisible. A committed dark bar is both safer and better — it leads
   into the hero instead of apologising in front of it. */
.nwp-header {
	position: relative;
	z-index: 5;
	padding: var( --nwp-space-sm ) var( --nwp-space-lg );
	background: var( --nwp-ink );
	border-block-end: 0;
	color: var( --nwp-fixed-white );
}

.nwp-header__inner {
	max-width: var( --nwp-container-wide );
	margin-inline: auto;
	gap: var( --nwp-space-lg );
	align-items: center;
}

.nwp-header a {
	color: var( --nwp-fixed-white );
}

.nwp-brand {
	display: inline-flex;
	align-items: center;
	gap: var( --nwp-space-sm );
	text-decoration: none;
	color: inherit;
}

.nwp-brand__text {
	display: grid;
	gap: 1px;
}

.nwp-brand__name {
	font-family: var( --nwp-font-display );
	text-transform: uppercase;
	letter-spacing: -0.02em;
	font-size: 1.25rem;
	line-height: 1;
}

.nwp-brand__sub {
	font-family: var( --nwp-font-mono );
	font-size: 0.625rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	opacity: 0.75;
}

/* Navigation. The compressed face at a size that can actually be seen, with
   an underline that grows from the baseline on hover rather than appearing.
   Mono at 12px was the "technical costume" tell; this is a club, not a
   terminal. */
.nwp-nav .wp-block-navigation-item__content {
	position: relative;
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding-inline: var( --nwp-space-xs );
	font-family: var( --nwp-font-compressed );
	font-size: 1.125rem;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	text-decoration: none;
	color: inherit;
}

.nwp-nav .wp-block-navigation-item__content::after {
	content: '';
	position: absolute;
	inset-inline: var( --nwp-space-xs );
	inset-block-end: 8px;
	block-size: 2px;
	background: currentColor;
	transform: scaleX( 0 );
	transform-origin: left center;
	transition: transform var( --nwp-dur-fast ) var( --nwp-ease-standard );
}

.nwp-nav .wp-block-navigation-item__content:hover::after,
.nwp-nav .wp-block-navigation-item__content:focus-visible::after {
	transform: scaleX( 1 );
}

/* The current page is marked with a persistent rule, not colour alone. */
.nwp-nav .current-menu-item .wp-block-navigation-item__content::after {
	transform: scaleX( 1 );
	opacity: 0.55;
}

@media ( prefers-reduced-motion: reduce ) {
	.nwp-nav .wp-block-navigation-item__content::after {
		transition: none;
	}
}

/* 🔴 Ink, not maroon. The join panel above is already a maroon field, and two
   maroon blocks in a row flatten each other. Ink bookends the header. */
.nwp-footer {
	background: var( --nwp-ink );
	color: var( --nwp-bone );
	padding: var( --nwp-space-huge ) var( --nwp-space-lg ) var( --nwp-space-xl );
}

.nwp-footer__inner {
	max-inline-size: var( --nwp-container-wide );
	margin-inline: auto;
	display: grid;
	gap: var( --nwp-space-xl );
	grid-template-columns: minmax( 0, 1fr );
}

@media ( min-width: 40rem ) {
	.nwp-footer__inner {
		grid-template-columns: repeat( 2, minmax( 0, 1fr ) );
	}
}

@media ( min-width: 62rem ) {
	.nwp-footer__inner {
		/* The brand block takes a wider column; the four link lists share the
		   rest evenly. */
		grid-template-columns: minmax( 0, 1.4fr ) repeat( 4, minmax( 0, 1fr ) );
		gap: var( --nwp-space-xxl );
	}
}

.nwp-footer__brand {
	display: grid;
	gap: var( --nwp-space-xs );
	justify-items: start;
	align-content: start;
}

.nwp-footer__name {
	margin: var( --nwp-space-xs ) 0 0;
	font-family: var( --nwp-font-heading );
	font-weight: 700;
	font-size: 1.0625rem;
}

.nwp-footer__place {
	margin: 0;
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --nwp-bone-dim );
}

.nwp-footer__heading {
	margin: 0 0 var( --nwp-space-sm );
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	font-weight: 500;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var( --nwp-bone-dim );
}

.nwp-footer ul {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var( --nwp-space-3xs );
}

.nwp-footer a {
	color: var( --nwp-bone );
	text-decoration: none;
	display: inline-flex;
	align-items: center;
	/* 44px, matching the target size the rest of the site keeps. The footer
	   was the one place still at 32px. */
	min-block-size: 44px;
	font-size: 0.9375rem;
}

.nwp-footer a:hover {
	text-decoration: underline;
	text-underline-offset: 0.2em;
}

/* --- Social ------------------------------------------------------------- */

.nwp-social {
	display: flex !important;
	flex-wrap: wrap;
	gap: var( --nwp-space-sm ) var( --nwp-space-md ) !important;
	margin-block-start: var( --nwp-space-sm ) !important;
}

/* 🔴 The icon is never the sole label — the platform name is visible beside
   it, not hidden behind a tooltip. DESIGN-TOKENS §11: icons are affordances,
   never the only thing naming a control. */
.nwp-social__link {
	display: inline-flex;
	align-items: center;
	gap: var( --nwp-space-2xs );
	min-block-size: 44px;
	color: var( --nwp-bone-dim );
}

/* ==========================================================================
   THE INVERTING WIPE
   ==========================================================================
   The brief: as the ground fades lighter, the mark fades darker, at the same
   pace.

   🔴 As a TEMPORAL crossfade that is not implementable, and the reason is
   arithmetic rather than effort. A dark ground going light and a light mark
   going dark must both pass through the middle of the range, at the same
   moment, by construction. Contrast at that instant is about 1:1 and the mark
   is gone. Retiming does not help — every schedule has the crossing somewhere,
   and `mix-blend-mode: difference` reproduces it exactly, because the
   difference of a mid-grey against itself is also mid-grey.

   Done SPATIALLY it works, and reads better than the crossfade would have.
   A bone panel wipes across on the club's 8° shear axis. At any instant every
   pixel of the ground is either ink or bone — never the average of the two —
   so the mark simply needs to be the opposite of whatever is directly behind
   it. `mix-blend-mode: difference` against white does that per pixel, for
   free: light on the ink side of the edge, dark on the bone side, inverting
   continuously as the edge sweeps through it.

   Both halves of the brief are satisfied — ground lightening and mark
   darkening, in perfect lockstep — and contrast is correct at every frame by
   construction rather than by measurement. `isolation` keeps the blend inside
   the control instead of reaching the page behind it.
   ========================================================================== */

.nwp-social__link {
	position: relative;
	isolation: isolate;
	overflow: hidden;
	transition: color var( --nwp-dur-fast ) var( --nwp-ease-standard );
}

.nwp-social__link::before {
	content: '';
	position: absolute;
	inset-block: 0;
	inset-inline-start: -14%;
	inline-size: 128%;
	z-index: -1;
	background: var( --nwp-bone );
	transform: skewX( var( --nwp-shear-angle ) ) translateX( -110% );
	transition: transform var( --nwp-dur-standard ) var( --nwp-ease-broadcast );
	pointer-events: none;
}

.nwp-social__link:hover::before,
.nwp-social__link:focus-visible::before {
	transform: skewX( var( --nwp-shear-angle ) ) translateX( 0 );
}

/* Exit faster than entrance. */
.nwp-social__link:not( :hover ):not( :focus-visible )::before {
	transition-duration: var( --nwp-dur-fast );
}

/* The mark inverts against whatever is under it, pixel by pixel. */
.nwp-social__icon {
	mix-blend-mode: difference;
	color: var( --nwp-fixed-white );
}

/* 🔴 The visible label in the footer cannot use difference blending — blended
   text renders without subpixel antialiasing and looks broken at 14px. It gets
   the safe treatment instead: it is only ever on one ground at a time, because
   the wipe is behind the icon column, not the words. */
.nwp-social__link:hover .nwp-social__name,
.nwp-social__link:focus-visible .nwp-social__name {
	color: var( --nwp-fixed-ink );
}

.nwp-social__icon {
	inline-size: 20px;
	block-size: 20px;
	flex: none;
}

.nwp-social__name {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
}

/* --- Legal line ---------------------------------------------------------- */

.nwp-footer__legal {
	max-inline-size: var( --nwp-container-wide );
	margin: var( --nwp-space-xxl ) auto 0;
	padding-block-start: var( --nwp-space-md );
	border-block-start: 1px solid rgba( 245, 241, 234, 0.16 );
	display: flex;
	flex-wrap: wrap;
	justify-content: space-between;
	gap: var( --nwp-space-sm );
}

.nwp-footer__legal p {
	margin: 0;
	font-size: 0.8125rem;
	line-height: 1.6;
	color: var( --nwp-bone-dim );
	max-inline-size: 62ch;
}

.nwp-footer__copy {
	font-family: var( --nwp-font-mono );
	letter-spacing: 0.08em;
}

/* 🔴 The footer surface is maroon, which is NOT an approved logo ground. The
   mark sits on a Bone plate — that changes the surface, never the artwork. */
.nwp-footer .nwp-logo--plate {
	background: var( --nwp-bone );
}

/* ==========================================================================
   5  ALERT — operational notices only.
   🔴 No danger variant exists. No red, no icon, no triangle, no alarm styling.
   🔴 Never used to style safeguarding urgency.
   ========================================================================== */

/* 🔴 A SHORT RULE ABOVE, NOT A COLOURED TAB DOWN THE SIDE.
   A thick coloured left border on a callout is the single most recognisable
   tell of generated UI, and this design system bans it outright above 1px.
   It had been used here at 2px, and at 4px for the operational variant.

   The replacement is grammar this system already speaks: the short accent
   rule that heads every section, at the same 3px and the same 4rem. An alert
   is then a small section rather than a card wearing a stripe — and it
   inherits meaning from a pattern the reader has already seen five times up
   the page, instead of introducing a new one. */
.nwp-alert {
	display: grid;
	gap: var( --nwp-space-2xs );
	padding: var( --nwp-space-md ) var( --nwp-space-lg );
	background: var( --nwp-surface );
	border-block-start: 1px solid var( --nwp-hairline );
}

.nwp-alert::before {
	content: '';
	display: block;
	inline-size: 4rem;
	block-size: 3px;
	margin-block-end: var( --nwp-space-2xs );
	background: var( --nwp-maroon );
}

/* The operational variant earns a longer rule, not a thicker one. Weight
   reads as alarm; length reads as emphasis, which is what is meant. */
.nwp-alert--operational::before {
	inline-size: 6rem;
}

/* ==========================================================================
   6  SAFEGUARDING AND POLICY — calm by construction
   ========================================================================== */

.nwp-safeguarding,
.nwp-policy {
	max-width: var( --nwp-container-reading );
	margin-inline: auto;
	/* 🔴 Colour is set explicitly, not inherited. A mode block redefines custom
	   properties but does NOT reset an inherited `color`, so governance content
	   dropped inside a dark surface would otherwise render bone-on-white. */
	color: var( --nwp-fixed-ink );
}

.nwp-safeguarding__route {
	display: grid;
	gap: var( --nwp-space-2xs );
	padding: var( --nwp-space-md );
	border: 1px solid var( --nwp-hairline );
	background: var( --nwp-warm );
	color: var( --nwp-fixed-ink );
}

/* 🔴 No badge, no icon, no trust framing, no red. */
.nwp-safeguarding__route::before {
	content: none;
}

.nwp-policy__meta {
	display: grid;
	gap: var( --nwp-space-2xs );
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	letter-spacing: 0.06em;
	color: var( --nwp-fixed-muted );
	padding: var( --nwp-space-md );
	border: 1px solid var( --nwp-hairline );
}

.nwp-policy__meta dl {
	display: grid;
	gap: var( --nwp-space-2xs );
	margin: 0;
}

@media ( min-width: 30rem ) {
	.nwp-policy__meta dl {
		grid-template-columns: minmax( 0, 12rem ) minmax( 0, 1fr );
	}
}

.nwp-policy__meta dt {
	text-transform: uppercase;
	letter-spacing: 0.14em;
}

.nwp-policy__meta dd {
	margin: 0;
}

/* --------------------------------------------------------------------------
   Download control.

   The stamp, running line and watermark are rendered into the page but belong
   only to a printed or saved copy. They are hidden here and revealed by
   policy-print.css.
   -------------------------------------------------------------------------- */

.nwp-print-only {
	display: none;
}

.nwp-policy__download {
	margin-block-start: var( --nwp-space-lg );
	padding-block-start: var( --nwp-space-md );
	border-top: 1px solid var( --nwp-hairline );
}

.nwp-policy__download-button {
	font-family: var( --nwp-font-heading );
	font-size: 1rem;
	color: var( --nwp-fixed-white );
	background: var( --nwp-maroon );
	border: 1px solid var( --nwp-maroon );
	border-radius: 2px;
	padding: var( --nwp-space-xs ) var( --nwp-space-md );
	cursor: pointer;
}

.nwp-policy__download-button:hover,
.nwp-policy__download-button:focus-visible {
	background: var( --nwp-maroon-deep );
	border-color: var( --nwp-maroon-deep );
}

.nwp-policy__download-note {
	font-size: 0.875rem;
	line-height: 1.5;
	color: var( --nwp-fixed-muted );
	margin-block-start: var( --nwp-space-xs );
	max-inline-size: 34rem;
}

/* An adopted governing-body policy: the club points at the source rather than
   handing out a copy it does not control. */
.nwp-policy__adopted {
	margin-block-start: var( --nwp-space-lg );
	padding: var( --nwp-space-md );
	border: 1px solid var( --nwp-maroon );
}

.nwp-policy__adopted-lead {
	font-size: 1rem;
	line-height: 1.55;
	margin: 0 0 var( --nwp-space-xs );
}

.nwp-policy__adopted-link {
	font-family: var( --nwp-font-heading );
	font-size: 1rem;
}

/* When the club last confirmed the adopted policy against England Netball.
   Quiet when all is well, plain when it is not. No alarm styling: a policy
   being under review is a process working, not an emergency. */
.nwp-policy__sourcecheck {
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	line-height: 1.55;
	color: var( --nwp-fixed-muted );
	margin-block-start: var( --nwp-space-sm );
	padding-block-start: var( --nwp-space-xs );
	border-top: 1px solid var( --nwp-hairline );
}

.nwp-policy__sourcecheck--changed,
.nwp-policy__sourcecheck--unverified {
	color: var( --nwp-fixed-ink );
	font-weight: 600;
}

/* --------------------------------------------------------------------------
   Version history. Sits at the FOOT of a policy, because the metadata block at
   the top answers "is this current?" and that is what a parent needs. This
   answers "what changed?", which matters to the committee and to anyone
   holding an older copy.

   Quiet by design. It is a provenance record, not content, and it must never
   compete with the policy itself for attention.
   -------------------------------------------------------------------------- */

.nwp-policy__history {
	margin-block-start: var( --nwp-space-xl );
	padding-block-start: var( --nwp-space-md );
	border-top: 1px solid var( --nwp-hairline );
}

.nwp-policy__history h2 {
	font-family: var( --nwp-font-heading );
	font-size: 1rem;
	color: var( --nwp-fixed-muted );
	margin-block-end: var( --nwp-space-sm );
}

.nwp-policy__history table {
	inline-size: 100%;
	border-collapse: collapse;
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	color: var( --nwp-fixed-muted );
}

.nwp-policy__history th,
.nwp-policy__history td {
	text-align: start;
	vertical-align: top;
	padding: var( --nwp-space-2xs ) var( --nwp-space-xs );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-policy__history thead th {
	text-transform: uppercase;
	letter-spacing: 0.14em;
	white-space: nowrap;
}

/* The version number is the row's label, so it is a th. Keep it unbold: this
   is a reference table, not a place for emphasis. */
.nwp-policy__history tbody th {
	font-weight: 400;
	white-space: nowrap;
}

/* ==========================================================================
   6b  SQUAD DETAIL — the page a parent reaches by clicking their child's
   age group. It answers which years, which night, and who coaches.

   🔴 The withheld note is styled to read as a STATEMENT, not an error.
   Nothing has gone wrong when a venue is not shown — a decision was taken.
   No red, no icon, no warning treatment; that would make an ordinary
   safeguarding default look like an alarm.
   ========================================================================== */

.nwp-squad {
	display: grid;
	gap: var( --nwp-space-md );
	margin-block: var( --nwp-space-lg );
}

.nwp-squad__pathway {
	margin: 0;
	font-size: 1.125rem;
	color: var( --nwp-ink );
}

.nwp-squad__facts {
	display: grid;
	gap: var( --nwp-space-2xs );
	margin: 0;
	padding: var( --nwp-space-md );
	border: 1px solid var( --nwp-hairline );
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	letter-spacing: 0.06em;
}

@media ( min-width: 30rem ) {
	.nwp-squad__facts {
		grid-template-columns: minmax( 0, 12rem ) minmax( 0, 1fr );
	}
}

.nwp-squad__facts dt {
	text-transform: uppercase;
	letter-spacing: 0.14em;
	color: var( --nwp-fixed-muted );
}

.nwp-squad__facts dd {
	margin: 0;
	color: var( --nwp-ink );
}

.nwp-squad__withheld {
	margin: 0;
	max-inline-size: 42rem;
	color: var( --nwp-fixed-muted );
}

.nwp-squad__coaches h2 {
	font-size: 1rem;
	text-transform: uppercase;
	letter-spacing: 0.14em;
	margin-block-end: var( --nwp-space-xs );
}

.nwp-squad__coaches ul {
	display: grid;
	gap: var( --nwp-space-2xs );
	margin: 0;
	padding: 0;
	list-style: none;
}

.nwp-squad__role {
	color: var( --nwp-fixed-muted );
}

.nwp-squad__role::before {
	content: "· ";
}

.nwp-squad__open {
	margin: 0;
	font-weight: 600;
}

/* ==========================================================================
   7  RESULTS — 🔴 never signalled by colour alone.
   Each carries a letterform AND a word.
   ========================================================================== */

.nwp-result {
	display: inline-flex;
	align-items: center;
	gap: var( --nwp-space-2xs );
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
}

.nwp-result__letter {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 1.5rem;
	block-size: 1.5rem;
	font-weight: 700;
	color: var( --nwp-result-ink );
}

.nwp-result--win .nwp-result__letter {
	background: var( --nwp-win );
}

.nwp-result--draw .nwp-result__letter {
	background: var( --nwp-draw );
}

.nwp-result--loss .nwp-result__letter {
	background: var( --nwp-loss );
}

/* ==========================================================================
   8  SPONSORS — 🔴 fixed-aspect slot, logo CONTAINED and never cropped.
   Partner brands are not ours to distort.
   ========================================================================== */

.nwp-sponsors__grid {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	grid-template-columns: minmax( 0, 1fr );
	/* Rows are equal height so the field reads as one strip rather than a
	   ragged set of boxes. Tier is expressed by SLOT height inside the tile,
	   never by making one tile taller than its neighbours. */
	align-items: stretch;
}

.nwp-sponsors__grid > li {
	display: grid;
}

/* 🔴 `auto-fit`, NOT a fixed column count — and the reason is a bug, not taste.

   The ruled field below is painted as a background on this grid, showing
   through 1px gaps. That is a good technique and it is kept. But it assumes
   every track is occupied: with `repeat(4, 1fr)` and two partners, tracks 3
   and 4 held nothing and the club's page showed two logos followed by a bare
   grey slab two cells wide. It would have broken identically at 1, 2, 3, 5, 6
   and 7 partners — every count except an exact multiple of four.

   `auto-fit` collapses an empty repeated track to zero AND collapses the
   gutters either side of it, so the painted ground can only ever appear
   between two real tiles. The strip is now correct at any number of partners,
   which for a volunteer-run club that gains and loses a sponsor a season is
   the only version that survives contact.

   The tracks are bounded rather than `1fr` so two partners do not each stretch
   to half the viewport; `fit-content` plus auto margins then centres the whole
   board instead of leaving it hanging off the left edge. */
@media ( min-width: 30rem ) {
	.nwp-sponsors__grid {
		grid-template-columns: repeat( auto-fit, minmax( 13rem, 17rem ) );
		justify-content: center;
		inline-size: fit-content;
		max-inline-size: 100%;
		margin-inline: auto;
	}
}

.nwp-sponsor {
	/* 🔴 REQUIRED, and not boilerplate. This theme has NO global border-box —
	   the only other declaration is on `.nwp-logo`. With the browser default of
	   content-box, `block-size: 100%` below resolved to the full row height and
	   then ADDED the block padding on top, so every tile stood taller than the
	   row it sat in. The result on the club's page: the tile's off-white field
	   spilling past the bottom of the grid's border, and a border that looked
	   like it had failed to close. Neither was a border bug; both were this. */
	box-sizing: border-box;
	position: relative;
	isolation: isolate;
	overflow: hidden;
	display: grid;
	gap: var( --nwp-space-xs );
	justify-items: center;
	text-align: center;
	align-content: center;
	/* Was `xl` block padding, which on a two-partner board produced tall tiles
	   mostly made of empty field. The logo is the content; the padding is the
	   mount, and a mount should not out-measure what it holds. */
	padding: var( --nwp-space-lg ) var( --nwp-space-md );
	block-size: 100%;
	/* 🔴 A neutral LIGHT field, held explicitly. No lime, no dark ground. */
	background: var( --nwp-fixed-field );
	color: var( --nwp-fixed-ink );
	/* Four outlined boxes in a row is the "same-size cards as page structure"
	   pattern, and it made the partners read as a form. The strip is now one
	   continuous field divided by rules: still even-handed by construction,
	   but it reads as a board rather than as four little cards. */
	border: 0;
}

/* ── Motion: a wipe, and 🔴 DELIBERATELY NOT THE SHEAR ─────────────────────

   The club's motion signature is the 8° shear at the scale of a control
   (DEC-060), and the reflex here was to reach for it — a sheared rule arriving
   at the tile's base, matching `.nwp-social__link`.

   🔴 That is prohibited on this component, twice over. The rule above sets
   `transform: none !important` on `.nwp-sponsors *`, and this pattern's header
   states plainly: "never on maroon, never on ink, NEVER SHEARED, and never
   adjacent to safeguarding content."

   A pseudo-element slips past the `*` selector on a technicality, which is
   exactly why writing the shear here would have been wrong rather than clever:
   the ban is a decision about whose space this is. The shear is the club's
   gesture, and a partner's tile is not the club's surface to inflect.

   So the wipe keeps the family — same easing, same exit-faster rule, same
   arrival from the inline-start — and travels straight. It also never crosses
   the artwork: it is the tile's own base rule, not a field sweeping under
   somebody else's logo.
   ------------------------------------------------------------------------- */

.nwp-sponsor::after {
	content: '';
	position: absolute;
	inset-block-end: 0;
	inset-inline: 0;
	block-size: 3px;
	/* Scale from the inline-start edge: no transform on the box, no shear, and
	   it animates a compositor-friendly property rather than width. */
	transform-origin: left center;
	/* 🔴 MAROON, NOT LIME — measured, not chosen.
	   Lime is the club's live-state accent and was the instinctive pick here.
	   On this tile field (#fbf9f7) it measures 1.10:1: an indicator nobody can
	   see, failing WCAG 1.4.11's 3:1 for a state indicator. The principal
	   maroon is 13.17:1 on the same ground.
	   Lime earns its keep on the maroon bands, where it is the high-contrast
	   partner. Here it would have been decoration that only worked on the
	   designer's monitor. */
	background: var( --nwp-maroon );
	scale: 0 1;
	transition: scale var( --nwp-dur-standard ) var( --nwp-ease-broadcast );
	pointer-events: none;
}

/* 🔴 `scale`, not `transform: scaleX()`. The prohibition above is written as
   `transform: none !important` and this component is inside its scope. `scale`
   is a separate CSS property, so the rule stands untouched and unweakened —
   the same reasoning the motion spec records for `translate` on buttons. No
   second `!important`, no exception carved into the ban. */
.nwp-sponsor:hover::after,
.nwp-sponsor:focus-within::after {
	scale: 1 1;
}

/* 🔴 Exit faster than entrance — a rule that leaves as slowly as it arrives
   reads as the interface lagging behind the pointer. */
.nwp-sponsor:not( :hover ):not( :focus-within )::after {
	transition-duration: var( --nwp-dur-fast );
}

/* 🔴 Hover is not a state a touchscreen has, and the primary visitor is a
   parent on a phone. Parked on touch, which also kills the sticky-hover
   artefact where a tapped tile keeps its bar until the next tap elsewhere.
   Focus still brings it in, because focus is real on every input. */
@media ( hover: none ) {
	.nwp-sponsor:hover::after {
		scale: 0 1;
	}

	.nwp-sponsor:focus-within::after {
		scale: 1 1;
	}
}

/* 🔴 Reduced motion removes TRAVEL, not FEEDBACK. The rule still appears — it
   just stops growing. A control that goes inert is a worse outcome than one
   that responds without moving. */
@media ( prefers-reduced-motion: reduce ) {
	.nwp-sponsor::after {
		transition: opacity var( --nwp-dur-fast ) var( --nwp-ease-standard );
		scale: 1 1;
		opacity: 0;
	}

	.nwp-sponsor:hover::after,
	.nwp-sponsor:focus-within::after {
		opacity: 1;
	}
}

/* 🔴 Calm mode is ZERO motion, regardless of preference, and it overrides
   `no-preference` too — it is not the visitor's preference to express. */
[ data-nwp-calm='true' ] .nwp-sponsor::after {
	transition: none;
	scale: 1 1;
	opacity: 0;
}

[ data-nwp-calm='true' ] .nwp-sponsor:hover::after,
[ data-nwp-calm='true' ] .nwp-sponsor:focus-within::after {
	opacity: 1;
}

/* 🔴 The tile is not a link and must not pretend to be one. Where a partner
   has supplied no URL there is nothing to activate, so the rule that signals
   "this responds" would be a lie told on hover. */
.nwp-sponsor:not( :has( a ) )::after {
	content: none;
}

/* The rules come from a 1px grid gap over a ruled background, so no two
   borders double up at a join. 3.34:1 against the field — the separation
   between one partner's mark and the next is meaningful, not decorative. */
.nwp-sponsors__grid {
	background: var( --nwp-fixed-rule-strong );
	gap: 1px;
	border: 1px solid var( --nwp-fixed-rule-strong );
}

/* 🔴 HEIGHT BUDGET, NOT A FIXED-ASPECT BOX.

   The slot was `aspect-ratio: 3/2` with the logo contained inside it. Contain
   fits the LONGEST side, so a wide lockup — the Avrenim mark is 800×139, very
   nearly 6:1 — shrank until its width fitted a 3:2 box, landing at roughly a
   quarter of the available height and reading as a smaller partner than a
   squarer logo beside it. The strip literally captioned itself "all partners
   shown at equal weight" while rendering them at visibly unequal weight.

   Equal weight between marks of different proportion is equal OPTICAL height,
   which is how a physical sponsor board is set out: every logo gets the same
   vertical budget and takes whatever width its own geometry needs. So the slot
   constrains height, lets width flow, and caps width at the tile so nothing
   can bleed. A 6:1 lockup and a 2.5:1 logo now read as peers.

   The 3:2 box was not wrong when the tier heights were 7rem/4.5rem/3.5rem and
   logos were assumed squarish. It stopped being right the moment real artwork
   arrived. */
.nwp-sponsor__slot {
	display: grid;
	place-items: center;
	inline-size: 100%;
	block-size: var( --nwp-sponsor-slot-h, 4rem );
	overflow: hidden;
}

/* Tier raises the budget rather than changing the shape, so the marks stay
   comparable to each other even when the club does grade its partners.
   🔴 With no tier set, every partner falls to `supporting` and the board is
   even-handed by construction — which is what the note above it claims. */
.nwp-sponsor__slot--principal {
	--nwp-sponsor-slot-h: 4.5rem;
}

.nwp-sponsor__slot--supporting {
	--nwp-sponsor-slot-h: 4rem;
}

.nwp-sponsor__slot--community {
	--nwp-sponsor-slot-h: 3.25rem;
}

/* 🔴 No logo, no slot. The fixed aspect exists to contain artwork without
   cropping it; with nothing to contain it just reserves empty field and —
   because the reserved height varies by tier — pushes each partner's name to
   a different baseline. A row of names at four different heights reads as
   broken, not as hierarchy. */
.nwp-sponsor__slot--wordmark {
	/* A set wordmark is type, not artwork, so it needs no height budget to be
	   contained within — it needs enough room to sit on the same optical line
	   as the logos beside it. */
	block-size: auto;
	min-block-size: var( --nwp-sponsor-slot-h, 4rem );
}

/* 🔴 The BOX fills the slot; `object-fit` fits the PICTURE inside it.
   Measured, after the previous approach shipped visibly broken.

   The obvious version — `max-inline-size: 100%; max-block-size: 100%` on an
   auto-sized image — fails whenever the logo is wider than the slot. The width
   cap binds first and scales the height proportionally to satisfy it; the
   percentage height cap never resolves against the grid area, so nothing
   catches the result. HCS measured 240×138 in a 52px slot: 86px of a partner's
   logo cut off, on the component whose stated rule is that it is never
   cropped.

   Giving the element the slot's exact dimensions and letting `contain`
   letterbox the bitmap inside cannot fail that way, at any aspect ratio,
   because the element never has to be measured at all. */
.nwp-sponsor__slot img {
	inline-size: auto;
	block-size: auto;
	/* 🔴 Not 100%: a very wide lockup would otherwise run the full width of the
	   tile and read as the dominant partner purely because of its proportions.
	   Holding the widest marks off the edge costs them a little size and buys
	   every squarer logo beside them a fairer share of the eye. The two caps
	   together are as close to equal optical weight as CSS can get without
	   per-logo tuning — a 6:1 lockup and a 1.7:1 roundel can never fill the
	   same box, and pretending otherwise is what produced the original mess. */
	max-inline-size: 88%;
	/* 🔴 A LENGTH, never `100%` — and this is the whole bug, twice over.
	   A percentage max-height has to resolve against the containing block, and
	   against a grid area it silently does not: it falls back to auto, the
	   width cap alone decides the size, and the intrinsic ratio supplies a
	   height nothing then checks. HCS measured 240×138 in a 52px slot.
	   The same custom property that sets the slot's height sets the cap here,
	   so the two cannot drift, and no percentage has to resolve at all. */
	max-block-size: var( --nwp-sponsor-slot-h, 4rem );
	/* 🔴 contain, never cover. */
	object-fit: contain;
	object-position: center;

	/* 🔴 Neutralises a baked-in white matte.
	   The HCS artwork is a 2005-era GIF with a hard white rectangle behind it,
	   which sat on the tile's warm off-white field as a visible pale box.
	   Multiplying against a light ground drops white to nothing while leaving
	   the mark itself untouched — so a partner who has never supplied a
	   transparent file still sits on the same field as everyone else. */
	mix-blend-mode: multiply;

	/* 🔴 Grey at rest, colour on hover — but the colour is NOT the message.
	   Greyscale evens out artwork the club does not control: a scanned red
	   GIF and a clean gradient lockup read as one set rather than as one
	   partner shouting. Nothing is communicated by the colour returning, so a
	   visitor who never hovers, or cannot, loses no information — which is the
	   only reason this treatment is acceptable at all. */
	filter: grayscale( 1 );
	transition:
		filter var( --nwp-dur-standard ) var( --nwp-ease-standard ),
		opacity var( --nwp-dur-standard ) var( --nwp-ease-standard );
	opacity: 0.78;
}

.nwp-sponsor:hover .nwp-sponsor__slot img,
.nwp-sponsor:focus-within .nwp-sponsor__slot img {
	filter: grayscale( 0 );
	opacity: 1;
}

/* Exit faster than entrance, as everywhere else. */
.nwp-sponsor:not( :hover ):not( :focus-within ) .nwp-sponsor__slot img {
	transition-duration: var( --nwp-dur-fast );
}

/* 🔴 A touchscreen has no hover, and the primary visitor is a parent on a
   phone. Leaving the logos grey for them would mean every partner is only ever
   seen in the club's downgraded version — a real discourtesy to an organisation
   giving the club money. On touch, colour is the resting state. */
@media ( hover: none ) {
	.nwp-sponsor__slot img {
		filter: grayscale( 0 );
		opacity: 1;
	}
}

/* Reduced motion: the change still happens, it just does not fade. */
@media ( prefers-reduced-motion: reduce ) {
	.nwp-sponsor__slot img {
		transition: none;
	}
}

/* 🔴 Calm mode: no transition at all, and no greyed resting state either.
   A policy or safeguarding page is not a surface for interface character. */
[ data-nwp-calm='true' ] .nwp-sponsor__slot img {
	transition: none;
	filter: grayscale( 0 );
	opacity: 1;
}

/* 🔴 The tile is the hit area, not the logo. A parent tapping "somewhere near
   the sponsor" should land on the link, and 44px is the touch default from the
   motion spec. Stretching the anchor over the tile also means the focus ring
   frames something the size of a control rather than the size of an image. */
.nwp-sponsor a {
	display: grid;
	place-items: center;
	gap: inherit;
	inline-size: 100%;
	min-block-size: 44px;
	color: inherit;
	text-decoration: none;
}

/* 🔴 An explicit ring: there is no global focus style for arbitrary links in
   this theme, so this was relying on the browser default over a coloured
   field. The offset keeps it clear of the partner's artwork. */
.nwp-sponsor a:focus-visible {
	outline: 3px solid var( --nwp-maroon );
	outline-offset: 3px;
}

/* ==========================================================================
   9  STATES — empty, loading, error
   🔴 No lime on an error state. Lime means LIVE; an error is not a live state.
   ========================================================================== */

.nwp-state {
	display: grid;
	gap: var( --nwp-space-xs );
	justify-items: start;
	padding: var( --nwp-space-xl ) var( --nwp-space-lg );
	background: var( --nwp-surface );
	border: 1px dashed var( --nwp-hairline-strong );
}

/* Same reasoning as the alert above: the empty/error state marks itself with
   the system's accent rule, not with a coloured tab. */
.nwp-state--error {
	border-style: solid;
}

.nwp-state--error::before {
	content: '';
	display: block;
	inline-size: 4rem;
	block-size: 3px;
	margin-block-end: var( --nwp-space-2xs );
	background: var( --nwp-maroon );
}

.nwp-state__meta {
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	color: var( --nwp-text-muted );
}

/* ==========================================================================
   9b  THE HOMEPAGE FOLD AND THE LOCKED PANEL
   ========================================================================== */

/* 🔴 THE FOLD.
   Ink, not maroon: maroon is the club's colour but a full-bleed maroon field
   with nothing in it reads as an unfilled box. Ink gives the type somewhere to
   burn, and holds the maroon for the shapes that carry meaning. */
.nwp-chero {
	position: relative;
	overflow: hidden;
	background: var( --nwp-ink ) !important;
	isolation: isolate;
	min-block-size: min( 88vh, 54rem );
	display: grid;
	align-content: center;
}

/* A maroon field cut on the shear axis, running under the type. This is the
   club colour doing structural work instead of being a background. */
.nwp-chero::after {
	content: '';
	position: absolute;
	inset: 0 42% 0 -10%;
	background: var( --nwp-maroon );
	transform: skewX( -8deg );
	z-index: -2;
	pointer-events: none;
}

/* 🔴 THE PANTHER AT SCALE (DEC-056).
   Placed as COMPOSITION, not as a cropped asset: the complete, unmodified
   artwork is positioned so the page edge decides what is seen. No cropped
   file exists, no path is altered, nothing is recoloured or sheared — which
   keeps DEC-052 and DEC-055 intact. */
.nwp-chero::before {
	content: '';
	position: absolute;
	/* Sits on the maroon field, leading left — the animal runs INTO the
	   statement rather than decorating a corner behind a panel. Held high
	   enough that the head reads: cropping it to a set of legs turns the mark
	   into an abstract smudge, which is not what the identity is for. */
	inset-block-end: -6%;
	inset-inline-start: -18%;
	inline-size: min( 52rem, 60% );
	aspect-ratio: 1;
	background: url( '../img/nwp-panther-device-unchanged.svg' ) no-repeat center / contain;
	/* On the maroon field the artwork's dark body needs to read as a shadow of
	   itself, not as a grey smudge: a low-opacity multiply deepens the maroon
	   rather than greying it. */
	mix-blend-mode: multiply;
	opacity: 0.5;
	z-index: -1;
	pointer-events: none;
}

@media ( max-width: 899px ) {
	.nwp-chero {
		min-block-size: 0;
	}

	.nwp-chero::after {
		inset-inline: -20% -20%;
	}

	.nwp-chero::before {
		inline-size: 110%;
		inset-inline-end: -34%;
		inset-block-end: -8%;
		opacity: 0.1;
	}
}

.nwp-chero__inner {
	position: relative;
	inline-size: 100%;
}

/* The words column and the panel share the fold. Neither stretches to match
   the other, so the field does not grow a dead area under the statement. */
.nwp-chero__inner .wp-block-columns {
	align-items: flex-start;
	gap: var( --nwp-space-xxxl );
	margin-block-end: 0;
}

.nwp-chero__inner .wp-block-column {
	align-self: start;
}

/* The statement at poster scale. This is the whole point of the direction. */
.nwp-chero .is-style-nwp-display {
	font-size: clamp( 2.75rem, 8.5vw, 7rem );
	max-width: 12ch;
	margin-block: 0 var( --nwp-space-lg );
}

.nwp-chero__eyebrow,
.nwp-chero .is-style-nwp-eyebrow {
	margin-block-end: var( --nwp-space-lg );
}

/* 🔴 Two lines. The scale is locked, so the measure is what gives. */
.nwp-chero .is-style-nwp-display {
	max-width: 16ch;
	margin-block-end: var( --nwp-space-sm );
}

/* 🔴 The locked four-question panel — the best idea on the site, previously
   dressed as an FAQ widget. It is the club answering the four questions a
   parent actually arrived with, so it is set as a plain white plate with the
   questions at real size and the answers subordinate. On WHITE, inside the
   field, never sheared. */
.nwp-starthere {
	display: grid;
	gap: var( --nwp-space-md );
	transform: none !important;
	box-shadow: 0 18px 48px rgba( 10, 10, 12, 0.28 );
}

.nwp-starthere__head {
	font-family: var( --nwp-font-compressed ) !important;
	font-size: 1.125rem !important;
	letter-spacing: 0.1em;
	text-transform: uppercase;
}

.nwp-starthere__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
}

.nwp-starthere__list li {
	border-block-start: 1px solid var( --nwp-fixed-rule-soft );
}

.nwp-starthere__list li:first-child {
	border-block-start: 0;
}

/* A leading rule that grows on hover — the row reads as a destination rather
   than as a line of text with a link in it. */
/* 🔴 The indent is RESERVED, not animated.
   This transitioned `padding-inline-start` from 0, which relayouts the row —
   and every row after it — on each frame of a hover. The space is now held
   permanently and the CONTENT is moved with `translate`, which the compositor
   handles without touching layout. The effect on screen is identical; the
   difference is that nothing reflows. */
.nwp-starthere__list li {
	position: relative;
	padding-inline-start: var( --nwp-space-sm );
}

.nwp-starthere__list li::before {
	content: '';
	position: absolute;
	inset-block: 12px;
	inset-inline-start: 0;
	inline-size: 2px;
	background: var( --nwp-maroon );
	transform: scaleY( 0 );
	transform-origin: top center;
	transition: transform var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-starthere__list li > * {
	transition: translate var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-starthere__list li:hover > *,
.nwp-starthere__list li:focus-within > * {
	translate: var( --nwp-space-2xs ) 0;
}

.nwp-starthere__list li:hover::before,
.nwp-starthere__list li:focus-within::before {
	transform: scaleY( 1 );
}

@media ( prefers-reduced-motion: reduce ) {
	.nwp-starthere__list li,
	.nwp-starthere__list li > *,
	.nwp-starthere__list li::before {
		transition: none;
	}

	.nwp-starthere__list li:hover > *,
	.nwp-starthere__list li:focus-within > * {
		translate: none;
	}
}

/* 44px minimum tap row at EVERY viewport, not only on mobile. A parent
   reading this on a phone in a car park is the intended user. */
.nwp-starthere__list a,
.nwp-on-maroon .nwp-starthere__list a:not( .wp-block-button__link ) {
	display: grid;
	gap: 2px;
	align-content: center;
	min-height: 44px;
	padding-block: var( --nwp-space-xs );
	/* 🔴 The whole row is one link, so only the QUESTION carries the underline.
	   Underlining both lines reads as two separate destinations. */
	text-decoration: none;
	line-height: 1.35;
}

.nwp-starthere__list a strong {
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

/* The answer is supporting text, not a second link. */
.nwp-starthere__list a {
	color: var( --nwp-fixed-subtle );
}

.nwp-on-maroon .nwp-starthere__list a strong {
	color: var( --nwp-fixed-ink );
}

.nwp-starthere__list a strong {
	font-size: 0.9375rem;
}

.nwp-starthere__list a:hover strong {
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

/* ==========================================================================
   9b  MATCH CENTRE

   Operate mode. Somebody wants one squad's last result, next fixture and
   league position, usually on a phone, sometimes standing at a venue.
   Scanability beats expression, and the brand lives in the details.

   There is no live score component here because the club has no volunteer to
   score a match live. An empty "Live" panel every Sunday would read as a
   fault; the page is a record, and says so.
   ========================================================================== */

.nwp-matchcentre {
	display: grid;
	gap: var( --nwp-space-xl );
}

/* --- The chooser ----------------------------------------------------------
   Eleven entries across four leagues is the single most specific fact about
   this page: it is a club's season, not a team's. That makes choosing one the
   page's first job, so it gets a real control rather than a list of links. */

.nwp-chooser {
	display: grid;
	gap: var( --nwp-space-xs );
	padding-block-end: var( --nwp-space-lg );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-chooser__label {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
}

.nwp-chooser__controls {
	display: flex;
	flex-wrap: wrap;
	gap: var( --nwp-space-xs );
	align-items: stretch;
}

/* The select is drawn rather than left to the browser. A default control is
   the one element on the page that belongs to no design system, and on a dark
   ground it arrives as a light rectangle. */
.nwp-chooser__select {
	flex: 1 1 18rem;
	min-block-size: 2.75rem;
	padding: var( --nwp-space-xs ) var( --nwp-space-xl ) var( --nwp-space-xs ) var( --nwp-space-sm );
	font-family: inherit;
	font-size: 1rem;
	font-weight: 600;
	color: var( --nwp-text );
	background-color: var( --nwp-surface );
	border: 1px solid var( --nwp-hairline-strong );
	border-radius: 0;
	appearance: none;
	/* The disclosure arrow, as geometry rather than as a glyph. currentColor
	   keeps it correct in both modes without a second asset. */
	background-image: linear-gradient( 45deg, transparent 50%, currentColor 50% ),
		linear-gradient( 135deg, currentColor 50%, transparent 50% );
	background-position: right 1.05rem center, right 0.75rem center;
	background-size: 0.3rem 0.3rem, 0.3rem 0.3rem;
	background-repeat: no-repeat;
}

.nwp-chooser__select optgroup {
	font-style: normal;
	font-weight: 700;
	color: var( --nwp-text-muted );
	background-color: var( --nwp-surface );
}

.nwp-chooser__select option {
	font-weight: 400;
	color: var( --nwp-text );
	background-color: var( --nwp-surface );
}

/* 🔴 Outlined, not filled.
   This button disappears the moment the enhancement script runs, and the page
   spec caps accent controls at three per viewport. A control that most people
   never see should not be the brightest object on the page, the accent is
   spent on the club's own row in the table, which is the thing somebody came
   to find. */
.nwp-chooser__go {
	min-block-size: 2.75rem;
	padding-inline: var( --nwp-space-lg );
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --nwp-text );
	background-color: transparent;
	border: 1px solid var( --nwp-hairline-strong );
	cursor: pointer;
	transition: border-color var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-chooser__go:hover,
.nwp-chooser__go:focus-visible {
	border-color: var( --nwp-text );
}

/* 🔴 Hidden only once the script that replaces it is actually running, so a
   blocked or failed script leaves a working button rather than no control. */
.nwp-chooser--enhanced .nwp-chooser__go {
	display: none;
}

/* --- What you are reading ------------------------------------------------- */

.nwp-matchcentre__head {
	display: grid;
	gap: var( --nwp-space-2xs );
}

.nwp-matchcentre__division {
	font-family: var( --nwp-font-display );
	font-size: clamp( 2rem, 6vw, 3rem );
	line-height: 1.02;
	margin: 0;
	text-wrap: balance;
}

.nwp-matchcentre__meta {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
	margin: 0;
}

/* --- Two columns ----------------------------------------------------------
   The three sections are not equals. Results and fixtures are the club's own
   season and read as a sequence; the table is a reference object you look
   across. One column on a phone, in that reading order. */

.nwp-matchcentre__cols {
	display: grid;
	gap: var( --nwp-space-xxl );
}

.nwp-matchcentre__season,
.nwp-matchcentre__standing {
	display: grid;
	gap: var( --nwp-space-xxl );
	align-content: start;
}

@media ( min-width: 60rem ) {
	.nwp-matchcentre__cols {
		grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1.05fr );
		gap: var( --nwp-space-2xl ) var( --nwp-space-xxl );
	}

	/* The table column is ruled off rather than boxed. A card here would make
	   the table a widget sitting on the page instead of part of it. */
	.nwp-matchcentre__standing {
		padding-inline-start: var( --nwp-space-xxl );
		border-inline-start: 1px solid var( --nwp-hairline );
	}
}

/* --- Sections ------------------------------------------------------------- */

.nwp-mcsection {
	display: grid;
	gap: var( --nwp-space-md );
}

.nwp-mcsection__heading {
	font-family: var( --nwp-font-compressed );
	text-transform: uppercase;
	font-size: clamp( 1.375rem, 4vw, 1.75rem );
	line-height: 0.95;
	margin: 0;
	padding-block-start: var( --nwp-space-sm );
	border-block-start: 3px solid var( --nwp-rule-accent );
}

/* 🔴 Why the venue and the kick-off are not on the page. Silence looks like an
   omission somebody forgot to fill in; a stated reason looks like the decision
   it is. */
.nwp-mcsection__note {
	font-size: 0.875rem;
	line-height: 1.5;
	color: var( --nwp-text-muted );
	margin: 0;
	max-inline-size: 46ch;
	/* Separated from the disclosure above it, which it is not part of: the
	   note applies to every fixture in the competition, folded or not. */
	padding-block-start: var( --nwp-space-xs );
}

/* --- The archives ---------------------------------------------------------
   🔴 /fixtures/ and /results/ are THE CLUB'S WEEKEND, not the leagues'
   divisions.

   Grouped by competition these were unreadable for the people who use them. A
   parent looking for how their daughter got on had to know that the Greens
   play Warrington Years 7&8 Division 1 before they could find the row, and the
   word "Greens" was nowhere on the page. A committee member wanting Sunday's
   results had to scan eleven boxes and assemble the weekend themselves.

   One list, in date order, with the side named on every row. The
   per-competition view still exists in depth on the Match Centre, and this
   page is the way in to it. */

/* Straight to your team. The club's own names, nothing else. */
.nwp-teamjump {
	display: grid;
	gap: var( --nwp-space-xs );
	padding-block-end: var( --nwp-space-lg );
	margin-block-end: var( --nwp-space-xl );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-teamjump__label {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	font-weight: 400;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
	margin: 0;
}

.nwp-teamjump__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: flex;
	flex-wrap: wrap;
	gap: var( --nwp-space-xs );
}

.nwp-teamjump__link {
	display: inline-flex;
	align-items: center;
	min-block-size: 2.75rem;
	padding-inline: var( --nwp-space-md );
	font-family: var( --nwp-font-compressed );
	text-transform: uppercase;
	font-size: 1.0625rem;
	letter-spacing: 0.01em;
	text-decoration: none;
	color: var( --nwp-text );
	border: 1px solid var( --nwp-hairline-strong );
	transition: border-color var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-teamjump__link:hover,
.nwp-teamjump__link:focus-visible {
	border-color: var( --nwp-text );
}

/* A matchday. Netball here is a Sunday sport, so the day is a real unit. */
.nwp-matchdays {
	display: grid;
	gap: var( --nwp-space-xl );
}

.nwp-matchday {
	display: grid;
	gap: var( --nwp-space-xs );
}

.nwp-matchday__date {
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	font-weight: 400;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
	margin: 0;
	padding-block-end: var( --nwp-space-2xs );
	border-block-end: 1px solid var( --nwp-hairline-strong );
}

.nwp-matchday__list {
	list-style: none;
	margin: 0;
	padding: 0;
}

/* 🔴 The cell a parent reads first, so it leads the row and is set as a label
   rather than as body text. It is the club's own name for the side, Greens,
   Pinks, U13, Tigers, and it is a link to that side's Match Centre. */
.nwp-matchrow__side {
	grid-area: side;
	align-self: center;
	font-family: var( --nwp-font-compressed );
	text-transform: uppercase;
	font-size: 1rem;
	line-height: 1;
	letter-spacing: 0.01em;
	text-decoration: none;
	color: var( --nwp-text );
	border-block-end: 2px solid transparent;
	transition: border-color var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

a.nwp-matchrow__side:hover,
a.nwp-matchrow__side:focus-visible {
	border-block-end-color: var( --nwp-state-active );
}

/* The sided variants add a leading column for the side and keep everything
   else where it already was. */
.nwp-resultrow.nwp-resultrow--sided {
	grid-template-columns: 6rem auto minmax( 0, 1fr ) auto;
	grid-template-areas: 'side outcome teams score';
	column-gap: var( --nwp-space-md );
}

.nwp-fixture.nwp-fixture--sided {
	grid-template-columns: 6rem minmax( 0, 1fr ) auto;
	grid-template-areas: 'side teams meta';
	column-gap: var( --nwp-space-md );
}

.nwp-fixture--sided .nwp-fixture__teams {
	grid-area: teams;
}

.nwp-fixture--sided .nwp-fixture__meta {
	grid-area: meta;
}

/* On a phone the side sits above the match rather than beside it: at 390px a
   5.5rem column left the opponent 12 characters and wrapped every row to
   three lines. */
@media ( max-width: 37.49rem ) {
	.nwp-resultrow.nwp-resultrow--sided {
		grid-template-columns: auto minmax( 0, 1fr ) auto;
		grid-template-areas:
			'side    side  side'
			'outcome teams score';
		row-gap: var( --nwp-space-2xs );
	}

	.nwp-fixture.nwp-fixture--sided {
		grid-template-columns: minmax( 0, 1fr ) auto;
		grid-template-areas:
			'side  side'
			'teams meta';
		row-gap: var( --nwp-space-2xs );
	}

	.nwp-matchrow__side {
		justify-self: start;
		align-self: start;
	}
}

/* --- The rest of a season, folded -----------------------------------------
   A native <details>. No script, keyboard-operable, and the summary counts
   what is inside so somebody can decide whether to open it without opening
   it. A CJNL division publishes twenty-two fixtures running to next June;
   almost nobody arriving here wants all of them at once. */

.nwp-fold {
	margin-block-start: calc( var( --nwp-space-sm ) * -1 );
}

.nwp-fold__summary {
	display: inline-flex;
	align-items: center;
	gap: var( --nwp-space-xs );
	padding-block: var( --nwp-space-sm );
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
	cursor: pointer;
	list-style: none;
	transition: color var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-fold__summary::-webkit-details-marker {
	display: none;
}

.nwp-fold__summary:hover {
	color: var( --nwp-text );
}

/* The disclosure triangle, as geometry in currentColor rather than the
   browser's own marker or a glyph standing in for an icon. */
.nwp-fold__summary::before {
	content: '';
	inline-size: 0.4rem;
	block-size: 0.4rem;
	border-inline-end: 1px solid currentColor;
	border-block-end: 1px solid currentColor;
	transform: rotate( 45deg );
	transform-origin: center;
	transition: transform var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-fold[ open ] .nwp-fold__summary::before {
	transform: rotate( -135deg );
}

@media ( prefers-reduced-motion: reduce ) {
	.nwp-fold__summary::before {
		transition: none;
	}
}

/* --- Provenance -----------------------------------------------------------
   A club website asserting somebody else's league table should say whose, and
   when it last looked. This is also where a reader is told that matches are
   not scored live, rather than being left to conclude the page is broken. */

.nwp-mcprovenance {
	display: grid;
	gap: var( --nwp-space-2xs );
	padding-block-start: var( --nwp-space-lg );
	border-block-start: 1px solid var( --nwp-hairline );
	font-size: 0.8125rem;
	line-height: 1.5;
	color: var( --nwp-text-muted );
}

/* The rule belongs to the page and runs its full width; the prose keeps a
   reading measure. Capping the whole block made the rule stop halfway across
   and the footnote look like it belonged to the fixtures column. */
.nwp-mcprovenance p {
	margin: 0;
	color: inherit;
	max-inline-size: 62ch;
}

/* ==========================================================================
   9c  LISTINGS RENDERED BY THE PLUGIN
   ========================================================================== */

.nwp-teamgrid,
.nwp-fixtures,
.nwp-results,
.nwp-policylist__items {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	gap: var( --nwp-space-sm );
}

.nwp-teamgrid {
	grid-template-columns: repeat( auto-fit, minmax( 15rem, 1fr ) );
	gap: var( --nwp-space-lg );
}

/* Squad cards. The border-and-grey-box treatment was the lazy container the
   craft floor warns about — same-size boxes as the page structure. These are
   now edge-defined: a heavy rule on the leading edge, no fill, and the age
   label carrying the whole card. */
.nwp-teamcard {
	display: grid;
	gap: var( --nwp-space-xs );
	align-content: start;
	padding: var( --nwp-space-lg ) 0 var( --nwp-space-lg ) var( --nwp-space-lg );
	background: transparent;
	border: 0;
	border-inline-start: 2px solid var( --nwp-maroon );
	position: relative;
	transition: border-color var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

.nwp-teamcard:hover {
	border-inline-start-color: var( --nwp-ink );
}

/* 🔴 The age label IS the identifier, so it is set as a graphic object rather
   than as a heading. Squads are distinguished TYPOGRAPHICALLY — there is no
   per-squad colour coding, and none is needed when the scale does the work. */
.nwp-teamcard__age {
	font-family: var( --nwp-font-compressed );
	text-transform: uppercase;
	font-size: clamp( 2.75rem, 5vw, 4.25rem );
	line-height: 0.82;
	letter-spacing: -0.005em;
	padding-block-end: 0.08em;
	margin: 0;
	color: var( --nwp-maroon );
}

.nwp-teamcard h3 {
	margin: 0;
	font-family: var( --nwp-font-heading );
	font-size: 1.0625rem;
	font-weight: 600;
}

/* ==========================================================================
   9d  SECTION RHYTHM
   A page of white bands with grey boxes has no depth. Alternating grounds
   give the eye somewhere to land and make the maroon mean something when it
   arrives.
   ========================================================================== */

.nwp-band {
	padding-block: var( --nwp-space-huge );
	padding-inline: var( --nwp-space-lg );
}

.nwp-band--ink {
	background: var( --nwp-ink );
	color: var( --nwp-bone );
	position: relative;
	overflow: hidden;
}

.nwp-band--ink :is( h1, h2, h3, h4, p, li, dt, dd ) {
	color: var( --nwp-bone );
}

.nwp-band--warm {
	background: var( --nwp-warm );
}

/* 🔴 The panther as a SECTION MARKER (DEC-056). Composition, not a cropped
   asset — the band's own edge decides what is seen. */
.nwp-band--ink::before {
	content: '';
	position: absolute;
	inset-block-start: -30%;
	inset-inline-start: -8%;
	inline-size: min( 40rem, 46% );
	aspect-ratio: 1;
	background: url( '../img/nwp-panther-device-unchanged.svg' ) no-repeat center / contain;
	opacity: 0.07;
	pointer-events: none;
}

/* 🔴 SCALE CONTRAST. A 7rem hero followed by 24px section headings collapses
   the hierarchy at the first scroll — the page stops being confident the
   moment you leave the fold. Section headings run at display scale, with a
   maroon rule that ties them to the field above. */
main h2.is-style-nwp-display {
	font-size: clamp( 2rem, 4.5vw, 3.5rem );
	margin-block: var( --nwp-space-xxl ) var( --nwp-space-lg );
	position: relative;
	padding-block-start: var( --nwp-space-md );
}

main h2.is-style-nwp-display:first-child {
	margin-block-start: 0;
}

main h2.is-style-nwp-display::before {
	content: '';
	position: absolute;
	inset-block-start: 0;
	inset-inline-start: 0;
	inline-size: 3.5rem;
	block-size: 3px;
	background: var( --nwp-rule-accent );
}

/* Section headings: an eyebrow is a system only if it is not everywhere.
   These carry a rule and scale instead. */
.nwp-sectionhead {
	display: grid;
	gap: var( --nwp-space-sm );
	margin-block-end: var( --nwp-space-xl );
	max-width: var( --nwp-container-wide );
	margin-inline: auto;
}

.nwp-sectionhead__rule {
	inline-size: 3.5rem;
	block-size: 3px;
	background: var( --nwp-rule-accent );
}

.nwp-band--ink .nwp-sectionhead__rule {
	background: var( --nwp-bone );
}

.nwp-teamcard__nights,
.nwp-teamcard__open {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
	margin: 0;
}

/* 🔴 Grid, not flex-wrap. As a wrapping flex row the date landed in a
   different place on every line, inline after a short opponent name, below
   after a long one, and a column of results stopped being a column. Every
   cell now has a fixed place, including the empty one a scratched match
   leaves where a score would be. */
.nwp-resultrow {
	display: grid;
	grid-template-columns: auto 1fr auto;
	grid-template-areas:
		'outcome teams score'
		'.       date  date';
	align-items: baseline;
	gap: var( --nwp-space-2xs ) var( --nwp-space-sm );
	padding-block: var( --nwp-space-sm );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-resultrow .nwp-result {
	grid-area: outcome;
}

.nwp-resultrow__teams {
	grid-area: teams;
}

.nwp-resultrow__score {
	grid-area: score;
}

.nwp-resultrow__date {
	grid-area: date;
}

.nwp-fixture {
	display: grid;
	grid-template-columns: 1fr auto;
	align-items: baseline;
	gap: var( --nwp-space-2xs ) var( --nwp-space-sm );
	padding-block: var( --nwp-space-sm );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-fixture__teams,
.nwp-resultrow__teams {
	font-weight: 600;
	text-wrap: pretty;
}

.nwp-fixture__meta,
.nwp-resultrow__date {
	font-family: var( --nwp-font-mono );
	font-size: 0.75rem;
	letter-spacing: 0.08em;
	color: var( --nwp-text-muted );
	white-space: nowrap;
}

/* 🔴 On a phone the date stops competing for the line.
   At 390px "at home to Cheshire Stars Netball Club" and "Sun 11 Oct 2026"
   were two columns fighting over 358px, wrapping the opponent to three lines
   to keep a date on the right that nobody reads first. Below `sm` the date
   goes underneath, where it is still scannable down a column and the
   opponent gets the width it needs. */
@media ( max-width: 37.49rem ) {
	.nwp-fixture {
		grid-template-columns: 1fr;
	}

	.nwp-resultrow {
		grid-template-columns: auto 1fr auto;
	}
}

.nwp-resultrow__score {
	font-family: var( --nwp-font-display );
	font-size: 1.125rem;
	/* Scores are measurement. Proportional figures make 27-15 and 0-20 sit at
	   different widths and the column stops reading as one. */
	font-variant-numeric: tabular-nums;
	white-space: nowrap;
}

/* A scratched match has no score, because there was no match. The row has to
   read correctly with that cell simply absent rather than showing 0-0, which
   would be a lie in the shape of a number. */
.nwp-result--scratched .nwp-result__letter {
	background: transparent;
	border: 1px solid var( --nwp-hairline-strong );
	color: var( --nwp-text-muted );
}

.nwp-standings {
	width: 100%;
	border-collapse: collapse;
	font-size: 0.875rem;
	font-variant-numeric: tabular-nums;
}

.nwp-standings :is( th, td ) {
	text-align: left;
	padding: var( --nwp-space-xs ) var( --nwp-space-sm );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-standings thead th {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
}

/* The club's own row. 🔴 Also marked in words for a screen reader — never
   colour alone. */
.nwp-standings__row--club {
	background: var( --nwp-surface );
	font-weight: 700;
	box-shadow: inset 3px 0 0 var( --nwp-state-followed );
}

/* 🔴 No horizontal scroll. Below md the dense columns are dropped rather
   than the table being made scrollable. */
@media ( max-width: 599px ) {
	.nwp-standings__dense {
		display: none;
	}
}

/* --------------------------------------------------------------------------
   POLICY LIST

   Grouped, because "the club's own policies" and "policies the club follows
   from England Netball" are different commitments and a parent should be able
   to tell them apart.

   Each entry leads with the plain-English summary rather than the version
   number. Somebody looking for the rules on photographs needs to recognise the
   right document; the provenance matters, but it is not what they came for.
   -------------------------------------------------------------------------- */

.nwp-policy__lead {
	font-size: 1.0625rem;
	line-height: 1.6;
	max-inline-size: 42rem;
	margin-block-end: var( --nwp-space-lg );
}

.nwp-policy__ask {
	margin-block-start: var( --nwp-space-xl );
	padding-block-start: var( --nwp-space-md );
	border-top: 1px solid var( --nwp-hairline );
	color: var( --nwp-text-muted );
	max-inline-size: 42rem;
}

.nwp-policylist__heading {
	font-family: var( --nwp-font-heading );
	font-size: 1.25rem;
	color: var( --nwp-maroon );
	margin-block: var( --nwp-space-lg ) var( --nwp-space-2xs );
}

.nwp-policylist__heading:first-child {
	margin-block-start: 0;
}

.nwp-policylist__intro {
	color: var( --nwp-text-muted );
	max-inline-size: 42rem;
	margin-block-end: var( --nwp-space-md );
}

.nwp-policylist__item {
	padding-block: var( --nwp-space-sm );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-policylist__link {
	font-family: var( --nwp-font-heading );
	font-size: 1.125rem;
	line-height: 1.3;
}

.nwp-policylist__summary {
	margin-block: var( --nwp-space-2xs ) 0;
	max-inline-size: 42rem;
	line-height: 1.5;
}

.nwp-policylist__meta {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
	margin-block-start: var( --nwp-space-2xs );
}

/* What is NOT on the list yet. Stated plainly, never styled as a warning:
   a policy being drafted is a club working, not a fault. */
.nwp-policylist__pending {
	margin-block-start: var( --nwp-space-lg );
	padding: var( --nwp-space-md );
	background: var( --nwp-surface-alt );
	color: var( --nwp-text-muted );
	max-inline-size: 42rem;
}

.nwp-sponsor__wordmark {
	font-family: var( --nwp-font-heading );
	font-weight: 600;
	font-size: 0.9375rem;
}

.nwp-sponsor__rel {
	font-family: var( --nwp-font-mono );
	font-size: 0.625rem;
	letter-spacing: 0.12em;
	text-transform: uppercase;
	color: var( --nwp-fixed-subtle );
}

.nwp-safeguarding__limits,
.nwp-safeguarding__verified {
	font-size: 0.875rem;
	color: var( --nwp-fixed-muted );
}

.nwp-policy__summary {
	font-family: var( --nwp-font-text );
	font-size: 0.9375rem;
	margin-block-start: var( --nwp-space-sm );
}

/* ==========================================================================
   9d-ii  THE JOIN PANEL AS A FULL-BLEED BAND
   A maroon rectangle floating inside a white column reads as a card. The
   club's single strongest ask should own the full width of the page and break
   the white run — that is what makes it register as an event rather than as
   another section.
   ========================================================================== */

/* 🔴 CONTAINED, NOT FULL-BLEED.
   Two viewport-relative attempts failed and both are worth recording:
   `inline-size: 100vw` overflows by the scrollbar width and adds a horizontal
   scrollbar; viewport-relative padding assumes the panel spans the viewport,
   so on `/join/` — where the parent column is 42rem — it produced a 160px
   slab of empty maroon before the first word.
   A band that is predictable on every template beats one that is dramatic on
   one and broken on the rest. */
.nwp-join {
	position: relative;
	overflow: hidden;
	inline-size: 100%;
	max-inline-size: var( --nwp-container-club );
	margin-inline: auto;
	padding: var( --nwp-space-xxxl ) var( --nwp-space-xxl ) !important;
}

@media ( max-width: 599px ) {
	.nwp-join {
		padding: var( --nwp-space-xxl ) var( --nwp-space-lg ) !important;
	}
}

/* 🔴 The panther again, as a section marker (DEC-056) — composition only, the
   band's own edge does the cropping. */
.nwp-join::before {
	content: '';
	position: absolute;
	inset-block-start: -22%;
	inset-inline-end: -6%;
	inline-size: min( 34rem, 42% );
	aspect-ratio: 1;
	background: url( '../img/nwp-panther-device-unchanged.svg' ) no-repeat center / contain;
	mix-blend-mode: multiply;
	opacity: 0.4;
	pointer-events: none;
}

@media ( max-width: 899px ) {
	.nwp-join::before {
		display: none;
	}
}

/* 🔴 ONE LEFT EDGE.
   The pattern's group is `is-layout-constrained`, so WordPress generates
   `> * { max-width: 42rem; margin-inline: auto }` for every direct child.
   Combined with the measure caps above, that gave the panel SIX different
   left edges — the eyebrow, heading, paragraph, list, fees line and links all
   started at different x positions. Children are pinned to the start edge
   here and keep only their measure. */
.nwp-join > * {
	margin-inline-start: 0 !important;
	margin-inline-end: 0 !important;
}

.nwp-join > :is( p, ol, ul, h2, h3 ) {
	max-inline-size: 62ch;
}

.nwp-join > .wp-block-buttons,
.nwp-join > .wp-block-button {
	max-inline-size: none;
	justify-content: flex-start;
}

/* Vertical rhythm inside the panel: tight groups, generous separation. */
.nwp-join > * + * {
	margin-block-start: var( --nwp-space-md );
}

.nwp-join > h2 {
	margin-block-start: var( --nwp-space-xs );
}

.nwp-join > .wp-block-buttons {
	margin-block-start: var( --nwp-space-xl );
}

.nwp-join .is-style-nwp-display {
	font-size: clamp( 2rem, 5vw, 4rem );
	max-inline-size: 20ch;
}

/* The panel's own heading must not pick up the light-ground rule above. */
.nwp-join h2.is-style-nwp-display::before {
	background: var( --nwp-fixed-white );
}

/* ==========================================================================
   9d-iii  THE PATHWAY RAIL
   The positioning, drawn. Ink band, so it breaks the white run and reads as
   the structural claim it is rather than as another content section.
   ========================================================================== */

.nwp-pathway {
	position: relative;
	overflow: hidden;
	background: var( --nwp-ink );
	color: var( --nwp-bone );
	padding-block: var( --nwp-space-huge );
	padding-inline: var( --nwp-space-lg );
	margin-block: var( --nwp-space-xxl ) 0;
}

/* 🔴 The panther as a section marker — composition only (DEC-056, club
   approved 2026-07-26): the band's own edge decides what is seen. */
.nwp-pathway::before {
	content: '';
	position: absolute;
	inset-block-start: -46%;
	inset-inline-end: -6%;
	inline-size: min( 44rem, 52% );
	aspect-ratio: 1;
	background: url( '../img/nwp-panther-device-unchanged.svg' ) no-repeat center / contain;
	opacity: 0.09;
	pointer-events: none;
}

.nwp-pathway__inner {
	position: relative;
	max-inline-size: var( --nwp-container-wide );
	margin-inline: auto;
}

.nwp-pathway__eyebrow {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.18em;
	text-transform: uppercase;
	color: var( --nwp-bone-dim );
	margin: 0 0 var( --nwp-space-sm );
}

.nwp-pathway__heading {
	font-family: var( --nwp-font-display );
	text-transform: uppercase;
	font-size: clamp( 2rem, 5vw, 4rem );
	line-height: 0.88;
	letter-spacing: -0.02em;
	padding-block-end: 0.1em;
	margin: 0 0 var( --nwp-space-md );
	max-inline-size: 16ch;
}

.nwp-pathway__intro {
	margin: 0 0 var( --nwp-space-xxl );
	max-inline-size: 56ch;
	color: var( --nwp-bone-dim );
	font-size: 1.0625rem;
	line-height: 1.6;
}

/* The rail itself. A real ordered list — the sequence IS the information, so
   it is marked up as one rather than drawn with divs. */
.nwp-pathway__rail {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	/* 🔴 NO PAINTED GROUND, and no 1px gap standing in for rules.
	   That technique needs every track occupied. It was safe at six literal
	   stops; the rail is now drawn from the club's squads and there are nine,
	   so it wraps — and `auto-fit` only collapses tracks empty across the WHOLE
	   grid, not the trailing tracks of a part-filled last row. The painted
	   ground would have shown through them as a pale slab, which is precisely
	   the bug the sponsor strip had.
	   The rules are drawn INSIDE each stop instead, so they exist only where a
	   stop exists, at any number of squads the club ever runs. */
	gap: 0;
	/* 🔴 Sized so the club's NINE squads sit on ONE line at desktop width.
	   A pathway is a sequence, and a sequence broken across two rows with a
	   hole in the second reads as a grid of boxes instead — which is the thing
	   the rail exists not to be. It still wraps below that, in order, because
	   a phone cannot hold nine stops and pretending otherwise would mean
	   shrinking the age past legibility. */
	grid-template-columns: repeat( auto-fit, minmax( 7rem, 1fr ) );
	border-block: 1px solid rgba( 245, 241, 234, 0.16 );
}

.nwp-pathway__stop {
	display: grid;
	align-content: start;
	background: var( --nwp-ink );
	position: relative;
	/* The dividing rules: a leading edge on every stop, and a lower edge so a
	   wrapped row is separated from the one above it. */
	box-shadow:
		inset 1px 0 0 rgba( 245, 241, 234, 0.16 ),
		inset 0 -1px 0 rgba( 245, 241, 234, 0.16 );
	transition: background var( --nwp-dur-standard ) var( --nwp-ease-standard );
}

/* 🔴 The whole stop is the target, not the age glyph. 44px is the touch
   default; a parent on a phone should be able to tap the tile, not aim. */
.nwp-pathway__stop > a {
	display: grid;
	gap: var( --nwp-space-2xs );
	align-content: start;
	/* Tightened with the track: at nine stops the old md inline padding left
	   too little room for the age between the dividing rules. */
	padding: var( --nwp-space-md ) var( --nwp-space-sm );
	min-block-size: 44px;
	color: inherit;
	text-decoration: none;
}

.nwp-pathway__stop > a:focus-visible {
	outline: 3px solid var( --nwp-lime );
	outline-offset: -3px;
}

.nwp-pathway__stop:hover {
	background: color-mix( in srgb, var( --nwp-ink ) 92%, var( --nwp-bone ) );
}

/* The age label as a graphic object. This is the compressed face doing the
   job it was loaded for. */
.nwp-pathway__age {
	font-family: var( --nwp-font-compressed );
	/* Reduced from clamp( 2.5rem, 4.5vw, 3.75rem ), which was set when the rail
	   held six stops. At nine, "U15" at 3.75rem overflowed a 7rem track and the
	   glyph collided with its own dividing rule. Still the largest thing in the
	   section, and still the compressed face doing the job it was loaded for. */
	font-size: clamp( 1.75rem, 2.6vw, 2.5rem );
	line-height: 0.8;
	padding-block-end: 0.08em;
	color: var( --nwp-bone );
}

.nwp-pathway__label {
	font-family: var( --nwp-font-heading );
	font-weight: 600;
	font-size: 0.9375rem;
	line-height: 1.25;
}

.nwp-pathway__note {
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	color: var( --nwp-bone-dim );
}

/* 🔴 Back to Netball is ON the rail, at the far end — the placement is the
   argument. It is marked as an entry point, not as an afterthought. */
.nwp-pathway__stop--entry {
	background: var( --nwp-maroon );
}

.nwp-pathway__stop--entry:hover {
	background: color-mix( in srgb, var( --nwp-maroon ) 88%, var( --nwp-bone ) );
}

.nwp-pathway__stop--entry .nwp-pathway__note {
	color: var( --nwp-maroon-tint40 );
}

.nwp-pathway__foot {
	margin: var( --nwp-space-lg ) 0 0;
	max-inline-size: 62ch;
	color: var( --nwp-bone-dim );
	font-size: 0.9375rem;
	line-height: 1.6;
}

.nwp-pathway__foot strong {
	color: var( --nwp-bone );
}

.nwp-pathway__foot a {
	color: var( --nwp-bone );
	text-decoration: underline;
	text-underline-offset: 0.16em;
}

@media ( prefers-reduced-motion: reduce ) {
	.nwp-pathway__stop {
		transition: none;
	}
}

/* ==========================================================================
   9d-iv  CLUB NEWS — editorial, and honest about scarcity
   Three equal cards is the shape that looks worst at the volume this club
   actually publishes: padded with two posts, broken with one. A lead plus a
   ruled list reads as deliberate at any count from one upward.
   ========================================================================== */

.nwp-news {
	display: grid;
	gap: var( --nwp-space-xl );
	grid-template-columns: minmax( 0, 1fr );
	align-items: start;
}

@media ( min-width: 60rem ) {
	.nwp-news {
		grid-template-columns: minmax( 0, 1.45fr ) minmax( 0, 1fr );
		gap: var( --nwp-space-xxl );
	}

	.nwp-news__stale {
		grid-column: 1 / -1;
	}
}

/* 🔴 Said plainly rather than dressed as current. The old site presented a
   nine-month-old post as news; that reads as a dormant club. */
.nwp-news__stale {
	margin: 0;
	padding: var( --nwp-space-md ) var( --nwp-space-lg );
	border-inline-start: 2px solid var( --nwp-hairline-strong );
	background: var( --nwp-surface );
	font-size: 0.9375rem;
	line-height: 1.6;
	color: var( --nwp-text-muted );
	max-inline-size: 62ch;
}

.nwp-news__lead {
	display: grid;
	gap: var( --nwp-space-sm );
	align-content: start;
	padding-block-start: var( --nwp-space-md );
	border-block-start: 3px solid var( --nwp-rule-accent );
}

/* The date as a graphic object. Netball is seasonal — when a thing happened
   is genuinely part of the information, not metadata to be shrunk away. */
.nwp-news__date {
	margin: 0;
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
}

.nwp-news__leadtitle {
	margin: 0;
	font-family: var( --nwp-font-heading );
	font-weight: 700;
	font-size: clamp( 1.5rem, 3vw, 2.25rem );
	line-height: 1.1;
	max-inline-size: 20ch;
}

.nwp-news__leadtitle a {
	color: inherit;
	text-decoration: none;
}

.nwp-news__leadtitle a:hover {
	text-decoration: underline;
	text-underline-offset: 0.12em;
}

.nwp-news__excerpt {
	margin: 0;
	max-inline-size: 52ch;
	line-height: 1.65;
	color: var( --nwp-text-muted );
}

/* The tail: a ruled list, not more cards. */
.nwp-news__list {
	list-style: none;
	margin: 0;
	padding: 0;
	display: grid;
	border-block-start: 1px solid var( --nwp-hairline );
}

.nwp-news__item {
	display: grid;
	gap: var( --nwp-space-3xs );
	padding-block: var( --nwp-space-sm );
	border-block-end: 1px solid var( --nwp-hairline );
}

.nwp-news__itemdate {
	font-family: var( --nwp-font-mono );
	font-size: 0.625rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --nwp-text-muted );
}

.nwp-news__itemtitle {
	/* The whole title is the target rather than a "read more" that names
	   nothing. 44px, not the 32px it was — a headline is a primary
	   destination, not incidental text. */
	display: flex;
	align-items: center;
	min-block-size: 44px;
	font-family: var( --nwp-font-heading );
	font-weight: 600;
	font-size: 1rem;
	line-height: 1.3;
	color: inherit;
	text-decoration: none;
}

.nwp-news__itemtitle:hover {
	text-decoration: underline;
	text-underline-offset: 0.12em;
}

/* ==========================================================================
   9d-v  THE SQUAD FINDER
   A parent's first question, answered on the page instead of by email.
   ========================================================================== */

.nwp-finder {
	position: relative;
	overflow: hidden;
	background: var( --nwp-maroon );
	color: var( --nwp-fixed-white );
	padding: var( --nwp-space-xxl ) var( --nwp-space-xl );
	display: grid;
	gap: var( --nwp-space-xl );
	align-items: start;
}

@media ( min-width: 56rem ) {
	.nwp-finder {
		grid-template-columns: minmax( 0, 1fr ) minmax( 0, 1fr );
		gap: var( --nwp-space-xxl );
	}
}

/* 🔴 The panther again — composition only (DEC-056). */
.nwp-finder::before {
	content: '';
	position: absolute;
	inset-block-end: -30%;
	inset-inline-end: -8%;
	inline-size: min( 30rem, 40% );
	aspect-ratio: 1;
	background: url( '../img/nwp-panther-device-unchanged.svg' ) no-repeat center / contain;
	mix-blend-mode: multiply;
	opacity: 0.35;
	pointer-events: none;
}

.nwp-finder > * {
	position: relative;
}

.nwp-finder__heading {
	margin: 0 0 var( --nwp-space-md );
	font-family: var( --nwp-font-display );
	text-transform: uppercase;
	font-size: clamp( 1.5rem, 3.2vw, 2.5rem );
	line-height: 0.92;
	letter-spacing: -0.015em;
	padding-block-end: 0.1em;
	max-inline-size: 16ch;
	color: var( --nwp-fixed-white );
}

.nwp-finder__control {
	display: flex;
	flex-wrap: wrap;
	gap: var( --nwp-space-sm );
	align-items: flex-end;
}

.nwp-finder__label {
	display: block;
	inline-size: 100%;
	margin-block-end: var( --nwp-space-2xs );
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --nwp-maroon-tint40 );
}

/* Superseded by section 26 — the finder control. */

.nwp-finder__select:focus-visible {
	outline: 3px solid var( --nwp-fixed-focus-on-maroon );
	outline-offset: 2px;
}

.nwp-finder__go {
	font-family: var( --nwp-font-mono );
	font-size: 0.8125rem;
	letter-spacing: 0.1em;
	text-transform: uppercase;
	min-block-size: 52px;
	padding-inline: var( --nwp-space-lg );
	background: transparent;
	color: var( --nwp-fixed-white );
	border: 1px solid rgba( 255, 255, 255, 0.55 );
	border-radius: var( --nwp-radius-action );
	cursor: pointer;
}

.nwp-finder__hint {
	margin: var( --nwp-space-sm ) 0 0;
	font-size: 0.8125rem;
	line-height: 1.55;
	color: var( --nwp-maroon-tint40 );
	max-inline-size: 46ch;
}

/* The answer plate. White, so it reads as the club replying rather than as
   more of the same field. */
.nwp-finder__answer {
	background: var( --nwp-fixed-white );
	color: var( --nwp-fixed-ink );
	padding: var( --nwp-space-lg );
	display: grid;
	gap: var( --nwp-space-sm );
}

.nwp-finder__eyebrow {
	margin: 0;
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	color: var( --nwp-fixed-subtle );
}

.nwp-finder__squad {
	margin: 0;
	font-family: var( --nwp-font-compressed );
	text-transform: uppercase;
	font-size: clamp( 2.5rem, 6vw, 4rem );
	line-height: 0.82;
	padding-block-end: 0.08em;
	color: var( --nwp-maroon );
}

.nwp-finder__facts {
	margin: 0;
	display: grid;
	gap: 0;
	border-block-start: 1px solid var( --nwp-fixed-rule-soft );
}

.nwp-finder__fact {
	display: grid;
	gap: 2px;
	padding-block: var( --nwp-space-xs );
	border-block-end: 1px solid var( --nwp-fixed-rule-soft );
}

@media ( min-width: 26rem ) {
	.nwp-finder__fact {
		grid-template-columns: minmax( 0, 7rem ) minmax( 0, 1fr );
		gap: var( --nwp-space-sm );
		align-items: baseline;
	}
}

.nwp-finder__fact dt {
	font-family: var( --nwp-font-mono );
	font-size: 0.625rem;
	letter-spacing: 0.14em;
	text-transform: uppercase;
	color: var( --nwp-fixed-subtle );
}

.nwp-finder__fact dd {
	margin: 0;
	line-height: 1.45;
}

.nwp-finder__none {
	margin: 0;
	line-height: 1.6;
	max-inline-size: 46ch;
}

.nwp-finder__cta {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	padding-inline: var( --nwp-space-lg );
	background: var( --nwp-maroon );
	color: var( --nwp-fixed-white );
	font-family: var( --nwp-font-mono );
	font-size: 0.8125rem;
	letter-spacing: 0.08em;
	text-transform: uppercase;
	text-decoration: none;
	border-radius: var( --nwp-radius-action );
}

.nwp-finder__more {
	display: inline-flex;
	align-items: center;
	min-block-size: 44px;
	margin-inline-start: var( --nwp-space-sm );
	color: var( --nwp-fixed-ink );
	text-decoration: underline;
	text-underline-offset: 0.16em;
	font-size: 0.9375rem;
}

/* ==========================================================================
   9e  THE MOTION SIGNATURE
   DESIGN-TOKENS §10: "content enters along the shear axis — a short translate
   on that diagonal plus an opacity fade. Once per Club page."
   🔴 ONE authored moment, not an entrance on every section. It fires on the
   statement only, from an ALREADY-VISIBLE default, so a failed animation or a
   blocked script can never hide the club's own name.
   ========================================================================== */

@media ( prefers-reduced-motion: no-preference ) {
	@supports ( animation-timeline: view() ) or ( animation: none ) {
		.nwp-reveal {
			animation: nwp-shear-in var( --nwp-dur-reveal ) var( --nwp-ease-entrance ) both;
		}

		/* The sentence follows a beat later. Two elements, one moment — not a
		   staggered cascade down the page. */
		.nwp-chero__sentence {
			animation: nwp-shear-in var( --nwp-dur-reveal ) var( --nwp-ease-entrance ) 0.08s both;
		}
	}
}

@keyframes nwp-shear-in {
	from {
		/* The shear axis: 8° means the diagonal is (cos, sin) of that angle,
		   so the travel is mostly horizontal with a small rise. */
		transform: translate( -1.6rem, 0.5rem );
		opacity: 0;
	}

	to {
		transform: none;
		opacity: 1;
	}
}

/* 🔴 Reduced motion removes the travel entirely and keeps a 0.12s opacity
   fade, exactly as the token spec requires. Calm mode already carries zero
   motion regardless of preference. */
@media ( prefers-reduced-motion: reduce ) {
	.nwp-reveal,
	.nwp-chero__sentence {
		animation: none;
	}
}

/* ==========================================================================
   9f  TOUCH, POINTER AND THE PHYSICAL DEVICE
   🔴 Screen width does not tell you the input method. A 1440px laptop can have
   a touchscreen and a 390px phone can have a stylus, so these key off POINTER
   rather than off a breakpoint.
   ========================================================================== */

@media ( pointer: coarse ) {
	/* Anything a finger has to hit gets the full 44px, everywhere — not only
	   at phone widths. */
	a,
	button,
	summary,
	[ role='button' ],
	.wp-block-button__link,
	.wp-block-navigation-item__content {
		min-block-size: 44px;
	}

	/* WordPress core ships the overlay close control at 24×24. That clears
	   WCAG 2.5.8 by exactly nothing, and it is the one control a parent needs
	   when they have opened the menu by accident. */
	.wp-block-navigation__responsive-container-close,
	.wp-block-navigation__responsive-container-open {
		min-inline-size: 44px;
		min-block-size: 44px;
	}

	/* Inline links inside prose stay as they are — WCAG 2.5.8 exempts them,
	   and inflating them would wreck the line spacing of body copy. */
	p > a,
	li > a:not( .nwp-news__itemtitle ):not( .nwp-social__link ) {
		min-block-size: 0;
	}

	/* Space between adjacent targets matters as much as their size: two 44px
	   links touching each other still produce mis-taps. */
	.nwp-footer ul,
	.nwp-social {
		gap: var( --nwp-space-xs );
	}
}

/* 🔴 Hover is not available on touch, so nothing may DEPEND on it. These
   effects are additive only — every one of them has a persistent equivalent
   (an underline, a border, a colour) that is present without hovering. */
@media ( hover: none ) {
	.nwp-teamcard:hover {
		border-inline-start-color: var( --nwp-maroon );
	}

	.nwp-starthere__list li:hover {
		padding-inline-start: 0;
	}
}

/* Notched and rounded phones. The footer and the fixed banner are the two
   places content can otherwise sit under the home indicator or a corner. */
.nwp-footer {
	padding-inline-start: max( var( --nwp-space-lg ), env( safe-area-inset-left ) );
	padding-inline-end: max( var( --nwp-space-lg ), env( safe-area-inset-right ) );
	padding-block-end: max( var( --nwp-space-xl ), env( safe-area-inset-bottom ) );
}

.nwp-header,
.nwp-envbanner {
	padding-inline-start: max( var( --nwp-space-lg ), env( safe-area-inset-left ) );
	padding-inline-end: max( var( --nwp-space-lg ), env( safe-area-inset-right ) );
}

/* Landscape on a phone: the hero's 88vh becomes taller than the screen and
   pushes everything below the fold out of reach. */
@media ( max-height: 30rem ) and ( orientation: landscape ) {
	.nwp-chero {
		min-block-size: 0;
		padding-block: var( --nwp-space-xl );
	}
}

/* ==========================================================================
   10  TEST-ENVIRONMENT BANNER
   Only rendered when WP_ENVIRONMENT_TYPE is not "production".
   ========================================================================== */

.nwp-envbanner {
	position: relative;
	z-index: 100;
	padding: var( --nwp-space-2xs ) var( --nwp-space-md );
	background: repeating-linear-gradient(
		135deg,
		var( --nwp-fixed-ink ),
		var( --nwp-fixed-ink ) 10px,
		color-mix( in srgb, var( --nwp-fixed-ink ) 80%, var( --nwp-bone ) ) 10px,
		color-mix( in srgb, var( --nwp-fixed-ink ) 80%, var( --nwp-bone ) ) 20px
	);
	color: var( --nwp-fixed-white );
	font-family: var( --nwp-font-mono );
	font-size: 0.6875rem;
	letter-spacing: 0.16em;
	text-transform: uppercase;
	text-align: center;
}

/* ==========================================================================
   22  UTILITY BAND — the club's other addresses
   A thin strip above the main bar. Ranked BELOW the navigation deliberately:
   these three links lead off the site, and they must not compete with the
   links that answer a parent's question.
   ========================================================================== */

/* 🔴 The SAME ink as the bar below it, and no dividing rule. The first
   attempt used `--nwp-fixed-ink` (#241c1f) against the bar's `--nwp-ink`
   (#0a0a0c) and drew a near-white hairline between them: two subtly different
   blacks with a bright seam, which read as a rendering fault rather than as a
   band. One ink, one block. */
.nwp-header__utility {
	background: var( --nwp-ink );
}

.nwp-header__utility-inner {
	display: flex;
	justify-content: flex-end;
	align-items: center;
	max-inline-size: var( --nwp-container-wide );
	margin-inline: auto;
	padding-inline: var( --nwp-space-lg );
	padding-block: 0;
}

.nwp-social--bar {
	display: flex;
	gap: var( --nwp-space-xxs );
	margin: 0;
	padding: 0;
	list-style: none;
}

/* 🔴 44px. These are the smallest targets on the page and they sit at the very
   top edge, which on a phone is the hardest place to hit accurately. The icon
   stays 20px; the TARGET is what grows. */
/* 🔴 32px with a fine pointer, 44px with a coarse one.
   WCAG 2.2 AA (2.5.8) asks for 24px; 44px is the AAA figure and the right
   default for a thumb. Applying 44 unconditionally made this band 44px tall on
   a desktop where the pointer is a mouse — a thick empty strip above the logo,
   paying touch-target cost for an input device that does not need it. The
   uplift is driven by the POINTER, not by the viewport width: a small laptop
   still has a mouse, and a large tablet still has fingers. */
.nwp-social--bar .nwp-social__link {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	inline-size: 32px;
	block-size: 32px;
	color: var( --nwp-bone-dim );
	text-decoration: none;
	transition:
		color var( --nwp-dur-fast ) var( --nwp-ease-standard ),
		background-color var( --nwp-dur-fast ) var( --nwp-ease-standard );
}

/* The header band inherits the inverting wipe above; it needs no colour of
   its own. Stated explicitly so nobody reinstates a background-color here and
   quietly puts the crossing back. */
.nwp-social--bar .nwp-social__link:hover,
.nwp-social--bar .nwp-social__link:focus-visible {
	background-color: transparent;
}

@media ( prefers-reduced-motion: reduce ) {
	.nwp-social__link::before {
		transition: none;
	}
}

@media ( pointer: coarse ) {
	.nwp-social--bar .nwp-social__link {
		inline-size: 44px;
		block-size: 44px;
	}
}

/* Below the small breakpoint the band goes: the social links are already in
   the footer, and the header needs its width for the logo and menu button. */
@media ( max-width: 599px ) {
	.nwp-header__utility {
		display: none;
	}
}

/* ==========================================================================
   23  SUBMENUS
   Click-disclosed (core `openSubmenusOnClick`), so they work on a touchscreen
   and carry aria-expanded without hand-rolled JS.
   ========================================================================== */

.nwp-nav .wp-block-navigation-submenu {
	position: relative;
}

/* The parent of an open submenu is a button, not a link. It must read the
   same as its siblings — core's default gives it a different padding box. */
/* 🔴 The toggle is a <button>, and a button does NOT inherit the nav link's
   typography — `font: inherit` inherits from the list item, which carries none
   of it. So "Squads" and "About" rendered in the browser's default UI font,
   lower case, at a different size and baseline from every other item in the
   bar. The styling has to be restated here, not inherited. */
.nwp-nav .wp-block-navigation-submenu__toggle,
.nwp-nav .wp-block-navigation-submenu > .wp-block-navigation-item__content {
	display: inline-flex;
	align-items: center;
	min-height: 44px;
	padding-inline: var( --nwp-space-xs );
	font-family: var( --nwp-font-compressed );
	font-size: 1.125rem;
	font-weight: 400;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	text-decoration: none;
	color: inherit;
	background: transparent;
	border: 0;
	cursor: pointer;
}

/* Core's chevron is sized for its own default type. Bring it back in scale and
   give it a little air so it reads as part of the label, not an artefact. */
.nwp-nav .wp-block-navigation__submenu-icon {
	margin-inline-start: var( --nwp-space-xxs );
	inline-size: 0.7em;
	block-size: 0.7em;
	opacity: 0.7;
}

/* 🔴 SPECIFICITY, MEASURED AGAINST CORE'S ACTUAL SELECTOR.
   Core ships:
       .wp-block-navigation:not(.has-background) .wp-block-navigation__submenu-container
   which is (0,3,0) — the `:not()` contributes its argument's class weight.
   A rule of `.nwp-nav .wp-block-navigation__submenu-container` is (0,2,0) and
   loses. It lost silently and selectively: the `color` declaration had no
   competitor so it applied, while `background` was overridden — leaving bone
   text on core's white panel at about 1.3:1. Legible in neither theme.

   Matching core's own shape puts this at (0,4,0), which wins on merit rather
   than with `!important`. */
.nwp-nav.wp-block-navigation:not( .has-background ) .wp-block-navigation__submenu-container,
.nwp-nav .wp-block-navigation__submenu-container {
	min-inline-size: 15rem;
	padding-block: var( --nwp-space-xs );
	background-color: var( --nwp-ink );
	color: var( --nwp-bone );
	border: 1px solid var( --nwp-fixed-subtle );
	box-shadow: 0 14px 36px -10px var( --nwp-ink );
}

.nwp-nav.wp-block-navigation:not( .has-background ) .wp-block-navigation__submenu-container .wp-block-navigation-item__content,
.nwp-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
	display: block;
	inline-size: 100%;
	min-block-size: 44px;
	padding-block: var( --nwp-space-xs );
	padding-inline: var( --nwp-space-md );
	color: var( --nwp-bone );
	font-family: var( --nwp-font-mono );
	font-size: 0.8125rem;
	letter-spacing: 0.04em;
	text-transform: none;
	text-decoration: none;
}

/* 🔴 The underline sweep belongs to the top-level bar only. Repeating it on
   every submenu row turns a signature into wallpaper. */
.nwp-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content::after {
	content: none;
}

.nwp-nav.wp-block-navigation:not( .has-background ) .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover,
.nwp-nav.wp-block-navigation:not( .has-background ) .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus-visible,
.nwp-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:hover,
.nwp-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content:focus-visible {
	background-color: var( --nwp-maroon );
	color: var( --nwp-fixed-white );
}

/* The finder row leads the Squads menu and is the only emphasised row in it:
   a parent who cannot map a school year to an age band needs the way out of
   that problem to be the first thing, not one of seven equal choices. */
.nwp-nav .nwp-nav__lead .wp-block-navigation-item__content,
.nwp-nav .wp-block-navigation-item.nwp-nav__lead > a {
	font-weight: 700;
	color: var( --nwp-fixed-white );
	border-block-end: 1px solid var( --nwp-fixed-rule-soft );
	margin-block-end: var( --nwp-space-xxs );
}

/* ==========================================================================
   24  ACTION FEEDBACK — the shear, at the scale of a control
   ==========================================================================
   The site's structural gesture is an 8 degree shear. Buttons acknowledge a
   pointer by filling along that SAME axis: a maroon face wipes in from the
   leading edge on the shear angle, rather than the button lifting, glowing or
   growing. The gesture is already the club's; this borrows it rather than
   importing a generic hover lift that would belong to any site.

   🔴 The wipe lives on ::before, and the press displacement uses the
   independent `translate` property. Both are deliberate: section 3 sets
   `transform: none !important` on buttons to keep them out of the shear
   system, and that ban is correct. A pseudo-element is not matched by it, and
   `translate` is a separate property from `transform`, so the motion works
   WITHOUT weakening the prohibition or reaching for another !important.
   ========================================================================== */

.wp-block-button__link,
.nwp-button {
	position: relative;
	overflow: hidden;
	isolation: isolate;
	transition:
		color var( --nwp-dur-fast ) var( --nwp-ease-standard ),
		border-color var( --nwp-dur-fast ) var( --nwp-ease-standard ),
		background-color var( --nwp-dur-fast ) var( --nwp-ease-standard );
}

/* The wipe. Parked off the leading edge and sheared to the club angle; the
   overhang on both sides means the sheared corners never expose a gap. */
.wp-block-button__link::before,
.nwp-button::before {
	content: '';
	position: absolute;
	inset-block: -1px;
	inset-inline-start: -12%;
	inline-size: 124%;
	z-index: -1;
	/* 🔴 THE WIPE COLOUR CASCADES; IT IS NOT SELECTED PER CONTEXT.
	   The first version inverted the wipe with `.nwp-on-maroon .wp-block-
	   button__link::before`. That is right for a button sitting on the maroon
	   field and WRONG for one inside a white card nested in it — the Start
	   Here panel is exactly that, so its primary button wiped bone underneath
	   white text: 1.06:1, and the label vanished on hover.
	   A descendant selector cannot express "unless something re-established a
	   light ground in between". A custom property can, because a light panel
	   simply sets it back. */
	background: var( --nwp-btn-wipe, var( --nwp-maroon-deep ) );
	transform: skewX( var( --nwp-shear-angle ) ) translateX( -108% );
	transition: transform var( --nwp-dur-standard ) var( --nwp-ease-broadcast );
	pointer-events: none;
}

.wp-block-button__link:hover::before,
.wp-block-button__link:focus-visible::before,
.nwp-button:hover::before,
.nwp-button:focus-visible::before {
	transform: skewX( var( --nwp-shear-angle ) ) translateX( 0 );
}

/* 🔴 Exit faster than entrance. A wipe that leaves as slowly as it arrives
   reads as the interface lagging behind the pointer. */
.wp-block-button__link:not( :hover ):not( :focus-visible )::before,
.nwp-button:not( :hover ):not( :focus-visible )::before {
	transition-duration: var( --nwp-dur-fast );
}

/* Press: the smallest displacement that registers as contact, and the face
   locks to the deep maroon. No scale, no bounce — Quiet Speed is mechanical,
   not springy. */
.wp-block-button__link:active,
.nwp-button:active {
	translate: 0 1px;
	transition-duration: 0.08s;
}

.wp-block-button__link:active::before,
.nwp-button:active::before {
	transform: skewX( var( --nwp-shear-angle ) ) translateX( 0 );
	transition-duration: 0.08s;
}

/* The secondary button has no fill of its own, so the wipe is what supplies
   its hover ground — which means its text must invert with it or the pairing
   goes to 1.6:1 the moment the maroon arrives. */
.wp-block-button.is-style-nwp-secondary .wp-block-button__link:hover,
.wp-block-button.is-style-nwp-secondary .wp-block-button__link:focus-visible {
	color: var( --nwp-fixed-white );
	border-color: var( --nwp-maroon-deep );
}

/* On a maroon ground the wipe would be maroon-on-maroon, so it inverts to
   bone and the label goes to ink. Both are set as properties so anything
   nested can put them back. */
.nwp-on-maroon {
	--nwp-btn-wipe: var( --nwp-bone );
	--nwp-btn-wipe-fg: var( --nwp-fixed-ink );
}

.nwp-on-maroon .wp-block-button__link:hover,
.nwp-on-maroon .wp-block-button__link:focus-visible {
	color: var( --nwp-btn-wipe-fg, var( --nwp-fixed-ink ) );
	border-color: var( --nwp-btn-wipe, var( --nwp-bone ) );
}

/* 🔴 A LIGHT PANEL INSIDE THE MAROON CONTEXT PUTS THE WIPE BACK.
   These re-establish a light ground, so a button inside them is a button on
   white and must behave like one. Without this the inherited inversion paints
   a bone wipe under white text. */
.nwp-on-maroon :is( .nwp-starthere, .nwp-alert, .nwp-state, .nwp-finder__answer--none ) {
	--nwp-btn-wipe: var( --nwp-maroon-deep );
	--nwp-btn-wipe-fg: var( --nwp-fixed-white );
}

/* ==========================================================================
   25  MOTION CONSENT
   ==========================================================================
   🔴 Two separate obligations, and the second is stricter than the first.

   `prefers-reduced-motion` is the visitor's OS preference: honour it by
   removing the travel, not the feedback. The state change still happens —
   instantly — because a button that stops responding is a worse outcome than
   one that responds without sliding.

   Calm mode is the CLUB's decision, applied to safeguarding and policy pages,
   and PRODUCT.md holds it to ZERO motion regardless of preference. A person
   reporting a concern about a child is not an audience for interface
   character. It is not a preference to be negotiated with, so it wins over
   `no-preference` as well.
   ========================================================================== */

@media ( prefers-reduced-motion: reduce ) {
	.wp-block-button__link,
	.nwp-button,
	.wp-block-button__link::before,
	.nwp-button::before {
		transition: none;
	}

	.wp-block-button__link::before,
	.nwp-button::before {
		transform: skewX( var( --nwp-shear-angle ) ) translateX( -108% );
	}

	.wp-block-button__link:hover::before,
	.wp-block-button__link:focus-visible::before,
	.nwp-button:hover::before,
	.nwp-button:focus-visible::before {
		transform: skewX( var( --nwp-shear-angle ) ) translateX( 0 );
	}

	.wp-block-button__link:active,
	.nwp-button:active {
		translate: none;
	}
}

[data-nwp-calm='true'] .wp-block-button__link,
[data-nwp-calm='true'] .nwp-button,
[data-nwp-calm='true'] .wp-block-button__link::before,
[data-nwp-calm='true'] .nwp-button::before,
[data-nwp-calm='true'] .nwp-social__link {
	transition: none !important;
	animation: none !important;
}

[data-nwp-calm='true'] .wp-block-button__link:active,
[data-nwp-calm='true'] .nwp-button:active {
	translate: none;
}

/* 🔴 Hover is not a state a touchscreen has. Everything above must therefore
   be enhancement only — the press feedback and the focus ring carry the whole
   interaction where there is no pointer. Parking the wipe permanently avoids
   the sticky-hover artefact where a tapped button keeps its hover fill until
   the next tap elsewhere. */
@media ( hover: none ) {
	.wp-block-button__link::before,
	.nwp-button::before {
		transition: none;
	}

	.wp-block-button__link:hover::before,
	.nwp-button:hover::before {
		transform: skewX( var( --nwp-shear-angle ) ) translateX( -108% );
	}

	.wp-block-button__link:active::before,
	.nwp-button:active::before {
		transform: skewX( var( --nwp-shear-angle ) ) translateX( 0 );
	}
}

/* ==========================================================================
   26  THE FINDER CONTROL
   ==========================================================================
   🔴 This stays a real `<select>`. Not for want of ambition — because the
   finder must answer a parent with JavaScript disabled, and because a native
   select is the only control that gets the iOS wheel, the Android sheet, voice
   control, switch access and the screen-reader listbox for free. Every
   hand-built div-and-listbox combobox on the web is a reimplementation of
   those, and most of them are worse.

   What was wrong was not the element. It was that the element had been left
   looking like a 1995 form control on the club's best page. A native select
   accepts a great deal of styling; almost none of it had been applied.

   Two tiers, and the first is not a fallback — it is the real design:

   1. Every browser: club typography, a drawn chevron, a proper hit area, and
      an open/press state. Nothing here depends on script.
   2. Browsers with `appearance: base-select`: the option list itself becomes
      stylable, so the popup is rendered in the club's own ink and maroon with
      an animated entrance. Where that is unsupported, the OS list appears and
      is perfectly good.
   ========================================================================== */

.nwp-finder__field {
	position: relative;
	display: inline-block;
}

/* The chevron. Drawn in CSS rather than shipped as an image so it inherits
   colour and cannot 404. Sits on the wrapper so the select keeps its own
   background. */
.nwp-finder__field::after {
	content: '';
	position: absolute;
	inset-inline-end: var( --nwp-space-md );
	inset-block-start: 50%;
	inline-size: 0.55rem;
	block-size: 0.55rem;
	border-inline-end: 2px solid var( --nwp-maroon );
	border-block-end: 2px solid var( --nwp-maroon );
	transform: translateY( -70% ) rotate( 45deg );
	transition: transform var( --nwp-dur-fast ) var( --nwp-ease-standard );
	pointer-events: none;
}

.nwp-finder__field:has( .nwp-finder__select:hover )::after {
	transform: translateY( -40% ) rotate( 45deg );
}

.nwp-finder__select {
	appearance: none;
	font-family: var( --nwp-font-mono );
	font-size: 1rem;
	letter-spacing: 0.02em;
	min-block-size: 56px;
	min-inline-size: 18rem;
	padding-block: var( --nwp-space-xs );
	padding-inline: var( --nwp-space-md ) var( --nwp-space-2xl );
	background: var( --nwp-fixed-white );
	color: var( --nwp-fixed-ink );
	border: 2px solid var( --nwp-fixed-white );
	border-radius: var( --nwp-radius-action );
	cursor: pointer;
	transition:
		border-color var( --nwp-dur-fast ) var( --nwp-ease-standard ),
		box-shadow var( --nwp-dur-fast ) var( --nwp-ease-standard );
}

/* 🔴 The shadow is offset and blurred. A zero-offset ring is decoration; this
   has to read as a raised control sitting on the maroon field. */
.nwp-finder__select:hover {
	border-color: var( --nwp-maroon-tint40 );
	box-shadow: 0 4px 14px -4px var( --nwp-maroon-deep );
}

.nwp-finder__select:focus-visible {
	outline: 3px solid var( --nwp-fixed-focus-on-maroon );
	outline-offset: 2px;
	border-color: var( --nwp-fixed-white );
}

.nwp-finder__select:active {
	translate: 0 1px;
}

/* ==========================================================================
   26b  THE STYLABLE POPUP, WHERE THE BROWSER ALLOWS IT
   --------------------------------------------------------------------------
   `appearance: base-select` opts the control into the customisable-select
   model, which makes `::picker(select)` and the `<option>`s real styleable
   boxes. Gated behind `@supports`, so a browser without it simply keeps its
   own list — which is a good list. This is enhancement in the strict sense:
   removing the whole block changes nothing about whether the finder works.
   ========================================================================== */

@supports ( appearance: base-select ) {
	.nwp-finder__select,
	.nwp-finder__select::picker( select ) {
		appearance: base-select;
	}

	/* The wrapper's chevron would double up with the one the base appearance
	   provides. */
	.nwp-finder__field::after {
		content: none;
	}

	.nwp-finder__select::picker-icon {
		color: var( --nwp-maroon );
		transition: rotate var( --nwp-dur-standard ) var( --nwp-ease-broadcast );
	}

	.nwp-finder__select:open::picker-icon {
		rotate: 180deg;
	}

	.nwp-finder__select::picker( select ) {
		border: 1px solid var( --nwp-maroon-deep );
		border-radius: var( --nwp-radius-action );
		background: var( --nwp-ink );
		padding-block: var( --nwp-space-xxs );
		box-shadow: 0 18px 44px -12px var( --nwp-maroon-deep );

		/* Entrance: the list arrives from just under the control rather than
		   appearing whole. 180ms — long enough to show direction, short enough
		   that it never delays the choice. */
		opacity: 0;
		translate: 0 -6px;
		transition:
			opacity var( --nwp-dur-fast ) var( --nwp-ease-standard ),
			translate var( --nwp-dur-fast ) var( --nwp-ease-broadcast ),
			display var( --nwp-dur-fast ) allow-discrete,
			overlay var( --nwp-dur-fast ) allow-discrete;
	}

	.nwp-finder__select:open::picker( select ) {
		opacity: 1;
		translate: 0 0;
	}

	@starting-style {
		.nwp-finder__select:open::picker( select ) {
			opacity: 0;
			translate: 0 -6px;
		}
	}

	.nwp-finder__select option {
		display: flex;
		align-items: center;
		gap: var( --nwp-space-xs );
		min-block-size: 44px;
		padding-inline: var( --nwp-space-md );
		font-family: var( --nwp-font-mono );
		font-size: 0.9375rem;
		color: var( --nwp-bone );
		background: transparent;
	}

	.nwp-finder__select option:hover,
	.nwp-finder__select option:focus {
		background: var( --nwp-maroon );
		color: var( --nwp-fixed-white );
	}

	/* 🔴 The selected row is marked by a tick AND a background, never by
	   colour alone. Core requirement, not a flourish. */
	.nwp-finder__select option:checked::before {
		content: '';
		inline-size: 0.5rem;
		block-size: 0.5rem;
		background: var( --nwp-ochre );
	}

	.nwp-finder__select option::checkmark {
		display: none;
	}
}

/* Reduced motion: the list still appears, it simply does not travel. */
@media ( prefers-reduced-motion: reduce ) {
	.nwp-finder__field::after,
	.nwp-finder__select,
	.nwp-finder__select::picker( select ),
	.nwp-finder__select::picker-icon {
		transition: none;
	}
}

/* ==========================================================================
   27  THE ANSWER ARRIVES
   ==========================================================================
   The answer card was appearing with no transition whatsoever: one frame it is
   absent, the next it is there. That is not "fast" — it is a jump cut, and it
   is the one moment on this site that has genuinely earned an authored
   entrance. It is the payoff of the club's single best feature, and the point
   at which a parent finds out whether their child has somewhere to go.

   🔴 THE ANIMATION IS ON ARRIVAL ONLY, AND IT NEVER GATES THE CONTENT.
   `@starting-style` animates from a state that only exists at the moment of
   insertion, so the resting state is fully visible. A failed script, an
   unsupported browser, or `prefers-reduced-motion` all leave the answer
   present and readable — there is no keyframe that starts at `opacity: 0` and
   relies on something firing to undo it. The server-rendered no-JS answer is
   already on the page at load and simply does not animate; only the
   JS-inserted one does, which is correct, because only that one arrives.

   The material is the shear again, at panel scale: the card wipes in along the
   club's 8° axis rather than fading. One idea, used in three places now — the
   page bands, the buttons, and here — which is what makes it read as a
   signature rather than an effect.
   ========================================================================== */

.nwp-finder__result {
	display: block;
}

.nwp-finder__answer {
	--nwp-answer-reveal: inset( 0 0 0 0 );

	clip-path: var( --nwp-answer-reveal );
	opacity: 1;
	translate: 0 0;
}

@media ( prefers-reduced-motion: no-preference ) {
	.nwp-finder__answer {
		transition:
			opacity var( --nwp-dur-standard ) var( --nwp-ease-standard ),
			translate var( --nwp-dur-reveal ) var( --nwp-ease-broadcast ),
			clip-path var( --nwp-dur-reveal ) var( --nwp-ease-broadcast );
	}

	/* 🔴 The state the card is in for exactly one frame, as it is inserted.
	   `polygon` rather than `inset` so the leading edge can carry the 8°:
	   the reveal runs off the top-left on the shear axis, matching the way
	   every other band on the site is cut. */
	@starting-style {
		.nwp-finder__answer {
			opacity: 0;
			translate: 0 10px;
			clip-path: polygon( 0 0, 0 0, -12% 100%, 0 100% );
		}
	}

	/* The facts inside land just behind the card, so the eye reaches the squad
	   name before the detail under it. Capped at four steps — a stagger that
	   keeps counting past that stops reading as one movement. */
	.nwp-finder__squad,
	.nwp-finder__fact,
	.nwp-finder__cta {
		opacity: 1;
		translate: 0 0;
		transition:
			opacity var( --nwp-dur-standard ) var( --nwp-ease-standard ),
			translate var( --nwp-dur-standard ) var( --nwp-ease-broadcast );
	}

	@starting-style {
		.nwp-finder__squad,
		.nwp-finder__fact,
		.nwp-finder__cta {
			opacity: 0;
			translate: 0 6px;
		}
	}

	.nwp-finder__fact:nth-child( 1 )  { transition-delay: 0.04s; }
	.nwp-finder__fact:nth-child( 2 )  { transition-delay: 0.08s; }
	.nwp-finder__fact:nth-child( 3 )  { transition-delay: 0.12s; }
	.nwp-finder__fact:nth-child( n+4 ) { transition-delay: 0.16s; }
	.nwp-finder__cta { transition-delay: 0.18s; }
}

/* 🔴 Calm mode: zero motion, no exceptions, regardless of preference. */
[data-nwp-calm='true'] .nwp-finder__answer,
[data-nwp-calm='true'] .nwp-finder__squad,
[data-nwp-calm='true'] .nwp-finder__fact,
[data-nwp-calm='true'] .nwp-finder__cta {
	transition: none !important;
	transition-delay: 0s !important;
	clip-path: none;
	opacity: 1;
	translate: none;
}

/* ==========================================================================
   28  PHOTOGRAPHY, a photograph does a job, or it does not appear.

   The club's cleared set (D-3, consent recorded) is eleven frames from phones.
   Ten are usable. Nine of those ten are the same photograph: a squad stood in
   a line, facing the camera, mid-distance. One frame, a huddle shot from above
   with hands joined in the centre, is the only picture in the set showing
   BELONGING rather than ATTENDANCE.

   That distribution decides the whole layer, so it is worth stating plainly:

   🔴 A squad line-up is not a hero. It is a picture of who is in the squad,
   which makes it a strong factual asset and a poor emotional one. Used as a
   squad identity it is honest, and the repetition reads as house style; used
   as a homepage hero it reads as a school photo and asks a parent to feel
   something the picture cannot deliver. Nine identical compositions are a
   SYSTEM when they sit in nine equivalent slots and a RUT anywhere else.

   Three consequences, enforced below rather than documented and hoped for:

   1  The homepage fold carries no photograph at all. It is locked typographic
      ground (D-33, DEC-057), and a parent needs the four answers before the
      club asks for a feeling.
   2  Contrast over a photograph is produced by the SCRIM, never by the
      photograph. An editor attaches an image; they never have to judge whether
      the text still reads. Measured below.
   3  Every slot declares the native width of the asset it holds and refuses to
      render wider. The cleared set tops out near 1600px, so the failure mode
      here is not a missing image, it is a soft one.
   ========================================================================== */

.nwp-figure {
	/* 🔴 The resolution ceiling, as a control rather than a note in a document.
	   Every asset in the cleared set is a compressed phone frame; the largest
	   is 1600px on its long edge and several are near 900px. A slot that grows
	   past its asset does not fail loudly, it just goes soft, and soft is
	   precisely the amateur quality the grade was applied to remove. Each
	   modifier sets `--nwp-photo-native` to its own asset's real width, and the
	   figure never exceeds it however much room the grid offers. */
	inline-size: 100%;
	max-inline-size: var( --nwp-photo-native, 100% );
	margin: 0;
	position: relative;
	overflow: hidden;
	background-color: var( --nwp-maroon-deep );
}

.nwp-figure img {
	/* The BOX owns the ratio and `cover` fits the picture inside it. Same
	   reasoning as the sponsor slot at section 8, opposite conclusion: a
	   partner's logo must never be cropped, a photograph must never letterbox.
	   A letterboxed photograph puts club maroon in bars around a picture and
	   reads as a broken embed. */
	display: block;
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	object-position: var( --nwp-photo-focus, 50% 50% );
}

/* --- The general landscape figure ---------------------------------------
   🔴 Named `--wide`, and deliberately NOT `--squad`. It was called that while
   the line-ups were destined for squad cards, and the name outlived the plan:
   the set turned out to be unattributed, so no photograph may sit on a card
   headed with a squad's name. A modifier called `--squad` that must never go on
   a squad card is a trap for whoever reads this next. */

.nwp-figure--wide {
	/* Sized for a three-up grid inside the 70rem club container, so the asset
	   is never asked for more than about a third of it: comfortably inside
	   1600px even at 2x device pixel ratio. */
	--nwp-photo-native: 1600px;
	aspect-ratio: 3 / 2;
}

/* --- The one expressive frame -------------------------------------------
   🔴 Reserved for the huddle. This modifier exists for a PROPERTY of a
   photograph (a moment, shot close, subject filling the frame), never for a
   position on a page. Applying it to a line-up puts a school photo at display
   scale, which is the worst single thing that can be done with this set. */

.nwp-figure--moment {
	/* The huddle is 900px at source. Held well inside that: at 2x DPR a 26rem
	   column is 832 device pixels, so it renders at native or better and never
	   has to be upscaled. */
	--nwp-photo-native: 26rem;
	aspect-ratio: 4 / 5;
}

/* --- Atmosphere ----------------------------------------------------------
   The two wide sports-hall frames. As subject photographs they fail: the
   players are thirty metres out and read as ants. As GROUND they work, which
   is the only honest use for them. They carry the room, the light and the
   scale of a tournament without asking anyone to look at a face. */

.nwp-photoband {
	position: relative;
	isolation: isolate;
	display: grid;
	align-items: center;
	min-block-size: 22rem;
	padding-block: var( --nwp-space-3xl, 4rem );
	padding-inline: var( --nwp-space-lg, 1.5rem );
	overflow: hidden;
}

.nwp-photoband__media {
	position: absolute;
	inset: 0;
	margin: 0;
	z-index: -2;
}

.nwp-photoband__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	object-position: 50% 55%;
}

.nwp-photoband__scrim {
	position: absolute;
	inset: 0;
	margin: 0;
	z-index: -1;
	/* 🔴 MEASURED, and the reason an editor never has to think about contrast.
	   Worst case is a blown-out white frame under the lightest end of this
	   gradient: ink #0A0A0C at 0.62 over #FFFFFF resolves to sRGB 97, relative
	   luminance 0.119, putting white text at 6.19:1. Above the 4.5:1 floor with
	   room to spare, so the guarantee holds for ANY photograph attached to this
	   slot, including one nobody has graded yet. The maroon end is darker still
	   and needs no separate check.

	   This is the difference between a system and a suggestion. Tuning the
	   scrim per photograph would look marginally better on the two frames the
	   club has today, and would fail silently on the first one a volunteer
	   adds. */
	background-image: linear-gradient(
		100deg,
		rgba( 62, 7, 24, 0.92 ) 0%,
		rgba( 62, 7, 24, 0.78 ) 38%,
		rgba( 10, 10, 12, 0.62 ) 100%
	);
}

.nwp-photoband__inner {
	position: relative;
	inline-size: 100%;
	max-inline-size: 70rem;
	margin-inline: auto;
}

/* The band is the one photographic slot allowed to run full-bleed, and it can
   afford to be: the asset is 1600px on its long edge, it sits under a 62% to
   92% scrim, and nobody is asked to resolve a face in it. Softness that would
   be obvious in a squad card is invisible here. */
.nwp-photoband--bleed {
	margin-inline: calc( 50% - 50vw );
	max-inline-size: 100vw;
}

/* --- Prohibitions --------------------------------------------------------
   Enforced here, in the same spirit as the shear prohibitions at section 3,
   because an instruction in a document is not a control. */

/* 🔴 No photography on safeguarding or policy surfaces. Not a stylistic
   preference. A photograph of children on a safeguarding page can be read two
   ways, as marketing attached to a duty of care or as an illustration of who
   is at risk, and both are wrong. The requirement is that reporting feels like
   an ordinary, expected thing to do, and ordinary things do not arrive with a
   picture of the people they concern. Calm mode already forbids the warning
   vocabulary; this closes the remaining gap. */
[data-nwp-calm='true'] .nwp-figure,
[data-nwp-calm='true'] .nwp-photoband {
	display: none;
}

/* 🔴 Photographs never move, never scale on hover, never parallax. The
   approved motion is the 8 degree shear at the scale of a CONTROL (DEC-060). A
   photograph is not a control, and a squad of children is not a texture to
   animate. The single authored entrance is `nwp-reveal` on the moment frame,
   which the motion-consent rules at section 25 already govern. */
.nwp-figure:hover img,
.nwp-figure:focus-within img,
.nwp-photoband__media img {
	transform: none;
	scale: none;
	transition: none;
}

/* ==========================================================================
   29  PHOTOGRAPHY IN NAVIGATION, arriving somewhere, and going somewhere

   Section 28 decided what a photograph is FOR. This decides where the set
   earns its place in the act of moving around the site, which is the only
   place an unattributed photograph can do real work.

   🔴 The set is unattributed. Nobody can say which squad, season or event any
   frame shows, so no photograph may sit beside a specific label. That rules
   out squad cards, news items and fixtures. What is LEFT is everything to do
   with transition: the band a page opens on, and the ground behind the menu.
   Those two surfaces are about the club as a whole, they assert nothing, and
   they are the two moments a visitor feels whether a site is alive.
   ========================================================================== */

/* --- The band a page arrives on ----------------------------------------- */

.nwp-pagehead {
	position: relative;
	isolation: isolate;
	display: grid;
	align-items: end;
	/* 26rem, not 20rem. The band has to hold a group of people standing up, and
	   at 20rem on a desktop viewport it was a 4.5:1 slot: every frame came out
	   as a strip of torsos with the sheared edge cutting through faces. Taller
	   is the only real fix. The asset is a 3:1 crop, so at this height the CSS
	   barely crops it at all and the photograph arrives as it was composed. */
	min-block-size: 26rem;
	padding-block-start: var( --nwp-space-3xl, 4rem );
	padding-inline: var( --nwp-space-lg, 1.5rem );
	overflow: hidden;
	background-color: var( --nwp-maroon-deep );
}

/* 🔴 The empty-pool state is a DESIGN, not a fallback. Before the photographs
   are imported, and on any page whose frame has been withdrawn from the media
   library, this band is a flat maroon field with the title on it. That has to
   look deliberate, because for the first weeks of the site's life it is what
   everybody sees, and because "design for the season nobody posts" applies to
   photography exactly as it applies to news. Nothing below assumes an image. */

/* 🔴 `margin: 0` is not tidiness, it is the fix for a visible defect.
   WordPress gives every non-first child of an `is-layout-flow` group a
   block-gap margin. On an absolutely positioned element with `top: 0` that
   margin still applies, so the scrim below rendered 16px lower than the
   photograph it covers and left a bright unscrimmed strip across the top of
   every page head. It shipped, and it was the first thing anyone noticed.
   Both layers pin their own margin so neither can drift again. */
.nwp-pagehead__media {
	position: absolute;
	inset: 0;
	margin: 0;
	z-index: -2;
}

.nwp-pagehead__media img {
	inline-size: 100%;
	block-size: 100%;
	object-fit: cover;
	/* 🔴 CENTRED, and this is load-bearing rather than a default.

	   The pool holds purpose-built 3:1 crops whose vertical placement is already
	   art-directed per photograph (scripts/grade-photography.py, HEAD_FOCAL):
	   faces just inside the top edge, the cut at the waist. Applying an
	   off-centre object-position here would crop an already-cropped frame a
	   second time, and the two compound.

	   That is not hypothetical. Setting this to 38% cut the tops of heads off,
	   and correcting it to 25% pushed the squad to the floor of the band with
	   half a building above them. Neither value was wrong on its own; asking
	   CSS to art-direct a frame that had already been art-directed was. The
	   composition is decided once, in the asset, where it can be judged
	   per photograph. */
	object-position: 50% 50%;
}

.nwp-pagehead__scrim {
	position: absolute;
	inset: 0;
	z-index: -1;
	margin: 0;
	/* 🔴 LIGHT, and that is the whole point of the plate below.

	   This scrim used to run 0.46 to 0.90 because the title sat directly on the
	   photograph and had to stay readable over any frame. It worked, and it
	   produced exactly the wrong page: on a Join Us page, a band of children in
	   silhouette. Darkening a photograph of smiling faces to make room for a
	   word is solving the typography at the expense of the only thing the
	   photograph was there to do.

	   So the contrast moved off the photograph and onto the plate. Nothing
	   readable sits on the picture now, which frees this layer to do the only
	   job left: seat a phone snapshot in the club's palette, and hand off from
	   the near-black header above without a hard line. Faces stay bright.

	   The maroon at the foot is heavier than the rest because the sheared edge
	   cuts there and wants something to cut through. */
	background-image:
		linear-gradient(
			180deg,
			rgba( 10, 10, 12, 0.30 ) 0%,
			rgba( 10, 10, 12, 0.10 ) 38%,
			rgba( 62, 7, 24, 0.42 ) 100%
		);
}

/* 🔴 The title's contrast comes from the PLATE, never from the photograph.
   White on #5B0B24 is 13.83:1, so the guarantee is absolute and independent of
   which frame is behind it: a blown-out snapshot and a night shot give the same
   result. It also means an editor can put any photograph here without anyone
   checking whether the heading still reads.

   The plate carries the approved 8 degree shear, counter-skewed on the heading
   so the letterforms stay upright. Headings are not in the shear prohibition
   list at section 3, so this is safe; buttons and tables are, and must never
   be given this treatment. */
.nwp-pagehead__plate {
	display: inline-block;
	max-inline-size: 100%;
	padding: var( --nwp-space-sm, 0.75rem ) var( --nwp-space-xl, 2rem );
	background-color: var( --nwp-maroon );
	transform: skewX( var( --nwp-shear-angle ) );
}

.nwp-pagehead__plate > :is( h1, h2 ) {
	margin: 0;
	color: var( --nwp-fixed-white );
	transform: skewX( calc( var( --nwp-shear-angle ) * -1 ) );
}

/* 🔴 Suppressed below 380px, matching the shear utilities at section 3. At that
   width the skew costs more horizontal room than the title has to give. */
@media ( max-width: 379px ) {
	.nwp-pagehead__plate,
	.nwp-pagehead__plate > :is( h1, h2 ) {
		transform: none;
	}
}

.nwp-pagehead__inner {
	position: relative;
	inline-size: 100%;
	max-inline-size: 70rem;
	margin-inline: auto;
	/* Clears the sheared edge below, so a descender never lands in the notch. */
	padding-block-end: var( --nwp-space-xl, 2rem );
}

/* Shorter on phones, but not short. A phone is portrait, so the band is nowhere
   near as wide a slot as it is on a desktop and the faces survive a smaller
   height. 17rem keeps the group intact without spending half the viewport
   before the first word of content. */
@media ( max-width: 600px ) {
	.nwp-pagehead {
		min-block-size: 17rem;
	}

	.nwp-pagehead__plate {
		padding-inline: var( --nwp-space-lg, 1.5rem );
	}

	/* 🔴 Drop the plate to the floor of the band on phones, and this is a face
	   fix rather than a spacing preference.

	   `.nwp-shear-bottom` adds `--nwp-space-3xl + 3vw` of bottom padding, and
	   `__inner` adds 2rem more. In a 26rem desktop band that is fine. In a 17rem
	   phone band it is over 100px of a 272px slot, which floats the plate to
	   roughly mid-height, and mid-height in a photograph of people standing up
	   is exactly where the faces are. It shipped covering two girls' faces on
	   the Join Us page.

	   Low is also the right place on its own merits: a phone crops the 3:1 frame
	   hard to the horizontal centre, so the plate has only one safe band to sit
	   in, and that is below the group. The sheared edge lifts away from the left
	   here, so nothing clips the plate. */
	.nwp-pagehead.nwp-shear-bottom {
		padding-block-end: calc( var( --nwp-space-md, 1rem ) + 3vw );
	}

	.nwp-pagehead__inner {
		padding-block-end: var( --nwp-space-xs, 0.5rem );
	}

	/* 🔴 The display face has to step down over a photograph, and further than
	   it does over a flat surface. Archivo Black at 2.5rem broke a one-sentence
	   band heading onto six lines at 390px, which turned a statement into a
	   wall and buried the picture behind it. Capped here rather than in
	   theme.json because the constraint belongs to these two components: the
	   same size is correct on the ordinary page surfaces, where the line is
	   never competing with an image for the same rectangle. */
	.nwp-pagehead__inner :is( h1, h2 ),
	.nwp-photoband__inner :is( h1, h2 ) {
		font-size: clamp( 1.625rem, 7.4vw, 2.25rem );
		line-height: 1.08;
	}
}


/* --- The band with no photograph in it ----------------------------------
   🔴 THE DEFAULT STATE, not a fallback, and designed as such.

   The cleared set turned out to be ten near-identical establishing shots at
   phone resolution, and a page head is the one slot that punishes both of those
   at once: it is wide, it is large, and it wants a subject. Rather than keep
   forcing frames into it, the band stands on its own and photography became
   something the site can take rather than something it needs.

   The form is not invented here. DEC-057 already settled it for the homepage
   fold, in words worth repeating: the ground is INK, not maroon, because a
   full-bleed maroon field with nothing in it reads as an unfilled box, whereas
   on ink the maroon becomes a shape that carries meaning and the type has
   somewhere to burn. That was true of the hero and it is true here, so the page
   heads are siblings of the fold rather than a second system beside it.

   🔴 The slot is preserved exactly. `--flat` is added only when no photograph
   resolves, so setting a Featured Image on any page still produces the
   photographic band with no change to markup, CSS or templates. Better
   photographs improve this site later; they are not a prerequisite for it. */

.nwp-pagehead--flat {
	/* One number drives the shape and the mark's position, so they cannot drift
	   apart at any width. */
	--nwp-pagehead-shape: min( 100%, 62rem );

	background-color: var( --nwp-ink );
	/* Shorter than the photographic band, and shorter than the first attempt.
	   26rem exists to hold a group of people standing up; type and a mark need
	   far less. `.nwp-shear-bottom` contributes another 107px of padding at this
	   width, which took the first version to 491px of mostly empty maroon, so
	   the padding is pulled back here too. */
	min-block-size: 17rem;
	padding-block-start: var( --nwp-space-xl );
}

.nwp-pagehead--flat.nwp-shear-bottom {
	padding-block-end: calc( var( --nwp-space-lg ) + 3vw );
}

/* The maroon shape. It bleeds off the left and the bottom, and its right edge
   carries the 8 degree shear, so it reads as a form the page is cut from rather
   than a panel sitting on top of one. */
.nwp-pagehead--flat::before {
	content: '';
	position: absolute;
	inset-block: 0;
	inset-inline-start: 0;
	inline-size: var( --nwp-pagehead-shape );
	background-color: var( --nwp-maroon );
	clip-path: polygon( 0 0, 100% 0, calc( 100% - 4.5rem ) 100%, 0 100% );
	z-index: -2;
	pointer-events: none;
}

/* The identity mark, reusing the approved treatment from the hero at section 2
   without alteration: the unmodified SVG, positioned so the band's own edge
   decides what is seen, deepened into the maroon with a low-opacity multiply
   rather than recoloured. No cropped file, no altered path, nothing sheared, so
   DEC-052 and DEC-055 hold.

   🔴 Anchored to the RIGHT of the shape, not the left. Leading left put the
   animal directly under the title, which is where the type has to be legible
   and where the mark has least room to read as an animal. Out here it has the
   empty half of the shape to itself.

   🔴 It is held INSIDE the shape, with 4rem of clearance for the sheared edge.
   The first version let it overrun on the theory that a multiply against
   near-black ink would erase it. It did not: the artwork carries enough maroon
   that the overrun stayed visible as a paw floating on the ink, which reads as
   a mistake rather than as a crop. Fitting the mark to the shape is the honest
   fix, and it costs nothing. */
.nwp-pagehead--flat::after {
	content: '';
	position: absolute;
	inset-block-end: -16%;
	inset-inline-start: calc( var( --nwp-pagehead-shape ) - 34rem );
	inline-size: 30rem;
	aspect-ratio: 1;
	background: url( '../img/nwp-panther-device-unchanged.svg' ) no-repeat center / contain;
	mix-blend-mode: multiply;
	opacity: 0.42;
	z-index: -1;
	pointer-events: none;
}

/* 🔴 The plate is redundant here and is neutralised rather than removed. Its
   whole job is to guarantee the title's contrast against an unknown photograph;
   with the maroon shape behind the type that guarantee is already met by the
   ground itself, and a maroon plate on a maroon field is the muddy rectangle
   this redesign exists to delete. The element stays in the markup so the
   photographic band needs no separate template. */
.nwp-pagehead--flat .nwp-pagehead__plate {
	padding: 0;
	background-color: transparent;
	transform: none;
}

.nwp-pagehead--flat .nwp-pagehead__plate > :is( h1, h2 ) {
	transform: none;
}

/* 🔴 The shape narrows but NEVER fills the width. The first version set it to
   100% below 1100px, which turned the band back into a full-bleed maroon field
   with nothing in it: precisely the "unfilled box" DEC-057 rejected for the
   homepage fold. The ink has to stay visible for the maroon to read as a shape,
   so the shape gives up width and keeps its edge instead. */
@media ( max-width: 1100px ) {
	.nwp-pagehead--flat {
		--nwp-pagehead-shape: 86%;
	}

	.nwp-pagehead--flat::before {
		clip-path: polygon( 0 0, 100% 0, calc( 100% - 3rem ) 100%, 0 100% );
	}

	.nwp-pagehead--flat::after {
		inset-inline-start: calc( var( --nwp-pagehead-shape ) - 25rem );
		inline-size: 22rem;
	}
}

@media ( max-width: 600px ) {
	.nwp-pagehead--flat {
		--nwp-pagehead-shape: 90%;

		min-block-size: 12rem;
	}

	.nwp-pagehead--flat::after {
		inset-inline-start: calc( var( --nwp-pagehead-shape ) - 16rem );
		inline-size: 14rem;
		inset-block-end: -12%;
	}
}

/* --- The ground behind the menu ------------------------------------------
   🔴 The one place the photographs get to be big. The overlay is the only
   full-screen surface on the site, it carries no factual content to
   contradict, and it is the moment a visitor is deciding where to go. A
   darkened hall behind the destinations is worth more here than anywhere else
   on the site, and it costs nothing in meaning because it claims nothing. */

.wp-block-navigation__responsive-container.is-menu-open {
	position: relative;
	isolation: isolate;
}

.wp-block-navigation__responsive-container.is-menu-open::before {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -2;
	/* Supplied at runtime from the same deterministic pool as the page heads.
	   The custom property is unset until PHP defines it, and an unset
	   background-image is simply no image, so the overlay keeps its solid
	   ground and nothing breaks. */
	background-image: var( --nwp-nav-photo, none );
	background-size: cover;
	background-position: 50% 38%;
}

.wp-block-navigation__responsive-container.is-menu-open::after {
	content: '';
	position: absolute;
	inset: 0;
	z-index: -1;
	/* Heavier than the page head, deliberately. This surface is a list of
	   destinations and the photograph is the furthest thing back in the stack,
	   so the links read like links and the picture stays a suggestion of a room
	   rather than something competing with the words on top of it.

	   0.82 at the light end rather than the 0.88 first tried: at 0.88 the
	   photograph had gone so dark on a phone that it read as noise on a maroon
	   field, which is the worst of both, an image the visitor pays to download
	   and cannot see. 0.82 over a blown-out frame still returns 12.6:1 for
	   white text, four times the floor, so the room becomes visible at no cost
	   to a single link. */
	background-image: linear-gradient(
		160deg,
		rgba( 62, 7, 24, 0.90 ) 0%,
		rgba( 10, 10, 12, 0.82 ) 100%
	);
}

/* 🔴 No photograph behind a calm menu. Consistent with section 28: if a
   visitor opens the menu from a safeguarding page they are mid-task, and the
   task is reporting a concern. */
[ data-nwp-calm='true' ] .wp-block-navigation__responsive-container.is-menu-open::before {
	background-image: none;
}

/* --------------------------------------------------------------------------
   POLICY INDEX ALIGNMENT

   🔴 The reading column is LEFT-ALIGNED to the page container, not centred in
   it.

   A constrained layout centres a child narrower than its container, so a 42rem
   reading column inside a 70rem page sat 224px in from the left while the page
   title sat on the container edge. Measured at 1280px: title at 96, column at
   304, and the lead paragraph at 356 because a 62ch prose cap then centred
   again inside that. Three different left edges down one short page, none of
   them related to the others.

   The reading measure is worth keeping. Centring it is not: it is what breaks
   the relationship between the title and the text underneath it.
   -------------------------------------------------------------------------- */

/* 🔴 `!important` is required here, not lazy. WordPress emits its constrained
   layout as inline CSS carrying `margin-left: auto !important`, so a plain
   declaration in a stylesheet cannot win however specific it is. This is the
   documented way to opt a block out of that centring. */
.nwp-policy--index {
	margin-inline-start: 0 !important;
	margin-inline-end: auto !important;

	/* The page title sits inside a skewed plate, so its first glyph lands 1rem
	   inside the page container rather than on it. Measured, not assumed: 16px
	   at both 1280px and 940px. Matching it puts the title and the text
	   underneath on exactly the same edge. A 16px near-miss reads as a mistake
	   in a way that a large offset does not. */
	padding-inline-start: 1rem;
}

/* Children too, so nothing re-centres itself inside the column. */
.nwp-policy--index > * {
	margin-inline-start: 0 !important;
	margin-inline-end: auto !important;
}

/* The lead and closing note carry their own measure. Left-align those as well,
   or they float inside a column that is itself already left-aligned. */
.nwp-policy--index .nwp-policy__lead,
.nwp-policy--index .nwp-policy__ask,
.nwp-policy--index .nwp-policylist__intro,
.nwp-policy--index .nwp-policylist__summary,
.nwp-policy--index .nwp-policylist__pending {
	margin-inline-end: auto;
	margin-inline-start: 0;
}
