/* JKhub hub portal — single stylesheet (CSP default-src 'self': no inline styles anywhere). */
:root {
  --bg: #f4f6f8;
  --card: #ffffff;
  --text: #1c2430;
  --muted: #5b6776;
  --line: #d9dee5;
  --accent: #0b6e4f;
  --accent-dark: #084f39;
  --danger: #b3261e;
  --warn: #8a5a00;
  --warn-bg: #fff4d6;
  --ok-bg: #e6f4ee;
  --err-bg: #fbe9e7;
  --radius: 6px;
  /* Šířky sloupce stránky. Jsou tokeny, protože je čte i hlavička (aby pruh nav seděl na obsah)
     a protože „jak široká smí stránka být" je rozhodnutí, ne číslo rozsypané po souboru.
     `--page-wide` (zadání vlastníka 30. 9. 2026: „stránky bych chtěl upravit tak aby využívali
     šířku okna") NENÍ bezbřehá: 96 vw nechá po stranách vzduch a 1800 px je strop, za kterým
     už graf jen roste a text se stává nečitelným. */
  --page: 1100px;
  --page-wide: min(96vw, 1800px);
  --page-narrow: 520px;
  /* Nejdelší rozumný řádek textu. Souvislý text v kartě se přes celý široký sloupec nečte —
     oko na konci řádku netrefí začátek dalšího. Platí jen na `main.wide`; obrázky, tabulky
     a řady ovládání se tím NEomezují, ty šířku chtějí. */
  --text-measure: 92ch;
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { font-family: var(--font); font-size: 16px; color: var(--text); background: var(--bg); }
body { margin: 0; min-height: 100vh; display: flex; flex-direction: column; }
a { color: var(--accent); }
a:hover { color: var(--accent-dark); }
code, .mono { font-family: var(--mono); font-size: 0.95em; }

header.top { background: #102a24; color: #fff; }
header.top .bar { max-width: var(--page); margin: 0 auto; padding: 0.6rem 1rem; display: flex; align-items: center; gap: 1.2rem; flex-wrap: wrap; }
header.top .brand { font-weight: 700; color: #fff; text-decoration: none; letter-spacing: 0.02em; }
header.top nav { display: flex; gap: 1rem; flex-wrap: wrap; flex: 1; }
header.top nav a { color: #d7e6df; text-decoration: none; padding: 0.25rem 0; }
header.top nav a:hover, header.top nav a.active { color: #fff; border-bottom: 2px solid #7fd3b0; }
header.top .user { color: #d7e6df; font-size: 0.9rem; display: flex; gap: 0.6rem; align-items: center; }
header.top form { margin: 0; }

main { flex: 1; max-width: var(--page); width: 100%; margin: 0 auto; padding: 1.5rem 1rem; }
main.narrow { max-width: var(--page-narrow); }
/* Široký sloupec podstran, na kterých je hlavní obsah OBRÁZEK: Historie, Poruchy, Kvalita, Schéma
   (zadání vlastníka 30. 9. 2026). Přehled a formuláře zůstávají, jak byly — širší formulář se
   nevyplňuje o nic líp, jen se hůř čte. */
main.wide { max-width: var(--page-wide); }
/* Pruh v hlavičce se roztáhne s obsahem, aby nad širokou stránkou neseděla úzká navigace.
   `:has()` umí každý dnešní prohlížeč; kde ne, zůstane hlavička na 1100 px jako dosud — tedy
   přesně to, co bylo do 30. 9. 2026, ne rozbitá stránka. */
body:has(main.wide) header.top .bar { max-width: var(--page-wide); }
/* Souvislý text v kartách na široké stránce. Vybrané ODSTAVCE, ne „všechno": popisky grafů,
   vysvětlivky a patičky. Tabulky, SVG, řady přepínačů ani dlaždice se neomezují. */
main.wide .card > p,
main.wide .card > figure > figcaption,
main.wide .card > noscript > p,
main.wide .card table caption,
main.wide p.lead { max-width: var(--text-measure); }
footer { color: var(--muted); font-size: 0.8rem; text-align: center; padding: 1rem; }

h1 { font-size: 1.5rem; margin: 0 0 1rem; }
h2 { font-size: 1.15rem; margin: 1.5rem 0 0.6rem; }
p.lead { color: var(--muted); }

.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.25rem; margin-bottom: 1.25rem; }
.flash { border-radius: var(--radius); padding: 0.7rem 1rem; margin-bottom: 1rem; border: 1px solid transparent; }
.flash.ok { background: var(--ok-bg); border-color: #b9dccb; }
.flash.error { background: var(--err-bg); border-color: #efb8b2; color: var(--danger); }
.flash.warn { background: var(--warn-bg); border-color: #eed49a; color: var(--warn); }

form.stack { display: flex; flex-direction: column; gap: 0.9rem; }
form.inline { display: inline; }
label { display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.92rem; font-weight: 600; }
label span.hint { font-weight: 400; color: var(--muted); font-size: 0.85rem; }
input[type="text"], input[type="password"], input[type="email"], select {
  font: inherit; padding: 0.55rem 0.7rem; border: 1px solid var(--line); border-radius: var(--radius); background: #fff; width: 100%;
}
input:focus, select:focus { outline: 2px solid #7fd3b0; outline-offset: 1px; border-color: var(--accent); }
input.code { font-family: var(--mono); font-size: 1.4rem; letter-spacing: 0.35em; text-align: center; }

button, .btn {
  font: inherit; font-weight: 600; padding: 0.55rem 1rem; border-radius: var(--radius); border: 1px solid var(--accent);
  background: var(--accent); color: #fff; cursor: pointer; text-decoration: none; display: inline-block;
}
button:hover, .btn:hover { background: var(--accent-dark); color: #fff; }
button.secondary, .btn.secondary { background: #fff; color: var(--accent); }
button.secondary:hover, .btn.secondary:hover { background: #eef6f2; }
button.danger, .btn.danger { background: #fff; color: var(--danger); border-color: var(--danger); }
button.danger:hover, .btn.danger:hover { background: #fdf0ee; }
button.small, .btn.small { padding: 0.3rem 0.6rem; font-size: 0.85rem; }
button.link { background: none; border: none; color: #d7e6df; padding: 0; font-weight: 400; cursor: pointer; }
button.link:hover { color: #fff; background: none; text-decoration: underline; }
.actions { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; margin-top: 0.5rem; }

table { width: 100%; border-collapse: collapse; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); }
th, td { text-align: left; padding: 0.55rem 0.7rem; border-bottom: 1px solid var(--line); vertical-align: top; font-size: 0.93rem; }
th { background: #eef1f4; font-weight: 600; }
tr:last-child td { border-bottom: none; }
td.num, th.num { text-align: right; }

.badge { display: inline-block; padding: 0.1rem 0.5rem; border-radius: 999px; font-size: 0.78rem; font-weight: 600; background: #e4e8ec; color: var(--text); }
.badge.ok { background: var(--ok-bg); color: var(--accent-dark); }
.badge.warn { background: var(--warn-bg); color: var(--warn); }
.badge.off { background: var(--err-bg); color: var(--danger); }

.qr { width: 220px; height: 220px; margin: 0.5rem 0; }
.qr svg { width: 100%; height: 100%; display: block; }
.codes { columns: 2; list-style: none; padding: 0; margin: 0.5rem 0 1rem; font-family: var(--mono); font-size: 1.05rem; }
.codes li { padding: 0.25rem 0; }
.secret { font-family: var(--mono); word-break: break-all; background: #f1f3f5; padding: 0.4rem 0.6rem; border-radius: var(--radius); display: inline-block; }
.muted { color: var(--muted); }
.small { font-size: 0.85rem; }
/* Text jen pro odečítač: nese to, co oko čte z ikony („↗" = nový panel, „⚠" = zvláštnost
   zařízení). clip-path, ne display:none — skryté přes display se nepřečte vůbec. */
.vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
      clip-path: inset(50%); white-space: nowrap; border: 0; }
dl.props { display: grid; grid-template-columns: max-content 1fr; gap: 0.35rem 1.2rem; margin: 0; }
dl.props dt { color: var(--muted); }
dl.props dd { margin: 0; }
.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 1.25rem; }
.error-page { text-align: center; padding: 3rem 1rem; }
.error-page .code { font-size: 4rem; font-weight: 700; color: var(--line); line-height: 1; }
@media print { header.top, footer, .no-print { display: none; } }

/* --- Živý panel výrobny (sites/_live.html, app.live.pq) -----------------------------------------
   Tři stavy (načítání / živá data / nedostupná jednotka) sdílejí stejnou kostru i stejně velké SVG,
   takže výměna fragmentu přes HTMX nemění výšku karty. Animace se vypínají při prefers-reduced-motion
   (text „Načítám hodnoty… čekejte" nese informaci sám). */
.card.live { min-height: 27rem; }
.live-head { display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap; margin-bottom: 0.4rem; }
.live-head h2 { margin: 0; }
.live-age { font-size: 0.85rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.live-age.is-warn { color: var(--warn); font-weight: 600; }
/* pevná výška hlášky i řádků hodnot: výměna fragmentu (načítání → data → nedostupná
   jednotka) tak nemůže změnit výšku karty ani o pixel */
.live-state { margin: 0.2rem 0 0.9rem; min-height: 4.2rem; }
.live-state .muted { display: block; font-size: 0.9rem; font-weight: 400; }
.live-edges { list-style: none; display: flex; gap: 0.8rem; flex-wrap: wrap; padding: 0; margin: 0 0 0.7rem; font-size: 0.9rem; }
.live-edges .is-active { font-weight: 600; }

.live-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 360px); gap: 1.25rem; align-items: start; }
.live-values { align-content: start; min-width: 0; }

/* P a Q velkou dlaždicí, ostatní veličiny malým písmem v tabulce (zadání vlastníka 28. 9. 2026).
   Výška dlaždic i tabulek je pevná: skeleton v načítání a pomlčka v nedostupném stavu zabírají
   přesně tolik místa co číslo, takže výměna fragmentu kartou neposkočí. */
.live-tiles { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.8rem; margin-bottom: 0.9rem; }
.live-tile { border: 1px solid var(--line); border-radius: var(--radius); padding: 0.55rem 0.7rem; }
.live-tile .l { color: var(--muted); font-size: 0.85rem; }
.live-tile .v { font-size: 1.75rem; font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.25; min-height: 2.2rem; }
.live-tile .n { color: var(--muted); font-size: 0.85rem; min-height: 1.2rem; }

.live-tbl { margin-bottom: 0.6rem; }
.live-tbl caption { text-align: left; padding: 0.1rem 0.45rem 0.25rem; }
.live-tbl caption .badge { margin-left: 0.4rem; }
.live-tbl th, .live-tbl td { padding: 0.25rem 0.45rem; font-size: 0.82rem; }
.live-tbl thead th { background: #f4f6f8; }
.live-tbl tbody th { font-weight: 600; color: var(--muted); }
.live-tbl td.num { text-align: right; font-variant-numeric: tabular-nums; min-height: 1.4rem; }
.live-tbl td.live-dir { text-align: left; white-space: normal; }
.live-figure { max-width: 360px; width: 100%; }
.live-figure svg { display: block; width: 100%; aspect-ratio: 1 / 1; }
.live-quadrants { list-style: none; padding: 0; margin: 0.6rem 0 0; font-size: 0.82rem; color: var(--muted); }
.live-quadrants li { padding: 0.1rem 0; }
.live-quadrants li.is-active { color: var(--text); font-weight: 600; }
.live-foot { margin-top: 1rem; min-height: 2.2rem; }  /* i s tlačítkem „Pokračovat" drží stejnou výšku */
.live-foot .btn { margin-left: 0.5rem; }
.live-note { margin-top: 0.3rem; }
.live-sr { position: absolute; width: 1px; height: 1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.live-spinner { width: 1rem; height: 1rem; border-radius: 50%; border: 2px solid var(--line); border-top-color: var(--accent); display: inline-block; animation: live-spin 0.9s linear infinite; }
.skel-line, .live-skel { display: inline-block; height: 0.85rem; border-radius: 3px; background: #e6eaee; vertical-align: middle; animation: live-pulse 1.4s ease-in-out infinite; }
.skel-line.w1 { width: 5rem; }
.skel-line.w2 { width: 8rem; }
.skel-line.w3 { width: 11rem; }
.pq-skel { animation: live-pulse 1.4s ease-in-out infinite; }
.pq-dim { opacity: 0.45; }

@keyframes live-spin { to { transform: rotate(360deg); } }
@keyframes live-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.45; } }

@media (prefers-reduced-motion: reduce) {
  .live-spinner, .live-skel, .skel-line, .pq-skel { animation: none; }
  .live-skel, .skel-line { background: #eef1f4; }
}
@media (max-width: 640px) {
  /* jednosloupcově a bez přetékání: SVG má vlastní šířku 360 px, proto minmax(0, 1fr) */
  .live-grid { grid-template-columns: minmax(0, 1fr); }
  .live-figure { max-width: 100%; }
  .card.live { min-height: 0; }
}

/* --- Karta „Historie" výrobny (sites/_power.html, app.live.history) -----------------------------
   Počet grafů se řídí VYBRANÝMI veličinami, nikdy tím, jestli data jsou (app.live.history), a
   prázdný graf má stejný viewBox jako plný => karta má stejnou výšku ve všech stavech a přepnutí
   okna, veličiny nebo znaménkové konvence stránkou neposkočí. Kompaktní karta na přehledu výrobny
   kreslí jediný graf. Grafy jsou serverové SVG (žádné CSS uvnitř, CSP). */
.card.power .power-range { margin-left: auto; }
/* .power-switch (klouzavá okna) je jedna z řad .power-row níž — tady zůstává jen odsazení popisku. */
.power-switch .small.muted { margin-left: 0.5rem; }
.power-state { margin: 0.2rem 0 0.9rem; min-height: 3rem; }
.power-state .muted { display: block; font-size: 0.9rem; font-weight: 400; }
.power-chart { margin: 0 0 1.1rem; }
.power-chart svg { display: block; width: 100%; height: auto; }
.power-chart figcaption { margin-top: 0.2rem; }

/* --- široké plátno na úzké obrazovce -----------------------------------------------------------
   Graf je SVG s pevným viewBoxem (1600 × 420 na Historii, Kvalitě i časové ose Poruch) a
   `width: 100%`, takže se celý ZMENŠUJE. Na telefonu (343 px obsahu) z něj je 90 px vysoký
   obrázek s popisky os kolem 3 px — nečitelný, a od 30. 9. 2026 je v něm navíc až dvanáct křivek
   místo dvou. Na úzkých displejích si proto graf drží minimální šířku a rámec kolem něj se posouvá
   vodorovně, přesně jako široká tabulka `.ev-faults` o kus níž. Popisek pod obrázkem zůstává mimo
   rámec, ten se má zalomit do šířky stránky.
   Graf a legendy jsou v JEDNOM rámci, aby se posouvaly spolu — legenda odsunutá proti grafu by
   ukazovala na jiné místo, než na které patří. */
@media (max-width: 760px) {
  .chart-scroll { overflow-x: auto; }
  .chart-scroll svg { min-width: 900px; }
}
.power-tbl { margin-top: 0.4rem; }
.power-tbl caption { text-align: left; padding: 0.1rem 0.7rem 0.35rem; }
.power-tbl th, .power-tbl td { font-size: 0.85rem; }
.power-tbl tbody th { font-weight: 600; }
.power-foot { margin-top: 0.8rem; }

@media (max-width: 640px) {
  .live-tiles { grid-template-columns: minmax(0, 1fr); }
  .card.power .power-range { margin-left: 0; }
  .power-switch .small.muted { margin-left: 0; }
}

/* (Zástupná karta historie `.power-chart-skel` / `.power-tbl-skel` odsud zmizela: přehled si
   kompaktní kartu vykresluje rovnou serverem, takže na ni nečeká a nemá co zastupovat.) */

/* --- pruh podstran výrobny (templates/sites/_tabs.html) ----------------------------------------
   Vodorovný pruh TLAČÍTEK (pilulek) hned pod <h1>: Přehled / Historie / Kvalita / Poruchy /
   Schéma / Správa. Zůstávají to odkazy <a> — musí fungovat bez JS a jít otevřít v novém panelu —
   jen vypadají jako tlačítka. Aktivní odkaz pozná CSS podle aria-current="page", stav je tedy
   v HTML jen jednou a odečítač i oko čtou totéž. Na úzký displej se řada nevejde, proto se ZALOMÍ
   (flex-wrap) — vodorovné rolování tu záměrně není: `overflow-x` by z pruhu udělal ořezávací
   kontejner a usekl by fokusový prstenec kreslený vně pilulky. */
.subnav {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  align-items: center;
  margin: -0.3rem 0 1.25rem;
}
.subnav a {
  color: var(--muted);
  background: var(--card);
  text-decoration: none;
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.2;
  padding: 0.45rem 0.9rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  white-space: nowrap;
}
.subnav a:hover { color: var(--text); border-color: var(--muted); }
.subnav a[aria-current="page"] {
  color: #fff;
  background: var(--accent);
  border-color: var(--accent);
  font-weight: 700;
  text-decoration: none;
}
.subnav a[aria-current="page"]:hover {
  color: #fff;
  background: var(--accent-dark);
  border-color: var(--accent-dark);
}
/* Prstenec leží v mezeře nad pozadím stránky (--bg), ne na výplni pilulky: musí mít proti --bg
   aspoň 3 : 1 (WCAG 2.2 SC 1.4.11). Světle zelená #7fd3b0 dává 1,6 : 1, --accent-dark 8,9 : 1. */
.subnav a:focus-visible { outline: 2px solid var(--accent-dark); outline-offset: 2px; }

@media (max-width: 640px) {
  /* Na dotyku se pilulka NEZMENŠUJE — užší je jen vodorovně, aby se jich vešlo víc na řádek. */
  .subnav { gap: 0.25rem; }
  .subnav a { padding: 0.5rem 0.6rem; }
}

/* --- pruh prokliků na weby zařízení (templates/sites/_devlinks.html) ----------------------------
   Druhý, ZÁMĚRNĚ lehčí pruh hned pod pilulkami podstran: PŘÍMÉ odkazy na webová rozhraní zařízení
   té výrobny. Nevedou přes hub, ale rovnou na jednotku ve VPN výroben
   (`http://<vpn_ip>:<edge_port>/`, jen role admin), takže se od tabů musí lišit na první pohled —
   menší písmo, čárkovaný rámeček, barva odkazu a textový ukazatel „↗" (žádný obrázek, žádný inline
   styl; CSP style-src 'self'). Záporné horní odsazení ho přitáhne pod pruh podstran; když pruh
   není, spodní odsazení tabů platí beze změny.
   Odsazení drží dotykovou plochu nad 24 × 24 px (WCAG 2.2 SC 2.5.8) — jsou to „prokliky", na které
   se klepe prstem. .lead je viditelná věta na začátku pruhu („přímo ve VPN, mimo hub a bez
   záznamu") — rozdíl proti auditované cestě přes hub nesmí být jen v title, hlavně na stránce
   Vzdálený přístup, kde obě cesty stojí vedle sebe. .off je zakázané zařízení bez odkazu,
   .devlinks-hint věta mimo pruh (prázdný stav a věta technika o vzdáleném přístupu). Vše .no-print.
   Stejný vzhled má i <div class="devlinks"> — pruh se kreslí jako <div> místo <nav>, když v něm
   není ani jeden odkaz (všechna zařízení zakázaná), viz komentář v templates/sites/_devlinks.html.
   Upozornění „přístup k výrobně není otevřen" (.need) tu skončilo 29. 9. 2026 spolu s odkazy přes
   hub: přímé spojení žádnou relaci přístupu nepotřebuje, takže není co hlásit. */
.devlinks {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.3rem 0.45rem;
  margin: -1rem 0 1.25rem;
  font-size: 0.85rem;
}
.devlinks a, .devlinks .off {
  padding: 0.3rem 0.55rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  white-space: nowrap;
}
.devlinks a { color: var(--accent); text-decoration: none; }
.devlinks a:hover {
  color: var(--accent-dark);
  background: var(--card);
  border-style: solid;
  border-color: var(--accent);
}
.devlinks a:focus-visible { outline: 2px solid var(--accent-dark); outline-offset: 2px; }
.devlinks .off { color: var(--muted); }
.devlinks .lead { color: var(--muted); }
.devlinks .badge { font-size: 0.72rem; font-weight: 600; }
.devlinks-hint { color: var(--muted); font-size: 0.85rem; margin: -1rem 0 1.25rem; }

@media (max-width: 640px) {
  .devlinks { gap: 0.25rem 0.35rem; }
}

/* --- Historie výrobny: ovládání karty (sites/_power.html, app.live.history) ---------------------
   Doplněk k bloku „Karta „Historie" výrobny" výše. Ovládání je od 29. 9. 2026 sloupec řad
   (.power-controls > .power-row) v pořadí, v jakém ho má DataLogger v jednotce: den (.power-day,
   společná řada .daynav), výřez uvnitř dne (.power-cut), klouzavá okna s formulářem vlastního
   úseku (.power-switch + .power-section), kanály (.power-chans / .power-chan se zaškrtávacím
   políčkem a barevným proužkem .power-sw-a/-b/-c) a znaménková konvence (.power-signs). Pod grafy
   pak vysvětlivka zdrojů (.power-sources), věta o veličinách, které hub za období má, ale nejsou
   zaškrtnuté (.power-hint), prázdný stav bez vybrané veličiny (.power-empty) a stejně široké
   číslice v tabulkovém dvojčeti.

   Platí tu totéž co výš: žádný inline styl ani <style> (CSP style-src 'self'), ovládací prvky se
   netisknou (.no-print) a na displeji do 640 px se nic nesmí rozjet do vodorovného rolování.
   Jediné barvy mimo tokeny :root jsou proužky kanálů — ty se MUSÍ rovnat SERIES_COLORS
   v app/quality/chart.py, protože slibují barvu čáry v grafu (hlídá to test). Existující třídy
   (.card, .actions, .btn, .small, .muted, .mono, .num, .badge, .power-state, .power-chart,
   .power-tbl, .power-foot) se nemění. */

/* Ovládání karty stojí ve SLOUPCI řad (předloha DataLoggeru v jednotce): čas (den, výřez ve dni,
   klouzavá okna s vlastním úsekem), pak kanály, pak znaménka — a teprve pod tím grafy. */
.power-controls { margin: 0.3rem 0 0.9rem; }
.power-row { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.5rem; margin: 0 0 0.45rem; }
.power-row > span[role="group"] { display: inline-flex; gap: 0.3rem; flex-wrap: wrap; }
.power-row .btn[aria-current="true"] { box-shadow: inset 0 0 0 1px var(--accent-dark); }
/* Zvolený den je rovnocenná cesta ke klouzavému oknu — když je zapnutý, je to na řadě vidět. */
.power-day.is-on { box-shadow: inset 2px 0 0 var(--accent); padding-left: 0.5rem; }
.power-cut { margin-bottom: 0.6rem; }

/* Vysvětlivka zdrojů — od 29. 9. 2026 pod grafy, ne mezi ovládáním (kdo si vybírá čas a kanály,
   ten ji nečte; kdo se diví chybějící čáře, ten se dívá pod graf). */
.power-sources { margin: 0.8rem 0 0; max-width: 70ch; }

/* Aktuální výřez u šipek, které jím posouvají („06:00–12:00"; dvakrát ročně i se zkratkou pásma). */
.power-cut-now { color: var(--muted); }

/* Vlastní úsek od–do: obyčejný GET formulář v téže řadě jako klouzavá okna, na úzkém displeji se
   zalomí po dvojicích. Popisek a jeho pole jsou v jedné obálce .power-sec-field, aby se „do"
   nikdy nezalomilo samo na konec předchozího řádku (na 375 px se to dělo). */
.power-section { display: flex; margin: 0; gap: 0.35rem; align-items: center; flex-wrap: wrap; }
.power-sec-field { display: inline-flex; align-items: center; gap: 0.35rem; min-width: 0; }
.power-section label { margin-left: 0.3rem; }
.power-section input[type="date"] {
  font: inherit;
  font-size: 0.9rem;
  padding: 0.25rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--text);
}
.power-section input[type="date"]:focus-visible { outline: 2px solid var(--accent); }

/* --- Kanály (veličiny) --------------------------------------------------------------------------
   Předloha jsou zaškrtávátka kanálů na stránce DataLogger v jednotce: barevný proužek v barvě
   čáry v grafu. Barvy jsou TÝŽ seznam jako app/quality/chart.py SERIES_COLORS (hlídá to test
   v portal/tests/test_power_chart.py) — kdyby se rozešly, slibovala by přepínačka jinou čáru, než
   která se nakreslí.
   Zapnuto × vypnuto se NIKDY nepozná jen barvou: nese to zaškrtávací políčko (✓ / prázdné), plné
   × slabé orámování a u odečítače obrazovky text „zapnuto / vypnuto". Na černobílé tiskárně i pro
   barvoslepé tedy zůstává čitelné, které veličiny jsou v grafu. */
.power-chans { display: inline-flex; flex-wrap: wrap; gap: 0.3rem; }
.power-chan {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  line-height: 1.5;
}
.power-chan:hover { color: var(--text); border-color: var(--muted); }
.power-chan:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.power-chan.is-on { color: var(--text); font-weight: 600; box-shadow: inset 0 0 0 1px var(--accent-dark); }
.power-chan-box {
  display: inline-block;
  width: 0.95rem;
  height: 0.95rem;
  line-height: 0.9rem;
  text-align: center;
  font-size: 0.72rem;
  border: 1px solid var(--muted);
  border-radius: 3px;
  background: var(--card);
}
.power-chan.is-on .power-chan-box { border-color: var(--accent-dark); }
.power-chan-sw { display: inline-flex; gap: 1px; }
.power-chan-sw i { display: inline-block; width: 0.25rem; height: 0.85rem; border-radius: 1px; }
/* Vypnutý kanál má proužek zeslabený — ale poznat ho podle toho není potřeba (viz políčko výš). */
.power-chan:not(.is-on) .power-chan-sw i { opacity: 0.4; }
/* Barvy čar grafu (app/quality/chart.py PALETTE): a = L1/P, b = L2/Q, c = L3/S — to jsou
   SERIES_COLORS, fázová paleta celého portálu. „d" a „e" jsou EXTRA_COLORS a existují jen kvůli
   jednomu společnému grafu historie (30. 9. 2026): účiník a frekvence nemají fázi, takže by v něm
   jinak byly tou samou modrou jako P a U1. Hlídá to test — tenhle seznam a ta n-tice se nesmí
   rozejít, protože proužek u přepínače SLIBUJE barvu čáry v grafu. */
.power-sw-a { background: #2a78d6; }
.power-sw-b { background: #eb6834; }
.power-sw-c { background: #1baf7a; }
.power-sw-d { background: #6d4bb6; }
.power-sw-e { background: #c2185b; }

/* --- legendy pod grafem (30. 9. 2026) ----------------------------------------------------------
   Dvě serverová SVG hned pod jedním grafem: legenda KŘIVEK (u každého měřítka jednotka, rozsah
   a jestli patří levé nebo pravé ose — app/quality/chart.py scale_legend) a legenda ZNAČEK
   poruch, ve které jsou jen kategorie, které v okně opravdu jsou (app/faults/timeline.py
   mark_legend). Jsou to obrázky, ne HTML: tisknou se s grafem a nedají se „odstylovat" pryč. */
.power-legend { margin: 0.1rem 0 0; }
.power-legend svg { display: block; width: 100%; height: auto; }
.power-marks-legend { margin-top: 0.15rem; }
/* --- poznámky pod grafem (sazba, 30. 9. 2026) --------------------------------------------------
   Poznámek je pod JEDNÍM grafem osm až deset (zdroj dat, meze, znaménko, značky, osy). Do
   30. 9. 2026 to byly `display: block` bez čehokoli dalšího, takže na širokém sloupci (1600 px)
   z nich byl slitý blok drobného textu bez mezer přes celou obrazovku — přesně to, co vlastník
   popsal jako „rozsypanou stránku". Sazba to řeší třemi věcmi: seznam místo odstavce (každá
   poznámka je položka), mezera mezi položkami a hlavně OMEZENÁ DÉLKA ŘÁDKU. Široký má být graf,
   ne text — 74 znaků je řádek, na jehož konci oko ještě trefí začátek dalšího.
   `list-style: none`: je to popisek obrázku, ne výčet, a odrážky by z něj udělaly seznam úkolů. */
.power-caption { margin-top: 0.35rem; }
.power-notes {
  list-style: none;
  margin: 0;
  padding: 0;
  max-width: 74ch;
  display: grid;
  gap: 0.3rem;
}
.power-note { display: block; line-height: 1.45; }
/* Druhý blok: stálá vysvětlení („co je značka", jak se počítá účiník, jak se dělí osy). Jsou pod
   každým oknem stejná, takže nemají stát mezi větami o právě zobrazených datech — oddělí je linka
   a vlastní nadpis. Není to <details>: karta se u krátkých oken sama obnovuje (hx-trigger), takže
   rozbalené podrobnosti by se čtenáři uprostřed čtení samy zavřely. */
.power-more {
  max-width: 74ch;
  margin-top: 0.55rem;
  padding-top: 0.45rem;
  border-top: 1px solid var(--line);
}
.power-more-head { margin: 0 0 0.3rem; font-weight: 600; }
/* Řada s přepínačem os a značek. Popisek „Značky poruch:" stojí až za skupinou os, proto mu
   odsazení zleva, aby se od ní oddělil i na jednom řádku. */
.power-axes #power-marks-label { margin-left: 0.6rem; }

/* Věta „za zvolené období má hub data i pro: …" — odkazy v ní veličinu rovnou zapnou. */
.power-hint a { white-space: nowrap; }

/* Prázdný stav: nevybraná žádná veličina (předloha na jednotce má totéž — „vyber hodnoty
   vpravo"). Není to chyba, proto bez červené; jen viditelně, aby stránka nevypadala rozbitě. */
.power-empty {
  margin: 0.2rem 0 1rem;
  padding: 0.9rem 1rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  color: var(--muted);
}

/* Čísla v tabulkovém dvojčeti: pravý okraj řeší už td.num v app.css, tady jde o to, aby číslice
   měly stejnou šířku a sloupec „nepoletoval" při obnově karty. */
.power-tbl td.num, .power-tbl th.num { font-variant-numeric: tabular-nums; }

/* --- Táhlo výřezu, ikony a kurzor s hodnotami (29. 9. 2026) --------------------------------------
   Zadání vlastníka: „chci v grafech historie ovládání jako na stránce Kvalita v jednotce" — nad
   grafem popisek, pod grafem táhlo výřezu, vpravo nahoře drobné ikony.

   Rozdělení práce je schválně tohle: SVG kreslí server (i táhlo — je to obyčejný graf v malém),
   CSS ho jen umístí, a portal/app/static/chart.js přidává gesta. Bez skriptu je táhlo obrázek
   „kde v rozsahu jsem", ikony jsou odkazy a kurzor prostě není.

   Co se váže na .has-gestures (třídu přidá až skript na kartu), se váže PROTO, že bez skriptu
   by to buď lhalo, nebo překáželo: nápověda ke kolečku, kurzor typu „grab" a touch-action na
   táhle (prst by jinak nemohl rolovat stránku), místo držené pro odečet a táhlo, které nic
   nezvýrazňuje (viz .power-strip-flat).

   Žádný inline styl ani <style> (CSP style-src 'self'). Barvy proužků v odečtu jsou tytéž třídy
   .power-sw-a/-b/-c co u kanálů — skript tak nemusí sahat na element.style. */
.power-tools { display: flex; align-items: center; gap: 0.4rem; margin: 0 0 0.25rem; }
/* Ikony patří k pravému okraji grafu, popisek zůstane vlevo. */
.power-tools .power-icon { margin-left: 0; }
.power-tools .power-gest { margin-right: auto; }
/* Nápověda ke gestům: viditelná, teprve když se chart.js opravdu načetl. */
.power-gest { display: none; }
.power.has-gestures .power-gest { display: inline; }
.power-icon { font-size: 0.95rem; line-height: 1; padding: 0.15rem 0.45rem; }

/* Táhlo výřezu — stejná šířka jako grafy, aby okno sedělo pod tím, co zvýrazňuje. */
.power-strip { margin: -0.6rem 0 1.1rem; }
.power-strip svg { display: block; width: 100%; height: auto; }
.power-strip p { margin: 0.1rem 0 0; }
/* Uchopit se dá jen tam, kde skript opravdu je: touch-action: none by jinak prstu vzalo rolování
   stránky (pruh jde přes celou šířku) a kurzor „grab" by sliboval tažení, které neexistuje. */
.power.has-gestures .power-strip svg { touch-action: none; cursor: grab; }
.power.has-gestures .power-strip svg:active { cursor: grabbing; }
/* Táhlo, na kterém je zvýrazněné VŠECHNO (obyčejná stránka: klouzavé okno, celý den, úsek),
   neříká nic, co už není v hlavičce karty — bez skriptu je to jen 74 px kopie grafu navíc.
   Se skriptem zůstává: právě v tomhle stavu se za úchyty poprvé přibližuje. */
.power-strip-flat { display: none; }
.power.has-gestures .power-strip-flat { display: block; }

/* Odečet hodnot pod kurzorem. Místo si drží i prázdný — ale až tam, kde se kurzor může objevit:
   `hidden` je jinak display: none a karta by při prvním najetí myší poskočila o výšku odečtu. */
.power-readout {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.8rem;
  min-height: 1.6rem;
  margin: 0 0 0.35rem;
  padding: 0.15rem 0.4rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  font-size: 0.85rem;
}
.power-readout[hidden] { display: none; }
.power.has-gestures .power-readout[hidden] { display: flex; visibility: hidden; }
.power-ro { display: inline-flex; align-items: center; gap: 0.3rem; }
.power-ro i { display: inline-block; width: 0.25rem; height: 0.85rem; border-radius: 1px; }
.power-ro-time { color: var(--muted); }

/* Svislá čára kurzoru kreslí skript do SVG dvěma tahy (bílý podklad + tmavá linka), takže je vidět
   i přes křivku a na papíře. Tisk ji spolu s ovládáním schovává — na papíře není kam najet myší. */
@media print {
  .power-tools, .power-readout { display: none; }
  .power.has-gestures .power-readout[hidden] { display: none; }
  /* Pruh, na kterém je zvýrazněné všechno, na papíře nic neříká — ať už se skript načetl, nebo ne.
     Pruh se zvýrazněným VÝŘEZEM se tiskne dál: úchyty a časy pod ním fungují i černobíle. */
  .power.has-gestures .power-strip-flat { display: none; }
  /* Čáru kreslí skript do SVG GRAFU (figure.power-chart), ne do táhla — pravidlo napsané na
     .power-strip nematchovalo nic a kdo dal Cmd+P s myší nad grafem, vytiskl si svislou čáru. */
  .power-chart svg line[data-role="cursor"],
  .power-chart svg line[data-role="cursor-halo"] { display: none; }
}

/* Bez animací, když si o to prohlížeč řekne (žádná tu stejně není — pravidlo je tu proto, aby
   případná budoucí nepřibyla bez téhle výjimky). */
@media (prefers-reduced-motion: reduce) {
  .power-strip svg, .power-readout { transition: none; }
}

@media (max-width: 640px) {
  .power-row > span[role="group"], .power-chans { width: 100%; }
  .power-section { width: 100%; }
  .power-section label { margin-left: 0; }
  /* Pružná je OBÁLKA popisku s polem, ne pole samo: zalomit se smí jen mezi dvojicemi. */
  .power-sec-field { flex: 1 1 10rem; }
  .power-section input[type="date"] { flex: 1 1 6rem; min-width: 0; }
  /* Na úzkém displeji ikony patří na vlastní řádek, aby nesrážely popisek — a nápověda ke gestům
     přestane mluvit o kolečku a o myši, které telefon nemá. Táhlo prstem funguje, proto zbývá. */
  .power-tools { flex-wrap: wrap; }
  .power-gest-mouse { display: none; }
}


/* --- Kvalita sítě (GET /sites/{id}/quality, templates/quality/index.html) ----------------------
   Každá třída tohoto bloku má prefix .q-, aby bylo poznat, ke které podstraně patří.

   Použité tokeny jsou ty z :root nahoře (--card, --line, --muted, --radius, --accent-dark, --warn,
   --warn-bg, --danger, --ok-bg, --err-bg). Žádný inline styl ani <style> (CSP default-src 'self';
   style-src 'self'). Barva je v celém bloku jen doprovod — verdikt „splněno / nesplněno" je vždy
   vypsaný slovem, takže tisk, monochrom i barvoslepost nesou stejný stav. */

/* --- přepínač období (24 h / 7 dní / 30 dní / 1 rok) -------------------------------------------
   Aktivní odkaz nese aria-current="page"; stav je tedy v HTML jen jednou (stejně jako v .subnav). */
.q-range > span[role="group"] { display: inline-flex; gap: 0.3rem; flex-wrap: wrap; }
.q-range .btn[aria-current="page"] { box-shadow: inset 0 0 0 1px var(--accent-dark); }

/* --- řádek posledního intervalu (f · U1 · U2 · U3 · THD U1 · Plt · nesymetrie) ------------------
   Jeden řádek hodnot jako v jednotce; na úzkém displeji se zalomí, nikdy neroluje stránku. */
.q-last-time { margin: 0 0 0.4rem; font-weight: 600; font-variant-numeric: tabular-nums; }
.q-last { list-style: none; display: flex; flex-wrap: wrap; gap: 0.35rem 1.1rem; padding: 0; margin: 0 0 0.6rem; }
.q-last li { display: flex; align-items: baseline; gap: 0.35rem; }
.q-last-l { color: var(--muted); font-size: 0.85rem; }
.q-last-v { font-size: 1.05rem; font-weight: 600; font-variant-numeric: tabular-nums; }

/* --- dlaždice plnění EN 50160 -----------------------------------------------------------------
   Nejvýraznější prvek stránky (předloha: „Kvalita" v jednotce Unipi). Barva je jen doprovod —
   verdikt je v .q-verdict vypsaný slovem, takže tisk, monochrom i barvoslepost nesou stejný stav. */
.q-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 0.8rem; margin: 0.2rem 0 0.9rem; }
.q-tile { border: 1px solid var(--line); border-left: 4px solid var(--line); border-radius: var(--radius); padding: 0.6rem 0.8rem; background: var(--card); }
.q-tile p { margin: 0 0 0.25rem; }
.q-tile p:last-child { margin-bottom: 0; }
.q-tile-h { font-weight: 600; }
.q-pct { font-size: 1.6rem; font-weight: 700; line-height: 1.2; font-variant-numeric: tabular-nums; }
.q-verdict { font-size: 0.8rem; font-weight: 600; text-transform: lowercase; margin-left: 0.3rem; white-space: nowrap; }
.q-req { font-size: 0.85rem; color: var(--muted); }
.q-n { font-size: 0.85rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.q-note { font-size: 0.85rem; margin-top: 0.35rem; }

.q-tile.is-ok { border-left-color: var(--accent); background: var(--ok-bg); }
.q-tile.is-ok .q-verdict { color: var(--accent-dark); }
.q-tile.is-warn { border-left-color: var(--warn); background: var(--warn-bg); }
.q-tile.is-warn .q-verdict { color: var(--warn); }
.q-tile.is-bad { border-left-color: var(--danger); background: var(--err-bg); }
.q-tile.is-bad .q-pct, .q-tile.is-bad .q-verdict { color: var(--danger); }
/* málo dat / bez dat: procento se NIKDY nebarví zeleně, když nemá z čeho vzniknout */
.q-tile.is-thin, .q-tile.is-none { background: #f1f3f5; }
.q-tile.is-thin .q-pct, .q-tile.is-none .q-pct { color: var(--muted); }
.q-tile.is-thin .q-verdict, .q-tile.is-none .q-verdict { color: var(--warn); }

/* --- věta pod grafem (počet bodů a největší mezera v datech) -----------------------------------*/
.q-chart-meta { margin-top: 0.15rem; font-variant-numeric: tabular-nums; }

/* --- výtah „Poruchy dle přístroje — EN 50160" --------------------------------------------------*/
.q-dev th, .q-dev td { font-size: 0.85rem; padding: 0.35rem 0.55rem; }
.q-dev td.num { font-variant-numeric: tabular-nums; }

@media (max-width: 640px) {
  .q-tiles { grid-template-columns: minmax(0, 1fr); }
  .q-last { gap: 0.3rem 0.8rem; }
}


/* --- Poruchy a události (templates/faults/*) ---------------------------------------------------
   Jmenné prostory: .ev- = události a poruchy (log, štítky, tabulka oken), .tl- = časová osa dne.

   CSP style-src 'self' — v šablonách není ANI JEDEN inline style="…". Barva kategorie se proto
   nese třídou .ev-cat-<klíč>, která nastaví jedinou proměnnou --ev-color; tu pak používá tečka
   štítku i levý proužek řádku. Stejné hodnoty jsou i v portal/app/faults/timeline.py (CATEGORIES),
   protože SVG značky v grafu se kreslí atributem stroke a ten na CSS proměnnou stránky nedosáhne.
   Klíče kategorií: dip, swell, u_low, interruption, freq, fault, dyn, manual, record, other. */

/* Napěťová hladina a prahy (faults/list.html) — obdoba prvního řádku stránky DataLogger
   na jednotce. Prahy jsou oddělené tečkou-odrážkou, aby řádek šel číst i zalomený. */
.fl-levels { margin: 0.4rem 0 0.2rem; font-variant-numeric: tabular-nums; }
.fl-thr { white-space: nowrap; }
.fl-thr::before { content: " · "; color: var(--muted); }

/* --- barvy kategorií (jediné místo v CSS; druhé je CATEGORIES v app/faults/timeline.py) --------- */
.ev-cat-dip          { --ev-color: #fbbf24; }
.ev-cat-swell        { --ev-color: #fb923c; }
.ev-cat-u_low        { --ev-color: #f59e0b; }
.ev-cat-interruption { --ev-color: #f87171; }
.ev-cat-freq         { --ev-color: #a78bfa; }
.ev-cat-fault        { --ev-color: #ef4444; }
.ev-cat-dyn          { --ev-color: #38bdf8; }
.ev-cat-manual       { --ev-color: #94a3b8; }
.ev-cat-record       { --ev-color: #64748b; }
.ev-cat-other        { --ev-color: #9ca3af; }

/* Štítek kategorie: neutrální podklad + barevná tečka. Barva je tak vždy čitelná (u světlé žluté
   ani u syté červené se nemusí přebarvovat text) a nespoléhá se jen na ni — vedle je vždy slovo. */
.ev-tag {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  padding: 0.1rem 0.5rem;
  border-radius: 999px;
  background: #eef1f4;
  font-size: 0.78rem;
  font-weight: 600;
  white-space: nowrap;
}
.ev-tag::before {
  content: "";
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 2px;
  background: var(--ev-color, var(--muted));
  flex: none;
}

/* --- log událostí (faults/_events.html) --------------------------------------------------------
   Seznam, ne tabulka: zpráva z jednotky nese hodnoty i prahy a musí se celá zalomit, ne oříznout. */
.ev-log {
  list-style: none;
  margin: 0.6rem 0 0.4rem;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;
}
.ev-row {
  display: grid;
  grid-template-columns: 9.5rem 6.5rem minmax(0, 1fr);
  gap: 0.2rem 0.7rem;
  padding: 0.35rem 0.7rem;
  border-bottom: 1px solid var(--line);
  border-left: 3px solid transparent;
  font-size: 0.88rem;
}
.ev-row:last-child { border-bottom: none; }
.ev-time { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.ev-log .ev-tag {
  justify-self: start;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  font-size: 0.75rem;
}
/* Plná délka, zalomená i uprostřed dlouhého výrazu — nikdy se neořezává. */
.ev-msg { min-width: 0; overflow-wrap: anywhere; }

/* Závažnost: barevný proužek vlevo + jemný podklad. Info zůstává neutrální. */
.ev-sev-warning  { border-left-color: var(--warn); background: #fffdf3; }
.ev-sev-critical { border-left-color: var(--danger); background: #fdf6f5; }
tr.ev-sev-warning td  { box-shadow: inset 3px 0 0 var(--warn); }
tr.ev-sev-critical td { box-shadow: inset 3px 0 0 var(--danger); }
tr.ev-sev-warning td:not(:first-child),
tr.ev-sev-critical td:not(:first-child) { box-shadow: none; }

/* Zvolené období / závažnost v pruhu odkazů (stejný způsob jako .power-switch v app.css). */
.ev-pick[aria-current="true"] { box-shadow: inset 0 0 0 1px var(--accent-dark); font-weight: 700; }

/* Tabulka uložených oken: čísla na sebe pod sebou sedí. */
.ev-faults td.num, .ev-faults th.num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.ev-faults td, .ev-faults th { font-size: 0.88rem; }

/* --- časová osa dne (faults/_timeline.html) ----------------------------------------------------- */
/* Řada „‹ den | datum | den › | dnes" se odsud odstěhovala do .daynav níž: kreslí ji společná
   šablona templates/_daynav.html, kterou má časová osa i karta historie výrobny. */

.tl-cats { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.8rem 0 0.9rem; }
.tl-cat {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--line);
  border-left: 4px solid var(--ev-color, var(--muted));
  border-radius: var(--radius);
  background: var(--card);
  color: var(--text);
  text-decoration: none;
  font-size: 0.82rem;
}
.tl-cat:hover { color: var(--text); border-color: var(--ev-color, var(--muted)); }
.tl-cat .tl-count { color: var(--muted); font-variant-numeric: tabular-nums; }
/* Kategorie, která se v daný den nevyskytuje — zašedlá, ale pořád použitelná (jako na jednotce). */
.tl-cat.is-empty { opacity: 0.45; }
.tl-cat.is-active { font-weight: 700; box-shadow: inset 0 0 0 1px var(--accent); }
.tl-cat:focus-visible { outline: 2px solid #7fd3b0; outline-offset: 1px; }

.tl-chart { margin: 0 0 1.1rem; }
.tl-chart svg { display: block; width: 100%; height: auto; }
.tl-chart figcaption { margin-top: 0.2rem; }

/* Legenda značek — serverové SVG (app.faults.timeline.mark_legend). Na rozdíl od štítků .tl-cats,
   které jsou filtry a v tisku mizí, tahle legenda se TISKNE: jinak by na papíře byl graf plný
   čar bez klíče. */
.tl-legend { margin: -0.4rem 0 1rem; }
.tl-legend svg { display: block; width: 100%; height: auto; }
.tl-legend figcaption { margin-top: 0.1rem; }

.tl-tbl { margin-top: 0.5rem; }
.tl-tbl th, .tl-tbl td { font-size: 0.86rem; padding: 0.35rem 0.6rem; }
.tl-tbl td.num { font-variant-numeric: tabular-nums; }

@media (max-width: 640px) {
  /* Na mobilu se řádek logu zalomí pod sebe: čas a značka na jeden řádek, zpráva přes celou šířku. */
  .ev-row { grid-template-columns: 9.5rem minmax(0, 1fr); }
  .ev-msg { grid-column: 1 / -1; }
  .ev-faults { display: block; overflow-x: auto; }
}


/* --- Procházení po dnech (templates/_daynav.html, app.daynav) ----------------------------------
   JEDINÁ řada „‹ den | datum | den › | dnes" pro celý portál: časová osa dne na Poruchách a karta
   Historie výrobny. Kdyby měla každá stránka svou, rozešly by se při prvním zásahu do jedné z nich.
   Předloha je ovládání dne na stránce DataLogger v jednotce. */
.daynav { align-items: flex-end; margin-top: 0; }
.daynav-form { display: flex; align-items: flex-end; gap: 0.4rem; margin: 0; }
.daynav-date { margin: 0; }
.daynav-date input[type="date"] {
  font: inherit;
  padding: 0.3rem 0.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  color: var(--text);
}
.daynav-date input[type="date"]:focus-visible { outline: 2px solid var(--accent); }

@media (max-width: 640px) {
  /* Pozor: globální `label { display: flex; flex-direction: column }` dělá z popisku SLOUPEC, takže
     `flex-basis` na poli uvnitř by byla jeho VÝŠKA. Pružný je proto popisek, pole vyplní jeho šířku. */
  .daynav-form { flex-wrap: wrap; }
  .daynav-date { flex: 1 1 8rem; min-width: 0; }
  .daynav-date input[type="date"] { width: 100%; }
}


/* --- Správa (.mg-) a Schéma (.sch-) výrobny ----------------------------------------------------
   Šablony manage/index.html a schema/index.html jsou psané tak, aby byly čitelné i bez tohoto
   bloku: všechno nosné (karty, tabulky, odznaky, tlačítka) používá existující třídy a .mg-/.sch-
   jen dolaďují vzhled.

   Žádný inline styl, žádné <style> v šabloně — CSP je style-src 'self'. Používají se jen tokeny
   z :root (--card, --line, --accent, --muted, --warn, --warn-bg, --danger, --radius). */

/* --- Správa (templates/manage/index.html) ------------------------------------------------------
   Karty Výrobna / Edge jednotky / Sběr dat / Zařízení / Vzdálený přístup / Přiřazení uživatelé.
   Karta má jeden <h2>; <h3> uvnitř je jen dělítko sekce, proto je drobný a nenápadný. */
.mg-sub {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--muted);
  margin: 1.4rem 0 0.5rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--line);
}

/* Poctivý prázdný stav: celá věta, proč tu nic není — ne šedivá pomlčka.
   Barevně neutrální (není to chyba), jen odsazená svislou linkou, aby ji oko našlo. */
.mg-empty {
  margin: 0.2rem 0 0.8rem;
  padding: 0.55rem 0.9rem;
  border-left: 3px solid var(--line);
  background: #f7f9fa;
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--muted);
}

/* Nevyplněné jmenovité parametry: není to chyba, ale má to důsledky (meze v grafech, fázová vs.
   sdružená napětí), proto varovná, ne červená. */
.mg-warn {
  margin: 0.2rem 0 0.8rem;
  padding: 0.55rem 0.9rem;
  border-left: 3px solid var(--warn);
  background: var(--warn-bg);
  border-radius: 0 var(--radius) var(--radius) 0;
  color: var(--warn);
}
.mg-warn strong { color: inherit; }

/* Příkaz pro konzoli u pozastaveného streamu — portál stream nezapíná (do jednotky nikdy
   nezapisuje), jen ukáže, co napsat na hubu. Musí jít označit myší celý, proto vlastní řádek
   a zalomení na dlouhých hodnotách. */
.mg-cmd {
  display: block;
  margin-top: 0.3rem;
  padding: 0.3rem 0.5rem;
  background: #f1f3f5;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 0.8rem;
  line-height: 1.5;
  overflow-wrap: anywhere;
  user-select: all;
}

/* Formulář „Přidat uživatele": pole a tlačítko na jedné řádce, na úzkém displeji pod sebou. */
.mg-add {
  display: flex;
  gap: 0.6rem;
  align-items: flex-end;
  flex-wrap: wrap;
  margin-top: 0.9rem;
}
.mg-add label { flex: 1 1 16rem; }
.mg-add .actions { margin-top: 0; }

@media (max-width: 640px) {
  .mg-add { align-items: stretch; }
  .mg-add label { flex: 1 1 100%; }
}


/* --- Schéma (templates/schema/index.html + schema/_figure.html) ---------------------------------
   Vykreslené schéma je JEDNO serverové SVG z app/schema/render.py — barvy i tloušťky si veze jako
   atributy, protože CSP je style-src 'self' a v šabloně není žádný inline styl. CSS tady tedy
   nekreslí schéma, jen mu dává místo na stránce a stará se o tisk.

   Prázdný stav (schéma ještě není zrcadlené): místo prázdného plátna věta, proč tu nic není.
   Mřížka v pozadí je odkaz na plátno editoru v jednotce a zároveň říká „sem se bude kreslit". */
.sch-frame {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 14rem;
  padding: 1.5rem;
  margin: 0.6rem 0 1rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius);
  background-color: var(--card);
  background-image:
    repeating-linear-gradient(0deg, var(--line) 0 1px, transparent 1px 24px),
    repeating-linear-gradient(90deg, var(--line) 0 1px, transparent 1px 24px);
  background-size: 24px 24px;
  text-align: center;
}
.sch-frame p {
  margin: 0;
  max-width: 34rem;
  padding: 0.6rem 0.9rem;
  background: var(--card);
  border-radius: var(--radius);
  color: var(--muted);
}

/* Fragment s obrázkem (schema/_figure.html) — vyměňuje se celý, takže hlavička, stavová věta
   i tabulka drží stejné místo ve všech stavech a stránka pod obrázkem neposkakuje. */
.sch-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-top: 0.4rem;
}
.sch-count { margin-left: auto; }
.sch-state {
  margin: 0.4rem 0 0;
  min-height: 1.4rem;
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.sch-state strong { font-weight: 600; }

/* Plátno: SVG na celou šířku karty, bez vodorovného posuvu. Rám je světlý — schéma samo je kresba
   tenkými linkami a potřebuje kolem sebe klid. */
.sch-canvas {
  margin: 0.6rem 0 1rem;
  padding: 0.4rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--card);
}
.sch-canvas svg { display: block; width: 100%; height: auto; }

/* Textové dvojče obrázku: každý štítek ještě jednou jako řádek. */
.sch-tbl { width: 100%; border-collapse: collapse; margin: 0.2rem 0 0.6rem; }
.sch-tbl caption { text-align: left; padding-bottom: 0.3rem; }
.sch-tbl th, .sch-tbl td {
  border-bottom: 1px solid var(--line);
  padding: 0.3rem 0.5rem;
  text-align: left;
  font-weight: 400;
}
.sch-tbl thead th { color: var(--muted); font-size: 0.85rem; }
.sch-tbl tbody th { font-weight: 600; }
.sch-tbl .num { text-align: right; font-variant-numeric: tabular-nums; }

.sch-legend { margin: 0.2rem 0 0.6rem; }
.sch-source { margin: 0.2rem 0 0.4rem; }

/* Kresba, která není celá. Patří i na papír — proto ji @media print níž neschovává. */
.sch-warn {
  margin: 0.2rem 0 0.6rem;
  padding: 0.4rem 0.6rem;
  border-left: 3px solid var(--warn);
  background: var(--warn-bg);
  color: var(--warn);
}

.sch-sub {
  font-size: 0.95rem;
  font-weight: 600;
  color: var(--muted);
  margin: 1.4rem 0 0.5rem;
  padding-top: 0.8rem;
  border-top: 1px solid var(--line);
}

.sch-steps { margin: 0.3rem 0 0.8rem; padding-left: 1.3rem; }
.sch-steps li { margin: 0.3rem 0; }

@media (max-width: 640px) {
  .sch-count { margin-left: 0; width: 100%; }
}

@media print {
  /* Mřížka je jen náznak plátna — na papíře by z ní byl šedý obdélník. Schéma se tiskne samo
     o sobě: kresba nese význam TVAREM (sepnutý nůž je rovný, rozepnutý šikmý, plná šipka ukazuje
     směr, prázdná znamená „směr neznám"), takže funguje i černobíle — legenda tvarů ve fragmentu
     se proto tiskne s ním. Odznak stavu a tlačítko „Pokračovat" na papír nepatří; věta o stáří
     kopie (.sch-source) a upozornění na neúplnou kresbu (.sch-warn) ano. */
  .sch-frame { background-image: none; border-style: solid; }
  .sch-canvas { border: none; padding: 0; }
  .sch-head, .sch-state .btn { display: none; }
  .sch-figure { break-inside: avoid; }
}

/* --- Verze a aktualizace jednotky (kontrakt §2.3, packages/_system.html) ----------------------
   Karta je jediný blok, který z portálu vede k ZÁPISU do jednotky. Vypadá proto jako ostatní karty
   a nic nezvýrazňuje barvou samo o sobě: zvýrazněné je až to, co jednotka opravdu hlásí (běžící
   aktualizace, selhání). Odznak „aktuální" se nekreslí nikdy, dokud verzi neřekne jednotka. */
.sys-head { display: flex; align-items: baseline; gap: 0.6rem; flex-wrap: wrap; }
.sys-head h2 { margin: 0; }
.sys-age { font-size: 0.85rem; color: var(--muted); margin-left: auto; }
.sys-age.is-warn { color: var(--warn); }
.sys-note { margin: 0.4rem 0 0.8rem; }

.sys-mods { list-style: none; margin: 0; padding: 0; display: flex; gap: 0.2rem 1rem; flex-wrap: wrap; }
.sys-mods li { white-space: nowrap; }

.sys-job {
  margin: 1rem 0 0.4rem;
  padding: 0.6rem 0.8rem;
  border-left: 3px solid var(--line);
  background: #f7f9fa;
}
.sys-job h3 { margin: 0 0 0.3rem; font-size: 1rem; }
.sys-job p { margin: 0.2rem 0; }
.sys-job.is-running { border-left-color: var(--accent); background: var(--ok-bg); }
.sys-job.is-ok { border-left-color: var(--accent); }
.sys-job.is-bad { border-left-color: var(--danger); background: var(--err-bg); }

.sys-log { margin-top: 0.5rem; }
.sys-log summary { cursor: pointer; color: var(--muted); font-size: 0.85rem; }
/* Protokol z jednotky je nedůvěryhodný text: nikdy se nezalamuje do šířky karty na úkor čitelnosti
   a hlavně nikdy nepřeteče stránku — dlouhý řádek se posouvá uvnitř bloku. */
.sys-log pre {
  margin: 0.4rem 0 0;
  padding: 0.5rem 0.6rem;
  max-height: 16rem;
  overflow: auto;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  white-space: pre-wrap;
  word-break: break-word;
}

/* Otisk sha256 je 64 znaků; v tabulce skladu se musí zalomit, jinak by na úzkém displeji
   roztáhl celou tabulku a stránka by se posouvala do stran. */
.pkg-sha { word-break: break-all; }

.sys-why { margin-top: 0.4rem; }
.sys-why ul { margin: 0.2rem 0 0; padding-left: 1.3rem; }
.sys-steps { margin: 0.6rem 0 0.8rem; padding-left: 1.3rem; }
.sys-steps li { margin: 0.35rem 0; }
.sys-sub {
  font-size: 0.95rem; font-weight: 600; color: var(--muted);
  margin: 1.4rem 0 0.5rem; padding-top: 0.8rem; border-top: 1px solid var(--line);
}

button[disabled], .btn[disabled] { opacity: 0.5; cursor: not-allowed; }
button[disabled]:hover, .btn[disabled]:hover { background: var(--accent); }

@media (max-width: 640px) {
  .sys-age { margin-left: 0; width: 100%; }
}

/* Cesta zpět nad nadpisem (edges/detail.html). Drobná a tichá — je to navigace, ne obsah; stojí
   nad nadpisem, aby ji člověk našel tam, kde ji čeká, a netlačila se mezi karty. */
.crumb { margin: 0 0 .35rem; font-size: .9rem; }
.crumb a { color: var(--muted, #5a6472); text-decoration: none; }
.crumb a:hover, .crumb a:focus { color: var(--ink, #1c2430); text-decoration: underline; }
