/* Three theme states: "auto" (follow the OS/browser via prefers-color-scheme,
   the default - no data-theme attribute set), or an explicit "light"/"dark"
   stamp on <html> from the nav toggle (static/common.js), which always wins
   over the OS preference. Light is the base (untagged :root); dark is
   layered on top via the media query (guarded so an explicit light stamp
   can still beat OS-dark) and via the explicit dark stamp. */
:root {
  color-scheme: light;
  --surface-1:      #fcfcfb;
  --surface-2:      #f2f1ee;
  --page-plane:     #f9f9f7;
  --text-primary:   #0b0b0b;
  --text-secondary: #52514e;
  --text-muted:     #898781;
  --gridline:       #e1e0d9;
  --baseline:       #c3c2b7;
  --border:         rgba(11,11,11,0.10);
  --good:           #006300;
  --critical:       #d03b3b;

  --series-1: #2a78d6; /* blue */
  --series-2: #eb6834; /* orange */
  --series-3: #1baf7a; /* aqua */
  --series-4: #eda100; /* yellow */
  --series-5: #e87ba4; /* magenta */
  --series-6: #008300; /* green */
  --series-7: #4a3aa7; /* violet */
  --series-8: #e34948; /* red */

  /* Chart threshold-band backgrounds (cold/hot/good-range annotations) -
     tints of series-1 (blue), series-5 (magenta) and --good, not new hues. */
  --zone-cold: rgba(42,120,214,0.12);
  --zone-hot:  rgba(232,123,164,0.16);
  --zone-good: rgba(0,99,0,0.10);
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --surface-1:      #1a1a19;
    --surface-2:      #232322;
    --page-plane:     #0d0d0d;
    --text-primary:   #ffffff;
    --text-secondary: #c3c2b7;
    --text-muted:     #898781;
    --gridline:       #2c2c2a;
    --baseline:       #383835;
    --border:         rgba(255,255,255,0.10);
    --good:           #0ca30c;
    --critical:       #e66767;

    --series-1: #3987e5;
    --series-2: #d95926;
    --series-3: #199e70;
    --series-4: #c98500;
    --series-5: #d55181;
    --series-6: #008300;
    --series-7: #9085e9;
    --series-8: #e66767;

    --zone-cold: rgba(57,135,229,0.16);
    --zone-hot:  rgba(213,81,129,0.18);
    --zone-good: rgba(12,163,12,0.14);
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --surface-1:      #1a1a19;
  --surface-2:      #232322;
  --page-plane:     #0d0d0d;
  --text-primary:   #ffffff;
  --text-secondary: #c3c2b7;
  --text-muted:     #898781;
  --gridline:       #2c2c2a;
  --baseline:       #383835;
  --border:         rgba(255,255,255,0.10);
  --good:           #0ca30c;
  --critical:       #e66767;

  --series-1: #3987e5;
  --series-2: #d95926;
  --series-3: #199e70;
  --series-4: #c98500;
  --series-5: #d55181;
  --series-6: #008300;
  --series-7: #9085e9;
  --series-8: #e66767;

  --zone-cold: rgba(57,135,229,0.16);
  --zone-hot:  rgba(213,81,129,0.18);
  --zone-good: rgba(12,163,12,0.14);
}

* { box-sizing: border-box; }

body {
  font-family: system-ui, -apple-system, "Segoe UI", sans-serif;
  background: var(--page-plane);
  color: var(--text-primary);
  margin: 0;
  padding: 0;
}

.topbar {
  padding: 1rem 1.5rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-1);
}

.topbar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 0.75rem;
}

.topbar-title {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.topbar-badges {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-shrink: 0;
}

.topbar h1 {
  margin: 0;
  font-size: 1.3rem;
  color: var(--series-1);
}

/* The official Homey wordmark is black-on-transparent - a white chip keeps
   it legible in dark mode, where it would otherwise vanish. */
.homey-logo {
  height: 26px;
  width: auto;
  background: #ffffff;
  border-radius: 4px;
  padding: 3px 8px;
}

.homey-device-icon {
  height: 44px;
  width: auto;
  border-radius: 8px;
  flex-shrink: 0;
}

.topbar nav { display: flex; align-items: flex-start; flex-wrap: wrap; gap: 0.25rem; }

/* The page tabs plus Theme toggle and Log out, in one fixed 5-column
   grid - left-aligned (grid's default), regardless of viewport width. Was
   a plain flex-wrap before (2026-08-09), which gave an uneven,
   width-dependent split; then a fixed 2-row layout with Theme/Log out
   outside the grid, pushed right (2026-08-09). Since 2026-08-21 Theme and
   Log out live INSIDE the grid right after the last tab (operator's ask:
   "place les à la suite de Sweeties"). Columns are fixed at the longest
   tab's width (13.5rem) with auto-fill so buttons are uniform, never
   stretched, and as many fit per row as the viewport allows. */
.nav-tabs {
  display: grid;
  /* 13.5rem (216px) - measured the longest real label ("Temp/Humidity
     History", 198.5px on one line) live in the browser and added a small
     buffer, rather than guessing. 11.5rem (2026-08-09, earlier same day)
     was too narrow and wrapped that one tab to 2 lines, which stretched
     every other tab in its grid row to match - not just cosmetic on that
     one tab, it broke the whole row's uniform height. */
  /* 13.5rem (216px) - the width of the LONGEST tab (measured live:
     "Temp/Humidity History", 198.5px content + padding, 2026-08-09). All
     buttons are exactly this size - operator: "les boutons doivent être
     aussi grand le plus grand d'entre eux" (2026-08-21). auto-fill packs
     the max number of columns per row (6-7 on a wide screen instead of 5),
     so the nav takes as few lines as possible. */
  /* width:100% is required for auto-fill: as a flex item with no width,
     the grid container collapses to a single track (auto-fill has no
     definite available space to fill). With 100%, it packs the max number
     of 13.5rem columns per row the viewport allows. */
  width: 100%;
  grid-template-columns: repeat(auto-fill, 13.5rem);
  gap: 0.25rem;
}

.topbar nav a {
  color: var(--text-secondary);
  text-decoration: none;
  padding: 0.4rem 0.75rem;
  border-radius: 0.5rem;
  font-size: 0.9rem;
  background: var(--surface-2);
  text-align: center;
  white-space: nowrap;
}

/* Theme toggle and Log out are grid cells inside .nav-tabs now
   (2026-08-21) - the grid's 13.5rem columns size them, no width rule needed. */

.topbar nav a:hover { background: var(--gridline); color: var(--text-primary); }
.topbar nav a.active { background: var(--series-1); color: #ffffff; }

.theme-toggle-btn {
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--text-secondary);
  background: var(--surface-2);
  border: none;
  padding: 0.4rem 0.75rem;
  border-radius: 0.5rem;
  cursor: pointer;
}
.theme-toggle-btn:hover { background: var(--gridline); color: var(--text-primary); }

main {
  padding: 1.5rem;
  max-width: 1100px;
  margin: 0 auto;
}

.page-footer {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0.5rem 1.5rem 1.5rem;
  color: #6b6a66;
  font-size: 0.75rem;
  text-align: center;
}

.footer-logo {
  height: 0.9rem;
  width: auto;
  vertical-align: -0.1rem;
  margin-left: 0.15rem;
}

.loading, .error, .empty {
  color: var(--text-muted);
  padding: 2rem 0;
  text-align: center;
}

.error { color: var(--critical); }

.card {
  background: var(--surface-1);
  border: 1px solid var(--border);
  padding: 1.25rem 1.5rem;
  border-radius: 0.75rem;
  margin-bottom: 1.25rem;
}

.card h2 {
  margin-top: 0;
  font-size: 1.05rem;
  color: var(--text-primary);
}

.card h3 {
  margin: 0 0 0.75rem 0;
  font-size: 0.85rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-muted);
}

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 1rem;
}

.device-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--gridline);
}
.device-row:last-child { border-bottom: none; }

/* Notifications page: a muted alert stays listed (still a real, active
   condition) but visually recedes so unmuted ones stand out at a glance. */
.notification-row.muted { opacity: 0.55; }

/* Speaker icon next to the mute toggle: 🔊 in full color when a notification
   is audible (not muted), swapping to the already-crossed-out 🔇 glyph AND
   greyed/faded out once muted - the emoji swap alone covers "barré", the
   filter/opacity covers "passe en gris" (Bazo, 2026-08-07 asked for either). */
.speaker-icon {
  font-size: 1.1rem;
  line-height: 1;
  transition: filter 0.15s, opacity 0.15s;
}
.speaker-icon.muted {
  filter: grayscale(1);
  opacity: 0.45;
}

.archive-btn {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  padding: 0.3rem 0.65rem;
  font-size: 0.78rem;
  color: var(--text-secondary);
  cursor: pointer;
}
.archive-btn:hover { background: var(--gridline); color: var(--text-primary); }

.device-name { font-weight: 600; }
.device-trigger-label { display: flex; align-items: baseline; }
.device-temps { margin-left: 0.5rem; }
.device-name-row { display: flex; align-items: baseline; }
.device-power { margin-left: 0.5rem; color: var(--series-8); }

.boiler-table {
  width: 100%;
  border-collapse: collapse;
  margin-top: 0.5rem;
  font-size: 0.95rem;
}
.boiler-table th {
  text-align: left;
  color: var(--text-muted);
  font-size: 0.8rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 0.5rem 0.75rem;
  border-bottom: 2px solid var(--gridline);
}
.boiler-table td {
  padding: 0.5rem 0.75rem;
  border-bottom: 1px solid var(--gridline);
  vertical-align: top;
}
.boiler-table tbody tr:hover { background: var(--surface-2); }
.temp-actual { color: #3aa76d; font-weight: 600; }
.temp-target { color: #e05d44; font-weight: 600; }
.device-zone { color: var(--text-muted); font-size: 0.85rem; }

.stat-tile {
  background: var(--surface-2);
  border-radius: 0.6rem;
  padding: 0.85rem 1rem;
}
/* Climate & Heating page: distinguish sensor tiles from heating-valve tiles
   at a glance, using the same categorical slots as the rest of the charts
   (blue = slot 1, orange = slot 2) but as a subtle tint, not full saturation. */
.stat-tile.sensor { background: color-mix(in srgb, var(--series-1) 15%, var(--surface-2)); }
.stat-tile.heating { background: color-mix(in srgb, var(--series-2) 15%, var(--surface-2)); }
/* Instant Power page: same blue/orange tints as above, generically named
   since these two tiles (IT Infra total, Total instantaneous power) aren't
   sensor/heating tiles - just reusing the same categorical color slots for
   visual consistency across pages. */
.stat-tile.tile-blue { background: color-mix(in srgb, var(--series-1) 15%, var(--surface-2)); }
.stat-tile.tile-orange { background: color-mix(in srgb, var(--series-2) 15%, var(--surface-2)); }
.stat-tile.tile-green { background: color-mix(in srgb, var(--series-8) 15%, var(--surface-2)); }
/* Target temperature above current reading = boiler is probably actively heating this valve. */
.stat-tile.heating.heating-active { border: 2px solid var(--series-8); }
.heating-flame.inactive { filter: grayscale(1); opacity: 0.35; }
.stat-tile .label {
  color: var(--text-muted);
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin-bottom: 0.25rem;
}
.stat-tile .value {
  font-size: 1.4rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.stat-tile .sub {
  color: var(--text-secondary);
  font-size: 0.85rem;
}
/* Climate & Heating: sensors pushed LEFT, heating valves pushed RIGHT.
   Narrow tiles (150px min) so 2 fit per row on mobile. */
.climate-row {
  display: flex;
  justify-content: flex-start;
  align-items: flex-start;
  gap: 0.75rem;
  margin-bottom: 1rem;
}
.climate-col {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.6rem;
  flex: 0 1 auto;
  min-width: 0;
}
/* All climate tiles the SAME size: width of the widest tile (Bathroom Thermostat) */
.climate-row .stat-tile {
  width: 191px;
  min-height: 79px;
  padding: 0.85rem 0.6rem;
}
.climate-row .stat-tile .label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
/* Empty blue placeholder for rooms without sensors */
.climate-row .stat-tile.sensor-empty {
  border: 1px dashed var(--border, rgba(128,128,128,0.45));
  background: transparent;
  min-height: 79px;
}
@media (max-width: 700px) {
  /* narrower on mobile so 2 tiles still fit per row */
  .climate-row .stat-tile {
    width: 155px;
  }
}

/* Climate sensor tile: temperature + humidity side by side in big text,
   so the tile stays short (no separate humidity sub-line). */
.stat-tile .sensor-values {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
}
.stat-tile .sensor-values .value {
  color: #3aa76d; /* temperature (measured) — green like heating current */
}
.stat-tile .sensor-values .value.humidity {
  color: var(--series-1); /* humidity — blue */
}
/* Heating tile: target (red, left) | current (green, right), one line.
   Example: 15° / 26.7° — we aim for 15° but it is 26.7°. */
.stat-tile .heating-values {
  display: flex;
  align-items: baseline;
  gap: 0.45rem;
}
.stat-tile .heating-values .value.target {
  color: #e05d44;
}
.stat-tile .heating-values .value.current {
  color: #3aa76d;
}
.stat-tile .heating-values .heating-sep {
  color: var(--text-muted);
  font-size: 1rem;
}

/* Toggle switch */
.toggle {
  position: relative;
  display: inline-block;
  width: 42px;
  height: 24px;
  flex-shrink: 0;
}
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle .slider {
  position: absolute; inset: 0;
  background: var(--baseline);
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s;
}
.toggle .slider::before {
  content: "";
  position: absolute;
  width: 18px; height: 18px;
  left: 3px; top: 3px;
  background: #fff;
  border-radius: 50%;
  transition: transform 0.15s;
}
.toggle input:checked + .slider { background: var(--good); }
.toggle input:checked + .slider::before { transform: translateX(18px); }
.toggle input:disabled + .slider { cursor: not-allowed; opacity: 0.4; }

/* Big toggle for the sweeties page plug card (same look, larger) */
.toggle.large { width: 64px; height: 34px; }
.toggle.large .slider::before { width: 26px; height: 26px; left: 4px; top: 4px; }
.toggle.large input:checked + .slider::before { transform: translateX(30px); }

/* Sweeties page value colors: current green / target red / humidity blue */
.sweeties-current { color: #3aa76d; font-weight: 600; }
.sweeties-target { color: #e05d44; font-weight: 600; }
.sweeties-humidity { color: var(--series-1); font-weight: 600; }

.lock-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  color: var(--text-muted);
  padding: 0.25rem 0.5rem;
}
.lock-btn.locked { color: var(--critical); }
.lock-btn:hover { color: var(--text-primary); }

.controls-row {
  display: flex;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1.25rem;
  flex-wrap: wrap;
}

select, input[type="number"] {
  background: var(--surface-2);
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  padding: 0.45rem 0.75rem;
  font-size: 0.9rem;
}

input[type="number"] { width: 5.5rem; font-variant-numeric: tabular-nums; }

/* Temp/Humidity History: "Since 1st Jan" / "Past week" range toggle next
   to the sensor selector - same pill shape/active-state pattern as the
   topbar nav tabs, scoped to this page's controls-row. */
.range-btn {
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--text-secondary);
  background: var(--surface-2);
  border: none;
  padding: 0.45rem 0.9rem;
  border-radius: 0.5rem;
  cursor: pointer;
}
.range-btn:hover { background: var(--gridline); color: var(--text-primary); }
.range-btn.active { background: var(--series-1); color: #ffffff; }
.range-btn:disabled { opacity: 0.4; cursor: not-allowed; }
.range-btn:disabled:hover { background: var(--surface-2); color: var(--text-secondary); }

.legend {
  display: flex;
  gap: 1rem;
  margin-bottom: 0.5rem;
  font-size: 0.85rem;
  color: var(--text-secondary);
}
.legend .item { display: flex; align-items: center; gap: 0.4rem; }
.legend .swatch { width: 10px; height: 10px; border-radius: 2px; display: inline-block; }

.zone-heading {
  color: var(--text-muted);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin: 1.25rem 0 0.4rem 0;
}
.zone-heading:first-child { margin-top: 0; }

.chart-caption {
  color: var(--text-muted);
  font-size: 0.8rem;
  margin: -0.5rem 0 0.75rem 0;
}

canvas { max-width: 100%; }

a.nav-link-card {
  display: block;
  color: var(--text-primary);
  text-decoration: none;
}
a.nav-link-card .card { transition: border-color 0.15s; }
a.nav-link-card:hover .card { border-color: var(--series-1); }

/* Home page: fixed 2-column grid so tiles sit 2-by-2 instead of stacking
   full-width one per row (the default .grid's auto-fill/minmax would have
   given 3+ narrow columns on a wide screen instead). Tighter padding + no
   redundant margin-bottom (the grid's own `gap` already spaces rows) so
   each tile is shorter, not just narrower. */
.home-grid { grid-template-columns: repeat(2, 1fr); }
.home-grid .card { margin-bottom: 0; padding: 1rem 1.25rem; }
@media (max-width: 700px) {
  .home-grid { grid-template-columns: 1fr; }
  .nav-tabs { grid-template-columns: repeat(2, 1fr); }
}


/* Boiler History page: a single shared ON/OFF timeline, not a Chart.js
   chart - the data is inherently sparse (a handful of ON segments/trigger
   points, not a per-sample series), so a plain absolutely-positioned DOM
   strip reads more simply than forcing Chart.js into an unsupported
   floating-bar Gantt shape. Red reuses --series-8, the same color already
   meaning "actively heating" on the Climate & Heating / Sweeties tiles. */
.boiler-timeline-wrap { position: relative; }
.boiler-timeline {
  position: relative;
  height: 56px;
  background: var(--surface-2);
  border-radius: 0.5rem;
  overflow: visible;
}
.boiler-segment {
  position: absolute;
  top: 0;
  bottom: 0;
  background: var(--series-8);
  border-radius: 0.3rem;
}
.boiler-trigger {
  position: absolute;
  top: -9px;
  width: 0;
  height: 0;
  border-left: 5px solid transparent;
  border-right: 5px solid transparent;
  border-top: 8px solid var(--text-primary);
  transform: translateX(-5px);
}
.boiler-timeline-axis {
  display: flex;
  justify-content: space-between;
  color: var(--text-muted);
  font-size: 0.8rem;
  margin-top: 0.4rem;
}


/* Marks where 6-hourly historical backfill gives way to the real 60s live
   poller (DENSE_DATA_START) - segments to the left of this line can only be
   timed to within a 6-hour bucket, segments to the right are accurate to
   the minute. A dashed divider + the caption's own text carry that
   distinction rather than a second bar color, to keep the timeline itself
   simple (still just ON=red / OFF=empty). */
.boiler-divider {
  position: absolute;
  top: -4px;
  bottom: -4px;
  width: 0;
  border-left: 2px dashed var(--text-muted);
}
/* Subtle month-boundary gridlines on the Boiler Activity timeline - behind
   the ON segments/markers (see DOM order in page_boiler_history.js), just
   there to help the eye separate months on a long single-strip timeline. */
.boiler-month-line {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0;
  border-left: 1px solid var(--gridline);
  z-index: 0;
}

/* ON-period accordion (Boiler History): a native <details>/<summary> per
   segment needs no extra JS/state - the date range + duration is always
   visible, individual thermostat trigger rows (.device-row, reused from
   the Climate/Smart-Plugs pages) are one click away instead of hidden
   behind hover-only tooltips, which stopped being discoverable once a full
   year of real data pushed the trigger count into the hundreds. */
details {
  border-bottom: 1px solid var(--gridline);
  padding: 0.5rem 0;
}
details summary {
  cursor: pointer;
  font-weight: 600;
  color: var(--text-primary);
}
details[open] summary { margin-bottom: 0.4rem; }
