/* ══════════════════════════════════════════════════════════════════════════
   CAPITAL CULTURES · COMPONENTS
   Every block on the site lives inside a full-bleed ink band.
   No cards. No radius. No shadow (one exception: the cursor card, which is
   an overlay and not a surface). Separation is colour.
   ══════════════════════════════════════════════════════════════════════════ */

/* The form styles live in assets/css/forms.css (owner: W5, with lib/forms.mjs
   and api/). The document head links it beside this file — see lib/head.mjs —
   so nothing here reaches for it. */


/* ══ 1. THE BAND — the one repeated primitive ═════════════════════════════
   The ground is a real background on the element, so a contrast checker can
   see it and a CSS failure can never leave ink type on the ink page.       */
/* overflow:clip clips exactly as hidden did — the seam wedges and the flood
   still cannot escape the band — without making the band a scroll container.
   A scroll container is what silently disabled position:sticky inside it, so
   a frame beside a two-thousand-pixel form sat at the top and let the column
   die under it. `hidden` stays first for the browsers that predate clip. */
.band{position:relative;isolation:isolate;overflow:hidden;overflow:clip;
  background:var(--ground);color:var(--type)}
.band > .wrap{position:relative;z-index:2}
/* rhythm between blocks stacked inside one band — set once, here, so no
   content module ever needs a margin of its own */
.band > .wrap > * + *{margin-top:clamp(30px,4vw,56px)}
.band--pad{padding-block:var(--sec-y)}
.band--tight{padding-block:var(--sec-y-tight)}
.band--flush{padding-block:0}

/* the flood: an ink curtain that drops away, so nothing is read through it */
html.js .band::after{content:"";position:absolute;inset:0;z-index:var(--z-flood);
  pointer-events:none;background:var(--ink);clip-path:inset(0);
  transition:clip-path var(--t-flood) var(--snap)}
html.js .band.in::after{clip-path:inset(100% 0 0 0)}
/* A band we arrived INSIDE — an anchor jump, a restored scroll position, End —
   never «entered», so its curtain would sit over the reader for 460ms of solid
   ink. motion.js marks those and the curtain is simply already up. */
html.js .band.in-now::after{transition:none}
html:not(.js) .band::after{display:none}

/* ── the ink table. Type colour is measured, never chosen by eye.
      turmeric 10.4:1 · matcha 6.5:1 · saffron 6.5:1  → carry ink
      indigo   7.0:1  · sumac  6.3:1                  → carry paper
      chilli   4.0:1 on paper → carries paper, and the band forces short,
      heavy copy so every string clears the WCAG large-text bar.           */
/* ── THE QUIET STEP ─────────────────────────────────────────────────────
   Small type steps down by blending toward its own ground, never by opacity.
   Alpha multiplies through every ancestor that carries one, so two stacked
   dims (a dimmed row holding a dimmed index, a .req inside a dimmed label)
   land far under the WCAG floor while each rule looks innocent on its own.
   82 % toward the ground measures 4.6:1 on sumac — the tightest ground that
   keeps a quiet step — and better on every other ink. Chilli has no headroom
   at all (4.01:1 at full strength), so a chilli band has no quiet step.
   Declared on .band--<ink> so it resolves against that element's own ground,
   which also covers the curtain strips, and restated on every piece of
   chrome that paints its own ink ground.                                   */
.band--turmeric,.band--chilli,.band--sumac,.band--matcha,.band--saffron,
.band--indigo,.band--ink,.band--paper,
.mast,.foot,.parade,.curtain,.callout,.imgband figcaption,.cursor-shot{
  --type-2:color-mix(in srgb,var(--type) 82%,var(--ground))}

.band--turmeric{--ground:var(--turmeric);--type:var(--ink)}
.band--matcha  {--ground:var(--matcha);  --type:var(--ink)}
.band--saffron {--ground:var(--saffron); --type:var(--ink)}
.band--indigo  {--ground:var(--indigo);  --type:var(--paper)}
.band--sumac   {--ground:var(--sumac);   --type:var(--paper)}
.band--chilli  {--ground:var(--chilli);  --type:var(--paper)}
.band--ink     {--ground:var(--ink);     --type:var(--paper)}
.band--paper   {--ground:var(--paper);   --type:var(--ink)}

/* ══ 1b. THE DOSAGE — quiet is the ground, spice is the punctuation ═══════
   Law of 28.08.2026. Two bands are QUIET and they carry most of the site:
     · quiet ink   — ink ground, paper type
     · quiet paper — paper ground, ink type
   Both keep everything else the loud bands have: the same overprinted seams,
   the same rhythm, the same components. What they drop is the flood of colour,
   and what they gain is --accent: the section's spice, used for rules, marks,
   numbers and the one button, never for a wall.

   --accent is ground-aware because a spice reads differently on the two quiet
   grounds. Measured against #17120F / #FFF7EA (sRGB, WCAG 2.1):
     on ink   — turmeric 10.4:1 · matcha 6.5 · saffron 6.5 · chilli-lit 5.2 ·
                indigo-lit 4.9 · sumac-lit 4.7   → every one clears 4.5, which
                is why the ink ground reads --section-lit and not --section-ink
     on paper — chilli 4.0 · sumac 6.3 · indigo 7.0, but turmeric 1.7,
                matcha 2.7 and saffron 2.7 fail even 3:1
   So the rule the whole stylesheet obeys: on the ink ground a spice may carry
   large type; on the paper ground a spice paints fills, rules and marks only,
   and type standing on a spice fill takes --accent-type.                   */
.band--ink   {--accent:var(--section-lit);--accent-type:var(--section-lit-type)}
.band--paper {--accent:var(--section-ink);--accent-type:var(--section-type)}
/* A saturated band IS the accent. Nothing inside it takes a second colour. */
.band--turmeric,.band--chilli,.band--sumac,.band--matcha,.band--saffron,.band--indigo{
  --accent:var(--type);--accent-type:var(--ground)}

/* the eyebrow wears the section's mark, so the register line is where the
   colour enters a quiet band first */
.band--ink .eyebrow::before,.band--paper .eyebrow::before{
  content:"";display:inline-block;width:clamp(22px,2.4vw,34px);height:var(--rule-thick);
  background:var(--accent);margin-right:11px;vertical-align:.3em}

/* ONE action in the field of view carries colour. Anton has no bold, so a
   filled label sits at 24px and up, where the tightest pairing (paper on
   chilli, 4.0:1) is legally large text. */
.band--ink .btn--solid,.band--paper .btn--solid{
  background:var(--accent);color:var(--accent-type);font-size:clamp(24px,2.2vw,30px)}
.band--ink .btn--solid:hover,.band--paper .btn--solid:hover{
  background:var(--type);color:var(--ground)}
/* a second solid button in the same band steps back to a ghost */
.band--ink .btn--solid ~ .btn--solid,.band--paper .btn--solid ~ .btn--solid{
  background:transparent;color:var(--type);box-shadow:inset 0 0 0 var(--rule-thick) var(--type)}

/* the enormous number takes the spice — ink ground only, see the table above */
.band--ink .big{color:var(--accent)}

/* rules that introduce numbers, registers and lists are spice rules. They are
   not type, so every spice is legal on both grounds. */
.band--ink .fact,.band--paper .fact,
.band--ink .table-wrap,.band--paper .table-wrap,
.band--ink .faq,.band--paper .faq,
.band--ink .links,.band--paper .links,
.band--ink .timeline,.band--paper .timeline,
.band--ink .passport,.band--paper .passport{border-top-color:var(--accent)}
.band--ink .passport,.band--paper .passport{border-color:var(--accent)}
/* the marker on the line that is happening now */
.band--ink .timeline li[data-state="now"],.band--paper .timeline li[data-state="now"]{
  box-shadow:inset var(--rule-thick) 0 0 var(--accent)}

/* Every section head on a quiet band gets the section's mark above it. It is
   the smallest dose that still keeps the colour in the reader's eye all the
   way down a page whose grounds have gone silent, and it repeats on a rhythm
   the reader can predict — one per section of the page, never two in a row. */
.band--ink .head,.band--paper .head{position:relative;padding-top:clamp(20px,2.2vw,28px)}
.band--ink .head::before,.band--paper .head::before{content:"";position:absolute;
  left:0;top:0;width:clamp(44px,5vw,76px);height:var(--rule-thick);background:var(--accent)}

/* accentRule() — a spice rule under a block of quiet, with the register label
   hanging off it. The label stays in --type-2: at 11px a spice would be
   arguing with the contrast table above. */
.accent-rule{position:relative;margin-top:clamp(28px,3.4vw,48px);padding-top:15px;
  border-top:var(--rule-thick) solid var(--accent)}
.accent-rule::before{content:"";position:absolute;left:0;
  top:calc(-1 * var(--rule-thick));height:9px;width:clamp(56px,8vw,128px);
  background:var(--accent)}
.accent-rule .lb{font-family:var(--face-mono);font-size:var(--fs-mono);font-weight:600;
  letter-spacing:var(--ls-mono);text-transform:uppercase;color:var(--type-2)}

/* the closing ask is a quiet band, so it gets a spice rule across the top to
   tell a scrolling eye that the page has arrived somewhere */
.cta-band{border-top:var(--rule-thick) solid var(--accent)}
/* Chilli measures 4.01:1 against paper: enough for WCAG large text, short of
   the 4.5:1 body-copy bar. So a chilli band is a SHOUT band — display type and
   short heavy lines — and every string on it is forced to 19px/700, which is
   the large-text threshold. Long copy goes on ink, turmeric, matcha, saffron,
   indigo or sumac. */
.band--chilli .body,.band--chilli .lede,.band--chilli .mono,.band--chilli .eyebrow,
.band--chilli .small,.band--chilli .row-t,.band--chilli .note,.band--chilli .help,
.band--chilli .src,.band--chilli p,.band--chilli li,.band--chilli td,.band--chilli th,
.band--chilli label,.band--chilli figcaption,.band--chilli .when,.band--chilli .k{
  font-size:clamp(19px,1.6vw,22px);font-weight:700;line-height:1.45}

/* AODA fix, measured: dimming defeats the large-text floor this band relies on.
   Paper at .72 over chilli measures 2.69:1 and fails even the 3:1 large-text
   bar, so every string on a chilli band stays at full strength. */
/* .quote figcaption below carries its own size and dim, and being the later
   rule it beat the shout-band floor above — measured 11px at .85 opacity over
   chilli, ~2.7:1. Restated here so a quote source on a chilli band keeps the
   large-text floor it depends on. */
.band--chilli .quote figcaption{font-size:clamp(19px,1.6vw,22px);
  font-weight:700;line-height:1.45;opacity:1}

.band--chilli{--type-2:var(--type)}

/* A button label is Anton 400 at 17.3px, which is neither body-size legal
   (4.01 < 4.5) nor large text (17.3 < 18.66 and Anton has no 700). On a chilli
   band it goes to 24px, where 4.01 clears the 3:1 large-text bar. */
.band--chilli .btn{font-size:clamp(24px,2.2vw,30px)}

/* table.data's own rules out-specify the shout floor above, so a data table on
   a chilli band kept 11px thead cells and 600-weight row headers at 4.01:1.
   Restated at matching specificity. An operational register still belongs on
   ink, indigo, sumac, turmeric, matcha or saffron. */
.band--chilli table.data caption,.band--chilli table.data thead th,
.band--chilli table.data tbody th,.band--chilli table.data td{
  font-size:clamp(19px,1.6vw,22px);font-weight:700;line-height:1.45;color:var(--type)}

/* `.row .row-t` is two classes and it is declared later in this file, so it
   out-cascaded the shout-band floor above and left 15.5px paper on chilli at
   4.01:1. Restated at three classes. Under the dosage law any block can land
   on the section's one loud band, so the floor has to hold for all of them. */
.band--chilli .row .row-t,.band--chilli .rows .row-t{
  font-size:clamp(19px,1.6vw,22px);font-weight:700;line-height:1.45;color:var(--type)}

.band--chilli .hero-note,.band--chilli .mono,.band--chilli .note,
.band--chilli .row .n,.band--chilli .row .row-t,.band--chilli .src,
.band--chilli .help,.band--chilli .timeline .note,.band--chilli .when,
.band--chilli .prose,.band--chilli .form .note{opacity:1}

/* ══ 2. THE SEAM — the signature. Two inks overprint and make a third. ═══ */
/* margin-block:-1px closes the sub-pixel hairline that fractional band heights
   leave between a band and its seam — the gap shows the ink page through. */
.seam{position:relative;height:clamp(56px,8vw,116px);background:var(--from);
  overflow:hidden;isolation:isolate;margin-block:-1px}
/* A joint between two quiet bands runs shorter. At full height the diagonal
   became the loudest shape on a page whose grounds had gone quiet, which is
   the dosage mistake again in a different currency. A joint that touches a
   saturated band keeps the full wedge, because there it is separating two
   colours and has work to do. */
.seam--quiet{height:clamp(34px,4.4vw,66px)}
.seam::before{content:"";position:absolute;inset:0;background:var(--to);
  clip-path:polygon(0 100%,100% 0,100% 100%)}
/* The overprinted wedge. It used to be the band's own ink multiplied over the
   next one, which worked while every band was saturated. On a quiet page ink
   over ink is invisible, so the wedge is now the SECTION's spice: it multiplies
   to the spice over the paper half of the joint and to a near-black over the
   ink half, which is what an overprint actually does and keeps the signature
   on every seam of a quiet page. */
.seam::after{content:"";position:absolute;inset:0;
  background:var(--spice,var(--section-ink));
  clip-path:polygon(0 100%,100% 0,100% 34%,0 66%);mix-blend-mode:multiply}
/* ── the achromatic joint ──────────────────────────────────────────────────
   About has no spice, so its wedge multiplied ink over ink and came out as a
   black triangle on the paper half and nothing at all on the ink half: the
   signature of the site simply did not run on thirteen of its pages. The
   achromatic accent pair is paper on ink and ink on paper, and difference is
   exactly that — the wedge comes up light where the joint is dark and dark
   where it is light, on one flat colour each side.                        */
.sec--about .seam::after{background:var(--paper);mix-blend-mode:difference;
  clip-path:polygon(0 100%,100% 0,100% 22%,0 78%)}
.sec--about .seam--flip::after{clip-path:polygon(0 0,100% 100%,100% 78%,0 22%)}

.seam--flip::before{clip-path:polygon(0 0,100% 100%,0 100%)}
.seam--flip::after{clip-path:polygon(0 0,100% 100%,100% 66%,0 34%)}

/* ══ 3. MASTHEAD ═════════════════════════════════════════════════════════ */
.mast{position:sticky;top:0;z-index:var(--z-mast);
  --ground:var(--ink);--type:var(--paper);background:var(--ground);color:var(--type);
  transition:background var(--t-micro)}
.mast-in{display:flex;align-items:center;gap:clamp(10px,1.4vw,20px);
  padding-block:clamp(10px,1.4vw,16px)}
.mark{display:flex;align-items:center;gap:10px;font-family:var(--face-display);
  font-size:clamp(16px,1.6vw,21px);text-transform:uppercase;letter-spacing:.02em;
  line-height:1;white-space:nowrap;text-decoration:none;flex:0 0 auto}
.mark svg{width:clamp(32px,2.8vw,42px);height:auto;flex:0 0 auto}
.mark:hover span{color:var(--section-lit)}

.nav{display:none;margin-left:auto}
.nav ul{display:flex;align-items:center;gap:clamp(10px,1.5vw,26px);
  list-style:none;margin:0;padding:0}
.nav a{position:relative;display:block;text-decoration:none;padding:6px 0;
  font-family:var(--face-display);text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(13px,1.05vw,16px);line-height:1;
  transition:color var(--t-micro)}
/* each section owns an ink; the hover rule paints it */
.nav a::after{content:"";position:absolute;left:0;right:0;bottom:0;height:var(--rule-thick);
  background:var(--sec-ink,var(--section-lit));transform:scaleX(0);transform-origin:0 50%;
  transition:transform var(--t-micro) var(--snap)}
.nav a:hover::after,.nav a:focus-visible::after,.nav a[aria-current="true"]::after{transform:none}
.nav a[aria-current="true"]{color:var(--paper)}
@media(min-width:1080px){.nav{display:block}}

.util{display:flex;align-items:center;gap:8px;margin-left:auto}
@media(min-width:1080px){.util{margin-left:clamp(14px,2vw,32px)}}
.util-btn{display:inline-flex;align-items:center;gap:7px;background:transparent;
  color:inherit;border:var(--rule) solid currentColor;padding:7px 10px;cursor:pointer;
  font-family:var(--face-mono);font-size:10px;font-weight:600;letter-spacing:var(--ls-mono);
  text-transform:uppercase;text-decoration:none;line-height:1.2;
  transition:background var(--t-micro),color var(--t-micro)}
.util-btn .soon{color:var(--type-2);font-size:9px}
.util-btn:hover{background:var(--paper);color:var(--ink)}
.util-btn[data-state="soon"]{color:var(--type-2)}
.util-btn[aria-pressed="true"]{background:var(--section-lit);color:var(--section-lit-type);
  border-color:var(--section-lit)}
@media(max-width:640px){.util-btn--hide-s{display:none}}

/* the section trigger: mono, squared, never a hamburger glyph. It carries the
   spice of the room it is standing in — the masthead wears sec--<slug> — so
   the first screen of a Festival page never opens on Join's turmeric. */
.nav-trigger{display:inline-flex;align-items:center;gap:9px;
  background:var(--section-lit);color:var(--section-lit-type);border:0;cursor:pointer;padding:8px 12px;
  font-family:var(--face-mono);font-size:10px;font-weight:600;letter-spacing:var(--ls-mono);
  text-transform:uppercase;line-height:1.2;
  transition:background var(--t-micro)}
.nav-trigger:hover{background:var(--ink);color:var(--paper);
  box-shadow:inset 0 0 0 var(--rule-thick) var(--section-lit)}
.nav-trigger .bars{display:grid;gap:2px;width:14px}
.nav-trigger .bars i{display:block;height:2px;background:currentColor}
.nav-trigger .bars i:nth-child(1){background:var(--chilli)}
.nav-trigger .bars i:nth-child(2){background:var(--matcha)}
.nav-trigger .bars i:nth-child(3){background:var(--indigo)}
@media(min-width:1080px){.nav-trigger{display:none}}

/* ══ 4. THE CURTAIN — mobile navigation as a stack of ink strips ═════════ */
.curtain{position:fixed;inset:0;z-index:var(--z-curtain);
  --ground:var(--ink);--type:var(--paper);background:var(--ground);
  display:grid;grid-template-rows:auto 1fr auto;
  visibility:hidden;pointer-events:none}
.curtain.open{visibility:visible;pointer-events:auto}
.curtain-top{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:clamp(10px,1.4vw,16px) var(--gut);border-bottom:var(--rule) solid var(--paper)}
.curtain-close{background:var(--paper);color:var(--ink);border:0;cursor:pointer;
  padding:8px 12px;font-family:var(--face-mono);font-size:10px;font-weight:600;
  letter-spacing:var(--ls-mono);text-transform:uppercase}
.curtain-close:hover{background:var(--section-lit);color:var(--section-lit-type)}
.strips{display:flex;flex-direction:column;overflow-y:auto;min-height:0}
.strip{position:relative;display:flex;align-items:center;justify-content:space-between;
  gap:14px;flex:1 1 auto;min-height:clamp(56px,9vh,84px);
  padding:10px var(--gut);text-decoration:none;
  background:var(--ground);color:var(--type);
  clip-path:inset(0 100% 0 0);
  transition:clip-path 320ms var(--snap),padding-left var(--t-micro) var(--snap)}
.curtain.open .strip{clip-path:inset(0)}
.strip:hover,.strip:focus-visible{padding-left:calc(var(--gut) + 12px)}
.strip b{font-family:var(--face-display);font-weight:400;text-transform:uppercase;
  letter-spacing:var(--ls-display);font-size:clamp(28px,7.4vw,46px);line-height:.9}
.strip .mono{color:var(--type-2);font-size:24px;line-height:1}
.strip:hover .mono,.strip:focus-visible .mono{color:var(--type)}
.curtain-foot{padding:14px var(--gut) calc(14px + env(safe-area-inset-bottom));
  border-top:var(--rule) solid var(--paper);display:flex;flex-wrap:wrap;gap:8px;align-items:center}
html.curtain-open{overflow:hidden}

/* ══ 5. PAGE HERO ════════════════════════════════════════════════════════ */
/* ── the hero, and the one thing that changes with depth ──
   A section keeps its ink on every page inside it, so depth cannot be said in
   colour. It is said in area: the deeper the page, the less of the room is
   painted, and the smaller the shout at the top of it. */
.hero{padding-block:clamp(52px,7vw,104px) clamp(44px,6vw,88px)}
.hero--l1 .hero{padding-block:clamp(64px,8.4vw,126px) clamp(54px,7.2vw,106px)}
.hero--l3 .hero{padding-block:clamp(38px,4.6vw,68px) clamp(32px,4vw,58px)}
.hero--l3 h1{font-size:clamp(34px,4.9vw,74px)}
.hero--l3 .lede{font-size:var(--fs-body)}
.hero .eyebrow{margin-bottom:clamp(12px,1.6vw,20px)}
.hero h1{max-width:17ch}
.hero .lede{margin-top:clamp(16px,2vw,26px);max-width:56ch}
.hero-note{margin-top:clamp(16px,2vw,24px);color:var(--type-2)}
.hero-grid{display:grid;gap:var(--gap);align-items:end}
@media(min-width:1000px){.hero-grid{grid-template-columns:7fr 5fr}}

/* ══ 6. ACTIONS ══════════════════════════════════════════════════════════ */
.actions{display:flex;flex-wrap:wrap;gap:12px;margin-top:clamp(18px,2.2vw,28px)}
.btn{display:inline-flex;align-items:center;gap:12px;text-decoration:none;cursor:pointer;
  max-width:100%;overflow-wrap:anywhere;
  font-family:var(--face-display);text-transform:uppercase;letter-spacing:.01em;
  font-size:clamp(15px,1.35vw,20px);line-height:1;border:0;
  padding:14px 22px;
  transition:transform var(--t-micro) var(--snap),background var(--t-micro),color var(--t-micro)}
.btn--solid{background:var(--type);color:var(--ground)}
/* Hover is an ink stamp rather than a spice: a saturated band already IS the
   colour, and turmeric landing on a chilli hero put a second room's ink in the
   field of view. 17.5:1 on every ground. Quiet bands override this above. */
.btn--solid:hover{background:var(--ink);color:var(--paper);transform:translate(-3px,-3px)}
.band--turmeric .btn--solid:hover,.band--ink .btn--solid:hover{background:var(--paper);color:var(--ink)}
.btn--ghost{background:transparent;color:var(--type);
  box-shadow:inset 0 0 0 var(--rule-thick) currentColor}
.btn--ghost:hover{background:var(--type);color:var(--ground);transform:translate(-3px,-3px)}
.btn:active{transform:none}
.btn[aria-disabled="true"],.btn:disabled{opacity:.6;cursor:not-allowed;transform:none}

/* inline text link inside a band */
.link{text-decoration:none;border-bottom:var(--rule) solid currentColor;
  transition:background var(--t-micro),color var(--t-micro)}
.link:hover{background:var(--type);color:var(--ground)}

/* ══ 7. SECTION HEAD ═════════════════════════════════════════════════════ */
.head .mono,.hero-note{max-width:64ch}
.head{display:grid;gap:clamp(16px,2.2vw,32px)}
@media(min-width:900px){.head{grid-template-columns:6fr 6fr;gap:var(--gap);align-items:end}}
/* wide — the title takes the measure and the reading column sits under it.
   A three-hundred-character dek in six columns is a paragraph in a gutter. */
.head--wide{grid-template-columns:minmax(0,1fr)}
@media(min-width:900px){
  .head--wide{grid-template-columns:minmax(0,1fr);align-items:start}
  .head--wide > div{max-width:64ch}
}
/* index — the register line stands in the narrow column and the title takes
   the nine beside it. Used where a head is a title and a mono line. */
@media(min-width:900px){
  .head--index{grid-template-columns:3fr 9fr;align-items:start}
  .head--index > div{padding-top:.5em}
}
.eyebrow{font-family:var(--face-mono);font-size:var(--fs-mono);font-weight:600;
  letter-spacing:var(--ls-mono);text-transform:uppercase;line-height:1.5;color:var(--type-2)}

/* ══ 8. RULED ROWS — index · name · text, full width ═════════════════════ */
/* The signature list runs long, and a page whose ground has gone quiet can
   spend four screens on it. The law puts colour on exactly this: rules and
   numbers in the operational register. So the list opens on a spice rule, and
   on the INK ground — where a spice clears 4.7:1 and may carry type — the
   index numbers take it too. On paper a spice paints fills only, so there the
   numbers stay ink and the rule does the work. */
.rows{border-top:var(--rule-thick) solid var(--accent);margin-top:clamp(24px,3.2vw,44px)}
/* minmax(0,1fr) rather than 1fr: a grid track's default minimum is the widest
   unbreakable thing inside it, so at 320-360px a long address, a mono token or
   a wide table pushed the column past the viewport and the text ran off the
   screen. Reflow at 400 % zoom is the AA requirement this page promises.
   29.08.2026 */
.row{display:grid;grid-template-columns:44px minmax(0,1fr);gap:8px 16px;
  padding-block:clamp(16px,2.1vw,28px);border-bottom:var(--rule) solid currentColor;
  align-items:start;text-decoration:none;color:inherit;
  transition:padding-left var(--t-micro) var(--snap),color var(--t-micro)}
.row .n{grid-row:1;color:var(--type-2)}
.band--ink .row .n{color:var(--accent)}
/* On paper a spice may not carry type — turmeric measures 1.7:1 there — so the
   index takes the site's other mark instead: the short spice bar that already
   sits above every section head and every accent rule. Without it the longest
   component on the site ran two screens of black on cream with no colour in it
   at all, and the paper half of a long page went grey while the ink half did
   not. It is a mark, so every spice is legal on it. */
.band--paper .row .n{position:relative}
.band--paper .row .n::before{content:"";position:absolute;left:0;top:-11px;
  width:18px;height:var(--rule-thick);background:var(--accent)}
.row h3,.row .row-t{grid-column:2}
@media(min-width:560px){.row{grid-template-columns:56px 1fr;gap:10px 22px}}
@media(min-width:900px){
  .row{grid-template-columns:64px 6fr 6fr;gap:var(--gap);align-items:baseline}
  .row h3{grid-column:2}.row .row-t{grid-column:3;max-width:56ch}
}
.row:hover,.row:focus-within,.row:focus-visible{padding-left:12px}
.row:focus-visible{outline:var(--rule-thick) solid var(--type);outline-offset:4px}
/* the non-hovered lines step back in colour. Opacity here multiplied with
   every dim inside the row and took an index number to 2.4:1. */
@media(min-width:1000px){
  .rows:hover .row:not(:hover){color:var(--type-2)}
  .rows:hover .row:not(:hover) .n{color:var(--type-2)}
}
.row .row-t{color:var(--type-2);font-size:var(--fs-body);line-height:1.55}
a.row:hover h3{color:var(--ground);background:var(--type);box-decoration-break:clone}

/* the picture that rides the cursor (rows with data-shot) */
.cursor-shot{display:none}
@media (hover:hover) and (pointer:fine){
  .cursor-shot{display:block;position:fixed;top:0;left:0;z-index:var(--z-cursor);
    width:290px;aspect-ratio:4/3;pointer-events:none;overflow:hidden;
    /* the card paints its own ink ground, so it has to declare the pair too:
       inheriting a quiet PAPER band's --type/--ground put a dark quiet step on
       a dark card and the credit line measured 1.7:1 */
    --ground:var(--ink);--type:var(--paper);background:var(--ground);
    opacity:0;transform:translate3d(-9999px,-9999px,0);
    transition:opacity var(--t-micro) var(--snap)}
  .cursor-shot.on{opacity:1}
  .cursor-shot img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
    opacity:0;transition:opacity var(--t-micro) var(--snap)}
  .cursor-shot img.on{opacity:1}
  .cursor-shot .mono{position:absolute;left:10px;bottom:8px;z-index:2;color:var(--type-2);
    font-size:9px}
}

/* The masthead offer in two lengths — see mastAction() in lib/layout.mjs. */
.lbl-short{display:none}
@media(max-width:560px){
  .lbl-long{display:none}
  .lbl-short{display:inline}
}

/* ══ 9. SPLIT BLOCK ══════════════════════════════════════════════════════ */
.split{display:grid;gap:var(--gap)}
.split--one{grid-template-columns:minmax(0,1fr)}
@media(min-width:900px){
  .split{grid-template-columns:minmax(0,5fr) minmax(0,7fr)}
  .split--one{grid-template-columns:minmax(0,10fr)}
  .split--7-5{grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
  .split--4-8{grid-template-columns:minmax(0,4fr) minmax(0,8fr)}
  .split--8-4{grid-template-columns:minmax(0,8fr) minmax(0,4fr)}
  .split--6-6{grid-template-columns:minmax(0,6fr) minmax(0,6fr)}
  .split--top{align-items:start}
  .split--end{align-items:end}
}

/* ══ 10. DATA TABLE — the operational register ═══════════════════════════ */
.table-wrap{position:relative;overflow-x:auto;margin-top:clamp(20px,2.6vw,36px);
  border-top:var(--rule-thick) solid currentColor}
/* The register is the one component that legitimately runs wider than a phone.
   It says so in words rather than hoping the reader finds the edge: the line
   shows only where the table can actually move. */
/* The hint appears only on a register that has somewhere to move: motion.js
   marks the wrap, so a table that fits says nothing. */
.table-swipe{display:none;position:sticky;left:0;padding-block:8px;color:var(--type-2)}
.table-wrap.is-scrollable .table-swipe{display:block}
@media(max-width:560px){
  table.data{font-size:11px}
  table.data td.t{font-size:14.5px}
}
table.data{width:100%;border-collapse:collapse;
  font-family:var(--face-mono);font-size:var(--fs-mono-lg);line-height:1.5}
table.data caption{text-align:left;font-family:var(--face-mono);font-size:var(--fs-mono);
  font-weight:600;letter-spacing:var(--ls-mono);text-transform:uppercase;
  color:var(--type-2);padding-block:10px 14px;
  /* balance, so a caption never hangs a two-letter word on a line of its own */
  text-wrap:balance;max-width:76ch}
table.data th,table.data td{text-align:left;vertical-align:top;
  padding:14px 18px 14px 0;border-bottom:var(--rule) solid currentColor}
/* a cell that is a sentence, not a value — see dataTable() in lib/blocks.mjs */
table.data td.t{font-family:var(--face-body);font-size:var(--fs-body);
  line-height:1.55;letter-spacing:0;text-transform:none;max-width:52ch}
table.data thead th{font-weight:600;text-transform:uppercase;letter-spacing:var(--ls-mono);
  font-size:var(--fs-mono);padding-block:12px}
table.data tbody th{font-weight:600}
table.data tbody tr:hover{background:color-mix(in srgb,var(--type) 10%,transparent)}
table.data td:last-child,table.data th:last-child{padding-right:0}

/* ══ 11. TIMELINE ════════════════════════════════════════════════════════ */
.timeline{list-style:none;margin:clamp(20px,2.6vw,36px) 0 0;padding:0;
  border-top:var(--rule) solid currentColor}
.timeline li{display:grid;gap:6px 22px;padding-block:clamp(16px,2vw,26px);
  border-bottom:var(--rule) solid currentColor;align-items:baseline}
@media(min-width:720px){.timeline li{grid-template-columns:minmax(150px,3fr) 9fr}}
.timeline .when{font-family:var(--face-mono);font-size:var(--fs-mono);font-weight:600;
  letter-spacing:var(--ls-mono);text-transform:uppercase;color:var(--type-2)}
.timeline .what{font-family:var(--face-display);text-transform:uppercase;
  letter-spacing:var(--ls-display);font-size:var(--fs-d4);line-height:1}
.timeline .note{grid-column:1/-1;font-size:var(--fs-body);color:var(--type-2);max-width:60ch}
@media(min-width:720px){.timeline .note{grid-column:2}}
/* the state, in a word. See timeline() — meaning never rides on colour. */
.timeline .state,.passport .state{display:block;margin-top:5px;font-size:10px;
  letter-spacing:.1em;opacity:.85}
/* The word carries the meaning, so it takes the band's own type colour and
   full opacity. --accent is the MARK colour: legible against ink, and on a
   paper band it is the raw spice — turmeric on paper measured 1.69:1 at 10px,
   which is how the volunteer page failed the contrast gate on 29.08.2026. The
   colour is kept where it is legible, and the inset rule marks the row on both
   grounds either way. */
.timeline li[data-state="now"] .state,.passport .stamp[data-state="now"] .state{
  color:var(--type);opacity:1}
.band--ink .timeline li[data-state="now"] .state,
.band--ink .passport .stamp[data-state="now"] .state{color:var(--accent,currentColor)}
.timeline li[data-state="done"] .when::before{content:"✓ "}
.timeline li[data-state="now"]{padding-left:12px;box-shadow:inset var(--rule-thick) 0 0 currentColor}
/* a planned line is marked by the absent ✓ and the absent inset rule, not by
   a second dim: .6 over sumac measures 3.2:1 at 11px. */
.timeline li[data-state="planned"] .when{color:var(--type-2)}

/* ══ 12. FACTS ═══════════════════════════════════════════════════════════ */
.facts{display:grid;gap:var(--gap);margin-top:clamp(24px,3vw,44px);
  grid-template-columns:1fr}
@media(min-width:640px){.facts{grid-template-columns:repeat(2,1fr)}}
@media(min-width:1000px){.facts--3{grid-template-columns:repeat(3,1fr)}
  .facts--4{grid-template-columns:repeat(4,1fr)}}
.fact{border-top:var(--rule-thick) solid currentColor;padding-top:14px}
.fact .v{display:block;font-family:var(--face-display);font-size:var(--fs-fact);
  line-height:.9;letter-spacing:-.03em;text-transform:uppercase}
.fact .k{display:block;margin-top:10px;font-family:var(--face-mono);font-size:var(--fs-mono);
  font-weight:600;letter-spacing:var(--ls-mono);text-transform:uppercase;color:var(--type-2)}
.fact .src{display:block;margin-top:8px;font-size:12px;color:var(--type-2);max-width:36ch}

/* the single enormous number */
.big{display:block;font-family:var(--face-display);font-size:var(--fs-big);
  line-height:.9;letter-spacing:-.04em;margin-bottom:.04em}

/* ══ 13. QUOTE BAND ══════════════════════════════════════════════════════ */
.quote{margin:0}
.quote blockquote{margin:0;font-family:var(--face-display);text-transform:uppercase;
  letter-spacing:var(--ls-display);font-size:var(--fs-quote);line-height:.94;
  max-width:20ch;text-wrap:balance}
.quote figcaption{margin-top:clamp(18px,2.2vw,30px);font-family:var(--face-mono);
  font-size:var(--fs-mono);font-weight:600;letter-spacing:var(--ls-mono);
  text-transform:uppercase;color:var(--type-2)}
.quote blockquote::before{content:"“"}
.quote blockquote::after{content:"”"}
/* the two marks are the cheapest dose of colour on a quiet band, and at this
   size a spice on the ink ground clears the contrast table twice over */
.band--ink .quote blockquote::before,.band--ink .quote blockquote::after{color:var(--accent)}

/* ══ 15. FAQ ═════════════════════════════════════════════════════════════ */
.faq{border-top:var(--rule) solid currentColor;margin-top:clamp(22px,2.8vw,40px)}
.faq details{border-bottom:var(--rule) solid currentColor}
.faq summary{display:flex;gap:18px;align-items:baseline;
  cursor:pointer;list-style:none;padding-block:clamp(16px,2vw,24px);
  font-family:var(--face-display);text-transform:uppercase;letter-spacing:var(--ls-display);
  font-size:clamp(19px,2.1vw,28px);line-height:1.05;
  transition:padding-left var(--t-micro) var(--snap)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{padding-left:12px}
/* The sign used to sit at the far right of the row — 1,670px from the end of
   the question on a desktop, which is a sign for nobody. It follows the
   question instead, and an open row is a minus: a cross reads as «close and
   discard», and this closes nothing. */
.faq summary::after{content:"+";font-family:var(--face-mono);font-size:20px;line-height:1;
  flex:0 0 auto;color:var(--accent,currentColor)}
.faq details[open] summary::after{content:"\2212"}
.faq summary > *{min-width:0}
.faq .a{padding-bottom:clamp(18px,2.2vw,28px);max-width:64ch;
  font-size:var(--fs-body);line-height:1.6;color:var(--type-2)}
.faq .a > * + *{margin-top:.8em}

/* ══ 16. LINK GRID ═══════════════════════════════════════════════════════ */
.links{display:grid;gap:0;margin-top:clamp(22px,2.8vw,40px);
  border-top:var(--rule) solid currentColor}
@media(min-width:760px){.links{grid-template-columns:repeat(2,1fr);
  column-gap:var(--gap)}
  .links--3{grid-template-columns:repeat(3,1fr)}}
.links a{display:block;text-decoration:none;color:inherit;
  padding-block:clamp(16px,2vw,26px);border-bottom:var(--rule) solid currentColor;
  transition:padding-left var(--t-micro) var(--snap)}
.links a:hover{padding-left:12px}
.links a :is(h2,h3,h4){font-size:var(--fs-d4)}
.links a :is(h2,h3,h4) .arw{font-family:var(--face-body);display:inline-block;
  transition:transform var(--t-micro) var(--snap)}
.links a:hover :is(h2,h3,h4) .arw{transform:translateX(6px)}
.links a .note{display:block;margin-top:8px;font-size:var(--fs-body);color:var(--type-2);max-width:44ch}

/* ══ 17. CALLOUT — the honest "this is a plan" plate ═════════════════════ */
.callout{margin-top:clamp(22px,2.6vw,36px);padding:clamp(18px,2.2vw,28px);
  --ground:var(--ink);--type:var(--paper);
  background:var(--ground);color:var(--type);max-width:72ch;
  box-shadow:inset 0 0 0 var(--rule-thick) var(--tone,var(--section-lit))}
.band--ink .callout{background:transparent}
/* the tone colour is a spice ink on the callout's ink ground; --warn is chilli
   at 4.32:1, so the title stays large text at every width. --fs-d4 bottomed out
   at 20px on a phone. */
.callout .t{font-family:var(--face-display);text-transform:uppercase;
  letter-spacing:var(--ls-display);font-size:clamp(24px,2.4vw,30px);line-height:1;
  color:var(--tone,var(--section-lit))}
.callout .c{margin-top:12px;font-size:var(--fs-body);line-height:1.6}
/* The four tones used to be four spices, so a Festival page carried a turmeric
   plate, a matcha plate and a chilli plate inside one chilli room, and an About
   page — the achromatic section — carried three spices it has no claim to.
   Under the dosage law an accent belongs to the SECTION, so three of the four
   tones now draw in the section's own ink and say which they are in the title
   and the frame. A warning is the one meaning that has to survive a change of
   room, so it stays chilli everywhere; chilli is already Festival's ink, and
   no new colour enters the site.
   The callout paints its own ink ground, so the tone is the LIT variant. */
.callout--plan{--tone:var(--section-lit)}
.callout--note{--tone:var(--section-lit);box-shadow:inset var(--rule-thick) 0 0 var(--tone)}
.callout--ai{--tone:var(--section-lit);
  box-shadow:none;border:var(--rule-thick) dashed var(--tone)}
.callout--warn{--tone:var(--chilli-lit)}

/* ══ 18. PARADE — the roll-call of communities ═══════════════════════════ */
.parade{--ground:var(--ink);--type:var(--paper);
  background:var(--ground);color:var(--type);overflow:hidden;white-space:nowrap;
  padding-block:clamp(10px,1.2vw,16px);position:relative;z-index:3}
.parade-track{display:inline-flex;gap:0;animation:march 46s linear infinite}
.parade-pass{display:inline-flex}
/* Hover and focus pause it, and so does the button — WCAG 2.2.2 is level A and
   there is nothing inside the belt to focus, so a keyboard had no way to stop
   it at all. data-paused is set by motion.js: from the button, and from the
   observer when the belt has scrolled out of sight. */
.parade:hover .parade-track,.parade:focus-within .parade-track,
.parade[data-paused] .parade-track,
.parade[data-offscreen] .parade-track{animation-play-state:paused}

.parade-foot{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 18px;
  white-space:normal;max-width:var(--max);margin-inline:auto;
  padding:8px var(--gut) 2px}
.parade-pause{flex:0 0 auto;background:transparent;color:var(--type-2);cursor:pointer;
  border:0;box-shadow:inset 0 0 0 var(--rule) currentColor;
  font-family:var(--face-mono);font-size:clamp(10px,.78vw,12px);font-weight:600;
  letter-spacing:.06em;text-transform:uppercase;padding:5px 10px;
  transition:background var(--t-micro),color var(--t-micro)}
.parade-pause:hover{background:var(--type);color:var(--ground)}
.parade-pause[aria-pressed="true"]{background:var(--type);color:var(--ground)}
.parade-pause[aria-pressed="true"]::after{content:" · paused"}
@media (prefers-reduced-motion:reduce){.parade-pause{display:none}}
/* chilli on the ink ground measures 4.32:1 — large-text legal, body-copy short.
   Anton has no 700, so the floor has to be 24px, which is where the clamp now
   starts. It used to start at 17px and every phone read the roll-call at 4.3. */
.parade b{font-family:var(--face-parade);font-weight:400;text-transform:uppercase;
  font-size:clamp(24px,1.9vw,27px);letter-spacing:-.01em;
  padding-inline:clamp(12px,1.4vw,22px)}
@keyframes march{from{transform:translateX(0)}to{transform:translateX(-50%)}}
@media (prefers-reduced-motion:reduce){.parade{white-space:normal}
  .parade-track{flex-wrap:wrap;animation:none}}

/* ══ 19. THE FRAME — three formats, six proportions ══════════════════════
   One picture shape held this whole site until 28 August 2026: a 1440×518
   strip, one per page, on all seventy-one. Three formats now, and the word
   names the width the frame is given —

     full      all the width there is: the viewport between bands (.imgband),
               the measure inside one (.fig--full)
     half      six or seven columns, standing beside text, a form, a pull-out
     portrait  four or five columns, standing. Objects, costume, hands.

   Proportion is the second, independent choice, and it arrives as --ar from
   lib/blocks.mjs RATIOS. Every format reserves its box from --ar before the
   picture lands, so no format can move the page under a reader.            */

/* ── full: the band, edge to edge ─────────────────────────────────────────*/
.imgband{position:relative;background:var(--ground);isolation:isolate}
/* A frame that follows a joint used to start on the pixel the wedge ends on,
   so the diagonal read as a corner torn out of the photograph. The band's own
   ground runs between them instead, and the wedge lands on ground. */
.imgband--seamed{padding-top:clamp(20px,2.6vw,38px)}
/* height:var(--h,auto) with an aspect-ratio under it: a named height still
   wins outright (an explicit height beats aspect-ratio), and everything else
   takes its shape from the ratio the page chose. */
.imgband img{width:100%;height:var(--h,auto);aspect-ratio:var(--ar,37/13);
  object-fit:cover;object-position:var(--focus,50% 50%);display:block;
  /* a bleed frame is as wide as the screen, so a tall proportion on one is a
     picture taller than the screen with a caption bar below the fold. The cap
     crops rather than argues: full takes wide or film, and anything else is
     held to something a reader can see all of. */
  max-height:86vh}
.imgband--dye img{mix-blend-mode:multiply}
.imgband--contain img{height:auto;aspect-ratio:auto;object-fit:contain}
/* A phone is 390 wide. The long strip at that width is 137px of picture, which
   is a rule rather than a photograph, so the narrow screen keeps the frame at
   a shape it can be read at and the ratio the page picked applies to the desk.
   A page that names its own --ar-narrow overrides this. */
@media(max-width:700px){
  .imgband img{aspect-ratio:var(--ar-narrow,3/2);min-height:240px}
}
.imgband figcaption{position:relative;z-index:2;display:flex;flex-wrap:wrap;gap:8px 22px;
  justify-content:space-between;padding:12px var(--gut);
  --ground:var(--ink);--type:var(--paper);background:var(--ground);color:var(--type);
  font-family:var(--face-mono);font-size:var(--fs-mono);font-weight:600;
  letter-spacing:var(--ls-mono);text-transform:uppercase}
.imgband figcaption .credit{color:var(--type-2)}

/* ── half and portrait: the frame inside a band ───────────────────────────
   Standing on its own in a band, a half or a portrait puts its caption in the
   columns the picture leaves, so the row runs the full measure and the empty
   half stops being empty. Inside a mediaSplit column it stacks — there the
   other column is the point. */
.fig{margin-top:clamp(22px,2.8vw,40px);display:grid;gap:10px var(--gap)}
.fig img{width:100%;height:var(--h,auto);aspect-ratio:var(--ar,16/9);
  object-fit:cover;object-position:var(--focus,50% 50%);display:block}
.fig--dye img{mix-blend-mode:multiply}
.fig--contain img{height:auto;aspect-ratio:auto;object-fit:contain}
.fig figcaption{font-family:var(--face-mono);font-size:var(--fs-mono);
  font-weight:600;letter-spacing:var(--ls-mono);text-transform:uppercase;
  color:var(--type-2);align-self:end;text-wrap:balance}
.fig figcaption .credit{display:block;color:var(--type-2)}
@media(min-width:900px){
  .fig--half{grid-template-columns:7fr 5fr;align-items:end}
  .fig--portrait{grid-template-columns:5fr 7fr;align-items:end}
  /* the caption stands as a column of its own, on the picture's baseline,
     with a rule over it so it reads as placed rather than left over */
  .fig--half figcaption,.fig--portrait figcaption{
    border-top:var(--rule) solid currentColor;padding-top:12px;padding-bottom:2px}
  /* inside a split the frame owns its whole column */
  .split .fig{display:block}
  .split .fig figcaption{margin-top:10px}
}

/* ── the ask with a frame beside it ───────────────────────────────────────
   mediaSplit(). The site's intake forms and main pull-outs sat in a full-width
   band with a 760px form in it, leaving four hundred pixels of ground beside
   the one thing the page wants a reader to do. The frame takes that column.  */
/* A block built for the whole measure, dropped into half of it, halves again:
   bigNumber() is a 6/6 split and inside a column it became 3 and 3, with the
   text broken to one word a line. Anything nested in a split takes the column
   whole. */
.split .split{grid-template-columns:minmax(0,1fr)}
.split--media{align-items:start}
.split--media .form{max-width:none}
@media(min-width:900px){
  /* a frame that leads reads better with its top on the head's cap-height */
  .split--media .fig{margin-top:0}
  /* fill: the frame runs the whole height of the row and crops to it. For the
     ask that is taller than any proportion keeps up with — a twelve-field
     intake form with a picture beside it and no ground under the picture. */
  .split--media-fill{align-items:stretch}
  .split--media-fill .fig{height:100%;grid-template-rows:1fr auto}
  .split--media-fill .fig img{height:100%;aspect-ratio:auto;min-height:280px}
  /* ride: the frame travels with the ask. A twelve-field intake form is two
     and a half thousand pixels tall and no proportion keeps up with it —
     filled, the crop stops being a crop; aligned, the column dies two
     screens before the form ends and the reader scrolls half a page of bare
     ground beside the one thing the page wants. Sticky is the third answer:
     the frame holds under the masthead while the fields go past, so the
     column is never empty and the picture is never stretched. */
  /* the column has to be as tall as the row for the frame to have anywhere to
     travel — splitBlock wraps each side in a div, and align-items:start makes
     that div hug its own content. */
  .split--media-ride > div{align-self:stretch}
  .split--media-ride .fig{position:sticky;
    top:calc(var(--mast-h) + clamp(14px,1.8vw,26px))}
}

/* ══ 19b. SWATCHES — the palette, shown ══════════════════════════════════
   Each tile paints its own ink and sets its own type colour from the same
   .band--<ink> table every band uses, so a swatch cannot drift from the thing
   it is a swatch of. */
.swatches{display:grid;gap:var(--rule-thick);margin-top:clamp(22px,2.8vw,40px);
  grid-template-columns:repeat(auto-fit,minmax(190px,1fr))}
.swatch{padding:clamp(16px,1.8vw,22px);min-height:168px;
  display:flex;flex-direction:column;gap:7px;background:var(--ground);color:var(--type)}
.swatch .anton{font-family:var(--face-display);text-transform:uppercase;
  letter-spacing:var(--ls-display);font-size:clamp(22px,2.2vw,30px);line-height:.95}
.swatch .ratio{font-size:var(--fs-mono-lg);margin-top:auto}
.swatch .small{font-size:12.5px;line-height:1.45}

/* ══ 20. PASSPORT STRIP ══════════════════════════════════════════════════ */
.passport{display:grid;gap:0;margin-top:clamp(22px,2.8vw,40px);
  grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  border:var(--rule-thick) solid currentColor}
.passport .stamp{position:relative;padding:clamp(16px,2vw,24px);
  border-right:var(--rule) dashed currentColor;min-height:118px;
  display:flex;flex-direction:column;justify-content:space-between;gap:12px}
.passport .stamp:last-child{border-right:0}
.passport .stamp .no{font-family:var(--face-mono);font-size:var(--fs-mono);font-weight:600;
  letter-spacing:var(--ls-mono);text-transform:uppercase;color:var(--type-2)}
.passport .stamp .lb{align-self:start;font-family:var(--face-display);text-transform:uppercase;
  letter-spacing:var(--ls-display);font-size:clamp(17px,1.8vw,24px);line-height:.95}
.passport .stamp[data-state="planned"] .no{color:var(--type-2)}
.passport .stamp[data-state="done"] .lb{color:var(--ground);background:var(--type);
  padding:2px 7px;box-decoration-break:clone}
.passport .stamp[data-state="now"]::after{content:"";position:absolute;
  inset:auto 8px 8px auto;width:12px;height:12px;background:currentColor}
.passport-state{margin-top:10px}
/* A catalogue tile that has an article behind it is the link to it. */
.passport a.stamp{text-decoration:none}
.passport a.stamp .lb{text-decoration:underline;text-underline-offset:4px;
  text-decoration-thickness:var(--rule)}
.passport a.stamp:hover .lb,.passport a.stamp:focus-visible .lb{
  color:var(--ground);background:var(--type);padding:2px 7px;
  box-decoration-break:clone;text-decoration:none}

/* ══ 21. FOOTER ══════════════════════════════════════════════════════════ */
.foot{--ground:var(--ink);--type:var(--paper);
  background:var(--ground);color:var(--type);padding-block:clamp(40px,5vw,72px)}
.foot-map{display:grid;gap:clamp(22px,2.6vw,36px);grid-template-columns:repeat(2,1fr);
  padding-bottom:clamp(28px,3.4vw,48px);border-bottom:var(--rule) solid currentColor}
@media(min-width:660px){.foot-map{grid-template-columns:repeat(4,1fr)}}
@media(min-width:1100px){.foot-map{grid-template-columns:repeat(7,1fr)}}
/* h3, not h4: on a page whose deepest heading is an h2 the footer used to jump
   two levels. The size is set here, so the level is free to be correct. */
.foot-map h3{font-size:15px;line-height:1.2;letter-spacing:.01em;color:var(--type);
  border-top:var(--rule-thick) solid var(--sec-ink,var(--section-lit));padding-top:11px}
.foot-map ul{list-style:none;margin:12px 0 0;padding:0;display:grid;gap:7px}
.foot-map a{font-size:14.5px;text-decoration:none;color:var(--type-2);
  transition:color var(--t-micro)}
.foot-map a:hover{color:var(--sec-ink,var(--section-lit))}
.foot-sub{padding-block:clamp(28px,3.4vw,44px);border-bottom:var(--rule) solid currentColor}
.foot-legal{display:flex;flex-wrap:wrap;gap:10px 26px;align-items:baseline;
  padding-top:clamp(22px,2.6vw,34px);font-size:13.5px;color:var(--type-2)}
.foot-legal a{color:var(--section-lit);text-decoration:none;
  border-bottom:var(--rule) solid currentColor}
.foot-legal a:hover{color:var(--paper)}
.foot-terr{margin-top:16px;font-size:13.5px;color:var(--type-2);max-width:70ch}


/* ══ 22. SMALL SCREENS ═══════════════════════════════════════════════════ */
@media(max-width:760px){
  .mast-in{gap:8px;padding-block:9px}
  .mark{font-size:15px;gap:7px}
  .mark svg{width:28px}
  .util{gap:6px}
  /* 9px was below anything the rest of the site sets, and both controls stood
     under the 44px target the accessibility page promises. The mono register
     keeps its size (--fs-mono, 11px) and the height is set outright. */
  .util-btn{padding:6px 10px;font-size:var(--fs-mono);min-height:44px;white-space:nowrap;
    display:inline-flex;align-items:center}
  .util-btn .soon{font-size:10px}
  .nav-trigger{padding:7px 11px;font-size:var(--fs-mono);gap:6px;min-height:44px;
    display:inline-flex;align-items:center}
  .hero{padding-block:clamp(38px,10vw,56px) clamp(34px,9vw,50px)}
  .imgband figcaption{flex-direction:column;gap:4px}
  .passport{grid-template-columns:1fr}
  .passport .stamp{border-right:0;border-bottom:var(--rule) dashed currentColor;min-height:0}
  .passport .stamp:last-child{border-bottom:0}
  table.data{font-size:12px}
  table.data th,table.data td{padding:11px 14px 11px 0}
}
@media(max-width:430px){
  /* the wordmark drops out of sight, and the link keeps its name */
  .mark span{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
}

/* The parade's visible disclaimer. The roll-call is a picture of the city, and
   on a page about kitchens or pavilions a reader will otherwise read it as the
   line-up. The aria-label says so to a screen reader; this says so to an eye. */
.parade-note{white-space:normal;margin:0;padding:0;
  font-size:clamp(10px,.78vw,12px);letter-spacing:.06em;
  text-transform:uppercase;color:var(--type-2)}
