/* ===========================================================================
   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 night navy 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 NIGHT NAVY, AND THE METAL IS A SEAL.

   The Council spent its first year in deep bottle green. Green reads as
   money - a private bank, a members club, a room you are let into - and that
   was the right note while GDTC was proving it could seat anybody at all.

   It is the wrong note for what this is now. An institution that expects to
   be read by ministries, missions and multilateral bodies wants the colour of
   a chancery after dark, not of a club: ink navy, ivory set on it, and metal
   used only where something has actually been sealed. Navy is the colour
   institutions choose when they want to be believed rather than admired.

   THE METAL IS A SEAL, NOT A DECORATION. --gold is #c9a227, struck brass,
   and it appears where the Council has put its authority behind something -
   a member number, a verification, a rule under a heading - and nowhere else.
   The token KEEPS ITS NAME through the palette change: two thousand references
   mean "the Council's metal", never a hue, and renaming them would say nothing
   new in a very large number of places.

   CONTRAST, CHECKED RATHER THAN ASSUMED, against --canvas #070e1a:
     --text      #efeae0   ~16:1    body
     --soft      #a9b4c4   ~9:1     secondary
     --faint     #7c8798   ~4.9:1   meta only, never body
     --gold-lift #e3c765   ~10:1    small metal text
     --gold      #c9a227   ~8:1     rules, large text, and now small text too

   That last line is the one improvement the move buys outright: the old brass
   stopped at 4.9:1 on green and could never carry small text. On navy it
   clears 8:1. The rule stays anyway - small metal text uses --gold-lift - so
   that the metal reads as one weight wherever it appears.

   THE CORNERS ARE CHAMFERED, NOT ROUNDED. The mark is a shield with cut
   corners, and the radii here were halved to agree with it. A 28px radius is
   a product; an 18px chamfer is a crest. */
:root {
  --void:#04070f; --canvas:#070e1a; --canvas-2:#0a1424;
  --surface:#0e1b2e; --surface-2:#132339; --surface-3:#1b2f49;
  --hairline:rgba(239,234,224,.10); --hairline-strong:rgba(239,234,224,.20);
  --text:#efeae0; --soft:#a9b4c4; --faint:#7c8798;
  --gold-deep:#6e5411; --gold:#c9a227; --gold-lift:#e3c765; --gold-white:#f7ecc0;
  --gold-wash:rgba(201,162,39,.12); --gold-glow:rgba(227,199,101,.28);
  /* WHERE THE LIGHT IS, said once. Three shadows were hand picked rgba values in
     three files, which is three answers to the same question and three things to
     drift apart. --sheen is the lit edge, --shade the cast, --shade-deep the cast
     from something standing well clear of the page. */
  --shade:rgba(3,10,34,.55); --shade-deep:rgba(2,6,22,.82); --sheen:rgba(255,244,214,.07);
  --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 came back up:
     on green it had to be muted to stop reading as camouflage, and on navy it
     is a genuine second colour again. */
  --cyan:#4bd0e0; --cyan-lift:#8ae5ef;
  --emerald:#5fd4a0; --emerald-lift:#9cebc4;
  --rose:#e58496; --rose-lift:#f4b0bb;
  --violet:#a292e0; --violet-lift:#c4b8ec;
  --a:var(--gold); --a-lift:var(--gold-lift); --a-deep:var(--gold-deep);
  --a-wash:var(--gold-wash); --a-glow:var(--gold-glow);
  /* Spectral is a screen-native serif with the sharp detailing of a printed
     record, which is what the Council's headings should sound like. Public
     Sans is the face the United States federal design system runs on: it was
     drawn to be read in forms and filings, and it is the reason a page of
     Council prose reads as administration rather than as marketing. */
  /* FOUR ROLES, NOT TWO.

     --font-body was carrying both the interface and the PROSE, and Public Sans
     is a face drawn for government forms: it is superb at a label on a button
     and it makes a paragraph read like a notice of assessment. Every argument
     this Council makes is a paragraph, so the prose moves to the serif and the
     sans keeps what it is good at, which is chrome.

     --font-caps is the real small-caps cut. The labels on this site were faked
     with an uppercased monospace, which is a programmer's small caps: it has
     the wrong colour, the wrong width and needs a quarter of an em of tracking
     to be legible at all. A drawn small cap needs almost none. */
  --font-display:"Spectral","Iowan Old Style","Palatino Linotype",Georgia,serif;
  --font-text:"Spectral","Iowan Old Style","Palatino Linotype",Georgia,serif;
  --font-caps:"Spectral SC","Spectral",Georgia,serif;
  --font-body:"Public Sans","Segoe UI",system-ui,sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,"SFMono-Regular",monospace;

  /* THE MEASURE SYSTEM. Twelve literal max-widths were scattered across four
     files, each invented where it was needed. Four decisions, named once. */
  --measure-display:14ch;
  --measure-lede:56ch;
  --measure-body:64ch;
  --measure-note:58ch;
  --ease:cubic-bezier(.16,1,.3,1); --t-micro:150ms; --t-ui:250ms; --t-section:600ms;
  --r-sm:3px; --r-md:6px; --r-lg:10px; --r-xl:14px;
  --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(201,162,39,.3), transparent 70%),
    radial-gradient(34% 40% at 78% 20%, rgba(227,199,101,.16), transparent 70%),
    radial-gradient(46% 42% at 62% 80%, rgba(110,84,17,.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(239,234,224,.028) 0 1px, transparent 1px 76px),
    repeating-linear-gradient(90deg, rgba(239,234,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 {
  /* The mega menu panels anchor to the header, not to the item that opened one,
     so that every panel opens at the same edge. */
  position: relative;
  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);
}

/* The mark stopped being a link, so the hover rule that used to hold its colour steady against
   the anchor styles has nothing to hold. What it needs instead is to stop LOOKING clickable: no
   pointer, and text that cannot be dragged into a selection by somebody trying to click it. */
.brand { cursor: default; user-select: none; }

.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(239,234,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:hover {
  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(239,234,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(239,234,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(239,234,224,.045), rgba(239,234,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(239,234,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(247,236,192,.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(239,234,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(239,234,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(239,234,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(239,234,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(239,234,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; }


  .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. ==== */

/* ---- badge-path.css ---- */
/* ===========================================================================
   THE PATH TO THE BADGE
   Three steps on the member's overview, with their own state against each.
   =========================================================================== */

.badge-steps {
  list-style: none;
  margin: 1.2rem 0 1.4rem;
  padding: 0;
  display: grid;
  gap: 1rem;
}

.badge-step {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: .9rem;
  align-items: start;
}

/* The numeral becomes a tick when the step is done, so the member reads their
   own progress off the same column rather than hunting for a state elsewhere. */
.badge-step-n {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  flex: none;
  border: 1px solid var(--hairline-strong);
  border-radius: 999px;
  color: var(--faint);
}

.badge-step.is-done .badge-step-n {
  border-color: color-mix(in srgb, var(--gold) 55%, transparent);
  background: var(--gold-wash);
  color: var(--gold-lift);
}

.badge-step-title { margin: 0 0 .15rem; font-weight: 600; }
.badge-step-body { margin: 0; color: var(--soft); font-size: .92rem; }

/* A step the member has finished stops competing for attention with the one
   they have not. */
.badge-step.is-done .badge-step-title { color: var(--soft); }

/* ---- the members roll ---- */

/* A status tag is a block by default, which in a list row stretched into a bar
   the width of the column. It is a label; it should be the width of its word. */
.member-row-state { margin: .35rem 0 0; }
.member-row-state .status-tag { display: inline-flex; width: auto; }

/* ---- the decision panel on a company record ---- */

/* THREE DECISIONS IN ONE CARD NEED AIR BETWEEN THEM. The badge, the waiver and
   the membership decision were stacked with no rhythm, so a hint line for one
   sat against the heading of the next and the whole card read as one paragraph
   of small print. The eyebrow that opens each block gets the space instead. */
[data-decision] .card-body > .eyebrow { margin-top: 1.4rem; }
[data-decision] .card-body > .rule { margin-block: 1.5rem; }
[data-decision] .card-body > p { margin-block: .35rem; }
[data-decision] .card-body > .form-actions { margin-top: .9rem; }
[data-decision] .form { margin-top: 1rem; }

/* ---- the membership credential ---- */

/* The card is the page. Everything around it is quiet so the thing somebody
   came to look at is the thing they look at. */
.credential-frame { max-width: 44rem; margin: 0 auto 1.4rem; }
.credential-actions { justify-content: center; margin-bottom: 1.6rem; }

/* PRINTING IS A REAL USE, not a courtesy. A member printing their credential
   wants the card and nothing else on the sheet: no navigation, no buttons, no
   verification panel they are about to hold in their hand anyway. */
@media print {
  .site-header, .site-footer, .credential-actions, .notice,
  .page-head .lede, .skip-link { display: none !important; }
  .credential-frame { max-width: none; margin: 0; }
  body { background: #fff; }
}

/* ---- 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 (#6e5411),
   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(247,236,192,.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(247,236,192,.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(4,7,15,.62);
  text-shadow: 0 1px 0 rgba(247,236,192,.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(201,162,39,.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(247,236,192,.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(239,234,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(239,234,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(247,236,192,.42), transparent 46%),
    var(--foil);
  background-size: 100% 100%, 220% 100%;
  box-shadow:
    inset 0 0 0 1px rgba(247,236,192,.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(4,7,15,.6);
  text-shadow: 0 1px 0 rgba(247,236,192,.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; }

/* ---- home.css ---- */
/* ===========================================================================
   THE FRONT DOOR
   One drawing, and the rules it needs. Everything else on this page is the
   platform's shared vocabulary: .hero-split, .hero-words, .hero-object,
   .page-head, .panel, .company-grid.

   Prefixed .front-, for the reason mandate.css gives: several pages were
   written into one stylesheet in parallel and an unprefixed .ring or .object
   would have taken somebody else's.
   =========================================================================== */

/* It scales with the column rather than sitting at a fixed size: the drawing is
   the only thing in the right-hand half, and a fixed size leaves that half
   empty on a wide screen and overflows a narrow one. */
.front-ring {
  display: block;
  width: 100%;
  max-width: 30rem;
  height: auto;
  margin-inline: auto;
  color: var(--text);
}

.front-object { margin: 0; }

/* ON A PHONE THE DRAWING YIELDS TO THE WORDS. The hero puts the object first at
   narrow widths, which is right - it is the thing worth seeing - but at full
   column width it stood 350px tall and pushed the sentence explaining the
   Council most of the way down the screen. Two thirds the size keeps the object
   leading and gets the heading and its first lines above the fold. */
@media (max-width: 47.99rem) {
  .front-ring { max-width: 17rem; }
}

/* ---- institution.css ---- */
/* ---------------------------------------------------------------------------
   THE INSTITUTIONAL COMPONENTS.

   Seven pages of the Council describe structures: governance layers, network
   levels, partner classes, exchange modules. Every one of them is the same
   shape of information - a numbered thing, its name, what it is, and who
   decides it - and the temptation is to draw seven grids of cards.

   Cards are wrong for this. A card says "pick one"; these are not choices, they
   are a register. So the Council's structures are set as a LEDGER: a ruled list
   with the number in the gutter, the name struck in the display face, and the
   definition beside it. It reads as a record rather than as a menu, it holds
   any number of rows without reflowing into a ragged last line, and on a phone
   it simply stacks.
   --------------------------------------------------------------------------- */

/* ---- the record line: mono label, gold rule, used at the head of every page - */
/* flex-basis 100% because .page-head is a flex ROW: without it the record is
   sized to its own text, the rule inside it has nothing to stretch across, and
   the line simply does not appear. It did not, the first time. */
.record {
  flex: 1 0 100%;
  display: flex;
  align-items: center;
  gap: .9rem;
  margin: 0 0 1.35rem;
}
.record-text {
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold-lift);
  white-space: nowrap;
  min-width: 0;
}

/* CANADIAN NOT-FOR-PROFIT CORPORATION does not fit on a 320px screen at this
   tracking, and nowrap made it push the page sideways rather than wrap. Below
   the smallest phone width it wraps and the rule sits under it. */
@media (max-width: 26rem) {
  .record { flex-wrap: wrap; row-gap: .5rem; }
  .record-text { white-space: normal; letter-spacing: .16em; }
  .record-rule { flex-basis: 100%; }
}
.record-rule {
  flex: 1 1 auto;
  height: 1px;
  min-width: 0;
  background: linear-gradient(90deg, var(--gold) 0%, rgba(201,162,39,.28) 42%, transparent 100%);
}

/* ---- the ledger ---------------------------------------------------------- */
.ledger { border-top: 1px solid var(--hairline-strong); }

.ledger-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: .5rem 1.6rem;
  padding: 1.6rem 0;
  border-bottom: 1px solid var(--hairline);
}
@media (min-width: 48rem) {
  .ledger-row {
    grid-template-columns: 3.2rem minmax(0, 15rem) minmax(0, 1fr);
    align-items: start;
    gap: 0 1.6rem;
    padding: 1.85rem 0;
  }
}

.ledger-no {
  font-family: var(--font-mono);
  font-size: .78rem;
  color: var(--faint);
  padding-top: .3rem;
  font-variant-numeric: tabular-nums;
}
.ledger-name {
  font-family: var(--font-display);
  font-size: 1.16rem;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  margin: 0;
}
.ledger-body { margin: 0; color: var(--soft); max-width: 46ch; }
.ledger-body + .ledger-body { margin-top: .5rem; }

/* The authority note: who decides this row. Mono, quiet, and on its own line so
   the eye can run down the column and read only that. */
.ledger-by {
  display: block;
  margin-top: .55rem;
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--faint);
}
.ledger-by b { color: var(--gold-lift); font-weight: 500; }

/* A row the reader can open. Same ledger, one hairline hover, no card. */
a.ledger-row {
  text-decoration: none;
  transition: background var(--t-ui) var(--ease);
}
a.ledger-row:hover { background: rgba(239,234,224,.028); }
a.ledger-row:hover .ledger-name { color: var(--gold-lift); }

/* ---- the standing note: what a page is honest about ---------------------- */
.standing {
  border-left: 2px solid var(--gold);
  padding: .1rem 0 .1rem 1.15rem;
  margin: 2.2rem 0 0;
  color: var(--soft);
  max-width: 60ch;
}
.standing p { margin: 0; }
.standing p + p { margin-top: .6rem; }

/* ---- an empty register, said plainly rather than mocked up --------------- */
.register-empty {
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-md);
  padding: clamp(1.6rem, 4vw, 2.4rem);
  background: var(--surface);
  max-width: 46rem;
}
.register-empty .ledger-name { margin-bottom: .6rem; }

/* ---- the hero rule: the one short struck line under the Council's name ---- */
.hero-rule {
  width: 88px;
  height: 2px;
  border: 0;
  margin: 1.4rem 0 1.55rem;
  background: var(--foil);
  background-size: 300% 100%;
}

/* The colon is punctuation, not language: it belongs to the layout so that the
   label either side of it stays a whole word a translator can place. */
.ledger-by-label::after { content: ":"; }

/* ---------------------------------------------------------------------------
   THE ROSTER.

   A ledger is right when each row needs a sentence. Some of the Council's lists
   do not: eleven sector councils, thirteen member services, twenty-four policy
   instruments. Those are NAMES, and a name given a paragraph it does not need
   is padding.

   So they are set as a dense ruled roster: several columns, one rule per row,
   nothing but the name. The density is the point. A reader scrolling past
   twenty-four ruled lines understands the size of the thing without reading one
   of them, which is exactly what a list of instruments is for.
   --------------------------------------------------------------------------- */

.roster-index {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
  gap: 0 2.5rem;
  border-top: 1px solid var(--hairline-strong);
}

.roster-index li {
  padding: .85rem 0;
  border-bottom: 1px solid var(--hairline);
  color: var(--soft);
  font-size: .93rem;
  line-height: 1.4;
  min-width: 0;
}

/* The counter runs across the whole roster rather than restarting per column,
   so the numbers read as one list that happens to be set in columns. */
.roster-index { counter-reset: roster; }

.roster-index li::before {
  counter-increment: roster;
  content: counter(roster, decimal-leading-zero);
  display: inline-block;
  width: 2.4rem;
  font-family: var(--font-mono);
  font-size: .72rem;
  color: var(--faint);
  font-variant-numeric: tabular-nums;
}

/* ---- 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; }

/* ---- nav.css ---- */
/* ===========================================================================
   THE MAIN NAVIGATION
   Sections in the row, pages in a panel under it. Prefixed .nav-, which the
   stylesheet already uses for .main-nav and .nav-link, so this extends that
   family rather than starting a second one.

   THE PANEL IS OPENED BY SCRIPT, NOT BY CSS ALONE. session.js sets [hidden]
   and aria-expanded, so a reader with no pointer and a reader with no mouse
   both get the same behaviour. The hover rule below is an accelerator for a
   pointer and nothing depends on it.
   =========================================================================== */

.nav-section { position: relative; display: inline-flex; }

/* The button has to sit in the row as though it were one of the links beside
   it: .nav-link carries the shape, this removes what a <button> brings with
   it that an <a> does not. */
.nav-toggle {
  border: 0;
  background: none;
  font: inherit;
  cursor: pointer;
  gap: .3rem;
}

.nav-caret {
  width: 12px;
  height: 12px;
  flex: none;
  transition: transform var(--t-micro) var(--ease);
}

.nav-toggle[aria-expanded="true"] .nav-caret { transform: rotate(180deg); }

/* The open section reads as the selected tab: the gold the site uses for "this
   one", and a wash behind it so the eye can find it again after reading the
   shelf. */
.nav-toggle[aria-expanded="true"] {
  color: var(--gold-lift);
  background: var(--gold-wash);
}

/* ---- the panel ---- */

/* FULL WIDTH OF THE HEADER, NOT OF THE BUTTON. A panel hanging off one item is
   a dropdown; this is a shelf under the whole row, which is what lets each
   destination carry a line of description without the column going thin. */
/* A SHELF ABOVE THE PAGE, NOT A BLOCK IN IT. The gradient runs from the header's
   own ground to the page's, so the panel reads as the header extending downwards
   rather than as a separate slab landing on top. */
.nav-panel {
  position: absolute;
  inset-inline: 0;
  top: 100%;
  z-index: 40;
  background: linear-gradient(180deg, var(--surface) 0%, var(--canvas-2) 78%);
  border-bottom: 1px solid var(--hairline);
  box-shadow: 0 24px 50px -12px rgba(0, 0, 0, .6);
  animation: nav-shelf 140ms var(--ease) both;
}

/* THE SAME GOLD HAIRLINE THE ACTIVE LINK ALREADY WEARS, drifting at the same
   rate. The house marks what you are looking at with a foil rule; the shelf
   wearing one is the panel saying it belongs to the item above it, which is what
   a connector line would have said less reliably. */
.nav-panel::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  top: 0;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  animation: foil-drift 11s linear infinite;
}

/* It arrives rather than appears. Six pixels and 140ms: enough for the eye to
   register where it came from, too little to wait for. */
@keyframes nav-shelf {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: none; }
}

@media (min-width: 56.25rem) {
  /* Anchored to the header rather than to the section, so every panel opens at
     the same edge and the reader's eye does not have to travel to find it.
     The header is position: relative for this. */
  .nav-section { position: static; }
  .nav-panel { inset-inline: 0; }
}

.nav-panel-inner { padding-block: 1.1rem 1.3rem; }

/* The section named again inside its own shelf, in the mono eyebrow with the gold
   dash that every page on this site opens with. It is the cheapest way to make a
   menu belong to the Council rather than to the browser: the reader has seen this
   device on the mandate, the programs and the directory already. */
.nav-panel-eyebrow { margin: 0 0 .8rem; }

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

/* The leading edge is the hover, and it is on the INLINE start so it moves to the
   right-hand side in Arabic without a second rule. A card that only changed its
   background left the reader's eye nothing to travel along. */
.nav-card {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  padding: .7rem .8rem;
  border-inline-start: 1px solid transparent;
  border-radius: var(--r-md);
  color: var(--text);
  text-decoration: none;
  transition: background-color var(--t-ui) var(--ease),
              border-color var(--t-ui) var(--ease);
}

.nav-card:hover,
.nav-card:focus-visible {
  background: var(--surface-2);
  border-inline-start-color: var(--gold);
  color: var(--text);
}

.nav-card:hover .nav-card-label,
.nav-card:focus-visible .nav-card-label { color: var(--gold-lift); }

.nav-card.is-active {
  background: var(--gold-wash);
  border-inline-start-color: var(--gold-lift);
}

.nav-card-label {
  font-weight: 600;
  font-size: .95rem;
  transition: color var(--t-ui) var(--ease);
}

.nav-card-blurb {
  color: var(--soft);
  font-size: .82rem;
  line-height: 1.45;
}

/* ---- the page behind ---- */

/* A SHELF THAT OVERLAYS HAS TO SAY SO. Without this the panel's lower edge slices
   through whatever heading happens to sit under it, and a cut-off headline reads
   as a rendering fault rather than as a menu. Dimming the page makes the overlay
   deliberate and gives the shelf somewhere to sit.

   :has() is the whole mechanism, so a browser without it simply gets no scrim and
   an ordinary opaque panel, which is what it had a minute ago. */
/* ON #site-header, NOT .site-header, and the reason is a bug I introduced.

   .site-header carries backdrop-filter for the frosted glass. A filtered element
   becomes the containing block for its position: fixed descendants, so this
   scrim - which is meant to dim the whole page behind an open mega menu - was
   trapped inside the header and painted nothing at all. The shelf then sliced
   across an undimmed page.

   #site-header is the sticky wrapper and carries no filter, so a fixed child
   escapes to the viewport the way it is supposed to. */
#site-header:has(.nav-toggle[aria-expanded="true"])::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 30;
  background: rgba(4,7,15, .55);
  animation: nav-scrim 140ms var(--ease) both;
  pointer-events: none;
}

/* The header itself stays out of the dimming. The scrim is drawn by the header so
   that :has() can see the open button, which puts it in the header's own painting
   order; without this the row, the brand and the buttons dim along with the page
   they are supposed to be sitting above. */
.site-header .header-inner { position: relative; z-index: 42; }

/* THE SHELF OPENS OVER THE MEMBER AREA BAR, not under it, and the reason it did
   not is worth writing down because nothing about it is visible in the panel's
   own rules.

   The panel is z-index 40, the bar was 41, so the obvious reading is that the
   bar simply outranks it. It does not: .header-inner carries a z-index of its
   own, which makes it a STACKING CONTEXT, and the panel lives inside it. The
   panel's 40 is therefore only a rank among its siblings inside that box; what
   competes with the bar is .header-inner's number, not the panel's. Lowering
   the bar to 39 changed nothing at all, because a tie is broken by document
   order and the bar comes second.

   So the number that had to move was the one on the container. A signed in
   member opening a mega-menu was getting the top third of the shelf hidden,
   with a strip of unrelated navigation wedged between a tab and its own
   contents. A menu covers what is beneath it. */
.site-header .seat-bar { position: relative; z-index: 41; }

@keyframes nav-scrim {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* ---- pointer devices only ---- */

/* An accelerator, and deliberately not the mechanism. hover cannot be the way a
   panel opens: a touch screen reports no hover, and a keyboard never will. */
@media (hover: hover) and (pointer: fine) and (min-width: 56.25rem) {
  .nav-section:hover .nav-panel,
  .nav-section:focus-within .nav-panel { display: block; }
  .nav-section:hover .nav-panel[hidden],
  .nav-section:focus-within .nav-panel[hidden] { display: block; }
}

/* ---- the phone ---- */

/* The button itself. Three bars drawn with a border rather than three elements,
   because the markup for a control this small should be one tag. */
.nav-menu-btn {
  display: none;
  align-items: center;
  justify-content: center;
  width: var(--tap);
  height: var(--tap);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-sm);
  background: none;
  color: var(--text);
  cursor: pointer;
}

.nav-menu-bars,
.nav-menu-bars::before,
.nav-menu-bars::after {
  display: block;
  width: 17px;
  height: 1.5px;
  background: currentColor;
  border-radius: 2px;
}

.nav-menu-bars { position: relative; }
.nav-menu-bars::before,
.nav-menu-bars::after { content: ""; position: absolute; inset-inline: 0; }
.nav-menu-bars::before { top: -5px; }
.nav-menu-bars::after { top: 5px; }

/* Below 48rem the whole navigation lives behind that button. Measured at 390px,
   the header was 315px tall and put the page's own heading at 761px, which is
   under the fold: the reader met the menu and had to scroll a screen to learn
   what they were looking at. Brand and button alone bring the row back to about
   sixty pixels. */
@media (max-width: 47.99rem) {
  .nav-menu-btn { display: inline-flex; }

  .header-inner { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
  .brand { grid-row: 1; grid-column: 1; }
  .nav-menu-btn { grid-row: 1; grid-column: 2; }

  .main-nav,
  .header-right { display: none; }

  .site-header.is-menu-open .main-nav,
  .site-header.is-menu-open .header-right {
    display: flex;
    grid-column: 1 / -1;
    width: 100%;
  }

  /* Stacked and full width: a tap target that spans the screen is one nobody
     misses, and the row has nothing to scroll sideways any more. */
  .site-header.is-menu-open .main-nav {
    flex-direction: column;
    align-items: stretch;
    padding-top: .6rem;
    border-top: 1px solid var(--hairline);
    margin-top: .6rem;
  }

  .site-header.is-menu-open .nav-section { display: block; }
  .site-header.is-menu-open .nav-link { justify-content: space-between; width: 100%; }

  .site-header.is-menu-open .header-right {
    flex-wrap: wrap;
    justify-content: flex-start;
    padding-block: .8rem 1rem;
  }

  /* IN THE MENU A PANEL IS PART OF THE LIST, not a shelf over the page. An
     overlay inside a menu that is already an overlay is two layers arguing. */
  .site-header.is-menu-open .nav-panel {
    position: static;
    background: none;
    box-shadow: none;
    border: 0;
    animation: none;
  }
  .site-header.is-menu-open .nav-panel::before { display: none; }
  .site-header.is-menu-open .nav-panel-inner { padding: .2rem 0 .6rem; }
  .site-header.is-menu-open .nav-panel-eyebrow { display: none; }
  .site-header.is-menu-open .nav-card { padding-inline: 1rem; }

  /* No scrim: the menu is the overlay. */
  #site-header:has(.nav-toggle[aria-expanded="true"])::after { display: none; }
}

/* ---- narrow screens ---- */

/* THE ROW WRAPS, THE PANEL STILL OVERLAYS. Putting each section on its own line
   made a header seven rows deep before any content began, which is worse than
   the sideways-scrolling row it replaced. Wrapping keeps it to two lines, and
   the panel stays anchored to the header the way it is on a wide screen: an
   overlay is what a reader expects a menu to be, at any width. */
@media (max-width: 56.24rem) {
  .main-nav { flex-wrap: wrap; justify-content: center; overflow: visible; }
  .nav-panel-inner { padding-block: .6rem 1rem; }
}

@media (prefers-reduced-motion: reduce) {
  .nav-caret,
  .nav-card { transition: none; }
  .nav-panel { animation: none; }
  .nav-panel::before { animation: none; }
  #site-header:has(.nav-toggle[aria-expanded="true"])::after { animation: none; }
}

/* ---- pay.css ---- */
/* ===========================================================================
   THE PAYMENT PAGE
   One panel, one number, one button. Prefixed .pay-.
   =========================================================================== */

/* The amount is what the reader came to decide about, so it is the largest
   thing on the page and set in the mono face the platform uses for every other
   figure it wants read exactly. */
.pay-amount {
  font-family: var(--font-mono);
  font-weight: 500;
  font-size: clamp(2.2rem, 1.5rem + 3vw, 3rem);
  line-height: 1;
  letter-spacing: -.02em;
  margin: .6rem 0 .5rem;
  background: var(--foil);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.pay-purpose { color: var(--soft); margin: 0; max-width: 40rem; }

/* ---- 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; }

/* ---- z1-stature.css ---- */
/* ---------------------------------------------------------------------------
   STATURE.

   The site was correct and quiet. Correct and quiet reads as small. This file is
   the pass that makes the Council look like the institution it is describing,
   and every rule in it does one of three things: gives the type more room to be
   certain, takes the softness out of the shapes, or holds a line where the eye
   expects one.

   None of it is decoration. There is no new colour here and no new device: it is
   the same palette, the same faces and the same hairlines, set with more nerve.
   --------------------------------------------------------------------------- */

/* ---- 1. the hero is a statement, not a column beside a picture -------------
   It used to be a two-up: an argument on the left and an emblem on the right.
   The emblem was a technical drawing of the Council's own structure, which is
   an interesting thing to know and a strange thing to be met by. Removing it
   leaves the whole width to the sentence, which is what an institution actually
   leads with. */
/* NO max-width HERE, and that is a correction rather than a preference. The
   element carries .shell as well, which centres what it constrains; giving the
   stack a narrower maximum therefore centred the whole hero inside the shell
   and left the Council's name starting 140px to the right of every other
   heading on the page. The measure belongs on the lines themselves, below. */
.hero-stack {
  position: relative;
  z-index: 1;
}

.hero-display {
  font-size: clamp(2.7rem, 1.1rem + 6.4vw, 6.1rem);
  line-height: .95;
  /* Large display type needs NEGATIVE tracking or it reads as a word processor.
     The bigger it gets the tighter it wants to be, which is why this is not the
     same value as the shared .display rule. */
  letter-spacing: -.045em;
  font-weight: 700;
  max-width: 15ch;
}

/* A measure, so the argument does not run the full width of a desk monitor.
   Roughly 62 characters: past that the eye loses the line return. */
.hero-lede {
  max-width: 54ch;
  font-size: clamp(1.02rem, .96rem + .45vw, 1.2rem);
  line-height: 1.62;
  color: var(--soft);
}

.hero-actions { margin-top: 2.4rem; }

/* The hero band carries more air than any other section on the site, because
   the first screen is the only one nobody scrolls past. */
.hero-band { padding-block: clamp(4rem, 2rem + 9vw, 9.5rem); }

/* ---- 2. the counted figures become an index, not a row of cards -----------
   Three panels with backgrounds and rounded corners is a dashboard. A rule, a
   large tabular number and a small mono label is a masthead. Same data. */
.hero-figures {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 0;
  margin-top: clamp(3rem, 1.5rem + 4vw, 5rem);
  background: none;
  border-radius: 0;
  border-top: 1px solid var(--hairline-strong);
}

.hero-figure {
  background: none;
  padding: 1.5rem 1.75rem 0 0;
}

.hero-figure-n {
  font-size: clamp(2.1rem, 1.2rem + 3vw, 3.1rem);
  font-weight: 400;
  letter-spacing: -.02em;
}

.hero-figure-label {
  margin-top: .7rem;
  font-size: .64rem;
  letter-spacing: .22em;
}

/* ---- 3. the shapes stop being soft ----------------------------------------
   The mark is a shield with cut corners and the tokens halved every radius to
   agree with it. The buttons did not get the message: a 999px pill is the most
   consumer shape there is, and two of them sat directly under the Council's
   name. Squared to the same radius as everything else, and given the room a
   primary action on an institutional site is entitled to. */
.btn {
  border-radius: var(--r-sm);
  letter-spacing: .015em;
}

.btn-lg {
  padding: 1.05rem 2.1rem;
  font-size: .96rem;
}

/* The primary action is struck metal on dark, and it should read as one plate
   rather than as a glowing lozenge. */
.btn-primary { box-shadow: none; }
.btn-primary:hover { box-shadow: 0 10px 30px -12px var(--gold-glow); }

/* ---- 4. the section rhythm ------------------------------------------------
   Space is the cheapest signal of seriousness and the one most often cut. */
.section { padding-block: clamp(3.4rem, 1.8rem + 5.2vw, 7rem); }

/* ---- 5. headings hold a line ---------------------------------------------
   Every section title on the site now opens against a hairline that runs the
   full width of the shell, the way a ruled sheet does. The eyebrow sits above
   the rule and the heading below it, so a reader scrolling fast still sees
   where one argument ends and the next begins. */
.section-title {
  font-size: clamp(1.8rem, 1.2rem + 2.4vw, 3rem);
  letter-spacing: -.03em;
  line-height: 1.06;
  margin: 0 0 1.6rem;
}

/* ---- 6. the display face, one notch braver everywhere else ---------------- */
.display { font-size: clamp(2.1rem, 1.35rem + 3.6vw, 4rem); letter-spacing: -.038em; }

/* ---- 7. the atmosphere -----------------------------------------------------
   One large, very soft light behind the first screen. It is not a gradient
   background: it is a single source, off centre, at low opacity, and it exists
   so the ground has depth rather than being a flat fill. */
/* THE LIGHT DOES THE WORK NOW.

   The world came out of the first screen, and what is left has to hold the
   right half of the composition on its own. So it is one source rather than
   three: a warm light off to the right at the height of the Council's name,
   falling away across the band, with a single cool fill low and left so the
   ground is not one temperature.

   A large soft light is the oldest way to make a dark surface read as lit
   rather than as printed, and it is the one thing on this band allowed to be
   big. */
.hero-band .aurora {
  filter: blur(140px);
  background:
    radial-gradient(42% 52% at 78% 34%, rgba(201,162,39,.32), transparent 70%),
    radial-gradient(34% 40% at 62% 18%, rgba(120,152,205,.17), transparent 72%),
    radial-gradient(46% 44% at 12% 88%, rgba(26,50,86,.55), transparent 74%);
  animation: aurora-drift 64s var(--ease) infinite alternate;
}

/* ---- 8. the front page stops using cards ----------------------------------
   Four bordered, rounded, gradient-filled boxes in a two-up grid is the house
   style of every SaaS landing page written since 2019, and it was carrying the
   two sections that explain what the Council actually is.

   They become a ruled sheet instead: a rule across the top, a rule under each
   row, one vertical rule down the middle, and the text set against them with
   room to breathe. It is the same device as the ledger on the institutional
   pages, which means the front page and the governance page are now visibly the
   same publication. */
#how .company-grid,
#carries .company-grid {
  gap: 0;
  border-top: 1px solid var(--hairline-strong);
}

#how .panel,
#carries .panel {
  background: none;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  border-radius: 0;
  box-shadow: none;
  padding: 2.4rem 3rem 2.6rem 0;
  transform: none;
}

/* No lift. A row of a ruled sheet does not rise when you point at it. */
#how .panel-lift:hover,
#carries .panel-lift:hover { transform: none; box-shadow: none; }

@media (min-width: 48rem) {
  #how .panel:nth-child(even),
  #carries .panel:nth-child(even) {
    border-left: 1px solid var(--hairline);
    padding-left: 3rem;
  }
}

#how .panel h3,
#carries .panel h3 {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.05rem + .7vw, 1.5rem);
  font-weight: 600;
  letter-spacing: -.02em;
  line-height: 1.2;
  margin: .55rem 0 .85rem;
}

#how .panel p,
#carries .panel p {
  color: var(--soft);
  max-width: 48ch;
  margin: 0;
}

/* ---- 9. the caveat is a standing note, not an alert -----------------------
   A blue-bordered information box is what software shows you when something
   went wrong. This paragraph is the Council being careful, which is a different
   tone entirely: a gold rule beside it, and nothing else. */
/* EVERY INFORMATIONAL NOTICE, NOT JUST THE ONE ON THE FRONT PAGE.

   .notice-info was a cyan bordered, cyan tinted box: the shape software uses to
   tell you something went slightly wrong. None of these are warnings. They are
   the Council being careful, which is a different tone entirely and deserves a
   different object: a gold rule beside the words, and nothing else.

   The alarming tones are untouched. A warning still has to look like one. */
.notice-info {
  background: none;
  border: 0;
  border-inline-start: 2px solid var(--gold);
  border-radius: 0;
  padding: .15rem 0 .15rem 1.3rem;
  max-width: 68ch;
  color: var(--soft);
}

#how .notice-info { margin-top: 3rem; }

/* ---- 10. the page head, given the same rule as everything else ------------ */
#how .page-head,
#carries .page-head,
#membership-fee .page-head,
#apply .page-head {
  display: block;
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: clamp(2.2rem, 1.4rem + 2.4vw, 3.4rem);
}

#how .page-head .lede,
#membership-fee .page-head .lede,
#apply .page-head .lede { max-width: 56ch; margin-top: 1.1rem; }

/* ---- z2-edge.css ---- */
/* ---------------------------------------------------------------------------
   EDGE.

   The Council was correct, quiet, and one single texture from top to bottom:
   dark navy, hairlines, serif headings, every element speaking at the same
   volume. A site with no dynamic range reads as careful rather than as
   confident, and careful is what "boring" actually means.

   Four things fix it, and none of them is an effect for its own sake:

     1. THE MASTHEAD SETS ITSELF. The Council's name arrives in order - record
        line, name, rule, argument, actions, register - over about 900ms. A
        reader who watches a page assemble reads it as machinery; a page that is
        simply there reads as a screenshot.

     2. ONE BAND IS PRINTED. The stylesheet says DARK ONLY at the top and it has
        been true for a year. It is now true with exactly one exception, and the
        exception is the point: the charter is a printed thing, so it is printed
        - ivory paper, ink, and the Council's seal struck into it. In a dark
        site one sheet of paper is an event. See .band-paper.

     3. THE METAL CATCHES LIGHT. The foil already drifts. It now also SWEEPS
        under the pointer, which is the difference between a gold fill and a
        struck surface.

     4. EVERY LINE ANSWERS. Nav underlines draw rather than appear, ledger rows
        move under the pointer and put an arrow where the eye already is, focus
        is gold and obvious. A site where nothing responds feels dead however
        well it is set.

   All of it is inside prefers-reduced-motion guards or is a transition on a
   property the reader asked for. Nothing here is required to read the page.
   --------------------------------------------------------------------------- */

/* ===========================================================================
   1  THE MASTHEAD SETS ITSELF
   =========================================================================== */

@media (prefers-reduced-motion: no-preference) {
  .hero-stack > * { animation: set-in 820ms var(--ease) both; }
  .hero-stack .record   { animation-delay: 40ms; }
  .hero-stack .display  { animation-delay: 140ms; }
  .hero-stack .lede     { animation-delay: 320ms; }
  .hero-actions         { animation-delay: 430ms; }
  .hero-figures         { animation-delay: 540ms; }

  /* The rule is DRAWN rather than faded, because a rule is a stroke and a
     stroke has a direction. It is the one element on the first screen that
     moves in a way the reader can name. */
  .hero-rule {
    animation: rule-draw 700ms var(--ease) 300ms both,
               foil-drift 13s linear 1s infinite;
  }
}

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

@keyframes rule-draw {
  from { width: 0; opacity: 0; }
  to   { width: 88px; opacity: 1; }
}

/* ===========================================================================
   2  ONE BAND IS PRINTED

   The tokens are redefined ON THE BAND, not on :root, so the whole component
   vocabulary - eyebrow, display, lede, mono-meta, hairline - inverts without a
   single component knowing anything about it. This is the reason every rule in
   this platform reads var(--text) instead of a colour.
   =========================================================================== */

.band-paper {
  --text: #14181c;
  --soft: #4c5560;
  --faint: #78828d;
  --hairline: rgba(20,24,28,.16);
  --hairline-strong: rgba(20,24,28,.30);
  --gold: #8a6b16;
  --gold-lift: #6e5411;
  --gold-white: #a98a2c;
  --gold-wash: rgba(138,107,22,.10);

  position: relative;
  isolation: isolate;
  color: var(--text);
  background: #f2efe6;
  /* Two very soft warm lights, so the sheet has a curve to it rather than
     being a flat swatch. Paper is never one value. */
  background-image:
    radial-gradient(60% 55% at 18% 12%, rgba(255,255,255,.85), transparent 70%),
    radial-gradient(55% 60% at 88% 96%, rgba(201,162,39,.10), transparent 72%);
  border-block: 1px solid rgba(20,24,28,.22);
}

/* The tooth of the paper. The same noise the dark bands use, at a weight that
   reads as fibre rather than as television. */
.band-paper::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23p)'/%3E%3C/svg%3E");
}

.charter {
  display: grid;
  gap: clamp(2.4rem, 1rem + 5vw, 4.5rem);
  align-items: start;
}

@media (min-width: 56rem) {
  .charter { grid-template-columns: minmax(0, 1fr) auto; }
}

.charter-statement {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(1.65rem, .95rem + 2.6vw, 2.9rem);
  line-height: 1.14;
  letter-spacing: -.03em;
  margin: 0 0 1.6rem;
  max-width: 20ch;
  text-wrap: balance;
}

.charter-body { max-width: 52ch; margin: 0; color: var(--soft); }
.charter-body + .charter-body { margin-top: .9rem; }

/* The signature block: a rule, the Council's name, the place. The way a
   document ends. */
.charter-sign {
  margin-top: 2.6rem;
  padding-top: 1.1rem;
  border-top: 1px solid var(--hairline-strong);
  font-family: var(--font-mono);
  font-size: .68rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--faint);
  max-width: 34ch;
}

/* ---- the seal, struck into the sheet ------------------------------------
   Not a diagram: no data nodes, no graduations, no legend. It is the emblem
   pressed into paper, which is what a seal is, and it is the only place on the
   site where the mark appears at a size you can actually look at. */
.charter-seal {
  width: clamp(7rem, 4rem + 9vw, 10.5rem);
  height: auto;
  justify-self: start;
  filter: drop-shadow(0 2px 1px rgba(255,255,255,.9)) drop-shadow(0 -1px 1px rgba(20,24,28,.22));
}

@media (min-width: 56rem) {
  .charter-seal { justify-self: end; align-self: center; }
}

/* ===========================================================================
   3  THE METAL CATCHES LIGHT
   =========================================================================== */

/* The metal's hover behaviour moved to z3-light.css, where it is a press rather
   than a sweep. What stood here animated background-position on an element whose
   background-image section 15 had already set to none: three rules, all dead,
   all still being parsed. */

/* ===========================================================================
   4  EVERY LINE ANSWERS
   =========================================================================== */

/* The underline is drawn from the leading edge on hover, and the active item
   keeps it. Same stroke, two states, so hovering an item shows you exactly what
   selecting it will look like. */
.nav-link::after {
  content: "";
  position: absolute;
  left: .8rem;
  right: .8rem;
  bottom: .55rem;
  height: 1px;
  background: var(--foil);
  background-size: 220% 100%;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 280ms var(--ease);
}

.nav-link:hover::after,
.nav-link.is-active::after { transform: scaleX(1); }

.nav-link.is-active::after { animation: foil-drift 11s linear infinite; }

/* A ledger row that goes somewhere says so. The name steps toward the reader
   and an arrow arrives in the space the step opened. */
a.ledger-row { position: relative; }

a.ledger-row .ledger-name {
  transition: transform 260ms var(--ease), color var(--t-ui) var(--ease);
}

a.ledger-row:hover .ledger-name { transform: translateX(6px); }

a.ledger-row::after {
  content: "";
  position: absolute;
  inset-inline-end: .4rem;
  top: 1.95rem;
  width: 18px;
  height: 8px;
  opacity: 0;
  transform: translateX(-8px);
  transition: opacity 260ms var(--ease), transform 260ms var(--ease);
  background: var(--gold-lift);
  /* A drawn arrow rather than a glyph: a character would be a font dependency
     and would flip the wrong way in Arabic. */
  clip-path: polygon(0 45%, 66% 45%, 66% 0, 100% 50%, 66% 100%, 66% 55%, 0 55%);
}

a.ledger-row:hover::after { opacity: 1; transform: none; }

/* Focus is not a smaller hover. It is the only signal a keyboard reader gets,
   so it is the loudest thing on the page while it is showing. */
:where(a, button, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--gold-lift);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* ===========================================================================
   5  THE GROUND IS MATERIAL

   A vignette on the deep bands. Nothing you would notice; the absence is what
   you notice, because a flat fill reads as a colour and a fill that falls off
   at the edges reads as a lit surface.
   =========================================================================== */

.band-deep { position: relative; }

.band-deep::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(120% 90% at 50% 40%, transparent 45%, rgba(4,7,15,.55) 100%);
}

/* THE SHELL, NOT EVERY CHILD. `.band-deep > *` also selects .aurora, .graticule
   and .grain, which are position:absolute and would have been forced back to
   relative by it - taking them out of their corner, into the flow, and pushing
   the section open. Only the content needs lifting above the vignette. */
.band-deep > .shell { position: relative; z-index: 1; }

/* ===========================================================================
   6  THE INSTITUTIONAL PAGE HEADS

   .page-head is a flex ROW with space-between, so a page can set a title
   against an action opposite it. The seven institutional pages have no action:
   they have a record line, a title and a measure of prose, and in a row those
   three wrap into whatever width is left and leave a hollow half-band beneath.

   :has(.record) selects exactly those pages and nothing else, because the
   record line is the thing they alone carry. A browser without :has() simply
   keeps the row, which is what the page looked like before.
   =========================================================================== */

.page-head:has(.record) {
  display: block;
  border-bottom: 0;
  padding-bottom: 0;
  margin-bottom: 0;
}

.page-head:has(.record) .lede {
  max-width: 56ch;
  margin-top: 1.25rem;
}

.section.band-deep:has(.page-head .record) {
  padding-block: clamp(3.2rem, 1.8rem + 5vw, 6.5rem);
}

/* ===========================================================================
   8  THE MARKS THAT SAY WHAT MEMBERSHIP CARRIES

   Four drawings, one per thing the platform actually does. They are line work
   in the Council's own geometry - the chamfered frame of the mark, the same
   gold, the same 1.6 stroke - rather than icons from a set, because a set is
   the fastest way to look like everybody else.

   THEY DRAW THEMSELVES WHEN THE ROW IS REACHED. Each path is dashed to its own
   length and the offset animates to zero, so the line is struck rather than
   revealed. Under the pointer the lit element in each drawing moves: the
   directory row slides, the arrows travel, the check is struck again.
   =========================================================================== */

.carries-mark {
  width: 52px;
  height: 52px;
  display: block;
  margin-bottom: 1.15rem;
  overflow: visible;
}

.carries-mark path,
.carries-mark circle {
  fill: none;
  stroke: var(--soft);
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: stroke var(--t-ui) var(--ease), transform 420ms var(--ease);
}

.carries-mark .cm-lit { stroke: var(--gold-lift); }
.carries-mark .cm-dot { fill: var(--gold-lift); stroke: none; }

/* The row a panel is in lights the whole drawing, not just the part under the
   pointer: the drawing belongs to the row, and a hover that only reaches one
   path reads as a bug. */
#carries .panel:hover .carries-mark path,
#carries .panel:hover .carries-mark circle { stroke: var(--text); }
#carries .panel:hover .carries-mark .cm-lit { stroke: var(--gold-white); }
#carries .panel:hover .carries-mark .cm-dot { fill: var(--gold-white); }

@media (prefers-reduced-motion: no-preference) {
  /* Each path carries its own dash length, so nothing is drawn at the same
     speed as anything else and the four do not read as one animation. */
  .carries-mark .cm-frame  { --dash: 190; stroke-dasharray: 190; animation: strike 1100ms var(--ease) both; }
  .carries-mark circle.cm-frame { --dash: 125; stroke-dasharray: 125; }
  .carries-mark .cm-dot { animation: set-in 700ms var(--ease) 380ms both; }
  .carries-mark .cm-line   { --dash: 30;  stroke-dasharray: 30;  animation: strike 620ms var(--ease) 320ms both; }
  .carries-mark .cm-arrow  { --dash: 60;  stroke-dasharray: 60;  animation: strike 760ms var(--ease) 240ms both; }
  .carries-mark .cm-check  { --dash: 34;  stroke-dasharray: 34;  animation: strike 620ms var(--ease) 420ms both; }

  #carries .panel:hover .cm-lit.cm-line  { transform: translateX(3px); }
  #carries .panel:hover .cm-arrow.cm-lit { transform: translateX(-3px); }
  #carries .panel:hover .cm-check        { animation: strike 520ms var(--ease) both; }
}

/* The offset starts at the path's OWN length, not at a shared number. A single
   190 across four different paths means each one starts part drawn by a
   different amount, which reads as four half finished drawings rather than as
   four lines being struck. */
@keyframes strike {
  from { stroke-dashoffset: var(--dash, 190); opacity: .15; }
  to   { stroke-dashoffset: 0; opacity: 1; }
}

/* ===========================================================================
   9  A DIFFERENT GROUND UNDER EACH BAND

   The site was one fill from top to bottom. Each band now stands on something
   of its own, all of it generated: no file is fetched, nothing is a photograph,
   and every one of them is the same two colours the rest of the site uses.
   =========================================================================== */

/* THE STEPS stand on a drawing board: a fine square grid, fading out downward,
   because a numbered procedure is a thing that was drafted. */
/* THE GRID IS A LAYER, NOT A BACKGROUND ON THE SECTION. A mask-image set on the
   section masks everything inside it, text included, so the fade at the bottom
   would have taken the closing paragraph down with it. The drawing board is its
   own element behind the content and is masked alone. */
#how { position: relative; isolation: isolate; }

#how::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(0deg, rgba(239,234,224,.032) 0 1px, transparent 1px 64px),
    repeating-linear-gradient(90deg, rgba(239,234,224,.032) 0 1px, transparent 1px 64px);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, #000 52%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 0%, #000 52%, transparent 100%);
}

/* WHAT MEMBERSHIP CARRIES stands on a chart of the sea floor: soft contour
   rings, off centre, the way depth is drawn. */
#carries {
  background-image:
    repeating-radial-gradient(circle at 82% 12%, transparent 0 38px, rgba(201,162,39,.055) 38px 39px),
    radial-gradient(70% 60% at 82% 12%, rgba(201,162,39,.05), transparent 70%);
}

/* THE FEE and THE WAY IN stand in a single low light, so the two places a
   reader has a decision to make are the two warmest parts of the page. */
#membership-fee,
#apply {
  background-image: radial-gradient(58% 70% at 22% 40%, rgba(201,162,39,.07), transparent 72%);
}

/* ===========================================================================
   10  THE WAY IN

   The last band on the page is the only one that asks for anything, so it gets
   the seal at charter size, struck into the ground behind the invitation. Very
   low contrast on purpose: a watermark is a thing you notice second.
   =========================================================================== */

.is-invitation {
  position: relative;
  overflow: hidden;
  padding-block: clamp(4rem, 2rem + 7vw, 8rem);
}

/* Same correction: the seal behind the invitation was 4 per cent outside the
   page, which measured between 13 and 66px depending on the width. */
.invitation-seal {
  position: absolute;
  z-index: 0;
  inset-inline-end: clamp(0.5rem, 2vw, 3rem);
  top: 50%;
  transform: translateY(-50%);
  width: clamp(11rem, 26vw, 24rem);
  max-width: 44%;
  height: auto;
  color: var(--gold);
  opacity: .085;
  pointer-events: none;
}

.is-invitation .display { font-size: clamp(2.2rem, 1.3rem + 4.2vw, 4.4rem); }
.is-invitation .lede { max-width: 52ch; }
.is-invitation .form-actions { margin-top: 2.2rem; }
.is-invitation .mono-meta { margin-top: 1rem; }

/* The two quiet lines under the actions are the only place on the page where a
   reader who is ALREADY a member, or who is not ready, is spoken to. They stay
   quiet, but they stop being invisible. */
.is-invitation .mono-meta a { color: var(--gold-lift); }
.is-invitation .mono-meta a:hover { color: var(--gold-white); }

/* ===========================================================================
   11  THE POINTER LIGHT

   Every deep band carries a soft light that follows the reader's pointer. The
   position arrives as two custom properties from motion.js; everything else,
   including the whole appearance of the thing, is here. It starts off centre
   rather than at 0,0 so a page nobody has touched yet still has a light in it.

   ::before, because ::after on this element is already the vignette. The two
   read as one lit surface: a source that moves, and a falloff that does not.
   =========================================================================== */

.band-deep {
  --lx: 72%;
  --ly: 30%;
}

.band-deep::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(30rem 24rem at var(--lx) var(--ly),
    rgba(201,162,39,.075), rgba(58,96,150,.05) 42%, transparent 72%);
  transition: background 240ms linear;
}

@media (prefers-reduced-motion: reduce) {
  .band-deep::before { transition: none; }
}

/* ===========================================================================
   12  MATERIAL

   Frosted surfaces where something floats above the page, deeper shadows under
   the things that are meant to be held. Two properties, and the difference
   between a flat dark theme and a lit one.
   =========================================================================== */

.site-header { backdrop-filter: blur(14px) saturate(135%); }

.nav-panel {
  backdrop-filter: blur(22px) saturate(150%);
  box-shadow: 0 32px 60px -18px rgba(2,5,12,.8), 0 1px 0 rgba(239,234,224,.05) inset;
}

/* ===========================================================================
   13  THE PAGE MOTIFS

   Seven institutional pages, each with a drawing of what it actually says: four
   nested frames for four layers of authority, concentric rings of nodes for a
   network that grows outward from one office, five stations and a direction for
   the exchange, eight spokes for eight kinds of collaboration.

   None of them is an illustration OF the page in the decorative sense. Each is
   the page's own structure drawn in line, which is why none of them needs a
   caption and why swapping one between pages would be visibly wrong.

   They sit behind the words at low contrast, are masked away at their edges,
   and strike themselves in when the band arrives.
   =========================================================================== */

/* MEASURED, NOT ESTIMATED. The inset was a negative clamp, which pushed the
   drawing OFF the right edge of the page at every width: 26 to 38px on a desktop
   and, once the narrow rule below took over, 136px of a 320px drawing at 820px.
   Forty three per cent of it was outside the page.

   A drawing that runs off the edge can be a deliberate crop, but only when the
   part still on the page reads as complete. These do not: they are centred
   figures, so cropping one takes its centre off and leaves an arc.

   The inset is positive now and the width is capped as a share of the space, so
   the figure sits INSIDE the page at every width from 320px up. Checked by
   measuring the bounding box against the viewport on ten widths rather than by
   looking at two screenshots. */
.page-motif {
  position: absolute;
  z-index: 0;
  inset-inline-end: clamp(0.75rem, 3vw, 4rem);
  top: 50%;
  transform: translateY(-50%);
  width: clamp(10rem, 22vw, 21rem);
  max-width: 40%;
  height: auto;
  pointer-events: none;
  opacity: .5;
  -webkit-mask-image: radial-gradient(72% 72% at 50% 50%, #000 42%, transparent 88%);
  mask-image: radial-gradient(72% 72% at 50% 50%, #000 42%, transparent 88%);
}

.page-motif path,
.page-motif circle {
  fill: none;
  stroke: var(--soft);
  stroke-width: 1.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}

.page-motif .mo-thin,
.carries-mark .cm-thin { stroke-width: 1; stroke-opacity: .55; }
.page-motif .mo-lit { stroke: var(--gold); }
.page-motif .mo-dot { fill: var(--soft); stroke: none; opacity: .75; }
.page-motif .mo-lit-fill { fill: var(--gold-lift); stroke: none; opacity: 1; }

@media (prefers-reduced-motion: no-preference) {
  /* Struck along each path's own length, one after another, so the drawing
     assembles in the order the page argues in. */
  .page-motif .mo-draw {
    stroke-dasharray: var(--dash, 400);
    animation: strike 1500ms var(--ease) both;
  }
  .page-motif .mo-dot { animation: set-in 900ms var(--ease) 700ms both; }
}

/* Below the fold of a phone the drawing sits behind the whole head, quieter,
   so it never competes with the sentence standing on it. */
/* On a narrow screen the drawing stays on the page and gets quieter, rather than
   being shoved off the side of it. */
@media (max-width: 60rem) {
  .page-motif { opacity: .22; width: clamp(8rem, 34vw, 14rem); max-width: 46%; }
}

/* ===========================================================================
   14  THE MARK, AND WHY IT HAS NO GRADIENT

   The mark inherits currentColor from the brand lockup, so it is one flat gold
   everywhere it appears and moves with the palette rather than with a hard
   coded stop list. A logotype carrying its own gradient is a logotype that will
   be wrong on the first surface nobody thought about.
   =========================================================================== */

/* THE LOCKUP IS THE WAY HOME. It was a span, and the base sheet set it to
   cursor: default and user-select: none, so on a phone - where the whole
   navigation is behind a hamburger - there was no visible way back to the front
   page at all. Every site on earth teaches that the mark is the way home. */
.brand {
  color: var(--gold);
  gap: .68rem;
  cursor: pointer;
  user-select: auto;
  text-decoration: none;
}
.brand:hover { color: var(--gold-lift); }
/* The base sheet sets .mark to --text, from when the mark carried its own
   gradients and only inherited a faint interior line. It is one flat stroke
   now, so it takes the lockup's colour: written as .brand .mark so it wins on
   specificity rather than on merge order, which is not a thing to depend on. */
.brand .mark {
  color: inherit;
  width: 30px;
  height: 30px;
  transition: color var(--t-ui) var(--ease);
}

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

.brand-sub {
  font-family: var(--font-mono);
  font-size: .555rem;
  letter-spacing: .26em;
  color: var(--faint);
}

/* ===========================================================================
   15  THE PROFESSIONALISM PASS

   Three habits were making a carefully structured site read as unserious, and
   all three are the same habit: reaching for an effect where a decision would
   have done.

   GRADIENTS INSIDE INTERFACE. The Council's foil is a beautiful thing on a
   printed credential, where it is standing in for struck metal on a physical
   card. On a button, a rule, a set of figures and a navigation underline it is
   not standing in for anything: it is a fill pretending to be a material, and
   an animated one at that. Those four become flat gold. The foil stays where it
   belongs, on the artifacts.

   GLOW. A gold halo under a primary button is the single most common tell of a
   page assembled from effects rather than designed. Removed. A button on a dark
   ground needs contrast and an edge, not light leaking out of it.

   STACKED ATMOSPHERE. Every deep band was carrying an aurora, a graticule, a
   grain, a vignette, a pointer light and, on seven pages, a motif. Six layers
   competing at ten percent each read as haze, not as depth. The aurora is now
   the hero's alone, which is the one place a light source is doing work.
   =========================================================================== */

/* ---- flat metal ---------------------------------------------------------- */

.btn-primary {
  background: var(--gold);
  background-image: none;
  animation: none;
  color: #1a1405;
  border-color: var(--gold);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.28);
}

.btn-primary:hover {
  background: var(--gold-lift);
  border-color: var(--gold-lift);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.36);
}

.hero-rule {
  background: var(--gold);
  background-image: none;
  height: 3px;
  width: 72px;
}

@media (prefers-reduced-motion: no-preference) {
  .hero-rule { animation: rule-draw 700ms var(--ease) 300ms both; }
}

@keyframes rule-draw {
  from { width: 0; opacity: 0; }
  to   { width: 72px; opacity: 1; }
}

/* The counted figures are DATA. Data is set in one colour, at one weight, and
   is read rather than admired. */
.hero-figure-n {
  background-image: none;
  color: var(--gold-lift);
  -webkit-text-fill-color: currentColor;
}

.nav-link.is-active::after,
.nav-link:hover::after {
  background: var(--gold);
  background-image: none;
  animation: none;
}

/* ---- the eyebrow ---------------------------------------------------------
   A 24px dash in front of every small caps label, on every section of every
   page, is a template's signature. The label carries itself: letterspaced,
   quiet, in the metal, with nothing leading it. */
.eyebrow::before { content: none; }
.eyebrow { color: var(--gold); letter-spacing: .2em; font-size: 10.5px; }

/* ---- one light, in one place --------------------------------------------- */

.aurora { display: none; }
.hero-band .aurora { display: block; opacity: .85; }

/* Without six competing layers the vignette and the pointer light can each do
   their own job, so both come down to where they read as lighting rather than
   as texture. */
.band-deep::after { background: radial-gradient(125% 95% at 50% 40%, transparent 52%, rgba(4,7,15,.42) 100%); }
.band-deep::before {
  background: radial-gradient(26rem 20rem at var(--lx) var(--ly),
    rgba(201,162,39,.05), rgba(58,96,150,.035) 44%, transparent 74%);
}

.graticule { opacity: .55; }
.page-motif { opacity: .38; }

/* The signature line is one line, or two at most. A 34ch measure broke a mono
   line of small caps into three ragged fragments, which is the opposite of what
   the bottom of a document should look like. */
.charter-sign { max-width: none; letter-spacing: .18em; }

/* ===========================================================================
   16  THE INDEX, AND THE STEP NUMERALS

   Two changes, one argument: the front page was quiet because it had nothing on
   it but a sentence and some air, and air is not the same thing as confidence.

   THE INDEX fills the right half of the first screen with the Council's own
   holdings, set as a ruled table with tabular figures. It is dense where the
   headline is open, which is the contrast the page was missing, and every line
   of it is true rather than decorative.

   THE STEP NUMERALS give the procedure a second scale. A four step process set
   entirely in body copy is a list; the same four with the number struck at
   eight times the size of its label is a document. The numerals are outlined
   rather than filled, so they carry the eye without ever competing with the
   words beside them.
   =========================================================================== */

.hero-grid {
  display: grid;
  gap: clamp(2.5rem, 1rem + 5vw, 5rem);
  align-items: start;
}

@media (min-width: 62rem) {
  .hero-grid { grid-template-columns: minmax(0, 1fr) minmax(16rem, 20rem); align-items: center; }
}

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

.index-block + .index-block { margin-top: 2.4rem; }

.index-title {
  font-family: var(--font-mono);
  font-size: .62rem;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 .9rem;
  padding-bottom: .75rem;
  border-bottom: 1px solid var(--hairline-strong);
}

.index-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.25rem;
  padding: .62rem 0;
  border-bottom: 1px solid var(--hairline);
}

.index-label { color: var(--soft); font-size: .88rem; min-width: 0; }

.index-n {
  font-family: var(--font-mono);
  font-size: 1.35rem;
  font-weight: 500;
  line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

@media (prefers-reduced-motion: no-preference) {
  .hero-index { animation: set-in 820ms var(--ease) 560ms both; }
}

/* ---- the step numerals --------------------------------------------------- */

#how .panel { position: relative; }

#how .panel .eyebrow {
  position: relative;
  z-index: 1;
  display: block;
  margin-bottom: .3rem;
}

/* The number is the eyebrow's own text, printed large and hollow behind it.
   Nothing new is added to the markup and nothing is repeated for a screen
   reader, because the numeral is drawn by the stylesheet from a counter. */
#how .company-grid { counter-reset: step; }

/* .panel::before is ALREADY the panel's top hairline, and it carries
   inset-inline: 0 - both edges pinned. Overriding only the end edge left the
   start edge pinned at 0, so the numeral stretched across the panel and printed
   at the left, on top of its own label. Everything the hairline set has to be
   undone explicitly; a partial override of a pseudo element already in use is
   how you get a numeral in the wrong corner and no obvious reason why. */
#how .panel::before {
  counter-increment: step;
  content: counter(step, decimal-leading-zero);
  position: absolute;
  background: none;
  border-radius: 0;
  opacity: 1;
  height: auto;
  width: auto;
  top: .2rem;
  inset-inline-start: auto;
  inset-inline-end: 2rem;
  z-index: 0;
  font-family: var(--font-mono);
  font-size: clamp(3.4rem, 2rem + 4vw, 5.6rem);
  font-weight: 500;
  line-height: 1;
  color: transparent;
  -webkit-text-stroke: 1px var(--hairline-strong);
  pointer-events: none;
  transition: -webkit-text-stroke-color var(--t-ui) var(--ease);
}

#how .panel:hover::before { -webkit-text-stroke-color: var(--gold); }

/* ===========================================================================
   17  THE SEAL AT REST

   join.html and donate.html each carried a blurred gold disc with GDTC printed
   across it, at about 230px: the single largest object on either page and a
   gradient blob rather than a mark. Both now show the same struck seal the
   charter carries, in the Council's own line weight, so the emblem is one
   object everywhere it appears instead of three impressions of one.
   =========================================================================== */

.rest-seal {
  width: clamp(9rem, 20vw, 15rem);
  height: auto;
  justify-self: center;
  align-self: center;
  color: var(--gold);
  opacity: .9;
}

@media (min-width: 56rem) {
  .rest-seal { justify-self: end; }
}

/* ===========================================================================
   18  THE FOOTER INDEX

   Six columns generated from the navigation, an identity block beside them, and
   one rule between that and the standing disclaimer. The columns are auto-fit
   rather than a fixed count, so adding a seventh section to NAV adds a seventh
   column and nothing here has to be told about it.
   =========================================================================== */

.site-footer { padding-block: clamp(3.4rem, 2rem + 4vw, 5.5rem) 2.2rem; }

.footer-top {
  display: grid;
  gap: clamp(2.4rem, 1.2rem + 4vw, 4rem);
  align-items: start;
}

@media (min-width: 64rem) {
  .footer-top { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr); }
}

.footer-identity .brand { margin-bottom: 1.1rem; }
.footer-identity .mono-meta { margin: 0 0 .35rem; }
.footer-identity .mono-meta a { color: var(--soft); }
.footer-identity .mono-meta a:hover { color: var(--gold-lift); }
.footer-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin: 1.35rem 0 0; }

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

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

.footer-head {
  font-family: var(--font-mono);
  font-size: .6rem;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--gold);
  margin: 0 0 .35rem;
  padding-bottom: .55rem;
  border-bottom: 1px solid var(--hairline);
}

.footer-col a {
  color: var(--soft);
  font-size: .85rem;
  line-height: 1.35;
  text-decoration: none;
  transition: color var(--t-ui) var(--ease);
}

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

/* max-width: none, because the base rule sets 68ch and the RULE inherits it: the
   closing line of the footer was stopping less than half way across, which reads
   as a broken border rather than as a measure. The sentence is short enough to
   sit on one line at full width. */
.footer-bottom {
  margin: clamp(2.4rem, 1.4rem + 3vw, 3.6rem) 0 0;
  padding-top: 1.4rem;
  border-top: 1px solid var(--hairline);
  color: var(--faint);
  font-size: .78rem;
  max-width: none;
}

/* ===========================================================================
   19  THE ENGRAVING, AND A GROUND WITH DEPTH

   The site's background was one flat navy fill with a light on it. Flat is not
   the same as calm, and a fill is not a material.

   TWO CHANGES. The ground becomes a long vertical gradient, deepest in the
   middle of the page and lifting at both ends, so scrolling passes through
   something rather than across it. And the first screen carries an ENGRAVING:
   an engine turned rosette, the figure a rose engine lathe cuts, and the reason
   banknotes, share certificates and passports look the way they do.

   It is computed rather than drawn. Three hypotrochoids at different periods,
   and the interference between them is the pattern; there is no way to arrive
   at it by hand and no way to mistake it for a stock texture. It is the right
   figure for this institution specifically: the Council's business is sealing
   and verifying, and this is the language every sealed document on earth is
   already written in.

   Kept at low contrast and masked away at its edges, because an engraving is a
   ground. The moment you can read it as a picture it has stopped working.
   =========================================================================== */

body {
  background:
    radial-gradient(120% 62% at 50% 0%, rgba(26,48,80,.42), transparent 62%),
    linear-gradient(180deg, #08111f 0%, var(--canvas) 32%, #050a14 68%, #07101d 100%);
  background-attachment: fixed;
}

.engine {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url("/guilloche.svg");
  background-repeat: no-repeat;
  background-position: 82% 50%;
  background-size: clamp(30rem, 62vw, 60rem) auto;
  /* THE ROSETTE SPINS ON ITSELF. Without this the element rotates about its own
     geometric centre while the rosette is PAINTED at 82% 50%, so the figure
     orbited that point and drifted under the body copy instead of turning in
     place. The origin has to match the background position. */
  transform-origin: 82% 50%;
  opacity: .5;
  -webkit-mask-image: radial-gradient(58% 68% at 82% 50%, #000 22%, transparent 78%);
  mask-image: radial-gradient(58% 68% at 82% 50%, #000 22%, transparent 78%);
}

@media (prefers-reduced-motion: no-preference) {
  /* One turn every four minutes. Slow enough that nobody catches it moving and
     fast enough that the page is never twice the same. */
  .engine { animation: engine-turn 240s linear infinite; }
}

@keyframes engine-turn {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@media (max-width: 60rem) {
  .engine {
    background-position: 50% 34%;
    background-size: 34rem auto;
    opacity: .3;
    animation: none;
    transform-origin: 50% 34%;
  }
}

/* ---- the seal in an engraved panel --------------------------------------- */

.charter-seal-panel {
  position: relative;
  display: grid;
  place-items: center;
  justify-self: start;
  isolation: isolate;
}

@media (min-width: 56rem) {
  .charter-seal-panel { justify-self: end; align-self: center; }
}

.charter-seal-panel::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: clamp(15rem, 34vw, 24rem);
  aspect-ratio: 1;
  background-image: url("/guilloche.svg");
  background-size: contain;
  background-repeat: no-repeat;
  opacity: .5;
  -webkit-mask-image: radial-gradient(closest-side, #000 62%, transparent 96%);
  mask-image: radial-gradient(closest-side, #000 62%, transparent 96%);
}

/* ===========================================================================
   20  THE ENGRAVED RULE, AND THE FEE AS A RECORD

   THE RULE is the border a banknote carries: six sinusoids of different
   frequency and phase drawn over one another, so the interference reads as
   woven line rather than as a row of curves. Every frequency is a whole number
   of cycles across the tile, which is what lets it repeat without a seam.

   It is used exactly twice, at the two edges a document actually has one: the
   top and bottom of the printed charter, and the head of the footer. A device
   like this is ruined by being everywhere; it works because it appears where a
   border belongs and nowhere else.
   =========================================================================== */

.band-paper { position: relative; }

.band-paper::after,
.site-footer::before {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 44px;
  pointer-events: none;
  background-image: url("/guilloche-rule.svg");
  background-repeat: repeat-x;
  background-size: auto 44px;
  background-position: center;
  opacity: .5;
}

.band-paper::after { top: 0; }

/* The paper sheet gets a border at both edges, the way a certificate does. */
.band-paper::before {
  /* already the paper tooth; the second edge rides on the section that follows */
}

.site-footer {
  position: relative;
  border-top: 1px solid var(--hairline-strong);
}

.site-footer::before { top: 0; opacity: .38; }

/* ---- the fee, as a record ------------------------------------------------ */

.fee-ledger { max-width: 62rem; }
.fee-actions { margin-top: 2.4rem; }

/* ===========================================================================
   21  ONE METAL

   The accent system gives every item of Council content a colour: cyan for one
   programme, violet for another, rose for a third, emerald for a fourth. It was
   a reasonable idea and it is the single largest thing still making this site
   look like two sites.

   The front page, the charter, the ledgers, the seal, the engraving and the
   mark are all navy and one metal. The programmes, the working groups, the
   publications and the events are a rainbow, and a reader moving between them
   is not reading a distinction, they are watching the house style change.

   COLOUR IS NOT HOW AN INSTITUTION DIFFERENTIATES. Five hues across five
   categories is a filing system nobody asked for, and no body that wants to be
   taken seriously runs one: the distinction is carried by the words, the
   number and the position, which this site already does everywhere else.

   THE MECHANISM STAYS, THE PALETTE COLLAPSES. Every data-accent value still
   resolves, so no page breaks and no markup changes; they all resolve to the
   Council's metal. Reinstating a hue later is five lines, and any component
   written against var(--a) will pick it up without being told.

   The sector tokens themselves are left defined and unused, because they are
   still the right colours for a chart, and a chart is where a fifth hue earns
   its place.
   =========================================================================== */

[data-accent] {
  --a: var(--gold);
  --a-lift: var(--gold-lift);
  --a-deep: var(--gold-deep);
  --a-wash: var(--gold-wash);
  --a-glow: var(--gold-glow);
}

/* ===========================================================================
   22  THE OLDER PAGES JOIN THE REST

   Programmes, working groups, publications and events were built before the
   ruled language existed and still carry the one it replaced: bordered panels
   with a gradient fill, a glowing rotated square for every bullet, and a
   chip grid of boxes. Alone each is fine. Beside a site that is now rules,
   hairlines and one metal, they read as a different publication.

   Nothing here changes a word or a class in those pages. The components they
   already use are restated in the Council's current language, which is what a
   shared vocabulary is for.
   =========================================================================== */

/* ---- the bullet ----------------------------------------------------------
   A rotated square with a glow behind it is a decoration standing in for a
   bullet. The Council's mark for an item in a list is a short rule, the same
   one that sits under every eyebrow and beside every standing note. */
.tick-list > li::before {
  top: .78em;
  width: 14px;
  height: 1px;
  border-radius: 0;
  background: var(--gold);
  box-shadow: none;
  transform: none;
}

.tick-list > li { padding-inline-start: 2.1rem; }

/* ---- the panels ----------------------------------------------------------
   Sheet, not card: a rule above, air around, and nothing drawn round the
   outside. The gradient and the border go; the structure stays exactly where
   it was. */
.program-panel,
.group-panel,
.pub-panel,
.event-panel {
  background: none;
  border: 0;
  border-top: 1px solid var(--hairline-strong);
  border-radius: 0;
  box-shadow: none;
  padding-inline: 0;
  padding-block: clamp(2rem, 1.4rem + 2vw, 3.2rem);
}

.program-panel::before,
.group-panel::before,
.pub-panel::before,
.event-panel::before { content: none; }

/* ---- the contents chips --------------------------------------------------
   Eight bordered boxes at the head of a page is a menu of buttons. The same
   eight as ruled rows is a table of contents, which is what it is. */
.program-toc { gap: 0; border-top: 1px solid var(--hairline-strong); }

.program-toc a {
  border: 0;
  border-bottom: 1px solid var(--hairline);
  border-radius: 0;
  padding: .95rem 1.6rem .95rem 0;
  background: none;
  transition: color var(--t-ui) var(--ease), padding-inline-start var(--t-ui) var(--ease);
}

.program-toc a:hover,
.program-toc a:focus-visible {
  background: none;
  border-color: var(--gold);
  color: var(--text);
  padding-inline-start: .4rem;
}

/* ===========================================================================
   23  SCROLL IS THE INTERACTION

   Everything on this site moved once, on load, and then stopped. A page that
   animates on arrival and is inert afterwards is a page that performed for you
   and then went back to being a document.

   These are SCROLL DRIVEN: the animation's timeline is the scroll position, so
   the page responds continuously to the reader rather than firing at them. No
   JavaScript, no observer, no rAF loop, and nothing to jank, because the whole
   thing runs off the compositor.

   WRAPPED IN @supports FOR A REASON THAT MATTERS. Without a scroll timeline an
   animation falls back to the DOCUMENT timeline, which means it plays
   immediately, all at once, on load: every heading on the page would wipe in
   over each other in the first second. Unsupported browsers must get NOTHING
   here, not a degraded version.
   =========================================================================== */

@supports (animation-timeline: scroll()) {

  /* ---- how far through the page you are -------------------------------
     A gold hairline along the foot of the header that fills as the document
     scrolls. It is the only element on the site that reports a fact about the
     reader rather than about the Council, and it costs one pseudo element. */
  #site-header::after {
    content: "";
    position: absolute;
    inset-inline: 0;
    bottom: -1px;
    height: 2px;
    z-index: 60;
    background: var(--gold);
    transform-origin: left center;
    transform: scaleX(0);
    animation: read-through linear both;
    animation-timeline: scroll(root block);
  }

  @keyframes read-through { to { transform: scaleX(1); } }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* ---- headings are struck, not faded -------------------------------
       A wipe from the leading edge, tied to the heading's own position in the
       viewport, so it is drawn AS the reader arrives at it rather than at a
       moment the page chose. */
    .section-title,
    .charter-statement,
    .is-invitation .display,
    #how .display,
    #carries .display,
    #membership-fee .display {
      /* THE RANGE ENDS AT `entry 100%`, NOT INSIDE `cover`, and this is a correctness fix rather
         than a taste one.

         `cover` measures how far the element has travelled across the whole viewport. An element
         near the END of the document can never finish that journey: the page runs out of scroll
         while it is still part way through, the animation freezes at that progress, and anything
         that started at opacity 0 STAYS at opacity 0. A sweep of governance.html found eight rows
         of the policy roster stranded invisible at the foot of the page, and a screenshot of a
         page you have not scrolled to the bottom of would never have shown it.

         `entry 100%` completes the moment the element is fully inside the viewport, which is true
         of the last row on any page by the time the reader reaches it. */
      animation: strike-in linear both;
      animation-timeline: view();
      animation-range: entry 8% entry 100%;
    }

    /* ---- the register fills in ----------------------------------------
       Every ruled row on the site, rising as it crosses in. A ledger of twenty
       four rows assembling under the reader is the single most institutional
       thing this page can do, and it is four declarations. */
    .ledger-row,
    .roster-index li,
    .index-row,
    .footer-col {
      animation: row-in linear both;
      animation-timeline: view();
      animation-range: entry 4% entry 100%;
    }

    /* ---- the engraving answers the scroll ------------------------------
       rotate and scale are their own properties now, not values inside
       transform, so the slow idle turn and the scroll response can run as two
       animations on one element without fighting over a single declaration. */
    /* AT DESKTOP WIDTHS ONLY. This block is the last in the file and therefore
       outranks the phone budget in section 19, which sets animation: none on
       .engine below 60rem. Without this guard the most expensive thing on the
       site - a 92KB rotating SVG - was running on exactly the devices least able
       to afford it, and the rule that said otherwise looked correct. */
    @media (min-width: 60.01rem) {
      .engine {
        animation: engine-turn 240s linear infinite, engine-recede linear both;
        animation-timeline: auto, scroll(root block);
        animation-range: normal, 0 100vh;
      }
    }
  }
}

@keyframes strike-in {
  from { clip-path: inset(0 100% 0 0); opacity: .25; }
  to   { clip-path: inset(0 0 0 0); opacity: 1; }
}

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

@keyframes engine-recede {
  from { scale: 1; opacity: .5; }
  to   { scale: 1.28; opacity: 0; }
}

/* The idle turn moves `rotate`, not `transform`, so engine-recede can own
   `scale` on the same element. */
@keyframes engine-turn {
  from { rotate: 0deg; }
  to   { rotate: 360deg; }
}

/* ===========================================================================
   24  THE SEAL PRESSES

   The one thing on this site a reader can touch and feel answer. A seal is an
   object that presses into a surface, so it presses: the mark steps back into
   the sheet and the engraved rosette behind it turns a few degrees, the way the
   die would if you leaned on it.

   It is the correct micro interaction for this site specifically, which is the
   test. A card that lifts on hover would say nothing about the Council.
   =========================================================================== */

.charter-seal,
.rest-seal {
  transition: transform 460ms var(--ease), opacity var(--t-ui) var(--ease);
  transform-origin: center;
}

.charter-seal-panel::before {
  transition: transform 900ms var(--ease), opacity 460ms var(--ease);
  transform-origin: center;
}

.charter-seal-panel:hover .charter-seal { transform: scale(.955); }
.charter-seal-panel:hover::before { transform: rotate(9deg); opacity: .72; }
.charter-seal-panel:active .charter-seal { transform: scale(.925); }

.rest-seal:hover { transform: scale(.96); opacity: 1; }

/* The line under the framework index, pointing at the page that says which of
   it is constituted. Small, quiet, and the reason the numbers above it can be
   believed. */
.index-note {
  margin: 1.1rem 0 0;
  font-family: var(--font-caps);
  font-size: .74rem;
  letter-spacing: .05em;
  text-transform: none;
}

.index-note a { color: var(--faint); }
.index-note a:hover { color: var(--gold-lift); }

/* ===========================================================================
   25  THE DECORATIONS ARE CONTAINED BY THEIR OWN BAND

   .aurora is inset: -20%, which is deliberate - a light has to be bigger than
   the thing it lights or its edges show. The consequence was not deliberate: in
   a 1280px viewport that element is 1826px wide and reaches 250px past the
   right edge of the page, and while body carries overflow-x: clip, the root
   element does not, so the document reported a scrollWidth of 1354 and the page
   scrolled sideways.

   It did NOT do this at 1440 or at 390, which is why two widths of sweeping
   never found it. It appeared between them.

   overflow-x: clip rather than hidden, deliberately: clip does not establish a
   scroll container, so position: sticky inside these sections - the mandate
   page's reading rail - keeps working. hidden would have broken it.
   =========================================================================== */

.band-deep,
.band-paper,
.is-invitation {
  overflow-x: clip;
}

/* ===========================================================================
   26  THE PROSE IS SET IN THE SERIF

   Everything the Council argues is a paragraph, and every paragraph was set in
   a face drawn for filling in forms. Public Sans is excellent at what it was
   made for and it keeps that work: buttons, form labels, navigation, the
   interface. The prose is now the serif, which is what the display face was
   already telling the reader to expect.

   Spectral has a smaller x-height than Public Sans, so this is not a swap: the
   size goes up and the leading comes down, or the same paragraph reads smaller
   and looser than it did before.
   =========================================================================== */

.lede,
.ledger-body,
.charter-body,
.standing p,
.notice-info p,
#how .panel p,
#carries .panel p,
.register-empty .ledger-body,
.mandate-tick-list,
.tick-list > li {
  font-family: var(--font-text);
  font-size: 1.0625rem;
  line-height: 1.58;
  max-width: var(--measure-body);
}

/* THE LEDE IS A DISPLAY PARAGRAPH, not slightly larger body copy. It was one
   pixel above the prose around it, which is not a step, it is a wobble. Full
   strength ink and tighter leading, because it is read once and quickly. */
.lede {
  font-size: clamp(1.14rem, 1.02rem + .55vw, 1.34rem);
  line-height: 1.5;
  max-width: var(--measure-lede);
  color: var(--text);
}

.hero-lede { max-width: var(--measure-lede); }

/* ---- real small caps ------------------------------------------------------
   Drawn small caps rather than an uppercased monospace. A drawn cap needs a
   fraction of the tracking a faked one does, and none of the text-transform. */
.eyebrow,
.record-text,
.index-title,
.footer-head,
.charter-sign,
.ledger-by,
.ledger-by-label {
  font-family: var(--font-caps);
  text-transform: none;
  letter-spacing: .055em;
  font-weight: 500;
}

.eyebrow { font-size: .85rem; color: var(--gold); }
.record-text { font-size: .82rem; }
.index-title { font-size: .78rem; }
.footer-head { font-size: .76rem; }
.charter-sign { font-size: .8rem; letter-spacing: .05em; }
.ledger-by { font-size: .78rem; letter-spacing: .04em; }

/* A step label sits UNDER a section label rather than beside it. */
#how .panel .eyebrow,
#carries .panel .eyebrow { font-size: .78rem; color: var(--faint); }

/* ---- the Council's figures are set, not printed ---------------------------
   The prestige numerals were terminal output, slashed zeros included. The
   display face has proper lining figures and they are what belongs under a
   serif heading. The ledger's own number keeps the mono, because there the
   fixed advance is the whole point. */
.index-n,
.hero-figure-n {
  font-family: var(--font-display);
  font-weight: 500;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums lining-nums;
}

.index-n { font-size: 1.6rem; }

/* ---- one italic, on the one sheet of paper --------------------------------
   There is no italic anywhere on this site, and the charter is the one place
   that earns one: a single sentence, set in italic on ivory, is the oldest
   typographic signal that a document is speaking in its own voice. */
/* 20ch, not the display measure. --measure-display is tuned for the hero, where
   the face is set at 98px and two words fill a line; the charter statement is
   half that size, and at 14ch it broke into four short lines that read as a
   poem rather than as an opening sentence. */
.charter-statement {
  font-style: italic;
  font-weight: 600;
  max-width: 20ch;
}

.charter-body {
  font-family: var(--font-text);
  font-size: 1.08rem;
  line-height: 1.58;
  max-width: 58ch;
}

/* The printed band keeps the dark band's greys, which are tuned for ivory on
   navy and are far too light for ink on paper. */
.band-paper { --soft: #2f3743; }

/* ---- the register's rule ends where its sentence ends ---------------------
   The ledger rule ran the full 1232px while the text stopped around 800: a
   ruled sheet whose rules are half again as long as anything written on them. */
.ledger { max-width: 62rem; }
.ledger-body { max-width: none; }

@media (min-width: 48rem) {
  .ledger-row { grid-template-columns: 3.5rem minmax(0, 17rem) minmax(0, 1fr); }
}

/* ---- the row name separates by size, not by ink --------------------------- */
.ledger-name {
  font-family: var(--font-display);
  font-size: 1.28rem;
  font-weight: 500;
  letter-spacing: -.005em;
  line-height: 1.26;
}

/* ---- tracking is a function of size ---------------------------------------
   One negative value across a 2.3x size range is too tight at the bottom of it
   and too loose at the top. */
.hero-display { letter-spacing: -.022em; }
.display { letter-spacing: -.018em; }
.section-title { letter-spacing: -.02em; }

@media (min-width: 62rem) {
  .hero-display { letter-spacing: -.045em; }
  .display { letter-spacing: -.036em; }
  .section-title { letter-spacing: -.03em; }
}

/* ---- the institution's name is not a footnote ----------------------------- */
.brand-sub {
  font-family: var(--font-caps);
  font-size: .72rem;
  letter-spacing: .06em;
  text-transform: none;
  color: var(--soft);
}

.brand-name { font-weight: 600; letter-spacing: .04em; }

/* The institution's own name was hidden entirely below 26rem. On the smallest
   phone the site then said "GDTC" and nothing else, to a reader who has never
   heard of it. It stays, one step smaller. */
@media (max-width: 26rem) {
  .brand-sub { display: block; font-size: .62rem; letter-spacing: .04em; }
}

/* ===========================================================================
   27  THE SHEET IS BORDERED ON BOTH EDGES, AND THE SEAL IS STRUCK

   A certificate is bordered top and bottom. This one had an engraved wave at the
   head and nothing at the foot, which reads as a band that happens to begin
   rather than as a document that has been laid on the page.

   And the seal was PRINTED on the paper rather than struck into it. A struck
   seal has relief: the sheet is pressed, so the upper edge of the impression
   catches the light and the lower edge falls into shadow. Two arcs and a fill a
   half step darker than the paper, which is the whole of what a deboss is.
   =========================================================================== */

.charter-edge {
  position: absolute;
  inset-inline: 0;
  bottom: 0;
  height: 44px;
  pointer-events: none;
  background-image: url("/guilloche-rule.svg");
  background-repeat: repeat-x;
  background-size: auto 44px;
  /* Mirrored, so the two borders face each other rather than running the same
     way, which is how a plate is actually laid out. */
  transform: scaleY(-1);
  /* .5 is tuned for the navy ground. On ivory the same value nearly disappears. */
  opacity: .8;
}

/* The head of the sheet gets the same correction. */
.band-paper::after { opacity: .8; }

/* ---- the seal, struck rather than printed --------------------------------- */

.charter-seal-panel::before {
  opacity: .8;
  -webkit-mask-image: radial-gradient(closest-side, #000 48%, transparent 88%);
  mask-image: radial-gradient(closest-side, #000 48%, transparent 88%);
}

/* The impression itself: a disc a half step darker than the sheet, with a light
   arc along its upper edge and a dark one along its lower. Light from the upper
   left, the same direction everything else on this site is lit from. */
.charter-seal-panel::after {
  content: "";
  position: absolute;
  z-index: -1;
  width: clamp(7.6rem, 17vw, 11.4rem);
  aspect-ratio: 1;
  border-radius: 50%;
  background: #ece8dd;
  box-shadow:
    inset 0 2px 3px -1px rgba(255,255,255,.95),
    inset 0 -2px 3px -1px rgba(20,24,28,.16),
    0 1px 0 rgba(255,255,255,.7);
}

.charter-seal { position: relative; z-index: 1; }

/* ---- z3-light.css ---- */
/* ---------------------------------------------------------------------------
   LIGHT.

   Everything on this site is drawn on one plane. The bands change colour, they
   change texture, and they change ground, but nothing sits ON anything: the
   ivory charter REPLACES a slice of the navy rather than lying on it, joined by
   a hard butt edge and a dark hairline, which is the join of a hole cut in a
   sheet and not of a sheet laid on a desk.

   A cast shadow is not an effect. It is a fact about where a thing is, and it
   is the oldest depth cue there is. Six declarations, no new hue, no motion,
   nothing to repaint, on the one join every reader crosses on the front page.

   The three tokens live in styles.css so that this shadow, the masthead's and
   the button's all agree about where the light is standing, instead of being
   three hand picked rgba values in three files that drift apart in a year.
   --------------------------------------------------------------------------- */

/* ---- 1. the sheet is laid on the page ------------------------------------
   z-index 2 lifts it over its band-deep siblings; .band-paper already carries
   position: relative and isolation: isolate, so no markup changes.

   The cast is written as a literal rather than as var(--shade-deep), and that
   is deliberate: the warm overrides declared on this same rule would resolve
   against the element's own box-shadow and turn the cast brown. The shadow
   falls on navy, so it stays cool. The tokens below it are for what the band
   CONTAINS. */
.band-paper {
  z-index: 2;
  border-block: 0;
  border-top: 1px solid rgba(255,252,244,.55);
  border-bottom: 1px solid rgba(6,10,18,.55);
  box-shadow:
    0 -34px 64px -26px rgba(2,6,22,.82),
    0  34px 64px -26px rgba(2,6,22,.82);

  /* Paper under a warm light throws a warm grey, so everything inside the sheet
     shades warm while the sheet's own cast stays cool. */
  --shade: rgba(48,38,20,.20);
  --shade-deep: rgba(48,38,20,.30);
  --sheen: rgba(255,255,255,.85);
}

/* ---- 2. the masthead casts onto the page ---------------------------------- */
.site-header { box-shadow: 0 1px 0 var(--sheen), 0 20px 34px -26px rgba(2,6,20,.95); }
.seat-bar { box-shadow: 0 14px 26px -22px rgba(2,6,20,.9); }

/* ---- 3. the metal is a plate that presses --------------------------------
   The gold action had a white specular band wiping across it on hover, which is
   the shine sweep the professionalism pass believed it had removed: that pass
   deleted the background gradient and never touched the pseudo element under
   it. Gone.

   What replaces it is not a second effect. A struck plate has a lit top edge, a
   dark bottom edge and a shadow beneath it, and when you press it the three
   invert: the lit edge goes under, the shadow closes up, and the plate moves a
   single pixel into the page. scale and translate rather than transform, so
   nothing fights the site's other transforms for one declaration. */
.btn {
  transition:
    scale 420ms var(--ease), translate 420ms 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 {
  scale: .978;
  translate: 0 1px;
  /* A press is fast and its release is slow. Equal timings on both read as a
     wobble rather than as weight. */
  transition-duration: 90ms;
  transition-timing-function: cubic-bezier(.4, 0, 1, 1);
}

.btn-primary {
  box-shadow:
    inset 0  1px 0 rgba(255,248,222,.50),
    inset 0 -1px 0 rgba(58,42,4,.45),
    0 1px 0 rgba(2,6,16,.6),
    0 12px 22px -14px var(--shade-deep);
}

.btn-primary:hover {
  box-shadow:
    inset 0  1px 0 rgba(255,248,222,.60),
    inset 0 -1px 0 rgba(58,42,4,.45),
    0 1px 0 rgba(2,6,16,.6),
    0 16px 28px -14px var(--shade-deep);
}

/* Pressed: the relief inverts and the cast closes up. */
.btn-primary:active {
  box-shadow:
    inset 0 2px 4px rgba(58,42,4,.45),
    inset 0 -1px 0 rgba(255,248,222,.25);
}

@media (prefers-reduced-motion: reduce) {
  .btn { transition: box-shadow var(--t-ui) linear, background-color var(--t-ui) linear; }
  .btn:active { scale: 1; translate: 0 0; }
}

/* ---------------------------------------------------------------------------
   4  THE ATTESTATION

   /verify is the only page on this site a stranger is sent to. The member's
   counterparty opens it, or their lawyer, or their bank. It is the page the
   membership is actually for, and it was a dark panel with a status line.

   It is a printed sheet now, and the seal is struck on it. The refusal is the
   same sheet with the die never coming down: the well holds its height, the
   engraved rosette is there, and the impression is empty. No red, no cross, no
   icon, ever. An unsealed instrument is a refusal that needs no vocabulary.
   --------------------------------------------------------------------------- */

.door-panel.band-paper {
  position: relative;
  /* 3.5rem minimum is load bearing: .band-paper::after drops a 44px engraved
     rule at top: 0, and less than this puts it through the Council's own name. */
  padding-block: clamp(3.5rem, 2rem + 4vw, 5.5rem);
  padding-inline: clamp(1.6rem, 4vw, 3rem);
}

.door-panel.band-paper .verify-verdict {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 600;
}

/* The facts become ruled entries on the sheet rather than tinted boxes. The
   white lip under each rule is the one place a blind impression is correct:
   a dark line with a light one beneath it is what a rule pressed into paper
   actually looks like. */
.door-panel.band-paper .verify-facts { background: none; border-radius: 0; }

.door-panel.band-paper .verify-facts > div {
  background: none;
  border-radius: 0;
  padding-inline: 0;
  border-bottom: 1px solid var(--hairline);
  box-shadow: 0 1px 0 rgba(255,255,255,.9);
}

.attest-seal-panel {
  position: relative;
  display: grid;
  place-items: center;
  margin-top: 2.8rem;
  isolation: isolate;
  /* THE WELL KEEPS ITS HEIGHT WHETHER OR NOT THE SEAL LANDS. This one
     declaration is the entire refusal. */
  min-height: clamp(6rem, 22vw, 8.5rem);
}

.attest-seal-panel::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: clamp(11rem, 46vw, 15rem);
  aspect-ratio: 1;
  background: url("/guilloche.svg") center / contain no-repeat;
  opacity: .5;
  -webkit-mask-image: radial-gradient(closest-side, #000 48%, transparent 88%);
  mask-image: radial-gradient(closest-side, #000 48%, transparent 88%);
}

/* The sheet's labels join the small caps the rest of the printed matter uses.
   An uppercased monospace beside a drawn small cap on the same sheet is the one
   place the difference between them is unmissable. */
.door-panel.band-paper .rite-label,
.door-panel.band-paper .verify-facts dt,
.door-panel.band-paper .figure-label {
  font-family: var(--font-caps);
  text-transform: none;
  letter-spacing: .05em;
  font-size: .8rem;
  font-weight: 500;
}

.attest-seal { width: clamp(6rem, 22vw, 8.5rem); height: auto; }

/* ==== end of the merged part files ==== */

/* ===========================================================================
   09  THE PHONE
   Written after the merged block on purpose: tools/merge-css.js replaces only
   what sits between its markers, so anything here survives a re-merge.

   MEASURED, NOT GUESSED. At a real 390px viewport the body runs 16px on a 26px
   line and the headings 34px, which read well. What did not were the two mono
   faces: an eyebrow at 11px with .16em of tracking, and metadata at 12px, both
   sized for a desktop where the reader is further from a bigger screen. A
   millimetre of glass is not the same reading distance.
   =========================================================================== */

@media (max-width: 47.99rem) {
  .eyebrow { font-size: 12px; letter-spacing: .13em; }

  /* THE CONTENTS STRIP WRAPS INSTEAD OF SCROLLING. It is a row that scrolls
     inside itself, which works with a mouse over a visible scrollbar and reads
     on a phone as a heading cut off mid-word: "03 OBJI" against the right edge,
     with nothing to say there is more. Six items on two or three lines cost a
     few pixels and say everything they have to say. */
  .dash-nav { flex-wrap: wrap; overflow-x: visible; }
  .dash-tab { padding-inline: .7rem; }

  .mono-meta { font-size: 13px; line-height: 1.6; }

  /* The tap target was already var(--tap) tall; it was only the label that was
     small, and a primary action a thumb is aiming at should read as one. */
  .btn { font-size: 14px; }
  .btn-lg { font-size: 15px; }
}
