/* The dashboard. Tables, tiles and charts - the map lives in index.html.
 *
 * 🔑 EVERY COLOUR AND SPACING HERE IS A TOKEN FROM /tokens.css. Nothing in
 * this file invents a hex. That is what keeps the two pages one product, and
 * it is the whole reason the tokens were lifted out of index.html.
 *
 * 🔑 THE BAR, THE BRAND, THE TABS, THE ICON BUTTONS, THE MENUS AND THE
 * SEGMENTED CONTROL ARE IN /nav.css. They were written here too, and the
 * two copies had drifted: this page's bar was shorter, its wordmark lighter
 * and its icons boxed, so stepping from Map to Overview redrew the whole
 * top of the window.
 *
 * ⚠️ No framework, no build. nginx sends `script-src 'self'`, which rules out
 * the Tailwind CDN (it is a runtime compiler, i.e. a script); and a built
 * stylesheet would need Node in the deploy plus a staleness check. See the
 * note at the top of tokens.css.
 */

*{box-sizing:border-box}
[hidden]{display:none !important}

html{color-scheme:light dark}
body{
  margin:0;background:var(--bg);color:var(--fg);
  font:13px/1.55 var(--mono);
  -webkit-font-smoothing:antialiased;
}

/* 🔑 TABULAR FIGURES COME FREE NOW. The page is monospace throughout, so a
   column of readings lines up by construction - which on a page whose whole
   job is comparing readings is the point. This stays for the one case mono
   does not cover: a face that ships proportional digits anyway. */
.num,td.num,th.num,.tile-v,.chart text{font-variant-numeric:tabular-nums}

/* ------------------------------------------------------------- chrome */

/* ⚠️ .ico and .mi are EXEMPT from the control rule below. That rule is what
   boxed them - a border and a card background belong on things you type
   into or pick from, not on a ghost icon or a menu row. */

.sp{flex:1}

select,button:not(.ico):not(.mi),input{
  font:inherit;height:var(--ctl-h);
  border:1px solid var(--line);border-radius:var(--r);
  background:var(--card);color:var(--fg);padding:0 var(--s2);
}
select{
  appearance:none;-webkit-appearance:none;
  padding-right:24px;background-image:var(--chev);
  background-repeat:no-repeat;background-position:right 5px center;
  background-size:15px;
}
button{cursor:pointer;transition:border-color var(--t),background var(--t)}
button:hover{border-color:var(--line2)}
:is(select,button,input):focus-visible{
  outline:2px solid var(--ring);outline-offset:1px;border-color:var(--acc)}

/* ------------------------------------------------------------- layout */

main{max-width:1440px;margin:0 auto;padding:var(--s5) var(--s4) 64px}

.card{
  background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-lg);box-shadow:var(--sh-sm);
  margin-bottom:var(--s4);overflow:hidden;
}
/* 🔑 THE HEADER IS A STRIP, not a line of bold text. A tinted band with a
   hairline under it says "this card is a thing with a name" at a glance,
   and it is where the chips live. */
.card > h2{
  margin:0;padding:var(--s2) var(--s3);
  font:600 12px/1.5 var(--mono);letter-spacing:-.01em;
  background:var(--bg);border-bottom:1px solid var(--line);
  display:flex;align-items:center;gap:var(--s2);
}
.card > h2 .sub{font-weight:400;color:var(--mut);font-size:11.5px}
.card > h2 .sp{flex:1}
.pad{padding:var(--s4)}

.grid{display:grid;gap:var(--s4)}
@media (min-width:900px){.g2{grid-template-columns:1fr 1fr}}

/* ---------------------------------------------------------- stat tiles */

/* 🔑 A TILE IS NOT A CHART, and the number is the point of it. The sparkline
   is secondary - it says "and here is the shape of how it got there" - so it
   is drawn recessively and carries no axis, no gridline and no label. */
.tiles{display:grid;gap:var(--s3);
  grid-template-columns:repeat(auto-fit,minmax(176px,1fr));
  margin-bottom:var(--s4)}
.tile{background:var(--card);border:1px solid var(--line);
      border-radius:var(--r-lg);padding:var(--s3) var(--s4);
      box-shadow:var(--sh-sm)}
.tile-k{font-size:11.5px;color:var(--mut);margin-bottom:2px;
        letter-spacing:.02em}
.tile-v{font-size:25px;font-weight:600;letter-spacing:-.03em;line-height:1.2}
.tile-v small{font-size:12px;font-weight:500;color:var(--mut);margin-left:3px}
.tile-s{font-size:11.5px;color:var(--mut);margin-top:2px}
.tile svg{display:block;margin-top:var(--s2)}

.good{color:var(--ok)} .warn{color:var(--warn)} .bad{color:var(--bad)}

/* ------------------------------------------------------------- tables */

.tw{overflow:auto;max-height:70vh}
table{border-collapse:separate;border-spacing:0;width:100%;font-size:12.5px}
thead th{
  position:sticky;top:0;z-index:1;
  background:var(--card);text-align:left;font-weight:500;color:var(--mut);
  padding:var(--s2) var(--s3);white-space:nowrap;
  border-bottom:1px solid var(--line);
}
/* Sortable headers are buttons in disguise - but keep the keyboard route. */
thead th[data-sort]{cursor:pointer;user-select:none}
thead th[data-sort]:hover{color:var(--fg)}
thead th[aria-sort] .arw{opacity:1}
thead th .arw{opacity:0;margin-left:4px;font-size:10px}
tbody td{padding:var(--s2) var(--s3);border-bottom:1px solid var(--line);
         white-space:nowrap}
tbody tr:hover td{background:var(--bg)}
tbody tr.sel td{background:var(--brand-soft)}
td.num,th.num{text-align:right}
td.mut{color:var(--mut)}

/* 🔑 AN EMPTY PANEL SAYS WHAT IT IS. A card that reads "no rows" tells you
   nothing about which card it is or why it is empty, and on a page of eight
   panels that is a puzzle. The ghost word is the subject; the line under it
   is the reason. */
.empty{padding:var(--s6) var(--s4);text-align:center;color:var(--mut)}
.empty b{display:block;font-size:30px;font-weight:700;letter-spacing:-.04em;
  color:var(--line2);margin-bottom:var(--s1);user-select:none}
.empty span{font-size:12px}

/* A value the device never sent. ⚠️ It must not read as a zero - that is the
   difference between "the battery is flat" and "this firmware has no ADC". */
.nil{color:var(--mut);opacity:.5}

/* 🔑 CHIPS, the reference's own idiom: a state is a small tinted box, not a
   coloured word floating in a row of other words. */
.pill{display:inline-block;padding:1px 6px;border-radius:var(--r-sm);
      font-size:11px;font-weight:500;border:1px solid var(--line);
      background:var(--bg);color:var(--mut)}
.pill.acc{border-color:transparent;background:var(--acc-soft);color:var(--acc)}
.pill.ok{border-color:transparent;background:var(--bg);color:var(--ok)}
.pill.bad{border-color:transparent;background:var(--bg);color:var(--bad)}

.bar{height:4px;border-radius:2px;background:var(--line);overflow:hidden;
     min-width:46px}
.bar i{display:block;height:100%;background:var(--acc);border-radius:2px}

.foot{display:flex;align-items:center;gap:var(--s3);
      padding:var(--s2) var(--s3);border-top:1px solid var(--line);
      background:var(--bg);color:var(--mut);font-size:11.5px}

/* ------------------------------------------------------------- charts */

/* Small multiples. One measure per chart, one axis each.
   ⚠️ NEVER a second y-scale on one chart: two scales let the author place
   the crossing wherever flatters the story, and the reader cannot tell. */
.charts{display:grid;gap:var(--s4);
  grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}
.chart{position:relative}
.chart h3{margin:0 0 2px;font-size:11.5px;font-weight:600}
.chart .cv{font-size:11.5px;color:var(--mut);margin-bottom:var(--s1);
           min-height:18px}
.chart svg{display:block;width:100%;height:112px;overflow:visible}
.chart .ax{stroke:var(--line);stroke-width:1}
.chart .gl{stroke:var(--line);stroke-width:1;stroke-dasharray:2 3;opacity:.7}
.chart text{fill:var(--mut);font-size:10px;font-family:var(--mono)}
.chart .ln{fill:none;stroke-width:2;stroke-linejoin:round;stroke-linecap:round}
.chart .ar{opacity:.12}
.chart .cur{stroke:var(--fg);stroke-width:1;opacity:.45}
.chart .dot{r:3.5;stroke:var(--card);stroke-width:2}

.lg{display:flex;gap:var(--s3);font-size:11px;color:var(--mut);
    margin-bottom:var(--s1)}
.lg i{display:inline-block;width:8px;height:8px;border-radius:2px;
      margin-right:4px;vertical-align:middle}

/* One tooltip element, moved about. A tooltip per mark is a thousand nodes
   on a 2,000-point series. */
#tip{position:fixed;z-index:200;pointer-events:none;
     background:var(--card);border:1px solid var(--line2);
     border-radius:var(--r);box-shadow:var(--sh-lg);
     padding:var(--s2) var(--s3);font:12px/1.5 var(--mono);white-space:nowrap}
#tip b{font-variant-numeric:tabular-nums}

/* ---------------------------------------------------------- cell map */

#cmap{height:420px;background:var(--bg)}
.leaflet-tile{filter:var(--tile-filter)}
.leaflet-container{background:var(--bg);font:inherit}
.leaflet-control-attribution{background:var(--attrib-bg) !important;
  color:var(--mut)}
.leaflet-control-attribution a{color:var(--mut)}

.note{padding:var(--s2) var(--s3);color:var(--mut);font-size:11.5px;
      border-top:1px solid var(--line);background:var(--bg)}

/* --------------------------------------------------------------- login */

#login{position:fixed;inset:0;z-index:999;display:grid;place-items:center;
       background:var(--bg)}
#login form{background:var(--card);border:1px solid var(--line);
  border-radius:var(--r-xl);box-shadow:var(--sh-lg);
  padding:var(--s6);width:min(360px,92vw);display:grid;gap:var(--s3)}
#login h1{margin:0 0 var(--s2);font-size:15px;color:var(--brand);
  letter-spacing:-.01em}
#login label{font-size:11.5px;color:var(--mut)}
#login input{width:100%}
#login button{background:var(--brand);border-color:var(--brand);
              color:var(--card);font-weight:500}
#login button:hover{filter:brightness(1.07)}
#err{color:var(--bad);font-size:11.5px;min-height:16px}

/* --------------------------------------------------------------- misc */

.loading{padding:var(--s6);text-align:center;color:var(--mut)}
@media (prefers-reduced-motion:reduce){*{transition:none !important}}
