/* Copied from src/webserver/home.html (local ESP webserver) — first on 2026-08-06,
   re-synced on 2026-09-25 (Rules/PTP tab: toolbox, helper variables, rule cards).
   Per docs/superpowers/specs/2026-08-01-mqtt-cloud-access-design.md "Wygląd cloud UI":
   deliberately NOT a shared file — local webserver stays untouched, this copy does not
   auto-sync with future local style changes. */

:root {
  --bg: #0f1724;
  --card: #0b1220;
  --muted: #93a1b0;
  --accent: #03A9F4;
  --accent-600: #0288d1;
  --danger: #ff5252;
  --danger-600: #e64545;
  --glass: rgba(255, 255, 255, 0.04);
  --radius: 12px;
  --sidebar-bg: #0a1320;
  --sidebar-border: rgba(255,255,255,0.06);
  --sidebar-width: 200px;
  --bottomnav-h: 56px;
  font-family: Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial;
}

* {
  box-sizing: border-box
}

html,
body {
  height: 100%
}

body {
  margin: 0;
  padding: 0;
  background: linear-gradient(180deg, var(--bg) 0%, #071022 100%);
  background-attachment: fixed;
  color: #e6eef6;
  min-height: 100vh;
}

.card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
  border-radius: var(--radius);
  padding: 22px;
  box-shadow: 0 6px 30px rgba(2, 8, 23, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.04);
}

.brand {
  display: flex;
  gap: 12px;
  align-items: center;
  margin-bottom: 12px
}

.logo {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: linear-gradient(135deg, var(--accent), var(--accent-600));
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  color: #042236;
  box-shadow: 0 4px 18px rgba(3, 169, 244, 0.18);
}

.brand h1 {
  font-size: 16px;
  margin: 0
}

.brand p {
  margin: 0;
  font-size: 12px;
  color: var(--muted)
}

label {
  display: block;
  font-size: 13px;
  margin-bottom: 4px;
  color: #d9e7f4
}

.input {
  width: 100%;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--glass);
  border: 1px solid rgba(255, 255, 255, 0.04);
  color: inherit;
  font-size: 14px;
  font-family: inherit;
}

select option {
  background: #0f1724;
  /* match var(--bg) to align with mobile dark mode style */
  color: #fff;
  font-family: inherit;
}

.field {
  margin-bottom: 10px
}

.row {
  display: flex;
  gap: 8px
}

.wifi-signal {
  display: inline-flex;
  align-items: flex-end;
  gap: 2px;
  height: 22px;
  padding: 0 6px;
  align-self: center;
}
.wifi-signal span {
  display: block;
  width: 4px;
  background: rgba(255,255,255,0.18);
  border-radius: 1px;
  transition: background 0.2s;
}
.wifi-signal span:nth-child(1) { height: 25%; }
.wifi-signal span:nth-child(2) { height: 50%; }
.wifi-signal span:nth-child(3) { height: 75%; }
.wifi-signal span:nth-child(4) { height: 100%; }
.wifi-signal[data-bars="1"] span:nth-child(-n+1),
.wifi-signal[data-bars="2"] span:nth-child(-n+2),
.wifi-signal[data-bars="3"] span:nth-child(-n+3),
.wifi-signal[data-bars="4"] span:nth-child(-n+4) {
  background: #4ade80;
}

.controls {
  display: flex;
  align-items: stretch;
  gap: 10px;
  margin-top: 18px
}

#scanModbusPanel .controls {
  flex-wrap: wrap;
}

#scanModbusPanel .controls > .btn,
#scanModbusPanel .controls > .btn-danger {
  flex: 1 1 120px;
}

.controls .btn,
.controls .btn-danger,
.controls .secondary {
  flex: 1;
}

.btn {
  background: linear-gradient(180deg, var(--accent), var(--accent-600));
  border: none;
  color: #042236;
  padding: 10px 16px;
  border-radius: 12px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 8px 30px rgba(3, 169, 244, 0.18);
}

.btn-danger {
  background: linear-gradient(180deg, var(--danger), var(--danger-600));
  border: none;
  color: #fff;
  padding: 10px 16px;
  border-radius: 12px;
  font-weight: 600;
  cursor: pointer;
  box-shadow: 0 8px 30px rgba(255, 82, 82, 0.2);
}

.secondary, .btn-secondary {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--muted);
  padding: 10px 14px;
  border-radius: 12px;
  cursor: pointer;
  transition: all 0.2s;
  font-weight: 500;
}
.secondary:hover, .btn-secondary:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.2);
  color: #fff;
}

.error {
  color: var(--danger);
  font-size: 13px;
  margin-top: 6px;
}

.status-console {
  background: rgba(0, 0, 0, 0.3);
  border-radius: 8px;
  padding: 12px;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 13px;
  margin-top: 12px;
  border: 1px solid rgba(255, 255, 255, 0.05);
  min-height: 40px;
  line-height: 1.5;
}
.status-ok { color: #81c784; }
.status-err { color: #e57373; font-weight: bold; }

/* PTP autocomplete popup — VS Code style */
.ptp-suggest {
  position: absolute;
  background: #1a1e2a;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 6px;
  max-height: 240px;
  overflow-y: auto;
  z-index: 10000;
  font-family: 'Consolas', 'Monaco', monospace;
  font-size: 13px;
  min-width: 220px;
  max-width: 400px;
  box-shadow: 0 6px 18px rgba(0,0,0,0.5);
}
.ptp-suggest.hidden { display: none; }
.ptp-suggest .sug-item {
  padding: 5px 10px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: #e0e0e0;
  white-space: nowrap;
}
.ptp-suggest .sug-item .sug-hint {
  color: #8e99b3;
  font-size: 11px;
  overflow: hidden;
  text-overflow: ellipsis;
}
.ptp-suggest .sug-item.active, .ptp-suggest .sug-item:hover {
  background: #2a3040;
}

/* PTP Easy mode */
.ptp-mode-tabs {
  display: flex;
  gap: 4px;
  background: rgba(0,0,0,0.25);
  border-radius: 10px;
  padding: 4px;
  margin-bottom: 12px;
}
.ptp-mode-tabs button {
  flex: 1;
  background: transparent;
  border: none;
  color: var(--muted);
  padding: 8px 12px;
  border-radius: 7px;
  cursor: pointer;
  font-weight: 500;
  transition: all 0.15s;
}
.ptp-mode-tabs button.active {
  background: var(--accent);
  color: #042236;
  font-weight: 600;
}
/* Karta reguły = pełnoprawna .card (taki sam background/shadow/radius). Container
   #ptpRulesList obsługuje spacing przez gap, więc margin-bottom: 0. */
.ptp-rule-card {
  background: linear-gradient(180deg, rgba(255,255,255,0.02), rgba(255,255,255,0.01));
  border: 1px solid rgba(255,255,255,0.04);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: 0 6px 30px rgba(2,8,23,0.6);
  margin-bottom: 0;
}
.ptp-rule-card .ptp-rule-hdr {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 10px;
  font-weight: 600;
  color: var(--muted);
  font-size: 13px;
  cursor: pointer;
  user-select: none;
}
.ptp-rule-card .ptp-rule-toggle {
  display: inline-block;
  margin-right: 8px;
  transition: transform 0.2s;
  color: var(--muted);
  font-size: 10px;
}
.ptp-rule-card.collapsed .ptp-rule-toggle { transform: rotate(-90deg); }
.ptp-rule-card.collapsed .ptp-rule-body { display: none; }
.ptp-rule-card.collapsed { margin-bottom: 8px; }
.ptp-rule-card.collapsed .ptp-rule-hdr { margin-bottom: 0; }
.ptp-rule-preview {
  color: var(--muted);
  font-size: 12px;
  font-weight: 400;
  margin-left: 4px;
  opacity: 0.8;
}
.ptp-rule-title { flex: 1; }
.ptp-subsection {
  background: rgba(0,0,0,0.15);
  border-radius: 8px;
  padding: 10px;
  margin-bottom: 8px;
}
.ptp-subsection .ptp-sub-hdr {
  font-size: 12px;
  color: var(--muted);
  margin-bottom: 8px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.5px;
}
.ptp-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 6px;
  flex-wrap: wrap;
}
.ptp-row label {
  min-width: 90px;
  font-size: 13px;
  color: var(--muted);
  margin: 0;
}
.ptp-row .input {
  flex: 1;
  min-width: 120px;
}
.ptp-condition-row {
  background: rgba(0,0,0,0.2);
  border: 1px solid rgba(255,255,255,0.05);
  border-radius: 6px;
  padding: 8px;
  margin-bottom: 6px;
}
.ptp-btn-small {
  background: rgba(255,82,82,0.15);
  border: 1px solid rgba(255,82,82,0.3);
  color: #ff8a80;
  padding: 4px 10px;
  border-radius: 6px;
  cursor: pointer;
  font-size: 12px;
}
.ptp-btn-small:hover {
  background: rgba(255,82,82,0.25);
}
.ptp-btn-add {
  background: rgba(129, 199, 132, 0.12);
  border: 1px dashed rgba(129, 199, 132, 0.4);
  color: #a5d6a7;
  padding: 8px 14px;
  border-radius: 8px;
  cursor: pointer;
  width: 100%;
  font-weight: 500;
  margin-top: 4px;
}
.ptp-btn-add:hover {
  background: rgba(129, 199, 132, 0.2);
}

details summary::-webkit-details-marker {
  display: none !important;
  /* Ukryj domyślną native strzałkę */
}

details summary {
  display: block;
  /* Ważne na mobile dla flex */
  list-style-type: none !important;
  /* Ukryj domyślną native strzałkę */
}

details summary::marker {
  display: none !important;
}

details>summary {
  list-style: none !important;
  position: relative;
}

details summary::after {
  content: '▼';
  position: absolute;
  right: 18px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 12px;
  color: var(--muted);
  transition: transform 0.2s;
}

details[open] summary::after {
  content: '▲';
}

/* --------------------------------------------- */
/*                RESPONSYWNOŚĆ                  */
/* --------------------------------------------- */
@media (max-width: 860px) {
  .card {
    padding: 18px;
  }

  .row {
    flex-direction: column;
    gap: 6px;
  }

  .controls {
    flex-direction: column;
    gap: 10px;
  }

  .btn,
  .btn-danger {
    width: 100%;
  }

  /* Przyciski karty urządzenia (Ustawienia/Usuń) — zawsze obok siebie, jak Skanuj sieć */
  .device-card-actions {
    flex-direction: row;
  }
}


/* --------------------------------------------- */
/*                MODBUS                         */
/* --------------------------------------------- */
.device-item {
  border: 1px solid #444;
  padding: 10px;
  margin-bottom: 10px;
  border-radius: 5px;
  background: #0f1724;
  color: #ffffff;
  /* czarny tekst na jasnym tle */
}

.device-header {
  font-size: 18px;
  cursor: pointer;
  color: #ffffff;
  /* opcjonalnie kolor nagłówka */
}

.device-details label {
  color: #ffffff;
  /* kolory etykiet w środku */
}

.io-section {
  margin: 10px 0;
}

.io-row {
  display: flex;
  align-items: center;
  margin-bottom: 8px;
}

.io-label {
  width: 80px;
  font-weight: bold;
}

.io-icons {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: flex-end;
}

.io-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.io-cell .idx {
  font-size: 10px;
  color: var(--muted);
  line-height: 1;
  user-select: none;
}

.io-icon {
  width: 16px;
  height: 16px;
  border-radius: 4px;
  background: #9e9e9e;
}

.hidden {
  display: none;
}

.section-disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* Static IP section — collapsible, BORDER ONLY (no background change, spójne
   ze stylem reszty karty WiFi). Chevron rotuje na open. */
.static-ip-section {
  margin-top: 10px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: transparent;
}
.static-ip-section > summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  cursor: pointer;
  font-size: 13px;
  color: var(--muted);
  list-style: none;
  user-select: none;
}
.static-ip-section > summary:hover { color: #d9e7f4; }
/* Chevron ▼/▲ dostarczany przez globalną regułę `details summary::after`
   (na górze pliku, ~linia 407). Spójność z innymi <details> na stronie. */
.static-ip-section[open] > .static-ip-fields {
  padding: 0 12px 12px 12px;
}

.card-list {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
  border-radius: var(--radius);
  padding: 8px;
  box-shadow: 0 6px 30px rgba(2, 8, 23, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.04);
  margin-top: 5px;
}

.card-list h3 {
  margin: 0;
}

/* Paski przewijania (Scrollbars) dopasowane do stylu strony */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}
::-webkit-scrollbar-track {
  background: var(--bg);
}
::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.15);
  border-radius: 5px;
}
::-webkit-scrollbar-thumb:hover {
  background: rgba(255, 255, 255, 0.25);
}
.btn-pending {
  background: linear-gradient(135deg, #f59e0b, #d97706) !important;
  color: #1a0a00 !important;
  cursor: not-allowed !important;
  opacity: 0.9;
}

.sidebar {
  width: var(--sidebar-width);
  background: var(--sidebar-bg);
  border-right: 1px solid var(--sidebar-border);
  display: flex; flex-direction: column;
  position: fixed; inset: 0 auto 0 0;
  z-index: 50;
}
.sidebar-brand { padding: 18px 16px; display:flex; gap:10px; align-items:center; }
.sidebar-logo  { width:36px; height:36px; border-radius:9px;
                 background: linear-gradient(135deg, var(--accent), var(--accent-600));
                 color:#042236; font-weight:700; display:grid; place-items:center; }
.sidebar-title { font-size:14px; font-weight:600; color:#e6eef6; }
.sidebar-nav { padding: 6px 8px; flex: 1; display:flex; flex-direction:column; gap:2px; }
.nav-item {
  display:flex; align-items:center; gap:10px;
  padding: 10px 12px; border-radius: 10px;
  color: var(--muted); text-decoration:none; font-size:14px;
  transition: background .15s, color .15s;
}
.nav-item:hover { background: rgba(255,255,255,0.04); color:#e6eef6; }
.nav-item.is-active {
  background: rgba(3,169,244,0.10);
  color:#e6eef6;
  border: 1px solid rgba(3,169,244,0.25);
}
.nav-ico {
  width:28px; height:28px; border-radius:8px;
  background: color-mix(in srgb, var(--ico) 18%, transparent);
  color: var(--ico);
  display:grid; place-items:center; font-size:15px;
  flex-shrink:0;
}
.nav-ext { margin-left:auto; opacity:.6; font-size:11px; }
.sidebar-foot {
  padding: 12px 14px;
  border-top: 1px solid var(--sidebar-border);
  display:flex; flex-direction:column; gap:6px;
}
.lang-switch {
  background: var(--glass);
  border:1px solid rgba(255,255,255,0.08);
  color:#e6eef6;
  padding:6px 8px;
  border-radius:8px;
  font-size:12px;
}
.mac-id {
  font-size:11px; color: var(--muted);
  font-family: monospace; opacity:.7;
}
.app-main { margin-left: var(--sidebar-width); padding: 24px; }

@media (max-width: 768px) {
  .sidebar {
    inset: auto 0 0 0; width: 100%;
    height: var(--bottomnav-h);
    flex-direction: row;
    border-right: none;
    border-top: 1px solid var(--sidebar-border);
  }
  /* Lang switcher + MAC przeniesione do karty "System" w Konfig — sidebar-foot
     już nie istnieje, nie ma top-stripa w mobile. */
  .sidebar-brand { display: none; }
  .sidebar-nav { flex-direction: row; padding: 4px; gap: 0; }
  .nav-item { flex:1; flex-direction:column; gap:2px; padding:6px 4px; }
  .nav-label { font-size:10px; }
  .nav-ext { display: none; }
  .app-main { margin-left: 0; padding: 16px 16px calc(var(--bottomnav-h) + 16px); }
}

.tab-panel { display: none; }
.tab-panel.is-active { display: block; }
.tab-head { margin-bottom: 16px; }
.tab-head h2 { margin: 0 0 4px; font-size: 22px; font-weight: 600; }
.tab-head .tab-desc { margin: 0; color: var(--muted); font-size: 13px; }

/* Karty Konfiguracji/Modbus w STAŁEJ liczbie kolumn (CSS Grid 3-col).
   Grid zamiast multi-column — gwarantuje że zwijanie/rozwijanie kart NIE zmienia
   liczby kolumn (multi-column z 'balance' algorithm potrafi przerzucać karty między
   kolumnami żeby zminimalizować height — wyglądało jak utrata kolumny).
   Trade-off: karty NIE pakują się masonry-style — zwinięcie karty zostawia pustą
   komórkę w jej rzędzie. Akceptowalne dla małej liczby kart (5 w Konfig, 4 w Modbus).
   grid-auto-rows: min-content + align-items: start utrzymują karty na ich naturalnej
   wysokości (nie stretch do najwyższej karty w wierszu). */
/* JS-MANAGED FLEX COLUMNS — natural heights, per-column stability.
   JS po DOM ready wstawia .masonry-col wrappery do .accordion-group i
   dystrybuuje karty round-robin (card[i] → col[i % N]). Każda kolumna jest
   niezależnym flex column container. Collapse karty 1 nie wpływa na sąsiednie
   kolumny, a karty poniżej w TEJ SAMEJ kolumnie naturalnie podjeżdżają do góry.
   Cards mają natural height — żadnego marnowanego miejsca, żadnego inner scroll'a. */
.accordion-group {
  display: flex;
  flex-direction: row;
  gap: 16px;
  align-items: flex-start;
}
.masonry-col {
  flex: 1 1 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-width: 0;
}
.accordion-group > .card,
.masonry-col > .card { margin: 0 !important; }

/* Mobile: jedna kolumna, flex stack. align-items: stretch override żeby karty
   wypełniały szerokość kontenera (w column flex-direction, align-items steruje
   szerokością — natural value flex-start zostawia karty na ich content-width). */
@media (max-width: 800px) {
  .accordion-group {
    flex-direction: column;
    align-items: stretch;
  }
  .masonry-col { width: 100%; }
}

/* Reguły tab — 2-strefowy layout.
   Lewa: ustawienia globalne PTP (sticky w desktop). Prawa: lista kart reguł
   w grid'zie auto-fill (każda reguła = pełnoprawna .card). Mobile: stack. */
.rules-layout {
  display: grid;
  grid-template-columns: minmax(320px, 380px) minmax(0, 1fr);
  gap: 16px;
  align-items: start;
}
/* min-width: 0 — bez tego szeroka zawartość (wiersze formularzy) rozpycha kolumnę
   poza ekran na telefonie (grid item ma domyślnie min-width: auto). */
.rules-layout > * { min-width: 0; }
.rules-settings { position: sticky; top: 16px; }
/* Miejsce na przypięty z prawej toolbox (otwarty 280px / zwinięty 44px) */
.rules-layout.tb-open { padding-right: 296px; }
.rules-layout.tb-closed { padding-right: 60px; }
.ptp-vars-card { margin-top: 16px; padding: 14px; }
.ptp-vars-sum { cursor: pointer; list-style: none; font-size: 15px; font-weight: 600; margin-bottom: 10px; }
#ptpVarsDetails:not([open]) .ptp-vars-sum { margin-bottom: 0; }
.ptp-vars-count { color: var(--muted); font-weight: 400; font-size: 13px; }
/* Zmienna: [nazwa ........ ×] / [typ] [wartość początkowa] */
.ptp-var-row {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: 6px;
  padding: 8px; margin-bottom: 6px; border-radius: 6px;
  background: rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.05);
}
.ptp-var-row > [data-f="name"] { grid-column: 1 / 3; }
.ptp-var-row > [data-f="type"] { grid-column: 1; }
.ptp-var-row > [data-f="init"] { grid-column: 2; }
.ptp-var-row .input { min-width: 0; width: 100%; padding: 6px 8px; }
.ptp-empty { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
/* Toolbox — panel przypięty do prawej krawędzi, pełna wysokość, zwijany */
.rules-toolbox {
  position: fixed; top: 0; right: 0; bottom: 0; width: 280px; z-index: 40;
  display: flex; flex-direction: column;
  background: var(--sidebar-bg); border-left: 1px solid var(--sidebar-border);
}
.ptp-tb-head {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 16px; cursor: pointer; user-select: none;
  font-weight: 600; font-size: 15px;
}
.ptp-tb-toggle { color: var(--muted); font-size: 14px; transition: transform 0.2s; }
.ptp-tb-body { flex: 1; overflow-y: auto; padding: 0 12px 12px; }
.rules-toolbox.collapsed { width: 44px; }
.rules-toolbox.collapsed .ptp-tb-body { display: none; }
.rules-toolbox.collapsed .ptp-tb-head { flex-direction: column; padding: 16px 0; }
.rules-toolbox.collapsed .ptp-tb-title { writing-mode: vertical-rl; }
.rules-toolbox.collapsed .ptp-tb-toggle { transform: rotate(180deg); }
.ptp-tool {
  display: flex; gap: 10px; align-items: center; justify-content: space-between;
  padding: 10px; margin-bottom: 8px; border-radius: 8px;
  background: rgba(0,0,0,0.2); border: 1px solid rgba(255,255,255,0.05);
}
.ptp-tool-title { font-weight: 600; font-size: 13px; }
.ptp-tool-desc { font-size: 12px; color: var(--muted); margin-top: 2px; }
.ptp-tool-add {
  flex: none; width: 32px; height: 32px; border-radius: 8px; cursor: pointer;
  font-size: 20px; line-height: 1; color: #a5d6a7;
  background: rgba(129,199,132,0.12); border: 1px dashed rgba(129,199,132,0.5);
}
.ptp-tool-add:hover { background: rgba(129,199,132,0.25); }
.ptp-tpl-card { border-color: rgba(129,199,132,0.25); }
/* Karty reguł/bloków: sekcje oddzielone poziomą linią (bez ramek w ramkach),
   etykieta w swojej linii, pola pod nią na pełną szerokość karty */
.ptp-rule-card .ptp-subsection {
  background: none; border-radius: 0; margin: 0; padding: 14px 0 10px;
  border-top: 1px solid rgba(255,255,255,0.08);
}
.ptp-rule-card .ptp-row { flex-direction: column; align-items: stretch; gap: 6px; margin-bottom: 10px; }
.ptp-rule-card .ptp-row label { min-width: 0; }
.ptp-rule-card .ptp-row .input { width: 100%; min-width: 0; }
.ptp-rule-card .ptp-condition-row {
  background: none; border: none; border-radius: 0; margin: 0; padding: 10px 0 0;
  border-top: 1px dashed rgba(255,255,255,0.08);
}
.ptp-rule-card .ptp-sub-hdr + .ptp-condition-row { border-top: none; padding-top: 0; }
.ptp-item-hdr {
  display: flex; justify-content: space-between; align-items: center;
  font-size: 12px; color: var(--muted); margin-bottom: 8px;
}
.ptp-check { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--muted); margin: 6px 0 10px; cursor: pointer; }
.ptp-check input { width: 16px; height: 16px; accent-color: var(--primary); }
.ptp-gap { height: 8px; }
.ptp-rule-card .ptp-btn-add { margin: 4px 0 6px; }
/* Telefon: toolbox = wysuwana sekcja na dole ekranu, nad dolną nawigacją */
@media (max-width: 768px) {
  .rules-layout.tb-open, .rules-layout.tb-closed { padding-right: 0; padding-bottom: 56px; }
  .rules-toolbox, .rules-toolbox.collapsed {
    top: auto; left: 0; bottom: var(--bottomnav-h); width: auto; max-height: 60vh;
    border-left: none; border-top: 1px solid var(--sidebar-border);
    box-shadow: 0 -6px 24px rgba(2,8,23,0.6);
  }
  .rules-toolbox .ptp-tb-toggle { transform: rotate(90deg); }
  .rules-toolbox.collapsed .ptp-tb-head { flex-direction: row; padding: 14px 16px; }
  .rules-toolbox.collapsed .ptp-tb-title { writing-mode: horizontal-tb; }
  .rules-toolbox.collapsed .ptp-tb-toggle { transform: rotate(-90deg); }
}
/* Lista reguł = flex row z masonry-col wrappers (JS-managed round-robin, jak urządzenia).
   Karty reguł + Add card dystrybuowane do N kolumn — każda kolumna to niezależny flex
   column container. Wysokie karty (otwarte z formularzami) NIE rozsuwają sąsiednich
   kolumn — karta poniżej w TEJ SAMEJ kolumnie podchodzi naturally pod swoją poprzedniczkę.
   Prawdziwy masonry, którego CSS Grid w Chrome nie potrafi. */
#ptpRulesList {
  display: flex;
  flex-direction: row;
  gap: 16px;
  align-items: flex-start;
}
#ptpRulesList > .ptp-rule-card,
#ptpRulesList > .card.add-card,
#ptpRulesList .masonry-col > .ptp-rule-card,
#ptpRulesList .masonry-col > .card.add-card { margin: 0; }
/* Add-card "+ Dodaj regułę" — wygląda jak .card ale z dashed border, pełni
   rolę droppera w gridzie reguł. JS handler na #ptpAddRule click bez zmian. */
.card.add-card {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  min-height: 88px;
  cursor: pointer;
  background: linear-gradient(180deg, rgba(129,199,132,0.05), rgba(129,199,132,0.02));
  border: 1px dashed rgba(129,199,132,0.4);
  color: #a5d6a7;
  font-weight: 600;
  transition: background 0.15s, border-color 0.15s;
}
.card.add-card:hover { background: rgba(129,199,132,0.12); border-color: rgba(129,199,132,0.6); }
.card.add-card .add-icon { font-size: 28px; line-height: 1; font-weight: 700; }

@media (max-width: 800px) {
  .rules-layout { grid-template-columns: 1fr; }
  .rules-settings { position: static; }
  #ptpRulesList { flex-direction: column; align-items: stretch; }
}

/* Liczba wyjść / Liczba wejść / Interwał — w jednym wierszu, równo dzielą szerokość karty.
   align-items: end + flex-direction: column wewnątrz .field gwarantuje że nawet jeśli
   label jednego pola się zawinie na 2 linie, inputy zostaną wyrównane na dole. */
.io-counts { display: flex; gap: 12px; align-items: end; }
.io-counts > .field {
  display: flex; flex-direction: column;
  flex: 1 1 0; min-width: 0; margin-bottom: 10px;
}
.io-counts > .field > .input { width: 100%; }
@media (max-width: 480px) {
  .io-counts { flex-wrap: wrap; }
  .io-counts > .field { flex: 1 1 calc(50% - 6px); }
}

.devices-toolbar {
  position: sticky; top: 0; z-index: 10;
  background: linear-gradient(180deg, rgba(15,23,36,0.95), rgba(15,23,36,0.75));
  backdrop-filter: blur(8px);
  padding: 14px 4px;
  display: grid;
  grid-template-columns: 1fr auto auto;
  align-items: center; gap: 12px;
  border-bottom: 1px solid rgba(255,255,255,0.05);
  margin-bottom: 18px;
}
.dt-left h2 { margin: 0; font-size: 22px; }
.dt-left .tab-desc { margin: 0; color: var(--muted); font-size: 13px; }
.dt-memory {
  display: flex; align-items: center; gap: 8px;
  font-size: 12px; color: var(--muted);
}
.dt-memory .memory-bar {
  width: 90px; height: 6px;
  background: rgba(255,255,255,0.08);
  border-radius: 3px; overflow: hidden;
}
.dt-memory .memory-fill {
  height: 100%; background: var(--accent);
  border-radius: 3px; width: 0%;
  transition: width .4s ease, background .2s;
}
.dt-memory.warning { color: #ff8888; }
.dt-memory.warning .memory-fill { background: var(--danger); }
.dt-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.dt-actions button { padding: 8px 14px; font-size: 13px; }

/* devices-grid — masonry layout (flex columns z JS round-robin distribution).
   Tak jak accordion-group: collapse karty w col 1 nie rusza sąsiednich kolumn.
   JS po loadDevicesFull() wywołuje masonryDistribute() aby rozłożyć karty round-robin. */
.devices-grid {
  display: flex;
  flex-direction: row;
  gap: 16px;
  align-items: flex-start;
}
/* Mobile: kolumna pojedyncza, stretch szerokość. */
@media (max-width: 800px) {
  .devices-grid { flex-direction: column; align-items: stretch; }
}

.scan-panel {
  background: rgba(15,23,36,0.96);
  border: 1px solid rgba(255,255,255,0.08);
  border-radius: 12px;
  padding: 18px;
  /* OVERLAY: panel nie zajmuje miejsca w flow — pływa nad urządzeniami,
     w prawym górnym rogu pod toolbarem. Sticky toolbar ma z-index 10,
     my idziemy wyżej (50). Backdrop blur dla wizualnej separacji od urządzeń. */
  position: fixed;
  top: 100px;
  right: 24px;
  width: 380px;
  max-width: calc(100vw - 48px);
  z-index: 50;
  box-shadow: 0 10px 40px rgba(0,0,0,0.5);
  backdrop-filter: blur(8px);
  margin: 0;
}
.scan-panel[hidden] { display: none; }

/* Override flex-grow na buttonach w .controls panelu skanowania — musi być
   w TYM SAMYM breakpoint co `.controls { flex-direction: column }` (860px).
   Inaczej window 769-860px łapał column layout BEZ tego override → buttony
   rozdmuchiwały się do pełnej dostępnej wysokości panelu (~150-200px).
   flex: 0 0 auto = no grow, no shrink, natural height. */
@media (max-width: 860px) {
  #scanModbusPanel .controls > .btn,
  #scanModbusPanel .controls > .btn-danger {
    flex: 0 0 auto;
  }
}
@media (max-width: 768px) {
  .devices-toolbar { grid-template-columns: 1fr; }
  .dt-memory { order: 3; }
  .dt-actions { order: 2; flex-wrap: wrap; }
  .dt-actions button { flex: 1 1 120px; }
  /* Na mobile panel w normalnym flow strony (nie fixed overlay) — position:fixed
     pływał NAD toolbarem i zasłaniał przycisk "Skanuj sieć", więc nie dało się go
     ponownie kliknąć, żeby zamknąć panel. W flow panel renderuje się po prostu pod
     przyciskiem (jest jego siblingiem w HTML), przycisk zostaje zawsze klikalny. */
  .scan-panel {
    position: static;
    width: auto;
    max-width: none;
    margin-top: 12px;
  }
}

/* Dashboard-specific additions (not present in home.html — new for cloud UI) */
.entity-offline { opacity: 0.45; }

/* Same visual chip as the "PV Data / Custom" registers on the local device
   card (home.html's inline-styled chip in updateIoStates()), promoted to a
   reusable class since the dashboard renders many of them from JS. */
.reg-chip {
  background: var(--glass);
  border: 1px solid rgba(255, 255, 255, 0.1);
  padding: 4px 8px;
  border-radius: 6px;
  font-size: 12px;
}

/* Centers the login card — local webserver has no auth page to copy this
   from, so this is new, but reuses the same .card/.brand/.input/.btn
   vocabulary as everything else. */
.auth-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

/* Zakładki "Dostęp lokalny" i "Panel użytkownika" (tylko chmura) */
.account-card { max-width: 420px; margin-bottom: 16px; }
.account-wide { display: block; text-align: center; text-decoration: none; margin-top: 14px; }
.account-hint { font-size: 12px; color: var(--muted); margin: 10px 0 0 0; }
.local-ip { display: inline-block; font-size: 15px; font-family: 'Consolas', 'Monaco', monospace; }
.account-device {
  display: flex; justify-content: space-between; align-items: center; gap: 10px;
  padding: 12px 0; border-top: 1px solid rgba(255,255,255,0.08);
}
.account-device-info { min-width: 0; }
.account-device-name { font-weight: 600; }
.account-device-meta { font-size: 12px; color: var(--muted); word-break: break-all; margin-top: 2px; }
.account-device-actions { display: flex; gap: 8px; align-items: center; flex: none; }
.account-device-actions form { margin: 0; }
.account-btn { width: auto; padding: 6px 12px; font-size: 13px; text-decoration: none; display: inline-block; }

/* ================= Zakładka Wykresy (history.js) =================
   Style skopiowane z src/webserver/charts.html, zawężone do .hist-root, żeby nie ruszały
   pozostałych zakładek. Paleta z :root dashboardu; --panel/--border/--warn tylko tutaj. */
.hist-root { --panel: #1e293b; --border: rgba(255, 255, 255, 0.08); --warn: #ca8a04; }
.hist-root .hist-head { display: flex; align-items: flex-start; gap: 12px; }
/* === Form controls — wyrównane do home.html (.input / .btn / .secondary) === */
.hist-root select, .hist-root input[type="text"], .hist-root input[type="number"], .hist-root input[type="datetime-local"] {
  width: 100%;
  padding: 8px 10px;
  border-radius: 10px;
  background: var(--glass);
  color: var(--text);
  border: 1px solid rgba(255, 255, 255, 0.04);
  font-size: 14px;
  font-family: inherit;
}
.hist-root select option {
  background: var(--bg);
  color: var(--text);
}
.hist-root button {
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.1);
  color: var(--muted);
  padding: 10px 14px;
  border-radius: 12px;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background .15s, border-color .15s, color .15s;
}
.hist-root button:hover {
  background: rgba(255, 255, 255, 0.08);
  border-color: rgba(255, 255, 255, 0.2);
  color: #fff;
}
.hist-root button.primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-600));
  border: none;
  color: #042236;
  font-weight: 600;
  box-shadow: 0 8px 30px rgba(3, 169, 244, 0.18);
}
.hist-root button.primary:hover { filter: brightness(1.05); color: #042236; }
.hist-root button.warn {
  background: linear-gradient(180deg, var(--warn), #a16207);
  border: none;
  color: #fff;
  font-weight: 600;
  box-shadow: 0 8px 30px rgba(202, 138, 4, 0.18);
}
.hist-root button.warn:hover { filter: brightness(1.05); color: #fff; }

.hist-root .chart-layout {
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 14px;
  padding: 14px;
  height: calc(100vh - 150px);
}
.hist-root aside.left {
  padding: 18px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.04);
  box-shadow: 0 6px 30px rgba(2, 8, 23, 0.6);
  overflow-y: auto;
}
.hist-root section.right {
  padding: 4px;
  overflow-y: auto;
}
@media (max-width: 768px) {
  .hist-root .chart-layout { grid-template-columns: 1fr; height: auto; padding: 10px; gap: 10px; }
  .hist-root aside.left { padding: 14px; }
}

.hist-root .field { margin-bottom: 14px; display: flex; flex-direction: column; gap: 6px; }
.hist-root .field label {
  font-size: 13px;
  color: #d9e7f4;
  margin-bottom: 0;
  font-weight: 500;
}
.hist-root .device-block {
  margin-top: 10px;
  padding: 14px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.04);
}
.hist-root .device-block summary {
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
  color: #e6eef6;
  padding: 2px 0;
}
.hist-root .channel-row {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 0; font-size: 13px;
}
.hist-root .channel-row label { flex: 1; cursor: pointer; color: var(--text); }
.hist-root .channel-row input[type="checkbox"] {
  width: 16px; height: 16px;
  accent-color: var(--accent);
}
.hist-root .channel-row select {
  padding: 4px 8px;
  font-size: 12px;
  width: auto;
}

.hist-root .chart-card {
  margin-bottom: 14px;
  padding: 18px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
  border-radius: 14px;
  box-shadow: 0 6px 30px rgba(2, 8, 23, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.04);
}
.hist-root .chart-card h3 {
  margin: 0 0 12px 0;
  font-size: 14px;
  color: #d9e7f4;
  font-weight: 600;
}
/* Kontener wykresu — wysokość domyślna liczona w JS (dopasowana do ekranu i liczby grup),
   ale user może ją ręcznie dociągnąć w dół natywnym uchwytem przeglądarki (resize: vertical).
   ResizeObserver w JS przerysowuje uPlot na nowy rozmiar (patrz renderGroupChart). */
.hist-root .chart-resizable {
  resize: vertical;
  overflow: hidden;
  min-height: 160px;
  max-height: 85vh;
}
.hist-root .empty-state {
  padding: 60px 40px;
  text-align: center;
  color: var(--muted);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.04);
}

/* === Własny kalendarz (tryb "Dzień") — te same zmienne co reszta apki, position:fixed
   (nie absolute) bo aside.left ma overflow-y:auto i przycięłoby popup pozycjonowany względnie. */
.hist-root .cal-popup {
  position: fixed;
  z-index: 200;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 12px 40px rgba(2, 8, 23, 0.7);
  padding: 14px;
  width: 260px;
  display: none;
}
.hist-root .cal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.hist-root .cal-title { font-weight: 600; font-size: 14px; color: #e6eef6; }
.hist-root .cal-nav { display: flex; gap: 4px; }
.hist-root .cal-nav-btn {
  background: var(--glass);
  border: 1px solid rgba(255, 255, 255, 0.08);
  color: var(--muted);
  border-radius: 8px;
  padding: 4px 8px;
  cursor: pointer;
  font-size: 11px;
}
.hist-root .cal-nav-btn:hover { color: #fff; background: rgba(255, 255, 255, 0.08); }
.hist-root .cal-weekdays, .hist-root .cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.hist-root .cal-dow {
  text-align: center;
  font-size: 11px;
  color: var(--muted);
  padding: 4px 0;
  font-weight: 600;
}
.hist-root .cal-day {
  background: none;
  border: none;
  color: var(--text);
  padding: 7px 0;
  border-radius: 8px;
  cursor: pointer;
  font-size: 13px;
  font-family: inherit;
}
.hist-root .cal-day:hover:not(:disabled) { background: rgba(255, 255, 255, 0.08); }
/* Dzień z poprzedniego/następnego miesiąca — bardzo wyblakły, tylko wypełnienie siatki. */
.hist-root .cal-day-other { color: rgba(148, 163, 184, 0.35); }
/* Dzień w zakresie [najstarszy istniejący log, dziś] — jasnoniebieskie tło (kolor akcentu). */
.hist-root .cal-day-has-data {
  background: rgba(3, 169, 244, 0.22);
  color: #e6eef6;
  font-weight: 600;
}
/* Dzień W BIEŻĄCYM miesiącu, ale sprzed najstarszego logu — wyraźnie inny niż .cal-day-other
   (poza miesiącem), stąd przekreślenie. */
.hist-root .cal-day-no-data {
  color: rgba(226, 232, 240, 0.45);
  text-decoration: line-through;
  text-decoration-color: rgba(226, 232, 240, 0.35);
  text-decoration-thickness: 1.5px;
}
.hist-root .cal-day-disabled { color: rgba(148, 163, 184, 0.25); cursor: not-allowed; }
.hist-root .cal-day-today { box-shadow: inset 0 0 0 1px var(--accent); }
.hist-root .cal-day-selected { background: var(--accent) !important; color: #042236 !important; font-weight: 700; }
.hist-root .cal-loading-hint {
  text-align: center;
  font-size: 11px;
  color: var(--muted);
  margin-top: 6px;
}
.hist-root .cal-footer {
  display: flex;
  justify-content: center;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.06);
}
.hist-root .cal-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
  padding: 4px 8px;
}
.hist-root .cal-link:hover { text-decoration: underline; }
/* Zakładka ma własne marginesy (.app-main) — bez podwójnego paddingu z charts.html */
.hist-root .chart-layout { padding: 0; }
