/* ==========================================================================
   SEKCJE — układ konkretnych bloków strony.
   Kolory, odstępy i rozmiary tylko przez tokeny. Wygląd przycisków, kart,
   pól itd. pochodzi z components.css — tu opisujemy wyłącznie kompozycję.
   ========================================================================== */

.k-skip {
  position: absolute;
  top: var(--k-space-2);
  left: var(--k-space-2);
  z-index: var(--k-z-modal);
  padding: var(--k-space-3) var(--k-space-4);
  border-radius: var(--k-radius-sm);
  background: var(--k-white);
  box-shadow: var(--k-shadow-md);
  transform: translateY(-200%);
}

.k-skip:focus {
  transform: translateY(0);
}

/* ==========================================================================
   TOP BAR — Figma: Navigation (166:17745), 390×64
   Wysokość 64 px, padding boczny 16 px, dolna linia Gray-200.
   ========================================================================== */

.k-header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--k-z-header);
  background: var(--k-white);
  border-bottom: 1px solid var(--k-border);
  /* Bez transform — belka nigdzie nie jedzie. Zostają przejścia koloru,
     bo obsługują stan is-menu-open. */
  transition: background-color var(--k-dur-menu) var(--k-ease-out-cubic),
              border-color var(--k-dur-menu) var(--k-ease-out-cubic);
}

/* Menu otwarte: belka zostaje na miejscu, ale wychodzi nad nakladke i oddaje
   tlo panelowi. Dzieki temu logo i przycisk nie przeskakuja ani o piksel —
   to caly czas ten sam element, zmienia sie tylko kolor. */
/* Tło belki idzie w kolor panelu, a nie w przezroczystość. Przy 500 ms panel
   wypełnia się na tyle wolno, że przez przezroczystą belkę przebijałaby treść
   strony. Tak samo robi referencja (.c-header.open → background #000). */
.k-header.is-menu-open {
  z-index: var(--k-z-header-open);
  background: var(--k-deep-mint);
  border-bottom-color: transparent;
}

/* Przy otwartym menu scroll strony jest zablokowany, więc wskaźnik postępu i tak
   by zamarł. Nieruchomy pasek nad pełnoekranowym menu to sam szum. */
.k-header.is-menu-open .k-scroll-progress {
  display: none;
}

.k-header__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--k-space-4);
  height: var(--k-header-h);
  padding-inline: 16px;
}

/* Tło belki zostaje pełnoekranowe — to pas przyklejony do krawędzi okna — ale
   jego TREŚĆ wraca na wspólną siatkę 1200/120, tę samą co hero, kalkulator,
   FAQ i stopka. Dzięki temu logo stoi w pionie z copy w hero, a hamburger
   kończy się równo z prawą krawędzią sekcji: przy 1440 px 120 i 1320,
   przy 1920 px 360 i 1560.

   Wcześniej stał tu kontener 1440 px i belka jako JEDYNA wychodziła 87 px
   poza siatkę w obie strony. Zapis z --k-container-desktop jest ten sam co
   w .k-benefits-section .k-container i w pozostałych sekcjach.

   Media query jest konieczne — poniżej 1024 px gutter rośnie ponad 16 px,
   a mobile ma trzymać 16 px z makiety. */
@media (min-width: 1024px) {
  .k-header__bar {
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
    margin-inline: auto;
    padding-inline: var(--k-gutter);
    /* 80 px z ustaleń z klientem — liczone od POLA KLIKALNEGO hamburgera
       (48×48), nie od jego kresek. To jedyny odstęp w belce, który cokolwiek
       robi: przestrzeń między logo a CTA pochłania margines automatyczny
       niżej, więc `gap` zostaje odległością CTA → hamburger. */
    gap: var(--k-space-10);
  }
}

.k-header__logo {
  position: relative;
  display: block;
  flex: 0 0 auto;
  width: 136px;
  height: 23px;
}

.k-header__logo-img {
  width: 136px;
  height: 23px;
  transition: opacity var(--k-dur-base) var(--k-ease-out);
}

/* biała wersja leży dokładnie na ciemnej i czeka wygaszona */
.k-header__logo-img--on-deep {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.k-header.is-menu-open .k-header__logo-img {
  opacity: 0;
}

.k-header.is-menu-open .k-header__logo-img--on-deep {
  opacity: 1;
}

/* ---------- CTA belki (714:6302) ----------
   Pokazuje się dopiero od 1024 px — poniżej to samo wezwanie stoi w przyklejonym
   pasku .k-cta-bar i w panelu menu, a w mobilnym frame'ie belki (166:17745)
   przycisku nie ma w ogóle. */

/* Lista przejść jest przepisana w CAŁOŚCI i to nie jest duplikat .k-btn.
   `transition` to shorthand, a ta reguła ma tę samą specyficzność co .k-btn
   (0-1-0) i leży w arkuszu ładowanym później — samo `transition: opacity`
   skasowałoby trzy nogi kolorów i przycisk byłby jedynym na stronie, który
   zmienia barwę pod kursorem skokowo, zamiast w 300 ms. Ta sama pułapka
   i to samo rozwiązanie co przy .k-js .k-btn[data-reveal] w components.css.

   Trzy pierwsze nogi są 1:1 z .k-btn, czwarta obsługuje wciśnięcie
   scale(0.98), piąta — gaszenie przy otwartym menu, tym samym czasem
   co podmiana logo wyżej, żeby oba szły razem. */
.k-header__cta {
  display: none;
  transition: background-color var(--k-dur-btn) var(--k-ease-btn),
              border-color var(--k-dur-btn) var(--k-ease-btn),
              color var(--k-dur-btn) var(--k-ease-btn),
              transform var(--k-dur-fast) var(--k-ease-out),
              opacity var(--k-dur-base) var(--k-ease-out);
}

/* Przy otwartym menu belka przechodzi w deep-mint, a panel ma własne
   „Kontakt z doradcą" — przycisk w belce byłby dublem i walczyłby o kontrast.
   Gasimy przezroczystością, nie `display`: element zostaje w układzie, więc
   hamburger nie przeskakuje w bok w chwili otwarcia. */
.k-header.is-menu-open .k-header__cta {
  opacity: 0;
  /* niewidoczny przycisk nie ma prawa łapać kliknięć */
  pointer-events: none;
}

/* Włączenie stoi TUTAJ, a nie w media query przy .k-header__bar wyżej:
   obie reguły mają specyficzność 0-1-0, więc rozstrzyga kolejność w pliku —
   z góry `display: none` wygrywałoby i przycisku nie byłoby nigdzie.
   Ta sama pułapka co przy .k-hero__badge niżej. */
@media (min-width: 1024px) {
  .k-header__cta {
    /* wartość z .k-btn — baza wyłącza przycisk przez display: none */
    display: inline-flex;
    /* Bez tego `justify-content: space-between` rozłożyłoby TRZY elementy
       równo i CTA wylądowałoby na środku belki. Margines zjada całą wolną
       przestrzeń przed przyciskiem: logo zostaje przy lewej, a CTA
       i hamburger schodzą się do prawej. */
    margin-inline-start: auto;
  }
}

/* przycisk 48×48 — cały kwadrat jest celem dotykowym, ikona 22×16 w środku */
.k-header__menu {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 48px;
  height: 48px;
  /* promień zostaje dla kształtu obwódki :focus-visible — tła przycisk nie ma */
  border-radius: var(--k-radius-pill);
  color: var(--k-energy-mint);
  transition: color var(--k-dur-fast) var(--k-ease-out),
              transform var(--k-dur-fast) var(--k-ease-out);
}

.k-header.is-menu-open .k-header__menu {
  color: var(--k-lime);
}

/* Wciśnięcie hamburgera. Skalujemy, a nie przemalowujemy, z dwóch powodów:
   reguła wyżej (0,3,0) i tak wygrałaby z kolorem przy otwartym menu, więc
   zamykanie „×" zostałoby nieme — a skala działa tak samo w obu stanach.
   Plamę dotyku gasi base.css, więc bez tego przycisk nie reagowałby wcale. */
.k-header__menu:active {
  transform: scale(0.9);
}

.k-header__menu-icon {
  position: relative;
  display: block;
  width: 20px;
  height: 16px;
}

.k-header__menu-line {
  position: absolute;
  left: 0;
  width: 20px;
  height: 2px;
  border-radius: var(--k-radius-pill);
  background: currentColor;
  transition: transform var(--k-dur-base) var(--k-ease-out),
              opacity var(--k-dur-fast) var(--k-ease-out);
}

.k-header__menu-line:nth-child(1) { top: 0; }
.k-header__menu-line:nth-child(2) { top: 7px; }
.k-header__menu-line:nth-child(3) { top: 14px; }

/* skrajne kreski zjeżdżają na środek (7 px) i krzyżują się,
   środkowa znika wcześniej, żeby nie przeświecała przez "X" */
.k-header.is-menu-open .k-header__menu-line:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.k-header.is-menu-open .k-header__menu-line:nth-child(2) {
  opacity: 0;
  transform: scaleX(0.2);
}

.k-header.is-menu-open .k-header__menu-line:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ==========================================================================
   MENU — Figma: 📱 | mobile • PL menu-ham-ext (310:476), 389×865
   Pełnoekranowa nakładka deep-mint. Wysokości i odstępy wprost z frame'a:
   belka na y=30 (48 px), pozycje od y=108, przyciski 108 px pod nimi.
   ========================================================================== */

.k-menu {
  position: fixed;
  inset: 0;
  z-index: var(--k-z-modal);
  display: flex;
  flex-direction: column;
  /* belka nagłówka lezy nad panelem i trzyma logo z "X" — panel zaczyna
     się dopiero pod nią, żeby treść nie wjeżdżała pod przycisk */
  padding-top: var(--k-header-h);
  background: var(--k-deep-mint);
  color: var(--k-white);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.k-menu[hidden] {
  display: none;
}

/* Stan początkowy tylko przy działającym JS — bez niego panel i tak nie
   istnieje na ekranie (atrybut hidden), a z JS-em ma się wsunąć. */
.k-js .k-menu {
  opacity: 0;
  transform: translateY(-8px);
  /* wygaszony panel nie może łapać kliknięć — przez chwilę po zamknięciu
     wciąż leży na całym ekranie */
  pointer-events: none;
  transition: opacity var(--k-dur-menu) var(--k-ease-out-cubic),
              transform var(--k-dur-menu) var(--k-ease-out-cubic);
}

.k-js .k-menu.is-open {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.k-menu__nav,
.k-menu__actions {
  width: 344px;
  max-width: calc(100% - 32px);
  margin-inline: auto;
}

.k-menu__nav {
  display: flex;
  flex-direction: column;
  gap: 14px;
  /* Figma: pozycje od y=108, minus 22 px paska statusu = 86.
     Belka zajmuje 64, więc zostaje 22. */
  margin-top: 22px;
}

.k-menu__link {
  font-size: 1.75rem;               /* 28 px */
  font-weight: var(--k-fw-news);
  line-height: 40px;
  letter-spacing: -1.2px;
  /* jawne zero — bez niego przejście nie ma od czego wystartować */
  padding-left: 0;
  transition: color var(--k-dur-base) var(--k-ease-out-cubic),
              padding-left var(--k-dur-base) var(--k-ease-out-cubic);
}

/* Pozycja odsuwa się w prawo, wzorem oknoplast.com.pl/pilar. Świadomie
   `padding-left`, nie `translateX`: link zajmuje pełne 344 px kontenera (cel
   dotykowy), więc przesunięcie ramki wypchnęłoby ją poza panel. Przy
   `box-sizing: border-box` padding przesuwa sam tekst. */
.k-menu__link:active {
  color: var(--k-lime);
  padding-left: var(--k-menu-hover-shift);
}

@media (hover: hover) {
  .k-menu__link:hover {
    color: var(--k-lime);
    padding-left: var(--k-menu-hover-shift);
  }
}

.k-menu__actions {
  display: flex;
  gap: 24px;
  margin-top: 108px;
  margin-bottom: 40px;
}

.k-menu__btn {
  width: 160px;
  padding-inline: 12px;             /* etykiety mieszczą się w stałych 160 px */
}

/* Panel nie ma sensu jako pełny ekran na desktopie — tam belka pokazuje
   pozycje wprost, więc menu zwęża się do kolumny przy prawej krawędzi. */
@media (min-width: 1024px) {
  .k-menu {
    inset: 0 0 0 auto;
    width: min(420px, 100%);
  }
}

/* ==========================================================================
   HERO — Figma: #baner-cont 390×399 + badge-informacja 78×78 + baner-kv 390×392
   Wszystkie liczby poniżej pochodzą wprost z frame'ów, dlatego są w px,
   nie w tokenach odstępów — to odwzorowanie makiety, nie rytm sekcji.
   ========================================================================== */

.k-hero {
  background: var(--k-deep-mint);
  color: var(--k-text-on-deep);
}

.k-hero__copy {
  position: relative;              /* kotwica dla koła badge'a */
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: calc(var(--k-header-h) + 32px) 16px 9px;
}

.k-hero__intro {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: flex-start;
}

.k-hero__text {
  align-self: stretch;             /* badge zwęża się do treści, tekst nie */
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.k-hero__title {
  color: var(--k-lime);
  font-weight: var(--k-fw-bold);
}

.k-hero__sub {
  color: var(--k-white);
  font-size: var(--k-fs-hero-sub);
  font-weight: var(--k-fw-news);
  line-height: 28px;
  text-transform: uppercase;
}

.k-hero__sub strong {
  font-weight: var(--k-fw-bold);
}

/* ---------- przyciski ---------- */

.k-hero__actions {
  display: flex;
  gap: 24px;
}

.k-hero__btn {
  width: 160px;
  padding-inline: 12px;            /* etykiety mieszczą się w stałych 160 px */
}

/* ---------- licznik ---------- */

.k-countdown {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.k-countdown__label {
  color: var(--k-power-mint);
  font-size: var(--k-fs-count-intro);
  font-weight: var(--k-fw-news);
  line-height: var(--k-lh-label);
  letter-spacing: var(--k-ls-label);
}

.k-countdown__label strong {
  font-weight: var(--k-fw-bold);
}

.k-countdown__list {
  display: flex;
  gap: 24px;
}

.k-countdown__cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 36px;
}

.k-countdown__value {
  font-size: var(--k-fs-count);
  font-weight: var(--k-fw-bold);
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.k-countdown__unit {
  font-size: var(--k-fs-count-unit);
  font-weight: var(--k-fw-book);
  line-height: var(--k-lh-label);
  letter-spacing: var(--k-ls-label);
}

.k-countdown__expired {
  color: var(--k-power-mint);
}

/* ---------- koło „Kup teraz, zamontuj później" ----------
   W Figmie leży na x=290 (czyli 22 px od prawej) i kończy się 9 px nad
   grafiką KV, nachodząc na rząd licznika. */

.k-hero__badge {
  position: absolute;
  /* Koło przestaje uciekać za prawą krawędź ekranu: do 422 px wygrywa 22px
     (na 390 px z Figmy pozycja jest co do piksela ta sama, x=290), powyżej
     ZAMARZA prawą krawędzią na 400 px. Bez tego przy 768 px stało 177 px od
     końca nagłówka, oddzielone pasem pustego tła — kolumna tekstu nie rośnie
     razem z oknem, więc koło zostawało samo.

     Dlaczego 400, a nie 368 (prawa krawędź z frame'u 390 px): cyfry licznika
     skalują się płynnie przez --k-fs-count aż do ~1127 px, więc rząd licznika
     rośnie w prawo (232 px przy 390, 302 px przy 1023). Zamrożenie na 368
     wpuszczałoby koło NA licznik powyżej ~900 px. 400 mija go z zapasem
     w całym zakresie układu mobilnego. */
  right: max(22px, 100% - 400px);
  bottom: 9px;
  /* wariant „solo" nie dostaje staggeru, więc opóźnienie bierze się stąd */
  --k-reveal-delay: var(--k-delay-hero-badge);
}

/* ---------- grafika KV ---------- */

.k-hero__kv {
  margin-top: -2px;                /* frame'y w Figmie nachodzą na siebie o 2 px */
}

.k-hero__kv img {
  width: 100%;
  height: auto;
}

/* Warstwy kompozycji desktopowej (706:6022). Na mobile KV jest jednym płaskim
   kadrem, więc te elementy nie mają czego pokazywać — a `display: none` ma tu
   drugie, ważniejsze zadanie: element ukryty w ten sposób NIE POBIERA swojego
   background-image, więc telefon nie płaci za dwa pliki, których nie zobaczy. */
.k-hero__kv-okno,
.k-hero__kv-chlopiec {
  display: none;
}

/* Kołysanie chłopca — jedyny ruch na stronie, który nie kończy się po wejściu.
   Klatki muszą stać tutaj, a nie w components.css: @keyframes jest globalne,
   a to nie komponent, tylko element kompozycji hero. Wyłącznik ruchu gasi je
   regułą .k-motion-off * w base.css. */
@keyframes k-hero-kv-plyn {
  from,
  to {
    transform: translateY(calc(-1 * var(--k-hero-idle-shift)));
  }
  50% {
    transform: translateY(var(--k-hero-idle-shift));
  }
}

/* ==========================================================================
   RYTM NAGŁÓWKA SEKCJI
   Etykieta → 24 px → H2 → 8 px → akapit. Powtarza się w poradniku, „O nas",
   kalkulatorze i formularzu, więc opisujemy go raz.
   ========================================================================== */

/* Etykieta stoi we własnym wierszu — jako inline-flex dokładałaby do odstępu
   leading linii bazowej i 24 px z makiety by się nie zgadzało. */
.k-container > .k-badge {
  display: flex;
  width: fit-content;
  margin-bottom: 24px;
}

.k-container > h2 + .k-lead {
  margin-top: 8px;
}

/* Karuzela wisi 24 px pod blokiem tekstu sekcji (packshoty mają 16 — patrz niżej) */
.k-carousel {
  margin-top: 24px;
}

/* ==========================================================================
   KORZYŚCI — Figma: #benefity-top (166:17773)
   ========================================================================== */

.k-benefits {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 24px;
}

/* Nagłówek jest w skali H4 (20/28 Medium), nie H2 — tak jest w makiecie. */
.k-benefits__title {
  font-size: var(--k-fs-h4);
  font-weight: var(--k-fw-medium);
  line-height: var(--k-lh-h4);
  letter-spacing: var(--k-ls-heading);
  /* nagłówek trzyma pełną szerokość kolumny — bez tego flex zwęża go do treści
     i łamanie linii rozjeżdża się z makietą */
  align-self: stretch;
  text-wrap: initial;
}

/* Interlinia 28 px jest stałą z makiety mobilnej. Powyżej 768 px nagłówek rośnie
   (na desktopie do skali H2), więc musi wrócić do proporcjonalnej — inaczej
   linie na siebie nachodzą. */
@media (min-width: 768px) {
  .k-benefits__title {
    line-height: var(--k-lh-heading);
  }
}

.k-benefits__list {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Packshotu nie ma w makiecie mobilnej (166:17773) — pojawia się dopiero
   we frame'ie desktopowym (166:21719). preload="none" na <video> sprawia,
   że ukryty player nie pobiera ani jednego bajtu. */
.k-benefits__media {
  display: none;
}

/* Każdy rząd ma w makiecie 56 px, także wtedy, gdy opis mieści się w jednej
   linii — inaczej lista jest o 16 px krótsza niż projekt. */
.k-benefits__list .k-feature {
  min-height: 56px;
}

/* ==========================================================================
   PACKSHOTY — Figma: #packshots-kolory (166:17933)

   Etykiety wychodzą 4 px poza lewą krawędź zdjęcia. W Figmie ten wysunięty
   margines ma 14 px, ale odstęp między kaflami to 12 px — overhang był więc
   WIĘKSZY niż odstęp i przy swipe'owaniu etykiety wchodziły na sąsiedni
   packshot. 4 px zostawia 8 px prześwitu.

   Tor jest wyśrodkowany (k-slider--centered): packshot zatrzymuje się na środku
   ekranu, nie przy lewej krawędzi. Przy kadrze 390 daje to padding
   (390 − 282) / 2 = 54 px, czyli blisko makiety — Frame 264 z packshotami stoi
   w Figmie na x=51. Wcześniejsze 38 px było odstępstwem od projektu.
   ========================================================================== */

.k-packshots-section .k-carousel {
  margin-top: 16px;
}

/* Jedyny nagłówek sekcji w wadze Medium — pogrubione jest tylko „Okno PIXEL"
   (Figma: 166:17935). Pozostałe H2 na stronie są w całości Bold. */
.k-packshots-section h2 {
  font-weight: var(--k-fw-medium);
}

/* Wymiary mobilne to PROPORCJA kadru 390 z Figmy, nie stała liczba pikseli —
   inaczej na iPhonie Pro Max zdjęcie zajmuje 66 % ekranu zamiast 72 %, a na
   tablecie 37 %. Podłoga 88 % i sufit 125 % projektu chronią skrajne ekrany.

   --k-kafel trzymamy BEZ JEDNOSTKI, bo `300px / 390 * 100vw` to mnożenie dwóch
   długości i CSS tego nie policzy. `liczba × długość ÷ liczba` już tak. */
.k-slider--packshots {
  --k-kafel: 282;                   /* szerokość packshotu z Figmy */
  --k-snap-w: clamp(
    calc(var(--k-kafel) * 0.88px),
    calc(var(--k-kafel) * 100vw / 390),
    calc(var(--k-kafel) * 1.25px)
  );
  gap: 12px;
}

/* Na desktopie tor wraca do rzędu od lewej (patrz k-slider--centered), a razem
   z nim wcześniejszy zapas 22 px na wysunięte etykiety pierwszego kafla.
   Szerokości kafli wracają do projektowych niżej — musi to stać PO ich
   definicjach, inaczej późniejsza reguła nadpisze nadpisanie. */
@media (min-width: 1024px) {
  .k-slider--packshots {
    padding-inline: calc(var(--k-gutter) + 22px);
    scroll-padding-inline: calc(var(--k-gutter) + 22px);
  }

}

.k-product__lead {
  margin-top: 8px;
}

.k-packshot {
  position: relative;
  /* Ta sama zmienna, z której tor liczy swój padding — dzięki temu
     wyśrodkowanie nie może rozjechać się ze zdjęciem. */
  width: var(--k-snap-w);
  padding-top: 4px;                 /* „kolor + okno" leży 4 px niżej niż etykiety */
}

/* aspect-ratio, NIE stała wysokość: przy object-fit: cover sztywne 300 px
   znaczyłoby, że im szerszy kafel, tym więcej ucinamy z góry i dołu. Proporcja
   trzyma kadr identyczny na każdym ekranie. */
.k-packshot img {
  width: 100%;
  height: auto;
  aspect-ratio: 282 / 300;
  object-fit: cover;
}

.k-packshot__badges {
  position: absolute;
  top: 2px;
  left: -4px;
  display: grid;
  gap: 8px;
  justify-items: start;
}

.k-packshot__caption {
  color: var(--k-plr-black);
  font-size: var(--k-fs-caption);
  font-weight: var(--k-fw-news);
  line-height: 18px;
  text-align: center;
}

/* Opakowanie „Zobacz Okno PIXEL" (Figma desktop 667:4940). Poniżej 1024 px
   ma być niewidoczne dla układu — display: contents wyjmuje sam <div> z drzewa
   pudełek, a obie sekcje zostają dziećmi <main> dokładnie jak wcześniej. */
.k-product-block {
  display: contents;
}

/* ==========================================================================
   BENEFITY — Figma: #benefity (166:17951)
   Sekcja to sama karta: 48 px odstępu nad nią i 8 px pod nią, bez rytmu
   .k-section — tak wychodzi z makiety.
   ========================================================================== */

.k-benefits-card-section {
  padding-block: 16px 8px;
}

.k-guarantee {
  position: relative;
  padding: 24px;
  border-radius: var(--k-radius-card);
  background: var(--k-surface-mint);
}

.k-guarantee__list {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.k-guarantee__item {
  display: flex;
  align-items: center;
  gap: 16px;
  color: var(--k-gray-800);
  font-size: var(--k-fs-body);
  font-weight: var(--k-fw-medium);
  line-height: 24px;
  letter-spacing: var(--k-ls-tight);
}

/* koło wychodzi 19 px ponad kartę i 7 px poza jej prawą krawędź */
.k-guarantee__badge {
  position: absolute;
  top: -19px;
  right: -7px;
  /* OBOWIĄZKOWE, nie ozdobne: --k-reveal-delay dziedziczy się, a plakietka jest
     dzieckiem .k-guarantee[data-reveal]. Bez własnej deklaracji przejęłaby
     inline'owy stagger karty i pojawiłaby się razem z nią. */
  --k-reveal-delay: var(--k-delay-badge);
}

/* ==========================================================================
   GALERIA — Figma: #galeria (386:5241)
   Osiem kafli w rytmie 300 300 195 300 300 195 300 300 — pozycje 3 i 6 są
   pionowe. Każdy kafelek niesie własną szerokość w --k-shot-w.

   Podpisy pod zdjęciami usunięte na życzenie klienta, choć Figma ma pod każdym
   kafelkiem `bodytext` — opis zdjęcia niesie teraz atrybut alt.
   ========================================================================== */

/* Tytuł stoi na środku na każdej szerokości — na mobile w dwóch wierszach,
   od 768 px w jednym (patrz .k-br-mobile w bloku tabletowym). */
.k-gallery-section h2 {
  text-align: center;
}

.k-gallery {
  /* Pierwszy i ostatni kafel mają po 300 — to one muszą dojechać na środek.
     Kafle pionowe (195) wychodzą na środek same, a puste miejsce po ich bokach
     wypełniają sąsiedzi.

     Tor niesie domyślne --k-shot-w kafla SKRAJNEGO i z niego liczy swój padding;
     każdy <li> nadpisuje tę zmienną dla siebie. Jedna liczba, zero duplikacji. */
  --k-shot-w: 300;
  --k-snap-w: clamp(
    calc(var(--k-shot-w) * 0.88px),
    calc(var(--k-shot-w) * 100vw / 390),
    calc(var(--k-shot-w) * 1.25px)
  );
  gap: 16px;
}

.k-shot {
  width: clamp(
    calc(var(--k-shot-w) * 0.88px),
    calc(var(--k-shot-w) * 100vw / 390),
    calc(var(--k-shot-w) * 1.25px)
  );
  /* Ta sama krzywa co przewijanie karuzeli — sekcja ma jeden charakter ruchu. */
  transition: opacity var(--k-dur-base) var(--k-ease-glide);
}

/* Przygaszenie kafla pod kursorem, jak w galerii na oknoplast.com.pl/pilar
   (`.b-gallery .item:hover { opacity: .8 }`). Krycie idzie na <li>, nie na
   <img> — w referencji też obejmuje cały kafel.

   Na dotyku reguła jest martwa i tak ma zostać: kafel ma tam cursor: zoom-in
   i otwiera lightbox, więc przygaszenie po tapnięciu tylko by myliło. */
@media (hover: hover) {
  .k-shot:hover {
    opacity: 0.8;
  }
}

/* Kafle wracają na desktopie do szerokości projektowych. Płynne skalowanie
   odpowiada na problem mobilny — jedno zdjęcie na ekran, więc ma zajmować stały
   procent kadru. Powyżej 1024 px widać ich kilka naraz i rozciąganie do sufitu
   (352 / 375 px) tylko rozpycha rząd. Wersja desktopowa dostanie własny projekt
   z Figmy.

   Blok MUSI stać za regułami .k-packshot i .k-shot: ma tę samą specyficzność,
   więc rozstrzyga kolejność w arkuszu. */
@media (min-width: 1024px) {
  .k-packshot {
    width: calc(var(--k-kafel) * 1px);
  }

  .k-shot {
    width: calc(var(--k-shot-w) * 1px);
  }
}

.k-shot img {
  width: 100%;
  height: auto;
  /* Kafle poziome i pionowe mają różne proporcje — bezwymiarowe --k-shot-w
     załatwia obie jednym zapisem. */
  aspect-ratio: var(--k-shot-w) / 262;
  object-fit: cover;
  border-radius: var(--k-radius-md);
  cursor: zoom-in;
}

/* ==========================================================================
   PORADNIK — Figma: #poradnik mobile (166:17858), desktop (234:22456)
   ========================================================================== */

.k-steps {
  display: flex;
  flex-direction: column;
  gap: var(--k-space-5);            /* 24 px */
  margin-top: var(--k-space-5);
}

/* Kolumna kroków. Na mobile obie stoją w jednym ciągu i mają ten sam odstęp
   co rodzic, więc styk kroku 2 z krokiem 3 niczym się nie różni od reszty. */
.k-steps__col {
  display: flex;
  flex-direction: column;
  gap: var(--k-space-5);
}

/* CTA do wyszukiwarki salonów. Figma ma je wyłącznie we frame'ie desktopowym
   (656:3331 — komponent „Secondary Buttons", u nas .k-btn--primary); na mobile
   ten sam adres podaje przyklejony pasek .k-cta-bar. Pokazujemy je od 1024 px,
   czyli dokładnie tam, gdzie pasek znika. */
.k-steps__cta {
  display: none;
}

/* Link kroku jest w deep-mincie i wadze Medium — inaczej niż domyślny .k-link */
.k-step__link {
  margin-top: 8px;
  color: var(--k-deep-mint);
  font-size: var(--k-fs-sm);
  font-weight: var(--k-fw-medium);
  line-height: 20px;
}

@media (hover: hover) {
  .k-step__link:hover {
    color: var(--k-energy-mint);
  }
}

/* Własne wciśnięcie, bo .k-link:active przyciemnia do deep-mintu — a ten link
   JUŻ jest w deep-mincie, więc tapnięcie nie dawałoby żadnej zmiany.
   Rozjaśniamy do mięty, tak samo jak hover wyżej. Ta sama specyficzność co
   .k-link:active, wygrywa kolejnością: sections.css ładuje się po components.css. */
.k-step__link:active {
  color: var(--k-energy-mint);
}

/* ==========================================================================
   O NAS — Figma: #o nas (166:17904)
   ========================================================================== */

.k-about__media {
  position: relative;
  margin-top: 24px;
}

/* Zdjęcie ma pełną szerokość, ale sztywne 262 px wysokości znaczyło, że na
   szerszym telefonie kadr się ZACIEŚNIA zamiast rosnąć. Proporcja z Figmy
   (358 × 262 przy kadrze 390) trzyma go stałym. max-height jest potrzebne,
   bo override wysokości wchodzi dopiero od 1024 px — bez sufitu przy 1000 px
   zdjęcie urosłoby do ~690 px. */
.k-about__media img {
  width: 100%;
  height: auto;
  aspect-ratio: 358 / 262;
  max-height: 420px;
  object-fit: cover;
  border-radius: var(--k-radius-md);
}

/* Pigułka leży wewnątrz kadru, nie wystaje poza zdjęcie (Figma: 166:17913) */
.k-about__pill {
  position: absolute;
  top: 185px;
  left: 12px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  border-radius: var(--k-radius-sm);
  background: var(--k-power-mint);
  color: var(--k-gray-800);
  font-size: var(--k-fs-caption);
  font-weight: var(--k-fw-news);
  line-height: normal;
}

.k-about__pill > strong {
  font-size: var(--k-fs-pill);
  font-weight: var(--k-fw-bold);
  line-height: normal;
}

.k-about__pill-lead {
  display: block;
  font-weight: var(--k-fw-bold);
}

/* statystyki siedzą na karcie deep-mint (Figma: 166:17918) */
.k-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 24px;
  margin-top: 24px;
  padding: 24px;
  border-radius: var(--k-radius-md);
  background: var(--k-surface-deep);
}

/* ==========================================================================
   KALKULATOR — Figma: #kalkulator (166:17793)
   Kreator czterokrokowy w jednej karcie:
   1-step 355:4419 · 2-step 482:6562 · 3-step 567:7967 · 4-step 567:8009.
   Krok 4 (wynik) przemalowuje kartę na deep-mint — patrz .k-calc.is-result.
   ========================================================================== */

.k-calc__title + .k-lead {
  margin-top: 8px;
}

/* Odstęp od leadu niesie teraz wrapper układu — karta w gridzie desktopowym
   musi startować równo z panelem. */
.k-calc-layout {
  margin-top: 24px;
}

.k-calc {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 24px;
  border: 1px solid var(--k-border);
  border-radius: var(--k-radius-md);
  background: var(--k-surface);
  box-shadow: 0 12px 16px rgba(0, 0, 0, 0.03);
  /* Ta sama wartość co dla kotwic w base.css — calculator.js sczytuje ją stąd,
     żeby po zmianie kroku ustawić górę karty tam, gdzie stoi po pierwszym kroku. */
  scroll-margin-top: calc(var(--k-header-h) + var(--k-space-4));
  transition: background-color var(--k-dur-base) var(--k-ease-out),
              border-color var(--k-dur-base) var(--k-ease-out);
}

/* Jeden krok = jeden ekran. Ukryte kroki zostają w DOM-ie, żeby wybory
   przetrwały cofnięcie się przez stepper. */
.k-calc__step {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.k-calc__step[hidden] {
  display: none;
}

.k-calc__step-title {
  font-size: 1.5rem;                /* 24 px */
  font-weight: var(--k-fw-bold);
  line-height: normal;
  letter-spacing: -0.8px;
}

/* Nagłówek i podtytuł dzieli 8 px, a nie 16 px odstępu kroku */
.k-calc__head {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.k-calc__step-sub {
  color: var(--k-gray-800);
  font-size: var(--k-fs-sm);
  font-weight: var(--k-fw-book);
  line-height: 1.4;
}

.k-calc__step-sub strong {
  font-weight: var(--k-fw-bold);
}

/* zdanie o niższym Uw jest w makiecie wyróżnione kolorem akcji */
.k-calc__step-sub em {
  color: var(--k-text-accent);
  font-style: normal;
  font-weight: var(--k-fw-medium);
}

/* <fieldset> celowo NIE jest tu flexem: przeglądarki wyjmują <legend> z układu
   flexowego rodzica i odstęp z `gap` nigdy by się nie pojawił. Stąd marginesy. */
.k-calc__field {
  padding: 0;
  border: 0;
}

.k-calc__label {
  display: block;
  margin-bottom: 16px;
  color: var(--k-gray-800);
  font-size: var(--k-fs-sm);
  font-weight: var(--k-fw-medium);
  line-height: normal;
}

/* zakres w nawiasie jest wyszarzony, ale to ta sama linia etykiety */
.k-calc__range {
  color: var(--k-gray-400);
}

/* legenda listy wyboru ma 14 px odstępu, suwak 16 — tak jest w makiecie;
   zerujemy też domyślny padding <legend>, żeby wyrównała się do etykiety suwaka */
.k-calc__field legend.k-calc__label {
  margin-bottom: 14px;
  padding-inline: 0;
}

/* Lista opcji — odstęp 14 px z makiety niesie kontener, nie sam komponent.
   Ośmiu modeli okien nie da się sensownie ustawić w słupku na desktopie,
   więc od tabletu przechodzą w dwie kolumny (Figma ma tylko frame mobilny). */
.k-calc__choices {
  display: grid;
  gap: 14px;
}

@media (min-width: 768px) {
  .k-calc__choices {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.k-calc__nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--k-space-4);
}

/* `display: flex` bije domyślne `display: none` z [hidden] — na kroku 4 chowamy
   całą nawigację, bo karta wyniku ma własny „Wstecz" obok CTA. */
.k-calc__nav[hidden] {
  display: none;
}

/* ---------- krok 4: karta wyniku (Figma: 4-step 567:8009, 358 × 496) ----------
   Osobny, zielony frame bez steppera i bez dolnej nawigacji kreatora — „Wstecz"
   stoi tu w jednym rzędzie z CTA. Padding 32/24 zamiast 24 z pozostałych kroków. */

.k-calc.is-result {
  /* Zielony frame w makiecie nie ma obrysu, a przezroczysty 1 px zjadał 2 px
     szerokości treści — rząd przycisków niżej walczy o każdy piksel.
     Bez obrysu padding 32/24 daje dokładnie 310 px wnętrza, tak jak w Figmie. */
  padding: 32px 24px;
  border-color: transparent;
  border-width: 0;
  background: var(--k-surface-deep);
  color: var(--k-hl-mint);
  box-shadow: 0 8px 12px rgba(0, 0, 0, 0.2);
}

.k-result {
  gap: 24px;
}

/* Figma (567:8010) zapisuje ten nagłówek wersalikami — w HTML zostaje zdanie,
   wielkie litery robi CSS, żeby czytnik ekranu nie literował skrótu. */
.k-result__label {
  color: var(--k-power-mint);
  font-size: 1.5rem;                /* 24 px */
  font-weight: var(--k-fw-bold);
  line-height: normal;
  letter-spacing: -0.8px;
  text-transform: uppercase;
}

.k-result__block {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.k-result__row {
  font-size: var(--k-fs-sm);
  font-weight: var(--k-fw-news);
  line-height: 18px;
}

.k-result__value {
  display: flex;
  align-items: baseline;
  gap: 8px;
  font-size: 2rem;                  /* 32 px */
  font-weight: var(--k-fw-bold);
  line-height: 38px;
  font-variant-numeric: tabular-nums;
}

/* kwota jest większa i w power-mincie — to główny wynik kalkulatora */
.k-result__value--accent {
  color: var(--k-power-mint);
  font-size: 2.75rem;               /* 44 px */
  line-height: 52px;
}

.k-result__unit {
  font-size: var(--k-fs-body);
  font-weight: var(--k-fw-news);
  line-height: 20px;
}

.k-result__value--accent .k-result__unit {
  font-size: 1.125rem;              /* 18 px */
  font-weight: var(--k-fw-medium);
  line-height: 22px;
}

.k-result__note {
  font-size: 0.6875rem;             /* 11 px */
  font-weight: var(--k-fw-news);
  line-height: var(--k-lh-label);
}

/* pytanie prowadzące do formularza (Figma: 568:8026) */
.k-result__cta-lead {
  font-size: var(--k-fs-sm);
  font-weight: var(--k-fw-bold);
  line-height: 20px;
}

/* Rząd „Wstecz" + CTA (Figma: 576:8044, odstęp 12 px). Oba przyciski przylegają
   do swoich etykiet — CTA nie rozpycha się na wolne miejsce, tak jak w makiecie.
   `flex-wrap` to tylko siatka bezpieczeństwa na dłuższą etykietę albo węższą kartę:
   wtedy CTA schodzi do drugiej linii, zamiast wychodzić poza kartę. */
.k-result__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

/* ==========================================================================
   CERTYFIKATY — Figma: certyfikaty (386:5236)
   Biała taśma logotypów o różnych proporcjach; każdy zachowuje własny rozmiar.
   ========================================================================== */

.k-certs {
  padding-block: 0 21px;
}

.k-certs__list {
  gap: 20px;
  align-items: center;
  padding-block: 16px;
  background: var(--k-white);
  /* Gdy logotypy mieszczą się w kadrze, cała taśma staje na środku; gdy nie —
     `safe` cofa wyrównanie do `start`, więc pierwszy logotyp zostaje w zasięgu
     przewijania. Samo `center` wypchnęłoby początek toru poza scroll.
     Dlatego nie ma tu media query: poniżej progu reguła zachowuje się dokładnie
     jak dotychczasowe wyrównanie do lewej. */
  justify-content: safe center;
  /* Ten sam blok 1440 px co hero. Przy dzisiejszych 1052 px treści nie zmienia
     nic wizualnie — zacznie działać po dołożeniu kolejnych logotypów. */
  max-width: var(--k-container);
  margin-inline: auto;
}

.k-certs__item {
  width: auto;
}

/* Logotypy mają w makiecie różne proporcje, więc rozmiar niesie atrybut
   width/height obrazka. Bez tego lazy-loading nie rezerwuje miejsca i taśma
   ma zerową wysokość, dopóki użytkownik do niej nie dojedzie. */

/* ==========================================================================
   FORMULARZ — Figma: #14 formularz (166:18000)
   ========================================================================== */

.k-form-section {
  background: linear-gradient(180deg, var(--k-hl-mint), var(--k-white));
  /* Gradient zamiast płaskiego tokena, więc sekcja nie bierze modyfikatora
     .k-section--* — limit szerokości trzeba powtórzyć tutaj. Powód i wartość
     jak w base.css przy modyfikatorach tła: krawędź równo z hero. */
  max-width: var(--k-container);
  margin-inline: auto;
}

.k-form__intro {
  margin-bottom: 24px;
}

.k-form__title {
  margin-bottom: 24px;
}

.k-form {
  display: grid;
  gap: 24px;
}

/* display: grid wyżej przebija natywne [hidden] — stąd jawna reguła */
.k-form[hidden] {
  display: none;
}

.k-form__consents {
  display: grid;
  gap: var(--k-space-3);
  /* 12 px — drobny druk zgód; tracking jak w Figmie dla tego stopnia pisma.
     „Czytaj więcej" dziedziczy te wartości (patrz .k-form__more). */
  font-size: var(--k-fs-label);
  letter-spacing: var(--k-ls-note);
}

/* Zwinięty tekst zgody — rozwija js/modules/form.js.
   Klamra daje wielokropek, a max-height to, czego klamra nie potrafi: płynne
   rozwijanie. Wysokość zwiniętego stanu = trzy linie interlinii treści; pełną
   podstawia JS (element.scrollHeight), bo CSS jej nie zna. */
.k-form__consent-text[data-clamp] {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
  max-height: calc(3 * var(--k-lh-body) * 1em);
  transition: max-height var(--k-dur-accordion) var(--k-ease-out);
}

.k-form__consent-text.is-expanded {
  -webkit-line-clamp: unset;
}

.k-form__consent-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--k-space-6);
  margin-block: var(--k-space-3);
}

/* Przycisk i komunikat w jednym rzędzie: status („Wysyłamy… 42%") stoi po
   prawej stronie przycisku, żeby postęp uploadu był widoczny bez wodzenia
   wzrokiem pod przycisk (OKP-878). Na wąskim ekranie zawija się pod przycisk,
   zamiast go ściskać. */
.k-form__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--k-space-4);
}

.k-form__submit {
  justify-self: start;
}

.k-form__status {
  min-height: 1.5rem;
  font-size: var(--k-fs-sm);
}

.k-form__status.is-error { color: var(--k-error); }
.k-form__status.is-success { color: var(--k-energy-mint); }

.k-form__status.is-pending {
  color: var(--k-text-muted);
  animation: k-form-status-pulse 1.1s var(--k-ease-in-out) infinite;
}

@keyframes k-form-status-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}

/* ---------- wyszukiwarka salonu (Figma: 166:18047) ---------- */

.k-salon {
  display: block;
  margin-top: 24px;
}

.k-salon__title {
  margin-bottom: 16px;
  font-size: var(--k-fs-h4);
  font-weight: var(--k-fw-medium);
  line-height: var(--k-lh-h4);
  letter-spacing: var(--k-ls-heading);
}

.k-salon .k-field {
  margin-bottom: 24px;
}

.k-salon__submit {
  /* etykieta jest jednym napisem rozbitym na dwa węzły (patrz .k-salon__submit-rest),
     więc odstęp robi twarda spacja, a nie gap z .k-btn */
  gap: 0;
  margin-bottom: 24px;
}

.k-salon .k-link--ext {
  margin-bottom: 8px;
}

.k-salon__map-link {
  display: block;
  border-radius: var(--k-radius-map);
  transition: opacity var(--k-dur-fast) var(--k-ease-out);
}

.k-salon__map-link:active {
  opacity: 0.85;
}

@media (hover: hover) {
  .k-salon__map-link:hover {
    opacity: 0.85;
  }
}

.k-salon__map {
  width: 100%;
  height: auto;
  border-radius: var(--k-radius-map);
}

/* ==========================================================================
   FAQ — Figma: #FAQ (166:18050), 390×1457
   Sekcja ma własny rytm pionowy (32 px z projektu), dlatego nie używa
   .k-section ani .k-container.

   Margines boczny: w Figmie frame FAQ stoi na x=22, gdy każda inna sekcja ma 16.
   Świadomie bierzemy wspólne --k-gutter — przy 22 px karty FAQ nie trzymały
   jednej pionowej krawędzi z sekcjami nad i pod nimi, co widać gołym okiem.
   ========================================================================== */

.k-faq {
  display: flex;
  flex-direction: column;
  gap: 24px;
  padding: 32px var(--k-gutter);
  background: var(--k-white);
}

.k-faq__head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 16px;
}

.k-faq__title {
  color: var(--k-gray-800);
  font-size: clamp(1.625rem, 1.1rem + 2.1vw, 2.5rem);   /* 26 px → 40 px */
  font-weight: var(--k-fw-bold);
  line-height: 32px;
  letter-spacing: var(--k-ls-display);
}

@media (min-width: 768px) {
  .k-faq__title {
    line-height: 1.2;
  }
}

@media (min-width: 1024px) {
  .k-faq {
    /* Wspólna siatka desktopowa — 1200 px treści przy marginesach 120, ten sam
       zapis co w .k-benefits-section .k-container i w sekcji kontaktu. Wcześniej
       stał tu kontener 960 px, przez co badge, tytuł i karty zaczynały się na
       273 zamiast 120 i kończyły 120 px przed prawą linią siatki. */
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
    margin-inline: auto;
    /* --k-space-10, nie --k-section-y: FAQ ma iść tym samym stałym rytmem
       co .k-section na desktopie (patrz base.css). */
    padding-block: var(--k-space-10);
  }

  /* Tytuł wraca do wspólnej skali H3, jak w poradniku, kalkulatorze, galerii
     i „O nas". Własny clamp z warstwy bazowej dobijał tu do 40/48 Bold — to
     była nasza ekstrapolacja, nie wartość z makiety: Figma ma dla FAQ tylko
     frame mobilny (166:18050) z tytułem 26/32. Medium, bo baza daje 700.

     Ta reguła MUSI stać za blokiem @media (min-width: 768px) wyżej, który
     ustawia tytułowi line-height: 1.2 — obie mają specyficzność 0-1-0, więc
     rozstrzyga kolejność w pliku. */
  .k-faq__title {
    font-size: var(--k-fs-h3-desktop);
    font-weight: var(--k-fw-medium);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }
}

/* ==========================================================================
   STOPKA — Figma: # footer (214:22183), 389×302
   Liczby wprost z frame'a. Rachunek pionu:
   32 (góra) + 32 (logo) + 32 + 52 (linki) + 18 + 32 (CTA) = 198,
   22 → linia na 220, 15 → blok prawny na 235, 47 (blok) + 20 (dół) = 302.
   ========================================================================== */

.k-footer {
  position: relative;               /* kotwica dla przycisku „TOP" */
  /* Dół 20 px z Figmy plus wysokość paska CTA, który leży na stałe nad stopką —
     bez tego linki prawne i przycisk „TOP" zostają trwale przykryte. Wyściółka
     jest STAŁA, nie doklejana przy pokazaniu paska: doklejanie przesuwałoby
     układ w trakcie przewijania. Powyżej 1024 px paska nie ma, więc wraca 20 px. */
  padding: 32px 0 calc(20px + var(--k-cta-bar-h));
  background: var(--k-hl-mint);
  text-align: center;
}

.k-footer__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 32px;
  /* bez tego na 320 px linkom produktowym zostaje po 1 px marginesu */
  padding-inline: var(--k-gutter);
}

.k-footer__logo img {
  width: 189px;
  height: 32px;
}

/* ---------- linki produktowe ---------- */

.k-footer__nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 4px 16px;
  max-width: 318px;
  /* wyrównanie do CTA: 18 px zamiast 32 px z kontenera */
  margin-bottom: -14px;
}

.k-footer__tab {
  color: var(--k-gray-800);
  font-size: 1rem;                  /* 16 px — ujednolicone dla obu stanów */
  font-weight: var(--k-fw-news);
  line-height: 24px;
  letter-spacing: 0.4px;
  white-space: nowrap;
  transition: color var(--k-dur-hover) var(--k-ease-out);
}

/* Frame mobilny ma 6 pozycji, desktopowy 9 — trzy dodatkowe i dłuższa etykieta
   „BRAMY GARAŻOWE" wchodzą dopiero od 1024 px (reguła w bloku desktopowym). */
.k-footer__tab--desktop {
  display: none;
}

/* Ukryta kopia etykiety w wadze pogrubionej rezerwuje szerokość, więc przejście
   400 → 700 na hoverze nie przepycha sąsiednich linków ani nie łamie rzędu. */
.k-footer__tab::after {
  content: attr(data-label);
  display: block;
  height: 0;
  overflow: hidden;
  font-weight: var(--k-fw-bold);
  visibility: hidden;
}

.k-footer__tab:active {
  color: var(--k-energy-mint);
  font-weight: var(--k-fw-bold);
}

@media (hover: hover) {
  .k-footer__tab:hover {
    color: var(--k-energy-mint);
    font-weight: var(--k-fw-bold);
  }
}

/* ---------- linia oddzielająca ---------- */

.k-footer__line {
  width: 348px;
  max-width: calc(100% - 42px);
  height: 1px;                      /* w Figmie 0,5 px — na ekranach 1× znikałaby */
  margin: 22px auto 0;
  border: 0;
  background: var(--k-gray-400);
}

/* ---------- copyright i linki prawne ---------- */

.k-footer__legal {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 11px;
  margin-top: 15px;
  color: var(--k-gray-500);
}

.k-footer__copy {
  font-size: var(--k-fs-xs);
  font-weight: var(--k-fw-news);
  line-height: 18px;
}

.k-footer__policies {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  font-size: 0.625rem;              /* 10 px */
  font-weight: var(--k-fw-news);
  line-height: 18px;
}

.k-footer__policies a {
  transition: color var(--k-dur-hover) var(--k-ease-out);
}

@media (hover: hover) {
  .k-footer__policies a:hover {
    color: var(--k-energy-mint);
  }
}

/* Ten sam sygnał co hover, ale dla palca — bez tego linki polityk byłyby
   po wygaszeniu plamy dotyku (base.css) zupełnie nieme. */
.k-footer__policies a:active {
  color: var(--k-energy-mint);
}

.k-footer__sep {
  width: 1px;
  height: 12px;
  border-radius: 2px;
  background: currentColor;
}

/* ---------- przycisk „TOP" ---------- */

.k-footer__top {
  position: absolute;
  top: 165px;
  right: 12px;                      /* w Figmie x=337 przy 389 szerokości */
}

/* ==========================================================================
   TABLET — od 768 px
   ========================================================================== */

@media (min-width: 768px) {
  /* ---------- karuzela packshotów ----------
     Od tabletu w górę kadr jest ograniczony do szerokości kafla, tak jak
     w makiecie desktopowej. Bez tego tor rozciągał się na całą szerokość
     ekranu, kafel zostawał na 353 px, a po bokach robiło się po ~335 px
     pustki z wyraźnymi wycinkami sąsiednich kolorów — im szerzej, tym
     bardziej odstawało to od mobile. Układ dwukolumnowy zostaje na 1024.

     Blok stoi w pliku ZA lokalnym @media 1024 z linii ~667, który ustawia
     kafel na 282 px — ta sama specyficzność, decyduje kolejność. */

  /* Odstęp musi być WIĘKSZY od bocznego paddingu toru o tyle, o ile etykiety
     wychodzą poza kafel (.k-packshot__badges ma left: -4px). Przy odstępie
     równym paddingowi sam packshot chował się za krawędzią, ale jego etykiety
     wystawały 4 px do środka kadru i wyglądało to na błąd. 32 > 24 + 4. */
  .k-slider--packshots {
    gap: var(--k-space-6);
  }

  .k-packshot {
    width: var(--k-packshot-desktop);
  }

  /* Kadrem jest sam tor; .k-carousel zostaje na pełnej szerokości kolumny,
     bo jest układem odniesienia dla strzałek, które mają wychodzić poza kadr.
     Gdyby to on był przycięty do 408 px, strzałki wypychałyby stronę. */
  .k-packshots-section .k-carousel {
    position: relative;
  }

  .k-packshots-section .k-slider--packshots {
    width: calc(var(--k-packshot-desktop) + 2 * var(--k-space-5));
    margin-inline: auto;
    padding-inline: var(--k-space-5);
    scroll-padding-inline: var(--k-space-5);
  }

  /* Poniżej 1024 .k-slider--centered snapuje do środka, powyżej do początku.
     slider.js odczytuje ten tryb z CSS-u i liczy pozycje inaczej dla każdego,
     więc wymuszamy „start" w całym zakresie 768+ — inaczej karuzela
     zachowywałaby się inaczej po obu stronach progu 1024. */
  .k-packshots-section .k-slider--packshots > .k-packshot {
    scroll-snap-align: start;
  }

  /* Strzałki wychodzą z rzędu navi i siadają po bokach kadru, wyśrodkowane
     w pionie względem samego zdjęcia. Robimy to wyłącznie CSS-em — slider.js
     dalej składa navi jako [prev][kreski][next] i nic o tym nie wie.

     Środek liczymy z proporcji kadru (282:300), a nie z 50 % karuzeli: ta
     obejmuje też rząd navi pod spodem, więc strzałki zjechałyby za nisko.
     4 px to padding-top kafla — „kolor + okno" leży niżej niż etykiety. */
  .k-packshots-section .k-carousel__arrow {
    position: absolute;
    top: calc(var(--k-space-1) + var(--k-packshot-desktop) * 300 / 282 / 2);
    width: 48px;
    height: 48px;
    transform: translateY(-50%);
  }

  .k-packshots-section .k-carousel__arrow::before {
    mask-size: 48px 48px;
    -webkit-mask-size: 48px 48px;
  }

  /* Odstęp liczymy od WIDOCZNEGO okna, nie od krawędzi pliku: packshot ma
     w środku ok. 20 px białego marginesu (zmierzone na wszystkich ośmiu
     kolorach), więc od krawędzi kadru wypada 40 − 20 = 20 px.

     Liczymy od środka kolumny, bo tor jest w niej wycentrowany: krawędź
     zdjęcia leży dokładnie pół kafla od środka. max(0px, …) trzyma strzałkę
     w kolumnie tam, gdzie jest za wąska na pełny odstęp — przy 1024 px
     kolumna ma 470 px i strzałka siada na jej krawędzi zamiast wypychać
     stronę poziomym paskiem. */
  .k-packshots-section .k-carousel__arrow--prev,
  .k-packshots-section .k-carousel__arrow--next {
    --k-arrow-offset: max(0px, calc(
      50% - var(--k-packshot-desktop) / 2
          - (var(--k-carousel-arrow-gap) - var(--k-packshot-bleed))
          - 48px
    ));
  }

  .k-packshots-section .k-carousel__arrow--prev {
    left: var(--k-arrow-offset);
  }

  .k-packshots-section .k-carousel__arrow--next {
    right: var(--k-arrow-offset);
  }

  /* Po wyjęciu strzałek w rzędzie zostają same kreski — mają być
     wyśrodkowane pod podpisem koloru. */
  .k-packshots-section .k-carousel__navi {
    justify-content: center;
  }

  /* ---------- galeria realizacji ----------
     Figma: #13 Galeria desktop (183:22002), 1440 × 821. Kafle rosną z 300/195
     do 690/384, tytuł staje na środku, a strzałki wchodzą na zdjęcia jako
     miętowe koła — przy kreskach zostają same kreski.

     Blok stoi ZA lokalnym @media 1024 z linii ~667, który ustawia kafle
     z powrotem na 300/195 px — ta sama specyficzność, decyduje kolejność. */

  /* Szerokość kafla poziomego liczona RAZ: czytają ją szerokość kafli, pionowy
     środek strzałki i zapas na końcu toru. Skala 0,75 to zmniejszenie zdjęć
     o 25 % względem makiety; proporcja zostaje, więc wysokość schodzi razem. */
  .k-gallery-section {
    --k-gallery-shot: min(
      calc(var(--k-shot-wide-d) * var(--k-gallery-scale) * 1px),
      calc(var(--k-shot-wide-d) * var(--k-gallery-scale) * 100vw / 1440)
    );
  }

  /* Odsunięcie od krawędzi okna do siatki treści. Frame 183:22002 stawia tor
     na x=120, czyli przy marginesie treści — nie przy krawędzi ekranu. Czytają
     to i tor, i strzałki; obie mają ten sam blok zawierający (.k-carousel na
     pełną szerokość okna), więc `100%` daje im tę samą liczbę: 120 przy 1440,
     360 przy 1920, a przy węższych ekranach schodzi do guttera. */
  .k-gallery-section {
    --k-gallery-inset: max(
      var(--k-gutter),
      calc((100% - var(--k-container-desktop)) / 2)
    );
  }

  .k-gallery-section h2 {
    /* jw. — Headers/H3 (Basic) to Medium, base.css daje 700.
       Wyśrodkowanie siedzi w warstwie bazowej, bo dotyczy też mobile. */
    font-weight: var(--k-fw-medium);
    font-size: var(--k-fs-h3-desktop);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  .k-gallery-section h2 .k-br-mobile {
    display: none;
  }

  /* „Ponad 60 kolorów do wyboru" łamie się tylko na mobile, gdzie lista jest
     jednokolumnowa i tekst wchodziłby pod plakietkę „7 lat". Od 768 px lista
     ma dwie kolumny (a na desktopie węższą kartę) i mieści się w wierszu. */
  .k-guarantee .k-br-mobile {
    display: none;
  }

  /* Tytuł → tor: 56 px z makiety. .k-carousel ma bazowo 24, więc dokładamy 32. */
  .k-gallery-section .k-carousel {
    position: relative;
    margin-top: calc(var(--k-space-5) + var(--k-space-6));
  }

  .k-gallery {
    gap: var(--k-space-5);
    padding-inline-start: var(--k-gallery-inset);
    /* Symetrycznie, mimo że sam padding toru symetryczny nie jest: snapport
       musi zostać wyśrodkowany, inaczej ostatni kafel (scroll-snap-align:
       center) przesunąłby się o połowę różnicy między stronami. */
    scroll-padding-inline: var(--k-gallery-inset);
    /* Zapas na końcu toru dobrany tak, żeby ostatnie zdjęcie zatrzymało się
       na ŚRODKU kadru, a nie przy lewej krawędzi z pustką po prawej.
       Przy połowie różnicy między torem a kaflem pozycja wyśrodkowana
       ostatniego kafla równa się maksymalnemu przewinięciu — czyli jest
       osiągalna i mandatory-snap jej nie odrzuca. */
    padding-inline-end: max(
      var(--k-gutter),
      calc(50% - var(--k-gallery-shot) / 2)
    );
  }

  /* Tylko ostatni kafel snapuje do środka — reszta zostaje przy lewej krawędzi.
     slider.js czyta tryb każdego kafla osobno, więc kreski i stan strzałek
     nadążają za tym wyjątkiem. */
  .k-gallery > .k-shot:last-child {
    scroll-snap-align: center;
  }

  /* Kafel zatrzymuje się na szerokości z makiety, a niżej maleje proporcjonalnie
     do szerokości okna — ten sam idiom, którym skalują się kafle na mobile
     (tam odniesieniem jest 390 px, tu 1440). Dzięki temu przy 768 px kafel
     poziomy schodzi do ~368 px i mieści się na ekranie. */
  .k-shot {
    width: min(
      calc(var(--k-shot-w-d) * var(--k-gallery-scale) * 1px),
      calc(var(--k-shot-w-d) * var(--k-gallery-scale) * 100vw / 1440)
    );
  }

  .k-shot img {
    aspect-ratio: var(--k-shot-w-d) / var(--k-gallery-img-h);
  }

  /* Strzałka leży na zdjęciu: koło energy-mint z białym szewronem, na hoverze
     koło jaśnieje do baby-mint. Komponent .k-carousel__arrow zostaje gołym
     szewronem — koło dokłada sekcja. Środek w pionie liczymy z proporcji kadru
     poziomego, bo 50 % karuzeli obejmuje też rząd kresek pod spodem. */
  .k-gallery-section .k-carousel__arrow {
    position: absolute;
    top: calc(var(--k-gallery-shot) * var(--k-gallery-img-h) / var(--k-shot-wide-d) / 2);
    width: 48px;
    height: 48px;
    border-radius: var(--k-radius-pill);
    background: var(--k-energy-mint);
    transform: translateY(-50%);
    transition: background-color var(--k-dur-btn) var(--k-ease-btn);
  }

  /* Szewron biały na energy-mintowym kole. Komponent bazowy przemalowuje go
     na baby-mint w hoverze i na Gray-200 przy wyłączeniu — nadpisujemy obie
     reguły selektorem scope'owanym sekcją. */
  .k-gallery-section .k-carousel__arrow::before {
    background-color: var(--k-white);
  }

  /* Hover i wciśnięcie: koło jaśnieje do baby-mint, a szewron ciemnieje do
     energy-mint — biały byłby na tym tle ledwo widoczny (kontrast ~1,5 : 1). */
  @media (hover: hover) {
    .k-gallery-section .k-carousel__arrow:not(:disabled):hover {
      background: var(--k-baby-mint);
    }

    .k-gallery-section .k-carousel__arrow:not(:disabled):hover::before {
      background-color: var(--k-energy-mint);
    }
  }

  .k-gallery-section .k-carousel__arrow:not(:disabled):active {
    background: var(--k-baby-mint);
  }

  .k-gallery-section .k-carousel__arrow:not(:disabled):active::before {
    background-color: var(--k-energy-mint);
  }

  /* Skrajna strzałka znika zamiast szarzeć. Tylko od 768 px: niżej stoi
     w rzędzie razem z kreskami i jej zniknięcie przesuwałoby je w bok. */
  .k-gallery-section .k-carousel__arrow:disabled {
    display: none;
  }

  .k-gallery-section .k-carousel__arrow--prev {
    left: var(--k-gallery-inset);
  }

  .k-gallery-section .k-carousel__arrow--next {
    right: var(--k-gallery-inset);
  }

  /* Po wyjęciu strzałek w rzędzie zostają same kreski — 48 px pod zdjęciami. */
  .k-gallery-section .k-carousel__navi {
    justify-content: center;
    margin-top: var(--k-space-8);
  }

  .k-benefits__list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--k-space-6);
    width: auto;
  }

  .k-guarantee__list {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
  }

  .k-stats {
    grid-template-columns: repeat(4, 1fr);
  }

  .k-form {
    grid-template-columns: repeat(2, 1fr);
  }

  .k-form > .k-field:nth-child(n + 6),
  .k-form__upload,
  .k-form__consents,
  .k-form__actions {
    grid-column: 1 / -1;
  }
}

/* ==========================================================================
   DESKTOP — od 1024 px
   ========================================================================== */

@media (min-width: 1024px) {
  /* Łamacz w tytule jest po to, żeby na telefonie nie została sierota — przy
     1200 px tytuł mieści się w jednej linii, tak jak w makiecie desktopowej.
     Spacja przed <br> w HTML pilnuje, żeby po jego ukryciu słowa się nie skleiły. */
  .k-calc__title br {
    display: none;
  }

  /* Tytuł sekcji idzie na desktopie stylem H3, nie H2 (203:22077 — Headers/H3
     (Basic), Clan Pro Medium 28/40, LS −1,6). Bez tego clamp z --k-fs-h2
     dobija przy 1440 px do 48 px i nagłówek wyłamuje się z rytmu pozostałych
     sekcji. Medium, bo base.css daje nagłówkom 700. */
  .k-calc__title {
    font-size: var(--k-fs-h3-desktop);
    font-weight: var(--k-fw-medium);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  /* Wstęp zostaje przy 14/20 z Figmy (203:22078). Globalne --k-fs-lead rośnie
     na desktopie do 17 px, a --k-lh-body rozpycha interlinię do ~26 — ta sama
     korekta co w poradniku i „O nas" niżej. Światła międzyliterowego nie
     ruszamy: baza .k-lead ma --k-ls-tight, czyli już −0,6 px z makiety. */
  .k-calc-section .k-lead {
    font-size: var(--k-fs-sm);
    line-height: var(--k-lh-lead);
  }

  /* Kalkulator na desktopie (Figma: 203:22072): kreator po lewej, panel wyniku
     po prawej. Proporcje 722 / 454 z odstępem 24 px składają się na 1200 px
     treści sekcji. */
  .k-calc-layout {
    display: grid;
    grid-template-columns: minmax(0, 722fr) minmax(0, 454fr);
    align-items: start;
    gap: 24px;
  }

  /* Sekcja kontaktu na desktopie: formularz po lewej, wyszukiwarka salonu po
     prawej — układ z oknoplast.com.pl/kontakt. Badge, wstęp i „Napisz do nas:"
     zostają nad lewą kolumną; salon startuje równo z badge'em. */
  .k-form-section .k-container--narrow {
    /* Sekcja wchodzi na wspólną siatkę desktopową — 1200 px treści przy
       marginesach 120, ten sam zapis co w .k-benefits-section .k-container.
       Wcześniej jako JEDYNA na stronie zostawała na kontenerze 960 px,
       przez co jej treść zaczynała się 153 px głębiej niż kalkulator nad nią.
       Warstwa bazowa (--k-container-narrow) zostaje nietknięta, więc telefon
       i tablet się nie ruszają. */
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
    display: grid;
    /* Podział z referencji oknoplast.com.pl/kontakt: formularz 588, odstęp 126,
       salon 384. Suma to 1098, a treść sekcji ma 1200 — nadwyżki 102 px NIE
       rozdzielamy, blok kończy się na 1218. To świadome odstępstwo: wierność
       referencji ma tu pierwszeństwo przed prawą linią siatki, więc mapa nie
       równa się z zielonym panelem kalkulatora ani ze stopką.

       Procentami, nie pikselami — tą samą techniką co .k-about-section niżej.
       Sztywne `588px 384px` z odstępem 126px sumuje się do 1098 i przepełniłoby
       kontener poniżej ~1224 px szerokości okna (przy 1024 px treści jest tylko
       972). Procenty schodzą razem z kontenerem: przy 1024 px wychodzi
       476 / 102 / 311, proporcje bez zmian. */
    grid-template-columns: 49% 32%;
    /* cztery wiersze na treść lewej kolumny + zapasowy 1fr: gdy salon jest od
       niej wyższy, nadmiar wysokości ląduje w pustym wierszu na dole, a nie
       rozpycha odstępów między badge'em, wstępem i formularzem */
    grid-template-rows: repeat(4, auto) 1fr;
    column-gap: 10.5%;
    /* nadwyżka 8,5 % zostaje po prawej, a nie rozpycha kolumn */
    justify-content: start;
    align-items: start;
  }

  /* Kolumna formularza urosła do ~790 px, a akapit wstępny to proza — przy
     pełnej szerokości wychodziłoby ~100 znaków w wierszu. Ten sam token, którym
     poradnik trzyma swój wstęp. Pól formularza to nie dotyczy: one korzystają
     z całej kolumny. */
  .k-form__intro {
    max-width: var(--k-measure-copy);
  }

  .k-form-section .k-badge,
  .k-form__intro,
  .k-form__title,
  .k-form,
  .k-form-success {
    grid-column: 1;
  }

  /* Podziękowanie ma stałe 239 px i centruje się marginesem auto z komponentu.
     W kolumnie szerokiej na 790 px odjeżdżałoby przez to daleko w prawo, od
     lewo-wyrównanego bloku copy nad sobą. Centrujemy je w mierze tekstu,
     czyli w tym samym pasie, w którym stoi akapit wstępny. */
  .k-form-success {
    margin-inline: calc(
        (var(--k-measure-copy) - var(--k-form-success-w)) / 2
      )
      auto;
  }

  /* „Napisz do nas:" tą samą skalą H3 co nagłówki pozostałych sekcji.
     Figma nie ma dla tej sekcji frame'a desktopowego, więc bierzemy styl
     Headers/H3 (Basic) — inaczej clamp z --k-fs-h2 robi z niego 48 px
     i nagłówek jest większy niż tytuł sekcji nad nim. */
  .k-form__title {
    font-size: var(--k-fs-h3-desktop);
    font-weight: var(--k-fw-medium);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  .k-salon {
    grid-column: 2;
    /* Wiersz 3 to ten, w którym stoi „Napisz do nas:" — lewa kolumna zajmuje
       wiersze 1–4 (badge, wstęp, tytuł, formularz). Dzięki temu oba nagłówki
       dostają przy align-items: start tę samą górną krawędź; wcześniej salon
       startował od wiersza 1 i wisiał 124 px wyżej, równo z badge'em.
       Koniec na -1 zostaje, żeby działało też po ukryciu formularza, gdy
       w lewej kolumnie jest samo podziękowanie (ukryty element nie jest
       elementem siatki, więc podziękowanie wchodzi w wiersz 4). */
    grid-row: 3 / -1;
    margin-top: 0;
  }

  /* Jedyny nagłówek w tej sekcji, który nie szedł skalą H3 — teraz zgadza się
     z „Napisz do nas:" obok. Na mobile zostaje H4: tam blok stoi POD
     formularzem, a nie równolegle do niego. */
  .k-salon__title {
    font-size: var(--k-fs-h3-desktop);
    font-weight: var(--k-fw-medium);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  /* pole i CTA w jednej linii; etykieta siedzi w .k-field, więc równamy do dołu */
  .k-salon__row {
    display: flex;
    align-items: flex-end;
    gap: var(--k-space-2);
  }

  .k-salon__row .k-field {
    flex: 1;
    min-width: 0;
    margin-bottom: 24px;
  }

  .k-salon__submit {
    min-height: 48px;                 /* równo z wysokością pola */
  }

  /* na desktopie zostaje samo „ZNAJDŹ" — przycisk ma zmieścić się obok pola */
  .k-salon__submit-rest {
    display: none;
  }

  /* ------------------------------------------------------------------------
     HERO — Figma: # hero-banner (706:6020), 1440 × 577.

     Copy po lewej, kompozycja KV po prawej — dwie równe kolumny po 720 px.
     Wszystkie liczby niżej to współrzędne z frame'a, dlatego są w px:
     to odwzorowanie makiety, nie rytm sekcji.

     Rytm pionowy lewej kolumny sumuje się dokładnie do 577 px
     (48 + 24 + 16 + 160 + 12 + 64 + 32 + 40 + 44 + 90 + 47), więc wysokość
     sekcji WYCHODZI Z TREŚCI i nie wpisujemy jej nigdzie na sztywno.
     ------------------------------------------------------------------------ */

  .k-hero {
    /* Belka jest position: fixed, a w makiecie baner zaczyna się POD nią.
       Bez tego paddingu górne 76 px kompozycji chowałoby się za białym pasem
       i chłopiec siedziałby za nisko względem projektu. */
    padding-top: var(--k-header-h);
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-items: stretch;
    max-width: var(--k-container);
    margin-inline: auto;
  }

  /* Odstępy w kolumnie są cztery różne (16 / 12 / 32 / 44), więc niosą je
     marginesy poszczególnych bloków, a nie jeden `gap` — ten sam zabieg co
     w kolumnie copy w #benefity-top niżej. */
  .k-hero__copy {
    gap: 0;
    /* Blok copy stoi w makiecie na x = 117, czyli praktycznie na siatce
       1200/120, którą trzymają wszystkie sekcje desktopowe — a nie na
       gutterze kontenera 1440. Kolumna ma połowę kontenera, więc
       „100% − połowa siatki" daje przy 1440 px równe 120 px, a poniżej
       1200 px schodzi płynnie do guttera, zamiast zaciskać tekst. */
    padding-block: 48px 47px;
    padding-inline: max(
      var(--k-gutter),
      calc(100% - var(--k-container-desktop) / 2)
    );
  }

  .k-hero__intro {
    gap: 16px;
  }

  .k-hero__text {
    /* 465 px z frame'a — bez tego H1 łamie się inaczej niż w makiecie */
    max-width: 465px;
    gap: 12px;
  }

  /* Stopień H1 na desktopie jest MNIEJSZY niż daje clamp z tokenów (64 wobec
     72 px). Nie ruszamy sufitu --k-fs-display, bo ten clamp obsługuje też
     zakres 768–1023 px, gdzie układ jest jeszcze mobilny. */
  .k-hero__title {
    font-size: var(--k-fs-display-desktop);
    line-height: var(--k-lh-display-desktop);
    letter-spacing: var(--k-ls-display-desktop);
  }

  .k-hero__sub {
    /* stopień 24 px clamp osiąga sam już przy ~1016 px — zostaje interlinia
       i światło międzyliterowe */
    line-height: var(--k-lh-hero-sub-desktop);
    letter-spacing: var(--k-ls-hero-sub-desktop);
  }

  .k-hero__actions {
    margin-top: 32px;
  }

  .k-hero .k-countdown {
    margin-top: 44px;
    gap: 12px;
  }

  .k-hero .k-countdown__label {
    font-size: var(--k-fs-count-intro-desktop);
  }

  .k-hero .k-countdown__value {
    font-size: var(--k-fs-count-desktop);
    line-height: var(--k-lh-count-desktop);
  }

  .k-hero .k-countdown__cell {
    min-width: 47px;
    gap: 10px;
    padding-block: 4px;
  }

  /* Koło stoi w makiecie na x = 479…599, czyli 121 px od prawej krawędzi
     kolumny. Liczymy je tym samym wyrażeniem co padding copy, więc wychodzi
     równe 120 — oba boki trzymają jedną siatkę, a piksel różnicy i tak gubi
     się w rozjeździe samej makiety (blok copy x 117, licznik x 121).
     Dół: 51 px od dołu sekcji.

     Ta reguła wygrywa z max() w warstwie bazowej KOLEJNOŚCIĄ w pliku, nie
     specyficznością: przeniesienie bloku media query wyżej cicho by ją
     unieważniło. */
  .k-hero__badge {
    --k-badge-scale: 1.53846;        /* 120 / 78 z 166:21641 */
    right: max(
      var(--k-gutter),
      calc(100% - var(--k-container-desktop) / 2)
    );
    bottom: 51px;
  }

  /* ---------- KV: kompozycja 720 × 577 (706:6022) ----------
     Tło (gradient + swoosh + żółta pętla) wchodzi jako <img> przez
     <source media> w index.html — jeden plik SVG. Na nim leżą okno, chłopiec
     i muszka; okno i chłopiec są osobnymi warstwami, bo mają wchodzić
     niezależnie i chłopiec dostaje po wejściu własny ruch.

     Pozycje podajemy w PROCENTACH kadru, a nie w px z frame'a: dzięki temu
     jedno miejsce (rozmiar kadru niżej) rządzi całą kompozycją i warstwy
     nie mogą rozjechać się z tłem. */

  .k-hero__kv {
    position: relative;
    margin-top: 0;                   /* zeruje hack −2 px z warstwy mobilnej */
    overflow: hidden;
  }

  /* Kadr kompozycji. Wysokość bierze z wiersza siatki (a ten z kolumny copy,
     czyli równe 577 px), szerokość z proporcji — więc kadr ma zawsze dokładnie
     720 × 577 i wyśrodkowuje się w kolumnie. Poniżej 1440 px kolumna jest
     węższa niż 720 i nadmiar przycina `overflow: hidden` symetrycznie z obu
     stron. To ten sam efekt co object-fit: cover, tylko obejmuje TAKŻE okno
     i chłopca — dzięki temu warstwy nigdy nie rozjeżdżają się z tłem.

     Skutek uboczny, wygodny: wszystko w środku jest position: absolute, więc
     kolumna KV nie wnosi własnej wysokości i nie ma z czego wziąć się CLS,
     mimo że atrybuty width/height na <img> opisują kadr MOBILNY (390 × 392). */
  .k-hero__kv-scena {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    height: 100%;
    min-width: 100%;
    aspect-ratio: 720 / 577;
  }

  .k-hero__kv img {
    display: block;
    width: 100%;
    height: 100%;
  }

  .k-hero__kv-okno,
  .k-hero__kv-chlopiec {
    display: block;
    position: absolute;
    background-repeat: no-repeat;
  }

  /* 706:6025 — rysunek okna. Współrzędne są współrzędnymi WYPEŁNIENIA
     obrazkowego, nie ramki: Figma przesuwa je w pionie o 3,18 % wysokości
     ramki i to przesunięcie widać w kompozycji. */
  .k-hero__kv-okno {
    left: 17.955%;
    top: 14.325%;
    width: 49.28%;
    height: 65.919%;
    background-image: image-set(
      url("../images/sections/hero-kv-okno-355.webp") 1x,
      url("../images/sections/hero-kv-okno-710.webp") 2x
    );
    background-size: contain;
    --k-reveal-delay: var(--k-delay-hero-okno);
  }

  /* 706:6026 — chłopiec. Sama ramka; obraz niesie warstwa ruchu niżej. */
  .k-hero__kv-chlopiec {
    left: 52.639%;
    top: 22.357%;
    width: 43.75%;
    height: 72.444%;
    --k-reveal-delay: var(--k-delay-hero-chlopiec);
  }

  /* `cover`, bo wypełnienie jest o pół piksela szersze niż ramka
     i Figma je przycina — tak samo jak object-fit: cover w makiecie. */
  .k-hero__kv-chlopiec-ruch {
    position: absolute;
    inset: 0;
    background: image-set(
        url("../images/sections/hero-kv-chlopiec-315.webp") 1x,
        url("../images/sections/hero-kv-chlopiec-630.webp") 2x
      )
      center / cover no-repeat;
    animation: k-hero-kv-plyn var(--k-dur-hero-idle) var(--k-ease-in-out) infinite;
  }

  /* Muszka (I706:6026;129:2426) leży na zdjęciu jako osobny wektor — sam
     packshot chłopca ma ją czarną. Jedzie razem z warstwą ruchu, więc jest
     jej pseudoelementem, a nie osobnym dzieckiem KV. */
  .k-hero__kv-chlopiec-ruch::after {
    content: "";
    position: absolute;
    left: 43.408%;
    top: 23.459%;
    width: 13.454%;
    height: 6.153%;
    background: url("../images/sections/hero-kv-muszka.svg") center / 100% 100%
      no-repeat;
  }

  /* ---------- wejście warstw KV ----------
     Obie deklarujemy PARAMI: stan spoczynku i stan po ujawnieniu. Reguła
     .k-js [data-reveal].is-revealed z base.css ma specyficzność 0-3-0, więc
     samo nadpisanie stanu spoczynku (też 0-3-0) remisowałoby z nią i warstwa
     zostałaby przesunięta na stałe — komentarz przy .k-badge-info w
     components.css opisuje dokładnie tę pułapkę. Stan ujawniony ma tu 0-4-0
     i wygrywa jednoznacznie. */

  .k-js .k-hero__kv-okno[data-reveal] {
    transform: translateY(12px) scale(0.98);
  }

  .k-js .k-hero__kv-okno[data-reveal].is-revealed {
    transform: none;
  }

  /* chłopiec nadlatuje z prawego dołu — kierunek lotu samolotu z makiety */
  .k-js .k-hero__kv-chlopiec[data-reveal] {
    transform: translate(40px, 28px);
  }

  .k-js .k-hero__kv-chlopiec[data-reveal].is-revealed {
    transform: none;
  }

  /* KORZYŚCI — Figma: #benefity-top desktop (166:21644), 1440 × 554.
     Ta sama siatka co poradnik i stopka: 1200 px treści przy 120 px marginesu.
     Dwie równe kolumny po 588 px z odstępem 24 px — copy po lewej, karta
     z animacją po prawej. Obie mają w makiecie dokładnie 394 px wysokości
     (120 + 16 + 194 + 24 + 40 po lewej), więc dół sekcji wychodzi równo. */
  .k-benefits-section .k-container {
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
  }

  .k-benefits {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    /* trzy wiersze na treść lewej kolumny + zapasowy 1fr: karta po prawej jest
       rozpięta na całą wysokość, a bez pustego wiersza jej 394 px rozpychałoby
       tytuł, listę i CTA. Ten sam zabieg co w .k-form-section wyżej. */
    grid-template-rows: repeat(3, auto) 1fr;
    column-gap: var(--k-space-5);
    /* odstępy w kolumnie copy nie są równe (16 px i 24 px), więc rytm niosą
       marginesy poszczególnych elementów, nie row-gap siatki */
    row-gap: 0;
    align-items: start;
  }

  /* Tytuł idzie na desktopie stylem H3 (166:21646), nie H2 — tak samo jak
     w poradniku. Bez text-wrap: balance, bo łamanie niesie <br> z makiety. */
  .k-benefits__title {
    grid-column: 1;
    grid-row: 1;
    /* w warstwie bazowej align-self: stretch rozciąga nagłówek na szerokość
       kolumny flexa; w siatce ta sama własność działa w pionie i rozciągnęłaby
       go na wysokość wiersza, więc ją zdejmujemy */
    align-self: start;
    font-size: var(--k-fs-h3-desktop);
    font-weight: var(--k-fw-medium);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  /* Makieta desktopowa łączy dwa pierwsze zdania w jeden wiersz (3 wiersze
     zamiast 4 z mobile) — gasimy pierwszy <br>. */
  .k-benefits__title .k-br-mobile {
    display: none;
  }

  .k-benefits__list {
    grid-column: 1;
    grid-row: 2;
    grid-template-columns: 1fr;
    max-width: var(--k-measure-params);
    margin-top: var(--k-space-4);
    gap: var(--k-space-3);
  }

  /* Pozycja jest na desktopie o stopień mniejsza niż na mobile:
     14/20 zamiast 16/20 w tytule i 12/16 zamiast 13/16 w opisie (166:21651). */
  .k-benefits .k-feature__title {
    font-size: var(--k-fs-sm);
  }

  .k-benefits .k-feature__desc {
    font-size: var(--k-fs-xs);
  }

  /* CTA jest elementem siatki — bez tego rozciąga się na całą kolumnę */
  .k-benefits > .k-btn {
    grid-column: 1;
    grid-row: 3;
    justify-self: start;
    margin-top: var(--k-space-5);
  }

  /* Karta packshotu (166:21719): białe tło, obrys Gray-200, promień 16.
     Wysokość równa kwadratowi animacji, więc medium wypełnia ją w pionie,
     a padding boczny zostaje na wypadek węższej kolumny niż 394 px. */
  .k-benefits__media {
    display: grid;
    place-items: center;
    grid-column: 2;
    grid-row: 1 / -1;
    height: var(--k-media-square);
    padding-inline: var(--k-space-4);
    border: 1px solid var(--k-border);
    border-radius: var(--k-radius-md);
    background: var(--k-surface);
  }

  .k-guarantee {
    padding: var(--k-space-7);
  }

  .k-guarantee__list {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--k-space-5) var(--k-space-7);
  }

  /* PORADNIK — Figma: #poradnik desktop (234:22456), 1440 × 540.
     Siatka 1200 px treści przy 120 px marginesu — ta sama, którą trzyma stopka.
     max-width liczymy razem z gutterem, bo .k-container ma padding wliczony
     w szerokość: przy 1440 px daje to dokładnie 120 px od krawędzi, a poniżej
     ~1250 px sekcja płynnie schodzi do samych gutterów zamiast wisieć na
     stałych 240 px marginesu. */
  .k-steps-section .k-container {
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
  }

  /* Tytuł sekcji idzie na desktopie stylem H3, nie H2 (Figma 234:22461) */
  .k-steps-section h2 {
    font-size: var(--k-fs-h3-desktop);
    font-weight: var(--k-fw-medium);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  .k-steps-section h2,
  .k-steps-section .k-lead {
    max-width: var(--k-measure-copy);
  }

  /* Wstęp zostaje przy 14/20 z Figmy (234:22462). Globalne --k-fs-lead rośnie
     na desktopie do 17 px, a --k-lh-body rozpycha interlinię do 26 px — w słupku
     481 px dawało to trzy wiersze i 78 px zamiast dwóch wierszy i 40 px. */
  .k-steps-section .k-lead {
    font-size: var(--k-fs-sm);
    line-height: var(--k-lh-lead);
  }

  /* Grid nad dwiema listami, nie nad czterema krokami: kolumny mają się
     układać niezależnie, żeby krok 4 startował wyżej niż krok 2. */
  .k-steps {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--k-space-6);   /* 32 px */
    align-items: start;
  }

  .k-steps__col {
    gap: var(--k-space-6);
  }

  /* Kolumna ma 584 px, krok tylko 481 px — reszta zostaje pustym marginesem,
     tak jak w makiecie. Bez tego opis rozlewa się na 528 px. */
  .k-step {
    max-width: var(--k-measure-copy);
  }

  /* 24 px pod kolumnami, równo z lewą krawędzią treści (Figma: 656:3331 na
     x=120, y=508). Stany hover/active niesie sam .k-btn--primary. */
  .k-steps__cta {
    display: inline-flex;
    margin-top: var(--k-space-5);
  }


  /* Desktop stopki — Figma: # footer (508:7591), 1440×394.
     Logo mniejsze niż na mobile, większe odstępy, CTA z promieniem 44,
     blok prawny rozjeżdża się na boki: copyright w lewo, polityki w prawo. */
  .k-footer {
    /* dół 48 px domyka ramkę do 394 px z frame'a */
    padding: 48px 0;
    /* Blok treści stopki: przy 1440 px daje 1200 px przy marginesach 120,
       czyli siatkę z frame'a. Rośnie razem z oknem do 1202 i tam się
       zatrzymuje — dalej blok się centruje, a marginesy rosną.

       Jedna zmienna, bo trzymają się jej TRZY elementy: linia, blok prawny
       i przycisk „TOP". Wcześniej to samo min() stało wypisane dwa razy przy
       linii i bloku prawnym, a „TOP" miał własne, sztywne right: 120px —
       i powyżej 1442 px, gdy blok przestawał rosnąć, uciekał poza siatkę
       (przy 1920 px o 239 px). */
    --k-footer-block: min(1202px, calc(100% - 240px));
  }

  .k-footer__inner {
    gap: 48px;
  }

  .k-footer__logo img {
    width: 142px;
    height: 24px;
  }

  .k-footer__nav {
    max-width: 949px;
    gap: 16px 32px;
    margin-bottom: -16px;         /* wyrównanie do odstępu 32 px przed CTA */
  }

  .k-footer__tab--desktop {
    display: block;
  }

  .k-footer__tab--mobile {
    display: none;
  }

  .k-footer__cta-pill {
    border-radius: 44px;
  }

  .k-footer__line {
    width: var(--k-footer-block);
    max-width: none;
    margin-top: 48px;
  }

  /* copyright i polityki rozchodzą się na krawędzie tej samej szerokości co linia */
  .k-footer__legal {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    width: var(--k-footer-block);
    margin-inline: auto;
    /* odstęp linia → blok prawny odczytany z renderu: metadane Figmy nie
       zwracają tych dwóch elementów, choć widać je na zrzucie frame'a */
    margin-top: 32px;
  }

  /* W Figmie (508:7606) koło stoi na x=1280 przy ramce 1440, czyli jego prawa
     krawędź leży dokładnie na prawej krawędzi siatki — 120 px od brzegu.
     Liczymy więc odstęp z bloku treści, a nie sztywną liczbą: powyżej 1442 px
     blok przestaje rosnąć i centruje się, a „TOP" ma jechać razem z nim. */
  .k-footer__top {
    top: 208px;
    right: calc((100% - var(--k-footer-block)) / 2);
  }

  /* ==========================================================================
     O NAS — Figma: 685:5205, 1200 × 779 (frame jest samą treścią, marginesy
     120 px są poza nim). Góra w dwóch kolumnach: wąska kolumna tekstu 384 px
     po lewej, zdjęcie 690 px dosunięte do prawej, między nimi 126 px. Pasek
     statystyk zostaje na pełnej szerokości pod spodem.

     Kolumny procentowo, a odstęp jako reszta szerokości: przy 1200 px treści
     daje to dokładnie 384 / 126 / 690, a niżej wszystko skaluje się razem.
     ========================================================================== */

  .k-about-section {
    padding-block: var(--k-space-10);
  }

  .k-about-section .k-container {
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
    display: grid;
    grid-template-columns: 32% 57.5%;
    /* trzy wiersze na treść lewej kolumny + zapasowy 1fr + wiersz statystyk.
       Bez pustego wiersza zdjęcie (397 px) rozpychało wiersze 1–3, bo grid
       rozdziela nadmiar wysokości elementu rozpiętego na kilka wierszy POMIĘDZY
       nie — odstęp badge → tytuł rósł z 24 do 91, a tytuł → lead z 8 do 75. */
    grid-template-rows: repeat(3, auto) 1fr auto;
    justify-content: space-between;
    align-items: start;
  }

  .k-about-section .k-badge {
    grid-column: 1;
    grid-row: 1;
  }

  .k-about-section h2 {
    grid-column: 1;
    grid-row: 2;
    /* Medium, nie Bold: base.css daje nagłówkom 700, a styl Headers/H3 (Basic)
       z Figmy to Clan Pro Medium — tak samo jak w pozostałych sekcjach. */
    font-weight: var(--k-fw-medium);
    font-size: var(--k-fs-h3-desktop);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  .k-about-section .k-lead {
    grid-column: 1;
    grid-row: 3;
    font-size: var(--k-fs-sm);
    line-height: var(--k-lh-lead);
  }

  /* Zdjęcie rozpięte na wszystkie trzy wiersze kolumny tekstu. Jest od niej
     wyższe (397 wobec 196), więc pasek statystyk w czwartym wierszu siada
     pod tym, co wyższe — bez liczenia offsetów. */
  .k-about__media {
    grid-column: 2;
    grid-row: 1 / 5;
    margin-top: 0;
  }

  /* Wysokość wychodzi z proporcji i szerokości kolumny — stąd żadnego
     clamp-a wysokości, który stał tu wcześniej. */
  .k-about__media img {
    aspect-ratio: var(--k-about-img-w) / var(--k-about-img-h);
    height: auto;
    max-height: none;
  }

  /* Pigułka kotwiczy do lewego dolnego rogu kadru. Na mobile jest liczona
     od góry (top: 185px) i przy tej wysokości zdjęcia by odjechała.
     W makiecie jest wtopiona w zdjęcie, więc odstęp jest naszą decyzją. */
  .k-about__pill {
    top: auto;
    bottom: var(--k-space-4);
    left: var(--k-space-4);
  }

  /* Pasek statystyk: cztery pozycje szerokości treści, wolna przestrzeń
     rozdzielona równo między nie (w makiecie po 103,3 px). */
  .k-stats {
    grid-column: 1 / -1;
    grid-row: 5;
    grid-template-columns: repeat(4, auto);
    justify-content: space-between;
    gap: 0;
    margin-top: var(--k-space-7);
    padding: var(--k-space-7) var(--k-stats-pad-x);
  }

  /* Padding pionowy 80/80 z frame'a 183:22002. --k-section-y jest clamp-em
     i przy 1440 px daje 76,8 — sąsiednia sekcja stoi już na równych 80, więc
     3 px różnicy byłoby widać na styku. Poniżej 1024 zostaje rytm globalny. */
  .k-gallery-section {
    padding-block: var(--k-space-10);
  }

  /* ==========================================================================
     ZOBACZ OKNO PIXEL — Figma: 667:4940, 1199 × 677
     Dwie kolumny 584 px w odstępie 32: packshoty po lewej, karta gwarancji
     po prawej. Siatkę niesie opakowanie, bo #produkt i #benefity zostają
     osobnymi sekcjami — #produkt jest celem kotwicy z menu.
     ========================================================================== */

  .k-product-block {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--k-space-6);
    /* góra karty równo z górą okna packshotu — odsunięcie niesie sama karta */
    align-items: start;
    max-width: calc(var(--k-container-desktop) + 2 * var(--k-gutter));
    margin-inline: auto;
    /* Rytm pionowy niesie opakowanie, nie poszczególne sekcje. Wcześniej
       padding stał na .k-packshots-section i był zjadany przez regułę
       .k-product-block > .k-section niżej — ta ma wyższą specyficzność.

       80 z tokena skali, nie --k-section-y: ten jest clamp-em i przy 1440 px
       daje dopiero 76,8 (osiąga 80 od ~1520). Referencja podaje równe 80. */
    padding-block: var(--k-space-10) var(--k-product-block-pb);
    padding-inline: var(--k-gutter);
  }

  /* Marginesy i szerokość niesie teraz opakowanie — wewnętrzne kontenery
     obu sekcji muszą je oddać, inaczej dokładają drugi komplet. */
  .k-product-block .k-container {
    max-width: none;
    padding-inline: 0;
  }

  .k-product-block > .k-section {
    padding-block: 0;
  }

  /* Nagłówek stylem H3 (28/40, LS −1,6) — tak samo jak w poradniku
     i korzyściach. Zmienna „Headers/H2 (Basic)" odczytana z tego frame'a
     opisuje tytuł zagnieżdżonej w nim galerii, nie tytuł tej sekcji. */
  .k-packshots-section h2 {
    font-size: var(--k-fs-h3-desktop);
    line-height: var(--k-lh-h3);
    letter-spacing: var(--k-ls-h3);
  }

  /* ---------- karta gwarancji ---------- */

  /* Górna krawędź karty ma stanąć równo z górą WIDOCZNEGO okna packshotu.
     Odsuwamy ją o wysokość wszystkiego, co w lewej kolumnie leży wyżej.
     Lead jest clamp()-em, więc jego wiersz liczymy jako fs × line-height,
     a nie zamrożoną liczbą — inaczej wyrównanie trzymałoby się tylko przy
     jednej szerokości okna. */
  .k-product-block > .k-benefits-card-section {
    padding-block: calc(
        var(--k-lh-h3)                          /* tytuł, jeden wiersz */
      + var(--k-space-2)                        /* .k-product__lead margin-top */
      + var(--k-fs-lead) * var(--k-lh-body)     /* lead, jeden wiersz */
      + var(--k-space-4)                        /* .k-carousel margin-top */
      + var(--k-space-1)                        /* .k-packshot padding-top */
      + var(--k-packshot-bleed-top)             /* biały margines nad oknem */
    ) 0;
  }

  /* Karta jest węższa niż kolumna (486 wobec 584) i stoi przy jej lewej
     krawędzi — nadmiar po prawej wypełnia wystająca plakietka. Nie musi się
     równać z siatką 1200 px, tak jest w UI Designie. */
  .k-guarantee {
    /* Przy 1440 px wychodzi 486 px z makiety. Poniżej ~1330 px kolumna jest
       węższa niż 486 + wysięgnik plakietki, więc karta ustępuje jej miejsca
       zamiast pozwolić, żeby koło zostało ucięte na krawędzi treści. */
    max-width: min(
      var(--k-guarantee-desktop),
      calc(100% - var(--k-guarantee-badge-bleed) - var(--k-space-4))
    );
    padding: var(--k-space-8);
  }

  /* W tej kolumnie karta jest wąska, więc lista wraca do jednej kolumny
     (nadpisuje siatkę 2-kolumnową z bloku wyżej). */
  .k-guarantee__list {
    grid-template-columns: 1fr;
    gap: var(--k-space-6);
  }

  /* Plakietka rośnie z 92 do 114 px (214:22274) — jedno pokrętło skali
     z components.css. Środek koła stoi 13 px na lewo od prawej krawędzi
     karty, co przy średnicy 114 daje offset −44. */
  .k-guarantee__badge {
    --k-badge-lg-scale: 1.24;
    top: -32px;
    right: calc(-1 * var(--k-guarantee-badge-bleed));
  }

  /* Pusty region statusu wychodzi z układu, zamiast rezerwować wiersz siatki
     wraz z odstępem — to te 48 px, przez które od przycisku „Wyślij" do
     granicy sekcji robiło się 128 px zamiast 80.

     `position: absolute`, a NIE `display: none`: to region aria-live.
     Czytniki ekranu ogłaszają zmianę wiarygodnie tylko wtedy, gdy region
     istniał w drzewie dostępności przed wstawieniem tekstu, a element
     przełączany z display: none bywa pomijany. Tu akapit zostaje w drzewie,
     tylko przestaje zajmować miejsce; gdy form.js wstawi komunikat, :empty
     przestaje pasować i akapit wraca do siatki.

     Koszt jest świadomy: min-height rezerwowało miejsce, żeby komunikat nie
     przesuwał treści. Teraz przesunie — raz, po wysyłce, gdy strona i tak
     się zmienia. Wcześniej psuł rytm przy każdym wyświetleniu. */
  .k-form__status:empty {
    position: absolute;
    min-height: 0;
  }
}
