/* ══════════════════════════════════════════════════════════════════════════════
   RDZEŃ — style wspólne dla WSZYSTKICH stron docelowych.            WERSJA: 10
   ══════════════════════════════════════════════════════════════════════════════
   ⛔ TU NIE MA WYGLĄDU. Zero kolorów marki, zero krojów pisma, zero układu.
      Dwie strony docelowe mają się RÓŻNIĆ — to jest sens, za który klient płaci.

   Jest tu wyłącznie to, czego nigdy nie projektujemy od nowa:
   dostępność, czytelność, stany interakcji, zachowanie przy ruchu.
   Wszystko sterowane zmiennymi, żeby każda strona nadała temu swój wygląd.

   Wpinać PRZED `app.css` strony:
     <link rel="stylesheet" href="assets/rdzen.css?v=10">
     <link rel="stylesheet" href="assets/app.css?v=N">

   Poprawka idzie do tego pliku, nie do kopii w repo klienta.
   ══════════════════════════════════════════════════════════════════════════════ */

:root{
  /* hover zdjęć — lekcja 2026-08-04-001: scale(1.05) skakał kadrem i wyglądał tanio */
  --img-zoom:1.02;
  --img-rest:brightness(.95) saturate(.99);
  --img-hot:brightness(1.06) saturate(1.05);
  --img-dur:.55s;
  --ease:cubic-bezier(.2,.7,.3,1);
  /* cień pod napisem leżącym na zdjęciu — lekcja 2026-08-06-004.
     Wartości dobrane tak, żeby ratować czytelność, a nie przyciemniać kadru. */
  --cien-na-zdjeciu:0 1px 2px rgba(0,0,0,.58),0 2px 22px rgba(0,0,0,.46);
  --cien-na-zdjeciu-lekki:0 1px 2px rgba(0,0,0,.55),0 1px 12px rgba(0,0,0,.4);
}

*{box-sizing:border-box}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth}
img{max-width:100%;height:auto;display:block}
a{color:inherit}

/* ── DOSTĘPNOŚĆ ──────────────────────────────────────────────────────────── */
/* obrys focusa MUSI zostać — bez niego strona jest nieobsługiwalna z klawiatury */
:focus-visible{outline:2.5px solid currentColor;outline-offset:3px;border-radius:2px}
.sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}
.skip{position:absolute;left:-9999px;top:0;padding:12px 18px;z-index:200}
.skip:focus{left:12px;top:12px}

/* ── ŁAMANIE TEKSTU ──────────────────────────────────────────────────────────
   Lekcja 2026-08-06-003: „wodno-kanalizacyjne” pękało po dywizie i druga linia
   zaczynała się od końcówki wyrazu. Generator owija takie wyrazy w .nw. */
.nw{white-space:nowrap}
h1,h2,h3{text-wrap:balance}          /* bez tego zostaje sierota w ostatniej linii */
p,li{text-wrap:pretty}

/* ── NAPISY NA ZDJĘCIU ───────────────────────────────────────────────────────
   Lekcja 2026-08-06-001 i 2026-08-07-015: biały tekst na jasnym kadrze znika,
   a bramka nie policzy kontrastu z kodu, bo tłem jest fotografia.
   Każdy napis leżący na zdjęciu dostaje cień — kosztuje nic, ratuje czytelność. */
.na-zdjeciu,.hero h1,.hero-lead,.hero .kicker,.hero-cap{text-shadow:var(--cien-na-zdjeciu)}
.na-zdjeciu-lekko{text-shadow:var(--cien-na-zdjeciu-lekki)}

/* ── STANY ─────────────────────────────────────────────────────────────────── */
/* pojawianie się sekcji; klasa is-in dokładana przez rdzen.js z bezpiecznikami */
.rv{opacity:0;transform:translateY(14px);transition:opacity .7s var(--ease),transform .7s var(--ease)}
.rv.is-in{opacity:1;transform:none}
/* BEZ JAVASCRIPTU treść musi po prostu BYĆ — klasę `js` dokłada rdzeń w pierwszej
   linijce, więc gdy skrypt nie wystartuje (blokada, błąd sieci, stara przeglądarka),
   nic nie zostaje ukryte. Bez tego strona bywa PUSTA i nikt tego nie widzi. */
html:not(.js) .rv,html:not(.js) .kaskada>*,html:not(.js) .proces-line > li{opacity:1!important;transform:none!important;animation:none!important}
/* górny pasek chowany przy przewijaniu w dół */
.top.is-hidden{transform:translateY(-102%)}

/* hover zdjęć w galeriach i kafelkach */
.tile img,.mosaic img,.gateway img,.m-tile img,.galeria img{
  transition:transform var(--img-dur) var(--ease),filter var(--img-dur) var(--ease)}
@media (hover:hover){
  .tile img,.mosaic img,.gateway img,.m-tile img,.galeria img{filter:var(--img-rest)}
  .tile:hover img,.mosaic a:hover img,.gateway:hover img,.m-tile:hover img,.galeria a:hover img{
    transform:scale(var(--img-zoom));filter:var(--img-hot)}
}

/* ── OSADZENIA ŁADOWANE PO KLIKNIĘCIU ────────────────────────────────────────
   Decyzja K. 07.08.2026: mapa łączy się z Google dopiero po kliknięciu, więc
   strona nie potrzebuje banera cookies. Zasłona ma wyglądać jak część strony,
   nie jak błąd — kolory i kroje dokłada `app.css`. */
[data-po-kliknieciu]{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:14px;text-align:center;padding:28px;width:100%}
.pk-btn{cursor:pointer;border:0}

/* ── RUCH PRZY PRZEWIJANIU (blok 10 rdzen.js) ────────────────────────────────
   Tu siedzi wyłącznie MECHANIKA: rytm, czasy, sposób wchodzenia. Kolory,
   grubości i kształty dokłada `app.css` każdej strony z osobna. */

/* KASKADA — dzieci wchodzą po kolei; `--i` ustawia rdzeń.
   Krok 70 ms: przy 5 pozycjach ostatnia rusza po 0,35 s, więc oko wodzi po
   sekcji, a nikt nie czeka na treść.

   🔴 WEJŚCIE ROBI `animation`, NIE `transition` (naprawa 16.08.2026, PEC STAL).
   Poprzednia wersja stała na `transition` + `transition-delay` — i to były DWIE
   ciche wady naraz, obie na KAŻDEJ naszej stronie:
     1. `.kaskada>*` (0,1,1) bije specyficznością zwykłą klasę kafla (0,1,0), więc
        NADPISYWAŁA cały `transition` dziecka. Kafel, któremu `app.css` ustawił
        reakcję na kursor w 0,12 s, i tak dostawał 0,55 s.
     2. Gorsze: `transition-delay` z kaskady zostaje na elemencie NA ZAWSZE i dotyczy
        każdej późniejszej zmiany. Ósmy kafel w siatce miał `--i:7`, czyli 490 ms —
        po najechaniu podświetlenie zapalało się z pół sekundy później (K. zgłaszał
        „opóźnienie na hoverze" DWA razy; za pierwszym skróciłem czas przejścia,
        co nie mogło pomóc, bo winny był delay z zupełnie innej reguły).
   `animation` nie dotyka `transition` dziecka, a `backwards` trzyma stan początkowy
   tylko w czasie oczekiwania — po zakończeniu wjazdu element wraca pod kontrolę
   reguł niżej i reaguje natychmiast. */
.kaskada>*{opacity:0;transform:translateY(16px)}
.kaskada.is-in>*{opacity:1;transform:none;
  animation:kaskada-wjazd .55s var(--ease) backwards;
  animation-delay:calc(var(--i,0) * 70ms)}
@keyframes kaskada-wjazd{from{opacity:0;transform:translateY(16px)}}

/* PASEK POSTĘPU CZYTANIA — wygląd (kolor, wysokość) należy do app.css */
.postep{position:fixed;top:0;left:0;right:0;height:2px;z-index:120;
  transform:scaleX(0);transform-origin:left center;pointer-events:none;
  transition:transform .1s linear}

/* OŚ PROCESU (blok 11) — TYLKO mechanika stanów. Kolory, odstępy, kształt
   numerów i kreski należą do `app.css` każdej strony z osobna.
   `os-on` na <html> dokłada skrypt: bez niego kroki są po prostu widoczne. */
.os-on .proces-line > li{opacity:0;transform:translateY(14px);
  transition:opacity .55s var(--ease),transform .55s var(--ease),color .35s ease}
.os-on .proces-line > li.os-seen{opacity:1;transform:none}
.proc-bar > i{transition:width .25s linear}
/* wypełnienie osi rośnie płynnie razem z przewijaniem; kolor i grubość w app.css */
.proces-line{position:relative}
.proces-line::before{content:"";position:absolute;left:0;top:0;width:1px;
  height:var(--os-fill,0);transition:height .25s linear;pointer-events:none}

/* PARALAKSA — element musi mieć własną warstwę, inaczej przeglądarka
   przerysowuje przy każdym przewinięciu i strona zaczyna się szarpać */
[data-paralaksa]{will-change:transform}

/* PRZEJŚCIE MIĘDZY PODSTRONAMI — zamiast białego mrugnięcia.
   Wychodzimy szybciej (.22s) niż wchodzimy (.4s): czekanie na wyjście czuć
   jak zacięcie, a spokojne wejście czyta się jak dopracowanie. */
.przejscie-wejscie body{opacity:0}
body{opacity:1;transition:opacity .4s var(--ease)}
.przejscie-wyjscie body{opacity:0;transition-duration:.22s}

/* Kto prosi system o mniej animacji, ma je dostać wyłączone — inaczej strona
   potrafi wywołać mdłości. Treść zostaje widoczna. */
@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;
    transition-duration:.01ms!important}
  .rv{opacity:1!important;transform:none!important}
  .kaskada>*,.os-on .proces-line > li{opacity:1!important;transform:none!important;animation:none!important}
  body{opacity:1!important}
  .postep{display:none}
}

/* ── DRUK ────────────────────────────────────────────────────────────────────
   Klienci drukują ofertę i kontakt. Bez tego wychodzą puste sekcje i menu. */
@media print{
  .top,.burger,.lb,.skip,[data-po-kliknieciu]{display:none!important}
  .rv,.kaskada>*,.proces-line > li{opacity:1!important;transform:none!important;animation:none!important}
  body{opacity:1!important;background:#fff;color:#000}
  .postep{display:none!important}
}

/* ── PLAKIETKA OPINII GOOGLE ──────────────────────────────────────────────
   Wyjątek od zasady „tu nie ma wyglądu" i to świadomy: to nie jest wygląd
   NASZEJ strony, tylko cudzy znak firmowy (Google) plus dowód zaufania, który
   ma być rozpoznawalny wszędzie tak samo - jak logotyp, nie jak nasza typografia.
   Decyzja K. 13.08.2026: „jak dajemy gdzieś na hero info o opiniach z Google,
   róbmy to wszędzie w obu silnikach tak, jak zrobił to Marceli".
   Wygląd i tak zostaje w rękach strony: tło i obwódka liczą się z KOLORU TEKSTU
   (currentColor), a rozmiar, promień i krój dziedziczą się z otoczenia -
   zmienne poniżej można nadpisać w app.css.
   HTML (gwiazdki wypełnia się szerokością prostokąta w clipPath - patrz SKILL.md).
   ──────────────────────────────────────────────────────────────────────── */
:root{
  --gb-tlo:color-mix(in srgb,currentColor 8%,transparent);
  --gb-obwodka:color-mix(in srgb,currentColor 20%,transparent);
  --gb-gwiazdka:#FBBC04;              /* kolor gwiazdek z systemu Google */
  --gb-promien:999px;
}
.g-badge{
  display:inline-flex;align-items:center;gap:.62em;
  padding:.52em 1em;border-radius:var(--gb-promien);
  background:var(--gb-tlo);border:1px solid var(--gb-obwodka);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px);
  font-size:.98rem;line-height:1;font-weight:500;letter-spacing:.01em;
  white-space:nowrap;vertical-align:middle;max-width:100%}
.g-badge .gb-ico,.g-badge .gb-stars{flex:none}
.g-badge .gb-ocena{font-weight:700;font-size:1.08em}
.g-badge .gb-txt{opacity:.92}
.g-badge .gb-stars .gb-peln{fill:var(--gb-gwiazdka)}
.g-badge .gb-stars .gb-pusta{fill:currentColor;opacity:.26}
@media(max-width:560px){
  .g-badge{gap:.45em;padding:.45em .8em;font-size:.86rem}
  .g-badge .gb-stars{width:62px;height:12.4px}
  .g-badge .gb-ico{width:16px;height:16px}
}
