/*
Theme Name: Prosty Website
Description: Elastyczny motyw potomny FSE bazujący na Frost.
Author: Prosty Website
Template: frost
Version: 1.0.0
*/

/* Tutaj wklejasz swój "Core CSS" (np. klasy narzędziowe, płynną typografię, animacje),
   zgodnie z "Zasadą powyżej 50 linijek". */

/* 1) TOKENS
   Selektor ma obok ":root" także "body". Powód: WordPress, wczytując ten
   plik do edytora, doprefiksowuje selektory klasą .editor-styles-wrapper,
   a ":root" to <html>, które nie jest jej potomkiem - tokeny by tam nie
   dojechały. "body" transformacja zamienia na samą nakładkę, więc docierają.
   Na froncie duplikat nic nie zmienia: body i tak dziedziczy z :root. */
:root,
body{
  /* fluid spacing: mobile -> desktop */
  --space-1: clamp(6px, 0.6vw, 8px);
  --space-2: clamp(12px, 1.2vw, 16px);
  --space-3: clamp(18px, 1.8vw, 24px);
  --space-4: clamp(24px, 2.4vw, 32px);
  --space-5: clamp(36px, 3.6vw, 48px);
  /* --space-6 to w praktyce rytm sekcji - jedyny odbiorca to padding
     .section. Podniesione z clamp(48px, 5vw, 72px), bo sekcje nie mają
     już między sobą blockGap (patrz sekcja 3) i trzeba było oddać te
     ~32px, które on wcześniej dokładał. */
  --space-6: clamp(56px, 6vw, 88px);

  /* Dwa promienie, jedna zasada:
     małe elementy interaktywne (przyciski, pigułki) -> --radius-pill,
     powierzchnie (karty, panele, pola formularza)   -> --radius-2.
     Wcześniej krążyły cztery wartości naraz (6, 8, 12, 999) i pigułka
     nagłówka gryzła się z kanciastym przyciskiem w środku.
     UWAGA: przycisk ma własny promień w theme.json (styles → elements →
     button → border). Zmieniasz tu - zmień i tam, inaczej się rozjadą. */
  --radius-2: 12px;
  --radius-pill: 999px;

  /* Wysokość przyklejonego nagłówka + zapas. Jedna liczba obsługuje
     i kotwice (scroll-padding-top), i panele position: sticky w treści -
     wcześniej stała wpisana osobno w każdym miejscu. Zmierzona: 134px
     na desktopie, 93px na telefonie. Popraw, jeśli sekcja po kliknięciu
     w kotwicę ląduje za wysoko albo za nisko. */
  --header-offset: 150px;

  /* --line to SKRÓT do koloru "line" z palety, nie osobna wartość. Sam
     kolor siedzi w theme.json, żeby dało się go wybrać w edytorze; tutaj
     jest tylko krótsza nazwa, bo używamy go w 20 miejscach.
     UWAGA przy dokładaniu kolejnych skrótów: nie nadawaj im nazw, które
     WordPress już generuje z palety (np. --surface przy slugu "surface") -
     dwie zmienne o tej samej nazwie w różnych przestrzeniach to gwarantowana
     pomyłka przy czytaniu kodu. */
  /* ZASADA KOLORU - trzymaj się jej przy każdej nowej regule:
     primary (niebieski) = MARKA. Logo, linki w tekście, nadtytuły,
       znaczniki list, kreski wyróżnień, duże liczby.
     accent (pomarańczowy) = AKCJA, czyli KAŻDY przycisk wypełniony.
       Ustawiony w theme.json jako domyślne tło przycisku, więc nie trzeba
       go wybierać w edytorze - wypełniony przycisk jest pomarańczowy sam
       z siebie. Drugi i jedyny dozwolony wariant to kontur.
       Przycisków niebieskich nie używamy w ogóle. */
  --line: var(--wp--preset--color--line);

  /* Złoto gwiazdek. NIE w palecie i nie w kolorach marki - to cudzy
     sygnał (ocena Google), a nie element naszej identyfikacji. W próbniku
     edytora byłby tylko szumem, bo nigdy nie wybiera się go ręcznie.
     Odcień dobrany do palety: #F59E0B to ten sam rodowód co reszta
     (slate/blue/orange), więc nie gryzie się z resztą strony. */
  --star: #F59E0B;
  --icon-star: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23000'%3E%3Cpath d='M12 17.27L18.18 21l-1.64-7.03L22 9.24l-7.19-.61L12 2 9.19 8.63 2 9.24l5.46 4.73L5.82 21z'/%3E%3C/svg%3E");

  /* Znaczniki list jako maski SVG. Maska bierze z pliku tylko kształt
     (kanał alfa), a kolor daje background-color - dzięki temu ptaszek
     dziedziczy kolor z motywu i skaluje się z rozmiarem tekstu.
     Kreska rysowana stroke'em z zaokrąglonymi końcami: obramowania CSS
     nie mają round cap i wychodziły cienkie oraz ostro ścięte. */
  --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12.5 9.5 17.5 19.5 6.5'/%3E%3C/svg%3E");
  --icon-cross: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3.2' stroke-linecap='round'%3E%3Cpath d='M6.5 6.5 17.5 17.5M17.5 6.5 6.5 17.5'/%3E%3C/svg%3E");

  /* Ikony pływającego przycisku kontaktu (zestaw Feather, licencja MIT). */
  /* Ikony "załączników" w sekcji rozmowy (Feather, licencja MIT). */
  --icon-doc: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z'/%3E%3Cpath d='M14 2v6h6'/%3E%3Cpath d='M16 13H8'/%3E%3Cpath d='M16 17H8'/%3E%3C/svg%3E");
  --icon-list: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 11l3 3L22 4'/%3E%3Cpath d='M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11'/%3E%3C/svg%3E");
  --icon-link: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3C/svg%3E");

  /* Ikony osi czasu po uruchomieniu (Feather, licencja MIT). */
  --icon-unlock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='11' width='18' height='11' rx='2' ry='2'/%3E%3Cpath d='M7 11V7a5 5 0 0 1 9.9-1'/%3E%3C/svg%3E");
  --icon-edit: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h9'/%3E%3Cpath d='M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z'/%3E%3C/svg%3E");
  --icon-branch: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='6' y1='3' x2='6' y2='15'/%3E%3Ccircle cx='18' cy='6' r='3'/%3E%3Ccircle cx='6' cy='18' r='3'/%3E%3Cpath d='M18 9a9 9 0 0 1-9 9'/%3E%3C/svg%3E");
  --icon-exit: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'/%3E%3Cpolyline points='16 17 21 12 16 7'/%3E%3Cline x1='21' y1='12' x2='9' y2='12'/%3E%3C/svg%3E");
  --icon-arrow-down: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cpolyline points='19 12 12 19 5 12'/%3E%3C/svg%3E");

  --icon-plus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'%3E%3Cline x1='12' y1='5' x2='12' y2='19'/%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3C/svg%3E");

  --icon-arrow-right: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'/%3E%3Cpolyline points='12 5 19 12 12 19'/%3E%3C/svg%3E");

  --icon-phone: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z'/%3E%3C/svg%3E");

  /* Kolory marek obcych. Świadomie NIE w palecie theme.json: to nie są
     kolory tej strony, tylko znaki rozpoznawcze cudzych serwisów, i nie
     wolno ich podmieniać pod klienta. Jedyne kolory na sztywno w tym pliku. */
}

/* 2) BAZA i WCAG */
*{ box-sizing: border-box; }

body{
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

:where(p, ul, ol){
  line-height: 1.7;
}

/* Przeglądarka sama wyrównuje długość wierszy w nagłówku, zamiast łamać
   tam, gdzie akurat skończy się miejsce. Kasuje sieroty w rodzaju jednego
   słowa w drugiej linii. Lepsze od ręcznego <br>, bo działa przy każdej
   szerokości ekranu - <br> wstawiony pod desktop łamie telefon w złym
   miejscu. Starsze przeglądarki po prostu to ignorują i łamią jak dotąd. */
:where(h1, h2, h3, h4){
  text-wrap: balance;
}

:where(a){
  text-underline-offset: 0.2em;
}

/* Nowoczesny stany focus dla nawigacji klawiaturą (WCAG) */
:focus-visible {
  outline: 2px solid var(--wp--preset--color--primary, #000);
  outline-offset: 4px;
  border-radius: 2px;
}

/* Wyłączenie domyślnego focusa myszką, zostawiamy tylko dla klawiatury */
:focus:not(:focus-visible) {
  outline: none;
}

/* 3) SEKCJE */
.section{
  padding-top: var(--space-6);
  padding-bottom: var(--space-6);
}

.section--tight{
  padding-top: var(--space-4);
  padding-bottom: var(--space-4);
}

/* Sekcje mają się stykać - własny padding w zupełności wystarcza.
   Bez tego WordPress wstawia między nie blockGap (32px na desktopie),
   a że sekcje są alignfull, pasek przyjmuje kolor tła STRONY. Dopóki
   sąsiedzi są jaśni, nikt tego nie widzi; przy sekcji z własnym tłem
   (ciemne CTA, cennik) wychodzi jasna szpara nad nią.
   Dwie klasy biją regułę .wp-container-... > * + *, więc bez !important. */
.wp-block-group.section{
  margin-block-start: 0;
}

/* Ta sama szpara pod ostatnią sekcją: <main> ma w szablonie dolny padding
   (preset space-7, do 72px), a pod nim leci jeszcze blockGap do stopki.
   Oba widać jako pasek, gdy strona kończy się sekcją z własnym tłem.
   !important, bo padding <main> jest w szablonie stylem inline. */
.site-content:has(.section:last-child){
  padding-bottom: 0 !important;
}

footer.site-footer{
  margin-block-start: 0;
}

/* 4) HERO: większy oddech + lepszy rytm.
   Nad hero sumowały się CZTERY odstępy: padding stopki nagłówka (30px),
   blockGap między częściami szablonu (32px), padding górny <main> (48px)
   i własny padding tej sekcji (~105px) - razem ponad 200px pustki.
   Regułą niżej kasujemy dwa środkowe, a tutaj ścinamy własny padding, więc
   odstęp nad hero ma jedno miejsce do regulacji zamiast czterech. */
.section--hero{
  padding-top: clamp(48px, 5.5vw, 88px);
  padding-bottom: clamp(40px, 5vw, 96px);
}

/* H1 w hero większy niż zwykły tytuł podstrony.
   Preset "huge" obsługuje H1 na KAŻDEJ stronie - szablon "Page" wstawia
   z niego tytuł strony - więc podniesienie go w theme.json zawyżyłoby
   też "Polityka prywatności". Hero dostaje własny rozmiar tutaj.
   Dlaczego w ogóle: przy presecie "huge" H1 ma na desktopie 44px, a H2
   38px - stosunek 1,16. Zdrowa skala typograficzna trzyma 1,25-1,5, więc
   nagłówek strony ginął wśród dziewięciu H2. Przy 52px stosunek to 1,37.
   Mobile celowo zostaje na 32px (tyle co "huge"): przy wadze 800
   najdłuższe polskie słowa zajmują już ~75% szerokości telefonu. */
.section--hero h1{
  font-size: clamp(2rem, 4.5vw, 3.25rem);
}

/* :has() sprawdza, czy pierwszym blokiem treści jest hero - zwykłe
   podstrony (z tytułem wstawianym przez szablon) zachowują swój odstęp.
   !important, bo padding <main> siedzi w szablonie jako styl inline
   i żaden selektor bez tego go nie przebije. */
.site-content:has(.section--hero:first-child){
  margin-block-start: 0 !important;
  padding-top: 0 !important;
}

.section--hero .stack > * + *{
  margin-top: var(--space-3);
}

/* 5) STACK: rytm pionowy treści (dla mniejszych komponentów) */
.stack > * + *{
  margin-top: var(--space-3);
}

.stack--tight > * + *{
  margin-top: var(--space-2);
}

/* 6) LEAD: tekst pod nagłówkiem */
.lead{
  font-size: clamp(1.05rem, 0.8vw + 1rem, 1.25rem);
  line-height: 1.6;
  opacity: .85;
  max-width: 65ch; /* miękko ogranicza długość wiersza */
}

/* 7) GRID */
.grid{
  display: grid;
  gap: var(--space-3);
}

.grid-2{ grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3{ grid-template-columns: repeat(3, minmax(0, 1fr)); }

@media (max-width: 900px){
  .grid-2, .grid-3{ grid-template-columns: 1fr; }
}

/* Automatyczny, płynny Grid (bez Media Queries) */
.grid-auto {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
}

/* 8) CARD */
/* Karta = czysta biel z palety (DECYZJE.md: „karty wybiją się z tła”),
   a nie przygaszone tło. Cień z presetu „Subtelny (Karty)”
   z theme.json - dzięki niemu karta czyta się także wtedy, gdy stoi na
   białej sekcji, gdzie samo tło jej nie odcina. */
.card{
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  background: var(--wp--preset--color--surface);
  box-shadow: var(--wp--preset--shadow--subtle);
  padding: var(--space-4);
}

/* Modyfikator wymuszający równą wysokość w siatkach Grid */
.card-flex {
  height: 100%;
  display: flex;
  flex-direction: column;
}

/* 9) FADE-IN
   Klasa .fade-section jest obsługiwana przez skrypt animacji z functions.php
   (dostaje .anim-fade) - style w sekcji "ANIMACJE WEJŚĆ" na końcu pliku.
   Dzięki temu bez JS treść nigdy nie zostaje niewidoczna. */

/* 10) EYEBROW – mały podpis nad nagłówkiem */
.eyebrow{
  display: inline-block;
  /* Był tu font mono. Po przejściu na jeden font eyebrow trzyma się na
     wielkich literach, rozstrzeleniu i kresce - nie na kroju.
     600 zamiast 500, bo zwykły font sans jest optycznie lżejszy niż
     JetBrains Mono Medium i przy 12px kapitaliki się rozmywały. */
  font-weight: 600;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--wp--preset--color--primary);
  padding-left: 12px;
  position: relative;
}

.eyebrow::before{
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 6px;
  height: 1px;
  background: currentColor;
}

/* 11) LIFT HOVER – subtelne uniesienie kart */
.lift{
  transition: transform .25s ease, box-shadow .25s ease;
  will-change: transform;
}

.lift:hover{
  transform: translateY(-3px);
  /* preset „Uniesiony (Hover)” z theme.json - ta sama skala cieni co .card */
  box-shadow: var(--wp--preset--shadow--elevated);
}

/* wyłącz animacje dla osób z reduced motion */
@media (prefers-reduced-motion: reduce){
  .lift{
    transition: none;
  }
  .lift:hover{
    transform: none;
    box-shadow: none;
  }
}

/* 12) LINK UNDERLINE – subtelna animacja */
:where(p, li, .lead) a{
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-size: 0% 1px;
  background-position: 0 100%;
  background-repeat: no-repeat;
  transition: background-size .3s ease;
}

:where(p, li, .lead) a:hover{
  background-size: 100% 1px;
}

/* 13) LISTS – czysto i czytelnie */
:where(ul, ol){
  padding-left: 1.2em;
  margin: 0;
}

:where(ul, ol) li{
  margin: 0;
}

:where(ul, ol) li + li{
  margin-top: 0.4em;
}

/* opcjonalnie: subtelniejszy marker */
:where(ul) li::marker{
  opacity: .6;
}

/* 1. Upewniamy się, że cały flexbox nawigacji trzyma oś środkową */
ul.wp-block-navigation__container {
    align-items: center;
}

/* 2. Szeroki reset - celujemy we wszystkie 'li' oraz linki 'a' na każdym poziomie zagnieżdżenia wewnątrz nawigacji */
.wp-block-navigation ul.wp-block-navigation__container li,
.wp-block-navigation ul.wp-block-navigation__container li + li,
.wp-block-navigation ul.wp-block-navigation__container a {
    margin-top: 0;
    margin-bottom: 0;
    margin-block-start: 0;
    margin-block-end: 0;
}

/* 3. Przyciski hamburgera/zamykania menu mobilnego - bez domyślnej ramki przeglądarki */
.wp-block-navigation__responsive-container-open,
button.wp-block-navigation__responsive-container-close {
    border: 0 !important;
    outline: none;
    box-shadow: none;
    background: transparent;
}

/* 4. Logo w headerze (plik SVG) - WordPress nie generuje metadanych
   wymiarów dla SVG w Bibliotece Mediów, więc suwak "Szerokość" w bloku
   Logo witryny nie ma z czego wyliczyć proporcji i logo renderuje się
   w swoim natywnym rozmiarze zapisanym w pliku (może wyjść na całą
   szerokość headera). Wymuszamy rozmiar przez CSS - !important nadpisuje
   inline style dopisywany przez sam blok.
   Sterujemy WYSOKOŚCIĄ, nie szerokością. Logo to szeroki wordmark
   (proporcje 8,48:1), więc o czytelności decyduje wysokość napisu -
   ograniczanie szerokości potrafi niepostrzeżenie zejść do kilkunastu
   pikseli wysokości i litery robią się nieostre. Szerokość dolicza się
   sama z proporcji pliku.
   Wysokość przez MAX-HEIGHT, nie height: przy sztywnej height i ciasnym
   pasku max-width przycina samą szerokość, a wysokość zostaje - logo
   wychodzi spłaszczone w poziomie. Przy max-height obraz zmniejsza się
   w obu wymiarach naraz i proporcja zostaje zachowana.
   PODMIEŃ dwie wartości px (28 / 22) pod logo konkretnego klienta. */
.wp-block-site-logo,
.custom-logo-link {
    width: auto !important;
    max-width: 100% !important;
}

.wp-block-site-logo img,
.wp-block-site-logo .custom-logo,
.custom-logo-link img {
    max-height: 28px !important;
    height: auto !important;
    width: auto !important;
    max-width: 100% !important;
}

/* Na mobile (ten sam próg co "is-style-hidden-mobile" w Frost) mniejsze. */
@media (max-width: 600px) {
    .wp-block-site-logo img,
    .wp-block-site-logo .custom-logo,
    .custom-logo-link img {
        max-height: 20px !important;
    }
}

/* 5. Nagłówek pływający – pasek odklejony od krawędzi, zaokrąglony.
   Klasę .header-floating dodaj w Edytorze witryny na WEWNĘTRZNEJ grupie
   nagłówka (tej „alignwide”, która trzyma logo i nawigację w jednym
   rzędzie) - nie na grupie zewnętrznej. Odstęp paska od krawędzi ekranu
   robi padding grupy zewnętrznej, ustawiany w edytorze - z wyjątkiem
   mobile, gdzie nadpisujemy go niżej. */
.header-floating{
  background: var(--wp--preset--color--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  box-shadow: var(--wp--preset--shadow--subtle);
  padding: var(--space-2) var(--space-4);
}

/* Poniżej 600px nagłówek łamie się na dwa wiersze - pełne zaokrąglenie
   dałoby wtedy kształt stadionu, więc schodzimy do zwykłego promienia.
   Ścinamy też padding grupy zewnętrznej z 30px do 16px: przy przyklejonym
   nagłówku 30px z góry i z dołu zjadało ok. 17% wysokości ekranu telefonu
   przez cały czas przewijania. !important, bo blok dopisuje ten padding
   inline'em z edytora - zwykła reguła by nie wygrała. Celujemy w grupę
   będącą bezpośrednim dzieckiem .site-header, żeby nie dotykać losowych
   klas .wp-container-core-group-is-layout-XXXX. */
@media (max-width: 600px){
  .header-floating{
    border-radius: var(--radius-2);
    padding: var(--space-2) var(--space-3);
  }

  .site-header > .wp-block-group{
    padding: 16px !important;
  }
}

/* 6. Nagłówek przyklejony przy przewijaniu - OPCJONALNY, włączany klasą.
   Dodaj klasę .header-sticky w Edytorze witryny na wewnętrznej grupie
   nagłówka (tej samej, na której ewentualnie siedzi .header-floating).
   Samo sticky musi trafić na .site-header, a nie na tę grupę: rodzic grupy
   jest wysoki dokładnie na nagłówek, więc przyklejony pasek nie miałby po
   czym jechać. Stąd :has() - klasę wpisujesz w edytorze w jednym miejscu,
   a działa na właściwym elemencie. Dzięki temu padding grupy zewnętrznej
   jedzie razem z paskiem i odstęp od górnej krawędzi zostaje zachowany po
   przewinięciu. Działa ze zwykłym nagłówkiem i z .header-floating. */
.site-header:has(.header-sticky){
  position: sticky;
  top: 0;
  z-index: 100;
}

/* Pasek admina WordPressa jest position:fixed dopiero powyżej 782px
   i zasłoniłby przyklejony nagłówek - schodzimy o jego wysokość.
   Niżej pasek admina przewija się razem ze stroną, więc offset szkodzi. */
@media (min-width: 783px){
  body.admin-bar .site-header:has(.header-sticky){
    top: 32px;
  }
}

/* Kotwice (linki do #sekcji) nie mogą chować się pod przyklejonym paskiem.
   Wartość = wysokość nagłówka (134px zmierzone) + zapas; popraw, jeśli
   sekcja ląduje za wysoko albo za nisko. */
html{
  scroll-padding-top: var(--header-offset);
}

/* Na mobile nagłówek jest niższy (93px zmierzone - mniejszy padding
   i mniejsze logo), więc zapas też musi być mniejszy. */
@media (max-width: 600px){
  :root,
  body{
    --header-offset: 110px;
  }
}

/* 14) LIST CLEAN – minimalistyczna lista */
.list-clean{
  list-style: none;
  padding-left: 0;
  margin: 0;
}

.list-clean li{
  position: relative;
  padding-left: 1.2em;
}

.list-clean li + li{
  margin-top: 0.6em;
}

.list-clean li::before{
  content: "–";
  position: absolute;
  left: 0;
  top: 0;
  opacity: .6;
}

/* 15) HEADING RHYTHM – logiczna hierarchia

   Uwaga na specyficzność: :where() waży zero, a WordPress generuje dla
   każdego kontenera regułę blockGap (.wp-container-... > * + *) o wadze
   jednej klasy. Reguły z :where() poniżej działają więc TYLKO tam, gdzie
   blok nie ma ustawionego blockGap. Gdzie ma - trzeba celować mocniej,
   jak w regule dla leadu niżej. */

/* większy dystans po H1 i H2 */
:where(h1, h2) + *{
  margin-top: var(--space-3);
}

/* Lead jest podtytułem nagłówka, nie osobnym blokiem treści - ma się z nim
   kleić. Globalny blockGap daje na desktopie 32px i rozrywa tę parę na dwa
   niezależne bloki. min() przycina odstęp do 24px, czyli tyle, ile wychodzi
   na telefonie, gdzie proporcja była dobra - i zostaje przy tokenie, więc
   zmiana skali odstępów nadal tu dojdzie.
   Selektor z elementem (0,1,1) bije regułę blockGap (0,1,0) - bez !important. */
h1 + .lead,
h2 + .lead{
  margin-top: min(var(--space-4), 24px);
}

/* trochę mniejszy po H3-H4 */
:where(h3, h4) + *{
  margin-top: var(--space-3);
}

/* W kartach o odstępach decyduje blockGap, który WordPress generuje jako
   .wp-container-... > * + * - ta reguła ma wyższą specyficzność niż
   :where() powyżej i wygrywała, przez co nagłówek kleił się do tekstu.
   W zwykłych kartach podniosłem blockGap w markupie; tutaj zostaje
   .card__body (karta ze zdjęciem), gdzie łańcuch eyebrow -> H3 -> akapit
   ma być ciasny wszędzie POZA przejściem H3 -> akapit. Trzy klasy, więc
   wygrywa bez !important. */
.card .card__body > h3 + *{
  margin-top: var(--space-3);
}

/* jeśli nagłówek nie jest w stack */
:where(h1, h2){
  margin-bottom: var(--space-2);
}

/* =========================================
   SECTION ALT – ULTRA SUBTLE
   ========================================= */

.section--alt{
  background: rgba(0,0,0,0.02);
}

/* =========================================
   SECTION ALT – SOFT CONTRAST
   ========================================= */

.section--alt-contrast{
  background: rgba(0,0,0,0.04);
}

/* ==========================================================================
   ANIMACJE WEJŚĆ (fade-in + stagger dla kart)
   Współpracuje ze skryptem IntersectionObserver z functions.php
   (frost_child_animation_observer_script) - bez tego CSS-a skrypt
   dodaje klasy, ale nic się wizualnie nie dzieje.
   Skrypt pomija: H1, wszystko widoczne przy załadowaniu strony (hero),
   elementy z klasą .no-anim (lub w kontenerze z .no-anim).
   ========================================================================== */

.anim-fade {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity 0.5s ease, transform 0.5s ease;
}

.anim-fade.is-visible {
    opacity: 1;
    transform: translateY(0);
}

/* Stagger — opóźnienia dla kart w gridzie.
   Rozszerzone do 12: przy siatce dłuższej niż lista opóźnień nadmiarowe
   karty wjeżdżały bez zwłoki i rząd rozjeżdżał się w połowie. */
.anim-stagger .card:nth-child(1)  { transition-delay: 0ms; }
.anim-stagger .card:nth-child(2)  { transition-delay: 80ms; }
.anim-stagger .card:nth-child(3)  { transition-delay: 160ms; }
.anim-stagger .card:nth-child(4)  { transition-delay: 240ms; }
.anim-stagger .card:nth-child(5)  { transition-delay: 320ms; }
.anim-stagger .card:nth-child(6)  { transition-delay: 400ms; }
.anim-stagger .card:nth-child(7)  { transition-delay: 480ms; }
.anim-stagger .card:nth-child(8)  { transition-delay: 560ms; }
.anim-stagger .card:nth-child(9)  { transition-delay: 640ms; }
.anim-stagger .card:nth-child(10) { transition-delay: 720ms; }
.anim-stagger .card:nth-child(11) { transition-delay: 800ms; }
.anim-stagger .card:nth-child(12) { transition-delay: 880ms; }

@media (prefers-reduced-motion: reduce) {
    .anim-fade,
    .anim-stagger .card {
        opacity: 1 !important;
        transform: none !important;
        transition: none !important;
    }
}

/* ==========================================================================
   KARTY W PĘTLI ZAPYTAŃ (Query Loop)
   Sekcja 12 (LINK UNDERLINE) dodaje podkreślenie-gradient do wszystkich
   linków w <p>/<li>/.lead. Tytuł i miniatura wewnątrz .card są linkami
   z bloku Query Loop, więc trzeba im to podkreślenie wyłączyć i zostawić
   tylko czystą zmianę koloru na hover.
   ========================================================================== */

.card .wp-block-post-title,
.card .wp-block-post-featured-image {
    text-decoration: none !important;
}

.card .wp-block-post-title a,
.card .wp-block-post-title a:hover,
.card .wp-block-post-title a:focus,
.card .wp-block-post-featured-image a,
.card .wp-block-post-featured-image a:hover,
.card .wp-block-post-featured-image a:focus {
    text-decoration: none !important;
    text-decoration-line: none !important;
    box-shadow: none !important;
    border: none !important;
    background: transparent !important;
    outline: none !important;
}

.card .wp-block-post-title a:hover,
.card .wp-block-post-title a:focus {
    color: var(--wp--preset--color--primary);
    transition: color 0.3s ease;
}

/* ==========================================================================
   FLUENT FORMS – dopasowanie do typografii i kolorystyki strony
   Selektory podbite o .fluentform (2 klasy), żeby bez !important nadpisać
   domyślne, jednoklasowe reguły wtyczki (.ff-el-form-control itd.).
   Zakłada darmową wersję Fluent Forms - sprawdź klasy na konkretnym
   formularzu (Inspect), jeśli coś nie zadziała 1:1.
   ========================================================================== */

.fluentform .ff-el-input--label label {
    font-family: var(--wp--preset--font-family--primary);
    font-weight: 600;
    color: var(--wp--preset--color--contrast);
}

.fluentform .ff-el-form-control {
    font-family: var(--wp--preset--font-family--primary);
    color: var(--wp--preset--color--contrast);
    background-color: var(--wp--preset--color--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-2); /* pole to powierzchnia, nie pigułka */
}

.fluentform .ff-el-form-control:focus {
    border-color: var(--wp--preset--color--primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--wp--preset--color--primary) 20%, transparent);
    outline: none;
}

/* Gwiazdka przy wymaganych polach (np. "Imię *") */
.fluentform .ff-el-is-required.asterisk-right label:after,
.fluentform .ff-el-is-required.asterisk-right:after {
    color: var(--wp--preset--color--primary);
}

.fluentform .ff-btn.ff-btn-submit.ff_btn_style {
    background-color: var(--wp--preset--color--accent);
    color: var(--wp--preset--color--white);
    border: none;
    border-radius: var(--radius-pill); /* tak samo jak globalny przycisk z theme.json */
    font-family: var(--wp--preset--font-family--primary);
    font-weight: 700;
    letter-spacing: 0.02em;
    transition: background-color 0.3s ease;
}

.fluentform .ff-btn.ff-btn-submit.ff_btn_style:hover {
    /* !important - domyślny hover Fluent Forms (przygaszenie/szarość)
       ma wyższą specyficzność albo dokłada opacity/filter, więc bez tego
       nasz kolor nie wygrywał. Przycisk wtyczki nie jest blokiem przycisku,
       więc nie łapie się na filter z reguły wyżej - ciemnienie robimy tu
       mieszanką z czernią, co daje ten sam efekt co brightness(0.88). */
    background-color: color-mix(in srgb, var(--wp--preset--color--accent) 88%, #000) !important;
    opacity: 1 !important;
    filter: none !important;
}

/* ==========================================================================
   SYSTEM SEKCJI PODSTRON
   Zestaw klas używanych przez markup podstron z _robocze/. Świadomie ograniczony:
   każda nowa podstrona ma się składać z TYCH klocków, nie z nowych za każdym razem.
   ========================================================================== */

/* 16) SEKCJA ALIGNFULL – awaryjny padding boczny
   Sekcje podstron to grupy "alignfull" z układem "constrained". WordPress
   zwykle dokłada im klasę .has-global-padding (bo motyw nadrzędny ma
   useRootPaddingAwareAlignments), ale nie w każdej wersji i nie w każdym
   kontekście - a bez tego na telefonie tekst dotyka krawędzi ekranu.
   Dokładamy padding TYLKO wtedy, gdy WordPress tego nie zrobił, więc
   nigdy nie wychodzi podwójny odstęp. */
.section:not(.has-global-padding){
  padding-inline: var(--wp--style--root--padding-left, var(--space-3));
}

/* 17) PROOF – rząd krótkich faktów pod przyciskami w hero.
   Znacznik "ptaszka" rysowany z obramowań, nie znakiem ✓ - generowana
   treść bywa czytana przez czytniki ekranu ("znak zaznaczenia") i byłaby
   tu tylko szumem. */
.proof{
  list-style: none;
  padding-left: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  font-size: var(--wp--preset--font-size--small);
}

.proof li{
  position: relative;
  padding-left: 1.6em;
}

/* nadpisuje :where(ul, ol) li + li z sekcji 13 - w rzędzie nie chcemy odstępu w pionie */
.proof li + li{
  margin-top: 0;
}

/* Na telefonie każdy fakt w osobnym wierszu. W rzędzie z zawijaniem
   o układzie decydowała długość tekstu, więc skrócenie jednej pozycji
   przestawiało całość - tak stało się po usunięciu "VAT" z "Umowa,
   faktura VAT". W kolumnie wygląda tak samo niezależnie od treści.
   Próg 600px, nie 781px: powyżej trzy krótkie fakty mieszczą się
   w jednym rzędzie i kolumna marnowałaby tam miejsce. */
@media (max-width: 600px){
  .proof{
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-2);
  }
}

.proof li::before{
  content: "";
  position: absolute;
  left: 0;
  top: 0.35em;
  width: 1em;
  height: 1em;
  background-color: var(--wp--preset--color--primary);
  -webkit-mask: var(--icon-check) center / contain no-repeat;
          mask: var(--icon-check) center / contain no-repeat;
}

/* 18) LIST-CHECK / LIST-CROSS – listy "tak" i "nie"
   Do sekcji "dla kogo to jest" i do wyliczenia zakresu w cenniku.
   Oba znaczniki rysowane z obramowań (patrz komentarz przy .proof). */
.list-check,
.list-cross{
  list-style: none;
  padding-left: 0;
  margin: 0;
}

.list-check li,
.list-cross li{
  position: relative;
  padding-left: 1.7em;
}

.list-check li + li,
.list-cross li + li{
  margin-top: 0.6em;
}

.list-check li::before,
.list-cross li::before{
  content: "";
  position: absolute;
  left: 0;
  top: 0.35em;
  width: 1em;
  height: 1em;
}

.list-check li::before{
  background-color: var(--wp--preset--color--primary);
  -webkit-mask: var(--icon-check) center / contain no-repeat;
          mask: var(--icon-check) center / contain no-repeat;
}

/* krzyżyk przygaszony - "to nie dla Ciebie" ma informować, nie krzyczeć */
.list-cross li::before{
  background-color: currentColor;
  opacity: 0.4;
  -webkit-mask: var(--icon-cross) center / contain no-repeat;
          mask: var(--icon-cross) center / contain no-repeat;
}

/* 19) STEPS – numerowany przebieg współpracy
   Zwykły <ol> z licznikiem CSS: numeracja zostaje w semantyce listy, a
   wygląd numeru jest w pełni nasz (::marker nie da się stylować tak swobodnie
   we wszystkich przeglądarkach). <strong> na początku <li> robi się tytułem
   kroku - dzięki temu krok nie potrzebuje własnego nagłówka i hierarchia
   H2 -> H3 na stronie zostaje czysta. */
.steps{
  list-style: none;
  padding-left: 0;
  margin: 0;
  counter-reset: step;

  /* Szerokość kolumny na cyfrę. Od niej zależy wcięcie treści ORAZ pozycja
     pionowej kreski, więc jedna zmiana przesuwa oba naraz i nic się nie
     rozjeżdża. Kolumna mieści też liczby dwucyfrowe. */
  --step-col: 2.25rem;

  /* Wysokość wiersza tytułu kroku = rozmiar fontu H3 razy jego interlinia.
     Cyfra dostaje pudełko dokładnie tej wysokości i jest w nim wyśrodkowana
     w pionie, więc trafia w środek tytułu zamiast wisieć nad nim.
     Liczone z presetu, nie wpisane na sztywno - preset jest płynny (clamp),
     więc przy zmianie szerokości ekranu cyfra jedzie razem z tytułem. */
  --step-title-line: calc(var(--wp--preset--font-size--x-large) * 1.3);
}

.steps li{
  counter-increment: step;
  position: relative;
  padding-left: calc(var(--step-col) + var(--space-3));
}

.steps li + li{
  margin-top: var(--space-4);
}

.steps li::before{
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  width: var(--step-col);
  height: var(--step-title-line);
  display: flex;
  align-items: center;      /* wyśrodkowanie cyfry względem tytułu */
  justify-content: center;  /* wyśrodkowanie w kolumnie, pod kreską */
  /* Cyfra siedzi w kolumnie o stałej szerokości (--step-col), a fonty sans
     mają domyślnie cyfry proporcjonalne - w Plus Jakarta Sans "1" jest
     niemal dwa razy węższa od "0", więc bez tabular-nums numery kroków
     stałyby nierówno. Wcześniej pilnował tego font mono, którego już nie ma.
     Przy zmianie fontu sprawdź tylko, czy ma funkcję "tnum". */
  font-variant-numeric: tabular-nums;
  font-size: 1.75rem;
  font-weight: 600;
  line-height: 1;
  color: var(--wp--preset--color--primary);
  opacity: 0.35;
}

/* pionowa kreska łącząca numery - podkreśla, że to jeden ciąg, a nie
   luźne punkty. Startuje pod pudełkiem cyfry i biegnie do następnego
   kroku. Jeśli przeszkadza, skasuj cały ten blok. */
.steps li:not(:last-child)::after{
  content: "";
  position: absolute;
  left: calc(var(--step-col) / 2 - 0.5px);
  top: calc(var(--step-title-line) + var(--space-1));
  bottom: calc(-1 * var(--space-4));
  width: 1px;
  background: var(--line);
}

.steps li strong{
  display: block;
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 600;
  line-height: 1.3; /* ta sama wartość co w --step-title-line */
  letter-spacing: 0;
  margin-bottom: var(--space-2);
}

/* 20) CARD--MEDIA – karta ze zdjęciem na całą szerokość
   Zdjęcie dotyka krawędzi karty, treść dostaje własny padding w .card__body.
   aspect-ratio + object-fit wyrównują karty w siatce, nawet gdy zdjęcia
   mają różne proporcje - bez tego rząd realizacji się rozjeżdża. */
.card--media{
  padding: 0;
  overflow: hidden;
}

.card--media > .wp-block-image{
  margin: 0;
}

.card--media > .wp-block-image img{
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
}

.card__body{
  padding: var(--space-4);
}

/* przy .card-flex treść rozpycha się tak, żeby link "Zobacz stronę"
   trzymał się dolnej krawędzi w każdej karcie */
.card--media.card-flex > .card__body{
  flex: 1;
}

/* 21a) UPSELL – pozycje podnoszące cenę, z kwotą po prawej
   Każdy wiersz to grupa z trzema akapitami zamiast jednego <li> z wstawkami
   <span>: nazwa, cena i opis są wtedy osobnymi, edytowalnymi blokami,
   a nie inline'em, który edytor potrafi zjeść przy pierwszej poprawce.
   Układ składa grid, nie kolejność w markupie. */
.upsell{
  display: flex;
  flex-direction: column;
}

.upsell__row{
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas:
    "mark name  price"
    "mark opis  opis";
  column-gap: var(--space-2);
  padding: var(--space-3) 0;
}

/* currentColor, nie --line: ta sekcja bywa ciemna i czarna kreska
   byłaby na niej niewidoczna. Tak kreska dopasowuje się do tła sama. */
.upsell__row + .upsell__row{
  border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent);
}

.upsell__row::before{
  content: "";
  grid-area: mark;
  width: 14px;
  height: 14px;
  margin-top: 0.3em;
  background-color: currentColor;
  opacity: 0.55;
  -webkit-mask: var(--icon-plus) center / contain no-repeat;
          mask: var(--icon-plus) center / contain no-repeat;
}

.upsell__name{
  grid-area: name;
  margin: 0;
  font-weight: 600;
}

.upsell__price{
  grid-area: price;
  margin: 0;
  text-align: right;
  white-space: nowrap;   /* "od 500 zł / szt." nie ma się łamać */
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.8;
}

.upsell__desc{
  grid-area: opis;
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.7;
}

/* 21) PRICE-BOX – panel z ceną wyjściową
   Tło "base" (nie surface), bo panel stoi na białej sekcji cennika. */
.price-box{
  background: var(--wp--preset--color--base);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  padding: var(--space-4);
}

/* cena i "netto" w jednym wierszu, wyrównane do linii pisma -
   WordPress w układzie flex domyślnie centruje w pionie, przez co mały
   dopisek wisiałby w połowie wysokości dużej kwoty */
.price-box__row{
  align-items: baseline;
}

.price-box__net{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.7;
}

.price-box__amount{
  font-size: clamp(2rem, 4vw, 2.75rem);
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
  color: var(--wp--preset--color--primary);
}

/* 22) NOTE – wyróżniony akapit (zastrzeżenie, koszt poza umową, gwarancja) */
.note{
  border-left: 3px solid var(--wp--preset--color--primary);
  padding: var(--space-2) 0 var(--space-2) var(--space-3);
  font-size: var(--wp--preset--font-size--small);
}

/* 23) FAQ – rozwijane pytania na bloku "Szczegóły" (core/details)
   Natywny <details> - żadnej wtyczki do akordeonów. Domyślny trójkącik
   podmieniamy na strzałkę rysowaną z obramowań. */
.faq .wp-block-details{
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  background: var(--wp--preset--color--surface);
  box-shadow: var(--wp--preset--shadow--subtle); /* jedna skala cieni z .card */
  padding: var(--space-3) var(--space-4);
}

.faq .wp-block-details summary{
  display: block; /* warunek zadziałania list-style: none w Firefoksie */
  list-style: none;
  cursor: pointer;
  font-weight: 600;
  position: relative;
  padding-right: var(--space-4);
}

.faq .wp-block-details summary::-webkit-details-marker{
  display: none; /* Safari nie respektuje list-style na summary */
}

.faq .wp-block-details summary::after{
  content: "";
  position: absolute;
  right: 2px;
  top: 0.35em;
  width: 0.5em;
  height: 0.5em;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 0.2s ease;
  opacity: 0.5;
}

.faq .wp-block-details[open] summary::after{
  transform: rotate(-135deg);
}

.faq .wp-block-details[open] summary{
  margin-bottom: var(--space-2);
}

@media (prefers-reduced-motion: reduce){
  .faq .wp-block-details summary::after{
    transition: none;
  }
}

/* 24) CTA-DARK – zamykająca sekcja na grafitowym tle */
.cta-dark .eyebrow{
  /* Czysty primary (#2563EB) na contrast (#1E293B) daje 2,83:1 - poniżej
     wymaganych 4,5:1 dla tekstu 12px. Rozjaśnienie bielą wychodzi na
     5,30:1, czyli AA z zapasem. */
  color: color-mix(in srgb, var(--wp--preset--color--primary) 65%, #fff);
}

/* 25) PANEL – biała płyta na treść (np. formularz na ciemnej sekcji) */
.panel{
  background: var(--wp--preset--color--surface);
  border-radius: var(--radius-2);
  padding: var(--space-4);
}

/* dwie klasy, żeby wygrać z .has-white-color dziedziczonym z ciemnej sekcji */
.cta-dark .panel{
  color: var(--wp--preset--color--contrast);
}

/* !important - Frost ustawia elements.link na kolor contrast, więc ciemna
   sekcja musi wymusić białe linki przez elements.link na grupie. WordPress
   generuje takie reguły blokowe z !important i obejmują one CAŁĄ sekcję,
   razem z białą płytą - bez tego link w akapicie pod formularzem byłby
   biały na białym. Trzy selektory biją regułę WordPressa (.wp-elements-hash
   a), więc przy równym !important wygrywa ta.
   primary (#2563EB) na bieli = 5,17:1, czyli AA. */
.cta-dark .panel a:where(:not(.wp-element-button)){
  color: var(--wp--preset--color--primary) !important;
}

/* 26) TEXT-CENTER – wyśrodkowanie całej sekcji jednym przełącznikiem.
   Blok „Grupa” nie ma w edytorze suwaka wyrównania tekstu, więc bez tej
   klasy trzeba centrować każdy blok z osobna. Co gorsza, listy (.proof,
   .list-check) w ogóle takiego suwaka nie mają i zostają po lewej, nawet
   gdy reszta sekcji jest wyśrodkowana.
   Klasę dodajesz w edytorze na grupie sekcji:
   panel bloku → Zaawansowane → Dodatkowe klasy CSS.

   Środek działa dopiero od tabletu w górę. Na telefonie treść wraca do
   lewej: wyśrodkowany akapit łamany na wiele wierszy ma poszarpaną lewą
   krawędź i oko za każdym razem szuka początku linii. Przy siedmiu
   wierszach leada na telefonie robi się to męczące.
   Próg 600px ten sam, co w regułach nagłówka wyżej. */
@media (min-width: 601px){
  .text-center{
    text-align: center;
  }

  /* .lead ma max-width 65ch - bez automatycznych marginesów zostałby
     przyklejony do lewej krawędzi mimo wyśrodkowanego tekstu w środku. */
  .text-center .lead{
    margin-inline: auto;
  }

  /* Flex nie reaguje na text-align, więc rzędy trzeba wyśrodkować osobno. */
  .text-center .proof,
  .text-center .wp-block-buttons{
    justify-content: center;
  }
}

/* Bloki, którym wyrównanie ustawiono osobno w edytorze, niosą własną klasę
   .has-text-align-center - sam zasięg @media wyżej by ich nie ruszył.
   Zdejmujemy to TYLKO wewnątrz .text-center, więc świadome wyśrodkowanie
   pojedynczego bloku gdzie indziej na stronie zostaje nietknięte. */
@media (max-width: 600px){
  .text-center .has-text-align-center{
    text-align: left;
  }
}

/* Treść list zostaje wyrównana do lewej. Wyśrodkowany tekst przy znaczniku
   przyklejonym do lewej krawędzi rozjeżdża się wizualnie - środkujemy samą
   listę jako blok, nie jej wiersze. */
.text-center :where(.list-check, .list-cross, .list-clean, .steps),
.text-center .proof li{
  text-align: left;
}

/* 27) SR-ONLY – tekst widoczny tylko dla czytników ekranu.
   Nie display:none ani visibility:hidden - te ukryłyby go także przed
   czytnikiem. Element zostaje w drzewie dostępności, tylko schodzi
   z ekranu do prostokąta 1x1 px. */
.sr-only{
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   29) PRZYCISKI – stan po najechaniu
   Ciemnienie robi filter: brightness(), a NIE podmiana koloru w theme.json:
   1. przycisk z kolorem ustawionym w edytorze dostaje klasę
      .has-*-background-color, którą WordPress generuje z !important -
      hover z theme.json w ogóle go nie rusza;
   2. filter nie walczy o tło, tylko przyciemnia gotowy piksel, więc działa
      tak samo na przycisku domyślnym i na przemalowanym w edytorze;
   3. nie trzeba utrzymywać drugiego, ciemniejszego koloru w palecie.
   Dlatego :hover w theme.json ma TEN SAM kolor co stan zwykły - jest tam
   tylko po to, żeby zablokować niebieski hover dziedziczony z Frosta.
   Biały tekst na przyciemnionym accent daje 6,32:1, czyli więcej niż
   w stanie spoczynku (5,18:1).
   ========================================================================== */
.wp-element-button,
.wp-block-button__link{
  transition: background-color .2s ease, border-color .2s ease,
              color .2s ease, filter .2s ease, transform .2s ease;
}

.wp-element-button:hover,
.wp-block-button__link:hover{
  transform: translateY(-1px);
}

/* Link tekstowy nie jest bryłą, więc nie ma czego unosić - uniesienie
   wyglądałoby jak drgnięcie tekstu. */
.wp-block-button.is-style-text-link > .wp-block-button__link:hover{
  transform: none;
}

/* Każdy przycisk WYPEŁNIONY, niezależnie od tego, czy kolor przyszedł
   z theme.json, czy został ustawiony w edytorze. Kontur wykluczony, bo ma
   przezroczyste tło - tam przyciemnianie zjadałoby tekst zamiast tła. */
.wp-block-button:not(.is-style-outline):not(.is-style-text-link) > .wp-block-button__link:hover{
  filter: brightness(0.88);
}

/* Wariant konturowy ma przezroczyste tło, więc ani podmiana koloru
   z theme.json, ani filter nic by na nim nie pokazały. Zmieniamy to,
   co u niego widać: obramowanie i tekst. */
.wp-block-button.is-style-outline > .wp-block-button__link:hover{
  border-color: var(--wp--preset--color--accent);
  color: var(--wp--preset--color--accent);
}

@media (prefers-reduced-motion: reduce){
  .wp-element-button,
  .wp-block-button__link{
    transition: none;
  }

  .wp-element-button:hover,
  .wp-block-button__link:hover{
    transform: none;
  }
}

/* ==========================================================================
   30) PRZYCISKI NA TELEFONIE – pełna szerokość
   Kciuk trafia w cały pas zamiast celować w pigułkę pośrodku ekranu,
   a dwa przyciski pod sobą tworzą czytelną kolejność ważności zamiast
   dzielić wiersz po połowie.
   Reguła ogólna plus wyjątek, a nie zasięg zawężony do .site-content:
   edytor bloków nie owija treści w <main class="site-content">, więc przy
   tamtym zapisie w edytorze nic by się nie pokazało. Tak napisane działa
   w obu miejscach - w edytorze po prostu nie ma nagłówka ani stopki,
   więc wyjątek nie ma czego wyłączać.
   ========================================================================== */
@media (max-width: 600px){
  .wp-block-buttons > .wp-block-button{
    width: 100%;
    /* flex-basis razem z width - sam width na elemencie flex potrafi
       zostać ściśnięty przez flex-shrink i przyciski zmieszczą się w rzędzie */
    flex-basis: 100%;
  }

  .wp-block-buttons > .wp-block-button > .wp-block-button__link{
    width: 100%;
    /* jawnie, bo sekcja 26 ustawia na telefonie text-align: left na całej
       sekcji .text-center i etykieta przykleiłaby się do lewej krawędzi */
    text-align: center;
  }

  /* Wyjątek: nagłówek i stopka. CTA w nagłówku siedzi na telefonie
     w rozwijanym menu i pas przez całą nakładkę wygląda źle.
     Ta sama specyficzność co reguła wyżej, ale stoi później, więc wygrywa. */
  .site-header .wp-block-button,
  .site-footer .wp-block-button{
    width: auto;
    flex-basis: auto;
  }

  .site-header .wp-block-button > .wp-block-button__link,
  .site-footer .wp-block-button > .wp-block-button__link{
    width: auto;
  }

  /* Wyjątek od wyjątku: przycisk w ROZWINIĘTYM menu na telefonie.
     Reguła wyżej zdejmuje pełną szerokość wszystkim przyciskom w nagłówku,
     bo CTA w pasku ma zostać pigułką obok logo. Ale w nakładce menu
     przycisk stoi pod pozycjami nawigacji jak zwykły przycisk w treści
     i pas przez całą szerokość jest tam właściwy - inaczej wygląda, jakby
     ktoś zapomniał go dokończyć.
     Trzy klasy biją .site-header (dwie), więc bez !important.
     .is-menu-open dokłada WordPress po otwarciu nakładki, więc w zamkniętym
     pasku ta reguła nie obowiązuje. */
  .wp-block-navigation__responsive-container.is-menu-open .wp-block-buttons,
  .wp-block-navigation__responsive-container.is-menu-open .wp-block-button,
  .wp-block-navigation__responsive-container.is-menu-open .wp-block-button > .wp-block-button__link{
    width: 100%;
    flex-basis: 100%;
  }

  /* Pozycje w rozwiniętej nakładce większe niż w pasku. Nakładka zajmuje
     cały ekran, więc tekst wielkości akapitu gubi się w niej i wygląda,
     jakby menu było puste. x-large to na telefonie 20px zamiast 17px.
     theme.json ustawia nawigacji rozmiar "medium" przez styl bloku, a nie
     przez klasę presetu, więc nie ma tam !important i trzy klasy wystarczą.
     Reguła wisi na .is-menu-open, czyli dotyczy WYŁĄCZNIE otwartej
     nakładki - pozioma nawigacja na desktopie zostaje bez zmian.
     UWAGA: razem z regułą wyżej zakłada domyślne ustawienie nawigacji
     "nakładka tylko na telefonie". Gdybyś przestawił ją na "zawsze",
     obie trzeba wyjąć z tego @media. */
  .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content{
    font-size: var(--wp--preset--font-size--x-large);
  }

  /* Przycisk wysyłki formularza nie jest blokiem przycisku, więc nie łapie
     się na regułę wyżej - a stojąc pod pełnowymiarowymi przyciskami
     w treści wyglądałby na niedokończony. */
  .fluentform .ff-btn.ff-btn-submit.ff_btn_style{
    width: 100%;
  }

  /* Link tekstowy zostaje szerokości tekstu. Pas przez cały ekran z samym
     podkreślonym napisem czytałby się jak pusty przycisk. */
  .wp-block-buttons > .wp-block-button.is-style-text-link,
  .wp-block-buttons > .wp-block-button.is-style-text-link > .wp-block-button__link{
    width: auto;
    flex-basis: auto;
  }
}

/* ==========================================================================
   31) SEKCJA DWUKOLUMNOWA Z PRZYKLEJONYM PANELEM
   Lewa kolumna (nagłówek, zdanie, CTA) stoi w miejscu, prawa przewija się
   obok. Przycisk zostaje w zasięgu wzroku przez całą długość listy, więc
   nie trzeba go powtarzać na dole sekcji.
   ========================================================================== */

/* .card z większym oddechem - domyślny space-4 jest pomyślany pod małą
   kartę w siatce, a nie pod płytę na całą szerokość sekcji. */
.card--roomy{
  padding: var(--space-5);
}

.sticky-panel{
  position: sticky;
  top: var(--header-offset);
}

/* Pasek admina jest position:fixed dopiero powyżej 782px i zepchnął
   nagłówek o swoją wysokość - przyklejony panel musi zejść tak samo,
   inaczej chowa się pod nagłówkiem. */
@media (min-width: 783px){
  body.admin-bar .sticky-panel{
    top: calc(var(--header-offset) + 32px);
  }
}

/* Poniżej 782px kolumny WordPressa układają się jedna pod drugą i panel
   nie ma już obok czego stać - przyklejony zjadałby pół ekranu telefonu
   razem z nagłówkiem. */
@media (max-width: 781px){
  .sticky-panel{
    position: static;
  }
}

/* --- lista pozycji: tytuł + opis w jednym wierszu listy --- */
.feature-list{
  list-style: none;
  padding: 0;
  margin: 0;
}

.feature-list li{
  position: relative;
  padding: var(--space-3) 0 var(--space-3) 2em;
  /* wiersz niesie styl OPISU, a tytuł nadpisuje go niżej - ten sam układ
     co w .steps, dzięki czemu pozycja to jeden edytowalny element listy */
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
  line-height: 1.5;
}

/* nadpisuje :where(ul, ol) li + li z sekcji 13 - odstęp robi padding,
   a rolę separatora przejmuje kreska */
.feature-list li + li{
  margin-top: 0;
  border-top: 1px solid var(--line);
}

.feature-list li::before{
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--space-3) + 0.15em);
  width: 1.15em;
  height: 1.15em;
  background-color: var(--wp--preset--color--primary);
  -webkit-mask: var(--icon-check) center / contain no-repeat;
          mask: var(--icon-check) center / contain no-repeat;
}

.feature-list strong{
  display: block;
  margin-bottom: 2px;
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 600;
  color: var(--wp--preset--color--contrast);
}

/* --- wiersz zbiorczy: drobniejsze pozycje bez osobnego opisu --- */
.feature-more{
  position: relative;
  margin: 0;
  padding: var(--space-3) 0 var(--space-3) 2em;
  border-top: 1px solid var(--line);
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* Trzy kropki rysowane cieniem, nie znakiem "…": generowana treść bywa
   odczytywana przez czytniki ekranu, a to czysta dekoracja. */
.feature-more::before{
  content: "";
  position: absolute;
  left: 0.2em;
  top: calc(var(--space-3) + 0.6em);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: currentColor;
  box-shadow: 6px 0 0 currentColor, 12px 0 0 currentColor;
}

/* --- przypis pod listą --- */
.feature-note{
  margin: 0;
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* ==========================================================================
   32) CHAT – proces pokazany jako rozmowa
   Dymki to zwykłe akapity z klasą, separatory kroków to H3 - dzięki temu
   czytnik ekranu dalej widzi strukturę kroków i da się po nich skakać,
   a edycja treści to edycja akapitu, nie grzebanie w kodzie.
   Zero JavaScriptu: cały układ robi flexbox i align-self.
   ========================================================================== */
.chat{
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-width: 640px;   /* rozmowa rozciągnięta na 840px przestaje nią wyglądać */
  margin-inline: auto;
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  /* tło "base", nie białe: sekcja jest biała i białe dymki po lewej
     nie miałyby się od czego odciąć */
  background: var(--wp--preset--color--base);
}

/* --- separator kroku --- */
.chat__step{
  align-self: center;
  margin: var(--space-3) 0 var(--space-1);
  /* H3 bierze z presetu x-large - tu ma być drobnym podpisem, nie nagłówkiem */
  font-size: var(--wp--preset--font-size--small);
  font-weight: 500;
  letter-spacing: 0;
  color: var(--wp--preset--color--muted);
}

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

/* rytm nagłówków z sekcji 15 dołożyłby tu margines ponad gap kontenera */
.chat :where(h3) + *{
  margin-top: 0;
}

/* --- dymki --- */
.chat__msg{
  max-width: min(78%, 42ch);
  margin: 0;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-2);
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.5;
}

.chat__msg--me{
  align-self: flex-start;
  background: var(--wp--preset--color--surface);
  border: 1px solid var(--line);
  color: var(--wp--preset--color--contrast);
}

.chat__msg--them{
  align-self: flex-end;
  /* rozjaśniony primary - kolor marki, nie przypadkowy błękit */
  background: color-mix(in srgb, var(--wp--preset--color--primary) 12%, var(--wp--preset--color--surface));
  color: var(--wp--preset--color--secondary);
}

/* dymek z załącznikiem jest grupą, więc akapit w środku traci margines */
.chat__msg > p:not(.chat__att){
  margin: 0;
}

/* --- "załącznik": ilustracja, nie link.
   Celowo nie jest klikalny i nie ma hoveru - obiecywałby działanie,
   którego nie ma. --- */
.chat__att{
  display: flex;
  align-items: center;
  gap: 8px;
  margin: var(--space-2) 0 0;
  padding: 8px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  background: var(--wp--preset--color--base);
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.3;
  color: var(--wp--preset--color--muted);
}

.chat__att::before{
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  background-color: var(--wp--preset--color--primary);
  -webkit-mask: var(--icon-doc) center / contain no-repeat;
          mask: var(--icon-doc) center / contain no-repeat;
}

.chat__att--list::before{
  -webkit-mask-image: var(--icon-list);
          mask-image: var(--icon-list);
}

.chat__att--link::before{
  -webkit-mask-image: var(--icon-link);
          mask-image: var(--icon-link);
}

@media (max-width: 600px){
  .chat{
    padding: var(--space-3);
  }

  /* na wąskim ekranie 78% zostawia za mało miejsca na tekst */
  .chat__msg{
    max-width: 88%;
  }
}

/* ==========================================================================
   33) TIMELINE – co dzieje się po uruchomieniu
   Oś czasu, która po 30 dniach rozwidla się na trzy warianty opieki.
   Etapy to .card, więc dziedziczą biel, obramowanie i cień z sekcji 8 -
   dzięki temu czytają się także na białej sekcji.
   ========================================================================== */
.timeline{
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

.timeline__item{
  position: relative;
  /* miejsce na ikonę po lewej; nadpisuje symetryczny padding z .card */
  padding-left: calc(var(--space-4) + 40px);
}

.timeline__item::before{
  content: "";
  position: absolute;
  left: var(--space-4);
  top: calc(var(--space-4) + 2px);
  width: 22px;
  height: 22px;
  background-color: var(--wp--preset--color--primary);
  -webkit-mask: var(--icon-unlock) center / contain no-repeat;
          mask: var(--icon-unlock) center / contain no-repeat;
}

.timeline__item--fix::before{
  -webkit-mask-image: var(--icon-edit);
          mask-image: var(--icon-edit);
}

.timeline__item--exit::before{
  -webkit-mask-image: var(--icon-exit);
          mask-image: var(--icon-exit);
}

/* Wyjście z umowy to nie etap, tylko furtka otwarta przez cały czas -
   przerywane obramowanie i brak cienia odróżniają je od kroków osi. */
.timeline__item--exit{
  border-style: dashed;
  box-shadow: none;
  background: transparent;
}

.timeline__when{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  font-weight: 500;
  color: var(--wp--preset--color--primary);
}

.timeline__title{
  /* H3 bierze z presetu x-large - tu ma być tytułem karty, nie nagłówkiem sekcji */
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 700;
  letter-spacing: 0;
}

/* Strzałka między etapami. Blok "Separator" zamiast pustego akapitu:
   to prawdziwy element do wstawienia w edytorze, a <hr> między etapami
   osi czasu jest uczciwym znaczeniem. */
.timeline__arrow{
  align-self: center;
  width: 18px;
  height: 18px;
  margin: 0;
  border: 0;
  background-color: color-mix(in srgb, var(--wp--preset--color--contrast) 45%, transparent);
  -webkit-mask: var(--icon-arrow-down) center / contain no-repeat;
          mask: var(--icon-arrow-down) center / contain no-repeat;
}

/* --- rozwidlenie --- */
.timeline__fork{
  margin: 0;
  text-align: center;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

.timeline__fork::before{
  content: "";
  display: block;
  width: 20px;
  height: 20px;
  margin: 0 auto var(--space-2);
  background-color: var(--wp--preset--color--primary);
  -webkit-mask: var(--icon-branch) center / contain no-repeat;
          mask: var(--icon-branch) center / contain no-repeat;
}

.branch{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-3);
}

.branch__name{
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 700;
  letter-spacing: 0;
}

.branch__price{
  /* .card-flex robi z karty kolumnę flex, więc auto spycha cenę na dół
     i ceny w trzech wariantach stoją w jednej linii mimo różnej długości opisu */
  margin-top: auto;
  padding-top: var(--space-2);
  font-weight: 700;
}

/* Wariant polecany. Obrys cieniem, nie grubszym obramowaniem - grubsze
   przesunęłoby zawartość o piksel względem sąsiadów. */
.branch__opt--featured{
  border-color: var(--wp--preset--color--primary);
  box-shadow: 0 0 0 1px var(--wp--preset--color--primary);
}

@media (max-width: 781px){
  .branch{
    grid-template-columns: 1fr;
  }
}

/* ==========================================================================
   34) SHOTS – zrzuty realizacji w ramkach przeglądarki pod hero
   Ramki rysowane w całości CSS-em, bez ani jednego obrazka na samą ramkę.
   Środkowa jest większa i uniesiona, boczne schodzą niżej i wychodzą poza
   dolną krawędź hero - stąd ujemny margines i position: relative.
   ========================================================================== */
.shots{
  /* Wysunięcie poniżej hero. Musi być MNIEJSZE niż górny padding następnej
     sekcji (--space-6, czyli 56-88px), inaczej ramki wejdą na jej nagłówek.
     clamp niżej trzyma się pod tym progiem na każdej szerokości. */
  --shots-overlap: clamp(32px, 4.5vw, 72px);

  display: flex;
  align-items: flex-start;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  margin-bottom: calc(-1 * var(--shots-overlap));
  padding-inline: var(--space-3);
  /* position bez z-index wystarcza: elementy pozycjonowane malują się
     w wyższej warstwie niż tła nienapozycjonowanych sekcji, więc ramki
     nie znikną pod tłem sekcji poniżej */
  position: relative;
}

/* Hero oddaje swój dolny padding, inaczej ramki nie miałyby jak wyjść
   poza jego krawędź - zamiast tego siedziałyby w pustym pasie. */
.section--hero:has(.shots){
  padding-bottom: 0;
}

.shot{
  flex: 1 1 0;
  min-width: 0;
  max-width: 460px;
}

.shot--featured{
  flex: 1.35 1 0;
  max-width: 620px;
}

/* Kolejność wizualna odwrócona względem kodu - na KAŻDEJ szerokości,
   także w karuzeli na telefonie.

   W kodzie wyróżniona ramka stoi PIERWSZA, bo WordPress przyznaje
   fetchpriority="high" i pomija lazy-loading dla pierwszego dużego
   obrazka w treści, kierując się kolejnością w kodzie, nie wielkością
   na ekranie. Na ekranie ma stać w środku - i tu to prostujemy.

   nth-of-type, NIE nth-child: pierwszym dzieckiem kontenera jest ukryty
   akapit dla czytników ekranu, który przesuwa całą numerację o jeden.
   nth-of-type liczy osobno dla każdego typu elementu, więc akapit nie
   wchodzi w rachubę z <div>-ami ramek. */
.shots > .shot:nth-of-type(1){ order: 2; }   /* wyróżniona -> środek */
.shots > .shot:nth-of-type(2){ order: 1; }   /* pierwsza boczna -> lewa */
.shots > .shot:nth-of-type(3){ order: 3; }   /* druga boczna -> prawa */

/* Zejście bocznych ramek niżej od środkowej robi margines.
   Selektor z rodzicem (dwie klasy) celowo: sam ".shot" waży tyle samo,
   co reguła blockGap generowana przez WordPressa dla kontenera
   (.wp-container-... > * + *), więc przy remisie o wyniku decydowała
   kolejność plików - i odstęp dostawała tylko część ramek.
   Schodki tylko od tabletu w górę; w karuzeli nie mają sensu. */
@media (min-width: 782px){
  .shots > .shot{
    margin-top: var(--space-5);
  }

  .shots > .shot--featured{
    margin-top: 0;
  }
}

/* --- ramka przeglądarki --- */
.shot__frame{
  position: relative;
  padding-top: 34px;   /* miejsce na pasek okna */
  border: 1px solid var(--line);
  border-radius: var(--radius-2);
  background: var(--wp--preset--color--surface);
  box-shadow: var(--wp--preset--shadow--elevated);
  overflow: hidden;
}

.shot__frame::before{
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 34px;
  border-bottom: 1px solid var(--line);
}

/* trzy kropki jednym elementem - dwie dolepione cieniem */
.shot__frame::after{
  content: "";
  position: absolute;
  left: 14px;
  top: 14px;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--wp--preset--color--contrast) 22%, transparent);
  box-shadow:
    12px 0 0 color-mix(in srgb, var(--wp--preset--color--contrast) 22%, transparent),
    24px 0 0 color-mix(in srgb, var(--wp--preset--color--contrast) 22%, transparent);
}

/* Zrzut pokazuje się w naturalnych proporcjach - bez object-fit i bez
   narzuconej wysokości. Każde wymuszenie wysokości sprawia, że pudełko
   przestaje pasować do proporcji obrazu, a cover dorównuje je, ścinając
   drugi wymiar: przy kwadratowym pudełku zrzut okna gubił po ~120px
   z lewej i prawej. Teraz ramka dopasowuje się do obrazu, nie odwrotnie.

   max-height to wyłącznie bezpiecznik na wypadek wgrania zrzutu CAŁEJ
   strony (takie bywają na 5000px) - wtedy overflow ramki utnie dół.
   Zwykły zrzut okna nigdy tego progu nie dotknie. */
.shot__frame{
  --shot-max: clamp(300px, 34vw, 480px);
  max-height: calc(var(--shot-max) + 35px);   /* +35px na pasek okna */
}

.shot--featured .shot__frame{
  --shot-max: clamp(340px, 42vw, 600px);
}

.shot__frame img{
  display: block;
  width: 100%;
  height: auto;
}

/* --- pasek adresu, tylko w wyróżnionej ramce --- */
.shot__url{
  position: absolute;
  top: 9px;
  left: 48px;
  right: 14px;
  z-index: 1;
  margin: 0;
  padding: 0 10px;
  height: 17px;
  line-height: 17px;
  border-radius: var(--radius-pill);
  background: var(--wp--preset--color--base);
  font-size: 11px;
  color: color-mix(in srgb, var(--wp--preset--color--contrast) 60%, transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
}

/* --- podpis pod ramką --- */
.shot__caption{
  margin: var(--space-2) 0 0;
  text-align: left;   /* hero bywa wyśrodkowane, podpis ma trzymać się ramki */
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

.shot__caption strong{
  color: var(--wp--preset--color--contrast);
  font-weight: 600;
}

/* --- telefon: karuzela zamiast trzech ramek obok siebie ---
   Wcześniej dwie boczne ramki były chowane przez display:none - a to NIE
   powstrzymuje pobierania, więc telefon ściągał trzy pliki, żeby pokazać
   jeden. W przewijanym kontenerze te dwie ramki są poza widocznym
   obszarem, więc lazy-loading faktycznie je odkłada do momentu przesunięcia
   palcem. Warunkiem jest próg ustawiony w functions.php
   (frost_child_lazy_threshold) - bez niego WordPress i tak ładowałby
   trzy pierwsze obrazki od razu.
   Całość na scroll-snap: zero JavaScriptu. */
@media (max-width: 781px){
  .shots{
    flex-wrap: nowrap;
    overflow-x: auto;
    /* mandatory + wyrównanie do środka to tutaj mechanizm, nie przypadek.
       "mandatory" znaczy, że kontener musi stać na punkcie zaczepienia
       zawsze. Punkt pierwszego slajdu wypada poza zakresem przewijania
       (wyśrodkowanie go wymagałoby przewinięcia w minus), więc przeglądarka
       zatrzymuje się na pierwszym osiągalnym - czyli na DRUGIM slajdzie.
       A drugim slajdem jest wyróżniona ramka, bo reguły order ustawiają ją
       w środku także na telefonie. Efekt: po wejściu na stronę widać
       wyróżnioną realizację na środku, ze skrawkami obu bocznych - czyli
       dokładnie ten sam układ co na desktopie. */
    scroll-snap-type: x mandatory;
    gap: var(--space-2);
    /* margines ujemny + padding: skrawek następnej ramki dochodzi do samej
       krawędzi ekranu, co jest jedyną wskazówką, że da się przesunąć */
    margin-inline: calc(-1 * var(--space-3));
    padding-inline: var(--space-3);
    padding-bottom: var(--space-2);
  }

  .shots > .shot{
    flex: 0 0 86%;   /* 14% zostaje na zapowiedź następnej ramki */
    max-width: 86%;
    /* center, nie start: slajd zatrzymuje się na środku ekranu, więc
       skrawek widać z obu stron, a nie tylko z prawej. Czytelniej mówi,
       że to karuzela, i nie przykleja ramki do lewej krawędzi.
       Pierwszy slajd i tak startuje przy lewej - dalej nie ma dokąd
       przewinąć - więc najlepsza realizacja zostaje widoczna od razu. */
    scroll-snap-align: center;
  }
}

/* ==========================================================================
   35) CASE – studium przypadku
   Zastępuje siatkę realizacji: jedna historia pokazana w całości zamiast
   trzech miniatur. Ramkę przeglądarki bierze z sekcji 34 (.shot__frame),
   więc wygląd okna jest jeden na całej stronie.
   ========================================================================== */

/* --- zrzut desktopowy z nachodzącym telefonem --- */
.case__visual{
  position: relative;
  /* Miejsce po prawej, żeby telefon nie zasłaniał treści zrzutu, i na dole,
     żeby miał gdzie wystawać poniżej ramki. Bez tego paddingu telefon
     wychodził POZA blok i nachodził na podpis oraz na separator niżej. */
  padding-right: 14%;
  padding-bottom: 6%;
}

.phone{
  position: absolute;
  right: 0;
  /* bottom: 0, nie wartość ujemna - telefon kończy się na krawędzi bloku
     i wystaje tylko w obręb jego dolnego paddingu, nigdy poza niego */
  bottom: 0;
  width: 24%;
  min-width: 96px;
  padding: 0;
  border: 7px solid var(--wp--preset--color--contrast);
  border-radius: 22px;
  overflow: hidden;
  background: var(--wp--preset--color--surface);
  box-shadow: var(--wp--preset--shadow--elevated);
}

.phone img{
  display: block;
  width: 100%;
  height: auto;
}

/* --- metryczka obok zrzutu: etykieta i wartość w jednym akapicie --- */
.case__meta-row{
  margin: 0;
  padding: var(--space-3) 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

.case__meta-row + .case__meta-row{
  border-top: 1px solid var(--line);
}

.case__meta-row strong{
  display: block;
  margin-top: 2px;
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 600;
  color: var(--wp--preset--color--contrast);
}

/* --- panel z liczbami --- */
.metrics{
  border-radius: var(--radius-2);
  padding: var(--space-5);
}

.metric__label{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.75;
}

/* <s> i <strong> to formaty, które edytor bloków zna (przekreślenie
   i pogrubienie) - przetrwają ręczną poprawkę tekstu, w odróżnieniu
   od wklejanych <span>. Stąd wartość "przed" i "po" siedzi w jednym
   akapicie zamiast w dwóch osobnych blokach. */
.metric__value{
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  margin: var(--space-2) 0;
}

.metric__value s{
  font-size: var(--wp--preset--font-size--large);
  opacity: 0.5;
}

.metric__value strong{
  position: relative;
  padding-left: 1.1em;   /* miejsce na strzałkę */
  font-size: clamp(1.75rem, 3.2vw, 2.5rem);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  /* Rozjaśniony primary. Czysty #2563EB na grafitowym tle daje 2,83:1,
     czyli poniżej progu nawet dla dużego tekstu. Po rozjaśnieniu 5,30:1. */
  color: color-mix(in srgb, var(--wp--preset--color--primary) 65%, #fff);
}

/* strzałka rysowana maską: pusty pseudoelement, więc czytnik ekranu
   nigdy go nie przeczyta. Kierunek "przed -> po" mówi etykieta. */
.metric__value strong::before{
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 0.55em;
  height: 0.55em;
  background-color: currentColor;
  opacity: 0.55;
  -webkit-mask: var(--icon-arrow-right) center / contain no-repeat;
          mask: var(--icon-arrow-right) center / contain no-repeat;
}

.metric__source{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.6;
}

.metrics__note{
  margin: var(--space-4) 0 0;
  padding-top: var(--space-3);
  border-top: 1px solid color-mix(in srgb, currentColor 18%, transparent);
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.7;
}

/* --- cytat klienta --- */
.quote-card{
  position: relative;
  margin: 0;
  padding: calc(var(--space-5) + 8px) 0 0;
  border: 0;
}

.quote-card::before{
  content: "\201C";   /* cudzysłów otwierający */
  position: absolute;
  left: 0;
  top: 0;
  font-size: 4rem;
  line-height: 0.8;
  font-weight: 700;
  color: var(--wp--preset--color--primary);
}

.quote-card p{
  margin: 0;
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 600;
  line-height: 1.4;
}

.quote-card cite{
  display: block;
  margin-top: var(--space-3);
  font-style: normal;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

.quote-card cite strong{
  display: block;
  font-weight: 600;
  color: var(--wp--preset--color--contrast);
}

/* podpis pod zrzutem; na telefonie przeniesie się obok telefonu */
.case__caption{
  margin: var(--space-3) 0 0;
}

@media (max-width: 781px){
  /* Zrzut desktopowy znika - na ekranie telefonu i tak nic by z niego
     nie było widać.
     To NIE marnuje transferu: ten obrazek nie jest pierwszy w treści,
     więc ma loading="lazy", a element z display:none nigdy nie wchodzi
     w pole widzenia - przeglądarka go po prostu nie pobiera. Inaczej niż
     przy obrazku ładowanym zachłannie, którego display:none nie zatrzyma.
     Selektor zawężony do .case__visual, żeby nie ruszyć ramek w hero. */
  .case__visual .shot__frame{
    display: none;
  }

  /* Telefon po lewej, podpis obok. Podpis jest RODZEŃSTWEM bloku
     wizualnego, nie jego dzieckiem - dlatego rząd robimy na kolumnie.
     :has() zawęża to do tej jednej kolumny, więc żadna inna kolumna
     na stronie się nie zmienia. */
  .wp-block-column:has(> .case__visual){
    display: flex;
    align-items: center;
    gap: var(--space-4);
  }

  .case__visual{
    flex: 0 0 44%;
    padding: 0;
  }

  .phone{
    position: static;
    width: 100%;
  }

  .case__caption{
    flex: 1;
    margin: 0;
  }

  /* Metryczka jako siatka 2x2 w ramce. Cztery wiersze pod sobą
     z kreskami zajmowały pół ekranu telefonu i rozbijały rytm sekcji. */
  .case__meta{
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3) var(--space-4);
    padding: var(--space-4);
    border: 1px solid var(--line);
    border-radius: var(--radius-2);
  }

  .case__meta-row{
    padding: 0;
  }

  .case__meta-row + .case__meta-row{
    border-top: 0;
  }

  .metrics{
    padding: var(--space-4);
  }
}

/* ==========================================================================
   36) ABOUT / WHY – kto robi stronę + pogrupowane argumenty
   Dwa bloki jednej sekcji. Góra: zdjęcie i przedstawienie się - jedyne
   miejsce na stronie, gdzie widać człowieka. Dół: osiem luźnych kart
   zastąpionych trzema grupami tematycznymi.
   ========================================================================== */

/* --- O MNIE: zdjęcie obok przedstawienia się ---
   Trzy klocki, nie dwie kolumny. Na desktopie zdjęcie stoi po lewej obok
   całego tekstu, ale na telefonie ma wejść DOPIERO pod nagłówek - najpierw
   "O mnie" i "Cześć, jestem Bartek", potem twarz, potem reszta. Blok
   "Kolumny" tego nie zrobi, bo nagłówka z prawej kolumny nie da się
   przestawić przed lewą. Siatka z nazwanymi obszarami owija wszystko
   w jeden kontener i przestawia samym przepisaniem układu - ten sam
   zabieg co w .cta-grid (sekcja 37).
   Grupa .about ma w markupie blockGap = 0, żeby marginesy WordPressa nie
   dokładały się do gap siatki. */
.about{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "head"
    "photo"
    "body";
  gap: var(--space-4);
}

.about__head{ grid-area: head; }
.about__photo{ grid-area: photo; }
.about__body{ grid-area: body; }

/* 900px jak w .cta-grid - poniżej kolumna na zdjęcie robi się węższa niż
   sensowny portret i tekst obok łamie się po 3-4 słowa. */
@media (min-width: 900px){
  .about{
    grid-template-columns: minmax(0, 45fr) minmax(0, 55fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "photo head"
      "photo body";
    column-gap: var(--space-6);
    row-gap: var(--space-3);
  }

  /* Zdjęcie rozpina się na oba wiersze siatki, więc dolna krawędź równa
     się z ostatnim akapitem obok. Nie ma tu align-self: start - domyślny
     stretch jest tym, czego chcemy. Wypełnienie kadru robi object-fit
     niżej. */
}

.about__photo{
  margin: 0;
  border-radius: var(--radius-2);
  overflow: hidden;
  background: var(--wp--preset--color--base);
}

/* <figure> bloku obrazka ma własny margines przeglądarki - bez tego
   zdjęcie odkleiłoby się od zaokrąglonej ramki. Wysokość 100% jest
   potrzebna, żeby rozciągnięcie przeszło z grupy przez figure aż do <img>:
   łańcuch wysokości urywa się na pierwszym elemencie, który jej nie poda. */
.about__photo .wp-block-image{
  margin: 0;
  height: 100%;
}

.about__photo img{
  display: block;
  width: 100%;
  /* BEZ aspect-ratio - wysokość dyktuje siatka, nie narzucona proporcja.
     Na desktopie kolumna zdjęcia rozpina się na oba wiersze, więc kadr
     dociąga do ostatniego akapitu obok, a cover dopełnia go przycinając
     boki. Przy zdjęciu 2193x1707 w kolumnie 45% i tekście ok. 492px wypada
     jakieś 13% szerokości - po równo z obu stron.
     Ile dokładnie wypadnie, zależy od długości tekstu obok: dłuższy tekst
     = wyższy kadr = więcej uciętych boków. Układ sam się dostosowuje i
     nigdy nie zostawi pustki, ale przy mocno rozbudowanym tekście warto
     zerknąć, czy postać nadal mieści się w kadrze.
     Chcesz zdecydować, KTÓRA część zostaje? Dopisz tu object-position
     z wartością poziomą, np. "object-position: 40% center" (0% = widać
     lewą krawędź, 100% = prawą). Tym razem zadziała, bo nadmiar jest
     właśnie w poziomie.
     PONIŻEJ 900px siatka ma jedną kolumnę, grupa nie ma narzuconej
     wysokości, więc height: 100% rozwiązuje się do auto i zdjęcie wraca
     do naturalnych proporcji - na telefonie nic nie jest przycinane. */
  height: 100%;
  object-fit: cover;
}

/* Przy kolumnie 55% wiersz sięgałby ~79 znaków - powyżej 75 oko gubi
   początek następnej linii. Rząd liczb świadomie bez ograniczenia, bo ma
   rozkładać się na całą szerokość kolumny. */
.about__body > p{
  max-width: 62ch;
}

.about__body > .about__claim{
  max-width: 46ch;
}

.about__claim{
  margin: 0;
  font-size: var(--wp--preset--font-size--large);
  font-weight: 700;
  line-height: 1.45;
  letter-spacing: -0.01em;
}

/* --- rząd liczb z pionowymi kreskami ---
   Bez gap: odstęp robi padding po obu stronach pozycji, więc kreska ma po
   równo z każdej strony. Przy gap wyszłaby doklejona do prawej sąsiadki. */
/* .stat-row to nazwa kanoniczna, .about-stats została jako alias: ten sam
   układ służy teraz sekcji "O mnie" i liście realizacji, więc nazwa z
   "about" przestała być prawdziwa. W nowym markupie używaj .stat-row.
   Starą klasę w Edytorze możesz podmienić przy okazji - nic od tego nie
   zależy, obie prowadzą do tych samych reguł.

   Flex z pozycjami szerokości treści, a NIE trzy równe kolumny.
   Przy repeat(3, 1fr) kreski stoją na sztywno w 1/3 i 2/3 szerokości,
   niezależnie od tego, ile tekstu jest przed nimi. Przy nierównych
   podpisach ("doświadczenia" obok "i okolice, zdalnie cała Polska")
   pierwsza pozycja zostawała z dużą pustką przed kreską, a druga stała
   do niej przyklejona - i rząd wyglądał na nierówny, bo nierówny był.
   Teraz każda pozycja jest szerokości swojej treści, a odstęp do kreski
   robi padding po obu jej stronach, więc jest wszędzie taki sam. */
.stat-row,
.about-stats{
  display: flex;
  flex-wrap: wrap;
  margin: 0;
}

/* Wygrywa z blockGap grupy (.wp-container-X > * + *), bo dwie klasy biją
   jedną - ten rząd potrzebuje więcej powietrza niż odstęp między akapitami. */
.about__body .about-stats{
  margin-block-start: var(--space-4);
}

.stat-row__item,
.about-stats__item{
  margin: 0;
  /* min-width: 0 pozwala długiemu podpisowi złamać się WEWNĄTRZ pozycji.
     Domyślne min-width: auto trzyma element na szerokości najdłuższego
     słowa i zamiast tego wypchnęłoby trzecią pozycję do nowego wiersza. */
  min-width: 0;
  padding-inline: var(--space-3);
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.4;
  color: var(--wp--preset--color--muted);
}

.stat-row__item:first-child,
.about-stats__item:first-child{
  padding-inline-start: 0;
}

.stat-row__item + .stat-row__item,
.about-stats__item + .about-stats__item{
  border-inline-start: 1px solid var(--line);
}

/* Liczba w <strong>, podpis dalej w tym samym akapicie - ten sam układ co
   .why-item i .feature-list. Jedna pozycja to jeden edytowalny blok. */
.stat-row__item strong,
.about-stats__item strong{
  display: block;
  margin-bottom: 2px;
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
  /* Fonty sans mają domyślnie cyfry proporcjonalne - patrz komentarz
     przy .steps. */
  font-variant-numeric: tabular-nums;
  color: var(--wp--preset--color--contrast);
}

.about__note{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.5;
  color: var(--wp--preset--color--muted);
}

/* przycisk z numerem - ikona słuchawki przed tekstem */
.btn-phone .wp-block-button__link{
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

.btn-phone .wp-block-button__link::before{
  content: "";
  flex: none;
  width: 1em;
  height: 1em;
  background-color: currentColor;
  -webkit-mask: var(--icon-phone) center / contain no-repeat;
          mask: var(--icon-phone) center / contain no-repeat;
}

/* --- pogrupowane argumenty --- */
.why-group{
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

/* Nagłówek grupy MUSI być wyraźnie większy od tytułu pozycji (.why-item
   strong). Przy tym samym rozmiarze oba poziomy różniły się tylko grubością
   700 vs 600 i oko ich nie rozdzielało. Teraz skala to 24 / 17 / 14 px.

   UWAGA: nie ustawiaj rozmiaru tego nagłówka w edytorze. WordPress generuje
   klasy presetów rozmiaru (.has-medium-font-size itd.) z !important, więc
   wybór z panelu bloku wygrałby z tą regułą i poziomy znów by się zlały.
   Rozmiar zostaje tutaj, w jednym miejscu dla wszystkich trzech grup. */
.why-group__title{
  margin: 0 0 var(--space-4);
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 700;
  letter-spacing: 0;
}

/* Tytuł pozycji w <strong>, opis dalej w tym samym akapicie - ten sam
   układ co .feature-list i .steps. Jedna pozycja to jeden edytowalny blok. */
.why-item{
  position: relative;
  margin: 0 0 var(--space-4);
  padding-inline-start: 22px;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
  line-height: 1.5;
}

/* Krótka rdzawa kreska przy tytule pozycji - ten sam motyw co kreska przed
   .eyebrow, więc nie wprowadza nowego słownika znaków. Mówi "to jest jedna
   z kilku równoległych pozycji pod nagłówkiem", czego samo wcięcie nie robi.
   Wysunięta poza kolumnę tekstu, żeby opis i tytuł trzymały wspólną lewą
   krawędź - inaczej wcięcie łamałoby rytm przy wielowierszowym tytule. */
.why-item::before{
  content: "";
  position: absolute;
  inset-inline-start: 0;
  /* 12px = połowa wiersza tytułu (17px x line-height 1.5 = 25,5px), liczone
     od góry akapitu, bo tytuł jest zawsze jego pierwszym wierszem. */
  top: 12px;
  width: 10px;
  height: 2px;
  border-radius: 1px;
  background: var(--wp--preset--color--primary);
}

.why-item:last-child{
  margin-bottom: 0;
}

.why-item strong{
  display: block;
  margin-bottom: 2px;
  font-size: var(--wp--preset--font-size--medium);
  font-weight: 600;
  color: var(--wp--preset--color--contrast);
}

@media (max-width: 781px){
  /* Jedna kolumna. Trzymanie trzech kolumn na telefonie nie działa, bo
     podpisy są dłuższe niż wartości - przy ok. 110px na kolumnę najdłuższy
     łamał się na cztery wiersze i rząd przestawał czytać się jako rząd.
     W pionie każda pozycja dostaje pełną szerokość, więc podpis mieści się
     w jednym-dwóch wierszach, a wartość może zostać w pełnym rozmiarze. */
  .stat-row,
  .about-stats{
    flex-direction: column;
  }

  /* Separator obraca się z pionowego na poziomy razem z układem. */
  .stat-row__item,
  .about-stats__item{
    padding-inline: 0;
    padding-top: var(--space-3);
  }

  .stat-row__item:first-child,
  .about-stats__item:first-child{
    padding-top: 0;
  }

  .stat-row__item + .stat-row__item,
  .about-stats__item + .about-stats__item{
    border-inline-start: 0;
    border-top: 1px solid var(--line);
  }
}

/* 37) CTA-GRID – sekcja wyceny: treść + formularz + telefon
   Trzy klocki, nie dwie kolumny. Na telefonie blok z numerem ma stać POD
   formularzem, a na desktopie w lewej kolumnie pod listą kroków - zwykłe
   kolumny tego nie zrobią, bo zagnieżdżonego dziecka nie da się przestawić
   przed rodzeństwo rodzica. Siatka z nazwanymi obszarami owija wszystkie
   trzy bloki w jeden kontener i przestawia je samym przepisaniem układu.
   Grupa .cta-grid ma w markupie blockGap = 0, żeby marginesy WordPressa
   nie dokładały się do gap siatki. */
.cta-grid{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "intro"
    "form"
    "call";
  gap: var(--space-5);
}

.cta-intro{ grid-area: intro; }
.cta-form{ grid-area: form; }
.cta-call{ grid-area: call; }

/* 900px, nie 781px jak reszta motywu: formularz z dwoma polami w rzędzie
   potrzebuje ok. 420px płyty, a przy 782px na kolumnę zostaje ~350px. */
@media (min-width: 900px){
  .cta-grid{
    grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
    /* druga wiersz 1fr - jeśli płyta formularza jest wyższa niż treść,
       nadwyżka wysokości ląduje tutaj i dociska blok z numerem do dołu,
       zamiast rozrywać odstęp między nagłówkiem a listą kroków. */
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "intro form"
      "call  form";
    column-gap: var(--space-6);
    row-gap: var(--space-5);
  }

  .cta-form{ align-self: start; }
  .cta-call{ align-self: end; }
}

/* --- lista kroków z numerami w kółkach --- */
.cta-steps{
  /* Jedna liczba na wszystko: szerokość kolumny na cyfrę ORAZ odstęp do
     tekstu. Cyfra ma ok. 15px, więc reszta tej wartości to światło między
     nią a treścią - przy 28px wychodzi ok. 13px. Wcześniej kolumna i odstęp
     były osobno (34px + 16px) i dawały razem ok. 35px przerwy, przez co
     cyfra wisiała w oderwaniu od wiersza, który opisuje. */
  --cta-step-col: 28px;
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: cta-step;
}

.cta-steps > li{
  counter-increment: cta-step;
  position: relative;
  padding-inline-start: var(--cta-step-col);
  line-height: 1.5;
}

.cta-steps > li + li{
  margin-top: var(--space-3);
}

.cta-steps > li::before{
  content: counter(cta-step);
  position: absolute;
  inset-inline-start: 0;
  top: 0;
  width: var(--cta-step-col);
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 700;
  /* Wyrównanie cyfry do PIERWSZEGO wiersza tekstu bez kombinowania z top.
     Przy position:absolute em w "top" liczy się od własnego font-size
     pseudoelementu (tu 24px), a nie od tekstu obok (17px) - łatwo się na tym
     przejechać. Zamiast tego dajemy cyfrze pudełko wiersza tej samej
     wysokości co wiersz tekstu (1,5 x ok. 1,0625rem), więc przy top: 0 oba
     glify siedzą na tej samej wysokości same z siebie. */
  line-height: 1.6rem;
  /* Przygaszona biel, nie akcent. currentColor bierze kolor sekcji, więc
     gdyby kiedyś zmieniła tło, cyfry pójdą za nim. 70% na tle contrast daje
     7,93:1 - czytelne, ale wyraźnie ciszej niż nagłówek i nadtytuł obok. */
  color: color-mix(in srgb, currentColor 70%, transparent);
  /* Fonty sans mają domyślnie cyfry proporcjonalne - patrz komentarz
     przy .steps. Bez tego "1" stałaby inaczej niż "2" i "3". */
  font-variant-numeric: tabular-nums;
}

/* --- blok „wolisz zadzwonić” --- */
.cta-call{
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  grid-template-areas:
    "photo intro"
    "photo phone"
    ".     wa";
  column-gap: var(--space-3);
  padding-top: var(--space-3);
  /* currentColor, nie --line: na ciemnym tle kreska musi być rozjaśnieniem,
     a nie przyciemnieniem. */
  border-top: 1px solid color-mix(in srgb, currentColor 22%, transparent);
}

.cta-call__photo{
  grid-area: photo;
  align-self: center;
  width: 52px;
  height: 52px;
  margin: 0;
  border-radius: var(--radius-pill);
  overflow: hidden;
  background: color-mix(in srgb, currentColor 12%, transparent);
}

.cta-call__photo img{
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cta-call__intro{
  grid-area: intro;
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  opacity: 0.8;
}

.cta-call__phone{
  grid-area: phone;
  margin: 0;
  font-size: var(--wp--preset--font-size--x-large);
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

/* Numer ma czytać się jak dana kontaktowa, nie jak odnośnik w tekście -
   dwie klasy wygrywają z regułami elements.link z theme.json, bo te
   WordPress generuje w :where() (specyficzność 0). */
.cta-call__phone a{
  font-weight: inherit;
  text-decoration: none;
}

.cta-call__phone a:hover{
  text-decoration: underline;
}

.cta-call__wa{
  grid-area: wa;
  margin: var(--space-2) 0 0;
  font-size: var(--wp--preset--font-size--small);
}

/* --- płyta z formularzem --- */
/* Przycisk na całą szerokość płyty i w kolorze sygnałowym - to jedyna
   akcja w tej sekcji, więc nie konkuruje z niczym o uwagę.
   Biały tekst na accent (#C2410C) daje 5,18:1, czyli AA. */
/* Tylko szerokość - kolor przycisku wysyłki jest już accent globalnie
   (sekcja FLUENT FORMS), więc nie dubluję go tutaj. */
.cta-form .fluentform .ff-btn.ff-btn-submit.ff_btn_style{
  width: 100%;
}

.cta-form__note{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.5;
  /* Kolor "muted" z palety: 5,88:1 na białej płycie, 5,72:1 na tle base. */
  color: var(--wp--preset--color--muted);
}

/* 38) STOPKA – dwa rzędy: marka / nawigacja / kontakt, pod kreską dane firmy
   Klasa .site-footer siedzi na części szablonu w plikach templates/, ale
   ZAWARTOŚĆ stopki jest w bazie (Edytor witryny) - te klasy wpisujesz na
   blokach ręcznie, markup do wklejenia leży w _robocze/stopka.html.
   Logo łapie się na globalną regułę wysokości z sekcji 4, więc w stopce
   ma ten sam rozmiar co w nagłówku - nie dubluję tu reguły. */
.footer-top{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  /* Na telefonie kontakt wchodzi PRZED nawigację: numer jest tym, po co
     ktoś schodzi na sam dół, a lista podstron to dodatek. Na desktopie
     wraca na prawo, bo tam wszystko mieści się w jednym rzędzie. */
  grid-template-areas:
    "brand"
    "contact"
    "nav";
  gap: var(--space-4);
}

.footer-brand{ grid-area: brand; }
.footer-nav{ grid-area: nav; }
.footer-contact{ grid-area: contact; }

@media (min-width: 782px){
  .footer-top{
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas: "brand nav contact";
    align-items: center;
    column-gap: var(--space-5);
  }

  .footer-contact{ text-align: right; }
}

.footer-tagline{
  margin: var(--space-1) 0 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* --- nawigacja --- */
/* Na telefonie dwie kolumny (jak w szkicu), od tabletu jeden rząd na środku. */
/* Na telefonie jedna kolumna, od tabletu jeden rząd na środku (niżej).
   Dwie kolumny zostawiały po prawej stronie dużo pustego miejsca przy
   krótkich pozycjach, a oko i tak czyta taką listę w pionie. */
.footer-nav{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

@media (min-width: 782px){
  .footer-nav{
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-2) var(--space-4);
  }
}

/* theme.json daje linkom podkreślenie i wagę 600 - w stopce to za dużo
   ozdobników naraz. Dwie klasy biją reguły z :where(), więc bez !important. */
/* nadpisuje :where(ul, ol) li + li z sekcji 13 (0.4em = ok. 6px) - obie
   listy w stopce układa gap siatki/flexa, więc margines górny tylko zbijał
   pozycje 2+ w dół i pierwsza wychodziła wyżej od reszty. */
.footer-nav li + li,
.footer-links li + li{
  margin-top: 0;
}

.footer-nav a{
  font-weight: 500;
  text-decoration: none;
}

.footer-nav a:hover{
  text-decoration: underline;
}

/* --- kontakt --- */
/* Numer i e-mail wyglądają identycznie i celowo cicho. Numer miał wcześniej
   24px/700 - dokładnie tyle co numer w sekcji CTA jakieś sto pikseli wyżej,
   więc dwa tak samo głośne wezwania stały obok siebie i żadne nie wygrywało.
   W stopce dane kontaktowe mają się dać ZNALEŹĆ, gdy ktoś ich szuka,
   a nie łapać wzrok. 65% contrast na białym tle = 4,72:1, czyli AA. */
.footer-phone,
.footer-mail{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
}

.footer-mail{
  margin-top: var(--space-1);
}

.footer-phone a,
.footer-mail a{
  font-weight: 400;
  text-decoration: none;
  color: var(--wp--preset--color--muted);
}

.footer-phone a:hover,
.footer-mail a:hover{
  text-decoration: underline;
}

/* --- dolny rząd: dane firmy i odnośniki formalne --- */
.footer-bottom{
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2) var(--space-4);
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

/* Grupa z dwoma akapitami zamiast jednego ze <span> - Gutenberg potrafi
   wyciąć goły <span> przy edycji, a osobne akapity przeżyją wszystko.
   Grupa ma w markupie blockGap = 0, bo przy układzie w rzędzie margines
   górny od WordPressa zepchnąłby drugi akapit w dół. */
.footer-legal{
  display: flex;
  flex-wrap: wrap;
  gap: 2px var(--space-3);
  margin: 0;
}

.footer-legal p{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

.footer-links{
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
  font-size: var(--wp--preset--font-size--small);
}

.footer-links a{
  font-weight: 400;
}

/* 39) PRZYCISK: LINK TEKSTOWY – trzeci wariant obok wypełnienia i konturu
   Rejestrowany w functions.php jako styl bloku, więc w edytorze wybierasz
   go z panelu "Style", nie wpisujesz klasy ręcznie.
   Kolor primary, bo to element MARKI, nie akcji - pomarańcz zostaje
   wyłącznie na przyciskach wypełnionych (zasada w sekcji TOKENS).
   Padding pionowy ZOSTAJE mimo braku tła: pole dotyku na telefonie ma mieć
   swoje 44px, a sam tekst dałby około 20px. */
.wp-block-button.is-style-text-link > .wp-block-button__link{
  padding-inline: 0;
  /* !important przy tle i kolorze: jeśli przycisk miał kiedykolwiek
     ustawiony kolor w edytorze, niesie klasę .has-*-background-color albo
     .has-*-color, a te WordPress generuje z !important. Bez tego link
     tekstowy zostałby pomarańczową bryłą mimo wybranego stylu.
     Wyczyszczenie koloru w edytorze też działa - to jest zabezpieczenie
     na wypadek, gdyby kolor tam został. */
  background: transparent !important;
  border: 0;
  /* Bez !important, inaczej nie dałoby się zrobić jasnego wariantu na
     ciemnej sekcji - tam primary ma tylko 2,83:1. */
  color: var(--wp--preset--color--primary);
  /* Bez podkreślenia w spoczynku. Strzałka w treści i kolor marki
     wystarczą, żeby było widać, że to odnośnik, a element drugorzędny
     nie ma konkurować z przyciskiem akcji obok. */
  text-decoration: none;
  text-underline-offset: 4px;
}

.wp-block-button.is-style-text-link > .wp-block-button__link:hover{
  background: transparent !important;
  text-decoration: underline;
  text-decoration-thickness: 1px;
}

/* ==========================================================================
   40) OPINIE Z GOOGLE
   Nagłówek z oceną zbiorczą, trzy opinie w kartach, pod nimi zastrzeżenie
   o źródle. Na telefonie karty zamieniają się w karuzelę, tak samo jak
   zrzuty realizacji w hero (sekcja 34).
   ========================================================================== */

/* --- rząd gwiazdek ---
   Jeden element, nie pięć. Maska powtarza się w poziomie, więc liczba
   gwiazdek to po prostu szerokość: 5em = pięć sztuk. Gwiazdka w pliku SVG
   ma 20 z 24 jednostek, więc odstęp między nimi bierze się z marginesu
   w samym rysunku i nie trzeba go ustawiać osobno.
   Tekst w akapicie ZOSTAJE - czytnik ekranu przeczyta "Ocena 5 na 5",
   bo sama grafika nic mu nie mówi. Na ekranie znika pod gwiazdkami. */
.stars{
  position: relative;
  display: block;
  width: 5em;
  height: 1em;
  margin: 0;
  overflow: hidden;
  white-space: nowrap;
  color: transparent;
}

.stars::before{
  content: "";
  position: absolute;
  inset: 0;
  background-color: var(--star);
  -webkit-mask: var(--icon-star) left center / 1em 1em repeat-x;
          mask: var(--icon-star) left center / 1em 1em repeat-x;
}

/* --- nagłówek sekcji: tytuł po lewej, ocena po prawej --- */
.reviews-head{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-4);
}

@media (min-width: 782px){
  .reviews-head{
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    column-gap: var(--space-5);
  }
}

.reviews-score{
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.reviews-score__value{
  margin: 0;
  font-size: var(--wp--preset--font-size--xx-large);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.02em;
  /* Ocena to liczba - cyfry tabelaryczne, patrz komentarz przy .steps. */
  font-variant-numeric: tabular-nums;
}

.reviews-score__meta{
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.reviews-score__count{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* --- karty --- */
.reviews-grid{
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--space-4);
  margin-top: var(--space-5);
}

.review{
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* Rozmiar ustawiony na KARCIE, nie na samym akapicie z cytatem.
     Klasa pojedynczego bloku łatwo ginie przy edycji w Edytorze (wystarczy,
     że wklejana treść rozbije akapit na dwa - nowy nie ma już klasy), a
     wtedy jedna opinia nagle czyta się większa od pozostałych. Dziedziczenie
     z karty jest odporne: cokolwiek w niej wyląduje, dostanie właściwy
     rozmiar. Elementy, które potrzebują innego, nadpisują go u siebie. */
  font-size: var(--wp--preset--font-size--small);
}

.review__text{
  margin: 0;
  line-height: 1.6;
}

/* Blok autora dociśnięty do dołu karty, żeby przy opiniach różnej długości
   wszystkie podpisy stały w jednej linii. Cytat zostaje przy górze. */
.review__who{
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
  padding-top: var(--space-3);
  border-top: 1px solid var(--line);
}

/* Inicjał zamiast zdjęcia: Google nie udostępnia awatarów w sposób, który
   wolno przechowywać u siebie, a pobieranie ich z serwerów Google na każdej
   podstronie to zbędne żądania i ciasteczka. */
.review__avatar{
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin: 0;
  border-radius: var(--radius-pill);
  background: color-mix(in srgb, var(--wp--preset--color--primary) 12%, transparent);
  color: var(--wp--preset--color--primary);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 700;
  line-height: 1;
  text-transform: uppercase;
}

.review__name{
  margin: 0;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.3;
  color: var(--wp--preset--color--muted);
}

.review__name strong{
  display: block;
  font-weight: 600;
  color: var(--wp--preset--color--contrast);
}

.reviews-note{
  margin-top: var(--space-4);
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* Odnośnik przy ocenie pokazujemy na desktopie, a przycisk pod kartami
   na telefonie - ten sam cel, inne miejsce, więc nigdy oba naraz.
   display: none zdejmuje element także z drzewa dostępności, więc czytnik
   nie przeczyta tego samego odnośnika dwa razy. */
.reviews-more--desktop{ display: none; }

@media (min-width: 782px){
  .reviews-more--desktop{ display: block; }
  .reviews-more--mobile{ display: none; }
}

@media (max-width: 781px){
  /* Karuzela jak przy zrzutach realizacji (sekcja 34): skrawek następnej
     karty jest jedyną wskazówką, że da się przewinąć. */
  .reviews-grid{
    display: flex;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: var(--space-3);
    margin-inline: calc(-1 * var(--space-3));
    padding-inline: var(--space-3);
    padding-bottom: var(--space-2);
  }

  .reviews-grid > .review{
    flex: 0 0 86%;
    max-width: 86%;
    scroll-snap-align: center;
  }
}

/* ==========================================================================
   41) REALIZACJE – lista studiów przypadku na osobnej podstronie
   Każda pozycja (.case-item) to zrzut z telefonem po jednej stronie i opis
   po drugiej,
   naprzemiennie. Ramkę przeglądarki, telefon i ukrywanie zrzutu
   desktopowego na telefonie bierze z sekcji 34 i 35 - nic nie dubluję.
   ========================================================================== */

/* --- filtry-kotwice pod nagłówkiem ---
   Zwykłe odnośniki do kotwic, nie filtrowanie. Prawdziwe filtrowanie
   wymagałoby JavaScriptu, a przy czterech realizacjach zysk byłby żaden:
   i tak wszystkie mieszczą się na jednym ekranie przewijania. */
.filters{
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: var(--space-4) 0 0;
  padding: 0;
}

/* nadpisuje :where(ul, ol) li + li z sekcji 13 - odstęp robi gap */
.filters li + li{
  margin-top: 0;
}

.filters a{
  display: inline-block;
  padding: 8px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: var(--wp--preset--font-size--small);
  font-weight: 500;
  text-decoration: none;
  transition: background-color .2s ease, border-color .2s ease, color .2s ease;
}

/* Podświetlenie całej pigułki, nie sama zmiana obrysu - skoro element ma
   kształt pigułki, to pigułka ma reagować, a nie jej kontur.
   Tło to 10% primary, NIE pełny kolor: wypełniony niebieski czytałby się
   jak niebieski przycisk, a tych na tej stronie nie używamy (zasada
   w sekcji TOKENS: niebieski = marka, pomarańczowy = akcja).
   Tekst schodzi na secondary, nie primary: primary na tym tle daje 4,31:1,
   czyli PONIŻEJ progu 4,5:1 dla 14px - przygaszenie tła zabiera kontrast
   tekstowi tego samego koloru. Secondary wychodzi 5,59:1. */
.filters a:hover{
  border-color: var(--wp--preset--color--primary);
  background: color-mix(in srgb, var(--wp--preset--color--primary) 10%, transparent);
  color: var(--wp--preset--color--secondary);
}

/* --- pojedyncza realizacja --- */
/* Trzy klocki, nie dwie kolumny - na telefonie zrzut wchodzi MIĘDZY
   nagłówek a opis (najpierw wiadomo, czyja to strona, potem ją widać,
   potem czytasz szczegóły). Blok "Kolumny" tego nie zrobi. Ta sama siatka
   z nazwanymi obszarami co w .about i .cta-grid. */
.case-item{
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "head"
    "media"
    "body";
  gap: var(--space-4);
  padding-block: var(--space-6);
  border-top: 1px solid var(--line);
}

.case-item__head{ grid-area: head; }
.case-item > .case__visual{ grid-area: media; }
.case-item__body{ grid-area: body; }

@media (min-width: 900px){
  .case-item{
    grid-template-columns: minmax(0, 52fr) minmax(0, 48fr);
    grid-template-rows: auto 1fr;
    grid-template-areas:
      "media head"
      "media body";
    align-items: start;
    column-gap: var(--space-6);
    row-gap: var(--space-3);
  }

  /* Co druga pozycja odwrócona. Zrzuty po tej samej stronie przez całą
     stronę dają rytm maszynowy; naprzemiennie oko ma na czym odpocząć. */
  .case-item:nth-child(even){
    grid-template-columns: minmax(0, 48fr) minmax(0, 52fr);
    grid-template-areas:
      "head  media"
      "body  media";
  }
}

@media (max-width: 781px){
  /* Zrzut desktopowy jest już ukryty regułą z sekcji 35, zostaje sam
     telefon - ograniczamy go, bo na pełnej szerokości kolumny wyglądałby
     jak tablet. */
  .case-item > .case__visual{
    max-width: 260px;
    margin-inline: auto;
  }
}

.case-item__url{
  margin: var(--space-1) 0 0;
  font-size: var(--wp--preset--font-size--small);
  color: var(--wp--preset--color--muted);
}

/* --- Sytuacja / Co zrobiłem / Efekt ---
   Kompaktowe rodzeństwo .why-item: ten sam układ (tytuł w <strong>, opis
   dalej w tym samym akapicie), ale tytuł w rozmiarze małym, bo na tej
   podstronie powtarza się cztery razy i nie ma konkurować z nazwą firmy. */
.case-note{
  margin: 0 0 var(--space-3);
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.6;
  color: var(--wp--preset--color--muted);
}

.case-note strong{
  display: block;
  margin-bottom: 2px;
  font-weight: 600;
  color: var(--wp--preset--color--contrast);
}

/* --- cytat klienta, wersja kompaktowa ---
   Bez karty i bez wielkiego cudzysłowu jak .quote-card: przy czterech
   realizacjach pod rząd taki znak robiłby się ozdobnikiem, nie akcentem. */
.case-quote{
  margin: var(--space-4) 0 0;
  font-size: var(--wp--preset--font-size--small);
  line-height: 1.6;
}

.case-quote cite{
  display: block;
  margin-top: 4px;
  font-size: var(--wp--preset--font-size--small);
  font-style: normal;
  color: var(--wp--preset--color--muted);
}

