/* =====================================================================
   PORTAL ABONENTA UNINET — własny arkusz, nie wariant panelu.

   Łukasz, 06.09.2026: „ogólnie pro portal, żeby z butów wywalało".
   Wcześniej, o marce: „logotypy Serwis24 i UNINET prezentowane na równi,
   ale Serwis24 ZAWSZE na pierwszym miejscu"; kolorystyka firmowa —
   granat i czerwień; interfejs profesjonalny i stonowany, bez emoji.

   DLACZEGO OSOBNY ARKUSZ, A NIE `app.css`
   Panel serwisowy jest gęsty: tabele, filtry, dwadzieścia wierszy na
   ekran, wszystko dla kogoś, kto siedzi w nim osiem godzin. Tu jest
   dokładnie odwrotnie — człowiek wchodzi raz na kwartał, zdenerwowany,
   z telefonu, i ma znaleźć JEDNĄ odpowiedź. Te dwa ekrany nie mogą mieć
   wspólnej skali typograficznej ani wspólnej gęstości, więc nie mają
   też wspólnego arkusza.
   ===================================================================== */

:root {
  /* --- MARKA -------------------------------------------------------
     Granat prowadzi (spokój, „to jest infrastruktura"), czerwień jest
     akcentem Serwis24 i pojawia się OSZCZĘDNIE — na jednym przycisku
     i na logotypie. Czerwień rozlana po całym ekranie czyta się jak
     ostrzeżenie, a ten portal ma uspokajać. */
  --granat:      #0f2b52;
  --granat-2:    #163b6e;
  --granat-jasny:#e8eef7;
  --czerwien:    #cf2027;
  --czerwien-2:  #b21a20;

  /* Neutralne z lekkim odchyleniem w stronę granatu — czysta szarość
     przy tej palecie wygląda na brudną. */
  --tlo:       #f4f6fa;
  --karta:     #ffffff;
  --karta-2:   #f7f9fc;
  --linia:     #dde3ed;
  --linia-2:   #eef1f7;
  --tekst:     #16202f;
  --tekst-2:   #4a566b;
  --tekst-3:   #78849a;

  --ok:      #0e7a4a;  --ok-tlo:#e7f5ee;  --ok-linia:#b3ddc7;
  --uwaga:   #92620a;  --uwaga-tlo:#fdf3e0;--uwaga-linia:#efd6a4;
  --zle:     #b4231f;  --zle-tlo:#fdecea; --zle-linia:#f3bfbb;

  --r:   14px;
  --r-s: 9px;
  --cien:   0 1px 2px rgba(15,43,82,.06), 0 8px 24px -12px rgba(15,43,82,.18);
  --cien-2: 0 2px 4px rgba(15,43,82,.08), 0 18px 40px -16px rgba(15,43,82,.28);

  /* SKALA PODNIESIONA o mniej więcej stopień, 07.09.2026.
     Powód nie jest estetyczny: to portal, do którego ludzie wchodzą,
     kiedy coś nie działa — często starsi, często z telefonu, często
     w pośpiechu. Dolne stopnie skali (12,5 i 14 px) trafiały dokładnie
     w to, co przy takim czytelniku znika: podpisy pod kafelkami,
     opisy w listach, treść FAQ. Najmocniej rosną właśnie one, bo to
     tam był problem, a nie w nagłówkach. */
  --fs-xs:13.5px; --fs-s:15.5px; --fs:17px; --fs-l:19.5px;
  --fs-xl:26px;   --fs-2xl:34px; --fs-3xl:44px;

  /* Szerzej — Łukasz, 07.09.2026: „nie możemy trochę szerszej części
     ekranu wykorzystać?". 1080 px było miarą pod jedną kolumnę tekstu,
     a ten portal ma dwie kolumny kart i listwę faktów, które przy tej
     szerokości robiły się ciasne. */
  --tresc: 1320px;
}

/* Ciemny motyw: osobno dobrane kroki, nie rozjaśnione jasne. Granat na
   ciemnym tle znika, więc rolę „spokojnego tła marki" przejmuje bardzo
   ciemny granat, a jasny granat staje się kolorem tekstu akcentowego. */
:root[data-theme="dark"] {
  --granat:      #9dc0f0;
  --granat-2:    #7ea9e8;
  --granat-jasny:#1f2f4d;
  --czerwien:    #f2565c;
  --czerwien-2:  #e0454b;

  --tlo:     #0d1420;
  --karta:   #141d2c;
  --karta-2: #1a2436;
  --linia:   #2a3646;
  --linia-2: #202b3b;
  --tekst:   #eef2f8;
  --tekst-2: #b3bdcd;
  --tekst-3: #808d9f;

  /* Tła stanów są jaśniejsze, niż podpowiada intuicja „ciemny motyw =
     ciemniej". Przy #2c1614 krążek z wykrzyknikiem tonął w tle: kolor
     był poprawny, ale sam znak jest cienką kreską i na tak ciemnej
     podkładce po prostu nie było go widać. */
  --ok:      #4bbd85;  --ok-tlo:#153b2b;   --ok-linia:#2a6b4d;
  --uwaga:   #e0a84a;  --uwaga-tlo:#3d2f16;--uwaga-linia:#6b5226;
  --zle:     #f2726d;  --zle-tlo:#43201d;  --zle-linia:#70332f;

  --cien:   0 1px 2px rgba(0,0,0,.4), 0 8px 24px -12px rgba(0,0,0,.6);
  --cien-2: 0 2px 4px rgba(0,0,0,.5), 0 18px 40px -16px rgba(0,0,0,.7);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--tlo);
  color: var(--tekst);
  font: var(--fs)/1.55 -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
        'Helvetica Neue', Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { margin: 0; line-height: 1.2; text-wrap: balance; font-weight: 650; }
p { margin: 0; }
a { color: var(--granat-2); }

/* =====================================================================
   PASEK GÓRNY — tu mieszka współbrandowanie
   ===================================================================== */
.pasek {
  background: var(--karta);
  border-bottom: 1px solid var(--linia);
  position: sticky; top: 0; z-index: 20;
}
.pasek-w {
  max-width: var(--tresc); margin: 0 auto; padding: 12px 20px;
  display: flex; align-items: center; gap: 16px;
}

/* SERWIS24 ZAWSZE PIERWSZY. Nie jest to kwestia estetyki, tylko
   ustalenia z Łukaszem — portal jest inicjatywą Serwis24, a UNINET
   stoi obok jako partner, nie nad nim jako zleceniodawca. */
.marka { display: flex; align-items: center; min-width: 0; }
/* PŁYTKA POD ZNAKAMI.
   Oba logotypy są ciemne na przezroczystym tle. Na jasnym motywie
   płytka jest ledwo widoczna, na ciemnym — konieczna: bez niej czarny
   wordmark UNINET-u znika. Rozjaśnianie cudzego znaku filtrem CSS
   odpada, bo to zmiana czyjegoś logo, a nie efekt graficzny. */
.plytka {
  display: inline-flex; align-items: center; gap: 14px;
  background: #fff; border: 1px solid var(--linia);
  border-radius: var(--r-s); padding: 8px 14px;
}
.plytka-kreska { width: 1px; align-self: stretch; background: #d5d8e2; flex: 0 0 auto; }
/* Wysokości dobrane tak, żeby oba znaki miały ten sam ciężar optyczny:
   „serwis24" ma podpis w linii pisma, „UNINET" ma nad nim kwiat, więc
   przy równej wysokości pliku wygląda na większy. */
.znak-s24    { height: 26px; width: auto; display: block; }
.znak-uninet { height: 22px; width: auto; display: block; }
.marka.mala .znak-s24    { height: 21px; }
.marka.mala .znak-uninet { height: 18px; }
.marka.mala .plytka { padding: 6px 11px; gap: 11px; }
.pasek-prawo { margin-left: auto; display: flex; align-items: center; gap: 8px; }
/* Kolejność w pasku: znaki firm, nawigacja, na końcu sterowanie sesją. */
.pasek-w > .marka { order: 1; }
.pasek-w > .zakladki { order: 2; }
.pasek-w > .pasek-prawo { order: 3; }

.ikonka {
  border: 1px solid var(--linia); background: var(--karta);
  color: var(--tekst-2); border-radius: var(--r-s);
  width: 38px; height: 38px; display: grid; place-items: center;
  cursor: pointer; font-size: 15px; line-height: 1;
}
.ikonka:hover { background: var(--karta-2); color: var(--tekst); }

/* =====================================================================
   UKŁAD
   ===================================================================== */
/* Dolny odstęp mniejszy — stopka jest teraz kartą z treścią, a nie
   linijką drobnego druku, więc nie potrzebuje przed sobą pustego pasa. */
.tresc { max-width: var(--tresc); margin: 0 auto; padding: 24px 20px 24px; }
/* Karty w parze mają teraz równą wysokość. Wcześniej stało tu
   `align-items:start`, żeby pusta karta „Prace i awarie" nie rozciągała
   się na wysokość sąsiada — ale to leczyło objaw, nie przyczynę: dziura
   pod niską kartą wyglądała dokładnie tak samo źle. Przyczynę usuwa
   `.pulpit` niżej (kolumny o różnej roli), a tam, gdzie naprawdę są dwie
   równorzędne karty, lepiej wygląda wspólna linia dołu. */
/* =====================================================================
   DIAGNOSTYKA — PEŁNA SZEROKOŚĆ, TREŚĆ W OSI.
   Zwężenie kolumny do 940 px naprawiało nie ten problem, co trzeba:
   kłopotem nie była szerokość, tylko tekst uciekający do lewej krawędzi
   i kafle rozciągnięte na pół ekranu. Kolumna wraca więc do `--tresc`
   (równo ze stopką), a rozjazdowi zapobiega co innego: treść stoi w osi,
   a kafle DZIELĄ szerokość na tyle kolumn, ile jest odpowiedzi — cztery
   odpowiedzi to cztery kafle w rzędzie, a nie dwa na pół ekranu.
   ===================================================================== */
.waski .stan { margin-bottom: 16px; }

.siatka { display: grid; gap: 16px; grid-template-columns: repeat(2, minmax(0, 1fr));
          align-items: stretch; }
.siatka > .szeroka { grid-column: 1 / -1; }
@media (max-width: 760px) { .siatka { grid-template-columns: 1fr; } }

/* PULPIT — czytanie po lewej, działanie po prawej.
   Dwie równe kolumny (stary układ) wyglądały źle nie przez proporcje,
   tylko przez to, że sąsiadowały w nich karty o skrajnie różnej
   objętości: jedno zdanie o awariach obok wysokiej karty diagnostyki
   zostawiało pod sobą dziurę na pół ekranu. Kolumny o różnej ROLI
   rozwiązują to u źródła — lewa rośnie treścią (awarie + najczęstsze
   przyczyny), prawa jest wąską szyną akcji i ma prawo być krótsza. */
.pulpit { display: grid; gap: 16px; align-items: start;
          grid-template-columns: minmax(0, 1.6fr) minmax(300px, .9fr); }
.pulpit-lewa, .pulpit-prawa { display: flex; flex-direction: column; gap: 16px;
                              min-width: 0; }
/* Szyna jedzie z ekranem: przycisk zgłoszenia ma być pod ręką, gdy ktoś
   czyta listę przyczyn, a nie dopiero na samym dole strony. */
/* Szyna przestała być przyklejona, gdy trafiła do niej prośba o opinię:
   przyklejona kolumna wyższa od ekranu chowa własny dół i nie da się do
   niego dojechać. Przycisk zgłoszenia i tak stoi wysoko. */
.pulpit-prawa { align-self: start; }
@media (max-width: 1000px) {
  .pulpit { grid-template-columns: 1fr; }
  .pulpit-prawa { position: static; }
}

.karta {
  background: var(--karta); border: 1px solid var(--linia);
  border-radius: var(--r); box-shadow: var(--cien);
  padding: 20px; min-width: 0;
}
/* TYTUŁY KART — czytelne, nie ozdobne.
   Łukasz, 07.09.2026: „tytuły kafli dałbym ciut większe i bardziej
   widoczne — pamiętaj, że z tego będą korzystali też starsi ludzie".
   Wersalik + rozstrzelenie + jasna szarość to trzy rzeczy naraz, z
   których każda osobno pogarsza czytelność, a razem robią z nagłówka
   ozdobnik. Zostaje normalna wielkość liter, pełny kolor tekstu
   i rozmiar o dwa stopnie wyżej. */
.karta-tytul {
  font-size: var(--fs-l); font-weight: 700; letter-spacing: -.01em;
  color: var(--tekst); margin-bottom: 12px; line-height: 1.25;
}

/* =====================================================================
   KARTA STANU — jedyna rzecz, po którą tu ktoś przychodzi
   =====================================================================
   Duża, u góry, jednym zdaniem. Człowiek, który wchodzi, bo „internet
   nie działa", ma dostać odpowiedź, zanim cokolwiek przeczyta. Kolor
   niesie stan, ale NIE SAM: obok stoi kropka o innym kształcie i pełne
   zdanie — bo część ludzi nie odróżni zieleni od czerwieni. */
/* =====================================================================
   STAN ŁĄCZA — najważniejszy element portalu
   =====================================================================
   Łukasz, 07.09.2026: „ten górny baner bym poprawił, potrzeba tam czegoś
   bardziej PRO".

   Cztery decyzje, które robią różnicę między „białym boksem z tekstem"
   a nagłówkiem, który wygląda na przyrząd pomiarowy:

   1. TŁO NIESIE WERDYKT. Delikatny gradient w kolorze stanu plus listwa
      u góry. Człowiek widzi odpowiedź, zanim przeczyta zdanie — a przy
      awarii liczy się właśnie ta pierwsza sekunda.
   2. FAKTY POD KRESKĄ, NA PEŁNĄ SZEROKOŚĆ. Doklejone z boku wyglądały
      na przypis; rozłożone w listwę czytają się jak odczyt z urządzenia.
   3. LICZBY MAJĄ SWOJĄ TYPOGRAFIĘ: cyfry tablicowe, większy stopień,
      etykiety wersalikami z rozstrzeleniem. To jest różnica między
      „danymi" a „tekstem, w którym są liczby".
   4. KROPKA „NA ŻYWO" PULSUJE tylko przy działającym łączu i tylko
      wtedy, gdy człowiek nie poprosił o mniej ruchu.
   ===================================================================== */
.stan {
  position: relative; overflow: hidden;
  border-radius: var(--r); padding: 30px 32px 0; border: 1px solid var(--linia);
  background: var(--karta); box-shadow: var(--cien-2);
  display: grid; gap: 20px 28px; align-items: start;
  grid-template-columns: auto minmax(0, 1fr) auto;
}
/* Listwa u góry w kolorze werdyktu — wąska, żeby nie krzyczała. */
.stan::before {
  content: ''; position: absolute; inset: 0 0 auto; height: 3px;
  background: var(--tekst-3);
}
.stan.dziala::before          { background: var(--ok); }
.stan.do-odswiezenia::before  { background: var(--uwaga); }
.stan.brak-polaczenia::before { background: var(--zle); }

.stan.srodek {
  grid-template-columns: 1fr; justify-items: center; text-align: center;
  gap: 26px; padding: 34px 32px 0;
}
.stan.srodek .stan-glowa {
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  /* SZEROKOŚĆ DLA TYTUŁU, NIE DLA AKAPITU.
     62ch liczone krojem tekstu dawało 586 px — a tytuł jest w 44 px
     i przy tej szerokości łamał się na trzy poszarpane wiersze, z
     myślnikiem wiszącym na początku drugiego. Kolumna jest więc
     szersza, a akapit trzyma własne 58ch (patrz `.stan p`), żeby
     wiersz tekstu dalej dało się czytać. */
  max-width: 78ch;
}
.stan.dziala          { background: linear-gradient(178deg, var(--ok-tlo) 0%, var(--karta) 46%); }
.stan.do-odswiezenia  { background: linear-gradient(178deg, var(--uwaga-tlo) 0%, var(--karta) 46%); }
.stan.brak-polaczenia { background: linear-gradient(178deg, var(--zle-tlo) 0%, var(--karta) 46%); }
.stan.nieznany        { background: linear-gradient(178deg, var(--karta-2) 0%, var(--karta) 46%); }

.stan-znak { flex: 0 0 auto; width: 60px; height: 60px; border-radius: 50%;
             display: grid; place-items: center; background: var(--karta);
             box-shadow: 0 0 0 6px var(--karta), var(--cien); }
.stan-znak svg { width: 30px; height: 30px; }
.stan.dziala          .stan-znak { background: var(--ok-tlo);    color: var(--ok);
                                   box-shadow: 0 0 0 7px rgba(14,122,74,.09); }
.stan.do-odswiezenia  .stan-znak { background: var(--uwaga-tlo); color: var(--uwaga);
                                   box-shadow: 0 0 0 7px rgba(146,98,10,.10); }
.stan.brak-polaczenia .stan-znak { background: var(--zle-tlo);   color: var(--zle);
                                   box-shadow: 0 0 0 7px rgba(180,35,31,.10); }
.stan.nieznany        .stan-znak { background: var(--karta-2);   color: var(--tekst-3);
                                   box-shadow: 0 0 0 7px rgba(120,132,154,.10); }
.stan-tresc { min-width: 0; }

/* Nadtytuł: co to za ekran i czy jest aktualny. */
.stan-nad { display: inline-flex; align-items: center; gap: 8px;
            font-size: var(--fs-xs); text-transform: uppercase;
            letter-spacing: .09em; font-weight: 650; color: var(--tekst-3);
            margin-bottom: 10px; }
.stan-kropka { width: 8px; height: 8px; border-radius: 50%;
               background: var(--tekst-3); flex: 0 0 auto; }
.stan.dziala .stan-kropka { background: var(--ok); }
.stan.do-odswiezenia .stan-kropka { background: var(--uwaga); }
.stan.brak-polaczenia .stan-kropka { background: var(--zle); }
@keyframes tetno {
  0%   { box-shadow: 0 0 0 0 rgba(14,122,74,.45); }
  70%  { box-shadow: 0 0 0 7px rgba(14,122,74,0); }
  100% { box-shadow: 0 0 0 0 rgba(14,122,74,0); }
}
.stan.dziala .stan-kropka { animation: tetno 2.4s ease-out infinite; }
:root[data-ruch="mniej"] .stan.dziala .stan-kropka { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .stan.dziala .stan-kropka { animation: none; }
}

.stan h1 { font-size: var(--fs-3xl); letter-spacing: -.025em; line-height: 1.08;
           text-wrap: balance; max-width: 38ch; }
.stan.srodek h1 { margin-inline: auto; }
/* `pretty` zamiast `balance`: w akapicie nie chodzi o równe wiersze,
   tylko o to, żeby ostatni nie był jednym słowem. */
.stan p  { color: var(--tekst-2); margin-top: 10px; max-width: 58ch;
           font-size: var(--fs-l); line-height: 1.5; text-wrap: pretty; }
.stan.srodek p { margin-inline: auto; }

/* LISTWA FAKTÓW — pełna szerokość, pod kreską, równe kolumny. */
/* FLEX, NIE GRID O STAŁEJ LICZBIE KOLUMN. Faktów bywa od jednego
   (gdy nie mamy odczytu z sieci — zostaje sam numer klienta) do czterech,
   a siatka `repeat(4, 1fr)` wciskała wtedy jedną pozycję w pierwszą
   ćwiartkę i listwa wyglądała na przesuniętą w lewo. Przy `flex: 1 1 0`
   pozycje dzielą szerokość równo, ile by ich nie było. */
.fakty { display: flex; width: 100%; margin: 0;
         border-top: 1px solid var(--linia-2); }
.fakty > div { flex: 1 1 0; min-width: 0; padding: 18px 20px; text-align: center;
               border-left: 1px solid var(--linia-2); }
.fakty > div:first-child { border-left: 0; }
.fakty dt { font-size: var(--fs-xs); color: var(--tekst-3); text-transform: uppercase;
            letter-spacing: .08em; font-weight: 650; }
.fakty dd { margin: 6px 0 0; font-weight: 680; font-size: var(--fs-l);
            font-variant-numeric: tabular-nums; letter-spacing: -.01em;
            overflow-wrap: anywhere; }
.fakty dd.mono { font-size: var(--fs); }
@media (max-width: 760px) {
  .stan.srodek { padding: 26px 20px 0; }
  .stan h1 { font-size: var(--fs-2xl); }
  .stan p { font-size: var(--fs); }
  .fakty { flex-wrap: wrap; }
  .fakty > div { flex: 1 1 46%; }
  .fakty > div:nth-child(odd) { border-left: 0; }
  .fakty > div:nth-child(n+3) { border-top: 1px solid var(--linia-2); }
}

/* Na ciemnym motywie gradient stanu musi być ledwie widoczny — te same
   kolory co na jasnym byłyby latarnią. */
:root[data-theme="dark"] .stan.dziala          { background: linear-gradient(178deg, rgba(35,120,80,.20) 0%, var(--karta) 46%); }
:root[data-theme="dark"] .stan.do-odswiezenia  { background: linear-gradient(178deg, rgba(150,110,30,.20) 0%, var(--karta) 46%); }
:root[data-theme="dark"] .stan.brak-polaczenia { background: linear-gradient(178deg, rgba(170,60,55,.20) 0%, var(--karta) 46%); }
:root[data-theme="dark"] .stan.nieznany        { background: linear-gradient(178deg, rgba(255,255,255,.05) 0%, var(--karta) 46%); }

/* =====================================================================
   PLAKIETKI, PRZYCISKI, POLA
   ===================================================================== */
.plakietka {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-xs); font-weight: 650; padding: 3px 10px;
  border-radius: 999px; border: 1px solid var(--linia); color: var(--tekst-2);
  background: var(--karta-2);
}
.plakietka.ok    { background: var(--ok-tlo);    color: var(--ok);    border-color: var(--ok-linia); }
.plakietka.uwaga { background: var(--uwaga-tlo); color: var(--uwaga); border-color: var(--uwaga-linia); }
.plakietka.zle   { background: var(--zle-tlo);   color: var(--zle);   border-color: var(--zle-linia); }

.btn {
  font: inherit; font-weight: 650; border-radius: var(--r-s);
  padding: 11px 18px; border: 1px solid var(--linia); background: var(--karta);
  color: var(--tekst); cursor: pointer; min-height: 44px;
}
.btn:hover:not(:disabled) { background: var(--karta-2); }
.btn:disabled { opacity: .55; cursor: default; }
.btn.glowny { background: var(--granat); border-color: var(--granat); color: #fff; }
:root[data-theme="dark"] .btn.glowny { color: #0d1420; }
.btn.glowny:hover:not(:disabled) { background: var(--granat-2); border-color: var(--granat-2); }
.btn.czerwony { background: var(--czerwien); border-color: var(--czerwien); color: #fff; }
.btn.czerwony:hover:not(:disabled) { background: var(--czerwien-2); }
.btn.pelny { width: 100%; }
.btn.maly { padding: 7px 12px; min-height: 36px; font-size: var(--fs-s); }

.pole { display: block; margin-bottom: 14px; }
.pole > span { display: block; font-size: var(--fs-s); font-weight: 650;
               margin-bottom: 6px; color: var(--tekst-2); }
.pole .podpowiedz { font-weight: 400; color: var(--tekst-3); font-size: var(--fs-xs);
                    display: block; margin-top: 5px; }
/* Selektor po `type` wymaga, żeby atrybut BYŁ w HTML-u. Pole bez
   `type` jest tekstowe dla przeglądarki, ale `input[type=text]` go nie
   obejmuje — i pole kodu było przez to węższe od reszty formularza.
   Stąd `input:not(...)`: łapie wszystko, co jest polem tekstowym,
   niezależnie od tego, czy ktoś napisał atrybut. */
input:not([type=checkbox]):not([type=radio]):not([type=file]), textarea {
  font: inherit; width: 100%; padding: 11px 13px; min-height: 44px;
  border: 1px solid var(--linia); border-radius: var(--r-s);
  background: var(--karta); color: var(--tekst);
}
input:focus-visible, textarea:focus-visible, .btn:focus-visible, .ikonka:focus-visible {
  outline: 2px solid var(--granat-2); outline-offset: 2px;
}
/* Kod jednorazowy: cyfry rozstrzelone i duże. Człowiek przepisuje je
   z telefonu na komputer i musi widzieć, czy trafił. */
input.kod {
  font-size: var(--fs-xl); letter-spacing: .38em; text-align: center;
  font-variant-numeric: tabular-nums; padding-left: .38em;
}

.blad, .info {
  border-radius: var(--r-s); padding: 11px 14px; font-size: var(--fs-s);
  margin-bottom: 14px; border: 1px solid;
}
.blad { background: var(--zle-tlo); color: var(--zle); border-color: var(--zle-linia); }
.info { background: var(--granat-jasny); color: var(--granat); border-color: var(--linia); }

/* =====================================================================
   EKRAN WEJŚCIA
   =====================================================================
   Dwie kolumny na monitorze: lewa mówi, czym to jest, prawa przyjmuje
   dane. Na telefonie zostaje sama prawa — nikt nie czyta manifestu,
   stojąc w kuchni z martwym routerem. */
.wejscie { min-height: 100dvh; display: grid; grid-template-columns: 1.05fr .95fr; }
@media (max-width: 900px) { .wejscie { grid-template-columns: 1fr; } }

/* =====================================================================
   LEWY PANEL JEST JASNY — I TO JEST DECYZJA O MARCE, NIE O GUŚCIE
   =====================================================================
   Łukasz, 07.09.2026: „zdecydowanie nasze loga dużo większe, niech się
   wyróżniają na ekranie, bez tego białego tła".

   Białą płytkę dało się zdjąć, ale wyszło wtedy coś gorszego: oba
   logotypy to PNG BEZ KANAŁU ALFA, z bielą wypaloną w obrazek. Po
   wycięciu tła granatowe „serwis" i „UNINET" zniknęły na granatowym
   panelu — te znaki są zaprojektowane pod jasne tło.

   Można było przemalować wordmarki na biało, ale to jest decyzja
   o cudzej marce, a nie poprawka układu. Więc zmieniamy PANEL, nie
   LOGOTYP: jasne tło, granatowa typografia, czerwień jako akcent.
   Logotypy stoją duże, bez żadnej płytki, dokładnie w swoich kolorach.
   ===================================================================== */
.wejscie-lewa {
  background:
    radial-gradient(110% 80% at 18% 12%, rgba(255,255,255,.9), transparent 58%),
    linear-gradient(158deg, #dde6f4 0%, #c9d7ec 100%);
  color: var(--tekst);
  padding: 56px 48px; display: flex; flex-direction: column;
  position: relative;
}
/* Czerwień Serwis24 jako cienki akcent na styku paneli — jedyne miejsce,
   w którym pojawia się na tym ekranie. */
.wejscie-lewa::after {
  content: ''; position: absolute; inset: 0 0 0 auto; width: 3px;
  background: linear-gradient(180deg, var(--czerwien), var(--granat));
}
/* Formularz na czystej bieli — podział czytelny bez ciemnego panelu. */
.wejscie-prawa { background: var(--karta); }
:root[data-theme="dark"] .wejscie-lewa {
  background: linear-gradient(158deg, #dde6f4 0%, #c9d7ec 100%);
  color: #16202f;
}
@media (max-width: 900px) { .wejscie-lewa { display: none; } }

/* WSZYSTKO W JEDNEJ OSI, NA ŚRODKU. Wcześniej logotyp siedział w lewym
   górnym rogu, a hasło było dociśnięte `margin-top:auto` do dołu — dwa
   osobne bloki na przeciwnych końcach wysokiego ekranu, między nimi pół
   metra pustego granatu. */
.wejscie-lewa { justify-content: center; align-items: center; text-align: center; }
/* OGRANICZENIE SZEROKOŚCI NALEŻY DO TEKSTU, NIE DO CAŁEJ KOLUMNY.
   Wcześniej `max-width: 52ch` siedziało tutaj i obejmowało też logotypy.
   Po ich powiększeniu lockup (ok. 670 px) przestał się mieścić w 492 px
   i wychodził poza kolumnę w prawo — wszystko było wyśrodkowane co do
   piksela, a mimo to wyglądało na przesunięte, bo przepełniony element
   rozlewa się w jedną stronę. Teraz kolumna jest pełnej szerokości,
   a miarę czytania trzyma sam blok tekstu. */
.wejscie-srodek { display: flex; flex-direction: column; align-items: center;
                  gap: 30px; width: 100%; }
/* Cytat stoi NIŻEJ niż wynikałoby z `gap` — hasło firmowe ma być
   domknięciem kolumny, a nie czwartym akapitem z rzędu. */
.wejscie-srodek > .wejscie-cytat { margin-top: 18px; }
.wejscie-haslo, .wejscie-cytat { max-width: min(52ch, 100%); }
.marka.duza .plytka { justify-content: center; }
.wejscie-haslo { margin-top: 0; }
.wejscie-haslo h2 { font-size: var(--fs-3xl); letter-spacing: -.03em; max-width: none; }
.wejscie-haslo h2 { color: var(--granat); }
.wejscie-haslo p { color: var(--tekst-2); margin-top: 14px; }
:root[data-theme="dark"] .wejscie-haslo h2 { color: var(--granat); }
:root[data-theme="dark"] .wejscie-haslo p,
:root[data-theme="dark"] .wejscie-punkty li { color: #3d4c63; }
/* Lista wyśrodkowana JAKO BLOK, a nie wyśrodkowanym tekstem: ptaszki
   stoją w jednej pionowej linii, a zdania zaczynają się równo od niej.
   Wyśrodkowanie samego tekstu rozjechałoby początki wierszy. */
.wejscie-punkty { list-style: none; margin: 30px 0 0; padding: 0;
                  display: flex; flex-direction: column; gap: 12px;
                  text-align: left; width: fit-content; margin-inline: auto; }
.wejscie-punkty li { display: flex; gap: 11px; align-items: flex-start;
                     color: var(--tekst-2); font-size: var(--fs-s); }
.wejscie-punkty svg { flex: 0 0 auto; width: 18px; height: 18px; margin-top: 2px;
                      color: var(--ok); }
/* =====================================================================
   HASŁO OBU FIRM JAKO CYTAT
   =====================================================================
   Łukasz, 07.09.2026: „mam wrażenie, że to »Razem możemy więcej« jest
   w prawo przesunięte. Możemy to wyrównać i delikatnie może dać niżej
   + powiększyć? (…) może też inną czcionką, jako cytat i hasło?".

   TRZY DECYZJE:

   1. WRAŻENIE PRZESUNIĘCIA BYŁO PRAWDZIWE, choć blok stał idealnie
      na środku. Winny był cudzysłów: „ to glif z dużym światłem po
      lewej, więc wyśrodkowany co do piksela wiersz zaczyna się
      OPTYCZNIE dalej niż wiersze nad nim. Klasyczna odpowiedź
      typografii to wiszący cudzysłów — cytat dostaje ujemny wcięcie
      równe szerokości glifu, a `hanging-punctuation` robi to samo tam,
      gdzie przeglądarka je zna.

   2. KRÓJ SZERYFOWY Z ZASOBÓW SYSTEMU, nie z sieci. Ten portal otwiera
      człowiek, któremu WŁAŚNIE NIE DZIAŁA INTERNET — font z Google
      Fonts nie doszedłby akurat wtedy, kiedy strona jest najbardziej
      potrzebna. Georgia i jej odpowiedniki są na każdym systemie
      i wystarczą, żeby hasło odcięło się od reszty ekranu.

   3. NIŻEJ I WIĘKSZE, ale bez konkurowania z nagłówkiem: kreska nad
      cytatem robi odstęp, którego samo powietrze nie zrobi — pod listą
      punktów pusta przestrzeń czyta się jak koniec strony, a kreska
      jak zmiana rejestru.
   ===================================================================== */
.wejscie-cytat { margin: 14px 0 0; padding-top: 26px; position: relative;
                 display: flex; flex-direction: column; align-items: center;
                 gap: 8px; }
.wejscie-cytat::before {
  content: ''; position: absolute; top: 0; left: 50%; transform: translateX(-50%);
  width: 56px; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(22,32,47,.28), transparent);
}
.wejscie-cytat blockquote {
  margin: 0;
  font-family: 'Iowan Old Style', 'Palatino Linotype', Palatino, Georgia,
               'Times New Roman', serif;
  font-style: italic; font-size: clamp(19px, 1.5vw, 23px); line-height: 1.35;
  letter-spacing: .005em; color: var(--granat);
  /* Wiszący cudzysłów — patrz punkt 1 wyżej. */
  hanging-punctuation: first last;
  text-indent: -.34em;
}
/* Cudzysłowy z CSS, nie z treści: w tekście zostaje samo hasło, więc
   kopiuje się bez ozdobników, a `::before`/`::after` nie wchodzą
   w rachubę przy zaznaczaniu. */
.wejscie-cytat blockquote::before { content: '\201E'; }
.wejscie-cytat blockquote::after  { content: '\201D'; margin-left: -.1em; }
/* Kursywa szeryfowa ma spory odstęp z prawej (pochylone „j" w „więcej"
   kończy się wyżej, niż sięga jego kreska), więc zamykający cudzysłów
   odrywał się od słowa. Setne części ema, ale to różnica między
   cytatem a cytatem z literówką. */
.wejscie-cytat figcaption {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .14em;
  font-weight: 600; color: var(--tekst-3);
}
/* Myślnik przed podpisem — w osobnym wierszu wygląda lepiej niż wklejony
   w treść i nie psuje wyśrodkowania samego hasła. */
.wejscie-cytat figcaption::before { content: '— '; }
:root[data-theme="dark"] .wejscie-cytat blockquote { color: var(--granat); }
:root[data-theme="dark"] .wejscie-cytat figcaption { color: #6b7890; }
/* Przeglądarki bez `hanging-punctuation` (dziś: wszystkie poza Safari)
   dostają samo ujemne wcięcie — to ta sama poprawka, tylko ręcznie. */
@supports (hanging-punctuation: first) {
  .wejscie-cytat blockquote { text-indent: 0; }
}

.wejscie-prawa { display: grid; place-items: center; padding: 32px 20px; }
.formularz { width: 100%; max-width: 400px; }
.formularz h1 { font-size: var(--fs-xl); margin-bottom: 6px; }
.formularz > p.wstep { color: var(--tekst-2); font-size: var(--fs-s); margin-bottom: 22px; }
.marka-mobil { display: none; margin-bottom: 28px; }
@media (max-width: 900px) { .marka-mobil { display: flex; align-items: center; gap: 12px; } }

.przelacz { display: flex; gap: 6px; background: var(--karta-2); padding: 4px;
            border-radius: var(--r-s); border: 1px solid var(--linia); margin-bottom: 22px; }
.przelacz button {
  flex: 1; font: inherit; font-size: var(--fs-s); font-weight: 650; cursor: pointer;
  border: 0; background: none; color: var(--tekst-2); padding: 9px 6px;
  border-radius: 6px; min-height: 38px;
}
.przelacz button[aria-selected="true"] {
  background: var(--karta); color: var(--tekst); box-shadow: var(--cien);
}
.pod-formularzem { margin-top: 18px; font-size: var(--fs-s); color: var(--tekst-2);
                   text-align: center; }
.jak-link { background: none; border: 0; padding: 0; font: inherit;
            color: var(--granat-2); cursor: pointer; text-decoration: underline; }

/* =====================================================================
   LISTY — awarie, zgłoszenia
   ===================================================================== */
.lista { list-style: none; margin: 0; padding: 0; display: flex;
         flex-direction: column; gap: 2px; }
.lista li { padding: 12px; border-radius: var(--r-s); background: var(--karta-2);
            display: flex; gap: 12px; align-items: flex-start; }
.lista .l-tresc { min-width: 0; flex: 1; }
.lista .l-tytul { font-weight: 650; }
.lista .l-pod { font-size: var(--fs-s); color: var(--tekst-2); margin-top: 2px; }
.pusto { color: var(--tekst-3); font-size: var(--fs-s); padding: 6px 0; }

/* Kroki bezpieczeństwa w ustawieniach konta */
.wiersz-ust { display: flex; align-items: center; gap: 14px; padding: 14px 0;
              border-bottom: 1px solid var(--linia-2); flex-wrap: wrap; }
.wiersz-ust:last-child { border-bottom: 0; }
.wiersz-ust .opis { flex: 1; min-width: 200px; }
.wiersz-ust .opis b { display: block; }
.wiersz-ust .opis span { font-size: var(--fs-s); color: var(--tekst-2); }

.kody-zapasowe { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px;
                 margin: 14px 0; }
.kody-zapasowe code {
  font-size: var(--fs); padding: 9px 12px; border-radius: var(--r-s);
  background: var(--karta-2); border: 1px solid var(--linia);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-align: center;
}
.qr { display: block; width: 190px; height: 190px; margin: 14px auto;
      border-radius: var(--r-s); border: 1px solid var(--linia); background: #fff; padding: 8px; }
.sekret-recznie { text-align: center; font-family: ui-monospace, monospace;
                  font-size: var(--fs-s); color: var(--tekst-2); word-break: break-all; }

/* =====================================================================
   POWIADOMIENIA
   ===================================================================== */
/* Licznik przy zakładce. Pojawia się TYLKO gdy coś czeka — zero
   w kółeczku uczy ludzi ignorować liczniki. */
.zakladki button { position: relative; }
.licznik {
  display: inline-grid; place-items: center; min-width: 20px; height: 20px;
  padding: 0 6px; margin-left: 7px; border-radius: 999px;
  background: var(--czerwien); color: #fff;
  font-size: 12px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; vertical-align: 1px;
}

.komunikaty { list-style: none; margin: 4px 0 0; padding: 0;
              display: flex; flex-direction: column; gap: 8px; }
.komunikat { border: 1px solid var(--linia); border-radius: var(--r-s);
             overflow: hidden; background: var(--karta); }
/* Nieprzeczytany ma pionową kreskę w kolorze marki. Wyróżnienie tłem
   dawało listę w dwóch kolorach, na której nie widać już nic innego. */
.komunikat.nowy { border-left: 3px solid var(--granat); }
.komunikat.otwarty { background: var(--karta-2); }
.komunikat > button {
  display: flex; align-items: flex-start; gap: 13px; width: 100%;
  font: inherit; color: inherit; text-align: left; cursor: pointer;
  background: none; border: 0; padding: 14px 14px; min-height: 44px;
}
.komunikat > button:hover { background: var(--karta-2); }
/* Płytka pod logotypem — te same znaki co w stopce, więc ta sama
   zasada: ciemne logo na przezroczystym tle potrzebuje białego podkładu,
   inaczej znika na ciemnym motywie. */
/* Płytka jest PROSTOKĄTNA, bo oba znaki są napisami, a nie sygnetami.
   W kwadracie 42×42 „serwis24" schodziło do wysokości ośmiu pikseli
   i przestawało być logotypem, a zaczynało być plamką. */
.kom-znak { flex: 0 0 auto; width: 78px; height: 40px; border-radius: 8px;
            background: #fff; border: 1px solid var(--linia);
            display: grid; place-items: center; padding: 5px 8px; }
.kom-znak img { max-width: 100%; max-height: 100%; display: block; }
.kom-srodek { flex: 1; min-width: 0; display: grid; gap: 3px; }
.kom-gora { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.kom-nadawca { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em;
               text-transform: uppercase; color: var(--tekst-3); }
.kom-nowy { font-size: var(--fs-xs); font-weight: 700; color: var(--czerwien); }
.kom-tytul { font-weight: 650; line-height: 1.3; }
.kom-data { font-size: var(--fs-xs); color: var(--tekst-3); }
.kom-tresc { padding: 0 14px 16px 105px; color: var(--tekst-2);
             font-size: var(--fs-s); white-space: pre-line; max-width: 78ch; }
@media (max-width: 560px) { .kom-tresc { padding-left: 14px; } }

/* PASEK NAD KARTĄ STANU */
.pasek-kom {
  display: flex; align-items: flex-start; gap: 14px; margin-bottom: 16px;
  border: 1px solid var(--linia); border-left: 4px solid var(--granat);
  border-radius: var(--r); background: var(--karta); box-shadow: var(--cien);
  padding: 16px 18px;
}
.pasek-kom.uwaga { border-left-color: var(--uwaga); }
.pasek-kom.zle   { border-left-color: var(--zle); }
.pasek-kom.ok    { border-left-color: var(--ok); }
.pasek-kom-znak { flex: 0 0 auto; width: 78px; height: 40px; border-radius: 8px;
                  background: #fff; border: 1px solid var(--linia);
                  display: grid; place-items: center; padding: 5px 8px; }
.pasek-kom-znak img { max-width: 100%; max-height: 100%; display: block; }
.pasek-kom-tresc { flex: 1; min-width: 0; }
.pasek-kom-gora { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
                  margin-bottom: 4px; }
.pasek-kom-gora b { font-size: var(--fs-l); }
.pasek-kom-tresc p { color: var(--tekst-2); font-size: var(--fs-s);
                     white-space: pre-line; max-width: 82ch; }
.pasek-kom-zamknij { flex: 0 0 auto; background: none; border: 0; cursor: pointer;
                     font-size: 26px; line-height: 1; color: var(--tekst-3);
                     padding: 0 4px; }
.pasek-kom-zamknij:hover { color: var(--tekst); }

/* =====================================================================
   UŁATWIENIA DOSTĘPU
   =====================================================================
   Trzy niezależne przełączniki na atrybutach korzenia dokumentu. Skala
   pisma jest zmienną, więc powiększenie działa na CAŁY interfejs —
   nagłówki, podpisy, przyciski i odstępy razem. Powiększenie samego
   akapitu bez reszty daje ścianę liter w za ciasnej karcie, czyli coś
   gorszego niż tekst, który był za mały. */
:root[data-tekst="l"] {
  --fs-xs:15px; --fs-s:17px; --fs:18.5px; --fs-l:21.5px;
  --fs-xl:28px; --fs-2xl:36px; --fs-3xl:46px;
}
:root[data-tekst="xl"] {
  --fs-xs:16.5px; --fs-s:18.5px; --fs:20.5px; --fs-l:24px;
  --fs-xl:31px;   --fs-2xl:39px; --fs-3xl:50px;
}
/* Przy powiększonym tekście karty dostają luźniejsze wnętrze, inaczej
   litery zaczynają dotykać ramek. */
:root[data-tekst="l"]  .karta { padding: 22px; }
:root[data-tekst="xl"] .karta { padding: 24px; }
:root[data-tekst="xl"] .kadr { min-height: 520px; }

/* WYŻSZY KONTRAST. Nie zmieniamy marki — dociemniamy to, co jest
   drugorzędne z założenia, i pogrubiamy linie. Nasze szarości są ładne
   na dobrym monitorze i nieczytelne na tanim laptopie pod oknem, a to
   jest sprzęt, na którym ten portal naprawdę będzie otwierany. */
:root[data-kontrast="wysoki"] {
  --tekst-2: #26303f; --tekst-3: #3b4658;
  --linia: #9aa6b8; --linia-2: #c3ccd9;
}
:root[data-kontrast="wysoki"][data-theme="dark"] {
  --tekst-2: #dee5ef; --tekst-3: #bcc6d4;
  --linia: #5d6b80; --linia-2: #465366;
}
:root[data-kontrast="wysoki"] .karta,
:root[data-kontrast="wysoki"] .stan,
:root[data-kontrast="wysoki"] .stopka-w { border-width: 2px; }
:root[data-kontrast="wysoki"] .kafelek { border-width: 2px; }

/* PODKREŚLONE ODNOŚNIKI. Kolor jako jedyny nośnik informacji nie działa
   u ośmiu procent mężczyzn — a tu odnośnik bywa jedyną drogą dalej. */
:root[data-linki="podkreslone"] a,
:root[data-linki="podkreslone"] .jak-link { text-decoration: underline; }

/* OGRANICZONY RUCH — ustawiony ręcznie, niezależnie od systemu. Ktoś
   może mieć w systemie animacje włączone i mimo to nie chcieć ich tutaj. */
:root[data-ruch="mniej"] *,
:root[data-ruch="mniej"] *::before,
:root[data-ruch="mniej"] *::after {
  animation-duration: .001s !important; animation-iteration-count: 1 !important;
  transition-duration: .001s !important; scroll-behavior: auto !important;
}

.dostep-kotwica { position: relative; display: inline-flex; }
.ikonka.wlaczona { border-color: var(--granat); color: var(--granat);
                   background: var(--granat-jasny); }
.dostep-zaslona { position: fixed; inset: 0; z-index: 55; }
.dostep-panel {
  position: absolute; top: calc(100% + 10px); right: 0; z-index: 56;
  width: min(330px, calc(100vw - 32px)); text-align: left;
  background: var(--karta); border: 1px solid var(--linia);
  border-radius: var(--r); box-shadow: var(--cien-2); padding: 18px;
}
.dostep-tytul { font-size: var(--fs-l); font-weight: 700; margin-bottom: 14px; }
.dostep-etykieta { display: block; font-size: var(--fs-s); font-weight: 650;
                   margin-bottom: 8px; }
.dostep-wybor { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.dostep-wybor button {
  font: inherit; cursor: pointer; background: var(--karta-2);
  border: 1.5px solid var(--linia); border-radius: var(--r-s);
  padding: 10px 6px; display: grid; gap: 2px; justify-items: center;
  color: var(--tekst); min-height: 62px;
}
.dostep-wybor button.wybrany { border-color: var(--granat); background: var(--granat-jasny); }
.dostep-wybor .litera { line-height: 1; }
.dostep-wybor .litera.n  { font-size: 15px; }
.dostep-wybor .litera.l  { font-size: 20px; }
.dostep-wybor .litera.xl { font-size: 25px; }
.dostep-wybor span { font-size: var(--fs-xs); color: var(--tekst-2); }
.dostep-przelacznik {
  display: flex; gap: 11px; align-items: flex-start; margin-top: 14px;
  cursor: pointer; padding: 8px; margin-left: -8px; margin-right: -8px;
  border-radius: var(--r-s);
}
.dostep-przelacznik:hover { background: var(--karta-2); }
.dostep-przelacznik input { width: 20px; height: 20px; margin: 2px 0 0; flex: 0 0 auto;
                            accent-color: var(--granat); cursor: pointer; }
.dostep-przelacznik b { display: block; font-size: var(--fs-s); font-weight: 650; }
.dostep-przelacznik small { color: var(--tekst-3); font-size: var(--fs-xs);
                            line-height: 1.4; }
.dostep-stopka { margin-top: 16px; padding-top: 12px;
                 border-top: 1px solid var(--linia-2); }

/* SKOK DO TREŚCI — widoczny dopiero, gdy dostanie ognisko klawiatury. */
.skok-do-tresci {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--granat); color: #fff; padding: 11px 18px;
  border-radius: var(--r-s); font-weight: 650; text-decoration: none;
  transition: top .14s;
}
.skok-do-tresci:focus { top: 12px; }

/* OGNISKO KLAWIATURY — jedna, wyraźna reguła dla całego portalu.
   Dwa piksele w kolorze marki plus odstęp: widać ją na białym, na
   granatowym przycisku i na ciemnym motywie. */
:focus-visible { outline: 3px solid var(--granat-2); outline-offset: 2px;
                 border-radius: 4px; }
:root[data-theme="dark"] :focus-visible { outline-color: #9dc0f0; }

/* =====================================================================
   STOPKA — dwie równe kolumny
   =====================================================================
   Obie firmy dostają ten sam rozmiar, tę samą płytkę z logotypem i tak
   samo duży numer. UNINET stoi pierwszy i ma plakietkę „całą dobę" —
   to wystarczy, żeby o 23:00 człowiek wybrał właściwy telefon, i nie
   wymaga robienia z naszego kontaktu drobnego druku. */
.stopka { max-width: var(--tresc); margin: 0 auto; padding: 0 20px 28px; }
.stopka-w {
  display: grid; grid-template-columns: 1fr 1fr; gap: 24px 36px;
  background: var(--karta); border: 1px solid var(--linia);
  border-radius: var(--r); box-shadow: var(--cien); padding: 24px 28px;
}
@media (max-width: 700px) { .stopka-w { grid-template-columns: 1fr; } }
.stopka-firma + .stopka-firma { border-left: 1px solid var(--linia-2);
                                padding-left: 36px; }
@media (max-width: 700px) {
  .stopka-firma + .stopka-firma { border-left: 0; padding-left: 0;
                                  border-top: 1px solid var(--linia-2);
                                  padding-top: 20px; }
}
/* Płytka pod znakiem — ten sam zabieg co w pasku górnym: oba logotypy
   są ciemne na przezroczystym tle, więc na ciemnym motywie bez białego
   podkładu po prostu znikają. Rozjaśnianie cudzego znaku filtrem CSS
   odpada — to zmiana logo, a nie efekt graficzny. */
.stopka-plytka {
  display: inline-flex; align-items: center; background: #fff;
  border: 1px solid var(--linia); border-radius: var(--r-s);
  padding: 8px 14px; margin-bottom: 12px; height: 44px;
}
.stopka-plytka .znak-uninet { height: 22px; width: auto; display: block; }
.stopka-plytka .znak-s24    { height: 24px; width: auto; display: block; }

.stopka-etykieta { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .09em;
                   text-transform: uppercase; color: var(--tekst-3); }
/* Numer i plakietka w jednym rzędzie z wyrównaniem do środka. Wcześniej
   stały obok siebie jako dwa elementy liniowe o różnym rozmiarze pisma
   i plakietka „siadała" niżej niż cyfry. */
/* Numer, a pod nim plakietka z dostępnością — po obu stronach tak samo.
   Godziny dopisane w linii za numerem czytały się jak przypis, a przy
   UNINET-cie plakietka i tak schodziła do własnego wiersza; dwie kolumny
   wyglądały wtedy na dwie różne rzeczy. */
.stopka-linia-tel { display: flex; flex-direction: column; align-items: flex-start;
                    gap: 8px; margin-top: 8px; }
.stopka-telefon {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: var(--fs-2xl); font-weight: 700; letter-spacing: -.01em;
  font-variant-numeric: tabular-nums; color: var(--granat);
  text-decoration: none; line-height: 1.1;
}
.stopka-telefon:hover { color: var(--granat-2); }
.stopka-telefon svg { width: 26px; height: 26px; flex: 0 0 auto; color: var(--czerwien); }
.stopka-24, .stopka-godziny {
  padding: 4px 12px; border-radius: 999px;
  font-size: var(--fs-xs); font-weight: 650; white-space: nowrap;
}
/* Zielona jest TYLKO całodobowa. To nie jest wyróżnienie UNINET-u
   kosztem nas, tylko informacja: zielone znaczy „zadzwonisz teraz",
   a nasze godziny to fakt neutralny, nie gorszy. Pomalowanie obu na
   zielono zabrałoby tej barwie jedyne znaczenie, jakie tu ma. */
.stopka-24 { background: var(--ok-tlo); color: var(--ok);
             border: 1px solid var(--ok-linia); }
.stopka-godziny { background: var(--karta-2); color: var(--tekst-2);
                  border: 1px solid var(--linia); }
.stopka-drobne { margin-top: 12px; color: var(--tekst-2); font-size: var(--fs-s);
                 line-height: 1.65; }
.stopka-drobne a { color: var(--tekst-2); text-decoration: none;
                   border-bottom: 1px solid var(--linia); }
.stopka-drobne a:hover { color: var(--tekst); border-bottom-color: var(--tekst-3); }
.stopka-kreska { text-align: center; color: var(--tekst-3);
                 font-size: var(--fs-xs); margin-top: 14px; }
.stopka-kreska b { color: var(--tekst-2); font-variant-numeric: tabular-nums; }

/* Ładowanie: zamiast pustej strony — kształt tego, co się pojawi.
   Pusty ekran przez sekundę czyta się jak „nie działa". */
.szkielet { border-radius: var(--r); background: var(--karta-2);
            animation: puls 1.4s ease-in-out infinite; }
@keyframes puls { 0%,100% { opacity: 1 } 50% { opacity: .55 } }
@media (prefers-reduced-motion: reduce) { .szkielet { animation: none } }
/* Szkielet w miejscu jednej wartości — nie cała karta, tylko ta linijka,
   której jeszcze nie znamy. */
.szkielet.w-linii { display: inline-block; width: 5.5ch; height: 1em;
                    vertical-align: -.12em; border-radius: 5px; }

/* CZEKANIE NA ODCZYT Z SIECI.
   Ten sam kształt, co gotowy ekran stanu — po odczycie nic nie skacze.
   Pierścień kręci się wolno i cicho: ma mówić „liczymy", a nie
   „coś się zacięło". */
.stan.czekamy { background: linear-gradient(178deg, var(--karta-2) 0%, var(--karta) 46%); }
.stan.czekamy::before { background: var(--linia); }
.stan.czekamy h1 { color: var(--tekst-2); }
.obrot { width: 26px; height: 26px; border-radius: 50%;
         border: 2.5px solid var(--linia);
         border-top-color: var(--granat); display: block;
         animation: obrot 900ms linear infinite; }
@keyframes obrot { to { transform: rotate(360deg) } }
:root[data-ruch="mniej"] .obrot { animation-duration: 2.4s; }
@media (prefers-reduced-motion: reduce) { .obrot { animation-duration: 2.4s; } }
.stan.czekamy .stan-kropka { background: var(--granat-2);
                             animation: puls 1.4s ease-in-out infinite; }
:root[data-ruch="mniej"] .stan.czekamy .stan-kropka { animation: none; }
@media (prefers-reduced-motion: reduce) {
  .stan.czekamy .stan-kropka { animation: none; }
}

/* =====================================================================
   TELEFON — pasek górny
   =====================================================================
   Zmierzone na 390 px: „Serwis24 | DLA SIECI UNINET" plus trzy przyciski
   dawały 395 px w pasku szerokim na 390 — dopisek marki wchodził pod
   przyciski i był ucięty w połowie słowa.

   Zdejmujemy DOPISEK, nie przyciski. Napis „dla sieci UNINET" jest
   informacją, którą człowiek przeczyta raz w życiu, na ekranie
   logowania; „Wyloguj" jest czynnością, której szuka za każdym razem.
   Sam logotyp Serwis24 zostaje — kolejność marek jest ustaleniem
   i nie znika razem z miejscem. */
@media (max-width: 560px) {
  .pasek-w { gap: 10px; padding: 10px 14px; }
  /* Na wąskim ekranie logotypy schodzą o stopień, zamiast znikać.
     Kolejność marek jest ustaleniem i nie ustępuje miejsca przyciskom
     — ustępuje im rozmiar. */
  .pasek .znak-s24    { height: 18px; }
  .pasek .znak-uninet { height: 15px; }
  .pasek .plytka { padding: 5px 9px; gap: 9px; }
  .pasek-prawo { gap: 6px; }
  .tresc { padding: 16px 14px 48px; }
  .stan { padding: 20px; gap: 14px; }
  .stan h1 { font-size: var(--fs-xl); }
  .stan-znak { width: 44px; height: 44px; }
  .stan-znak svg { width: 22px; height: 22px; }
  .karta { padding: 16px; }
  /* Fakty w dwóch kolumnach zamiast rozjeżdżającego się rzędu — inaczej
     „POŁĄCZONE OD" stoi samo w wierszu, a pod nim para. */
  .fakty { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
  .kody-zapasowe { grid-template-columns: 1fr; }
}

/* =====================================================================
   DIAGNOSTYKA
   ===================================================================== */
.zakladki { display: flex; gap: 2px; background: var(--karta-2);
            border: 1px solid var(--linia); border-radius: var(--r-s); padding: 3px; }
.zakladki button {
  font: inherit; font-size: var(--fs-s); font-weight: 600; cursor: pointer;
  border: 0; background: none; color: var(--tekst-2);
  padding: 7px 13px; border-radius: 6px; min-height: 36px; white-space: nowrap;
}
.zakladki button:hover { color: var(--tekst); }
.zakladki button.wybrana { background: var(--karta); color: var(--tekst); box-shadow: var(--cien); }

.pytanie { font-weight: 650; margin: 22px 0 10px; }
.pytanie:first-of-type { margin-top: 4px; }
.pytanie-opcjonalnie {
  font-weight: 400; font-size: var(--fs-xs); color: var(--tekst-3);
  margin-left: 8px; text-transform: uppercase; letter-spacing: .07em;
}

.wybor { display: grid; gap: 8px; }
.wybor-poz {
  display: flex; gap: 12px; align-items: flex-start; text-align: left; width: 100%;
  background: var(--karta-2); border: 1px solid var(--linia);
  border-radius: var(--r-s); padding: 12px 14px; cursor: pointer;
  font: inherit; color: inherit; min-height: 44px;
}
.wybor-poz:hover { border-color: var(--tekst-3); }
.wybor-poz[aria-pressed="true"] { border-color: var(--granat); background: var(--granat-jasny); }
/* Zaznaczenie niesie KSZTAŁT, nie tylko kolor: wypełnione kółko widać
   także wtedy, gdy ktoś nie odróżnia granatu od szarości. */
.wybor-kolko {
  flex: 0 0 auto; width: 19px; height: 19px; border-radius: 50%;
  border: 1.5px solid var(--linia); margin-top: 2px; display: grid; place-items: center;
}
.wybor-poz[aria-pressed="true"] .wybor-kolko { border-color: var(--granat); background: var(--granat); }
.wybor-poz[aria-pressed="true"] .wybor-kolko::after {
  content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--karta);
}
.wybor-tresc { min-width: 0; }
.wybor-tresc b { display: block; font-weight: 650; }
.wybor-tresc span { display: block; font-size: var(--fs-s); color: var(--tekst-2); margin-top: 1px; }

/* Karty domykające werdykt („co zrobimy my", sam pasek przycisków)
   są zakończeniem ekranu, nie akapitem w środku — stoją w osi. */
.waski .karta.co-zrobimy,
.waski .karta.szeroka:not(.sprzet):not(.predkosc) { text-align: center; }
.waski .karta.co-zrobimy p,
.waski .karta.szeroka:not(.sprzet):not(.predkosc) p { margin-inline: auto; max-width: 64ch; }
.waski .karta.co-zrobimy .akcje,
.waski .karta.szeroka:not(.sprzet):not(.predkosc) .akcje { justify-content: center; }

/* --- test prędkości (widget zewnętrzny) ----------------------------- */
/* MAŁA KARTA, NIE ROZDZIAŁ. Pierwsza wersja miała akapit wstępu i trzy
   rozpisane zastrzeżenia — razem pół ekranu tekstu, który spychał
   wszystko poniżej i przeważał nad rzeczą, o którą chodzi. Zostaje
   jedna linijka, przycisk i zwinięte „dlaczego"; reszta czeka na
   kliknięcie tego, kto zobaczył niski wynik. */
.karta.predkosc { padding-top: 16px; padding-bottom: 14px; }
.predkosc-gora { display: flex; align-items: center; gap: 16px;
                 flex-wrap: wrap; }
.predkosc-slowa { flex: 1 1 240px; min-width: 0; }
.predkosc-slowa .karta-tytul { margin-bottom: 2px; }
.predkosc-lead { color: var(--tekst-2); font-size: var(--fs-s); margin: 0; }

.predkosc-ramka { margin-top: 14px; border: 1px solid var(--linia);
                  border-radius: var(--r); overflow: hidden;
                  background: var(--karta-2); }
.predkosc-ramka iframe { display: block; width: 100%; height: 400px; border: 0;
                         color-scheme: light; }
@media (max-width: 560px) { .predkosc-ramka iframe { height: 470px; } }

/* Zwinięte zastrzeżenia — jedna linijka, dopóki nikt nie zapyta. */
.predkosc-wiecej { margin-top: 10px; }
.predkosc-wiecej > summary { cursor: pointer; list-style: none;
                             display: inline-flex; align-items: center; gap: 6px;
                             font-size: var(--fs-xs); color: var(--tekst-3); }
.predkosc-wiecej > summary::-webkit-details-marker { display: none; }
.predkosc-wiecej > summary::before { content: '▸'; font-size: .85em;
                                     transition: transform .15s; }
.predkosc-wiecej[open] > summary::before { transform: rotate(90deg); }
.predkosc-wiecej > summary:hover { color: var(--tekst-2); }
.predkosc-wiecej ul { list-style: none; margin: 10px 0 0; padding: 0;
                      display: grid; gap: 6px; }
.predkosc-wiecej li { position: relative; padding-left: 14px; max-width: 78ch;
                      font-size: var(--fs-xs); color: var(--tekst-2);
                      line-height: 1.5; }
.predkosc-wiecej li::before { content: ''; position: absolute; left: 0; top: .6em;
                              width: 4px; height: 4px; border-radius: 50%;
                              background: var(--tekst-3); }
.predkosc-wiecej b { font-weight: 650; color: var(--tekst); }
.predkosc-wiecej > p { margin-top: 10px; max-width: 78ch;
                       font-size: var(--fs-xs); color: var(--tekst-3); }

.akcje { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; margin-top: 22px; }
.hint { font-size: var(--fs-s); color: var(--tekst-3); }

/* --- przebieg pomiaru --------------------------------------------- */
/* Ekran pomiaru to jedyny moment, w którym człowiek NIE MA nic do
   zrobienia — tylko czeka. Wszystko idzie więc na środek kadru, w pionie
   i w poziomie. Wcześniej tekst stał w lewym górnym rogu wysokiej karty,
   a pod nim zostawało pół ekranu pustki: wyglądało to, jakby strona się
   zawiesiła w połowie ładowania. */
.kadr.pomiar { align-items: center; justify-content: center; text-align: center;
               gap: 2px; }
.kadr.pomiar h2 { font-size: var(--fs-xl); }
.kadr.pomiar .pomiar-uwaga { max-width: 48ch; }
.pomiar-kafel { text-align: center; }
.tetno {
  width: 56px; height: 56px; margin: 8px auto 16px; border-radius: 50%;
  border: 2px solid var(--granat); display: grid; place-items: center; position: relative;
}
.tetno::after {
  content: ''; position: absolute; inset: -2px; border-radius: 50%;
  border: 2px solid var(--granat); animation: fala 1.6s ease-out infinite; opacity: 0;
}
.tetno i { width: 14px; height: 14px; border-radius: 50%; background: var(--granat); display: block; }
@keyframes fala { 0% { transform: scale(1); opacity: .65 } 100% { transform: scale(1.65); opacity: 0 } }
@media (prefers-reduced-motion: reduce) { .tetno::after { animation: none } }

.pomiar-co { font-weight: 650; }
.pomiar-uwaga { font-size: var(--fs-s); color: var(--tekst-3); margin-top: 14px; }
/* Grubszy i o wyraźniejszym torze — pięciopikselowy pasek w kolorze
   linii ginął na ciemnym motywie, więc jedyną oznaką postępu zostawał
   licznik prób. */
.pasek-postepu { height: 7px; border-radius: 4px; background: var(--karta-2);
                 box-shadow: inset 0 0 0 1px var(--linia);
                 overflow: hidden; margin: 18px auto 4px; width: min(420px, 100%); }
.pasek-postepu i { display: block; height: 100%; background: var(--granat);
                   border-radius: 4px; transition: width .35s ease; }

/* --- wynik --------------------------------------------------------- */
.wynik-plakietki { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; }

/* Sygnał przy przesłance: kolor PLUS kształt. Sam kolor odpada —
   część ludzi nie odróżni zieleni od czerwieni, a to jest lista,
   z której człowiek ma wyczytać, co jest w porządku, a co nie. */
.lista.powody li { align-items: center; }
/* `padding:0` i prefiks `s-` w nazwach modyfikatorów — obie rzeczy
   z powodu kolizji: klasa `.info` jest w tym arkuszu ramką komunikatu
   z własnym paddingiem, więc znacznik `sygnal info` puchł do 30x24
   zamiast 12x12. Kolizja nazw w CSS nie daje żadnego ostrzeżenia. */
.sygnal { flex: 0 0 auto; width: 12px; height: 12px; margin-top: 2px; padding: 0;
          border: 0; background: none; }
.sygnal.s-ok    { border-radius: 50%; background: var(--ok); }
.sygnal.s-uwaga { background: var(--uwaga);
                  clip-path: polygon(50% 0, 100% 100%, 0 100%); }
.sygnal.s-zle   { background: var(--zle); clip-path: polygon(
  20% 0, 80% 0, 100% 20%, 100% 80%, 80% 100%, 20% 100%, 0 80%, 0 20%); }
.sygnal.s-info  { border-radius: 50%; border: 1.5px solid var(--tekst-3); }

.lista.nie-wiemy { margin-top: 10px; }
.lista.nie-wiemy li { background: none; padding: 6px 0; border-top: 1px solid var(--linia-2); }
.co-zrobimy p { color: var(--tekst-2); max-width: 68ch; }

@media (max-width: 560px) {
  .zakladki button { padding: 7px 9px; font-size: var(--fs-xs); }
  .akcje .btn { flex: 1 1 auto; }
}

/* Na telefonie zakładki schodzą do własnego wiersza pod logotypami.
   W jednym rzędzie (logo + trzy zakładki + dwie ikonki + „Wyloguj")
   pasek wystawał kilkanaście pikseli poza ekran i cała strona dawała
   się przesuwać w bok — najbardziej irytująca usterka, jaka może
   spotkać stronę otwieraną na telefonie. */
@media (max-width: 620px) {
  .pasek-w { flex-wrap: wrap; row-gap: 10px; }
  /* Zakładki na własny wiersz i na pełną szerokość — w jednym rzędzie
     (logo + trzy zakładki + dwie ikonki + „Wyloguj") pasek wystawał poza
     ekran i całą stronę dawało się przesuwać w bok. */
  .pasek-w > .zakladki { order: 4; flex: 1 0 100%; }
  .pasek-w > .zakladki button { flex: 1; min-width: 0; }
}

/* =====================================================================
   KREATOR — jedno pytanie na ekranie
   =====================================================================
   Łukasz: „zestawy pytań które pojawiają się po sobie, a nie lista
   w dół — starajmy się wszystko utrzymać na jednym ekranie".

   `min-height` na kadrze jest tu najważniejszą linijką w całym pliku.
   Bez niej karta zmienia wysokość przy każdym pytaniu, strona skacze,
   a przycisk „wróć" ucieka spod kursora. Stała wysokość to różnica
   między aplikacją a formularzem. */

.etapy { display: flex; gap: 0; list-style: none; margin: 0 0 18px; padding: 0; }
.etapy li { flex: 1; min-width: 0; padding-top: 10px;
            border-top: 2px solid var(--linia);
            font-size: var(--fs-xs); letter-spacing: .06em; text-transform: uppercase;
            color: var(--tekst-3); display: flex; align-items: center; gap: 7px; }
.etapy li.zrobione { border-top-color: var(--granat-2); color: var(--tekst-2); }
.etapy li.teraz    { border-top-color: var(--czerwien); color: var(--czerwien); font-weight: 700; }
.etap-kropka { width: 7px; height: 7px; border-radius: 50%; background: var(--linia);
               flex: 0 0 auto; }
.etapy li.zrobione .etap-kropka { background: var(--granat-2); }
.etapy li.teraz .etap-kropka { background: var(--czerwien);
                               box-shadow: 0 0 0 3px color-mix(in srgb, var(--czerwien) 22%, transparent); }

.kreator { padding: 26px 28px; }
/* Ruch obsługuje teraz `.kadr-anim` (kierunek, z prawej albo z lewej) —
   stara animacja na `.kadr` dokładała drugie przejście w tej samej
   klatce i wyglądało to jak drganie. */
.kadr { min-height: 430px; display: flex; flex-direction: column; }
/* Jeden rząd kafli mieści się w niższej karcie; podłoga zostaje po to,
   żeby karta nie skakała między pytaniami, a nie żeby dodawać powietrza. */
@media (min-width: 1100px) { .kreator .kadr { min-height: 360px; } }

.kadr-naglowek { margin-bottom: 20px; }
.kadr-krok { font-size: var(--fs-xs); font-weight: 700; letter-spacing: .12em;
             text-transform: uppercase; color: var(--czerwien); margin-bottom: 6px; }
.kadr h2 { font-size: var(--fs-xl); letter-spacing: -.02em; }
.kadr-pod { color: var(--tekst-2); font-size: var(--fs-s); margin-top: 7px; max-width: 62ch; }
.kadr-stopka { margin-top: auto; padding-top: 18px; display: flex; gap: 14px;
               align-items: center; flex-wrap: wrap; }
.kadr-stopka .btn { margin-left: auto; }
.wstecz { margin-top: auto; padding-top: 18px; align-self: flex-start; }

/* KREATOR CZYTA SIĘ W OSI. Pytanie stoi na środku, kafelki pod nim
   mają treść w tej samej osi — inaczej ikona i tytuł wiszą przy lewej
   krawędzi 450-pikselowego kafla i kolumna wygląda na rozjechaną.
   Dotyczy tylko kreatora: kafelki w innych miejscach (wybór dostępu,
   ustawienia) zostają wyrównane do lewej, bo tam sąsiadują z tekstem
   akapitowym. */
.kreator .kadr-naglowek { text-align: center; }
.kreator .kadr-pod { margin-inline: auto; }
.kreator .kafelek { align-items: center; text-align: center; }
.kreator .kafelek b { text-wrap: balance; }
.kreator .kadr-stopka { justify-content: center; }
.kreator .kadr-stopka .btn { margin-left: 0; }
.kreator .wstecz { align-self: center; margin-top: 18px; }

/* --- kafelki wyboru ------------------------------------------------ */
.kafelki { display: grid; gap: 10px; }
.kafelki.trzy   { grid-template-columns: repeat(3, 1fr); }
.kafelki.cztery { grid-template-columns: repeat(2, 1fr); }
.kafelki.piec   { grid-template-columns: repeat(5, 1fr); }
/* Na pełnej szerokości cztery odpowiedzi stają w jednym rzędzie.
   W dwóch kolumnach każdy kafel miałby 640 px na dwa słowa i pusty
   prostokąt dookoła — to właśnie wyglądało „średnio". */
@media (min-width: 1100px) {
  .kreator .kafelki.cztery { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 900px) {
  .kafelki.trzy, .kafelki.cztery, .kafelki.piec { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 560px) {
  .kafelki.trzy, .kafelki.cztery, .kafelki.piec { grid-template-columns: 1fr; }
}

.kafelek {
  display: flex; flex-direction: column; align-items: flex-start; gap: 4px;
  text-align: left; font: inherit; color: inherit; cursor: pointer;
  background: var(--karta-2); border: 1.5px solid var(--linia);
  border-radius: var(--r); padding: 16px 16px 15px; min-height: 118px;
  transition: border-color .14s, background .14s, transform .14s;
}
.kafelek:hover { border-color: var(--granat-2); transform: translateY(-2px); }
.kafelek.wybrany { border-color: var(--czerwien);
                   background: color-mix(in srgb, var(--czerwien) 6%, var(--karta)); }
.kafelek b { font-weight: 650; font-size: var(--fs); line-height: 1.25; }
.kafelek span:not(.kafelek-ikona) { font-size: var(--fs-s); color: var(--tekst-2); }
.kafelek.maly { min-height: 104px; padding: 13px; }
.kafelek.maly b { font-size: var(--fs-s); }
.kafelek.maly span:not(.kafelek-ikona) { font-size: var(--fs-xs); }
.kafelek-ikona { width: 34px; height: 34px; border-radius: 9px; margin-bottom: 6px;
                 display: grid; place-items: center; flex: 0 0 auto;
                 background: var(--granat-jasny); color: var(--granat); }
.kafelek-ikona svg { width: 19px; height: 19px; }
.kafelek.wybrany .kafelek-ikona { background: var(--czerwien); color: #fff; }

.pole.uwagi { margin-top: 16px; }
.pole.uwagi em { font-style: normal; font-weight: 400; color: var(--tekst-3);
                 text-transform: uppercase; font-size: var(--fs-xs); letter-spacing: .07em;
                 margin-left: 6px; }
textarea { resize: vertical; min-height: 62px; }

/* =====================================================================
   ONT — czarne pudełko przy ścianie
   =====================================================================
   Diody świecą i mrugają jak w rzeczywistości, bo człowiek ma porównać
   obrazek z urządzeniem stojącym u niego na półce, a nie z opisem.
   Czerwony alarm mruga — dokładnie tak zachowuje się dioda LOS. */
.ont { display: flex; justify-content: center; margin: 4px 0 20px; }
.ont-korpus {
  background: linear-gradient(168deg, #2b3550 0%, #131a2c 100%);
  border: 1px solid #3b4763; border-radius: 12px;
  padding: 15px 26px 14px;
  box-shadow: inset 0 1px 0 #454f6c, 0 10px 26px -14px rgba(0,0,0,.8);
}
.ont-marka { font-size: 9.5px; font-weight: 800; letter-spacing: .3em;
             color: #8892ac; margin-bottom: 12px; }
.ont-diody { display: flex; gap: 22px; }
.dioda { display: flex; flex-direction: column; align-items: center; gap: 7px; }
.dioda i { width: 11px; height: 11px; border-radius: 50%; background: #4a5470; display: block; }
.dioda b { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
           font-size: 8.5px; letter-spacing: .1em; color: #8892ac; font-weight: 500; }
.dioda.green i { background: #31be84; box-shadow: 0 0 10px rgba(49,190,132,.9); }
.dioda.red i { background: #f04a38; box-shadow: 0 0 10px rgba(240,74,56,.95);
               animation: mrug 1.1s steps(1, end) infinite; }
@keyframes mrug { 50% { opacity: .22 } }
@media (prefers-reduced-motion: reduce) { .dioda.red i { animation: none } }

.ont.male { margin: 0 0 10px; justify-content: flex-start; }
.ont.male .ont-korpus { padding: 9px 13px 8px; border-radius: 8px; }
.ont.male .ont-marka { font-size: 7px; letter-spacing: .22em; margin-bottom: 7px; }
.ont.male .ont-diody { gap: 11px; }
.ont.male .dioda i { width: 7px; height: 7px; }
.ont.male .dioda b { display: none; }
.diody-wybor .kafelek { min-height: 128px; }

/* =====================================================================
   CIEMNY MOTYW — poprawki kontrastu
   =====================================================================
   Dwa miejsca były narysowane pod jasne tło i w ciemnym znikały.

   1. ONT. To jest CZARNE pudełko — na białej stronie czyta się samo,
      na ciemnej zlewa się z kartą i zostaje po nim prostokątny cień.
      Nie rozjaśniamy go do szarości (przestałby być tym urządzeniem,
      które człowiek ma na półce) — dodajemy rant i poświatę, czyli to,
      co w rzeczywistości oddziela czarny sprzęt od ciemnej ściany.

   2. Podkładka pod ikonami kafelków. Miała ton o krok jaśniejszy od
      karty, co w jasnym motywie wystarcza, a w ciemnym daje różnicę
      kilku punktów jasności — ikona wisiała w powietrzu i wyglądała
      jak ciemna plamka na ciemnym tle. */
:root[data-theme="dark"] .ont-korpus {
  background: linear-gradient(168deg, #3a4767 0%, #1a2236 100%);
  border-color: #5a6890;
  box-shadow: inset 0 1px 0 #6b779f, 0 0 0 1px rgba(0,0,0,.55),
              0 16px 34px -14px rgba(0,0,0,.95);
}
:root[data-theme="dark"] .ont-marka { color: #b3bdd6; }
:root[data-theme="dark"] .dioda b   { color: #aab4cd; }
/* Tylko diody ZGASZONE — bez :not() ta reguła wygrywała specyficznością
   z .dioda.green i gasiła wszystkie kontrolki na ciemnym motywie. */
:root[data-theme="dark"] .dioda:not(.green):not(.red) i { background: #626d8c; }

:root[data-theme="dark"] .kafelek-ikona {
  background: #22324f; color: #bdd5f7; box-shadow: inset 0 0 0 1px #35486d;
}
:root[data-theme="dark"] .kafelek.wybrany .kafelek-ikona {
  box-shadow: none; color: #fff;
}
/* Znak stanu „nie wiemy" siedział na --karta-2, czyli praktycznie na
   kolorze karty — bez obwódki wyglądał jak brak ikony. */
/* Znak stanu: grubsza kreska i delikatny rant. Ta sama ikona, która
   na białym tle jest wyrazista, na ciemnym potrzebuje pół piksela
   więcej — inaczej czyta się jak plamka, a nie jak wykrzyknik. */
:root[data-theme="dark"] .stan-znak svg { stroke-width: 2.1; }
/* Sam znak jaśniejszy niż kolor stanu w tekście. To nie jest
   niekonsekwencja: napis „brak połączenia" to kilkadziesiąt pikseli
   wypełnienia, a wykrzyknik — kilka cienkich kresek. Przy tej samej
   barwie napis czyta się dobrze, a ikona ledwo. */
:root[data-theme="dark"] .stan.brak-polaczenia .stan-znak { color: #ff9b95; }
:root[data-theme="dark"] .stan.do-odswiezenia  .stan-znak { color: #f2c274; }
:root[data-theme="dark"] .stan.dziala          .stan-znak { color: #6fd6a4; }
:root[data-theme="dark"] .stan-znak {
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 28%, transparent);
}
:root[data-theme="dark"] .stan.nieznany .stan-znak {
  box-shadow: inset 0 0 0 1px var(--linia);
}
:root[data-theme="dark"] .faq-nr { border-color: var(--granat-2); color: var(--granat-2); }

/* =====================================================================
   FAQ I BRAMKA
   ===================================================================== */
.faq-wstep { color: var(--tekst-2); font-size: var(--fs-s); margin-bottom: 12px; }
.ptaszek-mini { display: inline-flex; align-items: center; gap: 5px; margin-left: 10px;
                color: var(--ok); text-transform: none; letter-spacing: 0; font-weight: 600; }
.ptaszek-mini svg { width: 13px; height: 13px; stroke-width: 3; }

.faq { list-style: none; margin: 0; padding: 0; display: flex;
       flex-direction: column; gap: 2px; }
.faq li { border-radius: var(--r-s); overflow: hidden; }
.faq li.otwarte { background: var(--karta-2); }
.faq button { display: flex; align-items: center; gap: 12px; width: 100%;
              font: inherit; color: inherit; text-align: left; cursor: pointer;
              background: none; border: 0; padding: 12px 12px; min-height: 44px; }
.faq button:hover { background: var(--karta-2); }
.faq-nr { flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
          border: 1px solid var(--granat); color: var(--granat);
          display: grid; place-items: center; font-size: var(--fs-xs); font-weight: 700; }
/* Przeczytana pozycja dostaje ptaszka zamiast numeru — warunek bramki
   wymaga kompletu, więc widać, czego jeszcze brakuje. */
.faq-nr.widziane { background: var(--ok); border-color: var(--ok); color: #fff; }
.faq-nr.widziane svg { width: 12px; height: 12px; stroke-width: 3; }
.licznik-faq { margin-left: 10px; text-transform: none; letter-spacing: 0;
               font-weight: 600; color: var(--tekst-3); }
.faq-p { flex: 1; font-weight: 600; }
.faq-strzalka { flex: 0 0 auto; width: 9px; height: 9px; border-right: 2px solid var(--tekst-3);
                border-bottom: 2px solid var(--tekst-3); transform: rotate(45deg);
                margin-top: -4px; transition: transform .16s; }
.faq li.otwarte .faq-strzalka { transform: rotate(225deg); margin-top: 3px; }
/* `pre-line` — dłuższe odpowiedzi mają akapity, a nie jedną ścianę
   tekstu. Puste linie w treści stają się przerwami, reszta zawija się
   normalnie. */
.faq-o { padding: 0 12px 14px 46px; color: var(--tekst-2); font-size: var(--fs-s);
         max-width: 78ch; white-space: pre-line; }

/* Bramka mieszka teraz w wąskiej szynie, więc układa się w pionie —
   dawny podział „opis | przycisk" rozjeżdżał się przy 300 pikselach. */
.brama { display: flex; flex-direction: column; gap: 16px;
         background: var(--karta); border: 1px solid var(--linia);
         border-left: 3px solid var(--linia-2);
         border-radius: var(--r); box-shadow: var(--cien); padding: 20px 22px; }
.brama.otwarta { border-left-color: var(--czerwien); }
.brama-opis { color: var(--tekst-2); font-size: var(--fs-s); max-width: 62ch; }
.brama-warunki { list-style: none; margin: 14px 0 0; padding: 0;
                 display: flex; flex-direction: column; gap: 8px; }
.brama-warunki li { display: flex; align-items: center; gap: 10px;
                    font-size: var(--fs-s); color: var(--tekst-2); }
.brama-warunki .ptaszek { width: 20px; height: 20px; border-radius: 50%; flex: 0 0 auto;
                          border: 1.5px solid var(--linia); display: grid; place-items: center;
                          color: transparent; }
.brama-warunki .ptaszek svg { width: 12px; height: 12px; stroke-width: 3; }
.brama-warunki li.ok .ptaszek { background: var(--ok); border-color: var(--ok); color: #fff; }
.brama-warunki li.ok { color: var(--tekst); }
.brama-po { border-top: 1px solid var(--linia-2); padding-top: 14px;
             color: var(--tekst-2); font-size: var(--fs-s); display: grid; gap: 8px; }
.brama-telefon a { color: var(--granat); font-weight: 700; text-decoration: none;
                   font-variant-numeric: tabular-nums; }
.brama-telefon a:hover { text-decoration: underline; }
.brama-akcja { display: flex; flex-direction: column; gap: 8px; align-items: stretch; }
/* Jedna decyzja dla całej szyny: przyciski akcji idą na pełną szerokość
   karty. Wcześniej jeden był dopasowany do napisu, a drugi rozciągnięty —
   dwie karty jedna pod drugą, dwie różne zasady, i widać to od razu. */
.brama-akcja .btn, .pulpit-prawa .karta .btn { width: 100%; }
.awaryjne { font-size: var(--fs-xs); color: var(--tekst-3); text-align: center; }

.zacheta p { color: var(--tekst-2); font-size: var(--fs-s); margin-bottom: 14px; }
.zacheta-wynik { margin-top: 12px; font-size: var(--fs-s); color: var(--tekst-2); }
.sprzet p { color: var(--tekst-2); max-width: 74ch; margin-bottom: 14px; }

/* =====================================================================
   RUCH
   =====================================================================
   Zasada jedna: animacja ma POTWIERDZAĆ, że kliknięcie zadziałało,
   i pokazywać, w którą stronę idziemy. Nic tu nie ozdabia i nic nie
   trwa dłużej niż jedna trzecia sekundy — przy kimś, kto właśnie stracił
   internet, każda animacja dłuższa od tego jest po prostu czekaniem.

   Wszystko siedzi w `prefers-reduced-motion: no-preference`, więc kto ma
   w systemie ograniczony ruch (a to bywa kwestia zdrowia, nie gustu),
   dostaje tę samą stronę bez jednego przesunięcia. */
@media (prefers-reduced-motion: no-preference) {
  @keyframes wjazd-prawo { from { opacity: 0; transform: translateX(22px); } }
  @keyframes wjazd-lewo  { from { opacity: 0; transform: translateX(-22px); } }
  @keyframes wjazd-dol   { from { opacity: 0; transform: translateY(12px); } }
  @keyframes puls-wyboru { 50% { transform: scale(.975); } }

  /* Pytania kreatora: do przodu z prawej, „Wróć" z lewej. */
  .kadr-anim.dalej  { animation: wjazd-prawo .26s cubic-bezier(.2,.7,.3,1) both; }
  .kadr-anim.wstecz { animation: wjazd-lewo  .26s cubic-bezier(.2,.7,.3,1) both; }

  /* Zakładki portalu. Krócej niż kreator, bo tu nie ma kierunku —
     zmiana ekranu to podmiana, nie ruch naprzód. */
  .ekran-anim { animation: wjazd-dol .22s ease-out both; }

  /* Kafelki i karty wchodzą kaskadą. Opóźnienia są malutkie: chodzi
     o wrażenie, że treść się układa, a nie o pokaz. Piąty kafelek
     rusza 60 ms po pierwszym — tego się nie liczy, to się czuje. */
  .kadr-anim .kafelek { animation: wjazd-dol .24s ease-out both; }
  .kadr-anim .kafelek:nth-child(2) { animation-delay: .04s; }
  .kadr-anim .kafelek:nth-child(3) { animation-delay: .08s; }
  .kadr-anim .kafelek:nth-child(4) { animation-delay: .11s; }
  .kadr-anim .kafelek:nth-child(5) { animation-delay: .14s; }

  .ekran-anim .siatka > *, .ekran-anim .pulpit > * > * {
    animation: wjazd-dol .26s ease-out both; }
  .ekran-anim .pulpit-lewa > *:nth-child(2),
  .ekran-anim .siatka > *:nth-child(2) { animation-delay: .05s; }
  .ekran-anim .pulpit-prawa > *:nth-child(2) { animation-delay: .05s; }

  /* Potwierdzenie kliknięcia. Kafelek wybrany na moment się „ugina",
     a dopiero potem kreator przechodzi dalej — to te 260 ms opóźnienia,
     które i tak już były w kodzie, tylko wcześniej nie było ich widać. */
  .kafelek:active { transform: scale(.985); }
  .kafelek.wybrany { animation: puls-wyboru .22s ease-out; }

  /* Odpowiedź w FAQ zsuwa się, zamiast wyskakiwać. */
  .faq li.otwarte .faq-o { animation: wjazd-dol .2s ease-out both; }

  /* Panel czatu wjeżdża z rogu, w którym stoi guzik. */
  @keyframes wjazd-czat { from { opacity: 0; transform: translateY(14px) scale(.98); } }
  .nora-panel { animation: wjazd-czat .24s cubic-bezier(.2,.7,.3,1) both; }
  .nora-msg { animation: wjazd-dol .22s ease-out both; }
}

/* Pasek postępu pomiaru i kropki etapów jadą płynnie w obie strony —
   to przejścia, nie animacje, więc działają też przy ograniczonym ruchu
   (nic tu nie „lata", zmienia się tylko szerokość i kolor). */
.pasek-postepu i { transition: width .35s ease; }
.etapy li .etap-kropka { transition: background .25s ease, transform .25s ease; }
.etapy li.teraz .etap-kropka { transform: scale(1.35); }

/* =====================================================================
   CZAT Z NORĄ
   ===================================================================== */
.nora-guzik {
  position: fixed; right: 20px; bottom: 20px; z-index: 40;
  display: flex; align-items: center; gap: 11px; cursor: pointer;
  background: var(--karta); border: 1px solid var(--linia); border-radius: 999px;
  padding: 8px 20px 8px 8px; box-shadow: var(--cien-2); font: inherit; color: inherit;
  transition: transform .16s;
}
.nora-guzik:hover { transform: translateY(-2px); }
.nora-guzik img { width: 40px; height: 40px; border-radius: 50%; object-fit: cover;
                  flex: 0 0 auto; }
.nora-guzik b { display: block; font-size: var(--fs-s); text-align: left; }
.nora-guzik small { display: block; font-size: var(--fs-xs); color: var(--tekst-3); }

/* Czat startuje ROZWINIĘTY, ale zostaje zwykłą nakładką w rogu —
   Łukasz, 07.09.2026: „chciałem, żeby automatycznie był rozwinięty, ale
   w formie takiej jak było wcześniej". Wersja dokowana odsuwała całą
   stronę w lewo przy każdym otwarciu i zwinięciu, co przy panelu
   otwierającym się samo z siebie znaczyło, że strona skacze zaraz po
   wejściu. */
.nora-panel {
  position: fixed; right: 20px; bottom: 20px; z-index: 50;
  width: 390px; max-width: calc(100vw - 32px);
  max-height: min(640px, calc(100vh - 40px));
  background: var(--karta); border: 1px solid var(--linia); border-radius: 14px;
  box-shadow: var(--cien-2); display: flex; flex-direction: column; overflow: hidden;
}
.nora-glowa { display: flex; align-items: center; gap: 11px; padding: 12px 14px;
              border-bottom: 1px solid var(--linia); background: var(--karta-2); }
.nora-glowa img { width: 36px; height: 36px; border-radius: 50%; object-fit: cover; }
.nora-kto b { display: block; font-size: var(--fs-s); }
.nora-stan { display: flex; align-items: center; gap: 6px; font-size: var(--fs-xs);
             color: var(--tekst-3); }
.nora-stan i { width: 6px; height: 6px; border-radius: 50%; background: var(--ok); }
.nora-zamknij { margin-left: auto; background: none; border: 0; cursor: pointer;
                font-size: 24px; line-height: 1; color: var(--tekst-3); padding: 0 6px; }
.nora-zamknij:hover { color: var(--tekst); }

.nora-wiadomosci { flex: 1; overflow-y: auto; padding: 16px 14px;
                   display: flex; flex-direction: column; gap: 13px; }
.nora-msg { display: flex; gap: 9px; align-items: flex-start; }
.nora-msg.moja { justify-content: flex-end; }
.nora-mini { width: 26px; height: 26px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.nora-dymek { background: var(--granat-jasny); border: 1px solid var(--linia);
              border-radius: 4px 12px 12px 12px; padding: 10px 13px;
              font-size: var(--fs-s); color: var(--tekst); max-width: 280px; }
.nora-msg.moja .nora-dymek { background: var(--czerwien); border-color: var(--czerwien);
                             color: #fff; border-radius: 12px 4px 12px 12px; }
.nora-pisze { display: flex; gap: 4px; padding: 13px; }
.nora-pisze i { width: 6px; height: 6px; border-radius: 50%; background: var(--granat);
                display: block; animation: skacz 1.2s infinite; }
.nora-pisze i:nth-child(2) { animation-delay: .18s }
.nora-pisze i:nth-child(3) { animation-delay: .36s }
@keyframes skacz { 0%, 60%, 100% { opacity: .28 } 30% { opacity: 1 } }
@media (prefers-reduced-motion: reduce) { .nora-pisze i { animation: none; opacity: .6 } }

.nora-podpowiedzi { display: flex; flex-wrap: wrap; gap: 6px; padding: 0 14px 12px; }
.nora-podpowiedzi button { background: var(--karta-2); border: 1px solid var(--linia);
                           border-radius: 999px; padding: 6px 12px; font: inherit;
                           font-size: var(--fs-xs); color: var(--tekst-2); cursor: pointer; }
.nora-podpowiedzi button:hover { border-color: var(--granat); color: var(--granat); }

.nora-pisanie { display: flex; gap: 8px; padding: 12px 14px;
                border-top: 1px solid var(--linia); background: var(--karta-2); }
.nora-pisanie input { flex: 1; min-height: 40px; }
.nora-pisanie .btn { min-height: 40px; }

@media (max-width: 560px) {
  .nora-panel { right: 0; left: 0; bottom: 0; width: 100vw; max-width: 100vw;
                border-radius: 14px 14px 0 0; max-height: 86vh; }
  .nora-guzik { right: 14px; bottom: 14px; padding: 7px 16px 7px 7px; }
  .kreator { padding: 18px 16px; }
  .kadr { min-height: 380px; }
  .etapy li { font-size: 0; padding-top: 8px; }
  .etapy .etap-kropka { margin: 0 auto; }
}

/* Ikona w przycisku paska górnego (odświeżenie, motyw). */
.ikonka svg { width: 17px; height: 17px; }

/* =====================================================================
   TWOJE URZĄDZENIE
   =====================================================================
   Rysunek stoi na własnej płycie, a nie wprost na karcie. Powód jest
   praktyczny: korpus routera ma stałe kolory (to przedmiot, nie element
   interfejsu), więc czarny router na białej karcie i biały router na
   ciemnej karcie wyglądałyby jak dwie różne jakości rysunku. Płyta
   w kolorze tła daje jednemu i drugiemu to samo otoczenie.
   ===================================================================== */
.urzadzenie .urz-glowa {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}
.urz-obraz {
  background: var(--karta-2);
  border: 1px solid var(--linia);
  border-radius: var(--r);
  padding: 10px;
  aspect-ratio: 5 / 4;
  display: flex; align-items: center; justify-content: center;
}
.urz-obraz img { max-width: 100%; max-height: 100%; object-fit: contain; }
.urz-nazwa {
  font-size: var(--fs-l);
  font-weight: 650;
  letter-spacing: -.01em;
  margin-bottom: 6px;
}
.urz-podtytul {
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--tekst-3);
  margin-bottom: 8px;
}
dl.urz-dane {
  display: grid;
  grid-template-columns: minmax(120px, auto) minmax(0, 1fr);
  gap: 4px 14px;
  margin: 10px 0 0;
}
dl.urz-dane dt { color: var(--tekst-3); font-size: var(--fs-s); }
dl.urz-dane dd { margin: 0; font-size: var(--fs-s); font-weight: 550; }
dl.urz-dane dd.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
                      font-weight: 500; }

.urz-wifi, .urz-lacze {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--linia-2);
}
.urz-wifi ul { list-style: none; margin: 0; padding: 0;
               display: flex; flex-wrap: wrap; gap: 8px; }
.urz-wifi li { display: flex; align-items: center; gap: 8px; }
.urz-ssid {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--granat-jasny);
  color: var(--granat);
  border-radius: var(--r-s);
  padding: 5px 10px;
  font-size: var(--fs-s);
}
.urz-uwaga { color: var(--tekst-3); font-size: var(--fs-s); margin: 10px 0 0; }

@media (max-width: 560px) {
  .urzadzenie .urz-glowa { grid-template-columns: 1fr; }
  .urz-obraz { max-width: 180px; }
}

/* Na ciemnym motywie płyta pod rysunkiem musi być JAŚNIEJSZA od karty,
   inaczej czarny router znika w czarnym prostokącie. */
:root[data-theme="dark"] .urz-obraz { background: #161c27; }
:root[data-theme="dark"] .urz-ssid { background: #1b2b45; color: #b9d0f0; }

/* Kolory rysowanego urządzenia. Dwa zestawy, bo router bywa czarny albo
   biały — i cztery, bo na ciemnym motywie jedno i drugie musi się
   odcinać od płyty. Czarny korpus na ciemnym tle rozjaśniamy: rysunek
   ma pokazać KSZTAŁT, a wierność koloru przy nieczytelnym kształcie
   nie jest nic warta. */
.rys-routera.ciemny { --urz-korpus:#252a34; --urz-krawedz:#12151c; --urz-panel:#171b23; }
.rys-routera.jasny  { --urz-korpus:#e9edf4; --urz-krawedz:#c3ccda; --urz-panel:#d5dce7; }
:root[data-theme="dark"] .rys-routera.ciemny {
  --urz-korpus:#3d4658; --urz-krawedz:#8a97ad; --urz-panel:#2a3140;
}
:root[data-theme="dark"] .rys-routera.jasny {
  --urz-korpus:#dfe4ec; --urz-krawedz:#9aa5b8; --urz-panel:#c3ccda;
}

/* Logotypy bez płytki — na ciemnym tle ekranu wejścia. Biała naklejka
   sprowadzała dwa logotypy do roli znaczka w rogu; tutaj mają być
   pierwszą rzeczą, którą widać. */
.plytka.bez-tla { background: none; border: 0; box-shadow: none; padding: 0; }
.plytka.bez-tla .plytka-kreska { background: var(--linia); }
/* LOGOTYPY SKALUJĄ SIĘ Z SZEROKOŚCIĄ PANELU.
   Łukasz, 07.09.2026: „ZDECYDOWANIE myślę, że możemy te nasze loga
   powiększyć DUŻO WIĘCEJ". Stała wysokość w pikselach zawsze będzie
   albo za mała na monitorze, albo za duża na laptopie — `clamp` rośnie
   razem z panelem i zatrzymuje się, zanim lockup dotknie krawędzi.
   Proporcja 46:40 zachowana z oryginalnych plików, żeby żaden znak nie
   dominował nad drugim: „prezentowane na równi". */
.marka.duza .znak-s24    { height: clamp(40px, 5.2vw, 96px); }
.marka.duza .znak-uninet { height: clamp(35px, 4.5vw, 83px); }
.marka.duza .plytka { gap: clamp(16px, 2vw, 34px); }
/* Lockup nie może dotknąć krawędzi panelu przy najszerszym stopniu. */
.marka.duza { max-width: 100%; }
.marka.duza .plytka { max-width: 100%; }


/* Rozliczenia */
/* --- rozliczenia ---------------------------------------------------- */
/* Kwota w panelu, nie na gołym tle. Ten sam język, co karta stanu łącza:
   listwa w kolorze, nadtytuł z kropką, liczba, zdanie wyjaśnienia. */
.karta.rozliczenia .fakty { margin-top: 18px; }
.saldo { position: relative; overflow: hidden; text-align: center;
         margin-top: 12px; padding: 22px 20px 20px;
         border: 1px solid var(--linia); border-radius: var(--r);
         background: var(--karta-2); }
.saldo::before { content: ''; position: absolute; inset: 0 0 auto; height: 3px;
                 background: var(--tekst-3); }
/* ZALEGŁOŚĆ NA CZERWONO — decyzja Łukasza, 07.09.2026.
   Sam panel zostaje stonowany (delikatny gradient, cienka listwa),
   bo czerwone tło całej karty wyglądałoby jak alarm o awarii. Krzyczy
   sama kwota — i to wystarczy, żeby nie dało się jej przeoczyć. */
.rozliczenia.zaplac .saldo { background: linear-gradient(178deg, var(--zle-tlo) 0%, var(--karta-2) 62%);
                             border-color: var(--zle-linia); }
.rozliczenia.zaplac .saldo::before { background: var(--zle); }
.rozliczenia.ok .saldo { background: linear-gradient(178deg, var(--ok-tlo) 0%, var(--karta-2) 62%);
                         border-color: var(--ok-linia); }
.rozliczenia.ok .saldo::before { background: var(--ok); }

.saldo-nad { display: inline-flex; align-items: center; gap: 8px;
             font-size: var(--fs-xs); text-transform: uppercase;
             letter-spacing: .09em; font-weight: 650; color: var(--tekst-3);
             margin-bottom: 8px; }
.saldo-kropka { width: 8px; height: 8px; border-radius: 50%;
                background: var(--tekst-3); flex: 0 0 auto; }
.rozliczenia.zaplac .saldo-kropka { background: var(--zle); }
.rozliczenia.ok     .saldo-kropka { background: var(--ok); }

/* Kwota i waluta w jednej linii bazowej: „zł" mniejsze i lżejsze, bo
   niesie zero informacji — cała treść jest w liczbie. */
.saldo-kwota { display: flex; align-items: baseline; justify-content: center;
               gap: 8px; line-height: 1; }
.saldo-liczba { font-size: var(--fs-3xl); font-weight: 700; letter-spacing: -.03em;
                font-variant-numeric: tabular-nums; }
.saldo-jedn { font-size: var(--fs-l); font-weight: 600; color: var(--tekst-3); }
.rozliczenia.zaplac .saldo-liczba { color: var(--zle); }
.rozliczenia.ok     .saldo-liczba { color: var(--ok); }
.saldo-pod { margin: 10px auto 0; max-width: 46ch;
             font-size: var(--fs-s); color: var(--tekst-2); line-height: 1.5; }
.saldo-kopiuj { margin-top: 14px; }
/* Numer konta jest długi — niech ma tyle miejsca, ile potrzebuje. */
.fakty > div.fakt-konto { flex: 2 1 0; }
.fakty dd.mono { overflow-wrap: anywhere; }
dl.urz-dane.szeroka { grid-template-columns: minmax(140px, auto) minmax(0, 1fr); }

/* Historia zgłoszeń abonenta */
.zgl-lista { list-style: none; margin: 0; padding: 0;
             display: flex; flex-direction: column; gap: 2px; }
.zgl-lista li { display: grid; grid-template-columns: auto 1fr auto; gap: 12px;
                align-items: center; padding: 11px 12px; border-radius: var(--r-s);
                background: var(--karta-2); }
.zgl-nr { font-weight: 650; }
.zgl-kiedy { color: var(--tekst-2); font-size: var(--fs-s); }
@media (max-width: 520px) {
  .zgl-lista li { grid-template-columns: 1fr auto; }
  .zgl-kiedy { grid-column: 1 / -1; }
}

/* Prośba o opinię — dwie firmy, dwa kody */
.opinie-wstep { color: var(--tekst-2); font-size: var(--fs-s); margin: 0 0 16px; }
.opinie-kafle { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
.opinia-kafel {
  flex: 1 1 150px; max-width: 200px; display: flex; flex-direction: column;
  align-items: center; gap: 6px; padding: 14px; border-radius: var(--r);
  border: 1px solid var(--linia); background: var(--karta-2);
  text-decoration: none; color: inherit;
}
.opinia-kafel:hover { border-color: var(--granat-2); }
.opinia-kafel img { width: 116px; height: 116px; display: block; background: #fff;
                    border-radius: var(--r-s); padding: 5px; }
.opinia-bezqr { width: 116px; height: 116px; display: grid; place-items: center;
                border-radius: var(--r-s); background: var(--granat-jasny);
                color: var(--granat); font-weight: 650; }
.opinia-nazwa { font-weight: 650; }
.opinia-pod { font-size: var(--fs-xs); color: var(--tekst-3); }


/* =====================================================================
   ROZLICZENIA — DWIE KOLUMNY
   =====================================================================
   Łukasz, 07.09.2026: „taki szeroki kafel na jedną fakturę? Nie możemy
   tego zwęzić, a wtedy z prawej strony zmieścimy widget z umowami
   i usługą?".

   Faktura niesie cztery dane. Rozciągnięta na 1320 px zostawiała dwie
   trzecie pustego pola, więc lista dziesięciu faktur wyglądała jak
   dziesięć ekranów. Teraz faktury dostają kolumnę czytelnej szerokości,
   a bok — rzeczy, które czyta się raz: usługi i umowy.

   Bok ma STAŁĄ szerokość, a faktury biorą resztę. Odwrotnie (obie po
   `1fr`) numer faktury łamałby się na dwa wiersze na laptopie, bo bok
   zabierałby połowę na trzy linijki tekstu.
   ===================================================================== */
.rozl { display: flex; flex-direction: column; gap: var(--s4, 18px); }
.rozl-kolumny { display: grid; gap: var(--s4, 18px); align-items: stretch;
                grid-template-columns: minmax(0, 1fr) 340px; }

/* OBIE KOLUMNY KOŃCZĄ SIĘ NA TEJ SAMEJ WYSOKOŚCI.
   Łukasz, 07.09.2026: „chodziło mi o to, żeby okienko z fakturami
   wyrównać z dołem okienka z umowami".

   `align-items: stretch` wyrównuje wysokość KOLUMN, ale to za mało:
   prawa kolumna to trzy osobne karty w pionie, więc rozciągnięcie
   opakowania zostawiłoby pustkę POD ostatnią kartą zamiast jej
   przedłużyć. Dlatego nadmiar wysokości pochłania ostatnia karta
   z boku (`flex: 1`) — i to ona kończy się równo z fakturami,
   niezależnie od tego, która kolumna akurat jest dłuższa.

   Karta faktur też musi być kolumną flex: bez tego jej zawartość
   trzyma się góry, ale samo pudełko nie rozciąga się do dołu
   i wyrównanie działa tylko w jedną stronę. */
.rozl-kolumny > .karta { display: flex; flex-direction: column; height: 100%; }
/* Karta stała się kolumną flex, więc jej dzieci domyślnie rozciągają
   się na całą szerokość — przycisk „Pokaż starsze faktury" urósł przez
   to na cały wiersz i zaczął wyglądać jak stopka listy, a nie jak
   przycisk. Wracamy mu jego szerokość. */
.rozl-kolumny > .karta > .btn { align-self: flex-start; }
.rozl-bok { display: flex; flex-direction: column; gap: var(--s4, 18px); }
.rozl-bok > .karta:last-child { flex: 1 1 auto; }
/* Poniżej 1080 px bok pod fakturami — kolumna 340 px obok wąskiej
   listy faktur to już dwie wąskie kolumny zamiast jednej czytelnej. */
@media (max-width: 1080px) {
  .rozl-kolumny { grid-template-columns: minmax(0, 1fr); }
  /* W jednej kolumnie nie ma czego wyrównywać — rozciąganie ostatniej
     karty zrobiłoby wtedy tylko pustą przestrzeń na końcu strony. */
  .rozl-kolumny > .karta { height: auto; }
  .rozl-bok > .karta:last-child { flex: 0 0 auto; }
}

/* --- FAKTURA -------------------------------------------------------
   Dwie kolumny w wierszu: treść i liczby. Liczby czyta się w pionie
   (kwota pod kwotą), więc stoją we własnej kolumnie po prawej i nie
   rozjeżdżają się z długością numeru faktury. */
/* JEDEN JĘZYK W OBU KOLUMNACH.
   Łukasz, 07.09.2026: „wyrównamy to, żeby się zgrało?".
   Miał rację i problem nie był w odstępach: faktury były PUDEŁKAMI
   w pudełku — ramka wiersza wewnątrz ramki karty — a usługi i umowy
   obok rozdzielała cienka kreska. Dwa różne języki w jednym ekranie
   czyta się jak dwa ekrany zestawione przypadkiem.
   Teraz wiersz faktury wygląda tak samo jak wpis usługi: bez ramki,
   bez tła, oddzielony włosową linią. Kolor zostaje TYLKO tam, gdzie
   niesie informację — przy fakturze, która czeka na zapłatę.
   Przy okazji lista skróciła się o jedną trzecią wysokości, więc
   widać osiem faktur zamiast pięciu. */
.dok-lista { list-style: none; margin: 12px 0 0; padding: 0;
             display: flex; flex-direction: column; }
.dok { padding: 11px 0 11px 11px; border-bottom: 1px solid var(--linia);
       border-left: 3px solid transparent;
       display: grid; gap: 10px; align-items: start;
       grid-template-columns: minmax(0, 1fr) auto; }
.dok:last-child { border-bottom: 0; }
/* Krawędź niesie stan tylko wtedy, gdy jest co nieść — i NIGDY jako
   jedyny nośnik: obok zawsze stoi słowo. Faktura opłacona nie dostaje
   nic, bo „wszystko w porządku" nie jest informacją, której się szuka. */
.dok.bad   { border-left-color: var(--zle); }
.dok.warn  { border-left-color: var(--uwaga); }
.dok.cicho { border-left-color: var(--linia); }

.dok-tresc { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.dok-numer { font-weight: 700; overflow-wrap: anywhere; }
.dok-daty { display: flex; flex-wrap: wrap; align-items: center; gap: 2px 12px;
            font-size: var(--fs-xs); color: var(--tekst-3); }
.dok-daty span + span::before { content: '·'; margin-right: 12px;
                                color: var(--linia); }

/* Odnośnik do PDF-u, a nie przycisk: to jest przejście do dokumentu,
   nie akcja zmieniająca cokolwiek. Ikona + słowo, bo sama ikona
   zmusza do zgadywania. */
.dok-pdf { display: inline-flex; align-items: center; gap: 5px;
           font-size: var(--fs-xs); font-weight: 700; letter-spacing: .04em;
           text-transform: uppercase; color: var(--granat);
           text-decoration: none; border-bottom: 1px solid transparent; }
.dok-pdf svg { width: 14px; height: 14px; }
.dok-pdf:hover { border-bottom-color: currentColor; }

.dok-prawo { text-align: right; display: flex; flex-direction: column;
             align-items: flex-end; gap: 2px; white-space: nowrap; }
.dok-kwota { font-size: 17px; font-weight: 700; letter-spacing: -.01em;
             font-variant-numeric: tabular-nums; }
.dok-stan { font-size: 10px; font-weight: 700; text-transform: uppercase;
            letter-spacing: .07em; }
.dok-stan.bad   { color: var(--zle); }
.dok-stan.warn  { color: var(--uwaga); }
.dok-stan.ok    { color: var(--ok); }
.dok-stan.cicho { color: var(--tekst-3); }
.dok-reszta { font-size: var(--fs-xs); color: var(--zle); font-weight: 700;
              font-variant-numeric: tabular-nums; }

/* --- USŁUGI I UMOWY W BOKU ----------------------------------------- */
.lista-czysta { list-style: none; margin: 12px 0 0; padding: 0;
                display: flex; flex-direction: column; }
/* Ten sam rytm co w fakturach: 11 px oddechu i włosowa kreska. */
.usl, .umowa { display: flex; flex-direction: column; gap: 3px;
               padding: 11px 0; border-bottom: 1px solid var(--linia); }
.usl:first-child, .umowa:first-child { padding-top: 0; }
.usl:last-child, .umowa:last-child { border-bottom: 0; padding-bottom: 0; }
.usl-glowa { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
.usl-kat { font-weight: 700; }
/* „aktywna" jako znacznik, nie jako zdanie — jedna z tych informacji,
   które mają być widoczne kątem oka i nieczytane, gdy wszystko gra. */
.usl-stan { font-size: 10px; font-weight: 700; text-transform: uppercase;
            letter-spacing: .07em; color: var(--ok);
            background: var(--ok-tlo); border: 1px solid var(--ok-linia);
            border-radius: 999px; padding: 1px 7px; }
.usl-pakiet { font-size: 19px; font-weight: 700; letter-spacing: -.02em;
              font-variant-numeric: tabular-nums; }
.usl-pakiet.mala { font-size: var(--fs-s); font-weight: 600;
                   letter-spacing: 0; color: var(--tekst-2); }
.usl-adres { font-size: var(--fs-xs); color: var(--tekst-3); }

/* --- NUMER KONTA DO WPŁAT ------------------------------------------ */
.konto-wplat { margin-top: 16px; padding-top: 14px;
               border-top: 1px solid var(--linia);
               display: flex; flex-direction: column; align-items: center; gap: 6px; }
.konto-etykieta { font-size: var(--fs-xs); text-transform: uppercase;
                  letter-spacing: .08em; font-weight: 700; color: var(--tekst-3); }
.konto-numer { font-size: 15px; font-weight: 600; letter-spacing: .02em;
               overflow-wrap: anywhere; }

@media (max-width: 520px) {
  .dok { grid-template-columns: minmax(0, 1fr); }
  .dok-prawo { text-align: left; align-items: flex-start; }
}

/* --- TWOJE DANE ----------------------------------------------------
   Dwa adresy w jednej karcie, wyraźnie rozdzielone. Adres świadczenia
   dostaje własną etykietę i kreskę nad sobą, bo pomylenie go z adresem
   do faktury kończy się wyjazdem technika w złe miejsce. */
.dane-nazwa { font-weight: 700; margin-top: 10px; }
.dane-adres { color: var(--tekst-2); font-size: var(--fs-s); margin-top: 2px;
              line-height: 1.45; }
.dane-drobne { font-size: var(--fs-xs); color: var(--tekst-3); margin-top: 4px; }
.dane-usluga { margin-top: 14px; padding-top: 12px;
               border-top: 1px solid var(--linia);
               font-size: var(--fs-s); line-height: 1.45; }
.dane-usluga .konto-etykieta { display: block; margin-bottom: 3px; }


/* =====================================================================
   OFERTA — PAKIETY
   =====================================================================
   Kafle w siatce, która sama dobiera liczbę kolumn. Nie trzy na sztywno:
   przy dwóch pakietach telefonicznych trzecia kolumna byłaby dziurą,
   a przy pięciu internetowych piąty pakiet spadałby sam do drugiego
   rzędu i wyglądał na dodany po czasie.

   Kafle mają JEDNAKOWĄ wysokość w rzędzie (`align-items: stretch`
   z siatki), więc ceny stoją w jednej linii nawet wtedy, gdy jeden
   opis jest o zdanie dłuższy — a przy porównywaniu ofert to właśnie
   linia cen jest tym, po czym wodzi się wzrokiem.
   ===================================================================== */
/* Kolumny mają GÓRNĄ granicę szerokości. Przy `1fr` kategoria z jednym
   pakietem (telefon) rozciągała jedyny kafel na całą szerokość ekranu —
   i „15 zł/mies." wisiało samotnie na 1200 px. Kafel oferty ma wyglądać
   tak samo, ile by ich nie było w rzędzie. */
.pakiety { display: grid; gap: 12px; margin-top: 12px; justify-content: start;
           grid-template-columns: repeat(auto-fit, minmax(210px, 300px)); }
.pakiet { position: relative; display: flex; flex-direction: column; gap: 4px;
          padding: 16px 14px 14px; border: 1px solid var(--linia);
          border-radius: var(--r-s); background: var(--karta-2, transparent); }
/* Wyróżniony pakiet — jedna rzecz, nie trzy naraz: mocniejsza ramka
   i wstążka. Bez zmiany tła, bo tło zmienia też czytelność tekstu. */
.pakiet.wyrozniony { border-color: var(--granat); border-width: 2px;
                     padding: 15px 13px 13px; }
.pakiet-wstazka { position: absolute; top: -9px; left: 13px;
                  background: var(--granat); color: #fff;
                  font-size: 10px; font-weight: 700; letter-spacing: .07em;
                  text-transform: uppercase; padding: 2px 8px;
                  border-radius: 999px; }
.pakiet-nazwa { font-weight: 700; }
/* Parametr jest tym, po co się tu przychodzi („1000/1000 Mb/s"),
   więc dostaje największy stopień pisma w kaflu — większy niż nazwa. */
.pakiet-parametr { font-size: 22px; font-weight: 700; letter-spacing: -.02em;
                   line-height: 1.15; font-variant-numeric: tabular-nums;
                   color: var(--granat); }
.pakiet-cena { font-size: var(--fs-m, 16px); font-weight: 700; margin-top: 2px; }
.pakiet-opis { font-size: var(--fs-s); color: var(--tekst-2); margin: 4px 0 0;
               line-height: 1.45; }
/* Drobny druk zostaje drobnym drukiem, ale idzie na SPÓD kafla —
   przyklejony do ceny czytałby się jak jej część. */
.pakiet-dopisek { font-size: var(--fs-xs); color: var(--tekst-3); margin-top: auto;
                  padding-top: 8px; line-height: 1.4; }

.bok-kontakt { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 12px; }
