:root {
  --indigo-50:  #EEF0FF;
  --indigo-100: #DDE0FB;
  --indigo-300: #A5A8F0;
  --indigo-500: #6366F1;
  --indigo-600: #5B5FE3;
  --indigo-700: #4F46E5;
  --indigo-900: #1E1B4B;
  --ink-900:    #0F172A;
  --ink-700:    #334155;
  --ink-500:    #64748B;
  --ink-400:    #94A3B8;
  --ink-200:    #E2E8F0;
  --ink-100:    #F1F5F9;
  --ink-50:     #F8FAFC;
  --green-500:  #22C55E;
  --red-500:    #EF4444;
  --amber-500:  #F59E0B;
  --bg:         #F5F6FB;
  --card-bg:    #FFFFFF;
  --shadow:     0 1px 2px rgba(15, 23, 42, .04), 0 4px 12px rgba(15, 23, 42, .04);
  --radius:     14px;
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  font-size: 14px;
  color: var(--ink-900);
  background: var(--bg);
}
a { color: inherit; text-decoration: none; }
.muted { color: var(--ink-500); }

/* =========================== Topbar =========================== */
.topbar {
  background: #1F2A52;
  background: linear-gradient(180deg, #1F2A52 0%, #232E5E 100%);
  color: #FFF;
}
.topbar-inner {
  max-width: 1400px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  padding: 14px 24px;
  gap: 32px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
  font-size: 17px;
  color: #FFF;
}
.brand-mark {
  width: 26px; height: 26px; border-radius: 6px;
  background: radial-gradient(circle at 30% 30%, var(--indigo-300), var(--indigo-600));
  box-shadow: inset 0 0 0 2px rgba(255,255,255,.15);
}
.brand-mark.large { width: 36px; height: 36px; }
.topnav {
  display: flex; gap: 6px; flex: 1;
}
.topnav a {
  padding: 8px 14px; border-radius: 8px; color: rgba(255,255,255,.7);
  font-weight: 500; transition: background .15s, color .15s;
}
.topnav a:hover { background: rgba(255,255,255,.06); color: #FFF; }
.topnav a.active { background: var(--indigo-500); color: #FFF; }
.topnav a.muted { color: rgba(255,255,255,.45); }

.avatar {
  width: 32px; height: 32px; border-radius: 50%;
  background: var(--indigo-500);
  display: flex; align-items: center; justify-content: center;
  font-weight: 600; font-size: 13px; color: #FFF;
}
.user-name { font-size: 13px; font-weight: 600; }
.user-role { font-size: 11px; color: rgba(255,255,255,.55); }

/* Top-right account dropdown: the user pill is now a button that opens a small
   menu (Change password / Log out). */
.user-menu { position: relative; }
.user-menu-trigger {
  display: flex; align-items: center; gap: 12px;
  background: rgba(255,255,255,.08);
  padding: 6px 12px 6px 8px;
  border: 0; border-radius: 999px; cursor: pointer;
  color: #FFF; font: inherit;
  transition: background .15s;
}
.user-menu-trigger:hover { background: rgba(255,255,255,.14); }
.user-menu-trigger .user-meta {
  display: flex; flex-direction: column; align-items: flex-start;
  line-height: 1.25; white-space: nowrap;
}
.user-menu-caret {
  width: 16px; height: 16px; color: rgba(255,255,255,.55);
  transition: transform .15s ease;
}
.user-menu-trigger[aria-expanded="true"] .user-menu-caret { transform: rotate(180deg); }
.user-menu-dropdown {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  min-width: 220px;
  background: var(--card-bg); border: 1px solid var(--indigo-100);
  border-radius: 12px; box-shadow: 0 14px 32px rgba(15,23,42,.16);
  padding: 6px; display: flex; flex-direction: column; gap: 2px;
}
.user-menu-dropdown[hidden] { display: none; }
.user-menu-item {
  display: flex; align-items: center; gap: 10px;
  width: 100%; padding: 9px 12px;
  background: transparent; border: 0; border-radius: 8px;
  color: var(--ink-700); font: inherit; font-size: 13px; font-weight: 500;
  text-align: left; text-decoration: none; cursor: pointer;
  transition: background .12s, color .12s;
}
.user-menu-item:hover { background: var(--ink-100); color: var(--ink-900); }
.user-menu-item svg { width: 18px; height: 18px; flex: 0 0 auto; color: var(--ink-400); }
.user-menu-item:hover svg { color: var(--indigo-600); }

/* ---- Header alarm bell ---- */
/* ---- Topbar: Solar agent health pill (mirrors the bell; dark topbar) ---- */
.agent-pill { position: relative; display: flex; align-items: center; }
.agent-pill[hidden] { display: none; }
.agent-pill-btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 12px; border: 0; border-radius: 999px;
  background: rgba(255,255,255,.08); color: #FFF; cursor: pointer;
  font: inherit; transition: background .15s;
}
.agent-pill-btn:hover { background: rgba(255,255,255,.14); }
.agent-pill-text { display: flex; flex-direction: column; line-height: 1.15; text-align: left; }
.agent-pill-title { font-size: 11px; font-weight: 700; }
.agent-pill-status { font-size: 10px; color: rgba(255,255,255,.72); white-space: nowrap; }
.agent-dot {
  width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto;
  background: var(--ink-400);
}
.agent-dot.agent-ok      { background: var(--green-500); box-shadow: 0 0 0 3px rgba(34,197,94,.18); }
.agent-dot.agent-unusual { background: var(--amber-500); box-shadow: 0 0 0 3px rgba(245,158,11,.18); }
.agent-dot.agent-down    { background: var(--red-500);   box-shadow: 0 0 0 3px rgba(239,68,68,.18);
                           animation: agent-pulse 1.6s ease-out infinite; }
.agent-dot.agent-unknown { background: var(--ink-400); }
@keyframes agent-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(239,68,68,.55); }
  70%  { box-shadow: 0 0 0 8px rgba(239,68,68,0); }
  100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); }
}
@media (prefers-reduced-motion: reduce) { .agent-dot.agent-down { animation: none; } }
.agent-pill-dropdown {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 300px; max-width: min(300px, calc(100vw - 32px));
  background: var(--card-bg); border: 1px solid var(--indigo-100);
  border-radius: 12px; box-shadow: 0 14px 32px rgba(15,23,42,.16); padding: 10px 12px;
}
.agent-pill-dropdown[hidden] { display: none; }
.agent-pill-head {
  display: flex; align-items: baseline; justify-content: space-between;
  padding-bottom: 8px; margin-bottom: 6px; border-bottom: 1px solid var(--ink-100);
}
.agent-pill-head-title { font-size: 13px; font-weight: 700; color: var(--ink-900); }
.agent-pill-head-state { font-size: 11px; color: var(--ink-500); text-transform: capitalize; }
.agent-pill-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.agent-row { display: flex; align-items: flex-start; gap: 8px; padding: 6px; border-radius: 8px; }
.agent-row:hover { background: var(--ink-50); }
.agent-row .agent-dot { margin-top: 3px; }
.agent-row-key { font-size: 12px; font-weight: 600; color: var(--ink-900); word-break: break-all; }
.agent-row-meta { font-size: 11px; margin-top: 2px; }
.agent-empty { font-size: 12px; padding: 8px 6px; }

.bell-root { position: relative; display: flex; align-items: center; }
.bell {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border: 0; border-radius: 999px;
  background: rgba(255,255,255,.08); color: #FFF; cursor: pointer;
  transition: background .15s;
}
.bell:hover { background: rgba(255,255,255,.14); }
.bell svg { width: 19px; height: 19px; display: block; }
.bell-badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 18px; height: 18px; padding: 0 5px; box-sizing: border-box;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--red-500); color: #FFF;
  font-size: 11px; font-weight: 700; line-height: 1;
  border-radius: 999px; border: 2px solid #232E5E;
}
.bell-badge[hidden] { display: none; }
/* Motion = active alarms need attention (mirrors the map pin-attn pulse). */
.bell.bell-attn { animation: bell-pulse 1.4s ease-in-out infinite; }
@keyframes bell-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(239,68,68,.55); }
  70%  { box-shadow: 0 0 0 8px rgba(239,68,68,0); }
  100% { box-shadow: 0 0 0 0 rgba(239,68,68,0); }
}
@media (prefers-reduced-motion: reduce) { .bell.bell-attn { animation: none; } }

.bell-dropdown {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 60;
  width: 320px; max-width: min(320px, calc(100vw - 32px));
  background: var(--card-bg); border: 1px solid var(--indigo-100);
  border-radius: 12px; box-shadow: 0 14px 32px rgba(15,23,42,.16);
  display: flex; flex-direction: column; overflow: hidden;
}
.bell-dropdown[hidden] { display: none; }
.bell-dropdown-head {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 12px 14px 8px; border-bottom: 1px solid var(--ink-100);
}
.bell-dropdown-title { font-size: 13px; font-weight: 700; color: var(--ink-900); }
.bell-dropdown-window { font-size: 11px; }
.bell-list {
  list-style: none; margin: 0; padding: 6px;
  max-height: 360px; overflow-y: auto;
}
.bell-empty { padding: 18px 16px; text-align: center; font-size: 13px; }
.bell-dropdown-foot {
  display: block; padding: 10px 14px; border-top: 1px solid var(--ink-100);
  font-size: 12px; font-weight: 600; color: var(--indigo-600); text-decoration: none;
}
.bell-dropdown-foot:hover { background: var(--ink-100); }

/* Header clock: business timezone (WITA), with the viewer's own local time
   beneath it when their browser timezone differs. Sits in the dark topbar. */
.topclock {
  display: flex; flex-direction: column; align-items: flex-end;
  line-height: 1.25; white-space: nowrap;
}
.topclock-main { font-size: 12.5px; font-weight: 600; color: #FFF; }
.topclock-alt  { font-size: 11px; color: rgba(255,255,255,.6); }
.topclock-alt[hidden] { display: none; }
@media (max-width: 700px) { .topclock { display: none; } }

/* =========================== Page =========================== */
/* The one page container. Its max-width and gutter match .topbar-inner, so page
   titles line up under the brand mark. Only the deliberately full-bleed pages
   (page-fleet, page-chart) may override it — nothing else should re-declare a
   width or padding here, or the pages drift apart. */
.page {
  max-width: 1400px; margin: 0 auto;
  padding: 28px 24px 60px;
}
/* Centers a single auth-style card (e.g. Change password) inside the in-app
   page chrome — unlike body.login-page, the topbar stays visible above it. */
.page-center { display: flex; justify-content: center; padding-top: 24px; }

/* The one page header: Dashboard, Alarms, Briefings and Devices all use this. */
.page-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
}
.page-head h1 {
  margin: 0; font-size: 22px;
  display: flex; align-items: center; gap: 10px;
}
.page-head h1 .badge {
  background: var(--indigo-50); color: var(--indigo-700);
  font-size: 12px; padding: 2px 10px; border-radius: 999px; font-weight: 600;
}

.crumbs { display: flex; gap: 6px; font-size: 13px; margin-bottom: 4px; }
.crumbs a { color: var(--ink-500); }
.crumbs a:hover { color: var(--indigo-600); }
.crumbs .current { color: var(--ink-700); font-weight: 500; }

.header-actions { display: flex; align-items: center; gap: 8px; }
.live-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--green-500);
  box-shadow: 0 0 0 4px rgba(34, 197, 94, .15);
  animation: pulse 1.6s ease-in-out infinite;
}
@keyframes pulse {
  0%,100% { box-shadow: 0 0 0 4px rgba(34, 197, 94, .15); }
  50%     { box-shadow: 0 0 0 8px rgba(34, 197, 94, .05); }
}

/* =========================== Device list =========================== */
.device-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}
.device-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  padding: 18px 18px 14px;
  box-shadow: var(--shadow);
  transition: transform .15s, box-shadow .15s;
  display: block;
}
.device-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 24px rgba(15,23,42,.08);
}
.device-card-head {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--ink-500); margin-bottom: 10px;
}
.status-dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--ink-200);
}
.status-dot.online  { background: var(--green-500); }
.status-dot.offline { background: var(--ink-400); }
.device-type {
  text-transform: uppercase; letter-spacing: .03em; font-weight: 600;
}
.device-name { font-size: 15px; font-weight: 600; word-break: break-all; }
.device-label { font-size: 12px; margin-top: 2px; word-break: break-all; }
.device-card-foot { font-size: 12px; margin-top: 14px; }
.empty { padding: 40px; text-align: center; color: var(--ink-500); }

/* =========================== Detail panels =========================== */
.panels {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 16px;
}
.panel {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.panel-head {
  padding: 14px 18px; border-bottom: 1px solid var(--ink-100);
}
.panel-head h2 {
  margin: 0; font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--indigo-700);
}
.panel-body {
  padding: 14px 18px 18px;
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px 18px;
}
.metric { padding: 4px 0; }
.metric-label { font-size: 11px; color: var(--ink-500); margin-bottom: 4px; }
.metric-value {
  display: flex; align-items: baseline; gap: 4px; line-height: 1;
}
.metric-number {
  font-size: 22px; font-weight: 600; color: var(--ink-900);
  font-variant-numeric: tabular-nums;
}
.metric-unit { font-size: 12px; color: var(--ink-500); font-weight: 500; }
.metric-ts { font-size: 10px; margin-top: 4px; }
.metric-number.flash { animation: flash .8s ease; }
@keyframes flash {
  0%   { background: var(--indigo-100); }
  100% { background: transparent; }
}

.gps-map {
  grid-column: 1 / -1;
  height: 220px; border-radius: 10px;
  background: var(--ink-100);
  margin-top: 6px;
}

/* =========================== Login =========================== */
body.login-page {
  min-height: 100vh;
  display: flex; align-items: center; justify-content: center;
  background:
    radial-gradient(1000px 600px at 80% 10%, rgba(99,102,241,.15), transparent 60%),
    radial-gradient(900px 600px at 0% 100%, rgba(99,102,241,.10), transparent 60%),
    var(--bg);
}
.login-card {
  width: 100%; max-width: 380px;
  background: var(--card-bg);
  border-radius: 16px;
  padding: 36px 32px;
  box-shadow: 0 30px 60px rgba(15,23,42,.10);
}
.login-brand {
  display: flex; align-items: center; gap: 10px;
  font-weight: 700; font-size: 18px; margin-bottom: 24px;
}
.login-card h1 { margin: 0 0 4px; font-size: 22px; }
.login-card p  { margin: 0 0 24px; }
.login-card form { display: flex; flex-direction: column; gap: 14px; }
.login-card label { display: flex; flex-direction: column; gap: 4px; }
.login-card label span { font-size: 12px; color: var(--ink-500); }
.login-card input {
  padding: 10px 12px; border-radius: 8px;
  border: 1px solid var(--ink-200); background: var(--ink-50);
  font: inherit; color: var(--ink-900);
}
.login-card input:focus {
  outline: 2px solid var(--indigo-300); outline-offset: 1px;
  border-color: var(--indigo-500); background: #FFF;
}
/* Password field with show/hide eye toggle.
   One eye that opens (revealed) / closes (masked) — the icon's state and color
   ARE the status: closed + grey when hidden, open + indigo when shown. */
.pw-field { position: relative; display: flex; }
.pw-field input { width: 100%; padding-right: 44px; }
.pw-toggle {
  position: absolute; top: 50%; right: 6px;
  transform: translateY(-50%);
  display: grid; place-items: center;
  width: 32px; height: 32px; padding: 0;
  background: transparent; border: 0; cursor: pointer;
  color: var(--ink-400); border-radius: 8px;
  transition: color .15s ease, background .15s ease;
}
.pw-toggle:hover { color: var(--ink-700); background: var(--ink-100); }
.pw-toggle.is-on { color: var(--indigo-600); }
.pw-toggle.is-on:hover { background: var(--indigo-50); }
.pw-toggle:focus-visible {
  outline: 2px solid var(--indigo-300); outline-offset: 2px;
}
.pw-icon { width: 20px; height: 20px; overflow: visible; }
/* The two states share the icon box and cross-fade with a subtle scale. */
.pw-icon-open,
.pw-icon-closed {
  transition: opacity .18s ease, transform .18s ease;
  transform-origin: 12px 12px;
}
.pw-icon-open   { opacity: 0; transform: scale(.65); }
.pw-icon-closed { opacity: 1; transform: scale(1); }
.pw-toggle.is-on .pw-icon-open   { opacity: 1; transform: scale(1); }
.pw-toggle.is-on .pw-icon-closed { opacity: 0; transform: scale(.65); }
@media (prefers-reduced-motion: reduce) {
  .pw-icon-open, .pw-icon-closed { transition: opacity .01s; }
}
.primary {
  margin-top: 6px;
  background: var(--indigo-600); color: #FFF; font-weight: 600;
  padding: 11px 14px; border: 0; border-radius: 8px; cursor: pointer;
  transition: background .15s;
}
.primary:hover { background: var(--indigo-700); }
/* Login error banner. Dedicated class so it doesn't collide with the alarm-list
   `.alert` component defined further down. */
.login-alert {
  display: flex; align-items: center; gap: 8px;
  background: #FEF2F2; color: #B91C1C;
  border: 1px solid #FECACA; border-radius: 8px;
  padding: 10px 12px; font-size: 13px; font-weight: 500;
}
.login-alert svg { flex: 0 0 auto; width: 16px; height: 16px; stroke: #DC2626; }

/* Green confirmation banner (e.g. "Your password has been updated."). */
.form-ok {
  display: flex; align-items: center; gap: 8px;
  background: #ECFDF5; color: #047857;
  border: 1px solid #A7F3D0; border-radius: 8px;
  padding: 10px 12px; font-size: 13px; font-weight: 500;
  margin-bottom: 16px;
}
.form-ok svg { flex: 0 0 auto; width: 16px; height: 16px; stroke: #059669; }

/* Secondary links under the form (Forgot password? / Back to sign in). */
.login-aux { margin-top: 14px; text-align: center; font-size: 13px; }
.login-aux a { color: var(--indigo-600); text-decoration: none; font-weight: 500; }
.login-aux a:hover { text-decoration: underline; }

/* "or" divider separating the password form from the Google button. */
.login-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0; color: var(--ink-400);
  font-size: 12px; text-transform: uppercase; letter-spacing: .04em;
}
.login-divider::before,
.login-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--ink-200);
}

/* "Sign in with Google" button — white/bordered so it reads as the secondary
   option next to the indigo primary submit. */
.btn-google {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; padding: 11px 14px;
  border: 1px solid var(--ink-200); border-radius: 8px;
  background: #FFF; color: var(--ink-700);
  font: inherit; font-weight: 600; text-decoration: none; cursor: pointer;
  transition: background .15s ease, border-color .15s ease, box-shadow .15s ease;
}
.btn-google:hover { background: var(--ink-50); border-color: var(--ink-400); }
.btn-google:focus-visible { outline: 2px solid var(--indigo-300); outline-offset: 2px; }
.btn-google-logo { flex: 0 0 auto; width: 18px; height: 18px; }

/* Anchor styled as the primary button (password-reset complete page). */
.login-cta { display: block; text-align: center; text-decoration: none; }

/* =========================== Fleet shell (combined list + detail) =========================== */
body.page-fleet .page { max-width: none; padding: 0; }
.fleet-shell {
  display: grid;
  /* Per-side column widths so the two sidebars collapse independently. */
  --col-devices: 340px;
  --col-alerts: 320px;
  grid-template-columns: var(--col-devices) minmax(0, 1fr) var(--col-alerts);
  height: calc(100vh - 64px);
  overflow: hidden;
  transition: grid-template-columns .25s ease;
}
@media (max-width: 1180px) {
  .fleet-shell { grid-template-columns: 340px minmax(0, 1fr); }
  .fleet-alerts-sidebar { grid-column: 1 / -1; border-left: none; border-top: 1px solid var(--ink-100); }
  /* Collapse is a desktop feature; hide the toggle where panels already reflow. */
  .sidebar-toggle { display: none; }
}
@media (max-width: 900px) {
  .fleet-shell { grid-template-columns: 1fr; }
}

/* --- Collapsible side panels (desktop only; below 1180px they already reflow) --- */
.sidebar-head-row {
  display: flex; align-items: flex-start;
  gap: 8px; margin-bottom: 12px;
}
/* Title fills the row, so the toggle sits at whichever end markup order puts it:
   right of "Devices" (left panel), left of "Active alerts" (right panel). */
.sidebar-head-row .sidebar-title { margin: 0; flex: 1; }
.sidebar-toggle {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 28px; height: 28px; padding: 0;
  background: transparent; border: 1px solid var(--ink-200); border-radius: 8px;
  color: var(--ink-500); cursor: pointer;
  transition: background .15s, color .15s, border-color .15s;
}
.sidebar-toggle:hover { background: var(--ink-100); color: var(--ink-700); }
.sidebar-toggle:focus-visible { outline: 2px solid var(--indigo-300); outline-offset: 2px; }
.sidebar-toggle svg { width: 16px; height: 16px; }
/* The slim rail shown in place of a collapsed sidebar. */
.sidebar-rail {
  display: none;                 /* shown only when that side is collapsed (desktop) */
  flex-direction: column; align-items: center; gap: 16px;
  padding-top: 16px; height: 100%;
}
.rail-label {
  writing-mode: vertical-rl; transform: rotate(180deg);
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  color: var(--ink-500); white-space: nowrap;
}
@media (min-width: 1181px) {
  .fleet-shell.is-devices-collapsed { --col-devices: 48px; }
  .fleet-shell.is-alerts-collapsed  { --col-alerts: 48px; }
  .is-devices-collapsed .fleet-sidebar .sidebar-head,
  .is-devices-collapsed .fleet-sidebar .device-list { display: none; }
  .is-devices-collapsed .fleet-sidebar .sidebar-rail { display: flex; }
  .is-alerts-collapsed .fleet-alerts-sidebar .sidebar-head,
  .is-alerts-collapsed .fleet-alerts-sidebar .fleet-alerts-list { display: none; }
  .is-alerts-collapsed .fleet-alerts-sidebar .sidebar-rail { display: flex; }
}
.fleet-sidebar {
  background: #FFFFFF;
  border-right: 1px solid var(--ink-100);
  display: flex; flex-direction: column;
  min-height: 0;
}
.sidebar-head {
  padding: 18px 18px 12px;
  border-bottom: 1px solid var(--ink-100);
  position: sticky; top: 0;
  background: #FFFFFF;
  z-index: 2;
}
.sidebar-title {
  margin: 0 0 12px; font-size: 16px;
  display: flex; align-items: center; gap: 8px;
}
.sidebar-title .badge {
  background: var(--indigo-50); color: var(--indigo-700);
  font-size: 11px; padding: 2px 8px; border-radius: 999px;
  font-weight: 600;
}
.sidebar-search {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--ink-200);
  border-radius: 8px;
  background: var(--ink-50);
  font: inherit; color: var(--ink-900);
}
.sidebar-search:focus {
  outline: 2px solid var(--indigo-300); outline-offset: 1px;
  border-color: var(--indigo-500); background: #FFF;
}
.status-chips {
  display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px;
}
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 10px;
  background: var(--ink-100); color: var(--ink-700);
  border: 1px solid transparent;
  border-radius: 999px;
  font-size: 11px; font-weight: 600; cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.chip .dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--ink-400);
}
.chip-ok      .dot { background: var(--green-500); }
.chip-unusual .dot { background: var(--amber-500); }
.chip-warn    .dot { background: var(--amber-500); } /* legacy freshness bucket, kept for old markup */
.chip-stale   .dot { background: #94A3B8; }          /* legacy freshness bucket, kept for old markup */
.chip-down    .dot { background: var(--red-500); }
.chip:hover { background: var(--ink-200); }
/* Freshness legend ⓘ, sat at the end of the chip row (reuses .tile-info/.tile-tip). */
.status-chips-info { align-self: center; margin-left: 2px; }
.chip.active {
  background: var(--indigo-50);
  border-color: var(--indigo-500);
  color: var(--indigo-700);
}

.device-list {
  list-style: none; margin: 0; padding: 6px 8px 12px;
  overflow-y: auto; flex: 1;
}
.device-row {
  display: grid;
  grid-template-columns: 14px 1fr 12px;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 10px;
  cursor: pointer;
  transition: background .12s;
}
.device-row:hover { background: var(--ink-100); }
.device-row.selected {
  background: var(--indigo-50);
  box-shadow: inset 3px 0 0 var(--indigo-600);
}
.device-row .status-dot {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--ink-400);
  box-shadow: 0 0 0 3px transparent;
}
.status-dot.status-ok      { background: var(--green-500); box-shadow: 0 0 0 3px rgba(34,197,94,.12); }
.status-dot.status-unusual { background: var(--amber-500); box-shadow: 0 0 0 3px rgba(245,158,11,.12); }
.status-dot.status-warn    { background: var(--amber-500); box-shadow: 0 0 0 3px rgba(245,158,11,.12); } /* legacy */
.status-dot.status-stale   { background: #94A3B8; }                                                      /* legacy */
.status-dot.status-down    { background: var(--red-500); box-shadow: 0 0 0 3px rgba(239,68,68,.12); }
.device-row .row-name { font-size: 13px; font-weight: 600; word-break: break-all; }
.device-row .row-meta { font-size: 11px; margin-top: 2px; }
.device-row .row-chev { color: var(--ink-400); font-size: 16px; }

/* Filter state — hide rows that don't match the active chip / search. */
.device-list[data-active-status="ok"]      .device-row:not([data-status="ok"]),
.device-list[data-active-status="unusual"] .device-row:not([data-status="unusual"]),
.device-list[data-active-status="down"]    .device-row:not([data-status="down"]) { display: none; }
.device-row.hide-search { display: none; }

/* ---- Area groups (sidebar) ---- */
.device-group { margin-bottom: 2px; }
.device-group-head {
  width: 100%;
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  background: none; border: 0; cursor: pointer;
  font: inherit; color: var(--ink-600);
  text-transform: uppercase; letter-spacing: .06em;
  font-size: 11px; font-weight: 700;
  position: sticky; top: 0; z-index: 1;
  background: #FFFFFF;
}
.device-group-head:hover { color: var(--ink-900); }
.device-group-head .group-chev {
  font-size: 10px; color: var(--ink-400);
  transition: transform .12s;
}
.device-group.is-collapsed .group-chev { transform: rotate(-90deg); }
.device-group-head .group-name { flex: 1; text-align: left; word-break: break-word; }
.device-group-head .group-count {
  background: var(--ink-100); color: var(--ink-600);
  font-size: 10px; font-weight: 700; letter-spacing: 0;
  padding: 1px 7px; border-radius: 999px;
}
.device-group-head .group-down {
  background: rgba(239,68,68,.12); color: var(--red-500);
  font-size: 10px; font-weight: 700; letter-spacing: 0;
  padding: 1px 7px; border-radius: 999px;
}
.device-group-list { list-style: none; margin: 0; padding: 0; }
.device-group.is-collapsed .device-group-list { display: none; }
.device-group.group-empty { display: none; }

/* =========================== Detail pane =========================== */
.fleet-detail {
  padding: 22px 28px 60px;
  overflow-y: auto;
  background: var(--bg);
  min-width: 0;
}
.detail-head {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; margin-bottom: 20px;
}
.detail-id {
  font-size: 11px; color: var(--indigo-700); font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em;
}
.detail-name { margin: 4px 0 4px; font-size: 22px; }
.detail-sub  { font-size: 12px; }
.detail-actions { display: flex; align-items: center; gap: 12px; }
.live-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(34,197,94,.1); color: #15803D;
  padding: 5px 10px; border-radius: 999px; font-size: 12px; font-weight: 600;
}
.live-pill .live-dot { width: 8px; height: 8px; }
.btn {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 8px 14px; border-radius: 8px; font: inherit; font-weight: 600;
  font-size: 13px; cursor: pointer; border: 1px solid transparent;
  text-decoration: none;
}
.btn-secondary {
  background: #FFFFFF; color: var(--indigo-700);
  border-color: var(--ink-200);
}
.btn-secondary:hover {
  background: var(--indigo-50); border-color: var(--indigo-500);
}

/* KPI strip on detail pane */
.kpi-strip {
  display: grid;
  /* auto-fit reflows by the panel's own width (not the viewport), so the strip
     wraps correctly even when it sits in the narrow fleet-detail column. */
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 12px;
  margin: 0 0 14px;
}

.kpi-tile {
  position: relative;
  border-radius: 12px;
  padding: 12px 14px;
  border: 1px solid transparent;
  display: flex; flex-direction: column; gap: 6px;
  min-width: 0;
  transition: background .25s ease, border-color .25s ease, color .25s ease;
}
.kpi-tile-head { display: flex; align-items: center; gap: 8px; }
.kpi-tile-icon { width: 18px; height: 18px; flex: 0 0 18px; }
.kpi-tile-label {
  font-size: 10px; font-weight: 700;
  letter-spacing: .07em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.kpi-tile-value {
  display: flex; align-items: baseline; gap: 6px;
  line-height: 1;
  min-width: 0;
}
.kpi-tile-number {
  font-size: 26px; font-weight: 700;
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
  min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Battery-state shows a text status ("Charging"/"Discharging"), not a number,
   so use a smaller size that fits a narrow tile without spilling. */
.kpi-tile[data-slug="batt_state"] .kpi-tile-number { font-size: 18px; }
.kpi-tile-unit { font-size: 12px; font-weight: 600; opacity: .85; flex: 0 0 auto; }
.kpi-tile-sub { font-size: 11px; }
.kpi-tile-number.flash { animation: flash .8s ease; }

/* Tinted themes — soft pastel surface, accent text for icon + label + sub */
.kpi-tile-solar    { background: #FEF3C7; border-color: #FDE68A; color: #92400E; }
.kpi-tile-load     { background: #EDE9FE; border-color: #DDD6FE; color: #5B21B6; }
.kpi-tile-ok       { background: #ECFDF5; border-color: #BBF7D0; color: #047857; }
.kpi-tile-warn     { background: #FEF3C7; border-color: #FDE68A; color: #8A5A06; }
.kpi-tile-danger   { background: #FEE2E2; border-color: #FECACA; color: #B91C1C; }
.kpi-tile-thermal  { background: #DBEAFE; border-color: #BFDBFE; color: #1E40AF; }
.kpi-tile-neutral  { background: var(--ink-100); border-color: var(--ink-200); color: var(--ink-700); }

.kpi-tile .kpi-tile-sub.muted { color: inherit; opacity: .75; }

/* ---- Battery health card (device detail) ---- */
.battery-health {
  background: var(--card-bg);
  border: 1px solid var(--ink-200);
  border-left: 4px solid var(--ink-400);
  border-radius: 12px;
  padding: 14px 16px;
  margin: 0 0 14px;
}
.battery-health.band-ok       { border-left-color: #22C55E; }
.battery-health.band-watch    { border-left-color: #EAB308; }
.battery-health.band-warn     { border-left-color: #F59E0B; }
.battery-health.band-critical { border-left-color: #EF4444; }

.bh-head { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.bh-title { font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; margin: 0; color: var(--ink-700); }
.bh-status { font-size: 11px; font-weight: 700; padding: 2px 9px; border-radius: 999px; }
.bh-status-good { background: #ECFDF5; color: #047857; }
.bh-status-attention { background: #FEE2E2; color: #B91C1C; }
.bh-asof { font-size: 11px; margin-left: auto; }

.bh-body { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 14px; align-items: end; }
.bh-metric { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.bh-metric-label { font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-500); }
.bh-metric-value { font-size: 22px; font-weight: 700; line-height: 1.1; color: var(--ink-900); font-variant-numeric: tabular-nums; }
.bh-metric-value.band-ok       { color: #047857; }
.bh-metric-value.band-watch    { color: #A16207; }
.bh-metric-value.band-warn     { color: #8A5A06; }
.bh-metric-value.band-critical { color: #B91C1C; }
.bh-unit { font-size: 13px; font-weight: 600; opacity: .8; }
.bh-metric-sub { font-size: 11px; }
.bh-na { color: var(--ink-400); font-weight: 600; }
.bh-yes { color: #047857; }
.bh-no  { color: #B91C1C; }

.bh-spark { display: flex; flex-direction: column; gap: 3px; color: #6366F1; min-width: 0; }
.bh-spark-svg { width: 100%; height: 30px; display: block; }
.bh-spark-label { font-size: 10px; text-transform: uppercase; letter-spacing: .06em; }

.bh-reasons { list-style: none; margin: 12px 0 0; padding: 10px 0 0; border-top: 1px solid var(--ink-100); display: flex; flex-direction: column; gap: 5px; }
.bh-reason { font-size: 12px; color: var(--ink-700); padding-left: 16px; position: relative; }
.bh-reason::before { content: "!"; position: absolute; left: 2px; color: #B91C1C; font-weight: 800; }

/* ---- Battery-health list page ---- */
.bh-list-flagged { margin-left: 10px; font-size: 13px; font-weight: 700; color: #B91C1C; background: #FEE2E2; border-radius: 999px; padding: 3px 10px; }
.bh-list-note { margin: 0 0 14px; font-size: 12px; max-width: 720px; }
.bh-table-wrap { overflow-x: auto; background: var(--card-bg); border: 1px solid var(--ink-200); border-radius: 12px; box-shadow: var(--shadow); }
.bh-table { width: 100%; border-collapse: collapse; font-size: 13px; }
.bh-table th { text-align: left; font-size: 10px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-500); font-weight: 700; padding: 10px 12px; border-bottom: 1px solid var(--ink-200); white-space: nowrap; }
.bh-table td { padding: 10px 12px; border-bottom: 1px solid var(--ink-100); vertical-align: top; }
.bh-table tbody tr:last-child td, .bh-table tr:last-child td { border-bottom: none; }
.bh-table .num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.bh-row td:first-child { border-left: 3px solid transparent; }
.bh-row.is-attention.band-critical td:first-child { border-left-color: #EF4444; }
.bh-row.is-attention.band-warn     td:first-child { border-left-color: #F59E0B; }
.bh-row.is-attention.band-watch    td:first-child { border-left-color: #EAB308; }
.bh-cell-name a { font-weight: 600; color: var(--ink-900); text-decoration: none; }
.bh-cell-name a:hover { text-decoration: underline; }
.bh-badge { font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
.bh-badge-good { background: #ECFDF5; color: #047857; }
.bh-badge-attention { background: #FEE2E2; color: #B91C1C; }
.bh-cell-notes { color: var(--ink-700); max-width: 340px; }
.bh-note-line { margin: 1px 0; }

/* Alarm-tile severity dots */
.kpi-alarms-breakdown { display: flex; align-items: center; gap: 10px; font-size: 11px; flex-wrap: wrap; }
.kpi-sev { display: inline-flex; align-items: center; gap: 4px; font-weight: 700; color: var(--ink-900); }
.kpi-sev .dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }
.kpi-sev-critical      .dot { background: #EF4444; }
.kpi-sev-major         .dot { background: #F59E0B; }
.kpi-sev-minor         .dot { background: #EAB308; }
.kpi-sev-warning       .dot { background: #3B82F6; }
.kpi-sev-indeterminate .dot { background: #94A3B8; }

.detail-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 16px;
  align-items: start;
}
@media (max-width: 1180px) {
  .detail-grid { grid-template-columns: 1fr; }
}

/* =========================== Alerts feed (sidebar on detail + history) =========================== */
.alerts-feed, .alerts-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  position: sticky; top: 16px;
}
.alerts-head, .card-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px;
  border-bottom: 1px solid var(--ink-100);
}
.alerts-head h2, .card-head h2 {
  margin: 0; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--indigo-700);
}
.alerts-head .badge, .card-head .badge {
  background: var(--ink-100); color: var(--ink-700);
  font-size: 11px; padding: 2px 8px; border-radius: 999px; font-weight: 600;
}
.alerts-list {
  list-style: none; margin: 0; padding: 6px;
  max-height: 480px; overflow-y: auto;
}
.alert {
  background: transparent !important;
  color: var(--ink-900) !important;
  display: grid;
  grid-template-columns: 10px 1fr;
  align-items: flex-start;
  gap: 10px;
  padding: 10px 12px;
  border-radius: 8px;
  font-size: 13px;
  transition: background .12s, opacity .25s;
}
.alert:hover { background: var(--ink-100) !important; }
.alert.is-cleared { opacity: .45; }
.alert-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ink-400);
  margin-top: 5px;
}
/* Severity dot colors — must match the "Alarms by severity" chart palette
   (home.js SEV_COLOR / .dot-* / .kpi-sev-* / .summary-sev-*).
   NOT the map pins: those encode freshness, never severity. */
.alert-critical      .alert-dot { background: #EF4444; box-shadow: 0 0 0 3px rgba(239,68,68,.12); }
.alert-major         .alert-dot { background: #F59E0B; box-shadow: 0 0 0 3px rgba(245,158,11,.12); }
.alert-minor         .alert-dot { background: #EAB308; box-shadow: 0 0 0 3px rgba(234,179,8,.12); }
.alert-warning       .alert-dot { background: #3B82F6; box-shadow: 0 0 0 3px rgba(59,130,246,.12); }
.alert-indeterminate .alert-dot { background: #94A3B8; }
.alert-type {
  font-weight: 600;
}
.alert-meta { font-size: 11px; margin-top: 2px; }
.alert-sev {
  text-transform: uppercase; font-weight: 600; letter-spacing: .03em;
}
.alerts-empty {
  padding: 14px 16px; text-align: center; font-size: 13px;
}
/* "All clear" state — green, like the map's floating device summary
   (.summary-card-sev-clear). Shared by the Devices sidebar and the header bell. */
.alerts-empty-clear { color: #16A34A; font-weight: 600; }
.alert.is-new { animation: alertSlideIn .35s ease; }
@keyframes alertSlideIn {
  0%   { background: var(--indigo-50) !important; transform: translateX(-8px); opacity: 0; }
  100% { background: transparent !important; transform: translateX(0); opacity: 1; }
}

/* =========================== History page =========================== */
.history-header {
  display: flex; justify-content: space-between; align-items: flex-start;
  gap: 16px; margin-bottom: 22px;
}
.crumb-back {
  display: inline-block; font-size: 12px; color: var(--ink-500); margin-bottom: 6px;
}
.crumb-back:hover { color: var(--indigo-600); }
.history-name { margin: 0 0 4px; font-size: 26px; }
.history-sub  { font-size: 13px; margin: 0; }
.history-status { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }
.status-badge {
  font-size: 11px; font-weight: 700; padding: 4px 10px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .04em;
}
.status-badge.status-ok      { background: rgba(34,197,94,.12); color: #15803D; }
.status-badge.status-unusual { background: rgba(245,158,11,.15); color: #B45309; }
.status-badge.status-warn    { background: rgba(245,158,11,.15); color: #B45309; } /* legacy */
.status-badge.status-stale   { background: rgba(148,163,184,.2); color: #475569; } /* legacy */
.status-badge.status-down    { background: rgba(239,68,68,.12); color: #B91C1C; }

.range-toggle {
  display: inline-flex; background: #FFF; border: 1px solid var(--ink-200);
  border-radius: 10px; padding: 2px; box-shadow: var(--shadow);
}
.range-btn {
  border: 0; background: transparent; color: var(--ink-500); font-weight: 600;
  font: inherit; font-size: 12px; padding: 7px 16px; border-radius: 8px; cursor: pointer;
}
.range-btn:hover { color: var(--ink-900); }
.range-btn.active {
  background: var(--indigo-600); color: #FFF;
}

.kpi-cards {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 14px;
  margin-bottom: 18px;
}
.kpi-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  padding: 14px 16px 6px;
  box-shadow: var(--shadow);
  position: relative;
}
.kpi-card header {
  display: flex; justify-content: space-between; align-items: center;
}
.kpi-card-title {
  font-size: 12px; color: var(--ink-500); font-weight: 600;
}
.kpi-card-pill {
  font-size: 10px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .03em;
}
.pill-ok   { background: rgba(34,197,94,.12);  color: #15803D; }
.pill-warn { background: rgba(245,158,11,.15); color: #B45309; }
.pill-down { background: rgba(239,68,68,.12);  color: #B91C1C; }
.kpi-card-value {
  display: flex; align-items: baseline; gap: 4px; margin-top: 8px;
}
.kpi-card-number {
  font-size: 30px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; color: var(--ink-900);
}
.kpi-card-number.flash { animation: flash .8s ease; }
.kpi-card-unit { font-size: 13px; color: var(--ink-500); font-weight: 500; }
.kpi-spark {
  display: block; width: 100% !important; height: 42px !important;
  margin-top: 8px;
}

.history-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: 16px;
  margin-bottom: 18px;
}
@media (max-width: 1180px) {
  .history-main { grid-template-columns: 1fr; }
  .kpi-cards    { grid-template-columns: repeat(2, 1fr); }
}

.chart-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px 12px;
}
.chart-head {
  display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;
}
.chart-head h2 { margin: 0; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em; color: var(--indigo-700); }
.chart-head-range { font-size: 11px; font-weight: 500; margin-left: 4px;
  text-transform: none; letter-spacing: 0; color: var(--ink-500); }
.chart-legend {
  display: flex; flex-wrap: wrap; gap: 12px; font-size: 12px; color: var(--ink-700);
}
.chart-legend .lg { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend .lg-swatch { width: 12px; height: 3px; border-radius: 2px; display: inline-block; }
.chart-canvas-wrap { position: relative; height: 380px; }
.chart-canvas-wrap canvas { width: 100% !important; height: 100% !important; }

.history-bottom {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 16px;
}
@media (max-width: 1180px) {
  .history-bottom { grid-template-columns: 1fr; }
}
.cells-card, .energy-card, .location-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.cells-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px;
  padding: 16px;
}
.cell {
  text-align: center; padding: 10px 6px;
  background: var(--ink-50); border-radius: 10px;
}
.cell-v {
  font-size: 18px; font-weight: 700; color: var(--ink-900); line-height: 1;
  font-variant-numeric: tabular-nums;
}
.cell-l { font-size: 10px; color: var(--ink-500); margin-top: 4px; font-weight: 600; }
.energy-rows { padding: 12px 16px 16px; display: flex; flex-direction: column; gap: 10px; }
.energy-row { display: flex; justify-content: space-between; align-items: baseline; }
.energy-label { font-size: 12px; }
.energy-value { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; }
.energy-value em { font-style: normal; font-size: 12px; color: var(--ink-500); font-weight: 500; }
.location-map { height: 180px; }

/* ===== Per-category drill-down + single-chart popout ===== */

/* Make panel headers a flex row so the drill link sits to the right. */
.panel-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.panel-drill {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
  color: var(--indigo-700); padding: 4px 8px; border-radius: 6px;
  background: transparent; transition: background .15s;
}
.panel-drill:hover { background: var(--indigo-50); color: var(--indigo-700); }

/* History page Power chart + category chart cards: legend + popout to the right. */
.chart-head-right {
  display: flex; align-items: center; gap: 12px;
}
.chart-popout {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; border-radius: 6px;
  font-size: 14px; color: var(--ink-500);
  background: transparent; transition: background .15s, color .15s;
}
.chart-popout:hover { background: var(--indigo-50); color: var(--indigo-700); }

/* ----- Category page ----- */
.category-header {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 24px; margin-bottom: 20px;
}
.category-name {
  margin: 8px 0 0; font-size: 22px; font-weight: 700; color: var(--ink-900);
}
.category-name .muted { font-weight: 500; }
.category-sub { margin: 4px 0 0; font-size: 13px; }
.category-actions { display: flex; gap: 12px; align-items: center; }
.category-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(540px, 1fr));
  gap: 16px;
}
@media (max-width: 900px) {
  .category-grid { grid-template-columns: 1fr; }
  .category-header { flex-direction: column; align-items: stretch; }
}
/* Slightly shorter chart on the category grid so multiple fit per viewport. */
.page-category .chart-canvas-wrap { height: 300px; }

/* ----- Single-chart popout page -----
 * Lock the page to the viewport so the canvas always shows its x-axis.
 * Body becomes a flex column; main fills the remaining viewport; canvas
 * needs `min-height: 0` so flex: 1 can actually shrink it (default
 * `min-height: auto` would otherwise let it overflow). */
body.page-chart {
  height: 100vh;
  display: flex; flex-direction: column;
  overflow: hidden;
}
.page-chart main.page {
  flex: 1; min-height: 0;
  max-width: none; width: 100%; margin: 0; padding: 0;
  display: flex; flex-direction: column;
}
.chart-page {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
  padding: 14px 24px 18px;
  gap: 10px;
  background: var(--card-bg);
}
.chart-page-head {
  flex: 0 0 auto;
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 16px; flex-wrap: wrap;
}
.chart-page-title {
  margin: 6px 0 0; font-size: 22px; font-weight: 700; color: var(--ink-900);
}
.chart-page-sub { margin: 4px 0 0; font-size: 13px; }
.chart-page-actions {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
.chart-page-legend {
  flex: 0 0 auto;
  display: flex; flex-wrap: wrap; gap: 16px; font-size: 13px; color: var(--ink-700);
  padding: 0 4px;
}
.chart-page-legend .lg { display: inline-flex; align-items: center; gap: 6px; }
.chart-page-legend .lg-swatch { width: 18px; height: 3px; border-radius: 2px; display: inline-block; }
.chart-page-canvas {
  flex: 1 1 auto; min-height: 0; position: relative;
}
.chart-page-canvas canvas { width: 100% !important; height: 100% !important; }
.fullscreen-toggle { font-size: 16px; padding: 6px 10px; }

/* ----- Series picker popover ----- */
.series-picker-wrap { position: relative; }
.series-picker {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 50;
  width: 480px; max-width: calc(100vw - 24px); max-height: 70vh;
  background: var(--card-bg); border: 1px solid var(--indigo-100);
  border-radius: 10px; box-shadow: 0 14px 32px rgba(15, 23, 42, .14);
  display: flex; flex-direction: column;
}
/* Restore the [hidden] semantics. `display: flex` above (and the same default
 * applies to dialog/details elements) outranks the user-agent
 * `[hidden] { display: none }` rule because of equal specificity, so the
 * picker would render even when the JS set picker.hidden = true. */
.series-picker[hidden] { display: none; }
.series-picker-search {
  padding: 10px; border-bottom: 1px solid var(--ink-100);
  position: sticky; top: 0; background: var(--card-bg);
}
.series-picker-search input {
  width: 100%; padding: 8px 10px; border-radius: 6px;
  border: 1px solid var(--ink-200); background: var(--ink-50);
  font: inherit; color: var(--ink-900);
}
.series-picker-body { overflow-y: auto; padding: 6px 12px; flex: 1; min-height: 0; }
.series-group { padding: 8px 0; }
.series-group + .series-group { border-top: 1px solid var(--ink-100); }
.series-group-title {
  font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--ink-500); margin-bottom: 6px;
}
.series-item {
  display: grid; grid-template-columns: 18px 1fr auto;
  align-items: center; gap: 10px; padding: 6px 6px;
  border-radius: 6px; font-size: 13px; cursor: pointer;
}
.series-item:hover { background: var(--indigo-50); }
.series-item input { margin: 0; accent-color: var(--indigo-600); }
.series-item-text {
  display: flex; flex-direction: column; gap: 1px; min-width: 0;
}
.series-item-label {
  color: var(--ink-900); font-weight: 500; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.series-item-sub {
  font-size: 11px; font-variant-numeric: tabular-nums; line-height: 1.2;
}
.series-item-unit { font-size: 11px; white-space: nowrap; }
.series-picker-foot {
  display: flex; justify-content: flex-end; gap: 8px;
  padding: 10px; border-top: 1px solid var(--ink-100);
}
.series-picker-foot .primary { padding: 6px 14px; border-radius: 6px; font-size: 13px; cursor: pointer; border: 0; }
.series-picker-foot .btn-secondary { padding: 6px 14px; border-radius: 6px; font-size: 13px; cursor: pointer; }

/* Multi-unit chart stack (popout only). JS picks single / dual / stacked. */
.chart-stack {
  display: flex; flex-direction: column;
  gap: 8px;
  min-height: 0;
}
.chart-stack > .chart-stack-row {
  flex: 1 1 0;
  min-height: 0;
  position: relative;
}
.chart-stack > .chart-stack-row > canvas {
  width: 100% !important;
  height: 100% !important;
}
.chart-mode-chip {
  display: inline-block;
  padding: 2px 8px;
  margin-left: 8px;
  border-radius: 999px;
  background: var(--indigo-50);
  color: var(--indigo-700);
  font-size: 12px; font-weight: 500;
  vertical-align: middle;
}
.chart-mode-chip-block {
  background: #FEF3C7;   /* amber-100 */
  color:      #92400E;   /* amber-900 */
}

/* Block (fixed-window) picker — sits next to the range toggle. */
.block-picker-wrap { position: relative; display: inline-block; }
.block-toggle.active {
  background: #FEF3C7;
  color: #92400E;
  border-color: #FDE68A;
}
.block-picker {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 30;
  min-width: 280px;
  padding: 12px;
  background: var(--bg, #fff);
  border: 1px solid var(--border, #E5E7EB);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.block-picker[hidden] { display: none; }
.block-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 12px;
  color: var(--muted, #6B7280);
}
.block-field input[type="datetime-local"] {
  padding: 6px 8px;
  border: 1px solid var(--border, #E5E7EB);
  border-radius: 4px;
  font-size: 13px;
}
.block-picker-hint {
  font-size: 11px;
  margin-top: -2px;
}
.block-picker-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 4px;
}

/* =========================== Fleet alerts sidebar (right side of Home) =========================== */
.fleet-alerts-sidebar {
  background: #FFFFFF;
  border-left: 1px solid var(--ink-100);
  display: flex; flex-direction: column;
  min-height: 0;
}
.fleet-alerts-sidebar .sidebar-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px;
}
.sidebar-link {
  font-size: 12px;
  color: var(--indigo-700);
  text-decoration: none;
  white-space: nowrap;
}
.sidebar-link:hover { text-decoration: underline; }
.fleet-alerts-list {
  list-style: none; margin: 0; padding: 8px;
  overflow-y: auto;
  flex: 1 1 auto;
}
.fleet-alerts-list .alert { background: transparent !important; }
.fleet-alerts-list .alert:hover { background: var(--ink-100) !important; }
.alert-cleared { opacity: .55; }
.alert-device {
  text-transform: none;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--ink-700);
}

/* Make the whole alert row a clickable anchor without breaking its grid layout. */
.alert-link {
  display: grid;
  grid-template-columns: subgrid;
  grid-column: 1 / -1;
  gap: 10px;
  color: inherit; text-decoration: none;
}
/* Fallback for browsers without grid-template-columns: subgrid. */
@supports not (grid-template-columns: subgrid) {
  .alert-link {
    display: grid;
    grid-template-columns: 10px 1fr;
    align-items: flex-start;
  }
}
/* On the standalone Alerts page, rows use 5 columns instead of the sidebar's 2. */
.alerts-table .alert.alert-row { grid-template-columns: 110px minmax(140px, 1.4fr) minmax(140px, 1.2fr) 110px 140px; }
.alerts-table .alert-link      { grid-template-columns: 110px minmax(140px, 1.4fr) minmax(140px, 1.2fr) 110px 140px; }

/* =========================== Devices page (standalone list) =========================== */
.devices-page-controls {
  display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap; justify-content: flex-end;
}
.devices-page-controls .sidebar-search { width: 240px; }

.device-table {
  list-style: none; margin: 0; padding: 0;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.device-table-head,
.device-table-link {
  display: grid;
  grid-template-columns: minmax(200px, 1.4fr) minmax(120px, 1fr) minmax(120px, 1fr) 110px 130px;
  align-items: center;
  gap: 12px;
}
.device-table-head {
  padding: 10px 14px;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-500);
  background: var(--ink-50);
  border-bottom: 1px solid var(--ink-100);
}
/* Row is a single-child container; its <a> child carries the column grid. */
.device-table-row { display: block; border-bottom: 1px solid var(--ink-100); }
.device-table-row:last-child { border-bottom: none; }
.device-table-link {
  padding: 12px 14px;
  color: inherit; text-decoration: none;
}
.device-table-link:hover { background: var(--ink-100); }
.device-table .cell.name { font-weight: 600; display: inline-flex; align-items: center; gap: 8px; }
.device-table .cell.type { font-size: 13px; color: var(--ink-700); }
.device-table .cell.label { font-size: 13px; }
.device-table .cell.last { font-size: 12px; color: var(--ink-700); font-variant-numeric: tabular-nums; }
.device-table-row.hide-search { display: none; }
.device-table[data-active-status="ok"]      .device-table-row:not([data-status="ok"]),
.device-table[data-active-status="unusual"] .device-table-row:not([data-status="unusual"]),
.device-table[data-active-status="down"]    .device-table-row:not([data-status="down"]) { display: none; }

/* =========================== Alerts page (standalone table) =========================== */
/* Alarms and Briefings both render into this shell: title → filter bar → table →
   pager. They share it so the two pages compose identically. */
.alerts-page { display: flex; flex-direction: column; }
.alerts-table {
  list-style: none; margin: 0; padding: 0;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.alerts-table-head {
  display: grid;
  grid-template-columns: 110px minmax(140px, 1.4fr) minmax(140px, 1.2fr) 110px 140px;
  gap: 12px;
  padding: 0 14px;
  min-height: 36px;
  align-items: center;
  font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-500);
  background: var(--ink-50);
  border-bottom: 1px solid var(--ink-100);
}
.alerts-table .alert.alert-row {
  border-bottom: 1px solid var(--ink-100);
  padding: 0;
  border-radius: 0;
  margin: 0;
}
.alerts-table .alert.alert-row:last-child { border-bottom: none; }
/* Row height is DECLARED, not emergent. Briefings' cells hold pill badges (padding
   + border) while the Alarms cells are plain text, so a content-driven row height
   drifts between the two pages. min-height, not height, so a long device name still
   wraps and grows the row rather than overflowing it. */
.alerts-table .alert.alert-row .alert-link {
  padding: 0 14px;
  min-height: 48px;
  align-items: center;
}
.alerts-table .alert.alert-row .alert-link:hover { background: var(--ink-100); }
.alerts-table .cell.sev { font-weight: 600; display: inline-flex; align-items: center; gap: 8px; text-transform: uppercase; font-size: 12px; }
.alerts-table .cell.type    { font-weight: 600; }
.alerts-table .cell.device  { color: var(--ink-700); }
/* Fixed-format timestamps must never wrap: a wrapped cell grows the row past its
   declared min-height, which is exactly how the two tables drift out of step. */
.alerts-table .cell.started { font-size: 12px; color: var(--ink-700); font-variant-numeric: tabular-nums; white-space: nowrap; }
.alerts-table .cell.state   { font-size: 12px; text-transform: uppercase; color: var(--ink-500); letter-spacing: .04em; }

/* ---- Alarms filter bar (multi-select chips + device search) ----
   Chips are <a> links whose href the view precomputes, so filtering needs no JS. */
.filter-bar {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 12px 14px;
  margin-bottom: 14px;
  display: flex; flex-direction: column; gap: 8px;
}
.filter-bar-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.filter-search  { display: flex; align-items: center; gap: 8px; }
.filter-search input[type="search"] {
  font: inherit; font-size: 13px; padding: 6px 10px; min-width: 240px;
  border: 1px solid var(--ink-200); border-radius: 8px;
  background: var(--card-bg); color: var(--ink-900);
}
.filter-clear {
  font-size: 12px; font-weight: 600; color: var(--indigo-700);
  text-decoration: none; padding: 4px 8px; border-radius: 6px;
}
.filter-clear:hover { background: var(--ink-100); }

/* Label column is fixed so the three chip rows line up into a grid. */
.filter-group { display: flex; align-items: baseline; gap: 12px; }
.filter-group-label {
  flex: 0 0 110px;
  font-size: 10px; font-weight: 700; color: var(--ink-500);
  text-transform: uppercase; letter-spacing: .06em;
}
.filter-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.filter-chips .chip { text-decoration: none; }
/* Status/ack chips carry no colour of their own — only severity is colour-coded,
   and it uses the canonical severity palette. */
.filter-chips .chip-active .dot        { background: var(--red-500); }
.filter-chips .chip-cleared .dot       { background: var(--ink-400); }
.filter-chips .chip-unacked .dot       { background: var(--amber-500); }
.filter-chips .chip-acked .dot         { background: var(--green-500); }
.filter-chips .chip-critical .dot      { background: #EF4444; }
.filter-chips .chip-major .dot         { background: #F59E0B; }
.filter-chips .chip-minor .dot         { background: #EAB308; }
.filter-chips .chip-warning .dot       { background: #3B82F6; }
.filter-chips .chip-indeterminate .dot { background: #94A3B8; }
/* Briefings chips. Dots take the same hues as the .kind-badge / .brief-status pills
   they filter, so the chip and the row it selects read as the same thing. */
.filter-chips .chip-intraday .dot      { background: #1f4f99; }
.filter-chips .chip-daily .dot         { background: #3f6249; }
.filter-chips .chip-ok .dot            { background: var(--green-500); }
.filter-chips .chip-error .dot         { background: var(--red-500); }
.filter-chips .chip-no_data .dot       { background: var(--ink-400); }

/* ---- Sortable column headers ----
   Used by both Alarms and Briefings; .is-sortable-row is the opt-in, so a head row
   with plain <span> cells gets no carets. The caret is driven purely by aria-sort,
   the same trick as the fleet table's th[aria-sort]::after. */
.alerts-table-head.is-sortable-row .cell.is-sortable {
  color: inherit; text-decoration: none; cursor: pointer;
  user-select: none; display: inline-flex; align-items: center;
}
.alerts-table-head.is-sortable-row .cell.is-sortable:hover { color: var(--ink-700); }
.alerts-table-head.is-sortable-row .cell.is-sortable::after {
  content: "↕"; opacity: .3; margin-left: 4px; font-size: 10px;
}
.alerts-table-head.is-sortable-row .cell[aria-sort="ascending"]::after  { content: "↑"; opacity: 1; }
.alerts-table-head.is-sortable-row .cell[aria-sort="descending"]::after { content: "↓"; opacity: 1; }
.alerts-table-head.is-sortable-row .cell[aria-sort] { color: var(--ink-900); }

/* The .panels container had an unused alongside-aside; the helper class is just
 * a hook for any future override. The base `.panels` rule (grid + gap: 16px) is
 * what produces the spacing between Battery / Solar Panel / Grid cards. */
.panels-fullwidth { width: 100%; }

/* =========================== Alarm 4-state pill =========================== */
/* Lifecycle state — see https://thingsboard.io/docs/user-guide/alarms/#alarm-states */
.state-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 11px; font-weight: 700;
  letter-spacing: .04em;
  border: 1px solid transparent;
}
.state-active_unack   { background: #fde7e9; color: #a01024; border-color: #f3b7bf; }
.state-active_ack     { background: #fef0d6; color: #8a5a06; border-color: #f6d291; }
.state-cleared_unack  { background: #e2eefc; color: #1f4f99; border-color: #b6d3f3; }
.state-cleared_ack    { background: #e8efe9; color: #3f6249; border-color: #c2d4c8; }

/* =========================== Alerts pager =========================== */
.alerts-pager {
  display: flex; align-items: center; justify-content: center;
  gap: 14px;
  margin: 16px 0 0;
  font-size: 13px;
}
.alerts-pager .pager-link {
  text-decoration: none; color: var(--indigo-700);
  padding: 6px 12px; border-radius: 8px;
  border: 1px solid var(--ink-100);
}
.alerts-pager .pager-link:hover { background: var(--ink-100); }
.alerts-pager .pager-link.disabled { color: var(--ink-500); border-color: var(--ink-100); cursor: default; }

/* Numbered pages. The alarms list runs to a dozen-plus pages, so prev/next alone
   would mean a click per page to reach the end. Server-rendered links, like the chips. */
.alerts-pager .pager-nums { display: flex; align-items: center; gap: 4px; }
.alerts-pager .pager-num {
  min-width: 32px; padding: 6px 8px;
  display: inline-flex; align-items: center; justify-content: center;
  text-decoration: none; color: var(--ink-700);
  border: 1px solid transparent; border-radius: 8px;
  font-variant-numeric: tabular-nums;
}
.alerts-pager .pager-num:hover { background: var(--ink-100); }
.alerts-pager .pager-num.is-current {
  background: var(--indigo-50); border-color: var(--indigo-500);
  color: var(--indigo-700); font-weight: 700;
}
.alerts-pager .pager-gap { color: var(--ink-400); padding: 0 2px; }

/* =========================== Briefings list + detail =========================== */
/* Sits inside .filter-search (which supplies the flex row), so this only styles
   the date controls — the shell is shared with the Alarms filter bar. */
.brief-filter { font-size: 12px; color: var(--ink-500); }
.brief-filter label { display: inline-flex; align-items: center; gap: 4px; }
.brief-filter input[type="date"] {
  font: inherit; font-size: 13px; color: var(--ink-900);
  padding: 6px 10px; border: 1px solid var(--ink-200); border-radius: 8px; background: var(--card-bg);
}

/* Briefings table — reuses the alarms-table shell and mirrors its column rhythm
   (leading badge = 110px like Severity; trailing time column = 150px), so the two
   list pages read as siblings. */
.briefs-table .alerts-table-head,
.briefs-table .alert.alert-row,
.briefs-table .alert-link {
  /* Trailing column is 170px, not 150px: "Jul 13, 2026 01:18 WITA" wrapped to two
     lines at 150px, which grew the row past its declared height and desynchronised
     it from the alarms table. */
  grid-template-columns: 110px minmax(160px, 1.6fr) 90px 120px 170px;
}
.briefs-table .cell.window    { font-variant-numeric: tabular-nums; color: var(--ink-700); }
.briefs-table .cell.devices   { font-variant-numeric: tabular-nums; }
/* Match the alarms "Started" cell typography exactly, nowrap included. */
.briefs-table .cell.generated { font-size: 12px; color: var(--ink-700); font-variant-numeric: tabular-nums; white-space: nowrap; }

.kind-badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  border: 1px solid transparent;
}
.kind-daily    { background: #e8efe9; color: #3f6249; border-color: #c2d4c8; }
.kind-intraday { background: #e2eefc; color: #1f4f99; border-color: #b6d3f3; }

.brief-status {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  font-size: 11px; font-weight: 700; letter-spacing: .04em; border: 1px solid transparent;
}
.status-ok      { background: #e8efe9; color: #3f6249; border-color: #c2d4c8; }
.status-error   { background: #fde7e9; color: #a01024; border-color: #f3b7bf; }
.status-no_data { background: var(--ink-100); color: var(--ink-500); border-color: var(--ink-200); }

/* Briefing detail — the report runs full width (a 36-device analysis list does not
   fit a sidebar-narrowed column), with the Details strip below it. */
.brief-detail-page { max-width: 1080px; }
.brief-back { margin: 0 0 12px; font-size: 13px; }
.brief-back a { color: var(--indigo-700); text-decoration: none; font-weight: 600; }
.brief-back a:hover { text-decoration: underline; }
/* Give the summary a touch more presence on the detail page. */
.brief-detail .ai-brief-text { font-size: 14px; line-height: 1.7; }

/* ---- report sections ---- */
.brief-section { margin-top: 20px; }
.brief-section:first-of-type { margin-top: 12px; }
.brief-section-title {
  margin: 0 0 10px; font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-500);
  padding-bottom: 6px; border-bottom: 1px solid var(--ink-100);
}
.brief-section .ai-brief-text { margin: 0 0 10px; }

/* ---- per-device analysis ---- */
.brief-devices { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.brief-device {
  border: 1px solid var(--ink-100); border-radius: 10px;
  padding: 10px 12px; background: var(--ink-50);
}
/* Devices needing attention get the rail treatment so they read first. */
.brief-device.has-issues { background: #fff; border-left: 3px solid var(--amber-500); }
.brief-device-head {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px; margin-bottom: 7px;
}
.brief-device-head .status-dot { display: inline-block; flex: 0 0 8px; }
.brief-device-name { font-size: 13px; color: var(--ink-900); }
.brief-device-status {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  padding: 2px 7px; border-radius: 999px; background: var(--ink-100); color: var(--ink-700);
}
.brief-device-status.status-ok      { background: rgba(34,197,94,.12);  color: #15803D; }
.brief-device-status.status-unusual { background: rgba(245,158,11,.14); color: #92400E; }
/* warn/stale kept so historical briefs (stored with the old categories) still render. */
.brief-device-status.status-warn    { background: rgba(245,158,11,.14); color: #92400E; }
.brief-device-status.status-stale   { background: rgba(148,163,184,.18); color: #475569; }
.brief-device-status.status-down    { background: rgba(239,68,68,.12);  color: #B91C1C; }
.brief-device-alarms {
  font-size: 11px; font-weight: 600; padding: 2px 7px; border-radius: 999px;
  background: rgba(239,68,68,.10); color: #B91C1C;
}
.brief-device-silent { font-size: 11px; color: var(--ink-500); }

.brief-vitals { display: flex; flex-wrap: wrap; gap: 6px; }
.brief-vital {
  font-size: 11px; color: var(--ink-500); background: #fff;
  border: 1px solid var(--ink-100); border-radius: 6px; padding: 2px 7px;
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.brief-vital b { color: var(--ink-900); font-weight: 600; }
/* Band colours mirror the device gauges, so the report agrees with the gauge. */
.brief-vital.band-warn   { background: rgba(245,158,11,.10); border-color: rgba(245,158,11,.35); }
.brief-vital.band-warn b { color: #92400E; }
.brief-vital.band-danger { background: rgba(239,68,68,.10); border-color: rgba(239,68,68,.35); }
.brief-vital.band-danger b { color: #B91C1C; }
.brief-device-note {
  margin: 7px 0 0; font-size: 12px; line-height: 1.55; color: var(--ink-700);
}
.brief-device:not(.has-issues) .brief-device-note { color: var(--ink-500); }

/* ---- Brief: standing battery-health section ---- */
.brief-section-note { font-size: 11px; font-weight: 500; color: var(--ink-500); text-transform: none; letter-spacing: 0; }
.brief-batteries { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.brief-battery {
  border: 1px solid var(--ink-100); border-left: 3px solid var(--ink-400);
  border-radius: 8px; padding: 8px 12px; background: #fff;
}
.brief-battery.band-watch    { border-left-color: #EAB308; }
.brief-battery.band-warn     { border-left-color: #F59E0B; }
.brief-battery.band-critical { border-left-color: #EF4444; }
.brief-battery-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.brief-battery-name { color: var(--ink-900); }
.brief-battery-soh { font-size: 11px; font-weight: 600; color: var(--ink-700); background: var(--ink-100); border-radius: 6px; padding: 1px 7px; font-variant-numeric: tabular-nums; }
.brief-battery-tag { font-size: 11px; font-weight: 600; color: #B91C1C; background: rgba(239,68,68,.10); border-radius: 6px; padding: 1px 7px; }
.brief-battery-note { margin: 5px 0 0; font-size: 12px; line-height: 1.5; color: var(--ink-700); }

/* ---- findings + recommendations ---- */
.brief-findings { margin: 0; padding-left: 18px; }
.brief-findings li {
  font-size: 13px; line-height: 1.6; color: var(--ink-700); margin-bottom: 5px;
}
.brief-recs { list-style: none; margin: 0; padding: 0; display: grid; gap: 7px; }
.brief-rec { display: flex; align-items: baseline; gap: 9px; }
.brief-prio {
  flex: 0 0 auto; font-size: 10px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .04em; padding: 2px 8px; border-radius: 999px; min-width: 58px;
  text-align: center;
}
.prio-high   { background: rgba(239,68,68,.12);  color: #B91C1C; }
.prio-medium { background: rgba(245,158,11,.14); color: #92400E; }
.prio-low    { background: var(--ink-100);       color: var(--ink-700); }
.brief-rec-text { font-size: 13px; line-height: 1.6; color: var(--ink-700); }

.brief-detail-side {
  margin-top: 16px;
  background: var(--card-bg); border-radius: var(--radius); box-shadow: var(--shadow);
  padding: 16px 18px;
}
.brief-side-title {
  margin: 0 0 12px; font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-500);
}
.brief-side-dl { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 9px 14px; }
.brief-side-dl dt {
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-500); align-self: center;
}
.brief-side-dl dd {
  margin: 0; font-size: 13px; color: var(--ink-900); text-align: right;
  font-variant-numeric: tabular-nums;
}
.brief-error {
  margin: 12px 0 0; font-size: 12px; color: #a01024;
  background: #fde7e9; border: 1px solid #f3b7bf; border-radius: 8px;
  padding: 8px 10px; white-space: pre-wrap;
}
@media (max-width: 820px) {
  .brief-side-dl { grid-template-columns: 1fr; gap: 2px 0; }
  .brief-side-dl dd { text-align: left; margin-bottom: 8px; }
}

/* =========================== Home (Fleet Map) page =========================== */
/* No padding here: .page already supplies the gutter, and adding a second one
   inset the title 24px from the brand mark above it. Header is .page-head. */
.home-updated { font-size: 12px; }

.home-tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}
@media (max-width: 900px) { .home-tiles { grid-template-columns: 1fr; } }

/* ---- Home: battery-health strip (links to the roll-up) ---- */
.battery-strip {
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; margin-bottom: 14px;
  background: var(--card-bg); border: 1px solid var(--ink-200);
  border-radius: 12px; box-shadow: var(--shadow);
  color: var(--ink-700); text-decoration: none;
  transition: border-color .2s ease, background .2s ease;
}
.battery-strip:hover { border-color: var(--ink-400); }
.battery-strip-icon { display: flex; color: var(--ink-500); }
.battery-strip-icon .kpi-tile-icon { width: 20px; height: 20px; }
.battery-strip-text { font-size: 13px; }
.battery-strip-text b { color: var(--ink-900); }
.battery-strip-cta { margin-left: auto; font-size: 12px; font-weight: 600; color: #4F46E5; white-space: nowrap; }
.battery-strip.has-attention { background: #FEF2F2; border-color: #FECACA; }
.battery-strip.has-attention .battery-strip-icon { color: #DC2626; }
.battery-strip.has-attention .battery-strip-text b { color: #B91C1C; }

.fleet-tile { padding: 12px 16px; }
.fleet-tile-head {
  display: flex; align-items: baseline; justify-content: space-between;
  margin-bottom: 6px;
}
.fleet-tile-head .kpi-card-title {
  font-size: 11px;
  color: var(--ink-500);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
}
.fleet-tile-number {
  font-size: 22px; font-weight: 700; color: var(--ink-900);
  font-variant-numeric: tabular-nums;
}
/* Info affordance on the Active/Inactive tiles — explains the freshness bands. */
.fleet-tile-titlewrap { display: inline-flex; align-items: center; gap: 5px; }
.tile-info {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center;
  width: 14px; height: 14px; color: var(--ink-400); cursor: help;
}
.tile-info svg { width: 13px; height: 13px; display: block; }
.tile-info:hover, .tile-info:focus-visible { color: var(--ink-700); outline: none; }
.tile-tip {
  position: absolute; top: calc(100% + 6px); left: -2px; z-index: 20;
  display: none; width: max-content; max-width: 240px;
  padding: 7px 10px; border-radius: 6px;
  background: var(--ink-900); color: #fff; box-shadow: var(--shadow);
  font-size: 11px; font-weight: 500; line-height: 1.5;
  text-transform: none; letter-spacing: 0; white-space: normal;
}
.tile-tip b { font-weight: 700; }
.tile-info:hover .tile-tip, .tile-info:focus-visible .tile-tip { display: block; }
.fleet-tile-body {
  display: flex; align-items: center; gap: 16px;
}
/* Fixed square box keeps the canvas from being stretched by flex.
   Chart.js then renders at 1:1 inside it. */
.fleet-tile-chart-wrap {
  flex: 0 0 84px;
  width: 84px;
  height: 84px;
  position: relative;
}
.fleet-tile-chart {
  display: block;
  width: 100% !important;
  height: 100% !important;
}
/* Chart.js draws its tooltip inside the canvas, and the canvas is only 84px —
   "indeterminate: 3" was getting its corners and its tail sliced off. home.js
   renders this instead, anchored to the wrap above, which nothing clips.
   Matches .tile-tip so every dark tip on the page is the same size and shape. */
.chart-tip {
  position: absolute; z-index: 20;
  transform: translate(-50%, calc(-100% - 10px));
  display: none; width: max-content; max-width: 240px;
  padding: 7px 10px; border-radius: 6px;
  background: var(--ink-900); color: #fff; box-shadow: var(--shadow);
  font-size: 11px; font-weight: 600; line-height: 1.5;
  white-space: nowrap;
  pointer-events: none;  /* must not sit under the cursor, or it flickers */
}
.chart-tip.is-shown { display: block; }
.fleet-tile-legend {
  list-style: none; margin: 0; padding: 0;
  font-size: 12px; color: var(--ink-700);
  display: flex; flex-direction: column; gap: 6px;
  flex: 1 1 auto;
  min-width: 0;
}
.fleet-tile-legend li {
  display: flex; align-items: center; gap: 6px;
  white-space: nowrap;
}
.fleet-tile-legend.fleet-tile-legend-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 6px 12px;
}
.fleet-tile-legend b {
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
  margin-left: auto;
  font-weight: 700;
}
.fleet-tile-legend .dot {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%;
  flex: 0 0 8px;
}
.dot-ok            { background: #22C55E; }
.dot-unusual       { background: #F59E0B; }
.dot-warn          { background: #F59E0B; } /* legacy freshness bucket */
.dot-stale         { background: #94A3B8; } /* legacy freshness bucket */
.dot-down          { background: #EF4444; }
.dot-critical      { background: #EF4444; }
.dot-major         { background: #F59E0B; }
.dot-minor         { background: #EAB308; }
.dot-warning       { background: #3B82F6; }
.dot-indeterminate { background: #94A3B8; }

/* Full-width fleet map card, sits below the Device Monitoring table. */
.home-map-card {
  margin-top: 14px;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  display: flex;
  flex-direction: column;
  height: 52vh;
  min-height: 380px;
  max-height: 560px;
  padding: 8px;
  position: relative;
}
#fleet-map {
  flex: 1 1 auto;
  width: 100%;
  min-height: 0;
  border-radius: calc(var(--radius) - 4px);
  background: var(--ink-100);
}
.home-map-foot { margin: 8px 4px 2px; font-size: 12px; flex: 0 0 auto; }

/* Key for the two independent pin signals: hue = freshness, motion = attention. */
.map-legend {
  margin: 0 4px 8px; font-size: 11px; flex: 0 0 auto;
  display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: center;
}
.map-legend-group { display: inline-flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.map-legend-key   { display: inline-flex; align-items: center; gap: 4px; }
.map-legend-key .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
/* .pin is sized for the map (14px, block) and is declared LATER in this file, so
   this needs the extra specificity to win. Shrink it to sit inline with the text. */
.map-legend .map-legend-pin { display: inline-block; width: 8px; height: 8px; border-width: 1.5px; }

/* ---- Fleet monitoring table (full-width, below the map + alerts row) ---- */
.fleet-table-card {
  margin-top: 14px;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
}
.fleet-table-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-bottom: 10px;
}
.fleet-table-title { margin: 0; font-size: 14px; color: var(--ink-700); }
.fleet-table-search {
  font: inherit; font-size: 13px; padding: 6px 10px; min-width: 220px;
  border: 1px solid var(--ink-100); border-radius: 8px;
  background: #fff; color: var(--ink-900);
}
.fleet-table-wrap { overflow: auto; max-height: clamp(300px, 48vh, 560px); }
.fleet-table {
  width: 100%; border-collapse: collapse;
  font-size: 13px; white-space: nowrap;
}
.fleet-table thead th {
  position: sticky; top: 0; z-index: 1;
  background: var(--card-bg);   /* opaque so rows scroll under the header */
}
.fleet-table th {
  text-align: right; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-500); font-weight: 600; padding: 8px 10px;
  border-bottom: 1px solid var(--ink-100);
}
.fleet-table th.col-name, .fleet-table td.col-name { text-align: left; }
/* sortable headers */
.fleet-table th.is-sortable { cursor: pointer; user-select: none; }
.fleet-table th.is-sortable:hover { color: var(--ink-700); }
.fleet-table th.is-sortable::after { content: "↕"; opacity: .3; margin-left: 4px; font-size: 10px; }
.fleet-table th[aria-sort="ascending"]::after  { content: "↑"; opacity: 1; }
.fleet-table th[aria-sort="descending"]::after { content: "↓"; opacity: 1; }
.fleet-table th[aria-sort] { color: var(--ink-900); }
.fleet-table td {
  padding: 9px 10px; text-align: right;
  font-variant-numeric: tabular-nums; color: var(--ink-900);
  border-bottom: 1px solid var(--ink-100);
}
.fleet-table tbody tr:hover { background: var(--ink-50, #F8FAFC); }
.fleet-table-name { font-weight: 600; color: var(--ink-900); text-decoration: none; }
.fleet-table-name:hover { text-decoration: underline; }
.fleet-table-type { display: block; font-size: 11px; color: var(--ink-500); font-weight: 400; }
.fleet-table-empty { padding: 16px 4px; }

/* battery bar — bar pinned left (reads left→right), % text pinned right, so
   bars and numbers each line up in their own column regardless of value width. */
.batt-cell { display: flex; align-items: center; gap: 8px; justify-content: space-between; }
.batt-bar {
  width: 64px; height: 8px; border-radius: 4px;
  background: var(--ink-100); overflow: hidden; flex: 0 0 64px;
}
.batt-val { font-variant-numeric: tabular-nums; white-space: nowrap; }
.batt-bar-fill { display: block; height: 100%; border-radius: 4px; }
.batt-bar-fill.is-high { background: #22C55E; }
.batt-bar-fill.is-mid  { background: #F59E0B; }
.batt-bar-fill.is-low  { background: #EF4444; }

/* status */
.fleet-table .status-cell { display: inline-flex; align-items: center; gap: 6px; text-transform: capitalize; }
.fleet-table .status-dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; }

/* ---- In-map device summary panel (Leaflet control, top-right, collapsible) ---- */
.map-summary {
  width: 290px;
  max-width: calc(100vw - 40px);
  background: rgba(255, 255, 255, .96);
  border-radius: 10px;
  box-shadow: 0 4px 16px rgba(15, 23, 42, .18);
  overflow: hidden;
  font: inherit;
}
.map-summary-head {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--ink-100);
  background: #FFFFFF;
}
.map-summary-toggle {
  border: 0; background: transparent; cursor: pointer;
  font-size: 13px; line-height: 1; padding: 2px 4px; color: var(--ink-700);
}
.map-summary-title {
  font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--ink-700); flex: 1 1 auto;
}
.map-summary-body { padding: 8px; }
.map-summary .summary-list {
  display: flex; flex-direction: column; gap: 8px;
  max-height: 360px; overflow-y: auto;
  margin: 0; padding: 0; list-style: none;
}
.map-summary.is-collapsed .map-summary-body { display: none; }
@media (max-width: 700px) { .map-summary { width: 240px; } }

.summary-clear {
  font-size: 11px; font-weight: 600;
  color: var(--indigo-700); background: transparent; border: 0; cursor: pointer;
  padding: 2px 6px; border-radius: 6px;
}
.summary-clear:hover { background: var(--ink-100); }
.is-hidden { display: none !important; }
.summary-empty { padding: 12px 4px; font-size: 12px; }

.summary-card {
  border: 1px solid var(--ink-100);
  border-left: 3px solid var(--ink-200);
  border-radius: 8px;
  padding: 10px 12px;
  display: flex; flex-direction: column; gap: 6px;
  background: var(--card-bg);
  transition: border-color .15s ease, background .15s ease;
}
.summary-card:hover { background: #FAFBFC; }
.summary-card.status-ok      { border-left-color: #22C55E; }
.summary-card.status-unusual { border-left-color: #F59E0B; }
.summary-card.status-warn    { border-left-color: #F59E0B; } /* legacy */
.summary-card.status-stale   { border-left-color: #94A3B8; } /* legacy */
.summary-card.status-down    { border-left-color: #EF4444; }

.summary-card-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.summary-card-id   { display: flex; align-items: center; gap: 6px; min-width: 0; }
.summary-status-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.summary-card-name { font-size: 13px; color: var(--ink-900); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.summary-card-meta { font-size: 11px; flex: 0 0 auto; }

/* Each dot now spells out its severity, so the count is what should pop — not
   the whole chip. Hence weight 500 here and 700 only on the number. */
.summary-card-alarms { display: flex; flex-direction: column; gap: 4px; }
.summary-alarms-label {
  font-size: 11px; font-weight: 600; color: var(--ink-500);
  letter-spacing: .05em;
}
.summary-card-sev { display: flex; flex-wrap: wrap; gap: 4px 10px; font-size: 11px; }
.summary-card-sev-clear { color: #16A34A; font-weight: 600; font-size: 11px; }
.summary-sev { display: inline-flex; align-items: center; gap: 4px; font-weight: 500; color: var(--ink-700); }
.summary-sev b { font-weight: 700; }
.summary-sev .dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.summary-sev-critical      .dot { background: #EF4444; }
.summary-sev-major         .dot { background: #F59E0B; }
.summary-sev-minor         .dot { background: #EAB308; }
.summary-sev-warning       .dot { background: #3B82F6; }
.summary-sev-indeterminate .dot { background: #94A3B8; }

.summary-card-foot { display: flex; justify-content: space-between; align-items: center; font-size: 11px; }
.summary-card-link { color: var(--indigo-700); font-weight: 600; text-decoration: none; }
.summary-card-link:hover { text-decoration: underline; }

/* =========================== Map pins =========================== */
.pin-wrap { background: transparent; border: 0; }
.pin {
  display: block;
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,.35);
  box-sizing: content-box;
}
/* Hue = device freshness, and nothing else. --pin-halo is the same colour in
   rgb triplet form, so one keyframe can pulse any of them. */
.pin-ok      { background: #22C55E; --pin-halo: 34,197,94; }
.pin-unusual { background: #F59E0B; --pin-halo: 245,158,11; }
.pin-warn    { background: #F59E0B; --pin-halo: 245,158,11; }  /* legacy */
.pin-stale   { background: #94A3B8; --pin-halo: 148,163,184; } /* legacy */
.pin-down    { background: #EF4444; --pin-halo: 239,68,68; }

/* Motion = needs attention: down, or carrying an active alarm. Pulse is
   the ONLY thing that means this, exactly as hue only ever means freshness. */
.pin-attn { animation: pin-pulse 1.4s ease-in-out infinite; }
@keyframes pin-pulse {
  0%   { transform: scale(1);    box-shadow: 0 1px 3px rgba(0,0,0,.35), 0 0 0 0 rgba(var(--pin-halo), .55); }
  70%  { transform: scale(1.15); box-shadow: 0 1px 3px rgba(0,0,0,.35), 0 0 0 8px rgba(var(--pin-halo), 0); }
  100% { transform: scale(1);    box-shadow: 0 1px 3px rgba(0,0,0,.35), 0 0 0 0 rgba(var(--pin-halo), 0); }
}
@media (prefers-reduced-motion: reduce) { .pin-attn { animation: none; } }

.pin-tooltip {
  background: var(--card-bg) !important;
  color: var(--ink-900) !important;
  border: 1px solid var(--ink-100) !important;
  border-radius: 10px !important;
  box-shadow: var(--shadow) !important;
  padding: 10px 12px !important;
  font-size: 12px !important;
}
.pin-tooltip::before { display: none !important; }
.pin-popup-title { font-weight: 700; color: var(--ink-900); margin-bottom: 2px; }
.pin-popup-meta { font-size: 11px; margin-bottom: 6px; }
.pin-popup-row { display: flex; justify-content: space-between; gap: 12px; line-height: 1.6; }
.pin-popup-row b { font-weight: 600; }
.pin-popup-row .status-ok      { color: #22C55E; }
.pin-popup-row .status-unusual { color: #F59E0B; }
.pin-popup-row .status-warn    { color: #F59E0B; } /* legacy */
.pin-popup-row .status-stale   { color: #94A3B8; } /* legacy */
.pin-popup-row .status-down    { color: #EF4444; }

/* =========================== Dashboard: power-flow diagram =========================== */
.flow-diagram {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px 18px;
  margin: 14px 0;
  /* Query container so the diagram stacks by its own width, not the viewport's. */
  container-type: inline-size;
  container-name: flow;
}

/* Single-line diagram stage: a 3×2 grid of node cards over an SVG wire layer.
   Fixed 5:2 aspect + the matching 500×200 viewBox means uniform scaling, so the
   wire coordinates always line up with the card cells. */
.flow-stage {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  /* minmax(0,…) so a tall Battery card can't stretch the row and grow the stage
     past its 5:2 aspect — that would break the fixed-viewBox SVG wire alignment.
     Any small overflow sits in the card's bottom padding instead. */
  grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-areas:
    "solar inverter load"
    "grid  battery  battery";
  place-items: center;
  aspect-ratio: 5 / 2;
  gap: 22px 6px;
}
/* Pin the bottom-row cards to the top of their row so the (tall) battery grows
   DOWNWARD only — this keeps Grid and Battery tops aligned and leaves a clean
   horizontal channel under the inverter for the Grid trace. */
.flow-node-grid,
.flow-node-battery { align-self: start; }
.flow-wires {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  z-index: 0;
  pointer-events: none;
}
.wire-base {
  fill: none;
  stroke: #F59E0B;            /* amber trace (static) */
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.wire-dashed { stroke-dasharray: 7 7; }
/* Live highlight + flow animation are deferred to a later phase: traces are
   static for now. viz.js still tags live paths with .is-active, so the active
   styling can be re-enabled here without touching the data layer. */

.flow-node {
  position: relative;
  z-index: 1;
  width: 84%;
  background: var(--ink-50);
  border: 1px solid var(--ink-100);
  border-radius: 14px;
  padding: 12px 14px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  min-width: 0;
}
.flow-node-icon { width: 26px; height: 26px; margin-bottom: 2px; color: var(--ink-500); }
.flow-node-label {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--ink-700);
  line-height: 1.2;
}
.flow-node-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--ink-900);
  font-variant-numeric: tabular-nums;
  min-width: 0; max-width: 100%;
  overflow-wrap: anywhere;
}
.flow-node-unit { font-size: 12px; font-weight: 600; color: var(--ink-500); }
.flow-node-sub  { font-size: 12px; font-weight: 600; color: var(--ink-500); }

/* Node placement (grid areas) + tints + icon accents (reuse KPI theme hues). */
.flow-node-solar    { grid-area: solar;    background: #FEF3C7; border-color: #FDE68A; }
.flow-node-grid     { grid-area: grid;     background: #DBEAFE; border-color: #BFDBFE; }
/* Battery bank spans the bottom-right two columns (it carries the most detail);
   the Grid elbow rises in the channel just left of it (see the SVG wire coords). */
.flow-node-battery  { grid-area: battery;  width: 92%; gap: 8px; background: #ECFDF5; border-color: #BBF7D0; }
.flow-node-load     { grid-area: load;     background: #EDE9FE; border-color: #DDD6FE; }
.flow-node-inverter { grid-area: inverter; width: 94%; background: #FFFFFF; border-color: var(--ink-200); box-shadow: 0 2px 8px rgba(15,23,42,.05); }
.flow-node-solar    .flow-node-icon { color: #B45309; }
.flow-node-grid     .flow-node-icon { color: #1D4ED8; }
.flow-node-battery  .flow-node-icon { color: #047857; }
.flow-node-load     .flow-node-icon { color: #6D28D9; }
.flow-node-inverter .flow-node-icon { color: #475569; }

/* --- Battery Bank node internals: Batt #1 — bank — Batt #2, series-linked --- */
/* Short connector segments tie the three squares in series; the bank (middle)
   node is the one wired up to the inverter (dashed, via the main SVG layer). */
.batt-row {
  display: flex; align-items: flex-start; justify-content: center; gap: 0;
}
.batt-conn { flex: 0 0 18px; height: 2px; margin-top: 15px; background: #34D399; }
/* Box is pinned to the square's width so the connectors meet every square (the
   wider V / BATT labels overflow-center below, clear of the connector line). */
.batt-box { display: flex; flex-direction: column; align-items: center; gap: 3px; flex: 0 0 32px; min-width: 0; }
.batt-square {
  display: grid; place-items: center;
  width: 32px; height: 32px; border-radius: 8px;
  background: #FFFFFF; border: 2px solid #34D399;
}
.batt-square svg { width: 18px; height: 18px; color: #047857; }
/* The bank/junction square: solid green, slightly recessed — the bus tie point. */
.batt-box-bank .batt-square { background: #047857; border-color: #047857; }
.batt-box-bank .batt-square svg { color: #FFFFFF; }
/* VB1/VB2 sized to match the other node values (Solar/Grid/Load). */
.batt-volt {
  font-size: 18px; font-weight: 700; color: var(--ink-900);
  font-variant-numeric: tabular-nums; line-height: 1; white-space: nowrap;
}
.batt-volt .flow-node-unit { font-size: 12px; }
.batt-name {
  font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--ink-500); line-height: 1;
}

/* Two-part card: batteries (structure) on the left, readings (measurements) on
   the right — keeps the node short while staying the same width as the others. */
.batt-main {
  display: flex; align-items: center; justify-content: center;
  gap: 20px; width: 100%;
}
/* Bank readings: power / voltage / current, as a light divided list on the right. */
.batt-stats {
  display: flex; flex-direction: column;
  min-width: 155px;
  padding-left: 18px; border-left: 1px solid #BBF7D0;
}
.batt-stat {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 5px 0;
}
.batt-stat + .batt-stat { border-top: 1px solid #D1FAE5; }
.batt-stat-label {
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em;
  color: var(--ink-500);
}
.batt-stat-val {           /* same size as the other node values (Solar/Grid/Load) */
  font-size: 18px; font-weight: 700; color: var(--ink-900);
  font-variant-numeric: tabular-nums; white-space: nowrap; line-height: 1;
}
.batt-stat-val .flow-node-unit { font-size: 12px; }

/* Stack to a vertical card list when the panel gets narrow; hide the wires. */
/* Stack to a vertical card list before the Battery card gets too narrow for its
   side-by-side layout. Switching straight to the stack (rather than letting the
   battery card grow tall in the grid) keeps the stage at its 5:2 aspect ratio,
   so the fixed-viewBox SVG wires stay aligned to the cards. Wires hidden here. */
@container flow (max-width: 640px) {
  .flow-stage {
    aspect-ratio: auto;
    grid-template-columns: 1fr;
    grid-template-rows: none;
    grid-template-areas: none;
    place-items: stretch;
    gap: 10px;
  }
  /* Reset the inline grid-area placement, the row-top pin, and any nudge
     (e.g. the Grid's translateY) so cards flow cleanly in DOM order. */
  .flow-stage > .flow-node {
    grid-area: auto; width: 100%; max-width: none;
    align-self: stretch; transform: none !important;
  }
  .flow-wires { display: none; }
}

/* =========================== Dashboard: 4-card viz grid =========================== */
.viz-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin: 0 0 14px;
}
@media (max-width: 1200px) { .viz-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 700px)  { .viz-grid { grid-template-columns: 1fr; } }

.viz-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.viz-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.viz-card-title {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-700);
  text-transform: uppercase;
  letter-spacing: .06em;
}
.viz-status-pill {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.viz-status-ok       { background: #ECFDF5; color: #047857; border-color: #BBF7D0; }
.viz-status-warn     { background: #FEF3C7; color: #8A5A06; border-color: #FDE68A; }
.viz-status-danger   { background: #FEE2E2; color: #B91C1C; border-color: #FECACA; }
.viz-status-neutral  { background: var(--ink-100); color: var(--ink-500); }

/* Gauge ---- SVG arc + center value */
.viz-gauge {
  width: 100%;
  display: flex;
  justify-content: center;
}
.viz-gauge .gauge-svg {
  width: 100%;
  max-width: 220px;
  height: auto;
  display: block;
}
.gauge-bg { stroke: var(--ink-100); stroke-width: 12; stroke-linecap: round; }
.gauge-fg { stroke-width: 12; stroke-linecap: round; transition: stroke .3s ease; }
.gauge-fg.gauge-ok       { stroke: #22C55E; }
.gauge-fg.gauge-warn     { stroke: #F59E0B; }
.gauge-fg.gauge-danger   { stroke: #EF4444; }
.gauge-fg.gauge-neutral  { stroke: var(--indigo-500); }
.gauge-value {
  font: 700 26px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  fill: var(--ink-900);
}
.gauge-unit {
  font: 600 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  fill: var(--ink-500);
  letter-spacing: .04em;
}

/* Secondary stat tiles below the gauge */
.viz-stats {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
  gap: 6px;
}
.viz-stat {
  background: var(--ink-50);
  border: 1px solid var(--ink-100);
  border-radius: 8px;
  padding: 6px 8px;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.viz-stat-value {
  display: block;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink-900);
}
.viz-stat-unit {
  font-size: 10px;
  color: var(--ink-500);
  text-transform: uppercase;
  letter-spacing: .04em;
}
.viz-stat-ok      .viz-stat-value { color: #047857; }
.viz-stat-warn    .viz-stat-value { color: #8A5A06; }
.viz-stat-danger  .viz-stat-value { color: #B91C1C; }

/* =========================== Dashboard: collapsible detail panels =========================== */
.detail-collapse {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  margin-top: 14px;
  overflow: hidden;
}
.detail-collapse > .detail-collapse-summary {
  list-style: none;
  cursor: pointer;
  padding: 14px 18px;
  display: flex;
  align-items: center;
  gap: 10px;
  user-select: none;
}
.detail-collapse > .detail-collapse-summary::-webkit-details-marker { display: none; }
.detail-collapse-chevron {
  display: inline-block;
  transition: transform .2s ease;
  color: var(--ink-500);
  font-size: 12px;
}
.detail-collapse[open] .detail-collapse-chevron { transform: rotate(90deg); }
.detail-collapse-title {
  font-weight: 700;
  color: var(--ink-900);
  font-size: 14px;
}
.detail-collapse-meta {
  font-size: 12px;
}
.detail-collapse > .panels {
  padding: 0 18px 18px;
}
.detail-collapse > .detail-collapse-summary:hover {
  background: var(--ink-50);
}

/* =========================== Critical-alert row highlight =========================== */
.alert.alert-critical {
  background: #FEE2E2;
  border-left: 3px solid #EF4444;
  padding-left: 9px;
}
.alert.alert-critical .alert-type   { color: #7F1D1D; font-weight: 700; }
.alert.alert-critical .alert-meta   { color: #991B1B; }
.alert.alert-critical .alert-sev    { color: #B91C1C; font-weight: 700; }
.alert.alert-critical:hover         { background: #FECACA; }
.alert.alert-critical.alert-cleared { opacity: .55; }

/* =========================== Dashboard analytics charts =========================== */
.dash-charts {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
  margin: 0 0 14px;
}
.dash-charts-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
}
@media (max-width: 1100px) { .dash-charts-row { grid-template-columns: 1fr; } }

.dash-chart-card {
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 18px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.dash-chart-head {
  display: flex; align-items: center; justify-content: space-between;
}
.dash-chart-title {
  margin: 0;
  font-size: 13px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-700);
}
.dash-chart-canvas-wrap {
  position: relative;
  height: 220px;
}
.dash-chart-canvas-wrap canvas { width: 100% !important; height: 100% !important; }

.range-chips {
  display: inline-flex; gap: 4px;
  background: var(--ink-100);
  border-radius: 8px;
  padding: 2px;
}
.range-chips button {
  background: transparent; border: 0;
  padding: 4px 10px; border-radius: 6px;
  font: 600 11px -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  color: var(--ink-500); cursor: pointer;
}
.range-chips button.active {
  background: var(--card-bg);
  color: var(--ink-900);
  box-shadow: 0 1px 2px rgba(15,23,42,.12);
}

/* ── AI device briefing (Home) ────────────────────────────────────────────
   Two columns between the KPI tiles and the map grid: intraday (left) + daily
   (right). Reuses the existing card tokens; the slim indigo rail is the one
   quiet "AI" signal. Columns stack on narrow viewports. */
.ai-brief-cols {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 6px;
}
.ai-brief-cols .ai-brief { margin-bottom: 0; height: 100%; }
@media (max-width: 900px) {
  .ai-brief-cols { grid-template-columns: 1fr; }
}
.ai-brief-more { margin: 0 0 14px; font-size: 12px; text-align: right; }
.ai-brief-more a { color: var(--indigo-700); font-weight: 600; text-decoration: none; }
.ai-brief-more a:hover { text-decoration: underline; }
.ai-brief {
  display: flex;
  background: var(--card-bg);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
  margin-bottom: 14px;
}
.ai-brief-rail {
  flex: 0 0 4px;
  background: linear-gradient(180deg, var(--indigo-500), var(--indigo-700));
}
.ai-brief-main { flex: 1 1 auto; min-width: 0; padding: 14px 18px 16px; }
.ai-brief-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.ai-brief-titlewrap { display: flex; align-items: center; gap: 8px; }
.ai-brief-title {
  margin: 0; font-size: 12px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--indigo-700);
}
.ai-brief-time { font-size: 11px; white-space: nowrap; }
.ai-brief-stale {
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em;
  color: #8A5A06; background: #FEF3C7; border: 1px solid #FDE68A;
  border-radius: 999px; padding: 1px 7px;
}
.ai-brief-text {
  margin: 10px 0 12px; font-size: 13px; line-height: 1.6;
  color: var(--ink-700);
}
.ai-brief-empty { margin: 8px 0 2px; font-size: 13px; }
.ai-brief-chips {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 8px;
}
.ai-brief-chips .ai-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--ink-700);
  background: var(--ink-50); border: 1px solid var(--ink-100);
  border-radius: 999px; padding: 4px 10px;
}
.ai-brief-chips .ai-chip b { color: var(--ink-900); font-weight: 700; }
.ai-brief-chips .ai-chip-muted {
  color: var(--ink-500); background: transparent; border-color: transparent;
}
.ai-brief-chips .ai-chip-attention {
  background: rgba(245,158,11,.12); border-color: rgba(245,158,11,.35); color: #92400E;
}
.ai-brief-chips .ai-chip-attention b { color: #92400E; }
/* Home card shows the executive summary only; this opens the full report. */
.ai-brief-link { margin: 10px 0 0; font-size: 12px; }
.ai-brief-link a { color: var(--indigo-700); font-weight: 600; text-decoration: none; }
.ai-brief-link a:hover { text-decoration: underline; }
