/* ══════════════════════════════════════════════════════════════════════
   COMPONENTS - elementy uzywane w wielu sekcjach.
   Kolejnosc: przyciski, naglowek, menu mobilne, karty, akordeon, stopka.
   ══════════════════════════════════════════════════════════════════════ */


/* ══ PRZYCISKI ═════════════════════════════════════════════════════════
   Proste, plaskie, ostre. Bez gradientow, bez poswiaty, bez pigulek.
   Primary niesie czerwien marki, secondary jest przezroczysty z ramka. */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 48px;                    /* cel dotykowy */
  padding: var(--s-3) var(--s-6);
  border-radius: var(--r-sm);
  font-size: var(--t-body);
  font-weight: var(--w-medium);
  line-height: 1;
  white-space: nowrap;
  transition: background-color var(--d-fast) var(--ease-out),
              border-color    var(--d-fast) var(--ease-out),
              color           var(--d-fast) var(--ease-out),
              transform       var(--d-fast) var(--ease-out);
}

/* uniesienie z --lift (patrz motion.css) - ta sama wartosc, co kazdy
   inny element interakcyjny w serwisie. Przycisk zablokowany stoi
   w miejscu: uniesienie obiecuje klikniecie, ktorego nie ma.

   OD 2026-08-11 blokada jest sygnalizowana `aria-disabled`, nie atrybutem
   `disabled` (uzasadnienie przy .btn--safe[aria-disabled] nizej), wiec kazda
   regula stanu musi lapac oba zapisy. `:disabled` zostaje dla przyciskow,
   ktore kiedys moglyby uzyc atrybutu wprost. */
.btn:hover  { transform: translateY(var(--lift)); }
.btn:active { transform: translateY(var(--lift)) scale(0.99); }
.btn:disabled,
.btn:disabled:hover,
.btn[aria-disabled='true'],
.btn[aria-disabled='true']:hover { transform: none; }

.btn--primary {
  background: var(--c-brand);
  color: #fff;
}
.btn--primary:hover  { background: var(--c-brand-hover); }
.btn--primary:active { background: var(--c-brand-active); }

/* Obrys z --c-border-kontrolka, nie z --c-border (2026-08-11). Ten przycisk
   nie ma wypelnienia, wiec obrys jest JEDYNYM znakiem, ze to kontrolka -
   a przy --c-border dawal 1,58 na kanwie (i 2,40 w wariancie nagłówka),
   czyli praktycznie znikal. Na hero oferty "Sprawdź ↓" czytalo sie jak
   podpis, nie jak przycisk. Nowy token daje 3,13, czyli prog WCAG 1.4.11.
   Uzasadnienie osobnego tokenu zamiast podniesienia --c-border: tokens.css. */
.btn--secondary {
  background: transparent;
  color: var(--c-text);
  box-shadow: inset 0 0 0 1px var(--c-border-kontrolka);
}
/* hover MUSI isc z pary --c-border-kontrolka-*, nie z --c-border-hover:
   ta druga jest ciemniejsza od nowego obrysu spoczynkowego, wiec najechanie
   kursorem PRZYGASZALOBY krawedz zamiast ja podkreslic */
.btn--secondary:hover {
  background: var(--c-surface);
  box-shadow: inset 0 0 0 1px var(--c-border-kontrolka-hover);
}

/* wariant "strefa bezpieczna" - progres formularza (Dalej/Wyslij), nie
   marketingowe wezwanie do dzialania. Ciemny tekst, nie bialy: ta zielen
   jest zbyt jasna, zeby bialy tekst dawal wystarczajacy kontrast. */
.btn--safe {
  background: var(--c-safe);
  color: var(--c-bg);
}
.btn--safe:hover  { background: var(--c-safe-hover); }
.btn--safe:active { background: var(--c-safe-active); }

/* ── STAN ZABLOKOWANY: `aria-disabled`, NIE `disabled` (2026-08-11) ────
   Atrybut `disabled` wyjmuje przycisk z kolejnosci Tab. Skutek byl taki, ze
   uzytkownik klawiatury NIE MOGL na niego trafic, wiec nie mial jak uslyszec,
   dlaczego "Dalej" nie dziala - a powod stoi tuz obok, w wierszu podpowiedzi.
   `aria-disabled` zostawia przycisk w kolejnosci Tab i oglasza stan; samo
   klikniecie i tak nic nie robi, bo bramkuje je krokPoprawny() w
   js/kontakt.js (`disabled` nigdy nie byl tu zabezpieczeniem, tylko wygoda).
   Przycisk dostaje przy tym `aria-describedby` wskazujace #kform-hint, wiec
   czytnik podaje powod razem ze stanem.

   Obrys, nie wypelnienie - --c-border ma niemal ta sama jasnosc co panel
   .kontakt__uklad (--c-surface-safe), wiec wypelniony szary przycisk
   znikal na tle panelu i wygladal jak zepsuty. Obrys zawsze widac,
   niezaleznie od tla, i wyrazniej kontrastuje z pelnym zielonym stanem.
   Konkretne wartosci obrysu i napisu liczone SA OD PANELU - patrz blok
   KONTAKT w sections.css, tam gdzie stoi cala reszta poprawek kontrastu
   tej sekcji. Tutaj zostaje sam ksztalt stanu. */
.btn--safe[aria-disabled='true'] {
  background: transparent;
  color: var(--c-text-muted);
  box-shadow: inset 0 0 0 1px var(--c-border-hover);
  cursor: not-allowed;                 /* kursor mowi "jeszcze nie", zanim
                                          uzytkownik zdazy kliknac w prozne */
}

/* ── STRZALKA W KWADRACIE ────────────────────────────────────────────
   Strzalka nie stoi naga obok napisu, tylko siedzi we wlasnym kwadracie
   z wloskiem - drugi, mniejszy element o wlasnej kinetyce. Przycisk pod
   kursorem unosi sie, a kwadracik dodatkowo dryfuje po skosie i wypelnia
   sie kolorem: dwa ruchy o roznej skali zamiast jednego plaskiego
   przesuniecia.

   Kwadrat, nie kolo - marka jest ostra (promien --r-sm = 2 px), a znak
   firmowy nie ma ani jednej pelnej krzywizny.

   Rozmiar w `em`, nie w pikselach: kwadracik ma sie skalowac razem
   z napisem przycisku, takze w wariancie kompaktowym (.btn--sm). */
.btn__arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;                             /* nie sciska sie przy waskim CTA */
  width: 1.75em;
  height: 1.75em;
  margin-right: calc(var(--s-2) * -1);    /* dosuniecie do prawego paddingu */
  font-size: 0.875em;
  line-height: 1;
  border: 1px solid color-mix(in oklab, currentColor 35%, transparent);
  border-radius: var(--r-sm);
  transition: transform        var(--d-fast) var(--ease-out),
              background-color var(--d-fast) var(--ease-out),
              border-color     var(--d-fast) var(--ease-out),
              color            var(--d-fast) var(--ease-out);
}

/* dryf po skosie - w strone, w ktora pokazuje strzalka, plus do gory,
   zgodnie z uniesieniem calego przycisku.

   `:not([aria-disabled])` na kazdej regule hoveru strzalki (2026-08-11):
   uniesienie calego przycisku bylo juz poprawnie wylaczone w stanie
   zablokowanym, ale kwadracik nadal dryfowal i wypelnial sie kolorem pod
   kursorem. Zablokowany przycisk reagowal wiec na najechanie i obiecywal
   klikniecie, ktorego nie ma - dokladnie ten efekt, ktory regula
   `.btn:disabled:hover` miala wykluczyc. */
.btn:not([aria-disabled='true']):hover .btn__arrow { transform: translate(3px, -2px); }

/* Strzalka w dol (przycisk prowadzacy do sekcji nizej, hero podstron).
   Dryf musi isc W DOL - bazowy skos do gory pokazywalby w przeciwna strone
   niz sama strzalka. To jedyny przypadek, w ktorym ruch strzalki idzie
   przeciwnie do uniesienia przycisku, i tak ma byc: liczy sie kierunek,
   ktory strzalka obiecuje. */
.btn:not([aria-disabled='true']):hover .btn__arrow--dol { transform: translate(0, 3px); }

/* na wypelnionych wariantach kwadracik odwraca kolory: staje sie jasnym
   znaczkiem na tle przycisku. Na wariancie z obrysem wystarczy akcent
   marki na krawedzi - pelne wypelnienie bilby sie z lekkoscia tego
   przycisku. */
.btn--primary:not([aria-disabled='true']):hover .btn__arrow {
  background: #fff;
  border-color: #fff;
  color: var(--c-brand-hover);
}
.btn--safe:not([aria-disabled='true']):hover .btn__arrow {
  background: var(--c-bg);
  border-color: var(--c-bg);
  color: var(--c-safe-hover);
}
.btn--secondary:not([aria-disabled='true']):hover .btn__arrow {
  border-color: var(--c-brand);
  color: var(--c-brand);
}

/* wariant kompaktowy - naglowek strony */
.btn--sm {
  min-height: 40px;
  padding: var(--s-2) var(--s-4);
  font-size: var(--t-sm);
}

/* odnosnik tekstowy z kreska - trzeci poziom hierarchii, nizej niz
   secondary. Uzywany tam, gdzie przycisk bylby za ciezki. */
.lnk {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding-block: var(--s-1);
  color: var(--c-text);
  font-size: var(--t-body);
  font-weight: var(--w-medium);
  border-bottom: 1px solid var(--c-border-hover);
  transition: color var(--d-fast) var(--ease-out),
              border-color var(--d-fast) var(--ease-out);
}
.lnk:hover { color: var(--c-brand); border-color: var(--c-brand); }

/* strzalka odnosnika jest naga, bez kwadratu - to swiadoma roznica
   hierarchii wobec .btn (przycisk = kwadracik, odnosnik = sama strzalka).
   Modyfikator --wstecz przesuwa ja w te strone, w ktora pokazuje. */
.lnk__arrow { transition: transform var(--d-fast) var(--ease-out); }
.lnk:hover .lnk__arrow { transform: translateX(3px); }
.lnk:hover .lnk__arrow--wstecz { transform: translateX(-3px); }


/* ══ NAGLOWEK STRONY ═══════════════════════════════════════════════════
   Przyklejony, minimalny: znak, nawigacja, jedno CTA.
   Tlo pojawia sie dopiero po odjechaniu od gory (klasa .is-scrolled
   nadawana z JS), zeby nad hero nie bylo paska odcinajacego scene. */

.header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  height: var(--h-header);
  display: flex;
  align-items: center;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color var(--d-normal) var(--ease-out),
              border-color     var(--d-normal) var(--ease-out);
}

.header.is-scrolled {
  background: color-mix(in oklab, var(--c-bg) 88%, transparent);
  border-bottom-color: var(--c-border);
  backdrop-filter: blur(12px);
}

.header__inner {
  width: 100%;
  max-width: var(--w-wide);
  margin-inline: auto;
  padding-inline: var(--pad-x);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
}

/* Znak - wysokosc sterowana jedna wartoscia.
   MINIMUM Z KSIEGI TO 32 PX i to jest podloga, nie sugestia: na waskim
   ekranie schodzimy dokladnie do niej, nizej nie. Logo poziome ma proporcje
   5,40, wiec 32 px wysokosci to 173 px szerokosci - przy 390 px ekranu
   nadal 44% paska, ale to najmniej, ile wolno.
   Od 900 px wraca 34 px, bo tam pasek jest wyzszy (84 px) i znak w nim
   nie dominuje. */
.header__logo img {
  height: 32px;
  width: auto;
}

/* ── nawigacja desktop ── */
.nav {
  display: none;
  align-items: center;
  gap: var(--s-8);
}

.nav__link {
  position: relative;
  padding-block: var(--s-2);
  color: var(--c-text-2);
  font-size: var(--t-sm);
  font-weight: var(--w-medium);
  transition: color var(--d-fast) var(--ease-out);
}
.nav__link:hover,
.nav__link[aria-current='page'] { color: var(--c-text); }

/* podkreslenie aktywnej pozycji - kreska marki, nie tlo */
.nav__link[aria-current='page']::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--c-brand);
}

/* CTA naglowka jest DRUGORZEDNE (2026-08-08). Wczesniej bylo .btn--primary
   i na pierwszym ekranie index.html staly dwa identyczne, wypelnione
   czerwienia przyciski naraz: "Porozmawiajmy" tutaj i "Kontakt" w hero.
   Naglowek to element staly (chrome), hero to wypowiedz strony - to hero
   ma byc glosne. Na podstronach hero nie ma juz przyciskow, wiec ten
   obrysowany przycisk zostaje tam jedynym CTA pierwszego ekranu.

   OSOBNE WZMOCNIENIE WLOSKA ODPADLO 2026-08-11. Stalo tu
   `box-shadow: ... var(--c-border-hover)`, bo bazowy .btn--secondary uzywal
   --c-border, ktory na kadrze hero po prostu znikal. Bazowy obrys idzie teraz
   z --c-border-kontrolka (3,13 na kanwie, patrz tokens.css), czyli jest juz
   mocniejszy niz dawne wzmocnienie - nadpisanie tylko by go OSLABIALO. */
.header__cta { display: none; }

@media (min-width: 900px) {
  .nav          { display: flex; }
  .header__cta  { display: inline-flex; }
  .header__burger { display: none; }
  .header__logo img { height: 34px; }
}


/* ══ MENU MOBILNE ══════════════════════════════════════════════════════
   Przycisk hamburgera nawiazuje do sygnetu: srodkowa linia jest ukosna,
   tak jak kreska przecinajaca okregi znaku. Pozostaje czytelny jako menu. */

.burger {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-right: calc(var(--s-3) * -1);   /* optyczne wyrownanie do krawedzi */
}

/* Wszystkie trzy linie leza w tym samym punkcie (srodek pudelka) i roznia
   sie wylacznie przesunieciem w pionie. Dzieki temu krzyz w stanie otwartym
   powstaje przez samo wyzerowanie przesuniecia - obie kreski obracaja sie
   wokol tego samego srodka i wychodzi symetryczny X, a nie zlozenie
   dwoch kresek o roznych osiach. */
.burger__box {
  position: relative;
  width: 22px;
  height: 16px;
}

.burger__box span {
  position: absolute;
  left: 0;
  top: 50%;
  width: 100%;
  height: 1.5px;
  margin-top: -0.75px;          /* polowa grubosci - kreska siedzi na osi */
  background: var(--c-text);
  transition: transform var(--d-normal) var(--ease-out),
              opacity   var(--d-fast)   var(--ease-out);
}

.burger__box span:nth-child(1) { transform: translateY(-6px); }
.burger__box span:nth-child(2) { transform: none; }
.burger__box span:nth-child(3) { transform: translateY(6px); }

/* stan otwarty: srodkowa znika, skrajne skladaja sie w krzyz */
.burger[aria-expanded='true'] .burger__box span:nth-child(1) { transform: rotate(45deg); }
.burger[aria-expanded='true'] .burger__box span:nth-child(2) { opacity: 0; }
.burger[aria-expanded='true'] .burger__box span:nth-child(3) { transform: rotate(-45deg); }

/* panel menu - pelny ekran pod naglowkiem.
   Nie lista pozycji, tylko trzy duze slowa dosuniete do prawej krawedzi,
   w pionowym srodku ekranu. Bez przyciskow i bez kresek - tekst jest tu
   jedynym elementem, wiec musi udzwignac cala kompozycje. */
.menu {
  position: fixed;
  inset: var(--h-header) 0 0 0;
  z-index: var(--z-menu);
  display: grid;
  align-content: center;
  justify-items: end;
  gap: clamp(var(--s-8), 6vh, var(--s-16));
  padding: var(--s-10) var(--pad-x) var(--s-16);
  background: var(--c-bg);
  text-align: right;
  overflow-y: auto;
}

.menu[hidden] { display: none; }

.menu__link {
  position: relative;
  font-family: var(--f-display);
  font-size: clamp(2.75rem, 15vw, 4.5rem);
  font-weight: var(--w-bold);
  line-height: 1.05;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  transition: color var(--d-fast) var(--ease-out);
}

/* kropka marki przy pozycji wskazanej palcem - jedyny akcent koloru,
   pojawia sie po prawej stronie slowa, poza jego swiatlem */
.menu__link::after {
  content: '';
  position: absolute;
  top: 50%;
  right: calc(var(--s-4) * -1);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--c-brand);
  opacity: 0;
  transform: translateY(-50%) scale(0.4);
  transition: opacity var(--d-fast) var(--ease-out),
              transform var(--d-normal) var(--ease-out);
}

.menu__link:hover::after,
.menu__link:focus-visible::after,
.menu__link[aria-current='page']::after {
  opacity: 1;
  transform: translateY(-50%) scale(1);
}

@media (min-width: 900px) {
  .burger { display: none; }
  .menu   { display: none; }
}

/* blokada przewijania tla przy otwartym menu */
body.menu-open { overflow: hidden; }


/* ══ KARTA ═════════════════════════════════════════════════════════════
   Powierzchnia plus delikatna ramka. Bez cieni, bez zagniezdzania.
   Karta wystepuje tylko tam, gdzie tresc naprawde jest odrebnym obiektem.
   Bez przejsc - karta nie ma stanu, w ktory moglaby przejsc. */

.card {
  display: flex;
  flex-direction: column;
  padding: var(--pad-card);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
}

/* ── wariant "szklo": biel 10% zamiast wlasnego odcienia ──
   Decyzja klienta 2026-08-10, wprowadzona po to, zeby kafle byly LEPIEJ
   WIDOCZNE. Zwykla .card ma odcien odrobine jasniejszy od tla strony
   i na ciemnym graficie potrafi sie w nim zgubic; biel 10% odbija sie
   od tla mocniej, a jednoczesnie jest przezroczysta, wiec nad wstega
   neonu (`.tor`) przepuszcza jej kolor zamiast go zakrywac.

   Wariant, a nie podmiana .card: reszta serwisu ma trzy stopnie
   powierzchni (--c-surface / --c-surface-up / --c-surface-safe) i to
   one budują hierarchie kart. Globalna podmiana skasowalaby ja calą.

   OD 2026-08-10 (druga tura) to nie plaska biel, tylko tafla: kierunek
   swiatla, refleks na gornej krawedzi, cien pod plyta i rozmycie tla.
   Wszystkie cztery skladniki siedza w tokenach (--grad-szklo, --cien-szklo,
   --blur-szklo, patrz tokens.css) - tutaj tylko ich zlozenie.

   `background-color` + `background-image` osobno, nie skrot `background`:
   skrot skasowalby jedno drugim. */
.card--szklo {
  background-color: var(--c-szklo);
  background-image: var(--grad-szklo);
  border-color: var(--c-szklo-krawedz);
  box-shadow: var(--cien-szklo);
  -webkit-backdrop-filter: var(--blur-szklo);
          backdrop-filter: var(--blur-szklo);
}

/* Bez obslugi backdrop-filter tafla zostaje przezroczysta bez rozmycia,
   czyli za cienka - wtedy wiecej bieli, zeby kafel nadal odcinal sie od
   tla. Warunek na `-webkit-` tez, bo Safari dlugo mial tylko prefiks. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .card--szklo { background-color: color-mix(in srgb, #fff 14%, transparent); }
}

/* Wariant .card--ghost (karta bez powierzchni) zostal USUNIETY 2026-08-07.
   Mial jednego uzytkownika - kroki procesu na oferta.html - a te dostaly
   wlasna kreske marki po lewej i wlasny odstep, wiec przestaly potrzebowac
   czegokolwiek z karty. Nadpisywanie trzech wlasciwosci karty po to, zeby
   zostal sam `flex-direction: column`, bylo droga naokolo. */


/* ══ FORMULARZ ═════════════════════════════════════════════════════════
   Pole tekstowe/textarea w jednym stylu (`.input`) plus miniaturowy
   wskaznik postepu (`.stepper`) uzywany przez formularz kontaktowy
   krokowy (patrz kontakt.html i js/kontakt.js). */

.input {
  display: block;
  width: 100%;
  padding: var(--s-4);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  color: var(--c-text);
  /* pelny reset dziedziczenia po etykiecie: pole siedzi WEWNATRZ <label>,
     a etykieta jest teraz pytaniem w kroju naglowkowym (patrz .kform__label).
     `font: inherit` z base.css sciagneloby na pole caly ten krok - Afacad
     w stopniu naglowka. Tresc wpisywana przez uzytkownika nalezy do kroju
     tekstowego, zawsze. */
  font-family: var(--f-body);
  font-size: var(--t-body);
  font-weight: var(--w-regular);
  letter-spacing: normal;
  line-height: var(--lh-body);
  transition: border-color var(--d-fast) var(--ease-out),
              box-shadow   var(--d-fast) var(--ease-out);
}
.input::placeholder { color: var(--c-text-muted); }

/* ── FOKUS I POPRAWNOSC TO DWA ROZNE ZNAKI (poprawka 2026-08-11) ──────
   BLAD, KTORY TO NAPRAWIA: do tej pory `:focus-visible` i `.is-valid`
   malowaly to samo (`border-color: var(--c-safe)`), wiec PUSTE, WYMAGANE
   POLE TUZ PO WEJSCIU W NIE wygladalo dokladnie tak, jak pole wypelnione
   poprawnie - zielona ramka, a nad nia podpowiedz "Wpisz imie, zeby przejsc
   dalej". Interfejs mowil dwie sprzeczne rzeczy naraz. Zlapane w tescie
   na kroku 1 (4 znaki przy wymaganych 10) i na kroku 2 (pole puste).

   Rozdzielony jest NOSNIK, nie kolor:
     fokus       - pierscien po CALYM obwodzie (obrys, patrz nizej),
     poprawnosc  - kreska przy LEWEJ krawedzi (cien wewnetrzny).
   Kreska jest dyskryminatorem: pole moze byc jednoczesnie sfokusowane
   i poprawne, i nadal widac, ktore z dwojga wlasnie sie stalo. Ten sam
   gest, co czerwona kreska przy komunikacie bledu i kreska kroku Procesu -
   znak "tu patrz", nie obwodka.

   `outline` zamiast cienia na fokusie (zmiana wobec poprzedniej wersji):
   obie wlasciwosci nie moga juz siedziec na `box-shadow`, bo ta niesie
   teraz kreske poprawnosci. Obrys jest zdefiniowany JAWNIE, wiec dawny
   powod wylaczenia go (`outline: none`) odpada - problemem byl domyslny,
   czerwony pierscien z base.css, a nie sam mechanizm. Ujemny offset kladzie
   go WEWNATRZ pola: krawedz grubieje o wlos, wymiar sie nie zmienia i nic
   nie "swieci" (brief wprost zabrania swiecacych elementow).

   Zielen, nie czerwien marki - w tym formularzu czerwien znaczy blad
   (patrz --c-err w tokens.css). Kontrola kontrastu obrysu fokusu:
   3,74 wobec panelu i 5,13 wobec wypelnienia pola, prog 1.4.11 to 3:1. */
.input:focus-visible {
  border-color: var(--c-safe);
  outline: 2px solid var(--c-safe);
  outline-offset: -2px;
}

.input.is-valid { box-shadow: inset 3px 0 0 0 var(--c-safe); }

.kform__textarea { resize: vertical; min-height: 8em; }

/* ── KROK FORMULARZA ─────────────────────────────────────────────────
   Krok chowa js/kontakt.js atrybutem [hidden]. Regula stoi tu JAWNIE,
   mimo ze przegladarka ma wlasna - w tym samym arkuszu zdarzylo sie juz
   dwa razy, ze wlasny `display` przebijal [hidden] (.menu, .kform__back).
   Przy kroku formularza taki blad wyglada dokladnie jak zgloszone
   "formularz nie przenosi do nastepnego kroku": wszystkie pola stoja
   widoczne naraz, wiec klikniecie "Dalej" nie zmienia nic, co widac. */
.kform__step[hidden] { display: none; }

/* ── OKNO KROKOW: STALA WYSOKOSC ─────────────────────────────────────
   Zgloszenie 2026-08-10: "po kliknieciu dalej przeskakuje wysokosc strony -
   formularza. Wrapper ma pozostac staly, a zmieniaja sie tylko pola".

   Przyczyna byla w tresci krokow, nie w animacji: krok 1 to pole opisu
   (textarea, min. 8em), kroki 2-3 to pojedyncze linie. Krok chowany przez
   `display: none` znika z ukladu razem ze swoja wysokoscia, wiec panel
   kurczyl sie o roznice, a wszystko pod nim skakalo w gore.

   Rozwiazanie: wszystkie trzy kroki ida do JEDNEJ komorki siatki
   (`grid-area: 1 / 1`), czyli leza jeden na drugim. Siatka bierze wtedy
   wysokosc najwyzszego dziecka i trzyma ja niezaleznie od tego, ktory krok
   jest widoczny. Schowany krok przestaje byc `display: none` (bo wtedy nie
   liczylby sie do wysokosci) i dostaje `visibility: hidden` - to nadal
   wyjmuje go z kolejnosci Tab i z czytnikow ekranu, a pole zostaje w DOM,
   wiec nadal trafia do FormData przy wysylce.

   Klasa `.kform--kroki` przychodzi z js/kontakt.js razem z reszta
   wzbogacenia. Bez JS jej nie ma i kroki stoja pod soba, jak dotad -
   inaczej caly formularz zlozylby sie w jeden nieczytelny stos. */
.kform__pola { display: grid; gap: var(--s-6); }

.kform--kroki .kform__step { grid-area: 1 / 1; }

.kform--kroki .kform__step[hidden] {
  display: block;
  visibility: hidden;
}

/* wjazd kroku - bez klasy z JS. Animacja startuje sama za kazdym pokazaniem
   kroku, bo to selektor decyduje, czy w ogole jest: pod [hidden] regula
   przestaje pasowac i animacja zostaje anulowana, a po zdjeciu atrybutu
   przypisuje sie od nowa. Dziala tak samo dla obu sposobow chowania kroku
   (`display: none` bez JS, `visibility: hidden` w ukladzie krokowym).
   Ruch idzie w prawo, zgodnie z kierunkiem "dalej", i jest krotki
   (--d-normal): to potwierdzenie klikniecia, nie osobna scena. */
.kform__step:not([hidden]) {
  animation: krok-in var(--d-normal) var(--ease-out) both;
}

@keyframes krok-in {
  from { opacity: 0; transform: translateX(12px); }
  to   { opacity: 1; transform: none; }
}

/* ── ETYKIETA JAKO PYTANIE ───────────────────────────────────────────
   Formularz pokazuje jedno pole na raz, wiec etykieta nie jest podpisem
   w gestym formularzu - jest PYTANIEM zadanym na tym ekranie. Dostaje
   krój naglowkowy i stopien --t-h3, tak jak kazde inne pytanie w serwisie
   (patrz .faq__q, ten sam stopien i ten sam krój). Wczesniejsze
   --t-sm w kolorze drugorzednym mowilo cos przeciwnego: "to jest podpis
   techniczny", chociaz to jedyna tresc na ekranie.

   Pole wewnatrz musi wtedy jawnie odzyskac krój tekstowy - patrz .input. */
.kform__label {
  display: grid;
  gap: var(--s-4);
  color: var(--c-text);
  font-family: var(--f-display);
  font-size: var(--t-h3);
  font-weight: var(--w-medium);
  line-height: var(--lh-head);
  letter-spacing: var(--ls-display);
}

/* ZNACZNIK POPRAWNOSCI PRZENIESIONY 2026-08-10 z rogu pola do wiersza
   podpowiedzi nad polem (`.kform__hint`, nizej). Byl tu jako
   `.kform__label::after` w komorce pola - lezal NA tekscie uzytkownika
   i mowil dokladnie to samo, co znikniecie podpowiedzi nad polem, czyli
   dwa znaki na jedno zdarzenie. Zostaje jeden, w linii, ktora i tak
   opisuje stan kroku. Zielona krawedz pola (`.input.is-valid`) zostaje
   bez zmian - to potwierdzenie przy samym polu, nie druga ikona. */

/* wskaznik postepu - "1 / 3" plus pasek. Chowany w HTML domyslnie:
   bez JS wszystkie kroki sa widoczne naraz, wiec numer kroku nie ma
   znaczenia (patrz js/kontakt.js, wlaczany po starcie skryptu). */
.stepper {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  /* bez wlasnego marginesu - odstep do pierwszego pola niesie `gap`
     formularza (.kform), inaczej odleglosc liczylaby sie dwa razy */
}
.stepper[hidden] { display: none; }

.stepper__krok {
  flex: none;
  color: var(--c-text-muted);
  font-size: var(--t-xs);
  font-weight: var(--w-medium);
  letter-spacing: var(--ls-label);
  font-variant-numeric: tabular-nums;
}

/* ── pasek postepu jako trzy kasety ──
   Ciagly pasek z zaokraglonymi koncami byl obcy dwa razy: marka jest ostra
   (promienie 2-4 px, decyzja 2026-08-07), a sam produkt sklada sie
   z modulow, nie z ciaglej tasmy. Pasek jest wiec przeciety na tyle
   segmentow, ile krokow ma formularz - postep "zapala" kolejna kaseta,
   dokladnie tak, jak buduje sie sciana LED.

   Maska liczy szerokosc segmentu tak, zeby OSTATNI konczyl sie rowno na
   100%: przy N segmentach miesci sie N-1 szczelin, wiec segment ma
   (100% - (N-1) * szczelina) / N. Dzieki temu na prawej krawedzi nie
   zostaje sierota po szczelinie.

   --segmenty musi byc rowne liczbie krokow formularza (3, patrz
   kontakt.html i js/kontakt.js). To jedyne miejsce, gdzie ta liczba
   wystepuje w CSS. */
.stepper__track {
  --segmenty: 3;
  --szczelina: 3px;
  --segment: calc((100% - (var(--segmenty) - 1) * var(--szczelina)) / var(--segmenty));

  flex: 1;
  height: 4px;
  background: var(--c-border);
  overflow: hidden;
  -webkit-mask-image: repeating-linear-gradient(to right,
      #000 0 var(--segment),
      transparent var(--segment) calc(var(--segment) + var(--szczelina)));
          mask-image: repeating-linear-gradient(to right,
      #000 0 var(--segment),
      transparent var(--segment) calc(var(--segment) + var(--szczelina)));
}

/* szerokosc ustawia js/kontakt.js (33% / 66% / 100%) - wartosci trafiaja
   dokladnie na granice segmentow, bo szczeliny sa i tak wymaskowane */
.stepper__track > i {
  display: block;
  height: 100%;
  /* wartość startowa - pierwszy z trzech kroków, ta sama zmienna co szczeliny wyżej */
  width: var(--segment);
  background: var(--c-brand);
  transition: width var(--d-normal) var(--ease-out);
}

/* ── AKCEPTACJA POLITYKI PRZY WYSYLCE ────────────────────────────────
   Pole wyboru rysowane od zera (`appearance: none`), bo natywne pobiera
   kolor z systemu operacyjnego uzytkownika - na ciemnym tle potrafi
   wyjsc bialym kwadratem z niebieskim ptaszkiem Windowsa, czyli jedynym
   elementem w calym serwisie spoza palety marki.

   Kwadrat 22 px: przy tekscie --t-xs to jedyny element formularza, ktory
   ma wlasny, powiekszony cel dotykowy (samo pole + etykieta, patrz nizej -
   klikalne jest jedno i drugie).

   Kolor stanu zaznaczonego to zielen "strefy bezpiecznej", ta sama, co
   krawedz poprawnego pola i przycisk wysylki - w tym formularzu zielen
   znaczy "idz dalej", a czerwien marki jest zarezerwowana na blad. */
.zgoda {
  /* bok kwadratu w jednym miejscu - liczy go tez pozycja ptaszka nizej */
  --pw-box: 22px;   /* pole wyboru: bok */
  --pw-check: 6px;  /* pole wyboru: wysokosc ptaszka przed obrotem */

  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s-3);
  align-items: start;
}

/* schowana zgoda ZOSTAWIA PO SOBIE MIEJSCE w ukladzie krokowym: znika
   dopiero z widoku i z kolejnosci Tab (`visibility`), nie z ukladu -
   inaczej panel rosnie o cala jej wysokosc dokladnie w chwili przejscia
   na ostatni krok, czyli tam, gdzie uzytkownik siega juz do przycisku.
   Ta sama zasada, co przy oknie krokow i wierszu podpowiedzi.

   Poza ukladem krokowym (bez JS) `[hidden]` dziala normalnie - ale tam
   skrypt nigdy tego atrybutu nie ustawia, wiec regula jest tylko
   zabezpieczeniem na wypadek uzycia `.zgoda` gdzie indziej. */
.zgoda[hidden] { display: none; }

.kform--kroki .zgoda[hidden] {
  display: grid;
  visibility: hidden;
}

.zgoda__pole {
  grid-area: 1 / 1;
  appearance: none;
  -webkit-appearance: none;
  width: var(--pw-box);
  height: var(--pw-box);
  margin: 0;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color var(--d-fast) var(--ease-out),
              border-color     var(--d-fast) var(--ease-out);
}

.zgoda__pole:hover { border-color: var(--c-border-hover); }

.zgoda__pole:checked {
  background: var(--c-safe);
  border-color: var(--c-safe);
}

/* obrys fokusu w zieleni, nie w domyslnej czerwieni marki z base.css -
   z tego samego powodu, co przy `.input:focus-visible`: czerwien w tym
   formularzu znaczy blad */
.zgoda__pole:focus-visible {
  outline: 2px solid var(--c-safe);
  outline-offset: 2px;
}

/* Ptaszek z dwoch krawedzi, tak samo jak znacznik poprawnosci pola
   (`.kform__label::after`) - jeden sposob rysowania checka w calym
   serwisie, zero plikow i zero biblioteki ikon.

   Siedzi na `.zgoda::after`, nie na `.zgoda__pole::after`: pole z
   `appearance: none` jest formalnie elementem zastepowalnym i jego
   pseudoelementy nie sa gwarantowane w kazdej przegladarce. Pseudoelement
   rodzica lezy w tej samej komorce siatki (`grid-area: 1 / 1`), czyli
   dokladnie na kwadracie, i nie lapie kursora - klikniecie i tak trafia
   w pole pod spodem. */
.zgoda::after {
  content: '';
  grid-area: 1 / 1;
  /* NIE `place-self: center` - wiersz siatki jest tak wysoki, jak etykieta
     obok, wiec przy dwuwierszowym tekscie wysrodkowanie w PIONIE zsunieloby
     ptaszek pod kwadrat. Poziomo srodkujemy (kolumna ma dokladnie szerokosc
     pola), pionowo liczymy odstep od gory: polowa roznicy miedzy bokiem
     kwadratu a wysokoscia ptaszka. */
  justify-self: center;
  align-self: start;
  margin-top: calc((var(--pw-box) - var(--pw-check)) / 2);
  width: 11px;
  height: var(--pw-check);
  border-left: 2px solid var(--c-bg);
  border-bottom: 2px solid var(--c-bg);
  opacity: 0;
  /* -1px podnosi ptaszek do optycznego srodka: po obrocie o 45 stopni
     ksztalt "siada" nizej, niz wynika z jego pudelka */
  transform: translateY(-1px) rotate(-45deg) scale(0.4);
  pointer-events: none;
  transition: opacity   var(--d-fast) var(--ease-out),
              transform var(--d-normal) var(--ease-out);
}

.zgoda:has(.zgoda__pole:checked)::after {
  opacity: 1;
  transform: translateY(-1px) rotate(-45deg) scale(1);
}

.zgoda__label {
  color: var(--c-text-muted);
  font-size: var(--t-xs);
  line-height: var(--lh-body);
  cursor: pointer;
}

/* odnosnik do polityki jest podkreslony na stale - to jedyny link wewnatrz
   formularza i musi byc rozpoznawalny bez najezdzania kursorem (WCAG 1.4.1,
   kolor nie moze byc jedynym nosnikiem informacji) */
.zgoda__label a {
  color: var(--c-text-2);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  transition: color var(--d-fast) var(--ease-out);
}
.zgoda__label a:hover { color: var(--c-brand); }

/* ── WIERSZ STANU KROKU (nad polem) ─────────────────────────────────
   Wyjasnienie, czego brakuje do odblokowania "Dalej" - bez tego zablokowany
   przycisk wygladal jak zawieszony, nie jak krok, ktory czeka na tresc.

   Od 2026-08-10 ten wiersz stoi NAD polem (patrz kontakt.html) i niesie
   dwie rzeczy naraz: podpowiedz po lewej i ptaszek poprawnosci po prawej.
   Nie moga wystapic jednoczesnie, bo skrypt czysci tresc podpowiedzi
   dokladnie wtedy, gdy krok robi sie poprawny - i to jest cala mechanika
   ptaszka: wchodzi na `:empty`, czystym CSS-em, bez ani jednej linii JS. */
.kform__hint {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  min-height: 16px;            /* wysokosc ptaszka - wiersz nie skacze */
  color: var(--c-text-muted);
  font-size: var(--t-xs);
}
.kform__hint:empty { display: none; }

/* Ptaszek z dwoch krawedzi, ten sam sposob rysowania co przy zgodzie
   (`.zgoda::after`) - zero plikow i zero biblioteki ikon. `:empty` to
   stan "krok poprawny", wiec znak pojawia sie dokladnie w chwili, w ktorej
   podpowiedz znika, i w tym samym miejscu wiersza.
   `margin-left: auto` zamiast `justify-self`: to jedyne dziecko wiersza
   w tym stanie, wiec samo `space-between` nie zepchneloby go w prawo. */
.kform__hint::after {
  content: '';
  margin-left: auto;
  width: 14px;
  height: 7px;
  border-left: 2px solid var(--c-safe);
  border-bottom: 2px solid var(--c-safe);
  opacity: 0;
  transform: rotate(-45deg) scale(0.4);
  pointer-events: none;
  transition: opacity   var(--d-fast) var(--ease-out),
              transform var(--d-normal) var(--ease-out);
}
.kform__hint:empty::after {
  opacity: 1;
  transform: rotate(-45deg) scale(1);
}

/* ...ale w wersji krokowej wiersz jest ZAREZERWOWANY, nawet pusty: gdyby
   znikal, pole i przyciski podskakiwalyby dokladnie w chwili, w ktorej
   krok robi sie poprawny. Ta sama zasada, co przy oknie krokow wyzej -
   uklad ma stac, zmieniac ma sie tresc. Rezerwa liczona z wiersza tekstu,
   nie z ptaszka: tekst jest wyzszy, wiec to on wyznacza wysokosc.

   `display: flex`, nie `block` - pusty wiersz nadal ustawia ptaszek po
   prawej stronie (patrz .kform__hint wyzej). Bez JS ta klasa nie pada
   w ogole i pusty wiersz po prostu znika, bo nie ma tam czego pilnowac. */
.kform--kroki .kform__hint {
  display: flex;
  min-height: calc(var(--t-xs) * var(--lh-body));
}

/* blad dostaje kreske po lewej - ten sam znak, co przy krokach procesu
   (patrz .proces__krok): pionowa linia znaczy "tu patrz". Sam kolor tekstu
   ginal w panelu, komunikat wygladal jak kolejna podpowiedz.

   KOLOR TO --c-err, NIE CZERWIEN MARKI (2026-08-11). Czerwien marki dawala
   tu 2,51 przy progu 4,5 - najgorszy kontrast w calym serwisie, i akurat
   w stanie, w ktorym czytelnosc decyduje o tym, czy zgloszenie w ogole
   dotrze. --c-err daje 4,78 na tym panelu (uzasadnienie wartosci
   w tokens.css). Kreska idzie tym samym kolorem, ale zostaje jako DRUGI
   nosnik znaczenia obok koloru - komunikat da sie znalezc takze wtedy,
   gdy odcien nie jest rozrozniany. */
.kform__status {
  font-size: var(--t-sm);
}
.kform__status.is-err {
  padding-left: var(--s-3);
  border-left: 2px solid var(--c-err);
  color: var(--c-err);
}

.kform__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
  margin-top: var(--s-2);   /* + gap formularza = jeden pelny stopien odstepu */
}

/* .lnk ustawia display:inline-flex, co bije atrybut [hidden] (te sama
   specyficznosc, .lnk pochodzi z arkusza autora wiec wygrywa z domyslnym
   stylem UA) - bez tej reguly "Wstecz" byl widoczny tez na kroku 1 */
.kform__back[hidden] { display: none; }

/* placeholder pusty - trzyma przycisk akcji po prawej, gdy "Wstecz" jest
   schowane (krok 1, tak samo jak w kreatorze kancelarii) */
.kform__back[hidden] + .btn { margin-left: auto; }

.kform__done-title {
  font-family: var(--f-display);
  font-size: var(--t-h3);
  font-weight: var(--w-semi);
}
.kform__done-body {
  margin-top: var(--s-2);
  color: var(--c-text-2);
}

/* pole-pulapka dla botow: poza kadrem, ale obecne w DOM, zeby skrypty
   wypelniajace kazde pole i tak je zlapaly */
.hp {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}


/* ══ AKORDEON FAQ ══════════════════════════════════════════════════════
   details/summary - pelna dostepnosc i obsluga klawiatury bez ani jednej
   linii JS. Znacznik rozwiniecia to plus zmieniajacy sie w minus.

   Rozwijanie jest animowane w czystym CSS (`::details-content`), bez
   mierzenia wysokosci w JS i bez zadnego opakowania w dodatkowy div.
   Szczegoly przy regule nizej. */

.faq__item {
  border-bottom: 1px solid var(--c-border);
}

.faq__q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-6);
  padding-block: var(--s-6);
  cursor: pointer;
  list-style: none;
  font-family: var(--f-display);
  font-size: var(--t-h3);
  font-weight: var(--w-medium);
  line-height: var(--lh-head);
  transition: color var(--d-fast) var(--ease-out);
}
.faq__q::-webkit-details-marker { display: none; }
.faq__q:hover { color: var(--c-brand); }

/* znacznik: dwie kreski, pionowa znika po rozwinieciu */
.faq__mark {
  position: relative;
  flex: none;
  width: 16px;
  height: 16px;
}
.faq__mark::before,
.faq__mark::after {
  content: '';
  position: absolute;
  inset: 50% 0 auto 0;
  height: 1.5px;
  background: currentColor;
  transition: transform var(--d-normal) var(--ease-out);
}
.faq__mark::after { transform: rotate(90deg); }
[open] .faq__mark::after { transform: rotate(0deg); }

.faq__a {
  max-width: var(--w-text);
  padding-bottom: var(--s-6);
  color: var(--c-text-2);
}

/* ── animacja rozwijania ─────────────────────────────────────────────
   `::details-content` to cala zawartosc <details> poza <summary>, jako
   jeden element do animowania. Bez niego animacja akordeonu wymaga albo
   mierzenia wysokosci w JS, albo sztucznego wrappera z `grid-template-rows:
   0fr -> 1fr` - tu nie potrzeba ani jednego, ani drugiego.

   Trzy rzeczy musza zagrac naraz, inaczej nie ma animacji:
   1. `interpolate-size: allow-keywords` - bez tego `block-size: auto` jest
      wartoscia nieanimowalna i przejscie po prostu przeskakuje,
   2. `content-visibility` z `transition-behavior: allow-discrete` -
      zamkniete <details> ma tresc ukryta w sposob nieciagly; bez tego
      wpisu tresc znikalaby natychmiast przy zwijaniu, zanim wysokosc
      zdazy zjechac,
   3. `overflow: clip` - w trakcie przejscia tresc jest wyzsza niz jej
      pole i bez przyciecia wychodzilaby na sasiednie pytanie.

   Caly blok stoi w `@supports`, bo silniki bez `::details-content` musza
   dostac dzialajacy akordeon bez animacji, a nie polamany z animacja.
   `interpolate-size` jest wlaczone TYLKO tutaj i tylko dla tego poddrzewa
   - to wlasciwosc dziedziczona, wiec na :root zmienialaby zachowanie
   kazdego przejscia wysokosci w serwisie. */

@supports selector(::details-content) {

  .faq__lista { interpolate-size: allow-keywords; }

  .faq__item::details-content {
    block-size: 0;
    overflow: clip;
    opacity: 0;
    transition: block-size  var(--d-normal) var(--ease-out),
                opacity     var(--d-normal) var(--ease-out),
                content-visibility var(--d-normal) allow-discrete;
  }

  .faq__item[open]::details-content {
    block-size: auto;
    opacity: 1;
  }
}


/* ══ STOPKA ════════════════════════════════════════════════════════════ */

/* ODCHUDZONA 2026-08-11 (zgloszenie klienta: "dosc dluga jak na drobna
   sekcje"). Stopka miala na telefonie ok. 600 px wysokosci przy dwoch
   listach po trzy pozycje. Zlozylo sie na to troje:
   pionowe logo (96 px + wlasne swiatlo), jedna kolumna na wszystko
   i 64 px odstepu nad paskiem dolnym. Wszystkie trzy sa nizej. */
.footer {
  /* clamp zamiast progu: 48 px na telefonie, 64 px od ok. 1070 px szerokosci */
  padding-block: clamp(var(--s-12), 6vw, var(--s-16)) var(--s-8);
  border-top: 1px solid var(--c-border);
  background: var(--c-bg);
}

/* Na waskim ekranie marka bierze caly wiersz, a DWIE LISTY staja obok
   siebie w wierszu drugim - to one dawaly stopce polowe dlugosci, stojac
   jedna pod druga przy zawartosci szerokiej na jedno slowo.
   `auto` dla "Serwis" (najdluzsze: "Kontakt", ok. 60 px) i cala reszte dla
   kolumny kontaktowej, ktora musi zmiescic adres e-mail w jednej linii
   (~175 px przy 242 px do dyspozycji na ekranie 390 px). Odwrotnie -
   przy rownych `1fr` - adres lamalby sie na dwie linie. */
.footer__grid {
  display: grid;
  gap: var(--s-8) var(--s-10);
  grid-template-columns: auto minmax(0, 1fr);
}

.footer__brand { grid-column: 1 / -1; }

/* Logo POZIOME, nie pionowe (2026-08-11, decyzja klienta) - to samo
   `iv-lg-long.svg`, co w naglowku. Pionowy wariant konczyl stopke bryla
   wysoka na 96 px, ktora nie mowila nic wiecej niz ten sam znak polozony.
   40 px wysokosci to 216 px szerokosci - wyraznie wiecej niz 32 px znaku
   w naglowku, wiec stopka nadal zamyka strone marka, a nie jej powtorka. */
.footer__logo img { height: 40px; width: auto; }

.footer__tagline {
  margin-top: var(--s-4);
  max-width: 28ch;
  color: var(--c-text-muted);
  font-size: var(--t-sm);
}

/* h2, nie h3 - stopka jest własnym punktem orientacyjnym dokumentu. */
.footer__col h2 {
  margin-bottom: var(--s-4);
  color: var(--c-text-muted);
  font-family: var(--f-body);
  font-size: var(--t-xs);
  font-weight: var(--w-medium);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

.footer__col li + li { margin-top: var(--s-2); }

.footer__col a {
  color: var(--c-text-2);
  font-size: var(--t-sm);
  transition: color var(--d-fast) var(--ease-out);
}
.footer__col a:hover { color: var(--c-text); }

.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-4);
  /* 40 px na telefonie, 64 px od ok. 1070 px - patrz komentarz przy .footer */
  margin-top: clamp(var(--s-10), 5vw, var(--s-16));
  padding-top: var(--s-6);
  border-top: 1px solid var(--c-border);
  color: var(--c-text-muted);
  font-size: var(--t-xs);
}

/* Polityka prywatnosci stoi w dolnym pasku, nie w kolumnie "Serwis" - to
   nie jest tresc oferty, tylko dokument, ktorego szuka sie na samym dole.

   PODKRESLENIE JEST STALE (2026-08-11). Wczesniej wchodzilo dopiero pod
   kursorem, przy zalozeniu, ze "sam kursor i zmiana koloru wystarcza za
   rozroznienie". Zalozenie przestalo byc prawdziwe: odnosnik dziedziczy kolor
   paska, wiec w spoczynku byl wizualnie NIEODROZNIALNY od dwoch szarych
   napisow obok - nic (ani kolor, ani kroj, ani podkreslenie) nie mowilo, ze
   to jedyny klikalny element w pasku. Kursor pojawia sie dopiero, gdy juz sie
   go szuka, a na dotyku nie ma go wcale. Dokument prawny ma dawac sie znalezc
   wzrokiem (WCAG 1.4.1).
   Podkreslenie idzie kolorem krawedzi, nie tekstu, wiec odnosnik jest
   rozpoznawalny, a nie glosniejszy od reszty stopki. */
/* wspoldzielona z .footer__autor a nizej - ten sam podpis wykonawcy
   niesie ten sam wzorzec podkreslenia, patrz komentarz przy .footer__autor */
.footer__bottom a,
.footer__autor a {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--c-border-hover);
  text-underline-offset: 0.2em;
  transition: color var(--d-fast) var(--ease-out),
              text-decoration-color var(--d-fast) var(--ease-out);
}
.footer__bottom a:hover,
.footer__autor a:hover {
  color: var(--c-text);
  text-decoration-color: currentColor;
}

/* ── PODPIS WYKONAWCY ──
   Osobny wiersz POD paskiem praw i polityki, bez wlasnej kreski: to
   dopisek do stopki, a nie jej trzecia sekcja. Stopien i kolor te same, co
   w pasku wyzej - nizej w skali juz nic nie ma - wiec hierarchie niesie
   sama pozycja i to, ze podkreslony jest wylacznie odnosnik.
   Regula podkreslenia odnosnika jest wspoldzielona z `.footer__bottom a`
   wyzej (byla bajtowo identyczna w obu miejscach, scalone 2026-08-14):
   odnosnik dziedziczy kolor otoczenia, wiec bez kreski nie da sie go
   odroznic od tekstu obok. */
.footer__autor {
  margin-top: var(--s-4);
  color: var(--c-text-muted);
  font-size: var(--t-xs);
}

@media (min-width: 760px) {
  /* od tego progu marka wraca do wlasnej kolumny obok list */
  .footer__grid { grid-template-columns: 1.6fr 1fr 1fr; gap: var(--s-16); }
  .footer__brand { grid-column: auto; }
  .footer__logo img { height: 44px; }
}
