/* Barnraise · transit signage
   Mid-century transit signage after Vignelli: strict grid, hairline rules, sharp
   corners, zero ornament. Surfaces are flat plates layered by luminance, never
   soft cards with shadows. Density is preferred to air.

   One rule governs colour: each organization owns a route colour, and cream is
   reserved for an agreement that both parties have signed. Cream appears nowhere
   else, so cream means done. */

:root {
  /* field and plates */
  --field:        #091421;
  --plate-low:    #121c2a;
  --plate:        #16202e;
  --plate-high:   #212a39;
  --plate-top:    #2b3544;

  --ink:          #d9e3f6;
  --ink-soft:     #a8b3c6;   /* raised from the Stitch value to clear 4.5:1 */
  --ink-faint:    #8e97a6;
  --rule:         rgba(217, 227, 246, 0.14);
  --rule-soft:    rgba(217, 227, 246, 0.07);
  --edge-top:     rgba(255, 255, 255, 0.06);

  /* One organization, one colour, used for that organization and nothing else:
     map route, ledger capsule, feed dot, requirement matrix.

     These were isoluminant on purpose, so that no organization would read as
     more important than another. That was the wrong call and it made the set
     unusable: L* 71 to 80 is a spread of nine points out of a hundred, which in
     greyscale is one colour, and a glance at a 10px dot could not tell six
     things apart. The eye separates by lightness before it separates by hue.
     They now climb a ladder, 54 61 68 74 80 87, keeping their hues, and the
     closest pair went from a CIE distance of 27 to 36. Every one clears 4.5:1
     against the field. */
  --route-food:   #f18a63;
  --route-lib:    #06d9fa;
  --route-school: #fdd669;
  --route-health: #6cc892;
  --route-kitchen:#c677c7;
  --route-youth:  #5f7ed1;

  /* states */
  --signed:       #f0e7d6;   /* cream. Only a fully signed agreement. */
  --signed-ink:   #1b2430;
  /* Attention and success are carried by INK and elevation, not by hue.
     --waiting used to be the same value as --route-food, so coral meant both
     "North Food Bank" and "this needs you", and both appeared in the same
     500px strip of the header meaning different things. --ok was a fourth
     accent nobody declared. The system now has exactly three chromatic
     identities, one for each organization, plus cream for a signed agreement. */
  --waiting:      #f2f6ff;
  --ok:           #f2f6ff;
  --danger:       #ffb4ab;

  --font-ui:   "Archivo Narrow", "Archivo", "Segoe UI", sans-serif;
  --font-mono: "JetBrains Mono", "IBM Plex Mono", Consolas, monospace;

  --t-micro: 0.6875rem;
  --t-small: 0.8125rem;
  --t-body:  0.9375rem;
  --t-lead:  1.1875rem;
  --t-h3:    1.5rem;
  --t-h2:    2.25rem;
  --t-h1:    clamp(2.25rem, 1.4rem + 3vw, 3.75rem);
  --t-mega:  clamp(3.5rem, 2rem + 6.5vw, 7rem);

  /* Ma: 2px to 160px */
  --s-1: 0.25rem;  --s-2: 0.5rem;  --s-3: 0.75rem; --s-4: 1rem;
  --s-6: 1.5rem;   --s-8: 2rem;    --s-12: 3rem;   --s-16: 4rem;  --s-24: 6rem;

  --ease-enter: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-move:  cubic-bezier(0.77, 0, 0.175, 1);
  --d-micro: 130ms;
  --d-ui:    200ms;
  --d-enter: 260ms;

  --gutter: 1px;   /* the hairline between plates. This is the whole look. */
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

body {
  margin: 0;
  background: var(--field);
  color: var(--ink);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: 1.5;
  font-variant-numeric: tabular-nums lining-nums slashed-zero;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; font-weight: 600; text-wrap: balance; }
p { margin: 0; text-wrap: pretty; }
ol, ul, dl { margin: 0; padding: 0; list-style: none; }

.mono { font-family: var(--font-mono); }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap;
}

/* ---------- icons ---------- */
.ico {
  width: 1.125rem; height: 1.125rem; flex: none;
  fill: none; stroke: currentColor; stroke-width: 11;
  stroke-linecap: round; stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.ico--lg { width: 1.75rem; height: 1.75rem; }

/* ---------- top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4);
  padding: var(--s-3) var(--s-6);
  background: var(--field);
  border-bottom: 1px solid var(--rule);
}
.brand { display: flex; align-items: center; gap: var(--s-3); }
.brand__mark { width: 1.75rem; height: 1.75rem; color: var(--ink); }
.wordmark {
  font-size: 1.25rem; font-weight: 700; letter-spacing: 0.02em;
  text-transform: uppercase;
}
.topbar__right { display: flex; align-items: center; gap: var(--s-4); }

/* The identity chip: who you are is the first question this screen answers. */
.identity {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  background: var(--plate);
  border: 1px solid var(--rule);
  font-family: var(--font-mono);
  font-size: var(--t-small);
  color: var(--ink);
  cursor: pointer;
}
.identity:hover { border-color: var(--ink-faint); }
.identity:focus-visible { outline: 2px solid var(--waiting); outline-offset: 2px; }
.identity__label { color: var(--ink-faint); }
.identity__dot { width: 8px; height: 8px; border-radius: 50%; flex: none; }

.live {
  display: flex; align-items: center; gap: var(--s-2);
  font-family: var(--font-mono); font-size: var(--t-micro);
  text-transform: uppercase; letter-spacing: 0.1em;
  color: var(--ink-faint); white-space: nowrap;
}
/* The server's idle phase is "inactiva", not "idle", so this selector matched
   from the first state response onward and the icon pulsed permanently. On
   mobile, where the text is hidden, a forever-pulsing icon was the only status
   signal the page had, and it always said a round was running. */
.live[data-fase]:not([data-fase="idle"]):not([data-fase="inactiva"]) { color: var(--waiting); }
.live[data-fase]:not([data-fase="idle"]):not([data-fase="inactiva"]) .ico { animation: pulse 1.8s var(--ease-move) infinite; }
/* The status chip is the longest string in the header. Without a floor it grew
   into the frame bleed: "NEGOTIATING TERMS" landed 6px from the edge of a 1920
   render, inside the title-safe area any player with overscan will clip. */
.live { min-width: 15.5rem; justify-content: flex-end; }
@keyframes pulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(0.82); } }

/* ---------- shell ---------- */
/* ---------- the stage ----------
   The map is the product, so it holds the viewport and everything else reads as
   a panel over it. The page used to be a six-thousand-pixel column with the map
   in section four, which buried the one surface that explains what this is. */
html, body { height: 100%; }
body { overflow: hidden; }

.stage {
  position: absolute; inset: 3.5rem 0 0 0;
}
.stage__map { position: absolute; inset: 0; }
.stage__map canvas { outline: none; }

.disclosure {
  position: absolute; right: var(--s-6); top: var(--s-4); z-index: 10;
  max-width: 30rem; margin: 0;
  padding: var(--s-3) var(--s-4);
  background: rgba(9, 20, 33, 0.82);
  backdrop-filter: blur(6px);
  border: 1px solid var(--rule-soft);
  font-family: var(--font-mono); font-size: var(--t-micro);
  line-height: 1.6; color: var(--ink-faint);
}

.panel {
  position: absolute; left: var(--s-6); top: var(--s-4); bottom: var(--s-4);
  z-index: 20;
  width: min(30rem, calc(100vw - 2 * var(--s-6)));
  display: flex; flex-direction: column;
  background: rgba(9, 20, 33, 0.93);
  backdrop-filter: blur(10px);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.panel__body { flex: 1; min-height: 0; display: flex; flex-direction: column;
               overflow-y: auto; overscroll-behavior: contain; padding: var(--s-6); }
/* The feed is the subject of the live view, so it takes the space that is left
   rather than a fixed 560px that ran past the bottom of the panel and hid every
   message the moment one arrived. */
.view-pane[data-pane="now"] { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.view-pane[data-pane="now"] .feed-block { flex: 1; min-height: 0; }
.panel__body > * + * { margin-top: var(--s-6); }

.views { display: flex; border-bottom: 1px solid var(--rule); flex: none; }
.view {
  flex: 1; appearance: none; background: none; border: 0;
  display: flex; align-items: center; justify-content: center; gap: var(--s-2);
  padding: var(--s-4) var(--s-3);
  font-family: var(--font-mono); font-size: var(--t-micro);
  text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-faint); cursor: pointer;
  border-bottom: 2px solid transparent;
  transition: color var(--d-fast) var(--ease-out), border-color var(--d-fast) var(--ease-out);
}
.view:hover { color: var(--ink-soft); }
.view[aria-current="true"] { color: var(--ink); border-bottom-color: var(--ink); }
.view:focus-visible { outline: 2px solid var(--waiting); outline-offset: -2px; }
.view .ico { width: 15px; height: 15px; flex: none; }
.view__n {
  font-size: 10px; letter-spacing: 0.04em;
  padding: 1px 5px; border: 1px solid var(--rule);
  color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
.view[aria-current="true"] .view__n { color: var(--ink); border-color: var(--ink-faint); }

.view-pane > * + * { margin-top: var(--s-6); }
.run { display: flex; flex-direction: column; gap: var(--s-3); align-items: flex-start; }
.feed-block { display: flex; flex-direction: column; gap: var(--s-3); }

.maplegend {
  position: absolute; left: calc(30rem + 2 * var(--s-6)); bottom: var(--s-6); z-index: 15;
  display: flex; flex-direction: column; gap: var(--s-2);
  padding: var(--s-3) var(--s-4);
  background: rgba(9, 20, 33, 0.86);
  backdrop-filter: blur(6px);
  border: 1px solid var(--rule-soft);
  font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint);
}
.maplegend__key { display: flex; align-items: center; gap: var(--s-3); }
.maplegend__line { width: 26px; height: 4px; flex: none; border-radius: 2px;
                   background: var(--route-lib); box-shadow: 0 0 0 2px #04080e; }
.maplegend__pin, .maplegend__wait {
  width: 12px; height: 12px; flex: none; border-radius: 50%;
  background: var(--field); border: 2px solid var(--route-kitchen);
}
.maplegend__wait { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(217, 227, 246, 0.28); }
@media (max-width: 68rem) { .maplegend { display: none; } }

/* ---------- pins ---------- */
.pin {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  font-family: var(--font-ui);
}
.pin__disc {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 11px; font-weight: 700;
  letter-spacing: 0.02em;
  background: var(--field); color: var(--ink);
  border: 2px solid currentColor;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.55);
  transition: transform var(--d-fast) var(--ease-out);
}
.pin__name {
  font-size: 11px; font-weight: 600; letter-spacing: 0.01em;
  color: var(--ink); white-space: nowrap;
  padding: 2px 6px;
  background: rgba(9, 20, 33, 0.86);
  border: 1px solid var(--rule-soft);
}
.pin:hover .pin__disc { transform: scale(1.12); }
.pin:focus-visible { outline: 2px solid var(--waiting); outline-offset: 4px; }
.pin--food   { color: var(--route-food); }
.pin--lib    { color: var(--route-lib); }
.pin--school { color: var(--route-school); }
.pin--health { color: var(--route-health); }
.pin--kitchen{ color: var(--route-kitchen); }
.pin--youth  { color: var(--route-youth); }
.pin--hit .pin__disc { animation: station-hit 560ms cubic-bezier(0.23, 1, 0.32, 1); }
/* A director has something to decide here. This is the only place the map ever
   asks for a person, which is the answer to "where do I come in". */
.pin--waiting .pin__disc { box-shadow: 0 0 0 3px rgba(217, 227, 246, 0.28), 0 2px 10px rgba(0,0,0,0.55); }
.pin--waiting .pin__name { color: var(--field); background: var(--ink); border-color: var(--ink); }

/* Where this director stands. */
/* The organization reads through the eyebrow and a wash of its own colour across
   the whole block. It used to be a 3px coloured stripe down the left edge, which
   is the single most recognisable tell of a generated interface. */
.youare { border: 1px solid var(--rule); padding: var(--s-4);
          background:
            linear-gradient(100deg, color-mix(in oklab, var(--org) 14%, transparent), transparent 62%),
            var(--plate-low); }
.youare__eyebrow { color: var(--org); }
.youare--food   { --org: var(--route-food); }
.youare--lib    { --org: var(--route-lib); }
.youare--school { --org: var(--route-school); }
.youare--health { --org: var(--route-health); }
.youare--kitchen{ --org: var(--route-kitchen); }
.youare--youth  { --org: var(--route-youth); }
.youare__who { margin: var(--s-1) 0 var(--s-3); font-size: var(--t-body); }
.youare__facts { list-style: none; margin: 0; padding: 0;
                 display: flex; flex-direction: column; gap: var(--s-2);
                 font-size: var(--t-small); color: var(--ink-soft); }
.youare__n { font-family: var(--font-mono); font-weight: 700; color: var(--ink);
             font-variant-numeric: tabular-nums; margin-right: var(--s-2); }
.youare .hint { margin-top: var(--s-3); }

/* The organization you are viewing as. A ring rather than a colour, because the
   colour on a pin already means which organization it is. */
.pin--me .pin__disc { box-shadow: 0 0 0 2px var(--field), 0 0 0 4px currentColor,
                                  0 2px 10px rgba(0, 0, 0, 0.55); }
.pin--me .pin__name { font-weight: 700; }

/* ---------- the selected organization ---------- */
.orgcard { position: relative; background: var(--plate); border: 1px solid var(--rule); padding: var(--s-6); }
/* The building, so an organization is a place rather than a row of text. The
   image is decorative: everything it conveys is also written beside it, which is
   why the alt is empty rather than a description a screen reader must sit
   through. */
.orgcard__shot {
  margin: calc(-1 * var(--s-6)) calc(-1 * var(--s-6)) var(--s-4);
  aspect-ratio: 16 / 7; overflow: hidden; background: var(--plate-low);
}
.orgcard__shot img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  /* Pulled toward the ground so six photographs from six angles still read as
     one set and do not fight the interface they sit in. */
  filter: saturate(0.72) contrast(1.04) brightness(0.82);
}
.orgcard__shot::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0;
  height: calc(var(--s-6) + 1px); pointer-events: none;
}
.orgcard--food   { border-left: 0; box-shadow: inset 3px 0 0 var(--route-food); }
.orgcard--lib    { box-shadow: inset 3px 0 0 var(--route-lib); }
.orgcard--school { box-shadow: inset 3px 0 0 var(--route-school); }
.orgcard--health { box-shadow: inset 3px 0 0 var(--route-health); }
.orgcard--kitchen{ box-shadow: inset 3px 0 0 var(--route-kitchen); }
.orgcard--youth  { box-shadow: inset 3px 0 0 var(--route-youth); }
.orgcard__name { margin: var(--s-1) 0 var(--s-2); font-size: var(--t-h3); letter-spacing: -0.015em; }
.orgcard__desc { margin: var(--s-3) 0 0; color: var(--ink-soft); font-size: var(--t-small); }
.orgcard__sub { margin-top: var(--s-6); }
.orgcard__close {
  position: absolute; top: var(--s-3); right: var(--s-3);
  appearance: none; background: none; border: 0; padding: var(--s-2);
  color: var(--ink-faint); cursor: pointer;
}
.orgcard__close:hover { color: var(--ink); }
.dists { list-style: none; margin: var(--s-3) 0 0; padding: 0;
         display: flex; flex-direction: column; gap: var(--s-2); }
.dists li { display: flex; align-items: center; gap: var(--s-2);
            font-size: var(--t-small); color: var(--ink-soft); }
.dists__n { margin-left: auto; font-family: var(--font-mono);
            font-size: var(--t-micro); color: var(--ink-faint);
            font-variant-numeric: tabular-nums; }

/* MapLibre's own furniture, brought into the palette. */
.maplibregl-ctrl-group { background: var(--plate); border: 1px solid var(--rule); box-shadow: none; }
.maplibregl-ctrl-group button + button { border-top: 1px solid var(--rule); }
.maplibregl-ctrl-group button span { filter: invert(1) opacity(0.7); }
.maplibregl-ctrl-attrib { background: rgba(9, 20, 33, 0.8) !important; }
.maplibregl-ctrl-attrib a { color: var(--ink-faint) !important; }

.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--ink-faint);
}
.eyebrow--alert { color: var(--waiting); }
.label {
  font-family: var(--font-mono);
  font-size: var(--t-micro); text-transform: uppercase; letter-spacing: 0.12em;
  color: var(--ink-faint); white-space: nowrap;
}
/* The ledger's headline is the only label whose length is data: it grows a part
   for every state present, and at three parts the nowrap inherited from .label
   ran it past the panel and clipped the last count. A summary that says "8
   agreements" and then shows a breakdown adding up to seven is worse than no
   breakdown, so this one wraps. */
#ledger-legend { white-space: normal; line-height: 1.7; }

.hint { font-size: var(--t-small); color: var(--ink-soft); }

/* The public demo notice. It sits where the round button's own hint sits, reads
   as part of the panel rather than as a banner pasted over it, and carries the
   one colour the interface reserves for something a director must act on. */
.hint--demo {
  margin-top: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: rgba(6, 217, 250, 0.06);
  border: 1px solid rgba(6, 217, 250, 0.24);
  border-radius: 3px;
  line-height: 1.55;
}
.hint--demo strong { color: var(--ink); font-weight: 600; }
.hint--demo a { color: var(--route-lib); }

.section-head {
  display: flex; align-items: baseline; justify-content: space-between;
  flex-wrap: wrap; gap: var(--s-4);
  padding-bottom: var(--s-3);
  border-bottom: 1px solid var(--rule);
  margin-bottom: var(--s-6);
}
.section-title { scroll-margin-top: 5.5rem;
  display: flex; align-items: center; gap: var(--s-3);
  font-size: var(--t-h3); letter-spacing: -0.01em;
}
.section-title .ico { color: var(--ink-faint); }

/* ---------- decision: the reason anyone opens this screen ---------- */
.decision {
  border: 1px solid rgba(217, 227, 246, 0.34);
  background: var(--plate);
  box-shadow: inset 0 1px 0 var(--edge-top);
}
.decision__head {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4) var(--s-6);
  border-bottom: 1px solid var(--rule);
}
.decision__head .ico { color: var(--waiting); }
.decision__body { padding: var(--s-6); }
.decision__title {
  font-size: var(--t-h3); letter-spacing: -0.015em; line-height: 1.15;
  margin-bottom: var(--s-4);
}
.decision__title:focus-visible { outline: 2px solid var(--waiting); outline-offset: 4px; }

.terms { display: grid; gap: var(--gutter); background: var(--rule-soft); margin-bottom: var(--s-6); }
/* Label above value, not beside it. A 13rem label column inside a 430px panel
   left 110px for the value and broke every term to one word per line. The panel
   is narrow everywhere now, so this is not a small-screen exception. */
.term {
  display: flex; flex-direction: column; gap: var(--s-1);
  background: var(--plate-low);
  padding: var(--s-3) var(--s-4);
}
.term__k { font-family: var(--font-mono); font-size: var(--t-micro);
           text-transform: uppercase; letter-spacing: 0.1em; color: var(--ink-faint); }
.term__v { font-family: var(--font-mono); font-size: var(--t-small); color: var(--ink);
           line-height: 1.55; }

.decision__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); align-items: center; }
.decision__note { font-size: var(--t-small); color: var(--ink-soft); margin-top: var(--s-4); }

/* nothing pending is a state, not an absence */
.allclear {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-6);
  background: var(--plate-low);
  border: 1px solid var(--rule);
}
.allclear .ico { color: var(--ok); }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 0.625rem 1.125rem; min-height: 44px;
  font: inherit; font-size: var(--t-small); font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--ink); background: var(--plate-high);
  border: 1px solid var(--rule); border-radius: 0;
  cursor: pointer;
  transition: transform var(--d-micro) var(--ease-enter),
              background-color var(--d-ui) var(--ease-enter),
              border-color var(--d-ui) var(--ease-enter);
}
.btn:hover { border-color: var(--ink-faint); background: var(--plate-top); }
.btn:active { transform: scale(0.97); }
.btn:focus-visible { outline: 2px solid var(--waiting); outline-offset: 2px; }
.btn[aria-disabled="true"] { color: var(--ink-faint); background: var(--plate-low); cursor: wait; }

/* Not cream. Cream is the one reserved colour in this system and it means an
   agreement both organizations signed; putting it on the button that STARTS a
   signature made it mean the act as well as the result, in the same frame. */
.btn--primary { background: var(--ink); color: var(--field); border-color: var(--ink); }
.btn--primary:hover { background: #eef3ff; border-color: #eef3ff; }
.btn--primary:hover { background: #fff6e8; border-color: #fff6e8; }
.btn--small { padding: 0.5rem 0.75rem; min-height: 40px; font-size: var(--t-micro); }
.btn--quiet { background: transparent; }

/* ---------- funding call ---------- */
.fund { background: var(--plate); border: 1px solid var(--rule); }
.fund__head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap;
  padding: 0 0 var(--s-6);
  border-bottom: 1px solid var(--rule);
}
.fund__name { font-size: var(--t-h2); letter-spacing: -0.02em; margin-top: var(--s-2); }
.amount { display: flex; align-items: baseline; gap: var(--s-2); }
.amount__n {
  font-size: var(--t-h1); font-weight: 700; letter-spacing: -0.035em;
  line-height: 0.9; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.amount__unit { font-family: var(--font-mono); font-size: var(--t-small); color: var(--ink-faint); }

.reqs { display: grid; gap: var(--gutter); background: var(--rule-soft); }
/* Three columns for a full-width page put every requirement's description into a
   column narrow enough to break one word per line inside the panel. The id and
   the coverage share a row, the sentence gets the full width under them. */
.req {
  display: grid; grid-template-columns: 4rem minmax(0, 1fr);
  gap: var(--s-2) var(--s-3); align-items: baseline;
  background: var(--plate); padding: var(--s-4);
  font-size: var(--t-small);
}
.req--hero { background: var(--plate-high); }
.req--hero .label { display: block; margin-top: var(--s-1); color: var(--waiting); }
.req__id { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint); }
.req__who { grid-column: 2; display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap; }
.req__text { grid-column: 2; }

/* route capsule: an organization, in its own colour */
.cap {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 0.15rem 0.5rem;
  font-family: var(--font-mono); font-size: var(--t-micro);
  color: var(--field); font-weight: 600; white-space: nowrap;
}
.cap--food   { background: var(--route-food); }
.cap--lib    { background: var(--route-lib); }
.cap--school { background: var(--route-school); }
.cap--youth { background: var(--route-youth); }
.cap--kitchen { background: var(--route-kitchen); }
.cap--health { background: var(--route-health); }
.cap--all    { background: transparent; color: var(--ink-soft); border: 1px dashed var(--rule); }

/* alone vs together */
/* Six organizations plus the combined figure is seven columns, which was
   unreadable at any panel width. A row each: the count, a bar, the name. */
.alone { display: flex; flex-direction: column; gap: var(--gutter);
         background: var(--rule-soft); margin-top: var(--s-6); }
.alone__col {
  background: var(--plate-low); padding: var(--s-3) var(--s-4);
  display: grid; grid-template-columns: 2.6rem minmax(0, 1fr) auto;
  gap: var(--s-3); align-items: center;
}
.alone__n { font-size: var(--t-h3); font-weight: 700; letter-spacing: -0.02em;
            line-height: 1; font-variant-numeric: tabular-nums; }
.alone__of { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint); }
.alone__who { margin: 0; }
.alone__bar { grid-column: 1 / -1; height: 3px; background: var(--rule-soft); }
.alone__bar i { display: block; height: 100%; background: var(--ink-faint);
                transform-origin: left; }
.alone--together { background: var(--plate-high); }
.alone--together .alone__bar i { background: var(--ink); }

/* ---------- ledger ---------- */
.ledger { display: grid; gap: var(--gutter); background: var(--rule-soft); }
.entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: var(--s-3);
  background: var(--plate); padding: var(--s-4);
  font-size: var(--t-small);
}
.entry__n {
  font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint);
  align-self: center;
}
.entry__side {
  grid-column: 1 / -1; min-width: 0;
  padding-left: var(--s-4); border-left: 1px solid var(--rule-soft);
}
.entry__side + .entry__side { margin-top: calc(-1 * var(--s-1)); }
.entry__org { font-weight: 600; font-size: var(--t-body); }
.entry__what { display: block; font-family: var(--font-mono); font-size: var(--t-small);
               opacity: 0.92; margin-top: var(--s-1); }
.entry__meta { display: block; font-family: var(--font-mono); font-size: var(--t-micro);
               color: var(--ink-faint); margin-top: var(--s-2); }
.entry__sign {
  grid-row: 1; grid-column: 2;
  display: flex; align-items: center; gap: var(--s-3); justify-content: flex-end;
}
.entry__state {
  font-family: var(--font-mono); font-size: var(--t-micro);
  text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--ink-faint); text-align: right;
}
.entry__prov {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; gap: var(--s-1) var(--s-4);
  font-family: var(--font-mono); font-size: var(--t-micro);
  color: var(--ink-faint);
  padding-top: var(--s-3);
  border-top: 1px solid var(--rule-soft);
}
.entry--signed { background: var(--signed); color: var(--signed-ink); }
.entry--signed .label, .entry--signed .entry__meta,
.entry--signed .entry__n, .entry--signed .entry__state { color: #5c6470; }
.entry--signed .entry__side { border-left-color: rgba(27, 36, 48, 0.16); }
.entry--signed .entry__prov { color: #6b7280; border-top-color: rgba(27, 36, 48, 0.14); }

.section-head__aside { display: flex; align-items: center; gap: var(--s-4); flex-wrap: wrap; }
/* Cream is the whole colour system in one rule: signed, and nothing else. */
.entry--signed { background: var(--signed); color: var(--signed-ink); }
.entry--signed .label, .entry--signed .entry__meta { color: #5c6470; }
.entry__n { font-family: var(--font-mono); font-size: var(--t-small); color: var(--ink-faint); }
.entry--signed .entry__n { color: #5c6470; }
.entry__side { min-width: 0; }
.entry__org { font-weight: 600; font-size: var(--t-body); }
/* Three steps, not six. The row carried six text runs spanning a 1.3x range,
   so hierarchy inside it was doing nothing and the distinctions vanished
   entirely at film scale. Organization name, resource, then everything else. */
.entry__what { display: block; font-family: var(--font-mono); font-size: var(--t-small); opacity: 0.92; margin-top: var(--s-1); }
.entry__meta { display: block; font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint); margin-top: var(--s-2); }
.entry__sign { display: flex; align-items: center; gap: var(--s-2); justify-content: flex-end; }

/* the two-signature capsule: half filled means half signed */
.seal { display: flex; }
.seal__half {
  width: 2.1rem; padding: 0.15rem 0;
  font-family: var(--font-mono); font-size: 0.625rem; font-weight: 700;
  text-align: center;
  border: 1px solid var(--rule);
  color: var(--ink-faint);
}
.seal__half--food   { border-color: var(--route-food); }
.seal__half--lib    { border-color: var(--route-lib); }
.seal__half--school { border-color: var(--route-school); }
.seal__half--youth { border-color: var(--route-youth); }
.seal__half--kitchen { border-color: var(--route-kitchen); }
.seal__half--health { border-color: var(--route-health); }
.seal__half--on.seal__half--food   { background: var(--route-food); color: var(--field); }
.seal__half--on.seal__half--lib    { background: var(--route-lib); color: var(--field); }
.seal__half--on.seal__half--school { background: var(--route-school); color: var(--field); }

/* ---------- network: map and feed ---------- */
.network { display: grid; grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); gap: var(--s-8); align-items: start; }
.map-wrap { background: var(--plate-low); border: 1px solid var(--rule); padding: var(--s-4); }
.map { width: 100%; height: auto; display: block; overflow: visible; }
.map__grid { stroke: var(--rule-soft); stroke-width: 1; }
/* Labels are drawn with a halo in the ground colour, the way a printed transit
   map does it, so a route that must pass behind a label never cuts its glyphs.
   paint-order puts the stroke under the fill; without it the halo covers the
   letterform it is meant to protect. */
.map__label, .map__meta {
  paint-order: stroke fill;
  stroke: var(--field);
  stroke-width: 5px;
  stroke-linejoin: round;
}
.map__route { fill: none; stroke-linecap: round; stroke-linejoin: round; }
.map__route--food   { stroke: var(--route-food); }
.map__route--lib    { stroke: var(--route-lib); }
.map__route--school { stroke: var(--route-school); }
.map__route--youth { stroke: var(--route-youth); }
.map__route--kitchen { stroke: var(--route-kitchen); }
.map__route--health { stroke: var(--route-health); }
.map__ghost { fill: none; stroke: var(--ink-faint); stroke-width: 1.5; stroke-dasharray: 2 10; opacity: 0.5; }
/* A route carrying a message right now. The line lifts rather than changes
   colour, because colour on this map already means which organization owns the
   route and a second meaning on the same channel would be unreadable. */
.map__route--live { filter: brightness(1.5); }
.map__pulse { stroke: none; }
/* The ring swells and settles. Transform only, and the origin has to be stated
   for SVG or the circle grows from the corner of the viewBox. */
.map__station { transition: none; transform-box: fill-box; transform-origin: center; }
.map__station--hit { animation: station-hit 520ms cubic-bezier(0.23, 1, 0.32, 1); }
@keyframes station-hit {
  0%   { transform: scale(1); }
  32%  { transform: scale(1.85); }
  100% { transform: scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .map__station--hit { animation: none; }
}
.map__pulse--food   { fill: var(--route-food); }
.map__pulse--lib    { fill: var(--route-lib); }
.map__pulse--school { fill: var(--route-school); }
.map__pulse--youth { fill: var(--route-youth); }
.map__pulse--kitchen { fill: var(--route-kitchen); }
.map__pulse--health { fill: var(--route-health); }

.map__station { fill: var(--field); stroke-width: 3.5; }
.map__label { font-family: var(--font-ui); font-size: 11px; font-weight: 600; fill: var(--ink); letter-spacing: 0.04em; }
.map__meta  { font-family: var(--font-mono); font-size: 9.5px; fill: var(--ink-faint); }
.legend { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-top: var(--s-4); }
.legend__item { display: flex; align-items: center; gap: var(--s-2); font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-soft); }
.legend__swatch { width: 18px; height: 3px; }

.feed { display: flex; flex-direction: column; gap: var(--gutter);
        flex: 1 1 auto; min-height: 9rem; overflow-y: auto; overscroll-behavior: contain;
        background: var(--rule-soft); }
.event { background: var(--plate-low); padding: var(--s-3) var(--s-4); display: grid;
         grid-template-columns: 3.5rem minmax(0, 1fr); gap: var(--s-3); }
.event__t { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint); }
.event__route { display: flex; align-items: center; gap: var(--s-2); margin-bottom: var(--s-2); flex-wrap: wrap; }
.event__text { font-size: var(--t-small); color: var(--ink-soft); }
.event--milestone { background: var(--plate-high); }
.event--milestone .event__text { color: var(--ink); }
.event__text--clamp { display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden; }
/* The caret only exists while an agent is writing. It is a block of ink rather
   than a border so it sits on the text baseline at any font size. */
.event__text.is-typing::after {
  content: "";
  display: inline-block;
  width: 0.5em;
  height: 1em;
  margin-left: 0.08em;
  vertical-align: -0.14em;
  background: var(--route-lib);
  opacity: 0.85;
  animation: caret 1s steps(1, end) infinite;
}
@keyframes caret { 0%, 55% { opacity: 0.85; } 56%, 100% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .event__text.is-typing::after { display: none; }
}
/* What the fund asks for, beside whether it is met. */
.req__asks { font-family: var(--font-mono); font-size: var(--t-micro);
             color: var(--ink-faint); letter-spacing: 0.06em;
             font-variant-numeric: tabular-nums; margin-left: var(--s-2); }

.dot { width: 9px; height: 9px; flex: none; border-radius: 2px; }
/* The name in the organization's own colour, matching its route on the map. */
.label--food   { color: var(--route-food); }
.label--lib    { color: var(--route-lib); }
.label--school { color: var(--route-school); }
.label--health { color: var(--route-health); }
.label--kitchen{ color: var(--route-kitchen); }
.label--youth  { color: var(--route-youth); }
.dot--food { background: var(--route-food); }
.dot--lib { background: var(--route-lib); }
.dot--school { background: var(--route-school); }
.dot--youth { background: var(--route-youth); }
.dot--kitchen { background: var(--route-kitchen); }
.dot--health { background: var(--route-health); }

.empty { padding: var(--s-8) var(--s-4); color: var(--ink-soft); font-size: var(--t-small); }
.steps { display: flex; flex-direction: column; gap: var(--s-3); margin-top: var(--s-4); }
.step { display: flex; align-items: center; gap: var(--s-3); }
.step__n { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint); width: 1.5rem; }
.step .ico { color: var(--ink-faint); }

/* ---------- organizations ---------- */
.orgs { display: grid; grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); gap: var(--gutter); background: var(--rule-soft); }
.org { background: var(--plate-low); padding: var(--s-6); }
.org__top { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.org__name { font-size: var(--t-lead); font-weight: 600; }
.org__pop { font-family: var(--font-mono); font-size: var(--t-small); color: var(--ink-soft); }
.org__dir { font-size: var(--t-small); color: var(--ink-faint); margin-top: var(--s-1); }
.things { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-4); }
.thing { display: flex; align-items: flex-start; gap: var(--s-2); font-size: var(--t-small); }
.thing .ico { width: 0.9rem; height: 0.9rem; margin-top: 0.2em; color: var(--ink-faint); }
.thing__when { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-faint); }
.thing--need { color: var(--ink-soft); }
.urg { font-family: var(--font-mono); font-size: var(--t-micro); padding: 0 0.25rem; }
.urg--alta { color: var(--waiting); }

/* ---------- acknowledgement and errors ---------- */
.ack {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4) var(--s-6);
  background: var(--plate-high); border: 1px solid rgba(217, 227, 246, 0.22);
  font-size: var(--t-small);
  scroll-margin-top: 5rem;
}
.ack .ico { color: var(--ok); }
.ack .btn { margin-left: auto; }
.ack--error { border-color: var(--danger); }
.ack--error .ico { color: var(--danger); }

.skeleton {
  display: block; height: 1em;
  background: linear-gradient(90deg, var(--plate-low) 0%, var(--plate-high) 50%, var(--plate-low) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.4s var(--ease-move) infinite;
}
@keyframes shimmer { from { background-position: 200% 0; } to { background-position: -200% 0; } }

/* seeded-data disclosure: stated once, early, small, away from the figures */
.disclosure {
  font-family: var(--font-mono); font-size: var(--t-micro);
  color: var(--ink-faint); text-align: center;
  padding: var(--s-3) var(--s-6);
  border-bottom: 1px solid var(--rule-soft);
}

.foot { border-top: 1px solid var(--rule); padding: var(--s-8) var(--s-6);
        text-align: center; font-family: var(--font-mono);
        font-size: var(--t-micro); color: var(--ink-faint); }

/* ---------- entry choreography ---------- */
@keyframes rise { from { transform: translateY(10px); } to { transform: none; } }
@media (prefers-reduced-motion: no-preference) {
  .shell section { animation: rise var(--d-enter) var(--ease-enter) backwards;
                   animation-delay: calc(var(--b, 0) * 60ms); }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* ---------- responsive ---------- */
@media (max-width: 68rem) {
  .network { grid-template-columns: minmax(0, 1fr); }
  .req { grid-template-columns: 3.5rem minmax(0, 1fr); }
  .req__who { grid-column: 2; }
}
@media (max-width: 44rem) {
  .shell { padding: var(--s-6) var(--s-4) var(--s-16); gap: var(--s-8); }
  .fund__head { padding: var(--s-6) var(--s-4); }

  /* The top bar carried the identity chip and the live status side by side and
     ran 110px past the viewport. The status text is the one that can go: the
     pulsing icon still says a round is running. */
  .topbar { padding: var(--s-3) var(--s-4); flex-wrap: wrap; }
  .identity__label { display: none; }
  .identity { min-width: 0; }
  .identity span:not(.identity__dot) { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  #live-text { display: none; }

  /* A signature is a commitment between institutions; the button that files one
     should not be a 40px target on a phone. */
  .btn--small { min-height: 44px; padding: 0.625rem 0.875rem; }
  .identity { min-height: 44px; }

}
