/* ===========================================================================
   GDTC member platform - the whole stylesheet.

   Hand written, no framework, no build step. One file, eighteen numbered
   sections, loaded by every page in platform/public/ and by the invoice that
   server.js composes.

   Three rules run through all of it and are worth stating once rather than
   apologising for eighteen times:

   1. DARK ONLY. There is no light mode, no prefers-color-scheme block and no
      [data-theme] switch. The canvas is obsidian and the page says so on the
      root element, so form controls, scrollbars and the flash before first
      paint are all dark too.

   2. NOTHING ESCAPES SIDEWAYS. Every grid track is minmax(0,1fr) and every
      auto-fit track is minmax(min(100%,Npx),1fr), because an implicit track
      sizes to its widest item's min-content and this platform renders company
      names and product codes that members typed. One 60-character unbroken
      string would otherwise set the width of the whole directory.

   3. GOLD IS A MATERIAL. It is the --foil gradient, oversized and slowly
      drifting, never a flat yellow fill. Small gold text uses --gold-lift,
      never --gold, which stops at about 4.6:1 on this canvas.

   Keyframes live in section 18 with the rest of the motion. CSS resolves
   @keyframes by name across the whole sheet, so rules above may reference
   them freely.
   =========================================================================== */


/* ===========================================================================
   01  TOKENS
   The live brand system. Every colour, font and duration in this file comes
   from here, so a change to the Council's palette is a change to this block.
   =========================================================================== */

/* THE GROUND IS DEEP GREEN, NOT BLACK, and that is the one decision this block
   is really making.

   It used to be near-black with bright gold, which is the default costume for
   "luxury" on the web - the look every template reaches for, and therefore the
   look that reads as reaching. Deep bottle green with antique brass is an
   older and quieter kind of money: it is the colour of institutions rather
   than of launches, and it carries particular weight for the audience this
   Council is built for.

   THE METAL IS BRASS, NOT GOLD. --gold is now #b8912f rather than #b8912f:
   dropped in chroma and warmed, so it reads as struck metal rather than as a
   bright yellow. The token KEEPS ITS NAME - renaming it would touch two
   thousand references to say nothing new, and every one of them means "the
   Council's metal" rather than a hue.

   CONTRAST, CHECKED RATHER THAN ASSUMED, against --canvas #0a1410:
     --text    #f2ede0   ~15:1    body
     --soft    #a9b8ac   ~7.5:1   secondary
     --faint   #7e8f84   ~4.6:1   meta only, never body
     --gold-lift #d9bc6b ~9:1     small metal text
     --gold    #b8912f   ~4.9:1   large text and rules only
   The rule from the old palette therefore still stands: small metal text uses
   --gold-lift, never --gold. */
:root {
  --void:#050b08; --canvas:#0a1410; --canvas-2:#0d1a14;
  --surface:#10201a; --surface-2:#16291f; --surface-3:#1e3428;
  --hairline:rgba(242,237,224,.10); --hairline-strong:rgba(242,237,224,.19);
  --text:#f2ede0; --soft:#a9b8ac; --faint:#7e8f84;
  --gold-deep:#6b5416; --gold:#b8912f; --gold-lift:#d9bc6b; --gold-white:#f0e4b4;
  --gold-wash:rgba(184,145,47,.12); --gold-glow:rgba(217,188,107,.28);
  --foil:linear-gradient(100deg,var(--gold-deep) 0%,var(--gold) 22%,var(--gold-white) 44%,var(--gold-lift) 60%,var(--gold) 82%,var(--gold-deep) 100%);
  /* The sector accents, pulled toward the new ground. emerald moved furthest:
     a mint green on a green page is not an accent, it is camouflage. */
  --cyan:#3fc9d8; --cyan-lift:#7fe0eb;
  --emerald:#6fd39b; --emerald-lift:#a3e6c1;
  --rose:#e08192; --rose-lift:#f0adb8;
  --violet:#9b8ad6; --violet-lift:#bcb0e6;
  --a:var(--gold); --a-lift:var(--gold-lift); --a-deep:var(--gold-deep);
  --a-wash:var(--gold-wash); --a-glow:var(--gold-glow);
  --font-display:"Space Grotesk","Segoe UI",system-ui,sans-serif;
  --font-body:"Inter","Segoe UI",system-ui,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,"SFMono-Regular",monospace;
  --ease:cubic-bezier(.16,1,.3,1); --t-micro:150ms; --t-ui:250ms; --t-section:600ms;
  --r-sm:8px; --r-md:14px; --r-lg:20px; --r-xl:28px;
  --shell:80rem; --pad:clamp(1.1rem,3.5vw,1.5rem);
}

/* ---- the accent system ------------------------------------------------
   Every item of Council content carries an accent: a sector, a program, a
   working group, a publication type. An element marked data-accent redefines
   the five accent tokens for its whole subtree, so a component is written once
   against var(--a) and recolours by attribute alone.

   THIS BLOCK LIVES HERE AND NOWHERE ELSE. Four of the six Council pages shipped
   their own copy of it, each slightly different, because each was written in
   isolation and needed it. Four copies of a token definition is four answers to
   what violet means, resolved by whichever stylesheet happened to load last.

   gold is the default and amber resolves to it, so the Council speaks in gold
   wherever nothing says otherwise. */
[data-accent="gold"],
[data-accent="amber"] {
  --a: var(--gold);
  --a-lift: var(--gold-lift);
  --a-deep: var(--gold-deep);
  --a-wash: var(--gold-wash);
  --a-glow: var(--gold-glow);
}

[data-accent="cyan"] {
  --a: var(--cyan);
  --a-lift: var(--cyan-lift);
  --a-deep: #0e7490;
  --a-wash: rgba(34, 211, 238, .08);
  --a-glow: rgba(34, 211, 238, .35);
}

[data-accent="violet"] {
  --a: var(--violet);
  --a-lift: var(--violet-lift);
  --a-deep: #6d28d9;
  --a-wash: rgba(139, 92, 246, .1);
  --a-glow: rgba(139, 92, 246, .38);
}

[data-accent="emerald"] {
  --a: var(--emerald);
  --a-lift: var(--emerald-lift);
  --a-deep: #059669;
  --a-wash: rgba(52, 211, 153, .09);
  --a-glow: rgba(52, 211, 153, .32);
}

[data-accent="rose"] {
  --a: var(--rose);
  --a-lift: var(--rose-lift);
  --a-deep: #be123c;
  --a-wash: rgba(251, 113, 133, .09);
  --a-glow: rgba(251, 113, 133, .34);
}


/* Derived measurements. Not brand, just arithmetic used in more than one place. */
:root {
  --tap:44px;                 /* the smallest thing a finger can be asked to hit */
  --sidebar:19rem;            /* .split-sidebar */
  --dash-nav:14rem;           /* .dash-nav on a wide screen */
  --header-h:5.5rem;          /* used only for :target scroll-margin under the sticky header */
}


/* ===========================================================================
   02  BASE + RESET
   =========================================================================== */

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

/* THE ROOT DECLARES THE SCHEME. Without color-scheme:dark the browser paints a
   white overscroll gutter, white form controls and a white flash before the
   first paint, all of which read as a broken page rather than a dark one. */
html {
  background: var(--canvas);
  color-scheme: dark;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* overflow-x:clip rather than hidden. hidden would make body a scroll
   container, which silently kills position:sticky on the header; clip does not
   create one. Either way, anything that spills horizontally is unreachable
   rather than merely off screen, so it is cut here and prevented everywhere
   else in this file. */
body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow-x: clip;
  background: var(--canvas);
  color: var(--text);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* The page skeleton: header wrapper, main, footer wrapper. The wrapper divs are
   what session.js writes into, so the sticky lives on the wrapper. Putting it
   on .site-header instead would let it stick only within its own parent's
   height, which is the header's height, i.e. not at all. */
#site-header { position: sticky; top: 0; z-index: 60; flex: none; }
#main { flex: 1 0 auto; min-width: 0; position: relative; }
/* Positioned for the same reason .shell is: the dashboard and the requests page
   hang their .aurora off <body>, and an unpositioned footer would be painted
   under it. */
#site-footer { flex: none; margin-top: auto; min-width: 0; position: relative; z-index: 1; }

main { display: block; }

h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd { margin: 0; }

ul, ol { margin: 0; padding: 0; list-style: none; }

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

svg { height: auto; }

a {
  color: var(--a-lift);
  text-decoration: none;
  transition: color var(--t-ui) var(--ease);
}

a:hover { color: var(--gold-white); }

button, input, select, textarea {
  font: inherit;
  color: inherit;
  margin: 0;
}

button { background: none; border: 0; cursor: pointer; }

table { border-collapse: collapse; border-spacing: 0; }

hr { border: 0; margin: 0; }

strong, b { font-weight: 600; color: var(--text); }

small { font-size: .8125rem; }

code, pre, kbd, samp { font-family: var(--font-mono); font-size: .875em; }

::selection { background: var(--a-glow); color: #fff; }

/* THE FOCUS RING IS NEVER REMOVED. Where a control needs a different ring it
   gets one that measures at least this well, never outline:none on its own. */
:focus-visible {
  outline: 2px solid var(--gold-lift);
  outline-offset: 3px;
  border-radius: 3px;
}

/* The sticky header would otherwise sit on top of whatever an in-page link
   (/dashboard.html#inbox) just scrolled to. */
:target { scroll-margin-top: var(--header-h); }

::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: var(--void); }
::-webkit-scrollbar-thumb {
  background: var(--surface-2);
  border-radius: 6px;
  border: 2px solid var(--void);
}
::-webkit-scrollbar-thumb:hover { background: var(--surface-3); }

[hidden] { display: none !important; }


/* ===========================================================================
   03  TYPOGRAPHY UTILITIES
   Space Grotesk for display, Inter for body, JetBrains Mono for micro-labels
   and anything that is data. Mono uppercase at 10-12px with wide tracking is
   the ledger voice and is used for every label that is not a sentence.
   =========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  color: var(--text);
  font-weight: 600;
  line-height: 1.08;
  letter-spacing: -.03em;
  text-wrap: balance;
  overflow-wrap: break-word;
}

h1 { font-size: clamp(1.85rem, 1.35rem + 2.4vw, 3rem); }
h2 { font-size: clamp(1.4rem, 1.15rem + 1.5vw, 2.05rem); }
h3 { font-size: clamp(1.1rem, 1.03rem + .45vw, 1.3rem); letter-spacing: -.02em; line-height: 1.24; }
h4 { font-size: 1rem; letter-spacing: -.01em; line-height: 1.3; }

p { color: var(--soft); }

.display {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -.035em;
  line-height: 1.02;
  color: var(--text);
  font-size: clamp(2rem, 1.4rem + 3vw, 3.25rem);
  text-wrap: balance;
  overflow-wrap: break-word;
}

.lede {
  color: var(--soft);
  font-size: 1.0625rem;
  line-height: 1.7;
  max-width: 62ch;
}

/* The manifest label. Inline rather than flex, so a long translated label wraps
   like normal text instead of forcing its own line width. */
.eyebrow {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--gold-lift);
  max-width: 100%;
  overflow-wrap: anywhere;
}

.eyebrow::before {
  content: "";
  display: inline-block;
  width: 24px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--a));
  vertical-align: middle;
  margin-inline-end: 10px;
}

.eyebrow--bare::before { display: none; }

.mono-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .08em;
  line-height: 1.5;
  color: var(--faint);
  overflow-wrap: anywhere;
}

/* Numbers that sit in a column have to line up. */
.tabular { font-variant-numeric: tabular-nums; font-feature-settings: "tnum" 1; }

/* Struck metal text. It carries its own bottom padding because background-clip
   crops descenders when the line box is tight. */
.foil {
  background: var(--foil);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: foil-drift 9s linear infinite;
  padding-bottom: .06em;
}

.foil-rule {
  display: block;
  border: 0;
  height: 1px;
  width: 100%;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 11s linear infinite;
  opacity: .75;
}

/* The separator between two facts on one line. */
.dot {
  color: var(--faint);
  opacity: .6;
  padding-inline: .15rem;
  user-select: none;
}

.right { text-align: end; }


/* ===========================================================================
   04  ATMOSPHERE
   Three decorative layers, all pointer-events:none, all cheap enough to sit on
   screen permanently. Their cost is cut again for touch and small screens at
   the foot of this section.
   =========================================================================== */

/* Candlelight on obsidian, warm only. Every stop stays on the gold axis: gold
   over blue-black averages to teal, and one cool counter-light turns the whole
   canvas green. */
/* WHATEVER HOLDS AN AURORA CLIPS IT. The field is inset by -20% and drifts on a
   scale(1.08), so its box is half again as wide as the band it decorates. Left
   unclipped that is real scrollable overflow on the page, and a decorative
   layer must never be the reason a member can scroll sideways. The clip is
   declared here rather than left to each page, because a page that forgot it
   would look correct on a desktop and be broken on a phone.

   overflow-x rather than overflow: `clip` on one axis with `visible` on the
   other creates no scroll container, so a sticky sidebar inside the same band
   still sticks to the viewport. */
*:has(> .aurora) {
  position: relative;
  overflow-x: clip;
}

.aurora {
  position: absolute;
  inset: -20%;
  z-index: 0;
  pointer-events: none;
  filter: blur(90px);
  opacity: .34;
  background:
    radial-gradient(42% 48% at 24% 26%, rgba(184,145,47,.3), transparent 70%),
    radial-gradient(34% 40% at 78% 20%, rgba(217,188,107,.16), transparent 70%),
    radial-gradient(46% 42% at 62% 80%, rgba(107,78,18,.34), transparent 72%);
  animation: aurora-drift 52s var(--ease) infinite alternate;
}

/* The faint map grid. A section or a panel that wants one nests a bare
   <div class="graticule"> rather than taking the class itself, because .panel
   already owns its ::before.

   THAT EMPTY DIV IS THE LAYER, so the grid is painted on the element and the
   element is positioned and full bleed. Painting it on ::before instead gives
   the pseudo-element a zero-height box to fill, because the div it belongs to
   has no content: the grid then never appears anywhere. */
*:has(> .graticule) { position: relative; }

.graticule {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(0deg, rgba(242,237,224,.028) 0 1px, transparent 1px 76px),
    repeating-linear-gradient(90deg, rgba(242,237,224,.028) 0 1px, transparent 1px 76px);
  -webkit-mask-image: radial-gradient(ellipse 100% 80% at 50% 40%, #000 35%, transparent 78%);
  mask-image: radial-gradient(ellipse 100% 80% at 50% 40%, #000 35%, transparent 78%);
}

/* Film grain, fixed so it never scrolls with the content it is sitting on. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: none;
  opacity: .032;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* UI.icon() emits width="24" height="24" so the SVG is legible with CSS off.
   On screen an icon is always the size of the text beside it. */
.ico {
  width: 1em;
  height: 1em;
  flex: none;
  display: inline-block;
  vertical-align: -.13em;
  stroke: currentColor;
  fill: none;
}


/* ===========================================================================
   05  LAYOUT
   =========================================================================== */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--pad);
  min-width: 0;
}

/* Declared after .shell so `class="shell shell-narrow"` narrows rather than ties. */
.shell-narrow {
  width: 100%;
  max-width: 56rem;
  margin-inline: auto;
  padding-inline: var(--pad);
  min-width: 0;
}

/* THE CONTENT SITS ABOVE THE ATMOSPHERE. .aurora and .graticule are absolutely
   positioned layers inside the band they decorate, and a positioned box paints
   above the in-flow content of the same parent rather than below it: without
   this step the aurora is a wash laid over the headline it was meant to sit
   behind. It is fixed by raising the wrapper rather than by sinking the layers,
   because a negative z-index would drop them behind the opaque background of
   .band-deep and out of sight altogether. */
.shell,
.shell-narrow { position: relative; z-index: 1; }

/* Space is the loudest signal this design has. Less than the marketing site,
   because a dashboard that pushes its first control below the fold is
   ceremony at the member's expense, but still unhurried. */
.section { padding-block: clamp(2.5rem, 1.6rem + 3.4vw, 4.5rem); }
.section-tight { padding-block: clamp(1.75rem, 1.3rem + 1.8vw, 2.75rem); }

.band-deep {
  background: var(--canvas-2);
  border-block: 1px solid var(--hairline);
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 1rem 1.75rem;
  padding-bottom: 1.5rem;
  margin-bottom: 2rem;
  border-bottom: 1px solid var(--hairline);
}

.page-head > * { min-width: 0; }

/* A TITLE IS A STACK, NOT A ROW. The head is a flex row so a page can set a
   title against an action opposite it, and every page writes its eyebrow,
   heading and lede as flat children rather than as one wrapped group. Left to
   `space-between` those three sit side by side whenever they are short enough
   to share a line, which makes the shape of the head a function of how long
   the words are, and a different shape again once they are translated. Each
   text child therefore claims a full line. A page that does wrap its title in
   one element is not matched here and still gets the two-group row. */
.page-head > .eyebrow,
.page-head > h1,
.page-head > h2,
.page-head > .display,
.page-head > .lede { flex: 1 0 100%; }

.page-head .eyebrow { margin-bottom: .6rem; }

.page-head .lede { margin-top: .85rem; }

/* Main column plus a rail. The rail is placed explicitly, so it lands in the
   second column whether the markup puts it before or after the main column. */
.split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem;
  align-items: start;
}

.split > * { min-width: 0; }

.split-sidebar { min-width: 0; }

@media (min-width: 62rem) {
  .split { grid-template-columns: minmax(0, 1fr) minmax(0, var(--sidebar)); gap: 2.5rem; }
  .split-sidebar { grid-column: 2; grid-row: 1; position: sticky; top: calc(var(--header-h) + .5rem); }
}

.rule { height: 1px; background: var(--hairline); border: 0; }

/* Off screen until it is focused, then a real, visible, tappable control.
   Clipped in place rather than parked at left:-9999px, because a negative
   offset is genuine overflow: harmless in this left-to-right layout, a
   sideways scroll the moment the page is read right-to-left. */
.skip-link {
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.skip-link:focus {
  position: fixed;
  inset-inline-start: 1rem;
  top: 1rem;
  clip-path: none;
  z-index: 10000;
  width: auto;
  height: auto;
  min-height: var(--tap);
  display: inline-flex;
  align-items: center;
  padding: .65rem 1.15rem;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--gold-lift);
  color: var(--text);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .1em;
  text-transform: uppercase;
}


/* ===========================================================================
   06  HEADER
   Written by session.js on every page. Two rows on a phone (brand + actions,
   then the nav), one row from 900px.
   =========================================================================== */

.site-header {
  background: rgba(5, 6, 10, .92);
  border-bottom: 1px solid var(--hairline);
}

.header-inner {
  display: grid;
  /* minmax(0,auto) rather than a bare auto: an auto track sizes to max-content
     and the actions column holds up to four wrapping controls, which at 360px
     would otherwise push the header wider than the screen. */
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  align-items: center;
  gap: .5rem 1rem;
  padding-block: .7rem;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .7rem;
  min-width: 0;
  min-height: var(--tap);
  color: var(--text);
}

.brand:hover { color: var(--text); }

.mark { flex: none; width: 34px; height: 34px; color: var(--text); }

.brand-text { display: flex; flex-direction: column; min-width: 0; line-height: 1.15; }

.brand-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.05rem;
  letter-spacing: .04em;
  color: var(--text);
}

.brand-sub {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

@media (max-width: 26rem) { .brand-sub { display: none; } }

/* Second row on a phone. It scrolls sideways inside itself rather than pushing
   the page wider. */
.main-nav {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: .15rem;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.main-nav::-webkit-scrollbar { display: none; }

.nav-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: .8rem;
  white-space: nowrap;
  font-size: .9rem;
  font-weight: 500;
  color: var(--soft);
  border-radius: var(--r-sm);
  transition: color var(--t-ui) var(--ease), background-color var(--t-ui) var(--ease);
}

.nav-link:hover { color: var(--text); background: rgba(242,237,224,.04); }

.nav-link.is-active { color: var(--gold-lift); }

.nav-link.is-active::after {
  content: "";
  position: absolute;
  left: .8rem;
  right: .8rem;
  bottom: .55rem;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 11s linear infinite;
}

.header-right {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: .4rem .55rem;
  min-width: 0;
}

/* The unread count. Its visual size is 26px because a fat circle in the header
   looks like an error, so the missing hit area is added back with a centred
   pseudo-element instead of by growing the pill. */
.pill-count {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 26px;
  height: 26px;
  padding-inline: .45rem;
  border-radius: 999px;
  background: var(--gold-wash);
  border: 1px solid color-mix(in srgb, var(--gold) 40%, transparent);
  color: var(--gold-lift);
  font-family: var(--font-mono);
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.pill-count::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--tap);
  height: var(--tap);
  transform: translate(-50%, -50%);
}

.pill-count:hover {
  background: color-mix(in srgb, var(--gold) 18%, transparent);
  color: var(--gold-white);
}

.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: .1rem;
  min-width: 0;
}

.lang-link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding-inline: .45rem;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .1em;
  color: var(--faint);
  white-space: nowrap;
}

.lang-link:hover { color: var(--text); }

.lang-link.is-on { color: var(--gold-lift); }

.lang-sep { color: var(--hairline-strong); font-size: 11px; user-select: none; }

/* THE NAV GETS ITS OWN ROW UNTIL THERE IS GENUINELY SPACE FOR IT.

   It carried three items when the platform was the whole site. The six Council pages took it to
   nine, and nine of them beside the brand block and the sign-in cluster do not fit on one line at
   1440: the first attempt at this painted the nav straight over the sign-in button, and the second
   scrolled it, which hides half the site behind a gesture nobody knows is there.

   So the nav sits on its own full-width row, centred, at every width. There is no wide-desktop
   variant that puts it back on the top row: .shell is capped at 80rem, so a 1700px window gives
   the header no more room than a 1280px one does, and the single-row version clipped at both.
   the shell caps its width. A two-row header is a deliberate shape
   rather than a fallback: it is what the row does at every width below a very wide desktop. */
@media (min-width: 56.25rem) {
  .header-inner {
    grid-template-columns: minmax(0, 1fr) minmax(0, auto);
    gap: .75rem 1.5rem;
    padding-block: .85rem;
  }
  /* Pinned, not auto-placed. A full-width nav takes the next free ROW, so with the brand in
     column one the controls were pushed down to a third row and the header grew by 40px of
     nothing. Brand and controls share row one; the nav has row two to itself. */
  .brand { grid-row: 1; grid-column: 1; }
  .header-right { grid-row: 1; grid-column: 2; }
  .main-nav { grid-row: 2; grid-column: 1 / -1; justify-content: center; overflow-x: auto; min-width: 0; }
  .nav-link { padding-inline: .6rem; }
  .main-nav .nav-link { white-space: nowrap; }
}


/* ===========================================================================
   07  FOOTER
   =========================================================================== */

.site-footer {
  border-top: 1px solid var(--hairline);
  background: var(--canvas-2);
  padding-block: 3rem 2rem;
  margin-top: 4rem;
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 2rem;
}

.footer-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .1rem;
  min-width: 0;
}

.footer-col > * { min-width: 0; }

.footer-col .brand-name { margin-bottom: .35rem; }

.footer-col a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  font-size: .9rem;
  color: var(--soft);
  overflow-wrap: anywhere;
}

.footer-col a:hover { color: var(--gold-lift); }

.footer-bottom {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--hairline);
  font-size: .8125rem;
  line-height: 1.65;
  color: var(--faint);
  max-width: 68ch;
}


/* ===========================================================================
   08  BUTTONS
   White-space wraps. A label is authored in English and translated in place, so
   the box has to survive a Chinese or German string that is half again as long;
   nowrap would clip it or push the page sideways. Every button clears 44px.
   =========================================================================== */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: var(--tap);
  max-width: 100%;
  min-width: 0;
  padding: .7rem 1.35rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: .9rem;
  font-weight: 600;
  letter-spacing: .01em;
  line-height: 1.25;
  text-align: center;
  white-space: normal;
  overflow-wrap: anywhere;
  cursor: pointer;
  color: var(--text);
  transition:
    transform var(--t-micro) var(--ease),
    box-shadow var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease),
    border-color var(--t-ui) var(--ease),
    color var(--t-ui) var(--ease);
}

.btn:active { transform: scale(.97); }

/* THE ONE FULL FOIL SURFACE ON THE PLATFORM. Dark ink on struck gold, a soft
   glow beneath, a highlight cut into the top edge, and a drift slow enough to
   read as light crossing metal rather than an animation. */
.btn-primary {
  position: relative;
  overflow: hidden;
  color: #2a1e05;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 9s linear infinite;
  box-shadow:
    0 10px 30px -12px var(--gold-glow),
    inset 0 1px 0 rgba(255,255,255,.45),
    inset 0 -1px 0 rgba(0,0,0,.25);
}

/* The specular band, crossing the face once per hover. */
.btn-primary::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-120%) skewX(-18deg);
  background: linear-gradient(90deg, transparent, rgba(255,255,255,.55), transparent);
  transition: transform 700ms var(--ease);
  pointer-events: none;
}

.btn-primary:hover {
  transform: translateY(-2px);
  box-shadow:
    0 16px 44px -12px var(--gold-glow),
    inset 0 1px 0 rgba(255,255,255,.6),
    inset 0 -1px 0 rgba(0,0,0,.25);
}

.btn-primary:hover::after { transform: translateX(120%) skewX(-18deg); }

.btn-ghost {
  color: var(--text);
  border-color: var(--hairline-strong);
  background: rgba(242,237,224,.03);
}

.btn-ghost:hover {
  color: var(--gold-lift);
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  background: var(--gold-wash);
  transform: translateY(-2px);
}

.btn-quiet {
  color: var(--soft);
  background: transparent;
  border-color: transparent;
}

.btn-quiet:hover {
  color: var(--text);
  background: rgba(242,237,224,.05);
  border-color: var(--hairline);
}

.btn-danger {
  color: var(--rose-lift);
  background: color-mix(in srgb, var(--rose) 12%, transparent);
  border-color: color-mix(in srgb, var(--rose) 38%, transparent);
}

.btn-danger:hover {
  color: #fff;
  background: color-mix(in srgb, var(--rose) 26%, transparent);
  border-color: var(--rose-lift);
  transform: translateY(-2px);
}

/* Small keeps the smaller type and the tighter padding, but never the smaller
   hit area: min-height is inherited from .btn on purpose. */
.btn-sm { padding: .5rem 1rem; font-size: .8125rem; gap: .4rem; }

.btn-lg { padding: .95rem 1.9rem; font-size: 1rem; min-height: 52px; }

.btn-block { display: flex; width: 100%; }

/* GDTC.busy() adds .is-loading and sets disabled, so the loading state is
   styled ahead of the disabled state rather than dimmed into invisibility. */
.btn.is-loading {
  cursor: progress;
  opacity: .9;
  pointer-events: none;
}

.btn.is-loading::before {
  content: "";
  flex: none;
  width: 1em;
  height: 1em;
  border-radius: 50%;
  border: 2px solid currentColor;
  border-top-color: transparent;
  animation: spin .7s linear infinite;
}

.btn[disabled],
.btn[aria-disabled="true"] {
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.btn[disabled]:not(.is-loading),
.btn[aria-disabled="true"]:not(.is-loading) { opacity: .48; }

.btn[disabled]:hover,
.btn[aria-disabled="true"]:hover { transform: none; }

.btn[disabled]::after,
.btn[aria-disabled="true"]::after { display: none; }


/* ===========================================================================
   09  SURFACES
   =========================================================================== */

/* No overflow:hidden. A panel holds fields and buttons, and clipping would eat
   their focus rings; the ::before edge is a transparent-ended gradient, so it
   has nothing visible to spill past the rounded corners anyway. */
.panel {
  position: relative;
  min-width: 0;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background:
    linear-gradient(180deg, rgba(242,237,224,.045), rgba(242,237,224,0) 42%),
    var(--surface);
  transition:
    border-color var(--t-ui) var(--ease),
    transform var(--t-ui) var(--ease),
    box-shadow var(--t-ui) var(--ease);
}

.panel::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  border-radius: inherit;
  background: linear-gradient(90deg, transparent, var(--a), transparent);
  opacity: .5;
  pointer-events: none;
  transition: opacity var(--t-ui) var(--ease);
}

.panel-lift:hover {
  transform: translateY(-4px);
  border-color: color-mix(in srgb, var(--a) 45%, transparent);
  box-shadow:
    0 18px 44px rgba(3,5,12,.55),
    0 0 0 1px color-mix(in srgb, var(--a) 18%, transparent),
    0 0 46px -18px var(--a-glow);
}

.panel-lift:hover::before { opacity: .95; }

.panel-lift:focus-within {
  border-color: color-mix(in srgb, var(--a) 45%, transparent);
}

/* A recess rather than a raised card: darker than its parent, lit from nothing. */
.inset-well {
  min-width: 0;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--void);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.5);
  padding: 1.1rem 1.15rem;
}

.card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .75rem 1.25rem;
  padding: 1.25rem 1.35rem;
  border-bottom: 1px solid var(--hairline);
}

.card-head > * { min-width: 0; }

.card-body { padding: 1.35rem; min-width: 0; }

.card-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .6rem .9rem;
  padding: 1.1rem 1.35rem;
  border-top: 1px solid var(--hairline);
  background: rgba(2,3,6,.35);
  border-radius: 0 0 var(--r-lg) var(--r-lg);
}

.card-foot > * { min-width: 0; }


/* ===========================================================================
   10  FORMS
   =========================================================================== */

.form { min-width: 0; }

/* A FORM THAT IS ITSELF THE PANEL, with no .card-body inside it to carry the
   padding. The sign-in page, the candidacy page and the password pages are all
   built that way, and every one of them was rendering its fields hard against
   the panel's border - the label of the first field sat on the top edge and the
   control ran to within a pixel of the left one.

   .panel deliberately has no padding of its own, because most panels hold a
   .card-head and a .card-body which bring their own. This is the case where
   neither is present, matched by saying so rather than by adding a class to
   every such form. The value is .card-body's, so a padded form and a padded
   card body agree. */
.panel.form:not(:has(> .card-body)):not(:has(> .card-head)) { padding: 1.35rem; }

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: 1.35rem 1.5rem;
}

.form-grid > * { min-width: 0; }

.field-row {
  display: flex;
  flex-direction: column;
  gap: .45rem;
  min-width: 0;
}

.field-label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .45rem;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--soft);
  min-width: 0;
  overflow-wrap: anywhere;
}

.req { color: var(--gold-lift); font-size: 11px; letter-spacing: .1em; }

.optional {
  color: var(--faint);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  font-weight: 400;
}

/* THE SECOND FORM VOCABULARY, AND THE BUG IT WAS HIDING.

   Two sets of class names grew up here. The pages written first say
   .field-row / .field-label / .field / .field-hint, all defined above and
   below. The pages written later - the Chamber, the contribution page, the
   front door, the credential - say .field / .label / .input / .hint, and only
   the first of those four was ever defined.

   So on those pages every label rendered as body text, every control rendered
   as a browser default, and the WRAPPER picked up the control's border and
   background because it happened to be called .field. A form that looked like
   a stack of boxes with tiny grey inputs floating inside them.

   Rather than rename ninety attributes across five files, the four names are
   defined here and the control rule below is scoped to actual controls, so a
   <div class="field"> is a wrapper and an <input class="field"> is an input.
   The element type is what tells them apart, which is the one thing that
   cannot drift. */
div.field {
  display: flex;
  flex-direction: column;
  gap: .45rem;
  min-width: 0;
}

/* AIR BETWEEN STACKED FIELDS, put on the container rather than the blocks,
   because every margin in this sheet is zero and vertical rhythm comes from a
   parent with a gap. Without it one field's hint and the next one's label are
   both small grey type touching each other, and the eye reads them as one
   paragraph belonging to the wrong control.

   Scoped with :has() to the card bodies that actually hold these fields, so a
   panel body full of prose is left exactly as it was. */
form .card-body:has(> div.field),
form .card-body:has(> .give-set) {
  display: flex;
  flex-direction: column;
  gap: 1.3rem;
}

.label {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .45rem;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--soft);
  min-width: 0;
  overflow-wrap: anywhere;
}

/* The control itself. Bare controls inside .form get it too, so a field that
   forgot its class is still a field rather than a browser default. */
input.field,
select.field,
textarea.field,
.input,
.form input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]),
.form select,
.form textarea {
  display: block;
  width: 100%;
  min-width: 0;
  max-width: 100%;
  padding: .8rem .95rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  color: var(--text);
  font-family: var(--font-body);
  font-size: .9375rem;
  line-height: 1.5;
  transition:
    border-color var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease),
    box-shadow var(--t-ui) var(--ease);
}

.field::placeholder,
.input::placeholder,
.form input::placeholder,
.form textarea::placeholder { color: var(--faint); opacity: 1; }

.field:hover,
.input:hover,
.form input:hover,
.form select:hover,
.form textarea:hover { border-color: color-mix(in srgb, var(--gold) 30%, var(--hairline-strong)); }

.field:focus,
.input:focus,
.form input:focus,
.form select:focus,
.form textarea:focus {
  border-color: var(--gold-lift);
  background: var(--surface-3);
  box-shadow: 0 0 0 3px var(--gold-wash);
}

.field[aria-invalid="true"],
.input[aria-invalid="true"],
.field.err {
  border-color: var(--rose);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--rose) 14%, transparent);
}

.field[disabled],
.field[readonly],
.input[disabled],
.input[readonly] { opacity: .6; cursor: not-allowed; }

textarea.field,
textarea.input,
.form textarea { min-height: 8rem; resize: vertical; line-height: 1.6; }

/* The native arrow is a light-mode artefact on some engines, so it is replaced
   with one drawn in --soft. */
select.field,
select.input,
.form select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 2.6rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%23ada69a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right .95rem center;
  background-size: 16px 16px;
  cursor: pointer;
}

select.field[multiple],
.form select[multiple] {
  appearance: auto;
  -webkit-appearance: auto;
  background-image: none;
  padding-inline-end: .95rem;
  min-height: 9rem;
}

select.field option,
.form select option { background: var(--surface-2); color: var(--text); }

input[type="checkbox"],
input[type="radio"] {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  accent-color: var(--gold);
  cursor: pointer;
}

input[type="file"] {
  width: 100%;
  min-width: 0;
  font-size: .875rem;
  color: var(--soft);
}

input[type="file"]::file-selector-button {
  margin-inline-end: .8rem;
  min-height: var(--tap);
  padding: .5rem 1rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: rgba(242,237,224,.03);
  color: var(--text);
  font: inherit;
  font-weight: 600;
  font-size: .8125rem;
  cursor: pointer;
}

input[type="file"]::file-selector-button:hover {
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  color: var(--gold-lift);
}

.field-hint,
.hint {
  font-size: .8125rem;
  line-height: 1.55;
  color: var(--faint);
  overflow-wrap: anywhere;
}

.field-error {
  font-size: .8125rem;
  line-height: 1.55;
  color: var(--rose-lift);
  overflow-wrap: anywhere;
}

.form-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1rem;
  margin-top: 1.75rem;
}

.form-actions > * { min-width: 0; }

/* GDTC.status() rewrites className to `form-status` plus a tone, so the base
   has to hold on its own with no tone at all. */
.form-status {
  margin-top: 1rem;
  min-height: 1.4em;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--soft);
  overflow-wrap: anywhere;
}

.form-status:empty { margin-top: 0; min-height: 0; }

.ok { color: var(--emerald-lift); }
.err { color: var(--rose-lift); }

.checkline {
  display: flex;
  align-items: flex-start;
  gap: .65rem;
  min-height: var(--tap);
  padding-block: .55rem;
  min-width: 0;
  font-size: .9rem;
  line-height: 1.5;
  color: var(--soft);
  cursor: pointer;
  overflow-wrap: anywhere;
}

.checkline:hover { color: var(--text); }

.checkline input { margin-top: .18rem; }

.checkgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: .1rem 1.25rem;
}

.checkgrid > * { min-width: 0; }

/* A whole card as a radio. The input stays in the markup and stays focusable,
   so :focus-within is what draws the ring. */
.option-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  min-width: 0;
  padding: 1.25rem 1.3rem;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: var(--surface);
  cursor: pointer;
  transition:
    border-color var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease),
    box-shadow var(--t-ui) var(--ease),
    transform var(--t-ui) var(--ease);
}

.option-card:hover {
  border-color: color-mix(in srgb, var(--gold) 40%, transparent);
  transform: translateY(-2px);
}

.option-card:focus-within {
  border-color: var(--gold-lift);
  box-shadow: 0 0 0 3px var(--gold-wash);
}

.option-card.selected {
  border-color: var(--gold-lift);
  background: linear-gradient(180deg, var(--gold-wash), transparent 60%), var(--surface);
  box-shadow: 0 0 40px -22px var(--gold-glow);
}

.option-card.selected::after {
  content: "";
  position: absolute;
  inset-inline: 1.3rem;
  bottom: 0;
  height: 2px;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 9s linear infinite;
}

/* iOS zooms into any control it measures below 16px and never zooms back out,
   which leaves the member on a page they now have to pan sideways. */
@media (pointer: coarse) {
  .field,
  .form input,
  .form select,
  .form textarea,
  input,
  select,
  textarea { font-size: 16px; }
}


/* ===========================================================================
   11  BADGES AND CHIPS
   The tone classes only carry two custom properties, so one set of semantics
   drives status tags, notices, chips and anything else that needs a tone.
   Small text on dark always takes the -lift variant.
   =========================================================================== */

.tone-good { --tone: var(--emerald); --tone-lift: var(--emerald-lift); color: var(--tone-lift); }
.tone-wait { --tone: var(--gold);    --tone-lift: var(--gold-lift);    color: var(--tone-lift); }
.tone-bad  { --tone: var(--rose);    --tone-lift: var(--rose-lift);    color: var(--tone-lift); }
.tone-info { --tone: var(--cyan);    --tone-lift: var(--cyan-lift);    color: var(--tone-lift); }

.chip-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
  min-width: 0;
}

/* Chips carry sector and product answers a member typed. Some of those are a
   60-character part number with no space in it. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  max-width: 100%;
  min-width: 0;
  padding: .3rem .7rem;
  border-radius: 999px;
  border: 1px solid var(--hairline);
  background: var(--surface-2);
  color: var(--soft);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .06em;
  line-height: 1.5;
  overflow-wrap: anywhere;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  max-width: 100%;
  min-width: 0;
  padding: .28rem .65rem;
  border-radius: 999px;
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  color: var(--soft);
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1.5;
  white-space: normal;
  overflow-wrap: anywhere;
}

/* Staff checked a registration document. It is the only badge that gets gold. */
.badge-verified {
  color: var(--gold-lift);
  background: var(--gold-wash);
  border-color: color-mix(in srgb, var(--gold) 42%, transparent);
  box-shadow: inset 0 1px 0 rgba(240,228,180,.14);
}

.badge-verified .ico { color: var(--gold-lift); }

.status-tag {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  min-width: 0;
  padding: .24rem .6rem;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--tone, var(--soft)) 32%, transparent);
  background: color-mix(in srgb, var(--tone, var(--soft)) 12%, transparent);
  color: var(--tone-lift, var(--soft));
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  line-height: 1.6;
  white-space: normal;
  overflow-wrap: anywhere;
}

.filter-pill {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: var(--tap);
  max-width: 100%;
  min-width: 0;
  padding: .4rem .95rem;
  border-radius: 999px;
  border: 1px solid var(--hairline);
  background: transparent;
  color: var(--soft);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .1em;
  text-transform: uppercase;
  line-height: 1.4;
  cursor: pointer;
  white-space: normal;
  overflow-wrap: anywhere;
  transition:
    color var(--t-ui) var(--ease),
    border-color var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease);
}

.filter-pill:hover { color: var(--text); border-color: var(--hairline-strong); }

.filter-pill.active {
  color: var(--gold-lift);
  border-color: color-mix(in srgb, var(--gold) 50%, transparent);
  background: var(--gold-wash);
}


/* ===========================================================================
   12  COMPANY CARDS AND FACTS
   =========================================================================== */

/* auto-fit with min(100%,Npx) is the whole point of this grid: on a 360px
   screen the track collapses to the container width instead of demanding
   320px and pushing the page sideways. */
.company-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr));
  gap: 1.15rem;
  /* Cards in a row are the same height whatever their text does. This is the
     grid default, said out loud because a card that stops short of its
     neighbour reads as unfinished rather than as brief. */
  align-items: stretch;
}

.company-grid > * { min-width: 0; }

/* A SET OF FOUR LAYS OUT TWO BY TWO, NOT THREE AND AN ORPHAN.

   auto-fit fills the row and then leaves the fourth card alone on a second
   line at a third of the width - ragged, and it reads as a card that failed to
   load rather than as the fourth of four. Four is the commonest count on this
   site: four steps, four things membership carries, four ways to give. */
@media (min-width: 58rem) {
  .company-grid:has(> :nth-child(4):last-child) {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* A block after a grid needs room to read as the next thing rather than as a
   fifth card that came out wrong. */
.company-grid + .notice { margin-top: 2.2rem; }

.company-card { padding: 0; min-width: 0; }

/* The whole card is the link, so the padding lives on the anchor and the hit
   area is the card rather than the title. */
.company-card-link {
  display: flex;
  flex-direction: column;
  gap: .7rem;
  min-width: 0;
  padding: 1.35rem;
  color: inherit;
  border-radius: inherit;
}

.company-card-link:hover { color: inherit; }

.company-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: .5rem .75rem;
  min-width: 0;
}

.company-name {
  min-width: 0;
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.25;
  color: var(--text);
  overflow-wrap: anywhere;
}

.company-about {
  min-width: 0;
  font-size: .9rem;
  line-height: 1.6;
  color: var(--soft);
  overflow-wrap: anywhere;
}

.trust-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .1rem .25rem;
  min-width: 0;
}

.trust-row > * { min-width: 0; }

.fact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1.25rem 1.5rem;
}

.fact {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  min-width: 0;
}

.fact-k {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  overflow-wrap: anywhere;
}

.fact-v {
  min-width: 0;
  font-size: .95rem;
  line-height: 1.55;
  color: var(--text);
  overflow-wrap: anywhere;
}


/* ===========================================================================
   13  STATES - empty, skeleton, notice, toast
   =========================================================================== */

.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .75rem;
  min-width: 0;
  padding: 3rem 1.5rem;
  border-radius: var(--r-lg);
  border: 1px dashed var(--hairline-strong);
  background: rgba(2,3,6,.35);
  text-align: center;
}

.empty-title {
  font-family: var(--font-display);
  font-size: 1.1rem;
  font-weight: 600;
  letter-spacing: -.02em;
  color: var(--text);
}

.empty-body {
  max-width: 46ch;
  font-size: .9rem;
  line-height: 1.65;
  color: var(--soft);
}

/* UI.skeleton() emits `.panel.skel`, so this only has to add the padding and
   the bars. The shimmer is a background-position tween on a static gradient,
   which still reads as a placeholder when the animation is switched off. */
.skel {
  padding: 1.35rem;
  margin-bottom: 1.15rem;
  min-width: 0;
}

.skel-line {
  height: .8rem;
  border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--surface-2) 0%, var(--surface-3) 38%, var(--surface-2) 76%);
  background-size: 220% 100%;
  animation: shimmer 1.6s linear infinite;
}

.skel-line + .skel-line { margin-top: .75rem; }

.skel-line.short { width: 42%; }

/* Gold is the default and it is written as a fallback, not as a declaration: a
   `--tone` set here would be declared later in the file than .tone-good and
   .tone-bad and would quietly beat them, so `class="notice tone-bad"` would
   come out gold. */
.notice {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .75rem;
  min-width: 0;
  padding: 1.1rem 1.25rem;
  border-radius: var(--r-md);
  border: 1px solid color-mix(in srgb, var(--tone, var(--gold)) 30%, transparent);
  border-inline-start-width: 3px;
  background: color-mix(in srgb, var(--tone, var(--gold)) 8%, var(--surface));
  color: var(--soft);
  font-size: .9rem;
  line-height: 1.65;
}

.notice > * { min-width: 0; max-width: 100%; }

.notice p { color: inherit; overflow-wrap: anywhere; }

.notice-warn { --tone: var(--gold); --tone-lift: var(--gold-lift); }
.notice-info { --tone: var(--cyan); --tone-lift: var(--cyan-lift); }

/* Above .grain, which sits at 9998. Centred by its own insets rather than by
   100vw arithmetic: vw includes the classic scrollbar, so a vw-sized toaster
   is a few pixels wider than the space it has. */
.toaster {
  position: fixed;
  left: 1rem;
  right: 1rem;
  bottom: 1.25rem;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .55rem;
  pointer-events: none;
}

.toast {
  pointer-events: auto;
  width: 100%;
  max-width: 30rem;
  min-width: 0;
  padding: .9rem 1.1rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline-strong);
  background: var(--surface-2);
  color: var(--text);
  font-size: .9rem;
  line-height: 1.55;
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  box-shadow: 0 18px 44px rgba(2,3,6,.7);
  animation: toast-in var(--t-ui) var(--ease) both;
}

.toast.ok {
  color: var(--emerald-lift);
  border-color: color-mix(in srgb, var(--emerald) 38%, transparent);
  background: color-mix(in srgb, var(--emerald) 10%, var(--surface-2));
}

.toast.err {
  color: var(--rose-lift);
  border-color: color-mix(in srgb, var(--rose) 38%, transparent);
  background: color-mix(in srgb, var(--rose) 10%, var(--surface-2));
}


/* ===========================================================================
   14  DASHBOARD
   =========================================================================== */

.dash-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.5rem;
  align-items: start;
}

.dash-layout > * { min-width: 0; }

/* THE PAGE WITH NO COMPANY BEHIND IT. The tab rail is gone, so the two-column
   rule below would leave a lone panel occupying the right-hand track and half
   the screen empty. One column, and narrow enough to read, because what stands
   here is a paragraph and a two-field form rather than a record. */
.dash-layout-bare { max-width: 46rem; }

/* On a phone the rail is a scrolling strip of tabs; it scrolls inside itself so
   the page never does. */
.dash-nav {
  display: flex;
  flex-direction: row;
  gap: .3rem;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: .35rem;
  border-bottom: 1px solid var(--hairline);
}

.dash-nav::-webkit-scrollbar { display: none; }

.dash-tab {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  min-height: var(--tap);
  padding: .5rem .95rem;
  border-radius: var(--r-sm);
  border: 1px solid transparent;
  background: transparent;
  color: var(--soft);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease),
    border-color var(--t-ui) var(--ease);
}

.dash-tab:hover { color: var(--text); background: rgba(242,237,224,.04); }

.dash-tab.is-active,
.dash-tab[aria-current="page"],
.dash-tab[aria-selected="true"] {
  color: var(--gold-lift);
  background: var(--gold-wash);
  border-color: color-mix(in srgb, var(--gold) 34%, transparent);
}

@media (min-width: 62rem) {
  .dash-layout { grid-template-columns: minmax(0, var(--dash-nav)) minmax(0, 1fr); gap: 2.25rem; }
  /* After the two-column rule, not before it: same specificity, so order decides. */
  .dash-layout-bare { grid-template-columns: minmax(0, 1fr); }
  .dash-nav {
    flex-direction: column;
    align-items: stretch;
    overflow-x: visible;
    padding-bottom: 0;
    border-bottom: 0;
    position: sticky;
    top: calc(var(--header-h) + .5rem);
  }
  .dash-tab { justify-content: flex-start; white-space: normal; }
}

/* Profile completeness. The fill is struck gold, the track is not. */
.meter {
  height: 8px;
  border-radius: 999px;
  border: 1px solid var(--hairline);
  background: var(--surface-3);
  overflow: hidden;
}

.meter-bar {
  display: block;
  height: 100%;
  width: 0;
  max-width: 100%;
  border-radius: 999px;
  background: var(--foil);
  background-size: 220% 100%;
  /* Restated rather than left to the shorthand: a page that also puts .foil on
     the fill would otherwise clip this gradient to the text of an element that
     has none, and the bar would vanish. */
  -webkit-background-clip: border-box;
  background-clip: border-box;
  animation: foil-drift 9s linear infinite;
  transition: width var(--t-section) var(--ease);
}

.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  gap: 1rem;
}

.stat {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  min-width: 0;
  padding: 1.15rem 1.25rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--surface);
}

.stat-num {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 1.35rem + 1vw, 2.15rem);
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1.05;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.stat-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  overflow-wrap: anywhere;
}

.doc-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .65rem 1rem;
  min-width: 0;
  padding: 1rem 0;
  border-bottom: 1px solid var(--hairline);
}

.doc-row:last-child { border-bottom: 0; }

.doc-row > * { min-width: 0; }

.doc-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .3rem .7rem;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .07em;
  color: var(--faint);
  overflow-wrap: anywhere;
}

.thread-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, auto);
  gap: .3rem .9rem;
  align-items: start;
  min-width: 0;
  padding: 1rem .35rem 1rem 1rem;
  border-bottom: 1px solid var(--hairline);
  color: inherit;
  border-inline-start: 2px solid transparent;
  transition: background-color var(--t-ui) var(--ease), border-color var(--t-ui) var(--ease);
}

.thread-row:last-child { border-bottom: 0; }

.thread-row:hover { background: rgba(242,237,224,.03); color: inherit; }

.thread-row > * { min-width: 0; overflow-wrap: anywhere; }

.thread-row.is-unread {
  border-inline-start-color: var(--gold);
  background: var(--gold-wash);
}

.thread-row.is-unread .company-name,
.thread-row.is-unread strong { color: var(--gold-lift); }

.msg-list {
  display: flex;
  flex-direction: column;
  gap: .85rem;
  min-width: 0;
  padding: .25rem 0;
}

/* A message body is a member's own words: it wraps anywhere, because a pasted
   tracking number has no space in it. */
.msg {
  max-width: min(100%, 44rem);
  min-width: 0;
  align-self: flex-start;
  padding: .9rem 1.1rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--surface-2);
  color: var(--text);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.msg.mine {
  align-self: flex-end;
  background: color-mix(in srgb, var(--gold) 9%, var(--surface-2));
  border-color: color-mix(in srgb, var(--gold) 32%, transparent);
}

.msg .mono-meta { margin-top: .5rem; }

.composer {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .85rem;
  min-width: 0;
  padding: 1.15rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--surface);
}

.composer > * { min-width: 0; }

.composer textarea { min-height: 6.5rem; }

/* What is still missing from a profile, as a plain ledger list. */
.missing-list {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  min-width: 0;
}

.missing-list li {
  display: flex;
  align-items: baseline;
  gap: .6rem;
  min-width: 0;
  padding: .3rem 0;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .06em;
  color: var(--soft);
  overflow-wrap: anywhere;
}

.missing-list li::before {
  content: "";
  flex: none;
  width: 14px;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold));
  transform: translateY(-.3em);
}


/* ===========================================================================
   15  TABLES
   A data table is the one thing on this platform that is allowed to be wider
   than the screen, and it is allowed only inside its own scroll container.
   =========================================================================== */

.table-wrap {
  min-width: 0;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  background: var(--surface);
}

.table {
  width: 100%;
  min-width: 30rem;
  border-collapse: collapse;
  font-size: .9rem;
}

.table caption {
  padding: .9rem 1.1rem;
  text-align: start;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
}

.table th {
  padding: .85rem 1.1rem;
  text-align: start;
  vertical-align: bottom;
  border-bottom: 1px solid var(--hairline-strong);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--faint);
  white-space: nowrap;
  overflow-wrap: anywhere;
}

.table td {
  padding: .85rem 1.1rem;
  vertical-align: top;
  border-bottom: 1px solid var(--hairline);
  color: var(--soft);
  overflow-wrap: anywhere;
}

.table tbody tr:last-child td { border-bottom: 0; }

.table tbody tr:hover { background: rgba(242,237,224,.025); }

.table tfoot th,
.table tfoot td {
  border-top: 1px solid var(--hairline-strong);
  border-bottom: 0;
  color: var(--text);
  font-weight: 600;
}


/* ===========================================================================
   16  ADMIN CONSOLE
   Denser than the member side on purpose: this is a work surface, not a
   showroom. It still uses the same materials.
   =========================================================================== */

.admin-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  gap: 1rem;
}

.admin-grid > * { min-width: 0; }

.queue-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .5rem .9rem;
  align-items: start;
  min-width: 0;
  padding: 1.1rem;
  border-bottom: 1px solid var(--hairline);
  transition: background-color var(--t-ui) var(--ease);
}

.queue-row:last-child { border-bottom: 0; }

.queue-row:hover { background: rgba(242,237,224,.025); }

.queue-row > * { min-width: 0; overflow-wrap: anywhere; }

@media (min-width: 48rem) {
  .queue-row { grid-template-columns: minmax(0, 1fr) minmax(0, auto); align-items: center; }
}

/* THE TWO HALVES OF A QUEUE ROW: what the record says, and what can be done
   about it. .queue-row is already a two-column grid on a wide screen, so these
   are simply its columns, named so that a stack of buttons cannot end up
   interleaved with the text it belongs to. On a phone the grid collapses to
   one column and the actions sit under the record, which is the right order to
   read them in. */
.queue-main,
.queue-side {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  min-width: 0;
}

.queue-side { align-items: flex-start; }

@media (min-width: 48rem) {
  .queue-side { align-items: flex-end; text-align: end; }
}

/* Somebody's own words, kept as they typed them: a request written in three
   short paragraphs is read as three short paragraphs. */
.queue-note {
  color: var(--muted);
  font-size: .9rem;
  white-space: pre-wrap;
}

/* THE CONSOLE'S OWN FURNITURE.

   A heading over each view, because a tool that opens straight into a table
   makes the operator work out where they are before they can work. The tabs
   below are grouped for the same reason. */
.nav-group {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  padding: 1.1rem .35rem .35rem;
}

.nav-group:first-child { padding-top: 0; }

/* On a phone the rail is one horizontal strip, and a group label inside it
   would be an item you could try to press. */
@media (max-width: 61.99rem) {
  .nav-group { display: none; }
}

.console-head {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding-bottom: 1.4rem;
  margin-bottom: 1.6rem;
  border-bottom: 1px solid var(--hairline);
}

.console-head h2 {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 1.1rem + 1.4vw, 2rem);
  line-height: 1.15;
}

.console-head p { color: var(--soft); max-width: 60ch; }

.console-subhead {
  display: flex;
  flex-direction: column;
  gap: .35rem;
  padding-bottom: 1rem;
  margin-bottom: 1.2rem;
  border-bottom: 1px solid var(--hairline);
}

.console-subhead h3 { font-size: 1.15rem; }

/* PICK A PAGE, THEN EDIT IT. A rail of pages beside the blocks of the one
   chosen: the same shape as the console around it, one level in. */
.cms-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.4rem;
  align-items: start;
}

@media (min-width: 70rem) {
  .cms-split { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); gap: 2rem; }
  .page-rail { position: sticky; top: calc(var(--header-h) + .5rem); }
}

.cms-split > * { min-width: 0; }

.page-rail {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: .3rem;
  min-width: 0;
}

@media (min-width: 70rem) {
  .page-rail { flex-direction: column; flex-wrap: nowrap; }
}

/* The divider inside the page rail. On a phone the rail is a wrapping row, so
   the label takes a line of its own rather than sitting between two buttons. */
.page-rail .nav-group { flex-basis: 100%; display: block; padding: .9rem .35rem .3rem; }

.page-tab {
  display: flex;
  flex-direction: column;
  gap: .15rem;
  align-items: flex-start;
  text-align: start;
  min-width: 0;
  padding: .6rem .8rem;
  border-radius: var(--r-md);
  border: 1px solid transparent;
  background: none;
  color: var(--soft);
  cursor: pointer;
  transition:
    color var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease),
    border-color var(--t-ui) var(--ease);
}

.page-tab:hover { color: var(--text); background: rgba(242,237,224,.04); }

.page-tab.is-on {
  color: var(--gold-lift);
  background: var(--gold-wash);
  border-color: color-mix(in srgb, var(--gold) 34%, transparent);
}

.page-tab-name { font-size: .9375rem; overflow-wrap: anywhere; }

.page-tab-meta {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .1em;
  color: var(--faint);
}

.cms-body { display: flex; flex-direction: column; gap: 1.1rem; min-width: 0; }

.cms-block .card-head h3 { font-size: 1.0625rem; }

/* THE PICTURE LIBRARY. Wide enough that somebody can tell two photographs of
   the same room apart, which is the whole job of a thumbnail here. */
.pic-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 19rem), 1fr));
  gap: 1.1rem;
}

.pic-grid > * { min-width: 0; }

.pic-card { overflow: hidden; }

.pic-thumb {
  display: block;
  width: 100%;
  height: 12rem;
  object-fit: cover;
  background: var(--surface-2);
  border-bottom: 1px solid var(--hairline);
}

/* A tick beside its own sentence, rather than a label above a lone checkbox. */
.option-inline {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .7rem .9rem;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  cursor: pointer;
}

.option-inline input { flex: 0 0 auto; }

/* THE PUBLIC GALLERY. Same idea, bigger, and captioned - it sits on a page a
   visitor reads rather than in a tool somebody works in. */
.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr));
  gap: 1.4rem;
}

.gallery-grid > * { min-width: 0; }

.gallery-figure {
  display: flex;
  flex-direction: column;
  gap: .7rem;
  min-width: 0;
}

.gallery-figure img {
  display: block;
  width: 100%;
  height: 16rem;
  object-fit: cover;
  border-radius: var(--r-lg);
  border: 1px solid var(--hairline);
  background: var(--surface-2);
}

.gallery-figure figcaption {
  font-size: .875rem;
  color: var(--soft);
  overflow-wrap: anywhere;
}

/* A convening with a date on it. The date block is set apart from the words
   because a reader scanning this page is scanning for when, not for what. */
.convening {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
}

@media (min-width: 44rem) {
  .convening { grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); gap: 1.6rem; }
}

.convening-when {
  font-family: var(--font-mono);
  font-size: .8125rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--gold-lift);
}

.convening-where {
  font-family: var(--font-mono);
  font-size: .75rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--faint);
}

/* An event's own photographs, under its description. Smaller than the site
   gallery: they are part of the entry rather than the point of the page. */
.convening-album { margin-top: 1rem; }
.convening-album .gallery-figure img { height: 11rem; }

.convening-image {
  display: block;
  width: 100%;
  height: 13rem;
  object-fit: cover;
  border-radius: var(--r-md);
  border: 1px solid var(--hairline);
  background: var(--surface-2);
}

/* A shared secret that has to be typed accurately into a phone. Bigger than
   body text and widely tracked, because the whole failure mode of this string
   is a 0 read as an O. */
.totp-secret {
  font-size: 1.05rem;
  letter-spacing: .14em;
  overflow-wrap: anywhere;
}

.audit-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .35rem .9rem;
  min-width: 0;
  padding: .9rem 1.1rem;
  border-bottom: 1px solid var(--hairline);
  font-size: .875rem;
}

.audit-row:last-child { border-bottom: 0; }

.audit-row > * { min-width: 0; overflow-wrap: anywhere; }

@media (min-width: 48rem) {
  .audit-row { grid-template-columns: minmax(0, 12rem) minmax(0, 1fr); align-items: baseline; }
}

/* Before and after, side by side on a wide screen and stacked on a phone. */
.diff {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .85rem;
  min-width: 0;
}

@media (min-width: 48rem) {
  .diff { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* A <pre> here is deliberate as well as convenient: the i18n walker skips PRE,
   so a stored JSON payload is never run through the dictionary. */
.diff-col {
  min-width: 0;
  max-height: 22rem;
  overflow: auto;
  padding: .9rem 1rem;
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline);
  background: var(--void);
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 1.6;
  color: var(--soft);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  tab-size: 2;
}

.kv {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .1rem .9rem;
  min-width: 0;
  padding: .45rem 0;
  border-bottom: 1px solid var(--hairline);
  font-size: .875rem;
  overflow-wrap: anywhere;
}

.kv:last-child { border-bottom: 0; }

.kv > * { min-width: 0; overflow-wrap: anywhere; }

.kv > :first-child {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--faint);
}

.kv > :last-child { color: var(--text); }

@media (min-width: 30rem) {
  .kv { grid-template-columns: minmax(0, 11rem) minmax(0, 1fr); align-items: baseline; }
}


/* ===========================================================================
   17  INVOICE - screen and print
   server.js composes the invoice itself and puts .invoice-page on <body>, so
   these rules style a whole document rather than a component. On screen it is
   the same obsidian as the rest of the platform; on paper it is ink on stock.
   =========================================================================== */

.invoice-page { background: var(--canvas); color: var(--text); }

.invoice-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.25rem 1.75rem;
  padding-bottom: 1.5rem;
  margin-bottom: 2.25rem;
  border-bottom: 1px solid var(--hairline);
}

.invoice-head > * { min-width: 0; }

.invoice-head .display { font-size: clamp(1.75rem, 1.4rem + 1.8vw, 2.5rem); margin-top: .5rem; }

.invoice-meta {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
  gap: 1.35rem 1.75rem;
  margin-bottom: 2.5rem;
}

.invoice-meta > div { min-width: 0; }

.invoice-meta dt {
  font-family: var(--font-mono);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: .35rem;
}

.invoice-meta dd {
  margin: 0;
  min-width: 0;
  font-size: .95rem;
  line-height: 1.6;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* Two columns only, so it fits a 360px screen without a scroll container. */
.invoice-table {
  width: 100%;
  table-layout: auto;
  margin-bottom: 2.25rem;
  font-size: .95rem;
}

.invoice-table th {
  padding: .8rem 0;
  text-align: start;
  border-bottom: 1px solid var(--hairline-strong);
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--faint);
  overflow-wrap: anywhere;
}

.invoice-table td {
  padding: 1rem 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--text);
  vertical-align: top;
  overflow-wrap: anywhere;
}

.invoice-table th.right,
.invoice-table td.right { text-align: end; }

.invoice-table tfoot th,
.invoice-table tfoot td {
  padding-top: 1.1rem;
  border-bottom: 0;
  border-top: 1px solid var(--hairline-strong);
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 700;
  letter-spacing: -.01em;
  color: var(--text);
  text-transform: none;
}

.invoice-note {
  max-width: 62ch;
  margin-top: .85rem;
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--faint);
}

/* Paper. Black on white, no chrome, no shadows, no atmosphere, and no controls:
   a printed Print button is a smudge. */
@media print {
  html,
  body,
  .invoice-page {
    background: #fff !important;
    color: #000 !important;
  }

  .site-header,
  #site-header,
  .site-footer,
  #site-footer,
  .skip-link,
  .grain,
  .aurora,
  .graticule,
  .toaster,
  .main-nav,
  .lang-switch,
  .btn,
  .dash-nav,
  .composer { display: none !important; }

  .invoice-page .shell,
  .invoice-page .shell-narrow { max-width: none; padding-inline: 0; }

  .invoice-page .section { padding-block: 0; }

  .invoice-page .display,
  .invoice-page h1,
  .invoice-page h2,
  .invoice-page h3 { color: #000 !important; }

  .invoice-page .eyebrow { color: #444 !important; }

  .invoice-page .eyebrow::before { background: #999 !important; }

  .invoice-head { border-bottom-color: #000 !important; margin-bottom: 1.5rem; }

  .invoice-meta dt { color: #555 !important; }
  .invoice-meta dd { color: #000 !important; }

  .invoice-table th { color: #555 !important; border-bottom-color: #000 !important; }
  .invoice-table td { color: #000 !important; border-bottom-color: #bbb !important; }
  .invoice-table tfoot th,
  .invoice-table tfoot td { color: #000 !important; border-top-color: #000 !important; }

  .invoice-note { color: #444 !important; }

  .panel,
  .inset-well,
  .table-wrap,
  .stat,
  .option-card,
  .notice {
    box-shadow: none !important;
    background: #fff !important;
    border-color: #bbb !important;
    color: #000 !important;
  }

  .panel::before { display: none !important; }

  .foil,
  .foil-rule,
  .btn-primary,
  .meter-bar {
    background: none !important;
    color: #000 !important;
    -webkit-text-fill-color: #000 !important;
    animation: none !important;
  }

  a { color: #000 !important; text-decoration: none; }

  @page { margin: 16mm; }
}


/* ===========================================================================
   18  MOTION AND REDUCED-MOTION
   Every keyframe in the sheet, then the budget for touch and small screens,
   then the opt-out.
   =========================================================================== */

/* Light crossing metal. background-position cannot run on the compositor, so
   every frame is a main-thread paint: this is the reason section 18 turns it
   off below 1024px. */
@keyframes foil-drift {
  0%   { background-position: 0% 50%; }
  100% { background-position: 200% 50%; }
}

@keyframes aurora-drift {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  50%  { transform: translate3d(-3%, 2%, 0) scale(1.08); }
  100% { transform: translate3d(3%, -2%, 0) scale(1.02); }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes shimmer {
  0%   { background-position: 120% 0; }
  100% { background-position: -20% 0; }
}

@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* The frosted header, granted only to pointer devices on a wide screen.
   Written as an opt-in rather than an override, because `backdrop-filter:none`
   and its -webkit- twin get collapsed into one declaration by a minifier and
   the override then silently stops working in whichever engine lost its
   spelling. */
@media (hover: hover) and (min-width: 64rem) {
  .site-header {
    background: color-mix(in srgb, var(--canvas) 82%, transparent);
    backdrop-filter: blur(18px) saturate(1.3);
    -webkit-backdrop-filter: blur(18px) saturate(1.3);
  }
}

/* The GPU budget for phones and tablets. The aurora rasterises a 90px Gaussian
   over a layer inset by -20%, and foil-drift repaints on the main thread; both
   are on screen permanently. The look survives: the radials are already soft,
   so a smaller blur reads almost the same, and struck gold still looks struck
   when it holds still. */
@media (hover: none), (max-width: 1023px) {
  .aurora { filter: blur(36px); }

  .btn-primary,
  .foil,
  .foil-rule,
  .meter-bar,
  .nav-link.is-active::after,
  .option-card.selected::after { animation: none; }
}

/* The opt-out, last so it wins. Nothing here changes a layout or hides a
   control: motion stops, the page does not move. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *,
  *::before,
  *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: .01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  .aurora,
  .foil,
  .foil-rule,
  .btn-primary,
  .meter-bar,
  .skel-line,
  .nav-link.is-active::after,
  .option-card.selected::after,
  .btn.is-loading::before { animation: none !important; }

  .aurora { transform: none; }

  .panel-lift:hover,
  .btn:hover,
  .btn-primary:hover,
  .btn-ghost:hover,
  .btn-danger:hover,
  .option-card:hover,
  .btn:active { transform: none; }

  .btn-primary::after,
  .btn-primary:hover::after { transform: translateX(-120%) skewX(-18deg); }

  .toast { animation: none !important; opacity: 1; }
}

/* ---- lists that carry the accent ---------------------------------------
   A bullet drawn as a 45 degree square in the accent, and a mono counter for an
   ordered one. Both were named in the page contract and neither existed, so the
   six Council pages each wrote a prefixed copy. These are the shared ones; a
   page that wants a variant still prefixes it. */
.tick-list { display: grid; gap: .85rem; min-width: 0; }
.tick-list > li {
  position: relative;
  min-width: 0;
  padding-inline-start: 1.9rem;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}
.tick-list > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .55em;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--a);
  box-shadow: 0 0 12px -2px var(--a-glow);
  transform: rotate(45deg);
}

.num-list { display: grid; gap: 0; counter-reset: n; min-width: 0; }
.num-list > li {
  counter-increment: n;
  position: relative;
  min-width: 0;
  padding: .9rem 0 .9rem 3rem;
  border-top: 1px solid var(--hairline);
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}
.num-list > li::before {
  content: counter(n, decimal-leading-zero);
  position: absolute;
  inset-inline-start: 0;
  top: .95rem;
  font-family: var(--font-mono);
  font-size: .75rem;
  letter-spacing: .08em;
  color: var(--a);
}

/* ==== merged from public/css-parts, by tools/merge-css.js. Edit the parts. ==== */

/* ---- chamber.css ---- */
/* ===========================================================================
   THE CHAMBER - the induction, the seal, and the Chamber's own pages.

   Merged into styles.css by tools/merge-css.js. Edit this file, never the
   merged block.

   ONE IDEA CARRIES THIS WHOLE FILE, and everything else is kept quiet so it
   lands: GOLD IS INLAID, NOT PRINTED. The member's name is not gold-coloured
   text. It is a mask cut through to the live --foil gradient underneath, which
   is oversized and drifting, so the letters read as metal set into the
   obsidian rather than as a colour applied on top of it. That is the one
   memorable thing in the ceremony and it is the only place this file spends
   any boldness.

   Everything around it is deliberately plain: a disc, a rule, a number in the
   mono face. The restraint is the point - a ceremony where six things compete
   is a screensaver.

   THE MONO FACE ON THE SEAT NUMBER IS A CHOICE, not a default. A seat number
   is a registration, not a headline, and the mono face is what says so. The
   display face would make it an announcement.

   The induction is the only page on this platform that refuses the site
   shell. No header, no footer, no navigation. It is a threshold rather than a
   page, and a threshold with a nav bar is a page.
   =========================================================================== */


/* ---------------------------------------------------------------------------
   C1  THE INLAY - the signature
   --------------------------------------------------------------------------- */

/* The mask. background-clip:text needs a painted background and a transparent
   fill; the oversized background-size is what gives the drift something to
   travel across. */
/* The starting position is 34%, not 0%. --foil begins at --gold-deep (#6b5416),
   which is nearly brown: a name set at 0% opens muddy and only brightens once
   the drift has run, and the first thing a member reads is their own name. 34%
   puts the pale --gold-white band across the opening letters. */
.inlay {
  background-image: var(--foil);
  background-size: 280% 100%;
  background-position: 34% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: inlay-drift 9s linear infinite;
}

@keyframes inlay-drift {
  from { background-position: 34% 50%; }
  to   { background-position: 314% 50%; }
}

/* A WORD IS INDIVISIBLE. Letters are inline-block so each can carry its own
   delay, and an inline-block is a break opportunity - which let the browser
   wrap inside a name. This is the guard against that, and it is the reason
   the letters are grouped per word at all. */
.inlay-word { white-space: nowrap; }
.inlay-gap { display: inline; }

/* Written letter by letter. Each letter is its own span so it can carry its
   own delay; the blur and the lift are what make it read as being set rather
   than switched on. */
.inlay-letter {
  display: inline-block;
  opacity: 0;
  transform: translateY(.18em);
  filter: blur(6px);
  animation: inlay-set .62s var(--ease) forwards;
}
.inlay-letter[data-space="1"] { width: .32em; }

@keyframes inlay-set {
  to { opacity: 1; transform: none; filter: blur(0); }
}


/* ---------------------------------------------------------------------------
   C2  THE STAGE
   --------------------------------------------------------------------------- */

.rite {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  background: var(--void);
  overflow: hidden;
  z-index: 60;
  padding: var(--pad);
}

/* Every act is stacked in the same cell and only one is live. Stacking rather
   than swapping is what lets an act fade out under the next one coming in. */
.act {
  grid-area: 1 / 1;
  width: min(46rem, 100%);
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--t-section) var(--ease);
}
.act[data-live="1"] { opacity: 1; visibility: visible; }

.rite-line {
  font-family: var(--font-body);
  color: var(--soft);
  font-size: clamp(.95rem, 2.4vw, 1.05rem);
  line-height: 1.6;
  margin: 0;
}

.rite-label {
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 1.6rem;
}


/* ---------------------------------------------------------------------------
   C3  ACT I & II - the seal, and the break
   --------------------------------------------------------------------------- */

.seal {
  position: relative;
  width: clamp(9rem, 30vw, 13rem);
  aspect-ratio: 1;
  margin: 0 auto 2.4rem;
}

/* The seal's own light, on the container so no clip-path touches it. Present
   while the seal is whole, and it stays after the halves have gone. */
.seal::before {
  content: "";
  position: absolute;
  inset: -18%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--gold-glow), transparent 58%);
  opacity: .55;
  pointer-events: none;
  transition: opacity 1.4s var(--ease);
}

/* Two halves of one disc. Each is the whole medallion, clipped - so the face
   stays continuous until the moment it parts. */
.seal-half {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 30%, rgba(240,228,180,.5), transparent 46%),
    var(--foil);
  background-size: 100% 100%, 220% 100%;
  /* INSET SHADOWS ONLY. An outer glow here is clipped by the clip-path to each
     half's RECTANGLE, and the two clipped glows compose into a visible square
     halo behind a round seal. The glow belongs to .seal-glow below, which is
     not clipped - and which is also where it should live, since after the
     break the halves are gone and the light is not. */
  box-shadow:
    inset 0 0 0 1px rgba(240,228,180,.28),
    inset 0 -14px 30px rgba(0,0,0,.45);
  animation: seal-turn 26s linear infinite;
  transition: transform 1.5s var(--ease), opacity 1.5s var(--ease);
}
.seal-half[data-side="l"] { clip-path: inset(0 50% 0 0); }
.seal-half[data-side="r"] { clip-path: inset(0 0 0 50%); }

@keyframes seal-turn {
  from { background-position: 34% 30%, 0% 50%; }
  to   { background-position: 34% 30%, 220% 50%; }
}

/* The device struck into the face. Kept to one mark: a struck seal that says
   several things is a sticker. */
.seal-mark {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 5.5vw, 2.3rem);
  letter-spacing: .12em;
  color: rgba(5,11,8,.62);
  text-shadow: 0 1px 0 rgba(240,228,180,.32);
  transition: opacity .7s var(--ease);
}

/* The light behind the seal, which only exists once the seal is gone. */
.seal-light {
  position: absolute;
  inset: -40%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--gold-glow), transparent 62%);
  opacity: 0;
  transform: scale(.4);
  transition: opacity 1.4s var(--ease), transform 1.8s var(--ease);
  pointer-events: none;
}

.seal[data-broken="1"] .seal-half[data-side="l"] {
  transform: translateX(-72%) rotate(-19deg);
  opacity: 0;
}
.seal[data-broken="1"] .seal-half[data-side="r"] {
  transform: translateX(72%) rotate(19deg);
  opacity: 0;
}
.seal[data-broken="1"] .seal-mark { opacity: 0; }
.seal[data-broken="1"] .seal-light { opacity: 1; transform: scale(1); }


/* ---------------------------------------------------------------------------
   C4  ACT III - the name
   --------------------------------------------------------------------------- */

.rite-style {
  font-family: var(--font-mono);
  font-size: clamp(.72rem, 2vw, .82rem);
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--gold-lift);
  margin: 0 0 1rem;
}

.rite-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2rem, 7.5vw, 4.1rem);
  line-height: 1.05;
  letter-spacing: -.02em;
  margin: 0;
  /* A long name must never push the ceremony sideways - but break-word, not
     anywhere: only a single word too wide for the line may be split, and a
     name made of ordinary words never is. */
  overflow-wrap: break-word;
}

/* The Arabic name sits under the Latin one at every language setting. It is
   not a translation - it is how the name is written. */
.rite-name-ar {
  font-family: var(--font-body);
  font-size: clamp(1.1rem, 4vw, 1.7rem);
  color: var(--gold-lift);
  margin: .9rem 0 0;
  direction: rtl;
  unicode-bidi: isolate;
}

.rite-rule {
  height: 1px;
  width: min(22rem, 70%);
  margin: 2rem auto;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
  transform: scaleX(0);
  transform-origin: 50% 50%;
  transition: transform 1.1s var(--ease);
}
.act[data-live="1"] .rite-rule { transform: scaleX(1); }


/* ---------------------------------------------------------------------------
   C5  ACT IV - the seat
   --------------------------------------------------------------------------- */

.seat-no {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(3.4rem, 15vw, 7rem);
  line-height: 1;
  letter-spacing: -.01em;
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.seat-caption {
  font-family: var(--font-mono);
  font-size: .72rem;
  letter-spacing: .32em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 1.1rem 0 0;
}

.seat-facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .6rem 2rem;
  margin: 2.2rem 0 0;
  font-family: var(--font-body);
  font-size: .92rem;
  color: var(--soft);
}


/* ---------------------------------------------------------------------------
   C6  ACT V - the circle
   --------------------------------------------------------------------------- */

/* Other seats as anonymous points of light. No names and no numbers: the
   circle shows its size, never its membership. */
.circle {
  position: relative;
  width: min(21rem, 74vw);
  aspect-ratio: 1;
  margin: 0 auto 2.4rem;
}

.circle-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid var(--hairline-strong);
}

.circle-seat {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 5px;
  height: 5px;
  margin: -2.5px 0 0 -2.5px;
  border-radius: 50%;
  background: var(--gold);
  opacity: 0;
  animation: seat-lit .8s var(--ease) forwards;
}

/* Theirs, and it is the only one that is not anonymous. */
.circle-seat[data-mine="1"] {
  width: 11px;
  height: 11px;
  margin: -5.5px 0 0 -5.5px;
  background: var(--gold-white);
  box-shadow: 0 0 18px 4px var(--gold-glow);
}

@keyframes seat-lit {
  from { opacity: 0; transform: scale(.3); }
  to   { opacity: .85; transform: scale(1); }
}


/* ---------------------------------------------------------------------------
   C7  THE CONTROLS
   --------------------------------------------------------------------------- */

.rite-go {
  margin-top: 2.6rem;
  display: flex;
  gap: .8rem;
  justify-content: center;
  flex-wrap: wrap;
}

/* Small, low-contrast, and present from the first frame to the last. Somebody
   opening this on a phone in a meeting has to be able to leave, and a skip
   that appears only after the part you wanted to skip is not a skip. */
.rite-skip {
  position: fixed;
  inset-inline-end: var(--pad);
  bottom: var(--pad);
  z-index: 61;
  background: none;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  color: var(--faint);
  font-family: var(--font-mono);
  font-size: .7rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  padding: .55rem .9rem;
  cursor: pointer;
  transition: color var(--t-ui) var(--ease), border-color var(--t-ui) var(--ease);
}
.rite-skip:hover { color: var(--text); border-color: var(--hairline-strong); }
.rite-skip:focus-visible { outline: 2px solid var(--gold-lift); outline-offset: 2px; }


/* ---------------------------------------------------------------------------
   C8  REDUCED MOTION - the same ceremony, composed rather than played
   --------------------------------------------------------------------------- */

/* NOT A DEGRADED FALLBACK. Every act's content is laid out as one static
   plate carrying exactly what the played version says, which is also what the
   credential is built from. Somebody who asked their system for less motion
   is not asking for less of the moment. */
@media (prefers-reduced-motion: reduce) {
  .inlay { animation: none; background-position: 40% 50%; }
  .inlay-letter { opacity: 1; transform: none; filter: none; animation: none; }
  .seal-half { animation: none; transition: none; }
  .seal-light { transition: none; }
  .circle-seat { animation: none; opacity: .85; transform: none; }
  .act { transition: none; }
  .rite-rule { transition: none; transform: scaleX(1); }

  .rite[data-composed="1"] { position: static; display: block; padding: 0; }
  .rite[data-composed="1"] .act {
    opacity: 1;
    visibility: visible;
    display: block;
    margin: 0 auto 3.4rem;
  }
  .rite[data-composed="1"] .seal[data-broken="1"] .seal-half { display: none; }
}


/* ---------------------------------------------------------------------------
   C9  THE CHAMBER'S OWN PAGES
   --------------------------------------------------------------------------- */

/* THE HERO. The seat number is the largest thing on the page and the name sits
   under it, not the other way round: the number is what ranks, and it is the
   thing the member cannot get again. */
.chamber-hero {
  position: relative;
  text-align: center;
  padding: clamp(2rem, 7vw, 4rem) var(--pad) clamp(2rem, 5vw, 3rem);
  margin-bottom: 1rem;
  isolation: isolate;
}

.chamber-hero-glow {
  position: absolute;
  inset-block-start: -30%;
  inset-inline-start: 50%;
  translate: -50% 0;
  width: min(40rem, 120%);
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle, var(--gold-glow), transparent 58%);
  opacity: .3;
  pointer-events: none;
  z-index: -1;
}

.chamber-seat-no {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(4rem, 20vw, 9rem);
  line-height: .92;
  letter-spacing: -.02em;
  font-variant-numeric: tabular-nums;
  margin: .4rem 0 0;
}

.chamber-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.4rem, 5vw, 2.4rem);
  line-height: 1.15;
  letter-spacing: -.01em;
  margin: 1rem 0 0;
  overflow-wrap: break-word;
}

.chamber-name-ar {
  font-family: var(--font-body);
  font-size: clamp(1rem, 3.4vw, 1.35rem);
  color: var(--gold-lift);
  margin: .5rem 0 0;
  direction: rtl;
  unicode-bidi: isolate;
}

.chamber-rule {
  height: 1px;
  width: min(20rem, 60%);
  margin: 2rem auto 1.8rem;
  background: linear-gradient(90deg, transparent, var(--gold), transparent);
}

/* Standing, jurisdiction, admitted, and the size of the circle. A definition
   list because that is what it is: four labelled facts about one seat. */
.chamber-facts {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 1.4rem 3rem;
  margin: 0;
}
.chamber-facts > div { text-align: center; }
.chamber-facts dt {
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--faint);
  margin-bottom: .45rem;
}
.chamber-facts dd {
  margin: 0;
  font-family: var(--font-body);
  font-size: .98rem;
  color: var(--text);
}
.chamber-facts dd.is-gold { color: var(--gold-lift); }

/* The roster. One row per seat, and the number leads because the number is
   what ranks. */
.roster { display: grid; gap: 1px; background: var(--hairline); border-radius: var(--r-md); overflow: hidden; }

.roster-row {
  display: grid;
  grid-template-columns: minmax(0, 5rem) minmax(0, 1fr) minmax(0, auto);
  gap: 1rem;
  align-items: baseline;
  padding: 1.1rem var(--pad);
  background: var(--surface);
}

/* The seat number leads every row, in foil, because the number is what ranks.
   Set in the mono face so 007 and 412 occupy the same width and the column
   reads as a register rather than as prose. */
.roster-seat {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: 1.05rem;
  letter-spacing: .04em;
  background-image: var(--foil);
  background-size: 280% 100%;
  background-position: 34% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

/* The member's own row, so a long roster still answers "where am I" at a
   glance without them counting. */
.roster-row[data-mine="1"] {
  background: linear-gradient(90deg, var(--gold-wash), transparent 46%), var(--surface-2);
  border-inline-start: 2px solid var(--gold);
}
.roster-name { font-family: var(--font-display); font-weight: 500; min-width: 0; overflow-wrap: anywhere; }
.roster-where { font-family: var(--font-body); font-size: .88rem; color: var(--faint); text-align: end; }

@media (max-width: 34rem) {
  .roster-row { grid-template-columns: minmax(0, 3.6rem) minmax(0, 1fr); }
  .roster-where { grid-column: 2; text-align: start; }
}

/* The count, stated plainly. It includes seats this member cannot see, which
   is deliberate and explained in chamber.js. */
.chamber-count {
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--faint);
  text-align: center;
  margin-top: 1.6rem;
}


/* ---------------------------------------------------------------------------
   C9a  THE SEAT BAR - the second line of the header
   --------------------------------------------------------------------------- */

/* Only a seat ever sees this. It sits UNDER the ordinary header rather than
   replacing it, because a Chamber member is still a member: the tier is added
   to what they had, not swapped for it.

   The foil hairline along the top edge is doing the whole job. It is the only
   place on any page outside the Chamber where the gold gradient appears, so it
   reads as a seam in the chrome rather than as decoration. */
.seat-bar {
  position: relative;
  background: linear-gradient(180deg, rgba(184,145,47,.09), transparent 62%), var(--canvas-2);
  border-block-start: 1px solid var(--hairline);
  border-block-end: 1px solid var(--hairline);
}
.seat-bar::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline: 0;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 14s linear infinite;
}

/* THE NAV SITS IN THE MIDDLE. Three columns, with the outer two given equal
   weight so the centre column is centred against the PAGE and not against
   whatever happens to be beside it - a nav pushed to one side read as an
   afterthought bolted to the header, which is the opposite of the point. */
.seat-bar-inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1.4rem;
  min-height: 3.4rem;
}
.seat-bar-inner > :last-child { justify-self: end; }

.seat-mark {
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: var(--gold-lift);
  white-space: nowrap;
}

/* The seat number, carried in the chrome on every page. It is the one number
   worth having in front of a member at all times. */
.seat-no-chip {
  font-variant-numeric: tabular-nums;
  letter-spacing: .12em;
  color: var(--void);
  background: var(--foil);
  background-size: 200% 100%;
  border-radius: 999px;
  padding: .16rem .5rem;
  font-size: .7rem;
}

.seat-nav {
  display: flex;
  gap: clamp(1rem, 3vw, 2.4rem);
  flex-wrap: wrap;
  justify-content: center;
}

.seat-link {
  position: relative;
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--soft);
  text-decoration: none;
  padding: 1rem 0;
  white-space: nowrap;
  transition: color var(--t-ui) var(--ease);
}
.seat-link::after {
  content: "";
  position: absolute;
  inset-block-end: .7rem;
  inset-inline: 0;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  transform: scaleX(0);
  transition: transform var(--t-ui) var(--ease);
}
.seat-link:hover { color: var(--text); }
.seat-link:hover::after { transform: scaleX(.5); }
.seat-link.is-active { color: var(--gold-lift); }
.seat-link.is-active::after { transform: scaleX(1); }
.seat-link:focus-visible { outline: 2px solid var(--gold-lift); outline-offset: 3px; }

/* On a narrow screen the three columns collapse and the nav keeps the middle. */
@media (max-width: 46rem) {
  .seat-bar-inner { grid-template-columns: 1fr; justify-items: center; gap: 0; padding-block: .3rem; }
  .seat-bar-inner > :last-child { justify-self: center; }
  .seat-link { padding: .5rem 0; }
}

/* The ceremony is still owed, so the bar carries one thing and no navigation. */
.seat-bar[data-owed="1"] .seat-bar-inner { gap: 1rem; }
.seat-bar[data-owed="1"] { background: linear-gradient(180deg, var(--gold-wash), transparent 70%), var(--canvas-2); }


/* ---------------------------------------------------------------------------
   C9b  WHAT A SEAT ENTITLES YOU TO
   --------------------------------------------------------------------------- */

.chamber-section { margin-top: 3.5rem; }

/* The roster row is two columns of fixed intent; these rows carry a variable
   number of parts, so they lay out by content instead. */
.roster-row-wide {
  grid-template-columns: minmax(0, 1fr) minmax(0, auto) minmax(0, auto);
  align-items: center;
  gap: 1rem;
}
@media (max-width: 38rem) {
  .roster-row-wide { grid-template-columns: minmax(0, 1fr); }
  .roster-row-wide .roster-where { text-align: start; }
}

/* The correspondence. Two speakers, and the Council is the one with the foil
   edge - the member's own words need no decoration to be found. */
.council-thread {
  display: grid;
  gap: .9rem;
  margin-bottom: 2rem;
}

.council-message {
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  padding: 1rem var(--pad);
  background: var(--surface);
  max-width: 44rem;
}
.council-message[data-from="council"] {
  border-inline-start: 2px solid var(--gold);
  background: linear-gradient(90deg, var(--gold-wash), transparent 40%), var(--surface);
}
.council-message[data-from="me"] {
  margin-inline-start: auto;
  background: var(--surface-2);
}

.council-who {
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0 0 .5rem;
}
.council-body { margin: 0; line-height: 1.6; overflow-wrap: anywhere; white-space: pre-wrap; }


/* ---------------------------------------------------------------------------
   C9c  A SEAT, OPENED
   --------------------------------------------------------------------------- */

/* The roster row as a control. It is a <button>, so it inherits none of the
   layout the div had - width, font and text alignment all have to be said. */
.roster-open {
  width: 100%;
  border: 0;
  font: inherit;
  text-align: start;
  cursor: pointer;
  color: var(--text);
  transition: background var(--t-ui) var(--ease);
}
.roster-open:hover { background: var(--surface-2); }
.roster-open:hover .roster-open-mark { opacity: 1; transform: none; }
.roster-open:focus-visible { outline: 2px solid var(--gold-lift); outline-offset: -2px; }

.roster-open-mark {
  color: var(--gold-lift);
  opacity: 0;
  transform: translateX(-.4rem);
  transition: opacity var(--t-ui) var(--ease), transform var(--t-ui) var(--ease);
}
/* The arrow points the way the language runs. */
[dir="rtl"] .roster-open-mark { scale: -1 1; }

/* The fourth column is the arrow, and it belongs ONLY to rows that open. Set on
   .roster-row this overrode .roster-row-wide - which is declared earlier and so
   loses at equal specificity - and squeezed every entity name in the sheet into
   a two-column column: "Gulf Cold / Chain". */
.roster-open { grid-template-columns: minmax(0, 5rem) minmax(0, 1fr) minmax(0, auto) minmax(0, 1.5rem); }

.seat-sheet {
  position: fixed;
  inset: 0;
  z-index: 80;
  display: grid;
  place-items: center;
  padding: var(--pad);
  background: rgba(2, 3, 6, .82);
  overflow-y: auto;
}
.seat-sheet[hidden] { display: none; }

/* The panel opens like a plate being set down rather than a box appearing. */
.seat-sheet-panel {
  position: relative;
  width: min(38rem, 100%);
  max-height: 92dvh;
  overflow-y: auto;
  text-align: center;
  padding: clamp(2rem, 6vw, 3.2rem) clamp(1.2rem, 5vw, 2.6rem) clamp(1.6rem, 4vw, 2.4rem);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surface), var(--canvas));
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.9);
  animation: sheet-set .42s var(--ease) both;
}

@keyframes sheet-set {
  from { opacity: 0; transform: translateY(14px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* The foil seam along the top edge, the same device the seat bar uses, so the
   two read as parts of one system. */
.seat-sheet-panel::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 12%;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 12s linear infinite;
}

.sheet-seal {
  width: 3.4rem;
  aspect-ratio: 1;
  margin: 0 auto 1.6rem;
  border-radius: 50%;
  background: var(--foil);
  background-size: 220% 100%;
  box-shadow: inset 0 0 0 1px rgba(240,228,180,.3), inset 0 -6px 14px rgba(0,0,0,.4);
  animation: foil-drift 18s linear infinite;
}

.sheet-seat-no {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(3rem, 13vw, 5rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin: .3rem 0 0;
}

.sheet-name {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.2rem, 4.4vw, 1.9rem);
  line-height: 1.2;
  margin: .9rem 0 0;
  overflow-wrap: break-word;
}

.sheet-name-ar {
  font-family: var(--font-body);
  font-size: clamp(.95rem, 3vw, 1.2rem);
  color: var(--gold-lift);
  margin: .45rem 0 0;
  direction: rtl;
  unicode-bidi: isolate;
}

.sheet-block { margin-top: 2.2rem; text-align: start; }
.sheet-block-tight { margin-top: 1.4rem; }

.sheet-prose {
  margin: 1.8rem 0 0;
  text-align: start;
  color: var(--soft);
  line-height: 1.7;
  overflow-wrap: anywhere;
}

.sheet-sub {
  display: block;
  font-family: var(--font-mono);
  font-size: .64rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  margin-top: .3rem;
}

/* How to reach them, when they have chosen to be reachable. */
.sheet-reaches {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .6rem;
  margin-top: 1.8rem;
}

.sheet-reach {
  font-family: var(--font-mono);
  font-size: .74rem;
  letter-spacing: .06em;
  color: var(--gold-lift);
  text-decoration: none;
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  padding: .42rem .9rem;
  overflow-wrap: anywhere;
  transition: border-color var(--t-ui) var(--ease), background var(--t-ui) var(--ease);
}
a.sheet-reach:hover { border-color: var(--gold); background: var(--gold-wash); }


/* ---------------------------------------------------------------------------
   C9d  WHAT YOU SHOW
   --------------------------------------------------------------------------- */

/* The field and its switch on ONE ROW. Splitting "what have I written" from
   "who may see it" across two panels is how somebody publishes a telephone
   number they believed was private. */
.show-panel {
  display: grid;
  gap: 1px;
  background: var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
}

.show-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 13rem);
  gap: 1.4rem;
  align-items: start;
  padding: 1.3rem var(--pad);
  background: var(--surface);
}
.show-row-plain { align-items: center; }

.show-field .label { margin-bottom: .45rem; }
.show-field .hint { margin-top: .4rem; }

/* The switch reads as a state, not as a checkbox in a form: it goes gold when
   it is on, so a glance down the panel answers "what am I showing". */
.show-toggle {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .6rem .8rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--faint);
  transition: color var(--t-ui) var(--ease), border-color var(--t-ui) var(--ease),
              background var(--t-ui) var(--ease);
}
.show-toggle:hover { color: var(--soft); border-color: var(--hairline-strong); }
.show-toggle:has(input:checked) {
  color: var(--gold-lift);
  border-color: var(--gold-deep);
  background: var(--gold-wash);
}
.show-toggle input { accent-color: var(--gold); flex: none; }

@media (max-width: 42rem) {
  .show-row { grid-template-columns: minmax(0, 1fr); gap: .9rem; }
  .show-toggle { justify-self: start; }
}

.seat-sheet-close {
  position: absolute;
  inset-block-start: .5rem;
  inset-inline-end: .7rem;
  background: none;
  border: 0;
  color: var(--faint);
  font-size: 1.7rem;
  line-height: 1;
  padding: .3rem .55rem;
  cursor: pointer;
  border-radius: var(--r-sm);
  transition: color var(--t-ui) var(--ease);
}
.seat-sheet-close:hover { color: var(--text); }
.seat-sheet-close:focus-visible { outline: 2px solid var(--gold-lift); outline-offset: 2px; }


/* ---------------------------------------------------------------------------
   C10  THE CREDENTIAL - seat.html
   --------------------------------------------------------------------------- */

.credential-sheet {
  max-width: 47rem;
  margin: 0 auto;
  /* The SVG is the artifact; the page is only holding it up. */
  filter: drop-shadow(0 24px 60px rgba(0,0,0,.55));
}
.credential-sheet svg { display: block; width: 100%; height: auto; }

.credential-actions { justify-content: center; margin-top: 2rem; }

.credential-verify { max-width: 47rem; margin: 2.6rem auto 0; }

.credential-url {
  word-break: break-all;
  color: var(--gold-lift);
  margin: .9rem 0 1.2rem;
}

/* PRINTING IS A REAL OUTPUT, not an afterthought. Browser print-to-PDF is how
   this credential becomes a file somebody can attach to an email, so the page
   furniture comes off and the artifact sits alone on the sheet. */
@media print {
  .aurora, .graticule, .grain,
  #site-header, #site-footer, .skip-link,
  .credential-actions, .credential-verify, .page-head { display: none !important; }

  html, body { background: #fff !important; }
  main, .shell, .section { padding: 0 !important; margin: 0 !important; }

  .credential-sheet {
    max-width: none;
    filter: none;
    /* Chrome drops SVG gradients without this; the credential is gold or it is
       not the credential. */
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}


/* ---------------------------------------------------------------------------
   C11  VERIFICATION - verify.html
   --------------------------------------------------------------------------- */

/* The answer comes first and largest. Somebody on this page has exactly one
   question, and making them read a layout to find it is the failure mode. */
.verify-verdict {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.5rem, 5vw, 2.2rem);
  line-height: 1.15;
  margin: 0 0 2.4rem;
}
.verify-verdict[data-tone="good"] { color: var(--gold-lift); }
.verify-verdict[data-tone="bad"] { color: var(--soft); }

.verify-seat { margin-bottom: 2.2rem; }

.verify-facts {
  display: grid;
  gap: 1px;
  background: var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
  text-align: start;
  margin: 0;
}
.verify-facts > div {
  display: grid;
  grid-template-columns: minmax(0, 9rem) minmax(0, 1fr);
  gap: 1rem;
  padding: 1rem var(--pad);
  background: var(--surface);
}
.verify-facts dt {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
}
.verify-facts dd { margin: 0; font-family: var(--font-body); overflow-wrap: anywhere; }

@media (max-width: 30rem) {
  .verify-facts > div { grid-template-columns: minmax(0, 1fr); gap: .3rem; }
}

.verify-note { margin-top: 1.8rem; font-size: .92rem; }


/* ---------------------------------------------------------------------------
   C12  THE DOOR - seal.html
   --------------------------------------------------------------------------- */

.door {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--pad);
}

.door-panel {
  width: min(34rem, 100%);
  text-align: center;
}

.door-form { margin-top: 2.4rem; text-align: start; }


/* ---------------------------------------------------------------------------
   C13  THE STAFF SIDE OF THE CHAMBER
   --------------------------------------------------------------------------- */

/* The one-time invitation link. Deliberately allowed to wrap and break, because
   a token clipped by an ellipsis is a token somebody copies half of. */
.cut-link {
  word-break: break-all;
  color: var(--gold-lift);
  margin: .8rem 0;
  line-height: 1.6;
}

/* The invoice a seat is holding against. Centred like the credential it will
   become, because it is the same page at an earlier moment. */
.owing-panel {
  max-width: 40rem;
  margin: 0 auto;
  text-align: center;
  padding: clamp(2rem, 6vw, 3rem) clamp(1.2rem, 5vw, 2.4rem);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, var(--surface), var(--canvas));
}
.owing-how { margin-top: 1.8rem; color: var(--faint); font-size: .92rem; }


/* ---------------------------------------------------------------------------
   C14  THE RING - the Chamber's centrepiece
   --------------------------------------------------------------------------- */

.ring-stage {
  position: relative;
  width: min(30rem, 100%);
  margin: 0 auto 3rem;
  display: grid;
  grid-template-rows: min(30rem, 100vw) auto;
  place-items: center;
}

.ring { grid-area: 1 / 1; width: 100%; height: auto; overflow: visible; }

.ring-track { fill: none; stroke: var(--hairline-strong); stroke-width: 1; }
.ring-track-inner { stroke: var(--hairline); stroke-dasharray: 2 10; }

/* THE SWEEP. A short arc travelling the full circumference, drawn with
   stroke-dasharray so nothing has to be re-rendered per frame - the browser
   animates one number and the GPU does the rest. */
.ring-sweep {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  /* circumference at r=176 is ~1106; a 90-unit arc is a short, deliberate
     sweep rather than a spinning halo. */
  stroke-dasharray: 90 1016;
  transform-origin: 50% 50%;
  animation: ring-sweep 9s linear infinite;
  opacity: .85;
}
@keyframes ring-sweep { to { transform: rotate(360deg); } }

.ring-seat { cursor: pointer; outline: none; }

/* An invisible disc under each point, so a 4px dot has a 40px target. Fitts's
   law does not care how elegant the dot is. */
.ring-hit { fill: transparent; }

.ring-dot {
  fill: var(--gold);
  transition: r .28s var(--ease), fill .28s var(--ease);
}
.ring-halo {
  fill: var(--gold-lift);
  opacity: 0;
  transition: opacity .28s var(--ease);
}

.ring-seat:hover .ring-dot,
.ring-seat:focus-visible .ring-dot { r: 7; fill: var(--gold-white); }
.ring-seat:hover .ring-halo,
.ring-seat:focus-visible .ring-halo { opacity: .16; }
.ring-seat:focus-visible .ring-halo { opacity: .3; }

/* Theirs. Lit from the start and never dimmed, so "where am I" is answered
   before the question is asked. */
.ring-seat.is-mine .ring-dot { fill: var(--gold-white); }
.ring-seat.is-mine .ring-halo { opacity: .22; }

.ring-centre {
  grid-area: 1 / 1;
  text-align: center;
  pointer-events: none;
  max-width: 60%;
}

.ring-centre-no {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(2.6rem, 11vw, 4.4rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin: 0;
}

.ring-centre-name {
  font-family: var(--font-body);
  font-size: clamp(.82rem, 2.6vw, .98rem);
  color: var(--soft);
  margin: .7rem 0 0;
  line-height: 1.4;
  overflow-wrap: break-word;
}

/* Flows under the ring rather than sitting absolutely at its edge, where a
   short viewport clipped it. The stage is a square grid cell; anything pinned
   to its bottom is pinned to the bottom of the SQUARE, not of the content. */
.ring-note {
  grid-area: 2 / 1;
  align-self: start;
  text-align: center;
  font-family: var(--font-mono);
  font-size: .66rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 0;
}


/* ---------------------------------------------------------------------------
   C15  ARRIVAL - sections rise as they are reached
   --------------------------------------------------------------------------- */

/* THE STYLESHEET DOES NOT HIDE CONTENT. This rule used to set opacity:0 here
   and rely on script to add .is-in - and the day a render helper threw before
   that ran, the entire Chamber rendered blank. Nothing is worth that.

   Rising is now motion.js's job for every page on the platform, and it only
   ever prepares elements that START BELOW THE FOLD, by adding a class from
   script. A page whose script fails is a page that does not animate, which is
   the correct failure. */

/* A page that never scrolls, or a reader who asked for less motion, must not
   be left with invisible sections. Both paths add .is-in immediately in JS;
   this is the belt to that braces, for the case where the script never runs. */
@media (prefers-reduced-motion: reduce) {
  .chamber-section { opacity: 1; transform: none; transition: none; }
  .ring-sweep { animation: none; opacity: .5; }
  .ring-dot, .ring-halo { transition: none; }
}


/* ---------------------------------------------------------------------------
   C16  MATERIAL - surfaces that read as objects
   --------------------------------------------------------------------------- */

/* One hairline of light along the top edge and a deeper ground beneath. It is
   the difference between a panel drawn on the page and a panel resting on it,
   and it costs one pseudo-element. */
.roster, .show-panel, .council-thread .council-message, .owing-panel {
  position: relative;
}
.roster::before, .show-panel::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(242,237,224,.14), transparent);
  pointer-events: none;
  z-index: 1;
}


/* ---------------------------------------------------------------------------
   C17  THE REACH - where the circle sits
   --------------------------------------------------------------------------- */

.reach-stage { position: relative; margin-top: 1rem; }
.reach { width: 100%; height: auto; display: block; overflow: visible; }

/* The graticule again, but here the lines are real degrees rather than
   texture, so they are allowed to be slightly more present than the ones in
   the page background. */
.reach-grid { stroke: var(--hairline); stroke-width: 1; }
.reach-grid-g { opacity: .55; }

/* Arcs drawn on, rather than simply appearing. stroke-dashoffset from the full
   length to zero is the cheapest way to draw a line for real. */
.reach-arc {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1;
  stroke-opacity: .28;
  stroke-dasharray: 1200;
  stroke-dashoffset: 1200;
  animation: reach-draw 1.5s var(--ease) forwards;
  transition: stroke-opacity var(--t-ui) var(--ease), stroke-width var(--t-ui) var(--ease);
}
@keyframes reach-draw { to { stroke-dashoffset: 0; } }

.reach-arc.is-lit { stroke: var(--gold-white); stroke-opacity: .9; stroke-width: 1.6; }

.reach-seat { cursor: pointer; outline: none; }
.reach-hit { fill: transparent; }

.reach-dot { fill: var(--gold); transition: r .28s var(--ease), fill .28s var(--ease); }
.reach-seat:hover .reach-dot,
.reach-seat:focus-visible .reach-dot { r: 6; fill: var(--gold-white); }

/* The soft disc under each point. It breathes on the member's own seat only -
   one moving thing on a map of thirty is a focal point; thirty is noise. */
.reach-pulse { fill: var(--gold-lift); opacity: .1; }
.reach-seat.is-mine .reach-pulse {
  fill: var(--gold-white);
  opacity: .18;
  animation: reach-breathe 3.6s ease-in-out infinite;
  transform-origin: center;
  transform-box: fill-box;
}
@keyframes reach-breathe {
  0%, 100% { opacity: .12; transform: scale(1); }
  50%      { opacity: .26; transform: scale(1.18); }
}
.reach-seat.is-mine .reach-dot { fill: var(--gold-white); }

.reach-note {
  text-align: center;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--faint);
  margin: 1rem 0 0;
  min-height: 1.2em;
}

@media (prefers-reduced-motion: reduce) {
  .reach-arc { animation: none; stroke-dashoffset: 0; }
  .reach-seat.is-mine .reach-pulse { animation: none; }
  .reach-dot { transition: none; }
}

/* One label per place, not per seat. Sized down and tracked out so a dense
   cluster reads as a list of cities rather than a smear of text. */



/* Drawn only where a label was stepped away from its point. */



/* ---------------------------------------------------------------------------
   C18  THE LEGEND - names, since the map carries geometry
   --------------------------------------------------------------------------- */

/* Labels in place could not work here: six Gulf capitals inside a few degrees
   have no room between them at any spacing, and pushing the text apart only
   moved the mess. The map keeps the geometry and this keeps the names, and
   hovering either lights the other - which reads faster than a label anyway,
   because a list can be scanned and a picture has to be hunted. */
.reach-legend {
  list-style: none;
  margin: 1.4rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 1px;
  background: var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
}

.reach-legend-row {
  width: 100%;
  display: flex;
  align-items: center;
  gap: .7rem;
  padding: .7rem var(--pad);
  background: var(--surface);
  border: 0;
  cursor: pointer;
  font: inherit;
  text-align: start;
  color: var(--soft);
  transition: background var(--t-ui) var(--ease), color var(--t-ui) var(--ease);
}
.reach-legend-row:hover,
.reach-legend-row.is-lit { background: var(--surface-2); color: var(--text); }
.reach-legend-row:focus-visible { outline: 2px solid var(--gold-lift); outline-offset: -2px; }

.reach-legend-dot {
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--gold);
}
.reach-legend-row.is-lit .reach-legend-dot {
  background: var(--gold-white);
  box-shadow: 0 0 10px 2px var(--gold-glow);
}

.reach-legend-name {
  flex: 1;
  min-width: 0;
  font-family: var(--font-body);
  font-size: .9rem;
  overflow-wrap: anywhere;
}

.reach-legend-n {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-size: .8rem;
  color: var(--gold-lift);
}

/* Everything that is not the hovered place steps back, so a lit point on a
   dense map is found rather than searched for. */
.reach-seat.is-dim { opacity: .28; }
.reach-seat.is-lit .reach-dot { r: 7; fill: var(--gold-white); }
.reach-seat.is-lit .reach-pulse { opacity: .3; }
.reach-seat { transition: opacity var(--t-ui) var(--ease); }

/* An ordinary member's line. The same bar without the metal: no foil seam, no
   chip, a quieter mark. The distinction between the tiers should be visible at
   a glance and should not require reading anything. */
.seat-bar[data-plain="1"] { background: var(--canvas-2); }
.seat-bar[data-plain="1"]::before { background: var(--hairline-strong); animation: none; }
.seat-bar[data-plain="1"] .seat-mark { color: var(--faint); }
.seat-bar[data-plain="1"] .seat-link.is-active { color: var(--text); }
.seat-bar[data-plain="1"] .seat-link::after { background: var(--hairline-strong); }

/* ---- events.css ---- */
/* ===========================================================================
   EVENTS - the convening programme.

   Everything below is prefixed .event-* except the accent block immediately
   under this header, which cannot be prefixed and is not mine.
   =========================================================================== */


/* ---------------------------------------------------------------------------
   SHARED, NOT PAGE SPECIFIC: the accent system.

   The porting contract says [data-accent] already lives in styles.css. It does
   not: the file defines --a, --a-lift, --a-deep, --a-wash and --a-glow once on
   :root as gold and never redefines them, so every data-accent on every one of
   the six new pages currently paints gold. This block is the marketing site's
   own definition (src/App.css) carried across unchanged, with the one
   difference that the platform's token block has no --cyan-deep, --violet-deep,
   --emerald-deep or --rose-deep, so those four values are written literally.

   TO WHOEVER MERGES THE PARTS: this block is very likely to arrive from more
   than one page. Keep exactly one copy, ideally moved up into section 01 of
   styles.css beside the tokens it derives from, and delete the rest. The
   copies should be identical; if one differs, the marketing site is the
   authority.
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   The statement at the top
   --------------------------------------------------------------------------- */

/* The one paragraph the page has to be read before anything else. It sits in a
   recess rather than a notice, because it is the Council stating what this page
   is, not the system warning about something. */
.event-statement {
  max-width: 68ch;
  padding: 1.35rem 1.4rem;
}

.event-statement .eyebrow { margin-bottom: .6rem; }

.event-statement p {
  font-size: .9375rem;
  line-height: 1.7;
  overflow-wrap: anywhere;
}


/* ---------------------------------------------------------------------------
   The filter row
   --------------------------------------------------------------------------- */

.event-filter-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: .5rem 1.5rem;
  min-width: 0;
}

.event-filter-head > * { min-width: 0; }

.event-filters {
  margin-top: 1.25rem;
  gap: .5rem;
}

/* .filter-pill.active in styles.css is written in literal gold, so a pill
   carrying data-accent="cyan" would still light gold. Scoped to this row rather
   than corrected in the shared class, because the shared class is somebody
   else's page too. */
.event-filters .filter-pill.active {
  color: var(--a-lift);
  border-color: color-mix(in srgb, var(--a) 50%, transparent);
  background: var(--a-wash);
}

.event-rule { margin-top: clamp(1.75rem, 1.2rem + 2vw, 3rem); }


/* ---------------------------------------------------------------------------
   The spine

   A hairline down the left with a node per format, on wide screens only. Below
   64rem the gutter would eat a third of the card, so the spine is simply not
   drawn and the entries stack as plain panels. The gap between entries is wider
   than a list needs: a programme should read unhurried.
   --------------------------------------------------------------------------- */

.event-timeline {
  position: relative;
  display: grid;
  gap: clamp(1.35rem, .9rem + 2vw, 3.25rem);
  min-width: 0;
}

.event-timeline > * { min-width: 0; }

.event-entry {
  position: relative;
  min-width: 0;
}

@media (min-width: 64rem) {
  .event-timeline::before {
    content: "";
    position: absolute;
    inset-inline-start: 7px;
    top: 3.4rem;
    bottom: 3.4rem;
    width: 1px;
    pointer-events: none;
    background: linear-gradient(180deg,
      transparent,
      var(--hairline-strong) 6%,
      var(--hairline-strong) 94%,
      transparent);
  }

  /* Four of the six filters resolve to exactly one format, and a spine drawn
     past a single node is a stray rule rather than a timeline. One entry gets
     its node and its connector and no line. */
  .event-timeline:has(> .event-entry:only-child)::before { display: none; }

  .event-entry { padding-inline-start: 5rem; }

  /* The node reads the entry's own accent, so the spine is colour-coded by
     format without a single per-format rule. */
  .event-entry::before {
    content: "";
    position: absolute;
    inset-inline-start: 0;
    top: 3rem;
    width: 15px;
    height: 15px;
    border-radius: 999px;
    pointer-events: none;
    background: var(--a);
    box-shadow: 0 0 0 4px var(--canvas), 0 0 20px var(--a-glow);
  }

  /* 15px of node plus 65px of reach is the 5rem gutter above. */
  .event-entry::after {
    content: "";
    position: absolute;
    inset-inline-start: 15px;
    top: calc(3rem + 7px);
    width: 65px;
    height: 1px;
    pointer-events: none;
    background: linear-gradient(90deg, var(--a), transparent);
  }
}


/* ---------------------------------------------------------------------------
   One format
   --------------------------------------------------------------------------- */

/* .panel carries no padding of its own, so a card that is not built out of
   .card-head / .card-body sets its own. */
.event-card { padding: clamp(1.5rem, 1.1rem + 1.6vw, 2.6rem); }

.event-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: .6rem 1rem;
  min-width: 0;
}

.event-card-head > * { min-width: 0; }

/* The chip is inline-flex with a gap, so its accent dot is a flex item. */
.event-type::before {
  content: "";
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: var(--a);
  box-shadow: 0 0 8px var(--a-glow);
}

/* --a-lift rather than --a: the catalogue number is a data label and every
   -lift tone clears 4.5:1 at this size on --surface. */
.event-index { color: var(--a-lift); }

.event-title {
  margin-top: 1.6rem;
  max-width: 44ch;
  font-size: clamp(1.3rem, 1.15rem + .7vw, 1.7rem);
}

.event-summary {
  margin-top: 1.15rem;
  max-width: 62ch;
  font-size: .9688rem;
  line-height: 1.7;
  overflow-wrap: anywhere;
}

.event-facts { margin-top: 1.85rem; }

.event-agenda { margin-top: 2rem; }


/* The marketing site's .tick-list, carried across under a prefixed name. The
   contract lists .tick-list in the class inventory but styles.css does not
   define it; a page-owned copy that works beats a shared edit that five other
   sessions overwrite. If it is promoted later, this rule becomes an alias.
   The mark is a rotated square rather than a bullet: a ledger tick. */
.event-tick-list {
  display: grid;
  gap: .9rem;
  margin-top: 1.15rem;
  max-width: 62ch;
  min-width: 0;
}

.event-tick-list > li {
  position: relative;
  min-width: 0;
  padding-inline-start: 1.9rem;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}

.event-tick-list > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .55em;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--a);
  box-shadow: 0 0 12px var(--a-glow);
  transform: rotate(45deg);
}


/* ---------------------------------------------------------------------------
   Convenings already held

   Renders only when GDTC_DATA.EVENTS_HELD has rows in it. With the array empty
   the host element is removed and none of this is ever matched.
   --------------------------------------------------------------------------- */

.event-held {
  padding: 1.5rem;
  display: flex;
  flex-direction: column;
  gap: .7rem;
  min-width: 0;
}


/* ---------------------------------------------------------------------------
   The close
   --------------------------------------------------------------------------- */

.event-close {
  padding: clamp(2.5rem, 1.6rem + 4vw, 5.5rem) clamp(1.35rem, 1rem + 2.5vw, 4rem);
  text-align: center;
}

.event-close-inner {
  position: relative;
  z-index: 1;
  min-width: 0;
}

.event-close-eyebrow { font-family: var(--font-display); font-weight: 600; }

.event-close h2 { margin-top: 1.75rem; }

.event-foil-rule {
  width: 88px;
  max-width: 40%;
  margin: 1.75rem auto 0;
}

/* .lede is measured for a left-aligned column, so a centred one is centred
   rather than left-hanging inside a wide box. */
.event-close-lede {
  margin: 1.75rem auto 0;
  max-width: 58ch;
}

/* The Council's own sentence about admission, from GDTC_DATA.ADMISSION. */
.event-close-admission { margin-top: 1.5rem; }

/* This is a pair of links at the close of a page, not a form, so it carries its
   own row rather than borrowing .form-actions from the form section of
   styles.css. Everything it needs is here. */
.event-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: .75rem 1rem;
  margin-top: 1.75rem;
  min-width: 0;
}

.event-actions > * { min-width: 0; }

.event-close-note { margin-top: 2.25rem; }

.event-fineprint {
  margin: 2rem auto 0;
  max-width: 54ch;
  font-size: .8125rem;
  line-height: 1.7;
  color: var(--faint);
  overflow-wrap: anywhere;
}

/* ---- frontdoor.css ---- */
/* ===========================================================================
   THE FRONT DOOR

   The hero of the member platform. It was a wall of text with two buttons and
   an empty right-hand column, on a site whose members' area opens with a
   drifting foil ring - the door did not match the room.

   Merged into styles.css by tools/merge-css.js. Edit this file.
   =========================================================================== */

.hero-split {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}

/* Below the split, the object leads. It is the thing worth seeing first on a
   phone, and the argument reads underneath it. */
@media (max-width: 60rem) {
  .hero-split { grid-template-columns: minmax(0, 1fr); }
  .hero-object { order: -1; }
}

.hero-words { min-width: 0; }

/* The Council's own name inlaid, so the one proper noun on the page is the one
   thing carrying the material. Everything else stays text. */
.hero-display { text-wrap: balance; }

/* ---- the counted figures ---- */

.hero-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 8.5rem), 1fr));
  gap: 1px;
  margin: 2.6rem 0 0;
  background: var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
}

.hero-figure { background: var(--surface); padding: 1.1rem var(--pad); }

.hero-figure-n {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(1.7rem, 4.5vw, 2.3rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  background-image: var(--foil);
  background-size: 280% 100%;
  background-position: 34% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}

.hero-figure-label {
  margin: .5rem 0 0;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
  line-height: 1.5;
}

/* ---- the corridors ---- */

.hero-object { min-width: 0; }
.corridors { width: 100%; height: auto; display: block; overflow: visible; }

.corridor-grid { stroke: var(--hairline); stroke-width: 1; }
.corridor-grid-g { opacity: .5; }

/* Each arc draws itself once, then stays. A loop would make the front door
   twitch forever in the corner of somebody's eye. */
.corridor {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1;
  stroke-opacity: .3;
  stroke-dasharray: 1400;
  stroke-dashoffset: 1400;
  animation: corridor-draw 2.2s var(--ease) forwards;
}
@keyframes corridor-draw { to { stroke-dashoffset: 0; } }

.corridor-dot { fill: var(--gold-white); }

/* One slow breath, staggered by nothing - they pulse together, which reads as
   a heartbeat rather than as scattered activity. */
.corridor-pulse {
  fill: var(--gold-lift);
  opacity: .1;
  transform-origin: center;
  transform-box: fill-box;
  animation: corridor-breathe 4.5s ease-in-out infinite;
}
@keyframes corridor-breathe {
  0%, 100% { opacity: .07; transform: scale(.9); }
  50%      { opacity: .2;  transform: scale(1.15); }
}

@media (prefers-reduced-motion: reduce) {
  .corridor { animation: none; stroke-dashoffset: 0; }
  .corridor-pulse { animation: none; }
}


/* ---------------------------------------------------------------------------
   MOTION - applied by motion.js to every page
   --------------------------------------------------------------------------- */

/* PREPARED, NOT HIDDEN. .will-rise is added by script and ONLY to elements that
   start below the fold, so nothing the reader is already looking at moves, and
   a page whose script never loads is a page that simply does not animate. The
   stylesheet never hides content on its own. */
.will-rise {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .65s var(--ease), transform .65s var(--ease);
}
.has-risen { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .will-rise { opacity: 1; transform: none; transition: none; }
}

/* ---- surfaces that read as objects ----

   The lift already existed on .panel-lift. This gives every panel the same
   material - a hairline of light along the top edge - so the depth is a
   property of the component rather than something each page opts into. */
.panel::after {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 14%;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(242,237,224,.16), transparent);
  pointer-events: none;
}

/* A figure block, reusable wherever a page has counted things to state. Same
   component as the front door's, so the register, the directory and the
   publications record all state their size the same way. */
.figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 9rem), 1fr));
  gap: 1px;
  background: var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
  margin: 0 0 2.5rem;
}
.figure { background: var(--surface); padding: 1.1rem var(--pad); }
.figure-n {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(1.6rem, 4vw, 2.1rem);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  background-image: var(--foil);
  background-size: 280% 100%;
  background-position: 34% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
}
.figure-label {
  margin: .5rem 0 0;
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--faint);
  line-height: 1.5;
}

/* ---- give.css ---- */
/* ===========================================================================
   SUPPORTING THE COUNCIL - donate.html

   Merged into styles.css by tools/merge-css.js. Edit this file.
   =========================================================================== */

.give-split {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  gap: clamp(2rem, 5vw, 4rem);
  align-items: center;
}
@media (max-width: 60rem) {
  .give-split { grid-template-columns: minmax(0, 1fr); }
  .give-seal { order: -1; }
}

/* THE SEAL AT REST. The induction breaks this open; here it simply sits, which
   is the whole difference between a ceremony and an invitation. */
.give-seal {
  position: relative;
  width: min(19rem, 70vw);
  aspect-ratio: 1;
  margin-inline: auto;
  display: grid;
  place-items: center;
}
.give-seal-glow {
  position: absolute;
  inset: -14%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--gold-glow), transparent 60%);
  opacity: .5;
}
.give-seal-disc {
  position: absolute;
  inset: 12%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 30%, rgba(240,228,180,.42), transparent 46%),
    var(--foil);
  background-size: 100% 100%, 220% 100%;
  box-shadow:
    inset 0 0 0 1px rgba(240,228,180,.28),
    inset 0 -16px 34px rgba(0,0,0,.4);
  animation: foil-drift 30s linear infinite;
}
.give-seal-mark {
  position: relative;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.5rem, 5vw, 2.1rem);
  letter-spacing: .14em;
  color: rgba(5,11,8,.6);
  text-shadow: 0 1px 0 rgba(240,228,180,.3);
}

/* ---- the form ---- */

.give-form { max-width: 42rem; margin-inline: auto; }
.give-set { border: 0; padding: 0; margin: 0 0 1.6rem; }
.give-set > .label { padding: 0; margin-bottom: .8rem; }

.give-amounts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 7.5rem), 1fr));
  gap: .6rem;
  margin-bottom: 1.2rem;
}

/* A preset fills the field; it never locks it. The chosen one carries the
   metal, so which was pressed is legible at a glance. */
.give-amount {
  font-family: var(--font-mono);
  font-size: .95rem;
  font-variant-numeric: tabular-nums;
  padding: .85rem .6rem;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--soft);
  cursor: pointer;
  transition: border-color var(--t-ui) var(--ease), color var(--t-ui) var(--ease),
              background var(--t-ui) var(--ease);
}
.give-amount:hover { color: var(--text); border-color: var(--gold-deep); }
.give-amount.is-on {
  color: var(--gold-white);
  border-color: var(--gold);
  background: var(--gold-wash);
}
.give-amount:focus-visible { outline: 2px solid var(--gold-lift); outline-offset: 2px; }

.give-custom { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 7rem); gap: .6rem; }
.give-currency { font-family: var(--font-mono); }

.give-choices { display: grid; gap: .55rem; }
.give-choice {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding: .7rem .9rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--surface);
  cursor: pointer;
  font-size: .93rem;
  color: var(--soft);
  transition: border-color var(--t-ui) var(--ease), color var(--t-ui) var(--ease);
}
.give-choice:hover { color: var(--text); border-color: var(--hairline-strong); }
.give-choice:has(input:checked) {
  color: var(--text);
  border-color: var(--gold-deep);
  background: var(--gold-wash);
}
.give-choice input { accent-color: var(--gold); margin-top: .15rem; flex: none; }

/* ---- what comes back ---- */

.give-done { max-width: 42rem; margin-inline: auto; }
.give-done-head {
  font-family: var(--font-display);
  font-size: clamp(1.3rem, 4vw, 1.9rem);
  line-height: 1.2;
  margin: .6rem 0 1.8rem;
}
.give-done-figures { margin-bottom: 1.8rem; }

/* The reference is quoted onto a bank form by hand, so it is set at a size
   somebody can read across a desk and never truncated. */
.give-ref {
  font-size: clamp(1rem, 3.2vw, 1.35rem);
  letter-spacing: .04em;
  overflow-wrap: anywhere;
}


/* ---------------------------------------------------------------------------
   CONTRIBUTORS - named on the front door, with their consent
   --------------------------------------------------------------------------- */

.contributors {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 1px;
  background: var(--hairline);
  border-radius: var(--r-md);
  overflow: hidden;
}

.contributor {
  background: var(--surface);
  padding: 1.3rem var(--pad);
  display: grid;
  gap: .35rem;
}

/* A short rule rather than a bullet. It reads as a mark of record - the same
   device the eyebrows use - instead of a list item. */
.contributor-mark {
  width: 1.6rem;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  margin-bottom: .5rem;
}

.contributor-name {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 1.02rem;
  overflow-wrap: anywhere;
}
.contributor-org {
  font-family: var(--font-body);
  font-size: .86rem;
  color: var(--faint);
  overflow-wrap: anywhere;
}

/* The listing choice on the dashboard borrows the contribution form's row,
   which is already the platform's shape for "a decision with its reason". */
.listing-choice { align-items: flex-start; }

/* ---- mandate.css ---- */
/* ===========================================================================
   MANDATE
   The founding document: six numbered articles, a reading rail that follows
   the reader, the scope diptych, and the admission tiers that close it.

   Every class here is prefixed .mandate-, because six pages were written in
   parallel into one stylesheet and an unprefixed .article, .tier or .half
   would have silently taken somebody else's.

   TWO OF THESE ARE LOCAL COPIES ON PURPOSE. .mandate-num-list and
   .mandate-tick-list are the two list shapes the page inventory names as
   .num-list and .tick-list, which this stylesheet does not define yet. They
   are prefixed rather than written under the shared names so that adding the
   shared ones later is an addition and not a collision. That matters more
   than usual here: styles.css sets `ol { list-style: none }`, so an <ol> with
   no numbering rule of its own loses its numerals entirely, and this page is
   six numbered articles.

   Colour is never named below. Every accent goes through var(--a) and its
   family, which the data sets per element with data-accent.

   ONE THING THIS FILE DELIBERATELY DOES NOT CARRY. styles.css defines --a and
   its family once on :root as gold and has no [data-accent] blocks at all, so
   the attribute currently recolours nothing. That block is shared, not page
   specific, and css-parts/events.css already carries the marketing site's copy
   of it verbatim with a note to whoever merges. A second copy here would be a
   second thing to keep in step, so there is none: if that block is dropped in
   the merge, this page paints gold throughout, which is coherent but wrong.
   =========================================================================== */

/* ---- the reading rail --------------------------------------------------- */

/* Stickiness belongs to .split-sidebar, which owns it from 62rem and leaves
   the rail a scrolling strip of tabs below that. Nothing here fights it. */
.mandate-rail {
  display: grid;
  gap: .85rem;
  min-width: 0;
}

.mandate-tab { text-decoration: none; }

.mandate-tab .mandate-tab-n {
  color: var(--faint);
  transition: color var(--t-ui) var(--ease);
}

/* Written with both classes so it outranks .dash-tab.is-active whichever way
   round the two files are merged. The rail is the one place on the page where
   six accents sit next to each other, and a gold highlight on all six would
   throw away the only signal the rail carries. */
.dash-tab.mandate-tab.is-active {
  color: var(--a-lift);
  background: var(--a-wash);
  border-color: color-mix(in srgb, var(--a) 34%, transparent);
}

.dash-tab.mandate-tab.is-active .mandate-tab-n { color: inherit; }

/* ---- the charter mark --------------------------------------------------- */

.mandate-charter {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(.75rem, .7rem + .2vw, .875rem);
  line-height: 1.6;
  text-transform: uppercase;
  letter-spacing: .42em;
  /* Matches the tracking, so the block stays optically flush left. */
  text-indent: .42em;
  overflow-wrap: anywhere;
}

.mandate-charter-rule {
  width: 72px;
  max-width: 100%;
  margin: 1.5rem 0 clamp(1.75rem, 1.2rem + 2vw, 3rem);
}

/* ---- the articles ------------------------------------------------------- */

.mandate-article {
  min-width: 0;
  /* Room for the sticky header when the rail scrolls to this article. */
  scroll-margin-top: calc(var(--header-h) + 1.5rem);
  padding-block: clamp(2.25rem, 1.6rem + 2.6vw, 4rem);
}

.mandate-article:first-child { padding-top: 0; }

.mandate-article + .mandate-article { border-top: 1px solid var(--hairline); }

/* The running head: 01 / ABOUT. */
.mandate-mark {
  text-transform: uppercase;
  letter-spacing: .16em;
  color: var(--a-lift);
}

/* An article header: mark, eyebrow, heading, lede, stacked. */
.mandate-head {
  display: grid;
  gap: 1.1rem;
  align-content: start;
  min-width: 0;
  margin-bottom: clamp(1.75rem, 1.2rem + 1.6vw, 2.75rem);
}

.mandate-head > * { min-width: 0; }

/* A heading column against its prose. Both columns are stacks in their own
   right, which is why the gap is set on the children as well as between them. */
.mandate-cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 2rem;
}

.mandate-cols > * {
  display: grid;
  gap: 1.1rem;
  align-content: start;
  min-width: 0;
}

.mandate-cols p { max-width: 64ch; }

@media (min-width: 48rem) {
  .mandate-cols { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 2.5rem 3rem; }
}

/* A plain vertical group inside a panel. */
.mandate-group {
  display: grid;
  gap: .75rem;
  align-content: start;
  min-width: 0;
}

.mandate-group > * { min-width: 0; }

/* The same, at the spacing whole blocks want rather than lines. */
.mandate-stack {
  display: grid;
  gap: clamp(1.25rem, 1rem + 1vw, 2rem);
  align-content: start;
  min-width: 0;
}

.mandate-stack > * { min-width: 0; }

/* The short rule under a heading. It takes the article's accent, so it is the
   quietest way the colour is stated. */
.mandate-accent-rule {
  height: 2px;
  width: 64px;
  max-width: 100%;
  border: 0;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--a), transparent);
}

/* ---- 03 objectives ------------------------------------------------------ */

/* The band the objectives are set in. Positioned and raised, because the
   graticule inside it is an absolutely positioned layer and would otherwise be
   painted over the text rather than behind it. */
.mandate-band {
  position: relative;
  z-index: 1;
  min-width: 0;
  padding: clamp(1.5rem, 1rem + 2.4vw, 3rem);
}

/* Numbered articles. The numeral is drawn by the counter rather than typed, so
   it cannot drift out of step with the list it is numbering. */
.mandate-num-list {
  counter-reset: mandate-n;
  min-width: 0;
}

.mandate-num-list > li {
  counter-increment: mandate-n;
  position: relative;
  min-width: 0;
  padding-inline-start: 3rem;
  padding-block: 1.15rem;
  border-top: 1px solid var(--hairline);
  color: var(--soft);
  overflow-wrap: anywhere;
}

.mandate-num-list > li:first-child { border-top: 0; padding-top: 0; }

.mandate-num-list > li::before {
  content: counter(mandate-n, decimal-leading-zero);
  position: absolute;
  inset-inline-start: 0;
  top: calc(1.15rem + .25em);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .1em;
  color: var(--a-lift);
}

.mandate-num-list > li:first-child::before { top: .25em; }

/* One objective: its title against its own sentence. */
.mandate-objective {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .5rem;
}

.mandate-objective > * { min-width: 0; }

@media (min-width: 48rem) {
  .mandate-objective {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: 2rem;
    align-items: baseline;
  }
}

/* ---- 04 scope, and the tier lists --------------------------------------- */

/* Half of the diptych, and the shape the vision and mission panels take too. */
.mandate-half {
  display: grid;
  gap: 1.5rem;
  align-content: start;
  min-width: 0;
  padding: clamp(1.35rem, 1rem + 1.2vw, 2.25rem);
}

.mandate-half > * { min-width: 0; }

.mandate-half-title { font-size: clamp(1.15rem, 1.05rem + .6vw, 1.5rem); }

.mandate-half-head {
  display: flex;
  align-items: center;
  gap: .8rem;
  min-width: 0;
}

.mandate-half-head > * { min-width: 0; }

.mandate-half-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 999px;
  background: var(--a-wash);
  border: 1px solid color-mix(in srgb, var(--a) 40%, transparent);
  color: var(--a-lift);
}

/* The exclusions are recessed rather than raised. Nothing in that half is an
   offer, so it does not get the lit surface the affirmations get. Both classes
   are named so this beats .panel wherever the two files land. */
.panel.mandate-recess { background: var(--void); }

/* Affirmations. */
.mandate-tick-list {
  display: grid;
  gap: .85rem;
  min-width: 0;
}

.mandate-tick-list > li {
  position: relative;
  min-width: 0;
  padding-inline-start: 1.9rem;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}

.mandate-tick-list > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .55em;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--a);
  box-shadow: 0 0 12px var(--a-glow);
  transform: rotate(45deg);
}

/* Exclusions. A struck line rather than a mark: none of these is a claim, and
   a row of ticks beside "not a regulatory authority" would read as one. */
.mandate-cross-list {
  display: grid;
  gap: .9rem;
  min-width: 0;
}

.mandate-cross-list > li {
  display: flex;
  gap: 1rem;
  min-width: 0;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}

.mandate-cross-list > li::before {
  content: "";
  flex: none;
  width: 16px;
  height: 1px;
  margin-top: .85em;
  background: linear-gradient(90deg, var(--a), transparent);
}

/* ---- 06 admission ------------------------------------------------------- */

/* The three tiers are a ladder and are meant to be read across, so the track is
   narrower than .company-grid's: three of them still fit beside the reading
   rail on a desktop, where the wider track would drop the third onto a line of
   its own. min(100%, ...) so the track collapses to the column on a phone
   instead of demanding a width the screen does not have. */
.mandate-tiers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 1.15rem;
}

.mandate-tiers > * { min-width: 0; }

.mandate-tier {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* So three cards of different lengths still put their actions on one line. */
.mandate-tier .card-foot { margin-top: auto; }

.mandate-numeral {
  font-family: var(--font-display);
  font-size: 1.2rem;
  font-weight: 700;
  letter-spacing: .14em;
  line-height: 1;
  color: var(--a-lift);
}

/* The close. Centred, and lifted above the aurora and the graticule behind it. */
.mandate-close {
  position: relative;
  z-index: 1;
  min-width: 0;
  padding: clamp(2rem, 1.4rem + 3vw, 4rem) clamp(1.35rem, 1rem + 2vw, 3rem);
  text-align: center;
}

.mandate-close h2 {
  max-width: 32ch;
  margin-inline: auto;
}

.mandate-close .lede {
  margin-inline: auto;
  margin-top: 1.5rem;
}

.mandate-close .form-actions { justify-content: center; }

.mandate-close .mono-meta { margin-top: 2rem; }

/* ---- members.css ---- */
/* members.html : the Council's named member companies.

   Everything here is prefixed .member- because six pages wrote their additions in parallel and a
   class called .row or .mark would have collided with somebody else's.

   THE MONOGRAM TILE IS THE POINT OF THIS FILE. No member has a logo file yet, so the tile drawn
   from the company's initials is what ships: a bordered square in the member's own accent, lit
   from --a-wash with a corner tick, sized and weighted like a mark rather than like a gap waiting
   to be filled. It is drawn from the same tokens as the rest of the page, so it reads as a
   designed element and not as a missing image. When a logo file does arrive the tile keeps its
   shape and swaps its material: neutral wash, hairline border, no tick. */

/* The accent tokens are defined once, in styles.css, beside the palette they derive from.
   This page only sets data-accent on its rows; it does not redefine what an accent means. */

.member-page .member-list {
  display: grid;
  gap: 1.15rem;
  margin-top: 1.75rem;
}

.member-list > * { min-width: 0; }

/* One member. A stack on a phone, two columns from 52rem: who they are, then what they do. */
.member-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: 1.25rem 2.5rem;
  padding: 1.5rem;
}

.member-row > * { min-width: 0; }

@media (min-width: 52rem) {
  .member-row {
    grid-template-columns: minmax(0, 21rem) minmax(0, 1fr);
    padding: 1.85rem 2rem;
  }
}

.member-head {
  display: flex;
  align-items: center;
  gap: 1.15rem;
  min-width: 0;
}

.member-ident { min-width: 0; }

.member-ident .company-name { margin-top: .3rem; }

.member-body {
  display: flex;
  flex-direction: column;
  gap: .9rem;
  min-width: 0;
}

.member-blurb {
  min-width: 0;
  font-size: .95rem;
  line-height: 1.7;
  color: var(--soft);
  overflow-wrap: break-word;
}

/* The company's own domain, shown only when the data holds a URL. */
.member-link {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-width: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .06em;
  color: var(--a-lift);
  overflow-wrap: anywhere;
}

.member-link:hover { color: var(--text); }

/* ---- the monogram tile ---- */

.member-mark {
  position: relative;
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: var(--r-lg);
  background: var(--a-wash);
  border: 1px solid color-mix(in srgb, var(--a) 32%, transparent);
  overflow: hidden;
}

/* The corner tick. It is what stops the tile reading as an empty box: a mark somebody drew rather
   than a frame around nothing. */
.member-mark::before {
  content: "";
  position: absolute;
  inset: 14%;
  border-top: 1px solid var(--a);
  border-inline-start: 1px solid var(--a);
  border-start-start-radius: .45rem;
  opacity: .32;
  pointer-events: none;
}

.member-mark-text {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.7rem;
  letter-spacing: -.04em;
  line-height: 1;
  color: var(--a-lift);
}

/* Four letters in the space three were drawn for. */
.member-mark-text.is-long { font-size: 1.3rem; letter-spacing: -.05em; }

/* A real logo file: the same tile, in neutral material, with the tick removed so nothing is drawn
   over the artwork. */
.member-mark.has-logo {
  background: rgba(232, 237, 247, .06);
  border-color: var(--hairline);
}

.member-mark.has-logo::before { display: none; }

.member-mark-img {
  width: 78%;
  height: 78%;
  object-fit: contain;
}

/* ---- the way in ---- */

.member-cta { padding: clamp(1.5rem, 1rem + 2.4vw, 3.25rem); }

/* The aurora inside the panel is at z-index 0, so the copy is raised above it rather than the
   layer being sunk behind the panel's own background, where it would not be seen at all. */
.member-cta > *:not(.aurora) { position: relative; z-index: 1; }

.member-cta .display { margin-top: 1.1rem; max-width: 20ch; }

.member-cta .lede { margin-top: 1.25rem; }

.member-cta .mono-meta { margin-top: 1.25rem; }

/* ---- programs.css ---- */
/* ===========================================================================
   PROGRAMS
   The portfolio page: a contents list, then eight numbered panels.

   Everything here is scoped to .program-*, and every colour is var(--a), so a
   panel recolours from the data-accent programs.js writes on it and there is
   not one per-accent rule in this file.

   WHAT THIS FILE DELIBERATELY DOES NOT CARRY, and what that costs until the
   merge: styles.css defines --a and its family once on :root as gold and has
   no [data-accent] blocks at all, so today the attribute recolours nothing and
   all eight programs paint gold. That block is shared, not page specific, and
   css-parts/events.css already carries the marketing site's copy of it verbatim
   with a note to whoever merges. A second copy here would be a second thing to
   keep in step, so there is none. If it is dropped in the merge, this page is
   monochrome: coherent, but it throws away the one signal that tells eight
   programs apart.
   =========================================================================== */

/* The contents. Eight lines, numbered, so the whole portfolio is visible
   before the reader commits to scrolling it. auto-fit with min(100%, Nrem)
   keeps the track from demanding more width than a phone has. */
.program-toc {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
  gap: .6rem;
  margin-bottom: clamp(2rem, 1.4rem + 2vw, 3.25rem);
}

.program-toc a {
  display: flex;
  align-items: baseline;
  gap: .7rem;
  min-width: 0;
  padding: .8rem 1rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-md);
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.45;
  overflow-wrap: anywhere;
  transition:
    color var(--t-ui) var(--ease),
    border-color var(--t-ui) var(--ease),
    background-color var(--t-ui) var(--ease);
}

.program-toc a:hover,
.program-toc a:focus-visible {
  color: var(--text);
  border-color: color-mix(in srgb, var(--a) 45%, transparent);
  background-color: var(--a-wash);
}

.program-toc-num {
  flex: none;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .12em;
  color: var(--a);
}

/* The stack. Far enough apart that eight panels read as a sequence of separate
   commitments rather than a grid of cards. */
.program-stack {
  display: grid;
  gap: clamp(1.15rem, .8rem + 1.2vw, 1.9rem);
}

.program-stack > * { min-width: 0; }

/* The panel. On a narrow screen the mark is a row above the title; from 48rem
   it becomes its own column and the accent runs down the side of the whole
   program. */
.program-panel {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.15rem;
  padding: clamp(1.35rem, 1rem + 1.8vw, 2.6rem);
}

.program-panel > * { min-width: 0; }

.program-mark {
  display: flex;
  align-items: center;
  gap: .9rem;
  min-width: 0;
}

/* The index itself: mono, tabular, and the one place on the panel where the
   accent is a light rather than a line. */
.program-num {
  font-family: var(--font-mono);
  font-size: clamp(1.5rem, 1.2rem + 1.1vw, 2.15rem);
  font-weight: 500;
  line-height: 1;
  letter-spacing: .05em;
  color: var(--a);
  text-shadow: 0 0 24px var(--a-glow);
}

/* The hairline that carries the accent out of the number: across the panel on
   a narrow screen, down its side on a wide one. Decorative, so it is a
   pseudo-element and never reaches the accessibility tree. */
.program-mark::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, var(--a), transparent);
  opacity: .5;
}

.program-body > h2 { text-wrap: balance; }

.program-body .lede { margin-top: .95rem; }

.program-body .eyebrow { margin-top: 1.85rem; }

.program-body .tick-list { margin-top: 1.05rem; }

/* The marketing site's .tick-list (src/App.css), carried across under a
   prefixed name because styles.css does not define .tick-list yet and a list
   of five commitments with no marks on it is not a finished panel. The markup
   carries both classes, so the shared rule wins the day it exists and this
   copy can be deleted.

   TO WHOEVER MERGES THE PARTS: more than one page has had to do this. One copy
   of the rule, promoted to styles.css under the shared name, retires all of
   them. The mark is a rotated square rather than a bullet: a ledger tick, in
   the program's own accent. */
.program-tick-list {
  display: grid;
  gap: .9rem;
  max-width: 62ch;
  min-width: 0;
}

.program-tick-list > li {
  position: relative;
  min-width: 0;
  padding-inline-start: 1.9rem;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}

.program-tick-list > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .55em;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: var(--a);
  box-shadow: 0 0 12px var(--a-glow);
  transform: rotate(45deg);
}

@media (min-width: 48rem) {
  .program-panel {
    grid-template-columns: minmax(0, 5rem) minmax(0, 1fr);
    column-gap: clamp(1.5rem, 1rem + 2vw, 3rem);
  }

  .program-mark {
    flex-direction: column;
    align-items: flex-start;
    gap: 1.1rem;
  }

  /* A grid item stretches to the row it is in, so the free space below the
     number is the height of the program: the rule fills it. */
  .program-mark::after {
    width: 1px;
    height: auto;
    min-height: 3rem;
    background: linear-gradient(180deg, var(--a), transparent);
  }
}

/* The closing panel. A program is something a member takes part in, so the
   page ends at the candidacy desk. */
.program-cta {
  padding: clamp(2.25rem, 1.5rem + 3vw, 4.25rem) clamp(1.35rem, 1rem + 2vw, 3.25rem);
  text-align: center;
}

/* The graticule is absolutely positioned and would otherwise paint over the
   copy it is meant to sit behind. */
.program-cta > :not(.graticule) {
  position: relative;
  z-index: 1;
}

.program-cta h2 { margin-top: 1.15rem; }

.program-cta .lede {
  margin-top: 1.4rem;
  margin-inline: auto;
}

.program-cta .form-actions { justify-content: center; }

.program-cta .mono-meta { margin-top: 1.6rem; }

/* Two whole sentences either side of the separator rather than the two short
   facts .dot was sized for, so it is given room to read as a break. */
.program-cta .mono-meta .dot { padding-inline: .5rem; }

/* ---- publications.css ---- */
/* ===========================================================================
   PUBLICATIONS
   The research record: one accented entry per publication, over a row of
   format filters. Everything here is prefixed .pub- and nothing outside this
   page is touched.
   =========================================================================== */

/* The accent tokens are defined once, in styles.css, beside the palette they derive from.
   This page only sets data-accent on its rows; it does not redefine what an accent means. */

/* ---- the index head ---- */

/* One of only two gold marks on the page. Struck short, under the heading,
   rather than run across the whole column. */
.pub-foil {
  width: min(9rem, 100%);
  margin: 1.6rem 0 0;
}

.pub-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .8rem 1.35rem;
  margin-top: 2.5rem;
  min-width: 0;
}

/* The row is hidden outright when there is nothing to filter, and a class that
   sets display:flex outranks the browser's rule for [hidden] on its own. */
.pub-filters[hidden] { display: none; }

.pub-filters > * { min-width: 0; }

.pub-filters > .eyebrow { flex: none; }

/* Pushed to the far end on a wide row, and onto its own line when the pills
   have already used the width. */
.pub-showing { margin-inline-start: auto; }

/* ---- the entries ---- */

.pub-state { margin-top: 2.5rem; }
.pub-state:empty { margin-top: 0; }

.pub-list {
  display: grid;
  gap: 1.5rem;
  margin-top: 2.5rem;
  min-width: 0;
}

.pub-list:empty { margin-top: 0; }

.pub-list > * { min-width: 0; }

/* An entry can be linked to directly, so it keeps clear of the sticky header
   when the browser jumps to it. */
.pub-entry {
  padding: clamp(1.35rem, 1rem + 1.5vw, 2.4rem);
  scroll-margin-top: calc(var(--header-h) + 1rem);
}

.pub-entry-grid {
  display: grid;
  gap: 1.5rem;
  min-width: 0;
}

.pub-entry-grid > * { min-width: 0; }

/* The ledger rail sits beside the entry once there is room for it, and above
   the entry when there is not. */
@media (min-width: 62rem) {
  .pub-entry-grid {
    grid-template-columns: minmax(0, 13rem) minmax(0, 1fr);
    gap: 2rem 3rem;
  }
}

.pub-rail {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .55rem .85rem;
  min-width: 0;
}

@media (min-width: 62rem) {
  .pub-rail {
    flex-direction: column;
    align-items: flex-start;
    gap: .9rem;
  }
}

/* --a-lift, not --a: at this size the base violet clears only about 4.2:1 on
   the panel, while every lift tone clears 4.5:1. */
.pub-index {
  flex: none;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .1em;
  line-height: 1.5;
  color: var(--a-lift);
}

.pub-rule { display: none; }

@media (min-width: 62rem) {
  .pub-rule {
    display: block;
    height: 2px;
    width: 64px;
    border-radius: 2px;
    margin-top: .3rem;
    background: linear-gradient(90deg, var(--a), transparent);
  }
}

.pub-title {
  max-width: 42rem;
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.2rem, 1.05rem + .8vw, 1.6rem);
  letter-spacing: -.025em;
  line-height: 1.22;
  color: var(--text);
  overflow-wrap: break-word;
}

.pub-summary {
  max-width: 60ch;
  margin: 1.1rem 0 0;
  color: var(--soft);
  font-size: .95rem;
  line-height: 1.7;
}

.pub-contents {
  max-width: 42rem;
  margin-top: 1.6rem;
}

.pub-contents > .eyebrow { margin-bottom: 1rem; }

.pub-bullets {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: .75rem;
}

.pub-bullets > li {
  position: relative;
  padding-inline-start: 1.7rem;
  color: var(--soft);
  font-size: .9rem;
  line-height: 1.6;
  overflow-wrap: anywhere;
}

.pub-bullets > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .5em;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--a);
  box-shadow: 0 0 12px var(--a-glow);
  transform: rotate(45deg);
}

/* ---- the closing band ---- */

/* The row of closing actions. styles.css has .form-actions, which is the same
   row, but it is not in the class inventory this page was given, so the page
   carries its own rather than depending on a shared class it was not promised. */
.pub-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .75rem 1rem;
  margin-top: 1.75rem;
}

.pub-actions > * { min-width: 0; }

/* A wrapper the page script fills only for a signed-out reader. display:contents
   keeps it out of the flex row, so the button inside it is spaced by
   .pub-actions exactly like the button beside it. */
.pub-join { display: contents; }

/* ---- working-groups.css ---- */
/* ===========================================================================
   WORKING GROUPS
   The five sector committees as an explorer: a rail of sectors beside the
   selected group's detail on a wide screen, all five stacked below the
   two-column breakpoint.

   Everything here is prefixed .group-. The rail itself is .dash-nav/.dash-tab
   out of the shared sheet, which already does exactly this job; only the sector
   dot, the ordinal and the accent on the selected item are added to it.
   =========================================================================== */

/* ---------------------------------------------------------------------------
   THE ACCENT TOKENS.
   styles.css declares --a and friends once, on :root, and its surfaces read
   them everywhere: .panel::before, .eyebrow::before and .panel-lift:hover are
   all painted in var(--a). What it does not carry is the [data-accent] blocks
   that redefine those tokens per subtree, so data-accent="violet" currently
   recolours nothing.

   They are declared here, under this page's own class, rather than added to
   the shared sheet: six pages are being written against that sheet at the same
   time and the last writer to it would silently discard the other five. The
   mapping and the values are src/App.css's, unchanged. If a later pass hoists
   one copy of this block to the top of styles.css, this one can go.

   --a-deep is written literally because the platform sheet carries no
   --cyan-deep, --violet-deep, --emerald-deep or --rose-deep.
   --------------------------------------------------------------------------- */

.group-page [data-accent="gold"],
.group-page .group-page .group-page .group-page .group-page /* ---------------------------------------------------------------------------
   THE RAIL
   --------------------------------------------------------------------------- */

.group-tab { gap: .55rem; }

.group-tab-name { min-width: 0; overflow-wrap: anywhere; }

/* The sector key. Lit when its group is the one being read. */
.group-tab-dot {
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--a);
  opacity: .45;
  transition:
    opacity var(--t-ui) var(--ease),
    box-shadow var(--t-ui) var(--ease);
}

.group-tab-index {
  margin-inline-start: auto;
  padding-inline-start: .6rem;
  font-size: 10px;
  letter-spacing: .1em;
  color: var(--faint);
  transition: color var(--t-ui) var(--ease);
}

/* The shared sheet paints the selected tab gold, which is right for the
   dashboard and wrong here: gold is the Council's own voice and each of these
   answers in its sector's colour. Selected by data-accent on the tab, so the
   rail is the colour key for the page. */
.group-page .dash-tab.is-active {
  color: var(--a-lift);
  background: var(--a-wash);
  border-color: color-mix(in srgb, var(--a) 38%, transparent);
}

.group-page .dash-tab.is-active .group-tab-dot {
  opacity: 1;
  box-shadow: 0 0 10px var(--a-glow);
}

.group-page .dash-tab.is-active .group-tab-index { color: var(--a-lift); }

.group-page .dash-tab:hover .group-tab-dot { opacity: 1; }


/* ---------------------------------------------------------------------------
   THE PANELS
   One at a time beside the rail; all five, in order, below the breakpoint
   where the rail stops being a column and becomes an index across the top.

   The state is a class rather than the hidden attribute on purpose: the shared
   sheet sets [hidden] { display: none !important }, which no media query could
   overrule, and the stacked layout needs exactly that overrule.
   --------------------------------------------------------------------------- */

.group-panels { min-width: 0; scroll-margin-top: var(--header-h); }

.group-panel + .group-panel { margin-top: 1.15rem; }

@media (min-width: 62rem) {
  .group-panel { display: none; }
  .group-panel.is-current { display: block; }
  .group-panel + .group-panel { margin-top: 0; }
}

.group-panel-body {
  display: grid;
  gap: 1.15rem;
  min-width: 0;
  padding: clamp(1.35rem, 1rem + 1.6vw, 2.5rem);
}

/* The struck accent line under the group's focus: the panel's one flourish. */
.group-rule {
  display: block;
  width: 64px;
  height: 2px;
  margin-block: .6rem;
  border-radius: 2px;
  background: linear-gradient(90deg, var(--a), transparent);
}

.group-panel .group-chip {
  color: var(--a-lift);
  border-color: color-mix(in srgb, var(--a) 32%, transparent);
}

/* .chip is an inline flex row, so the marker is a flex item rather than a
   floated decoration and never overlaps a wrapped label. */
.group-panel .group-chip::before {
  content: "";
  flex: none;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--a);
  box-shadow: 0 0 8px var(--a-glow);
}


/* ---------------------------------------------------------------------------
   OUTPUTS AND PARTICIPATION
   --------------------------------------------------------------------------- */

.group-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.15rem;
  min-width: 0;
}

@media (min-width: 48rem) {
  .group-split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.group-panel .group-well {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  min-width: 0;
  padding: clamp(1.15rem, .95rem + .7vw, 1.6rem);
}

.group-ticks {
  display: grid;
  gap: .8rem;
  min-width: 0;
  margin-top: .25rem;
}

.group-ticks > li {
  position: relative;
  min-width: 0;
  padding-inline-start: 1.75rem;
  color: var(--soft);
  font-size: .9375rem;
  line-height: 1.65;
  overflow-wrap: anywhere;
}

/* A struck lozenge in the sector's colour, not a bullet. */
.group-ticks > li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: .58em;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  background: var(--a);
  box-shadow: 0 0 12px var(--a-glow);
  transform: rotate(45deg);
}

/* Pushed to the foot of its well by margin-top:auto, so the action sits on the
   same line in both wells however unevenly the two lists run. */
.group-link {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  gap: .45rem;
  min-height: var(--tap);
  margin-top: auto;
  padding-top: 1.25rem;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--a-lift);
  transition:
    gap var(--t-ui) var(--ease),
    color var(--t-ui) var(--ease);
}

/* Restated rather than left to inherit: the base sheet's a:hover turns every
   link gold-white, which would drop the sector out of the one action inside it. */
.group-link:hover {
  gap: .8rem;
  color: var(--a-lift);
}


/* ---------------------------------------------------------------------------
   OPERATING MODEL AND CLOSE
   Both speak in the Council's gold rather than in a sector's colour: the
   operating model belongs to all five groups and to none of them.
   --------------------------------------------------------------------------- */

.group-model-body {
  display: grid;
  gap: .8rem;
  align-content: start;
  min-width: 0;
  padding: clamp(1.35rem, 1.15rem + .9vw, 2rem);
}

.group-model-index { color: var(--gold-lift); }

.group-close {
  padding: clamp(2.5rem, 1.8rem + 3vw, 4.5rem) clamp(1.35rem, .9rem + 2.2vw, 3.5rem);
  text-align: center;
}

.group-close-inner {
  position: relative;
  z-index: 1;
  display: grid;
  justify-items: center;
  gap: 1.5rem;
  min-width: 0;
}

.group-close .foil-rule { width: 72px; }

.group-close .form-actions { margin-top: .5rem; }

/* .mono-meta sets no measure of its own, and the disclaimer is the one run of
   it long enough to need one. */
.group-close .mono-meta { max-width: 42rem; }

/* ==== end of the merged part files ==== */
