/* Weightlifting Club Hoorn -- house style.
   The site reads dark text on muted, blue-grey light grounds; the header, the hero and
   the footer stay dark navy, so the club keeps its face. This scheme was picked on
   24 Aug 2026 from six prototyped variants (branch prototype/kleurvarianten holds them):
   the earlier dark-first scheme was hard to read on a phone in sunlight, a white one
   glared.
   The colours are taken from the club crest itself: navy #00295b, red #9b0000, gold.
   The gold (#b47a1b) is the one accent that stays the same on either ground: dark
   enough to meet 4.5:1 on the light page would stop reading as gold, so the labels
   wear the crest tint itself and lean on their weight and caps for legibility.
   Headings in Poppins, body text in Sora, both self-hosted so that no request goes to
   Google on every visit. */

/* ---- fonts --------------------------------------------------------------------- */
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/font/poppins-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/font/poppins-600-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/static/font/poppins-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Poppins';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/static/font/poppins-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Sora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/static/font/sora-variable-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Sora';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('/static/font/sora-variable-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---- variables ----------------------------------------------------------------- */
/* The grounds carry the scheme: a blue-grey page, lighter cards that lift off it, and
   dark text on both. --light is the text for whatever stays dark: the navy regions
   below and the filled buttons. */
:root {
  --navy: #00295b;
  --navy-hover: #0d3f80;
  --navy-deep: #001b3d;
  --red: #9b0000;
  --red-deep: #701316; /* the administrator's header (ADR 0025): the alert red taken
                          down to stand beside --navy-deep, dark enough for --light type */
  --red-hover: #c11d1d; /* hover and alert accent, dark enough to read on the grounds */
  --red-fill-hover: #c11d1d; /* the filled buttons' hover: the same on either ground,
                                where --red-hover flips inside the dark regions */
  --green: #2e7d52;       /* the confirm accents: calm, clearly not the red of a deviation */
  --green-deep: #1f6b40;  /* dark enough for small text on the surface colour */
  --gold: #b47a1b;   /* the crest gold, the same on either ground: a label colour that
                        leans on its weight and caps, not a running-text colour */
  --sky: #a3d5f0;    /* the coach's light blue in the header: light enough to carry the
                        same dark type as the gold, and well clear of the page ground,
                        which is a blue-grey of almost the same lightness as a mid blue */
  --bg: #b3bbc9;
  --surface: #e0e4ea;
  --border: #939eb1;
  --text: #131c2e;
  --text-muted: #333e57;
  --light: #f4f5f7;
  --slate: #6b7488; /* the off track of a switch: dark enough to clear the surface it
                       lies on at 3:1, which a phone's own pale grey track does not */
  --green-on-navy: #5cbf8e; /* the reserved dot on the selected day chip: the club
                               green disappears against the navy behind it */

  --font-heading: 'Poppins', ui-sans-serif, system-ui, sans-serif;
  --font-body: 'Sora', ui-sans-serif, system-ui, sans-serif;
  --width: 72rem;
  --radius: 0.5rem;
}

/* The dark regions: header, hero and footer keep the deep navy of the crest. Inside
   them the tokens flip to their on-dark values, so every rule below that reads a
   token keeps working on either ground. */
.site-header,
.hero,
.footer {
  --text: var(--light);
  --text-muted: #b3b9c4;
  --border: #23262f;
  --red-hover: #e74c4c;
  color: var(--text);
}

/* ---- base ---------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  /* The browser's own form controls (the radio buttons of the contact form) draw in
     the platform blue otherwise -- the one blue on the page that is not the club's. */
  accent-color: var(--navy);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.7;
  text-wrap: pretty;
}

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.15;
  text-wrap: balance;
  margin: 0 0 0.6em;
}

h1 { font-size: clamp(2rem, 1.4rem + 2.6vw, 3.1rem); }
h2 { font-size: clamp(1.5rem, 1.2rem + 1.4vw, 2.2rem); }
h3 { font-size: 1.25rem; font-weight: 600; }
h4 {
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 1.6em 0 0.5em;
}

p { margin: 0 0 1.1em; }

a { color: var(--text); text-decoration-color: var(--red-hover); text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:hover { color: var(--red-hover); }

img, picture, video { display: block; max-width: 100%; height: auto; }

:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }

.skip-link {
  position: absolute;
  left: -9999px;
  background: var(--navy-deep);
  color: var(--light);
  padding: 0.6rem 1rem;
  z-index: 10;
}
.skip-link:focus { left: 1rem; top: 1rem; }
/* Out of sight but not out of the page: a heading that names the screen for a screen
   reader where the screen itself needs no line of type to say what it is. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- site header --------------------------------------------------------------- */
.site-header {
  background: var(--navy-deep);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.site-header__inner {
  max-width: var(--width);
  margin: 0 auto;
  padding: 0.9rem 1.25rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.5rem;
}
.brand { display: flex; align-items: center; gap: 0.7rem; text-decoration: none; }
.brand__logo { width: 2.75rem; height: 2.75rem; }
.brand__name {
  font-family: var(--font-heading);
  font-weight: 700;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}
.nav { margin-left: auto; }
.nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav a {
  text-decoration: none;
  font-size: 0.95rem;
  color: var(--text-muted);
  padding: 0.25rem 0;
  border-bottom: 2px solid transparent;
}
.nav a:hover { color: var(--text); border-bottom-color: var(--red); }
.nav a[aria-current='page'] { color: var(--text); border-bottom-color: var(--gold); }

/* The language menu (ADR 0029): a pill with the current code that opens a short list
   underneath, right-aligned so it never runs off a phone. */
.lang-menu { position: relative; }
.lang-menu__button {
  list-style: none;
  cursor: pointer;
  font-size: 0.85rem;
  color: var(--text-muted);
  border: 1px solid var(--border);
  border-radius: 2rem;
  padding: 0.2rem 0.8rem;
}
.lang-menu__button::-webkit-details-marker { display: none; }
.lang-menu__button::after { content: " \25BE"; }
.lang-menu__button:hover, .lang-menu[open] .lang-menu__button { color: var(--text); border-color: var(--red); }
.lang-menu__list {
  position: absolute;
  right: 0;
  top: calc(100% + 0.4rem);
  z-index: 10;
  min-width: 10rem;
  margin: 0;
  padding: 0.4rem 0;
  list-style: none;
  background: var(--navy-deep);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.35);
}
.lang-menu__list a {
  display: block;
  padding: 0.5rem 1rem;
  text-decoration: none;
  color: var(--text-muted);
}
.lang-menu__list a:hover { color: var(--text); background: rgba(255, 255, 255, 0.06); }
.lang-menu__list a[aria-current='page'] { color: var(--text); font-weight: 600; }
/* When the website's header wraps, the menu takes the right end of its own row, so the
   list hanging off its right edge never runs off the screen. */
@media (max-width: 48rem) {
  .site-header:not(.site-header--app) .lang-menu { margin-left: auto; }
}
/* Behind the login the header carries the role, where the agenda used to open with a
   coloured band saying the same thing (besluit Michiel, 30 augustus 2026): red for an
   administrator, the crest gold for a head coach (ADR 0025), a light blue for a coach,
   the club navy for everybody else. The widest role wins ([headerRole]).

   The administrator's red is dark like the navy, so the header's on-dark tokens hold:
   light type at 10.7:1. Only the focus ring changes -- the site's gold ring lands on
   3.2:1 against this red, too close to the 3:1 line, so it goes light here.

   The gold and the blue are light, so on those every token the header flipped to its
   on-dark value flips back: the type, the gear and the pill's border are the deep
   navy. On the gold that is 4.7:1 for the type and the same for the gear and the
   border, over the 4.5:1 and 3:1 those need; on the light blue it is 11:1. The focus
   ring goes with them -- the site's gold ring is invisible on a gold band. */
.site-header--admin { background: var(--red-deep); }
.site-header--admin :focus-visible { outline-color: var(--light); }
.site-header--head-coach,
.site-header--coach {
  --text: var(--navy-deep);
  --text-muted: var(--navy-deep);
  --border: var(--navy-deep);
  color: var(--text);
  border-bottom-color: var(--navy-deep);
}
.site-header--head-coach { background: var(--gold); }
.site-header--coach { background: var(--sky); }
.site-header--head-coach :focus-visible,
.site-header--coach :focus-visible { outline-color: var(--navy-deep); }
.site-header--head-coach .settings-link:hover,
.site-header--coach .settings-link:hover { background: rgba(0, 27, 61, 0.12); }
/* Behind the login the header carries no menu (base.html): the public pages stand in
   the footer, and the logo itself leads to the agenda. What is left -- the embleem, the
   gear and the language -- stands on one line, on a phone as well. */
.site-header--app .site-header__inner { flex-wrap: nowrap; gap: 0.5rem; }
.site-header--app .brand { margin-right: auto; min-width: 0; gap: 0.5rem; }
.site-header--app .brand__logo, .site-header--app .lang-menu { flex: none; }
/* On a phone the club name gives way to the embleem alone (besluit Michiel, 29 augustus
   2026): the icon is the way home, the way an app on a beginscherm works, and an
   abbreviation would be a word the reader has to know first. It is moved out of sight
   rather than switched off, so a screen reader still names the link; the embleem itself
   is 2.75rem square, which is the thumb target this button needs. */
@media (max-width: 32rem) {
  .site-header--app .brand__name { position: absolute; left: -9999px; }
}

/* ---- sections ------------------------------------------------------------------ */
.section {
  max-width: var(--width);
  margin: 0 auto;
  padding: clamp(2.5rem, 6vw, 5rem) 1.25rem;
}
.section--narrow { max-width: 44rem; }
/* The page frame: the strip above every screen and the notice an action left behind,
   which base.html draws around that screen's own content. They stand outside the
   content's section, so they carry the gutter and the reading width themselves --
   the narrow one, because neither runs to more than a line or two. On the one screen
   that is wider than that (the deviations table) they sit a little inside the table
   below them; on the narrow ones they line up exactly. */
.page-frame { max-width: 44rem; margin: 0 auto; padding: 0 1.25rem; }

/* The strip above a screen that has somewhere to go back to (page-top.html): the way
   back and nothing else, so a screen without one draws no band at all. */
.page-top {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
/* The way back, as a button (besluit Michiel, 26 augustus 2026). Quiet -- a lifted card
   rather than a filled one -- so that it does not compete with the heading below it,
   and small enough to wrap instead of crowding the gear on the coach's narrow phone.
   Scoped to the strip because it has to beat the plain .button further down the file,
   which the cascade would otherwise let win on the properties they share. */
.page-top .button--back {
  padding: 0.5rem 0.9rem;
  font-size: 0.9rem;
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
}
.page-top .button--back:hover {
  color: var(--red-hover);
  background: var(--surface);
  border-color: var(--red);
}
/* The gear in the header of every screen behind the login (settings-link.html): one
   fixed entrance to what a member sets about themselves (besluit Michiel, 26 augustus
   2026). It is a round thumb target because it carries no word to aim at, and it reads
   its colours off the dark band it stands in. */
.settings-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  color: var(--text-muted);
}
.settings-link:hover { background: rgba(255, 255, 255, 0.08); color: var(--text); }
.settings-link__gear { width: 1.5rem; height: 1.5rem; }
/* A notice that opens the page carries the air of the section it does not stand in.
   The strip takes less of it: it is the first child now, and the whole point of moving
   the way back up here is that it is in reach without scrolling. What it does need is a
   little room underneath, because on the screens with a hero the coloured band starts
   right below it. Nothing of the frame closes a page anymore, so the foot of the page
   is the last section's own padding. */
.page-frame:first-child { padding-top: clamp(2.5rem, 6vw, 5rem); }
.page-frame.page-top { padding-top: 1.25rem; padding-bottom: 0.75rem; }
/* The alternating band: it lifts a step up from the page and fades back into it.
   Under the dark scheme this band went darker and was called section--dark; the
   direction flipped with the grounds, so the name followed. */
.section--raised {
  max-width: none;
  background: linear-gradient(180deg, var(--surface) 0%, var(--bg) 100%);
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.section--raised > * {
  max-width: var(--width);
  margin-left: auto;
  margin-right: auto;
}

.eyebrow {
  font-family: var(--font-heading);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.4em;
}

.split { display: grid; gap: clamp(1.5rem, 4vw, 3rem); align-items: center; }
@media (min-width: 48rem) {
  .split { grid-template-columns: 1.1fr 1fr; }
  .split--reversed .split__text { order: 2; }
  .split__media--portrait { max-width: 22rem; }
}
.split__media img { border-radius: var(--radius); border: 1px solid var(--border); }

.signpost { list-style: none; margin: 2rem 0 0; padding: 0; display: grid; gap: 0.5rem; }
.signpost a {
  display: inline-block;
  font-family: var(--font-heading);
  font-weight: 600;
  text-decoration: none;
  color: var(--light);
  background: var(--navy);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 1.1rem;
}
.signpost a:hover { background: var(--red); color: var(--light); }

/* ---- video --------------------------------------------------------------------- */
.video { margin: clamp(2rem, 5vw, 3.5rem) auto; max-width: 48rem; }
.video video { width: 100%; border-radius: var(--radius); border: 1px solid var(--border); background: #000; }
.video figcaption, .highlight figcaption {
  margin-top: 0.6rem;
  font-size: 0.9rem;
  color: var(--text-muted);
}

/* ---- track record -------------------------------------------------------------- */
.track-record {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
  margin-top: clamp(2rem, 5vw, 3rem);
}
@media (min-width: 60rem) {
  .track-record { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; }
  .list:last-child { grid-column: 1 / -1; }
}
.list {
  background: rgba(0, 41, 91, 0.06);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vw, 2rem);
}
.list h3 { border-bottom: 2px solid var(--red); padding-bottom: 0.4rem; }
.list h4:first-of-type { margin-top: 0.8em; }

.entries { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.7rem; }
.entries li { display: grid; gap: 0.1rem; }
.entry__text { font-weight: 600; line-height: 1.4; }
.entry__detail { color: var(--text-muted); font-size: 0.92rem; line-height: 1.5; }

@media (min-width: 60rem) {
  .list:last-child .entries { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.7rem 2rem; }
}

/* ---- highlights ---------------------------------------------------------------- */
.highlights { display: grid; gap: clamp(1.5rem, 4vw, 2.5rem); }
@media (min-width: 48rem) {
  .highlights { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.highlight { margin: 0; }
.highlight img { border-radius: var(--radius); border: 1px solid var(--border); }

/* ---- footer -------------------------------------------------------------------- */
.footer {
  background: var(--navy-deep);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.95rem;
}
.footer__inner {
  max-width: var(--width);
  margin: 0 auto;
  padding: clamp(2rem, 5vw, 3rem) 1.25rem;
  display: grid;
  gap: 2rem;
}
@media (min-width: 48rem) {
  .footer__inner { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
.footer h2 { font-size: 1rem; letter-spacing: 0.06em; text-transform: uppercase; }
.footer address { font-style: normal; color: var(--text-muted); }
.footer__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.4rem; }
.footer__list--row { display: flex; flex-wrap: wrap; gap: 0.4rem 1.5rem; justify-content: center; }
.footer__bottom {
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  padding: 1rem 1.25rem;
  color: var(--text-muted);
}
.footer a { color: var(--text-muted); text-decoration: none; }
.footer a:hover { color: var(--text); text-decoration: underline; }
/* The way into the members' section closes both lists of links, the main menu's and
   the footer's (besluit Michiel, 24 augustus 2026). It leads somewhere else than the
   five public pages before it -- behind a login, into somebody's own agenda -- so it
   is one shade brighter instead of a sixth item that reads like the rest. */
.nav a.nav__members,
.footer a.footer__members { color: var(--text); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

/* ---- buttons ------------------------------------------------------------------- */
.button {
  display: inline-block;
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: 0.95rem;
  text-decoration: none;
  color: var(--light);
  background: var(--red);
  border: 1px solid transparent;
  border-radius: var(--radius);
  padding: 0.7rem 1.4rem;
  cursor: pointer;
}
.button:hover { background: var(--red-fill-hover); color: var(--light); }
/* The secondary button: filled navy, so it reads as a button at a glance -- outlined
   on the blue-grey ground it sank away -- while staying clearly apart from the red
   that marks the primary and the destructive actions. */
.button--quiet { background: var(--navy); color: var(--light); }
.button--quiet:hover { background: var(--navy-hover); color: var(--light); }
/* The coach's own class today: green, because it is the one link on this screen that
   leads to somebody else's evening rather than to the reader's own -- and green is
   already what this site uses where the coach confirms rather than corrects. */
.button--today { background: var(--green-deep); color: var(--light); border-color: var(--green-deep); }
.button--today:hover { background: var(--green); color: var(--light); border-color: var(--green); }
.centered { text-align: center; margin-top: 2rem; }

/* ---- hero ---------------------------------------------------------------------- */
/* The band that opens the open website's pages, the login screen and the coach's own
   screen. The members' agenda had one too, gold for an administrator (besluit Michiel,
   24 augustus 2026); that decision was withdrawn (besluit Michiel, 30 augustus 2026),
   because on a phone it spent a screenful of height on what the colour of the header
   now says in none. The signal itself stayed: .site-header--admin, --head-coach and
   --coach. */
.hero {
  position: relative;
  isolation: isolate;
  background: var(--navy-deep);
  overflow: hidden;
}
.hero__background {
  position: absolute;
  inset: 0;
  z-index: -1;
}
.hero__background img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.4;
}
.hero--image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(180deg, rgba(11, 12, 15, 0.35) 0%, rgba(11, 12, 15, 0.85) 100%);
}
.hero__text {
  max-width: var(--width);
  margin: 0 auto;
  padding: clamp(3rem, 9vw, 7rem) 1.25rem;
}
.hero--image .hero__text { max-width: min(var(--width), 100%); }
.hero__text > * { max-width: 46rem; }
.hero__subheading {
  font-family: var(--font-heading);
  font-weight: 600;
  font-size: clamp(1.05rem, 0.9rem + 0.8vw, 1.4rem);
  color: var(--text);
}
.hero__text .button { margin-top: 0.6rem; }

/* ---- cards --------------------------------------------------------------------- */
/* Two to a row at most: with three side by side the five cards on /aanbod fell 3+2,
   which read as a full row with leftovers. The max-width fits exactly two cards plus
   the gap, and the centring keeps an odd last card in the middle instead of alone on
   the left -- four on the home page fall 2+2, five on /aanbod fall 2+2+1. */
.cards {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(1.25rem, 3vw, 2rem);
  margin: 2rem auto 0;
  max-width: 54rem;
}
/* Everything else in a section built around cards -- the heading above them, the
   button below them -- stands in the cards' own column; on the section's full
   72rem line a heading looks adrift from the rows it announces. */
.section:has(> .cards) > :not(.cards) {
  max-width: 54rem;
  margin-left: auto;
  margin-right: auto;
}
.card {
  flex: 1 1 20rem;
  max-width: 26rem;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.card picture img {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}
.card__text { padding: 1.25rem 1.25rem 1.5rem; }
.card__text h3 { margin-bottom: 0.4em; }
.card__text p { margin: 0; color: var(--text-muted); }

/* ---- people -------------------------------------------------------------------- */
.people { display: grid; gap: clamp(1.5rem, 4vw, 2.5rem); margin-top: 2rem; }
@media (min-width: 44rem) { .people { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.person {
  display: grid;
  gap: 1.25rem;
  align-items: start;
  grid-template-columns: minmax(0, 9rem) minmax(0, 1fr);
}
.person picture img {
  border-radius: var(--radius);
  border: 1px solid var(--border);
  aspect-ratio: 3 / 4;
  object-fit: cover;
  width: 100%;
}
.person__text h3 { margin-bottom: 0.1em; }
.person__role {
  font-family: var(--font-heading);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 0.6em;
}
.person__text p:last-child { margin: 0; color: var(--text-muted); }

/* ---- faq ----------------------------------------------------------------------- */
.faq { display: grid; gap: 0.75rem; margin-top: 1.5rem; }
.faq__item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.faq__item summary {
  cursor: pointer;
  padding: 1rem 1.25rem;
  font-family: var(--font-heading);
  font-weight: 600;
  line-height: 1.4;
}
.faq__item summary::marker { color: var(--red-hover); }
.faq__item[open] summary { border-bottom: 1px solid var(--border); }
.faq__item p { margin: 0; padding: 1rem 1.25rem; color: var(--text-muted); }

/* ---- rates --------------------------------------------------------------------- */
.note { color: var(--text-muted); max-width: 46rem; }
.rates { display: grid; gap: clamp(1.25rem, 3vw, 2rem); margin-top: 2rem; }
@media (min-width: 48rem) { .rates { grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; } }
.rate {
  background: rgba(0, 41, 91, 0.06);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: clamp(1.25rem, 3vw, 1.75rem);
}
.rate h3 { border-bottom: 2px solid var(--red); padding-bottom: 0.4rem; margin-bottom: 0.8rem; }
.rate__note { color: var(--text-muted); font-size: 0.92rem; }
.rate__entries { margin: 0; display: grid; gap: 0.6rem; }
.rate__entry {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  border-bottom: 1px dotted var(--border);
  padding-bottom: 0.5rem;
}
.rate__entry:last-child { border-bottom: 0; padding-bottom: 0; }
.rate__entry dt { color: var(--text); }
.rate__entry dd { margin: 0 0 0 auto; font-family: var(--font-heading); font-weight: 600; white-space: nowrap; }

/* ---- form ---------------------------------------------------------------------- */
.split--form { align-items: start; }
@media (min-width: 48rem) { .split--form { grid-template-columns: 1.2fr 1fr; } }
.form { display: grid; gap: 1rem; margin-top: 1.5rem; max-width: 32rem; }
.form__field { display: grid; gap: 0.35rem; margin: 0; }
.form__field label { font-size: 0.9rem; color: var(--text-muted); }
.form__required { color: var(--gold); }
/* A line under a field that says what it is for -- quieter than the label above it,
   because it is read once and then skipped over. */
.form__hint { color: var(--text-muted); font-size: 0.85rem; }
/* A line under a field that says what went wrong with it, next to the field itself,
   so nobody carries the error summary down the form in their head. */
.form__error { color: var(--red); font-size: 0.9rem; }
/* A group of radio buttons: the browser's own fieldset border would be the only box
   on the page with a look of its own, so it goes and the legend carries the group. */
.form fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: 0.35rem; }
.form legend { padding: 0; font-size: 0.9rem; color: var(--text-muted); }
.form__choice { display: flex; align-items: center; gap: 0.5rem; }
.form__choice input { width: auto; }
.form input, .form textarea {
  font: inherit;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.6rem 0.75rem;
  width: 100%;
}
.form input:focus, .form textarea:focus { border-color: var(--gold); }
.form__honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.notice {
  border-radius: var(--radius);
  padding: 0.9rem 1.1rem;
  border: 1px solid;
}
.notice ul { margin: 0.5rem 0 0; padding-left: 1.2rem; }
.notice--success { background: rgba(46, 125, 82, 0.1); border-color: var(--green); }
.notice--error { background: rgba(155, 0, 0, 0.07); border-color: var(--red-hover); }
.notice--warn { background: color-mix(in srgb, var(--gold) 20%, transparent); border-color: var(--gold); }

.contact-details h3 { margin-top: 1.5em; }
.contact-details address { font-style: normal; color: var(--text-muted); }

/* ---- schedule ------------------------------------------------------------------ */
.schedule {
  width: 100%;
  border-collapse: collapse;
  margin: 2rem 0;
  text-align: left;
}
.schedule th, .schedule td {
  border-bottom: 1px solid var(--border);
  padding: 0.85rem 0.5rem;
  vertical-align: top;
}
.schedule th {
  font-family: var(--font-heading);
  font-weight: 600;
  width: 10rem;
}
.schedule__classes { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.35rem; }
.schedule__classes li { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.schedule__time { font-variant-numeric: tabular-nums; min-width: 8rem; }
.schedule__level { color: var(--gold); }
.schedule__empty th, .schedule__none { color: var(--text-muted); font-weight: 400; }

/* ---- running text (privacy, terms) --------------------------------------------- */
.prose h2 { font-size: 1.3rem; margin-top: 2em; }
.prose section:first-of-type h2 { margin-top: 1.2em; }
.prose ul { color: var(--text-muted); padding-left: 1.2rem; display: grid; gap: 0.4rem; }
.updated { color: var(--text-muted); font-size: 0.9rem; }

/* ---- members' agenda ------------------------------------------------------------ */
.agenda__intro, .agenda__empty { color: var(--text-muted); }
/* The strips still on the card, above the agenda (besluit Michiel, 30 augustus 2026):
   a number to keep an eye on, so it carries the gold the labels have. */
.agenda__balance { color: var(--gold); font-weight: 600; margin-top: 0.6rem; }
/* The ways on at the foot of a setup step (besluit Michiel, 30 augustus 2026): going
   on and skipping side by side, each in a form of its own. */
.setup__actions { display: flex; flex-wrap: wrap; gap: 0.6rem 0.8rem; margin-top: 1.6rem; }
.setup__actions form { display: contents; }
/* The line under an agenda a level was left out of: quiet, because it is a reminder of
   the reader's own choice and not a warning. */
.agenda__filtered { color: var(--text-muted); font-size: 0.9rem; margin-top: 1.2rem; }
.agenda__week {
  font-size: 1.05rem;
  color: var(--red); /* the week headings carry the club red; gold is for the labels */
  margin: 2.2rem 0 0.9rem;
}
.session-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.2rem;
  margin-bottom: 0.9rem;
}
.session-card h3 { font-size: 1.05rem; margin-bottom: 0.15rem; }
.session-card--hero { border-color: var(--gold); }
.session-card--muted { opacity: 0.8; } /* the lowest fade that keeps the muted text above 4.5:1 on the card */
.session-card__when { color: var(--text-muted); font-size: 0.95rem; }
.session-card__note { color: var(--text-muted); font-size: 0.9rem; margin-top: 0.5rem; }
.session-card__slots {
  list-style: none;
  margin: 0.6rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem; /* the reserve buttons in these rows are thumb targets, so they need air between them */
}
.slot { display: flex; flex-wrap: wrap; gap: 0.25rem 1rem; }
.slot__times { font-variant-numeric: tabular-nums; min-width: 8rem; }
/* The status column of a slot reads bold, and the free count in club navy: clearly
   apart from the red of the alerts and the gold of the labels. The taken states
   below keep the bold but fall back in colour, so free places stand out most. */
.slot__status { color: var(--navy); font-weight: 600; }
.slot__status--full, .slot__status--cancelled { color: var(--text-muted); }
.slot__status--reserved { color: var(--text); }
.agenda__heading { font-size: 1.6rem; margin-bottom: 1.2rem; }
.agenda__notice {
  background: var(--surface);
  border: 1px solid var(--gold);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin: 1rem 0;
}
.session-card__hint { color: var(--gold); font-size: 0.9rem; margin-top: 0.5rem; }
.session-card__actions { margin-top: 0.6rem; }
/* The ways off one standing place stand in a row: two of them are links to a screen
   that confirms first, the third is a button that has nothing to confirm, and a form
   of its own would otherwise break the row in two. */
.session-card__actions--row { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
.session-card__actions--row form { display: contents; }
/* A card's ways on when they are buttons rather than links. They stand under each other
   and fill the card: the labels are long enough that a row of them would wrap into a
   ragged block, and a button the width of the card is what a thumb expects. The cap
   keeps them from stretching to a whole reading width on a laptop. */
.session-card__actions--buttons { display: grid; gap: 0.6rem; }
.session-card__actions--buttons form { display: contents; }
.session-card__actions--buttons .button { max-width: 20rem; text-align: center; }
.button--slot { padding: 0.55rem 0.9rem; font-size: 0.95rem; }
.slot__note { color: var(--gold); font-size: 0.9rem; }
.slot form { display: contents; }
.agenda__cancel-actions { display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }

/* One calendar week at a time (ADR 0028): the chevrons walk whole weeks. They are
   44px targets around a 20px glyph, and at the horizon's edge an empty span of the
   same width holds the heading centred. */
.week-nav { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 1.6rem; }
.week-nav__link {
  flex: none;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  color: var(--text);
  border-radius: var(--radius);
}
a.week-nav__link:hover { color: var(--red); }
.week-nav__heading { margin: 0; text-align: center; }
/* The day picker's strip: seven chips, each a thumb target of its own. The dot under
   the date says the club trains that day, and turns green on a day the member trains
   themselves (besluit Michiel, 1 september 2026). */
.day-strip {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.4rem;
}
.day-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  min-height: 3.5rem;
  padding: 0.45rem 0 0.4rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--text);
}
.day-chip--selected { background: var(--navy); border-color: var(--navy); color: var(--light); }
.day-chip--muted { opacity: 0.55; }
.day-chip__day { font-size: 0.7rem; color: var(--text-muted); }
.day-chip--selected .day-chip__day { color: #b3b9c4; }
.day-chip__date { font-family: var(--font-heading); font-weight: 600; font-size: 0.95rem; }
.day-chip__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--gold); }
.day-chip__dot--reserved { background: var(--green); }
.day-chip--selected .day-chip__dot--reserved { background: var(--green-on-navy); }
.day-chip__dot--none { background: transparent; }
/* The date heading over one day's cards, in both presentations: below the week
   heading, above the level. */
.agenda__day-heading { font-size: 0.95rem; margin: 1.4rem 0 0.6rem; }
.session-card__level { font-size: 1.05rem; margin-bottom: 0.15rem; }
/* The level inside a whole-week row, where the day heading already says when: the
   gold the labels carry, sized with the times beside it. */
.slot__level { color: var(--gold); font-weight: 600; min-width: 8rem; }

/* ---- coach check-off ------------------------------------------------------------- */
/* The ways off the agenda screen -- check-off, administration, history, standing
   places -- read as buttons, not as bare links between the running text. */
.agenda__links { display: flex; flex-wrap: wrap; gap: 0.6rem 0.8rem; margin: 1.2rem 0 0.6rem; }
/* The two ways through the pages of the member's history, in reading order: back
   towards today first, further into the past second. Only the ones that exist are
   rendered, so this must read right with one link as well as with two. */
.agenda__pages { display: flex; gap: 1.2rem; font-size: 0.95rem; }
.session-card--link { display: block; text-decoration: none; }
.session-card--link:hover { border-color: var(--gold); }
.session-card--link h3 { color: var(--text); }
/* ---- switches -------------------------------------------------------------------- */
/* The rows a member leaves on or switches off: the levels on their agenda and the mails
   they get. It is the phone's own toggle (besluit Michiel, 1 september 2026): the knob's
   side says the state, so no word and no second button say it again. The switch is the
   submit button itself, so pressing it posts the row's form and the screen comes back
   with the knob on the other side -- the site runs no script. Name left, switch right,
   the warning on its own line under them. */
.switch-list { list-style: none; margin: 0.6rem 0 0; padding: 0; display: grid; gap: 0.2rem; }
.switch-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.25rem 1rem;
  min-height: 2.75rem;
  /* Pressing a switch reloads the screen and the browser lands on the row's anchor.
     Landing it partway down instead of against the top edge keeps it near where the
     finger was, which is the closest a screen without script comes to not moving at
     all (besluit Michiel, 1 september 2026). */
  scroll-margin-top: 40vh;
}
.switch-row form { display: contents; }
.switch-row__label { font-weight: 600; }
.switch-row__warning { flex-basis: 100%; margin: 0 0 0.4rem; color: var(--gold); font-size: 0.9rem; }
/* 52 by 32, the proportions a phone's switch wears. */
.switch {
  position: relative;
  flex: none;
  width: 3.25rem;
  height: 2rem;
  padding: 0;
  border: 0;
  border-radius: 1rem;
  background: var(--slate);
  cursor: pointer;
  transition: background-color 0.2s ease;
  -webkit-tap-highlight-color: transparent;
}
/* A 32px track is smaller than a thumb, so the button reaches out to the 44px a finger
   needs without the track growing with it. */
.switch::before { content: ''; position: absolute; inset: -0.375rem -0.25rem; }
/* The knob travels the track's width less its own width and the two insets. */
.switch::after {
  content: '';
  position: absolute;
  top: 0.25rem;
  left: 0.25rem;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--light);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  transition: transform 0.2s ease;
}
.switch[aria-checked="true"] { background: var(--green-deep); }
.switch[aria-checked="true"]::after { transform: translateX(1.25rem); }
.switch:active::after { transform: scale(0.92); }
.switch[aria-checked="true"]:active::after { transform: translateX(1.25rem) scale(0.92); }
/* The radio in a choice-of-one row (ADR 0028): the same row as a switch, but a dot
   that says "this one" rather than a knob that says on or off. Like the switch it is
   the submit button itself, with the finger's 44px reached by the ::before hitbox. */
.radio {
  position: relative;
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  padding: 0;
  border: 2px solid var(--navy);
  border-radius: 50%;
  background: var(--surface);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.radio::before { content: ''; position: absolute; inset: -0.625rem; }
.radio[aria-checked="true"]::after {
  content: '';
  position: absolute;
  inset: 0.25rem;
  border-radius: 50%;
  background: var(--navy);
}
/* The confirm button is a quiet green gesture, deliberately unlike the red deviation
   button: optional, friendly, easily ignored (prototype variant A). */
.button--confirm {
  background: rgba(46, 125, 82, 0.12);
  border-color: var(--green);
  color: var(--green-deep);
}
.button--confirm:hover { background: rgba(46, 125, 82, 0.22); color: var(--green-deep); }
.roll { list-style: none; margin: 0 0 1rem; padding: 0; display: grid; gap: 0.5rem; }
.roll__entry {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 0.7rem 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.6rem 1rem;
  flex-wrap: wrap;
}
.roll__entry form { display: contents; }
.roll__who { display: grid; gap: 0.15rem; }
.roll__name { font-family: var(--font-heading); font-weight: 600; }
.roll__sub { color: var(--text-muted); font-size: 0.88rem; }
/* A roll entry that is a way in to somebody rather than a row to act on: the whole
   name block is the link, so a thumb has the height of the entry to hit. */
.roll__link { flex: 1; text-decoration: none; color: inherit; }
.roll__link:hover .roll__name, .roll__link:focus .roll__name { color: var(--gold); }
.roll__state { display: flex; align-items: center; gap: 0.8rem; flex-wrap: wrap; }
/* On a phone -- where the coach actually stands -- the state and its button go under
   the name instead of squeezing beside it. */
@media (max-width: 540px) {
  .roll__entry { flex-direction: column; align-items: stretch; }
  .roll__state { justify-content: space-between; }
}
.button--roll { padding: 0.55rem 0.9rem; font-size: 0.9rem; }
.badge { font-size: 0.85rem; }
.badge--present, .badge--free, .badge--departed { color: var(--text-muted); }
.badge--confirmed { color: var(--green-deep); }
.badge--noshow { color: var(--red-hover); }
.badge--late { color: var(--gold); }

/* ---- the administration's two comparison lists ------------------------------------ */
/* The deviations overview (P6) and the comparison with Moneybird (P14) are one shape:
   mostly a laptop screen, a table the administrator reads down, one row per member or
   per difference. On a phone the same table folds into cards -- the header row goes,
   every row becomes a bordered block and every cell a line of it -- so the markup stays
   one table and nothing is rendered twice (prototype variant B). The two screens share
   these rules rather than one copying the other, so they cannot drift apart. */
.deviations__week { display: flex; gap: 0.8rem; align-items: baseline; flex-wrap: wrap; }
.deviations__table, .moneybird__table { width: 100%; border-collapse: collapse; margin-bottom: 1.5rem; }
.deviations__table th, .moneybird__table th {
  text-align: left;
  font-size: 0.75rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--gold);
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--border);
}
.deviations__table td, .moneybird__table td {
  padding: 0.7rem 0.6rem;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.deviations__table td .roll__name, .deviations__table td .roll__sub,
.deviations__table td .badge,
.moneybird__table td .roll__name, .moneybird__table td .roll__sub,
.moneybird__table td .badge { display: block; }
.deviations__table .badge, .moneybird__table .badge { margin-top: 0.35rem; }
.deviations__table .badge:first-child,
.moneybird__table .badge:first-child { margin-top: 0; }
.badge--warning { color: var(--gold); }
/* A line already dealt with is still readable, just no longer the thing to look at. */
.roll--handled .roll__entry { opacity: 0.7; }
.roll--handled .badge { margin-right: 0.5rem; }
@media (max-width: 700px) {
  /* The table stops being a table: as a block it takes the width it is given
     instead of the width its widest cell wants, which is what keeps a long
     explanation from pushing the whole page sideways. */
  .deviations__table, .deviations__table tbody,
  .moneybird__table, .moneybird__table tbody { display: block; }
  .deviations__table thead, .moneybird__table thead { display: none; }
  .deviations__table tr, .moneybird__table tr {
    display: block;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    margin-bottom: 0.6rem;
    padding: 0.4rem 0;
  }
  .deviations__table td, .moneybird__table td {
    display: block;
    border-bottom: 0;
    padding: 0.35rem 0.9rem;
  }
}

/* The Moneybird screen's own two pieces: the fetch button above the list, and the points
   an inferred product was recognised on -- the block that turns a proposal into
   something an administrator can check (P14 §4.2b). */
.moneybird__fetch { margin-bottom: 1.2rem; }
.moneybird__points { margin: 0.2rem 0 0; padding-left: 1.1rem; }
