/* CITYarts core — tokens, reset, and the giving widget.
   Shared by all three variants. Variants override tokens and layout, never this file's structure. */

:root {
  /* Neutrals carry a slight blue bias so they read as chosen, not defaulted. */
  --ground:      #F7F7F4;
  --surface:     #FFFFFF;
  --surface-2:   #EFEFEA;
  --ink:         #12151C;
  --ink-soft:    #474D5B;
  --ink-faint:   #686C76;   /* 4.56:1 worst-case light (was #7A8290 at 3.36 -- AA fail) */
  --line:        #DCDCD4;
  --line-soft:   #E9E9E2;
  --line-strong: #94949C;   /* 3.01:1 on white -- for interactive boundaries only */
  --on-ink-faint: #9AA0AC;  /* muted text ON --ink grounds: 6.96:1. --ink-faint is 3.47:1 there. */

  /* Ultramarine — a real mural pigment, and it survives on both grounds. */
  /* CITYarts brand, set by Sima 2026-08-24: "the colors of city art are yellow, purple", plus
     "add the color green as an accent color". Three colours need three jobs or they fight:
       PURPLE  primary  -- buttons, links, active states. Was #1B3FA0 blue.
       GREEN   accent   -- every eyebrow and section label on the site, so it reads throughout.
       YELLOW  brand    -- only where it can hold contrast, which on a light ground is nowhere:
                          #F5C242 on #F7F7F4 is 1.7:1. It carries dark grounds (A's hero kicker)
                          and fills behind dark ink. --brand-yellow-ink is the text-safe variant. */
  --accent:      #5B2E90;   /* 10.0:1 on white -- carries --accent-ink text on buttons */
  --accent-ink:  #FFFFFF;
  --accent-soft: #EDE4F7;
  /* Both greens are SAMPLED FROM TSIPI'S GLASSES. Sima: "make the green a little lighter, that
     matches [Tsipi's] eyeglasses frames in the picture". public/img/tsipi.jpg was decoded and the
     eyewear region sampled -- the frame rim runs #50B870 to #78C880, hue 138 degrees.
       --green-bright  IS that frame colour, unmodified. 7.64:1 on the dark bands.
       --accent-green  is the SAME HUE walked darker until it clears 4.5:1 for an 11px bold label
                       on the light page. #50B870 itself is 2.32:1 there and unreadable.
     One colour, two lightnesses, so the site never shows two unrelated greens. */
  --accent-green: #2C8046;  /* 4.57:1 on --ground -- labels on light grounds */
  --green-bright: #50B870;  /* Tsipi's frames, 7.64:1 on dark -- labels on the photo bands */
  --accent-light: #C4AEF0;  /* purple that survives a dark photograph -- ghost buttons in A's hero */
  --brand-yellow: #F5C242;  /* dark grounds and fills ONLY -- see note above */
  --brand-yellow-ink: #6B4A00;  /* 6.3:1 on --ground, for yellow-as-text on light */

  --good:        #2E6B4F;
  --good-soft:   #DEEDE4;
  --warn:        #B8791F;
  --hot:         #B23E22;

  --r:      4px;
  --r-lg:   8px;
  --shadow: 0 1px 2px rgba(18,21,28,.05), 0 12px 32px -20px rgba(18,21,28,.35);

  --font-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-body:    "Newsreader", Georgia, "Times New Roman", serif;
  --font-ui:      "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-mono:    "IBM Plex Mono", ui-monospace, Menlo, monospace;

  --pad: clamp(1.15rem, 4vw, 2.5rem);
  --measure: 38rem;

  /* The sticky give bar is the only piece of fixed furniture on the page, and FOUR separate
     rules used to encode its height as a different hand-written constant: body padding 5rem,
     scroll-padding 6.5rem, scroll-margin 6.5rem, lane badge 4.4rem. None of them included
     env(safe-area-inset-bottom), so on any iPhone with a home indicator they were all short by
     the inset at once. Measured at 390x844 with a 34 px inset: the bar is 102 px tall and body
     padding was 80 px, so 22 px of the footer sat permanently under it with no way to scroll it
     clear. At 320x568 the bar wrapped to 83 px and was already 3 px short with NO inset.

     One number now, derived everywhere. --give-bar-h is the bar's content height and the inset is
     added wherever it is used. It is DERIVED from its own inputs, not typed: .btn's min-height,
     the bar's own vertical padding, and the top border. Writing 4.25rem here would have made it a
     FIFTH hand-written constant, and it was already wrong -- the true computed height is 68.2px,
     not the 68px that was measured and rounded. */
  --give-bar-h: calc(48px + 1.2rem + 1px);   /* .btn min-height + .6rem*2 padding + 1px border */
  --give-bar: calc(var(--give-bar-h) + env(safe-area-inset-bottom, 0px));
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --ground:#0E1015; --surface:#171A21; --surface-2:#1E222B;
    --ink:#EDEDE8; --ink-soft:#AFB6C4; --ink-faint:#838995;
    --line:#2C313B; --line-soft:#232830; --line-strong:#65656F; --on-ink-faint:#5E6470;
    --accent:#B69AE8; --accent-ink:#0E1015; --accent-soft:#241A38;
    --accent-green:#6ECB8C; --green-bright:#78C880; --accent-light:#C4AEF0;
    --brand-yellow:#F7C948; --brand-yellow-ink:#F7C948;
    --good:#6FC79C; --good-soft:#14291F; --warn:#E0A94E; --hot:#EC9077;
    --shadow:0 1px 2px rgba(0,0,0,.5), 0 14px 34px -22px rgba(0,0,0,.9);
  }
}
:root[data-theme="dark"] {
  --ground:#0E1015; --surface:#171A21; --surface-2:#1E222B;
  --ink:#EDEDE8; --ink-soft:#AFB6C4; --ink-faint:#838995;
  --line:#2C313B; --line-soft:#232830; --line-strong:#65656F; --on-ink-faint:#5E6470;
  --accent:#8CA8FF; --accent-ink:#0E1015; --accent-soft:#1A2240;
  --good:#6FC79C; --good-soft:#14291F; --warn:#E0A94E; --hot:#EC9077;
  --shadow:0 1px 2px rgba(0,0,0,.5), 0 14px 34px -22px rgba(0,0,0,.9);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Without this, every in-page anchor and every scrollIntoView can park content underneath the
     sticky bar -- measured at 375x812 with the payment confirmation 33px visible out of 101px,
     and elementFromPoint returning the bar. Derived from --give-bar so it tracks the home
     indicator instead of guessing at it. */
  scroll-padding-bottom: calc(var(--give-bar) + 1.5rem);
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }

h1, h2, h3, h4, .ui { font-family: var(--font-display); }
h1, h2, h3 { text-wrap: balance; margin: 0; letter-spacing: -.025em; line-height: 1.05; }
p { margin: 0; text-wrap: pretty; }

a { color: inherit; }
:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
  /* The hero is a photograph; a single-colour ring measured 1.45:1 against it. The white halo
     guarantees the indicator survives whatever image sits behind it. */
  box-shadow: 0 0 0 6px rgba(255,255,255,.92), 0 0 0 8px rgba(18,21,28,.35);
}

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

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--accent); color: var(--accent-ink);
  padding: .8rem 1.2rem; font-family: var(--font-ui); font-weight: 700;
}
.skip:focus { left: 0; }

.eyebrow {
  font-family: var(--font-ui); font-size: .69rem; font-weight: 700;
  letter-spacing: .15em; text-transform: uppercase; color: var(--accent-green);
}

.wrap { width: min(72rem, 100%); margin-inline: auto; padding-inline: var(--pad); }
.measure { max-width: var(--measure); }

/* ---------- buttons ---------- */

.btn {
  font-family: var(--font-ui); font-weight: 700; font-size: 1rem;
  border: 1.5px solid transparent; border-radius: var(--r);
  padding: .85rem 1.5rem; cursor: pointer; display: inline-flex;
  align-items: center; justify-content: center; gap: .5rem;
  text-decoration: none; transition: transform .12s ease, background .12s ease;
  min-height: 48px;
}
.btn:active { transform: translateY(1px); }
.btn-primary { background: var(--accent); color: var(--accent-ink); }
.btn-primary:hover { filter: brightness(1.08); }
/* Sima, 2026-08-24: "all the buttons purple". Primary is filled purple, secondary is outlined
   purple -- one family rather than a purple button beside a grey one. */
.btn-ghost { background: transparent; color: var(--accent); border-color: var(--accent); }
.btn-ghost:hover { background: var(--accent-soft); border-color: var(--accent); }
.btn-lg { font-size: 1.1rem; padding: 1.05rem 2rem; min-height: 56px; }
.btn-block { width: 100%; }

/* ================================================================
   GIVING WIDGET
   The whole point. Two taps: choose an amount, confirm.
   No page change, no account, no redirect.
   ================================================================ */

.give {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow);
  padding: clamp(1.1rem, 3vw, 1.6rem);
  display: flex; flex-direction: column; gap: 1rem;
  container-type: inline-size;
}

.give-head { display: flex; flex-direction: column; gap: .3rem; }
.give-title { font-family: var(--font-display); font-size: 1.25rem; font-weight: 800; }
.give-sub { font-size: .95rem; color: var(--ink-soft); line-height: 1.4; }

.give-freq {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0;
  border: 1.5px solid var(--line-strong); border-radius: var(--r); overflow: hidden;
}
.give-freq button {
  font-family: var(--font-ui); font-weight: 700; font-size: .92rem;
  padding: .7rem .5rem; border: 0; background: transparent; color: var(--ink-soft);
  cursor: pointer; min-height: 44px;
}
.give-freq button[aria-pressed="true"] { background: var(--accent); color: var(--accent-ink); }

.give-tiers {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: .5rem;
}
@container (max-width: 26rem) { .give-tiers { grid-template-columns: repeat(2, 1fr); } }

.tier {
  position: relative; text-align: left; cursor: pointer;
  /* A <button> does NOT inherit color -- the UA stylesheet sets it to `buttontext`, which is
     black. .buys declares its own colour and was fine; .amt declared none, so in dark mode all
     eight tier amounts rendered black on #171A21: 1.21:1 unselected, 1.35:1 selected. The
     dollar figure is the single most important text in the widget and it was invisible on every
     phone in dark mode, on all three variants. */
  color: var(--ink);
  background: var(--surface); border: 1.5px solid var(--line-strong); border-radius: var(--r);
  padding: .7rem .7rem .75rem; min-height: 76px;
  display: flex; flex-direction: column; gap: .18rem;
  font-family: var(--font-ui); transition: border-color .12s ease, background .12s ease;
}
.tier:hover { border-color: var(--ink-faint); }
.tier[aria-pressed="true"] {
  border-color: var(--accent); background: var(--accent-soft);
  box-shadow: inset 0 0 0 1px var(--accent);
}
.tier .amt {
  font-size: 1.22rem; font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums;
  /* A <button> does NOT inherit color -- the UA stylesheet sets it to `buttontext`, which is
     black. .buys declares its own colour and was fine; .amt declared none, so in dark mode all
     eight tier amounts rendered black on the dark surface. MEASURED on the deployed page
     2026-08-23: 1.21:1 against a 3.0 floor. The dollar figure is the single most important text
     in the widget, and it was invisible on every phone in dark mode, on all three variants.

     Fix authored on variant/a-mobile. Applied here directly rather than merging that branch:
     the branch carries eight commits of mobile work that is his to review, and this is one
     property repairing a defect measured on production. */
  color: var(--ink);
}
.tier .buys { font-size: .72rem; font-weight: 600; color: var(--ink-soft); line-height: 1.25; }
.tier[aria-pressed="true"] .buys { color: var(--ink); }
.tier .flag {
  position: absolute; top: -.55rem; right: .4rem;
  font-size: .58rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  background: var(--ink); color: var(--ground); padding: .16rem .38rem; border-radius: 2px;
}

.give-custom { display: flex; align-items: center; gap: .5rem; }
.give-custom label { font-family: var(--font-ui); font-size: .85rem; font-weight: 600; color: var(--ink-soft); }
.give-custom .field {
  flex: 1; display: flex; align-items: center; gap: .25rem;
  border: 1.5px solid var(--line-strong); border-radius: var(--r); padding: .1rem .7rem;
  background: var(--surface);
}
.give-custom .field:focus-within { border-color: var(--accent); }
.give-custom .cur { font-family: var(--font-ui); font-weight: 700; color: var(--ink-faint); }
.give-custom input {
  flex: 1; border: 0; background: transparent; color: var(--ink);
  font-family: var(--font-ui); font-size: 1.05rem; font-weight: 700;
  padding: .6rem 0; min-height: 44px; width: 100%;
  font-variant-numeric: tabular-nums;
}
.give-custom input:focus { outline: none; }

.give-buys {
  background: var(--accent-soft); border-radius: var(--r);
  padding: .75rem .9rem; font-size: .95rem; line-height: 1.4;
  display: flex; gap: .55rem; align-items: baseline; min-height: 3rem;
}
.give-buys b { font-family: var(--font-ui); color: var(--accent); }

.give-pay { display: flex; flex-direction: column; gap: .55rem; }

.give-wallet {
  background: var(--ink); color: var(--ground);
  border: 0; border-radius: var(--r); min-height: 54px;
  font-family: var(--font-ui); font-weight: 700; font-size: 1.06rem;
  cursor: pointer; display: none; align-items: center; justify-content: center; gap: .5rem;
}
.give-wallet[data-available="1"] { display: flex; }
.give-wallet:active { transform: translateY(1px); }
.give-wallet .glyph { font-size: 1.2em; line-height: 1; }

.give-or {
  display: none; align-items: center; gap: .7rem;
  font-family: var(--font-ui); font-size: .72rem; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-faint);
}
.give-wallet[data-available="1"] ~ .give-or { display: flex; }
.give-or::before, .give-or::after { content: ""; flex: 1; height: 1px; background: var(--line); }

.give-note {
  font-family: var(--font-ui); font-size: .74rem; color: var(--ink-faint);
  line-height: 1.4; display: flex; gap: .4rem; align-items: baseline;
}

.give-status[hidden] { display: none; }
.give-status { scroll-margin-bottom: calc(var(--give-bar) + 1.5rem); }
.give-status:focus { outline: 3px solid var(--accent); outline-offset: 3px; }
.give-status {
  border-radius: var(--r); padding: 1rem 1.1rem;
  font-family: var(--font-ui); font-size: .95rem; line-height: 1.45;
}
.give-status[data-kind="ok"]   { background: var(--good-soft); color: var(--good); }
.give-status[data-kind="err"]  { background: color-mix(in srgb, var(--hot) 12%, transparent); color: var(--hot); }
.give-status[data-kind="work"] { background: var(--surface-2); color: var(--ink-soft); }
.give-status b { display: block; font-weight: 800; margin-bottom: .2rem; }

/* sticky mobile give bar — never more than a thumb away */
.give-bar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 60;
  background: var(--surface); border-top: 1px solid var(--line);
  padding: .6rem var(--pad) calc(.6rem + env(safe-area-inset-bottom, 0px));
  display: none; gap: .6rem; align-items: center;
  /* nowrap, because --give-bar-h asserts this bar's height and every other measurement is
     derived from it. At 320px the label and the button wrapped onto two lines, the bar grew to
     83px, and the assertion silently stopped being true. */
  flex-wrap: nowrap;
  box-shadow: 0 -8px 24px -18px rgba(0,0,0,.5);
}
.give-bar strong {
  font-family: var(--font-ui); font-size: .9rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; min-width: 0;
}
/* Below ~23rem the label and the call to action cannot both fit on one line, so the label gives
   up its space. It is hidden VISUALLY ONLY: it names the recipient ("Give to CITYarts") and the
   button does not, so removing it from the accessibility tree would leave the page's one piece of
   persistent furniture asking for money without saying who for. 23rem also catches a low-vision
   user at 400% zoom, not just a 320px handset. */
@media (max-width: 23rem) {
  .give-bar strong {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}
.give-bar .btn { flex: 1 1 auto; white-space: nowrap; }
/* give.js sets bar.hidden = true once a gift completes. The UA's [hidden]{display:none} loses to
   the author `display:flex` above, so on every phone the bar stayed visible and tabbable after a
   donation -- offering "Choose an amount" on top of the "Thank you" it had just moved focus to.
   The attribute selector outranks the plain class, so this needs no !important. */
.give-bar[hidden] { display: none; }
@media (max-width: 52rem) {
  .give-bar { display: flex; }
  /* Clears the bar AND the home indicator, so the end of the footer can always be scrolled
     into view. Was a flat 5rem, which was 22px short on any iPhone with an inset. */
  body { padding-bottom: calc(var(--give-bar) + .75rem); }
}

/* ---------- shared sections ---------- */

.impact-row {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 1px; background: var(--line); border-block: 1px solid var(--line);
}
.impact-row div { background: var(--ground); padding: 1.4rem 1.1rem; }
.impact-row .n {
  font-family: var(--font-display); font-size: clamp(1.9rem, 4.5vw, 2.7rem);
  font-weight: 800; letter-spacing: -.04em; line-height: 1; display: block;
  font-variant-numeric: tabular-nums;
}
.impact-row .u { font-family: var(--font-ui); font-size: .8rem; font-weight: 700; text-transform: uppercase; letter-spacing: .1em; color: var(--accent); display: block; margin-top: .3rem; }
.impact-row .l { font-size: .88rem; color: var(--ink-soft); display: block; margin-top: .45rem; line-height: 1.35; }

.voice { display: flex; flex-direction: column; gap: .6rem; }
.voice q { font-size: 1.15rem; line-height: 1.45; font-style: italic; quotes: "\201C" "\201D"; }
.voice cite {
  font-family: var(--font-ui); font-style: normal; font-size: .78rem;
  font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-faint);
}

.card-grid { display: grid; gap: 1.1rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); }
.card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r);
  overflow: hidden; display: flex; flex-direction: column;
}
.card img { aspect-ratio: 4/3; object-fit: cover; width: 100%; }
.card .body { padding: 1rem 1.1rem 1.2rem; display: flex; flex-direction: column; gap: .4rem; }
.card h3 { font-size: 1.08rem; }
.card p { font-size: .93rem; color: var(--ink-soft); line-height: 1.45; }

footer.site {
  border-top: 1px solid var(--line); margin-top: 4rem;
  padding-block: 2.5rem 3.5rem; font-size: .9rem; color: var(--ink-soft);
}
footer.site a { color: var(--ink-soft); }
.foot-grid { display: grid; gap: 1.6rem; grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr)); }
.foot-grid h4 { font-size: .7rem; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: .6rem; }
/* Measured at 390x844: every link in these lists had a 15px-tall hit area, and the mailto/tel
   pair 19px. Twelve of the page's eighteen undersized targets were here.
   The gap shrinks rather than vanishing: WCAG 2.5.8 is about spacing as well as size, and two
   44px targets sharing a boundary means a thumb on the seam hits whichever wins by a pixel.
   It also keeps the focus ring (3px outline + 3px offset + 6px halo) off the neighbouring row. */
.foot-grid ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: .25rem; }
.foot-grid ul li { display: flex; }
/* The anchor, not the <li>: two of these lists carry plain-text rows (the address and the EIN)
   that nothing can tap, and a tap-target floor has no business inflating them. */
.foot-grid ul a {
  /* min-width too: "About" is 39.6px of text, and a 39.6x44 target still fails on the axis
     nobody checks. A 44px floor on both axes is the whole rule, not half of it. */
  display: inline-flex; align-items: center; min-height: 44px; min-width: 44px;
}

.social { display: flex; gap: .55rem; flex-wrap: wrap; }
.social a {
  width: 44px; height: 44px; border: 1px solid var(--line); border-radius: 50%;
  display: grid; place-items: center; font-family: var(--font-ui);
  font-size: .72rem; font-weight: 700; text-decoration: none;
}
.social a:hover { border-color: var(--accent); color: var(--accent); }

/* variant badge — dev lane only, stripped in prod */
.lane-badge {
  /* Bottom-left, not top-right: at 375px the top-right badge sat directly on top of the header's
     Give button, which is the one control the whole page exists to expose. A dev-only artefact
     must never occlude the primary action -- a reviewer cannot tell "hidden by the badge" from
     "missing", and the badge is invisible in prod so the defect would look intermittent. */
  position: fixed; bottom: 0; left: 0; z-index: 100;
  background: var(--ink); color: var(--ground);
  font-family: var(--font-mono); font-size: .64rem; font-weight: 600;
  padding: .3rem .55rem; border-top-right-radius: var(--r); opacity: .82;
  letter-spacing: .04em;
  pointer-events: none;
}
/* Sits directly on top of the give bar, never inside it. The flat 4.4rem was measured OVERLAPPING
   the bar at 320x568 (where the bar wrapped to 83px) and on any device with a home indicator. */
@media (max-width: 52rem) { .lane-badge { bottom: var(--give-bar); } }

/* ================================================================
   MOTION
   Sima: "a lot of the content on the site is static... I would like for the site to be a lot more
   animated and visual." Motion here sequences the impact story rather than decorating it.

   Everything below is gated on .motion, which core/js/motion.js only adds when it is certain it
   can run AND the visitor has not asked for reduced motion. Without that class every element sits
   at its finished state -- so a JS failure or a reduced-motion preference yields the complete,
   readable, donatable page rather than a blank one.
   ================================================================ */

.motion [data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .62s cubic-bezier(.22,.61,.36,1), transform .62s cubic-bezier(.22,.61,.36,1);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.motion [data-reveal].seen { opacity: 1; transform: none; }

/* A number that counts up must not reflow the line while it does it. */
[data-count] { font-variant-numeric: tabular-nums; }

/* ---------- the map ---------- */

.map {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(1rem, 3vw, 1.75rem);
  overflow: hidden;
}
.map svg { width: 100%; height: auto; display: block; }
.map .land { fill: var(--surface-2); stroke: var(--line); stroke-width: .6; }
.map .route { fill: none; stroke: var(--accent); stroke-width: 1.1; opacity: .5; stroke-linecap: round; }

.map .dot { fill: var(--accent); opacity: 0; transform-box: fill-box; transform-origin: center; }
.motion .map .dot { transform: scale(.2); transition: opacity .5s ease, transform .5s cubic-bezier(.34,1.56,.64,1); transition-delay: calc(var(--i,0) * 55ms + 250ms); }
.map .dot.seen, html:not(.motion) .map .dot { opacity: 1; transform: scale(1); }

.map .halo { fill: none; stroke: var(--accent); stroke-width: 1; opacity: 0; }
.motion .map .dot.seen + .halo { animation: ping 2.6s ease-out infinite; animation-delay: calc(var(--i,0) * 55ms + 700ms); }
@keyframes ping {
  0%   { r: 3; opacity: .5; }
  70%  { r: 13; opacity: 0; }
  100% { r: 13; opacity: 0; }
}

.map-legend {
  display: flex; flex-wrap: wrap; gap: .5rem 1.2rem; margin-top: 1rem;
  font-family: var(--font-ui); font-size: .78rem; font-weight: 600; color: var(--ink-faint);
}
.map-legend b { color: var(--ink); font-variant-numeric: tabular-nums; }

.map-places {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
  gap: .3rem 1rem; margin-top: 1.1rem;
  font-family: var(--font-ui); font-size: .82rem; color: var(--ink-soft);
}
.map-places span { display: flex; gap: .45rem; align-items: baseline; }
.map-places i { width: 6px; height: 6px; border-radius: 50%; background: var(--accent); flex: none; }

/* ---------- founder quote, front and centre ---------- */
/* Sima: the founder "really wants that to be front and center." */

.founder {
  background: var(--ink); color: var(--ground);
  padding-block: clamp(3rem, 7vw, 5rem);
}
.founder blockquote { margin: 0; max-width: 46rem; }
.founder q {
  font-size: clamp(1.5rem, 4.2vw, 2.5rem); line-height: 1.2; font-style: italic;
  letter-spacing: -.02em; quotes: "\201C" "\201D"; text-wrap: balance;
}
.founder cite {
  display: block; margin-top: 1.2rem; font-style: normal; font-family: var(--font-ui);
  font-size: .78rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  color: var(--on-ink-faint);
}

/* ---------- impact story: numbers that lead somewhere ---------- */
/* Sima on the live site: the impact page is "a compilation of different numbers that are not
   organized in any particular way"; she wants it succinct, aligned to the mission, and to
   "then drive to donation". So the row ENDS in a call to give rather than trailing off. */

.impact-story { display: flex; flex-direction: column; gap: clamp(1.4rem, 3vw, 2.2rem); }
.impact-cta {
  display: flex; flex-wrap: wrap; gap: .8rem 1.4rem; align-items: center;
  padding-top: 1.2rem; border-top: 1px solid var(--line);
}
.impact-cta p { font-size: 1.06rem; color: var(--ink-soft); max-width: 34rem; }

/* Card collection. Only shown once a PaymentIntent exists, so the donor never sees an empty form.
   The give-pay block is hidden while this is up -- two competing pay buttons is its own defect. */
.give-card-form { display: flex; flex-direction: column; gap: .8rem; }
.give-card-form[hidden] { display: none; }
.give-element { min-height: 3rem; }
.give-back {
  background: none; border: 0; cursor: pointer; align-self: center;
  font-family: var(--font-ui); font-size: .88rem; font-weight: 600;
  color: var(--ink-soft); text-decoration: underline; min-height: 44px;
}

/* ---------- keep in touch ---------- */
/* Sima: "there needs to be more ways for people to leave their information for re-engagement in
   the future." A $300K annual run rate is not closed by one-time gifts, so the visitor who is not
   ready today is the second most valuable person on the page -- if you can reach them again. */

.keep { background: var(--surface-2); border-block: 1px solid var(--line); padding-block: clamp(2.5rem, 6vw, 4rem); }
.keep-in { display: grid; gap: 1.6rem; align-items: center; }
@media (min-width: 56rem) { .keep-in { grid-template-columns: 1fr 24rem; gap: 3rem; } }
.keep h2 { font-size: clamp(1.5rem, 3.6vw, 2.1rem); margin-top: .4rem; }
.keep-sub { margin-top: .7rem; color: var(--ink-soft); font-size: 1rem; line-height: 1.5; max-width: 34rem; }
.keep-form { display: flex; flex-direction: column; gap: .6rem; }
.keep-form input, .keep-form select {
  font-family: var(--font-ui); font-size: 1rem; min-height: 48px;
  padding: .7rem .85rem; border: 1.5px solid var(--line-strong); border-radius: var(--r);
  background: var(--surface); color: var(--ink); width: 100%;
}
.keep-form input:focus, .keep-form select:focus { outline: 3px solid var(--accent); outline-offset: 1px; }
.keep-status { font-family: var(--font-ui); font-size: .9rem; margin-top: .2rem; }
.keep-status[hidden] { display: none; }
.keep-status[data-kind="ok"] { color: var(--good); }
.keep-status[data-kind="err"] { color: var(--hot); }
.give-status .sub-note {
  display: block; margin-top: .7rem; padding-top: .7rem;
  border-top: 1px solid color-mix(in srgb, currentColor 22%, transparent);
  font-size: .82rem; line-height: 1.45; font-weight: 500; opacity: .92;
}

/* ---------- routes: partner / artists / youth ---------- */
.routes { border-top: 1px solid var(--line); }
.ways { display: grid; gap: 1rem; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); margin-top: 1.8rem; }
.way { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); padding: 1.05rem 1.15rem 1.2rem; display: flex; flex-direction: column; gap: .35rem; }
.way b { font-family: var(--font-ui); font-size: .98rem; }
.way span { font-size: .92rem; color: var(--ink-soft); line-height: 1.45; }
.contact-card { margin-top: 1.8rem; background: var(--accent-soft); border-radius: var(--r-lg); padding: 1.35rem 1.4rem; }
.contact-card p { margin-bottom: .3rem; }
.contact-name { font-family: var(--font-ui); font-weight: 700; font-size: 1.08rem; }
/* The email and phone are the only route to a human at any gift size, and on a phone the tel:
   link is a real action, not a decoration. They were 19px tall. */
.contact-card a {
  color: var(--accent); font-family: var(--font-ui); font-weight: 600;
  display: inline-flex; align-items: center; min-height: 44px;
}
.contact-legal { margin-top: .8rem; font-size: .82rem; color: var(--ink-soft); line-height: 1.5; }

/* shared pillars grid -- variant A had its own copy; this is the one all three use */
.pillars { display: grid; gap: 1.2rem; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); margin-top: 2rem; }
.pillars article { background: var(--surface); border: 1px solid var(--line); border-radius: var(--r); overflow: hidden; }
.pillars img { aspect-ratio: 3/2; object-fit: cover; width: 100%; }
.pillars .in { padding: 1.05rem 1.15rem 1.3rem; display: flex; flex-direction: column; gap: .5rem; }
.pillars h3 { font-size: 1.1rem; line-height: 1.25; }
.pillars p { font-size: .93rem; color: var(--ink-soft); line-height: 1.5; }

/* ---------- post-gift monthly ask ---------- */
/* Shown only AFTER the one-time gift is banked. Declining is a real button, not a dismissal X --
   someone who has just given should never have to hunt for the way out. */
.give-upsell {
  margin-top: .9rem; padding: 1.1rem 1.15rem; border-radius: var(--r);
  background: var(--accent-soft); display: flex; flex-direction: column; gap: .5rem;
}
.give-upsell .up-q { font-family: var(--font-ui); font-weight: 700; font-size: 1.05rem; color: var(--accent); }
.give-upsell .up-w { font-size: .92rem; color: var(--ink-soft); line-height: 1.4; }
.give-upsell .up-btns { display: flex; flex-wrap: wrap; gap: .6rem; margin-top: .3rem; }
.give-upsell .up-yes { flex: 1 1 12rem; }
.give-upsell .up-no {
  background: none; border: 0; cursor: pointer; min-height: 48px; padding: 0 .6rem;
  font-family: var(--font-ui); font-size: .92rem; font-weight: 600;
  color: var(--ink-soft); text-decoration: underline;
}
/* Provenance on every headline figure. A reported number and a measured number look identical
   until someone says which it is -- and nobody could answer "what is the evidence for 200,000?" */
.impact-row .src {
  display: block; margin-top: .5rem; font-family: var(--font-ui);
  font-size: .7rem; line-height: 1.35; color: var(--ink-faint); font-style: normal;
}
/* Artist credits. The site's proposition is youth AND professional artists; the artists were
   invisible on every variant until the teaching-artist lens said so. */
.map-places em { display: block; font-style: normal; font-size: .74rem; color: var(--ink-faint); margin-top: .1rem; }
.geo-row em { font-style: normal; color: var(--ink-faint); }
/* Recurring disclosure. Stripe requires frequency, amount, how the amount is determined and the
   cancellation policy wherever credentials are stored -- and "can I stop it?" is the specific
   fear that stops people choosing monthly. */
.give-terms {
  background: var(--surface-2); border-left: 3px solid var(--accent);
  border-radius: var(--r); padding: .7rem .85rem;
  font-family: var(--font-ui); font-size: .82rem; line-height: 1.45; color: var(--ink-soft);
}
.give-terms[hidden] { display: none; }
/* Fee coverage. Default-on and removable. Deliberately NOT fine print: a pre-checked box that adds
   money is a dark pattern unless it is impossible to miss, so it sits directly above the pay
   button and every button states the total that will actually be charged. */
.give-fee {
  display: flex; gap: .6rem; align-items: flex-start; cursor: pointer;
  background: var(--surface-2); border-radius: var(--r); padding: .7rem .85rem;
  font-family: var(--font-ui); font-size: .86rem; line-height: 1.4; color: var(--ink);
}
.give-fee[hidden] { display: none; }
.give-fee input { width: 20px; height: 20px; margin: 0; flex: none; accent-color: var(--accent); }

.founder-bio { margin-top: 1.6rem; }
.founder-pull { border-left: 3px solid var(--accent); padding-left: 1.05rem; }
.founder-pull q { font-size: 1.05rem; line-height: 1.5; }
.founder-pull cite { display: block; margin-top: .5rem; font-style: normal;
  font-family: var(--font-ui); font-size: .84rem; color: var(--ink-soft); }
.founder-standing { margin: 1.2rem 0 0; padding-left: 1.1rem; display: grid; gap: .45rem; }
.founder-standing li { font-size: .95rem; line-height: 1.45; color: var(--ink-soft); }
.founder-links { margin-top: 1rem; font-family: var(--font-ui); font-size: .9rem; }
.founder-links a { color: var(--ink); text-underline-offset: 3px; }

/* --- Director: shared bones only. No decoration here; variants own the look. --- */
.director { position: relative; overflow: hidden; }
.director-backdrop {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; z-index: 0;
}
.director-in { position: relative; z-index: 2; display: grid; gap: 1.6rem; align-items: center; }
.director-portrait { margin: 0; }
.director-portrait img { display: block; width: 100%; height: auto; }
.director-headline { margin: .5rem 0 0; }
.director-headline q { quotes: none; }
.director-message { margin-top: 1rem; }
.director-message p { line-height: 1.6; }
.director-closing { margin-top: .9rem; line-height: 1.55; }
.director-attrib { margin-top: 1.2rem; font-family: var(--font-ui); display: flex;
  flex-wrap: wrap; align-items: baseline; gap: .1rem 1rem; }
.director-attrib b { font-size: 1rem; }
.director-attrib span { font-size: .88rem; opacity: .8; }
.director-standing-line { margin-top: .9rem; font-size: .86rem; line-height: 1.5; opacity: .72; }
@media (min-width: 56rem) {
  .director-in { grid-template-columns: 17rem 1fr; gap: 3rem; }
}


/* ---- "I am ..." route picker --------------------------------------------------------
   Six doors into the page, from the masthead. Renders from c["audiences"] -- the same list
   the route sections render from -- so the two cannot drift apart. A <details>, so it needs
   no JavaScript and answers the keyboard. Colours inherit, because this sits on variant A's
   dark hero and on B and C's light masthead. */
/* Sima, 2026-08-24: "make the top nav more visually distinct and more in line with I am.
   Could you please try a different font or maybe all caps". Caps and tracking do the work rather
   than a third typeface -- the masthead sits directly above a display-weight headline, and a new
   face there would fight it. Same face, same size, same tracking as the picker, so the two read
   as one row of controls instead of two unrelated things. */
.topbar nav a, .masthead nav a {
  font-family: var(--font-ui); font-size: .76rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .11em;
}

.iam { position: relative; font-family: var(--font-ui); }
.iam > summary {
  list-style: none; cursor: pointer; -webkit-user-select: none; user-select: none;
  font-size: .76rem; font-weight: 600; color: inherit; opacity: .9;
  text-transform: uppercase; letter-spacing: .11em;
  /* No frame. Sima, 2026-08-29: it read as a button sitting among plain nav items; the caret
     already says it opens. */
  padding: .5rem .4rem; border: 0; border-radius: var(--r);
  display: inline-flex; align-items: center; gap: .4rem; white-space: nowrap;
  /* 44px floor, the standard build/check_mobile.py enforces for the rest of the site. Measured at
     375px this summary was 40px and each menu row 43px -- close enough to look fine and small
     enough to miss with a thumb. */
  min-height: 44px;
}
.iam > summary::-webkit-details-marker { display: none; }
.iam > summary::after { content: "\25BE"; font-size: .7em; line-height: 1; }
.iam[open] > summary::after { content: "\25B4"; }
.iam > summary:hover, .iam > summary:focus-visible { opacity: 1; }
.iam-menu {
  /* Hangs from a control pinned to the right of the masthead, so it opens rightward. Left-
     aligned it ran off the viewport at 800px. Wide enough that the longest option -- "a corporate
     or foundation sponsor" -- sits on one line. */
  position: absolute; z-index: 40; top: calc(100% + .4rem); right: 0;
  min-width: 17.5rem; display: flex; flex-direction: column; padding: .35rem;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow);
}
.iam-menu a {
  text-decoration: none; color: var(--ink); font-size: .92rem; font-weight: 600;
  padding: .6rem .7rem; border-radius: var(--r); min-height: 44px;
  display: flex; align-items: center;
}
.iam-menu a:hover, .iam-menu a:focus-visible {
  background: var(--accent-soft); color: var(--accent); text-decoration: underline;
}
@media (max-width: 26rem) { .iam-menu { min-width: min(17.5rem, 78vw); } }


/* ---- the map inside "the work" ------------------------------------------------------
   Sima asked for the project map to sit with the work rather than only in variant C. It
   renders from c["projects"], the same array the tiles render from, so the dots, the tiles
   and the list cannot disagree about how many projects exist. */
.work-map { margin-top: 2.6rem; }
.work-map h3 {
  font-family: var(--font-display); font-weight: 700; margin-top: .3rem;
  font-size: clamp(1.1rem, 2.4vw, 1.45rem); letter-spacing: -.02em;
}


/* ---- the masthead mark --------------------------------------------------------------
   CITYarts' own logo, standing in as a placeholder at Sima's request. Sized by height so the
   bar keeps its rhythm whatever the logo's aspect ratio turns out to be, and the intrinsic
   width/height on the <img> stops it reflowing the masthead as it decodes. */
.mark-logo { display: inline-flex; align-items: center; line-height: 0; text-decoration: none; }
.mark-logo img { height: 34px; width: auto; display: block; }
@media (min-width: 54rem) { .mark-logo img { height: 40px; } }


/* ---- nav submenu --------------------------------------------------------------------
   Same <details> mechanism as the "I am" picker, deliberately: the masthead should have one
   interaction model, not two that look alike and behave differently. */
.navsub { position: relative; display: inline-block; }
.navsub > summary {
  list-style: none; cursor: pointer; -webkit-user-select: none; user-select: none;
  font-family: var(--font-ui); font-size: .76rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .11em; color: var(--ink-soft);
  display: inline-flex; align-items: center; gap: .3rem; min-height: 44px; white-space: nowrap;
}
.navsub > summary::-webkit-details-marker { display: none; }
.navsub > summary::after { content: "\25BE"; font-size: .7em; line-height: 1; }
.navsub[open] > summary::after { content: "\25B4"; }
.navsub > summary:hover, .navsub > summary:focus-visible { color: var(--ink); }
.navsub-menu {
  position: absolute; z-index: 40; top: calc(100% + .3rem); left: 50%; transform: translateX(-50%);
  min-width: 13rem; display: flex; flex-direction: column; padding: .35rem;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-lg); box-shadow: var(--shadow);
}
.navsub-menu a {
  text-decoration: none; color: var(--ink); font-size: .9rem; font-weight: 600;
  padding: .6rem .7rem; border-radius: var(--r); min-height: 44px;
  display: flex; align-items: center; text-transform: none; letter-spacing: 0;
}
.navsub-menu a:hover, .navsub-menu a:focus-visible {
  background: var(--accent-soft); color: var(--accent);
}

/* ---- the one audiences section ------------------------------------------------------
   Sima asked for the calls to action "all lined up in one line versus having them kind of
   break ... it's sort of uneven and it looks kind of out of balance". Descriptions differ in
   length, so a CTA that simply follows its paragraph sits at a different height in every card.
   margin-top:auto pushes it to the floor of the card instead, which is what puts them on one
   line regardless of how much text is above. */
.aud-grid {
  display: grid; gap: .9rem; margin-top: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.aud-card {
  display: flex; flex-direction: column; gap: .4rem; text-decoration: none;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  padding: 1.15rem 1.2rem 1.2rem; transition: border-color .12s ease;
}
.aud-card:hover, .aud-card:focus-visible { border-color: var(--accent); }
.aud-card .k {
  font-family: var(--font-ui); font-size: .67rem; font-weight: 700; letter-spacing: .13em;
  text-transform: uppercase; color: var(--accent-green);
}
.aud-card .l { font-family: var(--font-ui); font-weight: 700; font-size: 1.05rem; color: var(--ink); }
.aud-card .b { font-size: .92rem; color: var(--ink-soft); line-height: 1.45; }
.aud-card .c {
  margin-top: auto; padding-top: .8rem;
  font-family: var(--font-ui); font-size: .84rem; font-weight: 700; color: var(--accent);
}

/* ---- secondary pages ----------------------------------------------------------------- */
.page-h1 {
  font-family: var(--font-display); font-weight: 800; letter-spacing: -.035em;
  font-size: clamp(1.9rem, 4.6vw, 3rem); line-height: 1.06; margin-top: .4rem;
  text-wrap: balance;
}
.backlink { margin-top: 2.5rem; font-family: var(--font-ui); font-size: .9rem; font-weight: 600; }
.pull { margin: 1.2rem 0; }
.pull q {
  font-family: var(--font-display); font-weight: 700; quotes: none;
  font-size: clamp(1.3rem, 3vw, 1.9rem); line-height: 1.15; letter-spacing: -.025em; display: block;
}
.split-3 {
  display: grid; gap: 1.4rem; margin-top: 1.8rem;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.split-3 h3 { font-family: var(--font-ui); font-size: 1rem; font-weight: 700; }
.split-3 p { font-size: .95rem; color: var(--ink-soft); line-height: 1.5; margin-top: .3rem; }
.timeline { list-style: none; margin: 1.8rem 0 0; padding: 0; display: flex; flex-direction: column; }
.timeline li {
  display: grid; grid-template-columns: 5rem 1fr; gap: 1rem;
  padding: 1rem 0; border-top: 1px solid var(--line-soft);
}
.timeline li b {
  font-family: var(--font-ui); font-variant-numeric: tabular-nums;
  font-size: 1.05rem; color: var(--accent);
}
.timeline li span { color: var(--ink-soft); line-height: 1.5; }
.upcoming-grid {
  display: grid; gap: 1rem; margin-top: 1.8rem;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}
.upcoming-grid article {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 1.15rem 1.2rem;
}
.upcoming-grid h3 { font-family: var(--font-ui); font-size: 1.02rem; font-weight: 700; }
.upcoming-grid .meta {
  font-family: var(--font-ui); font-size: .72rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--accent-green); margin: .3rem 0 .5rem;
}
.upcoming-grid p { font-size: .93rem; color: var(--ink-soft); line-height: 1.45; }

/* ---- audience landing pages ---------------------------------------------------------- */
.page-hero { position: relative; height: clamp(11rem, 26vw, 20rem); overflow: hidden; background: var(--ink); }
.page-hero-img { width: 100%; height: 100%; object-fit: cover; opacity: .9; display: block; }
.page-cta { margin-top: 1.6rem; display: flex; flex-wrap: wrap; gap: .7rem; }
.page-voices {
  display: grid; gap: 1rem; margin-top: 1.6rem;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
}
.page-voices figure {
  margin: 0; background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: 1.2rem;
}
.page-voices blockquote {
  margin: 0; font-family: var(--font-body); font-size: 1.02rem; line-height: 1.5; color: var(--ink);
}
.page-voices figcaption {
  margin-top: .7rem; font-family: var(--font-ui); font-size: .78rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--accent-green);
}

/* ---- masthead actions: Sign up and Give, in line with the nav --------------------------
   Sima, 2026-08-24. The bar now carries four nav buckets plus two actions; .masthead-end keeps
   the picker and the actions together at the right so the row reads as one group rather than
   three things that happen to be adjacent. */
.masthead-end { display: flex; align-items: center; gap: .6rem; }
.nav-actions { display: flex; align-items: center; gap: .45rem; }
.btn-sm {
  padding: .45rem .85rem; min-height: 44px; font-size: .76rem; font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; white-space: nowrap;
  display: inline-flex; align-items: center;
}
/* Sign up used to be hidden below the nav breakpoint. It is not any more -- see the mobile
   header block at the end of this file, which follows the reference Sima sent. */

/* ---- Take action grid ---------------------------------------------------------------- */
.action-grid {
  display: grid; gap: .7rem; margin-top: 1.8rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.action-card {
  display: flex; align-items: center; justify-content: space-between; gap: .8rem;
  text-decoration: none; min-height: 56px; padding: .9rem 1.1rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
  font-family: var(--font-ui); font-weight: 700; font-size: .98rem; color: var(--ink);
  transition: border-color .12s ease;
}
.action-card:hover, .action-card:focus-visible { border-color: var(--accent); color: var(--accent); }
.action-card .c { color: var(--accent); font-size: 1.1rem; }

/* ---- map scope tabs -------------------------------------------------------------------
   Sima: "keep tabs on the map (remove from the top nav)". Radio inputs plus :checked
   selectors -- no JavaScript, works with scripting off, and the browser gives arrow-key
   navigation between radios in a group for free. Scope comes from each project's own
   coordinates, so adding a project to content/site.json files it correctly with no flag. */
.map-tabs { display: flex; flex-wrap: wrap; gap: .4rem; margin-bottom: 1rem; }
.map-tabs input { position: absolute; opacity: 0; pointer-events: none; }
.map-tabs label {
  font-family: var(--font-ui); font-size: .76rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; cursor: pointer; white-space: nowrap;
  padding: .55rem .9rem; min-height: 44px; display: inline-flex; align-items: center; gap: .4rem;
  border: 1px solid var(--line-strong); border-radius: 100px;
  color: var(--ink-soft); background: transparent;
}
.map-tabs label b { font-variant-numeric: tabular-nums; color: var(--ink-faint); }
.map-tabs label:hover { border-color: var(--ink); color: var(--ink); }
.map-tabs input:focus-visible + label { outline: 2px solid var(--accent); outline-offset: 2px; }
.map-tabs input:checked + label {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.map-tabs input:checked + label b { color: var(--accent-ink); opacity: .8; }

/* Default (All) shows everything; the other two hide the scope they exclude. */
#ms-us:checked    ~ svg .s-intl,
#ms-us:checked    ~ .map-places .s-intl { display: none; }
#ms-intl:checked  ~ svg .s-us,
#ms-intl:checked  ~ .map-places .s-us { display: none; }
@media (prefers-reduced-motion: no-preference) {
  .map-places span, .map .dot, .map .halo { transition: opacity .15s ease; }
}

/* ---- nav separator: the picker sits on the nav row ------------------------------------
   Sima: "I would almost move it at the same level ... maybe there's like a little tiny little
   separation like a dash". A hairline rather than a literal dash, so it separates without
   reading as a menu item of its own. */
.nav-sep { width: 1px; height: 1.1rem; background: var(--line-strong); opacity: .7; margin: 0 .2rem; flex: none; }
nav[aria-label="Main"] { display: flex; align-items: center; gap: 1.1rem; }

/* ---- the mobile menu ------------------------------------------------------------------
   Sima, 2026-08-28: "off the bat the mobile website doesn't have the main menu." It did not.
   The nav was display:none below 54rem with nothing in its place, and once the "I am" picker
   moved inside <nav>, phones lost the picker as well.

   One markup for both widths. BELOW 54rem the summary is a Menu button and the nav drops as a
   full-width panel. AT 54rem AND UP the summary is hidden and the nav is shown regardless of the
   open state, so the desktop bar never depends on a disclosure being toggled -- and a menu left
   open on a phone cannot leave the desktop layout in a strange state on rotate or resize. */
.navwrap { position: relative; }
.navtoggle {
  list-style: none; cursor: pointer; -webkit-user-select: none; user-select: none;
  display: inline-flex; align-items: center; gap: .5rem; min-height: 44px; padding: .4rem .2rem;
  font-family: var(--font-ui); font-size: .76rem; font-weight: 700;
  letter-spacing: .11em; text-transform: uppercase; color: var(--ink);
}
.navtoggle::-webkit-details-marker { display: none; }
/* Three bars from one element: the middle is the box, the outer two are box-shadows. Stacking
   three absolutely-positioned spans by hand produced overlapping, uneven rules. */
.navtoggle .bars {
  display: block; width: 20px; height: 2px; background: currentColor; position: relative;
  box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
}
.navwrap[open] .navtoggle .bars { box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor; }
.navwrap > nav { display: none; }
.navwrap[open] > nav {
  display: flex; flex-direction: column; align-items: stretch; gap: .2rem;
  position: absolute; z-index: 45; top: calc(100% + .5rem); left: 0;
  min-width: min(20rem, calc(100vw - 2rem)); padding: .5rem;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow);
}
/* On a phone the submenus and the picker open in place rather than floating off the panel. */
.navwrap[open] .navsub-menu, .navwrap[open] .iam-menu {
  position: static; transform: none; box-shadow: none; border: 0;
  min-width: 0; padding: 0 0 .3rem .8rem; background: transparent;
}
.navwrap[open] .nav-sep { width: auto; height: 1px; margin: .35rem 0; }
.navwrap[open] .navsub, .navwrap[open] .iam { width: 100%; }
.navwrap[open] .navsub > summary, .navwrap[open] .iam > summary { width: 100%; justify-content: space-between; }

@media (min-width: 54rem) {
  .navtoggle { display: none; }
  /* A CLOSED <details> HIDES ITS OWN CONTENT, and styling the child does not override that.
     Chrome now does the hiding on ::details-content with content-visibility, so display:flex on
     the <nav> left it laid out at ZERO WIDTH -- present, flex, and invisible. That is what broke
     the desktop bar when the nav was wrapped in a disclosure for the mobile menu: the whole nav
     and the picker vanished above 54rem while every rule looked right.
     Both mechanisms are covered: this line for the modern one, the display rules below for
     engines that still put display:none on the children. */
  .navwrap::details-content { content-visibility: visible; display: contents; }
  .navwrap > nav, .navwrap[open] > nav {
    display: flex; flex-direction: row; align-items: center; gap: 1.1rem;
    position: static; padding: 0; background: none; border: 0; box-shadow: none; min-width: 0;
  }
  .navwrap[open] .navsub-menu, .navwrap[open] .iam-menu {
    position: absolute; padding: .35rem; background: var(--surface);
    border: 1px solid var(--line); box-shadow: var(--shadow); border-radius: var(--r-lg);
  }
  .navwrap[open] .navsub-menu { transform: translateX(-50%); min-width: 13rem; }
  .navwrap[open] .iam-menu { min-width: 17.5rem; }
  .navwrap[open] .nav-sep { width: 1px; height: 1.1rem; margin: 0 .2rem; }
  .navwrap[open] .navsub, .navwrap[open] .iam { width: auto; }
}

/* ---- founder: an attributed quote, and a placeholder signature ------------------------- */
.director-headline cite {
  display: block; margin-top: .8rem; font-style: normal;
  font-family: var(--font-ui); font-size: .8rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; opacity: .8;
}
.director-attrib span { font-weight: 600; }
.director-signature {
  font-family: "Newsreader", Georgia, serif; font-style: italic; font-size: 1.6rem;
  margin-top: 1.2rem; opacity: .9;
}
.director-signature::after {
  content: " (placeholder signature)"; font-family: var(--font-ui); font-style: normal;
  font-size: .62rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  opacity: .55; vertical-align: middle;
}

/* ---- per-audience forms ---------------------------------------------------------------
   Every control clears the 44px tap floor the mobile gate enforces. The notice is deliberately
   loud: the form has no destination yet, and someone filling it in believing CITYarts received
   it would be the worst outcome this page could produce. */
.aud-form { margin-top: 1.4rem; max-width: 34rem; display: flex; flex-direction: column; gap: .9rem; }
.form-notice {
  background: var(--wait-soft, var(--surface-2)); border-left: 3px solid var(--warn);
  padding: .9rem 1rem; border-radius: var(--r); font-size: .92rem; color: var(--ink-soft);
  line-height: 1.45;
}
.form-notice b { color: var(--ink); }
.aud-form .field { display: flex; flex-direction: column; gap: .35rem; margin: 0; }
.aud-form label {
  font-family: var(--font-ui); font-size: .78rem; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase; color: var(--ink-soft);
}
.aud-form input, .aud-form select, .aud-form textarea {
  font: inherit; font-size: 1rem; color: var(--ink); background: var(--surface);
  border: 1px solid var(--line-strong); border-radius: var(--r);
  padding: .7rem .8rem; min-height: 44px; width: 100%;
}
.aud-form textarea { min-height: 88px; resize: vertical; }
.aud-form input:focus-visible, .aud-form select:focus-visible, .aud-form textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent);
}
.aud-form button[disabled] { opacity: .55; cursor: not-allowed; }

/* ---- mobile header, following the charity: water pattern Sima sent -----------------------
   Hamburger hard left, logo beside it, then a plain text link, a hairline rule, and the filled
   giving button. Three changes from what was here: the toggle moves from the middle to the far
   left, it loses its "Menu" label and becomes icon-only, and Sign up comes back on phones -- it
   had been display:none below the nav breakpoint, so a phone could not sign up at all. */
.act-link {
  font-family: var(--font-ui); font-size: .76rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; text-decoration: none;
  color: var(--ink-soft); display: inline-flex; align-items: center;
  min-height: 44px; padding: 0 .2rem; white-space: nowrap;
}
.act-link:hover, .act-link:focus-visible { color: var(--ink); }
.act-sep { width: 1px; height: 1.2rem; background: var(--line-strong); opacity: .8; flex: none; }
.nav-actions { display: flex; align-items: center; gap: .7rem; }

@media (max-width: 53.9375rem) {
  /* Order, not markup order: the logo stays first in the DOM so it is the first thing a screen
     reader meets, while the toggle sits first visually. */
  .navwrap { order: -1; }
  .masthead { gap: .6rem; }
  .navtoggle { padding: .4rem .1rem; }
  .navtoggle-label { position: absolute; width: 1px; height: 1px; overflow: hidden;
    clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; }
  .mark-logo { margin-right: auto; }
  /* This was hiding Sign up entirely on phones. The reference keeps it, and so should we. */
  .nav-actions .btn-ghost, .nav-actions .act-link { display: inline-flex; }
  .nav-actions { gap: .5rem; }
  .act-link { font-size: .7rem; letter-spacing: .08em; }
}
