/* =====================================================================
   SmartSide — arkusz stylów serwisu
   Wartości wprost z pliku „Smartside System Wizualny" (tokeny, skala
   typograficzna, siatka, stany, breakpointy).

   Budżet z briefu: CSS ≤ 25 KB, jeden plik, bez frameworka.
   Zasady: treść renderowana serwerowo, interakcje działają bez JS,
   każdy obraz z zadeklarowanymi proporcjami (CLS = 0).
   ===================================================================== */

/* --- Font: JEDEN krój pobierany (Jost), reszta systemowa ------------
   Jost obsługuje wyłącznie nagłówki, nawigację, przyciski i liczby.
   Treść bieżąca leci na system-ui — zero pobierania, zero CLS od fontu
   i tekstowy LCP dostępny natychmiast. To wymóg wydajnościowy briefu,
   nie preferencja estetyczna. */
@font-face {
    font-family: 'Jost';
    font-style: normal;
    font-weight: 500 600;          /* font zmienny — jeden plik na obie grubości */
    font-display: swap;
    src: url('/fonts/jost-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                   U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                   U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
    font-family: 'Jost';
    font-style: normal;
    font-weight: 500 600;
    font-display: swap;
    src: url('/fonts/jost-latin-ext.woff2') format('woff2');
    /* Polskie znaki diakrytyczne (ą, ć, ę, ł, ń, ś, ź, ż) leżą w tym zakresie */
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                   U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                   U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
    /* Kolory — role semantyczne */
    --c-accent: #fcb813;           /* żółty z sygnetu — CTA, akcenty, focus */
    --c-accent-hover: #e8a200;
    --c-ink: #1d1d1b;              /* grafit — tekst i ciemne sekcje */
    /* Petrol wzięty wprost z pliku logotypu (SmartSideLeft.svg, napis
       SMARTSIDE). Wcześniej token miał #14333f — zbliżony, ale nie ten
       sam kolor, więc nagłówki nie zgadzały się co do znaku z sygnetem. */
    --c-brand: #073142;            /* petrol z logotypu — nagłówki, blok CTA */
    --c-brand-soft: #7e939c;       /* ok. 45% bieli w petrolu — bez zmian, różnica niewidoczna */
    --c-text: #1d1d1b;
    --c-text-soft: #454542;
    --c-text-muted: #6b6b68;
    --c-surface: #ffffff;
    --c-surface-alt: #f2f2f2;
    --c-paper: #faf9f5;
    --c-line: #e3e3e0;
    --c-line-dark: #3a3a37;
    --c-error: #b3261e;
    --c-success: #2e7d32;
    --c-on-dark: #f2f2f2;
    --c-on-dark-soft: #c9c9c4;

    /* Typografia — dwa kroje, trzy odmiany */
    --f-display: 'Jost', 'Century Gothic', 'Avenir Next', system-ui, sans-serif;
    --f-body: system-ui, -apple-system, 'Segoe UI', sans-serif;

    /* Skala: desktop / mobile ustawiane w media query niżej */
    --t-h1: 32px;    --t-h1-lh: 1.12;
    --t-h2: 26px;    --t-h2-lh: 1.2;
    --t-h3: 20px;    --t-h3-lh: 1.3;
    --t-h4: 17px;    --t-h4-lh: 1.4;
    --t-lead: 18px;
    --t-body: 16px;
    --t-small: 13px;
    --t-overline: 12px;

    /* Siatka odstępów (bazowa 4 px) */
    --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
    --s-6: 24px; --s-8: 32px; --s-12: 48px;
    --s-section: 56px;             /* pion sekcji — mobile */

    /* Promienie: pola i przyciski 2 px, karty 8 px, zdjęcia 0 */
    --r-control: 2px;
    --r-card: 8px;

    --sh-1: 0 1px 3px rgba(29, 29, 27, .10);
    --sh-2: 0 8px 28px rgba(29, 29, 27, .16);

    /* Wysokosc przyklejonego naglowka. Wynika z wysokosci logo (34/44 px)
       i pionu paska (2 x --s-3). Uzywaja jej: przyklejona kolumna boczna
       i zapas nad kotwicami — bez tego oba wjezdzalyby pod naglowek. */
    --header-h: 58px;
    --wrap: 1360px;
    --wrap-pad: 20px;
    --measure: 720px;              /* kolumna treści — ok. 70ch */
}

@media (min-width: 768px) {
    :root {
        /* H1 płynne zamiast skokowego: przy 768 px daje 44 px (czyli tyle,
           co dotąd), przy 1250 px i szerzej dochodzi do 64 px. H1 jest
           elementem LCP i pozostaje tekstem, więc powiększenie nic nie kosztuje
           — to ten sam znak w tym samym miejscu. */
        --t-h1: clamp(2.75rem, 1.5rem + 3.2vw, 4rem);
        --t-h2: 32px; --t-h3: 24px; --t-h4: 19px;
        --t-lead: 20px; --t-body: 18px; --t-small: 14px; --t-overline: 13px;
        --s-section: 96px;
        --wrap-pad: 40px;
        --header-h: 68px;
    }
}

/* Od 1024 px śródtytuły dostają jeszcze jeden stopień. Powód z audytu:
   na stronach usług nagłówki sekcji to w większości H3 (poziom bierze się
   z bazy, kolumna `page_section`.`heading_level`), więc przy 24 px czytały
   się jak podpisy, nie jak tytuły sekcji. H1 i H2 zostają bez zmian —
   skala z systemu wizualnego. */
@media (min-width: 1024px) {
    :root { --t-h2: 40px; --t-h3: 26px; --t-h4: 20px; }
}

/* Odstęp nad śródtytułem w kolumnie treści: 48 px zamiast 32 px. Sekcje
   merytoryczne muszą się od siebie odklejać, inaczej cała treść czyta się
   jak jeden blok tekstu z pogrubieniami. */
.prose h2, .prose h3 { margin-top: var(--s-12); }
.prose > :first-child { margin-top: 0; }

/* --- Reset ---------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
body, h1, h2, h3, h4, p, ul, ol, figure, blockquote, fieldset { margin: 0; }
fieldset { border: 0; padding: 0; }
ul[class], ol[class] { list-style: none; padding: 0; }
img { max-width: 100%; height: auto; display: block; }

/* Warianty responsywne wchodza jako <picture><source><img>. Bez tej reguly
   <picture> tworzy wlasne pudelko o wysokosci auto, a wtedy `height: 100%`
   na obrazie w .hero__media, .card__media, .page-hero__media i .video__facade
   liczy sie wzgledem TEGO pudelka — kadr zapada sie do zera. `display: contents`
   usuwa pudelko z ukladu, wiec <img> zachowuje sie jak bezposrednie dziecko
   kadru i wszystkie istniejace selektory potomka nadal trafiaja.
   Regula jest bezczynna, dopoki na stronie nie ma <picture>. */
picture { display: contents; }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        transition-duration: .01ms !important;
    }
}

body {
    margin: 0;
    font-family: var(--f-body);
    font-size: var(--t-body);
    line-height: 1.7;
    color: var(--c-text);
    background: var(--c-paper);
    -webkit-font-smoothing: antialiased;
}

/* --- Typografia ----------------------------------------------------- */
h1, h2, h3, h4, .h-display {
    font-family: var(--f-display);
    font-weight: 600;
    color: var(--c-brand);      /* petrol z logotypu — kontrast 13,8:1 na białym */
    letter-spacing: -.01em;
    text-wrap: balance;
}
/* Jost przy dużych stopniach robi się luźny i rozłazi się w wierszu; przy
   32 px i niżej to samo podcięcie już zlepiałoby litery, stąd osobna wartość
   tylko dla H1 i H2, zamiast zmieniania wspólnej reguły wyżej. */
h1, h2 { letter-spacing: -.02em; }
h1 { font-size: var(--t-h1); line-height: var(--t-h1-lh); }
h2 { font-size: var(--t-h2); line-height: var(--t-h2-lh); margin-block: var(--s-8) var(--s-4); }
h3 { font-size: var(--t-h3); line-height: var(--t-h3-lh); margin-block: var(--s-8) var(--s-3); }
h4 { font-size: var(--t-h4); line-height: var(--t-h4-lh); font-weight: 500; margin-block: var(--s-6) var(--s-2); }
p { margin-block: var(--s-4); }

.overline {
    font-family: var(--f-display);
    font-weight: 500;
    font-size: var(--t-overline);
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--c-text-muted);
    margin-bottom: var(--s-2);
}
.overline--accent { color: var(--c-accent); letter-spacing: .16em; }
.aside-faq { border: 1px solid var(--c-line); border-radius: var(--r-card); padding: var(--s-6); background: var(--c-surface); }
.aside-faq h2 { font-size: var(--t-h4); margin-block: 0 var(--s-2); }
.aside-faq .faq { max-width: none; }
.aside-faq summary { font-size: 15px; padding-block: var(--s-3); }
/* Formularz w kolumnie bocznej: nagłówek w skali H3, nie H2 — obok karty FAQ
   z nagłówkiem 19 px 32 px wyglądało jak druga strona. */
.layout__aside .form-block .section-head h2 { font-size: var(--t-h3); }
.layout__aside .form-block { max-width: none; }
/* Żółty znacznik nad tytułem karty — sygnał marki zamiast ikony */
.card__mark { display: block; width: 28px; height: 6px; background: var(--c-accent); margin-bottom: var(--s-3); }
.lead { font-size: var(--t-lead); line-height: 1.6; color: var(--c-text-soft); max-width: 62ch; }
.muted { color: var(--c-text-muted); font-size: var(--t-small); }

a { color: var(--c-brand); text-underline-offset: .18em; }
a:hover { text-decoration-color: var(--c-accent); text-decoration-thickness: 2px; }

/* Focus widoczny wszędzie; na ciemnym tle biały, żeby zachować kontrast */
:focus-visible { outline: 3px solid var(--c-accent); outline-offset: 2px; }
.section--dark :focus-visible, .site-header :focus-visible, .site-footer :focus-visible {
    outline-color: #fff;
}

/* Kolumna treści: max 720 px — dłuższe wiersze męczą przy czytaniu */
.prose { max-width: var(--measure); min-width: 0; overflow-wrap: break-word; }
.prose ul, .prose ol { margin-block: var(--s-4); padding-left: var(--s-6); }
.prose li { margin-block: var(--s-2); }
.prose li::marker { color: var(--c-accent); }

/* --- Układ ---------------------------------------------------------- */
.wrap { width: min(100% - (2 * var(--wrap-pad)), var(--wrap)); max-width: 100%; margin-inline: auto; }
.section { padding-block: var(--s-section); }
.section > .wrap > :first-child, .section > :first-child { margin-top: 0; }
.section--tight { padding-block: calc(var(--s-section) / 2); }
.section--dark { background: var(--c-ink); color: var(--c-on-dark); }
.section--dark h2, .section--dark h3 { color: var(--c-on-dark); }
.section--alt { background: var(--c-surface-alt); }
/* Dwie jasne sekcje pod rząd dawały podwójny odstęp (96+96 px) i wyrwę
   w środku strony — druga zaczyna się od razu. */
.section + .section:not(.section--alt):not(.section--dark) { padding-top: 0; }

.grid { display: grid; gap: var(--s-6); align-items: stretch; }
/* Bez tego element siatki nie zejdzie poniżej szerokości swojej zawartości
   (domyślne min-width:auto) i wypycha układ poza ekran na wąskich widokach. */
.grid > *, .layout > * { min-width: 0; }
.grid--2, .grid--3 { grid-template-columns: 1fr; }

.skip-link {
    position: absolute; left: -9999px; top: 0; z-index: 100;
    background: var(--c-accent); color: var(--c-ink);
    padding: var(--s-3) var(--s-4); font-weight: 600;
}
.skip-link:focus { left: 0; }

/* --- Nagłówek ------------------------------------------------------- */
.site-header { background: var(--c-ink); color: var(--c-on-dark); }
.site-header a { color: var(--c-on-dark); text-decoration: none; }
.header-bar {
    display: flex; align-items: center; gap: var(--s-3);
    padding-block: var(--s-3);
    /* Bez zawijania: na wąskim ekranie skracamy elementy (patrz reguły
       poniżej 480 px), zamiast pozwolić im rozepchnąć stronę w poziomie. */
    flex-wrap: nowrap;
}
.brand {
    display: flex; align-items: center; gap: var(--s-3);
    font-family: var(--f-display); font-weight: 600; font-size: 16px;
    min-width: 0;                      /* pozwala się skurczyć zamiast rozpychać */
    margin-right: auto;
}
/* Logo skaluje się wysokością; szerokość wynika z proporcji pliku SVG,
   więc nagłówek nie skacze przed wczytaniem arkusza. Na wąskim ekranie
   niższe, bo dzieli pas z telefonem i przyciskiem menu. */
.brand__logo { display: block; height: 34px; width: auto; }
@media (min-width: 768px) { .brand__logo { height: 44px; } }
.nav { display: none; }        /* poniżej 768 px zastępuje ją .mobile-nav */
.nav__list { display: flex; flex-wrap: wrap; gap: 0; list-style: none; padding: 0; margin: 0; }
.nav__link {
    display: flex; align-items: center; min-height: 44px;   /* cel dotykowy */
    padding: var(--s-2) var(--s-3);
    font-family: var(--f-display); font-weight: 500; font-size: 15px;
    border-bottom: 3px solid transparent;
}
.nav__link:hover { color: var(--c-accent); }
.nav__link[aria-current="page"] { border-bottom-color: var(--c-accent); color: var(--c-accent); }

.header-phone {
    display: inline-flex; align-items: center; justify-content: center; gap: var(--s-2);
    min-height: 44px; min-width: 44px; padding: var(--s-2) var(--s-3);
    font-family: var(--f-display); font-weight: 600; flex: none;
    background: var(--c-accent); color: var(--c-ink) !important;
    border-radius: var(--r-control);
}
.header-phone:hover { background: var(--c-accent-hover); }
.header-phone svg { width: 20px; height: 20px; fill: currentColor; }
/* Mobile-first: w nagłówku zostaje sama ikona. Numer i tak jest
   w menu mobilnym oraz w przyklejonym pasku na dole, więc nic nie ginie,
   a nagłówek nie rozpycha strony na wąskich ekranach. */
.header-phone > span { display: none; }


/* --- Menu mobilne: <details>, działa bez JS -------------------------
   Specyfikacja: menu pełnoekranowe, otwierane bez JavaScriptu.
   <details> daje to natywnie — jest też obsługiwane klawiaturą
   (Enter/Spacja otwiera, Esc zamyka) bez ani jednej linii skryptu. */
.mobile-nav { margin-left: auto; }
.mobile-nav > summary {
    display: flex; align-items: center; gap: var(--s-2);
    min-height: 44px; padding: var(--s-2) var(--s-3);
    font-family: var(--f-display); font-weight: 500; font-size: 15px;
    color: var(--c-on-dark); cursor: pointer; list-style: none;
    border: 1px solid var(--c-line-dark); border-radius: var(--r-control);
}
.mobile-nav > summary::-webkit-details-marker { display: none; }
.mobile-nav > summary { font-size: 0; gap: 0; }     /* etykieta tylko dla czytników */
.mobile-nav > summary::after { content: "☰"; font-size: 18px; line-height: 1; }
.mobile-nav[open] > summary::after { content: "✕"; }

.mobile-nav__panel {
    position: absolute; left: 0; right: 0; z-index: 40;
    background: var(--c-ink); border-top: 1px solid var(--c-line-dark);
    box-shadow: var(--sh-2);
    padding: var(--s-4) var(--wrap-pad) var(--s-8);
}
.mobile-nav__panel ul { list-style: none; margin: 0; padding: 0; }
.mobile-nav__panel a {
    display: flex; align-items: center; min-height: 48px;
    padding: var(--s-3) 0; border-bottom: 1px solid var(--c-line-dark);
    font-family: var(--f-display); font-weight: 500; font-size: 17px;
}
.mobile-nav__panel a[aria-current="page"] { color: var(--c-accent); }
.mobile-nav__cta { margin-top: var(--s-6); display: grid; gap: var(--s-3); }

/* --- Sticky pasek CTA (mobile) --------------------------------------
   Na stronach usług i realizacji: telefon i zapytanie zawsze w zasięgu
   kciuka. Ukryty od 768 px, gdzie te akcje są widoczne w nagłówku. */
.sticky-cta {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
    background: var(--c-line-dark);
    box-shadow: 0 -2px 12px rgba(29, 29, 27, .18);
}
.sticky-cta a {
    display: flex; align-items: center; justify-content: center; gap: var(--s-2);
    min-height: 56px; padding: var(--s-3);
    font-family: var(--f-display); font-weight: 600; font-size: 16px;
    text-decoration: none;
}
.sticky-cta__call { background: var(--c-ink); color: var(--c-on-dark); }
.sticky-cta__quote { background: var(--c-accent); color: var(--c-ink); }
.sticky-cta svg { width: 18px; height: 18px; fill: currentColor; }
/* Rezerwa wysokości, żeby pasek nie zasłaniał końca treści */
body.has-sticky-cta { padding-bottom: 56px; }

@media (min-width: 768px) {
    .mobile-nav { display: none; }
    .sticky-cta { display: none; }
    body.has-sticky-cta { padding-bottom: 0; }
    .header-phone > span { display: inline; }       /* jest miejsce na numer */
    .header-phone { padding-inline: var(--s-4); }
}

/* Siatka bezpieczeństwa: nic nie może rozpychać strony w poziomie.

   `clip`, a NIE `hidden`. Różnica wygląda kosmetycznie, a jest zasadnicza:
   `overflow-x: hidden` zamienia element w kontener przewijania (przeglądarka
   wylicza wtedy `overflow-y` na `auto`), a `position: sticky` przykleja się
   zawsze do najbliższego takiego kontenera. Z `hidden` na <html> przyklejony
   nagłówek przyklejał się więc do czegoś, co samo się przewija — czyli
   w praktyce nie przyklejał się wcale. `clip` obcina tak samo, ale kontenera
   przewijania nie tworzy.

   Starsze przeglądarki bez obsługi `clip` (Safari poniżej 16) po prostu
   pominą tę deklarację: stracą zabezpieczenie przed poziomym przewijaniem,
   ale nic się nie zepsuje — `max-width: 100%` zostaje. */
html, body { max-width: 100%; overflow-x: clip; }

/* --- Okruszki ------------------------------------------------------- */
.breadcrumbs { padding-block: var(--s-4); font-size: var(--t-small); color: var(--c-text-muted); }
.breadcrumbs ol { display: flex; flex-wrap: wrap; gap: var(--s-2); list-style: none; padding: 0; margin: 0; }
.breadcrumbs li + li::before { content: "›"; margin-right: var(--s-2); color: var(--c-brand-soft); }
.breadcrumbs a { color: var(--c-text-muted); }

/* --- Hero ----------------------------------------------------------- */
.hero { background: var(--c-ink); color: var(--c-on-dark); }
.hero__inner { display: grid; gap: var(--s-8); padding-block: var(--s-section); align-items: center; }
.hero h1 { color: var(--c-on-dark); max-width: 20ch; }
.hero .lead { color: var(--c-on-dark-soft); margin-top: var(--s-4); }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-top: var(--s-8); }
/* Proporcje kadru zadeklarowane z góry — obraz hero nie przesuwa układu */
.hero__media { aspect-ratio: 4 / 5; border-radius: var(--r-card); overflow: hidden; background: var(--c-line-dark); }
.hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* Hero podstrony — ciemny pas otwierający stronę. Bez niego H1 wisiał
   na tym samym tle co treść i strona zaczynała się nijako. */
.page-hero { background: var(--c-ink); color: var(--c-on-dark); }
.page-hero .wrap { padding-block: var(--s-12); }
.page-hero__grid { display: grid; gap: var(--s-8); align-items: center; }
.page-hero__media { aspect-ratio: 16 / 10; border-radius: var(--r-card); overflow: hidden; background: var(--c-line-dark); }
.page-hero__media img { width: 100%; height: 100%; object-fit: cover; }
/* 6/6 zamiast 7/5: zdjęcie przestaje być ilustracją obok tekstu i staje się
   drugą połową kompozycji. Nagłówek i tak ma `max-width: 20ch`, więc szersza
   kolumna tekstu i tak nie zostałaby wykorzystana. */
@media (min-width: 1024px) { .page-hero__grid--split { grid-template-columns: 1fr 1fr; } }
.page-hero h1 { color: var(--c-on-dark); max-width: 20ch; }
.page-hero .lead { color: var(--c-on-dark-soft); margin-top: var(--s-4); }
.page-hero .overline { color: var(--c-accent); }
/* Okruszki wewnątrz ciemnego hero */
.page-hero .breadcrumbs { color: var(--c-on-dark-soft); padding-top: 0; }
.page-hero .breadcrumbs a { color: var(--c-on-dark-soft); }
.page-hero .breadcrumbs a:hover { color: var(--c-accent); }
.page-hero .breadcrumbs li + li::before { color: var(--c-line-dark); }

/* Hero realizacji. Tytuly case studies to zdania („Martin Garcia Garcia –
   Tężnia Busko"), a nie dwuwyrazowe nazwy uslug — przy limicie 20ch lamaly
   sie na cztery linijki obok w polowie pustej kolumny. Okladka idzie w 16/9,
   bo w tym kadrze robi sie zdjecia z wydarzen; przy 4/3 kadr byl przycinany
   po bokach i ze sceny zostawal srodek. */
.page-hero--project h1 { max-width: 30ch; }
.page-hero__media--wide { aspect-ratio: 16 / 9; }

/* Metryczka realizacji w jednej linii: klient · miejsce · data. Wczesniej
   byla tabela — trzy wiersze i ponad 150 px pionu na trzy wartosci, z ktorych
   kazda ma jedno slowo. Etykiety zostaja (bez nich „Busko-Zdrój · 29 czerwca
   2025" to zgadywanka), tylko schodza do wielkosci overline'u. */
.fact-line { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-6); margin-top: var(--s-6); }
.fact-line > div { display: flex; align-items: baseline; gap: var(--s-2); min-width: 0; }
.fact-line dt {
    font-family: var(--f-display); font-weight: 500; font-size: var(--t-overline);
    letter-spacing: .14em; text-transform: uppercase; color: var(--c-accent);
}
.fact-line dd { margin: 0; font-family: var(--f-display); font-weight: 600; }
.page-hero .fact-line dd { color: var(--c-on-dark); }
/* Kropka miedzy pozycjami: przy zawinieciu wiersza sam odstep to za malo,
   zeby „Miejsce Busko-Zdrój" i „Data 29 czerwca 2025" czytaly sie osobno. */
.fact-line > div + div::before { content: "·"; color: var(--c-line-dark); margin-right: var(--s-4); }

/* Hero kontaktu i dokumentów prawnych: okruszki + H1 + lead i koniec.
   Bez zdjęcia i bez overline'u ciemny pas nie ma czym wypełnić wysokości,
   więc zostaje na 48 px pionu zamiast rosnąć razem z resztą hero. */
.page-hero--slim .wrap { padding-block: var(--s-12); }
.page-hero--slim h1 { max-width: 28ch; }

/* --- Strona kontaktu -------------------------------------------------
   Desktop: dane po lewej (5 kolumn), formularz po prawej (7). Wcześniej
   jedna kolumna 720 px siedziała na środku, a formularz — jedyna rzecz,
   po którą klient tu przychodzi — lądował poniżej pierwszego ekranu. */
.contact-grid { display: grid; gap: var(--s-8); align-items: start; }
.contact-panel { display: grid; gap: var(--s-6); }
.contact-card {
    background: var(--c-surface); border: 1px solid var(--c-line);
    border-radius: var(--r-card); padding: var(--s-6);
}
.contact-card h2 { font-size: var(--t-h3); margin-block: 0 var(--s-3); }
.contact-card h3 { font-size: var(--t-h4); margin-block: var(--s-6) var(--s-1); }
.contact-card p { margin-block: var(--s-2); }
.contact-card address { line-height: 1.6; }
.contact-phone {
    font-family: var(--f-display); font-weight: 600; font-size: 24px;
    color: var(--c-brand); text-decoration: none;
    display: inline-flex; align-items: center; min-height: 44px; margin-top: var(--s-3);
}
.contact-phone:hover { color: var(--c-accent-hover); }

/* Mapa: obraz z pinezką, nie iframe. Osadzona mapa dociąga kilkaset
   kilobajtów obcych skryptów i ustawia ciasteczka przed zgodą. */
.contact-map {
    margin: 0; border: 1px solid var(--c-line);
    border-radius: var(--r-card); overflow: hidden; background: var(--c-brand);
}
.contact-map img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.contact-map__note {
    display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4);
    justify-content: space-between; align-items: baseline;
    padding: var(--s-3) var(--s-4);
    background: var(--c-surface); font-size: var(--t-small); color: var(--c-text-muted);
}
.contact-map__note a { font-family: var(--f-display); font-weight: 600; color: var(--c-brand); }

@media (min-width: 1024px) {
    .contact-grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); gap: 56px; }
}

.page-head { padding-block: var(--s-8); }
.page-head .lead { margin-top: var(--s-4); }

/* Nagłówek sekcji wyśrodkowany — inaczej przy szerokim ekranie tytuł
   siedzi w lewym rogu, a pod nim wyśrodkowana treść. */
.section-head { max-width: 960px; margin-inline: auto; margin-bottom: var(--s-8); }
.section-head h2 { margin-top: 0; }
/* Nad siatką kart nagłówek trzyma lewą krawędź kontenera. Wyśrodkowany na
   960 px wisiał 160 px w prawo od pierwszej karty i cała sekcja wyglądała
   na przesuniętą. Wyśrodkowanie zostaje tam, gdzie treść pod nagłówkiem
   też jest wyśrodkowana (FAQ, formularz). */
.section-head--grid { max-width: none; margin-inline: 0; }

/* --- Układ strony treściowej ----------------------------------------
   Kolumna tekstu ma 720 px (czytelna długość wiersza), ale w kontenerze
   1280 px zostawiałaby pustą prawą połowę. Od 1024 px obok treści idzie
   węższa kolumna z CTA — specyfikacja wymaga wezwania do działania przy
   każdej sekcji, a stale widoczna karta realizuje to bez powtarzania
   tego samego bloku po każdym H2. */
.layout { display: grid; gap: var(--s-8); align-items: start; }
/* Bez kolumny bocznej centrujemy tekst — inaczej kolumna 720 px klei się
   do lewej krawędzi, a prawa połowa ekranu zostaje pusta. */
.layout:not(.layout--sidebar) > div { max-width: var(--measure); margin-inline: auto; width: 100%; }

.aside-cta {
    background: var(--c-brand); color: var(--c-on-dark);
    border-radius: var(--r-card); padding: var(--s-6);
    display: grid; gap: var(--s-4);
}
.aside-cta h2 {
    color: var(--c-on-dark); font-size: var(--t-h3);
    margin: 0; letter-spacing: 0; text-transform: none;
}
.aside-cta p { margin: 0; font-size: var(--t-small); color: var(--c-on-dark-soft); }
.aside-cta .btn { width: 100%; }
.aside-cta__phone {
    font-family: var(--f-display); font-weight: 600; font-size: 20px;
    color: var(--c-accent); text-decoration: none; display: block;
}
.aside-facts { border: 1px solid var(--c-line); border-radius: var(--r-card); padding: var(--s-6); background: var(--c-surface); }
.aside-facts h2 { font-size: var(--t-h4); margin-block: 0 var(--s-3); }
.aside-facts ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); font-size: var(--t-small); }
.aside-facts li { display: flex; gap: var(--s-2); }
.aside-facts li::before { content: "✓"; color: var(--c-accent); font-weight: 700; flex: none; }
/* Wariant z odnosnikami (zakres prac realizacji): ptaszek znaczy „mamy to",
   a tu kazda pozycja jest linkiem do strony uslugi — stad strzalka. */
.aside-facts--links li::before { content: "→"; font-weight: 500; }
.aside-facts--links a { font-family: var(--f-display); font-weight: 600; }

@media (min-width: 1024px) {
    /* 7/5 zamiast 1fr/320px: przy stałej szerokości kolumny bocznej kolumna
       treści miała ok. 910 px, a tekst i tak łamał się na 720 px — między
       tekstem a kolumną boczną zostawał pas 190 px pustki, przez który cała
       strona wyglądała jak dosunięta do lewej krawędzi. 7fr to ok. 700 px,
       czyli dokładnie tyle, ile zajmuje kolumna treści: nic nie zostaje. */
    .layout--sidebar { grid-template-columns: minmax(0, 7fr) minmax(320px, 5fr); gap: 56px; }
    /* Zapas na przyklejony naglowek — bez tego karta CTA wjezdza pod pasek
       i chowa sie za nim jej wlasny naglowek. */
    .layout__aside { position: sticky; top: calc(var(--header-h) + var(--s-6));
        display: grid; gap: var(--s-6); }
}

/* --- Przyciski ------------------------------------------------------ */
.btn {
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; padding: var(--s-3) var(--s-6);
    font-family: var(--f-display); font-weight: 600; font-size: 16px;
    text-decoration: none; cursor: pointer;
    border: 2px solid transparent; border-radius: var(--r-control);
}
.btn--primary { background: var(--c-accent); color: var(--c-ink); }
.btn--primary:hover { background: var(--c-accent-hover); }
.btn--ghost { border-color: currentColor; color: inherit; background: transparent; }
.btn--ghost:hover { border-color: var(--c-accent); color: var(--c-accent); }
.btn--block { width: 100%; }

/* --- Karty ---------------------------------------------------------- */
.card {
    background: var(--c-surface);
    border: 1px solid var(--c-line);
    border-radius: var(--r-card);
    display: flex; flex-direction: column; overflow: hidden;
}
/* Stan wskazania: żółta ramka + delikatny cień. Ten sam stan dla klawiatury
   (focus-within), bo inaczej osoba tabująca po kartach nie widzi, w której
   karcie jest odnośnik. Wysokości kart wyrównuje siatka — karta jest
   kolumną flex, a odnośnik dolny ma margin-top: auto (patrz .card__more). */
.card { transition: border-color .15s ease, box-shadow .15s ease; }
.card:hover, .card:focus-within { border-color: var(--c-accent); box-shadow: var(--sh-1); }
.card__body { padding: var(--s-6); display: flex; flex-direction: column; gap: var(--s-2); flex: 1; }
.card__title { font-size: var(--t-h4); margin: 0; }
.card__title a { color: var(--c-ink); text-decoration: none; }
.card__title a:hover { color: var(--c-brand); }
.card__meta { font-size: var(--t-small); color: var(--c-text-muted); margin: 0; }
.card__text { font-size: var(--t-small); color: var(--c-text-soft); margin: 0; }
.card__more {
    margin-top: auto; padding-top: var(--s-3);
    font-family: var(--f-display); font-weight: 600; font-size: 14px; color: var(--c-brand);
}
/* Karty: 4:3 — także dla kafelka zastępczego, więc brak zdjęcia nie zmienia
   wysokości karty i lista nie skacze po uzupełnieniu galerii.
   Wyższy kadr niż dotychczasowe 3:2: zdjęcie z realizacji jest tu treścią,
   a nie ozdobą przy tytule, więc dostaje więcej miejsca niż podpis pod nim. */
.card__media { aspect-ratio: 4 / 3; background: var(--c-surface-alt); }
.card__media img { width: 100%; height: 100%; object-fit: cover; }
.card__media--fallback {
    background: var(--c-brand); display: flex; flex-direction: column;
    justify-content: flex-end; gap: var(--s-2); padding: var(--s-6);
}
.card__fallback-cat {
    margin: 0; color: var(--c-accent); font-family: var(--f-display);
    font-weight: 500; font-size: 12px; letter-spacing: .14em; text-transform: uppercase;
}
/* Tytuł realizacji bez zdjęcia siedzi w kafelku i tylko tam — pod kafelkiem
   zostaje data, miasto i odnośnik. Wcześniej ta sama nazwa czytała się
   dwa razy pod rząd. */
.card__fallback-title {
    margin: 0; color: #fff; font-family: var(--f-display);
    font-weight: 600; font-size: 22px; line-height: 1.2;
}
.card__fallback-title a { color: inherit; text-decoration: none; }
.card:hover .card__fallback-title a, .card__fallback-title a:hover { color: var(--c-accent); }
/* Wiersz oceny nad opiniami */
.rating-line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); font-size: var(--t-small); }
.rating-line strong { font-family: var(--f-display); font-size: 20px; color: var(--c-brand); }
.rating-line span { color: var(--c-accent); letter-spacing: .1em; }

/* --- FAQ: akordeon na <details>, działa bez JS ----------------------
   960 px, nie 860: pytania w wąskiej kolumnie na pustym tle wyglądały
   na desktopie jak lista wciśnięta w środek ekranu. Dwie kolumny
   (columns: 2) świadomie odrzucone — otwarcie jednego <details>
   przebudowuje wtedy cały układ i pytania skaczą pod kursorem. */
.faq { max-width: 960px; margin-inline: auto; }
.faq details { border-bottom: 1px solid var(--c-line); }
.faq summary {
    display: flex; align-items: center; gap: var(--s-3);
    min-height: 44px; padding: var(--s-4) 0;
    font-family: var(--f-display); font-weight: 600; font-size: var(--t-h4);
    cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::before {
    content: "+"; color: var(--c-accent); font-size: 22px; line-height: 1; flex: none;
}
.faq details[open] summary::before { content: "−"; }
.faq details > div { padding-bottom: var(--s-4); color: var(--c-text-soft); }

/* --- Galeria -------------------------------------------------------- */
/* Zdjęcie w treści zajmuje całą szerokość kolumny treści. Miało max 720 px
   niezależnie od kolumny, więc po zmianie siatki (7fr) było węższe od tekstu
   nad nim i pod nim — wyglądało jak wklejone z innej strony. */
.content-figure { margin: var(--s-12) 0 0; max-width: none; }
.content-figure img { width: 100%; aspect-ratio: 16 / 9; object-fit: cover; border-radius: var(--r-card); }
.content-figure figcaption { font-size: 14px; color: var(--c-text-muted); padding-top: var(--s-2); }
/* Film z realizacji. Podgląd to okładka z naszego katalogu, więc do kliknięcia
   nie leci żadne żądanie do YouTube — a proporcje 16/9 rezerwują miejsce z góry
   i podmiana podglądu na odtwarzacz nie przesuwa treści pod kursorem. */
.video { margin: var(--s-12) 0 0; }
.video__facade, .video iframe { display: block; width: 100%; aspect-ratio: 16 / 9;
    border: 0; border-radius: var(--r-card); }
.video__facade { position: relative; overflow: hidden; background: var(--c-ink); }
.video__facade img { width: 100%; height: 100%; object-fit: cover; }
/* Trójkąt bez pliku graficznego i bez fontu ikonowego — obrócony kwadrat
   z obciętymi rogami kosztuje zero zapytań. */
.video__play { position: absolute; inset: 0; margin: auto; width: 72px; height: 72px;
    border-radius: 50%; background: var(--c-accent); }
.video__play::after { content: ""; position: absolute; inset: 0; margin: auto;
    width: 0; height: 0; border-style: solid; border-width: 13px 0 13px 22px;
    border-color: transparent transparent transparent var(--c-ink); transform: translateX(3px); }
.video__facade:hover .video__play { background: var(--c-accent-hover); }
.video__label { position: absolute; left: 0; right: 0; bottom: 0; padding: var(--s-3) var(--s-4);
    color: #fff; font-size: var(--t-small);
    background: linear-gradient(to top, rgba(0,0,0,.72), rgba(0,0,0,0)); }
.video figcaption { font-size: var(--t-small); color: var(--c-text-muted); padding-top: var(--s-2); }

/* 380 px zamiast 280: przy szerokości 1360 px daje trzy kolumny po ok. 440 px
   zamiast czterech po 308 px. Galeria realizacji przestawała przez to wyglądać
   jak kontaktówka — a to jest materiał dowodowy, nie miniaturki. */
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); gap: var(--s-4); }
.gallery figure { margin: 0; }
.gallery img { aspect-ratio: 3 / 2; object-fit: cover; width: 100%; }
/* Pierwsze zdjęcie na dwie kolumny i w szerszym kadrze — otwiera galerię
   zamiast stać w szeregu z resztą. Dopiero od 768 px: na jednej kolumnie
   „span 2" nie ma czego objąć i rozpychałoby siatkę. */
@media (min-width: 768px) {
    .gallery figure:first-child { grid-column: span 2; }
    .gallery figure:first-child img { aspect-ratio: 16 / 9; }
}
.gallery figcaption { font-size: var(--t-small); color: var(--c-text-muted); padding-top: var(--s-2); }
/* Galeria realizacji stoi poza kolumna tekstowa, wiec ma pelna szerokosc
   kontenera i wlasny odstep od filmu — bez tego naglowek „Galeria" wisial
   16 px pod ostatnim kadrem. */
.project-block { margin-top: var(--s-12); }
.project-block > h2 { margin-top: 0; }

/* --- Tabele ---------------------------------------------------------
   Tabele specyfikacji i dojazdu to na stronach usług jedyny materiał
   „do przeczytania wzrokiem", a szły w 13-14 px szarym tekstem bez tła —
   czyli wyglądały jak przypis. Teraz: 15/16 px, nagłówek wiersza w petrolu,
   zebra co drugi wiersz i realne światło w komórce. */
.data-table {
    width: 100%; border-collapse: collapse; margin-block: var(--s-6);
    font-size: 15px; line-height: 1.55;
}
.data-table th, .data-table td {
    text-align: left; padding: 10px 16px; vertical-align: top;
    border-bottom: 1px solid var(--c-line);
}
.data-table th {
    width: 34%; font-weight: 600; color: var(--c-brand); font-family: var(--f-display);
}
/* Zebra: wiersze nieparzyste białe, parzyste #fafaf8. Samo #fafaf8 na kremowym
   tle strony (#faf9f5) było niewidoczne — te dwie barwy różnią się o 3 punkty
   na jednym kanale. Kontrast bierze się więc z bieli, nie z szarości. */
.data-table tbody tr:nth-child(odd) { background: var(--c-surface); }
.data-table tbody tr:nth-child(even) { background: #fafaf8; }
.data-table tbody tr:last-child th, .data-table tbody tr:last-child td { border-bottom: 0; }
.table-scroll { overflow-x: auto; }
@media (min-width: 768px) {
    .data-table { font-size: 16px; }
    .data-table th, .data-table td { padding: 12px 16px; }
}

/* --- Opinie ---------------------------------------------------------
   Trzy opinie w trzech kolumnach równej wysokości. Przy siatce grid--2
   wychodziło 2+1 i trzecia karta zostawała sama w wierszu, z pustym
   miejscem obok. Poniżej 1024 px opinie idą jedna pod drugą — dwie kolumny
   na tablecie dawałyby ten sam problem, tylko przy innej szerokości. */
.grid--quotes { grid-template-columns: 1fr; }
@media (min-width: 1024px) { .grid--quotes { grid-template-columns: repeat(3, 1fr); } }
.quote {
    background: var(--c-surface); border-left: 3px solid var(--c-accent);
    padding: var(--s-6); margin: 0; height: 100%;
    display: flex; flex-direction: column;
}
.quote p { margin: 0; font-size: var(--t-body); }
.quote figcaption { margin-top: auto; padding-top: var(--s-3); font-size: var(--t-small); color: var(--c-text-muted); }

/* --- Opinie: podpis i logotyp klienta --------------------------------
   Podpis to teraz wiersz z logotypem obok tekstu, a nie sam tekst — logo
   ustawia się w linii bazowej cytatu, więc nie potrzebuje własnego wiersza. */
.quote__foot { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.quote__logo { height: 32px; width: auto; max-width: 140px; object-fit: contain; }

/* --- Opinie: karuzela na podstronach ---------------------------------
   Pas przewijany natywnie (`overflow-x: auto` + `scroll-snap`), a nie
   przestawiany skryptem. Bez JS działa palcem, kółkiem i klawiaturą,
   a wszystkie cytaty siedzą w HTML — karuzela budowana skryptem pokazałaby
   Googlebotowi jeden slajd albo żadnego.

   `scroll-padding-inline` odsuwa przyklejony slajd od krawędzi kontenera,
   inaczej po kliknięciu strzałki cytat dotykałby brzegu ekranu. */
.quotes { position: relative; }
.quotes__viewport {
    margin-top: var(--s-8); padding-bottom: var(--s-4);
    overflow-x: auto; overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    /* Pasek przewijania zostaje widoczny: to jedyny sygnał bez JS,
       że pas ma ciąg dalszy poza krawędzią ekranu. */
    scrollbar-width: thin;
}
/* Karty rozciagniete do rownej wysokosci (domyslne `stretch`) — SWIADOMIE,
   mimo ze opinie roznia sie dlugoscia dwukrotnie.

   Probowalem `align-items: flex-start` i to NIE jest rozwiazanie: wysokosc
   pasa i tak wyznacza najwyzszy slajd, takze ten poza widocznym kadrem, wiec
   pod krotkimi cytatami pojawial sie pusty pas tla sekcji, a karty przestawaly
   tworzyc rzad. Pustka zostala ta sama, tylko wyszla poza karte i zaczela
   wygladac jak blad ukladu.

   Wysokosc pasa jest wiec kwestia REDAKCYJNA, nie CSS: skraca sie ja,
   skracajac najdluzsza opinie w panelu (Opinie), a nie regula tutaj. */
.quotes__track { display: flex; gap: var(--s-6); margin: 0; padding: 0; list-style: none; }
.quotes__slide {
    flex: 0 0 88%; scroll-snap-align: start;
    /* `display: flex` na slajdzie, żeby `.quote { height: 100% }` miało
       się do czego odnieść — inaczej karty w pasie mają różną wysokość. */
    display: flex;
}
/* Cytat wypelnia slajd: bez `flex: 1` figura mialaby szerokosc tresci,
   wiec kazda karta w pasie bylaby innej szerokosci mimo rownych slajdow. */
.quotes__slide > .quote { flex: 1 1 auto; min-width: 0; }
@media (min-width: 768px) { .quotes__slide { flex-basis: 46%; } }
@media (min-width: 1024px) { .quotes__slide { flex-basis: 31%; } }

/* Strzałki są wyłącznie wygodą dla myszy — bez skryptu nic by nie zrobiły,
   więc pokazuje je dopiero JS (atrybut `hidden` zdejmowany w site.js). */
.quotes__nav { display: flex; gap: var(--s-2); margin-top: var(--s-4); }
.quotes__btn {
    width: 44px; height: 44px;            /* minimalny cel dotykowy WCAG */
    display: inline-flex; align-items: center; justify-content: center;
    background: var(--c-surface); color: var(--c-brand);
    border: 1px solid var(--c-line); border-radius: var(--r-card);
    font-size: 18px; cursor: pointer;
}
.quotes__btn:hover { border-color: var(--c-brand); }
.quotes__btn[disabled] { opacity: .4; cursor: default; }
.quotes__btn[disabled]:hover { border-color: var(--c-line); }

/* --- Blok CTA ------------------------------------------------------- */
.cta {
    background: var(--c-brand); color: var(--c-on-dark);
    padding: var(--s-8); border-radius: var(--r-card);
    display: grid; gap: var(--s-6);
}
.cta h2, .cta p { color: var(--c-on-dark); margin: 0; }
.cta h2 { margin-bottom: var(--s-2); }
.cta .btn--ghost { color: var(--c-on-dark); }

/* --- Liczby --------------------------------------------------------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-6); }
.stat__value { font-family: var(--f-display); font-size: 40px; font-weight: 600; color: var(--c-accent); line-height: 1; margin: 0; }
.stat__label { font-size: var(--t-small); color: var(--c-text-muted); margin-top: var(--s-2); }
.section--dark .stat__label { color: var(--c-on-dark-soft); }

/* --- Formularz ------------------------------------------------------ */
.form { max-width: var(--measure); margin-inline: auto; display: grid; gap: var(--s-4); }
.form__row { display: grid; gap: var(--s-4); }
.field { display: grid; gap: var(--s-2); }
.field > label { font-family: var(--f-display); font-weight: 500; font-size: 15px; }
.field input, .field select, .field textarea {
    font: inherit; font-size: 16px;                /* 16 px — iOS nie przybliża widoku */
    min-height: 44px; padding: var(--s-3);
    border: 1px solid var(--c-line); border-radius: var(--r-control);
    background: var(--c-surface); color: var(--c-text); width: 100%;
}
.field textarea { min-height: 130px; resize: vertical; }
.field input:hover, .field textarea:hover, .field select:hover { border-color: var(--c-brand-soft); }
.field .hint { font-size: var(--t-small); color: var(--c-text-muted); }
/* Błąd sygnalizowany ramką, ikoną i tekstem — nigdy samym kolorem */
.field--error input, .field--error textarea, .field--error select { border-color: var(--c-error); border-width: 2px; }
.field__error { display: flex; align-items: center; gap: var(--s-2); color: var(--c-error); font-size: var(--t-small); }
.field__error::before { content: "!"; font-weight: 700; border: 2px solid currentColor; border-radius: 50%; width: 18px; height: 18px; display: grid; place-items: center; flex: none; font-size: 12px; }
.form__note { font-size: var(--t-small); color: var(--c-text-muted); }
.form-block { max-width: var(--measure); margin-inline: auto; }
/* Formularz zamykający stronę usługi: biała karta na szarym tle sekcji.
   Bez tła i ramki pola „pływały" na pustej stronie — na szerokim ekranie
   wyglądało to jak niedokończony układ, a nie jak wezwanie do działania. */
.form-card {
    max-width: var(--measure); margin-inline: auto;
    background: var(--c-surface); border: 1px solid var(--c-line);
    border-radius: var(--r-card); padding: var(--s-6);
}
@media (min-width: 768px) { .form-card { padding: var(--s-12); } }
.form-card .section-head { margin-bottom: var(--s-6); }
.form-card .section-head h2 { font-size: var(--t-h2); }
.alert { padding: var(--s-4); border-radius: var(--r-control); border-left: 3px solid; }
.alert--success { background: rgba(46, 125, 50, .08); border-color: var(--c-success); }
.alert--error { background: rgba(179, 38, 30, .07); border-color: var(--c-error); }
/* Pułapka na boty — ukryta przed ludźmi, widoczna dla automatów */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* --- Stopka --------------------------------------------------------- */
/* Bez marginesu górnego: ostatnia sekcja ma już 96 px paddingu na dole,
   więc margines dawał 192 px pustego tła nad stopką. */
.site-footer { background: var(--c-ink); color: var(--c-on-dark-soft); padding-block: var(--s-section) var(--s-8); }
.site-footer a { color: var(--c-on-dark-soft); }
.site-footer a:hover { color: var(--c-accent); }
.site-footer h2 {
    font-size: var(--t-overline); color: var(--c-on-dark);
    margin-block: 0 var(--s-4); letter-spacing: .14em; text-transform: uppercase; font-weight: 500;
}
.footer-grid { display: grid; grid-template-columns: 1fr; gap: var(--s-8); }
.footer-list { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--s-2); }
.footer-bottom {
    margin-top: var(--s-12); padding-top: var(--s-6);
    border-top: 1px solid var(--c-line-dark); font-size: var(--t-small);
    display: grid; gap: var(--s-2);
}
address { font-style: normal; }

/* --- Breakpointy (mobile-first; treść identyczna na każdej szerokości) */
@media (min-width: 480px) {
    .grid--2 { grid-template-columns: repeat(2, 1fr); }
    .form__row--2 { grid-template-columns: repeat(2, 1fr); }
    .footer-bottom { grid-template-columns: 1fr auto; }
}

@media (min-width: 768px) {
    /* menu mobilne → desktop, usługi 2 kolumny */
    .nav { display: block; margin-left: auto; }
    .header-phone { margin-left: 0; }
    .grid--3 { grid-template-columns: repeat(2, 1fr); }
    .footer-grid { grid-template-columns: 1.4fr 1fr 1fr; }
    .cta { grid-template-columns: 1fr auto; align-items: center; padding: var(--s-12); }
    .hero__media { aspect-ratio: 4 / 3; }
}

@media (min-width: 1024px) {
    /* usługi 3 kolumny, hero dzielony 7/5 */
    .grid--3 { grid-template-columns: repeat(3, 1fr); }
    /* Hero: obraz sięga wysokości bloku tekstu, a nie wisi wyśrodkowany
       w połowie pasa. Wcześniej kadr 4:3 przy szerokości 5fr miał ok. 375 px
       wysokości i przy 96 px pionu sekcji wyglądał na zdjęcie ilustracyjne,
       a nie na główny materiał wizualny strony. Tekst jest teraz wyśrodkowany
       w swojej kolumnie, więc pod przyciskami nie zostaje pusty pas. */
    .hero__inner--split { grid-template-columns: 7fr 5fr; align-items: stretch; }
    .hero__inner--split > div:first-child {
        display: flex; flex-direction: column; justify-content: center;
    }
    .hero__inner--split .hero__media { height: 100%; min-height: 420px; }
}

@media print {
    .site-header, .site-footer, .cta, .skip-link { display: none; }
    body { background: #fff; color: #000; }
}



/* =====================================================================
   WARSTWA RUCHU
   Wszystko ponizej jest DODATKIEM. Strona bez JavaScriptu i bez tych
   regul jest kompletna i czytelna — takze dla Googlebota. Animacje
   dzialaja wylacznie na `transform` i `opacity`, czyli po stronie
   kompozytora GPU: nie wymuszaja przeliczania ukladu przy przewijaniu.
   ===================================================================== */

/* --- Plynne przewijanie do kotwic ------------------------------------
   Zero JS. Globalny blok prefers-reduced-motion wyzej zeruje czasy przejsc
   i animacji, ale scroll-behavior go nie obchodzi — stad osobny warunek. */
html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

/* Kazdy element z identyfikatorem moze byc celem kotwicy (#formularz, #tresc),
   a przyklejony naglowek zaslonilby mu gore. */
[id] { scroll-margin-top: calc(var(--header-h) + var(--s-4)); }

/* --- Przyklejony naglowek --------------------------------------------
   Samo przyklejenie to CSS, wiec dziala bez JS. Skrypt doklada tylko klase
   `is-scrolled`. z-index 45: ponad trescia, ale ponizej przyklejonego paska
   CTA (50) i odnosnika „Przejdz do tresci" (100), ktore musza byc na wierzchu. */
.site-header {
    position: sticky; top: 0; z-index: 45;
    transition: box-shadow .2s ease;
}
.site-header.is-scrolled { box-shadow: 0 2px 14px rgba(0, 0, 0, .38); }
.header-bar { transition: padding .2s ease; }
/* Po odjechaniu od gory pasek oddaje pion tresci. Logo zmniejsza sie razem
   z nim, inaczej samo rozpychaloby naglowek z powrotem. */
.site-header.is-scrolled .header-bar { padding-block: var(--s-2); }
.site-header.is-scrolled .brand__logo { height: 30px; }
@media (min-width: 768px) {
    .site-header.is-scrolled .brand__logo { height: 36px; }
}

/* --- Podkreslenie w nawigacji ----------------------------------------
   Tylko dla wskazania mysza i klawiatura. Strone biezaca oznacza istniejacy
   `border-bottom` przy [aria-current] — to jest znacznik stanu, nie efekt,
   wiec ma sie pojawiac natychmiast, bez animacji. */
.nav__link { position: relative; }
.nav__link::after {
    content: ''; position: absolute; left: var(--s-3); right: var(--s-3); bottom: -3px;
    height: 3px; background: var(--c-accent);
    transform: scaleX(0); transform-origin: left center;
    transition: transform .2s ease;
}
.nav__link:hover::after, .nav__link:focus-visible::after { transform: scaleX(1); }
.nav__link[aria-current="page"]::after { content: none; }

/* --- Powiekszenie kadru na karcie ------------------------------------
   Czysty CSS, bez JS. `overflow: hidden` na kadrze, a nie tylko na karcie:
   inaczej powiekszony obraz wychodzilby na zaokraglony rog karty. */
.card__media { overflow: hidden; }
.card__media img { transition: transform .5s ease; }
.card:hover .card__media img,
.card:focus-within .card__media img { transform: scale(1.05); }

/* --- Wejscie elementow przy przewijaniu ------------------------------
   Ukrycie obowiazuje WYLACZNIE pod `html.motion`, czyli dopiero gdy maly
   skrypt w <head> potwierdzi, ze JavaScript dziala i ze uzytkownik nie prosil
   o ograniczenie ruchu. Bez JS `.reveal` nie ma zadnych wlasciwosci i tresc
   jest widoczna od pierwszej klatki.

   `reveal-failsafe` to siatka bezpieczenstwa na wypadek, gdyby skrypt w <head>
   zdazyl ukryc tresc, ale site.js sie nie wczytal (blad sieci, blokada
   rozszerzeniem). Po 1,2 s tresc pokazuje sie sama. site.js rozbraja to
   klasa `js-ready`, ustawiana dopiero gdy obserwator faktycznie dziala. */
html.motion .reveal {
    opacity: 0;
    transform: translateY(16px);
    animation: reveal-failsafe 0s 1.2s forwards;
}
html.motion.js-ready .reveal { animation: none; }
html.motion .reveal.is-in {
    opacity: 1; transform: none; animation: none;
    transition: opacity .5s ease-out, transform .5s ease-out;
}
@keyframes reveal-failsafe { to { opacity: 1; transform: none; } }

/* --- Powiekszenie zdjecia z galerii ----------------------------------
   Bez JS kazde zdjecie jest zwyklym odnosnikiem do pelnego pliku i otwiera sie
   w nowej karcie. Ponizsze style dotycza wylacznie nakladki budowanej skryptem. */
.gallery a { display: block; }

.lb {
    position: fixed; inset: 0;
    width: 100%; height: 100%; max-width: 100%; max-height: 100%;
    margin: 0; padding: 0; border: 0; background: transparent;
    overflow: hidden;
}
.lb::backdrop { background: rgba(29, 29, 27, .92); }
.lb__frame {
    display: grid; align-content: center; justify-items: center; gap: var(--s-4);
    width: 100%; height: 100%; padding: var(--s-12) var(--s-8);
}
.lb__img {
    max-width: min(1400px, 90vw); max-height: 80vh;
    width: auto; height: auto; object-fit: contain;
    border-radius: var(--r-card); background: var(--c-line-dark);
}
.lb__caption {
    margin: 0; max-width: 70ch; text-align: center;
    color: var(--c-on-dark-soft); font-size: var(--t-small);
}
.lb__close, .lb__nav {
    position: absolute; display: flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px;      /* cel dotykowy */
    padding: 0; border: 0; cursor: pointer;
    background: rgba(29, 29, 27, .6); color: var(--c-on-dark);
    font-family: var(--f-display); line-height: 1;
    border-radius: var(--r-control);
}
.lb__close:hover, .lb__nav:hover { background: var(--c-accent); color: var(--c-ink); }
.lb__close { top: var(--s-4); right: var(--s-4); font-size: 28px; }
.lb__nav { top: 50%; transform: translateY(-50%); font-size: 32px; }
.lb__nav--prev { left: var(--s-4); }
.lb__nav--next { right: var(--s-4); }

/* --- Zgoda na pliki cookie -------------------------------------------
   Okno buduje skrypt z views/layouts/_cookieConsent.php, klonujac markup
   z <template>. Ten sam <dialog> co w powiekszeniu zdjecia: pulapka focusa
   i wylaczenie tla dla czytnikow ekranu przychodza z przegladarki.
   Wysokosc ograniczona do ekranu, bo na niskim oknie telefonu lista
   kategorii wypchnelaby przyciski poza widok i nie dalo by sie kliknac. */
.cc {
    width: min(100% - (2 * var(--wrap-pad)), 560px);
    max-height: calc(100vh - (2 * var(--s-6)));
    padding: 0; border: 0; border-radius: var(--r-card);
    background: var(--c-surface); color: var(--c-text);
    box-shadow: var(--sh-2);
}
.cc::backdrop { background: rgba(29, 29, 27, .72); }
.cc__box { padding: var(--s-6); display: grid; gap: var(--s-4); }
.cc__title { font-size: var(--t-h3); margin: 0; }
.cc__text { margin: 0; font-size: var(--t-small); color: var(--c-text-soft); }
.cc__cats { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.cc__cat { border: 1px solid var(--c-line); border-radius: var(--r-control); padding: var(--s-3); }
/* Cala etykieta jest celem klikniecia — pole 20 px samo w sobie byloby
   za male na palec (wytyczne: 44 px), a rozpychanie kwadraciku psuje uklad. */
.cc__check {
    display: flex; align-items: center; gap: var(--s-3); min-height: 24px;
    font-family: var(--f-display); font-weight: 600; cursor: pointer;
}
.cc__check input { flex: none; width: 20px; height: 20px; accent-color: var(--c-accent); cursor: inherit; }
.cc__check input:disabled { cursor: default; }
.cc__hint { margin: var(--s-1) 0 0; font-size: var(--t-small); color: var(--c-text-muted); }
.cc__actions { display: grid; gap: var(--s-3); }
@media (min-width: 480px) {
    /* Wybor po lewej, zgoda na wszystko po prawej — kolejnosc jak w reszcie
       serwisu: dzialanie glowne konczy wiersz. */
    .cc__actions { grid-template-columns: 1fr 1fr; }
}

/* --- Przycisk „do góry" -----------------------------------------------
   Czysta wygoda, zero treści — dlatego pojawia się WYŁĄCZNIE gdy działa
   JavaScript (klasa `js` z site.js). Bez skryptu nie ma go w ogóle, zamiast
   wisieć bezużytecznie albo, co gorsza, zasłaniać treść na całej długości
   strony. Odnośnik w HTML jest zapasem na wypadek, gdyby skrypt przestał
   obsługiwać kliknięcie.

   Pozycja: nad przyklejonym paskiem CTA, który na wąskich ekranach zajmuje
   dolne 56 px. Bez tego przesunięcia przycisk lądowałby dokładnie na nim. */
.to-top { display: none; }
html.js .to-top {
    display: inline-flex; align-items: center; justify-content: center;
    position: fixed; right: var(--s-4); bottom: var(--s-4); z-index: 44;
    width: 48px; height: 48px;          /* cel dotykowy z zapasem */
    background: var(--c-brand); color: var(--c-on-dark);
    border: 0; border-radius: 999px; box-shadow: var(--sh-2);
    text-decoration: none; cursor: pointer;
    opacity: 0; visibility: hidden; transform: translateY(8px);
    transition: opacity .2s ease, visibility .2s ease, transform .2s ease, background .15s ease;
}
html.js body.has-sticky-cta .to-top { bottom: calc(56px + var(--s-3)); }
@media (min-width: 768px) {
    html.js body.has-sticky-cta .to-top { bottom: var(--s-4); }   /* pasek CTA znika od 768 px */
}
html.js .to-top.is-visible { opacity: 1; visibility: visible; transform: none; }
html.js .to-top:hover { background: var(--c-accent); color: var(--c-ink); }
.to-top svg { width: 22px; height: 22px; fill: currentColor; }

/* =====================================================================
   FAZA 4 — rytm portfolio: kafelki kategorii, wyrozniona realizacja,
   stronicowanie
   ===================================================================== */

/* Tekst wylacznie dla czytnikow ekranu. Wzorzec z `clip-path`, a nie
   `display: none` ani `left: -9999px`: pierwsze usuwa tresc takze z czytnika,
   drugie potrafi wygenerowac poziomy pasek przewijania. */
.u-visually-hidden {
    position: absolute; width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip-path: inset(50%); overflow: hidden; white-space: nowrap;
}

/* --- Kafelki kategorii na /realizacje/ --------------------------------
   Byly przyciskami w jednym rzedzie i czytaly sie jak pasek filtrow, ktory
   nic nie filtruje — bo kazdy prowadzi na osobna strone uslugi. Jako karty
   z liczba realizacji mowia, co za nimi stoi, i nie udaja filtrowania. */
.cat-grid { list-style: none; margin: 0; padding: 0; }
.cat-card {
    display: flex; flex-direction: column; gap: var(--s-2);
    height: 100%; padding: var(--s-6);
    text-decoration: none; color: inherit;
}
.cat-card__name {
    font-family: var(--f-display); font-weight: 600;
    font-size: var(--t-h4); line-height: 1.25; color: var(--c-brand);
}
.cat-card__count { font-size: var(--t-small); color: var(--c-text-muted); }
/* Odnosnik dosuniety do dolu, tak jak `.card__more` — karty w rzedzie maja
   wtedy wspolna linie bazowa, mimo roznej dlugosci nazw kategorii. */
.cat-card__more {
    margin-top: auto; padding-top: var(--s-3);
    font-family: var(--f-display); font-weight: 600; font-size: 14px;
    color: var(--c-brand);
}

/* --- Wyrozniona realizacja --------------------------------------------
   Kafel na dwie kolumny i dwa wiersze. Dopiero od 1024 px, bo ponizej siatka
   ma jedna albo dwie kolumny i „wyroznienie" nie mialoby czym sie odroznic.
   `dense` domyka dziury, ktore zostawia element rozciagniety na cztery pola. */
.card__media a { display: block; height: 100%; }

@media (min-width: 1024px) {
    .grid--portfolio { grid-auto-flow: dense; }
    .card--featured { grid-column: span 2; grid-row: span 2; }
    /* Kadr wypelnia wysokosc dwoch wierszy zamiast trzymac wlasna proporcje —
       inaczej pod zdjeciem zostawalby pusty pas do wysokosci siatki.
       Wysokosc wiersza wyznaczaja sasiednie karty, ktore maja zadeklarowane
       proporcje, wiec uklad jest policzalny przed wczytaniem zdjec (CLS = 0). */
    .card--featured .card__media { aspect-ratio: auto; flex: 1; min-height: 340px; }
    .card--featured .card__title { font-size: var(--t-h3); }
    .card--featured .card__body { padding: var(--s-8); }
}

/* --- Stronicowanie ----------------------------------------------------
   Zwykle odnosniki, zero JS. Cele dotykowe 44 px, bo na telefonie to jest
   glowny sposob przechodzenia miedzy stronami listy. */
.pager {
    display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
    gap: var(--s-3); margin-top: var(--s-12);
}
.pager__list { display: flex; flex-wrap: wrap; gap: var(--s-2); list-style: none; margin: 0; padding: 0; }
.pager__page, .pager__step {
    display: inline-flex; align-items: center; justify-content: center;
    min-width: 44px; min-height: 44px; padding: var(--s-2) var(--s-4);
    border: 1px solid var(--c-line); border-radius: var(--r-control);
    background: var(--c-surface); color: var(--c-text);
    font-family: var(--f-display); font-weight: 500; text-decoration: none;
    transition: border-color .15s ease, color .15s ease;
}
a.pager__page:hover, a.pager__step:hover { border-color: var(--c-accent); color: var(--c-ink); }
.pager__page.is-current {
    background: var(--c-brand); border-color: var(--c-brand);
    color: var(--c-on-dark); font-weight: 600;
}
/* „Poprzednia" na pierwszej stronie zostaje widoczna, ale wygaszona —
   znikajacy element przesuwalby numery pod kursorem przy kazdym przejsciu. */
.pager__step--off { opacity: .35; }
@media (max-width: 479px) {
    .pager__step { display: none; }   /* na waskim ekranie zostaja same numery */
}

/* --- Hero na pelna szerokosc okna -------------------------------------
   Zdjecie jest tlem, tekst lezy na nim. `isolation: isolate` zamyka
   kontekst nakladania w tej sekcji, dzieki czemu `z-index: -1` na obrazie
   i przeslonie chowa je pod trescia, ale NIE pod tlem calej strony. */
.hero--full { position: relative; isolation: isolate; overflow: hidden; }

/* Kadr wypelnia sekcje; `aspect-ratio` i zaokraglenie z wariantu kolumnowego
   trzeba tu jawnie skasowac, bo `.hero__media` niesie je z reguly wyzej. */
.hero--full .hero__media {
    position: absolute; inset: 0; z-index: -1;
    aspect-ratio: auto; border-radius: 0; height: auto; min-height: 0;
}
.hero--full .hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* Przeslona kontrastowa. Zdjecia eventowe sa kadrowane luzno i nie da sie
   zalozyc, ze lewa strona bedzie ciemna — bez tego bialy tekst na jasnym
   kadrze spada ponizej 4,5:1. Wartosci dobrane pod NAJJASNIEJSZE zdjecie
   z biblioteki, nie pod wybrany przyklad. */
.hero--full::after {
    content: ''; position: absolute; inset: 0; z-index: -1;
    background: linear-gradient(100deg,
        rgba(29, 29, 27, .94) 0%,
        rgba(29, 29, 27, .82) 45%,
        rgba(29, 29, 27, .45) 100%);
}
/* Na waskim ekranie tekst zajmuje cala szerokosc, wiec przeslona pozioma
   zostawilaby jasne tlo pod prawa krawedzia wierszy. Tam gradient idzie
   od dolu. */
@media (max-width: 767px) {
    .hero--full::after {
        background: linear-gradient(to top,
            rgba(29, 29, 27, .95) 35%,
            rgba(29, 29, 27, .70) 100%);
    }
}

.hero--full .hero__content {
    position: relative;
    display: flex; flex-direction: column; justify-content: center;
    min-height: clamp(460px, 68vh, 720px);
    padding-block: var(--s-section);
}
/* Tekst nie rozlewa sie na cala szerokosc okna — przy 1360 px wiersz
   prowadzacy mialby ponad 150 znakow. */
.hero--full .hero__content .lead { max-width: 54ch; }

/* --- Pas zdjec na pelna szerokosc okna --------------------------------
   Wychodzi poza `.wrap`: to jedyny element strony glownej bez marginesow
   bocznych, wiec dziala jak przerwa w rytmie siatek, a nie kolejna sekcja.
   Wysokosc zadeklarowana, wiec pas nie przesuwa ukladu (CLS = 0). */
.photo-band {
    display: grid; grid-template-columns: repeat(2, 1fr);
    gap: 2px; background: var(--c-ink);
}
.photo-band__cell { overflow: hidden; height: clamp(160px, 26vw, 380px); }
.photo-band__cell img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (min-width: 768px) {
    /* `auto-flow: column` zamiast sztywnych czterech kolumn: gdy kadrow jest
       trzy (bo czwarta realizacja nie ma okladki), dziela szerokosc po rowno
       zamiast zostawiac puste pole w rzedzie. */
    .photo-band { grid-template-columns: none; grid-auto-flow: column; grid-auto-columns: 1fr; }
}
/* Delikatne powiekszenie przy wskazaniu — pas jest dekoracja i nie jest
   klikalny, wiec to jedyny sygnal, ze to zdjecia, a nie tlo. */
.photo-band__cell img { transition: transform .6s ease; }
.photo-band__cell:hover img { transform: scale(1.06); }
