/* ============================================================
   Melbourne Punters Cricket Club
   Design system: "Form Guide"
   The club is called Punters, so the visual language is borrowed
   from the bookmaker's form guide and the suburban manual
   scoreboard: slat-textured boards, saddlecloth numbers, tabular
   mono numerals, and a six-box form line that encodes real
   recent-performance data.
   ============================================================ */

/* ---------- 1. Tokens ---------- */
:root {
  /* Prahran CC's own "True Blues" navy, taken from their site rather
     than lifted off it. */
  --pitch:      #002E5F;
  --pitch-2:    #073C74;
  --pitch-3:    #0F4E90;
  --pitch-line: #1C5C9C;
  /* Deep navy for text sitting on a light or amber fill. */
  --pitch-deep: #001E40;

  /* Paper: the cool light grey Prahran pairs with the navy. */
  --paper:     #F2F4F7;
  --paper-2:   #E8EAEC;
  --paper-line:#CFD6DF;

  /* Two tokens the theme switch turns on. --pitch and --chalk each did
     double duty — navy was both a section background and the body text
     colour, chalk both a card surface and the text on navy — so neither
     could be flipped without taking the other meaning with it.
     --ink is text on paper; --card is a raised surface on paper. */
  --ink:       #002E5F;
  --card:      #F7F9FC;

  /* Text on navy. Navy sections look the same in both themes, so this
     one does not move. */
  --chalk:     #F7F9FC;
  --ash:       #A3BBD4;
  /* Checked against --paper-2 (#E4E8ED), not just --paper: the
     scorebook-grid sections are the darker of the two, and a value
     tuned only to --paper left every table header at 4.29:1. */
  --ash-deep:  #4C6580;

  /* Accents taken from the club crest: crimson, orange and cyan.
     --claret/--amber keep their names so nothing downstream renames;
     the values are now the crest's own red and orange, deepened just
     enough to hold 4.5:1 against the paper and pitch backgrounds. */
  --claret:    #C41E32;
  /* Claret as TEXT on paper. The fill above keeps its value in both
     themes so white-on-claret buttons hold 5.5:1. */
  --claret-ink:#C41E32;
  --claret-lo: #A0182A;
  /* Crest orange and cyan, each lifted just enough to clear 4.5:1 on
     the lighter navy — at their raw crest values they measured 4.36:1
     and 4.24:1 and would have failed. */
  --amber:     #FF9130;
  --amber-lo:  #E0741B;
  --cyan:      #22BFD6;
  --cyan-lo:   #0F9DB4;
  /* Cards sit on --pitch-2, a lighter navy than the section behind
     them, so small amber text on a card needs lifting again: --amber
     measures 4.12:1 there against 5.03:1 on the section. */
  --amber-raised: #FFA751;

  /* Two families, not three. Archivo carries the headlines; Inter does
     everything else including figures — its tabular numerals align as
     well as a monospace without the technical noise. --mono is kept as
     a token name so label rules downstream don't all need renaming. */
  /* Prahran sets headings in Stag and everything else in Proxima Nova.
     Both are licensed Typekit faces we cannot embed, so these are the
     closest freely-licensed equivalents: Roboto Slab for the slab
     headings, Mulish for the humanist-geometric text face. */
  --display: "Roboto Slab", Rockwell, Georgia, serif;
  --body:    "Mulish", system-ui, -apple-system, sans-serif;
  --mono:    "Mulish", system-ui, -apple-system, sans-serif;

  --sp-section: clamp(4.25rem, 7.5vw, 8.5rem);
  /* The gutter scales with the viewport rather than sitting at a fixed
     28px, so the margin grows in proportion on a big screen instead of
     the content running hard to the edge. The max-width is set high
     enough that it only engages on very large displays — it stops the
     page becoming a 2500px-wide slab without ever making it a narrow
     centred column. */
  --gutter: clamp(14px, 2.2vw, 38px);
  --maxw: 2040px;
  /* Prose still needs a readable measure even when the page is wide. */
  --measure: 62ch;
  --r: 4px;

  --ease: cubic-bezier(.22, .61, .36, 1);

  /* ---- Elevation ----------------------------------------------------
     One scale, used everywhere, instead of the four hand-rolled shadows
     this file had grown. Two layers each: a tight contact shadow that
     sits the element on the page, and a wide ambient one that gives it
     height. A single blur reads as a smudge; the pair reads as depth.

     Tinted with the club navy rather than black — a black shadow over
     a blue-grey page goes muddy, and the tint is what makes it look
     considered rather than default. */
  --e1: 0 1px 2px rgba(0,30,64,.05),  0 1px 3px rgba(0,30,64,.07);
  --e2: 0 2px 4px rgba(0,30,64,.05),  0 5px 12px rgba(0,30,64,.09);
  --e3: 0 4px 8px rgba(0,30,64,.06),  0 14px 28px rgba(0,30,64,.11);
  --e4: 0 8px 16px rgba(0,30,64,.08), 0 28px 56px rgba(0,30,64,.16);
  /* The hairline that separates a raised surface from its own shadow. */
  --lip: inset 0 1px 0 rgba(255,255,255,.75);
}

/* ---------- 1b. Dark theme ----------
   Only the paper surfaces turn over. The navy bands — hero, page
   heads, on-pitch sections, footer — are the club's colour and stay
   exactly as they are, which keeps the site recognisably itself and
   means every contrast figure already measured against navy still
   holds. What changes is the light half of the page.

   The accents are re-tuned rather than reused: claret measures 3.1:1
   on the dark paper and would fail on every eyebrow. */
[data-theme="dark"] {
  --paper:      #061523;
  --paper-2:    #0B1F31;
  --paper-line: #17364F;
  --card:       #0E2438;
  --ink:        #E7EEF6;
  --ash-deep:   #9FB6CE;
  --claret-ink: #F2647A;
  --claret-lo:  #F2647A;
  --amber-lo:   #FFA751;
  --cyan-lo:    #4FD4E8;
  /* A navy-tinted shadow disappears on a dark surface. Dark mode goes
     back to black, and deeper, because there is less tonal room. */
  --e1: 0 1px 2px rgba(0,0,0,.30), 0 1px 3px rgba(0,0,0,.24);
  --e2: 0 2px 4px rgba(0,0,0,.30), 0 5px 12px rgba(0,0,0,.30);
  --e3: 0 4px 8px rgba(0,0,0,.32), 0 14px 28px rgba(0,0,0,.36);
  --e4: 0 8px 16px rgba(0,0,0,.36), 0 28px 56px rgba(0,0,0,.46);
  --lip: inset 0 1px 0 rgba(255,255,255,.06);
}
/* The switch itself should not animate the whole page. */
@media (prefers-reduced-motion: no-preference) {
  body, .section, .card, .foot { transition: background-color .3s var(--ease), color .3s var(--ease); }
}

/* Every figure on the site is tabular, so columns of numbers line up
   the way a monospace would without importing a third family. */
.tbl, .num, .stat__v, .plate__v, .tally__v, .fixture__day,
.ranked__v, .bline__key b, .player__cap, .board__foot b {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* ---------- 2. Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: clamp(1rem, .96rem + .2vw, 1.075rem);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }
a { color: inherit; }

::selection { background: var(--amber); color: var(--pitch-deep); }

:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--amber); color: var(--pitch-deep);
  padding: .75rem 1.25rem; font-weight: 700;
}
.skip:focus { left: 1rem; top: 1rem; }

/* ---------- 3. Typography ---------- */
.d1, .d2, .d3, .d4 {
  font-family: var(--display);
  font-weight: 800;
  font-stretch: 105%;          /* Archivo is variable-width; a touch expanded reads confident */
  line-height: .95;
  letter-spacing: -.008em;     /* a slab needs far less negative tracking than Archivo did */
  text-transform: uppercase;
  margin: 0;
}
.d1 { font-size: clamp(2.9rem, 8.6vw, 7.6rem); }
.d2 { font-size: clamp(2.05rem, 5vw, 4rem); }
.d3 { font-size: clamp(1.6rem, 3vw, 2.5rem); }
.d4 { font-size: clamp(1.05rem, 1.6vw, 1.35rem); line-height: 1.1; letter-spacing: -.015em; }
/* For headings with a long unbreakable word — "ACKNOWLEDGEMENT" is 15
   characters and overruns a split column at full .d2 size. */
.d2--long { font-size: clamp(1.5rem, 3.1vw, 2.5rem); }

.eyebrow {
  font-family: var(--mono);
  font-size: .7rem;
  font-weight: 600;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--claret-ink);
  margin: 0 0 1.1rem;
  display: flex;
  align-items: flex-start;
  gap: .7rem;
}
.eyebrow::before {
  content: "";
  width: 26px; height: 2px;
  background: var(--claret);
  flex: none;
  /* Sits on the first line's optical centre, so a wrapped label
     doesn't leave the rule floating between two lines. */
  margin-top: .52em;
}
.on-pitch .eyebrow { color: var(--amber); }
.on-pitch .eyebrow::before { background: var(--amber); }
.on-pitch .card .eyebrow,
.on-pitch .partner__tier { color: var(--amber-raised); }
.on-pitch .card .eyebrow::before { background: var(--amber-raised); }

.lede {
  font-size: clamp(1.1rem, 1.6vw, 1.3rem);
  line-height: 1.5;
  max-width: var(--measure);
  color: var(--ash-deep);
}
/* Long-form body copy keeps its measure on a wide page. */
.prose p { max-width: var(--measure); }
.on-pitch .lede { color: var(--ash); }
/* The hero is .hero, not .section.on-pitch, so it never picked up the
   light override above and was rendering the dark-background grey on a
   dark background — 2.82:1. */
.hero .lede { color: #C2D5EA; }
/* This one line of small type was capping how much photograph the
   whole left side could show: amber needs a near-solid scrim to hold
   4.5:1, and every lift that made the photo visible broke it first.
   Chalk holds 6.6:1 at a scrim light enough to show the picture. The
   claret rule before it still marks it as an eyebrow. */
.hero .eyebrow { color: var(--chalk); }

.num { font-family: var(--mono); font-variant-numeric: tabular-nums; font-weight: 700; }

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

/* ---------- 4. Layout ---------- */
.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.section { padding-block: var(--sp-section); position: relative; }
.section.is-tight { padding-block: clamp(3rem, 5vw, 4.5rem); }

.section.on-pitch {
  /* The navy fields were each one flat colour, which is what made the
     blue read as plain across every page. They now deepen top to
     bottom between two navies already in the palette. The gradient
     only ever gets darker than --pitch, so every contrast figure
     measured against flat --pitch still holds. */
  background: linear-gradient(180deg, var(--pitch) 0%, var(--pitch-deep) 100%);
  color: var(--chalk);
}
/* Slat texture — the horizontal timber of a manual scoreboard */
.section.on-pitch::before {
  content: "";
  position: absolute; inset: 0;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255,255,255,.028) 0 1px,
    transparent 1px 46px
  );
  pointer-events: none;
}
.section.on-pitch > * { position: relative; z-index: 1; }

/* Scorebook grid for paper sections */
.section.on-book {
  background-color: var(--paper-2);
  background-image:
    linear-gradient(to right, rgba(0,46,95,.055) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(0,46,95,.055) 1px, transparent 1px);
  background-size: 30px 30px;
}

.grid { display: grid; gap: clamp(1.25rem, 2vw, 2.25rem); }
/* minmax(0,…) rather than 1fr so wide children — tables above all —
   can shrink instead of forcing the row past the viewport. */
.g-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.g-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.g-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Cards size themselves, so a wide page adds columns rather than
   stretching each card. */
.g-auto { grid-template-columns: repeat(auto-fill, minmax(252px, 1fr)); }
.g-auto-lg { grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); }
.split {
  display: grid;
  gap: clamp(2rem, 5vw, 4.5rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
  align-items: start;
}

.stack-lg > * + * { margin-top: clamp(1.5rem, 3vw, 2.5rem); }

/* ---------- 5. Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--mono);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .085em;
  text-transform: uppercase;
  text-decoration: none;
  padding: .95rem 1.5rem;
  border: 2px solid transparent;
  border-radius: var(--r);
  cursor: pointer;
  transition: transform .18s var(--ease), background-color .18s, color .18s, border-color .18s;
}
.btn:hover { transform: translateY(-2px); }
.btn:active { transform: translateY(0); }

.btn--primary { background: var(--claret); color: var(--chalk); }
.btn--primary:hover { background: var(--claret-lo); }

.btn--amber { background: var(--amber); color: var(--pitch-deep); }
.btn--amber:hover { background: var(--amber-lo); }

.btn--ghost { border-color: currentColor; color: inherit; background: transparent; }
.btn--ghost:hover { background: var(--amber); border-color: var(--amber); color: var(--pitch-deep); }

.btn-row { display: flex; flex-wrap: wrap; gap: .75rem; }

/* ---------- 6. Masthead ---------- */
.masthead {
  position: sticky; top: 0; z-index: 100;
  background: linear-gradient(180deg, var(--pitch) 0%, var(--pitch-deep) 100%);
  color: var(--chalk);
  border-bottom: 1px solid var(--pitch-line);
}
.masthead__bar {
  max-width: var(--maxw);
  margin-inline: auto;
  padding: .8rem var(--gutter);
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.mark {
  display: flex; align-items: center; gap: .7rem;
  text-decoration: none; color: inherit;
  margin-right: auto;
}
/* Crest slot. The crest is drawn for a white ground, so it sits on a
   white chip — that keeps every colour in the mark true and gives the
   darker teal lettering something to read against.
   The ball-and-seam below is a fallback for when no crest file exists;
   `img + .mark__seam` hides it whenever the image is present, and the
   image removes itself on error, which brings the fallback back. */
.mark__badge {
  position: relative;
  /* 52px, not 40: the crest carries banners and fine lettering, and
     below about 50px it collapses into a coloured smudge. */
  width: 52px; height: 52px; flex: none;
  /* No chip — the crest sits directly on the navy. Its own reds,
     oranges, cyan and whites all carry against that ground. */
  background: transparent;
}
.mark__badge img {
  position: relative; z-index: 1;
  width: 100%; height: 100%;
  object-fit: contain;
}
.mark__badge img + .mark__seam { display: none; }
.mark__seam {
  position: absolute; inset: 5px;
  border-radius: 50%;
  background: var(--claret);
  box-shadow: inset 0 -4px 8px rgba(0,0,0,.35);
}
/* The seam: two stitched arcs of a cricket ball */
.mark__seam::before,
.mark__seam::after {
  content: "";
  position: absolute; inset: 4px 0;
  border-left: 1.5px dashed var(--paper-2);
  left: 50%;
  transform: translateX(-50%);
}
.mark__seam::after { inset: 8px 0; opacity: .5; }

.mark__text { line-height: 1; }
.mark__name {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.05rem;
  letter-spacing: -.01em;
  text-transform: uppercase;
  display: block;
}
.mark__sub {
  font-family: var(--mono);
  font-size: .58rem;
  letter-spacing: .07em;
  color: var(--ash);
  text-transform: uppercase;
}

.nav { display: flex; align-items: center; gap: .15rem; }
/* :not(.btn) so the Join CTA keeps its own button styling — plain
   `.nav a` (0,1,1) outranks `.btn--amber` (0,1,0) and would otherwise
   force white text on amber, a teal hover, and amber-on-amber text
   when aria-current lands on it. */
.nav a:not(.btn) {
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  text-decoration: none;
  padding: .55rem .62rem;
  border-radius: var(--r);
  color: var(--chalk);
  opacity: .78;
  transition: opacity .15s, background-color .15s;
  white-space: nowrap;
}
.nav a:not(.btn):hover { opacity: 1; background: var(--pitch-3); }
.nav a:not(.btn)[aria-current="page"] {
  opacity: 1;
  color: var(--amber);
  box-shadow: inset 0 -2px 0 var(--amber);
}

/* ---------- press feedback ----------
   Every clickable surface answers the pointer within its own frame: a
   small lift on hover, and a settle back down on press. Kept to
   transform and shadow so nothing reflows, and scoped to devices that
   actually hover — a phone would otherwise leave the lifted state
   stuck after a tap. */
@media (hover: hover) {
  .btn { transition: transform .18s var(--ease), box-shadow .18s var(--ease),
                     background-color .22s var(--ease), color .22s var(--ease); }
  .btn:hover { transform: translateY(-2px); box-shadow: var(--e2); }
}
.btn:active { transform: translateY(0) scale(.985); box-shadow: var(--e1); }

@media (prefers-reduced-motion: reduce) {
  .player, .btn { transition: none; }
  .player:hover, .player:focus-within, .btn:hover, .btn:active { transform: none; }
}

/* ---------- theme toggle ---------- */
.theme-toggle {
  flex: none;
  width: 38px; height: 38px;
  display: grid; place-items: center;
  margin-left: .35rem;
  border: 1px solid var(--pitch-line);
  border-radius: 50%;
  background: transparent;
  color: var(--chalk);
  cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease);
}
.theme-toggle:hover { background: var(--pitch-3); border-color: var(--amber); }
.theme-toggle__icon { width: 17px; height: 17px; }
/* One icon at a time: the sun offers the light theme, so it shows
   while the dark one is active, and vice versa. */
.theme-toggle__icon--sun { display: none; }
[data-theme="dark"] .theme-toggle__icon--sun  { display: block; }
[data-theme="dark"] .theme-toggle__icon--moon { display: none; }

.nav-toggle {
  display: none;
  background: transparent;
  border: 2px solid var(--pitch-line);
  color: var(--chalk);
  border-radius: var(--r);
  padding: .5rem .8rem;
  font-family: var(--mono);
  font-size: .72rem;
  letter-spacing: .085em;
  text-transform: uppercase;
  cursor: pointer;
}

/* ---------- 7. Scoreboard (hero signature) ---------- */
.hero {
  background: linear-gradient(180deg, var(--pitch) 0%, var(--pitch-deep) 100%);
  color: var(--chalk);
  position: relative;
  overflow: hidden;
  /* Cut right back. The controls no longer live in a bottom strip, so
     the band it needed goes with them. */
  padding-block: clamp(2rem, 3.6vw, 3.25rem);
}
/* The wordmark carried the old three-word slogan at slogan size. As a
   club name it wants to read as a wordmark, not a billboard — and it
   is what was making the section tall. */
.hero__title { font-size: clamp(2.1rem, 5.2vw, 4.4rem); }
/* Hero slideshow. The club's own photographs crossfade behind the
   headline; the scrim below keeps the type legible over all of them. */
.hero__stage {
  position: absolute; inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
.hero__slide {
  position: absolute; inset: 0;
  background-size: cover;
  /* Per-photo focal point, set by the script from the measured
     position of the players. See HERO_IMAGES in data.js. */
  background-position: center var(--posy, 42%);
  opacity: 0;
  transition: opacity 1s var(--ease);
}
.hero__slide.is-on { opacity: .84; }

@media (prefers-reduced-motion: reduce) {
  .hero__slide { transition: none; }
}
.hero::before {
  content: "";
  position: absolute; inset: 0;
  z-index: 1;
  /* Falls away past the text column, which ends at ~54% of the hero.
     Wound back as far as it goes: measured against the brightest pixel
     of all nine slides under the real glyph boxes, and at each photo's
     own focal crop, the lede lands at 4.85:1 against the 4.5 it needs.
     One step lighter puts it at 4.21:1. That one line of body copy is
     the whole constraint — everything else has room. */
  background:
    linear-gradient(96deg, rgba(0,46,95,.78) 0%, rgba(0,46,95,.75) 56%, rgba(0,46,95,.40) 78%, rgba(0,46,95,.26) 100%),
    radial-gradient(120% 90% at 82% 8%, rgba(245,130,31,.08), transparent 55%),
    repeating-linear-gradient(to bottom, rgba(255,255,255,.03) 0 1px, transparent 1px 46px);
  pointer-events: none;
}
/* Hero layers, back to front: slides (0) → scrim (1) → content (2) →
   controls (3). This names the content wrapper rather than matching
   every child: an earlier `.hero > *` also caught the backdrop and,
   on equal specificity, overrode its `position: absolute` — which
   collapsed the stage to 0px and blanked the slideshow entirely. */
.hero > .wrap { position: relative; z-index: 2; }

/* ---------- hero slide controls ---------- */
.hero__nav {
  position: absolute;
  bottom: clamp(1.25rem, 2.5vw, 2rem);
  z-index: 3;
  width: clamp(44px, 3.4vw, 52px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  border: 1px solid rgba(247,249,252,.32);
  border-radius: 50%;
  background: rgba(0,30,64,.55);
  color: var(--chalk);
  cursor: pointer;
  transition: background .3s var(--ease), border-color .3s var(--ease),
              transform .3s var(--ease);
}
.hero__nav--prev { left: var(--gutter); }
.hero__nav--next { right: var(--gutter); }

/* On a wide screen they move to the middle of each edge, the way
   Prahran's do. The hero content takes a wider inline padding to
   match — the type is left-aligned to the gutter, so without it the
   left arrow would land on top of the wordmark. */
@media (min-width: 901px) {
  .hero__nav {
    top: 50%; bottom: auto;
    translate: 0 -50%;
  }
  .hero__nav--prev { left: clamp(10px, 1.1vw, 18px); }
  .hero__nav--next { right: clamp(10px, 1.1vw, 18px); }
  .hero > .wrap { padding-inline: calc(var(--gutter) + 2.6rem); }
}
.hero__nav:hover {
  background: rgba(0,30,64,.82);
  border-color: var(--amber);
  transform: translateY(-2px);
}
.hero__nav:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; }
.hero__nav svg { width: 40%; fill: none; stroke: currentColor; stroke-width: 2.2; }
/* Hidden until the script wires them up — they do nothing without it,
   and `display: grid` would otherwise beat the UA rule for [hidden]. */
.hero__nav[hidden] { display: none; }
@media (prefers-reduced-motion: reduce) {
  .hero__nav { transition: none; }
  .hero__nav:hover { transform: none; }
}

@media (max-width: 900px) {
  /* The controls stay in the bottom corners here — a phone has no clear
     column for them to sit beside — so the hero keeps the strip they
     need. Desktop, where the height mattered, does not carry it. */
  .hero { padding-bottom: calc(clamp(2rem, 3.6vw, 3.25rem) + 3.75rem); }
  /* A portrait viewport crops a landscape photo hard to its centre,
     so the slides pull back and sit further behind the type. */
  .hero__slide { background-position: center 38%; }
  .hero__slide.is-on { opacity: .86; }
  /* There is no open column on a phone — the type runs the full width
     — so the scrim stays near-solid down through the lede (ending at
     41%) and only opens up over the button row, where the one piece of
     unbacked type gets its own plate below. The scoreboard is opaque,
     so nothing shows behind it either way. */
  .hero::before {
    background:
      linear-gradient(to bottom, rgba(0,46,95,.78) 0%, rgba(0,46,95,.78) 41%, rgba(0,46,95,.46) 47%, rgba(0,46,95,.40) 62%, rgba(0,46,95,.56) 100%),
      repeating-linear-gradient(to bottom, rgba(255,255,255,.03) 0 1px, transparent 1px 46px);
  }
  /* The outline button is the only hero text with nothing behind it
     once the scrim opens up; a photo can put sky right under it. */
  .hero .btn--ghost { background: rgba(0,30,64,.62); }
}

.hero__grid {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  align-items: end;
}

.hero__title { margin-bottom: 1.4rem; }
.hero__title .line { display: block; overflow: hidden; }
.hero__title .line > span { display: block; }
.hero__title em {
  font-style: normal;
  color: var(--amber);
}

.board {
  background: var(--pitch-2);
  border: 1px solid var(--pitch-line);
  border-radius: var(--r);
  padding: 1.4rem;
  box-shadow: var(--e4);
}
.board__head {
  display: flex; justify-content: space-between; align-items: baseline;
  font-family: var(--mono);
  font-size: .64rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ash);
  border-bottom: 1px solid var(--pitch-line);
  padding-bottom: .8rem;
  margin-bottom: 1.1rem;
  gap: 1rem;
}
.board__plates {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: .5rem;
}
.plate {
  background: var(--pitch);
  border: 1px solid var(--pitch-line);
  border-radius: 3px;
  padding: .85rem .4rem .6rem;
  text-align: center;
  box-shadow: inset 0 2px 0 rgba(0,0,0,.4);
}
.plate__v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: clamp(1.2rem, 2.1vw, 1.6rem);
  color: var(--amber);
  line-height: 1;
  display: block;
}
.plate__k {
  font-family: var(--mono);
  font-size: .55rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ash);
  margin-top: .45rem;
  display: block;
}
.board__foot {
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px dashed var(--pitch-line);
  font-family: var(--mono);
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ash);
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
}
.board__foot b { color: var(--chalk); font-weight: 700; }

/* ---------- 8. Boundary line (signature device) ----------
   A single bar split by the player's real fours-to-sixes ratio.
   It encodes something true and specific about this club: a
   hard-tennis-ball T10 side where several players hit more sixes
   than fours. Claret = fours, amber = sixes. */
.bline { margin-top: .2rem; }
.bline__bar {
  display: flex;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--paper-2);
}
.on-pitch .bline__bar { background: var(--pitch-3); }
.bline__4 { background: var(--claret); }
.bline__6 { background: var(--amber); }
.bline__4, .bline__6 {
  transform-origin: left;
  transition: flex-grow .5s var(--ease);
}
.bline__key {
  display: flex;
  gap: 1rem;
  margin-top: .55rem;
  font-family: var(--mono);
  font-size: .58rem;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ash-deep);
}
.on-pitch .bline__key { color: var(--ash); }
.bline__key span { display: flex; align-items: center; gap: .38rem; }
.bline__key i {
  width: 8px; height: 8px; border-radius: 2px; flex: none;
  background: var(--claret);
}
.bline__key span + span i { background: var(--amber); }
.bline__key b {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.on-pitch .bline__key b { color: var(--chalk); }

/* ---------- 9. Cards ---------- */
.card {
  /* A flat fill is what made these read as boxes. The gradient runs
     between two colours already in the palette, so nothing new is
     introduced — it just stops the surface being one dead tone. */
  background: linear-gradient(180deg, var(--card) 0%, var(--paper-2) 100%);
  border: 1px solid var(--paper-line);
  border-radius: var(--r);
  padding: clamp(1.25rem, 2.2vw, 1.75rem);
  box-shadow: var(--e1), var(--lip);
}
.on-pitch .card {
  background: linear-gradient(180deg, var(--pitch-2) 0%, var(--pitch) 100%);
  border-color: var(--pitch-line);
  box-shadow: var(--e2);
}

/* Player card — photo-led, with the cap number worn on the image */
.player {
  position: relative;
  display: flex;
  flex-direction: column;
  text-decoration: none;
  color: inherit;
  background: linear-gradient(180deg, var(--card) 0%, var(--paper-2) 100%);
  border: 1px solid var(--paper-line);
  border-radius: var(--r);
  overflow: hidden;
  box-shadow: var(--e1), var(--lip);
  /* 220ms sits in the 150-300ms band for a micro-interaction, and only
     transform and box-shadow move — nothing that triggers layout. */
  transition: box-shadow .22s var(--ease), border-color .22s var(--ease),
              transform .22s var(--ease);
}
.on-pitch .player {
  background: linear-gradient(180deg, var(--pitch-2) 0%, var(--pitch) 100%);
  border-color: var(--pitch-line);
}

.player:hover, .player:focus-within {
  transform: translateY(-3px);
  box-shadow: var(--e3), var(--lip);
  border-color: var(--pitch-line);
}

/* ---- photo ---- */
.player__shot {
  position: relative;
  /* Portrait ratio, but capped: without the cap the panel grows with
     the card, so a wide card produced a 500px+ image and a very tall
     card. The cap also means every card lands at the same height
     whatever the column width. */
  /* Square, matching the square source crops, so the framing chosen
     per photo is the framing that shows. No max-height: capping it
     turned the panel landscape between two and four columns (337x300
     at 768px) and re-cropped 11% off the top of every head. The
     column width already keeps this in range. */
  aspect-ratio: 1 / 1;
  background: var(--pitch);
  overflow: hidden;
}
.player__shot img {
  /* Positioned so it paints ABOVE the monogram. The monogram is
     absolutely positioned and comes first in the DOM, so a static img
     was painting underneath it — the photo only appeared on hover,
     when the scale transform promoted it into its own stacking
     context. */
  position: relative;
  z-index: 1;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: center;
  transition: transform .6s var(--ease);
}
.player:hover .player__shot img { transform: scale(1.04); }

/* Monogram stands in until a real photo is dropped in. It is a
   designed state, not a broken-image placeholder. */
.player__mono {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background:
    radial-gradient(120% 90% at 30% 15%, var(--pitch-3), var(--pitch) 70%);
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2rem, 3.2vw, 2.9rem);
  letter-spacing: .02em;
  color: rgba(245,247,242,.16);
  user-select: none;
}
/* Photo panel layers: monogram (0) -> photo (1) -> scrim (2) -> name (3).
   The scrim had no z-index while the photo has one, so the photo was
   painting straight over it and the name sat on bare picture — white
   type on a white studio background on half the squad. */
.player__shot::after {
  content: "";
  position: absolute; inset: 0;
  z-index: 2;
  /* No wash over the picture itself — see .player__id, which carries
     its own scrim sized to the text it holds. */
  background: none;
  pointer-events: none;
}

/* The scrim rides with the text rather than being a fixed slice of the
   panel. A one-line name sits 26% up and a wrapped one 32%, so any
   fixed ramp is either too weak for the long names or drowns the
   player for the short ones. Anchored to the text block it is always
   exactly as tall as it needs to be, and the fade happens inside the
   top padding, so the type always lands on the strong part. */
.player__id {
  position: absolute; left: 0; right: 0; bottom: 0;
  z-index: 3;
  padding: 2.75rem 1rem .95rem;
  background: linear-gradient(to top,
    rgba(0,46,95,.97) 0%, rgba(0,46,95,.95) 45%, rgba(0,46,95,.55) 75%, transparent 100%);
}
.player__name {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.02rem, 1.2vw, 1.24rem);
  line-height: .92;
  text-transform: uppercase;
  color: var(--chalk);
  margin: 0 0 .3rem;
}
.player__role {
  font-family: var(--mono);
  font-size: .58rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--amber);
}

/* Cap number, worn top-left like a shirt number */
.player__cap {
  position: absolute; top: .8rem; left: .8rem; z-index: 1;
  min-width: 38px; height: 38px;
  display: grid; place-items: center;
  padding: 0 .5rem;
  border-radius: 3px;
  background: rgba(0,46,95,.72);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(245,247,242,.18);
  color: var(--chalk);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: .82rem;
}
.player__cap.is-skipper { background: var(--claret); border-color: var(--claret); }

/* ---- body ---- */
.player__body {
  padding: 1.05rem 1.1rem 1.15rem;
  display: flex;
  flex-direction: column;
  gap: .8rem;
  flex: 1;
}
.player__stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(52px, 1fr));
  gap: .45rem .4rem;
  padding-bottom: .8rem;
  border-bottom: 1px solid var(--paper-line);
}
.on-pitch .player__stats { border-bottom-color: var(--pitch-line); }
.player__note {
  font-size: .85rem;
  line-height: 1.5;
  color: var(--ash-deep);
  margin: 0;
  margin-top: auto;
}
.on-pitch .player__note { color: var(--ash); }

.player__link {
  font-family: var(--mono);
  font-size: .58rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--claret-ink);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  align-self: flex-start;
}
.on-pitch .player__link { color: var(--amber); }
.player__link:hover { opacity: .75; }

.player__none {
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--ash-deep);
  padding: .5rem 0;
}
.stat__v {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  font-size: 1.05rem;
  display: block;
  line-height: 1.1;
}
.stat__k {
  font-family: var(--mono);
  font-size: .53rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--ash-deep);
  display: block;
  margin-top: .2rem;
}

.badge {
  position: absolute; top: .8rem; right: .8rem; z-index: 1;
  border-radius: 3px;
  background: var(--amber);
  color: var(--pitch-deep);
  font-family: var(--mono);
  font-size: .55rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: .3rem .6rem;
}

/* ---------- 10. Big stat blocks ---------- */
.tally { border-top: 2px solid currentColor; padding-top: 1rem; }
.tally__v {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.1rem, 3.8vw, 3.1rem);
  line-height: .85;
  display: block;
}
.on-pitch .tally__v { color: var(--amber); }
.tally__k {
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ash-deep);
  margin-top: .6rem;
  display: block;
}
.on-pitch .tally__k { color: var(--ash); }

/* ---------- 11. Tables ---------- */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

.tbl {
  width: 100%;
  border-collapse: collapse;
  min-width: 640px;
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
  font-size: .8rem;
}
.tbl th {
  text-align: left;
  font-size: .6rem;
  font-weight: 600;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ash-deep);
  padding: .7rem .8rem;
  border-bottom: 2px solid var(--pitch);
  white-space: nowrap;
}
.tbl td {
  padding: .85rem .8rem;
  border-bottom: 1px solid var(--paper-line);
  white-space: nowrap;
}
.tbl td:first-child, .tbl th:first-child { padding-left: 0; }
.tbl tbody tr:hover td { background: rgba(206,27,51,.06); }
.tbl .is-name { font-family: var(--body); font-weight: 600; white-space: normal; }
.tbl .is-lead { color: var(--claret-ink); font-weight: 700; }

.on-pitch .tbl th { color: var(--ash); border-bottom-color: var(--amber); }
.on-pitch .tbl td { border-bottom-color: var(--pitch-line); }
.on-pitch .tbl tbody tr:hover td { background: rgba(255,145,48,.08); }
/* Highlighted figures are claret, which is a light-background colour —
   on a dark section it measured 1.93:1. Amber on the same ground is
   5.03:1. */
.on-pitch .tbl .is-lead { color: var(--amber); }

.tbl__cap {
  caption-side: bottom;
  text-align: left;
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .06em;
  color: var(--ash-deep);
  padding-top: .9rem;
  white-space: normal;
}
.on-pitch .tbl__cap { color: var(--ash); }

/* ---------- 11b. Ranked bars ---------- */
.ranked {
  display: grid;
  grid-template-columns: minmax(0, 170px) minmax(0, 1fr) 40px;
  align-items: center;
  gap: 1rem;
  padding: .6rem 0;
  border-bottom: 1px solid var(--paper-line);
}
.on-pitch .ranked { border-bottom-color: var(--pitch-line); }
.ranked__name { font-weight: 600; font-size: .92rem; }
.ranked__track {
  height: 10px;
  border-radius: 999px;
  background: var(--paper-2);
  overflow: hidden;
}
.on-pitch .ranked__track { background: var(--pitch-3); }
.ranked__fill {
  display: block; height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--cyan), var(--amber));
}
.ranked__v { text-align: right; font-size: .92rem; }

.pill {
  display: inline-block;
  font-family: var(--mono);
  font-size: .58rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  padding: .22rem .5rem;
  border-radius: 2px;
}
.pill--w { background: var(--amber); color: var(--pitch-deep); }
.pill--l { background: var(--paper-2); color: var(--ash-deep); }
.on-pitch .pill--l { background: var(--pitch-deep); color: var(--ash); }
.pill--t { background: var(--claret); color: var(--chalk); }

/* ---------- 12. Fixture rows ---------- */
.fixture {
  display: grid;
  grid-template-columns: 86px minmax(0,1fr) auto;
  gap: 1.25rem;
  align-items: center;
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--paper-line);
}
.on-pitch .fixture { border-bottom-color: var(--pitch-line); }
.fixture:first-child { border-top: 1px solid var(--paper-line); }
.on-pitch .fixture:first-child { border-top-color: var(--pitch-line); }

.fixture__date {
  font-family: var(--mono);
  text-align: center;
  border-right: 1px solid var(--paper-line);
  padding-right: 1rem;
  line-height: 1.1;
}
.on-pitch .fixture__date { border-right-color: var(--pitch-line); }
.fixture__day { display: block; font-size: 1.35rem; font-weight: 700; font-variant-numeric: tabular-nums; }
.fixture__mon { display: block; font-size: .58rem; letter-spacing: .085em; text-transform: uppercase; color: var(--ash-deep); }
.on-pitch .fixture__mon { color: var(--ash); }

.fixture__opp { font-family: var(--display); font-weight: 700; font-size: 1.18rem; line-height: 1.15; letter-spacing: -.015em; text-transform: uppercase; }
.fixture__meta { font-family: var(--mono); font-size: .62rem; letter-spacing: .06em; text-transform: uppercase; color: var(--ash-deep); margin-top: .4rem; }
.on-pitch .fixture__meta { color: var(--ash); }

.fixture.is-next { background: rgba(245,165,36,.09); padding-inline: 1rem; margin-inline: -1rem; }

/* ---------- 13. Page header ---------- */
.pagehead {
  background: linear-gradient(180deg, var(--pitch) 0%, var(--pitch-deep) 100%);
  color: var(--chalk);
  padding-block: clamp(3rem, 7vw, 5.5rem) clamp(2.5rem, 5vw, 4rem);
  position: relative;
  overflow: hidden;
}
.pagehead::before {
  content: "";
  position: absolute; inset: 0;
  background: repeating-linear-gradient(to bottom, rgba(255,255,255,.03) 0 1px, transparent 1px 46px);
}
/* Names the wrapper rather than matching every child, so the artwork
   layer below keeps its own positioning. */
.pagehead > .wrap { position: relative; z-index: 2; }
/* Both lifted off --ash: there is artwork behind them now, and --ash
   was tuned for flat blue. The crumb links were already the tightest
   type on the site at 4.2:1 — small, dim, and dimmed again by an .8
   opacity on the anchor. */
.pagehead .lede { color: #C2D5EA; margin-top: 1.4rem; }
.pagehead .crumb { color: #C2D5EA; }
.pagehead .crumb a { opacity: .92; }

/* ---------- 13b. Page-head artwork ----------
   Eleven inner pages shared one flat blue band. Each now carries its
   own motif taken from the game, picked by the page key already on
   <body>. Every shape is styled at its finished state and the
   keyframes run *from* an off-state, so killing the animation under
   reduced motion leaves the drawing intact rather than an empty box.

   Entrances only ever touch `transform`; ambient loops only ever
   touch `translate`. Keeping them on separate properties means the
   two can run on one element without fighting over a shared value. */
.ph-art {
  position: absolute; inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  --ink: #A7C4E2;
}
.ph-art svg { display: block; width: 100%; height: 100%; }

@keyframes ph-riser  { from { transform: scaleY(0); opacity: 0; } }
@keyframes ph-pop    { from { transform: scale(0); opacity: 0; } }
@keyframes ph-wipe   { from { transform: scaleX(0); opacity: 0; } }
@keyframes ph-lift   { from { transform: translateY(26px) scaleY(.2); opacity: 0; } }
@keyframes ph-draw   { from { stroke-dashoffset: 1; } }
@keyframes ph-float  { to   { translate: 0 -9px; } }
@keyframes ph-run    { to   { translate: -1040px 0; } }
@keyframes ph-travel { from { offset-distance: 0%; } to { offset-distance: 100%; } }

/* Every stroked motif is normalised with pathLength="1", so one
   dash rule draws a line, an arc and a bezier alike. */
.ph-art [data-draw] {
  fill: none;
  stroke-dasharray: 1;
  stroke-dashoffset: 0;
  animation: ph-draw 1.1s var(--ease) backwards;
  animation-delay: calc(var(--i, 0) * 90ms);
}

/* about — eleven risers, for eleven on the park */
.a-riser {
  fill: var(--ink); opacity: .2;
  transform-box: fill-box; transform-origin: 50% 100%;
  transform: scaleY(var(--h));
  animation: ph-riser .9s var(--ease) backwards;
  animation-delay: calc(var(--i) * 70ms);
}
/* squad — the slip cordon */
.a-dot {
  fill: var(--ink); opacity: .22;
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: ph-pop .7s var(--ease) backwards,
             ph-float 7s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * 80ms), calc(var(--i) * 240ms);
}
.a-dot.is-key { opacity: .26; }
.a-cordon { stroke: var(--ink); stroke-width: 2; opacity: .14; }
/* fixtures — the draw */
.a-bar {
  fill: var(--ink); opacity: .18;
  transform-box: fill-box;
  animation: ph-wipe .8s var(--ease) backwards;
  animation-delay: calc(var(--i) * 90ms);
}
.a-bar.from-l { transform-origin: 0 50%; }
.a-bar.from-r { transform-origin: 100% 50%; }
/* results — over by over, wickets marked */
.a-over {
  fill: var(--ink); opacity: .2;
  transform-box: fill-box; transform-origin: 50% 100%;
  transform: scaleY(var(--h));
  animation: ph-riser .8s var(--ease) backwards;
  animation-delay: calc(var(--i) * 45ms);
}
.a-wk {
  fill: var(--ink); opacity: .26;
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: ph-pop .6s var(--ease) backwards;
  animation-delay: calc(var(--i) * 45ms + 320ms);
}
/* stats — the wagon wheel */
.a-ray { stroke: var(--ink); stroke-width: 2; opacity: .22; }
.a-hub { fill: var(--ink); opacity: .26; }
/* news — the ticker */
.a-tick {
  fill: var(--ink); opacity: .16;
  animation: ph-run var(--dur) linear infinite;
}
/* gallery — a contact sheet with a player in every frame */
.a-cell {
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: ph-pop .7s var(--ease) backwards,
             ph-float 6s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * 35ms), calc(var(--i) * 80ms);
}
.a-frame { fill: none; stroke: var(--ink); stroke-width: 2; opacity: .22; }
/* The player inside each frame. */
.a-player { opacity: .26; }
.a-player circle,
.a-player rect { fill: var(--ink); }
.a-player path,
.a-player line {
  fill: none;
  stroke: var(--ink);
  stroke-width: 5;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Pivot at the hands and at the shoulder, not at the middle of the
   limb. Durations run off --i so two dozen figures do not swing as
   one metronome. */
.a-mini-bat {
  transform-box: fill-box; transform-origin: 50% 0%;
  rotate: -30deg;
  animation: ph-minibat calc(2.8s + var(--i) * 90ms) var(--ease) infinite;
}
.a-mini-arm {
  transform-box: fill-box; transform-origin: 0% 100%;
  rotate: -140deg;
  animation: ph-miniarm calc(3.1s + var(--i) * 90ms) var(--ease) infinite;
}
@keyframes ph-minibat {
  0%, 55% { rotate: -30deg; }
  72%     { rotate: 26deg; }
  100%    { rotate: -30deg; }
}
@keyframes ph-miniarm {
  0%, 40% { rotate: -140deg; }
  62%     { rotate: 12deg; }
  100%    { rotate: -140deg; }
}
/* contact — the crease, and a ball bowled down it */
.a-line  { stroke: var(--ink); stroke-width: 3; opacity: .2; }
.a-stump { stroke: var(--ink); stroke-width: 6; opacity: .26; stroke-linecap: round; }
/* The line the ball comes down, up to the point of contact. It stops
   there deliberately — where the shot goes is the ball's business.
   No dash pattern here: `[data-draw]` sets stroke-dasharray to drive
   the draw-on, at higher specificity, so one would be dead code. */
.a-track { stroke: var(--ink); stroke-width: 2; opacity: .12; }
/* The two players. Silhouettes rather than detail — at this size and
   this opacity anything finer turns to mud. */
.a-figure { opacity: .26; }
.a-figure circle { fill: var(--ink); }
.a-figure path {
  fill: none;
  stroke: var(--ink);
  stroke-width: 7;
  stroke-linecap: round;
}
/* The bowling arm, pivoting at the shoulder rather than its middle. */
.a-arm {
  fill: none;
  stroke: var(--ink);
  stroke-width: 7;
  stroke-linecap: round;
  opacity: .26;
  transform-box: fill-box;
  transform-origin: 0% 100%;
  animation: ph-arm 4s var(--ease) infinite;
}
/* Releases at 0% with the ball, follows through, waits out the shot,
   then swings back over the top to deliver again. */
@keyframes ph-arm {
  0%   { rotate: 0deg; }
  20%  { rotate: 62deg; }
  56%  { rotate: 62deg; }
  82%  { rotate: -150deg; }
  100% { rotate: 0deg; }
}
.a-bat {
  fill: var(--ink); opacity: .24;
  transform-box: fill-box;
  transform-origin: 50% 4%;          /* the hands, not the middle of the blade */
  rotate: -44deg;
  animation: ph-bat 4s var(--ease) infinite;
}
.a-cherry {
  fill: var(--ink); opacity: .26;
  animation: ph-bowl 4s linear infinite;
}
/* Keyframed in viewBox units rather than along an offset-path. On an
   SVG child `offset-path: path()` does not resolve against the viewBox
   the way it reads: the ball came out at (725,98) for a path point of
   (545,170), a long way past the bat. `translate` on an SVG element is
   plain user units and lands where the numbers say.

   Down the pitch, pitching at 42%, met by the bat at 56%, then away —
   note the spacing between keyframes widens after contact, because a
   struck ball does not travel at bowling speed. */
@keyframes ph-bowl {
  0%        { translate: 440px 66px; }    /* out of the bowler's hand */
  14%       { translate: 478px 118px; }
  27%       { translate: 520px 165px; }
  38%       { translate: 556px 196px; }
  44%       { translate: 578px 205px; }   /* pitches */
  50%       { translate: 622px 191px; }
  56%       { translate: 672px 176px; }   /* met by the middle of the blade */
  62%       { translate: 760px 138px; }
  70%       { translate: 900px 82px; }
  80%       { translate: 1090px 12px; }
  88%, 100% { translate: 1290px -30px; }  /* held off-canvas until it restarts */
}
/* Held back, through the line at 56% to meet the ball, then reset
   while the ball is out of shot so the recovery is never seen. */
@keyframes ph-bat {
  0%, 40% { rotate: -44deg; }
  56%     { rotate: 12deg; }
  64%     { rotate: 32deg; }
  88%     { rotate: 32deg; }
  100%    { rotate: -44deg; }
}
/* join — the delivery */
.a-arc  { stroke: var(--ink); stroke-width: 3; opacity: .24; }
.a-ball {
  fill: var(--ink); opacity: .26;
  offset-path: path("M -20 96 C 300 40, 520 250, 760 236 S 1080 150, 1240 84");
  offset-rotate: 0deg;
  /* Linear, not eased: a ball in flight holds its pace, and the club's
     easing curve made it arrive and then loiter. */
  animation: ph-travel 9s linear infinite;
}
/* sponsors — the boundary boards */
.a-board {
  fill: var(--ink); opacity: .18;
  transform-box: fill-box; transform-origin: 50% 100%;
  animation: ph-lift .8s var(--ease) backwards;
  animation-delay: calc(var(--i) * 85ms);
}
/* policies — the ledger */
.a-rule { stroke: var(--ink); stroke-width: 2; opacity: .18; }

@media (prefers-reduced-motion: reduce) {
  /* The finished state is the base state, so this stops the motion
     without taking the artwork away. */
  .ph-art * { animation: none !important; }
  /* The ball's base position is off the left edge, which would just
     read as a missing element. Park it at the moment of contact. */
  .a-cherry { translate: 672px 176px; }
}

.crumb {
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--ash);
  margin-bottom: 1.4rem;
}
.crumb a { text-decoration: none; opacity: .8; }
.crumb a:hover { opacity: 1; color: var(--amber); }

/* ---------- 14. Timeline / values ---------- */
.rule-list { list-style: none; margin: 0; padding: 0; }
.rule-list li {
  padding: 1.15rem 0;
  border-bottom: 1px solid var(--paper-line);
  display: grid;
  grid-template-columns: minmax(0, 200px) minmax(0, 1fr);
  gap: 1.5rem;
  align-items: baseline;
}
.on-pitch .rule-list li { border-bottom-color: var(--pitch-line); }
.rule-list li:first-child { border-top: 1px solid var(--paper-line); }
.on-pitch .rule-list li:first-child { border-top-color: var(--pitch-line); }
.rule-list dt, .rule-list .k {
  font-family: var(--display);
  font-weight: 700;
  font-size: 1.05rem;
  text-transform: uppercase;
  line-height: 1.15;
}
.rule-list .k-mono {
  font-family: var(--mono);
  font-size: .7rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--claret-ink);
  font-weight: 700;
}
.on-pitch .rule-list .k-mono { color: var(--amber); }

/* ---------- 15. Gallery ---------- */
/* Every tile identical: same span, same ratio. Mixed spans and mixed
   ratios were what left the rows ragged before — uniform tiles mean a
   row can only ever close exactly. */
.gallery {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
  gap: clamp(.6rem, 1vw, 1rem);
}
.shot {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--r);
  overflow: hidden;
  background: var(--pitch-2);
  display: grid;
  place-items: center;
  border: 1px solid var(--pitch-line);
}
.shot img { width: 100%; height: 100%; object-fit: cover; }
.shot__ph {
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--ash);
  text-align: center;
  padding: 1rem;
}
.shot__cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: .7rem .85rem;
  background: linear-gradient(to top, rgba(0,46,95,.92), transparent);
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--chalk);
}

/* ---------- 16. Forms ---------- */
.field { display: block; margin-bottom: 1.1rem; }
.field > span {
  display: block;
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--ash-deep);
  margin-bottom: .45rem;
}
.on-pitch .field > span { color: var(--ash); }
.field input, .field select, .field textarea {
  width: 100%;
  font: inherit;
  font-size: .95rem;
  padding: .8rem .9rem;
  border: 1.5px solid var(--paper-line);
  border-radius: var(--r);
  background: var(--card);
  color: var(--ink);
}
.field textarea { min-height: 130px; resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--claret);
  outline: none;
  box-shadow: 0 0 0 3px rgba(0,46,95,.16);
}
.form-note {
  font-family: var(--mono);
  font-size: .62rem;
  letter-spacing: .06em;
  color: var(--ash-deep);
  line-height: 1.6;
}

/* ---------- 17. Footer ---------- */
.foot {
  background: linear-gradient(180deg, var(--pitch) 0%, var(--pitch-deep) 100%);
  color: var(--chalk);
  padding-block: clamp(3rem, 6vw, 4.5rem) 1.75rem;
  border-top: 4px solid var(--claret);
}
.foot__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr));
  gap: 2.5rem;
  padding-bottom: 2.5rem;
  border-bottom: 1px solid var(--pitch-line);
}
.foot h4 {
  font-family: var(--mono);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .085em;
  text-transform: uppercase;
  color: var(--amber);
  margin: 0 0 1rem;
}
.foot ul { list-style: none; margin: 0; padding: 0; }
.foot li { margin-bottom: .55rem; }
.foot a { text-decoration: none; color: var(--ash); font-size: .9rem; transition: color .15s; }
.foot a:hover { color: var(--chalk); }
.foot__bar {
  padding-top: 1.5rem;
  display: flex; flex-wrap: wrap; gap: 1rem; justify-content: space-between;
  font-family: var(--mono);
  font-size: .6rem;
  letter-spacing: .085em;
  text-transform: uppercase;
  /* --ash-deep is the grey for light backgrounds; the footer is navy,
     where it measured 2.2:1. */
  color: var(--ash);
}
/* Remove this chip once the placeholder data is replaced. */
.demo-chip {
  border: 1px solid var(--pitch-line);
  border-radius: 2px;
  padding: .25rem .5rem;
  color: var(--ash);
}

/* ---------- 18. Motion ----------
   Every hidden state is scoped to .js so the page is fully
   readable with JavaScript off, blocked, or still loading. */
.js [data-anim] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity .7s var(--ease), transform .7s var(--ease);
  transition-delay: var(--d, 0ms);
}
.js [data-anim].is-in { opacity: 1; transform: none; }

/* Board plates drop in like slotted number tiles */
.js .plate { opacity: 0; transform: translateY(-12px); }
.is-boarded .plate {
  animation: slot .5s var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * 90ms + 260ms);
}
@keyframes slot {
  from { opacity: 0; transform: translateY(-14px) scaleY(.86); }
  to   { opacity: 1; transform: none; }
}

.js .hero__title .line > span {
  transform: translateY(105%);
  animation: rise .9s var(--ease) forwards;
  animation-delay: calc(var(--i, 0) * 110ms);
}
@keyframes rise { to { transform: none; } }

/* The boundary bar fills from the left when it scrolls into view */
.js .bline__bar > * { transform: scaleX(0); }
.js .is-in .bline__bar > *,
.js .bline.is-in .bline__bar > * {
  animation: sweep .6s var(--ease) forwards;
  animation-delay: 120ms;
}
@keyframes sweep { to { transform: none; } }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0ms !important;
    transition-duration: .001ms !important;
  }
  .js [data-anim] { opacity: 1; transform: none; }
  .js .plate { opacity: 1; transform: none; }
  .js .bline__bar > * { transform: none; }
  .js .hero__title .line > span { transform: none; }
  .player:hover .player__shot img { transform: none; }
}

/* ---------- 19. Responsive ---------- */
@media (max-width: 1320px) {
  .nav a:not(.btn) { padding: .5rem .4rem; font-size: .69rem; letter-spacing: .05em; }
  .masthead__bar { gap: 1rem; }
}

@media (max-width: 1100px) {
  .nav {
    display: none;
    position: absolute; left: 0; right: 0; top: 100%;
    flex-direction: column;
    align-items: stretch;
    background: var(--pitch-2);
    border-bottom: 1px solid var(--pitch-line);
    padding: .75rem var(--gutter) 1.25rem;
    gap: 0;
  }
  .nav.is-open { display: flex; }
  .nav a:not(.btn) { padding: .85rem .25rem; font-size: .78rem; border-bottom: 1px solid var(--pitch-line); }
  .nav a:not(.btn)[aria-current="page"] { box-shadow: none; }
  .nav-toggle { display: block; }
  .masthead { position: relative; }
  .masthead__bar { position: relative; }

  .hero__grid, .split { grid-template-columns: 1fr; }
  .hero__grid { align-items: start; }
  .g-3, .g-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .foot__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 620px) {
  .g-2, .g-3, .g-4 { grid-template-columns: minmax(0, 1fr); }
  /* One card at a time. A 150px minimum still fitted two squad cards
     across a phone, which left every figure and every name cramped. */
  .g-auto { grid-template-columns: minmax(0, 1fr); }

  /* Square, matching the source photographs. 16/10 kept the card short
     but cropped a 700x700 portrait top and bottom — at one card to a
     row there is width to spare, and a square panel shows the whole
     frame with nothing cut off. */
  .player__shot { aspect-ratio: 1 / 1; }
  .player__body { padding: 1rem 1.1rem 1.15rem; }
  .player__stats { gap: .5rem .75rem; padding-bottom: .85rem; }
  .player__stats .stat__v { font-size: 1.15rem; }
  .player__note {
    font-size: .92rem;
    line-height: 1.5;
    /* Three lines is enough to place a player; the rest is on their
       profile. Without this the note alone ran half a screen. */
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .g-auto-lg { grid-template-columns: minmax(0, 1fr); }
  .ranked { grid-template-columns: minmax(0, 1fr) 34px; }
  .ranked__track { grid-column: 1 / -1; order: 3; }
  .foot__grid { grid-template-columns: 1fr; gap: 1.75rem; }
  .rule-list li { grid-template-columns: 1fr; gap: .4rem; }
  .fixture { grid-template-columns: 64px minmax(0,1fr); }
  .fixture > :last-child { grid-column: 1 / -1; }
  .board__plates { grid-template-columns: repeat(2, 1fr); }
  .player__stats { grid-template-columns: repeat(2, 1fr); }
  .fbox { width: 26px; height: 26px; font-size: .62rem; }
}

@media (max-width: 400px) {
  .masthead__bar { gap: .75rem; }
  .mark__badge { width: 44px; height: 44px; }
  .mark__name { font-size: 1.08rem; }
  .mark__sub { font-size: .52rem; letter-spacing: .1em; }
  .nav-toggle { padding: .45rem .6rem; font-size: .66rem; }
}

/* ---------- 21. Ethos & ticked lists ---------- */
.ethos__body {
  font-size: clamp(1rem, 1.2vw, 1.12rem);
  line-height: 1.55;
  margin: 0;
}
.on-pitch .ethos__body { color: var(--chalk); }

.ticked { list-style: none; }
ul.ticked-list { list-style: none; margin: 0; padding: 0; }
ul.ticked-list .ticked {
  position: relative;
  padding: .7rem 0 .7rem 2rem;
  border-bottom: 1px solid var(--paper-line);
  font-size: .98rem;
}
.on-pitch ul.ticked-list .ticked { border-bottom-color: var(--pitch-line); }
ul.ticked-list .ticked::before {
  content: "";
  position: absolute;
  left: .25rem;
  top: 1.15rem;
  width: 11px; height: 6px;
  /* Claret on light: the crest cyan only reaches 2.4:1 on paper, so it
     is reserved for dark surfaces where it clears 5.8:1. */
  border-left: 2px solid var(--claret);
  border-bottom: 2px solid var(--claret);
  transform: rotate(-45deg);
}
.on-pitch ul.ticked-list .ticked::before {
  border-left-color: var(--cyan);
  border-bottom-color: var(--cyan);
}

/* ---------- 22. Acknowledgement of Country ----------
   Given plainly in type. No artwork: the dot-painting style used by
   other cricket bodies is an Aboriginal artist's copyrighted work and
   is not ours to reproduce. */
.ack {
  margin: 0 0 1.5rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--pitch-line);
  max-width: 78ch;
}
.ack__label {
  margin: 0 0 .55rem;
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--amber);
}
.ack__body {
  margin: 0;
  font-size: .84rem;
  line-height: 1.7;
  color: var(--ash);
}

.ack-full p {
  font-size: clamp(1rem, 1.2vw, 1.1rem);
  line-height: 1.7;
  max-width: var(--measure);
}
.ack-full p:first-child { color: var(--chalk); }

/* ---------- 23. Next-page control ----------
   Sits at the end of every page's main content. A link the reader
   chooses, not a scroll-triggered jump. */
.pagenext {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding: clamp(2.25rem, 4.5vw, 3.75rem) var(--gutter);
  background: var(--pitch-2);
  border-top: 1px solid var(--pitch-line);
  color: var(--chalk);
  text-decoration: none;
  position: relative;
  overflow: hidden;
  transition: background-color .3s var(--ease);
}
.pagenext::before {
  content: "";
  position: absolute; inset: 0;
  background: repeating-linear-gradient(to bottom, rgba(255,255,255,.028) 0 1px, transparent 1px 46px);
  pointer-events: none;
}
.pagenext:hover { background: var(--pitch-3); }

.pagenext__inner {
  position: relative;
  max-width: var(--maxw);
  margin-inline: auto;
  flex: 1;
  min-width: 0;
}
.pagenext__label {
  display: block;
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--amber);
  margin-bottom: .5rem;
}
.pagenext__title {
  display: block;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.9rem, 4.2vw, 3.2rem);
  line-height: 1;
  letter-spacing: -.025em;
  text-transform: uppercase;
}
.pagenext__blurb {
  display: block;
  margin-top: .6rem;
  font-size: .94rem;
  color: var(--ash);
  max-width: 48ch;
}
.pagenext__arrow {
  position: relative;
  flex: none;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  line-height: 1;
  color: var(--amber);
  transition: transform .3s var(--ease);
}
.pagenext:hover .pagenext__arrow { transform: translateX(10px); }

@media (prefers-reduced-motion: reduce) {
  .pagenext:hover .pagenext__arrow { transform: none; }
}

@media (max-width: 620px) {
  .pagenext { gap: 1rem; }
}

/* ---------- 24. Partner wall ----------
   Dark tiles: sponsor marks are usually supplied light or single
   colour, and New Paradise Biryani's yellow (#F8DC20) measures well
   under 2:1 on white but clears 9:1 on the pitch ground. */
.partners {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: clamp(.85rem, 1.6vw, 1.25rem);
}
.partner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: .85rem;
  min-height: 190px;
  padding: 1.5rem 1.25rem;
  background: var(--pitch-2);
  border: 1px solid var(--pitch-line);
  border-radius: var(--r);
  text-decoration: none;
  color: var(--chalk);
  text-align: center;
  transition: border-color .25s var(--ease), background-color .25s var(--ease);
}
a.partner:hover { border-color: var(--amber); background: var(--pitch-3); }

.partner img {
  max-width: 82%;
  max-height: 96px;
  width: auto;
  object-fit: contain;
}
.partner__name {
  font-size: .84rem;
  font-weight: 600;
  line-height: 1.3;
}
.partner__tier {
  font-size: .58rem;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
  color: var(--amber);
}

.partner.is-empty,
.partner.is-open {
  border-style: dashed;
  color: var(--ash);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .11em;
  text-transform: uppercase;
}
.partner.is-open { color: var(--amber); border-color: rgba(245,130,31,.45); }
.partner.is-open:hover { background: var(--pitch-3); border-color: var(--amber); }

/* ---------- 25. Back to top ---------- */
.totop {
  position: fixed;
  right: clamp(14px, 2.4vw, 28px);
  /* clears the iOS browser chrome and any home indicator */
  bottom: calc(clamp(14px, 2.4vw, 28px) + env(safe-area-inset-bottom, 0px));
  z-index: 90;

  /* 48px square — comfortably over the 44px touch-target minimum */
  width: 48px; height: 48px;
  display: grid; place-items: center;
  padding: 0;
  border: 1px solid var(--pitch-line);
  border-radius: 50%;
  background: rgba(10,51,60,.92);
  backdrop-filter: blur(8px);
  color: var(--amber);
  font-size: 1.15rem;
  line-height: 1;
  cursor: pointer;

  opacity: 0;
  /* visibility, not opacity alone: opacity-0 would leave the button in
     the tab order while invisible. It is stepped rather than
     transitioned — instantly on show, delayed until the fade finishes
     on hide — so the button is never waiting on a transition to become
     visible. */
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .25s var(--ease), transform .25s var(--ease),
              background-color .2s, border-color .2s,
              visibility 0s linear .25s;
}
.totop.is-in {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .25s var(--ease), transform .25s var(--ease),
              background-color .2s, border-color .2s,
              visibility 0s linear 0s;
}
.totop:hover { background: var(--claret); border-color: var(--claret); color: var(--chalk); }
.totop:active { transform: translateY(1px); }

@media (prefers-reduced-motion: reduce) {
  .totop { transition: opacity .001ms, visibility .001ms; transform: none; }
  .totop.is-in { transform: none; }
}

@media print { .totop { display: none; } }

/* ---------- 26. Founding story ----------
   The emotional centre of the site, so it gets a wider measure and
   more air than ordinary body copy, and the club's own pivot lines
   are allowed to carry weight. */
/* The story runs as a single centred column rather than sitting in a
   split beside the club facts — longform needs one uninterrupted
   measure, and the facts were competing with it for the same vertical
   run. */
/* Centred, and wide enough that the margins either side are small.
   Left-aligning it had only moved the empty space to one end.

   The type scales up with the column instead of staying at reading
   size: a wider measure at the same size is what makes long prose
   hard to track, so the two move together and the line stays near
   90 characters. */
.story__head {
  max-width: min(100%, 1180px);
  margin: 0 auto clamp(2rem, 3.5vw, 3rem);
}
.story {
  max-width: min(100%, 1180px);
  margin-inline: auto;
}
.story p {
  font-size: clamp(1.05rem, .55vw + .78rem, 1.32rem);
  line-height: 1.72;
  margin: 0 0 1.4em;
}
.story__lead {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.35rem, 2.2vw, 1.9rem) !important;
  line-height: 1.15 !important;
  letter-spacing: -.02em;
  text-transform: uppercase;
  color: var(--chalk);
  margin: 2rem 0 1.5em !important;
}
.on-book .story__lead, .section:not(.on-pitch) .story__lead { color: var(--ink); }

.story__pull {
  margin: 2.5rem 0;
  padding: 0 0 0 1.5rem;
  border-left: 3px solid var(--amber);
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.6rem, 3.2vw, 2.6rem);
  line-height: 1.05;
  letter-spacing: -.025em;
  text-transform: uppercase;
  color: var(--amber);
  max-width: 20ch;
}

/* ---------- vision & mission ---------- */
.vm + .vm { margin-top: clamp(1.5rem, 3vw, 2.25rem); }
.vm__label {
  font-family: var(--mono);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--claret-ink);
  margin: 0 0 .5rem;
}
.vm__text {
  font-size: clamp(1.1rem, 1.5vw, 1.3rem);
  line-height: 1.55;
  color: var(--ink);
  margin: 0;
  max-width: 52ch;
}

/* ---------- club manager ---------- */
/* ---------- the Kannada mark ----------
   The badge is a navy disc, which on the dark theme sits close to the
   page behind it. The hairline ring keeps its edge readable there
   without drawing a box around it in light mode. */
.kmark {
  display: flex; align-items: center; flex-wrap: wrap;
  gap: clamp(1.25rem, 3vw, 2.75rem);
}
.kmark__badge {
  width: clamp(130px, 16vw, 190px); height: auto; flex: none;
  border-radius: 50%;
  box-shadow: 0 0 0 1px rgba(255,255,255,.10), var(--e2);
}
.kmark__name {
  font-family: var(--display);
  font-size: clamp(1.6rem, 3.6vw, 2.6rem);
  font-weight: 700; line-height: 1.25; color: var(--ink);
  margin: .35rem 0 0;
}

/* The manager block sits in the full-width grid, so the prose finished
   38px from the right edge — the page gutter and nothing else — while
   the portrait beside it had 133px of air on its left. Lopsided, and the
   line ran to 85 characters, which is what made it feel cramped.

   Two things fix it. The inset pads the text column back so both sides
   of the photo carry similar space, and it scales with the viewport so
   it does the work at laptop widths. The cap then holds the measure down
   on a large display, where the column would otherwise keep growing.
   Both collapse on a phone, where the two stack and the page gutter is
   the only spacing wanted.

   Vertically the portrait is the tallest thing in the row, so it set the
   band's height and got only the section's own padding above and below
   it — it read as filling the section edge to edge. The extra block
   padding here is on top of that, so the photo sits in open space rather
   than defining the band. */
.manager-split {
  --manager-inset: clamp(0px, 4.5vw, 88px);
  padding-block: clamp(0.5rem, 3.4vw, 3.75rem);
}
.manager-split > :last-child {
  padding-inline-end: var(--manager-inset);
  max-width: 76ch;
}
@media (max-width: 900px) {
  .manager-split > :last-child { padding-inline-end: 0; }
}

/* The portrait is 3:4, so on a wide screen it grows taller while the
   text beside it needs fewer lines — the column ends up floating in the
   middle of a tall photo. Capping the width caps the height, and past
   about 1400px the two stay within a tenth of each other. */
.manager__shot { margin: 0 auto; max-width: 34rem; width: 100%; }
.manager__shot img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--r);
  border: 1px solid var(--paper-line);
  box-shadow: var(--e2);
}

/* ---------- club socials ----------
   One grid for video and stills together. Everything sits in the same
   4:3 box: photographs fill it, video is fitted inside it. Mixing the
   two at their own ratios left portrait clips twice the height of
   their neighbours and holes in the rows. */
.media-grid {
  display: grid;
  gap: clamp(1.25rem, 2.4vw, 2.25rem);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
}
.media { margin: 0; }
.media__frame {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: var(--r);
  border: 1px solid var(--paper-line);
  background: var(--pitch-deep);
  box-shadow: var(--e1);
}
.media__frame > img,
.media__frame > video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  display: block;
}
/* A still can be cropped to the tile; a clip cannot, because the crop
   would hide whatever is being filmed. */
.media__frame > img   { object-fit: cover; }
.media__frame > video { object-fit: contain; background: var(--pitch-deep); }
.media figcaption {
  margin-top: .8rem;
  font-size: .9rem;
  line-height: 1.5;
  color: var(--ash-deep);
  max-width: 44ch;
}

/* The column beside the join form ran a long way down as empty paper —
   that form is tall and the copy next to it is three lines. */
.join-shot {
  margin: clamp(1.75rem, 3vw, 2.75rem) 0 0;
}
.join-shot img {
  width: 100%;
  height: auto;
  border-radius: var(--r);
  border: 1px solid var(--paper-line);
}
.join-shot figcaption {
  margin-top: .8rem;
  font-size: .84rem;
  line-height: 1.5;
  color: var(--ash-deep);
  max-width: 46ch;
}

.story__signoff {
  margin-top: 2.25rem !important;
  font-style: italic;
  color: var(--ash);
}
.on-book .story__signoff { color: var(--ash-deep); }

@media (max-width: 620px) {
  .story__pull { padding-left: 1rem; margin-block: 1.75rem; }
}


/* ---------- 27. Club facts ---------- */
.fact {
  display: flex;
  flex-direction: column;
  gap: .6rem;
  padding: 1.4rem 0 0;
  border-top: 2px solid var(--claret);
}
.fact__k {
  font-size: .64rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--claret-ink);
}
.fact__v {
  font-size: 1rem;
  line-height: 1.5;
  color: var(--ink);
}
.on-pitch .fact { border-top-color: var(--amber); }
.on-pitch .fact__k { color: var(--amber); }
.on-pitch .fact__v { color: var(--chalk); }
