/* ─────────────────────────────────────────────────────────────────────────
   Dispatch — one visual system.

   This is an OPERATIONS BOARD, not a dashboard. It is read fast, usually mid-
   task, often on a phone in a yard with a driver talking. So: dense, quiet,
   high contrast, and one accent that only ever means "look here".

   What this replaces, and why. The old sheet had fourteen distinct font sizes
   between 9px and 13px — which is not a scale, it is noise, and it made every
   element mumble at the same volume. It had twenty-one bordered boxes, so
   nothing could be more important than anything else. And it downloaded IBM
   Plex Sans Condensed on every page and used it twice.

   THE RULES HERE
   1. Six type steps. Nothing invents a seventh.
   2. Space separates; borders enclose. A border means "this is a distinct
      object you can act on", never "this is a region of the page".
   3. Numbers are tabular, right-aligned, and never wrap.
   4. Colour is for state and for data. Structure is monochrome.
   ───────────────────────────────────────────────────────────────────────── */

:root{
  /* surfaces */
  --ground:#eef1f3; --panel:#fff; --panel2:#f5f7f9; --raised:#fff;
  /* ink */
  --ink:#132029; --muted:#5a7380; --faint:#8ba0ab;
  /* lines: hairline for rhythm, strong for a real edge */
  --line:#dbe4e9; --line2:#e8eef1; --line3:#c3d2da;
  /* one accent */
  --accent:#0d6ea3; --accent-soft:#e3eef5;
  /* state */
  --hot:#1b6b3a; --warm:#a85a00; --cold:#7f8e99; --crit:#a31515;
  --warm-soft:#fdf2e0; --warm-line:#e5c187;
  /* data marks — validated for CVD in both themes, see the chart block below */
  --c-them:#0d6ea3; --c-us:#a85a00; --c-mark:#0d6ea3; --c-track:#e1e8ec;

  /* THE TYPE SCALE. Six steps. */
  --t-display:600 26px/1.15 "IBM Plex Sans",system-ui,sans-serif;
  --t-head:600 15px/1.3 "IBM Plex Sans",system-ui,sans-serif;
  --t-body:400 13px/1.55 "IBM Plex Sans",system-ui,sans-serif;
  --t-small:400 11.5px/1.5 "IBM Plex Sans",system-ui,sans-serif;
  --t-label:600 10px/1 "IBM Plex Sans Condensed","IBM Plex Sans",sans-serif;
  --t-mono:500 12.5px/1.4 "IBM Plex Mono",ui-monospace,monospace;

  --gap:16px; --pad:18px; --radius:6px;
}
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]){
  --ground:#0b1116; --panel:#131c23; --panel2:#18232b; --raised:#1a252d;
  --ink:#e6eef3; --muted:#93a9b5; --faint:#6b8290;
  --line:#243542; --line2:#1c2831; --line3:#324756;
  --accent:#4c9fc9; --accent-soft:#12303f;
  --hot:#5ec98a; --warm:#c2862f; --cold:#6b7c87; --crit:#e07a7a;
  --warm-soft:#2c2213; --warm-line:#6b4f21;
  --c-them:#4c9fc9; --c-us:#c2862f; --c-mark:#4c9fc9; --c-track:#1e2b34;
}}
:root[data-theme="dark"]{
  --ground:#0b1116; --panel:#131c23; --panel2:#18232b; --raised:#1a252d;
  --ink:#e6eef3; --muted:#93a9b5; --faint:#6b8290;
  --line:#243542; --line2:#1c2831; --line3:#324756;
  --accent:#4c9fc9; --accent-soft:#12303f;
  --hot:#5ec98a; --warm:#c2862f; --cold:#6b7c87; --crit:#e07a7a;
  --warm-soft:#2c2213; --warm-line:#6b4f21;
  --c-them:#4c9fc9; --c-us:#c2862f; --c-mark:#4c9fc9; --c-track:#1e2b34;
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--ground);color:var(--ink);font:var(--t-body);
  font-variant-numeric:tabular-nums;-webkit-font-smoothing:antialiased}
button,input,select,textarea{font-family:inherit}
[hidden]{display:none!important}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px}

.wrap{max-width:1360px;margin:0 auto;padding:0 20px 56px}
.spacer{flex:1}
.faint{color:var(--faint)}

/* A quiet link out of a panel — the page's navigation lives in the shell now. */
.navlink{font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);text-decoration:none;padding:7px 10px;border-radius:4px}
.navlink:hover{background:var(--panel2);color:var(--ink)}

.fresh{font:var(--t-label);letter-spacing:.06em;text-transform:uppercase;color:var(--faint);
  white-space:nowrap;padding:4px 6px}
.fresh.going{color:var(--accent)}
.fresh.bad,.fresh.off{color:var(--warm)}

/* ── panels: space separates, borders do not ─────────────────────────────── */
.panel{background:var(--panel);border-radius:var(--radius);margin-bottom:var(--gap);
  overflow:hidden}
.phead{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  padding:14px var(--pad) 10px}
.phead h2{font:var(--t-head);margin:0;letter-spacing:-.01em}
.lab{font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--faint)}
.empty{padding:22px var(--pad);color:var(--muted);font:var(--t-body)}
.empty b{color:var(--ink)}
footer,#foot{color:var(--faint);font:var(--t-small);padding:4px 2px 0;max-width:80ch}
footer b,#foot b{color:var(--muted);font-weight:600}

/* A warning is a real object, so it gets an edge — but a quiet one on the left
   only, because a full box here would compete with the data above it. */
.warn{margin:0 var(--pad) 14px;padding:10px 0 10px 12px;border-left:3px solid var(--line3);
  color:var(--muted);font:var(--t-small)}
.warn b{color:var(--ink)}
.warnrow{color:var(--warm);font:var(--t-small);padding:8px 0}

/* ── controls ────────────────────────────────────────────────────────────── */
.btn{font:var(--t-small);font-weight:500;color:var(--ink);background:var(--panel2);
  border:1px solid var(--line);border-radius:4px;padding:6px 11px;cursor:pointer;
  display:inline-flex;align-items:center;gap:6px;text-decoration:none;white-space:nowrap}
.btn:hover{border-color:var(--line3)}
.btn.solid{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.solid:hover{filter:brightness(1.08)}
.btn.quiet{background:none;border-color:transparent;color:var(--muted)}
.btn.quiet:hover{background:var(--panel2);color:var(--ink)}
.btn.sm{font-size:11px;padding:4px 8px}
.btn:disabled{opacity:.45;cursor:default}

.pick{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));
  gap:12px 18px;padding:0 var(--pad) 16px}
.g{display:flex;flex-direction:column;gap:5px;min-width:0}
.q{font:var(--t-body);color:var(--ink);background:var(--panel2);border:1px solid var(--line);
  border-radius:4px;padding:7px 9px;width:100%}
.q:focus{border-color:var(--accent);outline:none}
.states{display:flex;flex-wrap:wrap;gap:4px}
.states button{font:var(--t-mono);font-size:11px;color:var(--muted);background:var(--panel2);
  border:1px solid var(--line);border-radius:3px;padding:5px 8px;cursor:pointer}
.states button:hover{color:var(--ink);border-color:var(--line3)}
.states button[aria-pressed="true"]{background:var(--accent);border-color:var(--accent);color:#fff}
.chip{display:inline-block;font:var(--t-mono);font-size:11px;color:var(--muted);
  background:var(--panel2);border:1px solid var(--line);border-radius:3px;padding:5px 9px;cursor:pointer}
.chip.on{background:var(--accent);border-color:var(--accent);color:#fff}

/* ── tables: hairlines, sticky head, numbers that line up ────────────────── */
.tw{overflow-x:auto;padding:0 var(--pad) 16px}
.grid{border-collapse:collapse;width:100%;font:var(--t-body)}
.grid th{font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--faint);
  text-align:left;padding:0 14px 8px 0;border-bottom:1px solid var(--line3);white-space:nowrap;
  position:sticky;top:0;background:var(--panel);z-index:1}
.grid td{padding:9px 14px 9px 0;border-bottom:1px solid var(--line2);vertical-align:top}
.grid tbody tr:last-child td{border-bottom:0}
/* One gutter, on the right of every cell, last column excepted. Right-alignment
   never needed padding-right zeroed — doing that ran "LAST SEEN" straight into
   the next header, twice, because I fixed it by adding a LEFT gutter that the
   non-numeric column beside it did not have. */
.grid .n,.grid th.n{text-align:right;white-space:nowrap}
.grid td:last-child,.grid th:last-child{padding-right:0}
.grid .n{font-variant-numeric:tabular-nums}
.grid .k{font:var(--t-mono);color:var(--ink);white-space:nowrap}
.grid .lanes{font:var(--t-small);color:var(--muted);min-width:180px}
.grid .zero{color:var(--warm);font-weight:600}
tr.open{cursor:pointer}
tr.open:hover td{background:var(--panel2)}
.open{cursor:pointer}
.open:focus-visible{outline:2px solid var(--accent);outline-offset:-2px}

/* ── the funnel: three numbers and the rates between them ────────────────── */
.funnel{display:flex;flex-wrap:wrap;align-items:stretch;gap:2px;padding:4px var(--pad) 16px}
.stage{flex:1 1 128px;min-width:116px;display:flex;flex-direction:column;gap:2px;
  padding:12px 14px;background:var(--panel2);border-radius:5px}
.stage.won{background:var(--accent-soft)}
.stage .k{font:var(--t-label);letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}
.stage b{font:600 27px/1.05 "IBM Plex Sans",sans-serif;letter-spacing:-.025em;color:var(--ink)}
.stage .u,.arrow .u{font:var(--t-small);font-size:11px;color:var(--faint);line-height:1.35}
.arrow{flex:0 0 74px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:1px}
.arrow .rate{font:600 15px/1 "IBM Plex Sans",sans-serif;color:var(--muted)}
.arrow .rate.big{font-size:18px;color:var(--ink)}
.arrow::before{content:"→";color:var(--line3);font-size:14px;line-height:1;margin-bottom:2px}
.ftwo{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:10px 22px;
  padding:0 var(--pad) 16px;color:var(--muted);font:var(--t-small)}
.ftwo b{color:var(--ink);font-weight:600}

/* ── bars ────────────────────────────────────────────────────────────────── */
.bars{display:flex;flex-direction:column;gap:6px;padding:2px var(--pad) 14px}
.bar{display:grid;grid-template-columns:168px 1fr 54px;align-items:center;gap:12px;font:var(--t-body)}
.bt{height:10px;background:var(--c-track);border-radius:2px;overflow:hidden}
.bf{display:block;height:100%;border-radius:2px;background:var(--c-them)}
.bf.us{background:var(--c-us)}
.bn{text-align:right;font-weight:600;font-variant-numeric:tabular-nums}
.legend{display:flex;align-items:center;gap:5px;font:var(--t-small);color:var(--muted)}
.sw{width:9px;height:9px;border-radius:2px;background:var(--c-them);display:inline-block;margin-left:8px}
.sw.us{background:var(--c-us)}

/* in-cell magnitude */
.cell{min-width:148px}
.ib{display:block;height:7px;background:var(--c-track);border-radius:2px;overflow:hidden;margin-bottom:3px}
.ibf{display:block;height:100%;border-radius:2px;background:var(--c-mark)}
.ibn{font:var(--t-small);font-size:11px;color:var(--muted)}

/* ── week bars ───────────────────────────────────────────────────────────── */
.trends{display:grid;grid-template-columns:repeat(auto-fit,minmax(212px,1fr));gap:16px;
  padding:2px var(--pad) 18px}
.tr{display:grid;grid-template-columns:auto 1fr;grid-template-rows:auto auto;gap:4px 10px;align-items:end}
.tr .k{grid-column:1/-1;font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--faint)}
.tr b{font:600 18px/1 "IBM Plex Sans",sans-serif;color:var(--ink)}
.tr .u{font:var(--t-small);font-size:10.5px;color:var(--faint)}
.spark .wb{fill:var(--c-mark);opacity:.38}
.spark .wb.now{opacity:1}
.spark.tiny .wb{opacity:.6}

/* ── where a number sits against the fleet ───────────────────────────────── */
.vs{margin-left:4px;font-size:9px;line-height:1;cursor:default}
/* Beating what we earn is the signal; falling short of it is the common case on
   any screen listing what the market offered. Marking both in strong colour put
   an amber arrow on four rows in five and pointed at nothing. Below recedes,
   above stands out, and the exact multiple is on hover either way. */
.vs.up{color:var(--hot)}
.vs.down{color:var(--faint);opacity:.55}
.vs.flat{color:var(--faint);opacity:.55}

/* ── a truck that wants looking at ───────────────────────────────────────── */
.flags{display:flex;flex-wrap:wrap;gap:8px;padding:2px var(--pad) 14px}
.flag{flex:1 1 214px;display:flex;flex-direction:column;gap:2px;padding:10px 12px;
  border:1px solid var(--warm);border-radius:5px}
.flag b{font:var(--t-mono);font-size:13px;color:var(--ink)}
.flag span:not(.u){color:var(--warm);font-weight:600;font-size:11.5px}
.flag .u{font:var(--t-small);font-size:11px;color:var(--faint)}
.flag.open:hover{background:var(--panel2)}
.tflag{display:inline-block;margin-left:6px;width:14px;height:14px;line-height:14px;text-align:center;
  border-radius:50%;background:var(--warm);color:var(--panel);font:700 9px "IBM Plex Sans",sans-serif;
  vertical-align:middle;cursor:default}

/* ── cards: what a table becomes on a phone, and how lanes read ──────────── */
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(268px,1fr));gap:8px;
  padding:2px var(--pad) 16px}
.card{border:1px solid var(--line);border-radius:5px;padding:11px 12px;background:var(--panel)}
.card.open:hover{border-color:var(--accent)}
.ch{display:flex;align-items:baseline;gap:8px;margin-bottom:8px}
.ch b{font:var(--t-mono);font-size:13px;color:var(--ink)}
.tag{font:var(--t-label);letter-spacing:.06em;text-transform:uppercase;padding:3px 6px;
  border-radius:3px;white-space:nowrap}
.tag.ours{color:var(--hot);border:1px solid var(--hot)}
.tag.never{color:var(--warm);border:1px solid var(--warm)}
.cm{display:grid;grid-template-columns:1fr 1fr;gap:4px 12px;font:var(--t-small);font-size:12px;color:var(--ink)}
.cm span{display:flex;gap:6px;align-items:baseline;line-height:1.5;font-variant-numeric:tabular-nums}
.cm i{font:var(--t-label);letter-spacing:.05em;text-transform:uppercase;color:var(--faint);
  font-style:normal;min-width:54px;flex:0 0 auto;white-space:nowrap}

/* ── the rules directory ─────────────────────────────────────────────────── */
/* One ruleset per row: a tick, the board and what it is, and its actions on the
   right. These class names are built inside a template literal in app.js, which
   is why a regex sweep of the markup did not find them and an earlier pass
   dropped their styles — the page fell back to stacked full-width blocks. */
.list{display:flex;flex-direction:column;padding:0 var(--pad) 8px}
.rule{display:grid;grid-template-columns:auto 1fr auto;gap:10px 14px;align-items:center;
  padding:10px 0;border-bottom:1px solid var(--line2)}
.rule:last-child{border-bottom:0}
.rule.sel{background:var(--accent-soft);margin:0 calc(var(--pad) * -1);
  padding-left:var(--pad);padding-right:var(--pad)}
.rule h3{font:var(--t-head);font-size:14px;margin:0 0 3px;letter-spacing:-.01em}
.tick{padding-top:2px}
.tick input{width:15px;height:15px;accent-color:var(--accent);cursor:pointer}
.by{font:var(--t-small);color:var(--muted)}
.by b{color:var(--ink);font-weight:600}
/* Label/value pairs on one line need their own gaps — without them they ran
   together as "origins CT MA NY PAcities BINGHAMTON". */
.crit{display:flex;flex-wrap:wrap;gap:3px 16px;margin-top:4px;font:var(--t-small);color:var(--muted)}
.crit b{color:var(--ink);font-weight:600;font-family:"IBM Plex Mono",monospace;font-size:11.5px}
.note{font:var(--t-small);color:var(--muted);margin:6px 0 0;max-width:70ch}

/* The row's action group, scoped. `.acts` is also the activity list below — two
   unrelated things under one name, the same collision `.ref` had. */
/* Horizontal and compact. Stacked, four buttons made every row 148px tall and
   the page 5,500px for a list of twenty-one boards — eighty-four controls all
   shouting at the same volume. Only "Copy" carries weight; the rest are text. */
.rule .acts{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;
  gap:2px;padding:0;max-width:330px}
.rule .acts .btn{font-size:11px;padding:4px 8px}
.rule .acts .btn.quiet{color:var(--faint)}
.rule .acts .btn.quiet:hover{color:var(--ink)}
.tok{font:var(--t-small);font-size:11px;color:var(--muted);background:var(--panel2);
  border-radius:3px;padding:3px 7px}
.tok b{color:var(--ink);font-weight:600}
.toks{display:flex;flex-wrap:wrap;gap:6px;padding:0 var(--pad) 12px}
.asme{font:var(--t-body);font-weight:600;color:var(--ink);padding:8px 0 0}

/* ── the rule editor ─────────────────────────────────────────────────────── */
.form{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:12px 18px;padding:0 var(--pad) 14px}
.form .full{grid-column:1/-1}
.form label{display:block;font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);margin-bottom:5px}
.form input{font:var(--t-body);color:var(--ink);background:var(--panel2);border:1px solid var(--line);
  border-radius:4px;padding:7px 9px;width:100%}
.form input:focus{border-color:var(--accent);outline:none}
.formfoot{display:flex;align-items:center;gap:10px;padding:0 var(--pad) 16px}
.err{color:var(--crit);font:var(--t-small)}
.ed{display:grid;grid-template-columns:1fr;gap:14px;padding:0 var(--pad) 8px}
.ed h3{font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin:0 0 7px}
.edtools{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:8px}
.edtools button{font:var(--t-small);color:var(--muted);background:var(--panel2);
  border:1px solid var(--line);border-radius:4px;padding:5px 9px;cursor:pointer}
.edtools button:hover{color:var(--ink);border-color:var(--line3)}
.ed textarea{width:100%;min-height:320px;font:var(--t-mono);font-size:12px;color:var(--ink);
  background:var(--panel2);border:1px solid var(--line);border-radius:5px;padding:11px;resize:vertical}
.ed textarea:focus{border-color:var(--accent);outline:none}
.msgs{display:flex;flex-direction:column;gap:5px;margin-top:9px}
.msg{font:var(--t-small);padding:7px 10px;border-radius:4px;background:var(--panel2);color:var(--muted)}
.msg b{color:var(--ink);font-weight:600}
.msg.stop{border-left:3px solid var(--crit);color:var(--ink)}
.ref{margin-top:12px;border-top:1px solid var(--line2);padding-top:10px}
.ref summary{cursor:pointer;font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;
  color:var(--muted);list-style:none}
.ref summary::-webkit-details-marker{display:none}
.ref summary::before{content:"\25B8  ";color:var(--faint)}
.ref[open] summary::before{content:"\25BE  "}
.ref table{width:100%;border-collapse:collapse;font:var(--t-small);margin-top:8px}
.ref td{padding:4px 10px 4px 0;border-bottom:1px solid var(--line2);vertical-align:top;color:var(--muted)}
.ref td:first-child{font:var(--t-mono);font-size:11.5px;color:var(--ink);white-space:nowrap}
.rnote{font:var(--t-small);color:var(--muted);margin-top:6px}
.rtab{width:100%;border-collapse:collapse;font:var(--t-small)}
.rwrap{overflow-x:auto}

/* what a rule would have caught */
.back{border-top:1px solid var(--line2);margin:0 var(--pad);padding-top:12px}
.backhead{font:var(--t-small);color:var(--muted);padding-bottom:8px}
.backhead b{color:var(--ink);font-weight:600}
.blind{margin-top:5px;font:var(--t-small);font-size:11px;color:var(--warm)}
.blind b{font-family:"IBM Plex Mono",monospace;font-weight:500}

/* ── archived boards and the activity list ───────────────────────────────── */
.arcs,#aside .acts{display:flex;flex-direction:column;padding:0 var(--pad) 14px}
.arc,#aside .act{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;font:var(--t-body);
  padding:8px 0;border-bottom:1px solid var(--line2)}
.arc:last-child,#aside .act:last-child{border-bottom:0}
.arc b,#aside .act b{color:var(--ink);font-weight:600}
.act .w{font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--faint);min-width:64px}
#aside .act .d{flex:1 1 auto;color:var(--faint);font:var(--t-small);padding-left:0;margin:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:34ch}
#aside .act{padding:6px 0}

/* ── signing in ──────────────────────────────────────────────────────────── */
.signin{min-height:100dvh;display:grid;place-items:center;padding:24px 16px}
.signin .card{width:100%;max-width:340px;background:var(--panel);border:1px solid var(--line);
  border-radius:8px;padding:28px 26px 22px;display:flex;flex-direction:column;gap:5px}
.signin h1{font:var(--t-display);font-size:22px;margin:0;letter-spacing:-.02em}
.signin .lede{color:var(--muted);font:var(--t-small);margin:3px 0 16px}
.signin label{font:var(--t-label);letter-spacing:.07em;text-transform:uppercase;color:var(--muted);margin-top:11px}
.signin input{font:var(--t-body);font-size:14px;color:var(--ink);background:var(--panel2);
  border:1px solid var(--line);border-radius:4px;padding:9px 10px;width:100%}
.signin input:focus{border-color:var(--accent);outline:none}
.signin .btn{margin-top:18px;justify-content:center;padding:9px}
.signin .msg{font:var(--t-small);margin:10px 0 0;min-height:1.2em;background:none;padding:0}
.signin .msg.bad{color:var(--crit)}
.signin .foot{color:var(--faint);font:var(--t-small);margin:16px 0 0;
  border-top:1px solid var(--line2);padding-top:12px}

/* ── transient ───────────────────────────────────────────────────────────── */
.toast{position:fixed;left:50%;bottom:22px;transform:translateX(-50%);background:var(--ink);
  color:var(--ground);font:var(--t-small);padding:9px 16px;border-radius:5px;z-index:20}
.why{font:var(--t-small)}
.why.us{color:var(--warm)}
.why .msg{display:block;color:var(--faint);font-size:10.5px;margin-top:2px;background:none;padding:0;
  max-width:38ch;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* ─────────────────────────────────────────────────────────────────────────
   THE PHONE. Not "it does not break at 390px" — a different layout.
   A dispatcher here has one hand and eight seconds. Tables become cards,
   because a table that scrolls sideways hides exactly the columns that made
   it worth opening, behind a gesture nobody discovers.
   ───────────────────────────────────────────────────────────────────────── */
@media (max-width:760px){
  .wrap{padding:0 12px 40px}
  .phead{padding:12px 14px 8px}
  .pick,.form,.ftwo,.trends,.cards,.cm{grid-template-columns:1fr}
  .tw,.bars,.flags,.arcs,.acts,.toks{padding-left:14px;padding-right:14px}
  .warn{margin-left:14px;margin-right:14px}

  /* the funnel reads down the page */
  .funnel{gap:4px;padding:4px 14px 14px}
  .stage{flex:1 1 100%;flex-direction:row;align-items:baseline;gap:10px}
  .stage .k{min-width:58px}
  .stage b{font-size:23px}
  .stage .u{margin-left:auto;text-align:right}
  .arrow{flex:1 1 100%;flex-direction:row;justify-content:flex-start;gap:8px;padding-left:4px}
  .arrow::before{content:"↓";margin:0}

  /* label, number, then the bar beneath both */
  .bar{grid-template-columns:1fr auto;gap:3px 10px}
  .bar .bt{grid-column:1/-1;order:3;height:8px}

  /* A TABLE BECOMES A LIST OF RECORDS. Each cell keeps its column name, so
     nothing is hidden and nothing needs a sideways swipe. */
  .grid,.grid tbody,.grid tr,.grid td{display:block;width:100%}
  .grid thead{display:none}
  .grid tbody tr{border:1px solid var(--line);border-radius:5px;padding:9px 11px;
    margin-bottom:8px;background:var(--panel)}
  .grid tbody tr:last-child td{border-bottom:0}
  .grid td{border-bottom:1px solid var(--line2);padding:4px 0;display:flex;
    align-items:baseline;gap:10px;text-align:left!important;font-size:12.5px}
  .grid td:last-child{border-bottom:0}
  .grid td::before{content:attr(data-h);font:var(--t-label);letter-spacing:.06em;
    text-transform:uppercase;color:var(--faint);min-width:78px;flex:0 0 auto}
  /* Only the FIRST cell is the row's identity and goes without a label. A row
     with two mono cells — From and To — showed two bare city names otherwise. */
  .grid td.k:first-child{font-size:14px;border-bottom:1px solid var(--line3);
    padding-bottom:7px;margin-bottom:3px}
  .grid td.k:first-child::before{content:"";min-width:0}
  .grid .n{text-align:left;margin-left:0}
  .grid .n::after{content:"";}
  /* A cell of free-flowing text is not a label/value pair — making it a flex row
     turned every text node into its own line and dropped each count onto one. */
  .grid td.lanes,.grid td.cell{display:block;min-width:0;line-height:1.55}
  .grid td.lanes::before,.grid td.cell::before{display:block;margin-bottom:3px}
  .grid td.why{display:block}
  .grid td.why::before{display:block;margin-bottom:2px}
  .grid td.why .msg{white-space:normal;max-width:none}
  footer,#foot{font-size:11px}
}

/* a sortable header says so, and says which way */
.grid th.sortable{cursor:pointer;user-select:none}
.grid th.sortable:hover{color:var(--ink)}
.grid th[aria-sort]{color:var(--ink)}
.sarr{margin-left:4px;font-size:8px;color:var(--accent);vertical-align:1px}
