/*
 * Styl portalu i prodejniho webu. Zamerne jeden soubor bez buildu
 * a bez inline stylu - CSP je `default-src 'self'` bez `unsafe-inline`
 * (SecurityHeadersMiddleware), takze styl nesmi byt v sablone.
 *
 * Vizualni smer: grafit + jedna signalni barva na kostni bile.
 *
 * Signalni (cihlova) barva **neni** barva primarniho tlacitka. Nese ji
 * odkaz, mikropopisek sekce, cena a focus - tlacitka jsou grafitova.
 * Duvod je provozni, ne estetickcy: cervena pak jednoznacne znamena
 * "tohle neco smaze". Kdyby byl primarni CTA cihlovy a mazani cervene,
 * jsou to na jedne obrazovce dve skoro stejne barvy s opacnym vyznamem.
 */

:root {
    color-scheme: light;

    /* Plochy. `--bg` je tepla kostni, ne cista bila - papirove karty
       se na ni daji odlisit hranou, ne stinem. */
    --bg: #f5f4f1;
    --paper: #ffffff;
    --paper-sunken: #faf9f7;

    /* Text. Grafit misto cerne: #000 na bile na LCD "vibruje". */
    --ink: #1a1c20;
    --ink-soft: #3c4149;
    /* `--muted` se meri proti `--bg`, ne proti bile: nese ho i paticka
       a popisky dlazdic, ktere lezi na kostnim podkladu. Na nem dava
       4.95:1, tj. WCAG AA i pro bezny text. Svetlejsi odstin uz AA
       na kostni nesplnil, i kdyz na bile vypadal v poradku. */
    --muted: #656a72;
    --faint: #848a92;

    /* Linky. Vlasova cara nese celou strukturu misto stinu. */
    --line: #e4e1dc;
    --line-strong: #cbc7c0;

    /* Signalni barva. */
    --signal: #bf3f26;
    --signal-dark: #96301b;
    --signal-tint: #fdf2ee;
    /* Oznaceny text. Pruhledna, ne `--signal-tint`: vyber lezi na
       kartach, v zapustenych panelech i na kostnim pozadi a pod kazdym
       z nich ma zustat videt, ze je to tatáž barva. */
    --signal-select: rgba(191, 63, 38, .22);

    /* Stavy. `--error` je hlubsi karmin, aby se nepletl se signalni.
       `--info` (probiha) je zamerne mimo cervenou rodinu: "Zřizuje se"
       a "Zřízení selhalo" jsou dva sousedni stavy jedne sluzby a nesmi
       se dat splest podle barvy. */
    --ok: #1f7a4d;
    --ok-tint: #eef7f2;
    --info: #1f5f8b;
    --info-tint: #eef4f9;
    --warn: #8a6100;
    --warn-tint: #fbf5e6;
    --error: #a2181a;
    --error-tint: #fdeeee;

    --radius: 8px;
    --radius-sm: 6px;

    /* Vyska hlavicky. Verejny web ma v ni tlacitko a portal jen textove
       odkazy, takze bez teto miry mel kazdy obal jinak vysoky pruh a pri
       prechodu mezi weby znacka poskocila. Hodnota je vyska toho
       nejvyssiho obsahu - tlacitka i s odsazenim hlavicky. */
    --topbar-h: 4.5rem;

    /* Stin jen tam, kde neco opravdu lezi nad strankou. */
    --lift: 0 1px 2px rgba(26, 28, 32, .05), 0 8px 24px -12px rgba(26, 28, 32, .18);

    --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    --mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

/* `display` z tridy jinak atribut `hidden` prebije - a prvky, ktere
   odkryva az skript (tlacitko tisku dokladu), by blikaly i bez nej. */
[hidden] { display: none !important; }

/* Misto pro svisly posuvnik drzime i na strankach, ktere se vejdou na
   obrazovku. Bez toho byl prehled o sirku posuvniku sirsi nez objednavka
   a pri prechodu mezi nimi cely obsah vcetne navigace poskocil do strany. */
html { scrollbar-gutter: stable; }

/* Kotvy (zalozky ceniku, rozbalovaci nabidka) nesmi skoncit pod lepici
   hlavickou - bez odsazeni byl nadpis sekce schovany za ni. */
html { scroll-padding-top: 5.5rem; }

body {
    margin: 0;
    background: var(--bg);
    color: var(--ink);
    font: 16px/1.6 var(--sans);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: var(--signal); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { color: var(--signal-dark); }

/* Oznaceny text nese signalni barvu, ale jen naredenou. Plna cihlova
   plocha pod delsim odstavcem prebije text a cte se to spatne - proto
   zustava pismo grafitove a barva je jen v podkladu. */
::selection {
    background: var(--signal-select);
    color: var(--ink);
}

/* Na grafitovych plochach by naredena cihlova zmizela a grafitovy text
   na ni nebyl videt. Tam se vyber obraci: plna signalni, bile pismo.
   `::selection` se nededi, takze kazda takova plocha musi byt vyjmenovana. */
.button::selection,
.chip.is-active::selection,
.adminbar-tag::selection {
    background: var(--signal);
    color: var(--paper);
}

/* Jeden focus styl pro celou aplikaci. Klavesnice se tu pouziva
   (spravci sluzeb), takze prstenec nesmi nikde zmizet. */
:focus-visible {
    outline: 2px solid var(--signal);
    outline-offset: 2px;
    border-radius: 2px;
}

h1, h2, h3 {
    /* Zaporny tracking drzi velke nadpisy pohromade - system-ui je
       na displejovych velikostech rozsypany. */
    letter-spacing: -.018em;
    line-height: 1.22;
    text-wrap: balance;
}

h1 { margin: 0 0 .75rem; font-size: 1.6rem; font-weight: 650; }
h2 { margin: 2rem 0 .75rem; font-size: 1.2rem; font-weight: 650; }
h3 { margin: 0 0 .35rem; font-size: 1rem; font-weight: 650; letter-spacing: -.01em; }

h1:first-child, h2:first-child, h3:first-child { margin-top: 0; }

p { margin: 0 0 1rem; }
p:last-child { margin-bottom: 0; }

code { font-family: var(--mono); font-size: .92em; }

/* ─────────────────────────────────────────────────────────────────────
   Kostra stranky
   ───────────────────────────────────────────────────────────────────── */

.topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    min-height: var(--topbar-h);
    padding: .9rem 1.5rem;
    border-bottom: 1px solid var(--line);
    background: var(--paper);
}

.brand {
    font-weight: 700;
    font-size: 1.05rem;
    letter-spacing: -.02em;
    text-decoration: none;
    color: var(--ink);
    white-space: nowrap;
}

.brand span { color: var(--signal); }

/* Znacka pred textem (E1c9). Dokud neni logo (E13), je to dlazdice
   z faviconu - stejna, jakou clovek vidi v zalozce. */
.brand { display: inline-flex; align-items: center; gap: .5rem; }
.brand-mark { display: block; width: 1.6rem; height: 1.6rem; flex: none; }

.topbar-user {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .35rem 1rem;
}

.topbar-user a {
    color: var(--ink-soft);
    text-decoration: none;
    font-size: .875rem;
}

.topbar-user a:hover { color: var(--signal); }

.user-email {
    color: var(--muted);
    font-size: .8rem;
    padding-left: 1rem;
    border-left: 1px solid var(--line);
}

.topbar-logout { display: none; }

.content {
    max-width: 62rem;
    margin: 2rem auto 3.5rem;
    padding: 0 1.5rem;
}

/* ─────────────────────────────────────────────────────────────────────
   Administrace

   Vlastni pruh pod hlavickou. Neni to jen navigace - je to hlavni
   signal, ze clovek saha na cizi data. Proto ma jinou plochu nez
   zbytek portalu a nezmizi ani na uzkem displeji.
   ───────────────────────────────────────────────────────────────────── */

.adminbar {
    background: var(--paper-sunken);
    border-bottom: 1px solid var(--line);
}

.adminbar-inner {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: .35rem 1.25rem;
    max-width: 84rem;
    margin: 0 auto;
    padding: 0 1.5rem;
}

.adminbar-tag {
    margin-right: .5rem;
    padding: .18rem .5rem;
    border-radius: var(--radius-sm);
    background: var(--ink);
    color: var(--paper);
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Aktivni sekce se pozna podvrzenim, ne jen tucnym pismem - tucne
   pismo v rade odkazu splyne. */
.adminbar-link {
    padding: .8rem 0;
    border-bottom: 2px solid transparent;
    color: var(--ink-soft);
    font-size: .875rem;
    text-decoration: none;
    white-space: nowrap;
}

.adminbar-link:hover { color: var(--ink); }

.adminbar-link.is-active {
    color: var(--ink);
    font-weight: 600;
    border-bottom-color: var(--signal);
}

.topbar-admin-link.is-active { color: var(--signal); font-weight: 600; }

/* Tabulky administrace jsou sirsi nez klientske - je v nich klient,
   tarif, stav, node i cas. V 62rem se lamaly do dvou radku, zatimco
   vedle nich zustavala tretina obrazovky prazdna. */
.admin .content { max-width: 84rem; }

/* Prehled sluzeb (`body.wide`). Neni to administrace, ale radek ma stejny
   problem: pet rychlych akci vedle domeny a data se do 62rem nevejde,
   tlacitka se zalomila do druhe rady a domena se rozdelila na dva radky. */
.wide .content { max-width: 72rem; }

/* Tlacitko v administraci si bere sirku podle textu. Prihlasovaci
   formular naopak plnou sirku chce - proto jen tady. */
.admin .form .button { align-self: flex-start; }

.footer {
    max-width: 62rem;
    margin: 0 auto;
    padding: 1.5rem;
    color: var(--muted);
    font-size: .85rem;
    border-top: 1px solid var(--line);
}

.footer .footer-inner {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .5rem 2rem;
    flex-wrap: wrap;
    max-width: none;
    padding: 0;
}

.footer a { color: var(--muted); text-decoration: none; }
.footer a:hover { color: var(--signal); }

.admin .footer { max-width: 84rem; }
.wide .footer { max-width: 72rem; }

/* ─────────────────────────────────────────────────────────────────────
   Karta
   ───────────────────────────────────────────────────────────────────── */

.card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.75rem;
}

/* Karty jdou pod sebou v proudu stranky. V mrizce (`.cards`, `.plan-grid`)
   o rozestupy uz stara `gap` - bez tohohle vynuleni by prvni karta v rade
   sedela o 1.25rem vys nez ostatni a cely cenik stal do schodu. */
.card + .card { margin-top: 1.25rem; }
.cards .card + .card,
.plan-grid .card + .card { margin-top: 0; }

.card-narrow { max-width: 26rem; margin: 2rem auto; }

/* Karta pro nevratnou akci. Smazani sluzby vypadalo presne jako sekce
   "Doklady" o kus vys - jediny rozdil byl v nadpisu. Cervena hrana je
   tu proto, aby se na ni nedalo dostat omylem pri rolovani. */
.card-danger { border-color: rgba(162, 24, 26, .35); }
.card-danger > h2:first-child { color: var(--error); }

/* Zapustena plocha uvnitr karty - shrnuti, vypocet, vysledek. */
.card-inset {
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    padding: 1rem 1.25rem;
    margin: 1.25rem 0;
}

/* ─────────────────────────────────────────────────────────────────────
   Formulare
   ───────────────────────────────────────────────────────────────────── */

/* Pole se nemaji roztahovat pres celou kartu. V klientskem portalu to
   nevadilo, ale v sirsi administraci vznikla policka pres 80 znaku,
   do kterych se pise jeden duvod. */
.form { display: flex; flex-direction: column; gap: .3rem; max-width: 34rem; }

.form label {
    margin-top: .9rem;
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--ink-soft);
}

.form input,
.form select,
.form textarea {
    padding: .6rem .7rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
}

.form input::placeholder { color: var(--faint); }

.form input:focus,
.form select:focus,
.form textarea:focus {
    outline: 2px solid var(--signal);
    outline-offset: 1px;
    border-color: var(--signal);
}

/* Tlacitko odeslani stoji od posledniho pole dal nez pole mezi sebou. */
.form .button { margin-top: 1.4rem; }

.form-inline {
    border-bottom: 1px solid var(--line);
    padding-bottom: 1.25rem;
    margin-bottom: .5rem;
}

/* Výpis logu (A19.3). Řádky se **nezalamují**: záznam nginxu i zásobník
   volání PHP jsou dlouhé a zalomení z nich udělá kaši, ve které nejde
   poznat, kde jeden řádek končí. Scrolluje se proto vodorovně uvnitř
   bloku, ne celou stránkou. */
.log {
    max-height: 32rem;
    overflow: auto;
    margin-top: .9rem;
    padding: .8rem 1rem;
    border: 1px solid var(--line);
    border-radius: 4px;
    background: var(--paper-sunken);
    color: var(--ink);
    font-family: var(--mono);
    font-size: .82rem;
    line-height: 1.5;
    white-space: pre;
    tab-size: 4;
}

/* Neměnná část cesty před polem (kořen webu, A19.1). Je to údaj, ne vstup —
   proto zarovnané k řádku pole a bez rámečku, aby nesvádělo do něj psát. */
.path-prefix {
    display: inline-block;
    margin-right: .15rem;
    color: var(--ink-soft);
    font-size: .85rem;
    white-space: nowrap;
}

.checkbox {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin-top: .85rem;
    font-size: .9rem;
    color: var(--ink-soft);
}

.checkbox input { width: auto; accent-color: var(--signal); }

/* Souhlas s VOP je na dva radky - zaskrtavatko patri k prvnimu, ne doprostred. */
.checkbox-consent { align-items: flex-start; line-height: 1.5; margin-bottom: .75rem; }
.checkbox-consent input { margin-top: .3rem; }

.filters {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    margin: 1.25rem 0;
    padding-bottom: 1.25rem;
    border-bottom: 1px solid var(--line);
}

.filters select,
.filters input {
    padding: .4rem .55rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .875rem;
}

/* ─────────────────────────────────────────────────────────────────────
   Tlacitka

   Primarni je grafitove, ne cihlove - viz poznamka v hlavicce souboru.
   ───────────────────────────────────────────────────────────────────── */

.button {
    display: inline-block;
    padding: .62rem 1.15rem;
    border: 1px solid var(--ink);
    border-radius: var(--radius-sm);
    background: var(--ink);
    color: var(--paper);
    font: inherit;
    font-weight: 600;
    font-size: .95rem;
    line-height: 1.35;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
    transition: background-color .12s ease, border-color .12s ease;
}

.button:hover {
    background: var(--signal);
    border-color: var(--signal);
    color: var(--paper);
}

.button-ghost {
    display: inline-block;
    padding: .62rem 1.15rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-weight: 600;
    font-size: .95rem;
    line-height: 1.35;
    text-decoration: none;
    cursor: pointer;
    transition: border-color .12s ease, color .12s ease;
}

.button-ghost:hover { border-color: var(--ink); color: var(--ink); }

/* Musi stat az za `.button-ghost`, ne pred nim: obe pravidla maji stejnou
   specificitu, takze rozhoduje poradi v souboru. Driv bylo `.button-small`
   vys a `button-ghost button-small` tak melo plnou vysku - zmenseni se
   tise nekonalo. */
.button-small { padding: .42rem .8rem; font-size: .85rem; }

/* Nevratna akce: obrys, ne plocha. Plny cerveny obdelnik svadi
   ke kliknuti prave tam, kde se klikat nema. */
.button-danger {
    background: var(--paper);
    border-color: var(--error);
    color: var(--error);
}

.button-danger:hover { background: var(--error); border-color: var(--error); color: var(--paper); }

/* Druha cesta do portalu: prihlaseni uctem poskytovatele (A2.17).

   Zamerne `button-ghost`, ne druhe plne tlacitko. Dve stejne vyrazna
   tlacitka vedle sebe znamenaji rozhodovani tam, kde clovek jen chce
   dovnitr - primarni zustava to, co uz zna. */
.button-provider {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .6rem;
    width: 100%;
}

.button-provider .provider-mark { flex: none; }

/* Oddelovac "nebo" mezi formularem a druhou cestou. Cara sama by rekla
   "konec formulare"; tady jde o to, ze pod ni je alternativa. */
.form-divider {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin: 1.5rem 0 1rem;
    color: var(--muted);
    font-size: .85rem;
}

.form-divider::before,
.form-divider::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--line);
}

/* Tlacitko, ktere se tvari jako odkaz - odhlaseni, drobne akce v tabulce. */
.link-button {
    /* Uvnitr flexu se blokovalo samo, v bunce tabulky uz ne - a jako
       radkovy prvek by svisle odsazeni netlacilo radek od radku. */
    display: inline-block;
    border: 1px solid var(--line-strong);
    background: var(--paper);
    color: var(--ink-soft);
    border-radius: var(--radius-sm);
    padding: .3rem .65rem;
    font: inherit;
    font-size: .82rem;
    cursor: pointer;
}

.link-button:hover { color: var(--ink); border-color: var(--ink); }
.link-button-active { border-color: var(--ink); color: var(--ink); font-weight: 600; }

/* Odkaz "dal" v rade rychlych akci. Rada vedle sebe vypada jako uplny
   vycet moznosti, takze ten jediny, ktery vede na celou administraci,
   musi byt videt jako tezsi - jinak splyne s ostatnimi. */
.link-button-more { color: var(--ink); border-color: var(--ink); }
.link-button-more:hover { background: var(--ink); color: var(--paper); }

.link-danger { color: var(--error); }
.link-danger:hover { color: var(--error); }

/* Akce v tabulce: formularova tlacitka vedle sebe, ne pod sebou. */
.actions, .row-actions { display: flex; flex-wrap: wrap; gap: .4rem; align-items: center; }
.actions form, .row-actions form { display: inline; }

/* V tabulce se akce lamat nesmi. Sloupec je uzky, takze "Znovu" a "Zrušit"
   skoncily pod sebou a kazdy radek mel jinou vysku - seznam se pak necte. */
.table .row-actions { flex-wrap: nowrap; justify-content: flex-end; }
.table .row-actions .link-button { white-space: nowrap; }

/* Kdyz je ta bunka primo `<td>`, `display: flex` z pravidla vyse ji vyradi
   z rozvrzeni radku: prohlizec kolem ni vyrobi anonymni bunku, tlacitka
   pak stoji jinde nez text vedle nich a spodni linka radku pod nimi
   nepokracuje. Bunka proto zustava bunkou a odsazeni drzi `margin`. */
td.actions, td.row-actions { display: table-cell; white-space: nowrap; }
td.row-actions { text-align: right; }

td.actions > *, td.row-actions > * { vertical-align: top; }
td.actions > * + *, td.row-actions > * + * { margin-left: .4rem; }

/* Rozbalovaci potvrzeni uvnitr bunky akci (obnova ze zalohy).
   `td.actions` ma `nowrap`, aby se tlacitka nelamala do dvou radku -
   jenze rozbaleny panel je bezny odstavcovy text a s nowrap se roztahne
   az za okraj karty. Uvnitr `details` proto zalamovani zase zapiname
   a formular ma svou sirku, ne sirku sve nejdelsi vety. */
td.actions details { white-space: normal; }
td.actions details > form {
    display: block;
    max-width: 34rem;
    margin-top: .5rem;
    margin-left: 0;
}
td.actions details > form input[type="text"] { width: 100%; max-width: 18rem; }

/* Shluk tlacitek, ktery se smi zalomit. Bunka s `nowrap` se neda zmensit
   pod sirku vsech tlacitek v rade - pate tlacitko u sluzby uz tabulku
   pretahlo a prehled dostal vodorovny posuvnik. Uvnitr shluku rozhoduje
   `flex-wrap`, takze nejuzsi mozna bunka je jedno tlacitko a zalomi se
   az tehdy, kdyz sirka opravdu dojde. */
.action-cluster {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    justify-content: flex-end;
}

/* V tabulce je shluk uzsi nez jinde a rozhoduje kazdy pixel: ctyri akce
   souboru se do sloupce vejdou jen tesne. Mensi mezera a uzsi tlacitka
   jsou to, co drzi radek na jedne rade - jinak "Smazat" spadne samo dolu
   a kazdy radek ma jinou vysku. */
.table .action-cluster { gap: .3rem; }
.table .action-cluster .link-button { padding: .3rem .55rem; white-space: nowrap; }

/* Rozbalene `details` uvnitr shluku visi pod svym tlacitkem, misto aby se
   roztahlo v rade. Jako bezna flex polozka si vzalo cely radek uprostred
   shluku, takze se otevrenim prejmenovani prerovnaly akce kolem nej -
   "Smazat" skocilo o radek niz a mirilo se na nej naslepo. Takhle se
   nad tabulkou nehne nic. */
.action-cluster details { position: relative; }

.action-cluster details[open] > form {
    position: absolute;
    top: calc(100% + .35rem);
    right: 0;
    z-index: 5;
    width: max-content;
    max-width: min(22rem, 80vw);
    padding: .65rem .75rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    box-shadow: 0 8px 24px rgba(17, 19, 22, .14);
    text-align: left;
}

/* Pole primo v rade akci (prejmenovani, prava) byla dosud bez stylu, takze
   vedle tlacitek stal syrovy prvek prohlizece. Vlastni vzhled nechteji -
   jen stejnou vysku a stejny obrys jako tlacitko, u ktereho stoji.

   Selektor jde pres `.actions`, ne pres `.table`: v administraci sedi
   uvnitr bunek i cele formulare (`.form`) a ty maji svou vlastni, vetsi
   miru. `.table input` by je pretlacil - je specifictejsi nez `.form input`. */
.table .actions input[type="text"],
.table .actions select {
    padding: .28rem .5rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .82rem;
    line-height: 1.35;
}

.table .actions input[type="text"]:focus,
.table .actions select:focus {
    outline: 2px solid var(--signal);
    outline-offset: 1px;
    border-color: var(--signal);
}

/* Popisek, pole a tlacitko v plovoucim panelu. Obecne pravidlo pro
   `td.actions details > form` davalo poli `width: 100%`, coz tlacitko
   odstrcilo na dalsi radek. */
.rename-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
}

.rename-form label { margin: 0; }

td.actions details > form.rename-form input[type="text"] {
    width: auto;
    min-width: 9rem;
    flex: 1 1 9rem;
    max-width: 18rem;
}

/* Prava jsou v tabulce jedina bunka s formularem, ktery neni akce na konci
   radku - drzi se proto vlevo a nesmi se lamat pod sebe. */
.perm-form { flex-wrap: nowrap; }
.perm-form select { max-width: 12rem; }

/* ─────────────────────────────────────────────────────────────────────
   Hromadne akce pod tabulkou (spravce souboru)

   Driv to byl jeden odstavec, ve kterem stala tlacitka, popisky a pole
   v jedne rade. Pri zalomeni se popisek odtrhl od sveho pole a "Zabalit"
   skoncilo pod "Presunout do slozky" - nedalo se poznat, co k cemu patri.
   Kazda akce s polem je proto vlastni neroztrzitelna skupina.
   ───────────────────────────────────────────────────────────────────── */

.bulk-actions {
    margin-top: 1.25rem;
    padding: 1rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
}

.bulk-actions > * + * { margin-top: .75rem; }

.bulk-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem .75rem;
}

/* Popisek a pole jsou jedna polozka radku, takze zalomeni je nikdy
   nerozdeli. Tlacitko za nimi uz zalomit smi. */
.bulk-field {
    display: flex;
    align-items: center;
    gap: .4rem;
    white-space: nowrap;
}

.bulk-field label {
    font-size: .8rem;
    font-weight: 600;
    letter-spacing: .01em;
    color: var(--ink-soft);
}

.bulk-field input[type="text"] {
    padding: .38rem .6rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .85rem;
}

.bulk-field input[type="text"]::placeholder { color: var(--faint); }

.bulk-field input[type="text"]:focus {
    outline: 2px solid var(--signal);
    outline-offset: 1px;
    border-color: var(--signal);
}

/* Mazani stoji za carou, ne v rade s ostatnimi. Nevratna akce nema byt
   ctvrte tlacitko v poradi, o ktere clovek zavadi cestou k "Presunout". */
.bulk-destructive {
    padding-top: .75rem;
    border-top: 1px solid var(--line);
}

/* Druhy radek v bunce: tarif pod nazvem sluzby. Je to udaj k tomu nad nim,
   ne dalsi sloupec - proto slabsi a bez vlastniho odsazeni shora. */
.row-sub { display: block; font-size: .8rem; color: var(--muted); }

/* Bunky, ktere maji zustat na jednom radku (nazev sluzby, cislo, cas).
   Sirsi obsah radeji odroluje - `.table-scroll` je na to. */
.cell-nowrap { white-space: nowrap; }

/* Nazev se lame i uprostred slova. Bez toho si jedina polozka jako
   `logo-hodne-dlouhy-nazev-souboru.png` vzala sirku sloupce, akce vedle ni
   uz se nevesly do jedne rady - a zaplatily to vsechny ostatni radky. */
.entry-name { max-width: 18rem; overflow-wrap: anywhere; }

/* Cesta ke slozce domeny (A2.6o) je jedno dlouhe slovo - bez zalomeni
   roztahne sloupec domen a tlacitka akci vytlaci z karty. */
/* Lame se radeji u lomitek (`<wbr>` v sablone) nez uprostred `public_html`. */
.hint.domain-target { display: block; margin: .35rem 0 0; overflow-wrap: anywhere; }

/* Slozka se od souboru pozna koncovym lomitkem, jako v `ls -F`. Pripona je
   v CSS zamerne: do nazvu polozky nesmi, jinak by ji uzivatel zkopiroval
   vcetne lomitka a cesta by nesedela. */
.entry-directory::after { content: "/"; color: var(--muted); }

/* ─────────────────────────────────────────────────────────────────────
   Hlavicka obrazovky, filtry, strankovani

   Sdilene prvky administrace. Filtr byl driv na kazde obrazovce jiny -
   fronta mela stitky s pocty, sluzby formular s tlacitkem "Filtrovat",
   audit taky formular. Tri obrazovky vedle sebe, tri ovladani.
   ───────────────────────────────────────────────────────────────────── */

.page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.page-head h1 { margin: 0; }
.page-sub { margin: .35rem 0 0; color: var(--muted); font-size: .9rem; }
.page-actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }

/* Panel filtru: jeden pruh, ne rozsypane ovladaci prvky. */
.toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem 1.25rem;
    flex-wrap: wrap;
    padding: .75rem 0 1rem;
    border-bottom: 1px solid var(--line);
    margin-bottom: .25rem;
}

.chips { display: flex; gap: .4rem; flex-wrap: wrap; }

.chip {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .34rem .7rem;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    background: var(--paper);
    color: var(--ink-soft);
    font-size: .84rem;
    text-decoration: none;
    white-space: nowrap;
}

.chip:hover { border-color: var(--ink); color: var(--ink); }

/* Aktivni filtr je plocha, ne jen silnejsi obrys - v rade stitku
   se rozdil v barve okraje ztrati. */
.chip.is-active {
    background: var(--ink);
    border-color: var(--ink);
    color: var(--paper);
    font-weight: 600;
}

.chip-count {
    font-variant-numeric: tabular-nums;
    font-size: .78rem;
    color: var(--muted);
}

.chip.is-active .chip-count { color: rgba(255, 255, 255, .75); }

/* Poplach v poctu: nula selhani se nema tvarit stejne jako dvanact. */
.chip-count-alert { color: var(--error); font-weight: 700; }
.chip.is-active .chip-count-alert { color: #ffb4a8; }

.toolbar-search { display: flex; gap: .4rem; align-items: center; }

.toolbar-search input,
.toolbar-search select {
    padding: .4rem .6rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .875rem;
}

.toolbar-search input[type="search"] { min-width: 15rem; }

.pagination {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--line);
}

.pagination-info { color: var(--muted); font-size: .85rem; margin: 0 auto 0 0; }

/* Konec seznamu se ma poznat. Driv vedlo "další →" i z posledni
   strany na prazdnou. */
.pagination-disabled {
    padding: .3rem .65rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    color: var(--faint);
    font-size: .82rem;
    cursor: default;
}

/* Cas v tabulce: relativni napred, presny v `title`. */
.cell-time { color: var(--muted); white-space: nowrap; font-size: .85rem; }
.cell-time time { border-bottom: 1px dotted var(--line-strong); cursor: help; }

/* Prazdny stav rekne, co to znamena - ne jen "nic tu neni". */
.empty {
    padding: 2.5rem 1.5rem;
    text-align: center;
    color: var(--muted);
    border: 1px dashed var(--line-strong);
    border-radius: var(--radius);
    background: var(--paper-sunken);
}

.empty strong { display: block; color: var(--ink); font-size: 1rem; margin-bottom: .3rem; }
.empty p { margin: 0; font-size: .9rem; }

/* ─────────────────────────────────────────────────────────────────────
   Hlaseni
   ───────────────────────────────────────────────────────────────────── */

.notice {
    position: relative;
    margin: 0 0 1rem;
    padding: .75rem 1rem .75rem 1.15rem;
    border: 1px solid var(--line);
    border-left: 3px solid var(--line-strong);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    background: var(--paper-sunken);
    font-size: .92rem;
}

.notice-ok    { border-left-color: var(--ok);    background: var(--ok-tint);    border-color: rgba(31, 122, 77, .22); }
.notice-warn  { border-left-color: var(--warn);  background: var(--warn-tint);  border-color: rgba(138, 97, 0, .22); }
.notice-error { border-left-color: var(--error); background: var(--error-tint); border-color: rgba(162, 24, 26, .22); }

.hint {
    color: var(--muted);
    font-size: .85rem;
    margin-top: 1.25rem;
    margin-bottom: 0;
}

.note { color: var(--muted); font-size: .85rem; }

/* ─────────────────────────────────────────────────────────────────────
   Tabulky
   ───────────────────────────────────────────────────────────────────── */

.table { width: 100%; border-collapse: collapse; margin-top: 1.25rem; font-size: .92rem; }

.table th, .table td {
    text-align: left;
    padding: .7rem .6rem;
    border-bottom: 1px solid var(--line);
    vertical-align: top;
}

.table thead th {
    color: var(--muted);
    font-weight: 600;
    font-size: .75rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    border-bottom: 1px solid var(--line-strong);
    white-space: nowrap;
}

/* Posledni radek nema cim oddelovat - vcetne radku, ktery zacina <th>
   (tabulka parametru ma zahlavi ve sloupci, ne v hlavicce). */
.table tbody tr:last-child td,
.table tbody tr:last-child th { border-bottom: 0; }

.table tbody tr:hover { background: var(--paper-sunken); }

/* Cisla se ctou ve sloupci - stejna sirka cislic a zarovnani doprava.
   Selektor musi byt stejne specificky jako `.table td`, jinak ho
   zarovnani doleva z hlavicky tabulky pretlaci. */
.num, .price,
.table .num, .table .price {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.table-scroll { overflow-x: auto; margin-top: 1.25rem; }
.table-scroll .table { margin-top: 0; }

/* Nadpis sekce uz odstup drzi sam. */
.section-head + .table-scroll,
.section-head + .table { margin-top: 0; }

/* Dlouhe chybove hlasky se musi zalomit, ne roztahnout tabulku. */
.wrap { white-space: pre-wrap; word-break: break-word; max-width: 32rem; font-size: .85rem; }

/* ─────────────────────────────────────────────────────────────────────
   Stavy
   ───────────────────────────────────────────────────────────────────── */

.state {
    display: inline-block;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .01em;
    padding: .15rem .55rem;
    border-radius: 999px;
    border: 1px solid var(--line-strong);
    background: var(--paper-sunken);
    color: var(--ink-soft);
    white-space: nowrap;
}

.state-ok      { color: var(--ok);     background: var(--ok-tint);     border-color: rgba(31, 122, 77, .3); }
.state-warn    { color: var(--warn);   background: var(--warn-tint);   border-color: rgba(138, 97, 0, .3); }
.state-pending { color: var(--info);   background: var(--info-tint);   border-color: rgba(31, 95, 139, .3); }
.state-error   { color: var(--error);  background: var(--error-tint);  border-color: rgba(162, 24, 26, .3); }
.state-off     { color: var(--muted); }

/* ─────────────────────────────────────────────────────────────────────
   Fakta, dlazdice, grafy
   ───────────────────────────────────────────────────────────────────── */

/* Detail sluzby: fakta ve dvou sloupcich. */
.facts, .detail {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: .55rem 1.5rem;
    margin: 1.25rem 0;
    font-size: .92rem;
}

.facts dt, .detail dt { color: var(--muted); }
.facts dd, .detail dd { margin: 0; }

.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr));
    gap: .75rem;
    margin-top: 1.25rem;
}

/* Sloupec se zarovnanim na kraje: hodnota nahore, popisek dole. Popisky
   maji ruzne velke hodnoty nad sebou (datum je mensi nez pocet) a v proudu
   za sebou by kazdy skoncil jinde - "nejblizsi obnova" stala vys nez
   "nezaplacenych faktur" vedle ni. */
.tile {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 1rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    text-decoration: none;
    color: var(--ink);
}

.tile:hover { border-color: var(--ink); color: var(--ink); }
.tile-alert { border-color: rgba(162, 24, 26, .45); background: var(--error-tint); }
.tile-alert .tile-value { color: var(--error); }

.tile-value {
    display: block;
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
    line-height: 1.15;
}

.tile-label { display: block; color: var(--muted); font-size: .8rem; margin-top: .15rem; }

/* Graf metrik - inline SVG, zadna knihovna a zadny JavaScript. */
.chart { margin: 1.25rem 0 0; }

.chart svg {
    display: block;
    width: 100%;
    height: 10rem;
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}

/* Meritko patri k caram, ne do vety pod grafem - SVG se roztahuje na sirku,
   takze text uvnitr nej by byl zdeformovany. Popisky proto lezi v HTML vedle. */
.chart-plot { position: relative; padding-left: 3rem; }

.chart-scale { position: absolute; top: 0; bottom: 0; left: 0; width: 3rem; }

.chart-tick {
    position: absolute;
    right: .5rem;
    color: var(--muted);
    font-size: .72rem;
    line-height: 1;
    white-space: nowrap;
}

.chart-tick-top    { top: 1px; }
.chart-tick-mid    { top: 50%; transform: translateY(-50%); }
.chart-tick-limit  { top: 30%; transform: translateY(-50%); color: var(--error); }
.chart-tick-bottom { bottom: 1px; }

.chart-grid   { stroke: var(--line-strong); stroke-width: .4; vector-effect: non-scaling-stroke; }
.chart-cpu    { fill: none; stroke: var(--signal); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.chart-memory { fill: none; stroke: var(--info); stroke-width: 1.5; vector-effect: non-scaling-stroke; }

.chart figcaption { display: flex; flex-wrap: wrap; gap: .3rem 1.25rem; align-items: baseline; margin-top: .6rem; padding-left: 3rem; font-size: .82rem; }
.legend::before { content: "—"; margin-right: .3rem; font-weight: 700; }
.legend-cpu { color: var(--signal); }
.legend-memory { color: var(--info); }
/* Disk (A17.21): treti barva mimo cervenou (CPU) i modrou (pamet). */
.chart-disk { fill: none; stroke: var(--warn); stroke-width: 1.5; stroke-dasharray: 3 2; vector-effect: non-scaling-stroke; }
.legend-disk { color: var(--warn); }

@media (max-width: 30rem) {
    .chart-plot, .chart figcaption { padding-left: 2.4rem; }
    .chart-scale { width: 2.4rem; }
    .chart-tick { right: .35rem; font-size: .68rem; }
}

.range-switch { display: flex; gap: .4rem; flex-wrap: wrap; margin: 0 0 1rem; }
.alerts-toggle { display: flex; gap: .75rem; align-items: center; flex-wrap: wrap; margin-top: 1rem; }

/* ─────────────────────────────────────────────────────────────────────
   Tajemstvi a kody
   ───────────────────────────────────────────────────────────────────── */

/* Zobrazene heslo - musi jit bezpecne oznacit mysi i na mobilu. */
.secret {
    display: inline-block;
    padding: .3rem .55rem;
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    border: 1px solid var(--signal);
    color: var(--ink);
    font-family: var(--mono);
    font-size: .9rem;
    user-select: all;
    word-break: break-all;
}

/* Sloupec s heslem u pristupovych udaju (A2.6c): heslo nebo tlacitka
   a pod nimi jedna veta vysvetlivky.
   Zamerne to NENI `td.actions` - ten ma `white-space: nowrap`, takze
   veta "Vydano 19. 8. 2026 05:57 - uz ho u sebe nemame" si rekla o sirku
   celeho radku, zbytek tabulky sesypala do sloupecku po jednom slove
   a stejne pretekla ven z karty. */
.credential-secret { white-space: normal; }
.credential-secret .secret { margin-bottom: .4rem; }
.credential-secret .hint { display: block; margin-top: .35rem; }

/* Tlacitka vedle sebe; zalomi se az kdyz sirka opravdu dojde. */
.credential-controls {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    align-items: center;
}

.credential-controls .link-button { white-space: nowrap; }

/* Zachranne kody k dvoufazovemu overeni (A6.11) - vidi se jednou, takze
   musi jit pohodlne oznacit a opsat, idealne ve dvou sloupcich. */
.code-list {
    list-style: none;
    margin: 1.25rem 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: .4rem;
}

.code-list code {
    display: block;
    padding: .4rem .5rem;
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    user-select: all;
    text-align: center;
}

/* Potvrzeni mazani opsanim nazvu - nevratna akce nesmi byt jeden klik. */
.inline-confirm { display: flex; gap: .4rem; align-items: center; }

/* Promo kod se zadava velkymi pismeny. Trida, ne `style=""` v sablone -
   inline styl CSP portalu zahodi a pole by se chovalo jinak, nez vypada. */
.input-upper { text-transform: uppercase; }

.inline-confirm input {
    width: 12rem;
    padding: .32rem .5rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: .85rem;
}

.debug {
    overflow-x: auto;
    padding: .9rem 1rem;
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    font-family: var(--mono);
    font-size: .78rem;
    line-height: 1.6;
}

/* Popisek jen pro odecitace - pole ma placeholder, ale ten label nenahradi. */
.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ─────────────────────────────────────────────────────────────────────
   Doklad (A3.11): na obrazovce karta, v tiskarne cisty papir.
   ───────────────────────────────────────────────────────────────────── */

.document-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1.5rem; flex-wrap: wrap; }

.document-parties, .parties {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
    gap: 1.5rem;
    margin: 1.75rem 0;
}

.document-parties h2, .parties h2 {
    font-size: .75rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: .06em;
    margin: 0 0 .5rem;
}

.document-parties p, .parties p { line-height: 1.6; }
.document tfoot th { text-align: right; }
.document tfoot td { font-variant-numeric: tabular-nums; }
.document-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-top: 1.5rem; }

@media print {
    body { background: #fff; }
    .topbar, .footer, .no-print, .document-actions { display: none; }
    .content, .wide .content { padding: 0; margin: 0; max-width: none; }
    .card { border: 0; box-shadow: none; padding: 0; }
    a { text-decoration: none; color: inherit; }
}

/* ═════════════════════════════════════════════════════════════════════
   Verejny prodejni web (E1)

   Vlastni blok, protoze tyhle stranky vidi lide, kteri jeste nejsou
   zakaznici - jine proporce nez portal, kde jde o hustotu informaci.
   Zustava to ale v jednom souboru: viz poznamka o CSP nahore.
   ═════════════════════════════════════════════════════════════════════ */

body.public { background: var(--paper); }

/* Lepivá hlavicka: cenik je dlouhy a cesta k objednavce nesmi
   znamenat rolovani zpet nahoru. */
.topbar-sticky { position: sticky; top: 0; z-index: 10; }

/* Mezera mezi shluky je vetsi nez uvnitr nich - tri oddily a domeny drzi
   pohromade jako nabidka, ucet stoji zvlast. */
.topbar-public { display: flex; align-items: center; gap: 2rem; }

.nav-group { display: flex; align-items: center; gap: 1.15rem; }

/* Delici cara mezi nabidkou a uctem. Je vysoka jen jako tlacitko vedle ni -
   pres celou hlavicku by z ni byl druhy ram pod spodni linkou. */
.nav-group-account {
    padding-left: 2rem;
    border-left: 1px solid var(--line);
}

.topbar-public a {
    font-size: .9rem;
    font-weight: 500;
    color: var(--ink-soft);
    text-decoration: none;
}

/* Jen textove odkazy - tlacitko ma vlastni hover (cervene pozadi) a
   cervenym pismem by na nem napis zmizel. */
.topbar-public a:not(.button):hover { color: var(--signal); }
.topbar-public .button { color: var(--paper); font-weight: 600; }

/* ── Oddíly v hlavičce (E1f, E1g) ────────────────────────────────────────
   Název oddílu je odkaz na jeho ceník; nabídka se rozbalí po najetí myší
   a při příchodu klávesnicí (`:focus-within`). Všechno v CSS — prodejní
   web žádný skript nenačítá. Panel je `position: absolute`, aby otevřené
   menu neposouvalo stránku pod kurzorem. */

.nav-menu { position: relative; }

.nav-menu-label {
    display: inline-block;
    font-size: .9rem;
    font-weight: 500;
    color: var(--ink-soft);
    white-space: nowrap;
}

/* Šipka. Zavřená míří nahoru, po rozbalení se otočí dolů — ukazuje na
   panel, který se pod ní otevřel, aby bylo poznat, že patří k téhle
   položce. */
.nav-menu-label::after {
    content: "";
    display: inline-block;
    width: .38rem;
    height: .38rem;
    margin-left: .4rem;
    vertical-align: .1em;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: rotate(-135deg) translate(-.1em, -.1em);
    transition: transform .12s ease;
}

.nav-menu:hover > .nav-menu-label,
.nav-menu:focus-within > .nav-menu-label { color: var(--signal); }

.nav-menu:hover > .nav-menu-label::after,
.nav-menu:focus-within > .nav-menu-label::after { transform: rotate(45deg) translate(-.1em, -.1em); }

.nav-menu-panel {
    position: absolute;
    top: calc(100% + .7rem);
    left: 0;
    z-index: 20;
    display: none;
    flex-direction: column;
    gap: .1rem;
    min-width: 14rem;
    max-width: min(20rem, calc(100vw - 2rem));
    padding: .6rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: .5rem;
    box-shadow: var(--lift);
}

.nav-menu:hover > .nav-menu-panel,
.nav-menu:focus-within > .nav-menu-panel { display: flex; }

/* Neviditelný můstek přes mezeru mezi názvem a panelem. Bez něj kurzor
   cestou dolů opustí `:hover` a nabídka zmizí pod rukou. */
.nav-menu-panel::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: -.7rem;
    height: .7rem;
}

.nav-menu-panel a {
    padding: .45rem .55rem;
    border-radius: .35rem;
    font-size: .88rem;
    line-height: 1.35;
}

.nav-menu-panel a:hover { background: var(--paper-sunken); color: var(--signal); }

/* Co se teprve staví: text, ne odkaz — vede to zatím nikam. */
.nav-menu-planned {
    margin: .35rem .55rem .2rem;
    font-size: .78rem;
    line-height: 1.45;
    color: var(--muted);
}

.nav-menu-panel .nav-menu-all {
    margin-top: .3rem;
    padding-top: .5rem;
    border-top: 1px solid var(--line);
    border-radius: 0;
    font-weight: 600;
}

.public .content { max-width: 68rem; margin-bottom: 0; }

/* Mikropopisek nad nadpisem sekce. Nese signalni barvu - je to
   jediny prvek, ktery ji ma na strance vic nez jednou. */
.eyebrow {
    display: block;
    margin: 0 0 .6rem;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .11em;
    text-transform: uppercase;
    color: var(--signal);
}

/* Sekce prodejniho webu odděluje vlasova cara, ne karta na karte. */
.section { padding: 3.5rem 0; border-top: 1px solid var(--line); }
.section:first-child { border-top: 0; }
.section-head { max-width: 38rem; margin-bottom: 2rem; }
.section-head h2 { font-size: 1.65rem; margin: 0 0 .6rem; }
.section-head p { color: var(--ink-soft); margin: 0; }

/* Doplnujici veta pod uvodnim odstavcem (napr. „nejsme platci DPH")
   potrebuje vlastni odstup - jinak splyne s vetou nad sebou. */
.section-head .hint { display: block; margin-top: .8rem; }

/* ── Hero ────────────────────────────────────────────────────────────
   Zamerne zarovnany doleva a asymetricky. Vystredeny sloupec s podnadpisem
   a dvema tlacitky je presne ten tvar, ktery ma dnes kazda druha stranka. */

.hero {
    display: grid;
    grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
    gap: 3rem;
    align-items: start;
    padding: 3.5rem 0 3rem;
}

/* Hero bez praveho sloupce (detail tarifu). Bez teto varianty by mrizka
   drzela .85fr prazdna a nadpis by koncil v pulce stranky. */
.hero-solo { grid-template-columns: minmax(0, 1fr); }

.hero h1 {
    font-size: clamp(2.1rem, 4.6vw, 3.1rem);
    font-weight: 700;
    letter-spacing: -.032em;
    line-height: 1.08;
    margin: 0 0 1.1rem;
}

/* Klicove slovo v nadpisu podtrzene signalni barvou - jediny
   dekorativni prvek na strance. Podtrzeni, ne zvyraznovac: zluty/ruzovy
   pruh pres slovo je dnes vizualni klise. */
.hero h1 em {
    font-style: normal;
    box-shadow: inset 0 -.09em 0 var(--signal);
}

.hero-lead {
    color: var(--ink-soft);
    font-size: 1.1rem;
    line-height: 1.65;
    max-width: 34rem;
    margin: 0 0 1.75rem;
}

.hero-actions { display: flex; gap: .65rem; align-items: center; flex-wrap: wrap; margin-top: 1.5rem; }

/* Pravy sloupec hero: vlastni jednoducha ilustrace (E1c9), ne fotobanka. */
.hero-art { align-self: center; }
.hero-art img { display: block; width: 100%; height: auto; max-width: 30rem; margin-left: auto; }

/* ── Hledani domeny (E1c) ───────────────────────────────────────────── */

.domain-search { display: flex; gap: .5rem; max-width: 32rem; margin: 0; }

.domain-search input {
    flex: 1;
    min-width: 0;
    padding: .72rem .9rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    color: var(--ink);
    font: inherit;
    font-size: 1rem;
}

.domain-search input::placeholder { color: var(--faint); }

.domain-search input:focus {
    outline: 2px solid var(--signal);
    outline-offset: 1px;
    border-color: var(--signal);
}

.domain-search .button { white-space: nowrap; margin-top: 0; }
.domain-search-hint { margin-top: .65rem; font-size: .85rem; color: var(--muted); }

.domain-results { list-style: none; margin: 1.25rem 0 0; padding: 0; }

.domain-results li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    padding: .8rem 0;
    border-bottom: 1px solid var(--line);
}

.domain-results li:last-child { border-bottom: 0; }

.domain-name {
    font-family: var(--mono);
    font-size: .95rem;
    word-break: break-all;
}

/* Prava strana radku vysledku: cena, stav a tlacitko. Na uzkem displeji
   se zalomi pod jmeno misto toho, aby se cena rozdrtila na jedno slovo
   na radek. */
.domain-result-meta {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: .6rem;
    flex-wrap: wrap;
}

.domain-price {
    font-size: .88rem;
    color: var(--ink-soft);
    white-space: nowrap;
}

/* Formular na strance domen (E1c5): vetsi policko nez na homepage - je to
   jedina vec, kvuli ktere sem clovek prisel. Pod nim vyjede panel
   s vysledkem. Homepage ma dal holy `.domain-search`. */
.domain-form { margin: 1.5rem 0 0; max-width: 48rem; }

.domain-search-large { max-width: none; gap: .6rem; }
.domain-search-large input { padding: 1.05rem 1.25rem; font-size: 1.2rem; border-radius: var(--radius); }
.domain-search-large .button { padding: .95rem 1.6rem; font-size: 1.05rem; border-radius: var(--radius); }

/* Panel ma pevnou nejvyssi vysku a scrolluje sam: s tipy a vic koncovkami
   by jinak odsunul cenik i "Doménu už máte?" o obrazovku niz. */
.domain-panel {
    margin-top: .6rem;
    padding: .25rem 1.2rem 1rem;
    max-height: 28rem;
    overflow-y: auto;
    overscroll-behavior: contain;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--paper);
    box-shadow: 0 12px 32px rgba(0, 0, 0, .08);
    animation: domain-panel-open .18s ease-out;
    transition: opacity .15s;
}

.domain-panel[hidden] { display: none; }
.domain-panel.is-loading { opacity: .55; }
.domain-panel .domain-exact { margin-top: 1rem; }
.domain-panel .domain-results { margin-top: .5rem; }
.domain-panel .domain-tips { margin-top: .75rem; }
.domain-panel-notice { margin: 1rem 0 0; }
.domain-panel-note { margin: .9rem 0 0; }
.domain-results li.is-pending .domain-name { color: var(--ink-soft); }

/* Zbytek nabidky pod overenymi (E1c6). Obsazene ztlumene, at se mezi
   stovkami radku daji volne najit okem. */
.domain-rest-title { margin: 1.5rem 0 0; font-size: 1rem; }
.domain-rest-title .tld-count { margin-left: .35rem; color: var(--muted); font-size: .85rem; font-weight: 400; }
.domain-rest li { padding: .55rem 0; }
.domain-rest li.is-taken .domain-name,
.domain-rest li.is-taken .domain-price { color: var(--faint); }

@keyframes domain-panel-open {
    from { opacity: 0; transform: translateY(-6px); }
    to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .domain-panel { animation: none; transition: none; }
}

/* Presne hledana domena - to, kvuli cemu clovek prisel, proto nad ostatnimi
   a vetsi. Volna ma zeleny okraj, at se odpoved pozna bez cteni. */
.domain-exact {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    margin-top: 1.25rem;
    padding: 1rem 1.2rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--paper);
}

.domain-exact.is-free { border-color: rgba(31, 122, 77, .45); background: var(--ok-tint); }
.domain-exact-name { font-size: 1.2rem; font-weight: 650; }
.domain-exact-note { margin: .3rem 0 0; font-size: .9rem; color: var(--ink-soft); }
.domain-results li.is-free .domain-name { font-weight: 650; }
.domain-price small { color: var(--muted); font-size: .78rem; }

.domain-tips { margin-top: 1.25rem; font-size: .9rem; color: var(--ink-soft); }
.domain-tips p { margin: .4rem 0 0; display: flex; flex-wrap: wrap; gap: .35rem .75rem; align-items: baseline; }
.domain-tips strong { color: var(--ink); font-weight: 650; }

/* Cenik vychozich koncovek. */
.tld-table { width: 100%; max-width: 32rem; margin-top: 1.25rem; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.tld-table th, .tld-table td { padding: .55rem 0; border-bottom: 1px solid var(--line); text-align: right; font-weight: 400; }
.tld-table thead th { font-size: .75rem; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.tld-table th:first-child { text-align: left; }
.tld-table tbody tr:last-child th, .tld-table tbody tr:last-child td { border-bottom: 0; }
.tld-table td { color: var(--ink-soft); font-size: .9rem; padding-left: 1rem; }

/* ── Kontrola posty (A19.14) ────────────────────────────────────────── */

/* Dve policka vedle sebe: na uzkem displeji pod sebe, jinak se z nich
   stanou dve nepouzitelne skulinky. Selektor je uzsi - je nepovinny
   a nema stahovat pozornost k sobe. */
.mail-check-form { max-width: 44rem; flex-wrap: wrap; }
.mail-check-form input[name="domena"] { flex: 3 1 14rem; }
.mail-check-form input[name="selektor"] { flex: 2 1 11rem; }
.mail-check-notice { margin-top: 1.25rem; }

.mail-score {
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
    padding: 1.1rem 1.25rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper);
}

.mail-score p { margin: 0; flex: 1 1 16rem; color: var(--ink-soft); }

/* Skore je cislo, ne odznak: bere barvu ze `state-*`, ale ne jejich
   tvar - pilulka o velikosti nadpisu vypada jako tlacitko. */
.mail-score-value {
    font-family: var(--mono);
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 1;
    white-space: nowrap;
}

.mail-score-value.state-ok    { color: var(--ok); }
.mail-score-value.state-warn  { color: var(--warn); }
.mail-score-value.state-error { color: var(--error); }
.mail-score-value.state-off   { color: var(--muted); }

.mail-score-max { font-size: 1rem; font-weight: 500; color: var(--muted); }

.mail-checks { list-style: none; margin: 1.5rem 0 0; padding: 0; }

.mail-check {
    padding: 1.1rem 0;
    border-bottom: 1px solid var(--line);
}

.mail-check:last-child { border-bottom: 0; }

.mail-check-head {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 1rem;
}

.mail-check-summary { margin: .5rem 0 0; color: var(--ink-soft); }
.mail-check-notes { margin: .6rem 0 0; padding-left: 1.15rem; }

.mail-check-notes li {
    margin: .35rem 0;
    color: var(--ink-soft);
    font-size: .92rem;
    line-height: 1.55;
}

/* Nalez z DNS je jedine, co si navstevnik overi jinym nastrojem -
   proto doslovne a v monospace. Dlouhy SPF zaznam roluje sam v ramci
   bloku, aby neroztahl celou stranku. */
.mail-check-records {
    margin: .75rem 0 0;
    padding: .6rem .8rem;
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    font-family: var(--mono);
    font-size: .8rem;
    color: var(--ink-soft);
    overflow-x: auto;
}

.mail-check-records span { display: block; white-space: pre; }

/* ── Tarify ─────────────────────────────────────────────────────────── */

.cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 1rem;
}

.plan-card {
    display: flex;
    flex-direction: column;
    padding: 1.5rem;
    transition: border-color .12s ease, box-shadow .12s ease;
}

.plan-card:hover { border-color: var(--line-strong); box-shadow: var(--lift); }
.plan-card h2, .plan-card h3 { font-size: 1.1rem; margin: .1rem 0 .9rem; }
.plan-card .button-small { margin-top: auto; }

.plan-category {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .09em;
    font-weight: 700;
    color: var(--signal);
    margin: 0;
}

.plan-price { margin: 0 0 1.1rem; display: flex; align-items: baseline; gap: .35rem; flex-wrap: wrap; }

.plan-price strong {
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -.03em;
    font-variant-numeric: tabular-nums;
}

.plan-price span { color: var(--muted); font-size: .88rem; }

/* Stitek "Pripravujeme" u tarifu, ktery je v ceniku videt, ale neprijima
   objednavky (E5). Zamerne drobny: je to provozni stav, ne sleva - kdyby
   krical, prehlusi cenu, kvuli ktere clovek na kartu kouka. */
.plan-badge {
    display: inline-block;
    margin: 0 0 .6rem;
    padding: .12rem .5rem;
    border: 1px solid rgba(138, 97, 0, .22);
    border-radius: 999px;
    background: var(--warn-tint);
    color: var(--warn);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
}
.plan-price-large strong { font-size: 2.6rem; }
.plan-price-yearly { display: block; flex-basis: 100%; margin-top: .3rem; }

/* Objednavka: formular vedle shrnuti. Shrnuti je lepive, takze pri
   vyplnovani dlouheho formulare porad vidim, co kupuji a za kolik. */
.order-layout {
    display: grid;
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    gap: 1.25rem;
    align-items: start;
}

.order-summary { position: sticky; top: 1.25rem; background: var(--paper-sunken); }
.order-summary h2 { font-size: .75rem; text-transform: uppercase; letter-spacing: .08em; color: var(--muted); margin: 0 0 .75rem; }
.order-summary h3 { margin-top: 1.5rem; font-size: .9rem; }
.order-summary .plan-params { margin-bottom: 0; }

.order-summary-plan {
    font-size: 1.25rem;
    font-weight: 650;
    letter-spacing: -.02em;
    margin: 0 0 .5rem;
}

/* Nadpisy sekci uvnitr formulare. Formular je flex se `gap`, takze
   nadpis potrebuje vlastni odstup shora, ne zdedeny margin. */
.form h2 {
    margin: 1.75rem 0 .25rem;
    font-size: .95rem;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--line);
}

.form h2:first-of-type { margin-top: .5rem; }

/* Dve kratka pole vedle sebe - PSC s mestem, ICO s DIC (A3.15).
   Formular je flex se `gap`, takze radek je vlastni grid a popisky
   uvnitr nej si nesou svuj vlastni odstup jako kdekoliv jinde. */
.field-row {
    display: grid;
    grid-template-columns: minmax(7rem, 1fr) 2fr;
    gap: .3rem .8rem;
}

.field-row > div { display: flex; flex-direction: column; gap: .3rem; }

/* ICO a DIC jsou stejne siroke, na rozdil od PSC a mesta. */
.field-row:has(#ico) { grid-template-columns: 1fr 1fr; }

@media (max-width: 34rem) {
    .field-row { grid-template-columns: 1fr; }
}

@media (max-width: 56rem) {
    .order-layout { grid-template-columns: 1fr; }
    /* Na uzkem displeji shrnuti nad formular - dokud clovek nevi,
       co kupuje, nema smysl mu ukazovat pole. */
    .order-summary { position: static; order: -1; }
}

/* Tlacitka na konci karty tarifu. `margin-top: auto` je drzi u spodni
   hrany, takze v rade karet stoji v jedne linii i pri ruzne dlouhem
   vyctu parametru. */
.plan-card-actions {
    display: flex;
    gap: .5rem;
    align-items: center;
    flex-wrap: wrap;
    margin-top: auto;
}

.plan-params { list-style: none; margin: 0 0 1.5rem; padding: 0; font-size: .9rem; color: var(--ink-soft); }
.plan-params li { padding: .45rem 0; border-bottom: 1px solid var(--line); }
.plan-params li:last-child { border-bottom: 0; }

/* ── Ceník oddílu: mřížka tarifů (E1g) ───────────────────────────────
   Kategorie ma dva az tri tarify. `auto-fit` by dvema tarifum dal dva
   sloupce pres celou sirku stranky - karta by pak byla siroky pruh
   se dvema udaji a v kazde kategorii jinak siroka. Pocet sloupcu proto
   urcuje sablona podle poctu tarifu a mrizka ma strop na sirce, takze
   karta vyjde stejne siroka v cele stránce. */

.plan-grid { display: grid; gap: 1rem; }
.plan-grid-1 { grid-template-columns: minmax(0, 22rem); }
.plan-grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 45rem; }
.plan-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Parametry v karte: popisek vlevo, hodnota vpravo. Poradi je u vsech
   tarifu stejne, takze se radky daji cist i napric kartami - to je to
   jedine, co srovnavaci tabulka umela navic. */
.plan-specs { margin: 0 0 1.25rem; font-size: .88rem; }

.plan-specs > div {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding: .45rem 0;
    border-bottom: 1px solid var(--line);
}

.plan-specs > div:last-child { border-bottom: 0; }
.plan-specs dt { color: var(--muted); }

.plan-specs dd {
    margin: 0;
    font-weight: 600;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ── Ceník aplikací (A21, A22) ───────────────────────────────────────
   `app-offer`, ne `app-card`: tak se jmenuje karta aplikace v portalu
   (stranka VPS) a ta ma jinou praci - nabizi instalaci na bezicim
   serveru. Jedno jmeno pro obe by znamenalo, ze uprava jedne stranky
   tise prekresli druhou.

   Karta aplikace je zamerne mensi nez karta tarifu. Nevybira se na ni
   velikost serveru, ale aplikace - nazev je to, co clovek hleda, takze
   cena pod nim nesmi byt vetsi nez on. Spolecne udaje (domena, instalace,
   root) stoji jednou nad mrizkou, ne v kazde karte. */

/* Co patri ke kazde aplikaci - ctyri fakta nad nabidkou. Uzsi sloupec
   nez ma `.feature-grid`, aby stala v jedne rade; ve trech sloupcich
   zbyval ctvrty sam pod nimi. */
.feature-grid.app-included { grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); gap: 1.5rem 2rem; }

.app-offer {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding: 1.25rem;
    transition: border-color .12s ease, box-shadow .12s ease;
}

.app-offer:hover { border-color: var(--line-strong); box-shadow: var(--lift); }
.app-offer h3 { font-size: 1.02rem; margin: 0; }
.app-offer p { margin: 0; }
.app-offer-note { color: var(--ink-soft); font-size: .92rem; line-height: 1.6; }

/* Vlastni selektor s `p`: `.app-offer p { margin: 0 }` o par radku vys
   je specifictejsi nez holá trida, takze by `margin-top: auto` prebilo
   a tlacitka v rade karet by nestala v jedne lince. */
.app-offer p.app-offer-price {
    display: flex;
    align-items: baseline;
    gap: .3rem;
    flex-wrap: wrap;
    margin-top: auto;
    padding-top: .35rem;
}

.app-offer-price strong {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}

.app-offer-price span { color: var(--muted); font-size: .85rem; }

/* Velikost serveru pod cenou: patri k ni, proto stoji v tomtez odstavci
   a jen na vlastnim radku. */
.app-offer-size { flex-basis: 100%; line-height: 1.5; }

/* Tlacitko az pod cenou, u spodni hrany - v rade karet pak stoji
   v jedne lince i pri ruzne dlouhem popisku. */
.app-offer .plan-card-actions { margin-top: .6rem; }

/* ── Srovnání tarifů (E1g) ───────────────────────────────────────────
   Druhy pohled na tataz cisla, ktera stoji v kartach - proto je zavreny
   a otevira ho `<details>`. Skript by na nej stejne nebyl: CSP je
   `default-src 'self'` bez `unsafe-inline`. */

/* Prepinac je pruh pres sirku obsahu, ne tlacitko nekde v prazdnu:
   je to hrana tabulky pod nim, takze ma stejnou sirku jako ona. */
.compare > summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .8rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    font-weight: 600;
    font-size: .95rem;
    cursor: pointer;

    /* Vlastni sipka misto trojuhelnicku prohlizece - ten sedi mimo
       pruh a v kazdem prohlizeci jinak. */
    list-style: none;
}

.compare > summary::-webkit-details-marker { display: none; }
.compare > summary:hover { border-color: var(--line-strong); }

/* Sipka ukazuje na obsah, ne na smer prepnuti: otevrena tabulka ji ma dolu
   k tabulce, zavrena vpravo za nadpis. Nahoru u zavrene tabulky se cetlo
   jako "sbalit" u neceho, co uz sbalene bylo. */
.compare-chevron {
    flex: none;
    color: var(--muted);
    transform: rotate(-90deg);
    transition: transform .2s ease;
}

.compare[open] .compare-chevron { transform: rotate(0deg); }

@media (prefers-reduced-motion: reduce) {
    .compare-chevron { transition: none; }
}

/* Otevrena tabulka navazuje na pruh, proto se rohy mezi nimi srovnaji. */
.compare[open] > summary { border-radius: var(--radius-sm) var(--radius-sm) 0 0; }

/* Otevreni ma nabehnout, ne seknout. Vyska se animuje jen tam, kde to
   prohlizec umi (nize) - nabeh obsahu zvladne kazdy. */
.compare[open] .table-scroll {
    margin-top: 0;
    padding: 0 1.1rem 1.1rem;
    border: 1px solid var(--line);
    border-top: 0;
    border-radius: 0 0 var(--radius-sm) var(--radius-sm);
    /* Bez `both`: kdyby animace z jakehokoli duvodu nebezela, zustal by
       s vyplni obsah na `opacity: 0` - tabulka by mela misto, ale nebyla
       by videt. Takhle je nejhorsi mozny vysledek skok bez nabehu. */
    animation: compare-open .22s ease;
}

@keyframes compare-open {
    from { opacity: 0; transform: translateY(-.4rem); }
    to   { opacity: 1; transform: none; }
}

@supports (interpolate-size: allow-keywords) {
    :root { interpolate-size: allow-keywords; }

    .compare::details-content {
        height: 0;
        overflow: clip;
        transition: height .24s ease, content-visibility .24s allow-discrete;
    }

    .compare[open]::details-content { height: auto; }
}

.compare-table thead th { vertical-align: bottom; text-align: right; }
.compare-table thead th:first-child { text-align: left; }

/* Kategorie jako nadhlavicka nad svymi sloupci. V jedne tabulce stoji
   vedle sebe tarify ze vsech kategorii oddilu a bez tohohle patra je to
   sedm sloupcu v rade, ve kterych se nepozna, kde jedna kategorie konci. */
/* Selektor musi byt stejne specificky jako `.compare-table thead th`,
   jinak nadhlavicku pretlaci zarovnani a barva nazvu tarifu. */
.compare-table .compare-groups th {
    text-align: center;
    font-size: .78rem;
    font-weight: 600;
    color: var(--muted);
    white-space: normal;
    padding-bottom: .3rem;
}

/* Nadhlavicka je popisek, ne radek s daty - cara pod ni by tabulku
   rozdelila na dve. Deli az radek s nazvy tarifu. */
.compare-groups th,
.compare-groups td { border-bottom: 0; }

/* Skupinu oddeluje mezera, ne cara. Svisle linky pres celou tabulku
   z ni udelaly mrizku, ve ktere se ztratila cisla - a to je jedine,
   pro co se tabulka otevira. Selektor musi byt stejne specificky jako
   `.compare-table td`, jinak vypln pretlaci vychozi padding. */
.compare-table .compare-group-start { padding-left: 1.9rem; }

.compare-table thead th {
    color: var(--ink);
    font-size: .85rem;
    text-transform: none;
    letter-spacing: 0;

    /* Hlavicka tabulky se jinde nelame (`.table thead th`), tady musi:
       nazev kategorie pod nazvem tarifu je dlouhy a na jednom radku
       roztahl sloupec tak, ze se sedm tarifu do sirky stranky nevešlo. */
    white-space: normal;
}

.compare-table tbody th { font-weight: 400; color: var(--muted); white-space: nowrap; }

/* Prvni sloupec zustava videt i pri odrolovani vpravo - jinak clovek
   po treti tabulce nevi, ktery radek cte. Podbarveni proto musi byt
   pevne, a radek se z tehoz duvodu pri najeti neprebarvuje. */
.compare-table tbody th {
    position: sticky;
    left: 0;
    /* Prodejni web ma bilou plochu (`body.public`), ne kostnou - `--bg`
       tu delal sedy pruh pres celou vysku tabulky. */
    background: var(--paper);
}

.compare-table tbody tr:hover { background: transparent; }

/* Sedm tarifu webhostingu se do sirky stranky vejde jen tesne - drobnejsi
   pismo a uzsi bunky jsou tu proto, aby se pro posledni sloupec nemuselo
   rolovat uz na desktopu. */
.compare-table { font-size: .85rem; }
.compare-table th, .compare-table td { padding: .6rem .5rem; }
.compare-action { text-align: right; }

.mark { font-size: 1rem; line-height: 1; }
.mark-yes { color: var(--ok); }
.mark-no { color: var(--faint); }

/* ── Technický list tarifu (E1) ──────────────────────────────────────
   Parametry na detailu tarifu. Tabulka o dvou sloupcich tu mela uzky
   sloupec s popiskem a pul stranky prazdna vedle hodnoty; v mrizce je
   hodnota to velke a popisek nad ni jen popisek. */

.spec-sheet {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    gap: 1.1rem 1.75rem;
    margin: 0;
}

.spec-sheet > div { border-top: 1px solid var(--line); padding-top: .7rem; }

.spec-sheet dt {
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--muted);
}

.spec-sheet dd {
    margin: .3rem 0 0;
    font-size: 1.05rem;
    font-weight: 650;
    letter-spacing: -.01em;
    font-variant-numeric: tabular-nums;
}

.spec-note {
    display: block;
    margin-top: .15rem;
    font-size: .85rem;
    font-weight: 400;
    letter-spacing: 0;
    color: var(--muted);
}

/* ── Oddíly (D0) ────────────────────────────────────────────────────────
   Patro nad kategoriemi: webhosting, serverhosting, aplikace. Karta je
   zamerne chudsi nez karta tarifu - nema cenu, protoze oddil se nekupuje. */

.division-card { display: flex; flex-direction: column; padding: 1.5rem; }
.division-card .button-small { margin-top: auto; align-self: flex-start; }

.division-lead {
    color: var(--ink-soft);
    font-size: .92rem;
    line-height: 1.6;
    margin: .4rem 0 1rem;
}

.division-planned { margin: 0 0 1.25rem; }

/* Kotvy na oddíly v hlavicce ceniku. */
.division-nav { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 1.1rem; }
.division-nav a { font-size: .88rem; font-weight: 600; }

/* Nadpis kategorie uvnitr oddilu - o patro niz nez `.section-head h2`. */
.category-head {
    margin: 2rem 0 0;
    font-size: 1.05rem;
    letter-spacing: -.01em;
}

.category-head:first-of-type { margin-top: 0; }

/* ── Vlastnosti ─────────────────────────────────────────────────────── */

.feature-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 2rem 2.5rem; }

.feature-grid > div { border-top: 2px solid var(--ink); padding-top: 1rem; }
.feature-grid h3 { font-size: 1.02rem; margin-bottom: .45rem; }
.feature-grid p { color: var(--ink-soft); line-height: 1.65; font-size: .92rem; margin: 0; }

/* Ohlaseny zamer, ne nabidka: slabsi linka nez u hotovych vlastnosti,
   aby se to na prvni pohled nepletlo s tim, co uz jde koupit. */
.feature-grid-planned { margin-top: 1.25rem; }
.feature-grid-planned > div { border-top: 1px solid var(--line); }
.feature-grid-planned h4 { font-size: 1.02rem; margin: 0 0 .45rem; }

/* ── Navody (E11) ───────────────────────────────────────────────────── */

/* Karta navodu je cela odkaz, vcetne podnadpisu: u navodu rozhoduje
   o kliknuti prave ta veta "co se v nem dozvim", takze delat odkaz jen
   z nadpisu znamena delat mensi cil pro to, na co lidi miri. */
.guide-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr)); gap: 1.25rem; }

.guide-card {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    text-decoration: none;
    color: inherit;
    transition: border-color .12s ease, transform .12s ease;
}

.guide-card:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.guide-card h3 { margin: 0; font-size: 1.05rem; color: var(--ink); }
.guide-card p { margin: 0; color: var(--ink-soft); font-size: .92rem; line-height: 1.6; }
.guide-card:hover h3 { color: var(--signal); }

/* Odhad casu je udaj pro orientaci, ne nadpis - drzi se u zeme
   velikosti i barvou, aby nesoutezil s nazvem navodu. */
.guide-meta { color: var(--muted); font-size: .8rem; margin-top: auto; padding-top: .35rem; }

.guide-head .section-head { max-width: 44rem; }
.guide-needs { border-left: 2px solid var(--line-strong); padding-left: .85rem; }

/* Vlastni sloupec o sirce vety, ne na celou mrizku: navod se cte
   souvisle a radek pres 68rem oko na dalsim radku nenajde. */
.guide-body { max-width: 44rem; border-top: 0; padding-top: 0; }
.guide-body h2 { font-size: 1.2rem; margin: 2.25rem 0 .6rem; }
.guide-body p { color: var(--ink-soft); line-height: 1.75; }
.guide-body ul { color: var(--ink-soft); line-height: 1.75; padding-left: 1.2rem; }
.guide-body li + li { margin-top: .3rem; }
.guide-body .table { font-size: .9rem; }

/* Uvodni odstavec navodu je tmavsi a vetsi nez zbytek textu. Selektor
   je dvoutridni schvalne: `.guide-body p` je specifictejsi nez samotna
   `.guide-lead` a barvu by prebilo. */
.guide-body .guide-lead { font-size: 1.05rem; color: var(--ink); }

/* Pravni dokumenty (C1-C4) sdili sloupec navodu. Clanky se cisluji
   rucne v nadpisu ("3. Cena a platby"), protoze se na ne odkazuje
   z jinych dokumentu a cislo musi byt v textu, ne jen v CSS. */
.legal-body ol { color: var(--ink-soft); line-height: 1.75; padding-left: 1.4rem; }
.legal-body ol li + li { margin-top: .3rem; }
.legal-body h3 { font-size: 1rem; margin: 1.5rem 0 .4rem; }
.legal-body .table-wrap { overflow-x: auto; }

/* Chybejici udaj prodavajiciho: musi byt videt na prvni pohled,
   ne jako prazdne misto ve vete. */
.legal-missing { background: var(--warn-tint); color: var(--warn); padding: 0 .25rem; border-radius: 3px; }

/* Cislovani si kresli sama sekce: `<ol>` zustava kvuli cteckam
   a kopirovani do mailu, ale vychozi cislo pred nadpisem stoji na
   spatne uctove care a pri zalomeni odskoci. */
.guide-steps { list-style: none; margin: 2rem 0 0; padding: 0; counter-reset: guide-step; }

.guide-steps > li {
    counter-increment: guide-step;
    position: relative;
    padding: 0 0 .25rem 3rem;
    margin-bottom: 2rem;
}

.guide-steps > li::before {
    content: counter(guide-step);
    position: absolute;
    left: 0;
    top: .1rem;
    width: 2rem;
    height: 2rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--line-strong);
    border-radius: 50%;
    font-size: .85rem;
    font-weight: 700;
    color: var(--signal);
    background: var(--paper);
}

/* Svisla linka mezi krokem a dalsim cislem - drzi pohromade krok,
   ktery je delsi nez obrazovka. Posledni ji nema, jinak by vedla nikam. */
.guide-steps > li::after {
    content: "";
    position: absolute;
    left: 1rem;
    top: 2.35rem;
    bottom: -1.75rem;
    border-left: 1px solid var(--line);
}

.guide-steps > li:last-child::after { display: none; }
.guide-steps > li > h2 { margin: .15rem 0 .55rem; font-size: 1.15rem; }
.guide-steps > li > h2:first-child { margin-top: .15rem; }

/* Ukazka prikazu. `pre` se na uzkem displeji nezalomi, takze musi mit
   vlastni posuvnik - jinak roztahne celou stranku do sirky. */
.guide-code {
    margin: .9rem 0;
    padding: .8rem 1rem;
    background: var(--paper-sunken);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow-x: auto;
    font-size: .88rem;
    line-height: 1.6;
}

.guide-code code { white-space: pre; }

/* ── Zavěrečná vyzva ────────────────────────────────────────────────── */

.cta {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 2rem;
    flex-wrap: wrap;
    padding: 2.25rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--paper-sunken);
}

.cta h2 { margin: 0 0 .4rem; font-size: 1.35rem; }
.cta p { margin: 0; color: var(--ink-soft); }
.cta .hero-actions { margin-top: 0; }

/* ── Paticka ────────────────────────────────────────────────────────── */

.footer-public {
    border-top: 1px solid var(--line);
    background: var(--paper-sunken);
    margin-top: 3.5rem;
    padding: 2.5rem 1.5rem;
    color: var(--muted);
    font-size: .85rem;
    max-width: none;
}

.footer-inner {
    max-width: 68rem;
    margin: 0 auto;
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1.25rem 2rem;
    flex-wrap: wrap;
}

.footer-links { display: flex; gap: 1.5rem; flex-wrap: wrap; }
.footer-public a { color: var(--muted); text-decoration: none; }
.footer-public a:hover { color: var(--signal); }
.footer-brand { color: var(--ink); font-weight: 650; }
/* Udaje o provozovateli (§ 435 OZ) - na kazde strance, ale jako drobny
   text v jednom bloku, ne dva sloupce, ktere prebiji obsah (E1c9). */
.footer-operator {
    margin-top: 1.5rem;
    padding-top: 1.1rem;
    border-top: 1px solid var(--line);
    display: block;
    font-size: .78rem;
    line-height: 1.6;
    color: var(--muted);
}
.footer-operator p { margin: 0; }
.footer-operator p + p { margin-top: .2rem; }
.footer-operator a { color: inherit; }

/* ── Responzivita prodejniho webu ───────────────────────────────────── */

@media (max-width: 56rem) {
    .hero { grid-template-columns: 1fr; gap: 2.25rem; padding-top: 2.5rem; }
    .hero-art img { max-width: 24rem; margin: 0; }

    /* Pod tuhle sirku uz pevny pocet sloupcu nema smysl - karta by byla
       uzsi nez cena v ni. Kolik se jich vedle sebe vejde, rozhodne mrizka. */
    .plan-grid-2, .plan-grid-3 { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); max-width: none; }
}

@media (max-width: 40rem) {
    .plan-grid { grid-template-columns: minmax(0, 1fr); }
    .content { padding: 0 1.15rem; }
    .topbar { min-height: 4.25rem; padding: .8rem 1.15rem; }
    .topbar-public { gap: 1.25rem; }
    .nav-group { gap: .9rem; }
    .nav-group-account { padding-left: 1.25rem; }
    .section { padding: 2.5rem 0; }
    .card { padding: 1.25rem; }
    .cta { padding: 1.5rem; }
    .facts, .detail { grid-template-columns: 1fr; gap: .15rem 0; }
    .facts dt, .detail dt { margin-top: .6rem; font-size: .8rem; }

    /* Na telefonu je odsazeni na cislo kroku ctvrtina sirky radku.
       Cislo proto zustava, ale text uz pod nim zacina od kraje. */
    .guide-steps > li { padding-left: 0; }
    .guide-steps > li::before { position: static; margin-bottom: .5rem; }
    .guide-steps > li::after { display: none; }
}

@media (max-width: 30rem) {
    .domain-search { flex-direction: column; }
    .user-email { padding-left: 0; border-left: 0; }

    /* Na uzkem displeji se navigace nevejde vedle znacky a lamala by
       "Přihlásit se" doprostred slova. Dostane proto vlastni radek -
       schovat odkaz na prihlaseni nepripada v uvahu. */
    .topbar { flex-wrap: wrap; row-gap: .7rem; }
    .topbar-public { width: 100%; flex-wrap: wrap; justify-content: flex-start; gap: .55rem .9rem; }
    .topbar-public a { white-space: nowrap; }

    /* Na vlastnim radku uz shluky nic nedeli - svisla cara by koncila
       uprostred zalomene navigace. Zustane jen mezera. */
    .nav-group { flex-wrap: wrap; gap: .55rem .9rem; }
    .nav-group-browse { width: 100%; }
    .nav-group-account { padding-left: 0; border-left: 0; }

    /* V úzkém okně by plovoucí panel u posledního oddílu vyjel mimo
       obrazovku. Roztlačí proto hlavičku, jako to dělá mobilní menu. */
    .nav-menu { width: 100%; }

    .nav-menu-panel {
        position: static;
        max-width: none;
        margin-top: .5rem;
        box-shadow: none;
    }
}

/* Na dotyku žádné najetí myší není a otevírat nabídku klepnutím by znamenalo,
   že první klepnutí na oddíl nikam nevede. Panel se proto schová celý —
   název oddílu zůstává odkazem a otevře ceník oddílu, kde jsou kategorie
   hned pod sebou. Stejný cíl, o krok dřív. */
@media (hover: none) {
    .nav-menu-label::after { display: none; }

    .nav-menu:hover > .nav-menu-panel,
    .nav-menu:focus-within > .nav-menu-panel { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* Datum v dlazdici. Cislo tarifu snese 1.75rem, datum uz ne - v te
   velikosti se lame na dva radky. */
.tile-value-date { font-size: 1.1rem; letter-spacing: -.01em; }

/* ─────────────────────────────────────────────────────────────────────
   Spravce souboru na uzkem displeji

   Sest sloupcu, z toho dva formulare, se na telefon nevejde a `.table-scroll`
   by z toho udelal jen jinou potiz: polozku by clovek videl, ale tlacitko
   k ni az po odrolovani do strany. Radek se proto pod 46rem rozpadne na
   kartu - nazev, pod nim udaje, prava a nakonec akce v jedne rade.

   Sloupcove nadpisy tim zmizi, takze co neni zrejme samo o sobe (prava)
   si nese vlastni popisek v `::before`. U velikosti a data by popisek
   prekazel: "3.0 kB" a datum se poznaji na prvni pohled.
   ───────────────────────────────────────────────────────────────────── */

@media (max-width: 46rem) {
    .files-table,
    .files-table tbody,
    .files-table tr,
    .files-table td { display: block; width: auto; }

    .files-table thead { display: none; }

    .files-table tr {
        position: relative;
        padding: .85rem 0 .85rem 1.9rem;
        border-bottom: 1px solid var(--line);
    }

    .files-table tbody tr:last-child { border-bottom: 0; }
    .files-table td { padding: 0; border: 0; }
    .files-table td:empty { display: none; }

    /* Zaskrtavatko drzi levy okraj karty, at je nad nim cokoli. Jako
       vlastni radek by z kazde polozky udelalo o radek vic. */
    .files-table td.tight {
        position: absolute;
        top: .9rem;
        left: 0;
        width: 1.4rem;
    }

    .files-table td.entry-name {
        max-width: none;
        font-weight: 600;
        font-size: 1rem;
    }

    /* Velikost a datum jsou jeden udajovy radek pod nazvem, ne dva. */
    .files-table td.cell-size,
    .files-table td.cell-date {
        display: inline-block;
        margin-top: .15rem;
        color: var(--muted);
        font-size: .85rem;
    }

    .files-table td.cell-size::after { content: " ·"; padding-right: .3rem; }
    .files-table td.cell-empty { display: none; }

    .files-table td.cell-perms { margin-top: .5rem; }

    .files-table td.cell-perms::before {
        content: "Přístup:";
        display: block;
        margin-bottom: .2rem;
        font-size: .8rem;
        font-weight: 600;
        color: var(--ink-soft);
    }

    .files-table .perm-form { justify-content: flex-start; }
    .files-table .perm-form select { max-width: none; flex: 0 1 14rem; }

    .files-table td.actions {
        display: block;
        margin-top: .55rem;
        white-space: normal;
    }

    /* Vlevo, ne vpravo: v karte neni pravy okraj, ke kteremu by se akce
       mely rovnat - je tam jen konec obrazovky. */
    .files-table .action-cluster { justify-content: flex-start; }

    /* Na sirce telefonu plovouci panel nema kam plout: kotvi se k tlacitku
       "Přejmenovat" a to stoji uprostred rady, takze by mu vpravo chybelo
       pres sto pixelu. V karte ho nic nestoji v ceste, at se tedy zaradi
       normalne pod tlacitka a roztlaci je. */
    .files-table .action-cluster details[open] > form {
        position: static;
        width: auto;
        max-width: none;
        margin-top: .5rem;
        box-shadow: none;
    }

    .files-table .action-cluster details[open] { flex: 1 0 100%; }
}

/* ─────────────────────────────────────────────────────────────────────
   Sprava serveru u VPS (A17.13)
   ───────────────────────────────────────────────────────────────────── */

/* Cesta zpet na detail sluzby. Stranka serveru je o uroven niz a bez
   tohohle radku se z ni na telefonu (kde neni kam kliknout vedle) vracelo
   jen tlacitkem prohlizece. */
.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    align-items: baseline;
    margin: 0 0 .9rem;
    font-size: .88rem;
    color: var(--muted);
}

.breadcrumb a { color: var(--ink-soft); }

/* Prikaz k pripojeni: vybere se celym klepnutim a nelame se uprostred. */
.copyable {
    display: inline-block;
    max-width: 100%;
    padding: .2rem .45rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    user-select: all;
    overflow-wrap: anywhere;
}

/* Otisk klice je dlouhy retezec bez mezer - bez zalamovani by na telefonu
   roztahl kartu do strany. */
.fingerprint { display: block; font-size: .8rem; overflow-wrap: anywhere; color: var(--ink-soft); }

.key-list { list-style: none; margin: 1rem 0 0; padding: 0; }

.key-list li {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 1rem;
    padding: .75rem 0;
    border-bottom: 1px solid var(--line);
}

.key-list li > div { min-width: 0; }

/* Pole a tlacitko v jedne rade; na uzkem displeji pod sebou. */
.input-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.input-row input { flex: 1 1 14rem; min-width: 0; }
.form .input-row .button { margin-top: 0; }

/* Destruktivni akce se potvrzuje rozbalenim, ne dialogem - portal je bez
   JavaScriptu a CSP nepusti inline `onclick="confirm()"`. */
.confirm > summary { list-style: none; cursor: pointer; display: inline-block; }
.confirm > summary::-webkit-details-marker { display: none; }
.confirm[open] > form { margin-top: .5rem; max-width: 22rem; }

.actions-cell { display: flex; flex-wrap: wrap; gap: .4rem; align-items: flex-start; }
.actions-cell form { display: inline; }

/* ─────────────────────────────────────────────────────────────────────
   Databaze (A2.6e, A2.6m, A2.6n)

   Kazda databaze je vlastni karta. Driv to byl radek tabulky se sesti
   sloupci, ktery se na telefon nevesel a mel "Smazat" hned vedle
   "Otevrit" - tedy nejnebezpecnejsi tlacitko na nejsnadnejsim miste.
   ───────────────────────────────────────────────────────────────────── */

.page-head .hint { margin: .35rem 0 0; }
.db-name { margin: 0; font-size: 1.15rem; overflow-wrap: anywhere; }
.db-name code { font-size: 1em; }

.db-usage {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem 1rem;
    font-size: .92rem;
}

/* Nativni <progress>: zadny inline styl (CSP), a ctecky obrazovky ho
   prectou jako hodnotu. Vzhled se jen srovna s paletou. */
.meter {
    flex: 1 1 10rem;
    max-width: 18rem;
    height: .5rem;
    border: 0;
    border-radius: 999px;
    background: var(--line);
    overflow: hidden;
    appearance: none;
}

.meter::-webkit-progress-bar { background: var(--line); border-radius: 999px; }
.meter::-webkit-progress-value { background: var(--ok); border-radius: 999px; }
.meter::-moz-progress-bar { background: var(--ok); border-radius: 999px; }
.meter-warn::-webkit-progress-value { background: var(--error); }
.meter-warn::-moz-progress-bar { background: var(--error); }

.facts-compact { gap: .35rem 1.25rem; margin: 1rem 0 .5rem; }

/* Rozbalovaci sekce uvnitr karty: ukazky pripojeni, import, smazani. */
.disclosure {
    margin-top: .9rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
}

.disclosure > summary {
    padding: .6rem .9rem;
    cursor: pointer;
    font-weight: 600;
    font-size: .92rem;
}

.disclosure[open] > summary { border-bottom: 1px solid var(--line); }
.disclosure-body { padding: .2rem .9rem .9rem; }
.disclosure-danger > summary { color: var(--error); }

.snippet {
    margin: .35rem 0 .9rem;
    padding: .7rem .85rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    font-family: var(--mono);
    font-size: .8rem;
    line-height: 1.5;
    white-space: pre;
    overflow-x: auto;
}

.db-card h3 { margin: 1.5rem 0 .5rem; font-size: 1rem; }
.db-transfer > div > p { margin: 0 0 .5rem; }

.transfer-list { list-style: none; margin: .9rem 0 0; padding: 0; font-size: .88rem; }

.transfer-list li {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem .75rem;
    align-items: baseline;
    padding: .4rem 0;
    border-top: 1px solid var(--line);
}

.transfer-error { flex-basis: 100%; color: var(--error); overflow-wrap: anywhere; font-family: var(--mono); font-size: .8rem; }

/* ─────────────────────────────────────────────────────────────────────
   Telefon (portal)

   Do 2026-09-18 byl portal na telefonu jen zmenseny desktop: hlavicka ve
   trech radcich zabrala petinu obrazovky, tabulky utikaly doprava (rychle
   akce na prehledu nebyly videt vubec) a detail sluzby byl stena trinacti
   tlacitek. Prodejni web a spravce souboru meli vlastni pravidla uz driv.
   ───────────────────────────────────────────────────────────────────── */

@media (max-width: 40rem) {
    /* Hlavicka: znacka a odhlaseni nahore, navigace pod nimi v jednom
       radku, ktery se da posunout prstem - ne tri zalomene radky. */
    .topbar:has(.topbar-user) {
        flex-wrap: wrap;
        row-gap: .35rem;
        padding: .6rem 1rem 0;
        min-height: 0;
    }

    .topbar-user {
        order: 3;
        width: calc(100% + 2rem);
        margin: 0 -1rem;
        padding: .15rem 1rem .6rem;
        flex-wrap: nowrap;
        overflow-x: auto;
        gap: 1.1rem;
        white-space: nowrap;
        scrollbar-width: none;
    }

    .topbar-user::-webkit-scrollbar { display: none; }
    .topbar-user a { font-size: .9rem; padding: .35rem 0; }
    .topbar-user .user-email { display: none; }
    /* Odhlaseni je v navigaci posledni, tedy za okrajem posuvneho radku.
       Na telefonu proto stoji zvlast vedle znacky (`.topbar-logout`). */
    .topbar-user form { display: none; }
    .topbar-logout { display: block; }

    .adminbar-inner { flex-wrap: nowrap; overflow-x: auto; padding: 0 1rem; scrollbar-width: none; }
    .adminbar-inner::-webkit-scrollbar { display: none; }

    .content { margin-top: 1rem; padding: 0 .75rem; }
    .card { padding: 1.1rem 1rem; }
    h1 { font-size: 1.45rem; }

    /* Dve dlazdice vedle sebe: jedna na radek byla tri obrazovky ctverecku. */
    .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .5rem; }
    .tile { padding: .75rem .85rem; }
    .tile-value { font-size: 1.4rem; }

    /* Tabulka jako karty: kazdy radek je blok, bunka ma popisek vlevo
       (z `data-label`, doplni ho portal.js) a hodnotu vpravo. */
    .table-stack, .table-stack tbody, .table-stack tr, .table-stack td { display: block; width: auto; }
    .table-stack thead { display: none; }
    .table-stack tr { padding: .7rem 0; border-bottom: 1px solid var(--line); }
    .table-stack td { border: 0; padding: .2rem 0; text-align: left; }
    .table-stack td.cell-nowrap { white-space: normal; overflow-wrap: anywhere; }

    /* Popisek plave vlevo, obsah bunky (klidne vic kusu - castka a pod ni
       poznamka) zustava pohromade zarovnany vpravo. Flex by kazdy kus
       textu rozhodil do vlastniho sloupce. */
    .table-stack td[data-label] { text-align: right; overflow: hidden; }

    .table-stack td[data-label]::before {
        content: attr(data-label);
        float: left;
        margin-right: 1rem;
        color: var(--muted);
        font-size: .78rem;
        font-weight: 600;
        line-height: 1.9;
    }

    .table-stack td:first-child:not([colspan]) { font-size: 1rem; text-align: left; }
    .table-stack td:first-child::before { display: none; }
    .table-stack td.row-actions, .table-stack td.actions { display: flex; flex-wrap: wrap; gap: .4rem; justify-content: flex-start; }
    .table-stack .row-actions, .table-stack .actions { justify-content: flex-start; margin-top: .35rem; }
    /* Shluk tlacitek v karte zacina vlevo jako zbytek karty; zarovnani
       doprava dava smysl jen ve sloupci tabulky. */
    .table-stack .action-cluster { justify-content: flex-start; }
    .table-stack td:empty { display: none; }

    /* Ostatni tabulky (statistiky, administrace, doklady) se posouvaji
       samy v sobe - stranka jako celek do strany nejede nikdy. */
    .table:not(.table-stack):not(.files-table) { display: block; overflow-x: auto; }

    /* Detail sluzby: odkazy v mrizce po dvou, ne stena tlacitek. */
    .service-links { display: grid; grid-template-columns: 1fr 1fr; gap: .4rem; }
    .service-links > a, .service-links > form, .service-links > form > button { width: 100%; text-align: center; }
    .service-links > .state { grid-column: 1 / -1; }

    /* `:has(#ico)` ma vyssi specifitu nez pravidlo pro 34rem vyse, takze
       ICO a DIC zustavaly vedle sebe a DIC utikalo z obrazovky. */
    .field-row, .field-row:has(#ico) { grid-template-columns: 1fr; }

    .page-head { flex-direction: column; }
    .page-actions { width: 100%; }
    .input-row .button { width: 100%; }
    .key-list li { flex-direction: column; gap: .35rem; }
}

/* ─────────────────────────────────────────────────────────────────────
   Stavebnice VPS a volba predinstalovane aplikace (A17.6, A21, A22)
   ───────────────────────────────────────────────────────────────────── */

.vps-builder { display: flex; flex-direction: column; gap: .3rem; }
.slider-field { margin-top: .6rem; }
.slider-field label { display: block; }
.slider-field .hint { margin: .15rem 0 0; }

.slider-row { display: flex; align-items: center; gap: .9rem; }
.slider-row input[type="range"] { flex: 1 1 auto; accent-color: var(--ink); padding: 0; border: 0; }

.slider-row output {
    flex: none;
    min-width: 4.5rem;
    padding: .3rem .55rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
    font-weight: 700;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.vps-live {
    margin: 1rem 0 0;
    padding: .8rem 1rem;
    border-radius: var(--radius-sm);
    background: var(--ink);
    color: var(--paper);
    font-size: 1.05rem;
}

.choice-group {
    margin: 1.5rem 0 0;
    padding: 0;
    border: 0;
}

.choice-group legend { font-weight: 700; font-size: 1.05rem; margin-bottom: .5rem; }

.choice {
    display: flex;
    gap: .7rem;
    align-items: flex-start;
    margin-top: .5rem;
    padding: .75rem .9rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    cursor: pointer;
}

.choice:has(input:checked) { border-color: var(--ink); background: var(--paper-sunken); }
.choice input { margin-top: .3rem; accent-color: var(--ink); }
.choice .hint { display: block; margin-top: .15rem; }
.form .choice { margin-top: .5rem; font-size: .95rem; font-weight: 400; color: var(--ink); letter-spacing: 0; }

/* Stavebnice pod tarify VPS (A17). */
.builder-card {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    margin-top: 1rem;
    border-style: dashed;
}

.builder-card > div { flex: 1 1 22rem; }
.builder-card h3 { margin: 0 0 .35rem; }
.builder-card p { margin: 0; color: var(--ink-soft); }

/* Zalozky na sekce oddilu pod hlavickou ceniku. */
.page-jumps { margin-top: 1.25rem; }

/* Co obnasi sprava VPS (D7e) - ctyri kratke radky misto ctyr odstavcu. */
.managed-facts {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1.75rem;
    margin: 0 0 1.25rem;
    padding: 0;
    list-style: none;
    font-size: .92rem;
    color: var(--ink-soft);
}

.managed-facts strong { color: var(--ink); font-weight: 600; }

/* Aplikace jednim kliknutim na strance serveru (A21, A22). */
.app-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: .75rem; margin-top: 1rem; }

.app-card {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding: 1rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--paper-sunken);
}

.app-card h3 { margin: 0; font-size: 1.05rem; }
.app-card p { margin: 0; color: var(--ink-soft); font-size: .92rem; }
.app-card .confirm { margin-top: auto; }

/* ─────────────────────────────────────────────────────────────────────
   Kod z aplikace po sesti polickach (A6.11, partials/otp_boxes.php)

   Policka jsou jen nadstavba z portal.js - bez skriptu zustane obycejne
   pole a nic z tohohle se neuplatni. Barvy drzi pravidla z hlavicky:
   cihlova je focus, zelena "kod je cely", karminova "kod nesouhlasil".
   ───────────────────────────────────────────────────────────────────── */

.otp-card .form { max-width: none; }
.otp-plain { display: flex; flex-direction: column; gap: .3rem; }

.otp-badge {
    display: grid;
    place-items: center;
    width: 4.25rem;
    height: 4.25rem;
    margin: 0 auto 1rem;
    border-radius: 50%;
    background: var(--paper-sunken);
    color: var(--ink);
    box-shadow: 0 0 0 0 transparent;
    transition: background-color .2s ease, color .2s ease, box-shadow .3s ease;
}

.otp-lock {
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.otp-lock-open { display: none; }

.otp-card h1,
.otp-lead { text-align: center; }

.otp-lead { color: var(--ink-soft); }

.otp { margin: 1rem 0 0; padding: 0; border: 0; min-width: 0; }

.otp-boxes {
    display: flex;
    justify-content: center;
    gap: .45rem;
}

/* Mezera za treti cislici - kod se opisuje po trojicich, tak jak ho
   aplikace ukazuje. */
.otp-box:nth-child(3) { margin-right: .5rem; }

.form .otp-box {
    flex: 1 1 0;
    min-width: 0;
    max-width: 3.1rem;
    aspect-ratio: 4 / 5;
    padding: 0;
    border: 1.5px solid var(--line-strong);
    border-radius: var(--radius);
    background: var(--paper);
    color: var(--ink);
    font-size: 1.6rem;
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    text-align: center;
    caret-color: transparent;
    transition: border-color .12s ease, background-color .12s ease, color .12s ease;
}

.form .otp-box::placeholder { color: transparent; }
.form .otp-box:focus::placeholder { color: var(--signal); }

.form .otp-box:focus {
    outline: 3px solid var(--signal-select);
    outline-offset: 0;
    border-color: var(--signal);
}

.form .otp-box.is-filled { border-color: var(--ink); }

/* Tlacitko nese pocet zbyvajicich cislic, dokud kod neni cely. */
.form .otp-submit { width: 100%; }

.otp-submit:disabled,
.otp-submit:disabled:hover {
    background: var(--paper-sunken);
    border-color: var(--line);
    color: var(--muted);
    cursor: default;
}

.otp-toggle { display: block; margin: 1rem auto 0; }

.otp-abandon { margin-top: .75rem; text-align: center; }

/* Cely kod: odemceny zamek. Odesila se hned, takze tohle je stav
   "overuji", ne vyzva ke kliknuti. */
.otp-card-ready .otp-badge {
    background: var(--ok-tint);
    color: var(--ok);
    box-shadow: 0 0 0 .6rem rgba(31, 122, 77, .07);
}

.otp-card-ready .otp-lock-closed { display: none; }
.otp-card-ready .otp-lock-open { display: block; }
.otp-card-ready .form .otp-box { border-color: var(--ok); }

/* Kod nesouhlasil: zamek a policka cervene, jedno zatreseni. Zmizi s prvni
   napsanou cislici (portal.js). */
.otp-card-error .otp-badge {
    background: var(--error-tint);
    color: var(--error);
    box-shadow: 0 0 0 .6rem rgba(162, 24, 26, .06);
}

.otp-card-error .form .otp-box {
    border-color: rgba(162, 24, 26, .55);
    background: var(--error-tint);
}

.otp-card-error .otp-boxes { animation: otp-shake .36s ease 1; }

@keyframes otp-shake {
    0%, 100% { transform: translateX(0); }
    20%      { transform: translateX(-6px); }
    40%      { transform: translateX(5px); }
    60%      { transform: translateX(-3px); }
    80%      { transform: translateX(2px); }
}

@media (prefers-reduced-motion: reduce) {
    .otp-card-error .otp-boxes { animation: none; }
    .otp-badge,
    .form .otp-box { transition: none; }
}

@media (max-width: 22rem) {
    .otp-boxes { gap: .3rem; }
    .otp-box:nth-child(3) { margin-right: .25rem; }
    .form .otp-box { font-size: 1.35rem; }
}

/* ─────────────────────────────────────────────────────────────────────
   DNS editor (A2.6f)
   ───────────────────────────────────────────────────────────────────── */

.dns-form { max-width: none; }

/* Nazev, typ, TTL a priorita v jedne rade - jsou kratke a patri k sobe;
   hodnota ma radek pro sebe, protoze TXT (SPF, DKIM) je dlouhy. */
.dns-form-row {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: .75rem;
}

.dns-form-row > div { display: flex; flex-direction: column; gap: .3rem; }
.dns-form-row input, .dns-form-row select { width: 100%; }

.dns-content code { word-break: break-all; }

.dns-table tr.is-editing td { background: var(--signal-tint); }

@media (max-width: 40rem) {
    .dns-form-row { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* Webova konzole VPS (A17.14). Vysku drzi kontejner, xterm si ji meri. */
.console-screen {
    height: min(70vh, 40rem);
    margin-top: 1rem;
    padding: .5rem;
    border-radius: var(--radius);
    background: #1a1c20;
}

.console-screen .xterm { height: 100%; }

/* Rozbalovaci cast formulare pro pokrocile (skript po spusteni VPS). */
.form-more { margin-top: 1rem; }
.form-more > summary { cursor: pointer; font-weight: 600; font-size: .9rem; }
.form-more[open] > summary { margin-bottom: .3rem; }
.form-more textarea { width: 100%; font-family: var(--mono); font-size: .85rem; }

/* ─────────────────────────────────────────────────────────────────────
   Administrace -> Stav (A7.9)
   ───────────────────────────────────────────────────────────────────── */

.host-card h2 { display: flex; gap: .6rem; align-items: baseline; flex-wrap: wrap; }
.chart-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); gap: 1.25rem; margin: 1rem 0; }
.chart-limit { stroke: var(--error); stroke-dasharray: 2 2; }
.plain-list { list-style: none; padding: 0; margin: .5rem 0; display: grid; gap: .35rem; }
.sensor-list { list-style: none; padding: 0; margin: .6rem 0 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: .25rem .75rem; font-size: .88rem; }

/* Detail sluzby: odkaz na prejmenovani hned za nazvem, ale potichu. */
.service-title { display: flex; align-items: baseline; flex-wrap: wrap; gap: .25rem .9rem; }
.service-rename-link { color: var(--muted); font-size: .85rem; }
.service-rename-link:hover { color: var(--ink); }

/* Kratka poznamka vedle tlacitka v rade akci. `.hint` tu nejde - ma horni
   okraj pro samostatny odstavec a vedle tlacitka by visela niz. */
.actions-note { color: var(--muted); font-size: .85rem; }

/* Druhy radek v bunce tabulky (port pod adresou, odkaz pod uzivatelem). */
.credential-sub { display: block; margin-top: .2rem; color: var(--muted); font-size: .82rem; }
.credential-sub code { font-size: inherit; }

/* Formularove tlacitko, ktere vypada jako obycejny odkaz - kde jde o POST
   (Adminer potrebuje CSRF), ale ramecek `.link-button` by byl moc hlucny. */
.text-button {
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    color: var(--signal);
    text-decoration: underline;
    text-underline-offset: .18em;
    text-decoration-thickness: 1px;
    cursor: pointer;
}
.text-button:hover { color: var(--signal-dark); }

/* Zaskrtavatka formulare vedle sebe; na uzkem displeji se zalomi. */
.checkbox-row { display: flex; flex-wrap: wrap; gap: 0 1.5rem; margin-bottom: .85rem; }

/* Barevne varianty drobnych akci. Danger je obrys, ne plocha - stejne
   jako `.button-danger`, plny cerveny by k nevratne akci lakal. */
.link-button-danger { color: var(--error); border-color: rgba(162, 24, 26, .45); }
.link-button-danger:hover { color: var(--paper); background: var(--error); border-color: var(--error); }
.link-button-gold { color: var(--warn); border-color: rgba(138, 97, 0, .45); background: var(--warn-tint); }
.link-button-gold:hover { color: var(--paper); background: var(--warn); border-color: var(--warn); }

/* "Vice" v rade akci: vzacne volby v rozbalovacim menu pod tlacitkem.
   Bez JS - `<details>`; menu visi absolutne, aby se rada nehybala. */
.row-more > summary { list-style: none; }
.row-more > summary::-webkit-details-marker { display: none; }
.row-more > summary::after { content: " ▾"; font-size: .75em; }
.action-cluster details[open] > .row-more-menu {
    position: absolute;
    top: calc(100% + .35rem);
    right: 0;
    z-index: 5;
    display: flex;
    flex-direction: column;
    gap: .3rem;
    min-width: 12rem;
    padding: .5rem;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-sm);
    background: var(--paper);
    box-shadow: 0 8px 24px rgba(17, 19, 22, .14);
}
.row-more-menu .link-button { display: block; width: 100%; text-align: left; border-color: transparent; }
.row-more-menu .link-button:hover { border-color: var(--line-strong); }

/* Navstevnost (A2.6h) ------------------------------------------------- */
.range-switch { margin-top: .25rem; }

/* Sloupcovy graf po dnech. Jedna rada, takze jedna barva a zadna legenda -
   nadpis rika, co to je. Hover cil je cely sloupec dne. */
.chart-bars svg { height: 12rem; }
.chart-bar { fill: var(--info); }
.chart-hit { fill: transparent; }
.chart-day:hover .chart-bar { fill: var(--ink); }
.chart-day:hover .chart-hit { fill: var(--info-tint); }
.chart-xaxis {
    display: flex;
    justify-content: space-between;
    padding-left: 3rem;
    margin-top: .35rem;
    color: var(--muted);
    font-size: .72rem;
}
@media (max-width: 40rem) { .chart-xaxis { padding-left: 2.4rem; } }

.chart-bars + .disclosure { margin-top: 1rem; }
.section-lead { margin-top: -.4rem; margin-bottom: .75rem; }

/* Vodorovne pruhy: popisek a cislo nad tenkym pruhem. Pomer se cte
   z delky, presne cislo je hned vpravo. */
.hbars { list-style: none; margin: .75rem 0 0; padding: 0; display: grid; gap: .7rem; }
.hbar { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .2rem 1rem; font-size: .9rem; }
.hbar-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar-value { font-variant-numeric: tabular-nums; font-weight: 600; text-align: right; }
.hbar-hint { color: var(--muted); font-size: .8rem; font-weight: 400; }
.hbar-track { grid-column: 1 / -1; display: block; width: 100%; height: 6px; border-radius: 3px; background: var(--paper-sunken); }
.hbar-track rect { fill: var(--info); }
.hbar-muted .hbar-track rect { fill: var(--line-strong); }

/* Skupiny aplikaci na prodejnim webu: sedy panel s bilymi kartami misto
   sekce oddelene jen tenkou carou. */
.section.app-group {
    margin: 2.5rem 0;
    padding: 2rem 2rem 2.25rem;
    border: 0;
    border-radius: var(--radius);
    background: var(--paper-sunken);
}
.app-group .section-head { margin-bottom: 1.5rem; }
.app-group .section-head h2::before {
    content: "";
    display: inline-block;
    width: .3rem;
    height: 1.1em;
    margin-right: .6rem;
    border-radius: 2px;
    background: var(--signal);
    vertical-align: -.15em;
}
.app-group + .section:not(.app-group) { border-top: 0; }
@media (max-width: 40rem) {
    .section.app-group { padding: 1.5rem 1rem; margin: 1rem -.5rem; }
}
