/* CWJA site styles.

   Built to the approved homepage mockup: navy ground, gold accent, white cards
   under navy header bars. The same theme carries across every page and into the
   admin - staff and members should feel they are in one product.

   No framework. The whole site is one stylesheet, which loads faster than any
   grid library would and leaves nothing extra to keep patched. */

:root {
  --navy: #0d2149;
  --navy-700: #122c5c;
  --navy-900: #0a1836;
  --gold: #c9a227;
  --gold-light: #e2c25a;
  --ink: #1b1b1b;

  /* Overridden per site by cms/_branding.html. Declared here so the stylesheet
     is still complete on its own - a missing branding row must not leave the
     page with no font. */
  --font-body: "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-heading: Georgia, "Times New Roman", serif;
  --font-scale: 1;
  --heading-scale: 1;
  --muted: #6b7280;
  --line: #e5e7eb;
  --paper: #ffffff;
  --shell: #f4f5f7;
  --up: #1a7f37;
  --down: #b00000;

  --radius: 10px;
  --radius-sm: 6px;
  --shadow: 0 1px 2px rgba(13, 33, 73, 0.06), 0 4px 12px rgba(13, 33, 73, 0.04);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--shell);
  line-height: 1.55;
  /* rem, so body copy follows the fluid root above rather than pinning at 15px. */
  font-size: 1rem;

  /* Sticky footer. A short page - About Us is three lines - otherwise left the
     footer floating mid-screen with the page background showing beneath it.
     min-height on the body plus a growing <main> pushes it to the bottom. */
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

main { flex: 1 0 auto; }
.ticker, .footer { flex: none; }

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; }
/* Sized in em so --heading-scale multiplies whatever the element would have been,
   rather than flattening h1, h2 and h3 to a single size. */
h1, h2, h3 { font-family: var(--font-heading); letter-spacing: -0.01em; }
h1 { font-size: calc(2em * var(--heading-scale)); }
h2 { font-size: calc(1.5em * var(--heading-scale)); }
h3 { font-size: calc(1.17em * var(--heading-scale)); }

/* Proportional, not a fixed pixel cap.
 *
 * A `max-width: 1680px` container looks right at 100% zoom and then strands the
 * whole page in a narrow ribbon the moment someone zooms out - zooming out grows
 * the CSS viewport, so a fixed cap keeps the same pixel width while the window
 * around it doubles. A percentage keeps the layout the same *shape* at every
 * zoom level, which is what people expect zoom to do.
 *
 * The 2560px ceiling only bites on genuinely enormous displays, where an
 * unbounded line length becomes hard to read. */
.wrap { width: min(94%, 2560px); margin-inline: auto; }

/* Type scales gently with the viewport for the same reason: at 50% zoom a fixed
 * 15px body against a 3840px-wide layout reads as a rumour. clamp() keeps it
 * inside sensible bounds at both extremes. */
/* The clamp keeps text readable across viewport sizes and zoom levels; the scale
   is the admin's body-size setting, applied as a multiplier so it moves the whole
   curve instead of flattening it to one fixed size. */
html { font-size: calc(clamp(15px, 0.28vw + 11px, 22px) * var(--font-scale)); }
.muted { color: var(--muted); font-size: 0.88rem; }
.narrow { max-width: 34rem; }
.ico { flex: none; }

.btn {
  display: inline-flex; align-items: center; gap: 0.45rem;
  background: var(--gold); color: var(--navy);
  font-weight: 600; font-size: 0.9rem;
  padding: 0.65rem 1.35rem; border: 0; border-radius: 999px;
  cursor: pointer; text-decoration: none; transition: background 0.15s ease;
}
.btn:hover { background: var(--gold-light); }

/* ---------- Top utility bar ---------- */
.topbar { background: var(--navy-900); color: #c3ccdd; font-size: 0.78rem; }
.topbar__inner {
  display: flex; flex-wrap: wrap; gap: 1rem;
  justify-content: space-between; align-items: center; min-height: 2.6rem;
}
.topbar ul { list-style: none; display: flex; gap: 1.4rem; margin: 0; padding: 0; flex-wrap: wrap; }
.topbar__contact li { display: flex; align-items: center; gap: 0.35rem; }
.topbar__link { display: inline-flex; align-items: center; gap: 0.35rem; }
.topbar__follow { opacity: 0.75; }
.topbar__actions { display: flex; gap: 1.1rem; align-items: center; }
.topbar a { text-decoration: none; }
.topbar a:hover { color: var(--gold-light); }
.topbar__logout { display: inline; }
.topbar__logout button { background: none; border: 0; color: inherit; font: inherit; cursor: pointer; padding: 0; }

/* Icon buttons, in the header and the footer both. Sized by the button rather
   than by the glyph so a custom upload and a built-in mark come out identical -
   the uploaded file is `object-fit: contain` inside the same circle. */
.social { list-style: none; display: flex; gap: 0.45rem; margin: 0; padding: 0; flex-wrap: wrap; }
.social a {
  display: grid; place-items: center; width: 1.75rem; height: 1.75rem;
  border-radius: 50%; background: rgba(255, 255, 255, 0.12);
  color: inherit; text-decoration: none;
  transition: background 0.15s ease, color 0.15s ease, transform 0.15s ease;
}
.social a:hover { background: var(--gold); color: var(--navy); transform: translateY(-1px); }
.social a:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.social__svg { width: 0.95rem; height: 0.95rem; display: block; }
.social__img { width: 0.95rem; height: 0.95rem; object-fit: contain; display: block; }
.social__letter { font-size: 0.68rem; font-weight: 700; line-height: 1; }

/* `.footer ul` sets `display: grid` for the link columns and outranks `.social`
   on specificity, which stacked the icons one per line. */
.footer .social { display: flex; flex-wrap: wrap; }
/* The icons belong to the association named above them, but they are a separate
   thing from its name - tight against it they read as a third line of the
   masthead rather than as buttons.
 *
   Qualified with `.footer` for the same reason as the rule above: `.footer ul`
   sets `margin: 0` and a `gap`, and at 0,1,1 it outranks a lone class - so both
   the space and the spacing here were being dropped without a word. */
.footer .social--footer { gap: 0.55rem; margin-top: 1.6rem; }
.social--footer a { width: 2.1rem; height: 2.1rem; background: rgba(255, 255, 255, 0.08); }
.social--footer .social__svg, .social--footer .social__img { width: 1.05rem; height: 1.05rem; }

.langswitch { list-style: none; display: flex; gap: 0.4rem; margin: 0; padding: 0; font-size: 0.75rem; }
.langswitch [aria-current] { color: var(--gold); font-weight: 700; }

/* ---------- Header ---------- */
.header { background: var(--paper); box-shadow: var(--shadow); position: relative; z-index: 10; }
.header__inner {
  display: flex; flex-wrap: wrap; gap: 1.5rem;
  align-items: center; justify-content: space-between; padding-block: 1.1rem;
}
.brand { text-decoration: none; display: flex; align-items: center; gap: 0.9rem; }
.brand__mark {
  width: 3.4rem; height: 3.4rem; flex: none; border-radius: 50%;
  border: 2px solid var(--gold); display: grid; place-items: center;
  color: var(--gold); font-weight: 800; font-size: 0.82rem; letter-spacing: 0.04em;
}
.brand__name {
  display: block; font-family: var(--font-heading);
  font-size: calc(1.42rem * var(--heading-scale)); line-height: 1.12; font-weight: 700;
  color: var(--navy); text-transform: uppercase;
}
.brand__logo {
  width: 3.4rem; height: 3.4rem; flex: none; border-radius: 50%;
  object-fit: cover; display: block;
}
.brand__tagline {
  display: block; font-size: 0.76rem; color: var(--gold);
  font-weight: 600; letter-spacing: 0.06em; margin-top: 0.15rem;
}

.nav__list { list-style: none; display: flex; flex-wrap: wrap; gap: 1.4rem; margin: 0; padding: 0; align-items: center; }
.nav__list > li > a, .nav__group > span {
  text-decoration: none; font-weight: 600; font-size: 0.8rem;
  text-transform: uppercase; letter-spacing: 0.03em; color: var(--navy);
  padding-block: 0.4rem; display: inline-block;
}
.nav__list > li > a:hover { color: var(--gold); }

/* Services dropdown. CSS-only: hover on desktop, and on narrow screens the
   sub-list stays in the flow so it is reachable without JavaScript. */
.nav__group { position: relative; }
.nav__group > span { cursor: default; }
.nav__group > span::after { content: " \25BE"; font-size: 0.7em; color: var(--muted); }
.nav__sub {
  list-style: none; margin: 0; padding: 0.4rem 0;
  position: absolute; top: 100%; left: 0; min-width: 12rem;
  background: var(--paper); box-shadow: var(--shadow);
  border-radius: var(--radius-sm); border: 1px solid var(--line);
  display: none; z-index: 20;
}
.nav__group:hover .nav__sub, .nav__group:focus-within .nav__sub { display: block; }
.nav__sub a { display: block; padding: 0.5rem 1rem; font-size: 0.85rem; text-decoration: none; color: var(--ink); }
.nav__sub a:hover { background: var(--shell); color: var(--gold); }

/* ---------- Hero ---------- */
/* Inset and rounded, as drawn - not full bleed - so it lines up with the panels
   below it down the page. */
.hero {
  position: relative; background: var(--navy); overflow: hidden;
  border-radius: var(--radius); margin-block: 1rem; box-shadow: var(--shadow);
}
.hero__slide { display: none; position: relative; }
.hero__slide.is-active { display: block; }
.hero__slide img { width: 100%; height: 23rem; object-fit: cover; }
/* A gradient rather than a flat opacity drop: the headline then stays readable
   over whatever photograph the association uploads, instead of depending on the
   image happening to be dark on the left. */
.hero__slide::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(
    90deg,
    var(--navy) 10%,
    rgba(13, 33, 73, 0.82) 42%,
    rgba(13, 33, 73, 0.15) 78%
  );
}
/* No caption means the artwork carries the words. Darkening it would be dimming
   the very thing the visitor is meant to read. */
.hero__slide--plain::after { content: none; }
.hero__slide--plain a { display: block; }

.hero__caption {
  position: absolute; inset: 0; z-index: 2;
  display: flex; flex-direction: column; justify-content: center; gap: 0.85rem;
  /* The floor clears the prev arrow (1.25rem in, 2.6rem wide). Below it the
     headline ran underneath the arrow at middling widths - around 1024px the
     third line of "Empowering Jewellers, Strengthening the Industry" came out
     with a white disc sitting on top of it. */
  padding: 2rem clamp(4.4rem, 5vw, 5.5rem); max-width: 46rem; color: #fff;
}
.hero__arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 2.6rem; height: 2.6rem; border-radius: 50%;
  background: rgba(255, 255, 255, 0.92); color: var(--navy);
  display: grid; place-items: center; text-decoration: none;
  font-size: 1.1rem; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.hero__arrow--prev { left: 1.25rem; }
.hero__arrow--next { right: 1.25rem; }
.hero__caption h1 { margin: 0; font-size: calc(clamp(1.9rem, 4.4vw, 3.35rem) * var(--heading-scale)); line-height: 1.08; font-weight: 700; }
.hero__caption p { margin: 0; color: #d7dfee; font-size: 1.02rem; }
.hero__caption .btn { align-self: flex-start; margin-top: 0.5rem; }
.hero__dots { position: absolute; bottom: 1.1rem; left: 50%; transform: translateX(-50%); display: flex; gap: 0.45rem; }
.hero__dots button {
  width: 0.5rem; height: 0.5rem; border-radius: 50%; padding: 0; border: 0;
  background: rgba(255, 255, 255, 0.45); cursor: pointer; appearance: none;
}
.hero__dots button.is-active { background: var(--gold); }
.hero__dots button:focus-visible, .hero__arrow:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* ---------- Panel row ---------- */
.panels { padding-block: 0 1.25rem; }
/* Four equal tracks for the four panels, so the row is exactly as wide as the
   hero above it. It briefly had five while the bullion panel was double-width to
   fit every purity; the home panel now shows the design's two metals, so the
   fifth track was empty and the row stopped short of the hero. */
.panels__grid { display: grid; gap: 1rem; grid-template-columns: repeat(4, 1fr); }
/* Available for a panel that needs the room - nothing uses it today. */
.panel--wide { grid-column: span 2; }

@media (max-width: 82rem) {
  .panels__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 48rem) {
  .panels__grid { grid-template-columns: 1fr; }
  .panel--wide { grid-column: span 1; }
}
.panel {
  background: var(--paper); border-radius: var(--radius);
  box-shadow: var(--shadow); overflow: hidden;
  display: flex; flex-direction: column;
}
.panel__title {
  display: flex; justify-content: space-between; align-items: center; gap: 0.75rem;
  margin: 0; background: var(--navy-700); color: #fff;
  font-family: var(--font-body);
  font-size: 0.82rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 0.85rem 1rem;
}
.panel__title .ico { color: var(--gold); }
.panel__title-text { display: flex; align-items: center; gap: 0.5rem; }
.panel__more { color: var(--gold-light); font-size: 0.72rem; text-decoration: none; white-space: nowrap; text-transform: none; letter-spacing: 0; }
.panel__more:hover { color: #fff; }
.panel__placeholder { color: var(--muted); font-size: 0.88rem; padding: 1.1rem; margin: 0; }
.panel__foot { padding: 0.75rem 1rem; border-top: 1px solid var(--line); text-align: center; margin-top: auto; }
.panel__foot a { font-size: 0.78rem; color: var(--navy); text-decoration: none; font-weight: 600; }
.panel__foot a:hover { color: var(--gold); }

/* ---------- Rate table ---------- */
.ratetable__scroll { overflow-x: auto; }
.ratetable { width: 100%; border-collapse: collapse; font-size: 0.82rem; }
.ratetable th, .ratetable td { padding: 0.6rem 0.85rem; text-align: left; white-space: nowrap; }
.ratetable thead th {
  background: var(--shell); color: var(--muted);
  font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700;
}
.ratetable thead th small { display: block; font-weight: 500; opacity: 0.85; letter-spacing: 0.02em; }
.ratetable tbody tr { border-top: 1px solid var(--line); }
.ratetable tbody th { font-weight: 600; color: var(--navy); font-size: 0.84rem; }
.ratetable__city { display: flex; align-items: center; gap: 0.35rem; }
.ratetable__city .ico { color: var(--gold); }
.ratetable tbody td { color: var(--gold); font-weight: 700; font-variant-numeric: tabular-nums; }
.ratetable tbody td:last-child { color: var(--muted); font-weight: 500; font-size: 0.76rem; }
.ratetable .is-stale { background: #fffaf6; }

.stale-flag {
  display: inline-block; margin-left: 0.35rem; padding: 0 0.35rem;
  border-radius: 3px; background: #fdecea; color: var(--down);
  font-size: 0.64rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700;
}
.dir--up { color: var(--up); }
.dir--down { color: var(--down); }
.dir--flat { color: var(--muted); }

/* ---------- MCX panel ---------- */
.mcx { list-style: none; margin: 0; padding: 0; }
.mcx__row {
  display: flex; justify-content: space-between; gap: 1rem; align-items: center;
  padding: 0.7rem 1rem; border-top: 1px solid var(--line); font-size: 0.84rem;
}
.mcx__row:first-child { border-top: 0; }
.mcx__label { color: var(--navy); font-weight: 600; font-size: 0.76rem; text-transform: uppercase; letter-spacing: 0.03em; }
.mcx__value { font-variant-numeric: tabular-nums; font-weight: 700; color: var(--up); display: flex; align-items: center; gap: 0.2rem; }

/* ---------- Trend ---------- */
.trend__tabs { display: flex; gap: 0.3rem; padding: 0.75rem 1rem 0.25rem; flex-wrap: wrap; }
.trend__tab { font-size: 0.72rem; padding: 0.3rem 0.8rem; border-radius: 999px; text-decoration: none; color: var(--muted); background: var(--shell); }
.trend__tab.is-active { background: var(--navy); color: #fff; font-weight: 600; }
.trend__figure { margin: 0; padding: 0.5rem 1rem 1rem; }
.trend__figure svg { width: 100%; height: 8.5rem; display: block; }
.trend__line { fill: none; stroke-width: 2; vector-effect: non-scaling-stroke; }
.trend__line--up { stroke: var(--gold); }
.trend__line--down { stroke: var(--down); }
.trend__line--flat { stroke: var(--muted); }
.trend__area { stroke: none; opacity: 0.16; }
.trend__area--up { fill: var(--gold); }
.trend__area--down { fill: var(--down); }
.trend__area--flat { fill: var(--muted); }
.trend__caption {
  display: flex; justify-content: space-between; gap: 0.5rem;
  font-size: 0.72rem; color: var(--muted); font-variant-numeric: tabular-nums;
  padding-top: 0.4rem; border-top: 1px solid var(--line); margin-top: 0.4rem;
}

/* ---------- News cards ---------- */
.newscard { display: flex; gap: 0.8rem; padding: 0.8rem 1rem; text-decoration: none; border-top: 1px solid var(--line); }
.newscard:first-of-type { border-top: 0; }
.newscard:hover { background: var(--shell); }
.newscard img { width: 4.6rem; height: 3.4rem; object-fit: cover; border-radius: var(--radius-sm); flex: none; }
.newscard h3 { margin: 0.1rem 0 0.2rem; font-size: calc(0.86rem * var(--heading-scale)); font-family: inherit; font-weight: 600; line-height: 1.3; }
.newscard time { color: var(--muted); font-size: 0.72rem; }
.newscard__cat { color: var(--gold); font-size: 0.64rem; text-transform: uppercase; font-weight: 700; letter-spacing: 0.06em; }

/* ---------- Quick links ---------- */
.quicklinks { padding-bottom: 1.5rem; }
.quicklinks__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  background: var(--paper); border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden;
}
.quicklinks__grid a { display: flex; align-items: center; gap: 0.7rem; padding: 1.15rem 1rem; text-decoration: none; border-left: 1px solid var(--line); }
.quicklinks__grid a:first-child { border-left: 0; }
.quicklinks__grid a:hover { background: var(--shell); }
.quicklinks__grid .ico { color: var(--gold); }
.quicklinks__grid strong { display: block; color: var(--navy); font-size: 0.86rem; line-height: 1.25; }
.quicklinks__grid span { color: var(--muted); font-size: 0.76rem; }

/* ---------- Advertisements ---------- */
.ads { padding-bottom: 2rem; }
.ads__grid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); align-items: stretch; }
.ad { border-radius: var(--radius); overflow: hidden; background: var(--navy); color: #fff; box-shadow: var(--shadow); }
.ad img { width: 100%; height: 100%; object-fit: cover; min-height: 9rem; }

/* ---------- Advertisement rotator ---------- */
/* Adverts were laid side by side, one tile each, so a third booking made every
   advert a third narrower. Each now gets the whole slot for its turn.

   The slides stack rather than flow: `position: absolute` on all of them and a
   min-height on the frame, because the frame cannot take its height from a slide
   that is fading out under one fading in. */
.adrot { position: relative; display: block; }
.adrot--many { min-height: clamp(11rem, 17vw, 16rem); }
.adrot__slide { display: block; text-decoration: none; }
.adrot--many .adrot__slide { position: absolute; inset: 0; display: none; }
.adrot--many .adrot__slide.is-active { display: block; }
.adrot__slide img, .adrot__slide .slot__video {
  width: 100%; height: 100%; object-fit: cover; display: block;
}

/* Smaller than the hero's. An advert slot is a third of the width the banner
   gets, and arrows sized for the banner cover the artwork someone paid for. */
.adrot__arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 3;
  width: 1.9rem; height: 1.9rem; padding: 0; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, 0.88); color: var(--navy);
  display: grid; place-items: center; cursor: pointer;
  font-size: 0.95rem; line-height: 1;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
  transition: background 0.15s ease;
}
.adrot__arrow:hover { background: #fff; }
.adrot__arrow:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.adrot__arrow--prev { left: 0.5rem; }
.adrot__arrow--next { right: 0.5rem; }

.adrot__dots {
  position: absolute; bottom: 0.7rem; left: 50%; transform: translateX(-50%);
  display: flex; gap: 0.4rem; z-index: 3;
}
.adrot__dots button {
  width: 0.5rem; height: 0.5rem; padding: 0; border: 0; border-radius: 50%;
  background: rgba(255, 255, 255, 0.55); cursor: pointer;
}
.adrot__dots button.is-active { background: var(--gold); }
.adrot__dots button:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* A video fills its slot the way the image does - `object-fit` applies to a
   <video> exactly as it does to an <img>, so a portrait film in a landscape
   slot is cropped rather than letterboxed into black bars. */
.slot__video { width: 100%; height: 100%; object-fit: cover; display: block; background: var(--navy); }

/* ---------- Changing slide ---------- */
/* The swap was a straight display:none/block - the old slide vanished and the
   new one appeared between one frame and the next, which reads as a flicker
   rather than as a rotation.
 *
 * A fade on the incoming slide rather than a crossfade of both: a true crossfade
 * needs every slide stacked and the frame given a fixed height, and the hero's
 * height is not fixed - below 48rem its caption stacks under the image, so the
 * slides are different heights and a fixed frame would clip one or gap the other. */
@keyframes slot-fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
.hero__slide.is-active, .adrot--many .adrot__slide.is-active {
  animation: slot-fade-in 0.45s ease both;
}

/* Anyone who has asked for less motion gets the swap with no fade. The rotation
   itself is already stopped for them in slider.js; this covers the arrows and
   dots, which still work. */
@media (prefers-reduced-motion: reduce) {
  .hero__slide.is-active, .adrot--many .adrot__slide.is-active { animation: none; }
}
/* A compact call to action, as drawn. The full enquiry form lives on its own page:
   five fields stretched this row to nearly a thousand pixels of empty white. */
.ad--enquiry { background: var(--navy); padding: 1.6rem; display: flex; flex-direction: column; justify-content: center; gap: 0.15rem; }
.ad--enquiry h2 { margin: 0; color: var(--gold); font-size: calc(1.4rem * var(--heading-scale)); }
.ad--enquiry p { margin: 0 0 0.9rem; color: #c3ccdd; font-size: 0.88rem; }
.ad--enquiry .btn { align-self: flex-start; }

/* The plain advertisement block: a headline over the uploaded artwork. */
.ad--banner { position: relative; display: block; min-height: 9.5rem; }
.ad--banner img { position: absolute; inset: 0; opacity: 0.55; }
.ad--banner span { position: relative; z-index: 2; display: block; padding: 1.6rem; }
.ad--banner strong { display: block; font-family: var(--font-heading); font-size: calc(1.4rem * var(--heading-scale)); }
.ad--banner em { font-style: normal; color: #c3ccdd; font-size: 0.88rem; }
/* 8rem fitted three columns onto a 390px phone, which left "Working together for
   a brighter tomorrow" stacked one or two words per line down a 120px column.
   13rem is the width the sentence actually needs, so the count drops to one. */
.ad--values { background: var(--paper); color: var(--ink); display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr)); }
.ad--values div { padding: 1.2rem 1rem; text-align: center; border-left: 1px solid var(--line); }
.ad--values div:first-child { border-left: 0; }
.ad--values .ico { color: var(--gold); margin: 0 auto 0.5rem; }
.ad--values strong { display: block; color: var(--navy); font-size: 0.9rem; }
.ad--values span { color: var(--muted); font-size: 0.78rem; }

/* ---------- Ticker ---------- */
/* The hairline matters when the shading is flat: the strip and the footer below
   it are then the same colour, and without it they run together into one dark
   block with the headline floating in the top of it. */
.ticker { background: var(--navy-900); color: #fff; border-bottom: 1px solid rgba(255, 255, 255, 0.09); }
.ticker__inner { display: flex; align-items: center; gap: 1rem; min-height: 3.2rem; }
.ticker__label {
  display: inline-flex; align-items: center; gap: 0.4rem;
  background: var(--gold); color: var(--navy);
  font-weight: 800; font-size: 0.7rem; letter-spacing: 0.06em;
  padding: 0.35rem 0.8rem; border-radius: var(--radius-sm); white-space: nowrap;
}
.ticker__items { list-style: none; display: flex; gap: 1.75rem; margin: 0; padding: 0; overflow: hidden; flex: 1; font-size: 0.83rem; }
.ticker__items li { white-space: nowrap; position: relative; }
.ticker__items li + li::before { content: "\2022"; color: var(--gold); position: absolute; left: -1rem; }
.ticker__items a { text-decoration: none; }
.ticker__all { color: var(--gold-light); font-size: 0.78rem; text-decoration: none; white-space: nowrap; }

/* ---------- Footer ---------- */
.footer { background: var(--navy); color: #b9c3d6; padding-block: 2.75rem 0; font-size: 0.86rem; }

/* The brand column is given more room than the link columns: it carries a
   40-character name and would otherwise wrap to four lines while a column of
   two links sat half empty beside it. */
/* A grid track minimum is a hard floor, and a fixed first column plus an auto
   one came to more than a 360px phone holds - so the page itself grew and the
   whole site scrolled sideways. `min(100%, 12rem)` on a single repeating track
   is what actually collapses: the count drops to one rather than the tracks
   overflowing. (`min(…, 100%)` on *two* tracks does not help - 100% is the
   container, so both still resolve to their rem value and still overflow.) */
.footer__inner {
  display: grid; gap: 2rem 2.5rem; align-items: start;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
}

/* The brand carries a 40-character name and would otherwise wrap to four lines
   beside a column holding two links. Only once there is room for it. */
@media (min-width: 64rem) {
  .footer__brand { grid-column: span 2; }
}
.footer h2 {
  font-family: var(--font-body);
  font-size: calc(0.78rem * var(--heading-scale)); text-transform: uppercase; letter-spacing: 0.09em;
  color: var(--gold); margin: 0 0 0.85rem;
}
.footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.5rem; }
.footer a { text-decoration: none; }
.footer a:hover { color: var(--gold-light); }
.footer address { font-style: normal; display: grid; gap: 0.5rem; }
.footer p { margin: 0; }

.footer__mark { display: flex; align-items: center; gap: 0.8rem; }
.footer__logo, .footer__initials {
  width: 3rem; height: 3rem; flex: none; border-radius: 50%;
  object-fit: cover; display: grid; place-items: center;
}
.footer__initials {
  border: 2px solid var(--gold); color: var(--gold);
  font-weight: 800; font-size: 0.72rem; letter-spacing: 0.04em;
}
.footer__name {
  display: block; font-family: var(--font-heading); color: #fff;
  font-size: calc(0.98rem * var(--heading-scale)); line-height: 1.2;
  font-weight: 700; text-transform: uppercase;
}
.footer__tagline {
  display: block; color: var(--gold); font-size: 0.72rem;
  font-weight: 600; letter-spacing: 0.06em; margin-top: 0.2rem;
}

/* Icon and text on one line, and the icon does not shrink when the address wraps. */
.footer__contact { display: inline-flex; align-items: center; gap: 0.45rem; }
.footer__contact .ico { flex: none; opacity: 0.75; }

.footer__bottom {
  margin-top: 2.25rem; padding-block: 1.1rem;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  display: flex; flex-wrap: wrap; gap: 0.35rem 1.5rem;
  justify-content: space-between; align-items: center;
  font-size: 0.78rem; color: #8fa0be;
}
.footer__by { opacity: 0.85; }

/* ---------- WhatsApp float ---------- */
.whatsapp-float {
  position: fixed; right: 1.1rem; bottom: 4.8rem; z-index: 30;
  width: 3.2rem; height: 3.2rem; border-radius: 50%;
  background: #25d366; color: #fff; display: grid; place-items: center;
  text-decoration: none; font-weight: 700; font-size: 0.62rem;
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.28);
}

/* ---------- Messages, prose, forms ---------- */
.messages { list-style: none; margin-inline: auto; padding: 0.75rem 0; width: min(94%, 2560px); }
.msg { padding: 0.65rem 1rem; border-radius: var(--radius-sm); background: #e8f5e9; margin-bottom: 0.4rem; font-size: 0.88rem; }
.msg--error { background: #fdecea; color: var(--down); }

.prose { background: var(--paper); border-radius: var(--radius); box-shadow: var(--shadow); padding: 2.25rem; margin-block: 1.75rem; }
.prose h1 { margin-top: 0; color: var(--navy); font-size: calc(1.85rem * var(--heading-scale)); }
.prose h2 { color: var(--navy); font-size: calc(1.25rem * var(--heading-scale)); margin-top: 1.75rem; }

.stackform p { margin-block: 0.8rem; }
.stackform label { display: block; font-weight: 600; font-size: 0.82rem; margin-bottom: 0.25rem; color: var(--navy); }
.stackform input, .stackform select, .stackform textarea {
  width: 100%; padding: 0.6rem 0.7rem; border: 1px solid var(--line);
  border-radius: var(--radius-sm); font: inherit; font-size: 0.9rem; background: #fff;
}
.stackform input:focus, .stackform select:focus, .stackform textarea:focus {
  outline: 2px solid var(--gold); outline-offset: 0; border-color: var(--gold);
}
.stackform .helptext { display: block; color: var(--muted); font-size: 0.76rem; }
.stackform ul.errorlist { list-style: none; margin: 0.2rem 0; padding: 0; color: var(--down); font-size: 0.8rem; }

.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.25rem; }
.filters input, .filters select { padding: 0.55rem 0.7rem; border: 1px solid var(--line); border-radius: var(--radius-sm); font: inherit; font-size: 0.88rem; }
.filters input[type="search"] { flex: 1 1 14rem; }

.pager { display: flex; gap: 1rem; align-items: center; margin-top: 1.5rem; font-size: 0.85rem; }

.module { border: 1px solid var(--line); border-radius: var(--radius); padding: 1.35rem; margin-block: 1rem; background: #fff; }
.module h2 { margin-top: 0; font-size: calc(1.02rem * var(--heading-scale)); color: var(--navy); font-family: inherit; }
.module dl { display: grid; grid-template-columns: auto 1fr; gap: 0.4rem 1.25rem; margin: 0; }
.module dt { font-weight: 600; color: var(--muted); font-size: 0.82rem; }
.module dd { margin: 0; }

/* ---------- Listings shared by members, events, gallery, forum ---------- */
.memberlist, .eventlist, .doclist, .activitylist, .albumgrid,
.boardlist, .topiclist, .postlist, .newslist { list-style: none; margin: 0; padding: 0; }

.memberlist { display: grid; gap: 0.85rem; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); }
.memberlist li { border-radius: var(--radius); padding: 1rem; background: #fff; box-shadow: var(--shadow); }
.memberlist a { text-decoration: none; color: var(--navy); }

.eventlist { display: grid; gap: 0.85rem; margin-bottom: 2rem; }
.eventcard { display: flex; gap: 1rem; align-items: flex-start; border-radius: var(--radius); padding: 1rem; background: #fff; box-shadow: var(--shadow); }
.eventcard img { width: 9rem; height: 6rem; object-fit: cover; border-radius: var(--radius-sm); }
.eventcard a { text-decoration: none; color: var(--navy); }
.eventcard p { margin: 0.35rem 0 0; }

.albumgrid { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); }
.albumgrid li { display: grid; gap: 0.35rem; }
.albumgrid img { border-radius: var(--radius); aspect-ratio: 4 / 3; object-fit: cover; width: 100%; }
.albumgrid a { text-decoration: none; color: var(--navy); }

.doclist { display: grid; gap: 0.7rem; }
.doclist li { display: flex; justify-content: space-between; gap: 1rem; align-items: center; flex-wrap: wrap; border-radius: var(--radius); padding: 1rem; background: #fff; box-shadow: var(--shadow); }
.doclist strong { display: block; color: var(--navy); }
.doclist p { margin: 0.25rem 0 0; }

.activitylist { display: grid; gap: 1.5rem; }
.activitylist li { display: flex; gap: 1.25rem; flex-wrap: wrap; }
.activitylist img { width: 12rem; border-radius: var(--radius); object-fit: cover; }
.activitylist h2 { margin: 0 0 0.25rem; font-size: calc(1.05rem * var(--heading-scale)); }

.newslist { display: grid; gap: 1.25rem; }
.newslist a { font-weight: 600; color: var(--navy); text-decoration: none; }

.boardlist, .topiclist { display: grid; gap: 0.6rem; margin-bottom: 1.75rem; }
.boardlist li, .topiclist li { border-radius: var(--radius); padding: 0.9rem 1rem; background: #fff; box-shadow: var(--shadow); }
.boardlist a, .topiclist a { text-decoration: none; color: var(--navy); font-weight: 600; }
.topiclist span { display: block; font-size: 0.78rem; color: var(--muted); }

.postlist { display: grid; gap: 1rem; margin-bottom: 1.75rem; }
.post { border-radius: var(--radius); padding: 1.1rem; background: #fff; box-shadow: var(--shadow); }
.post--removed { background: var(--shell); box-shadow: none; border: 1px dashed var(--line); }
.post__meta { display: flex; gap: 0.75rem; align-items: baseline; flex-wrap: wrap; font-size: 0.78rem; color: var(--muted); margin-bottom: 0.5rem; }
.post__meta strong { color: var(--navy); font-size: 0.88rem; }
.post__images { display: flex; gap: 0.5rem; flex-wrap: wrap; margin-top: 0.6rem; }
.post__images img { max-width: 14rem; border-radius: var(--radius-sm); }
.post__actions { display: flex; gap: 0.85rem; align-items: center; margin-top: 0.7rem; font-size: 0.8rem; }
.post__actions form { display: inline; }
.post__actions button { background: none; border: 0; color: var(--down); cursor: pointer; font: inherit; padding: 0; }

/* ---------- Responsive ---------- */
/* The brand is a 39-character name set in a serif face; the nav is seven items.
   Between the mobile breakpoint and about 1440px the two do not fit side by
   side, and `flex-wrap` resolved that by dropping the entire nav onto a second
   row underneath the logo - which is what a 1366px laptop, the commonest screen
   the members use, actually showed. Nowrap plus a brand allowed to shrink keeps
   them on one row; the name wraps to two lines instead, which reads fine. */
@media (min-width: 60.0625rem) {
  .header__inner { flex-wrap: nowrap; }
  .brand { min-width: 0; }
}

@media (min-width: 60.0625rem) and (max-width: 90rem) {
  .brand__logo, .brand__mark { width: 2.9rem; height: 2.9rem; }
  .brand__name { font-size: calc(1.1rem * var(--heading-scale)); }
  .brand__tagline { font-size: 0.7rem; margin-top: 0.1rem; }
  .nav__list { gap: 1rem; }
  .nav__list > li > a, .nav__group > span { font-size: 0.73rem; }
}

/* Just above the breakpoint - a 1024px tablet in landscape, or a small laptop -
   even the reduced sizes above leave the seven items one row short. */
@media (min-width: 60.0625rem) and (max-width: 72rem) {
  .brand__logo, .brand__mark { width: 2.6rem; height: 2.6rem; }
  .brand__name { font-size: calc(0.95rem * var(--heading-scale)); }
  .brand { gap: 0.7rem; }
  .header__inner { gap: 1rem; }
  .nav__list { gap: 0.75rem; }
  .nav__list > li > a, .nav__group > span { font-size: 0.68rem; letter-spacing: 0.02em; }
}

@media (max-width: 48rem) {
  .hero__slide img { height: 15rem; }
  /* The caption is below the image here, not beside the arrows, so it does not
     need to keep clear of them - and 4.4rem of padding either side of a 360px
     screen would leave the headline in a column barely wide enough for a word. */
  .hero__caption {
    position: static; background: var(--navy); max-width: none;
    padding-block: 1.75rem; padding-inline: 1.4rem;
  }

  /* The scrim covers the whole slide, and the caption is no longer on top of the
     image - it sits below it. Left in place it painted a navy gradient straight
     over the headline, which read as the text being cut off at the left. It is
     not needed here either: the caption has a solid background of its own. */
  .hero__slide::after { content: none; }

  /* The arrows centre on the slide, which now includes the caption stacked below
     the image - so they drifted down onto the join. Half the image height puts
     them back over the picture where they belong. */
  .hero__arrow { top: 7.5rem; }
  .hero__dots { bottom: auto; top: 13.5rem; }

  /* Any fixed float covers whatever happens to be under it, and 4.8rem up the
     right edge put this in the middle of a panel - at 360px it landed squarely
     on the rates card's "View All" link, so the link could not be tapped at all.
     The corner is where people expect it and where it blocks least. */
  .whatsapp-float { bottom: 1.15rem; right: 0.9rem; width: 2.9rem; height: 2.9rem; }
  .quicklinks__grid a { border-left: 0; border-top: 1px solid var(--line); }
  /* One headline, on one line.
   *
   * This stacked the items in a column inside a fixed 1.4rem height, meaning to
   * show the first and clip the rest. What it actually did was slice the second
   * one through the middle - half a line of "MEETING @2" showing under the first
   * headline, which is precisely what the strip looked like it was doing:
   * collapsing. Hiding them outright is deterministic; a height that happens to
   * equal one line is not, because the line box changes with the type scale.
   *
   * The rest of the headlines are one tap away on "View All". */
  .ticker__items { flex-direction: row; gap: 0; height: auto; min-width: 0; }
  .ticker__items li + li { display: none; }
  .ticker__items li + li::before { content: ""; }

  /* min-width:0 as well as max-width:100% - a flex item will not shrink below
     its content otherwise, and the ellipsis never appears. */
  .ticker__items li { min-width: 0; max-width: 100%; overflow: hidden; text-overflow: ellipsis; }

  /* Stacked, a left border is a stray vertical line beside a full-width block. */
  .ad--values div { border-left: 0; border-top: 1px solid var(--line); }
  .ad--values div:first-child { border-top: 0; }
}

/* ---------- Full rates page ---------- */
.ratespage { margin-block: 1.5rem 2rem; display: grid; gap: 1rem; }
.ratespage__heading { margin: 0; color: var(--navy); font-size: calc(1.85rem * var(--heading-scale)); }
.ratespage__split { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); }
.ratespage__note { margin: 0; }

/* ---------- XHR navigation progress ---------- */
/* Every navigation is an XHR now (see js/nav.js), which means the browser's own
   spinner and progress bar never appear. Without something in their place a slow
   page is indistinguishable from a dead click, so this is load-bearing feedback
   rather than decoration.

   The width is a fake: real progress is unknowable for a single request, so it
   eases out towards - never reaching - the full width, and the class coming off
   ends it. That is the same illusion the browser's own bar uses. */
#nav-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 100%;
  z-index: 9999;
  pointer-events: none;
  transform: scaleX(0);
  transform-origin: 0 50%;
  opacity: 0;
  background: linear-gradient(90deg, var(--gold) 0%, var(--gold-light) 100%);
}

html.nav-busy #nav-progress {
  opacity: 1;
  animation: nav-progress 8s cubic-bezier(0.15, 0.85, 0.25, 1) forwards;
}

@keyframes nav-progress {
  0%   { transform: scaleX(0); }
  35%  { transform: scaleX(0.55); }
  70%  { transform: scaleX(0.82); }
  100% { transform: scaleX(0.96); }
}

/* Anyone who has asked for less motion still needs to know the page is working,
   so the bar stays - it just appears rather than travels. */
@media (prefers-reduced-motion: reduce) {
  html.nav-busy #nav-progress { animation: none; transform: scaleX(1); opacity: 0.7; }
}

/* ---------- Error pages (400/403/404) ---------- */
/* 500 is deliberately not styled here - it inlines its own CSS, because it has
   to render when the static pipeline itself may be what failed. */
.errorpage { text-align: center; padding-top: 3rem; padding-bottom: 4rem; }
.errorpage__code {
  font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--gold); margin: 0 0 0.5rem;
}
.errorpage h1 { margin-top: 0; }
.errorpage__links {
  display: flex; flex-wrap: wrap; gap: 1.25rem;
  align-items: center; justify-content: center; margin-top: 2rem;
}


/* ---------- Honeypot ---------- */
/* A text input only a bot should fill. It has to stay a real, focusable-by-code
   text field - hidden inputs are exactly what the bots worth catching skip - so
   it is moved off screen rather than removed from the DOM.

   Two rules, because they fail differently. The first takes the input itself out
   of view and out of flow, and works everywhere. The second removes the empty
   paragraph as_p leaves behind; :has() is well supported now, and where it is
   not the cost is a little blank space rather than a visible box someone can
   type into. */
.honeypot {
  position: absolute !important;
  left: -9999px !important;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.stackform p:has(> .honeypot),
form p:has(> .honeypot) { display: none; }

/* ---------- Tables inside page bodies ---------- */
/* Authored in the admin editor, so they arrive as bare <table> markup with no
   classes to hook onto - the styling has to come from the element itself.

   Wrapped in its own scroll container: a table wide enough to overflow would
   otherwise push the whole page sideways, and a horizontally scrolling page is
   far worse than a horizontally scrolling table. */
.prose table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.5rem 0;
  font-size: 0.92rem;
}
.prose table caption {
  caption-side: top; text-align: left; padding-bottom: 0.5rem;
  font-size: 0.8rem; color: var(--muted); font-weight: 600;
}
.prose th,
.prose td { border: 1px solid var(--line); padding: 0.55rem 0.75rem; text-align: left; vertical-align: top; }
.prose th { background: var(--shell); color: var(--navy); font-weight: 700; }
.prose tbody tr:nth-child(even) td { background: rgba(13, 33, 73, 0.02); }

/* Long tables are the usual reason a page body overflows on a phone. */
@media (max-width: 40rem) {
  .prose table { display: block; overflow-x: auto; white-space: nowrap; }
}

/* The unit under a bullion column heading. Small, but not so small it reads as
   decoration - it is the difference between a price and a number. */
.ratetable__unit {
  display: block;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: none;
  opacity: 0.75;
  margin-top: 0.1rem;
}

/* ---------- Mobile navigation: a drawer ---------- */
/* The desktop nav is a row of links with hover dropdowns. Neither half of that
   survives a phone: there is no hover, and stacked into the flow it became a
   260px wall of interleaved parents and children that pushed the page content
   off the fold. Below the breakpoint it becomes a panel that slides in over the
   page instead, with its own title bar and a dimmed backdrop.

   The markup is the same markup - one set of links to keep correct - and the
   parts that only make sense in the drawer are hidden above the breakpoint. */
.nav__toggle, .nav__head, .nav__scrim, .nav__foot { display: none; }

@media (max-width: 60rem) {
  /* Brand on the left, button on the right, one row. `nowrap` plus a brand that
     may shrink is what keeps the button beside the logo rather than wrapping
     onto a line of its own underneath it. */
  .header__inner { flex-wrap: nowrap; align-items: center; gap: 0.75rem; }
  .brand { min-width: 0; }

  .nav__toggle {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.28rem;
    width: 2.75rem;
    height: 2.75rem;
    padding: 0.6rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper);
    cursor: pointer;
    flex: none;
  }
  .nav__toggle-bar {
    display: block;
    height: 2px;
    background: var(--navy);
    border-radius: 2px;
    transition: transform 0.18s ease, opacity 0.18s ease;
  }
  .nav__toggle:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

  /* Turns into a cross while open, so the button says what it will do next. */
  .nav__toggle[aria-expanded="true"] .nav__toggle-bar:nth-child(1) { transform: translateY(0.44rem) rotate(45deg); }
  .nav__toggle[aria-expanded="true"] .nav__toggle-bar:nth-child(2) { opacity: 0; }
  .nav__toggle[aria-expanded="true"] .nav__toggle-bar:nth-child(3) { transform: translateY(-0.44rem) rotate(-45deg); }

  /* Both of these are position:fixed siblings inside the header. The scrim comes
     after the drawer in the markup, so without the pair of z-indexes it painted
     its 55% navy straight over the panel and the whole menu came out washed
     grey with the page showing through it. */
  .nav__scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1;
    background: rgba(10, 24, 54, 0.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.26s ease;
  }

  /* Closed: parked off the right edge and `visibility: hidden`, which takes the
     links out of the tab order on their own - `inert` (set by mobile_nav.js) is
     the belt to that pair of braces. Visibility rather than `display: none`
     because display cannot be transitioned, and the slide is most of what makes
     this read as a drawer rather than a page that suddenly changed. */
  .nav {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(20rem, 82vw);
    z-index: 2;
    display: flex;
    flex-direction: column;
    background: var(--paper);
    box-shadow: -1.25rem 0 3rem rgba(10, 24, 54, 0.28);
    transform: translateX(100%);
    visibility: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s linear 0.26s;
  }

  html.nav-open .nav {
    transform: none;
    visibility: visible;
    transition: transform 0.26s cubic-bezier(0.4, 0, 0.2, 1), visibility 0s;
  }
  html.nav-open .nav__scrim { opacity: 1; pointer-events: auto; }

  /* Both live inside the header, which owns their stacking context - so while
     the menu is open the header has to out-rank the floating WhatsApp button
     (z-index 30) or that would sit on top of the drawer. */
  html.nav-open .header { z-index: 100; }

  /* Without this the page scrolls under your finger while the menu is open. */
  html.nav-open, html.nav-open body { overflow: hidden; }

  .nav__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex: none;
    padding: 0.85rem 1.15rem;
    background: var(--navy);
    position: sticky;
    top: 0;
    z-index: 1;
  }
  .nav__head-title {
    font-size: 0.68rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.16em;
    color: var(--gold);
  }
  .nav__close {
    width: 2.1rem;
    height: 2.1rem;
    flex: none;
    display: grid;
    place-items: center;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
  }
  .nav__close:hover { background: var(--gold); color: var(--navy); }
  .nav__close:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

  .nav__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-bottom: 1.5rem;
  }
  .nav__list > li + li { border-top: 1px solid var(--line); }

  .nav__list > li > a {
    display: block;
    padding: 0.95rem 1.15rem;
    font-size: 0.82rem;
    border-left: 3px solid transparent;
    transition: background 0.15s ease, border-color 0.15s ease;
  }
  .nav__list > li > a:hover,
  .nav__list > li > a:focus-visible {
    background: var(--shell);
    color: var(--gold);
    border-left-color: var(--gold);
  }

  /* A parent is a heading for the group under it, not something to tap: there is
     no page behind it, and on a touch screen nothing would happen if you tried. */
  .nav__group > span {
    display: block;
    padding: 1.05rem 1.15rem 0.4rem;
    font-size: 0.66rem;
    letter-spacing: 0.14em;
    color: var(--muted);
    cursor: default;
  }
  .nav__group > span::after { content: ""; }

  .nav__sub {
    position: static;
    display: block;
    background: none;
    box-shadow: none;
    border: 0;
    border-radius: 0;
    min-width: 0;
    margin: 0 1.15rem 0.75rem;
    padding: 0;
    border-left: 2px solid var(--line);
  }
  .nav__sub a {
    padding: 0.55rem 0.9rem;
    font-size: 0.88rem;
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  }

  /* `margin-top: auto` inside the column pins this to the bottom of the panel
     when the links do not fill it, and lets it scroll away with them when they
     do - so there is no dead white half-screen either way. */
  .nav__foot {
    display: grid;
    gap: 0.5rem;
    flex: none;
    margin-top: auto;
    padding: 1.1rem 1.15rem 1.3rem;
    border-top: 1px solid var(--line);
    background: var(--shell);
    text-align: center;
  }
  .nav__cta { justify-content: center; }
  .nav__alt, .nav__signout button, .nav__contact {
    font: inherit;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--navy);
    text-decoration: none;
    background: none;
    border: 0;
    padding: 0.4rem;
    cursor: pointer;
  }
  .nav__contact {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    font-weight: 500;
    color: var(--muted);
    font-size: 0.8rem;
  }
  .nav__alt:hover, .nav__signout button:hover, .nav__contact:hover { color: var(--gold); }
}

/* With scripting off the drawer can never be opened, so the menu would be
   unreachable on a phone. This puts the nav back in the flow as a plain stacked
   list - what it was before the drawer existed.
 *
 * `(scripting: none)` rather than a <noscript><style> block, which is what this
 * was first written as. htmx parses swapped-in HTML with scripting disabled, so
 * after any boosted navigation the browser treated the noscript contents as
 * live markup: the fallback stylesheet came into force on a page that does have
 * JavaScript, and the menu button vanished from the second page onwards. A
 * media query cannot be smuggled into effect that way.
 *
 * A JS-set class on <html> would be the other way round, but the script is
 * deferred, so on a phone the full menu could paint expanded before it ran. */
@media (max-width: 60rem) and (scripting: none) {
  .header__inner { flex-wrap: wrap; }
  .nav__toggle, .nav__head, .nav__scrim, .nav__foot { display: none; }
  .nav {
    position: static; visibility: visible; transform: none;
    width: auto; flex: 0 0 100%; box-shadow: none; overflow: visible;
    border-top: 1px solid var(--line); margin-top: 0.5rem;
  }
}

/* The name is 39 characters. Left at its full size it took three lines on a
   360px screen and the header alone was 177px - a quarter of the viewport gone
   before the page started. */
@media (max-width: 30rem) {
  .brand { gap: 0.6rem; }
  .brand__logo, .brand__mark { width: 2.6rem; height: 2.6rem; }
  .brand__name { font-size: calc(1.02rem * var(--heading-scale)); }
  .brand__tagline { font-size: 0.66rem; }
  .header__inner { padding-block: 0.85rem; }
}

/* ---------- Top bar on narrow screens ---------- */
/* Six kinds of thing compete for one strip: address, email, phone, account
   links, social icons and the language switcher. At full width they fit on one
   line; on a phone they wrapped into two ragged rows with no relationship to
   each other. Rather than shrink everything until it fits, each row is given a
   job and the things that duplicate something else on the page are dropped. */
@media (max-width: 48rem) {
  .topbar { font-size: 0.74rem; }
  .topbar__inner {
    gap: 0; padding-block: 0.15rem;
    flex-direction: column; align-items: stretch;
  }

  /* Row one: the two things that are actually tappable. The address is the one
     item here nobody taps on a phone, and it is in the footer in full. */
  .topbar__contact {
    justify-content: center; gap: 0.35rem 1.4rem;
    padding-block: 0.45rem;
  }
  .topbar__contact li:first-child { display: none; }

  /* Row two: who you are and what language you are reading, separated from the
     row above by a hairline so the two stop reading as one wrapped list. */
  .topbar__actions {
    justify-content: center; gap: 0 1.1rem;
    padding-block: 0.45rem;
    border-top: 1px solid rgba(255, 255, 255, 0.09);
  }

  /* "Follow Us:" costs a line and says nothing the icons do not - and the icons
     themselves are in the footer at a comfortable size, so the strip keeps the
     account links and the language instead. */
  .topbar__follow, .topbar .social { display: none; }

  /* A 12px link on a 44px-minimum touch target: the padding is the target, and
     without it these are two words you have to aim at. */
  .topbar__link, .topbar__logout button, .langswitch a, .langswitch span {
    padding-block: 0.3rem;
  }
}

/* ---------- Footer on narrow screens ---------- */
/* Stacked, the columns run together: gold heading, some text, gold heading, some
   text, with nothing to say where one ends. On a wide screen the columns do that
   job by sitting side by side. Here a hairline does it instead, and the spacing
   is opened up to match - a footer is the one place on a phone with no reason to
   be cramped, because nothing is competing for the room. */
@media (max-width: 48rem) {
  .footer { padding-top: 2.25rem; }

  /* Two columns, with the brand across the top of them.
   *
   * `auto-fit` was left to decide this and put three sections into a ragged 2x2
   * with the brand beside the contact block, so it was pinned to one column -
   * which then left Contact and Quick Links each alone on a line with half the
   * width empty beside them. Neither is a list of more than a few short items.
   *
   * Stated explicitly in both directions, because the failure mode of letting
   * the grid choose is a layout that changes shape with the content. */
  .footer__inner { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0; }
  .footer__brand { grid-column: 1 / -1; }

  /* The space between the two columns is padding, not a grid gap. A gap leaves a
     notch in the divider that runs above them, so what should read as one rule
     across the footer came out as two dashes with a hole in the middle.
     The brand is always first and spans the row, so the odd-numbered sections
     after it are the ones in the right-hand column. */
  .footer__col:nth-child(odd):not(.footer__brand) { padding-left: 1.5rem; }

  .footer__col + .footer__col {
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    margin-top: 1.5rem;
    padding-top: 1.5rem;
  }

  /* Bigger circles: 2.1rem is 32px, and a touch target should be nearer 44. */
  .footer .social--footer { margin-top: 1.5rem; gap: 0.65rem; }
  .social--footer a { width: 2.6rem; height: 2.6rem; }
  .social--footer .social__svg, .social--footer .social__img { width: 1.2rem; height: 1.2rem; }

  /* Same reason: these are the two links most likely to be tapped from a phone. */
  .footer__contact { padding-block: 0.15rem; }
  .footer ul { gap: 0.7rem; }

  /* Centred, because two left-aligned lines of small print under a full-width
     rule look like the start of another column rather than the end of the page.
   *
   * The bottom padding is for the floating WhatsApp button. It is fixed to the
   * bottom-right of the viewport, so at the end of the page - which is exactly
   * where this line sits - it covers the tail of the copyright permanently,
   * rather than only while you happen to be scrolled past something. Reserving
   * the band it occupies is the only thing that helps: no amount of wrapping
   * moves text out from under a fixed element. */
  .footer__bottom {
    margin-top: 1.9rem;
    justify-content: center;
    text-align: center;
    gap: 0.3rem;
    padding-bottom: 3.75rem;
  }
}

/* Only on the very narrowest phones do the account links and the language
   switcher stop sharing a line. They move into the menu drawer, where they are
   already repeated as full-width buttons, rather than wrapping to a third row.
   Note `rem` in a media query is always 16px - it does not follow the root size
   this stylesheet sets - so 20rem is 320px whatever the type scale is doing. */
@media (max-width: 20rem) {
  .topbar__actions .topbar__link, .topbar__logout { display: none; }
}
