/* Metview — kostra podle klikací makety `docs/design/maketa-oblasti.html`
   (issue #46). Mapa dostává celou plochu, legenda a členové rodiny jsou
   zasouvací svislé panely PŘES mapu (ne grid sloupce jako dřív, #26) — na
   telefonu i na šířku appka vypadá stejně, jen na `min-width:700px` se
   rodiny přesunou z pruhu pod plátnem do záhlaví (`.hdr .fams`/`.ov-fams`,
   viz media query níž).

   Tokeny (bg/panel/line/text/muted/accent) jsou beze změny z předchozí
   verze — maketa je navrhla se stejnými hodnotami, viz CLAUDE.md „Dvě
   kvality…". Nové tokeny (gold/lock/glass/btn/btn-on) přejaty z makety. */

:root {
  --bg: #0b1220;
  --panel: #131c2e;
  --line: #24304a;
  --text: #e8edf6;
  --muted: #94a3b8;
  --accent: #4ea1ff;
  --gold: #e6b84a;
  --lock: #7c8798;
  --glass: rgba(11, 18, 32, .74);
  --btn: #0f1728;
  --btn-on: #12253d;
  /* Podklad legendy — palety jsou návrhem průhledné, bílá dává nejvyšší
     kontrast pro barevná pásma (CLAUDE.md „Podklad mapy je bílý"). */
  --map-bg: #ffffff;

  /* Velikost podle ovládání (issue #46, bod 1): prst = základ, myš menší.
     Uživatelský krok malé/střední/velké (`html.fs-*`, viz níž) násobí navrch
     přes `@media (pointer:)` blok — kombinace dá přesně šest kroků z
     makety (`.app[data-pointer][data-size]`), beze změny JS. Střední =
     tenhle základ beze třídy (dřívější „normal"/nejmenší, #51). */
  --fs: 19px;
  --tap: 44px;
  --hdr: 52px;
  /* Odsazení panelu sytosti (`#layers`, #51) od levé hrany — mimo zónu gesta
     zpět v Androidu na prstu, menší na myši (tam žádné gesto zpět není). */
  --edge: 32px;
}

@media (pointer: fine) {
  :root { --fs: 15px; --tap: 34px; --hdr: 44px; --edge: 8px; }
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-size: var(--fs);
  line-height: 1.4;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}

/* Uživatelský krok malé/střední/velké (hamburger menu, #51) — násobí `--fs`
   NAVRCH ovládací základny, ne místo ní (viz `:root`/`@media(pointer:fine)`
   výš). Střední nemá vlastní třídu (= tenhle základ). Hodnoty přesně
   z makety: 17/19/23 px na prstu, 13/15/19 px na myši. */
html.fs-small { --fs: 17px; }
html.fs-large { --fs: 23px; }
@media (pointer: fine) {
  html.fs-small { --fs: 13px; }
  html.fs-large { --fs: 19px; }
}

button { font: inherit; color: inherit; cursor: pointer; }
button:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

svg.ic {
  width: 1.15em;
  height: 1.15em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  flex: 0 0 auto;
}

#app {
  position: relative;
  display: grid;
  grid-template-rows: var(--hdr) 1fr;
  height: 100dvh; /* dvh, ne vh — na mobilu se lišta prohlížeče schovává */
  overflow: hidden;
  padding: env(safe-area-inset-top) env(safe-area-inset-right)
           env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/* --- záhlaví: hamburger, oblast, rodiny (jen na širokém), tarif, běh --- */
.hdr {
  display: flex;
  align-items: center;
  gap: .35rem;
  padding: 0 .4rem;
  min-width: 0;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
}

.icon-btn {
  flex: 0 0 auto;
  width: var(--tap);
  height: var(--tap);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: .5rem;
  background: var(--btn);
  color: var(--text);
}
.icon-btn:active { background: #16203a; }

.hamburger {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  width: 18px;
}
.hamburger span { display: block; height: 2px; border-radius: 1px; background: var(--text); }

.region-btn {
  flex: 0 0 auto;
  height: var(--tap);
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: 0 .6rem;
  border: 1px solid var(--line);
  border-radius: .5rem;
  background: var(--btn);
  font-weight: 600;
  font-size: .9rem;
  color: var(--text);
}
.region-btn .caret { color: var(--muted); font-size: .8em; }

.grow { flex: 1 1 auto; min-width: 0; }

.tier {
  flex: 0 0 auto;
  height: calc(var(--tap) - 8px);
  display: flex;
  align-items: center;
  gap: .3rem;
  padding: 0 .55rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: transparent;
  color: var(--muted);
  font-size: .72rem;
  white-space: nowrap;
}
.tier b { color: var(--gold); }

.runinfo {
  flex: 0 0 auto;
  font-size: .66rem;
  line-height: 1.15;
  color: var(--muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.fams {
  display: flex;
  gap: .3rem;
  overflow-x: auto;
  scrollbar-width: none;
  min-width: 0;
}
.fams::-webkit-scrollbar { display: none; }

.chip {
  flex: 0 0 auto;
  height: var(--tap);
  display: flex;
  align-items: center;
  gap: .4rem;
  padding: 0 .6rem;
  border: 1px solid var(--line);
  border-radius: .5rem;
  background: var(--btn);
  color: var(--muted);
  font-weight: 600;
  font-size: .82rem;
  white-space: nowrap;
  transition: border-color .15s, background-color .15s, color .15s;
}
.chip[aria-selected="true"] { color: var(--text); border-color: var(--accent); background: var(--btn-on); }
.chip[disabled] { opacity: .4; }
/* Rodina bez aktivního člena, zobrazená jen díky oušku s okem (#48) —
   čárkovaně, kliknutí jen informuje (toast), nikam neodkazuje. */
.chip.inactive { color: var(--lock); border-style: dashed; cursor: default; }

/* Rodiny v záhlaví jen na širokém displeji (tablet i notebook) — na
   telefonu jsou v `.ov-fams` pod plátnem (spodní hrana je pro tažení
   nepraktická, viz CLAUDE.md „Přepis navigace…"). */
.hdr .fams { display: none; }
@media (min-width: 700px) {
  .hdr .fams { display: flex; flex: 1 1 auto; }
  .ov-fams { display: none; }
}

/* --- plátno: mapa dostane celou plochu, vše ostatní jsou překryvy --- */
.stage {
  position: relative;
  min-height: 0;
  background: var(--bg);
}
.map { position: absolute; inset: 0; width: 100%; height: 100%; }

.ov {
  position: absolute;
  background: var(--glass);
  border-radius: .45rem;
  padding: .25rem .55rem;
  font-size: .8rem;
  color: #fff;
  pointer-events: none;
}
/* Popisek produktu + atribuce Mapy.cz pod ním, jeden svislý sloupec v levém
   horním rohu (přesunuto z `#sideLeft` u panelu sytosti, #59 — tam se
   atribuce posouvala s `placeLayers()` podle otevřeného/zavřeného panelu a
   při otevření `#layers` se s ním vizuálně překrývala, viz git historie
   screenshotu v ticketu). Tady je pozice napevno, nezávislá na jakémkoli
   panelu — nemůže kolidovat s ničím, co se zasouvá/vysouvá. */
.ov-topleft {
  position: absolute;
  left: .5rem;
  top: .5rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
  max-width: calc(100% - 5.5rem);
}
.ov-label {
  position: static;
  max-width: 100%;
  display: flex;
  align-items: center;
  gap: .4rem;
  font-weight: 600;
  pointer-events: auto;
}
.ov-label span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ov-label small { font-weight: 400; color: var(--muted); }
.ov-label .info {
  flex: 0 0 auto;
  width: 1.5em;
  height: 1.5em;
  border-radius: 50%;
  border: 1px solid var(--muted);
  background: transparent;
  color: var(--muted);
  font-size: .8em;
  display: grid;
  place-items: center;
  padding: 0;
}
.ov-time {
  right: .5rem;
  top: .5rem;
  font-variant-numeric: tabular-nums;
}

/* --- svislé zasouvací panely: legenda vlevo, členové rodiny vpravo ---
   Úchyt je SAMOSTATNÝ prvek oddělený od těla 2px mezerou (`gap`) a zaoblený
   na všech rozích — dřív byly slité bez mezery a úchyt zaoblený jen zvenku,
   takže zaoblený roh těla za ním prosvítal (screenshot v #50). Tělo má
   vlastní zaoblení, jen na vnitřní straně (strana u okraje plátna je
   zarovnaná naostro, jinak by koukala mimo mapu) — 1:1 podle
   `docs/design/maketa-oblasti.html` (`.side`/`.side .handle`/`.side .body`). */
.side {
  position: absolute;
  top: 44%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  gap: 2px;
  z-index: 2;
  transition: transform .2s ease;
}
.side.left { left: 0; }
.side.right { right: 0; }
.side .handle {
  flex: 0 0 auto;
  width: 16px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: .4rem;
  background: var(--glass);
  color: var(--muted);
  font-size: .68rem;
  display: grid;
  place-items: center;
  padding: 0;
}
.side .body {
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: .45rem;
  display: flex;
  transition: padding .2s ease;
}
.side.left .body { border-left: 0; border-radius: 0 .45rem .45rem 0; }
.side.right .body { border-right: 0; border-radius: .45rem 0 0 .45rem; }

.legend .body { gap: .35rem; padding: .4rem .45rem; }
.legend canvas { display: block; width: 10px; height: 150px; border-radius: 3px; background: var(--map-bg); }
.legend .lab {
  position: relative;
  width: 3.4rem;
  font-size: .62rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.legend .lab span { position: absolute; left: 0; transform: translateY(-50%); white-space: nowrap; }
.legend.collapsed .lab { display: none; }
.legend.collapsed .body { padding: .3rem .25rem; }
.legend.collapsed canvas { width: 6px; height: 110px; }

/* Sloupec = tělo (grid s ouška) + oko POD ním, se STEJNOU 2px mezerou jako
   u úchytu od těla (`.side{gap:2px}`, #54 — dřív 4px, víc než úchyt bez
   zjevného důvodu). Dřív bylo oko přímo uvnitř `#railBody`, takže vypadalo
   jako další produkt (#50). `align-items: flex-end` zarovná oko na stejnou
   hranu jako tělo (u pravého okraje mapy) a zároveň dá `.col` jeho šířku =
   šířka těla, takže `.eye` (`width: 50%`) vyjde přesně na polovinu — 1:1
   podle makety. */
.rail .col { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
/* Tělo je grid, ne flex sloupec: `justify-items: stretch` roztáhne KAŽDÉ
   ouško na `width: 100%` grid dráhy, jejíž šířku určuje nejširší dítě —
   proto vyjdou všechna ouška stejně široká podle nejširšího, beze změny JS. */
.rail .body { display: grid; grid-auto-rows: auto; gap: 3px; padding: 4px 4px 4px 6px; justify-items: stretch; }
.rail button.m {
  width: 100%;
  min-width: 46px;
  min-height: var(--tap);
  padding: .2rem .45rem .2rem .4rem;
  border: 1px solid var(--line);
  border-radius: .45rem;
  background: var(--btn);
  color: var(--muted);
  font-size: .68rem;
  font-weight: 600;
  line-height: 1.15;
  display: flex;
  align-items: center;
  gap: .3rem;
  justify-content: flex-start;
  text-align: left;
  white-space: nowrap;
  transition: color .15s, border-color .15s, background-color .15s;
}
.rail button.m .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); flex: 0 0 auto; }
/* Dvouřádková ouška (#50, zarovnání doleva #54): `.lb` je sloupec zarovnaný
   DOLEVA (puntík vlevo, text hned za ním), `small` (první řádek — název
   rodiny, „Vítr"/„Vlny") je drobný a tlumený, druhý řádek (hodnota, „~3 km")
   nese základní řez. Jednořádkové členy (Oblačnost, Srážky, Teplota, …) mají
   v `.lb` jen prostý text bez `small`. Šířka podle nejširšího zůstává —
   určuje ji grid dráha (`.rail .body`), ne tenhle prvek. */
.rail button.m .lb { display: flex; flex-direction: column; align-items: flex-start; min-width: 0; }
.rail button.m .lb small { font-weight: 500; font-size: .86em; color: var(--muted); }
.rail button.m[aria-selected="true"] { color: var(--text); border-color: var(--accent); background: var(--btn-on); }
.rail button.m[aria-selected="true"] .dot { background: var(--accent); }
.rail button.m[disabled] { opacity: .4; }
/* Neaktivní člen, zobrazený jen díky oušku s okem — čárkovaně, klepnutí je
   jen toast s cenou (#48, CLAUDE.md „Přepis navigace…"). */
.rail button.m.inactive { color: var(--lock); border-style: dashed; }
.rail.collapsed button.m {
  min-width: 30px;
  max-width: 34px;
  min-height: 0;
  height: calc(var(--tap) - 10px);
  padding: .15rem .25rem;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 2px;
  font-size: .58rem;
  border-radius: .35rem;
}
.rail.collapsed button.m .lb { align-items: center; }
.rail.collapsed button.m .dot { width: 6px; height: 6px; }

/* Přepínač neaktivních (#50, nahrazuje dřívější `.rail button.eye` uvnitř
   těla): úzký prvek JAKO úchyt, mimo tělo, poloviční šířka menu (šířka
   `.col` = šířka těla, viz výš), zaoblený jen vlevo (`border-right: 0`,
   pravá strana je u okraje plátna). Ikony oko/oko-přeškrtnuté + zámek, ne
   text — stav (aktivní/vypnuto) nese `aria-pressed`, popis title/aria-label. */
.rail .eye {
  width: 50%;
  min-width: 40px;
  height: 24px;
  padding: 0;
  border: 1px dashed var(--line);
  border-right: 0;
  border-radius: .4rem 0 0 .4rem;
  background: var(--glass);
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-size: .62rem;
}
.rail .eye svg.ic { width: 1em; height: 1em; }
.rail .eye[aria-pressed="true"] { color: var(--text); border-style: solid; border-color: var(--accent); }
.rail.collapsed .eye { display: none; }
/* `.side{display:flex}` (author) by itself would beat the UA `[hidden]`
   rule — `hidden` toggling (legend bez palety, rail s jedním členem, viz
   app.js) potřebuje vlastní override. */
.side[hidden] { display: none; }

/* --- menu zobrazení produktu: ikona pod legendou, panel mimo gesto zpět
   (#51, 1:1 `docs/design/maketa-oblasti.html` `.layers-btn`/`.layers`) ---
   Svislá pozice `#sideLeft` (`top`) počítá `placeLayers()` v app.js, ne CSS
   — závisí na výšce legendy (nebo na výšce plátna, když legenda není).
   Nese jen ikonu vrstev — atribuce Mapy.cz bydlela tady taky (#55), ale
   sdílela `top` s panelem `#layers` a při jeho otevření se s ním vizuálně
   překrývala (zpětná vazba, #59), takže se přesunula na pevné místo pod
   popisek produktu (`.ov-topleft` výš). Vyšší `z-index` než `.layers`
   (panel má taky 2), ať tlačítko zůstane klikatelné nad ním. */
.side-left { position: absolute; left: .5rem; z-index: 3; display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.layers-btn { background: var(--glass); }
.layers-btn.hidden { visibility: hidden; }
/* Atribuce Mapy.cz — licence dlaždic vyžaduje viditelnou značku NA MAPĚ (ne
   v zasunovacím panelu), proto trvalý kompaktní odkaz, dřív pod ikonou
   vrstev (#55), od #59 pod popiskem produktu vlevo nahoře (`.ov-topleft`) —
   místo, které se nikdy nezasouvá ani nehýbe s jiným panelem. Text „Seznam.cz
   a.s. and others“ (v `title`) i odkaz ověřené 2026-09-11 proti
   developer.mapy.com/rest-api-mapy-cz/atribution/. */
.map-attrib {
  display: block;
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: .4rem;
  padding: 1px 6px;
  font-size: .6rem;
  line-height: 1.6;
  color: var(--muted);
  text-decoration: none;
  white-space: nowrap;
}
.map-attrib:hover, .map-attrib:focus-visible { color: var(--text); }
.layers {
  position: absolute;
  left: var(--edge);
  z-index: 2;
  display: flex;
  align-items: center;
  gap: 2px;
  transform: translateX(calc(-100% - var(--edge) - 2px));
  transition: transform .2s ease;
}
.layers.open { transform: none; }
.layers .body {
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: .5rem;
  padding: .45rem .6rem;
  width: 186px;
  display: grid;
  gap: .3rem;
}
.layers .body label {
  font-size: .68rem;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.layers .body input { width: 90px; margin: 0; flex: 0 0 auto; accent-color: var(--accent); }
/* Řádek „Moje poloha" (#55, dřív plovoucí `.locate` tlačítko na mapě) —
   stejné rozvržení jako `.layers .body label` výš (popisek vlevo, ovládací
   prvek vpravo), jen bez `<label>`, protože nejde o formulářový prvek. */
.layers .body .layers-row {
  font-size: .68rem;
  color: var(--muted);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
}
.layers .body .layers-row .icon-btn { width: calc(var(--tap) - 6px); height: calc(var(--tap) - 6px); }
/* Mezistav "získávám polohu" (#53) — okamžitá zpětná vazba na klik, ne až
   po 3 s GPS fixu. Ztlumení + zákaz dalšího kliknutí (`pointer-events`), ne
   `disabled` — tlačítko nesmí ztratit `aria-label`/přístupnost jen kvůli
   probíhajícímu dotazu. Pulzování respektuje globální
   `prefers-reduced-motion` pravidlo výš (animace se tam vypínají plošně). */
#locateBtn[aria-busy="true"] { opacity: .55; pointer-events: none; animation: locate-pulse 1.1s ease-in-out infinite; }
@keyframes locate-pulse { 0%, 100% { opacity: .55; } 50% { opacity: .9; } }
.layers .handle {
  flex: 0 0 auto;
  width: 16px;
  height: 44px;
  border: 1px solid var(--line);
  border-radius: .4rem;
  background: var(--glass);
  color: var(--muted);
  font-size: .68rem;
  display: grid;
  place-items: center;
  padding: 0;
}

/* --- spodní překryvy: časová osa (+ rodiny na telefonu) --- */
.bottom-ov {
  position: absolute;
  left: .5rem;
  right: .5rem;
  bottom: .5rem;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: .35rem;
}
@media (min-width: 700px) {
  .bottom-ov { left: 50%; right: auto; transform: translateX(-50%); width: min(70%, 560px); }
}

.ov-time-axis { width: 100%; padding: 2px .7rem; border-radius: .5rem; background: var(--glass); }
.ov-time-axis input[type="range"] {
  width: 100%;
  height: var(--tap);
  margin: 0;
  display: block;
  position: relative;
  /* Nad `.axis-days`/`.axis` (#55) — obě mají `pointer-events:none` (viz
     níž), takže na stackování pro DOTEK/KLIK nezáleží, ale palec (thumb)
     musí VIZUÁLNĚ malovat NAD popisky, ne pod nimi (zadání „palec přes ně
     smí jezdit"). `.axis` je v DOM AŽ PO sliderem, takže by bez vlastního
     `z-index` jinak stohovala nad ním navzdory `pointer-events:none`
     (to řeší jen hit-testing, ne malování). */
  z-index: 1;
  background: transparent;
  accent-color: var(--accent);
  -webkit-appearance: none;
  appearance: none;
}
.ov-time-axis input[type="range"]::-webkit-slider-runnable-track { height: 6px; border-radius: 3px; background: var(--line); }
.ov-time-axis input[type="range"]::-moz-range-track { height: 6px; border-radius: 3px; background: var(--line); }
.ov-time-axis input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px;
  height: 26px;
  margin-top: -10px;
  border-radius: 50%;
  border: 2px solid #0b1220;
  background: var(--accent);
}
.ov-time-axis input[type="range"]::-moz-range-thumb {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 2px solid #0b1220;
  background: var(--accent);
}

/* Datum dne (#54, přepočítáno #55) — vlastní řádek NAD sliderem (viz
   index.html), aby nemohl kolidovat s hodinami 6/12/18, které zůstávají pod
   linkou v `.axis`. Vycentrované na střed dne, `buildAxis()` počítá pozici.
   Zbytek modulu (výška pruhu, mezera k lince) je #55.

   Pruh osy (#55): dřív popisky seděly jako VLASTNÍ prostor NAD/POD celým
   sliderem (`height:var(--tap)`, plné dotykové pole), takže mezi textem a
   linkou zbýval poloviční `--tap` prázdna na obě strany — přesně to
   zpětná vazba popsala jako „vysoký pruh, popisky daleko od linky".
   `#slider` si dotykové pole ponechává (`var(--tap)`, nezmenšeno — jde jen
   o vizuální přesah, ne o zúžení cíle pro prst), ale `.axis-days`/`.axis`
   se do něj záporným marginem ZASUNOU, takže z něj navenek čouhá jen
   tenký pruh textu. Vzorec `4px - var(--tap)/2` počítá vzdálenost od
   OKRAJE `#slider` k lince (`var(--tap)/2` mínus polovina tloušťky trati
   3px) a přidává 1px mezeru — platí pro obě `--tap` (dotyk/myš, viz media
   query výš), bez duplikace. Text uvnitř obou řádků je proto
   `pointer-events:none`, ať zásah do sliderova dotykového pole nikdy
   neukrojí z plochy pro tažení (viz `z-index` u `#slider` výš, který řeší
   VIZUÁLNÍ pořadí — palec smí přes popisky přejíždět). */
.axis-days {
  position: relative;
  height: .8rem;
  margin-bottom: calc(4px - var(--tap) / 2);
  font-size: .62rem;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.axis-days span { position: absolute; bottom: 0; transform: translateX(-50%); white-space: nowrap; }

.axis {
  position: relative;
  height: .8rem;
  margin-top: calc(4px - var(--tap) / 2);
  font-size: .62rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  pointer-events: none;
}
.axis span { position: absolute; top: 0; transform: translateX(-50%); white-space: nowrap; }
.axis i { position: absolute; top: -1px; width: 1px; height: 4px; background: var(--muted); }
.axis i.day { top: -2px; height: .9rem; background: var(--text); opacity: .7; }

.ov-fams { padding: .3rem .35rem; border-radius: .5rem; background: var(--glass); }

/* --- toast --- */
.toast {
  position: absolute;
  left: 50%;
  top: calc(var(--hdr) + 10px);
  transform: translateX(-50%);
  z-index: 4;
  padding: .3rem .7rem;
  border-radius: .45rem;
  background: #1b2a44;
  border: 1px solid var(--line);
  font-size: .78rem;
  opacity: 0;
  pointer-events: none;
  white-space: nowrap;
  transition: opacity .2s;
}
.toast.show { opacity: 1; }

/* --- dotaz Ano/Ne (#51, nahrazuje `window.confirm()`) ---
   `position: fixed`, ne `absolute` — stejný grid-past jako u `.sheet` (viz
   níž): `#confirm` je přímý potomek `#app` (CSS grid) bez `grid-row`, takže
   `absolute` by se počítalo vůči implicitní gridové buňce, ne vůči appce. */
.confirm {
  position: fixed;
  left: 50%;
  top: 40%;
  transform: translate(-50%, -50%);
  z-index: 25;
  display: none;
  flex-direction: column;
  gap: .6rem;
  min-width: 240px;
  max-width: min(90vw, 320px);
  padding: .8rem 1rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: .7rem;
  box-shadow: 0 12px 30px rgba(0, 0, 0, .4);
  color: var(--text);
}
.confirm.open { display: flex; }
.confirm .btns { display: flex; gap: .4rem; justify-content: flex-end; }
.confirm .btns button {
  height: calc(var(--tap) - 6px);
  padding: 0 .8rem;
  border: 1px solid var(--line);
  border-radius: .45rem;
  background: var(--btn);
  color: var(--text);
  font-size: .8rem;
}
.confirm .btns button.ok { border-color: var(--accent); background: var(--btn-on); }

/* --- nabídka „Přidat na plochu" (#59, přepsáno po zpětné vazbě) ---
   PRVNÍ verze byla fixní banner dole — přes celou šířku, nad sliderem i
   pruhem rodin, i po zúžení na sloupec (text/tlačítka) pořád nápadný a
   rušil ovládání appky. Teď je to třetí, nejmenší řádek v `.ov-topleft`
   (pod popiskem produktu a atribucí Mapy.cz, viz index.html) — normální
   flow, žádné `position:fixed`/`z-index`/vlastní šířka, roste odshora dolů
   a nikdy nezasáhne do spodní časové osy. Drobné písmo (`.68rem`) záměrně
   — má tam BÝT, ne řvát. Zavření lze znovu otevřít z hamburgeru
   (`#menuInstallBtn`, `showInstallNudge(kind, {force:true})` v app.js). */
.install-nudge {
  display: none;
  flex-direction: column;
  gap: .3rem;
  max-width: 100%;
  padding: .4rem .55rem;
  background: var(--glass);
  border: 1px solid var(--line);
  border-radius: .4rem;
  color: var(--muted);
}
.install-nudge.open { display: flex; }
.install-nudge__text { font-size: .68rem; line-height: 1.3; }
.install-nudge__btns { display: flex; align-items: center; justify-content: flex-end; gap: .3rem; }
.install-nudge__btns button {
  height: 20px;
  padding: 0 .5rem;
  border: 1px solid var(--line);
  border-radius: .35rem;
  background: var(--btn);
  color: var(--text);
  font-size: .64rem;
  white-space: nowrap;
}
.install-nudge__btns button.ok { border-color: var(--accent); background: var(--btn-on); }
#installNudgeDismiss { padding: 0 .4rem; color: var(--muted); }

/* --- sheety: zespodu na telefonu, panel 480px zprava na širokém ---
   `.open` řídí transform/opacity, ne `hidden` atribut — jinak by se nedal
   animovat přechod (issue #46, bod 7). */
/* `position: fixed`, NE `absolute` — `#app` je grid a `.sheet` je jeho přímý
   potomek bez `grid-row`/`grid-column`; Chromium ho pak auto-umístí do
   implicitního gridového řádku a `inset:0` se spočítá vůči TÉ buňce, ne
   vůči `#app` (zažito: sheet vyjde o desítky px posunutý nahoru/dolů).
   `fixed` se řídí viewportem a gridová past ho vůbec nepotká. */
.sheet { position: fixed; inset: 0; z-index: 20; pointer-events: none; }
.sheet.open { pointer-events: auto; }
.sheet__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, .55);
  opacity: 0;
  transition: opacity .22s;
}
.sheet.open .sheet__backdrop { opacity: 1; }
.sheet__panel {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  max-height: 80dvh;
  display: flex;
  flex-direction: column;
  background: var(--panel);
  border-top: 1px solid var(--line);
  border-top-left-radius: 1rem;
  border-top-right-radius: 1rem;
  transform: translateY(100%);
  transition: transform .22s ease;
}
.sheet.open .sheet__panel { transform: translateY(0); }
/* Ukotvené záhlaví (#49): `.sheet__pinned` nescrolluje (titulek, podtitulek,
   u sheetu Předplatné navíc tarify/rozpočet/filtr), scrolluje jen
   `.sheet__scroll` pod ním — 1:1 tvar `.head`/`.scroll` z
   docs/design/maketa-oblasti.html, teď společný pro všechny sheety. */
.sheet__pinned { flex: 0 0 auto; padding: .5rem .75rem .35rem; border-bottom: 1px solid var(--line); }
.sheet__head { display: flex; align-items: center; justify-content: space-between; }
.sheet__title { font-weight: 600; }
/* Obnovit appku (#51) sedí v záhlaví hamburgeru vlevo od křížku — obě ikony
   spolu, `.sheet__head` je `justify-content:space-between` mezi titulkem
   a tímhle prvkem (ne mezi třemi položkami zvlášť). */
.sheet__head-actions { display: flex; align-items: center; gap: .3rem; flex: 0 0 auto; }
/* (i) sheet title nese jméno produktu + rodinu (`#infoTitle`, viz `openInfo()`
   v app.js) — rodina jako drobný odsazený štítek, ne slitá s názvem. */
.sheet__title span { margin-left: .4rem; font-size: .7rem; font-weight: 400; color: var(--muted); }
.sheet__scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: .4rem .75rem calc(1rem + env(safe-area-inset-bottom));
  /* Scrollbar jako součást appky, ne systémový — 1:1
     `.sheet .scroll` z docs/design/maketa-oblasti.html. */
  scrollbar-width: thin;
  scrollbar-color: var(--line) transparent;
}
.sheet__scroll::-webkit-scrollbar { width: 8px; }
.sheet__scroll::-webkit-scrollbar-thumb { background: var(--line); border-radius: 4px; border: 2px solid var(--panel); }
.sheet__scroll::-webkit-scrollbar-track { background: transparent; }

@media (min-width: 700px) {
  .sheet__panel {
    left: auto;
    top: 0;
    bottom: 0;
    width: min(480px, 100%);
    max-height: none;
    border-radius: 0;
    border-top: none;
    border-left: 1px solid var(--line);
    transform: translateX(100%);
  }
  .sheet.open .sheet__panel { transform: translateX(0); }
}

/* Hamburger (#51): na telefonu je zespodu JAKO OSTATNÍ sheety (beze
   změny — žádné `.sheet--left` pravidlo na malé šířce), na širokém vyjíždí
   ZLEVA místo zprava (na rozdíl od ostatních sheetů, které tam jedou
   zprava — viz `@media(min-width:700px) .sheet__panel` výš). Dřív vjíždělo
   zleva vždy, i na telefonu, což maketa (šesté kolo) změnila. */
@media (min-width: 700px) {
  .sheet--left .sheet__panel {
    left: 0; right: auto; top: 0; bottom: 0;
    width: min(480px, 100%);
    max-height: none;
    border-radius: 0;
    border-top: none;
    border-left: none;
    border-right: 1px solid var(--line);
    transform: translateX(-100%);
  }
  .sheet--left.open .sheet__panel { transform: translateX(0); }
}

.drawer__section { margin: 1rem 0; }
.drawer__label {
  font-size: .75rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  margin-bottom: .35rem;
}
.drawer__item {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: .6rem .75rem;
  margin-bottom: .4rem;
  border: 1px solid var(--line);
  border-radius: .6rem;
  background: var(--btn);
  color: var(--text);
  text-align: left;
}
.drawer__item[disabled] { opacity: .45; }

.drawer__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  min-height: var(--tap);
  margin-bottom: .5rem;
}
.drawer__row-label { color: var(--text); display: flex; align-items: center; gap: .4rem; }
.drawer__row input[type="range"] { flex: 1 1 auto; max-width: 160px; accent-color: var(--accent); }

/* Nápověda kláves (#52) — dvousloupcový seznam kbd/popisek, stejný vzor jako
   `docs/design/maketa-oblasti.html` (`.keys`/`kbd`). Obsah generuje
   `buildKeysHelp()` v app.js ze `keyHintRows()`. */
.keys {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: .3rem .8rem;
  align-items: center;
  font-size: .85rem;
}
.keys span { color: var(--muted); }
kbd {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: .8em;
  padding: .05rem .35rem;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: .3rem;
  background: var(--btn);
  color: var(--text);
  justify-self: start;
}

/* Tři písmena A v rostoucí velikosti (#51) — vizuálně napovídá, co tlačítko
   dělá, na rozdíl od dřívějšího stejně velkého textu. */
.font-size-group { display: flex; gap: .3rem; }
.font-size-opt { font-weight: 700; }
.font-size-opt[data-size="small"] { font-size: var(--fs); }
.font-size-opt[data-size="medium"] { font-size: calc(var(--fs) + 2px); }
.font-size-opt[data-size="large"] { font-size: calc(var(--fs) + 4px); }
.font-size-opt[aria-pressed="true"] { border-color: var(--accent); background: var(--btn-on); }

.run-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  min-height: var(--tap);
  padding: .6rem .75rem;
  margin-bottom: .35rem;
  border: 1px solid var(--line);
  border-radius: .6rem;
  background: var(--btn);
  color: var(--text);
  text-align: left;
}
.run-row[aria-current="true"] { border-color: var(--accent); background: var(--btn-on); }
.run-row__meta { font-size: .75rem; color: var(--muted); }

/* --- oblast (mapka pokrytí + seznam) a pořadí rodin (issue #47) ---
   `.row`/`.grp`/`.ttl` jsou 1:1 z docs/design/maketa-oblasti.html — sdílené
   mezi sheetem oblastí (výsledky klepnutí do mapky, seznam všech oblastí)
   a sheetem pořadí rodin (jeden řádek na rodinu). */
.sheet__subtitle { font-size: .7rem; color: var(--muted); margin: .3rem 0 0; }

.grp {
  font-size: .66rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: .8rem 0 .3rem;
}

.row {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: calc(var(--tap) + 4px);
  padding: .3rem .4rem;
  margin-bottom: .3rem;
  border-radius: .5rem;
  border: 1px solid transparent;
  background: var(--btn);
}
.row.sel { border-color: var(--accent); background: var(--btn-on); }
.row.off { background: transparent; }
.row.off .ttl b { color: var(--lock); }
.row[tabindex] { cursor: pointer; }
.ttl { flex: 1 1 auto; min-width: 0; }
.ttl b { display: flex; align-items: center; gap: .35rem; font-size: .88rem; font-weight: 600; }
.ttl span { display: block; font-size: .68rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.regmap {
  width: 100%;
  display: block;
  border: 1px solid var(--line);
  border-radius: .5rem;
  background: #0f1728;
  cursor: crosshair;
  margin-bottom: .3rem;
}

/* Pořadí rodin: úchyt tažení — `touch-action:none`, jinak prst posouvá
   stránku místo řádku (funguje prstem i myší, viz `startOrderDrag`). */
.row .grip {
  flex: 0 0 auto;
  width: 22px;
  align-self: stretch;
  display: grid;
  place-items: center;
  color: var(--muted);
  cursor: grab;
  touch-action: none;
  font-size: 1.1em;
  user-select: none;
}
.row.dragging { opacity: .55; border-color: var(--accent); }
.order-actions { display: flex; justify-content: flex-end; margin-top: .5rem; }

/* --- Předplatné (#48): tarify, rozpočet, řádek produktu, (i) --- */
.row button, .toggle {
  min-width: var(--tap);
  height: calc(var(--tap) - 6px);
  padding: 0 .55rem;
  border: 1px solid var(--line);
  border-radius: .45rem;
  background: var(--btn);
  color: var(--text);
  font-size: .76rem;
}
.row button[aria-pressed="true"], .toggle[aria-pressed="true"] { border-color: var(--accent); background: var(--btn-on); }
.row button:disabled { opacity: .35; cursor: default; }
/* (i) na řádku produktu — kolečko, stejný vzor jako `.ov-label .info`. */
.row button.i { min-width: calc(var(--tap) - 6px); height: calc(var(--tap) - 6px); padding: 0; border-radius: 50%; }
/* Zaškrtávátko řádku produktu (#49): vlastní `button role="checkbox"` vpravo
   na konci řádku — nezaškrtnuté tmavé (`--btn`) s rámečkem, zaškrtnuté zlaté
   s fajfkou. Nahrazuje `input[type=checkbox]` vlevo z #48 (zpětná vazba
   uživatele z telefonu: bílé zaškrtávátko vlevo rušilo). 1:1 `.cb` z
   docs/design/maketa-oblasti.html. */
.cb {
  width: calc(var(--tap) - 14px);
  height: calc(var(--tap) - 14px);
  flex: 0 0 auto;
  margin: 0;
  border: 1px solid var(--line);
  border-radius: .35rem;
  background: var(--btn);
  display: grid;
  place-items: center;
  color: #0b1220;
  padding: 0;
}
.cb[aria-checked="true"] { background: var(--gold); border-color: var(--gold); }
.cb[aria-checked="true"]::after { content: "✓"; font-weight: 700; font-size: .9em; }
.cb:disabled { opacity: .35; cursor: default; }

.menu-row { display: flex; align-items: center; gap: .6rem; min-height: var(--tap); font-size: .82rem; flex-wrap: wrap; }

.coin { font-size: .66rem; padding: .1rem .4rem; border-radius: .4rem; border: 1px solid var(--line); color: var(--muted); white-space: nowrap; }
.coin.paid { color: var(--gold); border-color: #6b5a24; }
.coin.free { color: #9fe0b8; border-color: #2d6b4a; }

.tiers { display: grid; grid-template-columns: repeat(4, 1fr); gap: .3rem; margin: .3rem 0 .6rem; }
.tiers button { height: calc(var(--tap) + 8px); border: 1px solid var(--line); border-radius: .45rem; background: var(--btn); color: var(--text); font-size: .78rem; line-height: 1.15; }
.tiers button[aria-pressed="true"] { border-color: var(--gold); color: var(--gold); background: #1c1a12; }

.budget { display: grid; grid-template-columns: 1fr auto; gap: .2rem .6rem; font-size: .78rem; margin: .4rem 0 .6rem; }
.budget .barx { grid-column: 1 / -1; height: 8px; border-radius: 4px; background: var(--btn); overflow: hidden; border: 1px solid var(--line); }
.budget .barx i { display: block; height: 100%; background: var(--gold); }

/* Hlavička sbalitelné oblasti v seznamu produktů (aktivní oblast otevřená,
   ostatní sbalené — `tierOpenRegions` v app.js). */
.reg-head { display: flex; align-items: center; gap: .5rem; min-height: var(--tap); cursor: pointer; border-radius: .45rem; padding: 0 .3rem; }
.reg-head:hover { background: var(--btn); }
.reg-head b { flex: 1 1 auto; font-size: .85rem; }
.reg-head span { font-size: .68rem; color: var(--muted); }
.reg-head .car { color: var(--muted); font-size: .8em; width: 1em; text-align: center; }
.reg-body[hidden] { display: none; }

/* (i) o produktu: náhled 96×72 ze skutečných dat, viz `setInfoThumbnail()`.
   Světlý podklad (ne `--bg`) — náhled je tmavý produktový snímek na
   průhledném pozadí, potřebuje kontrast nezávislý na tmavém tématu appky. */
.info-card { display: grid; grid-template-columns: 96px 1fr; gap: .6rem; align-items: start; margin: .4rem 0 .8rem; }
.info-thumb {
  width: 96px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: .4rem;
  background: #e6e8dc;
  color: #55605a;
  font-size: .6rem;
  text-align: center;
  padding: .2rem;
}
.info-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.info-card p { margin: 0 0 .3rem; font-size: .78rem; }
.info-card p.meta { color: var(--muted); font-size: .68rem; }

/* Čipy v režimu "ikona + drobný popisek" — ikona nahoře, malý text pod ní,
   místo ikony + textu vedle sebe (výchozí, viz `.chip` výš). `.chip--icons`
   je stejný vzhled jako samotný izolovaný modifikátor (#51, „Nabídka
   produktů" — živá ukázka obou variant musí vypadat správně bez ohledu na
   to, co appka zrovna má nastavené v `#app[data-chips]`). */
#app[data-chips="icons"] .chip,
.chip--icons {
  flex-direction: column;
  justify-content: center;
  gap: 1px;
  padding: 0 .4rem;
  min-width: var(--tap);
  height: calc(var(--tap) + 8px);
}
#app[data-chips="icons"] .chip svg.ic,
.chip--icons svg.ic { width: 1.35em; height: 1.35em; }
#app[data-chips="icons"] .chip .lb,
.chip--icons .lb { font-size: .56rem; font-weight: 500; }

/* "Nabídka produktů" (#51, dřív textový přepínač): dva živé čipy Oblačnost
   (ikona+text / ikona+popisek), klepnutí přepne volbu — `buildChipSample()`
   v app.js, `aria-selected` zvýrazní aktivní stejně jako u čipů rodin. */
.chip-sample { display: flex; gap: .4rem; }

/* Zásah do všech animací pod jedním pravidlem (issue #46, bod 7) — jednodušší
   a spolehlivější než hlídat `prefers-reduced-motion` v každé komponentě
   zvlášť. */
@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}
