/* The prospect research tool.
 *
 * Its own file rather than more of styles.css, which is the hub's shared
 * chrome: this is one tool's vocabulary — a map, a weighting panel, a ranked
 * row — and nothing else loads it.
 *
 * EVERY VALUE HERE NAMES A TOKEN. No literal colours, no typed-in spacing:
 * tokens.css is the design system and a value written here rather than taken
 * from a scale is how the next stylesheet starts drifting. The two exceptions
 * are declared and explained where they appear, and both are geometry rather
 * than colour.
 *
 * Light and dark come free, because every colour below is a semantic token
 * that tokens.css rebinds. The one thing needing its own dark block is the
 * map's colour scale, at the foot of this file.
 */

/* The tool used to read at a wider measure than the rest of the hub, through
 * #app.wide. Every page is that wide now: --page-w in tokens.css. */

/* ---------- the counts strip ---------- */

.prospect-counts {
  display: flex; flex-wrap: wrap; gap: var(--el-space-9);
  padding: var(--el-space-6) var(--el-space-8);
  border: var(--bw) solid var(--ink); border-radius: var(--radius);
  background: var(--surface);
}
.stat { display: flex; flex-direction: column; min-width: 0; }
.stat strong { font-size: var(--el-text-xl); line-height: 1.1; font-weight: 500; }
.stat-label {
  font-size: var(--el-text-xs); color: var(--ink-soft);
  text-transform: uppercase; letter-spacing: 0.06em;
  font-family: var(--cond); font-weight: 700;
}

/* ---------- controls ---------- */

.prospect-controls { gap: var(--el-space-4); align-items: center; }
.sortwrap {
  display: flex; align-items: center; gap: var(--el-space-4);
  margin-bottom: 0; flex: 0 0 auto;
}
.sortwrap select { width: auto; min-width: 11em; }

.panel {
  border: var(--bw) solid var(--ink); border-radius: var(--radius);
  background: var(--surface-2); padding: var(--el-space-8);
}

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

.weight-grid {
  display: grid; gap: var(--el-space-8);
  grid-template-columns: 1fr;
}
@media (min-width: 46rem) { .weight-grid { grid-template-columns: repeat(3, 1fr); } }

.weight-row {
  display: flex; flex-direction: column; gap: var(--el-space-3);
  padding: var(--el-space-6);
  border: var(--el-hairline) solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface);
}
.weight-head { display: flex; align-items: baseline; gap: var(--el-space-4); }
.weight-head strong { font-family: var(--cond); }
.weight-n {
  margin-left: auto; font-size: var(--el-text-md);
  padding: 0 var(--el-space-3); border-radius: var(--el-radius-pill);
  border: var(--el-hairline) solid var(--line); color: var(--ink-soft);
}
/* A weight of zero means the axis is switched off, which is a real and useful
   choice — but it must not look like the default. */
.weight-n.w-0 { color: var(--ink-faint); border-style: dashed; }
.weight-n.w-2, .weight-n.w-3 {
  background: var(--accent); color: var(--accent-ink); border-color: var(--ink);
}

/* The range input is the one control the hub had no style for. Kept close to
   the rest: a drawn track, a square thumb with the same 2px edge every other
   control has. */
.weight-row input[type="range"] {
  width: 100%; min-height: 0; padding: 0; margin: var(--el-space-2) 0;
  appearance: none; background: transparent; border: 0;
}
.weight-row input[type="range"]::-webkit-slider-runnable-track {
  height: var(--el-space-3); border-radius: var(--el-radius-pill);
  background: var(--surface-2); border: var(--el-hairline) solid var(--line);
}
.weight-row input[type="range"]::-moz-range-track {
  height: var(--el-space-3); border-radius: var(--el-radius-pill);
  background: var(--surface-2); border: var(--el-hairline) solid var(--line);
}
.weight-row input[type="range"]::-webkit-slider-thumb {
  appearance: none; width: var(--el-space-9); height: var(--el-space-9);
  margin-top: calc(var(--el-space-3) / 2 - var(--el-space-9) / 2);
  background: var(--accent); border: var(--bw) solid var(--ink);
  border-radius: var(--radius-sm); cursor: pointer;
}
.weight-row input[type="range"]::-moz-range-thumb {
  width: var(--el-space-9); height: var(--el-space-9);
  background: var(--accent); border: var(--bw) solid var(--ink);
  border-radius: var(--radius-sm); cursor: pointer;
}
.weight-row input[type="range"]:focus-visible {
  outline: var(--bw) solid var(--ink); outline-offset: var(--el-space-2);
}

.weight-foot { margin-top: var(--el-space-6); }

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

.map-panel { padding: var(--el-space-6); }
.map-controls { margin-bottom: var(--el-space-5); }
.map-slot { min-height: var(--el-space-12); }
.map-loading { text-align: center; padding: var(--el-space-11) 0; }

.map-wrap { position: relative; }

/* Leaflet's container. A fixed aspect rather than a fixed height, so the
   panel does not change shape between the framings — the generated boxes are
   all at the world's own aspect for the same reason. Leaflet needs a real
   height on the element it is handed; `height: auto` on an <svg> used to do
   this job and does not work for a div. */
.map-canvas {
  width: 100%; aspect-ratio: 1000 / 487;
  /* ITS OWN STACKING CONTEXT, AND THIS IS LOAD-BEARING.
     Leaflet stacks its panes at 400-700 and its control corners at 1000 —
     all of which outrank the navigation bar's 210, so the map painted over
     the bar as soon as the page scrolled: hit-testing the middle of the bar
     returned a country shape. nav.css says only a modal may cover the bar,
     and a modal is in the top layer where no z-index reaches.
     A positioned element with a z-index other than auto contains every
     z-index inside it, so Leaflet's numbers become local to the map and the
     whole map sits at 0. `isolation` says the same thing out loud and holds
     even if the position ever changes. Neither number is a token because
     neither is a position in the design system's scale — 0 means "do not
     compete", which is the point. */
  position: relative; z-index: 0; isolation: isolate;
  background: var(--map-sea); border-radius: var(--radius-sm);
  /* The projection boundary is drawn as a shape, so the box around it can be
     plain. */
  border: var(--el-hairline) solid var(--line);
  /* The map is inside a scrolling page. Without this, a one-finger drag that
     starts on the map is claimed by Leaflet and the page will not scroll
     past it — `pan-y` hands vertical drags back to the page and keeps
     horizontal ones and pinches for the map. */
  touch-action: pan-y;
}
/* Leaflet puts `leaflet-container` on the element it is handed, not on a
   child of it — so this is one selector, not a descendant one. Written the
   other way it silently never matched and Leaflet's own white showed. */
.map-canvas,
.map-canvas.leaflet-container { background: var(--map-sea); }

.map-sphere { fill: var(--map-sea); stroke: none; }
.map-graticule {
  fill: none; stroke: var(--map-grid);
  /* Sub-pixel on purpose: a graticule that reads as a line competes with the
     borders. It is here so empty ocean does not look like a failed tile
     load. Not from the scale because the scale's smallest step, 1px, is
     twice what this wants. */
  stroke-width: 0.5;
}

/* THE FILL IS A CLASS, NOT AN ATTRIBUTE.
 *
 * Leaflet writes a `fill` presentation attribute from its path options, and
 * a stylesheet rule beats a presentation attribute — so these win, and
 * tokens.css's rule holds: name a token, never write the value. The old map
 * set fill="var(--map-3)" from JavaScript, which worked but put five colour
 * names in a module that should not know any. */
/* Two classes, not one, so the step does not depend on sitting below
   `.map-country` in this file. It did not: at equal specificity the later
   rule wins, `.map-country { fill: var(--map-empty) }` was later, and every
   country rendered blank while carrying the right step class. */
.map-country.map-s1, .map-dot.map-s1 { fill: var(--map-1); }
.map-country.map-s2, .map-dot.map-s2 { fill: var(--map-2); }
.map-country.map-s3, .map-dot.map-s3 { fill: var(--map-3); }
.map-country.map-s4, .map-dot.map-s4 { fill: var(--map-4); }
.map-country.map-s5, .map-dot.map-s5 { fill: var(--map-5); }

.map-country {
  fill: var(--map-empty);
  stroke: var(--map-border);
  /* In pixels now, not viewBox units, because Leaflet's SVG renderer draws in
     screen space. That is the better behaviour: a hairline border stays a
     hairline as you zoom in, where a scaled one became a thick band. */
  stroke-width: 0.6;
  /* Only the countries holding prospects invite a click, and the cursor
     should say so before the hover colour does. */
  cursor: default;
  transition: fill 90ms linear;
}
.map-country.has-prospects { cursor: pointer; }
.map-country.has-prospects:hover { stroke: var(--ink); stroke-width: 1.4; }
.map-country.on { stroke: var(--ink); stroke-width: 2; }

/* The sub-pixel countries — Malta, Luxembourg, Monaco, Singapore and fifty
   others — drawn as a dot so they can be hit at world scale. Invisible until
   they hold prospects, so the map is not permanently freckled. The radius is
   in pixels, so a dot stays a dot as you zoom rather than swelling into a
   blob over its own continent. */
.map-dot { fill: transparent; stroke: var(--ink); stroke-width: 0; cursor: default; }
.map-dot.has-prospects { stroke-width: 1; cursor: pointer; }
.map-dot.has-prospects:hover { stroke-width: 2; }
.map-dot.on { stroke-width: 2.2; }

/* Leaflet's zoom buttons, in the hub's own clothes rather than its default
   blue-grey. Only the two buttons are restyled: nothing else of Leaflet's
   chrome is on screen, because there is no attribution bar, no scale and no
   layer switcher. */
.map-canvas .leaflet-bar {
  border: var(--bw) solid var(--ink); border-radius: var(--radius-sm);
  box-shadow: none; overflow: hidden;
}
.map-canvas .leaflet-bar a,
.map-canvas .leaflet-bar a:hover {
  width: var(--el-space-10); height: var(--el-space-10); line-height: var(--el-space-10);
  background: var(--surface); color: var(--ink);
  border-bottom-color: var(--line);
  font-family: var(--cond); font-size: var(--el-text-lg);
}
.map-canvas .leaflet-bar a:hover { background: var(--surface-2); }
.map-canvas .leaflet-bar a.leaflet-disabled {
  background: var(--surface-2); color: var(--ink-faint);
}
/* Leaflet puts the zoom control top-left, which is where the readout sits. */
.map-canvas .leaflet-top.leaflet-left { top: auto; bottom: 0; }

.map-readout {
  position: absolute; top: var(--el-space-4); left: var(--el-space-4);
  display: flex; align-items: baseline; gap: var(--el-space-5);
  padding: var(--el-space-3) var(--el-space-6);
  background: var(--surface); color: var(--ink);
  border: var(--bw) solid var(--ink); border-radius: var(--radius-sm);
  font-size: var(--el-text-md); pointer-events: none; max-width: 60%;
  white-space: nowrap;
}
.map-readout strong { font-family: var(--cond); }
.map-readout-n { font-family: var(--mono); font-size: var(--el-text-sm); color: var(--ink-soft); }

.map-foot { margin-top: var(--el-space-5); align-items: center; }
.map-legend { display: flex; align-items: center; gap: var(--el-space-3); flex-wrap: wrap; }
/* The five steps butted together, so the scale reads as one ramp rather than
   as five separate categories — which is what a sequential scale is. */
.map-ramp {
  display: inline-flex; align-items: stretch;
  border: var(--el-hairline) solid var(--line); border-radius: 2px;
  overflow: hidden;
}
.map-swatch { display: block; width: var(--el-space-9); height: var(--el-space-6); }
.map-swatch-1 { background: var(--map-1); }
.map-swatch-2 { background: var(--map-2); }
.map-swatch-3 { background: var(--map-3); }
.map-swatch-4 { background: var(--map-4); }
.map-swatch-5 { background: var(--map-5); }
.map-key-n { font-family: var(--mono); font-size: var(--el-text-2xs); color: var(--ink-faint); }
.map-chips { display: flex; gap: var(--el-space-3); flex-wrap: wrap; }
.map-credit { margin: var(--el-space-5) 0 0; font-size: var(--el-text-xs); }

/* THE COUNTRY FILTER, and on a phone the only usable one.
 *
 * It sits outside the map panel because it is the control and the map is a
 * picture of the control. Measured on a 390px screen: the world map renders
 * about 160px tall, which makes Germany a 7px tap target and Belgium a 3px
 * one against a 44px minimum — and touch has no hover, so the readout naming
 * what you are about to pick never appears. The map is collapsed by default
 * there and this is open instead.
 *
 * It is also the keyboard and screen-reader route, and the way anybody finds
 * a country they can name rather than hunting for its shape. A native
 * <details>, so it opens from the keyboard and is announced without script. */
.country-slot {
  border: var(--bw) solid var(--ink); border-radius: var(--radius);
  background: var(--surface); padding: var(--el-space-6) var(--el-space-8);
}
.country-slot:empty { display: none; border: 0; padding: 0; }
.country-list > summary {
  cursor: pointer; font-family: var(--cond); font-weight: 700;
  font-size: var(--el-text-xs); text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--ink-faint);
  /* A comfortable target in its own right — this is the control a phone
     reaches for first. */
  padding: var(--el-space-4) 0; min-height: var(--el-space-11);
  display: flex; align-items: center;
}
.country-list > summary:focus-visible {
  outline: var(--bw) solid var(--ink); outline-offset: var(--el-space-2);
}
.country-list[open] > summary { color: var(--ink); }
.country-pills { margin-top: var(--el-space-5); gap: var(--el-space-4); }
/* 44px is the minimum anybody can reliably hit with a thumb. The pills are
   the tap targets now, so they get it — the map's shapes never could. */
@media (pointer: coarse) {
  .country-pills .pill { min-height: 38px; padding: var(--el-space-4) var(--el-space-7); }
  .filters .pill { min-height: 36px; }
}

/* ---------- filters ---------- */

.filter-group { margin-bottom: var(--el-space-5); }
.filter-head { margin: 0 0 var(--el-space-2); }
.pill.flagged { border-color: var(--warn); color: var(--warn); }
.pill.flagged.on { background: var(--warn); color: var(--surface); border-color: var(--ink); }
.pill.flag-danger { border-color: var(--danger); color: var(--danger); }
.pill.flag-note { border-color: var(--line); color: var(--ink-soft); }
.pill.exported { border-color: var(--good); color: var(--good); }
.pill.conf-low { border-color: var(--warn); color: var(--warn); }
.pill.conf-high { border-color: var(--good); color: var(--good); }
.quiet-pill { border-style: dashed; }
/* The × on a removable chip — the research-category filter, which is set from
   a brief page and has no pill of its own to toggle off. */
.pill-x { margin-left: var(--el-space-2); font-weight: 700; opacity: 0.7; }

/* ---------- the bulk bar ---------- */

/* Sticks to the bottom of the viewport while a selection is live: with 789
   rows the selection is made by scrolling, and a bar at the top of the page
   would be somewhere you have to scroll back to. */
/* `display: flex` beats the user agent's `[hidden] { display: none }`, so the
   empty bar rendered as a black strip under the map whenever nothing was
   selected. Any rule that gives a `hidden` element a display needs this
   beside it. */
.bulkbar[hidden] { display: none; }

.bulkbar {
  position: sticky; bottom: var(--el-space-4); z-index: 40;
  display: flex; align-items: center; gap: var(--el-space-4); flex-wrap: wrap;
  padding: var(--el-space-5) var(--el-space-8);
  background: var(--nav); color: var(--el-dk-ink);
  border: var(--bw) solid var(--ink); border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.bulkbar strong { font-family: var(--cond); }
.bulkbar button { border-color: var(--el-dk-line); }

/* ---------- a row ---------- */

/* MOBILE FIRST, and this one matters. As a single flex row — tick, rank,
   name, score, star all on one line — the name column on a 390px phone came
   out about 90px wide and every organisation wrapped onto four or five
   lines, which turned nine rows into a page and a half.

   So on a phone the row is two lines: the controls and the score across the
   top, the whole of the row's text underneath at full width. It goes back to
   one line as soon as there is room for one. */
.prospect-rows .prospect-row {
  display: grid;
  grid-template-columns: auto auto 1fr auto;
  align-items: center;
  gap: var(--el-space-3) var(--el-space-5);
  padding: var(--el-space-6) var(--el-space-7);
}
.prospect-rows .prow-main { grid-column: 1 / -1; grid-row: 2; }

@media (min-width: 46rem) {
  .prospect-rows .prospect-row {
    display: flex; align-items: flex-start; gap: var(--el-space-5);
  }
}
.prospect-rows li.selected { background: var(--surface-2); box-shadow: inset var(--el-space-2) 0 0 var(--accent); }
.prow-tick { flex: 0 0 auto; padding-top: var(--el-space-2); }

/* The rank. A number in the mono face, because it is a position in a list and
   the score beside it is a score — the two being told apart at a glance is
   what stops "7" being read as "rank 7". */
.rank {
  flex: 0 0 auto; display: grid; place-items: center;
  min-width: var(--el-space-12); padding: var(--el-space-2) var(--el-space-4);
  border: var(--el-hairline) solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.rank-n { font-size: var(--el-text-sm); color: var(--ink-soft); }
/* The band, as a bar down the edge. Tier 1 takes the action colour, and
   nothing else on the row does. */
.rank.tier-1 { background: var(--accent); border-color: var(--ink); }
.rank.tier-1 .rank-n { color: var(--accent-ink); font-weight: 700; }
.rank.tier-2 { border-color: var(--ink); }
.rank.tier-4 { border-style: dashed; background: transparent; }

.prow-main {
  flex: 1 1 auto; min-width: 0; text-align: left;
  border: 0; background: transparent; border-radius: 0;
  padding: 0; min-height: 0; display: block;
}
.prow-main:hover { background: transparent; }
.prow-main:active { transform: none; }
.prow-top {
  display: flex; gap: var(--el-space-4);
  flex-wrap: wrap; margin-bottom: var(--el-space-2);
  /* Top-aligned, not centred: against a name that wraps to two lines a
     centred mark floats beside the gap between them. */
  align-items: flex-start;
}
/* Nudged down to sit on the first line's cap height rather than its box. */
.prow-top .mark { margin-top: var(--el-space-1); }
/* `min-width: 0` lets a long name wrap INSIDE its own box rather than being
   pushed whole onto the line below, which at phone width left the verdict
   mark stranded on a line of its own.

   `flex: 0 1 auto` and not `1 1 …`: a growing name fills the row and shoves
   the organisation across to the far right, so "Richard L. Hasen" and "UCLA
   School of Law" sat at opposite ends of the row with a void between them. */
.prow-name {
  font-weight: 500; font-size: var(--el-text-base);
  flex: 0 1 auto; min-width: 0;
}
.prow-org { color: var(--ink-soft); font-size: var(--el-text-md); }
.prow-meta {
  display: flex; align-items: center; gap: var(--el-space-6);
  flex-wrap: wrap; font-size: var(--el-text-sm); color: var(--ink-faint);
}
.prow-where { display: inline-flex; align-items: center; gap: var(--el-space-2); }
.prow-where svg { width: var(--el-space-7); height: var(--el-space-7); }
.prow-cat { font-family: var(--cond); }
.prow-route { font-family: var(--mono); font-size: var(--el-text-xs); }
.prow-angle {
  margin: var(--el-space-3) 0 0; color: var(--ink-soft);
  font-size: var(--el-text-md); line-height: 1.5;
  /* Two lines of the angle, which is the line you read to decide. More than
     two turns the list into a wall; fewer is not enough to judge by. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* On a phone the score sits in the top line's free column, which also stops
   the grid leaving a gap there. It is back to its own fixed column as soon as
   the row is a flex row again. */
.prow-score { justify-self: start; }
@media (min-width: 46rem) { .prow-score { flex: 0 0 auto; justify-self: auto; } }
.scorebar { display: inline-flex; align-items: center; gap: var(--el-space-3); }
.scorebar-track {
  display: block; width: var(--el-space-12); height: var(--el-space-5);
  background: var(--surface-2);
  border: var(--el-hairline) solid var(--line); border-radius: var(--el-radius-pill);
  overflow: hidden;
}
.scorebar-fill { display: block; height: 100%; background: var(--accent); }
/* A width per 5% step. The alternative is a style attribute, which the CSP
   blocks — style-src 'self' stops an inline style as surely as a <style>
   block, which is why .right and .m0 exist in styles.css. */
.pct-0 { width: 0; } .pct-5 { width: 5%; } .pct-10 { width: 10%; }
.pct-15 { width: 15%; } .pct-20 { width: 20%; } .pct-25 { width: 25%; }
.pct-30 { width: 30%; } .pct-35 { width: 35%; } .pct-40 { width: 40%; }
.pct-45 { width: 45%; } .pct-50 { width: 50%; } .pct-55 { width: 55%; }
.pct-60 { width: 60%; } .pct-65 { width: 65%; } .pct-70 { width: 70%; }
.pct-75 { width: 75%; } .pct-80 { width: 80%; } .pct-85 { width: 85%; }
.pct-90 { width: 90%; } .pct-95 { width: 95%; } .pct-100 { width: 100%; }
.scorebar-n { font-size: var(--el-text-sm); color: var(--ink-soft); min-width: 1.4em; }
.scorebar-edit { color: var(--warn); font-size: var(--el-text-sm); }

.followbtn {
  flex: 0 0 auto; width: var(--btn-h-sm); height: var(--btn-h-sm); min-height: 0;
  padding: 0; display: grid; place-items: center;
  border-color: transparent; background: transparent; color: var(--ink-faint);
  border-radius: var(--el-radius-pill);
}
.followbtn svg { width: var(--el-space-9); height: var(--el-space-9); }
.followbtn:hover { background: var(--surface-2); color: var(--ink); }
.followbtn.on { color: var(--accent-dk); }

.more-row { margin-top: var(--el-space-6); }

/* ---------- one prospect ---------- */

.prospect-head { align-items: flex-start; gap: var(--el-space-6); }
.prospect-tags { gap: var(--el-space-3); }
.prospect-tags .pill svg { width: var(--el-space-7); height: var(--el-space-7); }
.angle { font-size: var(--el-text-lg); line-height: 1.5; }
.breakable { overflow-wrap: anywhere; }

.axis-grid { display: flex; flex-direction: column; gap: var(--el-space-5); }
.axis-row {
  display: flex; align-items: center; gap: var(--el-space-6); flex-wrap: wrap;
  padding: var(--el-space-5) var(--el-space-6);
  border: var(--el-hairline) solid var(--line); border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.axis-pips { gap: var(--el-space-2); }
.pip {
  width: var(--btn-h-sm); height: var(--btn-h-sm); min-height: 0; padding: 0;
  font-family: var(--mono); font-size: var(--el-text-sm);
  border-color: var(--line);
}
.pip.on { background: var(--accent); color: var(--accent-ink); border-color: var(--ink); font-weight: 700; }
/* Zero on the ease axis parks a row, which is a bigger claim than the other
   values and reads as one. */
.pip-zero { border-style: dashed; }
.pip-zero.on { background: var(--ink-faint); color: var(--surface); border-style: solid; }

.choice-pill {
  display: inline-flex; align-items: center; gap: var(--el-space-3);
  border-color: var(--line);
}
.choice-pill.on { border-color: var(--ink); background: var(--surface-2); font-weight: 500; }

/* The add/edit form. Mirrors the contact form's shape — a label, the control,
   and the note that says what the field is for — because a person filling one
   in should not have to learn a second layout. */
.formrow { display: flex; flex-direction: column; gap: var(--el-space-2); }
.formrow label { margin-bottom: 0; }
.formrow .faint { font-size: var(--el-text-sm); }

/* ---------- the briefs ---------- */

/* A BRIEF'S HEADINGS ARE PROSE, NOT UI LABELS.
   styles.css sets h3 to the hub's small uppercase section label, which is
   right for "WHERE" over a row of filter pills and wrong for "4. What I
   looked for and could not find" — a sentence, shouted, in a reading column.
   The briefs' own headings were ALL CAPS in the source too; that was fixed in
   the data, and this stops the stylesheet putting it back. Scoped to
   .brief-body rather than .help-body because the help panels share that class
   and their headings really are labels. */
.brief-body h3 {
  font-size: var(--el-text-md); text-transform: none; letter-spacing: normal;
  color: var(--ink); font-weight: 700; font-family: var(--cond);
  margin: var(--el-space-9) 0 var(--el-space-3);
}
.brief-body h4 {
  font-size: var(--el-text-base); text-transform: none; letter-spacing: normal;
  color: var(--ink-soft); font-weight: 700;
  margin: var(--el-space-7) 0 var(--el-space-2);
}

.brief-n { flex: 0 0 2.2em; }
.brief-list { margin: 0 0 var(--el-space-6) var(--el-space-9); padding: 0; }
.brief-list li { margin-bottom: var(--el-space-3); line-height: 1.55; }
.brief-quote {
  margin: 0 0 var(--el-space-6); padding: var(--el-space-2) var(--el-space-8);
  border-left: var(--el-space-2) solid var(--accent); color: var(--ink-soft);
}
.brief-code {
  margin: 0 0 var(--el-space-6); padding: var(--el-space-6);
  background: var(--surface-2); border: var(--el-hairline) solid var(--line);
  border-radius: var(--radius-sm); overflow-x: auto;
  font-family: var(--mono); font-size: var(--el-text-sm);
}
.brief-rule { border: 0; border-top: var(--el-hairline) solid var(--line); margin: var(--el-space-9) 0; }

.tablewrap { overflow-x: auto; margin-bottom: var(--el-space-6); }
.brief-table { border-collapse: collapse; width: 100%; font-size: var(--el-text-md); }
.brief-table th, .brief-table td {
  text-align: left; padding: var(--el-space-4) var(--el-space-6);
  border-bottom: var(--el-hairline) solid var(--line-soft); vertical-align: top;
}
.brief-table th { font-family: var(--cond); font-weight: 700; border-bottom-color: var(--line); }

/* ---------- the tool's identity ---------- */

/* Its tile on the hub, in the coordination team's colour — the outreach list
   has outreach green and the graphic maker has social blue, and this is the
   third tool rather than a variant of either. See the team colour note in
   styles.css: a team colour identifies a TOOL and never a status. */
.tool-prospects { border-left: var(--el-space-3) solid var(--team-coordination-ink); }
.tool-prospects strong { color: var(--team-coordination-ink); }

/* An off-screen field, for the clipboard fallback on a non-secure origin. */
.offscreen { position: absolute; left: -9999px; top: 0; opacity: 0; }

/* A wider dialog, for the duplicate-match list and the help. */
dialog.wide { width: min(760px, calc(100vw - var(--el-space-11))); }

/* ---------- the filter sheet ----------
 *
 * On a phone the filter bar is eight groups of pills, more than a screen and
 * a half of them before the first row of the list. Behind a sheet instead,
 * reached from a button that carries the number of filters currently on —
 * because a filter you cannot see is a list quietly missing rows for no
 * visible reason.
 *
 * A bottom sheet rather than a centred box: it is tall, it is scrolled, and
 * its actions want to sit under the thumb rather than off the top of a long
 * scroll. On a wide screen it stays an ordinary dialog. */
.filterbtn { display: inline-flex; align-items: center; gap: var(--el-space-3); }
.filterbtn.on { border-color: var(--ink); }
.filter-count {
  display: inline-grid; place-items: center; min-width: var(--el-space-9);
  height: var(--el-space-9); padding: 0 var(--el-space-2);
  border-radius: var(--el-radius-pill);
  background: var(--accent); color: var(--accent-ink);
  font-family: var(--mono); font-size: var(--el-text-2xs); font-weight: 700;
}

@media (max-width: 46rem) {
  /* A WORLD MAP ON A PHONE IS A STRIP. At 330px wide the world's own aspect
     gives 161px of map, a quarter of which the readout sits on top of. That
     was fine when the map had one fixed scale and nothing else to show; now
     that it zooms, the extra height is where the zoomed-in map goes. The
     world still fits across the width — fitBounds letterboxes it — and the
     space below it stops being empty the moment anybody pinches. */
  .map-canvas { aspect-ratio: 3 / 2; }
  /* Smaller, and on one line: "Hover a country" wrapped to two and took a
     third of the map's height with it. */
  .map-readout {
    font-size: var(--el-text-sm);
    padding: var(--el-space-2) var(--el-space-4);
    max-width: calc(100% - var(--el-space-8));
  }

  dialog.sheet {
    width: 100vw; max-width: 100vw;
    max-height: 88vh; height: auto;
    margin: auto auto 0;                 /* sit on the bottom edge */
    border-radius: var(--radius) var(--radius) 0 0;
    border-bottom: 0;
  }
  dialog.sheet .dialog-body {
    max-height: calc(88vh - 76px);
    padding-bottom: var(--el-space-9);
  }
  /* The actions are the thumb's target: full width, and the one that closes
     the sheet carries the match count. */
  dialog.sheet .dialog-actions {
    padding: var(--el-space-6) var(--el-space-8);
    padding-bottom: calc(var(--el-space-6) + env(safe-area-inset-bottom));
    gap: var(--el-space-5);
  }
  dialog.sheet .dialog-actions button { flex: 1 1 auto; min-height: var(--btn-h); }
  /* Inside the sheet the country list has no card of its own — the sheet is
     the card. */
  dialog.sheet .country-slot { border: 0; padding: 0; }
  dialog.sheet .filter-group { margin-bottom: var(--el-space-8); }
}

/* ---------- the map's colour scale ----------
 *
 * Five steps of ONE hue, which is what a sequential scale wants: the only
 * thing the map encodes is "more rows", and a second hue would imply a second
 * meaning. Built by mixing the design system's own --accent into the surface
 * rather than by introducing five new colours, so the scale moves with the
 * theme and tokens.css stays the only place a colour is defined.
 *
 * Needed twice, because one of the two dark conditions is a media query and a
 * media query cannot be part of a selector — the same reason tokens.css
 * carries its theme block twice. Only the bindings repeat.
 */
:root {
  --map-sea: var(--surface-2);
  --map-grid: var(--line-soft);
  --map-border: var(--line);
  --map-empty: var(--surface);
  --map-1: color-mix(in srgb, var(--accent) 18%, var(--surface));
  --map-2: color-mix(in srgb, var(--accent) 36%, var(--surface));
  --map-3: color-mix(in srgb, var(--accent) 56%, var(--surface));
  --map-4: color-mix(in srgb, var(--accent) 78%, var(--surface));
  --map-5: var(--accent);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    /* On dark, an empty country has to be lighter than the sea rather than
       darker, or the land disappears and the map reads as an ocean. */
    --map-sea: var(--el-dk-bg);
    --map-empty: var(--el-dk-surface-2);
    --map-border: var(--el-dk-line);
  }
}
:root[data-theme="dark"] {
  --map-sea: var(--el-dk-bg);
  --map-empty: var(--el-dk-surface-2);
  --map-border: var(--el-dk-line);
}
