/* Commitment map — shared by the public home page and admin analytics.
 *
 * Scoped entirely under .rse-cmap so it can be dropped into the UIkit clone
 * chrome or the admin shell without either stylesheet and this one fighting.
 * Colours are literal rather than var()-based for the same reason: the clone
 * pages do not load /css/rise.css, so the admin's custom properties are not
 * there to inherit.
 *
 * Three fills, three different facts, and the legend says so:
 *   - "none on record"     grey      — we have never recorded a commitment there
 *   - "none in this period" near-white — we have, but not in the selected year
 *   - a ramp step          teal      — a real, non-zero count
 * An absent value and a zero must never look the same, and neither may look
 * like the bottom of the ramp. The ramp steps themselves are set inline by
 * commit-map.js, because the bins are computed from the data rather than
 * hard-coded — see binsFor() there.
 */

.rse-cmap {
  --cm-ink: #064443;
  --cm-mid: #0b6d68;
  --cm-accent: #c8102e;
  --cm-line: #ffffff;
  --cm-nodata: #dfe3e3;        /* never any commitment */
  --cm-zero: #fbfcfc;          /* has data, none in the chosen years */
  --cm-muted: #5d6b6a;
  box-sizing: border-box;
  max-width: 1180px;
  margin: 0 auto;
  font-family: inherit;
  color: #22302f;
  line-height: 1.45;
}
.rse-cmap *, .rse-cmap *::before, .rse-cmap *::after { box-sizing: inherit; }

.rse-cmap__head { display: flex; align-items: flex-end; gap: 16px; flex-wrap: wrap; margin-bottom: 10px; }
.rse-cmap__head h3 {
  margin: 0; font-size: 1.15rem; font-weight: 800; letter-spacing: .02em;
  color: var(--cm-ink); text-transform: uppercase;
}
.rse-cmap__total { font-size: .92rem; color: var(--cm-muted); margin: 0; }
.rse-cmap__total strong { color: var(--cm-ink); font-size: 1.05rem; }
.rse-cmap__spacer { flex: 1 1 auto; }

.rse-cmap__filter { display: flex; align-items: center; gap: 8px; font-size: .85rem; color: var(--cm-muted); }
.rse-cmap__filter select {
  font: inherit; padding: 5px 9px; border: 1px solid #c3cbca; border-radius: 6px;
  background: #fff; color: #22302f; max-width: 230px;
}

/* Map + panel sit side by side on a wide screen, stack on a phone. */
.rse-cmap__body { display: grid; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); gap: 18px; align-items: start; }
@media (max-width: 900px) { .rse-cmap__body { grid-template-columns: minmax(0, 1fr); } }
.rse-cmap__left { min-width: 0; }

.rse-cmap__mapwrap {
  position: relative; background: #fff; border: 1px solid #e3e8e7; border-radius: 10px; padding: 6px;
}
.rse-cmap__mapwrap svg { display: block; width: 100%; height: auto; overflow: visible; }

.rse-cmap .rse-state {
  fill: var(--cm-nodata);
  stroke: var(--cm-line);
  stroke-width: 0.8;
  cursor: default;
  outline: none;
  transition: fill .15s ease, opacity .15s ease;
}
.rse-cmap .rse-state.is-clickable { cursor: pointer; }
.rse-cmap .rse-state.is-zero { fill: var(--cm-zero); stroke: #cfd6d5; }

.rse-cmap .rse-state.is-clickable:hover,
.rse-cmap .rse-state.is-hot { stroke: var(--cm-accent); stroke-width: 1.6; }
.rse-cmap .rse-state:focus-visible { stroke: var(--cm-accent); stroke-width: 2.2; }
.rse-cmap .rse-state.is-selected { stroke: var(--cm-accent); stroke-width: 2.2; }

/* ---- the strobe pulse ----
 * Jeff: "strobe pulses of where the players went". A halo that breathes out of
 * every state with a commitment, drawn in its own layer over the choropleth so
 * the fill a reader is ranking never moves. Duration and reach are set inline
 * per state from its share of the busiest state, so Michigan pulses fastest and
 * widest and the eye goes there first.
 *
 * Slow on purpose: the fastest cycle is 1.9s (~0.5Hz), far below the ~3Hz
 * photosensitive-seizure threshold, and the halo is a soft teal tint rather
 * than a flash. Switched off entirely under prefers-reduced-motion below. */
.rse-cmap__pulses { pointer-events: none; }
.rse-cmap .rse-cmap__pulse {
  fill: none;
  pointer-events: none;
  stroke: var(--cm-mid);
  stroke-width: 0;
  stroke-opacity: 0;
  --cm-pulse-peak: .4;
  --cm-pulse-grow: 2px;
  animation-name: rse-cmap-pulse;
  animation-duration: 3s;
  animation-timing-function: ease-out;
  animation-iteration-count: infinite;
}
@keyframes rse-cmap-pulse {
  0%   { stroke-width: 0; stroke-opacity: 0; }
  35%  { stroke-width: var(--cm-pulse-grow); stroke-opacity: var(--cm-pulse-peak); }
  100% { stroke-width: calc(var(--cm-pulse-grow) * 2.1); stroke-opacity: 0; }
}

.rse-cmap__tip {
  position: absolute; z-index: 5; pointer-events: none; opacity: 0;
  transform: translate(-50%, -125%);
  background: #064443; color: #fff; font-size: .8rem; font-weight: 700; line-height: 1.35;
  padding: 7px 11px; border-radius: 6px; white-space: nowrap; text-align: left;
  transition: opacity .12s ease;
}
.rse-cmap__tip.is-on { opacity: 1; }
.rse-cmap__tip span { display: block; font-weight: 500; opacity: .85; }
.rse-cmap__tipschool { font-size: .74rem; opacity: .7 !important; }

.rse-cmap__legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 13px;
  margin: 10px 2px 0; font-size: .76rem; color: var(--cm-muted);
}
.rse-cmap__legend span { display: inline-flex; align-items: center; gap: 6px; }
.rse-cmap__legkey { font-weight: 700; color: var(--cm-ink); text-transform: uppercase; letter-spacing: .05em; font-size: .7rem; }
.rse-cmap__legend i {
  width: 14px; height: 14px; border-radius: 3px; display: inline-block;
  border: 1px solid rgba(0, 0, 0, .12);
}
.rse-cmap__swz { background: var(--cm-zero); border-color: #cfd6d5 !important; }
.rse-cmap__swn { background: var(--cm-nodata); }

.rse-cmap__offmap { margin: 8px 2px 0; font-size: .78rem; color: var(--cm-muted); }
.rse-cmap__offmap button {
  font: inherit; font-weight: 700; cursor: pointer; color: var(--cm-mid);
  background: #eef5f4; border: 1px solid #cfe1df; border-radius: 999px; padding: 3px 10px; margin-left: 4px;
}
.rse-cmap__offmap button:hover { color: #fff; background: var(--cm-mid); }

/* ---------------- the panel ---------------- */
.rse-cmap__panel {
  background: #fff; border: 1px solid #e3e8e7; border-radius: 10px; padding: 16px 18px;
  min-height: 260px; max-height: 78vh; overflow-y: auto; outline: none;
}
@media (max-width: 900px) { .rse-cmap__panel { max-height: none; } }

.rse-cmap__kicker {
  display: inline-block; font-size: .67rem; font-weight: 800; letter-spacing: .12em;
  text-transform: uppercase; color: var(--cm-accent); margin-bottom: 4px;
}
.rse-cmap__panel h4 {
  margin: 0 0 4px; font-size: 1.32rem; font-weight: 800; color: var(--cm-ink); line-height: 1.15;
}
.rse-cmap__lede { margin: 0 0 13px; font-size: .87rem; color: #465352; }
.rse-cmap__h5 {
  margin: 16px 0 8px; font-size: .7rem; font-weight: 800; letter-spacing: .1em;
  text-transform: uppercase; color: var(--cm-muted);
}
.rse-cmap__hint { color: var(--cm-muted); font-size: .88rem; margin: 0; }

.rse-cmap__back {
  font: inherit; font-size: .76rem; font-weight: 700; cursor: pointer; color: var(--cm-mid);
  background: #f2f8f7; border: 1px solid #d9e8e6; border-radius: 999px;
  padding: 3px 11px; margin: 0 0 9px;
}
.rse-cmap__back:hover { background: var(--cm-mid); color: #fff; border-color: var(--cm-mid); }

.rse-cmap__stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 7px; }
@media (max-width: 420px) { .rse-cmap__stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.rse-cmap__stat {
  background: #f4f9f8; border: 1px solid #e2eeec; border-radius: 8px; padding: 8px 9px; min-width: 0;
}
.rse-cmap__stat b { display: block; font-size: 1.12rem; font-weight: 800; color: var(--cm-ink); line-height: 1.1; }
.rse-cmap__stat span { display: block; font-size: .66rem; text-transform: uppercase; letter-spacing: .04em; color: var(--cm-muted); margin-top: 3px; }

.rse-cmap__pills { display: flex; flex-wrap: wrap; gap: 5px; }
.rse-cmap__pill {
  font-size: .73rem; font-weight: 600; color: #2d4645;
  background: #eef5f4; border: 1px solid #dbe9e7; border-radius: 999px; padding: 2px 9px;
}
.rse-cmap__pill b { color: var(--cm-ink); }

/* Ranked destinations, with a bar so the lopsidedness is visible as a shape
   rather than only as a number. */
.rse-cmap__top { list-style: none; margin: 0; padding: 0; }
.rse-cmap__top li { padding: 1px 0; }
.rse-cmap__top button {
  display: flex; align-items: center; gap: 9px; width: 100%; text-align: left;
  font: inherit; font-size: .82rem; background: none; border: 0; padding: 3px 2px; cursor: pointer; color: #2d4645;
  border-radius: 5px;
}
.rse-cmap__top button:hover { background: #f2f8f7; color: var(--cm-ink); }
.rse-cmap__topname { flex: 0 0 34%; font-weight: 600; }
.rse-cmap__bar { flex: 1 1 auto; height: 8px; background: #eef2f1; border-radius: 999px; overflow: hidden; }
.rse-cmap__bar i { display: block; height: 100%; background: var(--cm-mid); border-radius: 999px; }
.rse-cmap__top b { flex: 0 0 auto; min-width: 22px; text-align: right; color: var(--cm-ink); }

/* Schools and players */
.rse-cmap__school { border-top: 1px solid #edf1f0; padding: 11px 0 4px; }
.rse-cmap__school:first-of-type { border-top: 0; }
.rse-cmap__school header { display: flex; align-items: center; gap: 10px; }
.rse-cmap__school header strong { display: block; font-size: .95rem; color: #1d2c2b; line-height: 1.25; }
.rse-cmap__schoolmeta { display: block; font-size: .73rem; color: var(--cm-muted); }
.rse-cmap__schoolsport {
  display: inline-block; margin-top: 3px; font-size: .64rem; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: #8a5a10; background: #fdf3e0; border: 1px solid #f2e0bd;
  border-radius: 999px; padding: 1px 7px;
}
.rse-cmap__crest { width: 38px; height: 38px; flex: 0 0 38px; object-fit: contain; border-radius: 7px; }
.rse-cmap__mono {
  display: flex; align-items: center; justify-content: center;
  color: #fff; font-weight: 700; letter-spacing: .02em; line-height: 1;
}
.rse-cmap__crest.rse-cmap__mono { font-size: 14px; }

.rse-cmap__players { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 7px; margin: 9px 0 6px; }
.rse-cmap__player {
  display: flex; gap: 9px; align-items: flex-start; text-decoration: none; color: inherit;
  background: #fafcfc; border: 1px solid #ecf1f0; border-radius: 8px; padding: 8px 9px;
}
a.rse-cmap__player:hover { background: #f1f8f7; border-color: #cfe1df; text-decoration: none; }
a.rse-cmap__player:focus-visible { outline: 2px solid var(--cm-accent); outline-offset: 1px; }
.rse-cmap__face { width: 42px; height: 42px; flex: 0 0 42px; border-radius: 7px; object-fit: cover; background: #e6eceb; }
.rse-cmap__face.rse-cmap__mono { font-size: 15px; }
.rse-cmap__pbody { min-width: 0; }
.rse-cmap__pname { display: block; font-size: .85rem; font-weight: 700; color: #1d2c2b; line-height: 1.2; }
.rse-cmap__pmeta { display: block; font-size: .72rem; color: var(--cm-mid); font-weight: 600; margin-top: 1px; }
.rse-cmap__pline { display: block; font-size: .7rem; color: var(--cm-muted); line-height: 1.35; }
.rse-cmap__psport { color: #8a5a10; font-weight: 600; }
.rse-cmap__plink { display: none; }
a.rse-cmap__player:hover .rse-cmap__plink,
a.rse-cmap__player:focus-visible .rse-cmap__plink {
  display: block; font-size: .68rem; font-weight: 700; color: var(--cm-accent); margin-top: 2px;
}

/* The honest caveat. Most of `committed_to` has no state in it, so most
   commitments cannot be plotted; that is stated plainly instead of quietly
   dropped, and the biggest missing schools are named so the gap is actionable. */
.rse-cmap__note {
  margin-top: 16px; background: #fbf8f1; border: 1px solid #efe4cd; border-radius: 8px; padding: 11px 13px;
}
.rse-cmap__note .rse-cmap__h5 { margin-top: 0; color: #8a5a10; }
.rse-cmap__note p { margin: 0; font-size: .78rem; color: #5f5545; }
.rse-cmap__note b { color: #3f3626; }
.rse-cmap__notesub { margin-top: 8px !important; font-weight: 600; }
.rse-cmap__unplaced { list-style: none; margin: 5px 0 0; padding: 0; }
.rse-cmap__unplaced li { display: flex; gap: 8px; align-items: baseline; font-size: .76rem; color: #5f5545; padding: 1px 0; }
.rse-cmap__unplaced li b { margin-left: auto; color: #3f3626; }
.rse-cmap__foot { margin: 11px 0 0; font-size: .72rem; color: #8a938f; }

/* Panel updates are announced, so the map may be hidden from a screen reader
   walking the graphic itself — the state buttons carry the same labels. */
.rse-cmap__sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

@media (prefers-reduced-motion: reduce) {
  .rse-cmap .rse-state, .rse-cmap__tip { transition: none; }
  /* The pulse is the one thing on this page that could cause harm, so under a
     reduced-motion preference it does not run at all — not slower, not
     smaller. The halo is left visible as a static ring so the states with
     commitments still read as the busy ones. */
  .rse-cmap .rse-cmap__pulse {
    animation: none !important;
    stroke-width: var(--cm-pulse-grow);
    stroke-opacity: calc(var(--cm-pulse-peak) * .55);
  }
}
