:root {
  color-scheme: light;
  --bg: #f3f6f5;
  --surface: #fff;
  --border: #dfe8e4;
  --text: #142c25;
  --text-2: #52665e;
  --muted: #60766c;
  --grid: #ecf1ee;
  --accent: #137b5c;
  --soft: #e6f4ed;
  --s1: #3679bf;
  --s2: #c96335;
  --s3: #138d69;
  --s4: #c38a18;
  --s5: #9259b2;
  --s6: #95173e;
  /* Amber for cautions, dark enough to read on its own tint. */
  --warn: #8a5a00;
  --warn-soft: #fbf0d9;
}
@media (prefers-color-scheme: dark) {
  :root {
    color-scheme: dark;
    --bg: #101c18;
    --surface: #192923;
    --border: #30453b;
    --text: #edf7f0;
    --text-2: #b4c8bb;
    --muted: #9eb6a7;
    --grid: #293d32;
    --accent: #71d7ad;
    --soft: #243e30;
    --s1: #71a9e8;
    --s2: #ed9b72;
    --s3: #65d7ab;
    --s4: #edc471;
    --s5: #c79ae4;
    --s6: #d9608a;
    --warn: #edc471;
    --warn-soft: #3a3018;
  }
}
* {
  box-sizing: border-box;
}
/* On an iPhone the page should hold still like an app: it never pans sideways (anything too wide
   is cut off instead of widening the page), double taps don't zoom (pinching still does), text
   keeps its size when the phone turns, and taps don't flash grey. Sideways overscroll is only
   switched off on touch screens (see the end of this file): on a Mac it would also switch off the
   two-finger swipe back and forward. */
html {
  overflow-x: hidden;
  touch-action: manipulation;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  background: var(--bg);
}
body {
  overflow-x: clip;
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font:
    15px/1.55 -apple-system,
    BlinkMacSystemFont,
    'Segoe UI',
    sans-serif;
}
main {
  max-width: 1240px;
  margin: auto;
  padding: 32px max(32px, env(safe-area-inset-right)) 60px max(32px, env(safe-area-inset-left));
}
/* Opened from the home screen, the page runs under the iPhone's status bar: this strip keeps the
   clock readable over content scrolling past. It has no height anywhere else. */
body::before {
  content: '';
  position: fixed;
  z-index: 60;
  top: 0;
  left: 0;
  right: 0;
  height: env(safe-area-inset-top, 0px);
  background: var(--bg);
}
h1,
h2,
h3,
p {
  margin-top: 0;
}
h1 {
  font-size: 27px;
  letter-spacing: -0.8px;
  line-height: 1.25;
  margin-bottom: 5px;
}
h2 {
  font-size: 20px;
  letter-spacing: -0.4px;
  line-height: 1.35;
  margin-bottom: 8px;
}
h3 {
  font-size: 16px;
  margin: 20px 0 8px;
}
a {
  color: var(--accent);
  text-underline-offset: 3px;
}
.sub {
  color: var(--text-2);
  font-size: 13px;
}
.eyebrow {
  font-size: 11px;
  font-weight: 750;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 8px;
}
.app-header {
  display: flex;
  justify-content: space-between;
  gap: 20px;
  align-items: center;
  margin-bottom: 24px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 13px;
}
.brand-mark {
  display: grid;
  place-items: center;
  width: 45px;
  height: 45px;
  border-radius: 15px;
  background: var(--accent);
  color: var(--surface);
  font-size: 25px;
  font-weight: 800;
}
.header-actions {
  display: flex;
  align-items: center;
  gap: 14px;
}
#updated {
  font-size: 12px;
  max-width: 170px;
}
#status {
  font-size: 12px;
  max-width: 600px;
}
.app-nav {
  display: flex;
  gap: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  padding: 6px;
  border-radius: 16px;
  width: fit-content;
  margin-bottom: 24px;
}
.app-nav button {
  display: flex;
  align-items: center;
  gap: 8px;
  border: none;
  min-width: 126px;
  justify-content: center;
  color: var(--text-2);
}
.app-nav button[aria-selected='true'] {
  background: var(--soft);
  color: var(--accent);
  font-weight: 750;
}
/* Between phone and wide screens the tabs give up their fixed width, so all seven fit. */
@media (min-width: 801px) and (max-width: 1100px) {
  .app-nav button {
    min-width: 0;
    padding-inline: 8px;
  }
}
/* The shown view's pages: a row of links that stays at the top while the page scrolls. */
.sub-nav {
  position: sticky;
  top: env(safe-area-inset-top, 0px);
  z-index: 40;
  display: flex;
  gap: 6px;
  overflow-x: auto;
  scrollbar-width: none;
  margin: -12px 0 14px;
  padding: 10px 0;
  background: var(--bg);
}
.sub-nav::-webkit-scrollbar {
  display: none;
}
.sub-nav a {
  flex: none;
  padding: 7px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-2);
  text-decoration: none;
  font-size: 14px;
  font-weight: 600;
  white-space: nowrap;
}
@media (hover: hover) {
  .sub-nav a:hover {
    color: var(--text);
  }
}
.sub-nav a[aria-current='page'] {
  background: var(--soft);
  border-color: var(--accent);
  color: var(--accent);
}
.sub-off {
  display: none !important;
}
/* Time and date pickers stay in sight below the sub-page menu (app.js pinPickers sets the offsets
   and marks them .stuck): the time range across the whole page, the pickers inside a card for as
   long as that card is on screen. */
.range-slot {
  position: sticky;
  top: calc(env(safe-area-inset-top, 0px) + var(--subnav-h, 0px));
  z-index: 30;
  display: flow-root;
  background: var(--bg);
}
.range-slot.stuck {
  box-shadow: 0 1px 0 var(--border);
}
.range-slot.stuck .period-bar {
  margin-bottom: 0;
  padding-bottom: 10px;
}
.range-slot.stuck #range-label {
  display: none;
}
/* 8px lower than the bars above it, filled by the shadow, so sticking doesn't change its size. */
.card .date-sticky {
  position: sticky;
  top: calc(env(safe-area-inset-top, 0px) + var(--subnav-h, 0px) + var(--range-h, 0px) + 8px);
  z-index: 30;
  margin-left: calc(-1 * var(--card-pad));
  margin-right: calc(-1 * var(--card-pad));
  padding-left: var(--card-pad);
  padding-right: var(--card-pad);
  background: var(--surface);
}
.card .date-sticky.stuck {
  box-shadow:
    0 -8px 0 var(--surface),
    0 8px 0 var(--surface),
    0 9px 0 var(--border);
}
#report-band-pick:empty {
  display: none;
}
#report-band-pick label {
  display: flex;
  align-items: center;
  gap: 10px;
}
#report-band-pick select {
  width: auto;
  margin-top: 0;
}
/* On a phone a stuck picker keeps only its controls: one row each. */
@media (max-width: 480px) {
  .range-slot.stuck .eyebrow,
  .cal-toolbar.stuck #cal-mode {
    display: none;
  }
  .cal-toolbar.stuck {
    justify-content: center;
  }
}
.app-nav svg {
  width: 19px;
  height: 19px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}
button,
input,
select {
  font: inherit;
  color: var(--text);
  min-height: 44px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 9px 13px;
}
button {
  cursor: pointer;
  transition:
    background 0.15s,
    border-color 0.15s;
}
/* Hover only where there is a mouse: on a phone it would stick to the last button tapped. A tap
   shows while the finger is down instead. */
@media (hover: hover) {
  button:hover,
  a.button:hover {
    background: var(--soft);
    border-color: var(--accent);
  }
}
button:active,
a.button:active {
  background: var(--soft);
}
a.button {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 9px 13px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  white-space: nowrap;
}
button:disabled {
  opacity: 0.5;
  cursor: default;
}
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
summary:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}
.primary {
  background: var(--accent);
  color: var(--surface);
  border-color: var(--accent);
  font-weight: 700;
}
@media (hover: hover) {
  .primary:hover {
    filter: brightness(0.93);
    background: var(--accent);
  }
}
.primary:active {
  filter: brightness(0.93);
  background: var(--accent);
}
label {
  font-size: 13px;
  color: var(--text-2);
}
label input,
label select {
  display: block;
  width: 100%;
  margin-top: 6px;
}
input[type='checkbox'] {
  width: 20px;
  min-height: 20px;
  display: inline-block;
  vertical-align: middle;
  margin: 0 8px 0 0;
  accent-color: var(--accent);
}
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  margin: 16px 0;
}
.form-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
  margin: 20px 0;
}
.form-grid.two {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
.form-grid.four {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.card {
  --card-pad: 25px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: var(--card-pad);
  margin-bottom: 20px;
  min-width: 0;
}
.card-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 15px;
  margin-bottom: 20px;
}
.card-heading p {
  margin-bottom: 0;
}
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--soft);
  color: var(--accent);
  font-size: 12px;
  font-weight: 650;
  padding: 6px 10px;
  border-radius: 99px;
  white-space: nowrap;
}
.badge.failed {
  background: var(--bg);
  color: var(--s2);
}
.badge.unknown {
  background: var(--bg);
  color: var(--muted);
}
.credential-list {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: baseline;
  gap: 10px 12px;
  margin: 0 0 14px;
}
.credential-list dt {
  font-weight: 650;
}
.credential-list dd {
  margin: 0;
}
.credential-list dd.sub {
  overflow-wrap: anywhere;
}
@media (max-width: 560px) {
  .credential-list {
    grid-template-columns: auto 1fr;
  }
  .credential-list dd.sub {
    grid-column: 1 / -1;
    margin-top: -6px;
  }
}
.badge.warning {
  background: var(--warn-soft);
  color: var(--warn);
}
.alert-conditions {
  display: grid;
  gap: 10px;
  border: 0;
  padding: 0;
  margin: 8px 0 0;
}
.alert-conditions legend {
  font-weight: 650;
  margin-bottom: 4px;
}
.source-list {
  display: grid;
  gap: 12px;
}
.source-row {
  border: 1px solid var(--border);
  border-left: 4px solid var(--accent);
  border-radius: 14px;
  padding: 14px 16px;
}
.source-row.state-warning {
  border-left-color: var(--s4);
}
.source-row.state-failed {
  border-left-color: var(--s2);
}
.source-row.state-off,
.source-row.state-waiting {
  border-left-color: var(--border);
}
.source-row p {
  margin: 6px 0 0;
}
.source-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.source-head h3 {
  margin: 0;
  font-size: 15px;
}
.source-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  color: var(--text-2);
  font-size: 13px;
}
.source-message {
  font-size: 14px;
  overflow-wrap: anywhere;
}
.source-collects {
  margin: 8px 0 0;
  padding-left: 18px;
  color: var(--text-2);
  font-size: 13px;
}
.source-collects li + li {
  margin-top: 2px;
}
.source-row details {
  margin-top: 8px;
  font-size: 13px;
}
.section-intro {
  margin-bottom: 24px;
}
.section-intro p {
  max-width: 640px;
  margin-bottom: 0;
}
.period-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 18px;
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.filters {
  display: flex;
  gap: 4px;
  overflow: auto;
  max-width: 100%;
  padding: 5px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 13px;
  scrollbar-width: none;
}
.filters button {
  border: none;
  min-height: 44px;
  white-space: nowrap;
  padding: 7px 14px;
  background: transparent;
  font-size: 13px;
  color: var(--text-2);
}
.filters button[aria-pressed='true'] {
  background: var(--accent);
  color: var(--surface);
  font-weight: 700;
}
#range-label {
  font-size: 12px;
  margin: 0 0 20px;
  color: var(--muted);
}
.tiles {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin: 20px 0;
}
.tile {
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 17px;
  background: var(--surface);
  min-width: 0;
}
.tile .k {
  font-size: 12px;
  color: var(--text-2);
  margin-bottom: 6px;
}
.tile .v {
  font-size: 26px !important;
  letter-spacing: -0.6px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.tile .v.text {
  font-size: 17px !important;
  letter-spacing: -0.2px;
  line-height: 1.35;
}
.tile .u {
  font-size: 13px;
  font-weight: 400;
  margin-left: 5px;
  letter-spacing: 0;
}
.tile.featured {
  background: var(--soft);
  border-color: transparent;
}
.tile.featured .v {
  color: var(--accent);
}
#tiles {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
#tiles .tile .v {
  font-size: 23px !important;
}
.chart {
  position: relative;
  height: 290px;
  min-width: 0;
}
.chart.chart-short {
  height: 240px;
}
.chart.chart-shorter {
  height: 150px;
}
.chart.chart-gantt {
  height: 130px;
}
.plan-action {
  display: inline-flex;
  align-items: center;
  gap: 7px;
}
.plan-action i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
}
.session-card.now {
  border-color: var(--accent);
}
.chart-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}
.chart-grid .card {
  margin: 0;
}
.offplan-switch {
  display: block;
  margin-top: 12px;
  font-size: 13px;
  color: var(--text-2);
}
.offplan-list {
  list-style: none;
  padding: 0;
  margin: 8px 0 0;
  display: grid;
  gap: 6px;
}
.offplan-list button {
  width: 100%;
  text-align: left;
  display: flex;
  gap: 8px;
  align-items: baseline;
  font-size: 13px;
}
.offplan-list button i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  flex: none;
}
.offplan-list button span {
  color: var(--text-2);
}
/* A chart's key sits straight above its plot: a line for a line, a block for a bar or an area. */
.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  font-size: 12px;
  color: var(--text-2);
  margin: 10px 0 8px;
}
/* A timeline's key has one line per row, led by the row's name. */
.legend p {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 14px;
  width: 100%;
  margin: 0;
}
.legend b {
  font-weight: 600;
  color: var(--text);
}
.legend span {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.legend span[hidden] {
  display: none;
}
.legend i {
  flex: none;
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--c, var(--muted));
}
.legend i.line,
.legend i.dashed {
  width: 18px;
  height: 3px;
  border-radius: 2px;
}
.legend i.dashed {
  border-radius: 0;
  background: repeating-linear-gradient(90deg, var(--c) 0 5px, transparent 5px 8px);
}
.legend i.area {
  width: 14px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--c) 25%, transparent);
  border-top: 2px solid var(--c);
}
/* Grid charging drawn paler at lower power. */
.legend i.ramp {
  width: 18px;
  background: linear-gradient(90deg, color-mix(in srgb, var(--c) 35%, transparent), var(--c));
}
.legend i.offplan {
  width: 14px;
  border-radius: 2px;
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--s4) 30%, transparent) 50%,
    color-mix(in srgb, var(--s6) 30%, transparent) 50%
  );
}
.legend i.hatch,
.legend i.estimated-swatch {
  width: 18px;
  border-radius: 2px;
  background: repeating-linear-gradient(
    45deg,
    color-mix(in srgb, var(--text-2) 35%, transparent) 0 1px,
    transparent 1px 4px
  );
}
.day-picker {
  margin: 0 0 12px;
}
.day-picker summary {
  padding: 6px 0;
  font-size: 12px;
}
.verdict-period label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  color: var(--text-2);
}
.verdict-period input {
  width: auto;
  max-width: 170px;
}
.date-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  margin-bottom: 16px;
}
.date-controls input {
  width: auto;
  max-width: 180px;
}
.date-controls button:first-child,
.date-controls button:nth-child(3) {
  width: 44px;
  padding: 0;
  font-size: 20px;
}
.date-controls #charge-window {
  font-size: 12px;
  margin-left: auto;
}
.info-note {
  padding: 12px 15px;
  background: var(--bg);
  border-radius: 12px;
  line-height: 1.65;
}
.quality-line {
  font-size: 12px;
  margin-top: 18px;
  padding-top: 15px;
  border-top: 1px solid var(--border);
}
.session-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}
.session-card {
  padding: 18px;
  border: 1px solid var(--border);
  border-radius: 14px;
  min-width: 0;
}
.session-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 14px;
  font-size: 13px;
  font-weight: 650;
}
.session-top strong {
  font-size: 21px;
  color: var(--accent);
  white-space: nowrap;
}
.session-metrics {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  font-size: 13px;
}
.session-metrics span {
  display: block;
  font-size: 11px;
  color: var(--text-2);
  margin-bottom: 2px;
}
.session-metrics b {
  font-weight: 600;
}
.session-metrics small {
  display: block;
  font-size: 11px;
  color: var(--muted);
}
table {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
}
th,
td {
  text-align: right;
  padding: 12px 10px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
th:first-child,
td:first-child {
  text-align: left;
}
th {
  color: var(--text-2);
  font-size: 11px;
  font-weight: 600;
}
details {
  margin-top: 16px;
}
details summary {
  cursor: pointer;
  font-size: 13px;
  color: var(--text-2);
  padding: 12px 0;
  min-height: 44px;
}
details[open] > summary {
  color: var(--accent);
  margin-bottom: 12px;
}
.data-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}
.data-grid .card {
  margin: 0;
  border-radius: 14px;
  padding: 18px;
}
.tree {
  overflow: auto;
  max-height: 500px;
}
.tree td {
  white-space: normal;
  text-align: left;
  overflow-wrap: anywhere;
  vertical-align: top;
}
.tree details {
  padding-left: 6px;
}
.source-status {
  color: var(--text-2);
  font-size: 12px;
  overflow-wrap: anywhere;
}
.scroll-table {
  overflow: auto;
}
.error {
  color: var(--s2);
}
.ok {
  color: var(--s3);
}
.empty {
  background: var(--bg);
  border: 1px dashed var(--border);
  border-radius: 14px;
  color: var(--text-2);
  padding: 28px;
  text-align: center;
}
.panel-heading {
  margin: 0 0 22px;
}
#source-search {
  min-width: 0;
  flex: 1;
  width: 100%;
}
[hidden] {
  display: none !important;
}
@media (max-width: 800px) {
  main {
    padding: 22px max(18px, env(safe-area-inset-right)) 105px max(18px, env(safe-area-inset-left));
  }
  .header-actions {
    gap: 8px;
    align-items: flex-end;
    flex-direction: column;
  }
  .app-header {
    margin-bottom: 24px;
  }
  .brand-mark {
    width: 38px;
    height: 38px;
    font-size: 22px;
  }
  .brand {
    gap: 10px;
  }
  h1 {
    font-size: 22px;
  }
  .app-nav {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    width: 100%;
    margin: 0;
    z-index: 50;
    border-radius: 18px 18px 0 0;
    padding: 8px max(8px, env(safe-area-inset-right)) max(8px, env(safe-area-inset-bottom))
      max(8px, env(safe-area-inset-left));
    box-shadow: 0 -6px 24px #142c2508;
    /* A tab bar: no text selection or link menus on a long press. */
    -webkit-user-select: none;
    user-select: none;
    -webkit-touch-callout: none;
    justify-content: space-around;
    gap: 2px;
  }
  .app-nav button {
    min-width: 0;
    flex: 1;
    flex-direction: column;
    gap: 3px;
    font-size: 10px;
    min-height: 52px;
    border-radius: 11px;
    /* Seven tabs with the admin key: "Einstellungen" still fits on a 360 px phone. */
    padding: 5px 0;
  }
  .sub-nav {
    margin: -12px 0 10px;
    padding: 8px 0;
  }
  .app-nav svg {
    width: 21px;
    height: 21px;
  }
  .card {
    --card-pad: 20px;
    border-radius: 17px;
  }
  .chart-grid,
  .data-grid {
    grid-template-columns: 1fr;
  }
  .tiles {
    gap: 9px;
  }
  .tile {
    padding: 14px;
  }
  .tile .v {
    font-size: 22px !important;
  }
  .form-grid,
  .form-grid.four {
    grid-template-columns: 1fr 1fr;
  }
  .session-list {
    grid-template-columns: 1fr;
  }
  #tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  .chart {
    height: 250px;
  }
  .card-heading {
    margin-bottom: 15px;
  }
  h2 {
    font-size: 19px;
  }
}
@media (max-width: 480px) {
  main {
    padding: 18px max(14px, env(safe-area-inset-right)) 105px max(14px, env(safe-area-inset-left));
  }
  .brand-mark {
    display: none;
  }
  #status {
    max-width: 210px;
    font-size: 11px;
  }
  #updated {
    max-width: 120px;
    font-size: 10px;
  }
  #logout {
    min-height: 44px;
    padding: 6px 10px;
    font-size: 11px;
  }
  .eyebrow {
    font-size: 10px;
  }
  .section-intro h2 {
    font-size: 24px;
  }
  .card {
    --card-pad: 17px;
  }
  .tiles {
    grid-template-columns: 1fr 1fr;
  }
  .tile .v {
    font-size: 22px !important;
  }
  .form-grid,
  .form-grid.two {
    grid-template-columns: 1fr;
  }
  .period-bar {
    gap: 10px;
    display: block;
  }
  .filters button {
    padding: 7px 11px;
  }
  .badge {
    font-size: 10px;
  }
  .date-controls {
    gap: 6px;
  }
  .date-controls input {
    max-width: 150px;
    font-size: 14px;
  }
  .date-controls #charge-window {
    width: 100%;
    margin-top: 3px;
  }
  .chart {
    height: 235px;
  }
  .chart-grid {
    gap: 14px;
  }
  .responsive-table thead {
    display: none;
  }
  .responsive-table,
  .responsive-table tbody {
    display: block;
  }
  .responsive-table tr {
    display: grid;
    grid-template-columns: 1fr 1fr;
    border: 1px solid var(--border);
    border-radius: 13px;
    padding: 12px;
    gap: 10px;
    margin-bottom: 12px;
  }
  .responsive-table td {
    display: block;
    border: none;
    text-align: left;
    padding: 0;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .responsive-table td:before {
    content: attr(data-label);
    display: block;
    font-size: 10px;
    color: var(--text-2);
    margin-bottom: 2px;
  }
  .responsive-table td:first-child {
    grid-column: 1/-1;
    font-weight: 650;
  }
  .toolbar {
    align-items: stretch;
  }
  .toolbar button {
    flex: 1;
  }
  .card-heading .badge {
    margin-top: 2px;
  }
  .session-top {
    align-items: flex-start;
  }
  .session-top time {
    max-width: 210px;
  }
}
@media (prefers-reduced-motion: reduce) {
  * {
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

.chart-inspector {
  margin-top: 12px;
}
.chart-controls {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
}
.chart-controls button {
  min-width: 44px;
  min-height: 44px;
  padding: 8px 12px;
  font-size: 14px;
}
.chart-range {
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.chart-step {
  margin-left: auto;
}
.chart canvas {
  user-select: none;
  -webkit-user-select: none;
}
.chart-hint {
  font-size: 12px;
  color: var(--muted);
  margin: 9px 0;
}
/* The values of the picked time: a small card, beside the line inside the graph when it fits,
   otherwise straight below the graph. */
.chart-readout {
  max-width: 560px;
  margin-bottom: 8px;
  padding: 8px 10px;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 10px;
  font-variant-numeric: tabular-nums;
}
.chart-readout.floating {
  position: absolute;
  z-index: 1;
  width: max-content;
  max-width: min(280px, 48%);
  max-height: 100%;
  overflow: hidden;
  margin: 0;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  box-shadow: 0 2px 10px rgb(0 0 0 / 0.12);
  pointer-events: none;
}
.chart-readout strong {
  font-size: 12.5px;
}
.chart-readout p {
  font-size: 11px;
  color: var(--muted);
  margin: 1px 0 6px;
}
.chart-readout p:empty {
  display: none;
}
.chart-readout dl {
  display: grid;
  gap: 4px;
  margin: 0;
}
.chart-readout dl > div {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}
.chart-readout dt {
  font-size: 11.5px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 5px;
  min-width: 0;
}
.chart-readout dt i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.chart-readout dd {
  flex-shrink: 0;
  max-width: 70%;
  margin: 0;
  font-size: 12.5px;
  font-weight: 650;
  text-align: right;
  overflow-wrap: anywhere;
}
.chart canvas:focus-visible {
  outline: 2px solid var(--s1);
  outline-offset: 3px;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Live view */
.live-badge i {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
}
.live-badge.on i {
  animation: live-pulse 1.6s ease-in-out infinite;
}
.live-badge.off {
  background: var(--grid);
  color: var(--muted);
}
@keyframes live-pulse {
  50% {
    opacity: 0.25;
  }
}
.live-flow {
  max-width: 520px;
  margin: 0 auto;
}
#live-diagram {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}
#live-diagram .node circle:first-child {
  fill: var(--bg);
  stroke: var(--border);
  stroke-width: 1.5;
}
#live-diagram .node.featured circle:first-child {
  fill: var(--soft);
  stroke: transparent;
}
#live-diagram .node.active circle:first-child {
  stroke: var(--accent);
}
#live-diagram .icon {
  fill: none;
  stroke: var(--text-2);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
#live-diagram .node.featured .icon {
  stroke: var(--accent);
}
#live-diagram .soc-track,
#live-diagram .soc-ring {
  fill: none;
  stroke-width: 6;
}
#live-diagram .soc-track {
  stroke: var(--grid);
}
#live-diagram .soc-ring {
  stroke: var(--s3);
  stroke-linecap: round;
  stroke-dasharray: 0 100;
  transform: rotate(-90deg);
  transition: stroke-dasharray 0.6s;
}
#live-diagram text {
  fill: var(--text);
  font-variant-numeric: tabular-nums;
}
#live-diagram .soc {
  font-size: 22px;
  font-weight: 750;
  text-anchor: middle;
}
#live-diagram .soc-u {
  font-size: 11px;
  fill: var(--text-2);
  text-anchor: middle;
}
#live-diagram .value {
  font-size: 19px;
  font-weight: 700;
}
/* "No meter" is a remark, not a reading: smaller, so it keeps clear of the Home value. */
#live-diagram .value.note {
  font-size: 14px;
  font-weight: 600;
  fill: var(--text-2);
}
#live-diagram .label {
  font-size: 12px;
  fill: var(--text-2);
}
#live-diagram .center {
  text-anchor: middle;
}
/* The three phases under the diagram; the row opens the Phases page. */
#live-phases[hidden] {
  display: none;
}
#live-diagram .divider {
  stroke: var(--border);
  stroke-width: 1;
}
#live-diagram .phase .value {
  font-size: 17px;
}
#live-diagram .phase.battery .label {
  fill: var(--accent);
  font-weight: 650;
}
#live-diagram .phase-grid {
  font-size: 11px;
  fill: var(--text-2);
}
#live-phases:hover .label,
#live-phases:focus-visible .label {
  text-decoration: underline;
}
#live-diagram .flow {
  fill: none;
  stroke: var(--grid);
  stroke-width: 4;
  stroke-linecap: round;
}
#live-diagram .flow.active {
  stroke: var(--accent);
  stroke-dasharray: 2 10;
  animation: live-flow var(--speed, 1.2s) linear infinite;
}
#live-diagram .flow.active.reverse {
  animation-direction: reverse;
}
#live-diagram .flow.grid-buy {
  stroke: var(--s4);
}
@keyframes live-flow {
  to {
    stroke-dashoffset: -12;
  }
}
.live-tiles {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.live-card.stale #live-diagram {
  opacity: 0.6;
}
/* A stored report is not moving power right now. */
.live-card.stale #live-diagram .flow.active {
  animation: none;
}
@media (max-width: 800px) {
  .live-tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (prefers-reduced-motion: reduce) {
  #live-diagram .flow.active,
  .live-badge.on i {
    animation: none;
  }
}

/* Reports: a month that isn't complete keeps its numbers but says why. */
.report-flag {
  display: block;
  font-size: 12px;
  color: var(--muted);
  font-weight: 400;
}
.saving-positive {
  color: var(--s3);
}
.saving-negative {
  color: var(--s2);
}
#report-months td,
#report-bands td {
  font-variant-numeric: tabular-nums;
}
/* Savings calendar in Reports: a month of days coloured by what each saved. */
.cal-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  margin: 16px 0;
}
.cal-nav {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 700;
}
.cal-nav span {
  min-width: 9em;
  text-align: center;
}
.cal-nav button {
  min-width: 44px;
  min-height: 44px;
  border-radius: 50%;
  font-size: 20px;
  line-height: 1;
}
.cal-nav button:disabled {
  opacity: 0.35;
}
.cal-total .k {
  font-size: 13px;
  color: var(--muted);
}
.cal-total .v {
  font-size: 34px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.cal-total .sub {
  margin: 2px 0 14px;
}
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 6px;
  max-width: 640px;
}
.cal-weekday {
  text-align: center;
  font-size: 12px;
  color: var(--muted);
  padding-bottom: 2px;
}
.cal-day {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 56px;
  padding: 4px 2px;
  border: 1px solid transparent;
  border-radius: 10px;
  background: var(--grid);
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.cal-day .n {
  font-size: 13px;
}
.cal-day .e {
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
}
.cal-day.empty-day {
  color: var(--muted);
  opacity: 0.6;
}
.cal-day.selected {
  border-color: var(--text);
}
/* Today's number in a pill, like the "Now" label on the charts. */
.cal-day.today {
  opacity: 1;
}
.cal-day.today .n {
  padding: 0 7px;
  border-radius: 999px;
  background: var(--text);
  color: var(--surface);
  font-weight: 700;
}
.cal-day.band-1,
.cal-scale .band-1 {
  background: color-mix(in srgb, var(--s2) 30%, var(--surface));
}
.cal-day.band0,
.cal-scale .band0 {
  background: color-mix(in srgb, var(--s4) 18%, var(--surface));
}
.cal-day.band1,
.cal-scale .band1 {
  background: color-mix(in srgb, var(--s4) 38%, var(--surface));
}
.cal-day.band2,
.cal-scale .band2 {
  background: color-mix(in srgb, var(--s4) 62%, var(--surface));
}
.cal-day.band3,
.cal-scale .band3 {
  background: var(--s4);
  color: #1d1604;
}
.cal-scale {
  max-width: 640px;
  margin-top: 14px;
}
.cal-scale .bar {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
}
.cal-scale .ticks {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  color: var(--muted);
  margin-top: 4px;
  font-variant-numeric: tabular-nums;
}
@media (max-width: 520px) {
  .cal-grid {
    gap: 4px;
  }
  .cal-day {
    min-height: 50px;
  }
  .cal-day .e {
    font-size: 10.5px;
  }
}
#verdict-tiles .tile.featured .v .sub {
  margin-top: 6px;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text-2);
}
#verdict-caveats {
  margin: 8px 0 0;
  padding-left: 18px;
  line-height: 1.6;
}
@media (max-width: 800px) {
  #verdict-tiles .tile.featured {
    grid-column: 1 / -1;
  }
}

.payback-bar {
  height: 10px;
  border-radius: 99px;
  background: var(--bg);
  overflow: hidden;
  margin: 4px 0 8px;
}
.payback-bar i {
  display: block;
  height: 100%;
  width: 0;
  min-width: 2px;
  background: var(--accent);
  border-radius: 99px;
}
/* The suggestion gets its own row, the figures share the one below. */
#size-tiles .tile.featured {
  grid-column: 1 / -1;
}
#size-tiles .tile .v .sub {
  margin-top: 6px;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--text-2);
}
#size-table tr.size-best td {
  font-weight: 600;
}
@media (min-width: 481px) {
  #size-table tr.size-second td {
    border-top: 2px solid var(--border);
  }
}
.lang-toggle {
  font-size: 13px;
  padding: 6px 12px;
}
.glossary dl {
  display: grid;
  grid-template-columns: minmax(120px, 220px) 1fr;
  gap: 6px 16px;
  margin: 12px 0 0;
  font-size: 14px;
}
.glossary dt {
  font-weight: 600;
}
.glossary dd {
  margin: 0;
  color: var(--text-2);
}
@media (max-width: 600px) {
  .glossary dl {
    grid-template-columns: 1fr;
    gap: 2px;
  }
  .glossary dd {
    margin-bottom: 8px;
  }
}
/* Without the admin key the setup isn't shown at all (app.js applyLock). */
body.locked [data-admin],
body.locked [data-view='settings'],
body.locked [data-view='devices'],
body.ask-closed [data-view='ask'] {
  display: none !important;
}
/* Notes only a visitor needs, like where the downloads went. */
body:not(.locked) [data-visitor] {
  display: none !important;
}
.lock-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  padding: 6px 12px;
}
.lock-toggle svg {
  width: 16px;
  height: 16px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Open shackle once unlocked. */
.lock-toggle.unlocked #lock-shackle {
  transform: translateX(-6px) rotate(-12deg);
  transform-origin: 8px 11px;
}
.lock-toggle.unlocked {
  color: var(--accent);
  border-color: var(--accent);
}
#admin-dialog {
  width: min(440px, calc(100vw - 32px));
  border: 1px solid var(--border);
  border-radius: 17px;
  background: var(--surface);
  color: var(--text);
  padding: 22px;
}
#admin-dialog::backdrop {
  background: rgb(0 0 0 / 0.45);
}
#admin-dialog h2 {
  margin: 0 0 6px;
}
#admin-dialog label {
  display: grid;
  gap: 6px;
  margin: 14px 0;
}

/* Ask page (app.js askQuestion). */
textarea {
  font: inherit;
  color: var(--text);
  width: 100%;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface);
  padding: 9px 13px;
  margin-top: 6px;
  resize: vertical;
  box-sizing: border-box;
}
textarea:focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 3px;
}
.ask-examples {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 12px 0;
}
.ask-examples button {
  font-size: 13px;
  min-height: 36px;
  padding: 6px 12px;
  border-radius: 999px;
  color: var(--text-2);
  text-align: left;
}
.ask-answer {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
}
.ask-text {
  line-height: 1.55;
  overflow-wrap: anywhere;
}
.ask-text p {
  margin: 0 0 10px;
}
.ask-text ul {
  margin: 0 0 10px;
  padding-left: 20px;
}
.ask-sources {
  margin-top: 12px;
  font-size: 13px;
  color: var(--text-2);
}
.ask-sources a {
  margin-right: 12px;
  white-space: nowrap;
}
.ask-note {
  margin: 16px 0 0;
}
/* Live → Phases: one tile per phase, the battery's phase highlighted, and the advice list. */
.phase-heading {
  flex-wrap: wrap;
}
.phase-tiles .tile .sub {
  margin: 6px 0 0;
  font-size: 12px;
}
.phase-tiles .tile.feeding .v {
  color: var(--s2);
}
.phase-safe {
  margin: 0 0 16px;
}
.phase-safe .sub {
  margin: 6px 0 0;
}
.phase-safe.over {
  background: var(--warn-soft);
}
.phase-safe.over .v {
  color: var(--warn);
}
.advice-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 10px;
}
.advice-list .advice {
  padding: 12px 15px 12px 13px;
  border-left: 3px solid var(--s1);
  background: var(--bg);
  border-radius: 0 12px 12px 0;
  line-height: 1.6;
}
.advice-list .advice.ok {
  border-left-color: var(--accent);
}
.advice-list .advice.warn {
  border-left-color: var(--warn);
  background: var(--warn-soft);
}
@media (max-width: 560px) {
  .phase-tiles {
    grid-template-columns: 1fr;
  }
}
/* Live → Battery mode: one colour per mode of the Zendure app. */
.mode-picker {
  flex-wrap: wrap;
  margin-bottom: 6px;
}
.mode-help {
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 4px 14px;
  margin: 14px 0 0;
  color: var(--text-2);
  font-size: 14px;
}
.mode-help dt {
  font-weight: 600;
  color: var(--text);
}
.mode-help dd {
  margin: 0;
}
@media (max-width: 640px) {
  .mode-help {
    grid-template-columns: 1fr;
  }
  .mode-help dd {
    margin-bottom: 6px;
  }
}
.mode-bar {
  display: flex;
  height: 14px;
  border-radius: 7px;
  overflow: hidden;
  background: var(--grid);
  margin-bottom: 12px;
}
.mode-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  margin-right: 8px;
}
.mode-12 {
  background: var(--s1);
}
.mode-9 {
  background: var(--s3);
}
.mode-10 {
  background: var(--s4);
}
.mode-0 {
  background: var(--s5);
}
.mode-11 {
  background: var(--s2);
}
.mode-dashboard {
  background: var(--s6);
}

/* Last, so it wins over the smaller field sizes above: iPhones zoom the page into any field
   written smaller than 16px when it is tapped, and stay zoomed so the page pans sideways. */
@media (pointer: coarse) {
  /* Touch screens only: a Mac trackpad's two-finger swipe back and forward needs the overscroll. */
  html {
    overscroll-behavior-x: none;
  }
  .sub-nav {
    overscroll-behavior-x: contain;
  }
  input,
  select,
  textarea,
  .date-controls input {
    font-size: max(16px, 1em);
  }
}
