/* v2 — dashboard + map widget layer, loaded after app.css */
.wgrid{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:14px}
.w{min-width:0}
.card.pad{padding:15px 17px 17px}
.wh{display:flex;align-items:baseline;gap:9px;margin-bottom:13px}
.wh.pad-h{padding:15px 17px 0;margin-bottom:11px}
.wh h3{font-size:12.5px;font-weight:600;letter-spacing:-.005em}
.wh span{font-size:11.5px;color:var(--ink-3)}
.wlink{margin-left:auto;background:none;border:0;color:var(--brand);font-size:11.5px;cursor:pointer;padding:0}
.wlink:hover{text-decoration:underline}
.mini.pad{padding:22px 17px}

/* VSI adoption — two stat rows. (.donut/.dnum/.dsub, .minibar and
   `.card .track` lived here and went with the donut; the KPI strip's bar is
   `.kpi .track` in app.css and is a different rule entirely.) */
.adlab{font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-3);margin-bottom:6px}
.adrow{display:flex;align-items:baseline;justify-content:space-between;gap:10px;margin-bottom:8px}
.adbig{font-size:32px;font-weight:700;letter-spacing:-.02em;line-height:1;color:var(--ink)}
/* The unit and the denominator ride at the figure's own size rather than as
   a second 32px number — "542 / 11,279" is one fact, and setting both halves
   equally makes the reader work out which one is the answer. */
.adbig em{font-style:normal;font-size:.55em;font-weight:600;color:var(--ink-3);letter-spacing:0}
.adbig.sm{font-size:20px;letter-spacing:-.01em;font-variant-numeric:tabular-nums}
.adbig.sm em{font-size:.75em}
.adsub{font-size:12.5px;color:var(--ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.adbar{height:8px;border-radius:4px;background:var(--surface-3);overflow:hidden}
.adbar i{display:block;height:100%;border-radius:4px;background:var(--brand)}
.adsep{height:1px;background:var(--line);margin:18px 0 16px}

/* funnel */
.fnl{display:flex;flex-direction:column;gap:6px}
.fr{display:grid;grid-template-columns:82px minmax(0,1fr) 30px;align-items:center;gap:10px;background:none;border:0;padding:2px 6px;margin:0 -6px;border-radius:7px;cursor:pointer;text-align:left}
.fr:hover{background:var(--surface-3)}
.fl{font-size:11.5px;color:var(--ink-2);text-align:right;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* A TRACK with a left-aligned fill. It used to be a centred bar on no track
   (`justify-content:center`), so two stages of different size shared neither
   a start nor an end edge and there was nothing to read a length against —
   the one comparison a funnel is for. */
.fb{height:16px;border-radius:4px;background:var(--surface-3);overflow:hidden}
.fb i{display:block;height:100%;border-radius:4px}
/* Zero: an empty outline, no fill. `min-width:8px` used to give a count of
   nought the same solid block as a count of one. */
.fb.fz{background:transparent;border:1px dashed var(--line-2)}
.fv{font-size:12.5px;font-weight:600;font-variant-numeric:tabular-nums;text-align:right}
.fnote{display:flex;gap:16px;margin-top:12px;padding-top:11px;border-top:1px solid var(--line);font-size:11.5px;color:var(--ink-3)}
.fnote i{width:7px;height:7px;border-radius:2px;display:inline-block;margin-right:5px}

/* 7-day strip + agenda */
.dstrips{display:grid;grid-template-columns:repeat(7,1fr);gap:5px;margin-bottom:13px}
.dstrip{border:1px solid var(--line);border-radius:8px;padding:6px 4px 5px;text-align:center;background:var(--surface-2);display:flex;flex-direction:column;align-items:center;gap:1px}
.dstrip.has{background:var(--brand-soft);border-color:transparent}
.dstrip.now{border-color:var(--brand);box-shadow:inset 0 0 0 1px var(--brand)}
.dstrip .dd{font-size:9.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.dstrip .dn{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.dbars{display:flex;gap:2px;height:5px;margin-top:2px}
.dbars i{width:5px;height:5px;border-radius:50%;background:var(--amber)}
.dbars i.done{background:var(--green)}
/* A call is a square pip, a visit a round one — at 5px a colour difference is
   not readable but a shape difference is. */
.dbars i.call{border-radius:1px}
.agenda{display:flex;flex-direction:column;gap:6px}
.ag{display:flex;align-items:center;gap:11px;width:100%;text-align:left;background:var(--surface-2);border:1px solid var(--line);border-left:3px solid var(--blue);border-radius:8px;padding:7px 11px;cursor:pointer}
.ag:hover{background:var(--surface);border-color:var(--line-2)}
.ag.late{border-left-color:var(--red)}.ag.today{border-left-color:var(--amber)}
.agd{display:flex;flex-direction:column;align-items:center;line-height:1.05;min-width:26px}
.agd b{font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
.agd em{font-style:normal;font-size:9px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3)}
.agm{display:flex;flex-direction:column;min-width:0;flex:1}
.agm b{font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.agm em{display:flex;align-items:center;gap:4px;font-style:normal;font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden}
.agm em svg{width:11px;height:11px;flex:none;opacity:.75}
.ag.k-call .agm em svg{color:var(--violet);opacity:1}
.agp{font-size:9.5px;font-weight:600;letter-spacing:.07em;text-transform:uppercase;color:var(--ink-3);white-space:nowrap}
.ag.late .agp{color:var(--red)}.ag.today .agp{color:var(--amber)}

/* ===== "Where to go next" — recorded fleet bands + named go-list ===== */
.gocap{display:flex;align-items:center;gap:7px;font-size:11px;color:var(--ink-2);margin-bottom:9px}
.gocap i{width:11px;height:11px;border-radius:3px;background:var(--brand);opacity:.16;
  box-shadow:inset 0 0 0 1px var(--brand);flex:none}
.gocap b{font-weight:600;color:var(--ink)}
.gocap .gocount{margin-left:auto;font-variant-numeric:tabular-nums;color:var(--brand)}

/* The heatmap: 5 recorded fleet bands x 5 drive-time buckets, counts only.
   A grid of numbers rather than 139 plotted dots, because the fleet field is
   written in BANDS — the dot swarm had to invent a midpoint per record and
   then overlap them, and no amount of dodging made 25 points in one bucket
   legible. Here the bucket just says 25.
   Cells are NOT interactive: everything clickable in this widget is a named
   button in the list below. */
.gogrid{display:grid;grid-template-columns:64px repeat(5,minmax(0,1fr));gap:5px;margin-bottom:6px}
.gocol{text-align:center;font-size:10px;font-weight:600;letter-spacing:.04em;
  color:var(--ink-3);padding-bottom:3px}
.goband{text-align:right;font-size:11px;font-weight:500;color:var(--ink-2);
  align-self:center;padding-right:6px;white-space:nowrap}
/* --f is the ramp alpha, computed per cell in widgets.js. color-mix keeps the
   ramp in ONE place: the JS emits a number, the palette stays in CSS, so a
   theme change does not mean re-deriving rgba() strings in a string template. */
.gocell{height:44px;border-radius:var(--r-sm);display:flex;align-items:center;
  justify-content:center;border:1px solid var(--line);padding:0;margin:0;
  font:inherit;color:inherit;
  background:color-mix(in srgb,var(--ink-3) calc(var(--f,.05)*100%),transparent)}
.gocell b{font-size:15px;font-weight:700;font-variant-numeric:tabular-nums;line-height:1}
/* Only a cell with districts in it is a button — see widgets.js. */
button.gocell{cursor:pointer}
button.gocell:hover{border-color:var(--line-2)}
button.gocell:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
/* The open cell. A ring rather than a fill change, so the qualifying block's
   own tint still reads underneath and selecting a cell inside it does not
   look like it has left the block. */
.gocell.on{box-shadow:inset 0 0 0 2px var(--brand);border-color:var(--brand)}
.gocell.on b{color:var(--brand-ink)}
/* The qualifying block — top two bands x first two buckets — is tinted and
   outlined so "hit these first" reads as one shape rather than four unrelated
   squares. Its bounds are emitted from BIGBAND and the column rule, so the
   block cannot drift away from the count in the caption. */
.gocell.q{border:1.5px solid color-mix(in srgb,var(--brand) 55%,transparent);
  background:color-mix(in srgb,var(--brand) calc(var(--f,.12)*100%),transparent)}
.gocell.z b{color:var(--ink-5)}

.golegend{display:flex;align-items:center;gap:14px;font-size:10.5px;
  color:var(--ink-3);margin-bottom:4px}
.golegend span{display:flex;align-items:center;gap:5px}
.golegend i{width:9px;height:9px;border-radius:2px;display:block;flex:none}
.golegend .k1{background:color-mix(in srgb,var(--ink-3) 12%,transparent)}
.golegend .k2{background:color-mix(in srgb,var(--ink-3) 24%,transparent);margin-left:-3px}
.golegend .k3{background:color-mix(in srgb,var(--ink-3) 36%,transparent);margin-left:-3px;margin-right:1px}
.golegend .kq{background:color-mix(in srgb,var(--brand) 24%,transparent);
  box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--brand) 60%,transparent)}

/* Header shown when a cell is open, in place of nothing — the ranked list has
   no header because it is the card's default. */
.gosel{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap;
  margin:12px 0 -6px;font-size:11px;color:var(--ink-2)}
.gosel span{font-weight:600;color:var(--ink)}
.gosel .lnk2{margin-left:auto;font-size:11px}
/* The list's own empty state sits where rows would be, not as a page-level
   panel — .mini alone has no top margin and would ride up against the axis. */
.gonone{margin-top:12px;line-height:1.5}

.golist{list-style:none;margin:12px 0 0;padding:0;display:flex;flex-direction:column;gap:1px}
.gorow{display:grid;grid-template-columns:7px minmax(0,1fr) auto auto;align-items:center;gap:9px;
  width:100%;min-height:28px;background:none;border:0;border-radius:7px;padding:4px 8px;
  margin:0 -8px;cursor:pointer;text-align:left;font:inherit;color:inherit}
.gorow:hover{background:var(--surface-3)}
.gost{width:7px;height:7px;border-radius:2px}
.gon{font-size:12.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* The status WORD only where it is not Prospect — showing the exception, not
   the rule. 126 of 139 districts are Prospect; 9 of these 15 are not. */
.gosl{font-size:9.5px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  color:var(--ink-3);white-space:nowrap}
.god{font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums;white-space:nowrap}
.gorow.term .gon{color:var(--ink-3);font-weight:500}
/* <details> rather than a JS toggle: no new listener, no state to lose when
   app.js:866 replaces #viewbody on every Firestore snapshot, keyboard-native. */
.gomore{margin-top:5px}
.gomore>summary{font-size:11.5px;color:var(--brand);cursor:pointer;padding:4px 0;list-style:none}
.gomore>summary::-webkit-details-marker{display:none}
.gomore>summary::before{content:"▸ "}
.gomore[open]>summary::before{content:"▾ "}

@media(max-width:640px){
  /* All five columns stay — they are counts, not the old chart's hour ticks,
     so none of them has to be dropped to fit. The label gutter and the cells
     give back the height instead. */
  .gogrid{grid-template-columns:46px repeat(5,minmax(0,1fr));gap:4px}
  .goband{font-size:9.5px;padding-right:4px}
  .gocol{font-size:9px;letter-spacing:0}
  .gocell{height:36px}
  .gocell b{font-size:13.5px}
}
.axnote{display:flex;justify-content:space-between;font-size:10.5px;color:var(--ink-3);margin-top:2px}

/* Platform in use — one ranked row per platform. (Replaced .sbar/.sleg, a
   single stacked bar whose `flex:n` segments had no minimum width, so a
   platform with 3 of 140 was a few pixels while the legend beside it printed
   the real number.) */
.plist{display:flex;flex-direction:column;gap:13px}
.phead{display:flex;align-items:baseline;gap:7px;margin-bottom:5px}
.phead i{width:8px;height:8px;border-radius:2px;flex:none;align-self:center}
.pname{font-size:12.5px;font-weight:600;color:var(--ink);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* margin-left:auto on the COUNT, so the label keeps whatever room it needs
   and the count/share pair stays welded to the right edge.
   NOT `.pn` — app.css already owns that for the plain-text inputs in Settings,
   Issues and the VSI Queue, and this rule was silently shoving every one of
   them to the right edge of its row. */
.pcount{margin-left:auto;font-size:12.5px;font-weight:700;font-variant-numeric:tabular-nums;
  color:var(--ink);flex:none}
/* A fixed gutter, so the shares line up as a column instead of drifting with
   the width of each count. */
.ppct{font-size:11px;color:var(--ink-3);font-variant-numeric:tabular-nums;
  min-width:34px;text-align:right;flex:none}
.pbar{height:9px;border-radius:5px;background:var(--surface-3);overflow:hidden}
.pbar i{display:block;height:100%;border-radius:5px}
.pfoot{margin-top:14px;padding-top:11px;border-top:1px solid var(--line);
  font-size:11px;color:var(--ink-3)}
.pfoot b{color:var(--amber);font-weight:600}

/* hot list + feed */
.hotlist{display:flex;flex-direction:column;gap:5px}
.hot{display:flex;align-items:center;gap:10px;width:100%;text-align:left;background:none;border:0;border-radius:7px;padding:7px 8px;margin:0 -8px;cursor:pointer}
.hot:hover{background:var(--surface-3)}
.hot i{width:7px;height:7px;border-radius:2px;flex:none}
.hn{display:flex;flex-direction:column;min-width:0;flex:1}
.hn em{font-style:normal;font-size:11px;color:var(--ink-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.hd{font-size:11.5px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.feed{list-style:none;margin:0;padding:0;position:relative}
.feed::before{content:"";position:absolute;left:4px;top:8px;bottom:12px;width:1px;background:var(--line)}
.feed li{display:flex;gap:13px;padding:0 0 13px;cursor:pointer;position:relative}
.feed li:last-child{padding-bottom:0}
.fdot{width:18px;height:18px;border-radius:50%;background:var(--green-soft);color:var(--green);
  border:2px solid var(--surface);flex:none;margin-top:1px;z-index:1;display:grid;place-items:center}
.fdot svg{width:10px;height:10px}
.feed li.k-call .fdot{background:var(--violet-soft);color:var(--violet)}
.feed li div{display:flex;flex-direction:column;min-width:0}
.feed li b{font-size:12.5px;font-weight:600}
.feed li em{font-style:normal;font-size:11.5px;color:var(--ink-2)}
.feed li span{font-size:10.5px;color:var(--ink-3);font-variant-numeric:tabular-nums;margin-top:1px}
.feed li:hover b{color:var(--brand)}

/* map */
.mapwrap{display:grid;grid-template-columns:minmax(0,300px) minmax(0,260px);justify-content:center;gap:16px;padding:0 17px 17px}
.mapwrap.big{grid-template-columns:minmax(0,min(470px, calc((100vh - 250px) * .64))) minmax(0,440px);justify-content:center}
.mapbox{position:relative;display:flex;justify-content:center;align-items:flex-start;min-width:0}
/* The map scales with its column instead of being pinned to px. Alabama's
   viewBox is 0.64 wide per unit tall, so capping WIDTH is what bounds height:
   --maph is the tallest the map may draw, set inline from data-h. */
.almap{display:block;width:100%;max-width:100%;height:auto}
.mapbox{max-width:calc(var(--maph,320px) * .64)}
.mapwrap:not(.big) .mapbox{max-width:min(300px, calc((100vh - 420px) * .64))}
.mapwrap.big .mapbox{max-width:min(470px, calc((100vh - 250px) * .64))}

.maploading{padding:80px 20px;text-align:center;color:var(--ink-3);font-size:12.5px}
.mapside{display:flex;flex-direction:column;gap:14px;min-width:0}
.mstats{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:9px}
.mstats div{display:flex;flex-direction:column;background:var(--surface-2);border:1px solid var(--line);border-radius:8px;padding:8px 11px}
.mstats b{font-size:19px;font-weight:600;letter-spacing:-.025em;font-variant-numeric:tabular-nums}
.mstats b em{font-style:normal;font-size:11px;font-weight:500;color:var(--ink-3);margin-left:2px}
.mstats span{font-size:10.5px;color:var(--ink-3);letter-spacing:.02em}
.mslab{font-size:10.5px;font-weight:600;letter-spacing:.09em;text-transform:uppercase;color:var(--ink-4)}
.cty-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:1px 18px;margin-top:-8px}
.cty-row{display:flex;align-items:center;gap:8px;background:none;border:0;padding:5px 7px;margin:0 -7px;border-radius:6px;cursor:pointer;text-align:left;font-size:12px;color:var(--ink-2)}
.cty-row:hover{background:var(--surface-3);color:var(--ink)}
.cty-row i{width:7px;height:7px;border-radius:2px;flex:none}
.cty-row span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.cty-row em{margin-left:auto;font-style:normal;font-size:10.5px;color:var(--ink-3);white-space:nowrap}
.almap .outline{fill:var(--surface-2);stroke:none}
.almap .outline2{fill:none;stroke:var(--ink-4);stroke-width:1.1;pointer-events:none}
.almap .cty{stroke:var(--surface);stroke-width:.6;transition:fill-opacity .12s}
.almap .cty.on{cursor:pointer}
.almap .cty.on:hover{fill-opacity:1;stroke:var(--ink);stroke-width:1.2}
.almap .ring{fill:none;stroke:var(--brand);stroke-width:1;stroke-dasharray:3 4;opacity:.45}
.almap .ringlab{font-size:9px;fill:var(--brand);font-weight:600;opacity:.75}
.almap .cdot{cursor:pointer;stroke:var(--surface);stroke-width:1.4}
.almap .cdot:hover{stroke:var(--ink);stroke-width:2}
.almap .home circle{fill:var(--ink)}
.almap .home .hhalo{fill:var(--ink);opacity:.16}
.almap .home text{font-size:10px;font-weight:600;fill:var(--ink)}
.maplegend{display:flex;flex-wrap:wrap;gap:7px 14px;align-items:center;font-size:11px;color:var(--ink-2)}
.maplegend span{display:flex;align-items:center;gap:6px}
.maplegend i{width:8px;height:8px;border-radius:2px;flex:none}
.maplegend .dotml{border-radius:50%;background:var(--ink-3)}
.maplegend .ringml{border-radius:50%;background:none;border:1px dashed var(--brand)}
.ml-sep{width:100%;height:1px;background:var(--line);padding:0}

/* field log */
.logwrap{display:flex;flex-direction:column;gap:14px}
.logsum{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:22px;align-items:start}
.logstats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.logstats div{display:flex;flex-direction:column;gap:1px;background:var(--surface-2);border:1px solid var(--line);border-radius:9px;padding:10px 13px}
.logstats b{font-size:23px;font-weight:600;letter-spacing:-.028em;font-variant-numeric:tabular-nums;line-height:1.15}
.logstats span{font-size:10.5px;color:var(--ink-3);letter-spacing:.02em}
.logchartwrap{min-width:0}
.ckey{display:flex;align-items:center;gap:5px;margin-left:auto;font-size:10.5px;color:var(--ink-3)}
.ckey i{width:7px;height:7px;border-radius:2px;display:inline-block}
.ckey .kd{background:var(--green)}.ckey .kp{background:var(--amber);margin-left:7px}
.lchart{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:8px;align-items:end}
.lc{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:0}
.lc>b{font-size:11px;font-weight:600;color:var(--ink-2);font-variant-numeric:tabular-nums;height:14px}
.lcb{display:flex;flex-direction:column-reverse;justify-content:flex-start;align-items:stretch;width:100%;max-width:34px;height:74px;gap:2px}
.lcb i{display:block;border-radius:3px;min-height:3px}
.lcb .d{background:var(--green)}
.lcb .p{background:var(--amber)}
.lc>span{font-size:10.5px;color:var(--ink-3);letter-spacing:.03em}
.lc>span.cur{color:var(--ink);font-weight:600}

.logtop{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
/* Was `.logtop .btn.sm:nth-of-type(1){margin-left:auto}`. That counted the
   first sibling <button>, which is now the conditional Clear — so the actions
   drifted left the moment a filter was on. An explicit spacer cannot drift. */
.logspacer{flex:1 1 0;min-width:0}
.logsel{display:inline-flex;align-items:center;gap:7px;height:32px;padding:0 4px 0 11px;
  background:var(--surface-3);border-radius:9px;font-size:12.5px;color:var(--ink-2)}
.logsel>span{font-weight:500;white-space:nowrap}
.logsel select{max-width:190px;border:0;background:none;font:inherit;font-size:12.5px;color:var(--ink);
  cursor:pointer;padding:0 4px;outline:none}
.logsel:focus-within{box-shadow:var(--ring)}
.segbar{display:inline-flex;background:var(--surface-3);border-radius:9px;padding:3px;gap:2px}
.segbar button{display:inline-flex;align-items:center;gap:6px;background:none;border:0;border-radius:7px;padding:5px 12px;font-size:12.5px;font-weight:500;color:var(--ink-2);cursor:pointer}
.segbar button span{font-size:11px;color:var(--ink-3);font-variant-numeric:tabular-nums}
.segbar button svg{width:13px;height:13px;opacity:.7}
.segbar button[aria-pressed="true"] svg{opacity:1}
.segbar button:hover{color:var(--ink)}
.segbar button[aria-pressed="true"]{background:var(--surface);color:var(--ink);font-weight:600;box-shadow:var(--sh)}
.logtop .btn{margin-left:0}

.loglist{display:flex;flex-direction:column;gap:20px}
.lgroup{display:flex;flex-direction:column;gap:8px}
.lgh{display:flex;align-items:baseline;gap:10px;padding-bottom:7px;border-bottom:1px solid var(--line)}
.lgh b{font-size:12.5px;font-weight:600;letter-spacing:-.005em}
.lgh span{font-size:11.5px;color:var(--ink-3)}
.lentry{display:grid;grid-template-columns:52px minmax(0,1fr) auto;gap:14px;align-items:start;background:var(--surface);border:1px solid var(--line);border-left:3px solid var(--green);border-radius:var(--r);padding:12px 15px;box-shadow:var(--sh);cursor:pointer}
.lentry:hover{border-color:var(--line-2);box-shadow:var(--sh-2)}
.lentry.planned{border-left-color:var(--blue)}
.lentry.today{border-left-color:var(--amber)}
.lentry.late{border-left-color:var(--red)}
.led{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0;background:var(--surface-2);border:1px solid var(--line);border-radius:8px;padding:6px 2px 5px}
.led b{font-size:19px;font-weight:600;letter-spacing:-.03em;font-variant-numeric:tabular-nums;line-height:1.1}
.led em{font-style:normal;font-size:9.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.led span{font-size:9.5px;color:var(--ink-4);letter-spacing:.03em}
.lem{min-width:0}
.lehead{display:flex;align-items:center;gap:9px;flex-wrap:wrap}
.ledist{background:none;border:0;padding:0;font:inherit;font-size:14px;font-weight:600;letter-spacing:-.012em;color:var(--ink);cursor:pointer}
.ledist:hover{color:var(--brand);text-decoration:underline}
/* Kind is a SECOND axis, so it gets a labelled chip rather than a colour of
   its own: the entry's left border already means status (done / planned /
   today / overdue) and two competing colour systems on one card read as noise. */
.lekind{display:inline-flex;align-items:center;gap:4px;flex:none;font-size:10px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;padding:2px 7px;border-radius:999px;
  background:var(--surface-3);color:var(--ink-3);border:1px solid var(--line)}
.lekind svg{width:11px;height:11px}
.lentry.k-call .lekind{background:var(--violet-soft);color:var(--violet);border-color:transparent}
.lestat{font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-3)}
.lentry.late .lestat{color:var(--red)}
.lentry.today .lestat{color:var(--amber)}
.lentry.done .lestat{color:var(--green)}
.lewhere{display:flex;align-items:center;gap:5px;font-size:11.5px;color:var(--ink-3);margin-top:3px}
.lewhere svg{width:12px;height:12px;flex:none;color:var(--ink-4)}
.lefacts{display:grid;grid-template-columns:auto minmax(0,1fr);gap:3px 11px;margin:8px 0 0}
.lefacts dt{font-size:9.5px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;color:var(--ink-4);padding-top:2px}
.lefacts dd{margin:0;font-size:12.5px;color:var(--ink)}
.lefacts dd.ok{color:var(--green);font-weight:500}
.lenotes{margin:8px 0 0;font-size:12px;color:var(--ink-2);line-height:1.55;padding-left:11px;border-left:2px solid var(--line)}
.ler{display:flex;flex-direction:column;align-items:flex-end;text-align:right;white-space:nowrap}
.ler b{font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}
.ler span{font-size:10px;color:var(--ink-4);letter-spacing:.03em}
.logwho{font-size:12px;color:var(--ink-2);margin-top:2px}

/* ---------- who's active ----------
   Rows are a 3-column grid rather than flex space-between so the times form a
   column: scanning "who is around" is a vertical read down the right edge,
   and ragged right-alignment defeats that. minmax(0,1fr) on the name is what
   lets a long one ellipsise instead of shoving the time off the card. */
.walist{list-style:none;margin:2px 0 0;padding:0;display:flex;flex-direction:column}
/* Wraps rather than shrinks. This is the narrowest card on the dashboard, and
   "Last active 26 days ago" beside a name does not fit a 200px column — but a
   grid or a space-between flex row would have honoured the one-line layout and
   squeezed the NAME to an ellipsis instead, which is the half you cannot
   afford to lose. flex:1 0 auto on the name is the operative bit: flex line
   breaking uses the HYPOTHETICAL main size, so a non-shrinking name pushes the
   time onto its own line instead of the browser compressing both. Wide card:
   one line, time right. Narrow card: time drops under the name, still right. */
.wa{display:flex;flex-wrap:wrap;align-items:baseline;gap:1px 8px;padding:5px 0;font-size:12.5px}
.wa+.wa{border-top:1px solid var(--line)}
.wa>i{flex:none;width:7px;height:7px;border-radius:50%;background:var(--ink-5);align-self:center}
.wa.on>i{background:var(--green);box-shadow:0 0 0 3px var(--green-soft)}
.wan{flex:1 0 auto;max-width:calc(100% - 15px);color:var(--ink-2);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wa.on .wan{color:var(--ink);font-weight:600}
.wan em{color:var(--ink-4);font-style:normal;font-weight:400}
.wat{flex:none;margin-left:auto;font-size:11.5px;color:var(--ink-4);white-space:nowrap}
.wa.on .wat{color:var(--green);font-weight:600}


@media(max-width:1240px){
.wgrid>section[style*="span 2"],.wgrid>section[style*="span 3"],
.wgrid>section[style*="span 4"],.wgrid>section[style*="span 5"]{grid-column:span 6!important}
.wgrid>section[style*="span 7"]{grid-column:span 12!important}
}
/* NOTE: `.wgrid>section{grid-column:span 12!important}` below has never taken
   effect for a card carrying an inline span 3/4/5. Both it and the 1240px rule
   above are !important, so SPECIFICITY decides rather than source order, and
   `.wgrid>section` (0,1,1) loses to `.wgrid>section[style*=...]` (0,2,1). The
   dead rule is left as-is deliberately: the tablet band has always rendered
   those cards two-up, that is a reasonable use of 700-820px, and "fixing" it
   here would restyle tablets as a side effect of a phone change. The phone
   case, where two-up is NOT reasonable, is corrected at 640px below. */
@media(max-width:820px){.wgrid>section{grid-column:span 12!important}
.mapwrap,.mapwrap.big{grid-template-columns:1fr}
.logsum{grid-template-columns:1fr}.lentry{grid-template-columns:46px minmax(0,1fr)}.ler{grid-column:2;flex-direction:row;gap:5px;align-items:baseline;justify-content:flex-start}}

/* Phone: one column, for real this time. Measured on a 375px screen the
   two-up cards were 160px wide — the adoption card's "Buses covered" figure
   and the fraction beside it each wrapped to two lines (it was a donut then,
   and wrapped just the same), and the Next-7-days strip clipped at Friday. Every selector here carries the [style*=] attribute
   so it matches the 1240px rule's (0,2,1) specificity and wins on source
   order. A NEW inline span in the markup needs a new line here, or it will
   silently stay two-up on a phone. */
@media(max-width:640px){
  .wgrid>section,
  .wgrid>section[style*="span 2"],.wgrid>section[style*="span 3"],
  .wgrid>section[style*="span 4"],.wgrid>section[style*="span 5"],
  .wgrid>section[style*="span 6"],.wgrid>section[style*="span 7"],
  .wgrid>section[style*="span 8"]{grid-column:span 12!important}
}

/* Inline "clear the filter" inside an empty state. */
.lnk2{border:0;background:none;padding:0;font:inherit;color:var(--brand);cursor:pointer;text-decoration:underline}
.lnk2:hover{color:var(--brand-ink)}
@media(max-width:640px){
  /* Three filter groups will not sit on one 375px row. Let each own a line and
     keep the actions together at the end. */
  .logtop{gap:8px}
  .logtop .segbar{flex:1 1 auto;justify-content:space-between}
  .logsel{flex:1 1 100%}
  .logsel select{max-width:none;flex:1}
  .logspacer{display:none}
}

/* ---------- contracts view ----------
   Reuses the log layer's card, stat-tile, chart and segbar classes outright —
   the two views are structurally the same page and should not drift apart. */
.moneywrap .logstats b{font-variant-numeric:tabular-nums}
/* .logsum is a strict TWO-cell grid (logstats | chart). The unknown-value note
   is a third child, so without this it takes the chart's cell and shoves the
   chart into the left column. It belongs across both. */
.moneywrap .mnote{grid-column:1/-1}
/* Four segbars of full-word labels do not fit a 375px phone. .logtop already
   wraps, but an inline-flex segbar does not, so a single bar was pushing the
   page 119px wide — a horizontal page scroll, which this layout exists to
   never have. Let the bars wrap internally and never exceed their line. */
.moneywrap .segbar{flex-wrap:wrap;max-width:100%}
@media (max-width:760px){
  .moneywrap .segbar{width:100%;justify-content:flex-start}
  .moneywrap .segbar button{padding:5px 9px}
  .moneywrap .logtop .btn{flex:1 1 auto;justify-content:center}
}
.mnote{margin-top:10px;font-size:12px;color:var(--amber);background:var(--amber-soft);
  border-radius:var(--r-sm);padding:8px 11px;line-height:1.45}
.arrow2{display:flex;gap:18px;flex-wrap:wrap;margin-top:12px;padding-top:11px;border-top:1px solid var(--line)}
.arrow2 div{min-width:96px}
.arrow2 span{display:block;font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;color:var(--ink-3)}
.arrow2 b{font-size:16px;font-weight:600;font-variant-numeric:tabular-nums;letter-spacing:-.01em}
.arrow2 b.ok{color:var(--green)}
.arrow2 b.bad{color:var(--red)}

/* dashboard revenue tile */
.mstats{display:grid;grid-template-columns:1fr 1fr;gap:10px 12px}
.mstats b{display:block;font-size:19px;font-weight:600;letter-spacing:-.02em;font-variant-numeric:tabular-nums}
.mstats span{display:block;font-size:10.5px;font-weight:600;letter-spacing:.05em;text-transform:uppercase;color:var(--ink-3);margin-top:1px}
.mrev{margin-top:11px;padding-top:9px;border-top:1px solid var(--line);font-variant-numeric:tabular-nums}
.mrev b.bad{color:var(--red)}
.mwarn{color:var(--amber);margin-top:5px}
.mgo{margin-top:9px}
.wwarn{font-size:10.5px;font-weight:600;color:var(--red);background:var(--red-soft);border-radius:4px;padding:1px 6px}

/* No chart in this view, so .logsum's second cell would sit empty and squeeze
   the tiles into half the card. One column, tiles 4-up. */
.confwrap .logsum{grid-template-columns:1fr}
.confwrap .logstats{grid-template-columns:repeat(4,minmax(0,1fr))}
@media(max-width:1080px){.confwrap .logstats{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media(max-width:560px){.confwrap .logstats{grid-template-columns:1fr}}

/* conference scheduling watch-outs, from the source research */
.confnotes{grid-column:1/-1;margin-top:12px;padding:12px 14px}
.confnotes ul{margin:6px 0 0;padding-left:17px}
.confnotes li{font-size:12.5px;color:var(--ink-2);line-height:1.55;margin-bottom:4px}

/* ================= touch targets =================
   THIS BLOCK MUST STAY LAST IN THE LAST STYLESHEET. index.html loads app.css
   then widgets.css, and everything here is a plain class override at the same
   (0,1,0) specificity as the rule it is correcting — so source order is the
   only thing making it win. Written first at app.css:830 it silently lost to
   `.starbtn` (app.css, 460 lines further down) and to every control defined in
   this file, which is exactly the failure it exists to fix.

   Keyed on the POINTER, not the width: a touch laptop gets it and a narrow
   desktop window does not. The desktop UI is built for a cursor, so 8px/9px
   padding leaves most inline controls under 34px against a 44px HIG target and
   a 24px WCAG 2.2 minimum. Sizes here clear 24px everywhere and reach 36px
   wherever growing the control does not break the layout around it. */
@media(hover:none),(pointer:coarse){
  /* The 15 named rows are this card's tap surface. 139 dots at the 24px WCAG
     2.2 floor need 80,064px²; the chart on a 375px phone measures 259x104 =
     26,936px². The rows are the compliant equivalent control (2.5.8). */
  .gorow{min-height:44px}
  .gomore>summary{padding:11px 0}
  /* --- shell (app.css) --- */
  .nav button{padding:11px 10px;font-size:14px}
  .sidebtn{padding:11px 10px}
  .btn{height:40px}
  .btn.sm{height:34px}
  .iconbtn{min-width:36px;min-height:36px}
  .chip{min-height:36px}
  .lg{padding:8px 6px}

  /* The inline status/platform control is a <select> wearing a pill: the thing
     a finger actually hits is the absolutely-positioned select filling it, so
     the PILL is what has to grow. 28px -> 36px. */
  .pillsel{min-height:36px;padding-top:0;padding-bottom:0}

  /* Bare tel:/mailto: links in table cells were 88x15. Keyed on the href
     scheme rather than a class because these are written as plain anchors in
     the Leads, Contacts and Conferences tables and in the district drawer, and
     a class list would drift the first time one more is added. inline-flex +
     min-height buys the hit area without moving the text off the cell's
     baseline. */
  a[href^="tel:"],a[href^="mailto:"]{display:inline-flex;align-items:center;min-height:36px}

  /* A 13x13 map pin was the smallest control in the app. It sits beside the
     address text, so it grows around its icon rather than pushing the row. */
  .mp{min-width:36px;min-height:36px;align-items:center;justify-content:center;margin-left:1px;vertical-align:middle}

  /* 22x22, one per contact row, and the only way to pin someone. */
  .starbtn{padding:10px;border-radius:9px}

  /* Settings platform swatches were 19x19 — well under the WCAG minimum. They
     read as a palette, so they keep their square shape and grow as a set
     rather than gaining padding that would break the row rhythm. */
  .clr{width:32px;height:32px;border-radius:8px}
  .ic{width:36px;height:36px}

  /* --- widgets (this file) --- */
  /* Dashboard funnel rows (23px) and territory county rows (28px) are full-
     width list rows, so vertical padding is free — nothing sits beside them. */
  .fr{padding:7px 6px}
  .cty-row{padding:9px 7px}
  /* The Lead log's district filter: a 17px-tall <select> sitting inside a 32px
     wrapper, so the wrapper looked like the control and only the middle half
     of it responded. The select is what receives the tap, so the select is what
     has to fill the wrapper. */
  .logsel{height:40px}
  .logsel select{align-self:stretch;min-height:38px}
  /* Inline text buttons — the dashboard's "see the contracts" link, the
     clear-the-filter link in an empty state — are 20px of underlined text. */
  .lnk2{display:inline-flex;align-items:center;min-height:36px}
  /* The district name in a Lead log entry is a bare text button, 86x21, and it
     is the row's only link to the district. */
  .ledist{display:inline-flex;align-items:center;min-height:36px}
  /* Card-header links — "Open calendar", "Full map" — are 77x17 and sit in the
     top-right corner of a card, the hardest spot on a phone to hit precisely. */
  .wlink{display:inline-flex;align-items:center;min-height:36px;padding-left:8px}
  /* Every drawer and modal closes through this one 26px control. */
  .dclose{width:38px;height:38px;padding:0}

  /* ---- 16px is not a design choice, it is the iOS zoom threshold ----
     Safari on iOS force-zooms the viewport whenever a form control whose
     COMPUTED font-size is below 16px takes focus, and it does not zoom back
     out afterwards. Reported as "when I login the first time the screen looks
     zoomed in and I have to zoom out for it to fit correctly": the sign-in
     email field is .fld input at 13px, so the zoom fires on the very first tap
     a new user makes, and every field in the app was under the threshold, so
     it kept happening afterwards.

     The other way to stop it is `maximum-scale=1, user-scalable=no` on the
     viewport meta. That is deliberately NOT done here — it disables pinch-zoom
     for everyone, including people who need it to read, to paper over a
     type-size problem.

     Anything with a font-size below 16px that can receive focus belongs in
     this list. Keyed on the pointer, so desktop keeps its denser type. */
  .fld input,.fld select,.fld textarea,
  .iline input,.costrow input,
  .search input,.railsearch input,
  input.pn,.del-sel,.tk-ta,
  .logsel select,
  .chatform textarea{font-size:16px}
  /* Invisible: .pillsel select is opacity:0 and absolutely positioned over the
     pill, so it is the thing that actually receives the tap and triggers the
     zoom, while the pill's own 11.5px label is what you see. Sizing it costs
     nothing visually. */
  .pillsel select{font-size:16px}
}
