/* ==========================================================================
   Ladies First Charity Calendar — design system

   Pastel, feminine and contemporary, taking its restraint from the country
   house sites used as references: a lot of white space, one elegant serif for
   display, a quiet sans for everything else, and colour used sparingly so the
   photography and the charity logos carry the page.
   ========================================================================== */

:root {
  /* Ink — a plum-tinted charcoal rather than black, which reads softer
     against cream without losing contrast. */
  --ink: #2e2630;
  --ink-soft: #6b5f68;
  --ink-faint: #9c8f98;

  /* Grounds */
  --cream: #fdfaf7;
  --shell: #f7f1ee;
  --white: #ffffff;

  /* Pastels */
  --blush: #f7e8ea;
  --lilac: #eee7f3;
  --sage: #dfe8e0;
  --sky: #e4ecf2;
  /* Section tints, offered in the admin as the deeper and the neutral band.
     Both are themed: in the rose palette the deeper one is champagne taken
     right down so it reads as warmth rather than colour, and the neutral one
     carries the same plum as the type so it sits on the cream rather than
     against it. Each theme restates them in its own hue. */
  --gold: #f6efe1;
  --grey: #efedf0;

  /* Accents. Rose carries every primary action; champagne is the fine line
     and small-caps detail that makes the pastels feel considered. */
  --rose: #c4738a;
  --rose-deep: #a4576f;
  --rose-ink: #7d3f54;
  --champagne: #c2a37a;

  --line: #ece2e3;
  --line-strong: #ddcdd0;

  --shadow-sm: 0 1px 2px rgba(46, 38, 48, 0.04), 0 2px 8px rgba(46, 38, 48, 0.05);
  --shadow-md: 0 4px 12px rgba(46, 38, 48, 0.06), 0 12px 32px rgba(46, 38, 48, 0.08);
  --shadow-lg: 0 8px 24px rgba(46, 38, 48, 0.08), 0 32px 64px rgba(46, 38, 48, 0.1);

  --radius: 4px;
  --radius-lg: 8px;

  --display: "Playfair Display", "Iowan Old Style", Georgia, serif;
  --body: "Jost", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  --wrap: 1200px;
  --wrap-narrow: 760px;
  /* Tall enough for the stacked wordmark and its subtitle to sit with air
     around them. Every hero offsets itself by this, so it stays one number. */
  --header-h: 104px;

  /* The pale tint of "CHARITY CALENDAR" under the wordmark, and the same
     tint when the mobile menu is open over the dark panel. A token because it
     is the one place the accent appears as a literal, and it has to move with
     the theme. */
  --brand-sub-tint: #dcb3bf;
}

/* ================================================================ themes ===
   Set from the admin, written onto <html> as data-theme. Only the accent
   family and the pastels move: ink, cream, shell and white stay put, so the
   photography and the charity logos sit on the same grounds whichever theme
   is chosen, and only the colour that frames them changes.

   Every accent that carries white text (--rose, --rose-deep) is kept dark
   enough to clear 4.5:1 against it, which is what stops a pastel theme from
   turning the buttons into something nobody can read.
   ========================================================================== */

/* Gold — champagne and bronze. Warmer than the rose and a shade more formal,
   which suits the country-house photography. */
[data-theme="gold"] {
  /* The grounds shift with the accent. Left warm-pink they read as the rose
     layout showing through, which is exactly what a themed page must not do. */
  --cream: #fdfbf6;
  --shell: #f6f1e8;
  --gold: #f1e7d0;
  --grey: #efece6;

  --blush: #f7eeda;
  --lilac: #f2e9d6;
  --sky: #ece5d2;

  --rose: #8f7029;
  --rose-deep: #745a1f;
  --rose-ink: #5c4718;
  --champagne: #b08d4a;

  --line: #ebe0cb;
  --line-strong: #d9c69f;
  --brand-sub-tint: #e3cd9c;
}

/* Blue — powder blues against the same cream. Cooler and quieter; the one to
   reach for if the calendar art turns out warm and the page needs to step
   back from it. */
[data-theme="blue"] {
  --cream: #fafcfd;
  --shell: #eef3f7;
  --gold: #dfe9f1;
  --grey: #ebedf0;

  --blush: #e6eef5;
  --lilac: #e9f0f6;
  --sky: #dee9f2;

  --rose: #46759b;
  --rose-deep: #375d7d;
  --rose-ink: #2b4a63;
  --champagne: #6d94b3;

  --line: #dde7ef;
  --line-strong: #c2d4e2;
  --brand-sub-tint: #b8d0e2;
}

/* --------------------------------------------------------------- reset --- */

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

/* scroll-padding-top is what keeps an anchor clear of the sticky header. Land
   on /charities#mind or /the-women#bia-perry without it and the browser puts
   the card's top edge at the very top of the viewport — which is underneath the
   header, so the reader arrives at a name they cannot see and assumes the link
   is broken. Generous enough for the taller mobile header, plus a little air. */
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: 7.5rem; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.7;
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin: 0 0 0.5em;
  color: var(--ink);
}

h1 { font-size: clamp(2.4rem, 5.2vw, 4rem); }
h2 { font-size: clamp(1.9rem, 3.4vw, 2.75rem); }
h3 { font-size: clamp(1.25rem, 2vw, 1.6rem); }
h4 { font-size: 1.1rem; }

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

a { color: var(--rose-ink); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--rose-deep); }

/* A visible focus ring is the only way a keyboard user can tell where they
   are. It is styled to fit rather than removed. */
:focus-visible {
  outline: 2px solid var(--rose);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ink);
  color: var(--cream);
  padding: 0.75rem 1.25rem;
  z-index: 200;
}
.skip-link:focus { left: 0; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ------------------------------------------------------------ structure --- */

.wrap { width: min(100% - 2.5rem, var(--wrap)); margin-inline: auto; }
.wrap-narrow { width: min(100% - 2.5rem, var(--wrap-narrow)); margin-inline: auto; }

/* A comfortable reading measure that still starts on the page's left edge.
   Narrowing the container *and* centring it — which is what .wrap-narrow does
   — indents left-aligned prose by 220px against every section above and below
   it, and the ragged edge is what reads as wrong rather than the line length.
   Centred blocks still want .wrap-narrow; this is for prose that is set left. */
.wrap.measure > * { max-width: var(--wrap-narrow); }

/* A rich-text block set to centre. The measure is centred on the page rather
   than aligned left, which is the shape the section heads above the charity
   and sponsor walls already use. */
.prose-centred {
  max-width: var(--wrap-narrow);
  margin-inline: auto;
  text-align: center;
}

section { padding-block: clamp(3.5rem, 8vw, 7rem); }
section.tight { padding-block: clamp(2.5rem, 5vw, 4rem); }

.bg-shell { background: var(--shell); }
.bg-blush { background: var(--blush); }
.bg-white { background: var(--white); }
.bg-gold { background: var(--gold); }
.bg-grey { background: var(--grey); }
.bg-ink { background: var(--ink); color: var(--cream); }
.bg-ink h1, .bg-ink h2, .bg-ink h3 { color: var(--cream); }
.bg-ink a { color: var(--blush); }

.kicker {
  /* Scaled rather than fixed: at the larger size the longest kickers —
     "Warwickshire & the West Midlands", the full event name — no longer fit a
     phone on one line, so it eases back to where it was on narrow screens.
     Tracking comes off too; spacing that reads as fine detail at 12px reads
     as gappy at 14. */
  font-size: clamp(0.75rem, 1.2vw, 0.88rem);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 500;
  color: var(--champagne);
  margin: 0 0 1rem;
}
.bg-ink .kicker { color: var(--champagne); }

.lede {
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  line-height: 1.65;
  color: var(--ink-soft);
}

.section-head { max-width: 62ch; margin-bottom: clamp(2rem, 4vw, 3.5rem); }
.section-head.center { margin-inline: auto; text-align: center; }

/* A hairline rule with a diamond, used to separate movements on the page. */
.rule {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  color: var(--champagne);
  margin: 0 0 1.5rem;
}
.rule::before, .rule::after {
  content: "";
  height: 1px;
  background: var(--line-strong);
  flex: 1;
}
.rule.short::before { display: none; }
.rule.short::after { max-width: 72px; flex: 0 0 72px; }
.rule span { font-size: clamp(0.7rem, 1.05vw, 0.82rem); letter-spacing: 0.17em; text-transform: uppercase; }

/* In a centred heading the rule has to be centred too, and a line on one side
   only reads as a mistake next to a centred heading and lede. The short rule
   gets its leading line back and the whole thing is centred on the axis
   everything else in the block sits on. */
.section-head.center .rule,
.rule.center-rule { justify-content: center; }
.rule.center-rule::before {
  content: "";
  display: block;
  max-width: 72px;
  flex: 0 0 72px;
  height: 1px;
  background: var(--line-strong);
}

/* The PR agency's own mark, given room rather than set as a line of text. */
.pr-credit { display: flex; justify-content: center; }
/* A definite width, not auto. The tag is lazily loaded, and an image with no
   intrinsic size never intersects anything, so it never loads, so it never
   gains a size — it just sits at zero forever. */
.pr-credit img {
  width: min(260px, 60vw);
  height: auto;
  object-fit: contain;
}
.pr-credit a { display: block; transition: opacity 0.2s ease; }
.pr-credit a:hover { opacity: 0.75; }
.section-head.center .rule.short::before {
  display: block;
  max-width: 72px;
  flex: 0 0 72px;
}

/* --------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  font-family: var(--body);
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 1rem 2rem;
  border-radius: var(--radius);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease,
    transform 0.2s ease, box-shadow 0.2s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(0); }

.btn-primary { background: var(--rose); color: #fff; box-shadow: var(--shadow-sm); }
.btn-primary:hover { background: var(--rose-deep); color: #fff; box-shadow: var(--shadow-md); }

.btn-outline { border-color: var(--ink); color: var(--ink); background: transparent; }
.btn-outline:hover { background: var(--ink); color: var(--cream); }

.btn-light { border-color: rgba(255, 255, 255, 0.75); color: #fff; background: transparent; }
.btn-light:hover { background: #fff; color: var(--ink); }

/* Solid white with the rose lettering, for the middle of a run of buttons on
   the dark band — the alternation is what stops three actions reading as one
   undifferentiated row. */
/* The .bg-ink a rule tints every link on the dark band toward blush. On a
   white button that is white on white; on the rose button it is a muddier
   version of what the same button looks like everywhere else. Both are
   accidents of that rule rather than decisions, so both are pinned back. */
.bg-ink .btn-primary { color: #fff; }

.btn-white,
.bg-ink .btn-white { background: #fff; color: var(--rose-deep); border-color: #fff; box-shadow: var(--shadow-sm); }
.btn-white:hover,
.bg-ink .btn-white:hover { background: var(--blush); color: var(--rose-ink); border-color: var(--blush); box-shadow: var(--shadow-md); }

.btn-ghost { color: var(--ink); background: transparent; padding-inline: 0; }
.btn-ghost:hover { color: var(--rose-deep); }

.btn-sm { padding: 0.65rem 1.25rem; font-size: 0.75rem; }
.btn-block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: 0.85rem; }
.btn-row.center { justify-content: center; }

/* ---------------------------------------------------------------- header -- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: rgba(253, 250, 247, 0.92);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}

/* Over a hero the header starts transparent and inverts, the way the
   reference sites do, then solidifies once the page scrolls.

   :not(.open) on every one of these, because an open mobile menu is no longer
   "over the hero" — it is a cream panel, and the lockup and the Menu button
   have to be readable against it. Without it these rules outrank the .open
   ones below on specificity alone (three classes against two), so opening the
   menu left a white wordmark and a white Menu button on cream: the top of the
   header simply disappeared. */
.site-header.over-hero:not(.scrolled):not(.open) {
  background: transparent;
  border-bottom-color: rgba(255, 255, 255, 0.18);
}
.site-header.over-hero:not(.scrolled):not(.open) .nav-link,
.site-header.over-hero:not(.scrolled):not(.open) .nav-toggle { color: #fff; }

/* Over a photograph the lockup swaps to a solid white version rather than
   being filtered. "First" is drawn at 70%, and a filter cannot lift alpha —
   filtering it left that word grey against a white "Ladies". The white file
   is generated from the same artwork by `npm run brand`, so the two cannot
   drift apart. */
.brand-mark-white { display: none; }
.site-header.over-hero:not(.scrolled):not(.open) .brand-mark-colour { display: none; }
.site-header.over-hero:not(.scrolled):not(.open) .brand-mark-white { display: block; }
.site-header.over-hero:not(.scrolled):not(.open) .brand-sub { color: rgba(255, 255, 255, 0.92); }

/* Wordmark left, one run of links filling the rest and finishing on the right
   edge. It was a centred lockup with the links split either side; nine of them
   made that split lopsided and hard to read in order. */
.header-inner {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  gap: clamp(1.25rem, 3vw, 2.5rem);
  min-height: var(--header-h);
}

/* The wordmark with "CHARITY CALENDAR" set beneath it as live text rather
   than baked into the artwork: it stays sharp at any size, and it can be
   recoloured for the transparent-over-hero header without a second file. */
.brand {
  display: inline-flex;
  flex-direction: column;
  /* The lockup is left-aligned in the header, but the subtitle is centred
     under the wordmark — that is how the original artwork sets it, and the
     text-indent below compensates for the trailing letter-space. */
  align-items: center;
  gap: 0.34rem;
  text-decoration: none;
  line-height: 1;
}

.brand-mark { height: 52px; width: auto; }

/* Sized so the subtitle spans about 80% of the wordmark above it, which is the
   proportion the original lockup used. */
.brand-sub {
  font-family: "Lato", var(--body);
  font-weight: 300;
  font-size: 0.92rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  /* A pale tint of the accent in the wordmark. It tracked the old powder-blue
     artwork; when "First" went rose the blue was left stranded under it. Now a
     token, so it follows whichever theme is set. */
  color: var(--brand-sub-tint);
  white-space: nowrap;
  /* The tracking hangs a space off the last letter, which shifts the line
     left of the wordmark it sits under. */
  text-indent: 0.16em;
}

@media (max-width: 1040px) {
  .brand-mark { height: 42px; }
  .brand-sub { font-size: 0.75rem; }
}

/* The links close up as the viewport narrows so nine of them still fit on one
   line before the mobile menu takes over. */
.nav {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: nowrap;
  gap: clamp(0.7rem, 1.35vw, 1.5rem);
}

.nav-link {
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  padding: 0.35rem 0;
  border-bottom: 1px solid transparent;
  white-space: nowrap;
}
.nav-link:hover, .nav-link[aria-current="page"] {
  color: var(--rose-deep);
  border-bottom-color: currentColor;
}

.nav-toggle {
  display: none;
  background: none;
  border: 0;
  color: var(--ink);
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 0.5rem;
}

/* Hidden at every width by default; the mobile breakpoint below is the only
   thing that ever reveals it. Without this it renders under the desktop nav. */
.site-nav-mobile { display: none; }

@media (max-width: 1040px) {
  .header-inner { grid-template-columns: auto 1fr; }
  .nav { display: none; }
  .nav-toggle { display: block; justify-self: end; }

  .site-nav-mobile { padding: 1rem 0 2rem; border-top: 1px solid var(--line); }
  .site-header.open .site-nav-mobile { display: block; }
  .site-header.open { background: var(--cream); }
  .site-header.open .nav-link { color: var(--ink); }
  .site-header.open .brand-mark-colour { display: block; }
  .site-header.open .brand-mark-white { display: none; }
  .site-header.open .brand-sub { color: var(--brand-sub-tint); }
  .site-nav-mobile a {
    display: block;
    padding: 0.7rem 0;
    border-bottom: 1px solid var(--line);
    font-size: 0.85rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--ink);
  }
  .site-nav-mobile .btn { margin-top: 1.25rem; }
}

/* ------------------------------------------------------------------ hero -- */

.hero {
  position: relative;
  min-height: min(92vh, 860px);
  display: flex;
  align-items: center;
  justify-content: center;
  /* The header sits on top of the hero, so the content is pulled up under it. */
  margin-top: calc(-1 * var(--header-h));
  padding: calc(var(--header-h) + 3rem) 0 4rem;
  isolation: isolate;
  overflow: hidden;
}

.hero-media {
  position: absolute;
  inset: 0;
  z-index: -2;
}
.hero-media img,
.hero-media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Driven by the media record's focal point so a portrait subject stays in
     frame when the hero letterboxes on a phone. */
  object-position: var(--focal, 50% 50%);
}

/* The film is decoration, laid over a still of its own first frame. If
   playback never starts — reduced motion, low-power mode, data saver — the
   still is already there underneath and the hero looks finished. */
.hero-still { position: absolute; inset: 0; }
.hero-video { position: absolute; inset: 0; }

@media (prefers-reduced-motion: reduce) {
  .hero-video { display: none; }
}

/* Two layers: a wash that lifts the whole image, and a foot gradient so the
   text has contrast wherever the photograph happens to be light. */
.hero-media::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, rgba(46, 38, 48, 0.42) 0%, rgba(46, 38, 48, 0.18) 38%, rgba(46, 38, 48, 0.62) 100%),
    linear-gradient(to right, rgba(124, 63, 84, 0.16), rgba(46, 38, 48, 0.05));
}

/* The hero box: a translucent card floating over the photograph, in the
   manner of the Mallory Court hero. */
.hero-box {
  position: relative;
  z-index: 1;
  width: min(100% - 2.5rem, 720px);
  text-align: center;
  /* Translucent, so the film reads through the panel. The heavy blur is what
     buys that: it flattens the moving detail behind the text into soft colour,
     which keeps the heading legible at an opacity that would otherwise be
     unreadable over a bright sunset. */
  background: rgba(253, 250, 247, 0.78);
  backdrop-filter: blur(22px) saturate(1.15);
  -webkit-backdrop-filter: blur(22px) saturate(1.15);
  border: 1px solid rgba(194, 163, 122, 0.5);
  box-shadow: var(--shadow-lg);
  padding: clamp(2.25rem, 5vw, 3.75rem);
}
/* A fine inner keyline — the detail that reads as "considered" rather than
   "a box with a border". */
.hero-box::before {
  content: "";
  position: absolute;
  inset: 10px;
  border: 1px solid rgba(194, 163, 122, 0.35);
  pointer-events: none;
}

/* Safari on iOS and any browser without backdrop-filter gets no blur, so the
   panel would sit as flat 78% over moving video. Those browsers fall back to
   something close to opaque instead. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .hero-box { background: rgba(253, 250, 247, 0.94); }
}

.hero-box h1 { margin-bottom: 0.35em; }
.hero-box .kicker { margin-bottom: 0.9rem; }
.hero-box .lede { color: var(--ink-soft); margin-bottom: 1.9rem; }
.hero-box .btn-row { justify-content: center; }

/* The phone copy of the hero actions, hidden by default and switched on in the
   block below. It has to be declared BEFORE that media query: both selectors
   are a single class, so on equal specificity the later rule in the file wins —
   declared after, it silently overrode the media query and left the phone with
   no buttons at all. */
.hero-actions-mobile { display: none; }

/* PHONE ONLY, and only the home hero — the page heroes on the other pages are
   left exactly as they are.

   At 390px the panel is the full column width and was covering the film almost
   entirely, which is the one thing the hero exists to show. So the type comes
   down, the padding tightens, and the panel drops to barely more than a tint.

   At that transparency the champagne gold stops working: it was chosen against
   a near-solid cream panel, and over moving footage it greys out. The kickers,
   the year and both keylines go white instead — set as literal white rather
   than a token, so it holds on the pink, gold and blue themes alike, none of
   which can be assumed to be dark or light behind the panel. */
@media (max-width: 640px) {
  .hero-box {
    background: rgba(253, 250, 247, 0.32);
    border-color: rgba(255, 255, 255, 0.8);
    /* Narrower than the column as well as shorter. The panel no longer runs to
       the edges, so the film is visible down both sides of it rather than only
       above and below. */
    width: min(100% - 3.5rem, 400px);
    padding: 1.25rem 1.1rem;
  }
  .hero-box::before { border-color: rgba(255, 255, 255, 0.5); }

  .hero-box h1 { font-size: clamp(1.7rem, 7.4vw, 2.15rem); }
  /* Very light grey rather than white: it sits a step below the kickers and the
     heading so the panel still has a hierarchy, and it carries a shadow because
     at 20% there is film, not panel, behind these letters. */
  .hero-box .lede {
    margin-bottom: 1.35rem;
    font-size: 0.95rem;
    color: #e9e6e8;
    text-shadow: 0 1px 12px rgba(46, 38, 48, 0.55);
  }
  /* "Warwickshire & the West Midlands" is dropped on phones: it wrapped to two
     lines and cost more height than it earned, and the box is trying to get out
     of the film's way. Hidden rather than deleted — the text is still on the
     Home page record and still shows on desktop, so removing it everywhere
     stays a one-field decision in the admin rather than something the
     stylesheet has quietly made. */
  .hero-box .kicker { display: none; }
  .hero-box .hero-year { color: #fff; }

  /* The buttons leave the panel on a phone and reappear on the white below the
     film, where they are read as actions rather than as part of the picture —
     and where the donate outline works in ink again, as it does everywhere
     else. The panel keeps only the words. */
  .hero-box .btn-row,
  .hero-box .hero-tertiary { display: none; }

  .hero-actions-mobile { display: block; padding: 1.75rem 0 0.5rem; }
  .hero-actions-mobile .btn-row { flex-direction: column; align-items: stretch; gap: 0.7rem; }
  .hero-actions-mobile .btn { width: 100%; }
  .hero-actions-mobile .hero-tertiary { margin: 0.7rem 0 0; }

  /* The box sits at the foot of the film rather than centred in it, so the top
     of the frame — where the picture actually is — is left alone. */
  .hero { align-items: flex-end; padding-bottom: 3.25rem; }

  /* vh on a phone is the viewport WITHOUT the browser's address bar, so 92vh is
     taller than what you can actually see and the foot of the hero — the box —
     ends up underneath the chrome. dvh is the visible height, and it shrinks
     and grows as the bar hides on scroll. Left as an @supports so anything too
     old to know the unit keeps the vh rule above rather than losing its
     min-height altogether. */
  @supports (min-height: 100dvh) {
    .hero { min-height: min(88dvh, 860px); }
  }

  /* No blur means no way to keep text off the moving detail, so those browsers
     keep a solid enough panel to read — and with it, the gold. */
  @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .hero-box { background: rgba(253, 250, 247, 0.88); border-color: rgba(194, 163, 122, 0.5); }
    .hero-box::before { border-color: rgba(194, 163, 122, 0.35); }
    .hero-box .kicker, .hero-box .hero-year { color: var(--champagne); }
    .hero-box .lede { color: var(--ink-soft); text-shadow: none; }
  }
}

.hero-year {
  font-family: var(--display);
  font-style: italic;
  color: var(--champagne);
  font-size: 1.35rem;
  display: block;
  margin-bottom: 0.4rem;
}

/* Smaller hero for interior pages: image band with the title over it. */
.page-hero {
  position: relative;
  /* Tall enough that a portrait subject clears the sticky header. At 46vh the
     crop put the sitter's eyes directly behind it. */
  min-height: 58vh;
  display: flex;
  align-items: flex-end;
  margin-top: calc(-1 * var(--header-h));
  padding: calc(var(--header-h) + 4rem) 0 3.5rem;
  isolation: isolate;
  overflow: hidden;
  color: #fff;
}

/* Weighted to the foot rather than even. An even wash darkens the subject's
   face as much as the empty ground the heading sits on; this keeps the top of
   the frame bright enough to see who is in it, and puts the contrast where
   the text actually needs it. */
.page-hero .hero-media::after {
  background: linear-gradient(
    to bottom,
    rgba(46, 38, 48, 0.28) 0%,
    rgba(46, 38, 48, 0.24) 35%,
    rgba(46, 38, 48, 0.62) 72%,
    rgba(46, 38, 48, 0.82) 100%
  );
}

/* The heading crosses the middle of the picture. A soft shadow keeps it
   readable over a light face without another layer of darkening. */
.page-hero h1,
.page-hero .lede,
.page-hero .kicker { text-shadow: 0 1px 24px rgba(46, 38, 48, 0.55); }
.page-hero h1 { color: #fff; max-width: 20ch; }
.page-hero .lede { color: rgba(255, 255, 255, 0.88); max-width: 56ch; }
.page-hero .kicker { color: rgba(255, 255, 255, 0.82); }

/* Fallback when no hero image has been set yet. */
.page-hero.no-image {
  background: linear-gradient(135deg, var(--blush), var(--lilac) 55%, var(--sky));
  color: var(--ink);
  min-height: 34vh;
}
.page-hero.no-image h1 { color: var(--ink); }
.page-hero.no-image .lede { color: var(--ink-soft); }
.page-hero.no-image .kicker { color: var(--champagne); }

/* --------------------------------------------------------------- progress - */

.progress-band { border-block: 1px solid var(--line); background: var(--white); }

.progress-grid {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  align-items: center;
}
@media (max-width: 820px) {
  .progress-grid { grid-template-columns: 1fr; }
}

.meter-figures {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.6rem;
}
.meter-raised { font-family: var(--display); font-size: clamp(1.8rem, 3.6vw, 2.6rem); line-height: 1; }
.meter-target { font-size: 0.85rem; color: var(--ink-soft); letter-spacing: 0.06em; }

.meter {
  height: 10px;
  background: var(--shell);
  border-radius: 999px;
  overflow: hidden;
  border: 1px solid var(--line);
}
.meter-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--rose), var(--champagne));
  /* Always visible even at £0 raised, so the bar reads as a bar. */
  min-width: 6px;
}

.stat { text-align: center; }
/* The charities stat is a link. It should not look like body copy that
   happens to be underlined — it reads as the figure it is, and only shows its
   hand on hover. */
a.stat { display: block; text-decoration: none; color: inherit; transition: opacity 0.2s ease; }
a.stat:hover { opacity: 0.78; }
a.stat:hover .stat-label { color: var(--rose-deep); }
.stat-num {
  font-family: var(--display);
  font-size: clamp(2rem, 4vw, 3rem);
  line-height: 1;
  color: var(--rose-deep);
  display: block;
}
.stat-label {
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-top: 0.5rem;
  display: block;
}

/* ----------------------------------------------------------------- cards -- */

.grid { display: grid; gap: clamp(1.25rem, 2.5vw, 2rem); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }

/* Fixed-width tracks rather than 1fr, so a row holding three cards centres
   under its heading instead of stretching them across the full width or
   leaving a gap on the right. Months have between one and four women in them,
   and every one of those rows has to look deliberate. */
/* Sized so the widest month — five women — sits on one line. auto-fit counts
   how many tracks fit using the *maximum* of the minmax, so a 250px cap only
   ever allowed four across the 1200px column: 5 x 214 plus four 32px gaps is
   1198, which is the widest a card can be and still make five. Every month
   uses the same card width, so the months read as one grid rather than each
   sizing itself. */
.grid-cards-centred {
  grid-template-columns: repeat(auto-fit, minmax(170px, 214px));
  justify-content: center;
}

.card {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.25s ease, transform 0.25s ease, border-color 0.25s ease;
}
.card:hover { box-shadow: var(--shadow-md); transform: translateY(-3px); border-color: var(--line-strong); }

.card-media { aspect-ratio: 4 / 5; background: var(--shell); overflow: hidden; }
.card-media img { width: 100%; height: 100%; object-fit: cover; object-position: var(--focal, 50% 50%); }
.card-media.wide { aspect-ratio: 16 / 10; }

.card-body { padding: 1.4rem 1.5rem 1.6rem; flex: 1; display: flex; flex-direction: column; }
.card-body h3 { margin-bottom: 0.3rem; }
.card-meta {
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
  margin-bottom: 0.6rem;
}
.card-foot { margin-top: auto; padding-top: 1rem; }

/* ------------------------------------------------------------ month blocks */

/* A <section> for the outline, but it sits inside one already — without this
   it takes the site-wide section padding and puts 112px above and below every
   month on top of the margin. */
.month-block { padding-block: 0; margin-bottom: clamp(2.25rem, 4.5vw, 3.5rem); }
.month-block:last-child { margin-bottom: 0; }

.month-head { text-align: center; margin-bottom: clamp(1.25rem, 2.5vw, 1.75rem); }

/* The rule treatment used elsewhere on the site — champagne, tracked caps,
   hairlines running out to either side — scaled up so the month leads its
   own block. It is an h2 for the outline, so the body face and weight have to
   be set back explicitly against the heading defaults. */
.month-rule {
  margin: 0;
  font-family: var(--body);
  font-weight: 400;
  color: var(--champagne);
}

.month-rule span {
  font-size: clamp(1.15rem, 2.4vw, 1.9rem);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  line-height: 1.2;
  /* The tracking adds a trailing space that pushes the word off centre
     between its two lines. */
  text-indent: 0.2em;
}

/* No max-width: the measure was forcing even short themes onto two lines, and
   the longest of them clears the column comfortably on one. It still wraps on
   a narrow screen, where a single line is not possible. */
.month-theme {
  margin: 0.7rem auto 0;
  max-width: none;
  font-size: clamp(0.9rem, 1.25vw, 1.05rem);
  line-height: 1.5;
  color: var(--ink);
  /* Set in caps to sit with the month above it. Done here rather than in the
     stored text so the admin keeps sentence case, which is what an editor
     wants to read and correct. Capitals need the tracking: without it the
     longer themes set as a solid block. */
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

/* Month ribbon on a calendar-girl card. */
.month-tag {
  position: absolute;
  top: 1rem;
  left: 1rem;
  background: rgba(253, 250, 247, 0.94);
  color: var(--rose-ink);
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.35rem 0.7rem;
  border-radius: 2px;
}
.card-media-wrap { position: relative; }

/* ------------------------------------------------------------ logo walls -- */

/* Charity logos are the emotional core of the home page, so they get room to
   breathe and a white tile each — logos on a tinted ground look cheap and
   many charity marks assume white behind them. */
/* The hairlines are drawn by each tile rather than by a 1px gap over a tinted
   container — with 31 charities the last row is never full, and a container
   background shows through the empty cells as a grey slab. */
/* Flex rather than grid, so the last row centres. Thirty-one charities never
   divide evenly into a row, and a grid leaves the remainder hard against the
   left edge with a gap where the rest of the page is symmetrical. Fixed-width
   tiles keep every tile the same size — letting the short row stretch would
   make its three boxes visibly larger than all the others. */
.logo-wall {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0;
}

.logo-tile {
  flex: 0 0 auto;
  width: clamp(150px, 15vw, 185px);
}

.logo-tile {
  background: var(--white);
  box-shadow: 0 0 0 1px var(--line);
  aspect-ratio: 3 / 2;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1.25rem;
  text-align: center;
  text-decoration: none;
  color: var(--ink-soft);
  transition: background-color 0.2s ease;
}
/* Lifted above its neighbours so the hover tint is not clipped by their rings. */
.logo-tile:hover { background: var(--shell); color: var(--rose-deep); position: relative; z-index: 1; }
/* A tile with a mark stacks the picture over its caption; one without keeps
   the name centred as before.

   Grid rather than a column flex so the caption sits in its own row at the
   foot of the tile: the picture takes whatever is left and centres in it, and
   every caption on a row starts at the same height whatever shape its logo
   is. The row is two lines deep so a name that wraps does not shunt the
   single-line ones out of line with it. */
.logo-tile.has-logo {
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: 0.55rem;
  padding: 1.1rem 0.9rem 0.9rem;
  align-items: center;
  justify-items: center;
}
.logo-caption {
  font-size: 0.62rem;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
  line-height: 1.3;
  max-width: 100%;
  min-height: 2.6em;
  align-self: start;
}
.logo-tile:hover .logo-caption { color: var(--ink-soft); }

.logo-tile img {
  max-height: 100%;
  max-width: 100%;
  width: auto;
  object-fit: contain;
  /* Charity marks arrive in a dozen different colours. A slight desaturation
     at rest settles the wall; full colour on hover keeps each brand intact. */
  filter: saturate(0.85);
  transition: filter 0.2s ease;
}
.logo-tile:hover img { filter: saturate(1); }

/* Until a logo has been uploaded the charity's name stands in, so the wall is
   never a grid of empty boxes. */
.logo-tile .logo-name {
  font-size: 0.82rem;
  line-height: 1.35;
  letter-spacing: 0.02em;
  font-weight: 500;
}

/* Taller than it was, because the caption now takes a row of its own and the
   marks were being squeezed into what was left. */
.logo-wall.sponsors .logo-tile { aspect-ratio: 5 / 3; }
.logo-wall.sponsors .logo-tile.has-logo { aspect-ratio: 6 / 5; }

.sponsor-headline {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 1.5rem;
  margin-bottom: 2.5rem;
}
.sponsor-headline .logo-tile {
  aspect-ratio: 16 / 9;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 2rem;
}

/* --------------------------------------------------------------- feature -- */

/* Alternating image-and-text band. `data-flip` swaps the columns without a
   second set of rules. */
.feature {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: center;
}
/* Both columns from the top. The centred default suits a picture beside a
   paragraph; it does not suit a short column beside a long one, where centring
   leaves the short one adrift halfway down. */
.feature-top { align-items: start; }

/* The contact page: a form and the details that belong with it, per row. Rows
   rather than two long columns, so "Press enquiries" and the press office stay
   level however long either grows. Collapses to one column on a phone, where
   each form is simply followed by its own details. */
.contact-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(2rem, 5vw, 4.5rem);
  align-items: start;
}
/* Exactly two, not auto-fit: with four cells auto-fit found room for a third
   track and put the press office on a row of its own, which is precisely the
   alignment this layout exists to hold. */
@media (min-width: 780px) {
  .contact-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
.contact-grid > .prose > h3:first-child { margin-top: 0; }

.feature[data-flip="true"] .feature-media { order: 2; }
@media (max-width: 760px) {
  .feature[data-flip="true"] .feature-media { order: 0; }
}

.feature-media {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}
.feature-media img {
  width: 100%;
  /* Aspect and focal point are both set per block from the admin. */
  aspect-ratio: var(--ratio, 4 / 3);
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
}

/* An image the admin has sized down sits centred rather than stretching. */
.feature-media[data-width="narrow"] { max-width: 380px; margin-inline: auto; }
.feature-media[data-width="medium"] { max-width: 560px; margin-inline: auto; }

/* An image-and-text band whose image has not been chosen yet would otherwise
   leave the text stranded in the left half of an empty row. */
.feature:has(> .prose:only-child) { justify-items: center; text-align: center; }
.feature:has(> .prose:only-child) .prose { margin-inline: auto; }
.feature:has(> .prose:only-child) .prose ul { text-align: left; display: inline-block; }

.prose { max-width: 68ch; }
.prose h2 { margin-top: 0; }
.prose h3 { margin-top: 2rem; }
.prose ul { padding-left: 1.15rem; margin: 0 0 1.2em; }
.prose li { margin-bottom: 0.45em; }
.prose blockquote {
  margin: 2rem 0;
  padding: 0.4rem 0 0.4rem 1.5rem;
  border-left: 2px solid var(--champagne);
  font-family: var(--display);
  font-size: 1.25rem;
  font-style: italic;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------ pull quote -- */

.quote-panel { text-align: center; max-width: 46ch; margin-inline: auto; }
.quote-panel blockquote {
  font-family: var(--display);
  font-size: clamp(1.4rem, 2.8vw, 2rem);
  line-height: 1.4;
  font-style: italic;
  margin: 0 0 1.5rem;
  border: 0;
  padding: 0;
}
.quote-panel cite {
  font-style: normal;
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--champagne);
}

/* ------------------------------------------------------------------ shop -- */

.buy-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 900px) { .buy-layout { grid-template-columns: 1fr; } }

.price {
  font-family: var(--display);
  font-size: clamp(2rem, 4vw, 2.8rem);
  line-height: 1;
  color: var(--rose-deep);
}
.price small { font-family: var(--body); font-size: 0.85rem; color: var(--ink-soft); letter-spacing: 0.1em; }

.option {
  display: block;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 1.15rem 1.35rem;
  margin-bottom: 0.85rem;
  cursor: pointer;
  background: var(--white);
  transition: border-color 0.2s ease, background-color 0.2s ease, box-shadow 0.2s ease;
}
.option:hover { border-color: var(--line-strong); }
.option:has(input:checked) {
  border-color: var(--rose);
  background: var(--blush);
  box-shadow: 0 0 0 1px var(--rose);
}
.option input { margin-right: 0.6rem; accent-color: var(--rose); }
.option-head { display: flex; justify-content: space-between; gap: 1rem; align-items: baseline; font-weight: 500; }
/* Block, not inline: an option can carry two notes and they must stack rather
   than run together mid-sentence. */
.option-note { display: block; font-size: 0.85rem; color: var(--ink-soft); margin: 0.35rem 0 0 1.4rem; }

.summary {
  background: var(--shell);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 3vw, 2rem);
  position: sticky;
  top: calc(var(--header-h) + 1.5rem);
}
.summary-row { display: flex; justify-content: space-between; gap: 1rem; padding: 0.5rem 0; font-size: 0.95rem; }
.summary-row.total {
  border-top: 1px solid var(--line-strong);
  margin-top: 0.5rem;
  padding-top: 0.9rem;
  font-family: var(--display);
  font-size: 1.35rem;
}

/* ----------------------------------------------------------------- forms -- */

.field { margin-bottom: 1.2rem; }
.field label,
.form-label {
  display: block;
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0.45rem;
  font-weight: 500;
}
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; }
@media (max-width: 560px) { .field-row { grid-template-columns: 1fr; } }

input[type="text"], input[type="email"], input[type="password"], input[type="tel"],
input[type="number"], input[type="url"], input[type="search"], input[type="date"],
select, textarea {
  width: 100%;
  font-family: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--white);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 0.8rem 0.95rem;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--rose);
  box-shadow: 0 0 0 3px rgba(196, 115, 138, 0.15);
}
textarea { min-height: 150px; resize: vertical; }

.check { display: flex; gap: 0.65rem; align-items: flex-start; margin-bottom: 0.85rem; }
.check input { margin-top: 0.35rem; accent-color: var(--rose); flex: none; }
.check label { text-transform: none; letter-spacing: 0; font-size: 0.95rem; color: var(--ink); margin: 0; }
.check .hint { display: block; font-size: 0.85rem; color: var(--ink-soft); margin-top: 0.15rem; }

.hint { font-size: 0.85rem; color: var(--ink-soft); }

.notice {
  padding: 0.9rem 1.15rem;
  border-radius: var(--radius);
  border: 1px solid;
  margin-bottom: 1.5rem;
  font-size: 0.95rem;
}
.notice-error { background: #fdf0f2; border-color: #e8bec7; color: #8c2f45; }
.notice-ok { background: #eef6f0; border-color: #bcd9c6; color: #2c6141; }
.notice-info { background: var(--lilac); border-color: #d9cbe6; color: #4d3b5e; }

/* ------------------------------------------------------------- newsletter - */

.newsletter-form { display: flex; gap: 0.75rem; flex-wrap: wrap; }
.newsletter-form input[type="email"] { flex: 1 1 260px; }

/* -------------------------------------------------------------- account --- */

.account-layout { display: grid; grid-template-columns: 240px minmax(0, 1fr); gap: clamp(2rem, 4vw, 3.5rem); }
@media (max-width: 860px) { .account-layout { grid-template-columns: 1fr; } }

.account-nav { display: flex; flex-direction: column; gap: 0.15rem; }
.account-nav a {
  padding: 0.6rem 0.85rem;
  border-radius: var(--radius);
  text-decoration: none;
  color: var(--ink);
  font-size: 0.9rem;
  border-left: 2px solid transparent;
}
.account-nav a:hover { background: var(--shell); }
.account-nav a[aria-current="page"] {
  background: var(--blush);
  border-left-color: var(--rose);
  color: var(--rose-ink);
  font-weight: 500;
}

.download-row {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  padding: 1rem 0;
  border-bottom: 1px solid var(--line);
}
.download-thumb {
  width: 62px;
  aspect-ratio: 3 / 4;
  border-radius: 3px;
  background: var(--shell);
  object-fit: cover;
  flex: none;
  border: 1px solid var(--line);
}
.download-row .grow { flex: 1; min-width: 0; }

/* ---------------------------------------------------------------- tables -- */

.table-scroll { overflow-x: auto; }
table.data { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
table.data th, table.data td {
  text-align: left;
  padding: 0.7rem 0.85rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
table.data th {
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 500;
  white-space: nowrap;
}

.pill {
  display: inline-block;
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.25rem 0.6rem;
  border-radius: 999px;
  background: var(--shell);
  color: var(--ink-soft);
  white-space: nowrap;
}
.pill-paid { background: #e7f2ea; color: #2c6141; }
.pill-pending { background: #fcf1e3; color: #8a5a1b; }
.pill-shipped { background: var(--sky); color: #2f5673; }
.pill-cancelled, .pill-refunded { background: #f6e6e9; color: #8c2f45; }

/* --------------------------------------------------------------- gallery -- */

/* A masonry-ish column layout: it keeps portrait and landscape shots from
   being cropped, which matters when the photographs are the point. */
.masonry { columns: 3 260px; column-gap: 1rem; }
.masonry figure { break-inside: avoid; margin: 0 0 1rem; }
.masonry img { width: 100%; border-radius: var(--radius); }
.masonry figcaption { font-size: 0.82rem; color: var(--ink-soft); padding-top: 0.4rem; }

/* ---------------------------------------------------------------- footer -- */

.site-footer { background: var(--ink); color: rgba(253, 250, 247, 0.78); padding: clamp(3rem, 6vw, 5rem) 0 2rem; }
.site-footer h4 {
  color: var(--cream);
  font-family: var(--body);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-bottom: 1.1rem;
}
.footer-grid { display: grid; grid-template-columns: 1.6fr 1fr 1fr 1.4fr; gap: clamp(1.5rem, 4vw, 3rem); }
@media (max-width: 900px) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .footer-grid { grid-template-columns: 1fr; } }

.site-footer a { color: rgba(253, 250, 247, 0.78); text-decoration: none; }
.site-footer a:hover { color: #fff; text-decoration: underline; }
.footer-links { list-style: none; padding: 0; margin: 0; }
.footer-links li { margin-bottom: 0.5rem; }

/* Ten links in one column would run past the rest of the footer, so the full
   menu sets in two — filled down the first column and then the second, so it
   reads in menu order rather than zig-zagging across. Columns take their
   content's width so nothing wraps mid-name. */
.footer-links.two-col {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(5, auto);
  grid-auto-columns: max-content;
  column-gap: clamp(1rem, 2vw, 2rem);
}
@media (max-width: 620px) {
  .footer-links.two-col {
    grid-auto-flow: row;
    grid-template-rows: none;
    grid-auto-columns: auto;
  }
}

.footer-bottom {
  margin-top: clamp(2.5rem, 5vw, 4rem);
  padding-top: 1.5rem;
  border-top: 1px solid rgba(253, 250, 247, 0.14);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  justify-content: space-between;
  font-size: 0.82rem;
}

.social { display: flex; gap: 0.75rem; }
.social a {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border: 1px solid rgba(253, 250, 247, 0.24);
  border-radius: 50%;
}
.social a:hover { background: rgba(253, 250, 247, 0.12); }

/* The same row on a light ground. .social is drawn for the ink footer — its
   border is white at 24%, which is invisible on cream. */
.social-light { margin: 0 0 1.1rem; }
.social-light a { border-color: var(--line-strong); color: var(--ink-soft); }
.social-light a:hover { background: var(--shell); color: var(--rose-deep); }
.social svg { width: 17px; height: 17px; fill: currentColor; }

/* Red4Digital's credit — a sponsor line, not a hidden footer link.

   The mark is themed rather than fixed: the R takes --champagne, which is the
   fine-detail accent of whichever palette the site is set to, so the stamp
   belongs to the page instead of sitting on it. The 4 keeps Red4 red, which
   is the half that makes the mark ours. Both are tokens, so the stamp can be
   re-pointed wherever it lands on a ground these two do not suit. */
.built-by {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  --r4-red: #b91e24;
  --r4-r: var(--champagne);
}
/* Brand red is drawn for white paper and goes muddy on the ink footer, so it
   is lifted a shade there and only there. */
.site-footer .built-by { --r4-red: #d2373d; }
.built-by > span {
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.built-by:hover { text-decoration: none; }
.built-by:hover > span { text-decoration: underline; }
.r4-mark { height: 1.9rem; width: auto; display: block; }
.r4-four { fill: var(--r4-red); }
.r4-arr { fill: var(--r4-r); transition: fill 0.2s ease; }
/* currentColor rather than a literal, so the hover lifts on a dark footer
   and on a light one alike. */
.built-by:hover .r4-arr { fill: currentColor; }

/* ---------------------------------------------------------------- motion -- */

/* Content lifts in as it enters the viewport. Progressive: without the
   IntersectionObserver script everything simply starts visible. */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity 0.7s ease, transform 0.7s ease; }
.reveal.in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1; transform: none; }
}

@media print {
  .site-header, .site-footer, .btn { display: none !important; }
  body { background: #fff; }
}

/* ------------------------------------------------------------ launch night */

/* The event sits apart from the two calendar actions: a different job, and
   the one with a deadline on it. */
.hero-tertiary { margin: 1.1rem 0 0; }

.btn-event {
  background: var(--ink);
  color: var(--cream);
  box-shadow: var(--shadow-sm);
}
.btn-event:hover { background: #1d1720; color: #fff; box-shadow: var(--shadow-md); }

.event-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: start;
}
@media (max-width: 900px) { .event-layout { grid-template-columns: 1fr; } }

/* Sticky, because the date and the price are what the page is for and they
   should stay in reach while the venue notes are being read. */
.event-card {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.5rem, 3vw, 2rem);
  box-shadow: var(--shadow-sm);
  position: sticky;
  top: calc(var(--header-h) + 1.5rem);
}
.event-card h3 { margin-top: 0; }

.event-facts { margin: 0 0 1.5rem; display: grid; grid-template-columns: auto 1fr; gap: 0.55rem 1.1rem; }
.event-facts dt {
  font-size: 0.7rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding-top: 0.2rem;
}
.event-facts dd { margin: 0; }
.event-facts dd .hint { display: block; }

/* Sized for the column rather than capped at a card width — the artwork is a
   wide banner carrying the date, time and venue as small type, and at 420px
   those lines stopped being readable. */
/* The venue photograph closing the details card — full bleed to the card's
   edges, so it reads as part of it rather than a picture dropped inside. */
.event-card-media {
  /* The card's padding is fluid, so the pull has to use the same expression
     or the picture stops meeting the edges as the viewport changes. */
  margin: 1.25rem calc(clamp(1.5rem, 3vw, 2rem) * -1) calc(clamp(1.5rem, 3vw, 2rem) * -1);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
  overflow: hidden;
  aspect-ratio: 16 / 9;
}
.event-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--focal, 50% 50%);
  display: block;
}

/* The artwork is a button in all but name. */
.ticket-art a { display: block; transition: opacity 0.2s ease; }
.ticket-art a:hover { opacity: 0.9; }

.ticket-art {
  margin: clamp(1.75rem, 4vw, 2.5rem) 0 0;
  max-width: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-md);
}

/* Main supporters, given the room the billing implies. */
.supporter-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: clamp(2rem, 6vw, 4.5rem);
}
/* Rows are stacked deliberately rather than left to wrap, so the second needs
   its own space above it — the flex gap only separates circles within a row. */
.supporter-row + .supporter-row { margin-top: clamp(2rem, 5vw, 3.5rem); }

.supporter { margin: 0; text-align: center; }
.supporter-photo {
  width: clamp(140px, 18vw, 190px);
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  margin: 0 auto 1rem;
  border: 3px solid var(--white);
  box-shadow: var(--shadow-md);
}
.supporter-photo img { width: 100%; height: 100%; object-fit: cover; object-position: var(--focal, 50% 50%); }
.supporter figcaption strong { display: block; font-family: var(--display); font-size: 1.25rem; }
.supporter figcaption span {
  font-size: 0.72rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--champagne);
}

.map-frame { border-radius: var(--radius-lg); overflow: hidden; }
.map-frame iframe {
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  display: block;
}
.map-frame .hint { margin-top: 0.7rem; text-align: center; }

/* ------------------------------------------------- theme preview (temporary)
   Three buttons in the copyright row so the charity can look at the real site
   in each colour and choose. Added 14 Aug 2026; delete this block along with
   THEME_PREVIEW in layout.ts.
   -------------------------------------------------------------------------- */

.theme-try { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }

.theme-try-label {
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.6;
  margin-right: 0.15rem;
}

.theme-try button {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font: inherit;
  font-size: 0.78rem;
  color: inherit;
  padding: 0.24rem 0.6rem;
  border: 1px solid rgba(253, 250, 247, 0.28);
  border-radius: 999px;
  background: none;
  cursor: pointer;
}
.theme-try button:hover { border-color: rgba(253, 250, 247, 0.6); }
.theme-try button[aria-pressed="true"] {
  background: rgba(253, 250, 247, 0.14);
  border-color: rgba(253, 250, 247, 0.7);
}

/* The dot is the accent that button switches to, so the choice reads as a
   colour rather than as three words. */
.theme-try i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  display: block;
  box-shadow: 0 0 0 1px rgba(253, 250, 247, 0.35);
}

/* A buy action while the calendar is not yet on sale: the button itself greyed
   and inert, carrying "Coming soon" on a second line INSIDE it. Inside rather
   than beneath, so it reads as one control saying "not yet" rather than a dead
   button with a note attached — and so it cannot be separated from the button
   by a wrap in a row of two. */
.buy-soon {
  flex-direction: column;
  gap: 0.15rem;
  line-height: 1.25;
  padding-block: 0.7rem;
}
.buy-soon-block { display: flex; width: 100%; }
.buy-soon small {
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  opacity: 0.85;
}

.btn-disabled,
.btn-disabled:hover {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
  pointer-events: none;
}

/* The folded buy details on the calendar page. */
.presale-fold {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  margin-top: 1.5rem;
}
.presale-fold > summary {
  cursor: pointer;
  font-size: 0.85rem;
  letter-spacing: 0.06em;
  color: var(--ink-soft);
}
.presale-fold > summary:hover { color: var(--ink); }
.presale-fold[open] > summary { margin-bottom: 1rem; }

/* The two enquiry forms on the contact page.

   padding-block: 0 because these are <section> elements sitting INSIDE a
   section, and the global rule gives every section 3.5–7rem of vertical
   padding. Nested, that pushed "General enquiries" 112px below the top of its
   own column, so it sat well under "Ladies First" beside it. */
.enquiry-block { padding-block: 0; }

/* And the other half of the same alignment: .prose h3 carries a 2rem top margin
   to separate it from the paragraph above, which the first one has not got. */
.feature-top .prose > h3:first-child { margin-top: 0; }

/* The rule above the second block is what stops the pair reading as one long
   form with a stray heading in the middle. */
.enquiry-block + .enquiry-block {
  margin-top: 3rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--line);
}
.enquiry-block > .hint { margin-top: -0.4rem; margin-bottom: 1.25rem; }

/* A press cutting with two images takes two of the three columns and shows
   them side by side. Only where there are at least two columns to take: below
   that the grid is a single column and a span would overflow it. */
.press-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; }
@media (min-width: 700px) {
  .press-wide { grid-column: span 2; }
}

/* A mark drawn in white needs the outlet's own background behind it, but only
   behind the MARK: the tile itself stays white and the caption stays on white
   with every other caption on the wall, so one tinted outlet does not turn into
   a dark slab in the middle of the row. A box within the box. */
.logo-tile-tinted img {
  background: var(--tile-bg);
  padding: 0.55rem 0.7rem;
  border-radius: 2px;
  box-sizing: border-box;
}
