/*
 * WSSET.
 *
 * Two kinds of page share this stylesheet and they need opposite things.
 *
 * A page carried over from the old site arrives with its own CSS, written
 * by hand into Elementor's HTML widgets: 199 kB of it across 23 pages, and
 * 2,490 class attributes for it to describe. That CSS is not ours to
 * rewrite, so nothing here may reach into it. Those pages carry the class
 * `ported` on `main` and this stylesheet leaves them alone.
 *
 * A page written for the new site carries `native`, and everything below
 * the head is written to look like the pages next to it. The measurements
 * are taken from the old site's own CSS rather than chosen: a section is
 * 80px of air, a heading is Roboto 40/900 in the navy, a label above it is
 * 11px at 0.15em in the green, a button is a 40px pill, a card is a 20px
 * corner on a #e8e8e8 hairline. Where a number here looks arbitrary it was
 * copied.
 *
 * ---- The palette -------------------------------------------------------
 *
 * These are the values the old site actually uses, counted across all 23
 * pages, not derived. Each is measured against white:
 *
 *   navy    #003150   13.5:1   headings, the header, the footer ground
 *   green   #04633C    7.4:1   labels, links, the accent rule
 *   body    #444444    9.7:1   running text, as the old site sets it
 *   red     #F80013    4.2:1   FAILS AA for normal text. Decorative only:
 *                              the logo. Never a link, never a paragraph.
 *   muted   #666666    5.7:1   dates and captions
 *   rule    #E8E8E8    1.2:1   borders. Not text, so contrast does not apply.
 *   tint    #F8F9FB            panels
 *
 * ---- The fonts ---------------------------------------------------------
 *
 * Roboto and Inter, published under exactly those names. The ported pages
 * ask for `font-family: 'Roboto', sans-serif` in CSS we do not control, so
 * a family called "Roboto WSSET" is a family they never find: every ported
 * page fell back to the reader's system sans until these were renamed.
 *
 * Both are self-hosted and subset to Latin, Latin Extended and Vietnamese.
 * Vietnamese costs 29 kB across the five files, measured, and buys members'
 * names being set in the same font as the words around them. Inter unsubset
 * is 600 kB on its own.
 *
 * Weights 600 and 800 are not shipped. The ported pages ask for both, and
 * CSS rounds a missing 600 up to 700 and a missing 800 up to 900, which is
 * what those pages get from Google Fonts today.
 *
 * Chinese is deliberately not a downloaded font. A CJK webfont is several
 * megabytes and shipping one to China over a link that is already slow
 * would be worse than using the font already on the reader's machine, which
 * is what the stack below does.
 *
 * Nothing here loads from anywhere but this server. No Google Fonts, no
 * CDN, no icon font, no analytics. Google Fonts fails outright on Chinese
 * consumer broadband and hangs the page while it fails.
 */

/* ------------------------------------------------------------- fonts ---- */

@font-face {
  font-family: "Roboto";
  src: url("../fonts/web/Roboto-400.d03791ddded2.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("../fonts/web/Roboto-500.2fa0b657d4cb.woff2") format("woff2");
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("../fonts/web/Roboto-700.7b126fb3a061.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Roboto";
  src: url("../fonts/web/Roboto-900.e7a35eb4d44b.woff2") format("woff2");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter";
  src: url("../fonts/web/InterVariable.28759141255d.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

/* ------------------------------------------------------------ tokens ---- */

:root {
  --navy: #003150;
  --green: #04633C;
  --red: #F80013;

  --ink: #111111;
  /* Near-black running text. It was #444, a soft grey that reads as a
     product page. Harvard sets body at #1E1E1E and Oxford at a warm grey,
     and the difference between grey and near-black is most of the
     difference between "marketing" and "record". */
  --body: #1A1A1A;
  /* Muted text and the hairline rule are tints of the navy, like the
     ground below. They were #5C5C5A and #E3E3DF, warm greys from no brand
     document. Each is the navy mixed with white to the same lightness as
     the grey it replaced, so contrast is unchanged: muted text is 6.7:1
     on white and 6.4:1 on the tint, as before. James, 11 September 2026:
     "stick to the branding". */
  --muted: #3b6078;
  --rule: #dde4e8;
  /* THE ONE LIGHT GROUND, AND IT IS A TINT OF THE NAVY.
     It was #F4F4F2, a warm grey chosen as "the ground of paper". It
     appears in no brand document. The brand gives navy, green, red and
     white, and says the neutrals are to be derived as tints of the navy
     "so the palette reads as one system". The ported pages already use
     #f8f9fb, which is one, so running both put two light grounds on one
     page. James caught it twice. `GroundTests` in apps/cms/tests/test_design.py
     now fails on any other light neutral in the site's stylesheets. */
  --tint: #f8f9fb;
  --ground: #FFFFFF;

  /* The two families the ported pages name, with the reader's own CJK
     faces behind them. See the note at the top. */
  --display: "Roboto", "Helvetica Neue", Arial,
             "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
             "Noto Sans CJK SC", sans-serif;
  --text: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI",
          "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
          "Noto Sans CJK SC", sans-serif;

  /* 1100px with 40px either side, which is what every ported section uses.
     A page written here sits in the same column as a page ported into it. */
  --spine: 1100px;
  --gutter: 40px;
  --measure: 66ch;

  /* ---- the display scale ------------------------------------------------
     Set once here so that every heading on the site moves together.

     These are the ported pages' own numbers, measured off the home page's
     stylesheet rather than chosen: hero 52/1.0/900, section heading
     40/1.1/900, card title 22/1.2/900, and no tracking.

     They were briefly something else. On 7 September the display weight
     went to 500 with -0.02em of tracking, measured off Oxford (Tiempos
     Headline at 500) and Harvard (Canela Deck at 400), to take the tone
     from playful to serious. Set beside the twelve ported pages the result
     read as thinner rather than graver, and James's judgement on 9
     September was that the pages written for this site "lack the detail,
     care and attention of the original ported pages" and must be kept
     aligned with them.

     So the reference is the Society's own site, not Oxford's. What survives
     from that pass is the part that was never about weight: one sentence a
     point, headings that name the thing, near-black body text, and no
     figure typed into a heading. */
  --display-weight: 900;
  --display-weight-strong: 900;
  --display-tracking: 0;
  --hero: 52px;
  --h1: 40px;
  --h2: 40px;
  --h3: 22px;

  /* ---- shape ------------------------------------------------------------
     Also the ported pages': a 40px pill on a call to action, a 20px card on
     a #f8f9fb ground inside a 1px #e8e8e8 border, a 56px navy tile with a
     16px corner behind an icon, and a 4px lift at
     rgba(0,49,80,0.12) on hover. */
  /* The height of the sticky header: 52 and 62 for the two rows, plus its
     own bottom border. Two things below depend on knowing it, and both are
     invisible failures if it is wrong. */
  --header-h: 115px;

  --radius-pill: 40px;
  --radius-card: 20px;
  --radius-tile: 16px;
  --card: #f8f9fb;
  --card-border: #e8e8e8;
  --lift: 0 12px 40px rgba(0, 49, 80, 0.12);
}

@media (max-width: 900px) {
  :root { --gutter: 24px; }
}

/* Below 1100px the header collapses to one row with a Menu button. */
@media (max-width: 1100px) {
  :root { --header-h: 89px; }
}

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

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

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

/* The footer sits at the foot of the window on a short page rather than
   halfway up it with white below. */
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--ground);
  color: var(--body);
  font-family: var(--text);
  font-size: 18px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  font-feature-settings: "kern" 1, "liga" 1;
}

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

.native a, .site-foot a {
  color: var(--green);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
.native a:hover { color: var(--navy); }

/* Visible focus everywhere. Members navigate this on every kind of machine
   and a focus ring that only shows on some of them is not a focus ring. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--green);
  outline-offset: 2px;
  border-radius: 2px;
}

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

.spine {
  max-width: var(--spine);
  margin: 0 auto;
  padding-inline: var(--gutter);
}

/* An anchor link under a sticky header lands with its target hidden behind
   the header, and the reader is shown the end of the previous section
   instead of the start of the one they asked for. The site is full of them:
   the conference page's year grid, the journals page's nine anchors, every
   "what is SET?" in the footer. */
:target,
[id] { scroll-margin-top: calc(var(--header-h) + 16px); }

.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  position: static;
  display: inline-block;
  margin: 0.5rem;
  padding: 0.5rem 0.9rem;
  background: var(--navy);
  color: #fff;
}

/* -------------------------------------------------------------- head ----
 *
 * Rebuilt to match wsset.org, by measurement rather than by eye. The logo
 * sits on the left across the full height and the two rows of navigation
 * stack to its right: 62px above, 73px below, a 1450px container, and
 * navigation in Inter 14/500 at #003150 with 14px either side.
 */

/* Sticky. The membership page is 4,955 pixels tall and the news page 3,300,
   and on a page that long a reader who wants another section has to go back
   to the top to find one. The rows were trimmed from 62 and 73 to 52 and 62
   to pay for it: 115px of a 900px window is a header, 136px is a lid.

   Nothing here needs JavaScript, and nothing about it shrinks on scroll,
   which would. */
.masthead {
  background: #fff;
  border-bottom: 1px solid var(--rule);
  position: sticky;
  top: 0;
  z-index: 20;
}
.masthead__inner {
  max-width: 1450px;
  margin: 0 auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  gap: 2rem;
}

.masthead__logo { display: block; flex: none; }
.masthead__logo img { display: block; width: 250px; height: 80px; }

.masthead__rows {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}
.masthead__row {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  min-height: 52px;
}
.masthead__row--main { min-height: 62px; }

/* The two rows end on the same vertical line. Both were right-aligned, but
   the navigation's last link carried 14px of padding past its text while
   the search box ended at its own border, so the right margin was ragged by
   exactly that much. */
.masthead__row--main .nav-main__list > li:last-child > a { padding-right: 0; }
.masthead__row--utility .masthead__search { margin-right: 0; }

/* Both rows in the site's display face rather than its text face. Every
   heading on every page is Roboto; the header was the one piece of
   furniture set in Inter, and next to the pages under it that read as
   borrowed. The two rows are then separated by weight rather than by
   family: the utility row is quiet at 400, the main row carries the site
   at 700. Roboto ships here at 400, 500, 700 and 900, so both are real
   weights and neither is synthesised. */
.nav-utility a,
.nav-utility__account,
.nav-main__list > li > a {
  font-family: var(--display);
  font-size: 14px;
  font-weight: 400;
  line-height: 30px;
  color: var(--navy);
  padding: 0 14px;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  white-space: nowrap;
}
.nav-utility a:hover,
.nav-utility__account:hover,
.nav-main__list > li > a:hover { color: var(--green); }

.nav-utility { display: flex; flex-wrap: wrap; }

.icon {
  width: 1.15em;
  height: 1.15em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  flex: none;
}

/* The search box was the largest object in the header: 282 by 54 pixels at
   16px, physically bigger than the wordmark beside it and the first thing
   the eye landed on. Search is not what a member came for.
   
   It was not a design choice. `input[type="search"]` in the forms section
   below is an attribute selector, so it weighs the same as
   `.masthead__search input` and, being later in this file, won it: the
   header's own 14px and its padding were overridden by the 16px and the
   13px by 16px meant for a form field on a page. Named by type here so the
   header outranks it. */
.masthead__search { display: flex; align-items: center; margin-left: 0.6rem; }
.masthead__search input[type="search"] {
  font-family: var(--text);
  font-size: 13px;
  width: 172px;
  height: 34px;
  padding: 0 10px;
  border: 1px solid var(--rule);
  border-right: 0;
  border-radius: 0;
  background: #fff;
  color: var(--body);
}
.masthead__search input[type="search"]::placeholder { color: var(--muted); }
.masthead__search input[type="search"]:focus { border-color: var(--green); }
.masthead__search button[type="submit"] {
  font: inherit;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: 1px solid var(--rule);
  border-left: 0;
  border-radius: 0;
  background: #fff;
  color: var(--muted);
  cursor: pointer;
}
.masthead__search button[type="submit"]:hover { color: var(--green); }

/* The caret on an item that has a dropdown, drawn rather than fetched: an
   icon font would be another request from another host. */
.nav-main__caret {
  display: inline-block;
  width: 0.42em;
  height: 0.42em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-0.18em) rotate(45deg);
}

.nav-main__list {
  display: flex;
  flex-wrap: wrap;
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}
.nav-main__item { position: relative; margin: 0; }
.nav-main__list > li > a { font-weight: 700; letter-spacing: 0.01em; }

/* The item fills the row rather than just its own line of text, so that
   `top: 100%` on the panel below is the bottom edge of the header and not
   the bottom edge of a 30px link floating inside it. That is what lets the
   panel sit flush against the header instead of hovering four pixels under
   the words. */
/* `align-items: center` on the row makes each child as tall as its own
   content, so `height: 100%` on the navigation resolved to the height of a
   30px line of text and the panel opened seventeen pixels above the bottom
   of the header, overlapping it. The row stretches its children instead,
   and the items centre their own text. */
/* Stretched all the way down, by flex rather than by percentage.
   `height: 100%` looked like the obvious way and does not work here: the
   row's height comes from `min-height`, which is not a definite height for
   a percentage to resolve against, so the navigation fell back to the
   height of its own text and the panel opened well above the header's
   bottom edge. Each level stretches its children instead, and only the
   items themselves centre their text. */
.masthead__row--main { align-items: stretch; }
.nav-main { display: flex; }
.nav-main__list { align-items: stretch; }
.nav-main__item { display: flex; align-items: center; }

/* The dropdown, with no JavaScript. :focus-within is what makes it
   reachable from a keyboard, which Astra's version manages with a script.

   It was a rounded card on a soft drop shadow, which is the shape every web
   application gives a menu and the last piece of that idiom left on the
   site. It is now a flat panel: square, hung off the header's own edge, a
   hairline round it and a 2px green rule across the top to say which item
   it belongs to. No shadow. The rows carry a green edge on hover rather
   than changing colour, which is the same device the ruled lists use. */
.nav-main__sub {
  position: absolute;
  top: 100%;
  left: 0;
  min-width: 17rem;
  background: #fff;
  border: 1px solid var(--rule);
  border-top: 2px solid var(--green);
  border-radius: 0;
  list-style: none;
  margin: 0;
  padding: 6px 0;
  max-width: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.12s ease;
  z-index: 30;
}
.nav-main__item:hover > .nav-main__sub,
.nav-main__item:focus-within > .nav-main__sub {
  opacity: 1;
  visibility: visible;
}
.nav-main__sub li { margin: 0; }
.nav-main__sub a {
  display: block;
  padding: 10px 20px;
  font-family: var(--text);
  font-size: 15px;
  line-height: 1.45;
  color: var(--navy);
  text-decoration: none;
  white-space: nowrap;
  box-shadow: inset 0 0 0 0 var(--green);
  transition: background .15s ease, box-shadow .15s ease;
}
.nav-main__sub a:hover,
.nav-main__sub a:focus-visible {
  background: var(--tint);
  color: var(--navy);
  box-shadow: inset 2px 0 0 0 var(--green);
}

/* The last two dropdowns hang off the right-hand end of the navigation, so
   a left-aligned panel pushes the whole document wider than the window and
   every page on the site scrolls sideways. A hidden element still counts
   towards the scroll width. */
.nav-main__item:nth-last-child(-n+2) > .nav-main__sub { left: auto; right: 0; }

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

/* The menu button belongs to the phone layout only. Above 1100px the
   navigation is always there, so neither the checkbox nor its label exists
   as far as the reader is concerned. */
.masthead__state { position: absolute; opacity: 0; width: 1px; height: 1px; }
.masthead__toggle { display: none; }

@media (max-width: 1100px) {
  .masthead__inner { flex-wrap: wrap; gap: 0.75rem; padding-block: 0.75rem; }

  /* Collapsed by default. Expanded, the whole menu is there at once, with
     the sub-lists open: somebody who has just asked for the menu wants to
     see what is in it, and an accordion inside an accordion is two taps to
     reach a page. */
  .masthead__toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    margin-left: auto;
    padding: 0.55rem 1rem;
    font-family: var(--text);
    font-size: 14px;
    font-weight: 500;
    color: var(--navy);
    border: 1px solid var(--rule);
    border-radius: 0;
    cursor: pointer;
  }
  .masthead__state:focus-visible + .masthead__logo + .masthead__toggle {
    outline: 3px solid var(--green);
    outline-offset: 2px;
  }
  .masthead__rows { display: none; }
  /* The open menu is 1,432px of links on a phone. That was fine while the
     header scrolled with the page; once it was made sticky the header was
     pinned and everything past the fold became unreachable, so the last
     four items in it could not be tapped at all. It now takes what is left
     of the window and scrolls inside itself.

     `dvh` rather than `vh` because on a phone `vh` is the window with the
     browser's own chrome ignored, which is the height it is not. The `vh`
     line above it is the fallback for anything that does not know `dvh`. */
  .masthead__state:checked ~ .masthead__rows {
    display: flex;
    /* The 12px is the inner's own bottom padding at this width, which sits
       below the rows and is part of the header's height too. Without it the
       menu overhangs the window by exactly that much. */
    max-height: calc(100vh - var(--header-h) - 12px);
    max-height: calc(100dvh - var(--header-h) - 12px);
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* `flex: 1` gives this a basis of zero, so it never wraps onto its own
     line however narrow the window gets: it just stays beside the logo and
     pushes its navigation off the right-hand edge, which made every page on
     the site scroll sideways on a phone. A basis of 100% is what wraps. */
  .masthead__rows { flex: 1 0 100%; align-items: flex-start; }
  .masthead__row { min-width: 0; }
  .nav-main, .nav-utility, .nav-main__list { min-width: 0; max-width: 100%; }
  .masthead__row { min-height: 0; flex-wrap: wrap; padding-block: 0.35rem; }
  .masthead__logo img { width: 200px; height: 64px; }
  /* Each row keeps its own height. The rows are flex items in a column
     whose height the window caps, so with the default `flex-shrink: 1`
     both of them were squashed to fit it: the utility row measured 95px
     with 189px inside it, and its last two lines, the account link and the
     search box, were drawn on top of the navigation underneath. The rows
     do not shrink. The menu scrolls. */
  .masthead__rows > .masthead__row { flex: none; }

  /* The search box takes its own line, the full width of the menu. The
     `width: 100%` that used to be here was written as `.masthead__search
     input`, one class and one type, and lost to the
     `.masthead__search input[type="search"]` above it, one class and one
     attribute: the box stayed 172px wide and hung off the right-hand edge
     of a 390px window. Named the same way here so it wins. */
  .masthead__row--utility { width: 100%; row-gap: 0.15rem; }
  .masthead__search { flex: 1 0 100%; margin-left: 0; margin-top: 0.4rem; }
  .masthead__search input[type="search"] { width: 100%; height: 40px; }
  .masthead__search button[type="submit"] { width: 40px; height: 40px; }

  .nav-main__sub {
    position: static;
    opacity: 1; visibility: visible; transform: none;
    box-shadow: none; border: 0; padding: 0 0 0.5rem; min-width: 0;
  }

  /* A column at each level, which is what makes this a menu.

     An item is a flex row, because above this width the panel is
     absolutely positioned and the row is what lets it hang off the bottom
     edge of the header. Here `position: static` puts the panel back into
     flow, which made it a flex sibling sitting to the right of its own
     parent link, the parent centred against a column of children.
     Measured on wsset.org at 390px: "About Us" sat 100px down its own
     section with its five pages in a column beside it, "Get Involved" and
     "SET Conferences" broke over two lines with half the window empty, and
     at 820px the list's own `flex-wrap` packed two of those blocks side by
     side, so the menu read as four ragged columns rather than as a list. */
  .nav-main { display: block; width: 100%; }
  .masthead__row--main {
    width: 100%;
    border-top: 1px solid var(--rule);
    padding-top: 0.5rem;
  }
  .nav-main__list { flex-direction: column; flex-wrap: nowrap; width: 100%; }
  .nav-main__item { flex-direction: column; align-items: stretch; }
  .nav-main__item + .nav-main__item { border-top: 1px solid var(--rule); }

  /* 44px is the smallest target a finger hits reliably, and every link in
     the open menu was 30px. The rule above each section does the
     separating, so the sections need no gaps of their own. */
  .masthead__row--main .nav-main__list > li > a {
    display: flex;
    min-height: 44px;
    padding: 0.7rem 0;
    font-size: 15px;
    line-height: 1.35;
  }
  .nav-main__sub a {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0.5rem 0 0.5rem 1rem;
    font-size: 15px;
    line-height: 1.35;
  }
  .nav-utility a,
  .nav-utility__account {
    min-height: 44px;
    padding: 0.5rem 1.4rem 0.5rem 0;
    line-height: 1.35;
  }

  /* The sub-lists are open at this width, so a caret pointing at an
     expander that is not there tells the reader something untrue. */
  .nav-main__caret { display: none; }

  /* Nothing in the navigation may refuse to wrap once the window is
     narrower than the longest item in it. "Special Interest Groups (SIGs)"
     is 367px on its own. */
  .nav-main__sub a, .nav-main__list > li > a { white-space: normal; }
}

/* On a tablet the menu is 1,483px tall in one column, which is more than
   the window, and 899px in two, which is not: the whole of it is there
   without scrolling. Two columns are offered only where a column is still
   wide enough for "International Journal of Low-Carbon Technologies" on
   one line, which is 700px of window. A section is never broken across the
   column break. */
@media (min-width: 700px) and (max-width: 1100px) {
  .nav-main__list { display: block; columns: 2; column-gap: 3rem; }
  .nav-main__item { display: block; break-inside: avoid; padding-block: 0.25rem; }
  .nav-main__item + .nav-main__item { border-top: 0; }
  .masthead__row--main { border-top: 0; padding-top: 0; }
  .masthead__row--main .nav-main__list > li > a {
    border-top: 1px solid var(--rule);
  }
}

/* An id the old site's links point at, with nothing of its own to show.

   `/membership/#registration` and `/get-involved/#special-interest-groups`
   were in the old site's menus, so they are in bookmarks and in mail the
   Society sent. A server never sees a fragment, so a redirect cannot reach
   them: the id has to be on the page they land on. It is an empty span
   rather than an id moved onto the section, because the section already has
   one that the site's own links use, and a heading can only answer to one
   name. `scroll-margin-top` clears the sticky masthead, the same as every
   other target on the site. */
.anchor-was {
  display: block;
  height: 0;
  scroll-margin-top: calc(var(--header-h, 115px) + 12px);
}

/* ----------------------------------------------------------- content ----
 *
 * Everything from here to the footer is scoped to `.native`. It styles the
 * pages written for this site: the news, the member's own pages, signing
 * in, the contact form, the code of conduct, verifying a certificate.
 *
 * None of it may apply to a ported page. Those arrive with 199 kB of their
 * own CSS describing their own markup, and putting a measure, a type scale
 * and a link colour on top of them is what turned the navy full-bleed hero
 * into a white column the first time round.
 */

/* ------------------------------------------------- the news strip ------
 *
 * DELIBERATELY UNPREFIXED, and the only thing in this file that is.
 *
 * Everything below the "written for this site" banner is written with a
 * `.native` prefix so that it cannot reach inside a ported page. That is a
 * convention held by every selector, not a wrapper. This section IS inside
 * a ported page, because it is a block an editor drops into the home page,
 * whose body is seven pieces of the old site's own HTML. Prefixed, its
 * rules would never apply and the strip would render as unstyled markup in
 * the middle of the front page. Safe because every class here is
 * `wsset-hp-`, which appears nowhere in the 33kB of CSS that page brought
 * with it. Checked, not assumed.
 *
 * WHAT THIS IS AND WHY.
 *
 * A front page, not a grid. One story carries the photograph, in the idiom
 * James wrote for the conference cards further down the same page; two
 * more sit beside it as lines with a thumbnail, divided by a rule. Nothing
 * is the same size as anything else, which is what stops it reading as a
 * block.
 *
 * James, 10 September 2026: "i still think the latest news on the homepage
 * is very poor and lacks imagination, feels blocky and doesn't connect
 * with sections above and below... more space efficient and engaging."
 *
 * It connects because there are now three grounds in a row rather than
 * two: navy hero, warm tint here, white pillars beneath. Before, a white
 * band sat between a navy hero and a white section, so it had only one
 * edge and its 80px of padding met the pillars' 80px as 160px of nothing.
 * A tinted band has two edges and needs less air inside it, because the
 * ground is doing the separating.
 *
 * 797px became about 460, carrying more: a 500px photograph instead of
 * three 320px ones, and three headlines instead of three headlines with
 * three standfirsts under them that nobody reads on a front page.
 */
/* THE GROUND IS THE HOME PAGE'S OWN.
 *
 * It was #F4F4F2, the warm neutral this stylesheet then used for its own
 * panels, and which is now gone from them too. Wrong here, and James asked the right question: this band sits
 * inside a ported page, and that page has exactly one light ground of its
 * own, #f8f9fb, which it uses for the pillar cards and the journal cards.
 * A third neutral on one page is a third neutral.
 *
 * It is also the right direction by the brand guidelines, which give only
 * navy, green, red and white and say the neutrals "need deriving...
 * proposal: tints of the navy rather than pure greys, so the palette reads
 * as one system". #f8f9fb is a navy tint. #F4F4F2 is a warm grey and
 * belongs to nothing.
 *
 * SPACING. 60px top and bottom, which is three quarters of the 80px every
 * section on this page opens and closes with. A ribbon should be visibly
 * tighter than a section, and three quarters is a ratio rather than a
 * number somebody liked. The column gap is 32px, which is the gap the
 * journals grid on this same page uses.
 */
.wsset-hp-news {
  padding: 60px 0;
  background: #f8f9fb;
  font-family: 'Inter', sans-serif;
}
.wsset-hp-news-inner {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 40px;
}

/* The label and the link on one line, with a rule under them. The rule is
   what makes the band read as one thing rather than as three loose items,
   and it costs 1px where a heading costs 60. */
.wsset-hp-news-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 16px;
  margin-bottom: 28px;
  border-bottom: 1px solid #e2e7ec;
}
.wsset-hp-news-label {
  font-family: 'Roboto', sans-serif;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #04633C;
}
.wsset-hp-news-link {
  font-family: 'Roboto', sans-serif;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: #003150;
  text-decoration: none;
  white-space: nowrap;
  transition: color 0.2s ease;
}
.wsset-hp-news-link:hover { color: #04633C; }

.wsset-hp-news-row {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: 32px;
}

/* THE LEAD. The photograph is the card and the headline is set on it, the
   same device as `.wsset-prev-conf-card` and `.gtile`: 20px corner, the
   picture scaling on hover, a three-stop navy gradient under the words. */
.wsset-hp-lead {
  position: relative;
  display: block;
  /* 2:1 of its own width. The column is 7fr of 1020 less the 32px gap,
     which is 595px, and 595 halved is 297. A letterbox is the editorial
     crop for a lead picture, and it decides the height of the two items
     beside it rather than a number being picked for them. */
  height: 300px;
  border-radius: 20px;
  overflow: hidden;
  text-decoration: none;
}
.wsset-hp-lead-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.5s ease;
}
.wsset-hp-lead:hover .wsset-hp-lead-img { transform: scale(1.05); }
.wsset-hp-lead::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top,
    rgba(0, 49, 80, 0.95) 0%,
    rgba(0, 49, 80, 0.6) 48%,
    rgba(0, 49, 80, 0.05) 100%);
  transition: background 0.3s ease;
}
.wsset-hp-lead:hover::after {
  background: linear-gradient(to top,
    rgba(0, 49, 80, 0.97) 0%,
    rgba(0, 49, 80, 0.72) 48%,
    rgba(0, 49, 80, 0.14) 100%);
}
.wsset-hp-lead-body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 28px;
}
.wsset-hp-lead-head {
  display: block;
  font-family: 'Roboto', sans-serif;
  font-size: 27px;
  font-weight: 900;
  line-height: 1.16;
  color: #ffffff;
  margin-top: 8px;
}

/* THE OTHER TWO. A line each, with a thumbnail, and a rule between them.
   No standfirst: on a front page it is the headline that decides whether
   somebody clicks, and three of them fit where one and a half of the old
   cards did. */
/* Two equal halves of the lead's height, not two items pushed to the top
   and the bottom of it. `space-between` put 150px of nothing between them,
   which is the fault this whole band was rebuilt to remove. */
/* As many equal rows as there are items, so the column is filled rather
   than distributed. Two items left 156px of slack in a 300px column and
   it came out as a gap either side of the rule. */
.wsset-hp-news-rest {
  display: grid;
  grid-auto-rows: 1fr;
}
.wsset-hp-item {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  align-content: center;
  padding: 4px 0;
  text-decoration: none;
  border-top: 1px solid #e2e7ec;
}
/* The first item's top aligns with the top of the photograph and the
   second's foot with the foot of it, so the column reads as one block
   beside the lead rather than as two things floating in the middle of it.
   The rule between them lands halfway down either way. */
.wsset-hp-news-rest .wsset-hp-item:first-child {
  border-top: 0;
  align-content: start;
}
.wsset-hp-news-rest .wsset-hp-item:last-child { align-content: end; }
.wsset-hp-item-img {
  width: 96px;
  height: 66px;
  object-fit: cover;
  display: block;
  border-radius: 10px;
  background: #eef1f5;
}
.wsset-hp-item-head {
  display: block;
  font-family: 'Roboto', sans-serif;
  font-size: 17px;
  font-weight: 700;
  line-height: 1.32;
  color: #003150;
  margin-top: 6px;
  transition: color 0.2s ease;
}
.wsset-hp-item:hover .wsset-hp-item-head { color: #04633C; }

.wsset-hp-news-date {
  display: block;
  font-family: 'Inter', sans-serif;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #6b7480;
}
.wsset-hp-lead .wsset-hp-news-date { color: rgba(255, 255, 255, 0.82); }

/* The lead keeps its picture at every width; the two beside it fall under
   it rather than shrinking into a column too narrow for a headline. */
@media (max-width: 900px) {
  .wsset-hp-news-row { grid-template-columns: 1fr; gap: 26px; }
  .wsset-hp-lead { height: 260px; }
  .wsset-hp-lead-head { font-size: 23px; }
  /* Stacked, the rows size to their own content rather than to half of a
     lead that is no longer beside them. */
  .wsset-hp-news-rest { grid-template-rows: auto auto; }
  .wsset-hp-item { padding: 16px 0; }
}
@media (max-width: 600px) {
  .wsset-hp-news { padding: 48px 0 52px; }
  .wsset-hp-news-inner { padding: 0 24px; }
  .wsset-hp-lead { height: 220px; }
  .wsset-hp-lead-body { padding: 22px; }
  .wsset-hp-lead-head { font-size: 21px; }
  .wsset-hp-item { grid-template-columns: 84px minmax(0, 1fr); gap: 14px; }
  .wsset-hp-item-img { width: 84px; height: 58px; }
}

main { flex: 1 0 auto; }

/* A ported page is a sequence of full-bleed sections that set their own
   vertical rhythm. A written one gets the 80px the ported sections open
   with, so that the two read as the same site. */
main.native { padding-block: 80px 100px; }

/* A written page whose first element supplies its own ground and its own
   air. The 80px of white above would otherwise sit between the header and
   the colour, and read as a mistake. */
main.native--bleed { padding-block: 0; }
main.ported { padding-block: 0; }

@media (max-width: 900px) {
  main.native { padding-block: 56px 72px; }
  main.native--bleed { padding-block: 0; }
}

/* ---- the head of a page ----
 *
 * Label, heading, rule, standfirst. This is the opening of every section
 * on the old site, reduced to four elements and reused here so that a page
 * written for the new site opens the way the ported ones do.
 */

/* Every page ported from the old site opens the same way: a full-bleed
   navy band carrying a letterspaced label, a heading and one sentence.
   Pages written for this site opened on white with the same four elements
   at a quarter of the weight, so the site had two kinds of opening and a
   member could tell which pages were new.

   The band is drawn without leaving the column: a 100vmax box-shadow of
   the same navy, clipped to the band's own height, paints to both edges of
   the window while the words stay inside the 1100px spine. `100vw` would
   have done it too and would have been a horizontal scrollbar on every
   page with a vertical one. */
.page-head {
  position: relative;
  background: var(--navy);
  color: #fff;
  padding: 68px 0 64px;
  margin: -80px 0 64px;
  box-shadow: 0 0 0 100vmax var(--navy);
  clip-path: inset(0 -100vmax);
}

/* Only when it is the first thing on the page. A page that shows a message
   above its heading must not have the band pulled up over the message.

   THIS GUARD COULD NEVER FIRE. `_messages.html` renders its own `.spine`
   wrapper, so the messages are a sibling of the spine holding the heading,
   not a sibling of the heading. The band was therefore still the first
   child of its own spine, still pulled itself up 80px, and still covered
   the message underneath it. Seen on 14 September 2026 on the account page
   after confirming an email address: the second message was sliced in half
   by the navy.

   `:has` asks the question that was meant: is there a message anywhere on
   this page. The selector above is kept for the case where the heading and
   the message share a spine. */
.spine > .page-head:not(:first-child) { margin-top: 0; }

.eyebrow {
  display: block;
  font-family: var(--display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: #ffffff;
  margin: 0 0 16px;
}

/* `.native h1` sets the heading colour later in this file at the same
   weight of specificity, so these are written to outrank it rather than to
   rely on being read first. */
.native .page-head h1, .page-head h1 {
  margin-bottom: 24px;
  color: #fff;
}
.native .page-head .intro,
.native .page-head .intro p,
.page-head .intro { color: rgba(255, 255, 255, 0.86); }
.native .page-head a, .page-head a { color: #fff; }

@media (max-width: 900px) {
  .page-head { padding: 52px 0 48px; margin: -56px 0 48px; }
}

/* The 60 by 3 green rule that sits under every heading on the old site.
   It is an element rather than an ::after, because it belongs between the
   heading and the standfirst rather than at the end of the block. */
.rule {
  display: block;
  width: 60px;
  height: 3px;
  margin: 0 0 24px;
  background: var(--green);
}

.page-head .intro { margin-bottom: 0; }

/* A HEADING WITH NO STANDFIRST UNDER IT LEFT THE RULE FLOATING IN NAVY.
   The band is padded for the standfirst most pages carry. On the four that
   carry none, "Your membership" among them, that padding plus the rule's
   own 24px put 91 pixels of empty colour under a 3 pixel line and 68 above
   the eyebrow, which reads as a band with something missing from it rather
   than as an opening. Closed up to match the space above. */
.page-head:not(:has(.intro)) { padding-bottom: 40px; }
@media (max-width: 900px) {
  .page-head:not(:has(.intro)) { padding-bottom: 30px; }
}

/* A heading that opens a list directly under the filter pills, where the
   56px above an ordinary h2 is more air than the page wants. */
.section-heading { margin-top: 24px; }

/* Signing in, and resetting a password. allauth writes the heading itself,
   so the rule under it is drawn here. These are the most-visited pages on
   the site in the months after cutover: every one of 3,300 imported members
   passes through the password reset once. */
/* allauth writes its own heading into the content block, so the band that
   `.page-head` draws elsewhere is drawn on the heading itself. These are the
   most-visited pages on the site in the months after cutover, and they were
   the last two opening on bare white. */
.native.auth h1, .auth h1 {
  position: relative;
  background: var(--navy);
  color: #fff;
  padding: 68px 0 64px;
  margin: -80px 0 56px;
  box-shadow: 0 0 0 100vmax var(--navy);
  clip-path: inset(0 -100vmax);
}
.auth h1::after {
  content: "";
  display: block;
  width: 60px;
  height: 3px;
  margin: 24px 0 0;
  background: var(--green);
}
.auth form { margin-bottom: 32px; }

@media (max-width: 900px) {
  .auth h1 { padding: 52px 0 48px; margin: -56px 0 44px; }
}

/* An article: the same opening as any other page, then the body. */
.article .meta { margin: 0 0 32px; }
.page-head .meta,
.page-head .meta a,
.page-head .meta time { color: rgba(255, 255, 255, 0.72); margin: 0; }
.page-head .meta a:hover { color: #fff; }
/* The eyebrow on a news item is a <p>, not the <span> the include writes. */
.page-head p.eyebrow { margin: 0 0 16px; }
.back { margin-top: 56px; }

.native h1, .native h2, .native h3, .native h4 {
  font-family: var(--display);
  color: var(--navy);
  margin: 0 0 16px;
}
/* Balanced only on the big ones. In a 340px card it leaves a short second
   line and a hole where the first one should have run on. */
.native h1, .native h2 { text-wrap: balance; }
.native h1 {
  font-size: var(--h1);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.05;
}
.native h2 {
  font-size: 34px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.1;
  margin-top: 64px;
}
.native h3 {
  font-size: var(--h3);
  font-weight: var(--display-weight-strong);
  line-height: 1.25;
  margin-top: 40px;
}
.native h4 {
  font-size: 17px;
  font-weight: 700;
  margin-top: 28px;
}

@media (max-width: 768px) {
  .native h1 { font-size: 32px; }
  .native h2 { font-size: 26px; }
  /* Tracking that closes 44px type up pleasantly cramps 26px type. */
  .native h1, .native h2 { letter-spacing: -0.01em; }
}

.native p, .native ul, .native ol, .native blockquote {
  max-width: var(--measure);
}
.native p { margin: 0 0 20px; }
.native ul, .native ol { margin: 0 0 24px; padding-left: 1.3em; }
.native li { margin-bottom: 8px; }
.native li::marker { color: var(--green); }

.intro {
  font-size: 19px;
  line-height: 1.7;
  color: var(--body);
  max-width: 60ch;
  margin: 0 0 32px;
}
.intro p:last-child { margin-bottom: 0; }

.strapline {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 400;
  color: var(--muted);
  max-width: 50ch;
  margin: -8px 0 32px;
}

.meta {
  font-family: var(--display);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.04em;
  color: var(--muted);
}
.meta a { color: var(--muted); text-decoration: none; border-bottom: 1px solid var(--rule); }
.meta a:hover { color: var(--green); border-bottom-color: var(--green); }

.native blockquote {
  margin: 32px 0;
  padding: 4px 0 4px 24px;
  border-left: 3px solid var(--green);
  font-size: 19px;
  color: var(--navy);
}
.native blockquote p:last-child { margin-bottom: 0; }

.native hr { border: 0; border-top: 1px solid var(--rule); margin: 48px 0; }

code, pre {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 0.92em;
}
code {
  background: var(--tint);
  border: 1px solid var(--rule);
  border-radius: var(--radius-tile);
  padding: 0.05em 0.35em;
}
pre {
  background: var(--tint);
  border: 1px solid var(--rule);
  border-radius: var(--radius-tile);
  padding: 20px 24px;
  overflow-x: auto;
}
pre code { background: none; border: 0; padding: 0; }

.native figure { margin: 32px 0; }
.native figure img { display: block; }
.native figcaption {
  font-size: 14px;
  color: var(--muted);
  margin-top: 12px;
}

/* Wide things scroll inside themselves. The page never scrolls sideways. */
.scroller { overflow-x: auto; max-width: 100%; }

.native table {
  border-collapse: collapse;
  width: 100%;
  font-size: 15px;
  margin-bottom: 32px;
}
.native th, .native td {
  text-align: left;
  padding: 14px 16px;
  border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.native thead th {
  font-family: var(--display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--green);
  background: var(--tint);
}

/* ------------------------------------------------------------ buttons ---
 *
 * The 40px pill, straight off the old site: navy fill, white text, Roboto
 * 15/600, 15px by 40px, a 2px border of its own colour, and a hover that
 * empties the fill rather than darkening it.
 */

/* The pill, as the ported pages draw it: Roboto 15/700, 18px by 48px, a 2px
   border of its own colour, 0.02em of letterspacing, and a hover that
   empties the fill rather than darkening it.

   It was squared to 2px on 7 September, on the reading that a full pill is
   the most consumer-app shape on a page. The twelve ported pages went on
   drawing their own pills from their own CSS, so every call to action on
   the site disagreed with every other one, which is worse than either
   shape. The ported pages are the house style; this follows them.

   MEASURED OFF THE HOME PAGE, 11 September 2026. James: "just match the
   styles used on the home page and old pages, these new pages drifted."
   They had, in three ways. Every button on a new page was the size of the
   home page's hero button, wherever it sat; the ported pages use that
   size in a hero and 15px by 40px everywhere else. The line box was 1.4,
   which drew each one three pixels shorter than its neighbour on a ported
   page. And the outline button had a pale edge where every ported page
   draws it in navy. Now: 24px line, 15 by 40 in a section, 18 by 48 in a
   hero, navy edge, exactly as `wsset-btn-hero-primary`,
   `wsset-btn-set-primary` and `wsset-btn-mem-cta-secondary` are drawn. */
.button, button[type="submit"], input[type="submit"] {
  display: inline-block;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 24px;
  padding: 15px 40px;
  border: 2px solid var(--navy);
  border-radius: var(--radius-pill);
  background: var(--navy);
  color: #fff;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease;
}
.button:hover, button[type="submit"]:hover, input[type="submit"]:hover {
  background: transparent;
  color: var(--navy);
}
.native a.button { color: #fff; }
.native a.button:hover { color: var(--navy); }

/* THE MODIFIERS HAVE TO NAME THE ELEMENT, the same trick `--light` and
   `--ghost` already use further down. The base above is
   `button[type="submit"]`, which an attribute selector puts at (0,1,1), one
   point above a bare class: so `<button class="button button--quiet">` came
   out as a filled navy pill at full size, and `button--small` on a submit
   button did nothing at all. Every secondary action rendered as a primary
   one. Found on the member area's Payments screen, 15 September 2026, and
   it was wrong everywhere a form had a secondary button. */
.button--quiet,
button[type="submit"].button--quiet,
input[type="submit"].button--quiet {
  background: transparent;
  color: var(--navy);
  border-color: var(--navy);
}
.button--quiet:hover,
button[type="submit"].button--quiet:hover,
input[type="submit"].button--quiet:hover { background: var(--navy); color: #fff; border-color: var(--navy); }
.native a.button--quiet { color: var(--navy); }
.native a.button--quiet:hover { color: #fff; }

/* A hero's buttons are the home page hero's: 18px by 48px. */
.phero__actions .button,
.phero__actions button[type="submit"] { padding: 18px 48px; }

.button--small,
button[type="submit"].button--small,
input[type="submit"].button--small { font-size: 13px; line-height: 18px; padding: 12px 28px; }

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

label { display: block; font-family: var(--display); font-weight: 700; color: var(--navy); margin-bottom: 8px; }

input[type="text"], input[type="email"], input[type="search"],
input[type="password"], input[type="date"], input[type="number"],
input[type="tel"], input[type="url"],
select, textarea {
  font: inherit;
  font-size: 16px;
  width: 100%;
  max-width: 34rem;
  padding: 13px 16px;
  border: 1px solid var(--rule);
  border-radius: 8px;
  background: #fff;
  color: var(--ink);
}
input:focus, select:focus, textarea:focus { border-color: var(--green); }
textarea { min-height: 9rem; }

.field { margin-bottom: 24px; }

/* ---- a password field, with its Show control ----

   THE INPUT IS CAPPED AT 34rem BY THE RULE ABOVE, so the wrapper is capped
   to match and the button is positioned against the wrapper. Position it
   against `.field` instead and it lands wherever the column happens to end,
   which on the sign-up sheet is a long way to the right of the input.

   The input gets right padding equal to the button's width so that a long
   password runs underneath the word rather than through it. */
.field__pw { position: relative; max-width: 34rem; }
.field__pw input { padding-right: 72px; }
.pw__show {
  position: absolute;
  top: 50%;
  right: 6px;
  transform: translateY(-50%);
  padding: 6px 10px;
  border: 0;
  border-radius: 6px;
  background: none;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
  /* Green rather than the muted grey: it is a control, and at 14px the
     muted grey is the one contrast fault this would have introduced. */
  color: var(--green);
  cursor: pointer;
}
.pw__show:hover { text-decoration: underline; }
.pw__show:focus-visible { outline: 2px solid var(--green); outline-offset: 1px; }


/* A checkbox reads as one line: the box, then the words. */
/* A single checkbox: box first, words after. It was one flex row, which
   put any help text on the same line hard against the end of the label:
   "Show me in the members' directoryThis is what puts you in the list of
   people inside each of your Special Interest Groups". James saw that on
   14 September 2026 and called it weird and clunky, and it was. A grid, so
   the help text is a second line under the label where a reader expects it,
   and an error spans both columns. */
/* The tick is the browser's own blue until it is told otherwise, which on
   a navy and green site is the one control that belongs to somebody else.
   One declaration, and it reaches every checkbox and radio on the site. */
input[type="checkbox"], input[type="radio"] { accent-color: var(--navy); }

.field--check {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: 10px;
}
.field--check input { width: auto; margin: 0; }
.field--check label { margin: 0; font-weight: 400; color: var(--body); }
.field--check .helptext { grid-column: 2; margin-top: 4px; }
.field--check .errorlist { grid-column: 1 / -1; }

/* The honeypot. Taken out of the flow rather than display:none, because
   some form fillers skip anything that is display:none or type=hidden and
   the whole point is that they fill it in. */
.honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* Django's as_p puts the label before the input for every field type,
   including checkboxes, where a block label leaves the box orphaned on the
   line below it. :has() is how the checkbox case is told apart without
   writing a custom form renderer. */
p:has(> input[type="checkbox"]) label,
p:has(> input[type="radio"]) label {
  display: inline;
  font-weight: 400;
  color: var(--body);
}
p:has(> input[type="checkbox"]) input,
p:has(> input[type="radio"]) input { width: auto; margin-right: 8px; }

/* Definition lists carry the member's own facts on the account page. */
dl { max-width: 46rem; margin: 0 0 32px; }
dt {
  font-family: var(--display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--green);
  margin-top: 24px;
}
dd { margin: 6px 0 0; font-size: 17px; color: var(--ink); }

.field .helptext, .helptext {
  display: block;
  font-size: 14px;
  color: var(--muted);
  margin-top: 8px;
  max-width: 48ch;
}
.errorlist {
  list-style: none;
  padding: 12px 18px;
  margin: 0 0 12px;
  max-width: 34rem;
  border-left: 3px solid var(--red);
  border-radius: var(--radius-card);
  background: #FDECEE;
  color: #7A0009;   /* the brand red is too light on a tint to read */
  font-size: 15px;
}
.errorlist li { margin: 0; }

/* A form, in the card every other block of content on this site sits in.
   The contact form, the certificate check and the sign-in page were three
   pages where a stack of unboxed inputs floated in the left half of a
   1100px column with nothing in the right half. */
.form-card, .auth form {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-card);
  padding: 36px 32px 32px;
  max-width: 40rem;
}
.form-card > :last-child, .auth form > :last-child { margin-bottom: 0; }
@media (max-width: 600px) {
  .form-card, .auth form { padding: 28px 22px 24px; }
}

/* ------------------------------------------------------------ panels ----
 *
 * Corners follow the ported pages: 20px on anything that holds content,
 * 16px on an icon tile, 40px on a control.
 *
 * They were all squared off on 7 September, on the reading that a 20px
 * corner is the shape of a consumer app. It is, on a consumer app. On this
 * site it was also the shape of every card on the home page, the journals
 * page and the conference page, none of which this stylesheet reaches, so
 * squaring the rest split the site in two. James's judgement on 9 September
 * settled it: the pages written here follow the pages ported here.
 */

.panel {
  background: var(--tint);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  padding: 28px 32px;
  margin: 32px 0;
  max-width: var(--measure);
}
.panel > :last-child { margin-bottom: 0; }
.panel > :first-child { margin-top: 0; }
.panel--attention { border-left: 3px solid var(--red); background: #FDF2F3; }
.panel--good { border-left: 3px solid var(--green); }

/* The panel that carries a fact rather than a warning: white, so the number
   inside it is the only thing on it. */
.panel--card { background: #fff; }
.panel--card .headline-fact { margin-bottom: 20px; }

/* Two columns inside a panel, so a short label and a short value do not
   each take a line of their own. */
.dl--inline { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 8px 24px; }
.dl--inline dt { margin: 0; align-self: baseline; }
.dl--inline dd { margin: 0; font-size: 16px; }

@media (max-width: 480px) {
  .dl--inline { grid-template-columns: 1fr; gap: 2px; }
  .dl--inline dd { margin-bottom: 12px; }
}

/* A card, as the ported pages draw one: a #f8f9fb ground inside a 1px
   #e8e8e8 hairline, a 20px corner, and a 4px lift on hover that also brings
   the border to navy. Measured off `.wsset-pillar-card` on the home page,
   which is the card this site already had before any of these were
   written. */
.card {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-card);
  overflow: hidden;
  transition: box-shadow .3s ease, transform .3s ease, border-color .3s ease;
}
.card:hover {
  box-shadow: var(--lift);
  transform: translateY(-4px);
  border-color: var(--navy);
}

.native .cards, .cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 32px;
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: none;
}
.cards > li { margin: 0; }

/* ---------------------------------------------------------- toasts ----

   EVERY NOTIFICATION THE SITE SHOWS. See templates/_messages.html.

   James, 19 September 2026: "That pop up notification is so ugly, can you
   do it like Apple style notifications instead". So this is built to
   Apple's own published anatomy rather than to an impression of it, and
   every choice below cites the guideline it comes from.

   WHERE IT SITS: top right, stacking downward, sliding in from the right
   edge. That is the macOS banner, and it is James's choice of the three
   put to him. Apple never centres a notification, which is why the middle
   of the page, asked for earlier the same day, is gone. On a phone it
   drops from the top edge instead, which is what iOS does.

   Below the masthead, not over it: the masthead is this site's menu bar,
   and macOS hangs its banners under the menu bar rather than across it.
   The masthead measures 115px above 1100px and 89px at or below it.

   THE MATERIAL is Apple's regular Liquid Glass, not the clear variant.
   HIG, Materials: "Use the regular variant when background content might
   create legibility issues, or when components have a significant amount
   of text, such as alerts, sidebars, or popovers." Regular "blurs and
   adjusts the luminosity of background content to maintain legibility",
   which is the `brightness` in the filter and the 0.8 in the tint.

   THE TINT IS 0.8 AND THAT NUMBER IS LOAD-BEARING. Composited over the
   worst backdrop there is, pure black, 0.8 of a near-white tint still
   lands at sRGB 202, which carries navy text at better than 6:1. Thinning
   it for a glassier look puts the text under WCAG's 4.5:1 over a dark
   photograph. Both lines are navy for the same reason: `--muted` on that
   worst-case ground measures 3.2:1 and fails. Apple's own note is that
   thicker materials give better contrast, and that a notification is
   exactly where that matters.

   THE TIMING IS IN CSS so it works with scripting off. Seven seconds for
   something that went right, twenty for something that did not, paused
   while the pointer is over it. The script adds the dismiss button. */

.toasts {
  position: fixed;
  /* Clear of the masthead, which is sticky and always there. */
  top: calc(115px + 12px);
  right: 16px;
  z-index: 200;
  /* macOS's banner is about 344pt. At 360 the body was wrapping a plain
     sentence onto four lines, because the icon and the dismiss take 91px
     of it before a word is set. */
  width: 400px;
  max-width: calc(100vw - 32px);
  display: grid;
  /* `minmax(0, 1fr)`, not the default `auto`: an `auto` column takes the
     max-content width of the card inside it, so one long sentence grew the
     column past the layer and carried the whole stack off the screen. */
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  /* The layer catches nothing; the cards in it do. A dead strip down the
     side of every page would swallow clicks on whatever is under it. */
  pointer-events: none;
  margin: 0;
  padding: 0;
  list-style: none;
}

.toast {
  pointer-events: auto;
  display: grid;
  /* The icon, the words, and the way to get rid of it. The icon spans both
     text rows so it is centred against them however long the body runs. */
  grid-template-columns: 38px minmax(0, 1fr) 28px;
  column-gap: 12px;
  align-items: start;
  padding: 13px 13px 14px 13px;
  /* macOS's banner radius, near enough at this size. The site's own card
     radius is 20px, which on a 38px-tall icon row reads as a pill. */
  border-radius: 18px;
  background: rgba(252, 253, 254, .80);
  -webkit-backdrop-filter: blur(28px) saturate(170%) brightness(1.06);
          backdrop-filter: blur(28px) saturate(170%) brightness(1.06);
  /* The glass edge and the lift. A hairline that catches the light along
     the top, a tight contact shadow, and a wide soft one for the height.
     Apple's banner reads as a pane above the page, not a box drawn on it. */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .85),
              0 0 0 .5px rgba(0, 49, 80, .10),
              0 2px 6px rgba(0, 25, 45, .07),
              0 12px 32px rgba(0, 25, 45, .15);
  animation: toast-in 300ms cubic-bezier(0, 0, 0, 1) both,
             toast-out 300ms cubic-bezier(.3, 0, 1, 1) 7s both;
}
.toast:hover, .toast:focus-within { animation-play-state: paused, paused; }

/* Something that did not go right holds for twenty seconds, because it is
   usually the thing the reader has to do something about. */
.toast--error, .toast--warning { animation-delay: 0s, 20s; }
.toast--going { animation: toast-out 200ms cubic-bezier(.3, 0, 1, 1) both; }

/* THE LEADING ICON. Apple puts the app's icon here and says not to repeat
   it in the words: "The system automatically displays a large version of
   your app icon at the leading edge of each notification." On a website
   there is only ever one app, so the icon would say the same thing every
   time. The level is what actually varies, so the level is what goes in
   the slot, at the icon's size and in the icon's rounded square. */
.toast__mark {
  grid-row: 1 / span 2;
  width: 38px;
  height: 38px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  background: var(--green);
  color: #fff;
}
.toast__mark svg {
  width: 21px;
  height: 21px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.toast--error .toast__mark { background: var(--red); }
.toast--warning .toast__mark { background: #8a5a00; }
.toast--info .toast__mark, .toast--debug .toast__mark { background: var(--navy); }

/* THE WORDS. Apple's anatomy is a title at the top, "where it's most
   visible", and the body beneath it. A message with nothing to add is a
   title on its own, which is what macOS shows when there is no body.
   Title-style capitalisation and no full stop on the title; sentence case
   and proper punctuation in the body. Both are the site's navy: see the
   note on contrast above. */
.toast__title {
  grid-column: 2;
  margin: 0;
  font-family: var(--text);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.005em;
  color: var(--navy);
  overflow-wrap: anywhere;
}
.toast__text {
  grid-column: 2;
  margin: 2px 0 0;
  font-family: var(--text);
  font-size: 15px;
  font-weight: 400;
  line-height: 1.42;
  color: var(--navy);
  max-width: none;
  /* An email address or a certificate ID is one long word. */
  overflow-wrap: anywhere;
}
/* A title on its own sits against the middle of the icon rather than the
   top of it. */
.toast:not(:has(.toast__text)) .toast__title { align-self: center; }

.toast__off {
  grid-column: 3;
  grid-row: 1;
  position: relative;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  background: rgba(0, 49, 80, .06);
  border: 0;
  border-radius: 50%;
  padding: 0;
  margin: 1px 0 0;
  cursor: pointer;
  color: var(--navy);
}
/* 28px is what it looks like; 44px is what a thumb gets. WCAG 2.5.8 asks
   for 24, and the rest of this site was brought to 44. */
.toast__off::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}
.toast__off:hover { background: rgba(0, 49, 80, .13); }
.toast__off svg {
  width: 12px; height: 12px;
  fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round;
}

/* In from the right edge and back out the same way, which is the macOS
   banner. Transform and opacity only, 300ms, on the constitution's own
   entering and exiting curves. */
@keyframes toast-in {
  from { opacity: 0; transform: translateX(calc(100% + 24px)); }
  to   { opacity: 1; transform: none; }
}
/* `visibility: hidden` in the last frame, and `both` holds it there. The
   script removes a finished card, but with scripting off nothing does, and
   an invisible card that still takes pointer events sat over the page
   swallowing clicks for the rest of the visit. Checked: without it,
   `elementFromPoint` returned the toast eight seconds after it had gone. */
@keyframes toast-out {
  from { opacity: 1; transform: none; visibility: visible; }
  to   { opacity: 0; transform: translateX(calc(100% + 24px)); visibility: hidden; }
}

/* The masthead is 89px from here down. */
@media (max-width: 1100px) {
  .toasts { top: calc(89px + 12px); }
}

/* iOS drops its banner from the top edge, near enough full width. */
@media (max-width: 600px) {
  .toasts {
    left: 10px;
    right: 10px;
    width: auto;
    max-width: none;
    top: calc(89px + 10px);
  }
  @keyframes toast-in {
    from { opacity: 0; transform: translateY(calc(-100% - 24px)); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes toast-out {
    from { opacity: 1; transform: none; visibility: visible; }
    to   { opacity: 0; transform: translateY(calc(-100% - 24px)); visibility: hidden; }
  }
}

/* WITHOUT THE BLUR, THE TINT HAS TO CARRY THE WHOLE JOB, so it goes
   opaque. A 0.8 wash with nothing behind it is a smear. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .toast { background: #fcfdfe; }
}

/* Apple's own Reduce Transparency setting, which this honours the way the
   system does: the material goes solid and the blur goes away. */
@media (prefers-reduced-transparency: reduce) {
  .toast {
    background: #fff;
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
  }
}
@media (prefers-contrast: more) {
  .toast {
    background: #fff;
    -webkit-backdrop-filter: none;
            backdrop-filter: none;
    box-shadow: 0 0 0 1.5px var(--navy), 0 12px 32px rgba(0, 25, 45, .2);
  }
}

/* Rule 33 of the design constitution: replace motion with a cross-fade,
   do not delete it. And the fade is the card's only clock, so a blanket
   `animation: none` would park it on the screen for ever for anybody
   without scripting. */
@media (prefers-reduced-motion: reduce) {
  @keyframes toast-in { from { opacity: 0; } to { opacity: 1; } }
  @keyframes toast-out {
    from { opacity: 1; visibility: visible; }
    to   { opacity: 0; visibility: hidden; }
  }
}

/* -------------------------------------------------------------- news ---- */

.native .news, .news {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 32px;
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: none;
}
.news > li {
  margin: 0;
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.3s ease, transform 0.3s ease;
}
.news > li:hover { box-shadow: 0 12px 40px rgba(0, 49, 80, 0.12); transform: translateY(-4px); }

/* Every tile the same height, whatever shape the picture is.
 *
 * This is the point at which a portrait card would otherwise be destroyed:
 * a 4:5 card cropped into a 200px band across a 350px card keeps about a
 * seventh of it, and which seventh is decided by nothing at all.
 *
 * What makes this work is not here. It is the focal point written on the
 * image at upload by apps/cms/photocrop.py, which `fill-` renditions
 * honour: the band is taken from the photograph, above the headline and
 * below the mark, rather than from the middle of the card. So the grid
 * stays even, which is what the design needs, and no tile is a slice of
 * somebody's typography, which is what the reader needs. */
.news__thumb { display: block; }
.news__thumb img {
  display: block;
  width: 100%;
  height: 200px;
  object-fit: cover;
  background: var(--tint);
}
.news__text { padding: 28px 28px 32px; display: flex; flex-direction: column; flex: 1; }
.news h3 { margin: 0 0 12px; font-size: 20px; line-height: 1.35; }
.news h3 a { color: var(--navy); text-decoration: none; }
.news h3 a:hover { color: var(--green); }
.news .meta { margin: 0 0 12px; }
.news__text p { font-size: 15px; margin: 0; }
.news__text p + p { margin-top: 12px; }

/* A pinned item. The green edge is the whole signal at a glance; the label
   is there because a colour on its own says nothing to somebody who cannot
   see it, and because "why is this old item first?" is a fair question. */
/* An inset ring rather than a thicker border, so a pinned card is not one
   pixel taller than its neighbours in the grid. */
.news__item--pinned { box-shadow: inset 0 0 0 2px var(--green); }
.news__item--pinned:hover { box-shadow: inset 0 0 0 2px var(--green),
                                        0 12px 40px rgba(0, 49, 80, 0.12); }
.news .pin {
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--green);
}
.news .pin span { font-size: 10px; }

/* ------------------------------------------------------------- joining ---
   THE APPLICATION IS A SHEET LAID INTO THE SOCIETY'S OWN COLOUR.

   Three arrangements were rejected before this one, and the last rejection
   is the one that shaped it. James, 14 September 2026: "So some long thing
   then the form tacked to the bottom? terrible web design", and before it,
   "i don't like this floating panel ... really basic and really cheap ...
   i need to add weight, gravitas, prestige!"

   A form beside a price card reads as a checkout. A form under three
   paragraphs reads as an afterthought. So the form is the page: a white
   sheet pulled up into the navy field, opening with its own masthead, with
   every section numbered and named in its own column. It is the shape of an
   instrument of admission rather than of a shopping basket, it uses the
   full width of the spine, and the first field is on the first screen.

   No shadow lifts it. The design standard across all ten organisations
   studied is no gradients and no drop shadows; what separates the sheet
   from the ground is the navy behind it and one hairline. */

/* The navy runs deep at the foot so that the sheet has a margin of colour
   around its shoulders once it is pulled up. */
.phero--apply .phero__inner { padding-block: 88px 224px; }
@media (max-width: 900px) { .phero--apply .phero__inner { padding-block: 56px 140px; } }

/* TWO SELECTORS HERE ARE DELIBERATELY HEAVIER THAN THEY LOOK, AND BOTH
   FAILED ONCE AS THE SHORT FORM. `.section` sets `padding-block: 100px`
   further down this file, so `.section--apply` alone is the same weight and
   loses on order; and `.auth form` is 0,1,1, so a bare `.sheet` cannot
   change the width, the ground or the padding this form inherits from every
   other form on the site. Same trap as `.auth--bleed h1` on 14 September.
   Written to outrank rather than to be read first. */
.section.section--apply { padding-top: 0; }

.auth form.sheet, .sheet {
  /* POSITIONED, OR IT PAINTS UNDERNEATH THE NAVY. `.phero` is
     `position: relative`, so it stacks above later content that is not
     positioned, and the sheet's masthead simply disappeared behind it. */
  position: relative;
  z-index: 1;
  max-width: none;
  margin: -150px 0 0;
  padding: 0;
  background: #fff;
  border: 1px solid var(--card-border);
  border-radius: var(--radius-card);
  overflow: hidden;
}
@media (max-width: 900px) {
  .auth form.sheet, .sheet { margin-top: -100px; }
}

/* ---- the masthead of the sheet ---- */

.auth form.sheet .sheet__head, .sheet__head {
  padding: 44px 48px 36px;
  border-bottom: 1px solid var(--rule);
}
.native .sheet__of, .sheet__of {
  margin: 0 0 14px;
  max-width: none;
  font-family: var(--display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--green);
}
.native .sheet__title, .sheet__title {
  margin: 0;
  font-family: var(--display);
  font-size: 34px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.1;
  color: var(--navy);
}
.native .sheet__lead, .sheet__lead {
  margin: 18px 0 0;
  font-size: 15px;
  color: var(--muted);
  max-width: 60ch;
}
.sheet__errors { padding: 24px 48px 0; }

/* Everything that is wrong, at the top, each one a way down to the field.

   The sheet is 3,400 pixels tall and the form comes back at the top of it,
   so without this the reader is looking at a page that has plainly refused
   them and shows them nothing about why. The lead is the sentence that
   matters at that moment: the button said "Continue to payment", and
   nothing was taken. */
.errors-summary {
  border-left: 3px solid var(--red);
  border-radius: var(--radius-card);
  background: #FDECEE;
  color: #7A0009;
  padding: 16px 20px;
  max-width: 34rem;
}
.errors-summary__lead {
  margin: 0 0 6px;
  font-family: var(--display);
  font-weight: 700;
  font-size: 16px;
  color: #7A0009;
}
.errors-summary ul { list-style: none; margin: 0; padding: 0; }
.errors-summary li { margin: 0; font-size: 15px; }
.errors-summary li + li { margin-top: 4px; }
.errors-summary a { color: #7A0009; }
.errors-summary:focus-visible { outline: 3px solid var(--red); outline-offset: 3px; }

/* ---- a numbered section, named in its own column ---- */

.sheet__row {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 48px;
  padding: 40px 48px;
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 0;
}
.sheet__row:first-of-type { border-top: 0; }
.sheet__label { min-width: 0; }
.sheet__fields { min-width: 0; }

/* `legend` cannot be a grid item in every engine, so the name sits inside
   the label column and the fieldset keeps its own grouping semantics. */
.sheet__row legend,
.native .sheet__row legend {
  float: none;
  width: 100%;
  padding: 0;
  margin: 0 0 12px;
  display: flex;
  align-items: baseline;
  gap: 14px;
  font-family: var(--display);
  font-size: 21px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.2;
  text-transform: none;
  color: var(--navy);
}
.sheet__n {
  font-family: var(--display);
  font-size: 21px;
  font-weight: var(--display-weight);
  color: var(--green);
}
.native .sheet__close, .sheet__close {
  display: flex;
  align-items: baseline;
  gap: 14px;
  margin: 0 0 12px;
  font-family: var(--display);
  font-size: 21px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--navy);
}
.native .sheet__hint, .sheet__hint {
  margin: 0;
  font-size: 15px;
  line-height: 1.65;
  color: var(--muted);
}

/* Payment is the row the eye lands on last, so it is the one the Society's
   tint sits behind. */
.sheet__row--pay { background: var(--tint); }

/* ---- the payment section ----
 *
 * James, 14 September 2026: "the payment part looks amateur it should be a
 * proper section, with the icons and everything like a professional payment
 * section that people trust".
 *
 * What earns that trust is three facts and no ornament: who takes the money,
 * that the Society never holds a card number, and which methods are
 * accepted. The marks are set in the Society's own face rather than in each
 * scheme's artwork. THAT IS A PLACEHOLDER, NOT A PREFERENCE: the schemes
 * publish acceptance marks for exactly this use and they should be the files
 * shown here. Drop them in `static/img/payments/` and swap the `<li>` text
 * for an `<img>`; the row is built to take either.
 */
.pay {
  margin: 0 0 28px;
  padding: 20px 22px;
  background: #fff;
  border: 1px solid var(--card-border);
  border-radius: var(--radius-tile);
  max-width: 34rem;
}
.native .pay__secure + .pay__secure, .pay__secure + .pay__secure {
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
}
.native .pay__secure, .pay__secure {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0;
  font-size: 15px;
  line-height: 1.6;
  color: var(--navy);
}
.pay__secure > span { min-width: 0; }
.pay__secure svg {
  flex: 0 0 auto;
  width: 20px;
  height: 20px;
  margin-top: 2px;
  fill: none;
  stroke: var(--green);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.native .pay__marks, .pay__marks {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  list-style: none;
  margin: 18px 0 0;
  padding: 18px 0 0;
  border-top: 1px solid var(--rule);
}
.native .pay__marks li, .pay__marks li {
  margin: 0;
  padding: 7px 12px;
  border: 1px solid var(--card-border);
  border-radius: 6px;
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--navy);
  background: #fff;
}

/* With the schemes' own artwork in, the tile is a frame around a mark
   rather than a label: one height, centred, and the border does the
   aligning that five different aspect ratios will not do on their own.
   Each scheme's own clear-space rule is why the padding is generous. */
/* Uniform tiles, each mark contained and centred inside one. Left to
   themselves the five are a square, three wordmarks and a roundel at five
   aspect ratios, and a row of those reads as five pictures rather than as
   one statement of what is accepted. */
.pay__marks--art li {
  width: 62px;
  height: 40px;
  padding: 6px 8px;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pay__marks--art img {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: 24px;
}
@media (max-width: 600px) {
  .pay__marks--art li { width: 54px; height: 36px; }
  .pay__marks--art img { max-height: 20px; }
}

/* ---- the fee, in the one place it belongs ---- */

.form-fee {
  margin: 0 0 22px;
  font-size: 18px;
  line-height: 1.6;
  color: var(--navy);
  max-width: 46ch;
}

@media (max-width: 900px) {
  .sheet__head { padding: 32px 24px 26px; }
  .native .sheet__title, .sheet__title { font-size: 26px; }
  .sheet__errors { padding: 20px 24px 0; }
  .sheet__row { grid-template-columns: minmax(0, 1fr); gap: 20px; padding: 32px 24px; }
}

/* The account page and the groups page still use the two-column split. */
.split--wide { grid-template-columns: minmax(0, 1fr) 340px; }
@media (max-width: 1000px) {
  .split--wide { grid-template-columns: minmax(0, 1fr); }
}
.split__aside > * + * { margin-top: 24px; }

.join-card { background: var(--navy); color: #fff; border-color: var(--navy); }
.join-card__price {
  margin: 0 0 16px;
  font-family: var(--display);
  font-size: 40px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: #fff;
}
.join-card__price span {
  font-size: 16px;
  font-weight: 400;
  opacity: 0.75;
  margin-left: 6px;
}
/* A pill rather than coloured text. Run together on one wide line, "five of
   the Society's journals Saves £150 a paper" reads as one sentence and the
   figure stops being a figure. */

.native .steps, .steps {
  margin: 0;
  padding: 0 0 0 22px;
  display: grid;
  gap: 12px;
  max-width: none;
}
.steps li { margin: 0; font-size: 15px; line-height: 1.5; }
.steps li strong { color: var(--navy); }

/* A card is a sidebar, not a section of the page, so its heading is a
   heading for a small box rather than for a screen. */
.panel--card h2 { font-size: 20px; line-height: 1.3; margin: 0 0 14px; }
.split__aside .panel--card h2 { margin-top: 0; }

.form-foot { margin-top: 20px; font-size: 14px; color: var(--muted); }
/* Above the form rather than below it: somebody who already has an account
   has to find that out before fourteen fields, not after. */
.form-lead {
  margin: 0 0 32px;
  padding-bottom: 24px;
  border-bottom: 1px solid var(--rule);
  color: var(--muted);
}
/* What happens when the button is pressed, beside the button. It was a
   three-step card in the sidebar, describing a process that is now short
   enough to say in a sentence. */
.sheet__fields .button { display: inline-block; }
.aside-note { font-size: 14px; color: var(--muted); line-height: 1.6; }

/* ------------------------------------------------- contributions & people --
   A contribution is a name, a title, one figure and a paragraph: a
   conference abstract, essentially, and it is laid out like one. Numbered,
   because the number is the running order the chair works down, which is
   information rather than decoration. */
.native .contribs, .contribs {
  list-style: none;
  counter-reset: contrib;
  margin: 0 0 16px;
  padding: 0;
  max-width: none;
}
.contrib {
  margin: 0;
  padding: 28px 0;
  border-top: 1px solid var(--rule);
}
.contrib:last-child { border-bottom: 1px solid var(--rule); }
.contrib h3 {
  margin: 0 0 14px;
  font-size: 21px;
  line-height: 1.3;
  color: var(--navy);
}
.contribs > .contrib h3::before {
  counter-increment: contrib;
  content: counter(contrib);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  margin-right: 10px;
  border-radius: 50%;
  background: var(--green);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  vertical-align: 2px;
}
.contrib__who { margin: 0 0 6px; font-size: 14px; color: var(--muted); }

/* THE PROGRAMME BAND IS NAVY AND ALL OF THIS WAS WRITTEN FOR WHITE.
   The same fault as the white-on-white eyebrow, found the same way: by
   reading each element's colour back out of the browser and comparing it
   with what is actually behind it. Looking at the page does not catch it,
   because there is nothing there to see.

   Three of them, on the one band a member spends the most time reading:

   `.panel--card` is a white card. Inside a navy section it inherited the
   section's light text onto its own white ground, so "Put your work on it"
   and the paragraph under it printed white on white and the card read as
   an empty box with a button in the corner. That card is the only
   invitation on the page to contribute anything.

   `.contrib__who` and `.muted` are the grey small print uses on white,
   which on navy is barely lighter than the ground. That grey was carrying
   every contributor's name and institution, which is the part of a running
   order a reader scans first. */
.section--navy .panel--card { color: var(--ink); }
/* The headings need saying separately: `.section--navy h3` sets white
   explicitly, and an explicit rule beats an inherited one however specific
   the inheritance is. Without this the paragraph came back and the heading
   above it stayed missing, which is worse than both being gone. */
.section--navy .panel--card h2,
.section--navy .panel--card h3 { color: var(--navy); }
.section--navy .panel--card .muted,
.section--navy .panel--card .contrib__who { color: var(--muted); }
.section--navy .contrib__who,
.section--navy .muted { color: rgba(255, 255, 255, .72); }
.contrib__figure {
  display: block;
  width: 100%;
  max-width: 560px;
  height: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  margin: 0 0 16px;
  background: var(--tint);
}
.contrib p { margin: 0 0 12px; }
.call { margin-bottom: 32px; }
.call h3 { margin: 0 0 10px; font-size: 20px; color: var(--navy); }

.native .people, .people {
  list-style: none;
  margin: 0 0 32px;
  padding: 0;
  max-width: none;
}
.person {
  margin: 0;
  padding: 24px 0;
  border-top: 1px solid var(--rule);
  display: flex;
  flex-wrap: wrap;
  gap: 16px 32px;
  align-items: start;
  justify-content: space-between;
}
.person:last-child { border-bottom: 1px solid var(--rule); }
.person__who { flex: 1 1 380px; }
.person h3 { margin: 0 0 4px; font-size: 18px; color: var(--navy); }
.person__where { margin: 0 0 8px; font-size: 14px; color: var(--muted); }
.person__work { margin: 0; font-size: 15px; }

/* --------------------------------------------------------------- bands ---
   A full-bleed navy opening. The same device as the payment confirmation
   page, reused rather than reinvented, so the two pages on this site that
   have to persuade somebody look like they were designed together. */
.band {
  background: var(--navy);
  color: #fff;
  padding-block: 72px 64px;
  margin-bottom: 56px;
}
.band h1 { color: #fff; margin: 10px 0 0; }
.band__lede {
  margin: 20px 0 0;
  max-width: 34em;
  font-size: 19px;
  line-height: 1.6;
  color: rgba(255, 255, 255, .82);
}
.eyebrow--on-navy { color: #ffffff; }

/* Counted, not typed. These move on their own as the membership grows,
   which is what stops a page needing anybody to keep it looking current. */
.native .figures, .figures {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 56px;
  margin: 40px 0 0;
  padding: 0;
  max-width: none;
}
.figures > div { margin: 0; }
.figures dt {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .6);
  margin: 0 0 4px;
}
.figures dd {
  margin: 0;
  font-family: var(--display);
  font-size: 38px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.figures dd span {
  font-size: 15px;
  font-weight: 400;
  letter-spacing: 0;
  color: rgba(255, 255, 255, .62);
  margin-left: 4px;
}
@media (max-width: 700px) {
  .band { padding-block: 48px 44px; }
  .figures { gap: 20px 36px; }
  .figures dd { font-size: 30px; }
}

/* ------------------------------------------------------------ how it works
   Three steps, and they are a real sequence, so they are numbered. */
.native .how, .how {
  counter-reset: how;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 32px;
  margin: 0 0 56px;
  padding: 0;
  max-width: none;
}
.how li { margin: 0; padding-top: 18px; border-top: 2px solid var(--green); }
.how li::before {
  counter-increment: how;
  content: counter(how);
  display: block;
  font-family: var(--display);
  font-size: 13px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--green);
  margin-bottom: 8px;
}
.how h3 { margin: 0 0 8px; font-size: 19px; color: var(--navy); }
.how p { margin: 0; font-size: 15px; }

/* ----------------------------------------------------------------- cta --- */
.cta {
  display: grid;
  gap: 28px;
  align-items: center;
  padding: 40px;
  border-radius: var(--radius-card);
  background: var(--tint);
  border: 1px solid var(--rule);
  margin-bottom: 24px;
}
@media (min-width: 860px) { .cta { grid-template-columns: 1fr auto; gap: 48px; } }
.cta h2 { margin: 0 0 10px; font-size: 24px; }
.cta p { margin: 0; max-width: 46em; }
.cta__action { display: grid; gap: 12px; justify-items: start; }

/* `.native a.button` sets colour at (0,2,1), so a bare `.button--light`
   loses to it and the label disappears into the white pill. This is the
   fourth time the `.native <type>` layer has won an argument it should not
   have; match its specificity rather than adding !important.

   The fifth: `button[type="submit"]` is (0,1,1) and also beat the bare
   class, on the one element that is a real <button>, the one-click join on
   a group's hero. `button.button--light` is (0,1,1) and later. */
.button--light,
button.button--light,
.native a.button--light {
  background: #fff;
  border-color: #fff;
  color: var(--navy);
}
.button--light:hover,
button.button--light:hover,
.native a.button--light:hover {
  background: transparent;
  border-color: #fff;
  color: #fff;
}

.join-card__note { font-size: 14px; color: rgba(255, 255, 255, .72); margin: 0 0 18px; }
.join-card__signin { margin: 14px 0 0; font-size: 14px; }
.join-card__signin a { color: #9fd8bd; }
.join-card h2 { color: #fff; }

.locked { color: var(--muted); font-size: 15px; margin: 0; }
.convenor { margin: 0; font-weight: 700; color: var(--navy); }

/* ---------------------------------------------------------------- SIGs ---
   A group's page is a main column and a card beside it: what the group is
   for on the left, how to join and who runs it on the right. Below 900px
   the card goes under the text rather than beside it, because a 300px card
   next to a 300px column is two unreadable columns. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 48px;
  align-items: start;
}
@media (max-width: 900px) {
  .split { grid-template-columns: minmax(0, 1fr); gap: 32px; }
}
/* THE STICKY ASIDE, WHICH HAD NEVER ONCE STUCK.
 *
 * It used to read `.split__aside .panel--card { position: sticky }`, and it
 * did nothing at all. `.split` sets `align-items: start`, which sizes each
 * column to its own content rather than to the row, so the aside was 940px
 * tall beside a 2,024px form. A sticky element cannot travel outside the
 * box that contains it, so it reached the foot of its own short column
 * immediately and stopped.
 *
 * Measured on the sign-up page at 1440 on 14 September 2026: 1,084 pixels
 * of that column empty, on a page 3,517 pixels tall. James: "don't use
 * space well". The intent was right and had been dead since it shipped.
 *
 * Two changes. `align-self: stretch` gives the column the height of the
 * row, which is what sticky needs in order to travel. And ONE wrapper
 * sticks, not each card: two sticky siblings with the same offset climb on
 * top of each other.
 *
 * Opt-in, because a page with a short aside beside a short body does not
 * want its sidebar pinned, and because a rule that silently changes every
 * `.split` on the site is how this kind of thing gets introduced in the
 * first place. */
.split__aside--sticky { align-self: stretch; }
.split__aside--sticky .split__sticky {
  position: sticky;
  top: calc(var(--header-h) + 24px);
}
.split__sticky > * + * { margin-top: 24px; }
@media (max-width: 1000px) {
  .split__aside--sticky .split__sticky { position: static; }
  /* ONE COLUMN PUTS THE REASONS AFTER THE FORM, WHICH IS TOO LATE.
     Stacked, the summary fell below a form four thousand pixels long: a
     phone reader met the fee and what it covers only once they had already
     typed everything in. It goes first, where it is on a wide screen.
     Capped to the form's own 640px so the two do not stack to different
     widths: full bleed, the panel ran 83 pixels past the form under it. */
  .split--wide .split__aside--sticky { order: -1; max-width: 640px; }
}
@media (max-width: 900px) {
  .split__aside .panel--card { position: static; }
}

.native .groups, .groups {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 24px;
  list-style: none;
  margin: 0 0 48px;
  padding: 0;
  max-width: none;
}
.groups__item {
  margin: 0;
  padding: 28px;
  background: #fff;
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.groups__item h2 { margin: 0; font-size: 20px; line-height: 1.3; }
.groups__item h2 a { color: var(--navy); text-decoration: none; }
.groups__item h2 a:hover { color: var(--green); }
.groups__item p { margin: 0; font-size: 15px; }
.groups__meta { color: var(--muted); font-size: 14px; }
.groups__item .link-more { margin-top: auto; }

.native .meetings, .meetings {
  list-style: none;
  margin: 0 0 40px;
  padding: 0;
  max-width: none;
}
.meeting {
  margin: 0;
  padding: 24px 0;
  border-top: 1px solid var(--rule);
}
.meeting:last-child { border-bottom: 1px solid var(--rule); }
.meeting h3 { margin: 0 0 10px; font-size: 19px; line-height: 1.35; color: var(--navy); }
.meeting__when {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--green);
}
.meeting__tz { font-weight: 400; letter-spacing: 0; text-transform: none; color: var(--muted); }
.meeting__locked { color: var(--muted); font-size: 15px; margin: 0; }
.meetings--past .meeting h3 { color: var(--body); font-size: 17px; }

.link-more {
  display: inline-block;
  font-weight: 700;
  color: var(--green);
  text-decoration: none;
}
.link-more:hover { text-decoration: underline; }
.link-more::after { content: " \2192"; }

.muted { color: var(--muted); }
.tick { font-weight: 700; color: var(--green); margin: 0 0 8px; }
/* A margin rather than a space inside `content`: a trailing space in a
   generated string collapses, and the tick ends up welded to the word. */
.tick::before { content: "\2713"; margin-right: .4em; }

.native .prose > :first-child, .prose > :first-child { margin-top: 0; }

/* A question answered with several boxes or several buttons: the Special
   Interest Groups, and anything else with a list of options. Django wraps
   each option in a plain <div>, so the spacing is set here rather than
   inherited from anything. */
.field--choices .field__label {
  display: block;
  font-family: var(--display);
  font-weight: 700;
  color: var(--navy);
  margin-bottom: 8px;
}
.field--choices > div > div { margin-top: 10px; }
.field--choices > div > div:first-child { margin-top: 0; }
.field--choices > div label {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  font-family: var(--body-font, inherit);
  font-weight: 400;
  color: var(--body);
  font-size: 15px;
  line-height: 1.45;
  margin: 0;
  cursor: pointer;
}
.field--choices > div input { margin-top: 3px; flex: none; width: auto; }
.field--choices .helptext { margin-top: 10px; }

/* A long form read as four short ones. The rule under each legend is the
   same green rule that follows a heading everywhere else on the site, so a
   sign-up page looks like the rest of it rather than like a plugin. */
.fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 40px;
}
.fieldset legend {
  padding: 0;
  margin-bottom: 4px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--green);
}
.fieldset__note {
  margin: 0 0 20px;
  font-size: 15px;
  color: var(--muted);
  max-width: 46em;
}
.auth .lede, .lede {
  font-size: 18px;
  line-height: 1.6;
  max-width: 46em;
}

.news--empty { display: block; }

.news__hero {
  display: block;
  width: 100%;
  height: auto;
  margin: 0 0 40px;
  border-radius: var(--radius-card);
}

/* A gallery, as a contact sheet.
 *
 * `auto-fill` with a 240px floor rather than a fixed column count, so the
 * same markup is three across on a laptop, two on a tablet and one on a
 * phone with nothing declaring any of those.
 *
 * `align-items: start` matters: without it the grid stretches every image
 * to the height of the tallest in its row, which for a mix of portrait
 * slides and landscape photographs distorts every landscape one. */
.gallery { margin: 40px 0; }
.gallery__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  align-items: start;
  gap: 16px;
}
.gallery__item {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-tile);
  background: var(--tint);
  /* A hairline, because half of what goes in here is a designed slide on
   * a white ground. Without an edge those float on the page as loose
   * fragments and the grid reads as broken rather than as a set. A
   * photograph is not hurt by the same line. */
  border: 1px solid var(--card-border);
}
.gallery figcaption {
  margin: 14px 2px 0;
  font-size: 14px;
  color: var(--muted, #5b6470);
}

/* A portrait card, set into the margin the text does not use.
 *
 * The Society publishes news as 4:5 cards designed for LinkedIn. Run at
 * the full measure the way a landscape photograph is, one of those is
 * 1,500 pixels tall: a reader on a laptop scrolls past a wall of artwork
 * to reach the first sentence, and the artwork repeats the headline that
 * is already three inches above it.
 *
 * Setting it as a plate at the left fixed that and created a worse
 * problem, which James named: "a big gap to the right of it". The article
 * column is 1,020px wide and the text measure is about 745, so there is
 * always 275px of empty margin on the right of every page on this site.
 * On an ordinary page nobody notices. Put a tall picture at the left and
 * the eye is led straight into that emptiness.
 *
 * So the picture goes into the margin instead of beside it. The copy
 * starts exactly where it starts on every other page, which is the part
 * that matters for consistency, and the space that was doing nothing is
 * now doing the work.
 *
 * Floated rather than gridded, for two reasons that only show up in the
 * cases nobody designs for: a grid would move the copy to the right on
 * this one page and nowhere else, and a float lets the text close over
 * the picture when the picture runs out, so a long article does not end
 * with a column of text beside a column of nothing.
 *
 * Checked against how editorial sites actually do it. The Guardian keeps
 * pictures inside the text column at full measure, which works because
 * their layout has rails on both sides and no empty margin to fall into.
 * This site has the empty margin, so this is the version that suits it.
 */
/* `.native .news__plate` and not `.news__plate`, throughout.
 *
 * This is a <figure> inside <main class="native">, and line 832 of this
 * file says `.native figure { margin: 32px 0; }` at (0,1,1). A bare
 * `.news__plate` is (0,1,0) and loses, whatever the order. So the margin
 * that was meant to hold the copy away from the picture was silently
 * discarded and the text ran to within seven pixels of it.
 *
 * That is the fifth time the `.native <type>` layer has won an argument it
 * should not have, and the third time it has cost a rendering fault that
 * looked like a design decision. Match its specificity; never reach for
 * !important. */
.native .news__plate {
  margin: 0 0 40px;
  max-width: 520px;
}
.native .news__plate img {
  display: block;
  /* Sized by its height, not its width: `max-height` is what guarantees
   * the picture and the first paragraph share a screen. `width: auto` lets
   * the browser keep the proportions when that cap bites, and
   * `max-width: 100%` holds it inside the plate when it does not. */
  height: auto;
  max-height: 78vh;
  width: auto;
  max-width: 100%;
  border-radius: var(--radius-card);
  background: var(--tint);
}
.native .news__plate figcaption {
  margin: 12px 2px 0;
  font-size: 14px;
  color: var(--muted, #5b6470);
}

/* Wide enough for the picture to sit in the margin and still leave a
 * readable column beside it.
 *
 * 860px rather than 1000: a tablet has the same empty margin as a laptop,
 * just less of it, so it had the same fault. At 860 the column beside the
 * picture is about fifty characters, which is narrower than this site's
 * usual measure and still wider than a newspaper column. Below that there
 * is not enough width for two things at once, and the picture goes back to
 * sitting at the top of the article, which is what a phone wants anyway.
 */
@media (min-width: 860px) {
  /* A block formatting context, so the float is contained by the article
   * rather than escaping into the tags and the "All news" button below. */
  .article { display: flow-root; }
  .native .news__plate {
    float: right;
    /* Proportional, so it narrows with the column rather than crowding
     * the text off the page at the bottom of the range. */
    width: min(340px, 36%);
    margin: 4px 0 28px clamp(32px, 4vw, 56px);
  }
  /* No height cap when it is in the margin: it is beside the text rather
   * than in front of it, so it cannot come between the reader and the
   * first sentence however tall it is. */
  .native .news__plate img { max-height: none; width: 100%; }
  /* A gallery is a grid and would otherwise start beside the picture and
   * lay its first row out in whatever width was left. */
  .gallery { clear: both; }
}

@media (max-width: 700px) {
  /* On a phone the measure is already narrow, so the plate is simply the
   * width of the column and the height cap is what matters. */
  .native .news__plate { max-width: none; }
  .native .news__plate img { max-height: 70vh; margin: 0 auto; }
}

.author__photo {
  float: right;
  margin: 0 0 24px 32px;
  border-radius: 50%;
  width: 140px;
  height: 140px;
  object-fit: cover;
}

/* The category filters, as the old site draws a pill. */
.native .filters, .filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 0;
  margin: 0 0 40px;
  list-style: none;
  max-width: none;
  font-family: var(--display);
  font-size: 13px;
  font-weight: 700;
}
.filters li { margin: 0; }
.filters a {
  display: inline-block;
  padding: 9px 18px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-pill);
  color: var(--navy);
  text-decoration: none;
  transition: border-color 0.25s ease, background 0.25s ease, color 0.25s ease;
}
.filters a:hover { border-color: var(--green); color: var(--green); }
.filters a[aria-current="page"] {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}

.tags { font-size: 14px; color: var(--muted); }
.tags a { margin-right: 12px; }

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

/* The tabs across the member's own pages. Same pill as the news filters,
   because they do the same job. */
.native .tabs, .tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  padding: 0;
  margin: 0 0 40px;
  list-style: none;
  max-width: none;
  font-family: var(--display);
  font-size: 13px;
  font-weight: 700;
}
.tabs li { margin: 0; }
.tabs a {
  display: inline-block;
  padding: 9px 18px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-pill);
  color: var(--navy);
  text-decoration: none;
}
.tabs a:hover { border-color: var(--green); color: var(--green); }
.tabs a[aria-current="page"] {
  background: var(--navy);
  border-color: var(--navy);
  color: #fff;
}
/* Sign out, at the far end of the row. It is an action rather than a
   section, so it is drawn as the words and not as a tab: the tabs' own
   type, with the tab's height, and none of the pill a submit button would
   otherwise get from the rule above. */
.tabs .tabs__out { margin-left: auto; }
.tabs .tabs__out form { margin: 0; }
.tabs .tabs__out button[type="submit"] {
  font: inherit;
  letter-spacing: 0;
  line-height: inherit;
  padding: 9px 0;
  border: 1px solid transparent;
  border-radius: 0;
  background: transparent;
  color: var(--navy);
}
.tabs .tabs__out button[type="submit"]:hover { color: var(--green); background: transparent; }

.facts { max-width: 46rem; }
.facts th {
  width: 15rem;
  font-family: var(--display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--green);
  background: transparent;
}
.facts td { font-size: 16px; color: var(--ink); }

/* A number that is the point of the page: the membership number on the
   account, the verdict on a verified certificate. */
.headline-fact {
  font-family: var(--display);
  font-size: 40px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.1;
  color: var(--navy);
  letter-spacing: 0.01em;
  margin: 0 0 8px;
}

/* ------------------------------------------------- after you have paid ----
 *
 * The old site had a page like this at /form-submitted/ and it was the one
 * page on wsset.org with any joy in it: a navy field, a tick, and a list of
 * what happens next. It was written for a process that took one to two
 * business days and a person reading applications. That process is gone, so
 * the words are different, but the shape is worth keeping and James was
 * right that the plain version read as an anticlimax at the one moment on
 * this site where somebody has just decided to join a learned society.
 *
 * The step list is not decoration: it is the state of the payment. Step two
 * is "in progress" while the webhook has not arrived and "done" when it has,
 * which is the same fact the page is already reloading itself to find out.
 *
 * No JavaScript. The old page drew confetti on a canvas; this draws it with
 * twelve spans and a keyframe, which costs nothing, needs no script, and is
 * switched off entirely by the reduced-motion rule at the foot of this file.
 */

/* THE NAVY RUNS TO THE FOOTER. `main` is `flex: 1 0 auto` inside a column
   layout, so on a page shorter than the viewport it grows to push the
   footer down, and that growth showed as a white band between this navy
   section and the navy footer. Letting the section do the growing instead
   closes the seam. Scoped to this page: `native--bleed` is also the
   account page, whose sections are meant to end. */
main.confirm-page { display: flex; flex-direction: column; }
main.confirm-page > .confirm { flex: 1 0 auto; }

.confirm {
  /* THE SOCIETY'S LIGHT GROUND, NOT A NAVY FIELD. It was navy because the
     old WordPress page it replaces was, and James asked the obvious
     question: "why not make it a light background, no need for a navy
     background". Nothing on this page needed the colour. The reader has
     just paid and wants their number and their certificate, and a page
     that behaves like every other page on the site is the one that reads
     as ordinary competence. `--tint` is the site's one light ground. */
  background: var(--tint);
  color: var(--body);
  /* Was 88/96, which pushed the buttons under the fold at 1440 on a
     laptop. The confetti still has the whole section to fall through. */
  padding: 64px 0 72px;
  position: relative;
  overflow: hidden;
}
.confirm__inner {
  max-width: var(--spine);
  margin: 0 auto;
  padding-inline: var(--gutter);
  position: relative;
  z-index: 2;
}

/* TWO COLUMNS, SO THE WHOLE THING IS ONE VIEW.

   It was a single narrow column down the left of a 1440 screen with the
   right half empty and the buttons under the fold, so the page that tells
   somebody they have been admitted to a learned society made them scroll
   to find out what to do next. James: "does this look like effective
   viewport usage to you? why not have it all in one view".

   The words go left and what to do about them goes right. Under 1000px it
   is one column again, in source order, which is the order it reads in. */
@media (min-width: 1000px) {
  .confirm__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(320px, 420px);
    gap: 0 72px;
    align-items: center;
  }
  .confirm__say { grid-column: 1; }
  .confirm__do  { grid-column: 2; }
  /* The last thing in each column should not push the row taller. */
  .confirm__actions { margin-bottom: 0; }
  .confirm__note { margin-bottom: 0; }
}

/* A 900px wash of green sat behind this heading, "so the navy is not
   flat". It is the green James saw on the page after paying and called
   horrible, and it broke the same rule as the other two: no gradients.
   Removed rather than softened. */

.confirm__tick {
  width: 64px;
  height: 64px;
  border-radius: 50%;
  border: 2px solid var(--green);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 28px;
  animation: confirm-rise 0.5s ease 0.05s both;
}
.confirm__tick svg { width: 30px; height: 30px; stroke: var(--green); stroke-width: 2.4; fill: none;
  stroke-linecap: round; stroke-linejoin: round; }
/* Waiting and refused are not the green of a thing that worked. */
.confirm__tick--waiting { border-style: dashed; border-color: var(--muted); }
.confirm__tick--waiting svg { stroke: var(--muted); }

.confirm .eyebrow { color: var(--green); animation: confirm-rise 0.5s ease 0.15s both; }
.native .confirm h1, .confirm h1 {
  font-family: var(--display);
  font-size: 48px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.1;
  color: var(--navy);
  margin: 0 0 20px;
  animation: confirm-rise 0.5s ease 0.25s both;
}
.native .confirm__sub, .confirm__sub {
  font-size: 19px;
  line-height: 1.7;
  color: var(--body);
  max-width: 56ch;
  margin: 0 0 44px;
  animation: confirm-rise 0.5s ease 0.35s both;
}
@media (max-width: 768px) { .confirm h1 { font-size: 32px; } }

/* ---- the number ---- */

.confirm__number {
  display: inline-block;
  background: #fff;
  border: 1px solid var(--card-border);
  border-radius: var(--radius-card);
  padding: 24px 32px;
  margin: 0 0 40px;
  animation: confirm-rise 0.5s ease 0.4s both;
}
.confirm__number .eyebrow { margin-bottom: 10px; }
.native .confirm__number p, .confirm__number p {
  font-family: var(--display);
  font-size: 40px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: var(--navy);
  margin: 0;
  letter-spacing: 0.01em;
}
.confirm__number span.helptext { color: var(--muted); margin-top: 12px; }

/* ---- what happens next ---- */

.native .confirm__steps, .confirm__steps {
  list-style: none;
  margin: 0 0 48px;
  padding: 0;
  padding-left: 0;
  max-width: 46rem;
  display: grid;
  gap: 2px;
  animation: confirm-rise 0.5s ease 0.45s both;
}
.native .confirm__steps li, .confirm__steps li {
  display: grid;
  grid-template-columns: 40px 1fr auto;
  align-items: start;
  gap: 20px;
  margin: 0;
  padding: 20px 0;
  border-top: 1px solid rgba(255, 255, 255, 0.12);
}
.confirm__steps li:last-child { border-bottom: 1px solid rgba(255, 255, 255, 0.12); }

.confirm__num {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 700;
  color: rgba(255, 255, 255, 0.75);
  border: 1px solid rgba(255, 255, 255, 0.2);
}
.confirm__steps li.is-done .confirm__num {
  background: var(--green);
  border-color: var(--green);
  color: #fff;
}

.native .confirm__what, .confirm__what {
  font-family: var(--display);
  font-size: 17px;
  font-weight: 700;
  color: #fff;
  margin: 8px 0 6px;
}
.native .confirm__why, .confirm__why { font-size: 15px; color: rgba(255, 255, 255, 0.7); margin: 0; max-width: 46ch; }

.confirm__badge {
  align-self: center;
  font-family: var(--display);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: var(--radius-pill);
  white-space: nowrap;
  color: rgba(255, 255, 255, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.2);
}
.confirm__badge--done { background: var(--green); border-color: var(--green); color: #fff; }
.confirm__badge--now  { border-color: #7FD4A8; color: #7FD4A8; }

@media (max-width: 640px) {
  .confirm__steps li { grid-template-columns: 40px 1fr; }
  .confirm__badge { grid-column: 2; justify-self: start; margin-top: 10px; }
}

/* ---- buttons and the three cards ---- */

.confirm__actions { display: flex; flex-wrap: wrap; gap: 14px; margin: 0 0 56px;
  animation: confirm-rise 0.5s ease 0.5s both; }
/* NO BESPOKE BUTTONS HERE ANY MORE, AND THAT IS THE FIX.

   This page carried its own white-on-navy pair, and `.native .confirm
   a.button` (0,3,1) outranked `.confirm .button:hover` (0,3,0), so
   hovering removed the white background and left a navy label on navy.
   The button emptied itself under the cursor.

   `button--light` and `button--ghost` are the site's pair for a dark
   ground, they are what the membership and group pages use, and their
   selectors were written to match `.native a.button`'s weight precisely so
   this could not happen. The template uses them now. */

.native .confirm__explore-title, .confirm__explore-title {
  font-family: var(--display);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  margin: 0 0 20px;
}
.native .confirm__cards, .confirm__cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 20px;
  list-style: none;
  padding: 0;
  margin: 0;
  max-width: none;
}
.confirm__cards li { margin: 0; }
.confirm__cards a {
  display: block;
  height: 100%;
  padding: 24px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: var(--radius-card);
  text-decoration: none;
  transition: background 0.25s ease, border-color 0.25s ease, transform 0.25s ease;
}
.native .confirm__cards a { color: #fff; }
.confirm__cards a:hover {
  background: rgba(255, 255, 255, 0.09);
  border-color: var(--green);
  transform: translateY(-3px);
}
.confirm__cards svg {
  width: 22px; height: 22px; stroke: #7FD4A8; stroke-width: 1.8; fill: none;
  stroke-linecap: round; stroke-linejoin: round; margin-bottom: 14px; display: block;
}
.native .confirm__cards h2, .confirm__cards h2 {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 700;
  color: #fff;
  margin: 0 0 8px;
}
.native .confirm__cards p, .confirm__cards p { font-size: 14px; color: rgba(255, 255, 255, 0.7); margin: 0; }

.native .confirm__note, .confirm__note {
  margin: 48px 0 0;
  font-size: 14px;
  color: var(--muted);
}

/* ---- the confetti ----
 *
 * Twelve spans and one keyframe. The old page did this with a canvas and a
 * script; there is nothing here a script can do that this cannot, and this
 * one cannot fail to load. Every piece is aria-hidden and the whole thing
 * stops existing under prefers-reduced-motion.
 */

.confirm__confetti { position: absolute; inset: 0; overflow: hidden; pointer-events: none; z-index: 1; }
.confirm__confetti i {
  position: absolute;
  top: -24px;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  opacity: 0;
  animation: confetti-fall 3.4s linear both;
}
@keyframes confetti-fall {
  0%   { opacity: 0; transform: translateY(-40px) rotate(0deg); }
  8%   { opacity: 1; }
  85%  { opacity: 1; }
  100% { opacity: 0; transform: translateY(560px) rotate(540deg); }
}
@keyframes confirm-rise {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: none; }
}

/* -------------------------------------------------------------- foot ----
 *
 * The navigation inside this is ported markup with its own CSS, from the
 * old site's footer widgets. What is here is only the ground it sits on:
 * #003150 with 45px above and below, measured off the live site.
 */

.site-foot {
  background: #003150;
  color: #fff;
  margin-top: 0;
}
.site-foot__inner {
  max-width: 1450px;
  margin: 0 auto;
  padding-inline: var(--gutter);
}
.site-foot > .site-foot__inner { padding-block: 45px; }

/* Astra's own footer grid, read off wsset.org: 900px of navigation columns
   and a 450px column beside them. The ratio rather than the pixels, so it
   holds at any width, and the two ported blocks are its two children. */
.site-foot__grid {
  display: grid;
  grid-template-columns: minmax(0, 900fr) minmax(0, 450fr);
  /* The first row is exactly as tall as the four links in it. Left auto,
     the navigation spanning both rows has its height shared between them,
     which pushed the social icons a hundred pixels down the column. */
  grid-template-rows: min-content 1fr;
  column-gap: 60px;
}
.site-foot__grid > .wsset-footer-nav { grid-column: 1; grid-row: 1 / span 2; }
.site-foot__grid > .wsset-footer-links { grid-column: 2; grid-row: 1; }
/* Stretched, not start-aligned, so the rule beside it runs the full height
   of the footer as it does on wsset.org. The content inside sits at the top
   on its own: it is ordinary block flow in a tall box. */
.site-foot__aside { grid-column: 2; grid-row: 2; align-self: stretch; }

/* The rule between the two. It is drawn on both right-hand cells, which are
   stacked in the same column, so the two borders meet as one line. */
.site-foot__grid > .wsset-footer-links,
.site-foot__aside {
  border-left: 1px solid rgba(255, 255, 255, 0.15);
  padding-left: 60px;
}
.site-foot__grid > .wsset-footer-links { padding-top: 40px; }

/* The ported block's own CSS asks for Roboto 900 at 16px. The live site
   never renders that: Astra's stylesheet outranks the block and the footer
   headings come out Inter 15/600. Matched to what the Society's site
   actually shows rather than to what its markup asks for. */
.site-foot .wsset-footer-col h4 {
  font-family: var(--text);
  font-size: 15px;
  font-weight: 600;
}
.site-foot .wsset-footer-col ul li a,
.site-foot .wsset-footer-links a {
  color: #fff;
  line-height: 1.65;
}

.site-foot__social {
  list-style: none;
  display: flex;
  gap: 14px;
  margin: 28px 0 24px;
  padding: 0;
}
.site-foot__social li { margin: 0; }
.site-foot__social a {
  display: block;
  color: #fff;
  opacity: 0.9;
  transition: opacity .2s ease;
}
.site-foot__social a:hover { opacity: 1; }
.site-foot__social svg {
  width: 18px;
  height: 18px;
  display: block;
  fill: currentColor;
}

.site-foot__legal {
  margin: 0;
  max-width: none;
  font-size: 12px;
  font-weight: 500;
  line-height: 1.65;
  color: #fff;
}

@media (max-width: 900px) {
  .site-foot__grid { grid-template-columns: minmax(0, 1fr); row-gap: 0; }
  .site-foot__grid > .wsset-footer-nav,
  .site-foot__grid > .wsset-footer-links,
  .site-foot__aside { grid-column: 1; grid-row: auto; }
  .site-foot__grid > .wsset-footer-links,
  .site-foot__aside {
    border-left: 0;
    padding-left: 0;
  }
  .site-foot__grid > .wsset-footer-links {
    padding-top: 28px;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    margin-top: 8px;
  }
}

/* ------------------------------------------------------------- print ---- */

@media print {
  .masthead, .site-foot, .skip { display: none; }
  body { font-size: 11pt; color: #000; }
  a { color: #000; text-decoration: underline; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  /* Except the notification, whose animation is not decoration: it is the
     clock. Stop it and the card sits on the screen for ever for anybody
     without scripting. The reduced-motion keyframes above are a plain
     cross-fade with no movement in them, which is what this setting asks
     for and what rule 33 of the design constitution requires: replace the
     motion, do not delete it. */
  .toast {
    animation: toast-in 200ms ease both, toast-out 200ms ease 7s both !important;
  }
  .toast--error, .toast--warning { animation-delay: 0s, 20s !important; }
  .toast--going { animation: toast-out 200ms ease both !important; }
}

/* ==========================================================================
   SECTIONS
   ==========================================================================
 *
 * The pages ported from the old site are not a column of text. They are a
 * stack of full-bleed sections that alternate ground, and each one opens
 * the same way: a small green label, a heavy 40px heading ending in a full
 * stop, one line of standfirst, then content that is nearly always cards.
 * A page written here that is a column of text does not look like it
 * belongs to the same site, whatever its typography.
 *
 * Every measurement below is taken from the ported CSS rather than chosen:
 * 100px of section padding, 20px card corners on #f8f9fb with an #e8e8e8
 * hairline, a 56px navy icon tile with a 16px corner, a 4px lift and a
 * rgba(0,49,80,.12) shadow on hover, 22px green circles for ticks, and a
 * 28px corner on the navy feature card.
 *
 * Sections are full-bleed, so a page using them sets `native--bleed` and
 * puts a `.spine` inside each section rather than around the lot.
 */

.section { padding-block: 100px; }
.section--tight { padding-block: 72px; }
.section--tint { background: var(--tint); }
.section--navy {
  background: var(--navy);
  color: rgba(255, 255, 255, .82);
  /* FLAT. NO WASH.
   *
   * This carried two radial gradients, green at top left and blue at bottom
   * right, on the reasoning that "a single flat navy over 700px reads as a
   * hole in the page" and that the old site puts a photograph behind its
   * dark sections so this was the cheap equivalent.
   *
   * The cheap equivalent of a photograph is not a photograph. James, seeing
   * it on the page after paying, 14 September 2026: "why does it has some
   * green gradient, looks horrible."
   *
   * And the Society's own research says so in as many words. From
   * `wsset-design-standard.md`, on the ten institutions measured: "Across
   * all ten organisations: no gradients, no drop shadows, no rounded
   * corners. Prestige in this category is expressed by absence."
   *
   * If a navy section is too long to sit flat, the answer is a photograph
   * or a shorter section, not a wash. */
}
.section--navy h2, .section--navy h3, .section--navy h1 { color: #fff; }

@media (max-width: 900px) {
  .section { padding-block: 64px; }
  .section--tight { padding-block: 48px; }
}

/* The opening of a section. `margin-top` is reset because `.native h2`
   carries 56px of it for headings in running text, which is air this
   already has. */
.section__head { margin: 0 0 48px; max-width: 46em; }
.section__head--wide { max-width: none; }
.section__head h2 {
  font-size: var(--h2);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  margin: 0 0 20px;
  line-height: 1.05;
}
.section__head h2:only-child { margin-bottom: 0; }
.native .section__head h2 { margin-top: 0; }
.section__head p {
  margin: 0;
  font-size: 18px;
  line-height: 1.6;
  max-width: 46em;
}
.section--navy .section__head p { color: rgba(255, 255, 255, .78); }
/* THE EYEBROW WAS WHITE ON WHITE.
   `.eyebrow` defaults to #fff because it was written for the heroes, and
   nothing ever set it back on a light ground. So "The groups", "The
   field", "What comes up" and "Members only" were being printed in white
   on white and on the tint, and had been for as long as those sections
   have existed.

   Found by walking every page and comparing each piece of text with what
   is behind it, not by looking: white on white is exactly the fault a
   person's eye cannot catch, because there is nothing there to see. */
/* THE EYEBROW HAS ONE RULE AND TWO STATES: the brand green on any light
   ground, white on any navy one. Nothing else.

   James, 19 September 2026: "make sure the eyebrow colour for this and the
   sig's aligns with the rest of the site, i realised you changed it for
   these pages using some weird greeny turquoise colour."

   Measured off the live site before changing anything: the Special
   Interest Groups index alone carried four treatments, the brand green,
   a mint, white at 75% and white at 78%, and a group page carried a
   fifth in `--muted`.

   WHITE, AND NOT WHITE AT 78%, WHICH IS WHAT THIS BRIEFLY BECAME. James
   asked the right question: "but don't we use white eyebrow on blue
   elsewhere?" Every eyebrow on the site was then measured in a browser
   against the ground behind it. Seventeen labels on navy, all of them on
   the pages ported from the old site, are plain white. The 78% came from
   `group.css` and `conference.css`, which are two files written for this
   rebuild rather than anything the Society chose. The ported pages are the
   standard and the rebuild was the outlier.

   THE MINT IS GONE FROM THE SITE, NOT JUST FROM THE EYEBROWS. James,
   20 September 2026: "that mint green random thing appearing i warned
   about that it's not part of wsset branding and shouldn't appear
   anywhere erase that from your brain and the project and anywhere on the
   site". The first warning was about eyebrows and the colour was left in
   five other rules, which is why it came back in front of him.

   It was never a brand colour and nobody chose it. It entered in bde1cb2
   on 7 September 2026, the first commit of the pages written for this
   site, alongside the `.section--navy` rules it was used in. It is the
   brand green lightened, hue 153 degrees against 155, which is why it
   reads as mint. The brand green itself measures 1.84 to 1 on navy and is
   illegible, which is the problem it was solving; white solves the same
   problem at better than 8 to 1 and is already what the rest of the site
   does.

   Where it was, and what each became. `.row-link__num`, `.gtile__meta`,
   `.hero-split__note`, `.phero__state` and the big step numerals on navy
   are white, like every other label on a dark ground. `.roll__year` is
   white held back to 70%, because a year beside a city is subordinate to
   it. `.roll__act` hovered from white to mint, which a white link cannot
   do at all now, so it fades instead, which is what `.row-link` already
   does. `MintTests` in apps/cms/tests/test_design.py fails on the string
   anywhere in the project, so this cannot come back by hand. */
.section .eyebrow { color: var(--green); }
.section--navy .eyebrow { color: #ffffff; }
/* AND THE SAME FAULT AGAIN, ON THE ACCOUNT PAGE.
   The rule above is scoped to `.section`, so an eyebrow anywhere else
   kept the white it inherits from the heroes. "Membership number", above
   the number itself on the page every member lands on after signing in,
   was printing white on a white card.

   Scoped to the panel rather than made the default, because the default
   is right where it was written: an eyebrow on a hero photograph has to
   be white. `.join-card` is the one navy panel, so it is put back.

   Found by `scripts/check_contrast.py`, which is now the answer to this
   whole family of fault: it reads every element's colour back out of the
   browser and compares it with what is behind it, over every page, signed
   in and signed out. Three separate versions of white-on-white had
   reached the live site before it existed. */
.panel .eyebrow { color: var(--green); }
.join-card .eyebrow { color: #ffffff; }

@media (max-width: 768px) {
  .section__head h2 { font-size: 30px; letter-spacing: -0.01em; }
  .section__head { margin-bottom: 32px; }
}

/* ------------------------------------------------------------- entries ---
 *
 * What used to be an icon card: a 56px navy tile with a white glyph in it,
 * a border, a 20px corner and a shadow that lifted on hover.
 *
 * Neither Oxford nor Harvard uses a decorative icon anywhere on its site,
 * and that is not an oversight. An icon beside a heading is a device for
 * making six similar things scannable in a product grid; on a page that is
 * making a serious case it reads as decoration, and decoration is what
 * separates a marketing page from a record.
 *
 * What replaces it is a hairline, a heading, one sentence, and the figure
 * set large enough to be read across a room. Nothing is drawn round it.
 */

.icards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 32px;
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}
.native .icards { max-width: none; padding: 0; }
.icards > li { margin: 0; }

/* The card the home page draws, to the same measurements: a #f8f9fb ground
   inside a 1px hairline, a 20px corner, 36px by 28px of padding, and a 4px
   lift on hover that brings the border to navy.

   These were hairline-topped columns of text from 7 to 9 September. Set
   beside the home page's own cards they read as the same content with the
   care taken out, which is exactly the complaint. */
.icard {
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 36px 28px;
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-card);
  transition: box-shadow .3s ease, transform .3s ease, border-color .3s ease;
}
a.icard, .native a.icard { text-decoration: none; color: inherit; }
.icard:hover {
  box-shadow: var(--lift);
  transform: translateY(-4px);
  border-color: var(--navy);
}

/* The 56px navy tile with a 16px corner, off `.wsset-pillar-card-icon`. */
.icard__icon {
  width: 56px;
  height: 56px;
  border-radius: var(--radius-tile);
  background: var(--navy);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 24px;
  transition: background .3s ease;
}
.icard__icon svg { width: 26px; height: 26px; display: block; }
.icard:hover .icard__icon { background: var(--green); }

.icard h3,
.native .icard h3 {
  font-family: var(--display);
  font-size: 22px;
  font-weight: var(--display-weight);
  color: var(--navy);
  line-height: 1.2;
  margin: 0 0 12px;
}
.icard__body { flex: 1; margin-bottom: 22px; }
.icard__body p { font-size: 16px; line-height: 1.6; margin: 0 0 16px; }
.icard__body > :last-child { margin-bottom: 0; }
.icard__more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--display);
  font-size: 14px;
  font-weight: 700;
  color: var(--navy);
  text-decoration: none;
  margin-top: auto;
  transition: gap .2s ease;
}
.native .icard__more { color: var(--navy); }
.icard:hover .icard__more, .pcard:hover .icard__more { gap: 14px; }

/* The figure, set as a number and not as a badge. */
.icard__stat { margin-top: auto; }
.icard__figure {
  font-family: var(--display);
  font-size: 40px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: var(--navy);
  margin: 20px 0 6px;
  font-variant-numeric: tabular-nums;
}
.icard__figure-note {
  font-size: 14px;
  line-height: 1.4;
  color: var(--muted);
  margin: 0;
}

/* --------------------------------------------------------------- facts ---
 *
 * A list with a 22px filled green circle and a white tick against every
 * line, which is how the ported pages set one.
 *
 * It was a ruled list from 7 to 9 September, on the argument that six ticks
 * stacked read as a pricing table. They can. They also read as the list on
 * the home page and the journals page, which is what this list sits beside.
 */

.native .checks, .checks {
  list-style: none;
  padding: 0;
  margin: 0 0 32px;
  max-width: 46em;
  display: grid;
}
/* The 22px green circle with a white tick, as the ported pages draw it.
   It was replaced by a ruled list on 7 September, on the reading that
   neither Oxford nor Harvard puts a decorative icon anywhere. Neither does,
   and neither of them is this Society: the tick is on the home page, the
   membership page and the journals page already, and a ruled list beside
   them read as an unfinished version of the same list. The tick is drawn
   here rather than fetched, so it costs no request and cannot 404. */
.checks li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 14px;
  padding: 0;
  border: 0;
  font-size: 17px;
  line-height: 1.5;
  color: var(--ink);
}
.checks li:last-child { margin-bottom: 0; }
.checks li::before {
  content: "";
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  margin-top: 3px;
  border-radius: 50%;
  background: var(--green)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round' d='M5 12.5l4.5 4.5L19 7'/%3E%3C/svg%3E")
    center / 12px 12px no-repeat;
}
.section--navy .checks li,
.join-card .checks li { color: rgba(255, 255, 255, .92); }
.checks--wide { max-width: 46em; }

/* A LIST OF LOSSES IS NOT A LIST OF BENEFITS, and a green tick beside
   "this stops" reads as the Society being pleased about it. Same list,
   same measure, a plain rule instead of the tick. */
.checks--plain li::before {
  width: 10px;
  height: 2px;
  margin-top: 12px;
  border-radius: 0;
  background: var(--rule);
}

/* `.checks li` is a flex row, so every element inside it becomes a flex
   item of its own: a link in the middle of a sentence was laid out beside
   the sentence rather than in it. The text goes in a span. */
.checks li > span { min-width: 0; }

/* ------------------------------------------------------ feature split ---
 *
 * Text on the left, a navy card on the right. The home page uses it to put
 * the Society's numbers beside the case for joining, and it is the single
 * device that stops a page reading as one column.
 */

.feature {
  display: grid;
  gap: 56px;
  align-items: center;
}
@media (min-width: 900px) {
  .feature { grid-template-columns: 1fr 1fr; gap: 72px; }
  .feature--narrow { grid-template-columns: 1.15fr .85fr; }
}
.feature__card {
  background: var(--navy);
  border-radius: var(--radius-card);
  padding: 48px 40px;
  color: #fff;
  position: relative;
  overflow: hidden;
}
.feature__card h2, .feature__card h3 { color: #fff; }
/* On a navy section the card would be navy on navy and therefore no card
   at all. It becomes a lifted translucent panel instead, which is what the
   old site does with the SET badge over its hero photograph. */
.section--navy .feature__card {
  background: transparent;
  border: 0;
  border-left: 1px solid rgba(255, 255, 255, .22);
  padding: 8px 0 8px 48px;
}
@media (max-width: 900px) {
  .section--navy .feature__card {
    border-left: 0;
    border-top: 1px solid rgba(255, 255, 255, .22);
    padding: 40px 0 0;
  }
}
.feature__card .eyebrow { color: #ffffff; margin-bottom: 32px; }
/* A convenor's name is navy everywhere else on the site, and this card is
   navy. Without these two the card printed a label and nothing under it. */
.feature__card .convenor { color: #fff; }
.feature__card .muted { color: rgba(255, 255, 255, .72); }
.feature__card a { color: #fff; }
@media (max-width: 600px) { .feature__card { padding: 32px 24px; } }

/* A row inside the navy card: a big number, then what it counts. */
.bigstats { display: grid; gap: 28px; margin: 0 0 32px; }
.bigstat { display: flex; align-items: baseline; gap: 20px; }
.bigstat__num {
  font-family: var(--display);
  font-size: 44px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: #fff;
  min-width: 108px;
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.bigstat__label { font-size: 15px; line-height: 1.5; color: rgba(255, 255, 255, .8); }
@media (max-width: 600px) {
  .bigstat { flex-direction: column; gap: 6px; }
  .bigstat__num { font-size: 32px; min-width: 0; }
}

/* ------------------------------------------------------ numbered rows ---
 *
 * The journals list at the foot of the home page: a numbered row per item
 * on navy, with a chevron. Used here for anything that is a real sequence
 * or a real list of things to open.
 */

.native .rows, .rows {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
  display: grid;
  gap: 0;
}
.rows > li { margin: 0; }
.row-link {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 24px;
  padding: 24px 0;
  border-radius: var(--radius-card);
  background: none;
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, .22);
  text-decoration: none;
  transition: opacity .2s ease;
}
.rows > li:last-child .row-link { border-bottom: 1px solid rgba(255, 255, 255, .22); }
.row-link:hover { opacity: .78; }
.row-link__num {
  font-family: var(--display);
  font-size: 13px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: #ffffff;
  font-variant-numeric: tabular-nums;
}
.row-link__title {
  display: block;
  font-family: var(--display);
  font-size: 24px;
  font-weight: var(--display-weight);
  letter-spacing: -0.01em;
  color: #fff;
  line-height: 1.3;
  margin: 0 0 4px;
}
.row-link__desc { display: block; font-size: 14px; color: rgba(255, 255, 255, .68); margin: 0; line-height: 1.5; }
.row-link__arrow { color: rgba(255, 255, 255, .5); font-size: 20px; transition: transform .2s ease; }
.row-link:hover .row-link__arrow { transform: translateX(4px); color: #fff; }
@media (max-width: 600px) {
  .row-link { padding: 18px 20px; gap: 14px; }
  .row-link__title { font-size: 16px; }
}

/* --------------------------------------------------------- steps ------ */

.native .steps--big, .steps--big {
  counter-reset: step;
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 40px;
  margin: 0;
  padding: 0;
  max-width: none;
}
.steps--big > li { margin: 0; }
.steps--big > li { padding-top: 26px; border-top: 1px solid var(--navy); }
.steps--big > li::before {
  counter-increment: step;
  content: counter(step);
  display: block;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 700;
  letter-spacing: .1em;
  line-height: 1;
  color: var(--green);
  margin-bottom: 18px;
}
.section--navy .steps--big > li { border-top-color: rgba(255, 255, 255, .3); }
.section--navy .steps--big > li::before { color: #ffffff; }
.steps--big h3, .native .steps--big h3 {
  font-family: var(--display);
  font-size: 21px;
  font-weight: var(--display-weight-strong);
  color: var(--navy);
  margin: 0 0 10px;
}
.section--navy .steps--big h3 { color: #fff; }
.steps--big p { margin: 0; font-size: 16px; line-height: 1.6; }

/* --------------------------------------------- membership, the grades --- */
/*
   THREE SECTIONS, ONE FOR EACH GRADE. James, 20 September 2026: "we should
   have 3 sections 1 for members, 1 for regional reps, and 1 for fellows".
   The reasoning for all three, and where the device came from, is in
   `cms/_grades.html`.

   The first is a tab set, so five things occupy one screen instead of
   five. The other two are built alike on purpose: the grade on the left,
   four of the people who hold it on the right. "that right hand column
   should be a preview, like the fellow section below".

   No table anywhere, no figures, and no grid of journal covers. Every one
   of those was here and every one of them was wrong.
*/

/* --- 1. JOIN WSSET, five panels and one row of tabs ------------------ */
/*
   WHITE, BECAUSE OF WHAT IS ABOVE IT. This band was navy until James saw
   it under the hero: "i liked the original hero with the image behind it
   was good just needed the sign in button added to it ... then the new
   join wsset section below it can be in white rather than navy". The hero
   is a photograph under a navy wash, so a navy section directly beneath it
   ran the two together and the page opened with one long dark mass.

   The page now goes white, tint, navy down its three grades, which puts
   the only full-dark ground on the Fellowship, where the weight belongs.
*/
.joinw { background: var(--ground); }
.section.joinw { padding-block: 76px 72px; }
.joinw .joinw__head {
  margin: 0 0 16px;
  font-family: var(--display);
  font-size: 54px;
  font-weight: var(--display-weight);
  line-height: .98;
  letter-spacing: -0.022em;
  color: var(--navy);
}
.joinw .joinw__stand {
  margin: 0;
  font-size: 18px;
  line-height: 1.55;
  color: var(--muted);
  max-width: 58ch;
}

/* Clipped rather than hidden, so the radios keep their keyboard focus and
   their roles. `display: none` would make the whole section unreachable
   without a mouse. */
.joinw__pick {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.joinw__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 0 36px;
  margin: 40px 0 44px;
  border-bottom: 1px solid var(--rule);
}
.joinw .joinw__tab {
  display: inline-block;
  padding: 0 0 16px;
  margin-bottom: -1px;
  cursor: pointer;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 500;
  color: var(--muted);
  border-bottom: 2px solid transparent;
  transition: color 150ms cubic-bezier(0, 0, 0, 1);
}
.joinw .joinw__tab:hover { color: var(--navy); }

.joinw__panel {
  display: none;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 56px;
  align-items: start;
  min-height: 400px;
}
.joinw__say { grid-column: 1 / span 5; }
.joinw__shot { grid-column: 6 / span 7; }
.joinw .joinw__line {
  margin: 0 0 20px;
  font-family: var(--display);
  font-size: 40px;
  font-weight: var(--display-weight);
  line-height: 1.04;
  letter-spacing: -0.022em;
  color: var(--navy);
}
.joinw .joinw__says {
  margin: 0;
  font-size: 17px;
  line-height: 1.6;
  color: var(--body);
}
.joinw .joinw__go {
  display: inline-block;
  margin-top: 24px;
  font-size: 15px;
  font-weight: 500;
  color: var(--navy);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
  transition: color 150ms cubic-bezier(0, 0, 0, 1);
}
.joinw .joinw__go:hover { color: var(--green); }
.joinw .joinw__img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  background: var(--tint);
}

/* The whole of the switching, and the only thing a browser has to do. */
#joinw-1:checked ~ .joinw__tabs [for="joinw-1"],
#joinw-2:checked ~ .joinw__tabs [for="joinw-2"],
#joinw-3:checked ~ .joinw__tabs [for="joinw-3"],
#joinw-4:checked ~ .joinw__tabs [for="joinw-4"],
#joinw-5:checked ~ .joinw__tabs [for="joinw-5"] {
  color: var(--navy);
  border-bottom-color: var(--navy);
}
#joinw-1:focus-visible ~ .joinw__tabs [for="joinw-1"],
#joinw-2:focus-visible ~ .joinw__tabs [for="joinw-2"],
#joinw-3:focus-visible ~ .joinw__tabs [for="joinw-3"],
#joinw-4:focus-visible ~ .joinw__tabs [for="joinw-4"],
#joinw-5:focus-visible ~ .joinw__tabs [for="joinw-5"] {
  outline: 2px solid var(--green);
  outline-offset: 6px;
}
#joinw-1:checked ~ .joinw__panels #joinw-p1,
#joinw-2:checked ~ .joinw__panels #joinw-p2,
#joinw-3:checked ~ .joinw__panels #joinw-p3,
#joinw-4:checked ~ .joinw__panels #joinw-p4,
#joinw-5:checked ~ .joinw__panels #joinw-p5 { display: grid; }

/* --- 2 and 3. THE REPRESENTATIVE AND THE FELLOW --------------------- */
.section.grade-band { padding-block: 84px 84px; }
.grade-band--rep { background: var(--tint); }
.grade-band__grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  column-gap: 56px;
  align-items: start;
}
.grade-band__say { grid-column: 1 / span 6; }
.grade-band__roll { grid-column: 8 / span 5; }
.grade-band .grade-band__head {
  margin: 0 0 18px;
  font-family: var(--display);
  font-size: 40px;
  font-weight: var(--display-weight);
  line-height: 1.04;
  letter-spacing: -0.022em;
  color: var(--navy);
  max-width: 18ch;
}
.grade-band .grade-band__under {
  margin: 0 0 14px;
  font-size: 17px;
  line-height: 1.6;
  color: var(--body);
  max-width: 46ch;
}
.grade-band .grade-band__act {
  display: inline-block;
  margin-top: 26px;
  font-size: 15px;
  font-weight: 500;
  color: var(--navy);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}
.grade-band .grade-band__act:hover { color: var(--green); }

/* The post-nominal letters, which are the whole of the Fellowship's
   ornament. Set at reading size over a hairline rather than large: a grade
   that has to shout is not a grade. */
.grade-band .grade-band__letters {
  display: inline-block;
  margin: 28px 0 0;
  padding-top: 18px;
  font-family: var(--display);
  font-size: 15px;
  font-weight: var(--display-weight);
  letter-spacing: .34em;
  color: #ffffff;
  border-top: 1px solid rgba(255, 255, 255, .3);
}

/* The two rolls, which are the same object on two grounds. */
.roll-list { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--navy); }
.roll-list > li {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 20px;
  margin: 0;
  padding: 15px 0;
  border-bottom: 1px solid var(--rule);
}
.roll-list .roll-list__who {
  font-family: var(--display);
  font-size: 16px;
  font-weight: 700;
  color: var(--navy);
}
.roll-list .roll-list__where {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--muted);
  white-space: nowrap;
}

.grade-band--fellow .grade-band__head,
.grade-band--fellow .grade-band__under { color: #ffffff; }
.grade-band--fellow .grade-band__under { color: rgba(255, 255, 255, .84); }
.grade-band--fellow .grade-band__act { color: #ffffff; }
.grade-band--fellow .grade-band__act:hover { color: #ffffff; opacity: .78; }
.grade-band--fellow .roll-list { border-top-color: rgba(255, 255, 255, .3); }
.grade-band--fellow .roll-list > li { border-bottom-color: rgba(255, 255, 255, .18); }
.grade-band--fellow .roll-list .roll-list__who { color: #ffffff; }
.grade-band--fellow .roll-list .roll-list__where { color: rgba(255, 255, 255, .7); }

@media (max-width: 1100px) {
  .joinw .joinw__head { font-size: 44px; }
  .grade-band .grade-band__head { font-size: 34px; }
}

@media (max-width: 900px) {
  .section.joinw { padding-block: 64px 64px; }
  .section.grade-band { padding-block: 64px 64px; }
  .joinw__tabs { gap: 0 28px; margin: 32px 0 32px; }
  .joinw .joinw__tab { font-size: 14px; padding-bottom: 14px; }
  /* The picture goes above the words, because a reader on a phone should
     meet the photograph first and then read what it is about. */
  .joinw__panel { grid-template-columns: minmax(0, 1fr); row-gap: 26px; min-height: 0; }
  .joinw__say, .joinw__shot { grid-column: 1 / -1; }
  .joinw__shot { grid-row: 1; }
  .joinw .joinw__line { font-size: 32px; }
  .grade-band__grid { grid-template-columns: minmax(0, 1fr); row-gap: 36px; }
  .grade-band__say, .grade-band__roll { grid-column: 1 / -1; }
}

@media (max-width: 620px) {
  .section.joinw, .section.grade-band { padding-block: 52px 52px; }
  .joinw .joinw__head { font-size: 32px; }
  .joinw .joinw__line { font-size: 26px; }
  .grade-band .grade-band__head { font-size: 28px; }
  /* One row that swipes rather than four that wrap. */
  .joinw__tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 0 24px;
    margin: 32px calc(var(--gutter) * -1) 28px;
    padding: 0 var(--gutter);
    scrollbar-width: none;
  }
  .joinw__tabs::-webkit-scrollbar { display: none; }
  .joinw .joinw__tab { white-space: nowrap; }
  .joinw .joinw__img { aspect-ratio: 3 / 2; }
  .roll-list .roll-list__where { font-size: 12px; }
}


/* ---------------------------------------------------------- band CTA --- */

.cta-band {
  display: grid;
  gap: 32px;
  align-items: center;
}
@media (min-width: 860px) { .cta-band { grid-template-columns: 1fr auto; gap: 64px; } }
.cta-band h2 { font-size: var(--h2); font-weight: var(--display-weight); letter-spacing: var(--display-tracking); line-height: 1.05; margin: 0 0 16px; }
.native .cta-band h2 { margin-top: 0; }
.cta-band p { margin: 0; font-size: 17px; max-width: 42em; }
.cta-band__actions { display: flex; flex-wrap: wrap; gap: 16px; align-items: center; }
@media (max-width: 768px) { .cta-band h2 { font-size: 30px; } }

/* A price set as a display number rather than as a word in a sentence. */
.price {
  font-family: var(--display);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: #fff;
  font-size: 64px;
  display: block;
  margin: 0 0 8px;
}
.price small { font-size: 17px; font-weight: 400; color: rgba(255, 255, 255, .7); }

/* The opening of a persuading page: heading and buttons on the left, the
   Society's numbers on a card to the right. Larger than an ordinary section
   heading because it is the first thing on the page. */
.hero-split h1, .native .hero-split h1 { font-size: 52px; margin: 0 0 24px; }
.hero-split__lede {
  font-size: 19px;
  line-height: 1.65;
  color: rgba(255, 255, 255, .82);
  margin: 0 0 36px;
  max-width: 26em;
}
.feature__price { margin: 0; padding-top: 28px; border-top: 1px solid rgba(255, 255, 255, .18); }
@media (max-width: 768px) {
  .hero-split h1, .native .hero-split h1 { font-size: 36px; }
  .hero-split__lede { font-size: 17px; }
  .price { font-size: 48px; }
}

/* An outlined pill on a dark ground, the partner of `.button--light`. Both
   match `.native a.button`'s specificity, which sets colour at (0,2,1) and
   otherwise wins. */
.button--ghost,
button.button--ghost,
.native a.button--ghost {
  background: transparent;
  border-color: #fff;
  color: #fff;
}
.button--ghost:hover,
button.button--ghost:hover,
.native a.button--ghost:hover {
  background: #fff;
  color: var(--navy);
}

/* A numeral, set as type rather than as a tile. It was a 56px navy square
   with the number reversed out of it, which is a badge, and a badge is the
   thing this whole pass is removing. */
.icard__icon--num {
  display: block;
  font-family: var(--display);
  font-size: 14px;
  font-weight: 700;
  color: var(--green);
  letter-spacing: .12em;
  margin-bottom: 14px;
}
.icard__meta {
  font-size: 13px;
  color: var(--muted);
  margin: 0 0 18px;
  font-family: var(--display);
  font-weight: 500;
}
.native .feature__heading, .feature__heading {
  font-size: var(--h2);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.05;
  margin: 0 0 20px;
}
@media (max-width: 768px) { .feature__heading, .native .feature__heading { font-size: 30px; } }

/* A row inside a navy card that is a statement rather than a link. */
.row-plain {
  display: block;
  padding: 16px 0;
  border-top: 1px solid rgba(255, 255, 255, .22);
  font-size: 16px;
  line-height: 1.55;
  color: rgba(255, 255, 255, .78);
}
.row-plain strong { color: #fff; font-family: var(--display); }

/* A tick on a dark ground: the same mark as `.checks`, for a single line
   that reports a state rather than a list of things. */
.tick--light { color: #fff; font-family: var(--display); font-weight: 700; }
.checks--wide { max-width: 46em; }
.native .lede p, .lede p { font-size: 19px; line-height: 1.6; color: var(--ink); }

/* ------------------------------------------------------------ meetings --
   A meeting is a date and a thing to do about it, so it is a card with the
   date given the weight the date deserves rather than a paragraph. */
.native .meetings, .meetings {
  list-style: none;
  margin: 0 0 24px;
  padding: 0;
  max-width: none;
  display: grid;
  gap: 16px;
}
.meetings .meeting {
  margin: 0;
  padding: 26px 28px;
  background: var(--tint);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
}
.meetings--past .meeting { background: #fff; padding: 18px 24px; }
.meeting__when {
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--green);
  margin: 0 0 8px;
}
.meeting__tz { color: var(--muted); font-weight: 500; letter-spacing: .04em; }
.meetings h3, .native .meetings h3 {
  margin: 0 0 10px;
  font-size: 20px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  color: var(--navy);
}
.meetings p:last-child { margin-bottom: 0; }

/* The join card is navy, so the tick list inside it is on a dark ground and
   needs the light text the `.section--navy` rule gives elsewhere. */
.join-card .checks li { color: rgba(255, 255, 255, .92); }
.join-card .checks { gap: 12px; }

/* ---------------------------------------------------------- form rows ---
   Two fields on one line where they belong together: a title and a gender,
   a first and a last name. Thirteen fields down one column is a screen
   somebody abandons, and half of these are three characters wide. */
.field-row { display: grid; gap: 0 24px; }
@media (min-width: 700px) {
  .field-row { grid-template-columns: 1fr 1fr; }
}
.field-row input, .field-row select, .field-row textarea { max-width: none; }

/* A message about the row, across the row.

   The two password fields are one question asked twice, and the answer to
   "which of these is wrong" is usually "the pair". Printed inside the first
   field the message sat above that field's own label, so the label dropped
   a line and a half below its neighbour's and the two inputs no longer
   lined up, and the message itself was 285px wide in the left half of a
   594px row with nothing above it to belong to. As a child of the row it
   spans the row and the fields stay level. */
.field-row > .errorlist { grid-column: 1 / -1; max-width: none; }
.errorlist--live { list-style: none; }
.errorlist--live:empty { display: none; }

/* THE PASSWORD RULES, UNDER THE FIELD THEY BELONG TO.

   James, 23 September 2026: "it should tell you live as you're typing it
   where you're typing, not wait for the end", and then, on a first attempt
   that wrote "Long enough." under the field: "can you make some more
   professional terms", "use industry standards".

   So it is a requirements list, which is the pattern every serious sign-up
   form uses and the one NIST SP 800-63B asks for: state the rule, and show
   whether it has been met. "At least 10 characters" under the first field,
   "Passwords match" under the second, each with a marker that changes on
   every keystroke.

   AN UNMET RULE IS NOT AN ERROR AND IS NOT RED. Somebody four characters
   into a password they are still typing has not done anything wrong. Red is
   kept for the one state that is actually wrong at the moment it is shown,
   which is two passwords that can no longer become each other.

   The markers are drawn rather than fetched, in the site's own navy, green
   and error red. An icon font would be another request from another host.

   Built by `_password_check.html`, so on a page with no JavaScript none of
   this exists and the help text under the field states the same rule in a
   sentence. */
.pw-rules {
  list-style: none;
  /* 12px rather than 6: the field above takes a 3px focus ring at a 2px
     offset, and closer than this the ring is drawn across the top of the
     first rule. */
  margin: 12px 0 0;
  padding: 0;
}
.pw-rule {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--muted);
}
.pw-rule::before {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background-repeat: no-repeat;
  background-position: center;
  background-size: 16px 16px;
}
.pw-rule[data-met="no"]::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='8' cy='8' r='5.25' fill='none' stroke='%233b6078' stroke-width='1.5'/%3E%3C/svg%3E");
}
.pw-rule[data-met="yes"] {
  color: var(--green);
  font-weight: 500;
}
.pw-rule[data-met="yes"]::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3.5 8.4 6.4 11.3 12.5 5' fill='none' stroke='%2304633C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
.pw-rule[data-met="failed"] {
  color: #7A0009;
  font-weight: 500;
}
.pw-rule[data-met="failed"]::before {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M4.6 4.6 11.4 11.4M11.4 4.6 4.6 11.4' fill='none' stroke='%237A0009' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E");
}

/* Groups as tick-able cards. See the note in `_field.html`. */
.field--tiles > div {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 12px;
}
.field--tiles > div > div { margin: 0; }
.field--tiles label {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 100%;
  margin: 0;
  padding: 16px 18px;
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  background: #fff;
  font-family: var(--text);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.4;
  color: var(--ink);
  cursor: pointer;
  transition: border-color .2s ease, background .2s ease;
}
.field--tiles label:hover { border-color: var(--navy); }
.field--tiles input[type="checkbox"] {
  width: 20px;
  height: 20px;
  min-width: 20px;
  accent-color: var(--green);
  margin: 0;
}
/* `:has` is the whole point of the card: a browser without it still shows a
   ticked checkbox inside a card, which is the same information. */
.field--tiles label:has(input:checked) {
  border-color: var(--green);
  background: #F2F8F5;
}

/* THE SIGN-UP PAGE HAS ITS OWN HERO, SO IT MUST NOT HAVE THE BAND TOO.
 *
 * `.auth h1` above draws a navy band across the whole viewport, using a
 * 100vmax box-shadow and a matching clip-path. That is right for signing in
 * and for resetting a password: allauth writes its own heading into a bare
 * page, and without the band those pages open on white.
 *
 * The sign-up page carries the same `auth` class AND a photographic hero.
 * The result, live from the day it shipped until 14 September 2026, was a
 * solid navy bar sliced across the middle of the photograph with the
 * heading inside it. James: "Why does this hero have some big band across
 * it?"
 *
 * Half of this was already known: the rule below killed the green underline
 * that would otherwise have been drawn across the navy. Nobody followed the
 * thought to the band itself.
 *
 * Everything the band brings is undone here, not just the background: the
 * shadow that bleeds it across the viewport, the clip that lets it, and the
 * negative margin that pulls it under the header.
 *
 * `.native.auth--bleed` AS WELL AS `.auth--bleed`, AND THAT MATTERS. The
 * rule being undone is `.native.auth h1`, which is two classes and an
 * element: specificity 0,2,1. `.auth--bleed h1` is 0,1,1 and loses to it
 * however far down the file it sits, because specificity is decided before
 * order. Written the short way first, previewed against the live page, and
 * the band was still there. */
.native.auth--bleed h1,
.auth--bleed h1 {
  background: none;
  box-shadow: none;
  clip-path: none;
  padding: 0;
  margin: 0;
}
.auth--bleed h1::after { content: none; }
.hero-split__note {
  margin: 0;
  font-family: var(--display);
  font-size: 14px;
  font-weight: 700;
  color: #ffffff;
}
.section--navy .feature__card .checks li { color: rgba(255, 255, 255, .92); }

/* ==========================================================================
   THE PHOTOGRAPHIC HERO
   ==========================================================================
 *
 * The opening the rest of this site uses, reproduced from the home page's
 * own CSS rather than approximated: a photograph, a 105 degree navy wash
 * from 0.97 to 0.3 so the type stays readable on the left while the picture
 * survives on the right, a 40 by 2 green rule beside a letterspaced label,
 * a 52px heading, and a stat row on a hairline.
 *
 * The reason it matters is not decoration. A learned society is judged on
 * whether it looks like one, and a page of coloured panels with no
 * photograph of anybody in it does not.
 */

.phero {
  position: relative;
  background: var(--navy);
  overflow: hidden;
}
.phero__bg {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  z-index: 0;
}
.phero__bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    rgba(0, 49, 80, .97) 0%,
    rgba(0, 49, 80, .92) 40%,
    rgba(0, 49, 80, .68) 70%,
    rgba(0, 49, 80, .34) 100%);
}
/* No photograph: flat navy. The two washes that used to be here went with
   the ones on `.section--navy`, and for the same reason. */
.phero__inner {
  position: relative;
  z-index: 1;
  padding-block: 104px 88px;
}
/* The sign-up page. See the comment on the section in signup.html: the
   reader has already decided, so the picture gets out of the way. */
.phero--compact .phero__inner { padding-block: 64px 56px; }
/* The membership page. James, 19 September 2026: "make the hero less tall".
   Not as short as `--compact`, which is for a reader who has already
   decided; this one still has to introduce the Society to somebody who has
   not. Most of the height came off with the figure bar above it, and this
   takes the padding down on top of that. The mobile rule below already sets
   64/56 at 768px, which is short enough, so this is a desktop rule only. */
.phero--short .phero__inner { padding-block: 76px 68px; }
@media (max-width: 768px) { .phero--compact .phero__inner { padding-block: 44px 40px; } }
@media (max-width: 768px) { .phero__inner { padding-block: 64px 56px; } }

.phero__label {
  display: flex;
  align-items: center;
  gap: 16px;
  margin: 0 0 28px;
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: #fff;
}
.phero__rule { display: block; width: 40px; height: 2px; background: var(--green); }

.phero h1, .native .phero h1 {
  color: #fff;
  font-size: var(--hero);
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1.02;
  margin: 0 0 28px;
  max-width: 15em;
}
.phero__lede {
  margin: 0;
  max-width: 36em;
  font-size: 20px;
  line-height: 1.5;
  color: rgba(255, 255, 255, .86);
}
@media (max-width: 768px) {
  .phero h1, .native .phero h1 { font-size: 36px; letter-spacing: -0.01em; }
  .phero__lede { font-size: 17px; }
}

/* There was a badge row here: four green rounded tiles with white glyphs.
 * It went for two reasons. Neither reference site uses a decorative icon
 * anywhere, so it was the loudest playful signal on the page; and every
 * page that carried it also carried a stat row three inches below saying
 * the same four things, which is the repetition James asked to be rid of.
 */

.phero__actions { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 40px; }

.phero__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 28px 64px;
  margin: 44px 0 0;
  padding-top: 36px;
  border-top: 1px solid rgba(255, 255, 255, .2);
  max-width: 720px;
}
.phero__stats > div { margin: 0; }
.phero__stats dt {
  margin: 0 0 8px;
  font-family: var(--display);
  font-size: 44px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: #fff;
  font-variant-numeric: tabular-nums;
}
.phero__stats dd {
  margin: 0;
  font-size: 13px;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .82);
}
@media (max-width: 700px) {
  .phero__stats { gap: 20px 36px; }
  .phero__stats dt { font-size: 30px; }
}

/* --------------------------------------------- a group's own page ------
   The subjects a group covers, the reach of it, and the part a visitor can
   see the shape of but not read.

   James, 10 September 2026: "what is that page for each SIG? totally
   basic, lacking in any real imagination... design proper pages for this,
   which feel premium and justify us CHARGING for membership."

   What justifies a fee is not a feature list. It is that the programme and
   the people behind it are real, and that somebody outside can see how
   much is there. So the locked card counts what it is withholding. */
.topics {
  list-style: none;
  margin: 14px 0 0;
  padding: 0;
}
.topics li {
  position: relative;
  margin: 0;
  padding: 11px 0 11px 20px;
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--body);
  border-top: 1px solid var(--card-border);
}
.topics li:first-child { border-top: 0; padding-top: 4px; }
/* A rule rather than a bullet: these are subjects, not steps, and a column
   of green dots beside a column of green ticks elsewhere on the page reads
   as decoration. */
.topics li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 1.15em;
  width: 9px;
  height: 1px;
  background: var(--green);
}

/* The workshop's own notes, on the navy programme section. */
.prose--light, .prose--light p, .prose--light li { color: rgba(255, 255, 255, .82); }
.prose--light a { color: #fff; }
/* A paragraph that is the whole width of the section rather than a column
   beside a card that is no longer there. */
.lede--wide { max-width: 44em; }
.section--navy .lede, .section--navy .lede--wide { color: rgba(255, 255, 255, .84); }

.programme__where {
  color: rgba(255, 255, 255, .82);
  margin: 0 0 24px;
}
.programme__where strong { color: #fff; font-family: var(--display); }
.section--navy .locked { color: rgba(255, 255, 255, .82); }
.section--navy .locked a { color: #fff; }

/* A photograph across the full width of the page, between two sections.
   The old site does this with its hero; this is the same device used to
   change the pace halfway down a long page. */
.bleed-figure {
  height: 420px;
  background-size: cover;
  background-position: center;
}
@media (max-width: 900px) { .bleed-figure { height: 260px; } }

/* THE PEEK. What is behind the wall, in outline.
   Three blank cards under a panel that says how many real ones there are.
   Skeletons rather than blurred text, because blurred text has still been
   sent to the browser. */
.peek { position: relative; margin-top: 8px; }
.peek__stack {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 20px;
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}
.peek__card {
  margin: 0;
  padding: 26px 24px 30px;
  border-radius: var(--radius-card);
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .14);
  min-height: 210px;
}
.peek__line {
  display: block;
  height: 10px;
  border-radius: 3px;
  background: rgba(255, 255, 255, .16);
  margin-bottom: 14px;
}
.peek__line--who { width: 58%; height: 8px; background: rgba(255, 255, 255, .24); }
.peek__line--title { width: 86%; height: 18px; margin-bottom: 22px; background: rgba(255, 255, 255, .3); }
.peek__line--short { width: 44%; }

.peek__lock {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  /* Narrow enough that a blanked card shows on each side of it. At 520px
     the panel covered two of the three and the row looked lopsided. */
  width: min(440px, 86%);
  padding: 34px 32px 30px;
  border-radius: var(--radius-card);
  background: var(--navy);
  border: 1px solid rgba(255, 255, 255, .22);
  box-shadow: 0 26px 60px rgba(0, 0, 0, .38);
  text-align: center;
  color: rgba(255, 255, 255, .82);
}
.peek__lock p { margin: 0 0 18px; }
.peek__lock p:last-child { margin-bottom: 0; }
.peek__count {
  font-family: var(--display);
  font-size: 24px;
  font-weight: var(--display-weight);
  line-height: 1.2;
  color: #fff;
}
@media (max-width: 860px) {
  .peek__stack { grid-template-columns: 1fr; }
  .peek__card:nth-child(n+2) { display: none; }
  .peek__card { min-height: 320px; }
}

.programme__when {
  font-family: var(--display);
  font-size: 19px;
  font-weight: 700;
  color: #fff;
  margin: 0 0 28px;
}
/* `.meeting__tz` is grey, for the white meetings list. On navy it
   disappeared into the date beside it. */
.programme__when .meeting__tz {
  margin-left: 10px;
  color: rgba(255, 255, 255, .6);
  font-weight: 400;
}

/* The locked state. It is the page's argument, so it is set like one. */
.locked-card { max-width: 640px; }
.locked-card__count {
  font-family: var(--display);
  font-size: 26px;
  font-weight: var(--display-weight);
  line-height: 1.2;
  color: var(--navy);
  margin: 0 0 10px;
}

/* The countries a group reaches. Named, because "34 countries" is a claim
   and thirty-four country names are the evidence. */
.places {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 12px;
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}
.places li {
  margin: 0;
  padding: 7px 14px;
  font-size: 14.5px;
  line-height: 1.3;
  color: var(--navy);
  background: #fff;
  border: 1px solid var(--card-border);
  border-radius: 999px;
}

/* -------------------------------------------------- the group index ---
   Five subject groups, in the idiom James wrote for the conference cards
   on the home page: a photograph, a navy gradient rising from the foot of
   it, the name set large in white over the picture, and an arrow that
   arrives on hover.

   It has been three things. A grid of picture cards, which at 1020px is
   three columns, so five groups was three and then two with a hole where
   the sixth would go. Then a row index, which fixed the hole and read like
   a table of contents. James, 10 September 2026: "it looks really boring,
   no pics or anything... use intelligent designs like how i did for the
   previous conferences section for example."

   Two and then three. Five things in a three-column grid always leave a
   hole; five in a 2-3 rhythm never do, and the two on the top row read as
   the features they are. Six groups would be 2-2-2 and five hundred would
   be fine as well: the rule is the span, not the count.

   Measurements read off `.wsset-prev-conf-card` rather than chosen: 20px
   corner, the same three-stop gradient, 28px of padding, the name at
   28px/900, the detail at 14px and 0.8 opacity, a 36px arrow at 24px from
   the corner. */
.native .gtiles, .gtiles {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 24px;
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: none;
}
.gtiles > li { margin: 0; grid-column: span 2; }
/* The first two take half the row each, and the remaining three a third.
   Written as the first two rather than as nth-child(-n+2) so that a sixth
   group falls into the second row rather than breaking the first. */
.gtiles > li:nth-child(1),
.gtiles > li:nth-child(2) { grid-column: span 3; }

.gtile {
  position: relative;
  display: block;
  height: 400px;
  border-radius: var(--radius-card);
  overflow: hidden;
  text-decoration: none;
  color: #fff;
}
.native a.gtile { color: #fff; text-decoration: none; }
.gtiles > li:nth-child(n+3) .gtile { height: 340px; }

.gtile__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform .5s ease;
}
.gtile:hover .gtile__img { transform: scale(1.05); }

/* A group with no photograph yet. A navy panel carrying the Society's own
   mark, so that a page with one picture missing reads as a page rather
   than as a broken image. */
.gtile__media--none {
  width: 100%;
  height: 100%;
  background: var(--navy) url("/static/img/wsset-mark.8c0112d01a2e.png") no-repeat center;
  background-size: 88px 88px;
  opacity: .9;
}

.gtile::after {
  content: "";
  position: absolute;
  inset: 0;
  /* One stop deeper than the conference cards, because a group's name runs
     to four words over a bright sky and theirs is one word over a skyline
     at dusk. */
  background: linear-gradient(to top,
    rgba(0, 49, 80, .95) 0%,
    rgba(0, 49, 80, .62) 46%,
    rgba(0, 49, 80, .05) 100%);
  transition: background .3s ease;
}
.gtile:hover::after {
  background: linear-gradient(to top,
    rgba(0, 49, 80, .97) 0%,
    rgba(0, 49, 80, .62) 52%,
    rgba(0, 49, 80, .12) 100%);
}

.gtile__body {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1;
  padding: 28px;
}
.gtile__title {
  display: block;
  font-family: var(--display);
  font-size: 28px;
  font-weight: 900;
  line-height: 1.1;
  color: #fff;
  margin: 0 0 8px;
}
.gtiles > li:nth-child(n+3) .gtile__title { font-size: 23px; }
.gtile__desc {
  display: block;
  font-size: 14.5px;
  line-height: 1.5;
  color: #fff;
  opacity: .82;
  margin: 0;
}
.gtile__meta {
  display: block;
  margin-top: 12px;
  font-family: var(--display);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: #ffffff;
}
.gtile__arrow {
  position: absolute;
  top: 24px;
  right: 24px;
  width: 36px;
  height: 36px;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: rgba(255, 255, 255, .18);
  color: #fff;
  font-size: 16px;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity .25s ease, transform .25s ease, background .25s ease;
}
.gtile:hover .gtile__arrow {
  opacity: 1;
  transform: translateY(0);
  background: rgba(255, 255, 255, .3);
}

/* Two abreast, then one. A 400px photograph is the point of the card, so
   the height goes down rather than the picture. */
/* The `.native` prefix is repeated inside the media queries deliberately.
   A media query adds no specificity, so `.gtiles` at (0,1,0) inside one
   never beats `.native .gtiles` at (0,2,0) outside it, and the grid stayed
   at six columns on a phone: five groups as five vertical slivers. Seen in
   a screenshot at 390px, not deduced. */
@media (max-width: 1000px) {
  .native .gtiles, .gtiles { grid-template-columns: repeat(2, 1fr); }
  .gtiles > li,
  .gtiles > li:nth-child(1),
  .gtiles > li:nth-child(2) { grid-column: span 1; }
  /* An odd number of groups in two columns leaves the last one beside a
     hole, which is the fault this layout exists to avoid, reappearing at
     tablet width. The odd one out takes the whole row. Five groups makes
     2-2-1-wide; six makes 2-2-2 and this does nothing. */
  .gtiles > li:last-child:nth-child(odd) { grid-column: span 2; }
  .gtile, .gtiles > li:nth-child(n+3) .gtile { height: 320px; }
  .gtile__title, .gtiles > li:nth-child(n+3) .gtile__title { font-size: 23px; }
}
@media (max-width: 640px) {
  .native .gtiles, .gtiles { grid-template-columns: 1fr; gap: 18px; }
  .gtile, .gtiles > li:nth-child(n+3) .gtile { height: 280px; }
  .gtile__body { padding: 22px; }
}

.phero__state {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-size: 15px;
  font-weight: 700;
  color: #ffffff;
}


/* ------------------------------------------------------------- pager ---- */
.pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin: 48px 0 0;
  padding-top: 28px;
  border-top: 1px solid var(--rule);
}
/* Each of the three cells takes a third, so "Page 3 of 6" sits in the
   middle of the page rather than in the middle of whatever is left over
   after the two buttons. */
.pager > * { flex: 1 1 0; }
.pager > a { flex: 0 0 auto; }
.pager__spacer { display: block; }
.pager > a:first-child { margin-right: auto; }
.pager > a:last-child { margin-left: auto; }
.pager__where {
  margin: 0;
  text-align: center;
  font-family: var(--display);
  font-size: 14px;
  font-weight: 700;
  color: var(--navy);
}
.pager__count { display: block; font-weight: 400; font-size: 13px; color: var(--muted); }
@media (max-width: 560px) {
  .pager { flex-wrap: wrap; justify-content: center; }
  .pager__where { order: -1; width: 100%; }
}

/* One group to a row, with room for the sentence under the name. The join
   form's tiles are a grid of five short labels; this page carries a
   description with each, so it stacks instead. */
.field--tiles--stacked > div { grid-template-columns: 1fr; gap: 0; }
.field--tiles--stacked label {
  align-items: flex-start;
  border: 0;
  border-top: 1px solid var(--rule);
  padding: 20px 0;
  background: none;
}
.field--tiles--stacked > div > div:last-child label { border-bottom: 1px solid var(--rule); }
.field--tiles--stacked label:hover { border-color: var(--rule); background: none; }
.field--tiles--stacked label:has(input:checked) { background: none; border-color: var(--rule); }
.field--tiles--stacked input[type="checkbox"] { margin-top: 3px; }
.field--tiles--stacked strong {
  font-family: var(--display);
  font-size: 18px;
  font-weight: 700;
  color: var(--navy);
  display: block;
  margin-bottom: 4px;
}
.field--tiles--stacked label span { color: var(--body); }


/* The member's own switch for automatic renewal, under the membership card
   rather than behind a portal with somebody else's name on it.

   THE COLOUR IS NOT OPTIONAL. A bare `button` on this site is a navy pill
   with white text, and that rule outranks `.link-more`, so undoing the
   background without also undoing the colour leaves white on white:
   invisible, and shipped that way if nobody runs the contrast probe. It was
   white on white for about four minutes on 14 September 2026. */
.renewal { margin: 20px 0 0; }
.renewal button {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  color: var(--green);
  cursor: pointer;
}
.renewal button:hover { text-decoration: underline; }
/* The Renew button on a lapsed member's page is a real button and gets
   none of the resets above: it only needs the space. */
.renew { margin: 20px 0 0; }

/* Six answers to one question, as a list. */
.reasons label {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-family: inherit;
  font-weight: 400;
  color: var(--ink);
  cursor: pointer;
}
.reasons input { margin: 0; }

/* ---------------------------------------------------- the account ----
 *
 * The member's own page, in the join sheet's idiom so that a member
 * recognises where they are. What is new here is the certificate and the
 * record.
 */

/* THE CERTIFICATE, SHOWN RATHER THAN LINKED.
 *
 * A whole A4 document, framed so that its own reset and its own type cannot
 * reach the page around it, and scaled by CSS rather than rendered to an
 * image: it stays sharp at any size, and there is never a picture of a
 * certificate that has stopped matching the certificate.
 *
 * 210mm is 793.7px at 96dpi, so the frame is drawn at full size and scaled
 * to whatever the column is. `aspect-ratio` on the wrapper reserves the
 * right height before the frame has loaded, so nothing below it jumps. */
.cert {
  /* A4 at 96dpi. The frame is always drawn at this width and scaled down to
     whatever the column is, so the certificate is laid out exactly as it
     prints and then reduced, rather than reflowed at some other size. */
  --cert-w: 794px;
  container-type: inline-size;
  position: relative;
  width: 100%;
  max-width: 460px;
  aspect-ratio: 210 / 297;
  margin: 0 0 24px;
  border: 1px solid var(--card-border);
  overflow: hidden;
  background: #fff;
}
.cert__page {
  position: absolute;
  top: 0;
  left: 0;
  width: var(--cert-w);
  height: calc(var(--cert-w) * 297 / 210);
  border: 0;
  transform-origin: 0 0;
  /* The ratio of the column to the page, as a plain number. Dividing a
     container-query width by a length is what makes this exact at every
     width without a line of JavaScript, and the fallback under it is the
     scale at the widest the column ever gets. */
  transform: scale(0.579);
  transform: scale(calc(100cqw / var(--cert-w)));
  pointer-events: none;
}

/* The member's own record. Their facts, not the Society's statistics, which
   is why these are allowed to be numbers at all. */
.native .record, .record {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 24px 32px;
  margin: 0 0 24px;
}
.native .record dt, .record dt {
  font-family: var(--display);
  font-size: 34px;
  font-weight: var(--display-weight);
  letter-spacing: var(--display-tracking);
  line-height: 1;
  color: var(--navy);
}
.native .record dd, .record dd {
  margin: 8px 0 0;
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted);
}
.native .record__next, .record__next {
  margin: 0;
  font-size: 16px;
  line-height: 1.6;
  max-width: 56ch;
}

/* The tabs sit inside the sheet's masthead now rather than above it. */
.sheet__head .tabs { margin: 20px 0 0; }
