/* ============================================================
   Solion BMS Web GUI — light theme
   Web replica of the .NET desktop GUI (LiveView) look.
   Pure CSS, no external fonts/libs (for offline AP).
   ============================================================ */

:root {
  /* Nav / accent — .NET indigo nav bar */
  --nav-bg:        #3949ab;       /* indigo 600 */
  --nav-bg-2:      #3f51b5;
  --nav-active:    #ffffff;
  --nav-idle:      #c5cae9;

  /* Background / cards — light theme */
  --bg:            #f4f5f9;
  --card-bg:       #ffffff;
  --card-border:   #e3e6ef;
  --topbar-bg:     #ffffff;

  /* Text */
  --text:          #1f2330;
  --text-dim:      #5b6172;
  --label:         #5b6172;
  --value:         #1f2330;

  /* Status colors (identical to .NET) */
  --ok:            #43a047;       /* green */
  --warn:          #fb8c00;       /* orange — UI hints (dirty rows, toasts) */
  --alarm:         #fdd835;       /* yellow — pack alarm indicators */
  --error:         #e53935;       /* red */
  --charge:        #43a047;
  --discharge:     #e53935;
  --bar-empty:     #e0e0e0;

  --soc-fill:      #3949ab;
  --soc-track:     #e3e6ef;

  --shadow:        0 1px 3px rgba(20, 25, 50, 0.08), 0 1px 2px rgba(20, 25, 50, 0.04);
  --radius:        12px;
  --gap:           12px;

  --font: -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 14px;
  -webkit-font-smoothing: antialiased;
}

/* ---------------- Top status bar ---------------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  height: 44px;
  padding: 0 16px;
  background: var(--topbar-bg);
  border-bottom: 1px solid var(--card-border);
}
.topbar__brand { display: flex; align-items: center; gap: 8px; font-weight: 700; }
.topbar__logo  { display: inline-flex; align-items: center; }
/* Brand marks are inline SVG with baked-in brand colours: they must NOT follow
   the theme the way the old glyph did. Height-driven, width auto, so the
   aspect ratio comes from the viewBox and never needs maintaining here. */
.brandmark { height: 20px; width: auto; display: block; }
.topbar__title { font-size: 15px; letter-spacing: .2px; }
.topbar__status { display: flex; align-items: center; gap: 10px; color: var(--text-dim); font-size: 13px; }
.topbar__sep   { width: 1px; height: 18px; background: var(--card-border); }
.topbar__clock { font-variant-numeric: tabular-nums; }

.conn-dot {
  width: 10px; height: 10px; border-radius: 50%;
  display: inline-block; box-shadow: 0 0 0 3px rgba(0,0,0,.04);
}
.conn-dot--on   { background: var(--ok); }
.conn-dot--off  { background: var(--error); }

/* Boot config-health banner (app.js) — global strip above every screen when a
   persisted source failed to load. Red = critical (FETs held off); amber = soft. */
.cfg-health {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; font-size: 14px; font-weight: 600; color: #fff;
}
.cfg-health--err  { background: var(--error); }
.cfg-health--warn { background: var(--warn); color: #1a1a1a; }
.cfg-health__btn {
  margin-left: auto; padding: 6px 12px; border: 1px solid rgba(255, 255, 255, 0.7);
  border-radius: var(--radius); background: rgba(255, 255, 255, 0.18); color: #fff;
  font-weight: 700; cursor: pointer;
}
.cfg-health__btn:hover:not(:disabled) { background: rgba(255, 255, 255, 0.3); }
.cfg-health__btn:disabled { opacity: 0.6; cursor: default; }
.conn-text { min-width: 70px; }

/* Topbar action button — "Service login" on the viewer page, "Release control"
   on the service page. */
.topbar__btn {
  padding: 4px 10px; border: 1px solid var(--card-border); border-radius: var(--radius);
  background: transparent; color: var(--text-dim); font-size: 12px; font-weight: 600;
  cursor: pointer;
}
.topbar__btn:hover:not(:disabled) { background: var(--card-border); color: var(--text); }
.topbar__btn:disabled { opacity: 0.5; cursor: default; }

/* Phones: the brand + status row (dot, DEMO text, clock, button) is wider than
   375 px and would widen the whole page, so let the bar grow and wrap. */
@media (max-width: 520px) {
  .topbar { height: auto; min-height: 44px; padding: 6px 12px; flex-wrap: wrap; gap: 6px 12px; }
  .topbar__status { flex-wrap: wrap; gap: 6px 8px; min-width: 0; }
  .conn-text { min-width: 0; }
}

/* Session strip (app.js) — shown when the service session is lost or refused.
   Same geometry as the config-health banner so they stack cleanly. */
.op-banner {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 10px 16px; font-size: 14px; font-weight: 600;
  background: var(--warn); color: #1a1a1a;
}
/* A banner that can carry more than one independent warning at a time (the
   Configuration screen learns two scales from two registers, either of which
   can fail on its own). Each line keeps the single-warning layout. */
.op-banner--stack { flex-direction: column; align-items: stretch; gap: 8px; }
.op-banner__line { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }

/* ---------------- Navigation ---------------- */
.navbar {
  display: flex;
  align-items: stretch;
  background: linear-gradient(180deg, var(--nav-bg-2), var(--nav-bg));
  padding: 0 8px;
  overflow-x: auto;
}
.nav__item {
  display: flex; align-items: center; justify-content: center;
  padding: 0 22px; height: 46px;
  color: var(--nav-idle);
  text-decoration: none;
  font-size: 14px; font-weight: 600;
  border-bottom: 3px solid transparent;
  white-space: nowrap;
  transition: color .12s ease, border-color .12s ease;
}
.nav__item:hover { color: #e8eaf6; }
.nav__item.is-active { color: var(--nav-active); border-bottom-color: var(--nav-active); }

/* ---------------- Content area ---------------- */
.app { padding: var(--gap); max-width: 1680px; margin: 0 auto; }

/* Two-level nav: group tabs (in .navbar) + a vertical sub-nav sidebar per group. */
.shell { display: flex; gap: 14px; align-items: flex-start; }
.subnav {
  flex: 0 0 auto; width: 180px;
  background: var(--card-bg); border: 1px solid var(--card-border); border-radius: var(--radius);
  padding: 8px; display: flex; flex-direction: column; gap: 3px;
}
.subnav__item {
  display: block; padding: 9px 12px; border-radius: 8px; text-decoration: none;
  color: var(--text); font-size: 13px; font-weight: 600;
}
.subnav__item:hover { background: #f0f2f8; }
.subnav__item.is-active { background: #e8eaf6; color: var(--nav-bg); }
.screen-content { flex: 1 1 auto; min-width: 0; }
@media (max-width: 760px) {
  .shell { flex-direction: column; gap: 8px; }
  /* align-self: stretch — under the column shell's align-items: flex-start
     the bar sized to its content (12 wizard items ≈ 1500 px) and widened the
     whole page instead of scrolling sideways */
  .subnav { width: auto; align-self: stretch; min-width: 0; flex-direction: row; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .subnav__item { flex: 0 0 auto; white-space: nowrap; }
}

/* ---------------- Form controls (standard look across the app) ----------------
   Base style for every input/select/textarea, matching the Data Memory fields.
   More specific rules (.dm-val input, .dm-search…) still win where needed. */
input, select, textarea {
  font: inherit; font-size: 13px; color: var(--value);
  border: 1px solid var(--card-border); border-radius: 7px;
  padding: 6px 9px; background: #fff; box-sizing: border-box;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--nav-bg); box-shadow: 0 0 0 3px rgba(57, 73, 171, .12);
}
input[readonly], input:disabled, select:disabled, textarea[readonly], textarea:disabled {
  background: var(--bg); color: var(--text-dim); cursor: not-allowed;
}
input[type="file"] { border: none; padding: 0; }

/* ---------------- Cards ---------------- */
.card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 14px 16px;
}

/* LiveView top row: 3 cards */
.live-top {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--gap);
  margin-bottom: var(--gap);
}
@media (max-width: 1200px) { .live-top { grid-template-columns: 1fr 1fr; } }
@media (max-width: 640px)  { .live-top { grid-template-columns: 1fr; } }

/* Metric row (label left, value right) */
.metric {
  display: flex; align-items: baseline; justify-content: space-between;
  padding: 7px 0;
}
.metric + .metric { border-top: 1px dashed var(--card-border); }
.metric__label { color: var(--label); font-weight: 600; }
.metric__value { color: var(--value); font-weight: 700; font-variant-numeric: tabular-nums; }
.metric__unit  { color: var(--text-dim); font-weight: 600; margin-left: 4px; font-size: .9em; }

/* State pill */
.statepill {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 16px; margin-bottom: 12px;
}
.statepill__icon {
  width: 26px; height: 26px; border-radius: 7px;
  display: grid; place-items: center; color: #fff; font-size: 15px;
  background: var(--text-dim);
}
.statepill__label b { font-weight: 800; }
.state--off      { background: #9aa0b4; }
.state--chg      { background: var(--charge); }
.state--dis      { background: #fb8c00; }
.state--normal   { background: var(--nav-bg); }
.state--shutdown { background: var(--error); }

/* SOC bar */
/* Extra top margin keeps the SOC bar clear of the state rows above it. */
.soc { margin: 18px 0 4px; }
.soc__track {
  height: 18px; border-radius: 8px; background: var(--soc-track); overflow: hidden;
}
.soc__fill {
  height: 100%; width: 0%; border-radius: 8px;
  background: var(--soc-fill); transition: width .25s ease;
}
.soc__row { display: flex; justify-content: space-between; align-items: baseline; margin-top: 6px; }
/* SOC label + value doubled and darkened (operator request, 2026-08-22). */
.soc__label { color: var(--text); font-weight: 800; font-size: 36px; }
.soc__value { font-weight: 800; font-size: 36px; font-variant-numeric: tabular-nums; color: var(--text); }
/* SOH / CYCLE rows in the FET card: half the hero SOC size, deliberately NOT
   dark (operator request, 2026-08-22). */
.metric--soft .metric__label { font-size: 14px; }
.metric--soft .metric__value { color: var(--text-dim); font-weight: 600; font-size: 18px; }
/* Breathing room between the FET chips and the SOH/CYCLE block below them. */
.fetpanel + .metric--soft { margin-top: 14px; }

.lastevent { margin-top: 14px; font-size: 14px; }
.lastevent b { font-weight: 800; }
.lastevent__txt { color: var(--text-dim); font-weight: 600; }

/* ---------------- Bottom: chart ---------------- */
.live-bottom { display: flex; flex-direction: column; gap: var(--gap); }
.chart-card { padding: 14px 16px; }
.chart-wrap { position: relative; height: 340px; }
#cellChart { width: 100%; height: 100%; display: block; }
.chart-title {
  writing-mode: vertical-rl; transform: rotate(180deg);
  position: absolute; left: -2px; top: 50%; translate: 0 -50%;
  color: var(--text-dim); font-size: 12px; font-weight: 600;
}

/* Horizontal (row) chart — one cell per row, applied by live.js below 768px.
   Height comes from the cell count, so the fixed 340px is released here and the
   axis title flips from the left edge to under the (now horizontal) V axis. */
.chart-wrap--rows { height: auto; }
.chart-wrap--rows #cellChart { height: auto; }
.chart-wrap--rows .chart-title {
  writing-mode: horizontal-tb; transform: none;
  left: 50%; top: auto; bottom: 0; translate: -50% 0;
}

/* ---------------- Current bar ---------------- */
.currentbar { padding: 8px 6px 14px; }
.currentbar__heads {
  display: flex; justify-content: space-between;
  font-weight: 800; color: var(--text); letter-spacing: .5px; margin-bottom: 6px;
}
.currentbar__track {
  display: grid; grid-template-columns: 1fr 12px 1fr; align-items: center; height: 34px;
}
.cbar { height: 34px; background: var(--bar-empty); position: relative; overflow: hidden; }
.cbar--dis { border-radius: 6px 0 0 6px; }
.cbar--chg { border-radius: 0 6px 6px 0; }
.cbar__fill { position: absolute; top: 0; bottom: 0; width: 0%; transition: width .2s ease; }
.cbar--dis .cbar__fill { right: 0; background: var(--discharge); }
.cbar--chg .cbar__fill { left: 0;  background: var(--charge); }
.currentbar__mid { background: #555; height: 100%; }
.currentbar__value {
  text-align: center; font-weight: 800; font-size: 20px; margin-top: 10px;
  font-variant-numeric: tabular-nums;
}

/* ---------------- Console screen ---------------- */
.con-top { display: grid; grid-template-columns: 1fr 1fr; gap: var(--gap); margin-bottom: var(--gap); }
@media (max-width: 800px) { .con-top { grid-template-columns: 1fr; } }
.con-actions__title { font-weight: 800; margin-bottom: 10px; }
.btn-row { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.btn {
  border: 1px solid var(--card-border); background: #fff; color: var(--text);
  border-radius: 8px; padding: 7px 14px; font-weight: 600; font-size: 13px; cursor: pointer;
  transition: background .12s ease, border-color .12s ease;
}
.btn:hover { background: #f0f2f8; }
.btn--primary { background: var(--nav-bg); color: #fff; border-color: var(--nav-bg); }
.btn--primary:hover { background: var(--nav-bg-2); }
.btn--danger { background: var(--error); color: #fff; border-color: var(--error); }
.btn--danger:hover { background: #c62828; border-color: #c62828; }
.btn:disabled { opacity: .55; cursor: default; }
.con-hint { color: var(--text-dim); font-size: 12px; margin-top: 8px; }

/* Data Memory ▸ Commands — guarded action panel */
.cmd-body { display: flex; flex-direction: column; gap: var(--gap); padding: 14px; max-width: 640px; }
.cmd-pin { display: flex; align-items: center; gap: 10px; }
.cmd-pin label { color: var(--label); font-size: 13px; font-weight: 600; }
.cmd-pin input {
  border: 1px solid var(--card-border); border-radius: 8px; padding: 7px 10px;
  font-size: 14px; width: 120px; letter-spacing: 2px;
}
.cmd-card {
  background: var(--card-bg); border: 1px solid var(--card-border);
  border-radius: var(--radius); padding: 14px 16px; box-shadow: var(--shadow);
}
.cmd-card--danger { border-color: #f2b8b5; }
.cmd-card__title { font-weight: 800; font-size: 15px; margin-bottom: 4px; }
.cmd-card--danger .cmd-card__title { color: var(--error); }
.cmd-card__desc { color: var(--text-dim); font-size: 13px; line-height: 1.45; margin-bottom: 12px; }
.cmd-status { min-height: 18px; font-size: 13px; font-weight: 600; color: var(--text-dim); }
.cmd-status--ok  { color: var(--ok); }
.cmd-status--err { color: var(--error); }

.con-monitor { display: flex; flex-direction: column; padding: 12px 14px; }
.con-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 8px; }
.con-bar__lbl { font-weight: 800; }
.con-filters { display: flex; gap: 10px; flex-wrap: wrap; }
.chip { font-size: 12px; color: var(--text-dim); font-weight: 600; display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.con-search {
  margin-left: auto; border: 1px solid var(--card-border); border-radius: 8px;
  padding: 6px 10px; font-size: 13px; min-width: 160px;
}
.con-log {
  height: 56vh; overflow-y: auto; background: #0f1320; color: #d7dbe8;
  border-radius: 8px; padding: 8px; font-family: "Cascadia Code", Consolas, monospace;
  font-size: 12px; line-height: 1.5;
}
.con-row { display: flex; gap: 10px; white-space: nowrap; border-bottom: 1px solid #1b2030; padding: 1px 0; }
.con-c--t  { color: #7c89a8; flex: 0 0 96px; }
.con-c--d  { color: #9aa6c4; flex: 0 0 28px; }
.con-c--ty { flex: 0 0 78px; font-weight: 700; }
.con-c--data { color: #d7dbe8; white-space: pre-wrap; word-break: break-all; flex: 1; }
.con-row--report   .con-c--ty { color: #6cc8ff; }
.con-row--response .con-c--ty { color: #66d9a0; }
.con-row--senddata .con-c--ty { color: #ffd166; }
.con-row--event    .con-c--ty { color: #c792ea; }
.con-row--other    .con-c--ty { color: #9aa6c4; }
.con-row--log      .con-c--ty { color: #8fb0d8; }
.con-row--logwrn   .con-c--data { color: #ffd166; }
.con-row--logerr   .con-c--data { color: #ff6b6b; }

/* ---------------- Events screen ---------------- */
/* Single column since the Pack Status card was dropped (operator request,
   2026-08-22) — the event table takes the full width. */
.ev-grid { display: grid; grid-template-columns: 1fr; gap: var(--gap); }
/* Matches the 26px Events group tabs above (operator request, 2026-08-22). */
.ev-title { font-weight: 800; margin-bottom: 10px; font-size: 26px; }
.ev-table-card { padding: 14px 16px; }

.ev-thead, .ev-row {
  display: grid; grid-template-columns: 110px 80px 1fr; align-items: center;
}
.ev-thead {
  font-weight: 700; color: var(--text-dim); font-size: 13px;
  padding: 6px 8px; border-bottom: 1px solid var(--card-border);
}
.ev-log { max-height: 62vh; overflow-y: auto; }
.ev-row {
  padding: 7px 8px; border-bottom: 1px solid var(--card-border);
  border-left: 3px solid transparent; font-variant-numeric: tabular-nums;
}
.ev-row--error { border-left-color: var(--error); }
.ev-row--warn  { border-left-color: var(--alarm); }
.ev-c-t { color: var(--text-dim); }
.ev-c-c { font-weight: 700; }
.ev-c-n { font-weight: 600; }
.ev-empty { color: var(--text-dim); padding: 16px 8px; }

/* ---------------- Placeholder screens ---------------- */
.placeholder {
  display: grid; place-items: center; min-height: 60vh; color: var(--text-dim);
  text-align: center;
}
.placeholder h2 { color: var(--text); margin-bottom: 6px; font-weight: 800; }
.placeholder .soon {
  margin-top: 10px; display: inline-block; padding: 4px 12px; border-radius: 999px;
  background: #eef0f7; color: var(--nav-bg); font-weight: 700; font-size: 12px;
}

/* ---------------- Settings ▸ Data Memory ---------------- */
:root { --row-pad: 9px; }   /* spacious row height */

.dm-cats { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: var(--gap); }
.dm-cat {
  padding: 8px 16px; border-radius: 8px 8px 0 0; font-weight: 600; font-size: 13px;
  color: var(--text-dim); background: transparent; border: 1px solid transparent; cursor: pointer;
}
.dm-cat:hover { background: #eceef6; }
.dm-cat.is-active {
  color: var(--nav-bg); background: var(--card-bg); border-color: var(--card-border);
  border-bottom-color: var(--card-bg); box-shadow: var(--shadow);
}
.dm-cat.is-soon { opacity: .45; cursor: not-allowed; }
.soonbadge {
  font-size: 9px; font-weight: 800; background: #eef0f7; color: var(--nav-bg);
  border-radius: 999px; padding: 1px 6px; margin-left: 6px; vertical-align: middle;
}

.dm-head {
  display: flex; align-items: center; gap: 12px; background: var(--card-bg);
  border: 1px solid var(--card-border); border-radius: var(--radius) var(--radius) 0 0;
  box-shadow: var(--shadow); padding: 12px 16px;
}
.dm-head__title { font-weight: 800; font-size: 16px; }
.dm-head__sub { color: var(--text-dim); font-size: 12px; }
.dm-tools { margin-left: auto; display: flex; gap: 8px; align-items: center; }
.dm-search {
  border: 1px solid var(--card-border); border-radius: 8px; padding: 7px 10px;
  font-size: 13px; min-width: 170px;
}

.dm-body {
  display: grid; grid-template-columns: 230px 1fr; background: var(--card-bg);
  border: 1px solid var(--card-border); border-top: none;
  border-radius: 0 0 var(--radius) var(--radius); box-shadow: var(--shadow); min-height: 62vh;
}
.dm-groups { border-right: 1px solid var(--card-border); padding: 8px; }
.dm-group {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 12px; border-radius: 8px; font-size: 13px; font-weight: 600;
  color: var(--text); cursor: pointer;
}
.dm-group:hover { background: #f0f2f8; }
.dm-group.is-active { background: #e8eaf6; color: var(--nav-bg); }
.dm-group.is-soon { opacity: .5; cursor: not-allowed; font-weight: 500; }
.dm-group__count {
  font-size: 11px; color: var(--text-dim); font-weight: 700;
  background: #eef0f7; border-radius: 999px; padding: 1px 7px;
}

/* Battery Profile — brand list rows. Block layout that wraps (NOT the flex,
 * mobile-nowrap .dm-group), so "Ah/cell" never overflows the card. */
.pf-row {
  display: block; padding: 9px 11px; margin-bottom: 6px;
  border-radius: 8px; border: 1px solid transparent; cursor: pointer;
}
.pf-row:hover { background: #f0f2f8; }
.pf-row.is-active { background: #e8eaf6; border-color: #c5cae9; }
.pf-row__title { font-weight: 600; color: var(--text); word-break: break-word; }
.pf-row__sub {
  font-size: 12px; color: var(--text-dim); margin-top: 2px;
  line-height: 1.35; word-break: break-word;
}

/* Battery Profile — Add-brand modal (overlay, so it is not visually attached to
 * the chemistry-filtered list underneath it). */
.pf-modal-backdrop {
  position: fixed; inset: 0; z-index: 1000;
  background: rgba(20, 25, 50, 0.45);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 24px 12px; overflow: auto;
}
.pf-modal {
  background: var(--card-bg); border: 1px solid var(--card-border);
  border-radius: var(--radius); box-shadow: var(--shadow);
  width: 100%; max-width: 640px; padding: 18px 20px; margin: auto;
}
.pf-modal__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.pf-modal__x {
  cursor: pointer; font-size: 22px; line-height: 1; padding: 0 4px;
  color: var(--text-dim); background: none; border: none;
}
.pf-modal__x:hover { color: var(--text); }

/* Battery Profile — read-only detail key/value list (width-capped so values do
 * not stretch to the far edge on wide screens). */
.pf-info { max-width: 460px; margin-top: 10px; }
.pf-kv {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 16px; padding: 7px 0; border-bottom: 1px dashed var(--card-border);
}
.pf-kv > span:first-child { color: var(--label); font-size: 13px; }
.pf-kv > span:last-child { color: var(--value); white-space: nowrap; }
.pf-modal .pf-sect {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-dim); margin: 12px 0 6px; border-top: 1px solid var(--card-border); padding-top: 10px;
}
.pf-modal label { font-size: 12px; color: var(--label); }
.pf-modal input, .pf-modal select { }

.dm-content { overflow: auto; }
.dm-thead, .dm-row {
  display: grid; grid-template-columns: minmax(220px, 2fr) 150px 70px 120px; align-items: center;
}
.dm-row { grid-template-areas: "name val unit addr"; padding: var(--row-pad) 16px; border-bottom: 1px solid #eef0f5; }
.dm-thead {
  position: sticky; top: 0; background: #fafbfe; border-bottom: 1px solid var(--card-border);
  font-size: 12px; font-weight: 700; color: var(--text-dim); padding: 10px 16px; z-index: 1;
}
.dm-row:hover { background: #fafbff; }
.dm-row.is-dirty { background: #fff8ec; }
.dm-name { grid-area: name; font-weight: 600; }
.dm-name small { display: block; color: var(--text-dim); font-weight: 500; font-size: 11px; }
.dm-val { grid-area: val; display: flex; align-items: center; gap: 7px; }
.dm-val input {
  width: 120px; border: 1px solid var(--card-border); border-radius: 7px; padding: 6px 9px;
  font-size: 13px; font-variant-numeric: tabular-nums; text-align: right; background: #fff; color: var(--value);
}
.dm-val input:focus { outline: none; border-color: var(--nav-bg); box-shadow: 0 0 0 3px rgba(57,73,171,.12); }
.dm-row.is-dirty .dm-val input { border-color: var(--warn); }
/* Auto-derived, read-only field (e.g. Capacity Gain follows CC Gain). */
.dm-val input[readonly] { background: #f4f4f6; color: var(--text-dim); cursor: not-allowed; }
.dm-val input[readonly]:focus { box-shadow: none; border-color: var(--card-border); }
.dm-dirtydot { width: 8px; height: 8px; border-radius: 50%; background: var(--warn); visibility: hidden; }
.dm-row.is-dirty .dm-dirtydot { visibility: visible; }
.dm-unit { grid-area: unit; color: var(--text-dim); font-weight: 600; }
.dm-addr { grid-area: addr; color: #9098ad; font-variant-numeric: tabular-nums; font-size: 12px; }

/* ---- Configuration screen (config.js): physical-first, adds a Raw column.
   Scoped under .cfg so the old Data Memory grid (4 cols) is untouched. ---- */
.cfg .dm-thead, .cfg .dm-row {
  grid-template-columns: minmax(200px, 2fr) 130px 78px 72px 110px;
}
.cfg .dm-row { grid-template-areas: "name val raw unit addr"; }
.cfg-raw {
  grid-area: raw; text-align: right; padding-right: 7px;
  font-variant-numeric: tabular-nums; font-size: 13px; color: var(--value); font-weight: 600;
}
.cfg-raw.is-plain { color: #9098ad; font-weight: 500; }  /* no conversion: raw == value */
.dm-row.is-dirty .cfg-raw { color: var(--warn); }
.cfg .dm-val select {
  width: 120px; border: 1px solid var(--card-border); border-radius: 7px; padding: 6px 9px;
  font-size: 13px; font-variant-numeric: tabular-nums; text-align: right; background: #fff; color: var(--value);
}
.cfg .dm-val select:focus { outline: none; border-color: var(--nav-bg); box-shadow: 0 0 0 3px rgba(57,73,171,.12); }
/* brief highlight when a typed value is snapped to the achievable value on blur */
.cfg-snapped { animation: cfg-snap 0.7s ease; }
@keyframes cfg-snap { 0%,40% { background: #fff7e0; } 100% { background: #fff; } }

/* ---- bitfield inline editor (config.js): checkboxes/selects compose a hex reg ---- */
.dm-bittoggle {
  flex: none; border: 1px solid var(--card-border); border-radius: 6px; background: #fff;
  color: var(--nav-bg); font-size: 12px; line-height: 1; padding: 5px 7px; cursor: pointer;
}
.dm-bittoggle:hover { background: #f2f4ff; border-color: var(--nav-bg); }
.dm-bittoggle.is-open { background: var(--nav-bg); color: #fff; border-color: var(--nav-bg); }
.dm-bitpanel {
  margin: -1px 16px 8px; padding: 12px 16px 10px;
  background: #f7f8fc; border: 1px solid var(--card-border); border-top: none;
  border-radius: 0 0 10px 10px;
}
.dm-bitpanel__grid { display: flex; flex-wrap: wrap; gap: 9px 22px; }
.dm-bitfield {
  display: flex; align-items: center; gap: 6px; font-size: 13px; color: var(--text);
  min-width: 190px; cursor: pointer;
}
.dm-bitfield--ro { color: var(--text-dim); cursor: default; }
.dm-bitfield input[type="checkbox"] { width: auto; margin: 0; }
.dm-bitfield select, .dm-bitfield input[type="number"] {
  font-size: 12px; padding: 3px 6px; border-radius: 6px; border: 1px solid var(--card-border);
  text-align: left; width: auto;
}
.dm-bitno { color: var(--text-dim); font-size: 11px; font-weight: 600; }
.dm-bitpanel__foot {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--card-border);
}
.dm-bitprev { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--value); font-size: 13px; }

.dm-footer {
  display: flex; align-items: center; gap: 12px; padding: 10px 16px;
  border-top: 1px solid var(--card-border); color: var(--text-dim); font-size: 12px;
}
.dm-footer .spacer { margin-left: auto; }
.dm-status { font-weight: 600; }
.dm-status--ok   { color: var(--ok); }
.dm-status--warn { color: var(--warn); }
.dm-status--err  { color: var(--error); }

/* Top strip status indicator (next to the buttons) */
.dm-status-top { font-weight: 600; font-size: 13px; color: var(--text-dim); margin-right: 4px; white-space: nowrap; }

/* Non-blocking toast notification */
.toast {
  position: fixed; bottom: 18px; left: 50%; transform: translateX(-50%);
  background: #1f2330; color: #fff; padding: 10px 18px; border-radius: 10px;
  font-size: 13px; font-weight: 600; box-shadow: var(--shadow);
  opacity: 0; pointer-events: none; transition: opacity .2s ease; z-index: 1000;
}
.toast.show     { opacity: 1; }
.toast--ok      { background: var(--ok); }
.toast--warn    { background: var(--warn); }
.toast--err     { background: var(--error); }

/* Register description popup (BQ Studio-style) */
.dm-info { cursor: pointer; color: var(--nav-bg); font-weight: 700; margin-left: 5px; user-select: none; }
.dm-info:hover { color: var(--nav-bg-2); }
.dm-popup {
  display: none; position: fixed; z-index: 1100; min-width: 260px; max-width: 430px;
  max-height: 70vh; overflow: auto; background: var(--card-bg);
  border: 1px solid var(--card-border); border-radius: 10px;
  box-shadow: 0 6px 24px rgba(20, 25, 50, .18); font-size: 13px; color: var(--text);
}
.dm-popup__head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 12px; border-bottom: 1px solid var(--card-border); font-weight: 700;
}
.dm-popup__x { cursor: pointer; color: var(--text-dim); font-size: 16px; line-height: 1; }
.dm-popup__x:hover { color: var(--error); }
.dm-popup__body { padding: 10px 12px; line-height: 1.5; color: var(--text-dim); white-space: pre-wrap; }
.dm-popup__tbl { width: calc(100% - 24px); margin: 0 12px 12px; border-collapse: collapse; font-size: 12px; }
.dm-popup__tbl th, .dm-popup__tbl td { border: 1px solid var(--card-border); padding: 4px 8px; text-align: left; }
.dm-popup__tbl th { background: #f0f2f8; font-weight: 700; }
.dm-popup__tbl td:first-child { font-variant-numeric: tabular-nums; white-space: nowrap; color: var(--text); }
/* Bitfield register: one section per bit (header + body + its own table). */
.dm-popup__bit { padding: 10px 12px 2px; border-top: 1px solid var(--card-border); }
.dm-popup__bitname { font-weight: 700; color: var(--text); margin-bottom: 4px; }
.dm-popup__bitno { font-weight: 600; color: var(--text-dim); font-size: 12px; }
.dm-popup__bit .dm-popup__body { padding: 0 0 8px; }
.dm-popup__bit .dm-popup__tbl { width: 100%; margin: 0 0 10px; }

/* ---- mobile: single column, groups as a horizontal strip, row wraps to 2 lines ---- */
@media (max-width: 760px) {
  .dm-head { flex-wrap: wrap; border-radius: var(--radius); }
  .dm-tools { margin-left: 0; width: 100%; flex-wrap: wrap; }
  .dm-search { flex: 1 1 100%; min-width: 0; }
  .dm-tools .btn { flex: 1 1 auto; justify-content: center; }
  .dm-body { grid-template-columns: 1fr; min-height: 0; align-content: start; border-radius: var(--radius); margin-top: 8px; }
  .dm-groups {
    border-right: none; border-bottom: 1px solid var(--card-border);
    display: flex; align-items: center; gap: 6px; overflow-x: auto; -webkit-overflow-scrolling: touch;
  }
  .dm-group { flex: 0 0 auto; white-space: nowrap; border: 1px solid var(--card-border); }
  .dm-group.is-active { border-color: #c5cae9; }
  .dm-thead { display: none; }
  .dm-row { grid-template-columns: 1fr auto; grid-template-areas: "name val" "addr unit"; row-gap: 4px; column-gap: 10px; padding: 11px 14px; }
  .dm-val { justify-content: flex-end; }
  .dm-addr, .dm-unit { align-self: center; }
  .dm-unit { text-align: right; }
}

/* ── FET / status indicator chips (Live View panel + Diagnostics) ── */
.fetchip, .diagchip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px; border-radius: 999px; font-size: 12px; font-weight: 500;
  border: 1px solid var(--card-border); background: #fff; color: var(--text-dim);
  white-space: nowrap;
}
.fetchip__dot, .diagchip__dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--bar-empty); flex: none;
}
/* Softened text (translucent white, no bold) so the coloured chips read calmer. */
.fetchip--on, .diagchip--on { color: rgba(255,255,255,.92); background: var(--ok); border-color: var(--ok); }
.fetchip--on .fetchip__dot, .diagchip--on .diagchip__dot { background: #fff; }
.diagchip--fault { color: rgba(255,255,255,.92); background: var(--error); border-color: var(--error); }
.diagchip--fault .diagchip__dot { background: #fff; }
.diagchip--warn { color: rgba(255,255,255,.92); background: var(--warn); border-color: var(--warn); }
.diagchip--warn .diagchip__dot { background: #fff; }
.fetchip--off, .diagchip--off { opacity: .6; }

/* ── Live View device-state badges (ChargeState / Error / Alarm) ── */
/* Rendered as labelled metric rows; the badge is the right-hand value. Let it
   shrink so a long reason ellipsizes within the narrow column (full text on hover). */
.metric--state { align-items: center; }
.metric--state .lv-badge { min-width: 0; }
.metric--state .lv-badge__txt { overflow: hidden; text-overflow: ellipsis; }
/* Alarm State value = separate code chips, right-aligned, wrapping to the next line. */
.lv-codes { display: inline-flex; flex-wrap: wrap; gap: 4px; justify-content: flex-end; min-width: 0; }
.lv-codes .lv-badge { padding: 3px 7px; }
.lv-badge {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px; border-radius: 999px; font-size: 12px; font-weight: 500;
  border: 1px solid var(--card-border); background: #fff; color: var(--text-dim);
  white-space: nowrap;
}
/* Softened text (slightly translucent white / no bold) so the saturated pills
   read calmer; the ChargeState arrow already conveys direction, so no dot. */
.lv-badge--idle { opacity: .75; }
.lv-badge--charge    { color: rgba(255,255,255,.92); background: var(--charge);    border-color: var(--charge); }
.lv-badge--discharge { color: rgba(255,255,255,.92); background: var(--discharge); border-color: var(--discharge); }
.lv-badge--ok        { color: rgba(255,255,255,.92); background: var(--ok);        border-color: var(--ok); }
.lv-badge--error     { color: rgba(255,255,255,.92); background: var(--error);     border-color: var(--error); }
/* --alarm (#fdd835) is a light yellow: use dark text for contrast, not white. */
.lv-badge--alarm     { color: var(--value); background: var(--alarm); border-color: var(--alarm); }

/* ── Live View FET panel ─────────────────────────────────────── */
.fetpanel { margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--card-border); }
/* When the FET panel is the card's own content (its 4th top-row column), drop
   the divider that only made sense when it sat under the voltage metrics. */
.card > .fetpanel:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.fetpanel__head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 8px; }
.fetpanel__title { color: var(--label); font-weight: 600; }
.fetpanel__raw {
  color: var(--text-dim); font-size: 12px; font-variant-numeric: tabular-nums;
  font-family: "Cascadia Code", Consolas, monospace;
}
.fetpanel__row { display: flex; flex-wrap: wrap; gap: 6px; }
.fetpanel__row + .fetpanel__row { margin-top: 6px; }
.fetpanel__row--pins .fetchip { font-weight: 600; }
/* Every FET-panel chip shares the COOLING chip's footprint (the widest label)
   so both rows read as equal-sized pills (operator request, 2026-08-22). */
.fetpanel .fetchip { min-width: 86px; justify-content: center; box-sizing: border-box; }

/* ── Diagnostics screen ──────────────────────────────────────── */
.diag-intro {
  color: var(--text-dim); font-size: 13px; line-height: 1.5;
  margin-bottom: var(--gap); max-width: 900px;
}
.diag-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: var(--gap); }
.diag-card { padding: 14px 16px; }
.diag-card__head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 4px; }
.diag-card__title { font-weight: 700; color: var(--value); }
.diag-card__cmd {
  color: var(--text-dim); font-size: 12px;
  font-family: "Cascadia Code", Consolas, monospace;
}
.diag-card__raw {
  margin-left: auto; font-weight: 700; color: var(--value); font-variant-numeric: tabular-nums;
  font-family: "Cascadia Code", Consolas, monospace;
}
.diag-card__note { color: var(--text-dim); font-size: 12px; margin-bottom: 10px; }
.diag-chips { display: flex; flex-wrap: wrap; gap: 6px; }

/* ── Events screen: bqStudio-style bit register grid ─────────── */
.bq-toolbar {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: var(--gap);
}
.bq-tb__spacer { flex: 1 1 auto; }
.bq-tb__check {
  display: inline-flex; align-items: center; gap: 6px;
  color: var(--text-dim); font-size: 13px; cursor: pointer;
}
.bq-tb__msg { font-size: 12px; color: var(--text-dim); }
.bq-tb__msg--ok  { color: var(--ok); }
.bq-tb__msg--err { color: var(--error); }
.bq-seg { display: inline-flex; border: 1px solid var(--card-border); border-radius: 8px; overflow: hidden; }
.bq-seg__btn {
  border: 0; background: var(--card-bg); color: var(--text-dim);
  padding: 5px 14px; font: inherit; font-size: 13px; cursor: pointer;
}
.bq-seg__btn + .bq-seg__btn { border-left: 1px solid var(--card-border); }
.bq-seg__btn.is-active { background: var(--nav-bg); color: #fff; font-weight: 600; }
.bq-legend { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.bq-lg {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 3px 9px; border-radius: 4px; font-size: 11px; font-weight: 600;
  border: 1px solid var(--card-border);
}

/* Tab badge: how many "something is wrong" bits the group holds. The strip
   itself reuses .dm-cats / .dm-cat from Settings ▸ Data Memory unchanged. */
/* Events group tabs doubled (operator request, 2026-08-22) — scoped to the
   Events strip so Data Memory / Configuration keep the 13px tabs. */
#bq-cats .dm-cat { font-size: 26px; }
.bq-cat__badge {
  display: inline-block; min-width: 18px; margin-left: 7px;
  padding: 1px 6px; border-radius: 999px;
  font-size: 10px; font-weight: 800; line-height: 1.5; text-align: center;
  font-variant-numeric: tabular-nums; vertical-align: middle;
  color: rgba(255,255,255,.94);
}
.bq-cat__badge.is-empty { display: none; }
.bq-cat__badge--fault  { background: var(--error); }
.bq-cat__badge--warn   { background: var(--warn); }
.bq-cat__badge--custom { background: var(--nav-bg); }

.bq-card { padding: 14px 16px; margin-bottom: var(--gap); }
.bq-card__head {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  font-weight: 800; margin-bottom: 10px;
}
.bq-card__hint { font-weight: 400; font-size: 12px; color: var(--text-dim); }
.bq-badge {
  font-weight: 600; font-size: 11px; padding: 2px 8px; border-radius: 999px;
  background: var(--nav-bg); color: rgba(255,255,255,.94);
}
.bq-note { color: var(--text-dim); font-size: 12px; margin-top: 10px; }
/* Firmware inferences must never be mistaken for silicon bits. */
.bq-card--custom { border-left: 3px dashed var(--nav-bg); }

.bq-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
/* Every row carries the same explicit template (like .ev-thead / .ev-row) so
   the columns line up without needing `subgrid`, which is too new to rely on
   for a device-served page. */
.bq-grid { min-width: 1120px; }
.bq-hrow, .bq-row {
  display: grid;
  grid-template-columns: 176px 58px 62px repeat(16, minmax(52px, 1fr));
}
.bq-h {
  position: sticky; top: 0; z-index: 1; background: var(--card-bg);
  font-size: 11px; font-weight: 700; color: var(--text-dim);
  padding: 6px 4px; text-align: center;
  border-bottom: 1px solid var(--card-border);
}
.bq-h--name, .bq-h--cmd, .bq-h--val { text-align: left; }
.bq-name, .bq-cmd, .bq-val {
  display: flex; align-items: center; padding: 0 6px 0 0; font-size: 12px;
}
.bq-name { font-weight: 600; color: var(--value); }
.bq-cmd, .bq-val { color: var(--text-dim); font-family: "Cascadia Code", Consolas, monospace; }
.bq-val { font-weight: 700; color: var(--value); font-variant-numeric: tabular-nums; }
.bq-cell {
  display: flex; align-items: center; justify-content: center;
  min-height: 28px; margin: 1px; border-radius: 4px;
  font-family: "Cascadia Code", Consolas, monospace;
  font-size: 11px; font-weight: 600; letter-spacing: .2px;
  border: 1px solid var(--card-border); background: #fff; color: var(--text-dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.bq-cell--clear     { opacity: .5; }                       /* defined bit, reading 0 */
.bq-cell--set       { background: var(--error); border-color: var(--error); color: rgba(255,255,255,.94); }
.bq-cell--seton     { background: var(--ok);    border-color: var(--ok);    color: rgba(255,255,255,.94); }
.bq-cell--setwarn   { background: var(--warn);  border-color: var(--warn);  color: rgba(255,255,255,.94); }
.bq-cell--setcustom { background: var(--nav-bg); border-color: var(--nav-bg); color: rgba(255,255,255,.94); }
.bq-cell--rsvd {
  background: repeating-linear-gradient(45deg, #f7f8fc, #f7f8fc 4px, #eceef6 4px, #eceef6 8px);
  border-color: transparent;
}
.bq-cell--na  { background: transparent; border-color: transparent; }
.bq-cell--sec { grid-column: span 2; background: var(--bg); }
/* PDSG / PCHG / 12V Status rows: only a few labelled bits, so drop the empty
   bit cells and stretch the labels across the row — wide enough to read on
   one line. PDSG: 4 cells x 4 columns; PCHG: 3 cells at 5+5+6 columns;
   12V Output: one cell across all 16. */
#bqr-pdsgStatus .bq-cell--na, #bqr-pchgStatus .bq-cell--na,
#bqr-out12vStatus .bq-cell--na { display: none; }
#bqr-pdsgStatus .bq-cell, #bqr-pchgStatus .bq-cell,
#bqr-out12vStatus .bq-cell { grid-column: span 4; white-space: nowrap; }
#bqr-pchgStatus .bq-cell { grid-column: span 5; }
#bqr-pchgStatus .bq-cell:last-child { grid-column: span 6; }
#bqr-out12vStatus .bq-cell { grid-column: span 16; }
/* The 12V ACTIVE cell stays uncoloured even while the bit is set
   (operator request, 2026-08-22). */
#bqr-out12vStatus .bq-cell--setcustom {
  background: #fff; border-color: var(--card-border); color: var(--text-dim);
}
@media (max-width: 900px) {
  .bq-hrow, .bq-row { grid-template-columns: 128px 46px 56px repeat(16, 46px); }
  .bq-grid { min-width: 966px; }
}

/* ---------------- Drag & drop file zone (Firmware) ---------------- */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 26px 18px;
  margin-top: 14px;
  border: 2px dashed var(--card-border);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--text-dim);
  text-align: center;
  cursor: pointer;
  transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.dropzone:hover { border-color: var(--nav-bg); color: var(--text); }
.dropzone:focus-visible { outline: 2px solid var(--nav-bg); outline-offset: 2px; }
.dropzone.is-drag { border-color: var(--nav-bg); background: #eef1fb; color: var(--text); }
.dropzone.has-file { border-style: solid; border-color: var(--ok); background: #f1f8f2; }
.dropzone__icon { font-size: 26px; line-height: 1; color: var(--nav-bg); }
.dropzone__main { font-size: 13px; }
.dropzone__link { color: var(--nav-bg); font-weight: 600; text-decoration: underline; }
.dropzone__sub { font-size: 12px; color: var(--text-dim); }
.dropzone__sub code { font-size: 11px; }
.dropzone__file { margin-top: 6px; font-size: 12px; font-weight: 600; color: var(--ok); }

/* Live View identity strip — which pack is this browser talking to.
   `:empty` keeps the layout byte-identical when /api/ident is unavailable,
   so the card grid below is untouched either way. */
.live-ident { display: flex; flex-wrap: wrap; gap: 6px 90px; align-items: baseline;
  margin-bottom: var(--gap); font-size: 13px; color: var(--text-dim); }
.live-ident:empty { display: none; }
.live-ident__item { display: inline-flex; gap: 8px; align-items: baseline; }
.live-ident__v { color: var(--value); font-weight: 600; }

/* ---------------- About screen ---------------- */
.about-card { max-width: 520px; }
.about-hero { display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  padding-bottom: 14px;
  margin-bottom: 6px; border-bottom: 1px solid var(--card-border); }
.about-hero__logo { display: inline-flex; align-items: center; line-height: 1; }
/* Full lockup: 30px tall puts it at ~161px wide, which still leaves room for
   the title beside it on a 375px screen. flex-wrap above is the safety net. */
.brandfull { height: 30px; width: auto; display: block; }
.about-hero__title { font-size: 18px; font-weight: 700; color: var(--text); }
.about-hero__sub { font-size: 12px; color: var(--text-dim); }
.about-row { display: flex; justify-content: space-between; align-items: baseline;
  gap: 16px; padding: 8px 0; border-bottom: 1px solid var(--card-border); }
.about-row:last-of-type { border-bottom: none; }
.about-row__k { color: var(--text-dim); font-size: 13px; }
.about-row__v { color: var(--value); font-weight: 600; text-align: right;
  font-variant-numeric: tabular-nums; word-break: break-word; }
.about-hint { color: var(--text-dim); font-size: 12px; margin-top: 8px; min-height: 1em; }

/* Editable identity + service PIN cards. The label/input pair goes side by side
   on a roomy screen and stacks below 520px, where a right-aligned input would
   otherwise be squeezed to nothing. */
.about-sect { font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .06em; color: var(--label); margin-bottom: 10px; }
.about-field { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px;
  padding: 8px 0; border-bottom: 1px solid var(--card-border); }
.about-field__k { color: var(--text-dim); font-size: 13px; flex: 1 1 160px; }
/* Fixed basis, not `auto`: the passphrase row carries a Show button and would
   otherwise start its input further left than every other row. */
.about-field__v { display: flex; gap: 8px; align-items: center; flex: 0 0 300px; }
.about-field__v input { width: 220px; max-width: 100%; }
.about-field__hint { flex: 1 1 100%; color: var(--text-dim); font-size: 11px; }
.about-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 14px; }
.about-note { margin-top: 10px; padding: 8px 10px; border-radius: 6px; font-size: 12px;
  color: var(--warn); border: 1px solid var(--warn); background: transparent; }

@media (max-width: 620px) {
  .about-field__v { flex: 1 1 100%; }
  .about-field__v input { width: 100%; }
}

/* Small button, used by the Events screen toolbar. */
.btn--sm { padding: 4px 10px; font-size: 12px; }

/* ============================================================
   Predischarge bench (js/pdsgbench.js)
   ============================================================ */
.pb-intro { color: var(--text-dim); font-size: 13px; line-height: 1.55;
  margin-bottom: var(--gap); max-width: 900px; }
.pb-card { padding: 14px 16px; margin-bottom: var(--gap); }

.pb-h { display: flex; align-items: center; gap: 10px; font-weight: 700;
  color: var(--text); margin-bottom: 12px; }
.pb-raw, .pb-state { margin-left: auto; font-family: ui-monospace, monospace;
  font-size: 12px; color: var(--text-dim); }
.pb-raw--warn { color: var(--warn); font-weight: 600; }
.pb-state--live { color: var(--ok); font-weight: 700; }
/* A hold has no timeout, so it must be impossible to miss on the screen. */
.pb-state--held { color: #fff; background: var(--error); font-weight: 700;
  padding: 3px 10px; border-radius: 999px; }
.pb-sep { width: 1px; align-self: stretch; background: var(--card-border); margin: 0 4px; }
.pb-btns code { font-family: ui-monospace, monospace; font-size: 11px;
  background: var(--bg); padding: 1px 4px; border-radius: 4px; }

.pb-cfg { display: grid; gap: 4px 24px;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.pb-f { display: flex; align-items: center; gap: 10px; padding: 6px 0; font-size: 13px; }
.pb-f > span { color: var(--text-dim); flex: 1; }
.pb-f input { width: 96px; text-align: right; padding: 5px 8px;
  border: 1px solid var(--card-border); border-radius: 8px;
  font-variant-numeric: tabular-nums; }
.pb-f i { font-style: normal; color: var(--text-dim); width: 30px; font-size: 12px; }
/* PDSG Settings fields carry a hint under the row, so they stack rather than
   sit on one line. Without this the <i> unit and the <em> hint ran together as
   "2550 mVPredischarge ends when..." — .ps-f had no styling at all. */
.ps-f { display: grid; grid-template-columns: 1fr 96px 30px; align-items: center;
  gap: 4px 10px; padding: 7px 0; font-size: 13px; }
.ps-f > span { color: var(--text-dim); }
.ps-f input { width: 96px; text-align: right; padding: 5px 8px;
  border: 1px solid var(--card-border); border-radius: 8px;
  font-variant-numeric: tabular-nums; }
.ps-f i { font-style: normal; color: var(--text-dim); font-size: 12px; }
.ps-f em { grid-column: 1 / -1; font-style: normal; font-size: 12px;
  color: var(--text-dim); opacity: .85; line-height: 1.45; }
.ps-f select { padding: 5px 8px; border: 1px solid var(--card-border);
  border-radius: 8px; font-size: 13px; }
/* Derived, not editable: what the current settings imply for this board. */
.ps-derived { display: grid; grid-template-columns: 1fr auto; gap: 4px 12px;
  font-size: 13px; padding: 8px 0; }
.ps-derived b { font-variant-numeric: tabular-nums; }
/* What the chip holds, beside the staged input — never inside it. */
.pb-chip { font-style: normal; font-family: ui-monospace, monospace; font-size: 11px;
  color: var(--text-dim); white-space: nowrap; min-width: 84px; }

.pb-note { font-size: 12px; color: var(--text-dim); line-height: 1.5; margin: 8px 0 0; }
.pb-note b { color: var(--value); }
/* Chip-behaviour note: this is the device doing it, not the firmware. Set apart
   so an operator does not read it as another firmware warning. */
.pb-note--chip { border-left: 3px solid var(--card-border); padding: 6px 0 6px 10px;
  margin-top: 10px; background: var(--bg); border-radius: 0 8px 8px 0; }
.pb-warn { color: var(--error); font-size: 12px; line-height: 1.5; margin: 8px 0 0; }
.pb-btns { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.pb-msg { font-size: 12px; color: var(--text-dim); }
.pb-msg--err { color: var(--error); font-weight: 600; }
.pb-msg--ok { color: var(--ok); font-weight: 600; }
.pb-seq { font-size: 12px; color: var(--text-dim); line-height: 1.55; margin-top: 10px; }
.pb-dur { display: inline-flex; align-items: center; gap: 6px; font-size: 13px;
  color: var(--text-dim); }
/* 76px, not 54: the content box has to hold "2000" AND the number spinner
   Chrome reserves ~15px for on the right, or the max value clips. */
.pb-dur input { width: 76px; text-align: right; padding: 6px 8px;
  border: 1px solid var(--card-border); border-radius: 8px;
  font-variant-numeric: tabular-nums; }

/* FET chips */
.pb-fets { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.pbfet { display: flex; align-items: center; gap: 7px; padding: 8px 14px;
  border: 1px solid var(--card-border); border-radius: 999px; font-size: 13px;
  font-weight: 600; color: var(--text-dim); }
.pbfet__dot { width: 10px; height: 10px; border-radius: 50%; background: #c3c7d4; }
.pbfet.is-on { color: #fff; background: var(--ok); border-color: var(--ok); }
.pbfet.is-on .pbfet__dot { background: #fff; }

/* verdict + values */
.pb-verdict { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap;
  margin-bottom: 12px; }
.pb-exit { font-size: 15px; letter-spacing: .02em; }
.pb-exit--ok { color: var(--ok); }
.pb-exit--warn { color: var(--warn); }
.pb-exit--err { color: var(--error); }
.pb-verdict span { font-size: 12px; color: var(--text-dim); flex: 1; min-width: 240px;
  line-height: 1.5; }
.pb-vals { display: grid; gap: 6px 24px;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.pb-kv { display: flex; justify-content: space-between; align-items: baseline;
  gap: 12px; font-size: 13px; padding: 3px 0; }
.pb-kv span { color: var(--text-dim); }
.pb-kv b { font-variant-numeric: tabular-nums; color: var(--value); }

/* sequence strip — the chip's own flow, with the branch it took lit up */
.pb-flow { display: flex; align-items: stretch; gap: 6px; flex-wrap: wrap;
  margin: 4px 0 16px; }
.pb-stage, .pb-alt { border: 1px solid var(--card-border); border-radius: 10px;
  padding: 8px 12px; background: var(--bg); min-width: 0; }
.pb-stage { display: flex; flex-direction: column; justify-content: center; }
.pb-stage b, .pb-alt b { font-size: 12px; letter-spacing: .03em; text-transform: uppercase;
  color: var(--text-dim); }
.pb-stage span, .pb-alt span { font-size: 12px; color: var(--value);
  font-variant-numeric: tabular-nums; }
.pb-stage.is-done { border-color: var(--ok); }
.pb-stage.is-done b { color: var(--ok); }
.pb-stage.is-skipped { opacity: .5; }
.pb-stage.is-bad { border-color: var(--error); }
.pb-stage.is-bad b, .pb-stage.is-bad span { color: var(--error); }
.pb-arrow { align-self: center; color: var(--text-dim); font-size: 16px; }
.pb-branch { display: flex; flex-direction: column; gap: 6px; }
/* Not-taken branches stay visible but recede: seeing the condition that did NOT
   fire is half of what makes the result readable. */
.pb-alt { opacity: .45; border-style: dashed; }
.pb-alt.is-taken { opacity: 1; border-style: solid; border-color: var(--warn);
  background: color-mix(in srgb, var(--warn) 12%, transparent); }
.pb-alt.is-taken b { color: var(--warn); }

/* chart */
.pb-chart { margin-top: 16px; overflow-x: auto; }
.pb-svg { width: 100%; min-width: 560px; height: auto; display: block; }
.pb-empty { color: var(--text-dim); font-size: 13px; padding: 22px 0; text-align: center; }
.pb-line { fill: none; stroke-width: 1.8; }
.pb-line--stack { stroke: var(--nav-bg); }
.pb-line--ld { stroke: #fb8c00; }
/* The primary measurement, on its own axis at the right: ~100 fresh points in a
   2 s window against the ~11 the voltage rotation gives. */
.pb-line--cur { stroke: #7b1fa2; }
/* The abort boundary, drawn in current because the firmware's power column is
   just i^2*R_pre: i = sqrt(P_rating / R_pre). */
.pb-line--rate { stroke: var(--error); stroke-width: 1.4; stroke-dasharray: 6 4; fill: none; }
/* The span in which the series resistor is carrying the load. */
.pb-span { fill: #fb8c00; opacity: .08; }
.pb-mark { stroke-width: 1.2; stroke-dasharray: 3 3; }
.pb-mark--pdsg { stroke: #fb8c00; }
.pb-mark--dsg { stroke: var(--ok); }
.pb-mark--to { stroke: var(--error); }
.pb-mlbl { font-size: 10px; font-weight: 600; text-anchor: start; }
.pb-mlbl.pb-mark--pdsg { fill: #fb8c00; }
.pb-mlbl.pb-mark--dsg { fill: var(--ok); }
.pb-mlbl.pb-mark--to { fill: var(--error); }
.pb-mlbl--rate { fill: var(--error); text-anchor: end; }
.pb-lane--pdsg { fill: #fb8c00; }
.pb-lane--dsg { fill: var(--ok); }
.pb-tick { stroke: var(--card-border); stroke-width: 1; }
.pb-ax { font-size: 10px; fill: var(--text-dim); text-anchor: middle; }
.pb-ax--y { text-anchor: end; }
.pb-ax--y2 { text-anchor: start; fill: #7b1fa2; }
.pb-ax--l { text-anchor: start; font-weight: 600; }
.pb-legend { display: flex; align-items: center; gap: 8px; font-size: 12px;
  color: var(--text-dim); margin-top: 6px; }
.pb-key { width: 14px; height: 3px; border-radius: 2px; display: inline-block; }
.pb-key--stack { background: var(--nav-bg); }
.pb-key--ld { background: #fb8c00; }
.pb-key--cur { background: #7b1fa2; }
.pb-key--rate { background: repeating-linear-gradient(90deg, var(--error) 0 5px, transparent 5px 8px); }
.pb-axlbl { margin-left: auto; }

/* ---------------- Setup Wizard (Settings ▸ Setup Wizard) ----------------
   Horizontal stepper: the Settings group already owns the left sub-nav, so a
   second vertical rail would read as two competing navigations. */
.wiz { padding: 16px 18px; max-width: 900px; }
.wiz-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.wiz-head h2 { margin: 0; font-size: 18px; }
.wiz-badge {
  padding: 2px 8px; border-radius: 999px; font-size: 11px; font-weight: 700;
  background: var(--warn); color: #1a1a1a; text-transform: uppercase; letter-spacing: .4px;
}
.wiz-intro { font-size: 12px; color: var(--text-dim); margin-top: 6px; line-height: 1.55; }

.wiz-steps { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 14px; }
.wiz-step {
  display: flex; align-items: center; gap: 8px; padding: 7px 12px; border-radius: 999px;
  border: 1px solid var(--card-border); background: var(--card-bg);
  font-size: 12px; font-weight: 600; color: var(--text-dim); cursor: pointer;
}
.wiz-step:hover { background: #f0f2f8; }
.wiz-step__n {
  width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--card-border); color: var(--text-dim); font-size: 11px; font-weight: 700;
}
.wiz-step.is-active { border-color: var(--nav-bg); background: #e8eaf6; color: var(--nav-bg); }
.wiz-step.is-active .wiz-step__n { background: var(--nav-bg); color: #fff; }
.wiz-step.is-done { color: var(--text); }
.wiz-step.is-done .wiz-step__n { background: var(--ok); color: #fff; }
.wiz-step.is-skip .wiz-step__n { background: var(--warn); color: #fff; }

.wiz-bar { height: 4px; background: var(--soc-track); border-radius: 2px; overflow: hidden;
  margin: 10px 0 14px; }
.wiz-bar span { display: block; height: 100%; background: var(--nav-bg); transition: width .25s ease; }

.wiz-title { font-size: 15px; font-weight: 800; }
.wiz-sub { font-size: 12px; color: var(--text-dim); margin-top: 4px; line-height: 1.55; }
.wiz-sect {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px;
  color: var(--text-dim); margin: 16px 0 8px; padding-top: 12px;
  border-top: 1px solid var(--card-border);
}
.wiz-sect:first-of-type { margin-top: 14px; }
/* Section subtitles (the <em> after the title) stay lower-case prose —
   only the title itself is upper-cased (operator request, 2026-08-23). */
.wiz-sect em { text-transform: none; letter-spacing: 0; font-weight: 400; font-style: normal; }

.wiz-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 12px 18px; }
.wiz-f { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--label); }
.wiz-f > span b { color: var(--value); font-weight: 600; }
.wiz-f input, .wiz-f select { width: 100%; }
.wiz-f em { font-style: normal; font-size: 11px; color: var(--text-dim); line-height: 1.45; }
.wiz-f--wide { grid-column: 1 / -1; }
.wiz-inline { display: flex; gap: 8px; align-items: center; }

.wiz-ro { display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  padding: 6px 0; border-bottom: 1px dashed var(--card-border); font-size: 13px; }
.wiz-ro:last-child { border-bottom: none; }
.wiz-ro span { color: var(--text-dim); }
.wiz-ro b { color: var(--value); font-variant-numeric: tabular-nums; }

.wiz-note { font-size: 12px; color: var(--text-dim); line-height: 1.55; margin-top: 10px; }
.wiz-note b { color: var(--value); }
.wiz-note--chip { border-left: 3px solid var(--card-border); padding: 6px 0 6px 10px; }
.wiz-warn { font-size: 12px; line-height: 1.55; margin-top: 10px; padding: 8px 10px;
  border-radius: 6px; background: #fff8e1; border: 1px solid #ffe082; color: #6d4c00; }
.wiz-derived { margin-top: 12px; padding: 10px 12px; border-radius: 8px;
  background: var(--bg); border: 1px solid var(--card-border); }

/* The wizard's Calibration step and its .wiz-cal* rules are gone — the real
   screen is Settings ▸ Calibration. */

.wiz-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: 16px; }
.wiz-foot .wiz-spacer { flex: 1; }

/* ── Settings ▸ Calibration ─────────────────────────────────────────────
   One card per channel throughout; sections differ only in how many fit
   across. The sixteen cells are identical channels so they pack four-up; the
   named channels carry a sentence of explanation and take half the width. */
.cal-head { display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.cal-head__title { flex: 1 1 320px; font-weight: 700; font-size: 15px; }
.cal-head__title em { display: block; margin-top: 3px; font-style: normal; font-weight: 400;
                      font-size: 12px; color: var(--text-dim); max-width: 62ch; }
.cal-tools { display: flex; gap: 8px; flex-wrap: wrap; }

.cal-cards { display: grid; gap: 8px; margin-bottom: 6px; }
.cal-cards--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.cal-cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }

.cal-card {
  border: 1px solid var(--card-border);
  border-radius: 10px;
  padding: 8px 10px 7px;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.cal-card__top { display: flex; align-items: baseline; gap: 8px; }
.cal-card__name { font-size: 13px; font-weight: 600; flex: 1 1 auto; min-width: 0; }
.cal-card__name em { display: block; margin-top: 2px; font-style: normal; font-weight: 400;
                     font-size: 11px; color: var(--text-dim); }
.cal-card__live { font-size: 12px; color: var(--text-dim); white-space: nowrap;
                  font-variant-numeric: tabular-nums; }
.cal-card__gain { font-size: 12px; white-space: nowrap; }
.cal-gain__k { color: var(--text-dim); margin-right: 4px; }
.cal-gain__v { font-weight: 600; font-variant-numeric: tabular-nums; }

/* The whole result in one glyph. A card is far too narrow for a sentence like
   "Reading unstable — disconnect the load, let it settle, retry": wrapping it
   would shove every other card in the grid row down, and truncating it would
   lose the part that matters. The sentence lives on the title and on the
   status line at the top of the screen; this is just the at-a-glance state. */
.cal-card__mark { font-size: 12px; font-weight: 700; min-width: 14px; text-align: right;
                  white-space: nowrap; color: var(--text-dim); }
.cal-card__mark--ok  { color: var(--ok); }
.cal-card__mark--err { color: var(--error); }

.cal-card__act { display: flex; align-items: center; gap: 6px; }
/* min-width:0 lets the field shrink inside its grid track instead of forcing
   the card wider than the column it sits in. */
.cal-card__act input { flex: 1 1 auto; min-width: 0; width: 100%; text-align: right;
                       font-variant-numeric: tabular-nums; }
.cal-card__act .cal-go { flex: 0 0 auto; }
.cal-unit { font-size: 12px; color: var(--text-dim); min-width: 18px; }
.cal-noinput { flex: 1 1 auto; font-size: 11px; color: var(--text-dim); font-style: italic; }

.cal-card.is-pending { background: #fff8ec; border-color: #f6e2c4; }
.cal-card.is-pending .cal-card__act input { border-color: var(--warn); }

.cal-card.is-running { background: #f4f6ff; }
.cal-card.is-running .cal-go { opacity: .6; }

@media (max-width: 1100px) { .cal-cards--4 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 820px) {
  .cal-cards--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cal-cards--2 { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 480px) { .cal-cards--4 { grid-template-columns: minmax(0, 1fr); } }

/* ============================================================
   Function-first Data Memory screens (uikit.js / uiplan.js)
   UI/UX plan §7 row anatomy: friendly label + physical limits/step on the
   left, the component in the middle, raw code + address on the right.
   ============================================================ */
.subnav__sep {
  margin: 8px 4px 2px; padding: 6px 8px 2px;
  border-top: 1px solid var(--card-border);
  font-size: 10px; font-weight: 800; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-dim);
}
/* Horizontal phone sub-nav: the divider is a slim vertical rule, not a wrapping row. */
@media (max-width: 760px) {
  .subnav__sep { flex: 0 0 auto; white-space: nowrap; margin: 0 4px; padding: 9px 8px;
    border-top: 0; border-left: 1px solid var(--card-border); }
}

.uik-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(430px, 1fr));
  gap: var(--gap); margin-top: var(--gap); align-items: start; }
@media (max-width: 560px) { .uik-cards { grid-template-columns: 1fr; } }
.uik-card { padding: 12px 14px; }
.uik-card--full { grid-column: 1 / -1; }
/* Fixed two-column variant (Pack & Cells): non-full cards split one row 50/50,
   so together they always cover the same width as the full-row cards above. */
.uik-cards--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.uik-cards--2 .uik-card--right { grid-column: 2; }
@media (max-width: 760px) {
  .uik-cards--2 { grid-template-columns: 1fr; }
  .uik-cards--2 .uik-card--right { grid-column: auto; }
}

/* Guided Calibration register panel: the gain cards moved to the ADC &
   Offsets tab (operator request, 2026-08-23), so the panel is just the
   Current card with Shunt & Current Gain stacked directly below it. */
.cal-regs .uik-cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.cal-regs .cal-shunt-card { grid-column: 1; padding: 12px 14px; }
@media (max-width: 760px) {
  .cal-regs .uik-cards { grid-template-columns: 1fr; }
  .cal-regs .cal-shunt-card { grid-column: auto; }
}

/* Card-level Enable switch (rule cards bound to one register bit) */
.uik-switch { display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  margin-left: auto; user-select: none; }
.uik-switch__txt { font-size: 11px; font-weight: 700; color: var(--text-dim);
  min-width: 46px; text-align: right; }
.uik-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.uik-switch__pill { width: 40px; height: 22px; border-radius: 999px;
  background: #cfd4e3; position: relative; transition: background .15s ease; flex: none; }
.uik-switch__pill::after { content: ""; position: absolute; top: 3px; left: 3px;
  width: 16px; height: 16px; border-radius: 50%; background: #fff;
  box-shadow: 0 1px 3px rgba(20,25,50,.3); transition: left .15s ease; }
.uik-switch input:checked + .uik-switch__pill { background: var(--ok); }
.uik-switch input:checked + .uik-switch__pill::after { left: 21px; }
.uik-switch input:disabled + .uik-switch__pill { opacity: .5; }
.uik-switch input:checked ~ .uik-switch__txt { color: var(--ok); }

/* Rule card switched off: body stays visible but clearly inert */
.uik-card--off .uik-card__body { opacity: .45; pointer-events: none; filter: grayscale(.4); }
.uik-card--off .uik-card__note { opacity: .6; }

/* Row follows a bit of another register (row-level dimWith): readable but
   visibly inactive; its inputs are disabled from wireCards. */
.uik-row--dim .uik-row__ctl,
.uik-row--dim .uik-sliderwrap,
.uik-row--dim .uik-meta { opacity: .45; filter: grayscale(.4); }
.uik-row--dim .uik-row__label { opacity: .6; }
.uik-row--dim .uik-dimwhy { opacity: 1; }

/* editLock cards: values stay fully readable, only editing is withheld —
   no heavy dimming, just natively disabled controls plus the header state. */
.uik-card--locked .uik-card__body input,
.uik-card--locked .uik-card__body select { opacity: .75; }

/* Start/stop threshold band under the rule rows. The two value labels sit on
   separate lanes (stop above, start below) so they can never overlap; the
   segment names moved into a legend row for the same reason. */
.uik-gauge { margin-top: 14px; }
.uik-gauge__title { font-size: 11px; font-weight: 700; color: var(--text-dim); margin-bottom: 2px; }
.uik-gauge__lane { position: relative; height: 16px; }
.uik-gauge__lane span { position: absolute; transform: translateX(-50%);
  font-size: 10.5px; font-weight: 700; color: var(--text-dim); white-space: nowrap;
  font-variant-numeric: tabular-nums; line-height: 16px; }
.uik-gauge__bar { position: relative; display: flex; height: 16px; border-radius: 999px;
  overflow: hidden; border: 1px solid var(--card-border); }
.uik-gauge__bar i { min-width: 0; font-style: normal; }
.uik-gauge__ok  { background: var(--ok); }
.uik-gauge__mid { background: var(--warn); }
.uik-gauge__hot { background: var(--error); }
.uik-gauge__tick { position: absolute; top: 0; bottom: 0; width: 2px;
  background: rgba(255,255,255,.9); transform: translateX(-1px); }
.uik-gauge__legend { display: flex; flex-wrap: wrap; gap: 3px 18px; margin-top: 6px; }
.uik-gauge__legend span { display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; color: var(--text-dim); }
.uik-gauge__legend i { width: 12px; height: 12px; border-radius: 4px; flex: none; }
.uik-gauge__warn { margin-top: 6px; font-size: 11.5px; font-weight: 600; color: var(--error); }

/* Compact screens (plan.compact): the engineering chrome — bounds/step lines
   and raw/address badges — stays present but recedes, so the operator rows
   read first. */
.uik--compact .uik-row { padding: 7px 0 5px; }
.uik--compact .uik-row__label { font-size: 13.5px; }
.uik--compact .uik-row__label small { font-size: 10px; opacity: .7; }
.uik--compact .uik-meta { font-size: 10px; opacity: .65; }
.uik--compact .uik-row__note { font-size: 11px; }
.uik--compact .uik-card__note { font-size: 11.5px; }

/* Protection Overview dashboard (special "protstatus") */
.uik-protstat__grp { margin-bottom: 12px; }
.uik-protstat__grp:last-child { margin-bottom: 0; }
.uik-protstat__t { font-size: 11px; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--text-dim); margin: 8px 0 6px; }
.uik-protstat__sub { font-size: 10px; font-weight: 700; letter-spacing: .05em;
  text-transform: uppercase; color: #9aa0b4; margin: 7px 0 4px; }
/* At most 5 chips per row (operator request, 2026-09-29): the track minimum
   is a fifth of the row minus the 4 gaps (4 x 8 px — keep in step with
   `gap`, or only 4 fit), never below 150 px on narrow
   screens — so wide screens stop at 5, narrow ones still drop to 4/3/2/1. */
.uik-protstat__chips { display: grid;
  grid-template-columns: repeat(auto-fill, minmax(max(150px, calc((100% - 32px) / 5)), 1fr)); gap: 8px; }
.uik-protstat__chips + .uik-protstat__sub { margin-top: 10px; }
/* Folded group (Permanent Fail ▸ Advanced): the title row is the toggle */
.uik-protstat__advbtn { display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 0 2px; border: 0; background: none; cursor: pointer; text-align: left; }
.uik-protstat__advbtn .uik-protstat__t { margin: 8px 0 6px; }
.uik-protstat__advbtn em { font-style: normal; font-weight: 700; letter-spacing: .04em;
  margin-left: 6px; padding: 1px 6px; border-radius: 8px; background: #eef0f6; color: #6b7188; }
.uik-protstat__caret { font-size: 13px; color: var(--text-dim); }
.uik-protstat__advbtn:hover .uik-protstat__caret { color: var(--text); }
.uik-prot { display: flex; flex-direction: column; gap: 1px; padding: 7px 10px;
  border: 1px solid var(--card-border); border-radius: 10px; text-decoration: none;
  color: var(--text); background: #fff; }
.uik-prot:hover { box-shadow: var(--shadow); }
.uik-prot b { font-size: 12px; }
.uik-prot span { font-size: 10.5px; color: var(--text-dim); line-height: 1.25; }
.uik-prot i { font-style: normal; font-size: 9.5px; font-weight: 800;
  letter-spacing: .05em; text-transform: uppercase; margin-top: 2px; }
.uik-prot--armed { border-color: var(--ok); background: #f1f8f2; }
.uik-prot--armed i { color: var(--ok); }
.uik-prot--off i { color: var(--text-dim); }
.uik-prot--off { opacity: .62; }
.uik-prot--alert { border-color: var(--warn); background: #fff7e8; }
.uik-prot--alert i { color: var(--warn); }
.uik-prot--trip { border-color: var(--error); background: var(--error); color: #fff; }
.uik-prot--trip span { color: rgba(255,255,255,.85); }
.uik-prot--trip i { color: #fff; }
.uik-prot--unknown { border-style: dashed; opacity: .6; }

/* Alarms & Reporting: the live reporting-chain strip */
.uik-alflow { display: flex; align-items: stretch; flex-wrap: wrap; gap: 6px;
  margin: 6px 0 12px; }
.uik-alflow > span { flex: 1 1 120px; min-width: 110px; padding: 8px 10px;
  border: 1px solid var(--card-border); border-radius: 10px; background: #fafbfe;
  font-size: 12px; font-weight: 700; color: var(--text); text-align: center; }
.uik-alflow > span small { display: block; margin-top: 2px; font-size: 10.5px;
  font-weight: 600; color: var(--text-dim); }
.uik-alflow > em { align-self: center; font-style: normal; color: #9aa0b4;
  font-weight: 800; }
.uik-alflow__pin--on { border-color: var(--error) !important; background: #fdecea !important; }
.uik-alflow__pin--on small { color: var(--error) !important; font-weight: 800; }

/* Dual-handle temperature window (comp "temppair") */
.uik-row--pair .uik-tr { grid-area: wide; margin-top: 4px; }
.uik-metagrp { grid-area: meta; justify-self: end; display: flex; gap: 12px; }
.uik-tr__track { position: relative; height: 18px; }
.uik-tr__segs { position: absolute; inset: 0; display: flex; border-radius: 999px;
  overflow: hidden; border: 1px solid var(--card-border); }
.uik-tr__segs i, .uik-tr__legend i { font-style: normal; }
.uik-tr__cold { background: #64b5f6; }
.uik-tr__okz  { background: var(--ok); }
.uik-tr__hotz { background: var(--error); }
.uik-tr__range { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0;
  -webkit-appearance: none; appearance: none; background: transparent; border: none;
  pointer-events: none; padding: 0; }
.uik-tr__range:focus { box-shadow: none; outline: none; }
.uik-tr__range::-webkit-slider-runnable-track { background: transparent; height: 18px; }
.uik-tr__range::-webkit-slider-thumb { -webkit-appearance: none; pointer-events: auto;
  width: 16px; height: 26px; margin-top: -4px; border-radius: 7px; background: #fff;
  border: 2px solid var(--nav-bg); box-shadow: 0 1px 4px rgba(20,25,50,.35); cursor: ew-resize; }
.uik-tr__range::-moz-range-track { background: transparent; height: 18px; }
.uik-tr__range::-moz-range-thumb { pointer-events: auto; width: 14px; height: 24px;
  border-radius: 7px; background: #fff; border: 2px solid var(--nav-bg);
  box-shadow: 0 1px 4px rgba(20,25,50,.35); cursor: ew-resize; }
.uik-tr__legend { display: flex; flex-wrap: wrap; gap: 3px 18px; margin-top: 6px; }
.uik-tr__legend span { display: inline-flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 600; color: var(--text-dim); }
.uik-tr__legend i { width: 12px; height: 12px; border-radius: 4px; flex: none;
  border: 1px solid rgba(0,0,0,.08); }

/* Live balancing status (Cell Balancing screen) */
.uik-bal__wait { color: var(--text-dim); font-size: 12.5px; }
.uik-bal__hero { display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  margin: 4px 0 12px; }
.uik-bal__big { font-size: 34px; font-weight: 800; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -.5px; flex: none; }
.uik-bal__big u { text-decoration: none; font-size: 15px; font-weight: 700;
  margin-left: 3px; color: var(--text-dim); }
.uik-bal__big--ok  { color: var(--ok); }
.uik-bal__big--mid { color: var(--warn); }
.uik-bal__big--hot { color: var(--error); }
.uik-bal__big--off { color: var(--text-dim); }
.uik-bal__verdict { flex: 1 1 320px; min-width: 0; font-size: 13px;
  color: var(--text-dim); line-height: 1.45; }
.uik-bal__verdict b { color: var(--value); }
.uik-bal__pending { display: block; font-style: normal; font-weight: 700;
  color: var(--warn); margin-top: 2px; }
@keyframes uik-bleed { 0%, 100% { box-shadow: 0 0 0 0 rgba(229,57,53,.35); }
  50% { box-shadow: 0 0 0 4px rgba(229,57,53,.12); } }
.uik-balcell.is-bleed { animation: uik-bleed 1.6s ease-in-out infinite; }
.uik-bal__sum { display: flex; flex-wrap: wrap; gap: 6px 26px; margin: 6px 0 10px;
  font-size: 13px; color: var(--text-dim); }
.uik-bal__sum b { color: var(--value); font-variant-numeric: tabular-nums; }
.uik-bal__strip { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
  gap: 6px; }
.uik-balcell { display: flex; flex-direction: column; align-items: center; gap: 1px;
  padding: 6px 4px 5px; border: 1px solid var(--card-border); border-radius: 8px;
  background: #fff; }
.uik-balcell b { font-size: 11px; color: var(--text-dim); }
.uik-balcell i { font-style: normal; font-size: 12px; font-weight: 700;
  font-variant-numeric: tabular-nums; color: var(--value); }
.uik-balcell em { font-style: normal; font-size: 9px; font-weight: 800;
  letter-spacing: .06em; text-transform: uppercase; color: #fff;
  background: var(--error); border-radius: 999px; padding: 0 6px; margin-top: 2px; }
.uik-balcell.is-bleed { border-color: var(--error); background: #fdecea; }
.uik-balcell.is-min { box-shadow: inset 0 -3px 0 #90caf9; }
.uik-balcell.is-max { box-shadow: inset 0 -3px 0 var(--warn); }

/* Busbar resistance calculator */
/* the Bar and Holes groups share one row; they stack only when too narrow */
.uik-bb__groups { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 4px; }
.uik-bb__grp { flex: 1 1 380px; display: flex; flex-wrap: wrap; align-items: flex-end;
  gap: 8px 16px; padding: 8px 10px; border: 1px solid var(--card-border);
  border-radius: 10px; background: #fafbfe; }
.uik-bb__grptitle { flex: 0 0 64px; align-self: center;
  font-size: 11px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  color: var(--text-dim); }
.uik-bb__out span em { display: block; font-style: normal; font-weight: 500;
  font-size: 11px; color: var(--text-dim); }
.uik-bb__form { display: flex; flex-wrap: wrap; gap: 8px 16px; margin: 8px 0 4px; }
.uik-bb__f { display: inline-flex; flex-direction: column; gap: 3px;
  justify-content: flex-end;
  font-size: 11.5px; font-weight: 600; color: var(--text-dim); }
.uik-bb__f span { display: inline-flex; align-items: center; gap: 5px;
  font-weight: 500; font-size: 12px; }
.uik-bb__f input { width: 76px; text-align: right; font-variant-numeric: tabular-nums; }
/* selects and number boxes share one control height so the row lines up */
.uik-bb__f input, .uik-bb__f select { height: 30px; padding-top: 0; padding-bottom: 0; }
.uik-bb__diag { margin-top: 6px; border: 1px solid var(--card-border); border-radius: 10px;
  background: #fafbfe; padding: 6px 8px; }
.uik-bb__out { margin-top: 8px; display: flex; flex-direction: column; gap: 4px; }
.uik-bb__out div { display: flex; justify-content: space-between; align-items: flex-start;
  gap: 12px; padding: 5px 0; border-bottom: 1px dashed var(--card-border); }
.uik-bb__out span { color: var(--label); font-size: 12.5px; font-weight: 600; }
.uik-bb__out b { font-variant-numeric: tabular-nums; font-size: 13px;
  white-space: nowrap; line-height: 1.6; }
.uik-bb__err { color: var(--error); font-size: 12.5px; font-weight: 600; }
/* On the full-row card the two results sit side by side instead of stacking. */
.uik-card--full .uik-bb__out { flex-direction: row; flex-wrap: wrap; gap: 8px 32px; }
.uik-card--full .uik-bb__out div { flex: 1 1 300px; }
.uik-card__head { display: flex; align-items: center; gap: 10px; }
.uik-card__title { font-weight: 800; font-size: 14px; }
.uik-card__head .uik-expert-toggle { margin-left: auto; }
.uik-card__note { color: var(--text-dim); font-size: 12px; line-height: 1.45; margin-top: 3px; }

.uik-row {
  display: grid; grid-template-columns: minmax(180px, 1fr) auto;
  grid-template-areas: "label ctl" "meta meta" "note note" "wide wide";
  align-items: center; column-gap: 10px; row-gap: 2px;
  padding: 9px 0 7px; border-bottom: 1px solid #eef0f5; position: relative;
}
.uik-card__body > .uik-row:last-child { border-bottom: none; }
.uik-row.is-dirty { background: #fff8ec; }
.uik-row .dm-dirtydot { position: absolute; left: -12px; top: 14px; }
.uik-row.is-dirty .dm-dirtydot { visibility: visible; }

.uik-row__label { grid-area: label; font-weight: 600; font-size: 13px; min-width: 0; }
.uik-row__label small { display: block; color: var(--text-dim); font-weight: 500; font-size: 11px; }
.uik-row__ctl { grid-area: ctl; display: flex; align-items: center; gap: 7px; justify-content: flex-end; flex-wrap: wrap; }
.uik-row__ctl input:not([type="checkbox"]):not([type="range"]),
.uik-row__ctl select {
  width: 130px; text-align: right; font-variant-numeric: tabular-nums;
}
.uik-row__ctl select { width: auto; max-width: 300px; text-align: left; }
.uik-unit { color: var(--text-dim); font-weight: 600; font-size: 12px; min-width: 14px; }
.uik-meta {
  grid-area: meta; justify-self: end;
  color: #9098ad; font-size: 11px; font-variant-numeric: tabular-nums;
  font-family: "Cascadia Code", Consolas, monospace;
}
.uik-row.is-dirty .uik-meta { color: var(--warn); }
.uik-row__note { grid-area: note; color: var(--text-dim); font-size: 11.5px; line-height: 1.4; }
.uik-row__note a { color: var(--nav-bg); font-weight: 600; }

.uik-badge {
  display: inline-flex; align-items: center; font-size: 10px; font-weight: 700;
  padding: 2px 8px; border-radius: 999px; background: #eef0f7; color: var(--nav-bg);
  white-space: nowrap;
}
.uik-badge--auto { background: #e8f5e9; color: var(--ok); }
.uik-badge--ro { background: var(--bg); color: var(--text-dim); }

/* slider variant: the range rides full-width under the label/input line */
.uik-sliderwrap { grid-area: wide; display: flex; align-items: center; gap: 8px; margin-top: 2px; }
.uik-sliderwrap input[type="range"] { flex: 1 1 auto; accent-color: var(--nav-bg); }
.uik-slider__end { color: var(--text-dim); font-size: 11px; font-variant-numeric: tabular-nums; white-space: nowrap; }

.uik-tog { display: inline-flex; align-items: center; gap: 5px; font-size: 12px;
  color: var(--text-dim); font-weight: 600; cursor: pointer; }
/* Plain toggles (tognum / toghex) sit next to their input — give the box a
   size worth aiming at. */
.uik-tog input[type="checkbox"] { width: 16px; height: 16px; accent-color: var(--nav-bg); }
/* A bitrow's pill lives inside the row's control box, not a card header. */
.uik-switch--row { margin-left: 0; }
.uik-switch--row .uik-switch__txt { min-width: 26px; }
.uik-tog input { width: auto; margin: 0; }
.uik-hex { font-family: "Cascadia Code", Consolas, monospace; letter-spacing: 1px; }

/* checkbox-list rows: bits render full-width under the label line */
.uik-row--bits .uik-bits {
  grid-area: wide; display: flex; flex-wrap: wrap; gap: 8px 20px; margin-top: 6px;
  padding: 10px 12px; background: #f7f8fc; border: 1px solid var(--card-border);
  border-radius: 10px;
}

/* 16-cell grids (Vcell Mode toggles / Interconnect Resistance numbers) */
.uik-cellgrid { grid-area: wide; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px; margin-top: 8px; }
/* On a full-row card the 16 entries spread across 8 columns (2 rows). */
.uik-card--full .uik-cellgrid { grid-template-columns: repeat(8, minmax(0, 1fr)); }
@media (max-width: 1100px) { .uik-card--full .uik-cellgrid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 900px) { .uik-cellgrid,
  .uik-card--full .uik-cellgrid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.uik-cell {
  display: flex; align-items: center; gap: 7px; padding: 7px 10px;
  border: 1px solid var(--card-border); border-radius: 8px; cursor: pointer;
  font-size: 12px; font-weight: 600; color: var(--text-dim); background: #fff;
}
.uik-cell input { width: auto; margin: 0; }
.uik-cell.is-on { border-color: var(--ok); background: #f1f8f2; color: var(--text); }
.uik-cellnum {
  display: grid; grid-template-columns: auto 1fr; align-items: center; gap: 2px 8px;
  padding: 6px 9px; border: 1px solid var(--card-border); border-radius: 8px; background: #fff;
}
.uik-cellnum span { font-size: 11px; font-weight: 700; color: var(--text-dim); white-space: nowrap; }
.uik-cellnum input { width: 100%; min-width: 0; text-align: right; font-variant-numeric: tabular-nums; padding: 4px 7px; }
.uik-cellnum em {
  grid-column: 1 / -1; font-style: normal; font-size: 10px; color: #9098ad;
  font-family: "Cascadia Code", Consolas, monospace; text-align: right;
}
.uik-cellnum.is-dirty { border-color: var(--warn); background: #fff8ec; }

/* Vcell Mode: series-count combobox + connection schematic. The row needs
   more stacked full-width areas than the generic template carries. */
.uik-row--grid {
  grid-template-areas: "label ctl" "meta meta" "note note"
                       "diag diag" "legend legend" "wide wide";
}
.uik-vcsel__label { display: inline-flex; align-items: center; gap: 8px;
  font-size: 17px; font-weight: 800; color: var(--text); }
.uik-vcsel__label select { width: auto; text-align: left;
  font-size: 17px; font-weight: 800; }
.uik-vcdiag { grid-area: diag; margin-top: 8px; overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--card-border); border-radius: 10px;
  background: #fafbfe; padding: 4px 2px; }
.uik-vcdiag svg { display: block; }
.uik-vclegend { grid-area: legend; display: flex; flex-wrap: wrap; gap: 4px 18px;
  align-items: center; margin-top: 6px; font-size: 11.5px; color: var(--text-dim); }
.uik-vclegend i { display: inline-block; vertical-align: -2px; margin-right: 5px; }
.uik-vclegend__cell { width: 16px; height: 10px; border-radius: 3px; background: var(--ok); }
.uik-vclegend__short { width: 16px; height: 0; border-top: 2px solid var(--warn); vertical-align: 2px !important; }
.uik-vclegend__note { flex-basis: 100%; }

.uik-cellcount { font-size: 12.5px; margin-top: 6px; color: var(--text-dim); }
.uik-cellcount b { color: var(--value); }
.uik-cellcount--warn, .uik-cellcount--warn b { color: var(--error); }

/* the read-only register listing mounted under the guided calibration flow */
.cal-regs { margin-top: var(--gap); }
/* Its toast shares the viewport spot with the guided flow's #cal-toast —
   nudge it up so near-simultaneous toasts stack instead of covering. */
.cal-regs .toast { bottom: 64px; }

/* ============================================================
   Protection Configurations — pop-up editors (uikit cards flagged `modal`),
   dashboard chips as buttons, "More Settings" tiles (2026-09-02).
   Layering: pop-up 900 < toast 1000 < ⓘ description popup 1100.
   ============================================================ */
.uik-modal { position: fixed; inset: 0; z-index: 900; display: flex;
  align-items: center; justify-content: center; padding: 28px 12px; }
.uik-modal[hidden], .uik-modal [hidden] { display: none !important; }
.uik-modal__backdrop { position: absolute; inset: 0; background: rgba(20, 25, 50, .45); }
/* Width follows the content (applyPanelSize sets the classes): one protection
   with a few threshold rows stays narrow, bit lists / multi-column cards /
   mounted modules get the wide panel. */
.uik-modal__panel { position: relative; width: 100%; max-width: 600px;
  max-height: calc(100vh - 56px); display: flex; flex-direction: column;
  background: var(--bg); border: 1px solid var(--card-border); border-radius: 14px;
  box-shadow: 0 18px 48px rgba(20, 25, 50, .28); overflow: hidden; }
.uik-modal__panel--mid  { max-width: 780px; }
.uik-modal__panel--wide { max-width: 1000px; }
/* Solo (one card per pop-up): the card drops its frame and the panel body
   becomes the card surface — one box, not a box inside a box. */
.uik-modal__panel--solo .uik-modal__body { background: var(--card-bg); padding-top: 2px; }
.uik-card--solo { border: none; box-shadow: none; background: transparent;
  padding: 0; border-radius: 0; }
.uik-card--solo > .uik-card__head--solo { justify-content: flex-end; min-height: 28px;
  padding-top: 6px; }
.uik-card--solo > .uik-card__note { margin: 4px 0 2px; }
.uik-modal__head { display: flex; align-items: flex-start; gap: 12px;
  padding: 14px 18px 10px; background: var(--card-bg); }
.uik-modal__titles { flex: 1 1 auto; min-width: 0; }
.uik-modal__title { font-weight: 800; font-size: 16px; }
.uik-modal__sub { color: var(--text-dim); font-size: 12px; line-height: 1.45; margin-top: 2px; }
.uik-modal__x { font: inherit; font-size: 26px; line-height: 1; width: 36px; height: 36px;
  border: none; background: none; color: var(--text-dim); cursor: pointer; border-radius: 8px; flex: none; }
.uik-modal__x:hover { background: #f0f2f8; color: var(--text); }
/* Sibling switcher: one pill per card of the family — scrolls, never navigates */
.uik-modal__nav { display: flex; flex-wrap: wrap; gap: 4px; padding: 0 18px 10px;
  background: var(--card-bg); border-bottom: 1px solid var(--card-border); }
.uik-modal__nav[hidden] { display: none !important; }
.uik-modal__head + .uik-modal__nav[hidden] + .uik-modal__body { border-top: 1px solid var(--card-border); }
.uik-modal__navbtn { font: inherit; font-size: 11px; font-weight: 700; padding: 4px 10px;
  border-radius: 999px; border: 1px solid var(--card-border); background: #fff;
  color: var(--text-dim); cursor: pointer; }
.uik-modal__navbtn:hover { border-color: var(--nav-bg); color: var(--nav-bg); }
.uik-modal__navbtn.is-active { background: #e8eaf6; border-color: #c5cae9; color: var(--nav-bg); }
.uik-modal__body { flex: 1 1 auto; overflow: auto; padding: 0 18px 18px; }
/* The screen is `compact` (dashboard density); inside a pop-up there is room
   to read the label and the register path properly. */
.uik-modal__body .uik-row__label { font-size: 14px; }
.uik-modal__body .uik-row__label small { font-size: 11px; opacity: .85; }
.uik-modal__body .uik-meta { font-size: 11px; opacity: .8; }
.uik-modal__body .uik-row__ctl input:not([type="checkbox"]):not([type="range"]) { width: 150px; }
.uik-cards--modal { grid-template-columns: minmax(0, 1fr); }
.uik-modal__foot { display: flex; align-items: center; gap: 8px; padding: 10px 18px;
  background: var(--card-bg); border-top: 1px solid var(--card-border); }
.uik-modal__status { flex: 1 1 auto; min-width: 0; font-size: 12.5px; font-weight: 600;
  color: var(--text-dim); }
.uik-modal__status.dm-status--ok { color: var(--ok); }
.uik-modal__status.dm-status--warn { color: var(--warn); }
.uik-modal__status.dm-status--err { color: var(--error); }
.uik-modal__foot--flash { animation: uik-footflash .6s ease; }
@keyframes uik-footflash { 0%, 100% { background: var(--card-bg); } 40% { background: #fff3e0; } }
/* The card the operator clicked on: outlined, pulses once */
.uik-card--focus { box-shadow: 0 0 0 2px var(--nav-bg), var(--shadow); }
.uik-card--pulse { animation: uik-cardpulse 1.4s ease 1; }   /* added once by scrollToCode, not by repaints */
@keyframes uik-cardpulse { 0% { box-shadow: 0 0 0 7px rgba(57, 73, 171, .35), var(--shadow); }
  100% { box-shadow: 0 0 0 2px var(--nav-bg), var(--shadow); } }
/* keep the ring inside the scrollport when a card is scrolled to the top */
.uik-cards--modal .uik-card { scroll-margin-top: 10px; }
.uik-modal__body { padding-top: 0; }
.uik-cards--modal { margin-top: 10px; }
/* Module card (PreDischarge guard screen hosted in the pop-up) */
.uik-module > div { padding: 0 !important; max-width: none !important; }
.uik-card--module > .uik-card__head { display: none; }   /* the pop-up head already names it */

/* Dashboard chips are buttons now (they open the pop-ups) */
button.uik-prot { font: inherit; text-align: left; width: 100%; cursor: pointer; }
.uik-prot b { display: flex; align-items: center; justify-content: space-between; gap: 6px; }
.uik-prot b i { margin-top: 0; white-space: nowrap; }
.uik-prot em { font-style: normal; font-size: 10.5px; font-weight: 600; margin-top: 3px;
  color: var(--text); font-variant-numeric: tabular-nums; }
/* Off chips fade the state, not the configured value the operator reads before arming */
.uik-prot--off { opacity: 1; }
.uik-prot--off b, .uik-prot--off span { opacity: .62; }
.uik-prot--trip em { color: #fff; }
button.uik-prot:hover { border-color: var(--nav-bg); }
.uik-prot:focus-visible, .uik-tile:focus-visible, .btn:focus-visible, .uik-modal__x:focus-visible,
.uik-modal__navbtn:focus-visible { outline: 2px solid var(--nav-bg); outline-offset: 2px; }
.uik-switch input:focus-visible + .uik-switch__pill { outline: 2px solid var(--nav-bg); outline-offset: 2px; }

/* Chips that share one editor card: a thick box, chips side by side, so the
   shared pop-up is obvious from the dashboard (OCD tiers, raw-armed PFs). */
.uik-protbox { grid-column: 1 / -1; border: 2px solid #b9c0e0; border-radius: 12px;
  padding: 7px 10px 10px; background: #f4f6fd; }
.uik-protbox__t { font-size: 10px; font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--nav-bg); margin-bottom: 6px; }
.uik-protbox__chips { display: grid;
  grid-template-columns: repeat(auto-fill, minmax(max(150px, calc((100% - 32px) / 5)), 1fr)); gap: 8px; }
.uik-protbox .uik-prot { background: #fff; }
.uik-protbox .uik-prot--armed { background: #f1f8f2; }
.uik-protbox .uik-prot--alert { background: #fff7e8; }
.uik-protbox .uik-prot--trip { background: var(--error); }

/* "More Settings" tiles */
.uik-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(max(230px, calc((100% - 40px) / 5)), 1fr));
  gap: 10px; margin-top: 8px; }
.uik-tile { font: inherit; text-align: left; display: flex; flex-direction: column; gap: 2px;
  padding: 10px 12px; border: 1px solid var(--card-border); border-radius: 10px;
  background: #fff; color: var(--text); cursor: pointer; }
.uik-tile:hover { box-shadow: var(--shadow); border-color: var(--nav-bg); }
.uik-tile b { display: flex; justify-content: space-between; align-items: center; gap: 6px; font-size: 12.5px; }
.uik-tile b i { font-style: normal; font-size: 10px; font-weight: 800; color: var(--nav-bg);
  letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; }
.uik-tile span { font-size: 10.5px; color: var(--text-dim); line-height: 1.3; }
.uik-tile em { font-style: normal; font-size: 10.5px; font-weight: 600; margin-top: 3px;
  font-variant-numeric: tabular-nums; }

/* ============================================================
   Protection chips & tiles — visual rev 3 (operator request, 2026-09-29):
   taller boxes, larger type, a coloured state bar on the left, the state
   word as a pill with a dot, the written threshold anchored to the bottom
   behind a hairline. Max 5 per row comes from the grid rules above.
   ============================================================ */
.uik-prot { position: relative; overflow: hidden; min-height: 92px; gap: 3px;
  padding: 11px 14px 11px 17px; border-radius: 12px;
  box-shadow: 0 1px 2px rgba(20, 25, 50, .05);
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease; }
.uik-prot::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  background: #cfd3e0; }
.uik-prot--armed::before { background: var(--ok); }
.uik-prot--alert::before { background: var(--warn); }
.uik-prot--trip::before  { background: rgba(255, 255, 255, .55); }
.uik-prot--unknown::before { background: transparent; }
.uik-prot--armed { border-color: #bfe0c3; }
.uik-prot--alert { border-color: #f6cf93; }
button.uik-prot:hover { transform: translateY(-1px); border-color: var(--nav-bg);
  box-shadow: 0 6px 16px rgba(20, 25, 50, .12); }
.uik-prot b { font-size: 15px; letter-spacing: .01em; flex-wrap: wrap; row-gap: 4px; }
.uik-prot b i { display: inline-flex; align-items: center; gap: 5px; font-size: 10px;
  padding: 2px 8px 2px 7px; border-radius: 999px; background: #eef0f5; color: var(--text-dim); }
.uik-prot b i::before { content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: currentColor; flex: none; }
.uik-prot--armed b i { background: #e1f2e3; color: #2e7d32; }
.uik-prot--alert b i { background: #fde9c6; color: #a15c00; }
.uik-prot--trip b i  { background: rgba(255, 255, 255, .22); color: #fff; }
.uik-prot span { font-size: 12px; line-height: 1.3; }
.uik-prot em { margin-top: auto; padding-top: 7px; border-top: 1px dashed #e1e4ee;
  font-size: 13px; font-weight: 700; }
.uik-prot--trip em { border-top-color: rgba(255, 255, 255, .35); }
/* The shared-pop-up frame lives IN the grid gaps: margin -6 px against
   padding 4 + border 2, so the boxed chips line up with the columns and
   keep the row height (no caption). Row gap 12 px leaves the frame room. */
.uik-protstat__chips, .uik-protbox__chips { row-gap: 12px; }
.uik-protbox { margin: -6px; padding: 4px; border-radius: 15px; }
.uik-protstat__t { font-size: 12px; margin: 12px 0 8px; }
.uik-protstat__sub { font-size: 10.5px; margin: 10px 0 6px; }

.uik-tile { position: relative; min-height: 98px; gap: 4px; padding: 13px 15px;
  border-radius: 12px; box-shadow: 0 1px 2px rgba(20, 25, 50, .05);
  transition: box-shadow .15s ease, transform .15s ease, border-color .15s ease; }
.uik-tile:hover { transform: translateY(-1px); box-shadow: 0 6px 16px rgba(20, 25, 50, .12); }
.uik-tile b { font-size: 14px; }
.uik-tile b i { font-size: 10px; padding: 2px 9px; border-radius: 999px; background: #e8eaf6; }
.uik-tile span { font-size: 12px; line-height: 1.35; }
.uik-tile em { margin-top: auto; padding-top: 7px; border-top: 1px dashed #e1e4ee;
  font-size: 13px; font-weight: 700; }

/* Shared-pop-up box: hug the N chips instead of the whole row. The chip grid
   is a size container; a box of N spans N columns only once the grid really
   has N columns (N x 150 px + gaps), otherwise it keeps the full row — a
   span wider than the grid would add implicit columns and overflow. Boxes
   of 5+ chips always take the full row and wrap inside. */
.uik-protstat__chips { container-type: inline-size; }
@container (min-width: 308px) {
  .uik-protbox--n2 { grid-column: span 2; }
  .uik-protbox--n2 .uik-protbox__chips { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@container (min-width: 466px) {
  .uik-protbox--n3 { grid-column: span 3; }
  .uik-protbox--n3 .uik-protbox__chips { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
@container (min-width: 624px) {
  .uik-protbox--n4 { grid-column: span 4; }
  .uik-protbox--n4 .uik-protbox__chips { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Latch pop-ups (COVL / OCDL / SCDL): amber row warning (warnZero) and the
   live "How the latch clears" box under the rows. */
.uik-row__warn { grid-column: 1 / -1; margin-top: 6px; padding: 7px 10px; border-radius: 8px;
  background: #fff7e8; border: 1px solid #f3d19c; color: #8a5300;
  font-size: 12px; font-weight: 600; line-height: 1.4; }
.uik-row__warn[hidden] { display: none; }
.uik-latch { margin-top: 14px; padding: 12px 14px; border: 1px solid #dfe3f0;
  border-radius: 12px; background: #f6f7fc; }
.uik-latch__t { font-size: 11px; font-weight: 800; letter-spacing: .06em;
  text-transform: uppercase; color: var(--nav-bg); margin-bottom: 8px; }
.uik-latch__list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.uik-latch__list li { display: flex; gap: 9px; align-items: flex-start;
  font-size: 12.5px; line-height: 1.45; }
.uik-latch__ic { flex: none; width: 19px; height: 19px; border-radius: 50%; margin-top: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 800; }
.uik-latch__list li.is-on .uik-latch__ic  { background: #e1f2e3; color: #2e7d32; }
.uik-latch__list li.is-off .uik-latch__ic { background: #eceef4; color: #9aa0b4; }
.uik-latch__list li.is-off .uik-latch__txt { color: var(--text-dim); }
.uik-latch__txt b { color: var(--text); margin-right: 3px; }
.uik-latch__link { font: inherit; font-size: 12px; font-weight: 700; color: var(--nav-bg);
  background: none; border: none; padding: 0; margin-left: 2px; cursor: pointer; white-space: nowrap; }
.uik-latch__link:hover { text-decoration: underline; }
.uik-latch__link:focus-visible { outline: 2px solid var(--nav-bg); outline-offset: 2px; border-radius: 4px; }
.uik-latch__foot { margin-top: 9px; font-size: 11.5px; color: var(--text-dim); line-height: 1.45; }
.uik-latch__warn { margin-top: 9px; padding: 7px 10px; border-radius: 8px; background: #fff7e8;
  border: 1px solid #f3d19c; color: #8a5300; font-size: 12px; font-weight: 600; line-height: 1.4; }

@media (max-width: 760px) {
  .uik-modal { padding: 0; }
  .uik-modal__panel { max-width: none; height: 100%; max-height: 100%; border-radius: 0; border: none; }
  .uik-modal__x, .uik-modal__foot .btn { min-height: 44px; }
  .uik-cards--modal { grid-template-columns: 1fr; }
  /* three buttons + status do not fit one phone row: status on its own line */
  .uik-modal__foot { flex-wrap: wrap; }
  .uik-modal__status { flex-basis: 100%; order: -1; }
  .uik-modal__foot .btn--primary { flex: 1 1 auto; }
}
/* Pop-up Read (re-reads just this pop-up) sits at the footer's left edge */
.uik-modal__read { flex: none; }
.uik-modal__read[hidden] { display: none !important; }
/* A toast raised while a pop-up is open sits above the pop-up footer (which
   mirrors the same text), never across its buttons. */
.uik--modal-open .toast { bottom: 84px; }

/* ============================================================
   Factory Setup Wizard ▸ Temp Sensor Connections (fstemp.js, 2026-09-29).
   One tile per sensor in the Protections chip language: coloured state bar,
   big live reading, "Feeds" tags linked to the protections it serves.
   ============================================================ */
.tsc-cards { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--gap, 14px); }
.tsc-group .uik-card__note { margin-bottom: 10px; }
.tsc-grid { display: grid; gap: 10px;
  grid-template-columns: repeat(auto-fill, minmax(max(260px, calc((100% - 30px) / 4)), 1fr)); }
.tsc-tile { position: relative; overflow: hidden; display: flex; flex-direction: column; gap: 8px;
  padding: 12px 14px 10px 18px; border: 1px solid var(--card-border); border-radius: 12px;
  background: #fff; box-shadow: 0 1px 2px rgba(20, 25, 50, .05); }
.tsc-tile::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 5px;
  background: #cfd3e0; }
.tsc-tile.is-on { border-color: #bfe0c3; background: #f6fbf6; }
.tsc-tile.is-on::before { background: var(--ok); }
.tsc-tile.is-dirty { box-shadow: 0 0 0 2px rgba(251, 140, 0, .35); }
.tsc-tile__head { display: flex; align-items: flex-start; gap: 8px; }
.tsc-tile__head .dm-dirtydot { flex: none; margin-top: 6px; }
.tsc-tile.is-dirty .tsc-tile__head .dm-dirtydot { visibility: visible; }
.tsc-tile__names { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.tsc-tile__names b { font-size: 15px; }
.tsc-tile__names span { font-size: 12px; color: var(--text-dim); line-height: 1.3; }
.tsc-fixed { flex: none; font-size: 10px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  padding: 3px 9px; border-radius: 999px; background: #e8eaf6; color: var(--nav-bg); }
.tsc-tile__dyn { display: flex; flex-direction: column; gap: 8px; }
.tsc-live { font-size: 13px; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.tsc-live b { font-size: 24px; font-weight: 800; color: var(--text); letter-spacing: -.01em; }
.tsc-live--off b { color: #9aa0b4; }
.tsc-live--na { font-size: 12.5px; font-weight: 600; color: #9aa0b4; }
.tsc-tile__feeds { display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
  padding-top: 8px; border-top: 1px dashed #e1e4ee; }
.tsc-feeds__t { font-size: 10px; font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
  color: var(--text-dim); margin-right: 2px; }
.tsc-feed { font-size: 11px; font-weight: 700; text-decoration: none; padding: 2px 8px;
  border-radius: 999px; border: 1px solid var(--card-border); color: var(--text-dim); background: #fff; }
.tsc-feed--on { background: #e1f2e3; border-color: #bfe0c3; color: #2e7d32; }
.tsc-feed--unk { border-style: dashed; }
.tsc-feed:hover { border-color: var(--nav-bg); color: var(--nav-bg); }
.tsc-note { font-size: 11.5px; color: var(--text-dim); line-height: 1.4; }
.tsc-warn { padding: 7px 10px; border-radius: 8px; background: #fff7e8; border: 1px solid #f3d19c;
  color: #8a5300; font-size: 12px; font-weight: 600; line-height: 1.4; }
.tsc-tile__meta { margin-top: auto; }
.tsc-tile__meta .uik-meta { font-size: 10.5px; opacity: .75; }
.tsc-banner { margin: 0 0 var(--gap, 14px); padding: 10px 14px; border-radius: 10px;
  background: #e8eaf6; border: 1px solid #c5cae9; color: var(--nav-bg); font-size: 13px; font-weight: 600; }
.tsc-banner[hidden] { display: none; }
.tsc-banner a { color: inherit; }
.tsc-pins { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.tsc-pins th { text-align: left; font-size: 10.5px; font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--text-dim); padding: 6px 10px; border-bottom: 1px solid var(--card-border); }
.tsc-pins td { padding: 7px 10px; border-bottom: 1px solid #eef0f5; }
.tsc-pins tr.is-na td { color: #9aa0b4; }
.tsc-mono { font-family: ui-monospace, Consolas, monospace; font-size: 11.5px; }
@media (max-width: 760px) {
  .tsc-pins th:nth-child(3), .tsc-pins td:nth-child(3),
  .tsc-pins th:nth-child(4), .tsc-pins td:nth-child(4) { display: none; }
}
