/* ============================================================
   KWFoto.pl — PODSTRONA OFERTY ŚLUBNEJ
   ============================================================
   Ten arkusz obowiązuje TYLKO w tym podfolderze. Fundamenty (paleta, kroje,
   `.wrap`, `.label`, `.reveal`, `.clip-reveal`, nagłówek, stopka, FAQ,
   sekcja kontaktu, przyciski `.ig-btn`) przychodzą z `../style.css`, który
   ładuje się PRZED tym plikiem i którego przy pracy nad ofertą NIE RUSZAMY.

   Tutaj siedzi wyłącznie to, czego na stronie głównej nie ma:
   okładka, sekcje oferty z fakturą papieru, pakiety, zakres, przebieg,
   kalkulator wyceny i pasek postępu na dole.

   Zasady, które przenoszą się z całego projektu:
   • półpauza „–", nigdy długa pauza;
   • zero poziomego przewijania — sprawdzane na 360, 375 i 1280 px;
   • stan oznaczamy obrysem albo tłem, nigdy samym `opacity` (przygaszony
     tekst zjeżdża wtedy pod próg kontrastu WCAG AA);
   • wszystko musi być czytelne przy `prefers-reduced-motion`.
   ============================================================ */

/* ============================================================
   OKŁADKA — wstęp na cały ekran
   ============================================================
   Bez okienek ze zdjęciami: kadr w tle jest tylko głębią, a treść to marka,
   tytuł i jedno zdanie w cienkiej złotej ramie, jak wytłoczenie na płótnie.
   ------------------------------------------------------------ */
.of-hero {
  position: relative;
  min-height: 62vh;
  display: flex; align-items: center; justify-content: center;
  text-align: center;
  overflow: hidden;
  padding: clamp(6rem, 14vh, 9rem) clamp(1.4rem, 5vw, 4rem) clamp(3rem, 8vh, 5rem);
}
.of-hero-bg { position: absolute; inset: 0; z-index: 0; }
.of-hero-bg img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 42%;
  filter: saturate(0.9) contrast(0.97) brightness(0.72);
}
.of-hero-shade {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background:
    linear-gradient(to bottom, rgba(10, 12, 13, 0.72) 0%, rgba(10, 12, 13, 0.34) 42%, var(--bg) 100%),
    radial-gradient(75% 62% at 50% 50%, rgba(6, 7, 8, 0) 0%, rgba(6, 7, 8, 0.5) 100%);
}
.of-hero-in { position: relative; z-index: 2; max-width: 44rem; }
.of-hero h1 {
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  font-weight: 400; letter-spacing: 0.04em; line-height: 1.3;
  margin: 0.5rem 0 1.2rem;
  color: #f6f2e8;
  text-shadow: 0 2px 14px rgba(0, 0, 0, 0.8);
}

/* ------------------------------------------------------------
   MOZAIKA ZDJĘĆ — szuflada z kadrami przy lewej krawędzi
   ------------------------------------------------------------
   Pas przewija się razem ze stroną (`position: absolute`, rozpięty od góry do
   dołu <body>), a treść jedzie obok — dlatego <body> dostaje wcięcie o jego
   szerokość.

   DWA STANY: zwinięty to jedna kolumna kadrów (`--pas-min`), rozsunięty —
   cztery (`--pas` w `body.szuflada-otwarta`). Rozsuwa go złota strzałka
   (`.mozaika-uchwyt`). Przy rozsuwaniu treść (<main>) ustępuje jej miejsca
   marginesem, żeby oferta nie chowała się pod kolażem — wszystko na jednej
   krzywej `--plynnie`, więc ruch czyta się jak jeden gest.

   Kafelki mają PROPORCJE SWOICH ZDJĘĆ — pion zostaje pionem, poziom poziomem.
   Kolumny układa `oferta.js` metodą murarską (kolejny kadr idzie do najkrótszej
   kolumny), więc pas jest wypełniony bez dziur, a rytm nieregularny.

   TRZY WARSTWY, każda z innego powodu:
   1. `.mozaika`      — pudełko na całą wysokość strony, BEZ przycinania;
   2. `.mozaika-klip` — to ono przycina (`overflow: hidden`), żeby kolumny
      mogły płynąć poza swój zakres i nie wystawały ani nad stronę, ani pod
      stopkę (a przy okazji nie rozciągały obszaru przewijania);
   3. `.mozaika-lupa` — powiększony kadr; stoi POZA warstwą przycinającą, bo
      ma się kłaść na treści, i pokazuje OSTRE zdjęcie z `img/`, a nie
      rozciągnięty kafelek z `img/mini/`.
   ------------------------------------------------------------ */
body.oferta {
  /* DWIE szerokości, bo pas ma dwa stany:
     --pas-min  zwinięty (jedna kolumna) — tyle miejsca rezerwuje treść;
     --pas      bieżący; po rozsunięciu rośnie i treść ustępuje mu miejsca,
                żeby oferta nie chowała się za szufladą.
     --plynnie  wspólna krzywa i czas dla wszystkiego, co się przy tym rusza:
                szuflady, uchwytu, złotej linii i marginesu treści. Długa
                i miękka (bez odbicia), bo ruch ma być ledwie zauważalny. */
  /* ⚠️ FUNDAMENTEM JEST SZEROKOŚĆ KOLUMNY, nie szerokość pasa.
     Kolumny mają STAŁĄ szerokość, a szuflada je ODSŁANIA, zamiast dzielić
     między nie ten sam pas. Dzięki temu przy rozsuwaniu kadr nie zmienia
     rozmiaru ani o piksel — po prostu zza krawędzi wyjeżdżają kolejne trzy
     kolumny. Wcześniej cztery kolumny dzieliły się szerokością pasa, więc
     w chwili kliknięcia kafelek malał z 86 px do 19 px i przez całą sekundę
     rósł z powrotem; to było właśnie to „dziwne" przy rozsuwaniu.
     8 px to podwójne wcięcie warstwy przycinającej, 3 × 4 px to odstępy. */
  /* ⚠️ Dolna granica 72 px nie jest kosmetyką. Przy czystym `5.6vw` w oknie
     900 px kolumna schodziła do 50 px: kadry robiły się znaczkami, a że pas
     sięga całej strony, mieściło się ich w kolumnie o połowę więcej — czyli
     więcej elementów po to, żeby wyglądało gorzej. Górna granica trzyma pas
     w ryzach na monitorze 27". */
  --kol: clamp(72px, 5.6vw, 104px);
  --pas-min: calc(var(--kol) + 8px);
  --pas: var(--pas-min);
  --plynnie: 1.05s cubic-bezier(0.22, 1, 0.32, 1);
  position: relative;                 /* punkt odniesienia dla pasa */
  padding-left: var(--pas-min);
}
/* ⚠️ TRZY KOLUMNY (od 2026-08-24; wcześniej cztery). Rachunek szerokości:
   trzy kolumny + dwie szczeliny po 4 px + 4 px wyściółki z każdej strony
   `.mozaika-klip` = `--kol * 3 + 16`. Przy czterech było `* 4 + 20`.
   Liczba kolumn stoi też w `KOLUMN` w `oferta.js` — te dwie wartości muszą
   się zgadzać, bo arkusz rezerwuje miejsce, a skrypt buduje kolumny. */
body.oferta.szuflada-otwarta { --pas: calc(var(--kol) * 3 + 16px); }

/* Treść ustępuje rozsuniętej szufladzie — inaczej lewa krawędź kart pakietów
   i kalkulatora chowałaby się pod kolażem. Przesuwamy JEDEN element (<main>),
   więc przy zamykaniu wszystko wraca dokładnie tam, gdzie było. */
body.oferta main {
  padding-left: calc(var(--pas) - var(--pas-min));
  transition: padding-left var(--plynnie);
}

/* ⚠️ NAGŁÓWEK IDZIE PRZEZ CAŁĄ SZEROKOŚĆ.
   Wcześniej zaczynał się dopiero za pasem kadrów (`left: var(--pas-min)`),
   więc lewy skrawek strony zostawał bez paska, a logo stało w dziwnym miejscu.
   Teraz pasek jest jedną belką od krawędzi do krawędzi, a mozaika przewija się
   pod nim — nagłówek ma `z-index: 120`, pas 60, więc kolejność jest właściwa
   bez żadnej dodatkowej reguły.

   ⚠️ CHOWA SIĘ PRZY PRZEWIJANIU W DÓŁ — tak samo jak na stronie głównej
   (klasę `head-hidden` dokłada wspólny `script.js`). Do 2026-08-24 podstrona
   tę klasę unieważniała, żeby menu stało zawsze pod ręką; oddaliśmy ekran
   treści, bo sekcje mają się mieścić w całości. Belka wraca przy pierwszym
   ruchu w górę, więc droga do reszty serwisu jest jeden gest stąd.
   ⚠️ Sekcje dostają `scroll-margin-top` w bloku „ODDECH SEKCJI" niżej —
   inaczej skok w górę wsuwałby początek sekcji pod wracającą belkę. */
body.oferta .site-head { left: 0; }

/* pasek postępu trzyma się szerokości ZWINIĘTEJ — inaczej podskakiwałby
   przy każdym rozsunięciu szuflady */
body.oferta .pasek { left: var(--pas-min); }

.mozaika {
  position: absolute; left: 0; top: 0; bottom: 0;
  z-index: 60;                        /* nad treścią, pod nagłówkiem (120) */
  width: var(--pas);
  /* DELIKATNIE PRZEZROCZYSTA już w stanie zwiniętym: przez szczeliny między
     kadrami prześwituje film, a rozmycie trzyma to w ryzach, żeby prześwit
     nie robił się nerwowy. */
  background: rgba(7, 9, 10, 0.62);
  backdrop-filter: blur(14px) saturate(1.04);
  -webkit-backdrop-filter: blur(14px) saturate(1.04);
  border-right: 1px solid rgba(200, 176, 138, 0.18);
  transition:
    width var(--plynnie),
    background var(--plynnie),
    backdrop-filter var(--plynnie),
    box-shadow var(--plynnie);
}
/* ROZSUNIĘTA SZUFLADA: tło robi się szybą — przyciemnia i rozmywa to, co pod
   nią zostało (film i treść), a cień od prawej krawędzi odkleja ją od strony.
   Stąd wrażenie, że kolaż unosi się nad stroną. */
body.szuflada-otwarta .mozaika {
  background: rgba(7, 9, 10, 0.44);
  backdrop-filter: blur(22px) saturate(1.06);
  -webkit-backdrop-filter: blur(22px) saturate(1.06);
  box-shadow: 26px 0 60px rgba(0, 0, 0, 0.5);
}

/* ZŁOTA STRZAŁKA — uchwyt szuflady. Siedzi na krawędzi pasa, w połowie
   wysokości okna, i obraca się o 180° po rozsunięciu. */
.mozaika-uchwyt {
  position: fixed; top: 50%;
  left: calc(var(--pas) - 15px);
  z-index: 66;                        /* nad linią (65), pod nagłówkiem (120) */
  width: 30px; height: 30px;
  display: grid; place-items: center;
  margin: 0; padding: 0;
  transform: translateY(-50%);
  border: 1px solid rgba(200, 176, 138, 0.55);
  border-radius: 50%;
  background: rgba(10, 12, 13, 0.92);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.55);
  transition: left var(--plynnie), border-color 0.4s, background 0.4s;
}
.mozaika-uchwyt svg {
  width: 9px; height: 15px;
  fill: none; stroke: var(--gold); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform var(--plynnie);
}
.mozaika-uchwyt:hover { border-color: var(--gold); background: rgba(20, 17, 12, 0.95); }
body.szuflada-otwarta .mozaika-uchwyt svg { transform: rotate(180deg); }
.mozaika-klip {
  position: absolute; inset: 0;
  overflow: hidden;
  display: flex; gap: 4px;
  padding: 4px;
}
/* ⚠️ KOLUMNA NIC NIE ROBI POZA TRZYMANIEM SZEROKOŚCI. Był tu wcześniej dryf
   (`transform: translate3d(0, var(--dryf), 0)`) i perspektywa pod wygięcie
   pasa — jedno i drugie cofnięte na życzenie. Pas ma stać spokojnie
   i przewijać się razem ze stroną. */
.mozaika-kol {
  /* STAŁA szerokość — patrz komentarz przy `--kol` na górze pliku */
  flex: 0 0 var(--kol); min-width: 0;
  display: flex; flex-direction: column; gap: 4px;
}
/* ⚠️ KOLAŻ: KAŻDY KADR W SWOJEJ PROPORCJI (2026-08-24).
   Wcześniej stało tu sztywne `aspect-ratio: 4 / 5` — wszystkie kafelki miały
   ten sam pionowy format i pas wyglądał jak siatka, a nie jak rozłożone
   odbitki. Teraz proporcję każdego kadru wpisuje skrypt w `--ar` (zmierzoną
   z prawdziwego pliku, `proporcje` w bloku 2 `oferta.js`), a `4 / 5` zostaje
   tylko jako wartość zapasowa na czas przed pomiarem.

   ⚠️ WYSOKOŚĆ NADAL WYNIKA Z SZEROKOŚCI, a nie jest wpisywana w pikselach —
   i to zostaje. Rozwiązuje najbrzydszą rzecz w starej wersji: przy rozsuwaniu
   szuflady kafelki z wpisaną wysokością robiły się płaskimi pasami, żeby
   na końcu podskoczyć do nowego układu. Kafelek rośnie w proporcji przez całą
   animację i nic nie przeskakuje. */
.mozaika-kafel {
  position: relative; flex: none;
  aspect-ratio: var(--ar, 4 / 5);
  overflow: hidden;
  /* wyraźnie zaokrąglone rogi — kadry mają czytać się jak osobne odbitki
     ułożone obok siebie, a nie jak jedna pocięta płachta */
  border-radius: 10px;
  background: #101315;
}
.mozaika-kafel img {
  display: block; width: 100%; height: 100%;
  object-fit: cover;
  filter: saturate(0.88) brightness(0.7);
  transition: filter 0.6s var(--ease);
}
.mozaika-kafel.is-pod img { filter: saturate(1) brightness(0.95); }

/* SEDNO EFEKTU — kadr pod kursorem wypływa na treść.
   Przejście obejmuje też `left/top/width/height`, więc przy przesuwaniu kursora
   po pasie powiększenie PŁYNIE od kadru do kadru zamiast przeskakiwać.
   Zaczep (`--zaczep`) ustawia skrypt: przy lewej krawędzi kadr rośnie w prawo. */
.mozaika-lupa {
  position: absolute; z-index: 70; margin: 0;
  overflow: hidden;
  border-radius: 4px;
  opacity: 0;
  transform: scale(0.92);
  transform-origin: var(--zaczep, center);
  pointer-events: none;               /* nie odbiera najazdu kafelkom pod spodem */
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.75), 0 0 0 1px rgba(200, 176, 138, 0.5);
  transition:
    opacity 0.5s var(--ease), transform 0.65s var(--ease),
    left 0.55s var(--ease), top 0.55s var(--ease),
    width 0.55s var(--ease), height 0.55s var(--ease);
}
.mozaika-lupa.is-on { opacity: 1; transform: scale(1); }
.mozaika-lupa img { display: block; width: 100%; height: 100%; object-fit: cover; }

/* ZŁOTA LINIA między pasem kadrów a treścią.
   Przyklejona do okna, więc towarzyszy całej stronie, i WYPEŁNIA SIĘ OD DOŁU
   w miarę przewijania — przy okazji jest dyskretnym wskaźnikiem postępu.
   Robi to gradient sterowany zmienną `--postep` (0–1) z oferta.js: poniżej
   progu złoto, powyżej ledwie widoczny ślad, a styk rozmyty o kilka procent,
   żeby granica nie ciachała. */
.mozaika-linia {
  position: fixed; top: 0; bottom: 0;
  left: calc(var(--pas) - 1px);
  transition: left var(--plynnie);
  width: 2px;
  z-index: 65;                        /* nad pasem (60), pod nagłówkiem (120) */
  pointer-events: none;
  background:
    linear-gradient(to top,
      rgba(200, 176, 138, 0.85) 0%,
      rgba(200, 176, 138, 0.85) calc(var(--postep, 0) * 100%),
      rgba(200, 176, 138, 0.1) calc(var(--postep, 0) * 100% + 4%),
      rgba(200, 176, 138, 0.1) 100%);
  box-shadow: 0 0 10px rgba(200, 176, 138, 0.25);
}

/* ------------------------------------------------------------
   FILM — nieruchome tło całej strony
   ------------------------------------------------------------
   Film STOI W MIEJSCU (`position: fixed`), a strona jedzie po nim jak szyby
   nasuwane jedna na drugą: każda kolejna sekcja jest ciemniejsza i mocniej
   rozmywa to, co pod nią (patrz „SEKCJE OFERTY" niżej).

   ⚠️ Kadr jest PANORAMĄ na cały ekran — `object-fit: cover` przycina go do
   proporcji okna, a winieta u góry i u dołu wyprowadza obraz w ciemność,
   żeby nie kończył się twardą krawędzią pod nagłówkiem i nad stopką.
   ------------------------------------------------------------ */
/* ⚠️ PLAKAT JEST TŁEM RAMKI, nie atrybutem `poster` na wideo. Dzięki temu
   telefon — który filmu nie pobiera — dostaje tę samą rolkę co komputer:
   przeciągnięcie zmienia plakat i kartę pary, a odnośniki do galerii działają
   tak samo. Ścieżkę wpisuje `oferta.js` przy każdej zmianie reportażu. */
/* ⚠️ `background-color`, NIE SKRÓT `background` — i to nie jest drobiazg
   stylistyczny, tylko naprawa błędu z 2026-08-26. Stało tu:

       background-size: cover;
       background-position: 50% 45%;
       background: #07090a;          ← SKRÓT, i to PO tamtych dwóch

   `background` jest SKRÓTEM: ustawia wszystkie własności tła naraz, a te,
   których nie wymieniono, cofa do wartości początkowych. Kolor zapisany
   po `background-size` kasował więc `cover` (→ `auto`) i `50% 45%` (→ `0% 0%`),
   a przy okazji przywracał `repeat`. Zdjęcie leżało w naturalnym rozmiarze,
   przyklejone do lewego górnego rogu i KAFELKOWANE.
   Nie było tego widać, dopóki na wierzchu leciał film z `object-fit: cover` —
   błąd wyszedł dopiero po wyłączeniu filmu, gdy plakat stał się tym, co widać.
   Zmierzone przed poprawką: `background-size: auto`,
   `background-position: 0% 0%`, `background-repeat: repeat`.

   To ta sama pułapka, co przy `transition` w kartach pakietów (§7.17
   w `NOWY-WATEK.md`): SKRÓT WYMAZUJE TO, CZEGO NIE WYMIENIA. */
.film-tlo {
  position: fixed; inset: 0;
  z-index: 0;                         /* pod całą treścią */
  background-color: #07090a;
  background-size: cover;
  background-position: 50% 45%;
  background-repeat: no-repeat;
  overflow: hidden;
}
.film-tlo-v {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 45%;
}
/* WINIETA: ciemniej u góry i u dołu plus lekkie ściemnienie rogów. Bez tego
   biały tytuł potrafi wpaść na jasną klatkę i zniknąć. */
/* DWA ELEMENTY WIDEO leżą na sobie i przenikają się przy zmianie reportażu.
   Ten pod spodem jest przezroczysty, więc widać przez niego plakat — i to on
   łapie moment, zanim kolejny film będzie gotowy. */
.film-tlo-v {
  opacity: 0;
  transition: opacity 0.9s var(--ease);
}
.film-tlo-v.is-on { opacity: 1; }

/* ============================================================
   ROLKA JEDZIE ZA PALCEM (2026-09-02)
   ============================================================
   Przewracanie reportaży gestem działało od dawna, ale było PROGOWE: palec
   sunął po nieruchomej okładce i po 60 px reportaż przeskakiwał. Nic nie
   pokazywało, że gest jest zauważany ani ile jeszcze brakuje — a to jedyny
   sygnał, po którym poznaje się, że okładkę w ogóle da się przewracać.
   Dziś kadr idzie dokładnie za palcem i gaśnie w miarę odsuwania, a po
   puszczeniu albo wyjeżdża z ekranu (kolejny reportaż), albo wraca na
   miejsce. Ten sam mechanizm, te same progi i te same czasy co w obu
   podglądach kadru i w galerii aktu — cztery miejsca w serwisie, w których
   przesuwa się palcem, mają reagować identycznie.

   ⚠️ CO SIĘ RUSZA, ZALEŻY OD EKRANU — i dlatego reguła obejmuje OBA
   elementy naraz. Na komputerze reportażem jest tło na cały ekran
   (`.film-tlo`), na telefonie tło jest schowane (`display: none`)
   i reportażem jest kafelek (`.rolka`). Element, którego w danym układzie
   nie widać, nic nie kosztuje.
   ⚠️ WINIETA I ZASŁONA JADĄ W PRZECIWNĄ STRONĘ. Obie leżą WEWNĄTRZ
   `.film-tlo`, ale należą do okna, nie do zdjęcia: winieta ma trzymać
   biały tytuł na czytelnym tle, a zasłona odpowiada za ciemnienie przy
   przewijaniu. Bez cofnięcia przejechałyby razem z kadrem i tytuł na
   moment straciłby swoje tło.
   ⚠️ `transform`, NIE `translate` — osobną właściwość `translate` zajmuje
   już przesuwanie kafelka po zdjęciu („KAFELEK DA SIĘ PRZESUNĄĆ"
   w `oferta.js`), a dwie rzeczy nie mogą pisać po jednej właściwości
   (pułapka §7.17). Obie składają się bez kolizji.
   ⚠️ PRZEJŚCIE TYLKO NA CZAS DOJECHANIA — założone na stałe dokładałoby
   opóźnienie między palcem a kadrem, a to czyta się jak zacinanie.
   Czasy (190/240 ms w `oferta.js`) muszą się mieścić w 0,24 s.
   ============================================================ */
/* 🔴 TŁO JEST OSOBNĄ WARSTWĄ I JEDZIE INACZEJ NIŻ KAFELEK (2026-09-03).
   Zgłoszenie: „hero dziwnie przeskakuje, robi animację jakby urywał zdjęcie".
   I dokładnie tak było: `.film-tlo` przesuwało się o **55% szerokości okna**,
   a jest wielkości DOKŁADNIE jednego ekranu — więc z drugiej strony
   odsłaniało goły, ciemny kadr strony. Zamiast przesunięcia widać było
   urwaną krawędź zdjęcia.

   Dziś zdjęcie leży na własnej warstwie (`::before`), która ma 8% ZAPASU
   poza kadrem (`scale(1.08)`) i przesuwa się tylko o UŁAMEK drogi kafelka.
   Rachunek jest zamknięty: zapas na stronę to 4% szerokości, a maksymalny
   ruch to 0,55 × 0,07 ≈ **3,85%** — czyli mniej niż zapas i krawędź nie ma
   prawa się pokazać. Tło daje delikatny ruch w tle (paralaksa), kafelek
   jedzie całą drogę, a razem czyta się to jak głębia, nie jak urwanie.

   ⚠️ ZDJĘCIE WPISUJE `oferta.js` W ZMIENNĄ `--tlo-obraz`, nie w
   `background-image` samego `.film-tlo` — inaczej nie dałoby się go ruszać
   niezależnie od warstwy.
   ⚠️ TO KASUJE DAWNE COFANIE WINIETY I ZASŁONY. Skoro `.film-tlo` już się
   nie rusza, jego dzieci nie mają czego nadrabiać — a odejmowanie ruchu
   od ruchu było najkruchszą częścią tamtej wersji.
   ⚠️ `scale` NIE ZMIENIA KADROWANIA w sposób, który by szkodził: tło i tak
   jest `cover` i było przycinane; 8% to zapas, nie przybliżenie treści. */
.film-tlo::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--tlo-obraz, none);
  background-size: cover;
  background-position: 50% 45%;
  background-repeat: no-repeat;
  transform: translateX(calc(var(--rolka-przes, 0px) * 0.07)) scale(1.08);
  opacity: var(--rolka-kryc, 1);
}
/* Film w tle (dziś wyłączony) jedzie razem ze zdjęciem, nie osobno. */
.film-tlo-v { transform: translateX(calc(var(--rolka-przes, 0px) * 0.07)) scale(1.08); }

.rolka {
  transform: translateX(var(--rolka-przes, 0px));
  /* ⚠️ KRYCIE SPADA RAZEM Z ODSUNIĘCIEM: kadr nie tylko odjeżdża, ale
     i gaśnie. Bez tego wygląda, jakby zaciął się na krawędzi ekranu,
     a nie jakby z niego wychodził. */
  opacity: var(--rolka-kryc, 1);
}
html.rolka-ciagnie .film-tlo::before,
html.rolka-ciagnie .film-tlo-v,
html.rolka-ciagnie .rolka { transition: none; }
html.rolka-dojezdza .film-tlo::before,
html.rolka-dojezdza .film-tlo-v,
html.rolka-dojezdza .rolka {
  transition: transform 0.24s var(--ease), opacity 0.24s var(--ease);
}

.film-winieta {
  position: absolute; inset: 0; pointer-events: none;
  background:
    linear-gradient(to bottom,
      rgba(6, 7, 8, 0.82) 0%, rgba(6, 7, 8, 0.28) 22%,
      rgba(6, 7, 8, 0.18) 62%, rgba(6, 7, 8, 0.88) 100%),
    radial-gradient(84% 74% at 50% 46%, rgba(6, 7, 8, 0) 0%, rgba(6, 7, 8, 0.55) 100%);
}
/* ZASŁONA — narasta przy przewijaniu. Ciemność i rozmycie liczy oferta.js
   (`--ciemnosc`, `--rozmycie`), więc film gaśnie stopniowo, zamiast znikać
   pod pierwszą sekcją.
   ⚠️ Rozmycie robi `backdrop-filter` na JEDNEJ warstwie — gdyby `filter`
   siedział na samym wideo, przeglądarka rasteryzowałaby każdą klatkę osobno. */
.film-zaslona {
  position: absolute; inset: 0; pointer-events: none;
  background: rgba(6, 7, 8, var(--ciemnosc, 0));
  backdrop-filter: blur(var(--rozmycie, 0px));
  -webkit-backdrop-filter: blur(var(--rozmycie, 0px));
}

/* ------------------------------------------------------------
   DYM — stan wyjściowy
   ------------------------------------------------------------
   Wspólny arkusz daje dymowi krycie 0,8; tutaj startuje od zera i narasta
   dopiero od sekcji „Co dostajecie" — krycie wpisuje `oferta.js` (blok 5)
   wprost w element. Ta reguła istnieje po to, żeby przed pierwszą klatką
   skryptu dym nie mrugnął nad okładką.
   ⚠️ Bez `transition`: krycie zmienia się co klatkę przewijania, a przejście
   ciągnęłoby się za nim o pół sekundy.
   ------------------------------------------------------------ */
body.oferta #fog { opacity: 0; }

/* ------------------------------------------------------------
   OKŁADKA — sama treść na tle filmu
   ------------------------------------------------------------
   ⚠️ `svh`, nie `vh`: na telefonie pasek adresu chowa się przy przewijaniu
   i `100vh` byłoby wyższe niż widoczny kadr.
   Sekcja jest PRZEZROCZYSTA — kadr pod nią to `.film-tlo`.
   ------------------------------------------------------------ */
.of-hero.of-hero--okladka {
  position: relative;
  z-index: 1;
  height: 100svh;
  background: none;
  /* treść siada w PRAWYM dolnym rogu kadru: po lewej stoi szuflada z kadrami,
     więc tytuł i przycisk mają swój własny róg. `.of-hero` domyślnie centruje
     w obu osiach, więc nadpisujemy obie. */
  display: flex; align-items: flex-end; justify-content: flex-end;
  text-align: right;
  overflow: hidden;
  /* ⚠️ RUCH W BOK NALEŻY DO ROLKI, W PIÓN — DO PRZEGLĄDARKI (2026-09-02).
     Odkąd kadr jedzie za palcem, przeglądarka nie może zabierać ruchu
     poziomego na własne gesty (cofanie karty): przerywa go wtedy
     `pointercancel` w połowie drogi. `pan-y` oddaje jej przewijanie strony,
     a `pinch-zoom` zostawia szczypanie — powiększenie strony to ustawienie
     dostępności, a nie ozdobnik. */
  touch-action: pan-y pinch-zoom;
  /* ⚠️ Prawy margines jest CELOWO szerszy od lewego i od dolnego. Tekst
     wyrównany do prawej dotyka krawędzi każdą linijką — przy wcięciu równym
     reszcie strony wyglądał, jakby wypadał za kadr. Odsuwamy go na tyle,
     żeby najdłuższy wiersz tytułu miał pod sobą oddech, ale nie tak daleko,
     by wjechał na środek — stąd górny sufit 9rem. Zmierzone: 63 px przy oknie
     900 px, 90 px przy 1280 px, 134 px przy 1920 px. */
  padding: clamp(4.6rem, 9.5vh, 6rem)
           clamp(2rem, 7vw, 9rem)
           clamp(4.6rem, 10vh, 6.5rem)
           clamp(1.4rem, 4vw, 3.4rem);
}
.okladka {
  position: relative; z-index: 2;
  display: flex; flex-direction: column; align-items: flex-end;
  gap: clamp(0.5rem, 1.4vh, 0.95rem);
  max-width: 42rem;
  text-shadow: 0 2px 22px rgba(0, 0, 0, 0.65);
}
/* marka i „przewiń" mają wcięcie na rozstrzelone litery — przy wyrównaniu
   do prawej trzeba je przenieść na drugą stronę, inaczej napis odstaje */
.okladka-marka { padding-left: 0; padding-right: 0.5em; }
.okladka-cta { margin-top: clamp(0.4rem, 1.4vh, 0.9rem); }
.okladka-marka {
  font-family: var(--nav);
  font-size: 0.7rem; letter-spacing: 0.5em; text-transform: uppercase;
  color: var(--gold);
  padding-left: 0.5em;
}
.okladka-kreska { display: block; width: 3.2rem; height: 1px; background: rgba(200, 176, 138, 0.5); }
.okladka .label { margin: 0; }
.okladka-h {
  font-family: var(--serif); font-weight: 400;
  font-size: clamp(1.7rem, 3.6vw, 2.9rem);
  line-height: 1.22; letter-spacing: 0.02em;
  color: #f6f2e8;
  text-shadow: 0 2px 18px rgba(0, 0, 0, 0.8);
}
.okladka-p {
  color: rgba(240, 236, 226, 0.9);
  font-size: clamp(0.88rem, 1.2vw, 1rem);
  max-width: 30rem;
  text-shadow: 0 1px 10px rgba(0, 0, 0, 0.8);
}

/* ------------------------------------------------------------
   ROLKA REPORTAŻY — karta pary na okładce
   ------------------------------------------------------------
   Do trzech filmów jeden po drugim; przy każdym wachlarz kadrów z sesji tej
   pary, imiona, data, miejsce i odnośnik do pełnej galerii. Pod spodem kropki
   ze strzałkami — jak w mediach społecznościowych.

   ⚠️ Karta stoi w LEWYM DOLNYM ROGU okładki, a tytuł w prawym. To nie kwestia
   gustu: mozaika zajmuje lewą krawędź, tytuł prawą, a między nimi zostaje pas,
   w którym karta nikomu nie wchodzi w drogę. Wskaźnik „przewiń w dół" siedzi
   pośrodku i też ma spokój.

   ⚠️ Kropki i strzałki chowa SKRYPT (atrybut `hidden`), gdy dostępny jest tylko
   jeden reportaż — nie ma wtedy czego przełączać.
   ------------------------------------------------------------ */
/* ⚠️ KARTA UROSŁA (2026-08-26, druga tura). Odkąd w tle nie leci film, tylko
   `plakat.webp`, okładka jest ZDJĘCIEM Z WEJŚCIEM DO REPORTAŻU — a wejście
   ma być widać. Karta ma teraz do 23 rem zamiast 18,5, wachlarz do 13,5 rem
   zamiast 11, a odbitki do 6,8 rem zamiast 5,4.
   ⚠️ Rosnąc, karta musi zmieścić wachlarz: rozstaw odbitek stoi w tablicy
   `UKLAD` w `oferta.js` (blok 3) W PIKSELACH i został podniesiony razem z nią.
   Zmieniając rozmiar tutaj, przelicz tamto — inaczej odbitki albo zlepią się
   w stos, albo wyjdą poza kartę. */
.rolka {
  position: absolute;
  /* Podstawowe położenie — obowiązuje do 1200 px. Odsunięcie kafelka
     od krawędzi robi dopiero szeroki ekran (blok „OD 1201 px" niżej). */
  left: clamp(1.2rem, 3vw, 2.6rem);
  bottom: clamp(4.6rem, 10vh, 6.5rem);
  z-index: 3;
  width: clamp(16.5rem, 26vw, 23rem);
  text-align: left;
  /* ⚠️ `translate`, NIE `transform` — kafelek da się przesunąć po zdjęciu
     (`oferta.js`, blok „KAFELEK DA SIĘ PRZESUNĄĆ"), a osobna właściwość nie
     wejdzie w drogę niczemu, co ktoś kiedyś dołoży przez `transform`
     (pułapka 17). Przejście działa przy PUSZCZENIU i przy zmianie okna;
     w trakcie ciągnięcia musi zniknąć, bo kafelek ma iść za palcem
     jeden do jednego, a nie doganiać go z opóźnieniem. */
  translate: var(--przes-x, 0px) var(--przes-y, 0px);
  transition: translate 0.45s var(--ease);
  /* ⚠️ `pointer`, NIE `grab`. Kafelek jest drugim wyjściem z okładki
     do galerii — klik jest tu główną akcją, a przesuwanie drobiazgiem.
     Otwarta dłoń w spoczynku mówiła „przeciągnij mnie" o elemencie, którego
     zadaniem jest „kliknij mnie": najgłośniejszy sygnał dostawała najmniej
     ważna funkcja. Że kafelek da się chwycić, mówi teraz uchwyt w rogu
     (`.rolka-karta::after`), a `grabbing` wraca na czas ciągnięcia. */
  cursor: pointer;
  /* ⚠️ ZAZNACZANIE TEKSTU WYŁĄCZONE NA STAŁE, NIE DOPIERO PRZY CIĄGNIĘCIU.
     Przeciągnięcie kafelka po imionach pary zostawiało za sobą niebieską
     plamę zaznaczenia. Kusi, żeby wyłączyć to klasą `.ciagniemy`, ale jest
     na to za późno: przeglądarka zaczyna zaznaczać od PIERWSZEGO piksela
     ruchu, a klasa wchodzi dopiero po progu 6 px — i dopisane wtedy
     `user-select: none` NIE KASUJE zaznaczenia, które już powstało.
     Kosztem jest niemożność zaznaczenia myszą imion i daty na komputerze;
     kafelek jest jednym wielkim odnośnikiem, więc to zachowanie kontrolki,
     nie akapitu. Na telefonie reguła wraca do `auto` (blok responsywności). */
  user-select: none;
  -webkit-user-select: none;
}
.rolka.ciagniemy { transition: none; cursor: grabbing; }
.rolka:focus-visible { outline: 1px solid var(--gold); outline-offset: 12px; }

/* ---- ZDJĘCIE W KAFELKU — NA KAŻDYM EKRANIE (2026-08-26) ----
   Do tej pory to „okno" istniało wyłącznie na telefonie, bo na komputerze
   reportaż był tłem całej strony. Dziś tłem jest zdjęcie, a kafelek jest
   miniaturą galerii — i ma być duży na każdym ekranie, nie tylko w telefonie.
   ⚠️ Proporcja 3:2 pod ZDJĘCIE. Wracając z filmem, wróć do 16/9 — inaczej
   wideo dostanie czarne pasy albo zostanie przycięte.
   ⚠️ To ten sam plik, który leży w tle strony (`plakat.webp`), więc druga
   warstwa nie kosztuje ani jednego żądania. */
/* ---- KILKA ZDJĘĆ W KAFELKU ----
   Duże zdjęcie plus pasek kadrów — miniatura galerii ma pokazywać, że za
   kliknięciem stoi WIĘCEJ NIŻ JEDEN kadr.

   ⚠️ SIATKA, NIE WACHLARZ. Poprzednik — pięć odbitek rzuconych jedna
   na drugą — stał na `position: absolute`, więc nie zgłaszał rodzicowi swojej
   wysokości: pudełko miało 160 px, odbitki rozkładały się na 205 i wchodziły
   11 px w imiona pary. Siatka zajmuje dokładnie tyle, ile zajmuje;
   nachodzenie przestaje być możliwe z definicji.

   ⚠️ CAŁY BLOK WYCHODZI POZA WYŚCIÓŁKĘ KARTY — ujemne marginesy równe
   `--karta-pad`. Kafelek ma być miniaturą, a każdy piksel oddany na margines
   to piksel zabrany zdjęciom. Marginesy MUSZĄ równać się wyściółce, stąd jedna
   zmienna zamiast dwóch osobnych `clamp`.

   ⚠️ Zaokrąglenie tylko u GÓRY i o piksel mniejsze niż karty — inaczej między
   rogiem zdjęcia a rogiem karty zostaje jasny sierp.

   ⚠️ Duże zdjęcie to `plakat.webp`, TEN SAM, który leży w tle strony —
   nie kosztuje ani jednego żądania. Płacimy tylko za kadry w pasku. */
.rolka-kadry {
  display: grid;
  gap: 4px;
  margin: calc(-1 * var(--karta-pad)) calc(-1 * var(--karta-pad)) var(--karta-pad);
  border-radius: 13px 13px 0 0;
  overflow: hidden;
}
.rolka-okno {
  position: relative;
  aspect-ratio: 3 / 2;
  background-color: #0b0d0e;
  background-size: cover;
  background-position: center;
}
.rolka-okno[hidden] { display: none; }

/* pasek kadrów — na komputerze trzy w rzędzie pod dużym zdjęciem */
.rolka-mini {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 4px;
}
.rolka-mini-kadr {
  aspect-ratio: 3 / 2;
  background-color: #0b0d0e;
  background-size: cover;
  background-position: center;
  transition: opacity 0.5s var(--ease);
}
/* najazd na kafelek rozjaśnia pasek — sygnał, że to jedna całość */
.rolka-mini-kadr { opacity: 0.78; }
.rolka-karta:hover .rolka-mini-kadr,
.rolka-karta:focus-within .rolka-mini-kadr { opacity: 1; }

.rolka-karta {
  --karta-pad: clamp(1rem, 1.8vw, 1.35rem);
  position: relative;                 /* punkt zaczepienia pola dotyku niżej */
  padding: var(--karta-pad);
  border: 1px solid rgba(200, 176, 138, 0.28);
  border-radius: 14px;
  background: rgba(8, 10, 11, 0.42);
  backdrop-filter: blur(14px) saturate(1.05);
  -webkit-backdrop-filter: blur(14px) saturate(1.05);
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.5);
  transition: border-color 0.45s var(--ease), box-shadow 0.45s var(--ease);
}
/* ---- CAŁA KARTA JEST KLIKALNA — TAKŻE NA KOMPUTERZE (2026-08-26) ----
   Wcześniej pole dotyku rozpychaliśmy tylko na telefonie. Odkąd okładka jest
   zdjęciem, a karta pary JEDYNYM wejściem do reportażu, ograniczanie kliknięcia
   do podkreślonego napisu było zwykłą przeszkodą.
   ⚠️ Nie przez zagnieżdżenie karty w drugim `<a>` — dwa odnośniki jeden
   w drugim to nieprawidłowy HTML. Zamiast tego ROZPYCHAMY POLE DOTYKU
   istniejącego odnośnika „Zobacz pełen reportaż" na całą kartę: w drzewie
   zostaje jeden link, z jedną nazwą, a kliknięcie łapie też imiona i datę.
   ⚠️ Napis zostaje widoczny — jest jedyną informacją, że karta gdzieś prowadzi.
   ⚠️ Przeciągnięcie rolki startuje teraz na linku, więc ZUŻYTY GEST GASI
   NAJBLIŻSZE KLIKNIĘCIE (`podepnijGest` w `oferta.js`) — bez tego przesunięcie
   myszą kończyłoby się otwarciem galerii. */
.rolka-cta::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
}
/* ---- UCHWYT: „ten kafelek da się chwycić" BEZ ANI JEDNEGO SŁOWA ----
   Sześć kropek w prawym dolnym rogu karty, wchodzą po najechaniu.

   ⚠️ TO ZNAK, NIE UCHWYT — `pointer-events: none`. Przeciąganie działa
   z KAŻDEGO punktu kafelka i tak ma zostać; gdyby kropki przejęły zdarzenia,
   zrobiłby się z nich jedyny punkt chwytu, a przy okazji dziura w polu
   kliknięcia rozpychanym przez `.rolka-cta::after`.

   ⚠️ PSEUDOELEMENT, NIE ELEMENT W DRZEWIE. Czytnik ekranu nie ma tu czego
   ogłaszać, a `::after` nie dokłada węzła, którego trzeba by pilnować
   przy przebudowie kafelka (`zbudujMini`).

   ⚠️ NIE DOKŁADA WYSOKOŚCI — leży `absolute` w wyściółce, która i tak tam
   jest. Kafelek ma nad zgięciem 93 px zapasu i nie ma z czego oddawać
   (pułapka 36 działa i w tę stronę: co nie jest w układzie, nic nie waży).

   ⚠️ Napisu tu celowo NIE MA. Instrukcja obsługi ozdoby stanęłaby obok
   „Zobacz pełen reportaż" i konkurowała z jedyną rzeczą, po którą ten
   kafelek na okładce stoi. */
.rolka-karta::after {
  content: "";
  position: absolute;
  right: calc(var(--karta-pad) - 3px);
  bottom: calc(var(--karta-pad) - 3px);
  width: 12px; height: 18px;
  /* ⚠️ KROPKI ŚWIECĄ, NIE SĄ TYLKO ZŁOTE (2026-08-28). Sam `--gold`
     przy kryciu 0,5 gubił się na jasnym zdjęciu pod spodem — kafelek
     leży przecież na fotografii, a nie na jednolitym tle. Złoto idzie
     więc pełną mocą, a pod spodem stoi druga, rozmyta warstwa tych samych
     kropek jako poświata (`drop-shadow`), która odkleja je od zdjęcia
     niezależnie od tego, co akurat jest w kadrze. */
  background-image: radial-gradient(circle at 1.5px 1.5px, var(--gold) 1.6px, transparent 1.8px);
  background-size: 6px 6px;
  filter: drop-shadow(0 0 4px rgba(200, 176, 138, 0.85))
          drop-shadow(0 1px 2px rgba(0, 0, 0, 0.7));
  opacity: 0;
  transition: opacity 0.35s var(--ease);
  pointer-events: none;
}
.rolka:hover .rolka-karta::after,
.rolka:focus-within .rolka-karta::after { opacity: 0.92; }
.rolka.ciagniemy .rolka-karta::after { opacity: 1; }

/* karta odpowiada na najazd tak jak każdy inny przycisk na tej stronie */
.rolka-karta:hover,
.rolka-karta:focus-within {
  border-color: rgba(200, 176, 138, 0.6);
  box-shadow: 0 26px 62px rgba(0, 0, 0, 0.58), 0 0 30px rgba(200, 176, 138, 0.16);
}

/* ⚠️ `.rolka-wachlarz` / `.rolka-kadr` USUNIĘTE 2026-08-26. Pięć odbitek
   rzuconych jedna na drugą wyglądało dobrze, ale: NACHODZIŁO NA IMIONA
   (pudełko 160 px, odbitki 205 px — 11 px zachodzenia), WAŻYŁO 5 MB
   (`kadr-1..5.webp` po ~1 MB) i dawało miniaturę galerii wielkości znaczka.
   Zastąpiło je jedno zdjęcie na całą szerokość kafelka (`.rolka-okno` wyżej),
   które nic nie kosztuje, bo leży już w tle strony. */

.rolka-para {
  display: flex; align-items: baseline; gap: 0.55rem;
  font-family: var(--serif);
  font-size: clamp(1.15rem, 1.8vw, 1.45rem);
  color: var(--ink); line-height: 1.25;
}
.rolka-nr {
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.2em; color: var(--gold);
  flex: none;
}
.rolka-meta {
  margin-top: 0.25rem;
  font-family: var(--nav);
  font-size: 0.58rem; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--ink-dim);
}
.rolka-cta {
  display: inline-flex; align-items: center; gap: 0.5rem;
  margin-top: clamp(0.6rem, 1.2vh, 0.9rem);
  color: var(--ink); text-decoration: none;
  font-family: var(--nav);
  font-size: 0.6rem; letter-spacing: 0.2em; text-transform: uppercase;
  border-bottom: 1px solid var(--gold);
  padding-bottom: 0.35rem;
  transition: color 0.35s;
}
.rolka-cta i { font-style: normal; color: var(--gold); transition: transform 0.5s var(--ease); }
.rolka-cta:hover { color: var(--gold); }
.rolka-cta:hover i { transform: translateX(5px); }

/* ---- kropki i strzałki: NA ŚRODKU KADRU ----
   ⚠️ Celowo NIE w karcie pary. Kropki przełączają cały ekran — film, plakat,
   kartę i odnośnik do galerii — więc gdyby siedziały w rogu przy karcie,
   wyglądałyby na jej część. Na środku czytają się jak sterowanie całością.
   Karta zostaje w lewym dolnym rogu, tytuł w prawym, sterowanie NA ŚRODKU
   U DOŁU — jak pod postem w mediach społecznościowych.
   ⚠️ Centrujemy MARGINESAMI, nie `translateX(-50%)`: wskaźnik „przewiń w dół"
   obok robi to samo i z tego samego powodu — te elementy bywają zerowane przez
   `body.loaded .rise { transform: none }`, a wtedy wyśrodkowanie transformem
   znika i element ucieka w prawo.
   ⚠️ Siedzi 5,6rem nad dolną krawędzią, czyli NAD wskaźnikiem „przewiń w dół"
   (ten stoi na 2,2rem). Dwie rzeczy w tym samym miejscu by się zjadły. */
.rolka-ster {
  position: absolute;
  left: 0; right: 0; margin: 0 auto;
  width: max-content;
  /* ⚠️ ODLEGŁOŚĆ LICZONA OD WSKAŹNIKA „przewiń w dół", nie od dna okna.
     Oba elementy są wyśrodkowane i stoją jeden nad drugim, więc mierzy się
     tu odstęp MIĘDZY NIMI, a nie dwie niezależne wartości. Wskaźnik zajmuje
     2,2 rem od dołu (jego `bottom`) plus ~3,4 rem własnej wysokości — to jego
     strefa; `clamp` niżej to czysta przerwa nad nią.
     Zmierzone przed poprawką: 23 px prześwitu, czyli kropki siedziały
     praktycznie na napisie. Po zmianie przy oknie 900 px: ~70 px. */
  bottom: calc(2.2rem + 3.4rem + clamp(2.2rem, 4.6vh, 3.4rem));
  z-index: 4;
  display: flex; align-items: center; justify-content: center;
  gap: 0.9rem;
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  background: rgba(8, 10, 11, 0.34);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.rolka-strzalka {
  width: 30px; height: 30px; padding: 0; flex: none;
  display: grid; place-items: center;
  border: 1px solid rgba(200, 176, 138, 0.45); border-radius: 50%;
  background: rgba(10, 12, 13, 0.7);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  transition: border-color 0.35s, background 0.35s;
}
.rolka-strzalka svg {
  width: 12px; height: 8px;
  fill: none; stroke: var(--gold); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.rolka-strzalka:hover { border-color: var(--gold); background: rgba(20, 17, 12, 0.9); }
/* ⚠️ WĄSKI KOMPUTER (861–1200 px): sterowanie WYJEŻDŻA NAD TYTUŁ.
   Zmierzone przy oknie 1000 px: tytuł zajmuje x 440–920, a wyśrodkowane
   sterowanie x 475–595 — czyli siedziałoby dosłownie na napisie. Wyżej niż
   1200 px tytuł zaczyna się dopiero na 849 px i problemu nie ma.
   Zwężenie tytułu nic by nie dało: żeby zwolnić środek, musiałby zejść do 19rem
   i łamać się na cztery wiersze. Lepiej podnieść pasek niż zepsuć nagłówek. */
@media (min-width: 861px) and (max-width: 1200px) {
  .rolka-ster { bottom: 50%; }
}
/* ============================================================
   STRZAŁKI PRZY KRAWĘDZIACH OKŁADKI (2026-09-03)
   ============================================================
   Ta sama rzecz co `.lb-arrow` na stronie głównej i `.pg-strz` w galerii
   reportażu: przyciskiem jest CAŁA krawędź kadru, a nie kółko przy brzegu.
   Trzy miejsca w serwisie, w których przewraca się zdjęcia, mają wyglądać
   i reagować identycznie.

   ⚠️ TYLKO OD 861 px. Na telefonie okładka jest kolumną (tytuł → kafelek →
   kropki), a pas na całą wysokość leżałby na kafelku i na przycisku
   pakietów, połykając ich stuknięcia. Tam przewraca się palcem.
   🔴 `z-index: 2` — POD KAFELKIEM (`.rolka` ma 3), a nie nad nim.
   Pierwsza wersja stała nad wszystkim i zmierzone wyszło, że przy 1280 px
   lewy pas zabierał **77 px szerokości karty pary** (x 118–195), a prawy
   **26 px przycisku „Wybierzcie swój pakiet"**. Obie strzałki KRADŁY WIĘC
   KLIKNIĘCIA elementom, które są głównymi drogami dalej — karta prowadzi
   do galerii, przycisk do pakietów. Pas leży teraz pod nimi: w miejscu
   nakładania wygrywa treść, a strzałce zostaje to, co i tak jest gołym
   zdjęciem.

   ⚠️ SZEWRON TRZYMA SIĘ KRAWĘDZI EKRANU, nie środka pasa (`justify-items`).
   Wyśrodkowany wpadał na kartę przy węższym oknie: karta zaczyna się
   ok. 107 px od brzegu przy 900 px szerokości, a środek pasa wypadał na
   116 px — czyli szewron chowałby się ZA kartą. Przy krawędzi jest zawsze
   widoczny, niezależnie od szerokości okna, i tam też szuka go oko.

   ⚠️ Pas kończy się nad sterowaniem i nad wskaźnikiem „przewiń w dół":
   `bottom` zostawia im miejsce, żeby strzałka nie przechwytywała kliknięć
   w kropki.
   ⚠️ Znak ma własny cień, bo leży na zdjęciu — na jasnym kadrze biały
   szewron bez cienia znika. Ta sama zasada co w obu galeriach.
   ============================================================ */
.hero-strz {
  position: absolute;
  top: var(--glowa, 66px);
  bottom: clamp(4.6rem, 10vh, 6.5rem);
  width: clamp(72px, 8vw, 120px);
  display: none;                     /* włącza dopiero próg komputera */
  place-items: center;
  padding: 0 clamp(10px, 1.4vw, 22px);
  border: 0;
  background: none;
  color: var(--ink);
  cursor: pointer;
  /* ⚠️ 1, NIE 2 — `.okladka` (tytuł i przycisk pakietów) ma DOKŁADNIE 2,
     a przy równym `z-index` wygrywa to, co stoi później w kodzie: pasy
     stoją po tytule, więc zabierały przyciskowi 13 px prawej krawędzi.
     Drabinka jest teraz jednoznaczna: karta 3 > tytuł 2 > pasy 1. */
  z-index: 1;
  transition: color 0.35s, background 0.35s;
}
.hero-strz[hidden] { display: none; }
.hero-strz--lewo { left: 0; justify-items: start; }
.hero-strz--prawo { right: 0; justify-items: end; }
.hero-chev { width: clamp(20px, 2.2vw, 28px); height: auto; overflow: visible; }
.hero-chev path {
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
  filter: drop-shadow(0 2px 10px rgba(0, 0, 0, 0.95));
}
/* 🔴 PASY DOPIERO OD 1201 px, NIE OD 861 (poprawione 2026-09-03).
   Zmierzone przy 900 px: pas zajmuje lewą krawędź, a kafelek zaczyna się
   107 px od brzegu — czyli DOKŁADNIE na szewronie. Odsunięcie kafelka
   w prawo rozwiązywało jedno i psuło drugie: kafelek wchodził wtedy
   **109 px na akapit pod tytułem** i zasłaniał początek zdania (przy
   1280 px odstęp wynosi 160 px, przy 900 px miejsca po prostu nie ma).
   Na wąskim komputerze zostają więc kropki ze strzałkami — dokładnie
   jak na telefonie — a pasy przy krawędziach wchodzą tam, gdzie okładka
   jest naprawdę szeroka. */
@media (min-width: 1201px) {
  .hero-strz:not([hidden]) { display: grid; }

  /* ⚠️ KAFELEK ODSUNIĘTY OD KRAWĘDZI — robi miejsce strzałce. Wcześniej
     zaczynał się ok. 42 px od brzegu, a pas ma przy 1280 px 102 px:
     kafelek zaczynał się w połowie strzałki i zasłaniał szewron.
     Zmierzone po zmianie: 26 px czystego odstępu przy 1280 px, 48 px przy
     1920 px, a do akapitu pod tytułem zostaje 160 px.
     ⚠️ Środkowy człon w `vw`, bo pas też jest `clamp`-em i musi rosnąć
     razem z nim. */
  .rolka { left: clamp(7rem, 10vw, 10.5rem); }
}
.hero-strz:hover, .hero-strz:focus-visible { color: var(--gold); }
/* winieta pod kursorem pokazuje, dokąd sięga pas — jak w podglądzie kadru */
.hero-strz--lewo:hover, .hero-strz--lewo:focus-visible {
  background: linear-gradient(to right, rgba(0, 0, 0, 0.4), transparent);
}
.hero-strz--prawo:hover, .hero-strz--prawo:focus-visible {
  background: linear-gradient(to left, rgba(0, 0, 0, 0.4), transparent);
}

/* ⚠️ MAŁE STRZAŁKI PRZY KROPKACH ZNIKAJĄ DOKŁADNIE TAM, GDZIE POJAWIAJĄ SIĘ
   PASY — czyli od 1201 px, a nie od 861. Dwa komplety strzałek robiące to
   samo to szum; ZERO kompletów to gorzej niż szum. Próg musi być ten sam
   co przy `.hero-strz`, inaczej w przedziale 861–1200 px nie byłoby żadnych. */
@media (min-width: 1201px) {
  .rolka-strzalka { display: none; }
}

/* ⚠️ ODSTĘP 1.25rem, NIE 0.55rem (2026-09-05): pole dotyku każdej kropki
   (`::before` niżej) ma 25 × 31 px, więc przy ciaśniejszym odstępie pola
   sąsiednich kropek nachodziły na siebie — Lighthouse zgłaszał „touch
   targets do not have sufficient size or spacing". Same kropki zostają
   po 7 px; rośnie tylko powietrze między nimi. */
.rolka-kropki { display: flex; align-items: center; gap: 1.25rem; }
.rolka-kropka {
  position: relative;
  width: 7px; height: 7px; padding: 0;
  border: 1px solid rgba(200, 176, 138, 0.6); border-radius: 50%;
  background: none;
  transition: background 0.3s, transform 0.3s var(--ease);
}
/* pole dotyku 25 × 31 px przy kropce 7 px — ten sam zabieg co w pasku postępu
   (2026-09-05: w poziomie −9px zamiast −7px, bo próg to 24 px w OBU osiach) */
.rolka-kropka::before { content: ""; position: absolute; inset: -12px -9px; }
.rolka-kropka.is-on { background: var(--gold); transform: scale(1.35); }

/* ============================================================
   SEKCJE OFERTY — faktura papieru
   ============================================================
   Jedyna rzecz, która została po porzuconej koncepcji „oferta jako album":
   PAPIER bez ani jednego pliku graficznego. Dwa gęste rastry włókien (pion
   i poziom) plus miękkie światło od górnej krawędzi — wszystko na bardzo
   niskim kryciu, ma się czytać jako papier, a nie jako deseń. Ziarno
   (`.grain` ze wspólnego arkusza) leży nad tym i dokłada resztę.

   Włos u góry sekcji zastępuje dawną krawędź kartki: sekcje czytają się jak
   kolejne arkusze, a nie jak jedna długa płaszczyzna.
   ------------------------------------------------------------ */
.of-sec {
  position: relative;
  z-index: 1;                         /* nad filmem (0) */
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.013) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.009) 0 1px, transparent 1px 4px),
    radial-gradient(120% 70% at 50% 0%, rgba(255, 255, 255, 0.035), transparent 62%),
    rgba(10, 12, 13, var(--krycie, 0.97));
  backdrop-filter: blur(var(--rozm, 0px));
  -webkit-backdrop-filter: blur(var(--rozm, 0px));
  box-shadow: inset 0 1px 0 rgba(200, 176, 138, 0.1);
}
/* co druga sekcja odrobinę jaśniejsza — rytm bez twardych linii */
.of-sec--alt {
  background:
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.014) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg, rgba(255, 255, 255, 0.01) 0 1px, transparent 1px 4px),
    radial-gradient(120% 70% at 50% 0%, rgba(255, 255, 255, 0.04), transparent 62%),
    rgba(15, 18, 20, var(--krycie, 0.97));
}
/* sekcja kontaktu ma własne zdjęcie w tle i zostaje nieprzezroczysta */
.outro { position: relative; z-index: 1; }
/* ------------------------------------------------------------
   ODDECH SEKCJI — jedna sekcja ma się mieścić w jednym ekranie
   ------------------------------------------------------------
   ⚠️ TO JEST GŁÓWNE POKRĘTŁO WYSOKOŚCI CAŁEJ OFERTY. Sekcje przewija się
   skokami (kropki paska, strzałki, odnośniki `#…`), więc każda, która jest
   wyższa od okna, ląduje obcięta — raz od dołu, raz od góry. Marginesy idą
   więc od WYSOKOŚCI OKNA (`vh`), nie od szerokości: na niskim ekranie kurczą
   się same, zamiast spychać treść poza kadr.

   Do 2026-08-24 stało tu `clamp(3.4rem, 9vh, 5.5rem)` — przy oknie 950 px
   dawało 85 px u góry i 85 u dołu, czyli 171 px oddechu w każdej z sześciu
   sekcji. Zmierzone po zmianie: 41 + 41.

   ⚠️ Wysokość, w której trzeba się zmieścić, to NIE `100vh`: u góry stoi
   nagłówek (~66 px), u dołu pasek postępu (~50 px). Realny kadr to
   `100vh − 116 px` i pod ten próg dobrane są liczby niżej.
   ------------------------------------------------------------ */
.of-sec .wrap {
  padding-top: clamp(1.7rem, 4.2vh, 2.9rem);
  padding-bottom: clamp(1.7rem, 4.2vh, 2.9rem);
}
.of-title {
  font-size: clamp(1.5rem, 2.8vw, 2.1rem);
  margin: 0.2rem 0 clamp(0.85rem, 2.1vh, 1.4rem);
}
/* wspólny `.label` ma stały margines 1.4rem — na podstronie liczy się każdy
   piksel wysokości, więc i on schodzi razem z oknem */
body.oferta .label { margin-bottom: clamp(0.6rem, 1.6vh, 1rem); }

/* ⚠️ SKOK DO SEKCJI MUSI OMINĄĆ NAGŁÓWEK. `scrollIntoView({block:"start"})`
   stawia górną krawędź sekcji na y=0, a tam siedzi belka menu — przy skoku
   W GÓRĘ (belka wtedy wraca) pierwsze 66 px sekcji chowa się pod nią.
   `--glowa` wpisuje `oferta.js` po zmierzeniu paska; 4.2rem to bezpieczna
   wartość zapasowa na wypadek wyłączonego JS. */
body.oferta main > section { scroll-margin-top: var(--glowa, 4.2rem); }

/* ⚠️ KOTWICA STAREGO ADRESU. Do 2026-08-26 kalkulator był osobną sekcją
   `#kalkulator` i pod ten adres linkuje galeria reportażu — a mogą też
   linkować wyniki wyszukiwania. Po scaleniu sekcji id musiałoby zniknąć,
   więc zostaje jako punkt zerowej wielkości na początku sekcji: skok pod
   `#kalkulator` ląduje dokładnie tam, gdzie skok pod `#pakiety`, i to jest
   właściwe zachowanie — po scaleniu jedno i drugie to ten sam ekran. */
.kotwica {
  display: block;
  position: absolute; top: 0; left: 0;
  width: 1px; height: 1px;
  scroll-margin-top: var(--glowa, 4.2rem);
}

/* ============================================================
   PAKIETY
   ============================================================ */
/* ------------------------------------------------------------
   PAKIETY — dwie grupy, pięć kart
   ------------------------------------------------------------
   Zwykły układ, nic się nie rusza samo.

   ⚠️ DWIE GRUPY (2026-08-26, wieczorem): po lewej **Foto** — trzy pakiety,
   po prawej **Foto + Wideo** — dwa najwyższe, w których ruchomy obraz jest już
   w cenie. Wcześniej stało tu pięć równorzędnych kart bez żadnego podziału
   i nie było widać, gdzie kończy się sama fotografia.

   ⚠️ SZEROKOŚĆ KARTY JEST TA SAMA W OBU GRUPACH i nie bierze się z żadnego
   pomiaru — wychodzi z jednego równania:

       5 kart + 3 odstępy wewnątrz grup + 1 przerwa MIĘDZY grupami = 100%

   stąd `--karta`. Grupy dostają z tego swoje szerokości (`3 karty + 2 odstępy`
   i `2 karty + 1 odstęp`), a karty w środku dzielą je po równo (`flex: 1 1 0`).
   ⚠️ `--karta` WOLNO UŻYĆ WYŁĄCZNIE w `flex-basis` bezpośredniego dziecka
   `.pak-scena`. Siedzi w nim `100%`, a procent rozwiązuje się dopiero
   w miejscu użycia — wstawiony w kartę liczyłby się od `.pak-karty` zamiast
   od sceny i cały rachunek by się rozjechał.

   ⚠️ To FLEX, nie GRID — i nadal po to, żeby niepełny rząd nie wyglądał
   na pomyłkę składu. Poniżej 1360 px grupy schodzą jedna pod drugą
   i wtedy karty w obu liczą się już od szerokości grupy.

   ⚠️ Odstęp w PIONIE jest większy niż w poziomie: znacznik „najczęściej
   wybierany" wystaje 11 px ponad kartę i przy równym odstępie dotykałby
   rzędu wyżej.

   ⚠️ `--ile` USUNIĘTE. Liczba kart w rzędzie nie jest już jedną zmienną,
   bo rząd nie jest jeden — układ opisuje `--karta` i progi niżej.

   ⚠️ KARUZELA USUNIĘTA (2026-08-20). Karty jechały wokół pionowej osi —
   środkowa płasko, sąsiednie odchylone i cofnięte w głąb. Cofnięte na
   życzenie: pakiety mają być widoczne wszystkie naraz, obok siebie.
   ------------------------------------------------------------ */
.pak-scena {
  --odstep: clamp(1rem, 2.2vw, 1.6rem);
  /* ⚠️ PRZERWA MIĘDZY PÓŁKAMI KOSZTUJE SZEROKOŚĆ KART, a te płacą wysokością.
     Odstęp i kreska mają tę samą wartość (włos stoi wtedy pośrodku przerwy),
     ale idą od `vw`, żeby na wąskim ekranie same się skurczyły. Zmierzone przy
     1366 px: przerwa 77 px zabierała każdej karcie 6 px szerokości i podnosiła
     stan A o 39 px, bo punkty list zaczynały się łamać. Przy 55 px to 2 px
     na kartę i sekcja wraca na swoje. */
  --zakladki: clamp(8.5rem, 13vw, 12.5rem);
  position: relative;
  display: grid;
  grid-template-columns: var(--zakladki) minmax(0, 1fr);
  gap: clamp(1.2rem, 2.4vw, 2.4rem);
  align-items: start;
}

/* ---- ZAKŁADKI ZAMIAST DWÓCH PÓŁEK OBOK SIEBIE (2026-08-28) ----
   ⚠️ `--karta`, `--grupa-odstep` i `--grupa-kreska` USUNIĘTE. Nie ma już
   wspólnego rzędu pięciu kart ani przerwy między półkami, więc nie ma czego
   liczyć jednym równaniem. Naraz widać JEDNĄ półkę — trzy karty zamiast
   pięciu — dzięki czemu każda jest szersza, listy łamią się rzadziej,
   a sekcja przestała wychodzić poza kadr.
   ⚠️ To PRZYCISKI, nie odnośniki: nie prowadzą pod żaden adres, tylko
   przełączają widok. `role="tablist"` i `aria-selected` są po to, żeby
   czytnik ekranu ogłosił to jako wybór, a nie jako dwa niezależne guziki. */
.pak-zakladki {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.pak-zakladka {
  display: flex; flex-direction: column; gap: 0.15rem;
  padding: clamp(0.7rem, 1.5vh, 1rem) clamp(0.8rem, 1.2vw, 1.1rem);
  text-align: left;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.03);
  color: var(--ink-dim);
  transition: border-color 0.4s var(--ease), color 0.4s var(--ease),
              background 0.4s var(--ease);
}
.pak-zakladka-nazwa {
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.22em; text-transform: uppercase;
}
.pak-zakladka-ile {
  font-family: var(--serif); font-style: italic;
  font-size: 0.78rem; letter-spacing: 0.02em;
  opacity: 0.72;
}
.pak-zakladka:hover { border-color: rgba(200, 176, 138, 0.45); color: var(--ink); }
/* ⚠️ Stan wybrany niesie OBRYS I TŁO, nie samo przygaszenie pozostałych —
   alfa przy tekście zbija kontrast razem z tłem (NOWY-WATEK §7.14). */
.pak-zakladka.is-on {
  border-color: rgba(200, 176, 138, 0.65);
  background: rgba(200, 176, 138, 0.1);
  color: var(--ink);
}
.pak-zakladka.is-on .pak-zakladka-ile { opacity: 0.9; }
.pak-zakladka:focus-visible { outline: 1px solid var(--gold); outline-offset: 3px; }

/* ---- OPCJA KAMERALNA POD PAKIETAMI (2026-08-28) ----
   Jedno zdanie o ślubie cywilnym i małym przyjęciu. Ma być ZNALEZIONE przez
   tych, którzy go szukają, i przeoczone przez tych, którzy szukają pełnego
   reportażu — dlatego jest szeptem: mniejszy stopień, przygaszony kolor,
   złoty włos z lewej zamiast ramki.

   ⚠️ WŁOS Z BOKU, NIE RAMKA. Ramka zrobiłaby z tego kartę, a karta stanęłaby
   w jednym rzędzie znaczeniowym z pakietami — czyli dokładnie to, czego ten
   układ ma uniknąć. Włos mówi „przypis", nie „oferta".
   ⚠️ Kwota jest w `<strong>`, nie w osobnym, dużym napisie: ma być czytelna
   dla robota i dla szukającego, a nie krzyczeć ceną obok 8 900 zł. */
.pak-mini {
  margin-top: clamp(0.7rem, 1.6vh, 1.1rem);
  padding-left: clamp(0.8rem, 1.6vw, 1.2rem);
  border-left: 1px solid rgba(200, 176, 138, 0.35);
  max-width: 54rem;
  font-size: clamp(0.8rem, 1vw, 0.9rem);
  line-height: 1.6;
  color: var(--ink-dim);
}
/* ⚠️ ETYKIETA W LINII, nie nad tekstem — osobny wiersz kosztowałby ~20 px
   za jedno słowo, a ta sekcja walczy o każde 20 (NOWY-WATEK §7.28).
   Kropka rozdzielająca jest pseudoelementem, żeby nie stała w drzewie
   dostępności: czytnik ma przeczytać „Kameralnie. Sam ślub cywilny…". */
.pak-mini-tyt {
  font-family: var(--nav);
  font-size: 0.55rem; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--gold);
  white-space: nowrap;
}
.pak-mini-tyt::after {
  content: "·";
  margin: 0 0.5em 0 0.7em;
  opacity: 0.7;
}
.pak-mini strong { color: var(--ink); font-weight: 400; }
/* W wycenie znika razem z resztą stanu A — tam jest już wybrany pakiet. */
.kalk.ma-pakiet .pak-mini { display: none; }

/* Nieaktywna półka znika. ⚠️ Własna reguła `display` bije atrybut `hidden`,
   stąd ta linijka (NOWY-WATEK §7.5). W DRZEWIE ZOSTAJE — dane strukturalne
   czytają wszystkie pięć kart, i to `textContent`, a nie pomiar układu,
   więc ukrycie im nie szkodzi. */
.pak-grupa[hidden] { display: none; }
.pak-grupa { display: flex; flex-direction: column; min-width: 0; }
/* ⚠️ WŁOS MIĘDZY PÓŁKAMI I SZEROKOŚCI GRUP USUNIĘTE (2026-08-28).
   Kreska, cieplejsze tło i dwie etykiety miały rozdzielić dwie oferty stojące
   w JEDNYM rzędzie pięciu kart. Rzędu już nie ma — półki nie stoją obok siebie,
   tylko jedna pod drugą w zakładkach, więc rozdzielać nie ma czego.
   Zostaje cieplejsze tło kart po stronie wideo: to nadal jest droższa półka
   i ma się różnić, nawet gdy widać ją samą. */
.pak-grupa--wideo .pak {
  background: linear-gradient(155deg, rgba(200, 176, 138, 0.08), rgba(255, 255, 255, 0.014));
  border-color: rgba(200, 176, 138, 0.24);
}
.pak-karty {
  display: flex; flex-wrap: wrap; align-items: stretch;
  gap: clamp(1.4rem, 2.6vh, 2.1rem) var(--odstep);
  flex: 1;                              /* karty w obu grupach kończą równo */
}
.pak-karty > .pak { flex: 1 1 0; min-width: 0; max-width: 100%; }

/* ------------------------------------------------------------
   NAGŁÓWKI GRUP — pakietów i dodatków
   ------------------------------------------------------------
   Jeden wzór na dwa miejsca: nad kolumną pakietów („Foto", „Foto + Wideo")
   i nad każdą grupą dodatków („W dniu ślubu", „Film i sesje", „Pamiątki").
   Ma to być etykieta, nie nagłówek — mały krój nawigacyjny, szeroka spacja
   i włos, który biegnie do końca grupy i gaśnie. Tyle wystarczy, żeby oko
   złapało podział; wszystko więcej robiłoby z tego drugi poziom tytułów.
   ------------------------------------------------------------ */
/* ⚠️ `.pak-grupa-nazwa` USUNIĘTE 2026-08-28 — etykiety półek zastąpiły
   zakładki. Wzór został sam dla grup dodatków. */
.kalk-grupa-nazwa {
  display: flex; align-items: center; gap: 0.75rem;
  margin: 0 0 clamp(0.5rem, 1.2vh, 0.85rem);
  font-family: var(--nav);
  font-size: 0.58rem; letter-spacing: 0.26em; text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
}
/* ⚠️ Etykieta grupy dodatków NIE MA włosa za tekstem — ma go z boku
   (`.kalk-grupa` niżej). Dwa włosy na jednej grupie, poziomy i pionowy,
   zaczynają wyglądać jak tabela. */
.kalk-grupa-nazwa { color: var(--gold); opacity: 0.85; }
/* Złoto na droższej półce przeniosło się z etykiety na zakładkę — patrz
   `.pak-zakladka.is-on` wyżej. */
.pak {
  position: relative;
  display: flex; flex-direction: column;
  padding: clamp(1.15rem, 2.2vw, 1.7rem);
  background: linear-gradient(155deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012));
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
}
/* wyróżniony pakiet — złoty obrys zamiast innego tła, żeby nie krzyczał */
.pak--top { border-color: rgba(200, 176, 138, 0.55); }

/* ------------------------------------------------------------
   NAJAZD NA PAKIET — karta zapala się złotem i wychodzi z ekranu
   ------------------------------------------------------------
   Cztery rzeczy naraz, każda w swojej warstwie:
     1. karta unosi się i rośnie o 3,5% (`translate` + `scale`),
     2. obrys robi się złoty, a pod kartą zapala się aura (`box-shadow`),
     3. `::before` kładzie na tle ciepłą złotą poświatę od góry,
     4. `::after` przeciąga po karcie POŁYSK — wąski pas światła, wracający
        co kilka sekund, żeby złoto „mieniło się", a nie tylko świeciło.

   ⚠️ NAJWAŻNIEJSZE: RUCH IDZIE PRZEZ `scale` I `translate`, NIE PRZEZ
   `transform`. Karty mają klasę `.reveal` ze wspólnego arkusza, a ta odsłania
   je właśnie `transform`-em (`translateY(34px)` → `none`). Gdyby najazd też
   sięgnął po `transform`, obie rzeczy pisałyby po tej samej właściwości
   i najazd w trakcie odsłaniania zerwałby wejście karty w pół drogi.
   `scale` i `translate` to osobne właściwości — składają się z `transform`
   zamiast się z nim bić.

   ⚠️ DLATEGO TEŻ `transition` POWTARZA TU WPIS Z `.reveal` (opacity
   i transform, 1,1 s z opóźnieniem `--d`). `transition` to skrót — nasza
   reguła stoi w późniejszym arkuszu i wymazałaby tamten wpis w całości,
   a razem z nim schodkowe wchodzenie kart. Ruch najazdu ma za to opóźnienie
   zerowe: karta ma odpowiadać od razu, a nie po `--d`.

   ⚠️ `z-index: 2` przy najeździe — bez tego powiększona karta wchodziłaby
   POD sąsiednią, bo w rzędzie wygrywa kolejność w drzewie.

   ⚠️ Ten sam stan dostaje `:focus-within` — do „Dopasuj ten pakiet" da się
   dojść tabulatorem i wtedy też trzeba widzieć, na której karcie się stoi.
   ------------------------------------------------------------ */
.pak {
  transition:
    opacity 1.1s var(--ease) var(--d, 0s),
    transform 1.1s var(--ease) var(--d, 0s),
    scale 0.55s var(--ease),
    translate 0.55s var(--ease),
    box-shadow 0.55s var(--ease),
    border-color 0.5s var(--ease);
}
/* poświata na tle karty — pod tekstem, nad tłem */
.pak::before {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: radial-gradient(125% 85% at 50% 0%, rgba(200, 176, 138, 0.2), transparent 62%);
  opacity: 0;
  transition: opacity 0.55s var(--ease);
}
/* połysk — wąski pas światła przeciągany w poprzek karty.
   Ruch robi `background-position`, więc pas jest sam z siebie przycięty
   do prostokąta karty; nie trzeba `overflow: hidden`, które ucięłoby
   wystający znacznik „najczęściej wybierany". */
.pak::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: linear-gradient(104deg,
    transparent 40%,
    rgba(238, 222, 190, 0.13) 47%,
    rgba(255, 248, 233, 0.26) 50%,
    rgba(238, 222, 190, 0.13) 53%,
    transparent 60%);
  background-size: 280% 100%;
  background-position: 150% 0;
  opacity: 0;
  transition: opacity 0.4s var(--ease);
}
.pak:hover,
.pak:focus-within {
  scale: 1.035;
  translate: 0 -8px;
  z-index: 2;
  border-color: rgba(200, 176, 138, 0.78);
  box-shadow:
    0 30px 68px rgba(0, 0, 0, 0.55),            /* karta odrywa się od tła */
    0 0 0 1px rgba(200, 176, 138, 0.32),        /* cienki złoty kant */
    0 0 30px rgba(200, 176, 138, 0.26),         /* bliska łuna */
    0 0 88px rgba(200, 176, 138, 0.12);         /* daleka, ledwie widoczna */
}
.pak:hover::before,
.pak:focus-within::before { opacity: 1; }
.pak:hover::after,
.pak:focus-within::after {
  opacity: 1;
  animation: pakPolysk 3.6s var(--ease) infinite;
}
@keyframes pakPolysk {
  0%        { background-position: 150% 0; }
  55%, 100% { background-position: -50% 0; }
}
/* tekst też się ociepla — sama karta bez tego wygląda, jakby zapaliła się rama,
   a treść w środku została w cieniu */
.pak-name,
.pak-price { transition: color 0.45s var(--ease), text-shadow 0.45s var(--ease); }
.pak:hover .pak-name,
.pak:focus-within .pak-name { color: #fdf8ee; text-shadow: 0 0 22px rgba(200, 176, 138, 0.35); }
.pak:hover .pak-price,
.pak:focus-within .pak-price { color: #e6cfa0; }
.pak:hover .pak-cta,
.pak:focus-within .pak-cta { color: var(--gold); }
.pak:hover .pak-cta i,
.pak:focus-within .pak-cta i { transform: translateX(5px); }
.pak-tag {
  position: absolute; top: -0.7rem; left: 50%;
  transform: translateX(-50%);
  padding: 0.25rem 0.9rem;
  background: var(--gold); color: #14110c;
  border-radius: 999px;
  font-size: 0.56rem; letter-spacing: 0.2em; text-transform: uppercase;
  white-space: nowrap;
}
.pak-name {
  font-family: var(--serif); font-size: clamp(1.3rem, 2.2vw, 1.65rem);
  color: var(--ink); line-height: 1.2;
}
.pak-price {
  font-family: var(--nav);
  font-size: 0.78rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--gold);
  margin: 0.35rem 0 0.7rem;
}
.pak-note { color: #b3ada1; font-size: 0.88rem; line-height: 1.5; margin-bottom: 0.85rem; }
.pak-list {
  list-style: none;
  margin: 0 0 1rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
  /* lista rośnie, przycisk zostaje równo na dole każdej karty */
  flex: 1;
}
/* ⚠️ Pięć pozycji razy pięć kart to najgrubszy kawałek sekcji „Pakiety" —
   0,17 rem odstępu mniej na wierszu ścina karcie ~20 px, a całej sekcji tyle
   samo (karty stoją w rzędzie). Poniżej 1,45 wiersze zaczynają się zlewać. */
.pak-list li {
  position: relative;
  padding-left: 1.15rem;
  margin-bottom: 0.38rem;
  color: #b7b1a5; font-size: 0.88rem; line-height: 1.45;
}
.pak-list li::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--gold); opacity: 0.75;
}
.pak-cta {
  display: inline-flex; align-items: center; gap: 0.6rem;
  align-self: flex-start;
  color: var(--ink); text-decoration: none;
  font-family: var(--nav);
  font-size: 0.66rem; letter-spacing: 0.22em; text-transform: uppercase;
  border-bottom: 1px solid var(--gold);
  padding-bottom: 0.45rem;
  transition: color 0.35s;
}
.pak-cta i { font-style: normal; color: var(--gold); transition: transform 0.5s var(--ease); }
.pak-cta:hover { color: var(--gold); }
.pak-cta:hover i { transform: translateX(5px); }
/* ⚠️ CAŁA KARTA JEST POLEM KLIKNIĘCIA, nie sam napis na dole. Nakładka
   `::after` rozpycha pole dotyku etykiety na całą kartę — ta sama sztuczka
   co przy `.rolka-cta` na okładce. Powód jest ten sam: `<label>` przyjmuje
   wyłącznie treść frazową, więc opakowanie nią karty (z `<p>` i `<ul>`
   w środku) byłoby nieprawidłowym HTML-em.
   Nakładka anchorowana jest do `.pak` (to on ma `position: relative`),
   a nie do samej etykiety — dlatego `.pak-cta` NIE MOŻE dostać
   `position: relative`. */
.pak-cta::after {
  content: "";
  position: absolute; inset: 0;
  cursor: pointer;
}
/* Pole zostaje w drzewie (klawiatura, czytnik ekranu), tylko go nie widać —
   `display: none` odebrałoby mu fokus i sterowanie strzałkami.
   Stan „na tej karcie stoi fokus" pokazuje `.pak:focus-within` wyżej. */
.pak-radio {
  position: absolute; top: 0; left: 0;
  width: 1px; height: 1px; margin: 0; opacity: 0;
  pointer-events: none;
}
.pak-foot {
  margin-top: clamp(0.9rem, 2.2vh, 1.5rem);
  text-align: center;
  color: var(--ink-dim); font-size: 0.86rem; line-height: 1.55;
}

/* ============================================================
   STANY SEKCJI — wybór pakietu → wycena
   ============================================================
   Sekcja „Pakiety i wycena" ma DWA STANY, przełączane klasą `ma-pakiet`
   na <section>:

     STAN A · WYBÓR   — pięć kart na całą szerokość, kalkulatora nie ma;
     STAN B · WYCENA  — wybrana karta jedzie w LEWO i zostaje wąską kolumną,
                        obok stają wybory, a przy prawej krawędzi suma.

   ⚠️ STAN A JEST DOMYŚLNY, ale chowanie kalkulatora wisi na klasie `js`,
   którą dokłada `oferta.js`. Bez skryptu nie ma czym przełączyć stanu, więc
   kalkulator po prostu stoi pod kartami i działa jak zwykły formularz.
   Elementu, którego nie da się z powrotem pokazać, nie wolno chować.

   ⚠️ TRZY KOLUMNY, NIE „KARTA + DAWNY KALKULATOR". Karta pakietu zabiera
   ~240 px szerokości. Gdyby stanęła obok dwukolumnowego kalkulatora, kolumna
   wyborów zwęziłaby się poniżej progu `column-width: 19rem` i lista dziewięciu
   dodatków spadłaby do JEDNEJ kolumny, rosnąc o kilkaset pikseli — w sekcji,
   która i tak ledwie mieści się w kadrze. Dlatego `.of-wybor` jest jedną
   siatką KARTA · WYBORY · PODSUMOWANIE, a dawne opakowanie `.kalk-grid`
   zniknęło z HTML-a.

   ⚠️ SZEROKOŚĆ `.of-wybor` JEST TAKA SAMA W OBU STANACH (to zwykły blok na
   całą szerokość treści) — i na tym stoi rachunek `--pak-kol` w `oferta.js`:
   szerokość jednej karty z rzędu pięciu liczy się z szerokości tego elementu.
   Gdyby zależała od stanu, rachunek gryzłby własny ogon.
   ------------------------------------------------------------ */
.of-wybor {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: clamp(1.6rem, 3.4vh, 2.6rem);
  /* warunek działania `position: sticky` na karcie wyceny */
  align-items: start;
}
.of-wybor-karty { min-width: 0; }
.kalk-opts { display: grid; gap: clamp(1.8rem, 4.5vh, 2.8rem); min-width: 0; }

/* nagłówek stanu B czeka w drzewie z `display: none` */
.of-glowa--kalk { display: none; }

/* ---- co chowa stan A (dopiero z JavaScriptem) ---- */
.kalk.js .kalk-opts,
.kalk.js .kalk-sum { display: none; }
.pak-zmien { display: none; }

/* ---- co odsłania stan B ---- */
.kalk.ma-pakiet .of-glowa--wybor { display: none; }
.kalk.ma-pakiet .of-glowa--kalk { display: block; }
.kalk.ma-pakiet .kalk-opts { display: block; }
.kalk.ma-pakiet .kalk-sum { display: block; }
.kalk.ma-pakiet .pak-foot { display: none; }
.kalk.ma-pakiet .pak-zmien { display: inline-flex; }

/* ---- karta wybrana i karty odrzucone ----
   ⚠️ Odrzucone karty NIE dostają `display: none`. Musi po nich zostać ślad,
   bo to po nich przejeżdża karta wybrana — a poza tym znikanie w mgnieniu oka
   wygląda jak błąd, nie jak decyzja. Wychodzą więc z układu
   (`position: absolute`) DOKŁADNIE tam, gdzie stały: współrzędne wpisuje im
   `oferta.js` po pomiarze, tuż przed przełączeniem stanu.
   ⚠️ Własne `transition` zamiast tego z `.pak`: tamto ma schodkowe opóźnienie
   `--d` (do 0,32 s) z odsłaniania i gaszenie szłoby nie w tej kolejności,
   o którą chodzi. */
.pak-scena { position: relative; }

/* ---- STAN B: scena przestaje być rzędem ----
   Jedna karta nie potrzebuje ani flexa, ani grup: scena i oba pudełka grup
   schodzą na `display: block`, więc grupa bez wybranej karty ma zerową wysokość
   (jej karty są już poza układem), a wybrana ląduje przy lewej krawędzi
   niezależnie od tego, w której grupie stała.
   ⚠️ `width`, nie `flex-basis` — w bloku `flex-basis` nic nie znaczy. Karta
   trzyma ZMIERZONĄ szerokość (`--pak-kol`), żeby lot w lewo był czystym
   przesunięciem: karta, która przy okazji rośnie albo się kurczy, czyta się
   jak przeskok, nie jak lot. */
/* ⚠️ W WYCENIE ZAKŁADKI ZNIKAJĄ. Wybór jest zrobiony, a dwie zakładki nad
   jedną kartą sugerowałyby, że da się go zmienić tutaj — od tego jest
   przycisk „Zmień pakiet" pod kartą. */
.kalk.ma-pakiet .pak-zakladki { display: none; }
.kalk.ma-pakiet .pak-scena,
.kalk.ma-pakiet .pak-grupa,
.kalk.ma-pakiet .pak-karty { display: block; }
/* kreska między półkami rozgranicza WYBÓR — po wyborze nie ma już czego
   rozgraniczać, została jedna karta */
.kalk.ma-pakiet .pak-grupa--wideo {
  padding: 0;
  background-image: none;
}
/* Karta wypełnia swoją kolumnę — szerokość ustala siatka `.of-wybor`. */
.kalk.ma-pakiet .pak.is-wybor { width: 100%; flex: none; }

/* ⚠️ `visibility: hidden` PO ZGAŚNIĘCIU, nie od razu. Samo `opacity: 0`
   zostawia kartę w kolejności tabulacji i w drzewie dostępności: Klient
   z klawiaturą wchodziłby w niewidoczne przyciski odrzuconych pakietów.
   `visibility` przełącza się skokowo, więc dajemy jej opóźnienie równe
   gaśnięciu — karta znika z tabulacji dokładnie wtedy, gdy przestaje być
   widoczna. Przy powrocie tej reguły już nie ma, więc wraca natychmiast.
   ⚠️ To NIE JEST `display: none` — karty muszą zostać w drzewie, bo z nich
   powstaje katalog ofert w danych strukturalnych (`oferta.js`, blok 6).

   ⚠️ `--gasnie` WPISUJE SKRYPT: to odległość karty od wybranej (1, 2, 3…).
   Karty gasną WACHLARZEM OD WYBRANEJ NA ZEWNĄTRZ, po 70 ms różnicy — oko idzie
   wtedy za ruchem zamiast rejestrować, że „coś naraz zniknęło". Przy powrocie
   tej reguły nie ma, więc karty wracają bez opóźnień. */
.pak.is-poza {
  position: absolute;
  opacity: 0;
  /* ⚠️ `scale`, NIE `transform` — karta ma jeszcze `transform` z odsłaniania
     i najazd pisze po `scale`/`translate`. Osobne właściwości SKŁADAJĄ SIĘ,
     zamiast się nadpisywać (pułapka 17).
     Odrzucone karty nie tylko gasną, ale i cofają się w głąb: samo krycie robi
     „zniknięcie", krycie z kurczeniem robi „odsunięcie się". */
  scale: 0.965;
  visibility: hidden;
  pointer-events: none;
  /* ⚠️ WACHLARZ (`--gasnie`) USUNIĘTY razem z lotem — rozkładanie gaśnięcia
     na sekundę miało sens, gdy oko szło za lecącą kartą. Bez lotu jest tylko
     czekaniem. Zostaje krótkie, wspólne zgaśnięcie. */
  transition:
    opacity 0.28s var(--ease),
    scale 0.28s var(--ease),
    visibility 0s linear 0.28s;
}
/* wybrana karta zapala się na stałe — także po powrocie do stanu A,
   żeby było widać, co było wybrane */
.pak.is-wybor {
  border-color: rgba(200, 176, 138, 0.7);
  box-shadow:
    0 24px 58px rgba(0, 0, 0, 0.5),
    0 0 0 1px rgba(200, 176, 138, 0.26),
    0 0 26px rgba(200, 176, 138, 0.14);
}
.pak.is-wybor .pak-price { color: #e6cfa0; }
/* W stanie B karta nie jest już przyciskiem: nie ma czego wybierać, a ruch
   najazdu przeszkadzałby przyklejonej obok kolumnie. Zamiast niej stoi
   „Zmień pakiet" pod spodem. */
.kalk.ma-pakiet .pak.is-wybor .pak-cta { display: none; }
.kalk.ma-pakiet .pak.is-wybor:hover,
.kalk.ma-pakiet .pak.is-wybor:focus-within { scale: 1; translate: none; }

/* ---- droga powrotna ---- */
.pak-zmien {
  align-items: center; gap: 0.6rem;
  margin-top: clamp(0.9rem, 2vh, 1.4rem);
  padding: 0 0 0.4rem;
  background: none; border: 0;
  border-bottom: 1px solid rgba(200, 176, 138, 0.5);
  color: var(--ink-dim);
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.22em; text-transform: uppercase;
  cursor: pointer;
  transition: color 0.35s, border-color 0.35s;
}
.pak-zmien i { font-style: normal; color: var(--gold); transition: transform 0.4s var(--ease); }
.pak-zmien:hover { color: var(--gold); border-bottom-color: var(--gold); }
.pak-zmien:hover i { transform: translateX(-4px); }

/* ---- CHOREOGRAFIA PRZEJŚCIA ----
   ⚠️ CAŁE PRZEJŚCIE TRWA ~2,2 s I TO JEST CELOWE. Pierwsza wersja miała 0,62 s
   ⚠️ CHOREOGRAFIA LOTU USUNIĘTA 2026-08-28. Stała tu rozpiska na 1,5 s:
   karta jechała w lewo, cztery pozostałe gasły wachlarzem, kolumny wjeżdżały
   z opóźnieniem 0,62 i 0,72 s. Wyglądało to dobrze przy pierwszym wejściu —
   a Klient porównujący pakiety wchodzi w wycenę wielokrotnie i za trzecim
   razem zostaje z tego samo czekanie. Dziś kalkulator pojawia się od razu,
   a jedyny ruch to półsekundowe przenikanie kolumn.

   ⚠️ Animacja wjazdu siedzi na KOLUMNACH, nie na wspólnym opakowaniu — bo
   wspólnego opakowania nie ma (patrz „trzy kolumny" wyżej). Kończy się na
   `transform: none`: przekształcony przodek byłby blokiem zawierającym dla
   przyklejonej karty wyceny. */
/* ⚠️ `--ruch` i `--ease-lot` USUNIĘTE 2026-08-28 razem z lotem karty.
   Została krzywa wjazdu kolumn kalkulatora — one nadal wchodzą, tylko
   od razu, a nie po locie. */
.kalk {
  --ease-wjazd: cubic-bezier(0.22, 0.9, 0.24, 1);
}
@keyframes kalkWjazd {
  from { opacity: 0; transform: translateX(34px); }
  to   { opacity: 1; transform: none; }
}
@keyframes kalkWjazdDol {
  from { opacity: 0; transform: translateY(26px); }
  to   { opacity: 1; transform: none; }
}
/* ⚠️ BEZ OPÓŹNIENIA (2026-08-28). Opóźnienia 0,62 i 0,72 s były odliczane
   od startu lotu karty — kolumny miały wjechać, gdy karta była już w drodze.
   Lotu nie ma, więc czekanie nie ma na co czekać: kalkulator pojawia się
   od razu po kliknięciu i to jest cała zmiana, o którą tu chodzi. */
.kalk.ma-pakiet .kalk-opts { animation: kalkWjazdDol 0.5s var(--ease-wjazd) both; }
.kalk.ma-pakiet .kalk-sum { animation: kalkWjazdDol 0.5s var(--ease-wjazd) 0.06s both; }

/* ---- GRUPY DODATKÓW WCHODZĄ PO KOLEI ----
   Trzy grupy, które pojawiają się naraz, czytają się jak jeden blok tekstu.
   Wchodzące jedna po drugiej pokazują, że to trzy osobne porządki — i przy
   okazji prowadzą oko w dół listy, zamiast rzucać ją w całości.
   ⚠️ Opóźnienia liczą się OD WJAZDU CAŁEJ KOLUMNY (0,45 s), więc ostatnia
   grupa siada ~1,4 s po kliknięciu — czyli mniej więcej wtedy, gdy karta
   kończy lot. Całość ma się zamknąć w jednym oddechu. */
.kalk.ma-pakiet .kalk-grupa { animation: kalkWjazdDol 0.8s var(--ease-wjazd) both; }
.kalk.ma-pakiet .kalk-grupa:nth-child(1) { animation-delay: 0.8s; }
.kalk.ma-pakiet .kalk-grupa:nth-child(2) { animation-delay: 0.94s; }
.kalk.ma-pakiet .kalk-grupa:nth-child(3) { animation-delay: 1.08s; }

/* 🔴 ANIMACJA WEJŚCIA NALEŻY DO WEJŚCIA, A NIE DO STANU (2026-09-01).
   Wpisana na stałe w regułę stanu `ma-pakiet` odgrywa się PONOWNIE przy każdej
   okazji, która wyjmie element z drzewa renderowania albo tknie właściwość
   `animation` — a w tej sekcji takich okazji jest sporo: pomiar wysokości
   kroków, powrót na krok „Dodatki", przełączenie `display` gdziekolwiek wyżej.
   Trzy grupy z opóźnieniami do 1,08 s i wypełnieniem `both` mają wtedy krycie
   ZERO przez blisko dwie sekundy — i to jest połowa zgłoszenia „kalkulator
   ciągle się odświeża": nie przeliczał się, tylko wjeżdżał od nowa.
   `weszlo` dokłada skrypt po zakończeniu choreografii (`przelacz()` w bloku
   „WIDOK" w `oferta.js`); od tej chwili nie ma tu czego odtwarzać.
   ⚠️ Klasa SCHODZI przy powrocie do wyboru pakietu — kolejne wejście
   w wycenę ma znów wjechać, bo znów jest wejściem.
   ⚠️ Czas w skrypcie (`WJAZD_MS`) musi pokrywać najdłuższą ścieżkę stąd:
   1,08 s opóźnienia + 0,8 s animacji. */
.kalk.ma-pakiet.weszlo .kalk-opts,
.kalk.ma-pakiet.weszlo .kalk-sum,
.kalk.ma-pakiet.weszlo .kalk-grupa { animation: none; }

/* ---- GRUPY DODATKÓW ----
   Trzy grupy zamiast jednej listy dziewięciu pozycji: „W dniu ślubu",
   „Film i sesje", „Pamiątki". Nagłówki grup mają wspólny wygląd z etykietami
   pakietów (blok „NAGŁÓWKI GRUP" wyżej).

   ⚠️ KOLUMNY CSS ZNIKŁY, WRÓCIŁA SIATKA — i tym razem to nie jest cofnięcie
   dawnej decyzji. Kolumny CSS wygrywały wysokością na JEDNEJ długiej liście,
   bo pakowały kafelki bez wyrównywania rzędów. Przy trzech grupach nie ma
   czego pakować: grupa ma dwie, cztery i trzy pozycje, a `break-inside`
   i tak nie pozwoliłby jej pęknąć — kolumny rozłożyłyby CAŁE grupy i wyszłaby
   z tego kolumna 630 px obok kolumny 315 px.

   ⚠️ `auto-fill`, nie stała liczba kolumn: kolumna wyborów ma w stanie B
   ~665 px przy 1920 i ~578 px przy 1366, a lista ma się sama zdecydować,
   ile kafelków w rzędzie zmieści bez ściskania tekstu poniżej granicy
   czytelności.
   ⚠️ Siatka TYLKO wewnątrz grupy. Dojazd (poza grupami) zostaje jedną
   kolumną: trzy pozycje rozbite na 2+1 wyglądałyby jak błąd składu. */
.kalk-grupy { display: grid; gap: clamp(1.1rem, 2.6vh, 1.7rem); }
/* ⚠️ KAŻDA GRUPA MA WŁASNY WŁOS PRZY LEWEJ KRAWĘDZI — ten sam zabieg co przy
   półkach pakietów i z tego samego powodu: sam nagłówek nad listą to za słabo,
   żeby oko zobaczyło trzy osobne porządki zamiast jednego ciągu kafelków.
   Włos biegnie przez całą wysokość grupy i gaśnie u dołu, więc „obejmuje"
   swoje pozycje, zamiast je podkreślać.
   ⚠️ Tło o szerokości jednego piksela, nie pseudoelement — ta sama technika
   co przy półkach pakietów: nie wymaga ani dodatkowego elementu, ani
   pozycjonowania grupy.
   ⚠️ ODSUNIĘCIE IDZIE OD `vw` I JEST WĄSKIE — bo płaci za nie wysokość.
   Każdy piksel zabrany kolumnie wyborów zwęża kafelki dodatków, a te zaczynają
   łamać opisy. Zmierzone przy 1366 px: kreska kolumny 30 px + kreski grup
   16 px zwężały kafelek z 287 do 265 px i podnosiły krok „Dodatki" o 71 px.
   Po zwężeniu obu — 12 px różnicy na kafelku i sekcja wraca na swoje. */
.kalk-grupa {
  min-width: 0;
  padding-left: clamp(0.55rem, 0.9vw, 0.9rem);
  background-image: linear-gradient(180deg,
    rgba(200, 176, 138, 0.4) 0%,
    rgba(200, 176, 138, 0.16) 55%,
    rgba(200, 176, 138, 0) 100%);
  background-size: 1px 100%;
  background-repeat: no-repeat;
  background-position: left top;
}
.kalk-grupa .kalk-opt-lista {
  grid-template-columns: repeat(auto-fill, minmax(15.5rem, 1fr));
}
/* grupa, w której wybrany pakiet nie zostawił ani jednej pozycji do wzięcia —
   chowa ją `oferta.js`, żeby nie został sam nagłówek nad pustką */
.kalk-grupa[hidden] { display: none; }

/* ============================================================
   ZAKRES — co dostajecie
   ============================================================ */
.zak-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: clamp(1.4rem, 3vw, 2.4rem);
}
.zak-k {
  font-family: var(--nav);
  font-size: 0.8rem; letter-spacing: 0.24em; color: var(--gold); opacity: 0.7;
}
.zak-h {
  font-family: var(--serif);
  font-size: clamp(1.15rem, 2vw, 1.4rem);
  margin: 0.5rem 0 0.5rem; color: var(--ink);
}
.zak-p { color: #b3ada1; font-size: 0.92rem; line-height: 1.65; }

/* ============================================================
   PRZEBIEG — jak to wygląda
   ============================================================ */
.krok-lista { list-style: none; max-width: 46rem; }
/* ⚠️ Pięć etapów jeden pod drugim — przerwa pod każdym mnoży się przez pięć,
   więc idzie od wysokości okna. Przy 950 px: 19 px zamiast dawnych 38.
   ⚠️ Tu jest zapas na TREŚĆ: każdy dopisany wiersz w opisie etapu to ~14 px,
   a sekcja ma przy 1512×820 tylko kilkanaście pikseli luzu. Rozbudowując
   opisy, sprawdź wysokość sekcji, zanim uznasz rzecz za skończoną. */
.krok {
  position: relative;
  display: grid; grid-template-columns: auto 1fr;
  gap: clamp(1rem, 2.4vw, 1.8rem);
  padding: 0 0 clamp(0.75rem, 2vh, 1.35rem) 0;
}
/* pionowa nitka łącząca kolejne etapy — ostatni jej nie ma */
.krok::before {
  content: ""; position: absolute;
  left: 0.95rem; top: 2.2rem; bottom: 0;
  width: 1px; background: var(--line);
}
.krok:last-child::before { display: none; }
.krok-k {
  position: relative; z-index: 1;
  display: grid; place-items: center;
  width: 1.9rem; height: 1.9rem;
  border: 1px solid rgba(200, 176, 138, 0.5); border-radius: 50%;
  background: var(--bg);
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.06em; color: var(--gold);
}
.of-sec--alt .krok-k { background: var(--bg-2); }
.krok-h {
  font-family: var(--serif);
  font-size: clamp(1.1rem, 1.8vw, 1.32rem);
  margin-bottom: 0.28rem; color: var(--ink);
}
.krok-p { color: #b3ada1; font-size: 0.9rem; line-height: 1.55; }

/* ============================================================
   PYTANIA (FAQ) — ten sam akordeon, ciaśniejszy skład
   ============================================================
   Wygląd i mechanika idą ze wspólnego `style.css`; tutaj zostaje wyłącznie
   ODDECH, bo dziewięć pytań razy wspólny rozstaw dawało 752 px samej listy,
   a razem z tytułem i marginesami sekcji — 1127 px przy oknie 950.

   ⚠️ Nadpisujemy TYLKO wysokości. Kolory, złota kreska, ikona +/− i płynne
   rozwijanie zostają wspólne — inaczej strona główna i oferta zaczęłyby się
   rozjeżdżać przy każdej poprawce jednej z nich.
   ⚠️ Sekcja mieści się w kadrze także z JEDNĄ ROZWINIĘTĄ ODPOWIEDZIĄ —
   zmierzone przy oknie 1920×950: 654 px zwinięta, 772 px z najdłuższą
   odpowiedzią otwartą, przy kadrze 830. Dwie naraz już wyjdą poza i to jest
   w porządku: Klient sam je otworzył i patrzy wtedy na nie, a nie na listę.
   ------------------------------------------------------------ */
body.oferta .faq .wrap {
  padding-top: clamp(1.7rem, 4.2vh, 2.9rem);
  padding-bottom: clamp(1.7rem, 4.2vh, 2.9rem);
}
body.oferta .faq-title {
  font-size: clamp(1.5rem, 2.8vw, 2.1rem);
  margin: 0.2rem 0 clamp(0.85rem, 2.1vh, 1.4rem);
}
/* ⚠️ 1,3vh, a nie 1,45: dziesiąte pytanie („Ile kosztuje reportaż ślubny",
   dopisane 2026-08-24) podniosło zwiniętą listę o ~56 px i z jedną rozwiniętą
   odpowiedzią sekcja wychodziła 22 px poza kadr. Dwa piksele z wiersza razy
   dziesięć wierszy wystarczyły, żeby wróciła. Niżej nie schodzić: przy 44 px
   kończy się pole dotyku, w które trafia kciuk. */
body.oferta .faq-q { padding: clamp(0.55rem, 1.3vh, 0.88rem) 0.2rem; }
body.oferta .faq-qtext { font-size: clamp(1rem, 1.5vw, 1.2rem); }
body.oferta .faq-num { font-size: 0.82rem; }
/* ⚠️ ODDECH MIĘDZY PYTANIEM A ODPOWIEDZIĄ (2026-08-28). We wspólnym arkuszu
   odpowiedź zaczyna się 0,2 rem pod pytaniem — przy odpowiedziach na dwa
   i trzy wiersze wyglądało to, jakby tekst był drugą linijką pytania, a nie
   osobną wypowiedzią. 0,75 rem oddziela je na tyle, żeby oko zobaczyło dwie
   rzeczy, i na tyle mało, żeby nadal do siebie należały.
   ⚠️ Kosztuje wysokość TYLKO w rozwiniętej odpowiedzi: `.faq-a` jest siatką
   `0fr → 1fr`, więc u zwiniętych pozycji wyściółka nie ma czego podnosić.
   Otwarta jest zawsze jedna, więc rachunek to ~9 px na całą sekcję.
   ⚠️ Zmiana siedzi w `oferta.css` pod `body.oferta`, NIE we wspólnym
   `style.css` — strona główna ma własny akordeon i własny zapas wysokości. */
body.oferta .faq-a-in p {
  padding-top: 0.75rem;
  padding-bottom: 1.1rem;
  font-size: 0.92rem; line-height: 1.65;
}

/* ============================================================
   KALKULATOR WYCENY (druga połowa sekcji #pakiety)
   ============================================================
   Zasada: HTML trzyma tylko kwoty (`data-cena` i napis `.pak-price`), CSS
   wygląd, a `oferta.js` wypisuje napisy i liczy. Wszystkie kolory idą z palety
   strony — kalkulator ma wyglądać jak reszta oferty, a nie jak wtrącony
   formularz ze sklepu.

   ⚠️ 2026-08-26 kalkulator PRZESTAŁ BYĆ OSOBNĄ SEKCJĄ. Siedzi w tej samej
   sekcji co pakiety i pokazuje się dopiero po wybraniu jednego — cały ten
   przełącznik stoi w bloku „STANY SEKCJI" niżej.
   ------------------------------------------------------------ */
.kalk-nojs {
  padding: 1rem 1.2rem; margin-bottom: 2rem;
  border: 1px solid rgba(200, 176, 138, 0.45); border-radius: 12px;
  color: var(--ink); font-size: 0.9rem;
}
.kalk-blok { min-width: 0; }

/* ------------------------------------------------------------
   KROKI — jedna decyzja naraz
   ------------------------------------------------------------
   Wszystko naraz na jednym ekranie (pakiet, osiem dodatków, godziny, dojazd
   i podsumowanie obok) dawało się policzyć, ale nie dawało się spokojnie
   przeczytać: oko nie wiedziało, od czego zacząć. Teraz na raz widać jeden
   krok, a kwota i tak stoi obok przez cały czas.

   ⚠️ Kroki chowamy KLASĄ, nie atrybutem `hidden`: w środku kroku „Dodatki"
   siedzi `.kalk-blok-info` z własnym `hidden`, a dwa znaczenia jednego
   atrybutu w jednym poddrzewie to proszenie się o pomyłkę.
   ⚠️ `min-height` z `--krok-wys` (najwyższy krok, mierzy skrypt) trzyma
   kolumnę w miejscu — bez tego karta z podsumowaniem skakałaby przy każdym
   „Dalej".
   ------------------------------------------------------------ */
.kalk-opts.ma-kroki { display: block; }
.ma-kroki .kalk-blok[data-krok] { display: none; }
.ma-kroki .kalk-blok[data-krok].is-krok-on {
  display: block;
  min-height: var(--krok-wys, auto);
  animation: krokWejscie 0.5s var(--ease);
}
@keyframes krokWejscie {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
/* ⚠️ POMIAR NIE ANIMUJE. `zmierz()` w `oferta.js` odsłania na chwilę kroki,
   żeby poznać najwyższy — a odsłonięcie to ta sama klasa, na której wisi
   animacja wejścia.
   ⚠️ GASIMY WSZYSTKO WEWNĄTRZ, NIE SAM KROK: przełączenie `display` wyjmuje
   z drzewa renderowania także POTOMKÓW bloku, więc restartowały się animacje
   grup dodatków (`kalkWjazdDol`, opóźnienie do 1,08 s, wypełnienie `both` —
   przez ten czas krycie ZERO i kalkulator znikał).
   Gwiazdka NIE obejmuje pseudoelementów, stąd trzy selektory (§7.1).

   🔴 KLASA SIEDZI NA BLOKU KROKU, NIE NA CAŁEJ KOLUMNIE `.kalk-opts`
   (2026-09-01). Różnica jest zasadnicza: ZDJĘCIE tej klasy to zmiana
   `animation` z `none` z powrotem na animację, czyli KOLEJNY jej start.
   Dopóki klasa obejmowała całą kolumnę, każdy pomiar kończył się odegraniem
   dokładnie tego migotania, któremu miał zapobiec — na kroku, na który
   Klient właśnie patrzył. `zmierz()` dokłada ją teraz WYŁĄCZNIE krokom
   niewidocznym; krok czynny mierzy się tam, gdzie stoi, i nie dostaje
   jej nigdy. */
.kalk-blok.mierzymy,
.kalk-blok.mierzymy *,
.kalk-blok.mierzymy *::before,
.kalk-blok.mierzymy *::after {
  animation: none !important;
  transition: none !important;
}

/* pasek kroków — cienka linia nad każdym, złota przy bieżącym */
.kalk-stepper {
  list-style: none;
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr);
  gap: clamp(0.5rem, 1.4vw, 1.1rem);
  margin: 0 0 clamp(0.9rem, 2.2vh, 1.5rem); padding: 0;
}
.kalk-stepper-btn {
  width: 100%; text-align: left;
  display: grid; gap: 0.12rem;
  padding: 0.45rem 0.1rem 0;
  background: none; border: 0;
  border-top: 1px solid var(--line);
  transition: border-color 0.45s var(--ease);
}
.kalk-stepper-btn.is-zrobiony { border-top-color: rgba(200, 176, 138, 0.45); }
.kalk-stepper-btn.is-on { border-top-color: var(--gold); }
.kalk-stepper-nr {
  font-family: var(--nav);
  font-size: 0.58rem; letter-spacing: 0.16em; color: var(--gold); opacity: 0.6;
}
.kalk-stepper-btn.is-on .kalk-stepper-nr { opacity: 1; }
.kalk-stepper-nazwa {
  font-family: var(--serif); font-size: 1.02rem; line-height: 1.25;
  color: var(--ink-dim);
  transition: color 0.45s var(--ease);
}
.kalk-stepper-btn.is-on .kalk-stepper-nazwa { color: var(--ink); }
.kalk-stepper-opis {
  font-size: 0.74rem; line-height: 1.4; color: var(--ink-dim); opacity: 0.75;
}

/* „Wstecz / krok 2 z 3 / Dalej" */
.kalk-nawigacja {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem;
  margin-top: clamp(0.8rem, 1.9vh, 1.2rem);
  padding-top: clamp(0.6rem, 1.4vh, 0.95rem);
  border-top: 1px solid var(--line);
}
.kalk-nav {
  display: inline-flex; align-items: center; gap: 0.6rem;
  padding: 0.55rem 1.3rem;
  border: 1px solid rgba(200, 176, 138, 0.45); border-radius: 999px;
  background: none; color: var(--ink);
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.2em; text-transform: uppercase;
  transition: border-color 0.35s, background 0.35s, color 0.35s, opacity 0.35s;
}
.kalk-nav i { font-style: normal; color: var(--gold); }
.kalk-nav:hover:not(:disabled) { border-color: var(--gold); background: rgba(200, 176, 138, 0.12); }
.kalk-nav:disabled { opacity: 0.3; }
.kalk-nav--dalej { border-color: var(--gold); color: var(--gold); }
.kalk-nav-licznik {
  font-family: var(--nav);
  font-size: 0.58rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-dim);
}
/* Kwota w pasku kroków — POTRZEBNA TYLKO NA TELEFONIE. Na komputerze karta
   z podsumowaniem stoi obok przez cały czas i jest przyklejona do góry ekranu,
   więc druga kwota 20 px od pierwszej byłaby szumem. Odsłania ją blok
   „Responsywność". */
.kalk-nav-suma { display: none; }

/* druga legenda w kroku „Czas i dojazd" potrzebuje oddechu nad sobą */
.kalk-legend--druga { margin-top: clamp(1rem, 2.4vh, 1.6rem); }
.kalk-legend {
  display: flex; align-items: baseline; gap: 0.7rem;
  font-family: var(--nav);
  font-size: 0.68rem; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 0.75rem;
}
.kalk-nr { color: var(--gold); letter-spacing: 0.08em; opacity: 0.75; }

/* ⚠️ `.kalk-bazy` / `.kalk-baza*` USUNIĘTE 2026-08-26. Krok 1 kalkulatora był
   piątką pakietów w małych okienkach radiowych — czyli tą samą decyzją, która
   stała ekran wyżej w kartach. Dziś przyciski radiowe siedzą w samych kartach
   (`.pak-radio`), a kroków zostały dwa: Dodatki oraz Czas i dojazd. */

/* Pole zostaje w drzewie (klawiatura, czytnik ekranu), tylko go nie widać —
   `display: none` odebrałoby mu fokus i sterowanie strzałkami. */
.kalk-opt input { position: absolute; width: 1px; height: 1px; opacity: 0; }

/* ---- 01 i 02 · wiersze z zaznaczaniem ----
   Pierwsza wersja była jedną długą kolumną ośmiu wierszy rozdzielonych włosem:
   opis niewiele mniejszy od nazwy, cena szeptem z boku, a jedynym śladem wyboru
   ptaszek wielkości 18 px. Trzeba się było wczytywać, żeby zobaczyć, co jest
   zaznaczone. Teraz każda pozycja to osobny kafelek — na szerokim ekranie
   w dwóch kolumnach (osiem pozycji mieści się w czterech rzędach zamiast ośmiu),
   z wyraźnym stanem „wybrane" i ceną, która nie ucieka oku. */
/* Domyślnie JEDNA kolumna. Podział na kolumny dostają tylko listy w grupach
   dodatków (`.kalk-grupa .kalk-opt-lista` w bloku „GRUPY DODATKÓW" wyżej);
   dojazd zostaje jednokolumnowy, bo trzy pozycje rozbite na 2+1 wyglądałyby
   jak błąd składu.
   ⚠️ `.kalk-opt-lista--dwie` i kolumny CSS USUNIĘTE 2026-08-26 wraz
   z rozbiciem dodatków na grupy — uzasadnienie przy `.kalk-grupy`. */
.kalk-opt-lista { display: grid; gap: 0.42rem; }
.kalk-opt {
  position: relative;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start; gap: 0.75rem;
  padding: 0.55rem 0.9rem;
  border: 1px solid var(--line); border-radius: 12px;
  background: rgba(255, 255, 255, 0.022);
  transition: border-color 0.4s var(--ease), background 0.4s var(--ease);
}
.kalk-opt:hover { border-color: rgba(200, 176, 138, 0.42); background: rgba(255, 255, 255, 0.042); }
.kalk-opt.is-wybrany {
  border-color: rgba(200, 176, 138, 0.6);
  background: linear-gradient(155deg, rgba(200, 176, 138, 0.15), rgba(200, 176, 138, 0.04));
}
.kalk-mark {
  width: 1.15rem; height: 1.15rem; margin-top: 0.2rem;
  border: 1px solid rgba(200, 176, 138, 0.55); border-radius: 5px;
  position: relative;
  transition: background 0.3s, border-color 0.3s;
}
.kalk-mark::after {
  content: ""; position: absolute; left: 50%; top: 46%;
  width: 0.32rem; height: 0.6rem;
  border: solid #14110c; border-width: 0 1.5px 1.5px 0;
  transform: translate(-50%, -58%) rotate(45deg) scale(0.4);
  opacity: 0;
  transition: opacity 0.25s, transform 0.4s var(--ease);
}
.kalk-opt input:checked ~ .kalk-mark { background: var(--gold); border-color: var(--gold); }
.kalk-opt input:checked ~ .kalk-mark::after {
  opacity: 1; transform: translate(-50%, -58%) rotate(45deg) scale(1);
}
.kalk-opt input:focus-visible ~ .kalk-mark { outline: 1px solid var(--gold); outline-offset: 4px; }
/* dojazd to wybór jednego z trzech — kółko z kropką zamiast ptaszka */
.kalk-opt--radio .kalk-mark { border-radius: 50%; }
.kalk-opt--radio .kalk-mark::after {
  width: 0.42rem; height: 0.42rem;
  border: 0; border-radius: 50%; background: #14110c;
  top: 50%; transform: translate(-50%, -50%) scale(0.4);
}
.kalk-opt--radio input:checked ~ .kalk-mark::after { transform: translate(-50%, -50%) scale(1); }
.kalk-txt { display: block; }
.kalk-opt .kalk-nazwa { display: block; color: var(--ink); font-size: 0.95rem; line-height: 1.3; }
.kalk-opt .kalk-opis {
  display: block; margin-top: 0.12rem;
  color: #a8a297; font-size: 0.78rem; line-height: 1.38;
}
.kalk-opt .kalk-cena {
  font-family: var(--nav);
  font-size: 0.8rem; letter-spacing: 0.06em; color: var(--ink);
  white-space: nowrap; padding-top: 0.1rem;
}
.kalk-opt.is-wybrany .kalk-cena { color: var(--gold); }
/* Pozycja zawarta w wybranym pakiecie — zaznaczona i zablokowana przez skrypt.
   ⚠️ Znakiem tego stanu jest przerywany obrys, a NIE przygaszenie całego
   kafelka: `opacity` na już przyciemnionym opisie zbija kontrast poniżej
   progu WCAG AA, a to wciąż jest treść do przeczytania. */
.kalk-opt.is-inpak {
  border-style: dashed;
  border-color: rgba(200, 176, 138, 0.38);
  background: rgba(200, 176, 138, 0.05);
}
.kalk-opt.is-inpak:hover { background: rgba(200, 176, 138, 0.05); }
.kalk-opt.is-inpak .kalk-cena { color: var(--gold); }
/* Pozycja, której w wybranym pakiecie NIE MA — skrypt daje jej `hidden`.
   ⚠️ Sam atrybut nie wystarczy: `[hidden]` z arkusza przeglądarki ustawia
   `display: none`, ale nasza reguła `.kalk-opt { display: grid }` ma wyższą
   swoistość i wygrywałaby z nim. */
.kalk-opt[hidden] { display: none; }

/* jedno zdanie pod listą dodatków: co w tym pakiecie odpadło i od którego
   pakietu wraca. Treść wypisuje `oferta.js`, tu jest tylko wygląd. */
.kalk-blok-info {
  margin-top: 0.9rem;
  padding-left: 1.15rem;
  position: relative;
  color: var(--ink-dim); font-size: 0.82rem; line-height: 1.55;
}
.kalk-blok-info::before {
  content: ""; position: absolute; left: 0; top: 0.62em;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--gold); opacity: 0.65;
}

/* ---- 03 · godziny ponad pakiet ---- */
.kalk-step { display: flex; align-items: center; gap: 0.85rem; flex-wrap: wrap; }
.kalk-step-btn {
  width: 2.3rem; height: 2.3rem; flex: none;
  display: grid; place-items: center;
  border: 1px solid rgba(200, 176, 138, 0.5); border-radius: 50%;
  background: none; color: var(--gold);
  font-family: var(--nav); font-size: 1rem; line-height: 1;
  transition: background 0.3s, border-color 0.3s, opacity 0.3s;
}
.kalk-step-btn:hover:not(:disabled) { background: rgba(200, 176, 138, 0.14); border-color: var(--gold); }
.kalk-step-btn:disabled { opacity: 0.28; }
.kalk-step-val {
  font-family: var(--nav); font-size: 0.95rem; color: var(--ink);
  min-width: 4.2rem; text-align: center;
}
.kalk-step-info { color: var(--ink-dim); font-size: 0.84rem; }

/* ---- karta podsumowania ---- */
/* ⚠️ KARTA Z SUMĄ NIE JEST JUŻ PRZYKLEJONA (2026-08-28) — i to jest naprawa
   zgłoszonego błędu, nie zmiana upodobań. `position: sticky` trzyma element
   tylko dopóki trwa jego KONTENER. Kolumna wyborów ma 605 px, a karta z sumą
   447 — więc po przewinięciu o ~190 px kontener się kończył, karta odklejała
   się i odjeżdżała w górę razem z treścią. Z boku wyglądało to dokładnie tak,
   jak to opisano: „przy przewijaniu kalkulator dziwnie znika i przenosi się
   w dół". Zmierzone przy 1512×820: karta stała na 81 px, a 200 px niżej była
   już na −119 i uciekała dalej.
   Sekcja mieści się dziś w jednym kadrze (zakładki zamiast pięciu kart),
   więc nie ma czego doganiać przyklejeniem — a bieżącą kwotę niesie i tak
   przyklejony pasek kroków. */
/* ---- KOD RABATOWY ----
   ⚠️ SZEPTEM, NIE BANEREM. To pole ma być widoczne dla kogoś, kto kod DOSTAŁ,
   i niezauważalne dla reszty. Ramka w kolorze linii zamiast złota, etykieta
   w stopniu przypisu, całość pod kwotą. Wersja „krzycząca" (złota ramka,
   napis „ZNIŻKA") zamieniłaby ofertę premium w wyprzedaż.
   ⚠️ Chowa je SKRYPT, gdy nie ma żadnego kodu — stąd reguła na `[hidden]`,
   bo własna reguła `display` biłaby ten atrybut (§7.5). */
.kalk-kod { margin-top: clamp(0.6rem, 1.4vh, 0.95rem); }
.kalk-kod[hidden] { display: none; }
.kalk-kod-etyk {
  display: block;
  margin-bottom: 0.35rem;
  font-family: var(--nav);
  font-size: 0.52rem; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--ink-dim);
}
.kalk-kod-pole { display: flex; gap: 0.4rem; }
.kalk-kod-input {
  flex: 1 1 auto; min-width: 0;
  padding: 0.5rem 0.7rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.22);
  color: var(--ink);
  font-family: var(--nav);
  font-size: 0.68rem; letter-spacing: 0.12em;
  text-transform: uppercase;
}
.kalk-kod-input::placeholder { color: var(--ink-dim); opacity: 0.6; letter-spacing: 0.08em; }
.kalk-kod-input:focus-visible { outline: 1px solid var(--gold); outline-offset: 1px; border-color: var(--gold); }
.kalk-kod-ok {
  flex: 0 0 auto;
  padding: 0.5rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.05);
  color: var(--ink);
  font-family: var(--nav);
  font-size: 0.55rem; letter-spacing: 0.18em; text-transform: uppercase;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease);
}
.kalk-kod-ok:hover, .kalk-kod-ok:focus-visible { border-color: var(--gold); color: var(--gold); }
/* ⚠️ Odpowiedź KOLOREM WPROST, nie przygaszeniem alfą — alfa zbija kontrast
   razem z tłem (§7.14). Czerwień przygaszona, żeby literówka w kodzie nie
   wyglądała jak błąd krytyczny. */
.kalk-kod-info {
  margin-top: 0.4rem;
  font-size: 0.74rem; line-height: 1.45;
}
.kalk-kod-info[hidden] { display: none; }
.kalk-kod-info.is-ok { color: #b9d5b0; }
.kalk-kod-info.is-nie { color: #d9a9a0; }

/* ============================================================
   PANEL PODSUMOWANIA — karta wychodzi na ŚRODEK EKRANU
   ============================================================
   ⚠️ PRZEWIJANIE DO KARTY BYŁO ŚLEPĄ ULICZKĄ i trzeba to powiedzieć wprost.
   „Zobacz podsumowanie" przewijało stronę tak, żeby karta wypadła na środku
   kadru — i rachunek był poprawny. Tyle że na komputerze karta stoi w trzeciej
   kolumnie i przy sekcji wyrównanej do góry JEST JUŻ W CAŁOŚCI WIDOCZNA:
   zmierzone przy 1920×1080 przewinięcie wynosiło −39 px, przy 1512×820 +29 px.
   Klik nie mógł więc niczego zmienić, bo nie było czego przewijać.

   Karta wychodzi teraz NA ŚRODEK EKRANU jako panel nad przyciemnioną stroną.
   To jest ten sam element `.kalk-sum`, tylko z klasą — nie kopia. Gdyby
   podsumowanie istniało w dwóch miejscach, rozjechałoby się pierwsze
   (§7.18), a `przelicz()` musiałby wiedzieć o obu.

   ⚠️ WYŚRODKOWANIE IDZIE PRZEZ `translate`, NIE `transform` — na karcie
   siedzi animacja wejścia, która rusza `transform`, a od 2026-08-28 także
   `scale` przy wejściu panelu. Trzy osobne właściwości SKŁADAJĄ SIĘ zamiast
   się nadpisywać (§7.17).
   ⚠️ Kolumna po karcie NIE ZNIKA: siatka `.of-wybor` ma trzecią kolumnę
   o stałej szerokości (`clamp`), więc wyjęcie karty z przepływu nie przesuwa
   niczego pod spodem. Za zasłoną i tak tego nie widać, ale układ nie skacze
   przy zamknięciu.
   ============================================================ */
.kalk-zaslona {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: rgba(6, 7, 8, 0.72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 0;
  transition: opacity 0.35s var(--ease);
}
.kalk-zaslona.is-on { opacity: 1; }
.kalk-zaslona[hidden] { display: none; }

/* ⚠️ SELEKTORY PANELU NIE ODWOŁUJĄ SIĘ DO PRZODKÓW. Na czas otwarcia karta
   jest przenoszona do <body> (patrz niżej, dlaczego), więc `.kalk.ma-pakiet`
   nad nią już nie ma. Po wyjściu z sekcji nie obowiązuje jej też animacja
   wjazdu kolumny, więc nie trzeba jej niczym bić. */
.kalk-sum.is-panel {
  position: fixed;
  z-index: 210;
  left: 50%; top: 50%;
  translate: -50% -50%;
  width: min(30rem, calc(100vw - 2.4rem));
  /* ⚠️ Wysoki panel MUSI się przewijać w sobie, a nie wystawać poza ekran.
     Przy dziewięciu dodatkach lista rośnie, a okno bywa niskie. */
  max-height: min(86vh, 44rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  box-shadow: 0 40px 90px rgba(0, 0, 0, 0.6);
  animation: kalkPanel 0.38s var(--ease-wjazd) both;
}
@keyframes kalkPanel {
  from { opacity: 0; scale: 0.96; }
  to   { opacity: 1; scale: 1; }
}

/* Krzyżyk pokazuje się WYŁĄCZNIE w panelu — w kolumnie nie ma czego zamykać. */
.kalk-sum-x { display: none; }
.kalk-sum.is-panel .kalk-sum-x {
  display: inline-flex; align-items: center; justify-content: center;
  position: absolute; top: 0.7rem; right: 0.7rem;
  width: 34px; height: 34px;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.3);
  color: var(--ink);
  font-size: 0.9rem; line-height: 1;
  transition: border-color 0.3s var(--ease), color 0.3s var(--ease), rotate 0.3s var(--ease);
}
.kalk-sum.is-panel .kalk-sum-x:hover,
.kalk-sum.is-panel .kalk-sum-x:focus-visible {
  border-color: var(--gold); color: var(--gold); rotate: 90deg;
}
/* Strona pod panelem nie przewija się razem z nim. */
body.kalk-panel { overflow: hidden; }

/* ⚠️ PULS OBRYSU (`is-pokaz`) USUNIĘTY 2026-08-28 razem z przewijaniem
   do karty. Był protezą: skoro przewinięcie na komputerze wynosiło ~30 px,
   klik potrzebował JAKIEGOKOLWIEK potwierdzenia. Panel na środku ekranu jest
   potwierdzeniem sam w sobie i proteza przestała być potrzebna. */

.kalk-sum {
  padding: clamp(1.4rem, 2.6vw, 1.9rem);
  border: 1px solid rgba(200, 176, 138, 0.4); border-radius: 16px;
  background: linear-gradient(155deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.014));
  box-shadow: 0 22px 55px rgba(0, 0, 0, 0.42);
}
.kalk-sum-h {
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.28em; text-transform: uppercase;
  color: var(--gold);
}
.kalk-lista { list-style: none; display: grid; gap: 0.55rem; margin: 1.1rem 0 0; }
.kalk-lista li {
  display: flex; justify-content: space-between; align-items: baseline; gap: 0.8rem;
  color: #b7b1a5; font-size: 0.85rem; line-height: 1.45;
}
.kalk-lista .kalk-li-cena {
  font-family: var(--nav); font-size: 0.72rem; letter-spacing: 0.06em;
  color: var(--ink); white-space: nowrap;
}
.kalk-lista li.is-baza { color: var(--ink); }
.kalk-lista li.is-rabat .kalk-li-cena { color: var(--gold); }

/* ---- ZAKRES PAKIETU (`is-zakres`) ----------------------------------
   Punkty z karty pakietu, przepisane przez `przelicz()`: ile godzin, ile
   kadrów, co dostają w ręce. Do 2026-09-01 podsumowanie ich nie miało —
   Klient kopiował „Panorama: 3 900 zł" i tyle z tego zostawało.

   ⚠️ TO NIE SĄ POZYCJE RACHUNKU, tylko jego rozwinięcie — i tak mają
   wyglądać: bez kwoty, mniejszym stopniem, wcięte pod pozycją pakietu,
   ze złotą kropką zamiast wyrównanej do prawej ceny. Gdyby dostały ten sam
   ciężar co dopłaty, karta zmieniłaby się w listę kilkunastu równorzędnych
   wierszy i przestałaby odpowiadać na pytanie „za co płacimy".
   ⚠️ `is-pak` USUNIĘTE — osobne wiersze „w pakiecie" dublowały te punkty
   (patrz `przelicz()` w `oferta.js`).
   ⚠️ Ujemny odstęp zbija punkty w jeden blok: `gap` siatki jest liczony pod
   pozycje rachunku, a sześć punktów rozstrzelonych co 0,55 rem czytałoby się
   jak sześć osobnych rzeczy, a nie jak zawartość jednego pakietu. */
.kalk-lista li.is-zakres {
  position: relative;
  padding-left: 0.95rem;
  color: var(--ink-dim);
  font-size: 0.78rem; line-height: 1.4;
}
.kalk-lista li.is-zakres::before {
  content: "";
  position: absolute; left: 0.15rem; top: 0.62em;
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--gold); opacity: 0.7;
}
.kalk-lista li.is-zakres + li.is-zakres { margin-top: -0.22rem; }
/* ostatni punkt zakresu odsuwa się od pierwszej pozycji płatnej */
.kalk-lista li.is-zakres + li:not(.is-zakres) { margin-top: 0.3rem; }
.kalk-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 1rem;
  margin-top: 1.1rem; padding-top: 1rem;
  border-top: 1px solid var(--line);
}
.kalk-total-lab {
  font-family: var(--nav);
  font-size: 0.62rem; letter-spacing: 0.24em; text-transform: uppercase; color: var(--ink-dim);
}
.kalk-total-val {
  font-family: var(--serif); font-size: clamp(1.55rem, 3vw, 2.05rem);
  color: var(--gold); line-height: 1.1;
}
.kalk-total-val.bump { animation: kalkBump 0.55s var(--ease); }
@keyframes kalkBump {
  0%   { transform: none; }
  38%  { transform: translateY(-3px); }
  100% { transform: none; }
}
.kalk-zadatek {
  margin-top: 0.5rem;
  font-family: var(--nav); font-size: 0.64rem; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--ink-dim);
}
.kalk-uwaga { margin-top: 0.9rem; color: var(--ink-dim); font-size: 0.8rem; line-height: 1.55; }
.kalk-akcje { display: grid; gap: 0.6rem; margin-top: 1.3rem; }
/* w wąskiej kolumnie przyciski dostają ciaśniejszy oddech niż w sekcji kontaktu */
.kalk-akcje .ig-btn {
  justify-content: center; text-align: center;
  padding: 0.9rem 1.1rem;
  font-size: 0.62rem; letter-spacing: 0.18em;
  border-width: 1px;
}
.kalk-kopiuj { font-family: inherit; }
.kalk-kopiuj.is-done { background: rgba(200, 176, 138, 0.16); border-color: var(--gold); }
/* „Wyślij e-mailem" (2026-09-05) — trzeci przycisk, ten sam krój co „Skopiuj";
   ikonka koperty z tego samego zestawu kresek, co w sekcji kontaktu */
.kalk-mail svg { width: 1em; height: 1em; flex: none; fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
/* Jedno zdanie pod przyciskami: zapowiada, co się stanie, a po kliknięciu
   mówi, co się stało (treść podmienia `oferta.js`).
   ⚠️ Miejsce jest zarezerwowane na stałe — komunikat zmienia tylko TREŚĆ,
   nigdy widoczność. Pojawiający się i znikający wiersz przesuwałby przyciski
   pod kursorem dokładnie w chwili, w której Klient w nie celuje. */
.kalk-akcje-info {
  margin-top: 0.7rem;
  font-size: 0.72rem;
  line-height: 1.45;
  text-align: center;
  color: var(--ink-dim);
}
.kalk-reset {
  display: block; margin: 0.9rem auto 0;
  background: none; border: 0;
  font-family: var(--nav);
  font-size: 0.6rem; letter-spacing: 0.2em; text-transform: uppercase;
  color: var(--ink-dim);
  border-bottom: 1px solid transparent;
  transition: color 0.35s, border-color 0.35s;
}
.kalk-reset:hover { color: var(--gold); border-bottom-color: rgba(200, 176, 138, 0.6); }

/* ---- PIGUŁKA Z SUMĄ — USUNIĘTA (2026-08-24) ----
   Pływające okienko z kwotą i przyciskiem „podsumowanie ↓" wjeżdżało na
   telefonie nad dolną krawędź, gdy kalkulator był na ekranie. Razem
   z paskiem postępu zabierało 112 px dolnej krawędzi i potrafiło ZAKRYĆ
   przycisk „Dalej" — a to on prowadzi przez całą wycenę.
   Kwotę niesie teraz przyklejony pasek kroków (`.kalk-nawigacja` w bloku
   „Responsywność"), w którym stoi obok przycisków, a nie nad nimi. Pływające
   okienko nie miało już czego pokazywać. Usunięte z HTML, CSS i skryptu.
   ⚠️ Gdyby kiedyś wracało: nie może stać w tym samym rogu co „Dalej". */

/* ============================================================
   KALKULATOR NA SZEROKIM EKRANIE
   ============================================================
   ⚠️ UKŁAD CZTEROKOLUMNOWY ZOSTAŁ USUNIĘTY (2026-08-20). Rozkładał kalkulator
   na Pakiet · Dodatki · Godziny+Dojazd · Podsumowanie i naprawdę mieścił się
   na jednym ekranie — ale właśnie o to poszło: pięć pakietów, osiem dodatków,
   suwak i trzy dojazdy naraz to ściana, przed którą nie wiadomo, gdzie
   spojrzeć najpierw. Zastąpiły go KROKI (patrz wyżej): na raz widać jedną
   decyzję, a kwota stoi obok przez cały czas. Zostaje więc układ dwukolumnowy
   — wybory i podsumowanie — na każdej szerokości powyżej telefonu.

   Od 1360 px sekcja dostaje szerszą kolumnę treści, żeby dwie kolumny dodatków
   miały czym oddychać, gdy mozaika zabiera ćwiartkę okna.

   ⚠️ PRÓG ZSZEDŁ Z 1600 NA 1360 px (2026-08-24) i to jest zmiana o wysokość,
   nie o szerokość. Przy 1600 px sekcja „Pakiety" miała pięć kart w rzędzie
   i 715 px wysokości, a już przy 1512 px zwijała się do 3+2 i skakała
   do 1064 px — jeden piksel szerokości okna kosztował 350 px wysokości
   i wywalał sekcję poza kadr. 1360 px łapie jeszcze laptopy 1366×768.
   Zmierzone po obniżeniu progu: 1512 px → 666, 1440 px → 680, 1366 px → 743;
   karta ma wtedy 236 / 222 / 208 px szerokości, czyli wciąż powyżej granicy
   195 px, przy której robi się z nich ściana tekstu.
   ------------------------------------------------------------ */
@media (min-width: 1360px) {
  /* szersza kolumna treści to jedyny sposób, żeby pięć kart obok siebie miało
     po ~236 px zamiast ~195 px — poniżej tego robi się z nich ściana tekstu */
  .kalk .wrap { max-width: 1420px; }
  .pak { padding: clamp(1.3rem, 1.6vw, 1.7rem); }
  .pak-name { font-size: 1.25rem; }
  .pak-note { font-size: 0.84rem; }
  .pak-list li { font-size: 0.84rem; }

  /* ---- STAN B: karta | wybory | podsumowanie ----
     ⚠️ TO JEST JEDYNY PRÓG, OD KTÓREGO KARTA JEDZIE W BOK. Niżej pięć kart
     zwija się do 3+2, więc jedna ma już ~370 px i po odjęciu jej oraz
     podsumowania na wybory zostaje mniej, niż potrzebują dwie kolumny
     dodatków — lista spadłaby do jednej i urosła o kilkaset pikseli.
     Poniżej 1360 px stan B układa się więc pionowo: karta, wybory, suma.

     ⚠️ `--pak-kol` wpisuje `oferta.js` — to ZMIERZONA szerokość jednej karty
     z rzędu pięciu. Dzięki temu karta w locie w lewo nie zmienia rozmiaru
     ani o piksel i ruch jest czystym przesunięciem, bez skalowania tekstu.
     15rem to wartość zapasowa na wypadek, gdyby pomiar nie zdążył. */
  /* ---- WŁOS MIĘDZY „WASZ PAKIET" A „WASZE WYBORY" ----
     Trzy kolumny rozdzielone samą pustką czytały się jak jedna szeroka plansza.
     Ten sam włos co między półkami pakietów stawia granicę tam, gdzie ona
     naprawdę jest: po lewej to, co już wybrane, po prawej to, co jeszcze
     do wyboru. Karta z sumą nie potrzebuje własnej kreski — ma obrys i tło,
     więc odcina się sama; trzecia linia zrobiłaby z tego tabelę.

     ⚠️ WŁOS RYSUJEMY NA SIATCE, W JEJ ODSTĘPIE — NIE jako `padding` kolumny.
     Pierwsza wersja odsuwała kolumnę wyborów o 30 px i to były 30 px zabrane
     kafelkom dodatków: przy 1366 px kafelek schodził z 287 do 265 i krok
     „Dodatki" rósł o 71 px. Tło siatki nie zabiera nic — leży dokładnie
     w połowie przerwy, którą i tak trzeba było zostawić.
     ⚠️ Stąd `--of-gap`: ta sama wartość musi trafić do `gap` i do położenia
     tła. Zmieniając jedno, zmienia się oba — i o to chodzi. */
  .kalk.ma-pakiet .of-wybor {
    --of-gap: clamp(1.4rem, 2.6vw, 2.4rem);
    /* ⚠️ KOLUMNA KARTY MA STAŁĄ SZEROKOŚĆ, NIE ZMIERZONĄ (2026-08-28).
       Dopóki karta LECIAŁA ze stanu A do B, nie mogła po drodze zmienić
       szerokości — inaczej lot czytał się jak przeskok. Trzymała ją więc
       zmierzona `--pak-kol`. Lotu nie ma, a po przejściu na zakładki karta
       w stanie A urosła z 232 do 332 px: przeniesiona żywcem do wyceny
       zabierała 100 px kolumnie dodatków i podnosiła sekcję o ponad 100 px.
       W wycenie karta jest już tylko przypomnieniem wyboru — nie musi być
       tak szeroka jak wtedy, gdy się ją porównywało. */
    /* ⚠️ SZEROKOŚĆ ODDANA DODATKOM. Wysokość sekcji w wycenie robi krok
       „Dodatki", a ten rośnie, gdy kolumna wyborów się zwęża: kafelki łamią
       się na więcej wierszy. Karta i podsumowanie oddały więc po kilkanaście
       procent szerokości — obie tylko przypominają, co wybrano, a to trzecia
       kolumna jest tą, w której się PRACUJE. */
    --kol-karty: clamp(11rem, 13vw, 13.5rem);
    grid-template-columns: var(--kol-karty) minmax(0, 1fr) clamp(14rem, 17vw, 17rem);
    gap: var(--of-gap);
    background-image: linear-gradient(180deg,
      rgba(200, 176, 138, 0) 0%,
      rgba(200, 176, 138, 0.32) 12%,
      rgba(200, 176, 138, 0.32) 88%,
      rgba(200, 176, 138, 0) 100%);
    background-size: 1px 100%;
    background-repeat: no-repeat;
    background-position: calc(var(--kol-karty) + var(--of-gap) / 2) center;
  }
  .kalk-sum { padding: 1.3rem 1.4rem; }
}

/* ============================================================
   NISKIE OKNO NA DUŻYM EKRANIE (do 1000 px wysokości)
   ============================================================
   Zwykły monitor 1920×1080 daje przeglądarce ~950 px wysokości okna, a po
   odjęciu belki menu (66) i paska postępu (54) zostaje 830 px kadru. Sekcje
   są skrojone pod ten kadr — ale kalkulator i tak dochodził do niego z sześcio-
   pikselowym zapasem, a przy 860 px okna wychodził 62 px poza. Marginesy
   idą już od `vh`, więc tutaj schodzi to, co od wysokości okna nie zależy:
   DRUGI WIERSZ NAGŁÓWKA i opisy pod nazwami kroków.

   ⚠️ Nagłówki sekcji mają w HTML twardy `<br>` („Pięć dróg. / Jeden dzień.").
   Przy niskim oknie ten drugi wiersz kosztuje ~40 px w KAŻDEJ sekcji, a nic
   nie wnosi poza rytmem. Zdejmujemy sam podział, nie treść — zdanie zostaje
   w całości, tylko idzie jednym wierszem.
   ⚠️ Tylko powyżej 860 px szerokości: na telefonie o typografii decyduje blok
   „Responsywność", a tam podział na dwa wiersze jest jedynym, co trzyma
   nagłówek w ryzach.
   ------------------------------------------------------------ */
@media (max-height: 1000px) and (min-width: 861px) {
  body.oferta .of-title br,
  body.oferta .faq-title br { display: none; }
  /* nazwa kroku wystarczy — trzy zdania pod paskiem kroków to trzeci wiersz
     w każdej kolumnie, a Klient i tak czyta legendę kroku niżej */
  .kalk-stepper-opis { display: none; }
  .kalk-opt { padding: 0.45rem 0.85rem; }
  /* etykiety grup dodatków ściskają się razem z resztą — trzy nagłówki razy
     kilka pikseli oddechu to przy niskim oknie kolejny wiersz listy */
  .kalk-grupy { gap: 0.75rem; }
  .kalk-grupa-nazwa { margin-bottom: 0.4rem; }
  /* karta wybranego pakietu też schodzi: w stanie B stoi obok wyborów i to ona
     bywa najwyższą kolumną, a jej opis powtarza to, co Klient przed chwilą
     przeczytał, wybierając ją */
  .kalk.ma-pakiet .pak.is-wybor .pak-note { display: none; }
  .kalk.ma-pakiet .pak.is-wybor .pak-list { padding-top: 0.65rem; }

  /* ⚠️ SIÓDMY PUNKT W NAJWYŻSZEJ KARCIE (2026-09-01). „Pełen dzień" dostał
     mini album i pendrive, a że karty stoją w rzędzie, o wysokość najwyższej
     rośnie CAŁA sekcja: zmierzone przy 1366×768 — dwa punkty kosztowały 26 px
     i z zapasu nad krawędzią kadru (653 px) zostawało 10.
     Oddajemy je z odstępów samej listy, nie z treści: ta sama zasada, co przy
     `.pak-list li` w regule podstawowej („0,17 rem mniej ścina karcie ~20 px").
     ⚠️ Tylko przy niskim oknie — na dużym ekranie miejsce jest i lista może
     oddychać. */
  .pak-note { margin-bottom: 0.7rem; }
  .pak-list { padding-top: 0.7rem; margin-bottom: 0.8rem; }
  .pak-list li { margin-bottom: 0.26rem; }
}

/* ============================================================
   PASEK POSTĘPU — gdzie jesteśmy w ofercie
   ============================================================
   Wskaźnik przewijania z numerem i nazwą sekcji oraz kropkami do
   przeskakiwania. Wjeżdża po zejściu z okładki; kropki dorabia `oferta.js`
   z sekcji oznaczonych `data-sekcja="…"`.
   ------------------------------------------------------------ */
.pasek {
  position: fixed; left: 0; right: 0; bottom: 0;
  z-index: 115;                       /* pod nagłówkiem (120), nad treścią */
  background: linear-gradient(to top, rgba(8, 10, 11, 0.94), rgba(8, 10, 11, 0.62));
  backdrop-filter: blur(12px) saturate(1.1);
  -webkit-backdrop-filter: blur(12px) saturate(1.1);
  border-top: 1px solid rgba(200, 176, 138, 0.22);
  transform: translateY(105%);
  transition: transform 0.55s var(--ease);
}
.pasek.is-on { transform: none; }

.pasek-tor {
  position: absolute; left: 0; right: 0; top: -1px; height: 2px;
  background: rgba(200, 176, 138, 0.16);
}
.pasek-postep {
  display: block; height: 100%; width: 0;
  background: var(--gold);
  box-shadow: 0 0 12px rgba(200, 176, 138, 0.55);
  transition: width 0.25s linear;
}
.pasek-in {
  display: flex; align-items: center; gap: clamp(0.7rem, 2vw, 1.4rem);
  max-width: 1360px; margin: 0 auto;
  padding: clamp(0.5rem, 1.2vh, 0.8rem) clamp(1rem, 3.4vw, 2.4rem);
}
.pasek-licznik {
  font-family: var(--nav);
  font-size: 0.6rem; letter-spacing: 0.2em; color: var(--gold);
  flex: none;
}
.pasek-licznik i { font-style: normal; opacity: 0.45; margin: 0 0.3em; }
.pasek-nazwa {
  font-family: var(--serif); font-style: italic;
  font-size: clamp(0.9rem, 1.6vw, 1.1rem);
  color: var(--ink);
  margin-right: auto;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pasek-kropki { display: flex; align-items: center; gap: 0.5rem; flex: none; }

/* skok o sekcję w górę / w dół — dla tych, którzy nie chcą kręcić rolką */
.pasek-skoki { display: flex; align-items: center; gap: 0.35rem; flex: none; margin-left: 0.4rem; }
.pasek-skok {
  width: 26px; height: 26px; padding: 0;
  display: grid; place-items: center;
  border: 1px solid rgba(200, 176, 138, 0.4); border-radius: 50%;
  background: none;
  transition: border-color 0.35s, background 0.35s, opacity 0.35s;
}
.pasek-skok svg {
  width: 11px; height: 7px;
  fill: none; stroke: var(--gold); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
}
.pasek-skok:hover:not(:disabled) { border-color: var(--gold); background: rgba(200, 176, 138, 0.14); }
.pasek-skok:disabled { opacity: 0.3; }
.pasek-kropka {
  position: relative;
  width: 7px; height: 7px; padding: 0;
  border: 1px solid rgba(200, 176, 138, 0.55); border-radius: 50%;
  background: none;
  transition: background 0.3s, transform 0.3s var(--ease);
}
/* pole dotyku 31 px przy kropce 7 px — ten sam zabieg co w menu na telefonie */
.pasek-kropka::before { content: ""; position: absolute; inset: -12px -7px; }
.pasek-kropka.is-on { background: var(--gold); transform: scale(1.3); }



/* ============================================================
   Średnie okno — grupy pakietów schodzą jedna pod drugą
   ============================================================
   Poniżej 1360 px dwie grupy obok siebie dałyby karty po ~195 px, a przy tej
   szerokości robi się z nich ściana tekstu. Grupy idą więc jedna pod drugą,
   każda ze swoją etykietą — i to jest nawet czytelniejsze niż dawny rząd 3+2,
   bo podział „Foto / Foto + Wideo" staje się osią całej sekcji.

   ⚠️ KARTA LICZY SIĘ TERAZ OD SZEROKOŚCI GRUPY, nie sceny — a że grupa ma
   wtedy 100% szerokości, obie mają tę samą miarę i karty w obu wychodzą równe.
   Grupa „Foto + Wideo" ma dwie karty zamiast trzech i po prawej zostaje jej
   wolne miejsce: to widać jako różnicę, a nie jako błąd składu.

   ⚠️ Stan B jest tu PIONOWY (karta, wybory, suma) — dzielenie szerokości
   zaczyna się dopiero od 1360 px, patrz blok „STAN B" wyżej.
   ============================================================ */
@media (max-width: 1359px) {
  .pak-grupa { flex: 0 0 100%; }
  .pak-karty > .pak { flex: 0 0 calc((100% - 2 * var(--odstep)) / 3); }
  /* ⚠️ ZŁOTY WŁOS NAD PÓŁKĄ „FOTO + WIDEO" USUNIĘTY 2026-09-01 —
     ROBIŁ ZŁOTĄ POŚWIATĘ NA CAŁEJ GRUPIE, nie kreskę.
     Gradient miał wysokość `background-size: 100% 1px`, ale zabrakło
     `background-repeat: no-repeat` — a domyślne `repeat` powiela ten
     jeden piksel w dół przez całą wysokość grupy. Zamiast włosa przy
     górnej krawędzi wychodził ciepły prostokąt położony NA OBU KARTACH
     pakietu, najjaśniejszy z lewej (0.34) i gasnący w prawo. Na telefonie,
     gdzie karta zajmuje 80% szerokości, widać było go najmocniej.
     ⚠️ Sam włos i tak nie miał już czego rozdzielać: od czasu zakładek
     (2026-08-28) półki NIGDY nie stoją obok siebie ani jedna pod drugą —
     widać zawsze tylko jedną. Kreska pojawiałaby się więc wyłącznie
     na jednej z dwóch zakładek, bez niczego po drugiej stronie.
     Podział niesie sama zakładka — ta wybrana jest podświetlona.
     To ta sama decyzja, co przy cieplejszym tle kart w bloku poniżej.
     ⚠️ Wzór „gradient + `background-size` 1 px" żyje dalej przy włosie
     między „Wasz pakiet" a „Wasze wybory" (blok min-width: 1360px) —
     i TAM `background-repeat: no-repeat` stoi. Kopiując go, przenieś
     RÓWNIEŻ tę linijkę, inaczej wróci dokładnie ta poświata. */
}
/* trzy karty schodzą tu pod 300 px — dwie czytają się lepiej niż trzy ciasne */
@media (max-width: 1100px) {
  .pak-karty > .pak { flex: 0 0 calc((100% - var(--odstep)) / 2); }
}

/* ============================================================
   Responsywność — telefon i wąskie okno
   ============================================================ */
@media (max-width: 860px) {
  /* ---- mozaika znika ----
     Ćwiartka ekranu to na telefonie ~94 px: kadry byłyby znaczkami, a treść
     dostałaby kolumnę nie do czytania. Pasek chowamy w całości i strona wraca
     na pełną szerokość. */
  .mozaika,
  .mozaika-linia,
  .mozaika-uchwyt { display: none; }
  body.oferta { padding-left: 0; }
  body.oferta main { padding-left: 0; }
  /* sekcje zostają kryjące — przezroczyste szyby nad zdjęciem zjadałyby
     czytelność na małym ekranie */
  .of-sec { --krycie: 0.97; --rozm: 0px; }
  body.oferta .site-head,
  body.oferta .pasek { left: 0; }

  /* ============================================================
     OKŁADKA NA TELEFONIE — WSZYSTKO W JEDNEJ KOLUMNIE
     ============================================================
     ⚠️ TŁO FILMOWE ZNIKA (2026-08-24) i to jest sedno tej przebudowy.
     `.film-tlo` jest przyklejone do okna i wypełnia je `cover`-em. Kadr 16:9
     w pionowym oknie 390×844 pokazuje wtedy ~25% zdjęcia — resztę przycina —
     a na tę ćwiartkę nachodzą jeszcze: tytuł, karta pary (dawniej `absolute`),
     sterowanie rolki i pasek postępu. Trzy warstwy tekstu nad przyciętym
     zdjęciem to była papka, w której nie było widać ani zdjęcia, ani napisów.

     Teraz okładka jest ZWYKŁĄ KOLUMNĄ: tytuł → okno reportażu 16:9 → kropki →
     karta pary. Nic nie leży na niczym, wszystko ma swoje miejsce w przepływie,
     a zdjęcie widać w całości.

     ⚠️ `height: auto` zamiast `100svh`: treści jest teraz więcej, niż mieści
     jeden ekran niskiego telefonu, a ucinanie okładki było właśnie tym, przed
     czym uciekamy. `min-height` zostaje, żeby na wysokim ekranie okładka
     nadal wypełniała kadr.
     ------------------------------------------------------------ */
  .film-tlo { display: none; }

  .of-hero.of-hero--okladka {
    display: flex; flex-direction: column; align-items: stretch;
    justify-content: flex-start;
    text-align: left;
    height: auto;
    min-height: 100svh;
    gap: clamp(0.7rem, 1.9vh, 1.1rem);
    /* ⚠️ Dolny oddech ścięty z 7vh do 4,5vh, a odstępy z 2,4vh do 1,9vh
       (2026-08-26) — żeby powiększone okno reportażu zmieściło się RAZEM
       z kartą pary na pierwszym ekranie. Zmierzone: przy 390×844 dół karty
       wypada na 843 px — JEDEN PIKSEL zapasu; przy 414×896 zostaje 33 px.
       To jest bilans zamknięty: każdy kolejny wiersz treści w okładce wypchnie
       kartę pod zgięcie. Chcąc coś dopisać, oddaj to z proporcji okna. */
    padding: clamp(5rem, 12vh, 6rem) 1.2rem clamp(1.8rem, 4.5vh, 2.8rem);
    /* bez tła filmowego okładka potrzebuje własnej głębi — inaczej byłaby
       płaską czarną płachtą nad oknem ze zdjęciem */
    background:
      radial-gradient(120% 60% at 50% 0%, rgba(200, 176, 138, 0.07), transparent 60%),
      var(--bg);
  }
  /* ⚠️ KOLEJNOŚĆ ROBI `order`, NIE HTML. Zdjęcie siedzi od 2026-08-26 WEWNĄTRZ
     kafelka, więc do ustawienia zostały trzy rzeczy. Zmiana kolejności w HTML
     zepsułaby komputer, `order` nie rusza niczego poza tym progiem.
     ⚠️ STEROWANIE ZESZŁO POD KAFELEK (2026-08-28): tytuł → kafelek → kropki.
     Kropki i strzałki przełączają reportaż POKAZANY W KAFELKU, a stały nad
     nim — czyli nad rzeczą, której dotyczą, i pod tytułem, którego nie
     dotyczą wcale. Sterowanie pod spodem czyta się jako „to należy do tego,
     co widać wyżej", a przy okazji nie rozdziela już tytułu od zdjęcia. */
  .of-hero.of-hero--okladka > .okladka    { order: 1; }
  .of-hero.of-hero--okladka > .rolka      { order: 2; }
  .of-hero.of-hero--okladka > .rolka-ster { order: 3; }

  .okladka { align-items: flex-start; gap: 0.5rem; }
  .okladka-marka { padding-left: 0.5em; padding-right: 0; }
  .okladka-marka { font-size: 0.62rem; letter-spacing: 0.4em; }
  .okladka-h { font-size: clamp(1.6rem, 8vw, 2.2rem); }

  /* ---- zdjęcie w kafelku: na telefonie mocniej odcięte od tła ----
     ⚠️ 3:2 TO SUFIT, NIE PRZYPADEK. Próbowaliśmy 4:3 i tekst kafelka zjeżdżał
     41 px POD ZGIĘCIE przy 390×844, czyli na telefonie odniesienia. Wyżej
     zdjęcie rosnąć nie może bez zabrania miejsca imionom i odnośnikowi. */
  /* ---- na telefonie MOZAIKA, nie pasek pod spodem ----
     ⚠️ To jest decyzja o WYSOKOŚCI, nie o wyglądzie. Duże zdjęcie na całą
     szerokość plus pasek pod nim ma na telefonie ~280 px i wypycha odnośnik
     „Zobacz pełen reportaż" pod zgięcie. Ten sam komplet ułożony w mozaikę —
     duże po lewej, dwa kadry w słupku po prawej — mieści się w ~165 px,
     czyli MNIEJ, niż zajmowało samo duże zdjęcie.
     ⚠️ Trzeci kadr nie jest tu chowany, tylko NIEBUDOWANY — `oferta.js`
     stawia na telefonie dwa. `display: none` chowa, ale nie anuluje
     pobierania. */
  .rolka-kadry { grid-template-columns: minmax(0, 1fr) minmax(0, 0.42fr); }
  .rolka-mini {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: repeat(2, minmax(0, 1fr));
  }
  .rolka-mini-kadr { aspect-ratio: auto; opacity: 1; }

  /* ---- OKŁADKA JAKO PRZEWRACANY ALBUM (2026-09-09) ----------------
     Zdjęcie pary jest TŁEM CAŁEJ OKŁADKI i przewraca się jak kartka;
     tytuł, akapit, przycisk i pasek reportażu leżą na nim. Klasę
     `kartka-czynna` stawia `kartka.js` i tylko wtedy, gdy naprawdę zbudował
     płótno — bez niej (szeroki ekran, brak skryptu, brak płótna 2D) okładka
     zostaje kolumną z mozaiką, dokładnie taką jak przedtem.

     🔴 TO JEST ŚWIADOMY POWRÓT DO UKŁADU ZDJĘTEGO 2026-08-24. Powód tamtej
     decyzji stoi w komentarzu wyżej i był słuszny: poziome 4:3 w pionowym
     oknie pokazywało ~25% kadru, a na tę ćwiartkę nachodziły cztery warstwy
     treści. Wraca, bo zmieniły się OBIE przyczyny:
       • każda para ma teraz `pion.webp` — kadr 880×1560 przycięty pod
         telefon, więc nic się nie przycina na siłę,
       • warstwy zeszły do JEDNEJ: cała treść siada w dolnej części nad
         przyciemnieniem, karta pary spłaszczyła się do paska bez ramki
         i tła, a górna połowa kadru zostaje pusta.
     Zmieniając to, przeczytaj najpierw tamten komentarz — wraca się tam,
     skąd się przyszło.

     ⚠️ MOZAIKA ZNIKA CAŁA, RAZEM Z POBIERANIEM. `display: none` na
     `.rolka-kadry` nie tylko ją chowa — przeglądarka nie pobiera tła
     elementu, którego nie ma w układzie. `plakat.webp` (204 kB), `kadr-1`
     i `kadr-2` przestają być pobierane. */

  .kartka-czynna .of-hero.of-hero--okladka {
    /* treść na DÓŁ — górna połowa kadru ma zostać pusta */
    justify-content: flex-end;
    padding-top: clamp(4.5rem, 11vh, 5.5rem);
    padding-bottom: clamp(1.1rem, 2.6vh, 1.6rem);
    /* ⚠️ Odstępy ścięte z 1,9vh do 1,2vh: treść stoi teraz jednym blokiem na
       zdjęciu, a każdy oddany piksel to piksel kadru. Bilans jest zamknięty —
       dokładając wiersz, odbierz go czemuś innemu. */
    gap: clamp(0.45rem, 1.2vh, 0.8rem);
    /* ruch w bok należy do kartki, ruch w pionie do strony */
    touch-action: pan-y;
  }

  /* płótno leży POD wszystkim; to ono jest tłem okładki */
  .rolka-plotno {
    position: absolute;
    inset: 0;
    z-index: 0;
    display: block;
    width: 100%; height: 100%;
    background: #0b0d0e;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    -webkit-user-select: none;
  }

  /* ⚠️ TO NIE JEST SAMO PRZYCIEMNIENIE — TO RAMA KADRU (2026-09-09).
     Zdjęcie nadal wypełnia cały ekran, ale u góry i u dołu ROZPŁYWA SIĘ
     w kolorze strony (`--bg`), więc widać z niego wyraźny pas mniej więcej
     między 14% a 60% wysokości. Trzy rzeczy naraz:
       • kadr jest „ścieśniony" bez ani jednej twardej krawędzi — nie ma
         czarnych pasów jak w listwie filmowej, jest miękkie wyjście w tło,
       • napisy przestają leżeć NA zdjęciu: dół okładki jest już prawie
         czarny, zanim zacznie się tytuł,
       • okładka wpływa w następną sekcję bez szwu, bo kończy się dokładnie
         kolorem tła strony.
     ⚠️ Ostatnie stopnie muszą trzymać `--bg` (#0a0c0d), a nie „jakąś czerń".
     Przy rgba(6,7,8,1) na styku okładki i sekcji niżej widać było kreskę. */
  .kartka-mrok {
    position: absolute; inset: 0; z-index: 1; pointer-events: none;
    background:
      linear-gradient(to bottom,
        rgba(10, 12, 13, 0.97) 0%,
        rgba(10, 12, 13, 0.62) 6%,
        rgba(10, 12, 13, 0.14) 15%,
        rgba(10, 12, 13, 0.12) 42%,
        rgba(10, 12, 13, 0.48) 58%,
        rgba(10, 12, 13, 0.84) 71%,
        rgba(10, 12, 13, 0.96) 82%,
        rgba(10, 12, 13, 1) 92%,
        rgba(10, 12, 13, 1) 100%),
      radial-gradient(96% 46% at 50% 30%, rgba(10, 12, 13, 0) 0%, rgba(10, 12, 13, 0.34) 100%);
  }

  .kartka-czynna .okladka,
  .kartka-czynna .rolka,
  .kartka-czynna .rolka-ster { position: relative; z-index: 2; }

  /* ⚠️ KARTA PARY SPŁASZCZA SIĘ DO PASKA. Ramka, tło i rozmycie miały sens,
     gdy karta leżała na ciemnej kolumnie; na zdjęciu robią z niej drugie
     pudełko w pudełku. Zostaje sama treść: numer, imiona, data i wyjście
     do galerii — bo to jedyna droga z okładki do reportażu i nie wolno jej
     zgubić (ta sama pułapka co przy „kuli w tle", `galeria-sfera\`). */
  .kartka-czynna .rolka-kadry { display: none; }
  .kartka-czynna .rolka-karta {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    box-shadow: none;
  }
  .kartka-czynna .rolka-karta::after { display: none; }
  .kartka-czynna .rolka-opis { padding-top: 0.2rem; }
  .kartka-czynna .rolka-para,
  .kartka-czynna .rolka-meta,
  .kartka-czynna .rolka-cta { text-shadow: 0 1px 10px rgba(0, 0, 0, 0.75); }

  /* ⚠️ KROPKI SIADAJĄ W JEDNYM RZĘDZIE Z WYJŚCIEM DO GALERII, a nie pod nim.
     `.rolka-opis` dostaje wcięcie po prawej, żeby „Zobacz pełen reportaż"
     nie wchodziło pod sterowanie — bez tego oba napisy nachodziły na siebie
     (sprawdzone: kropki lądowały 26 px NA odnośniku).
     Sterowanie przenosi do opisu `kartka.js`; gdy go nie ma, kropki stoją
     tam, gdzie stały. */
  /* ⚠️ MNIEJ NAPISÓW NA ZDJĘCIU (2026-09-09). Z okładki schodzą trzy rzeczy,
     z których ŻADNA nie niosła frazy do wyszukiwarki:
       `.okladka-kreska` — czysta ozdoba między nadpisem a tytułem,
       `.rolka-nr`       — numer reportażu; kropki mówią to samo, obok,
       `.rolka-meta`     — data i miejsce; to szczegół dla galerii pary,
                           a nie dla pierwszego ekranu oferty.
     Zostaje pięć bloków zamiast ośmiu. Frazy („fotograf ślubny", „Kraków",
     „reportaż ślubny") siedzą w nadpisie i w akapicie — obie rzeczy zostają
     na miejscu, widoczne dla Klienta i dla robota tak samo. */
  .kartka-czynna .okladka-kreska,
  .kartka-czynna .rolka-nr,
  .kartka-czynna .rolka-meta { display: none; }

  /* ⚠️ AKAPIT SKRACA SIĘ, NIE ZNIKA. Ogon zdania („, od cichych przygotowań
     do ostatniego tańca nad ranem") schodzi tylko z telefonu i tylko wtedy,
     gdy okładka jest zdjęciem — na komputerze akapit zostaje w całości.
     Kropka stoi poza tym wycinkiem, więc krótsza wersja też jest zdaniem
     skończonym. Powód, dla którego akurat ten kawałek: nie ma w nim ani
     jednej frazy (opis przy akapicie w `index.html`). */
  .kartka-czynna .okladka-p-dalej { display: none; }

  .kartka-czynna .rolka-opis { position: relative; }
  .kartka-czynna .rolka-cta { padding-right: 5.4rem; }
  .kartka-czynna .rolka-ster {
    position: absolute;
    right: 0;
    bottom: 0.15rem;
    margin: 0;
    width: auto;
    justify-content: flex-end;
  }
  /* ⚠️ STRZAŁKI SCHODZĄ Z TELEFONU — i to jest ta sama decyzja, którą serwis
     podjął już przy strzałkach przy krawędziach okładki: „telefon ma zresztą
     coś lepszego — przewracanie palcem po całej okładce". Odkąd gest łapie
     CAŁY pierwszy ekran, dwa przyciski po 44 px tylko powtarzają to, co robi
     kciuk, a zabierają rząd, w którym musi się zmieścić „Zobacz pełen
     reportaż". Kropki zostają: pokazują, ile reportaży czeka, i dalej się
     klikają. */
  .kartka-czynna .rolka-strzalka { display: none; }

  /* ⚠️ ZJAZD ROLKI WYŁĄCZONY. `oferta.js` przesuwa kadr i kartę o
     `--rolka-przes` przy zmianie reportażu; tutaj ruchem JEST przewrócenie
     kartki, więc drugi ruch pod spodem tylko by go rozmywał. */
  .kartka-czynna .rolka { transform: none; opacity: 1; }

  .rolka-okno {
    /* stuknięcie w zdjęcie prowadzi do galerii pary — na telefonie to
       pierwszy odruch, a odnośnik pod spodem zostaje dla czytelności */
    -webkit-tap-highlight-color: transparent;
  }
  /* ---- film w oknie ----
     Leży NAD plakatem (tłem okna) i przenika dopiero, gdy jest gotowy —
     dzięki temu nie ma czarnego prostokąta w trakcie wczytywania, a przy
     braku pliku, oszczędzaniu danych albo `prefers-reduced-motion` w oknie
     po prostu zostaje zdjęcie.
     ⚠️ `pointer-events: none` — całe okno jest odnośnikiem do galerii
     i wideo nie może przechwytywać stuknięcia. */
  .rolka-okno-v {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    opacity: 0;
    transition: opacity 0.7s var(--ease);
    pointer-events: none;
  }
  .rolka-okno-v.is-on { opacity: 1; }


  /* ---- kafelek: z warstwy nad zdjęciem staje się zwykłym blokiem ----
     Pole dotyku na cały kafelek i `position: relative` stoją od 2026-08-26
     w regule podstawowej — na komputerze działają tak samo. */
  /* ⚠️ NA TELEFONIE KAFELKA SIĘ NIE PRZESUWA — stoi w normalnym przepływie
     i każdy odsunięty piksel byłby dziurą w układzie. Skrypt i tak nie
     podpina tam przeciągania, ale zerujemy przesunięcie także w arkuszu,
     na wypadek obrotu telefonu z odsuniętym kafelkiem. */
  .rolka {
    position: static;
    width: auto;
    left: auto; right: auto; top: auto; bottom: auto;
    translate: none;
    cursor: auto;
    /* Nie ma przeciągania — nie ma powodu odbierać zaznaczania. */
    user-select: auto;
    -webkit-user-select: auto;
  }
  /* ⚠️ CIEPŁE TŁO KART „FOTO + WIDEO" ZDJĘTE NA TELEFONIE (2026-08-28).
     Ten gradient miał POKAZYWAĆ RÓŻNICĘ między dwiema półkami stojącymi
     OBOK SIEBIE — droższa była o ton cieplejsza od tańszej. Od czasu zakładek
     półki nigdy nie są widoczne naraz: karta nie ma się z czym porównać,
     więc złoty odcień przestał znaczyć „droższa" i zaczął wyglądać po prostu
     jak dziwny gradient. Na wąskim ekranie, gdzie karta zajmuje 80% szerokości,
     widać go najmocniej.
     Podział niesie teraz sama zakładka — ta wybrana jest podświetlona. */
  .pak-grupa--wideo .pak {
    background: linear-gradient(155deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.012));
    border-color: var(--line);
  }
  .pak-grupa--wideo .pak--top { border-color: rgba(200, 176, 138, 0.55); }

  /* ⚠️ NIE MA PRZECIĄGANIA — NIE MA CO ZAPOWIADAĆ. Uchwyt znika razem
     z funkcją, którą oznacza. Samo „nie da się najechać palcem" nie
     wystarczy: na dotyku `:hover` potrafi zostać przyklejony po stuknięciu
     i kropki wisiałyby na kafelku, obiecując ruch, którego tu nie ma. */
  .rolka-karta::after { display: none; }
  .rolka-karta {
    --karta-pad: 0.9rem;
    background: rgba(255, 255, 255, 0.035);
    backdrop-filter: none; -webkit-backdrop-filter: none;
    box-shadow: none;
  }
  .rolka-karta:hover,
  .rolka-karta:focus-within { box-shadow: none; }
  /* sterowanie wraca do przepływu, nad kafelek */
  .rolka-ster {
    position: static;
    transform: none;
    left: auto; bottom: auto; top: auto;
    justify-content: center;
  }

  /* ⚠️ „PRZEWIŃ W DÓŁ" ZNIKA NA TELEFONIE. Wskaźnik jest przyklejony
     (`position: absolute; bottom: 2.2rem`) do DNA okładki, a ta nie kończy się
     już na krawędzi ekranu — ma tyle wysokości, ile trzeba na zdjęcie i kartę.
     Napis lądował więc pod zgięciem, czyli w miejscu, do którego trzeba
     przewinąć, żeby przeczytać, że można przewijać. Na telefonie ta zachęta
     jest zresztą zbędna: karta pary jest widocznie ucięta krawędzią ekranu
     i to wystarczy za zaproszenie. */
  .of-hero--okladka .scroll-hint { display: none; }

  .of-hero { min-height: 54vh; }
  .of-hero-cta .ig-btn { padding: 0.9rem 1.6rem; font-size: 0.66rem; letter-spacing: 0.2em; }

  /* ---- pakiety na telefonie ----
     Jedna kolumna i KOLEJNOŚĆ Z HTML, czyli od najtańszego do najdroższego.
     Wcześniej wyróżniony pakiet wskakiwał na górę (`order: -1`) — przy trzech
     kartach to działało, przy czterech rozbija drabinę cen: czytający przewija
     3 000 → 6 900 → 4 900 i przestaje rozumieć, co z czego wynika. Wyróżnienie
     niesie sam złoty obrys i znacznik.
     ⚠️ ETYKIETY GRUP ZOSTAJĄ. Na telefonie to jedyny sygnał, że po trzech
     kartach zaczyna się inna półka oferty — bez nich pięć kart jedna pod drugą
     czyta się jak jeden ciąg. Przerwa między grupami jest za to większa niż
     między kartami, żeby podział był widoczny bez patrzenia na napis. */
  /* ---- KARTY JADĄ W BOK, NIE W DÓŁ (2026-08-28) ----------------
     Pięć pakietów jedna karta pod drugą dawało na telefonie ok. 2400 px
     pionu: żeby porównać „Ceremonię" z „Pełnym dniem", trzeba było
     przewinąć trzy ekrany i zapamiętać, co się widziało. Teraz karty stoją
     OBOK SIEBIE, a przewija się je kciukiem w bok — porównanie wraca
     do jednego gestu.

     ⚠️ TO ZWYKŁE PRZEWIJANIE, NIE KARUZELA NA SKRYPCIE. Cały ruch robi
     `overflow-x` z zatrzaskiem (`scroll-snap`), więc działa BEZ
     JavaScriptu, z klawiaturą i z czytnikiem ekranu — a strzałki niżej
     są tylko wygodniejszym uchwytem do tego samego. Kod, którego brak
     nic nie psuje, jest tu wart więcej niż własna obsługa gestu.

     ⚠️ 84% SZEROKOŚCI, NIE 100% — i to jest cały sygnał „jedź dalej".
     Przy pełnej szerokości karta wypełnia ekran co do piksela i nic nie
     zdradza, że po prawej coś jest. Wystający skrawek sąsiadki mówi to
     bez ani jednego słowa (ta sama zasada co przy karcie pary na okładce).

     ⚠️ TYLKO W STANIE A. Po wybraniu pakietu grupy i tak znikają
     (`.kalk.ma-pakiet .pak-grupa`), a karta leci FLIP-em liczonym
     z `offsetLeft` — przewijalny kontener dokładałby do tego przesunięcie,
     którego układ nie widzi. W stanie B nie ma więc żadnej karuzeli. */
  .pak-scena { gap: 2.6rem; }
  .kalk:not(.ma-pakiet) .pak-karty {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;
    gap: 1rem;
    /* ⚠️ MIEJSCE NA ZNACZNIK „najczęściej wybierany" I NA CIEŃ KARTY.
       `overflow-x: auto` WYMUSZA `overflow-y: auto` — nie da się mieć
       przewijania w bok i widocznego przelewania w pionie naraz, taka jest
       specyfikacja. A znacznik wystaje 0,7 rem PONAD kartę
       (`.pak-tag`, `top: -0.7rem`), więc pas go po prostu ucinał.
       Zmierzone przed poprawką: górna krawędź znacznika 6 px nad krawędzią
       pasa, czyli ucięta.
       Wyściółka robi mu miejsce W ŚRODKU pasa, a ujemny margines oddaje te
       piksele układowi — sekcja nie rośnie ani o jeden. */
    padding: 0.95rem 0.2rem 0.9rem;
    margin: -0.95rem -0.2rem -0.9rem;
    scrollbar-width: none;
    -ms-overflow-style: none;
  }
  .kalk:not(.ma-pakiet) .pak-karty::-webkit-scrollbar { display: none; }
  .kalk:not(.ma-pakiet) .pak-karty > .pak {
    /* 80%, nie 84%: przy 84% sąsiadka wystawała 43 px, przy 80% — 52 px,
       czyli widać już jej lewą krawędź z zaokrągleniem, a nie sam pasek tła. */
    flex: 0 0 80%;
    scroll-snap-align: center;
  }
  /* 🔴 ODSŁANIANIE (`.reveal`) NIE DZIAŁA W POZIOMEJ KARUZELI — i to była
     przyczyna DWÓCH zgłoszonych objawów naraz.
     `.reveal` to krycie 0 i przesunięcie o 34 px w dół, a zdejmuje je
     obserwator przecięcia z OKNEM. W karuzeli karty stoją jedna obok drugiej
     POZA ekranem: zmierzone przy 390 px — trzecia karta na x 619–901, czyli
     nigdy się z oknem nie przecina i zostaje niewidoczna NA ZAWSZE.
     Druga odsłania się dopiero, gdy Klient ją przesunie — i wtedy wjeżdża
     z dołu, co czyta się jako „karty się przesuwają".
     W poziomym pasie karty mają po prostu BYĆ. Odsłanianie zostaje na
     komputerze, gdzie cały rząd wchodzi w kadr naraz. */
  .kalk:not(.ma-pakiet) .pak-karty > .pak.reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  /* Stan B: karty wracają do słupka — patrz uwaga wyżej. */
  .kalk.ma-pakiet .pak-karty { gap: 2rem; }
  .kalk.ma-pakiet .pak-karty > .pak { flex: 0 0 100%; }
  .pak--top { order: 0; }

  /* ---- STRZAŁKI PRZY ETYKIECIE GRUPY ----
     Dokłada je `oferta.js` (blok 1d) i tylko na telefonie. Stoją na końcu
     etykiety, za włosem, więc nie zabierają ani jednego wiersza wysokości.
     ⚠️ Są POWTÓRZENIEM gestu, nie jedyną drogą — stąd `aria-hidden` przy
     samym znaku i pełna nazwa w `aria-label`. */
  /* ---- ZAKŁADKI NA TELEFONIE ----
     Dwie zakładki obok siebie NAD kartami, nie w kolumnie po lewej: przy
     390 px kolumna zjadłaby połowę szerokości karty. */
  .pak-scena {
    display: block;
  }
  .pak-zakladki {
    flex-direction: row;
    gap: 0.5rem;
    margin-bottom: clamp(0.9rem, 2.5vw, 1.4rem);
  }
  .pak-zakladka { flex: 1 1 0; align-items: flex-start; }
  .pak-zakladka-ile { font-size: 0.72rem; }

  /* Pasek na strzałki karuzeli — dokłada go `oferta.js` (blok 1d).
     ⚠️ Stoi NAD kartami, w miejscu, które i tak zostaje po zakładkach;
     pod kartami zabrałby wiersz wysokości sekcji. */
  .pak-strzalki {
    display: flex; justify-content: flex-end; gap: 0.5rem;
    margin-bottom: 0.5rem;
  }
  /* ⚠️ W WYCENIE STRZAŁEK NIE MA. Została jedna karta, więc nie ma czego
     przewijać — a strzałki obiecywały ruch, którego tam nie ma. Chowa je
     arkusz, nie skrypt: stan sekcji niesie klasa `ma-pakiet`, a element,
     który ma zniknąć razem ze stanem, nie potrzebuje do tego kodu. */
  .kalk.ma-pakiet .pak-strzalki { display: none; }
  .pak-strz {
    flex: 0 0 auto;
    width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    border: 1px solid var(--line);
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.04);
    color: var(--ink);
    font-size: 0.9rem; line-height: 1;
    transition: opacity 0.3s var(--ease), border-color 0.3s var(--ease), color 0.3s var(--ease);
  }
  .pak-strz:disabled { opacity: 0.22; }
  .pak-strz:not(:disabled):active { border-color: var(--gold); color: var(--gold); }

  .pak { padding: 1.5rem 1.35rem; }
  .pak-name { font-size: 1.35rem; }
  .pak-note { font-size: 0.88rem; margin-bottom: 1rem; }
  .pak-list { margin-bottom: 1.2rem; padding-top: 0.9rem; }

  .zak-grid { grid-template-columns: 1fr 1fr; gap: 1.2rem; }

  /* ---- kalkulator na telefonie ----
     Jedna kolumna: wybrana karta, pod nią wybory, na końcu podsumowanie.
     Karta wyceny przestaje być przyklejona (zjadłaby pół ekranu), a bieżącą
     kwotę niesie przyklejony pasek kroków.
     ⚠️ Tu nic nie jedzie w bok — `.of-wybor` zostaje jednokolumnowy (dzielenie
     szerokości włącza się dopiero od 1360 px). Odrzucone karty i tak gasną,
     więc ekran po wyborze robi się krótszy i to wystarczy za sygnał. */
  .of-wybor { gap: 1.8rem; }
  .kalk-sum { position: static; }
  .kalk-opts { gap: 2.2rem; }

  /* ⚠️ ZDEJMUJEMY `--krok-wys` — to była najgorsza rzecz na telefonie.
     Kolumna kroków ma na komputerze wysokość NAJWYŻSZEGO kroku, żeby
     przyklejona karta z podsumowaniem nie skakała przy każdym „Dalej".
     Na telefonie karta nie jest przyklejona (`position: static` wyżej), więc
     nie ma czego stabilizować — a rachunek wygląda tak: krok „Pakiet"
     potrzebuje 434 px, krok „Dodatki" 1102 px, więc pod pięcioma kafelkami
     pakietów zostawało 668 PIKSELI PUSTKI, a dopiero pod nią przycisk „Dalej".
     Stąd wrażenie, że ekran jest rozjechany i że nie da się kliknąć dalej. */
  .ma-kroki .kalk-blok[data-krok].is-krok-on { min-height: 0; }

  /* ---- kroki na telefonie ----
     Pasek kroków nie zmieści trzech opisów obok siebie, więc zostają same
     nazwy z numerem, a podpisy znikają. Przyciski „Wstecz/Dalej" dostają
     pełne pola dotyku i rozpychają się na całą szerokość. */
  .kalk-stepper { gap: 0.4rem; margin-bottom: 1.6rem; }
  .kalk-stepper-opis { display: none; }
  .kalk-stepper-nazwa { font-size: 0.9rem; }

  /* ---- PASEK KROKÓW PRZYKLEJONY DO DOŁU ----
     ⚠️ To jest odpowiedź na „ciężko kliknąć dalej". Krok „Dodatki" ma na
     telefonie ponad 1100 px, więc „Dalej" leżało pod dziewięcioma pozycjami;
     a kiedy się już do niego doszło, w dolnych ~63 px ekranu siedziała
     pigułka z sumą, a pod nią pasek postępu. Przycisk bywał dosłownie
     przykryty. Teraz pasek jedzie razem z treścią i zatrzymuje się nad
     paskiem postępu — „Dalej" jest pod kciukiem przez cały krok.

     ⚠️ `--pasek` (wysokość paska postępu) mierzy `oferta.js`; 3rem to wartość
     zapasowa na wypadek wyłączonego JS. Bez tego przy jednej wysokości paska
     przycisk siedziałby na kropkach, a przy innej wisiał nad nimi w powietrzu.
     ⚠️ `position: sticky` UMIERA pod przodkiem z `overflow: hidden` — dlatego
     ten pasek musi zostać bezpośrednim dzieckiem `.kalk-blok`/`.kalk-opts`,
     a nie trafić do żadnego kontenera z przycinaniem. */
  .kalk-nawigacja {
    position: sticky;
    bottom: calc(var(--pasek, 3rem) + 0.5rem);
    z-index: 100;                    /* nad treścią, pod paskiem (115) */
    /* ⚠️ SIATKA, NIE FLEX Z ZAWIJANIEM. Cztery elementy w dwóch rzędach
       (kwota · numer kroku / Wstecz · Dalej) muszą stanąć TAK SAMO przy każdej
       szerokości i przy każdej długości napisu — „Dalej" zmienia się na
       ostatnim kroku w „Zobacz podsumowanie". Przy `flex-wrap` to, gdzie
       wypada łamanie, zależałoby od długości tekstu i jeden krok wyglądałby
       inaczej niż drugi. Dwie równe kolumny dają też oba przyciski tej samej
       szerokości, co jest ważniejsze, niż się wydaje: kciuk uczy się miejsca. */
    display: grid;
    grid-template-columns: 1fr 1fr;
    grid-template-areas: "suma licznik" "wstecz dalej";
    align-items: center;
    row-gap: 0.55rem; column-gap: 0.6rem;
    margin-top: 1.4rem;
    padding: 0.7rem 0.75rem;
    border: 1px solid rgba(200, 176, 138, 0.34);
    border-radius: 16px;
    background: rgba(10, 12, 13, 0.94);
    backdrop-filter: blur(12px) saturate(1.1);
    -webkit-backdrop-filter: blur(12px) saturate(1.1);
    box-shadow: 0 18px 44px rgba(0, 0, 0, 0.6);
  }
  .kalk-nav { justify-content: center; padding: 0.85rem 0.9rem; min-height: 44px; }
  /* kwota przejmuje robotę pigułki: stoi w pasku, nad przyciskami,
     obok numeru kroku — jedno spojrzenie zamiast dwóch pływających okienek */
  .kalk-nav-suma {
    grid-area: suma; display: block;
    font-family: var(--serif); font-size: 1.15rem; line-height: 1;
    color: var(--gold); text-align: left;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .kalk-nav-licznik { grid-area: licznik; justify-self: end; }
  .kalk-nav--wstecz { grid-area: wstecz; }
  .kalk-nav--dalej { grid-area: dalej; }

  .kalk-opt { padding: 0.85rem 0.8rem; gap: 0.75rem; }
  /* 2.3rem to na komputerze dość, ale palcem trafia się w 44 px – tyle mają
     u nas wszystkie okrągłe przyciski na telefonie (np. strzałki podglądu) */
  .kalk-step-btn { width: 2.75rem; height: 2.75rem; font-size: 1.1rem; }
  .kalk-step-info { flex: 1 0 100%; }
  /* zapas na pasek postępu, żeby nie zakrył końca karty z podsumowaniem
     (dawniej było tu też miejsce na pigułkę — ta zniknęła 2026-08-24) */
  .kalk .wrap { padding-bottom: clamp(3.5rem, 9vh, 5rem); }

  /* ---- POLA DOTYKU ----
     Odnośniki-napisy ze złotą kreską mają na komputerze 23–26 px wysokości,
     co dla myszy jest dość, a dla kciuka nie. Zamiast powiększać krój,
     rozpychamy samo pole dotyku do 44 px — wygląd zostaje ten sam.
     ⚠️ `.pak-cta` i `.rolka-cta` są `inline-flex`, więc `min-height`
     bez `align-items` nie wyrównałoby napisu do środka. */
  .pak-cta,
  .rolka-cta { min-height: 44px; align-items: center; }
  .kalk-reset { min-height: 44px; padding: 0.5rem 0; }
  /* wiersz FAQ schodzi przy 390 px do 43 px — jeden piksel pod progiem
     kciuka, więc dokładamy dolną granicę zamiast rozpychać wyściółkę */
  body.oferta .faq-q { min-height: 44px; }


  /* pasek postępu: ciaśniej, żeby nazwa sekcji zmieściła się w jednej linii */
  .pasek-in { gap: 0.7rem; padding: 0.5rem 0.9rem; }
  .pasek-nazwa { font-size: 0.92rem; }
  .pasek-kropki { gap: 0.42rem; }
}

/* ============================================================
   Wąski telefon (do 560 px)
   ============================================================
   Poniżej 560 px kończą się kompromisy: to, co da się złożyć w pion,
   idzie w pion, a to, na co nie ma miejsca, znika — byle nic się nie ścisnęło
   do nieczytelności i byle strona nigdzie nie przewijała się w bok.
   ============================================================ */
@media (max-width: 560px) {
  .of-hero.of-hero--okladka {
    padding: clamp(4.2rem, 12vh, 5.4rem) 1.1rem clamp(4rem, 10vh, 5rem);
  }

  /* ---- kalkulator ----
     Cena schodzi POD nazwę. W trzech kolumnach (kwadrat · tekst · cena) na
     320 px zostawało tekstowi ~150 px, a „Voucher na mini sesję" łamał się na
     cztery wiersze obok samotnego „+500 zł". */
  .kalk-opt { grid-template-columns: auto minmax(0, 1fr); row-gap: 0.35rem; }
  .kalk-opt .kalk-cena { grid-column: 2; padding-top: 0; }
  .kalk-legend { font-size: 0.64rem; letter-spacing: 0.18em; margin-bottom: 0.9rem; }
  /* trzy nazwy kroków obok siebie na 320 px to trzy słupki po jednej literze —
     zostają same numery, a nazwę bieżącego kroku niesie legenda pod spodem */
  .kalk-stepper-nazwa { display: none; }
  .kalk-stepper { grid-auto-columns: minmax(0, 1fr); gap: 0.35rem; }
  .kalk-step-val { min-width: 3.6rem; }

  /* dwie kolumny po ~150 px to dwa słowa na wiersz */
  .zak-grid { grid-template-columns: minmax(0, 1fr); gap: 1.6rem; }

  /* ---- pasek postępu ----
     Siedem kropek po 7 px z odstępami to ~85 px, których nie ma obok nazwy
     sekcji i dwóch strzałek. Kropki wypadają; skok o sekcję zostaje, bo to
     jedyny sposób nawigacji, którego nie da się zastąpić palcem. */
  .pasek-kropki { display: none; }
  .pasek-nazwa { font-size: 0.86rem; }
  .pasek-in { gap: 0.55rem; padding: 0.45rem 0.8rem; }

  .pak-tag { font-size: 0.52rem; letter-spacing: 0.16em; }
}

/* ============================================================
   Niski telefon (≤700 px wysokości) — okładka schodzi do esencji
   ============================================================
   Okładka nie ma już stałej wysokości: rośnie pod tytuł, zdjęcie 16:9
   i kartę pary. Na ekranie 844 px mieści się to w kadrze, na 640 px karta
   wystaje o ~120 px. Nie jest to błąd — po okładce się przewija — ale ładniej,
   gdy pierwszy ekran pokazuje komplet, więc tytuł oddaje tu trochę wzrostu.

   ⚠️ Próg 700 px, nie 760: Google renderuje strony mobilnie w oknie
   ~412×732, więc powyżej 700 px nic się nie zmienia i robot widzi pełny
   akapit wstępu z frazami.
   ============================================================ */
@media (max-width: 860px) and (max-height: 700px) {
  .of-hero.of-hero--okladka { gap: 0.7rem; }
  .okladka-h { font-size: clamp(1.35rem, 6.4vw, 1.8rem); }
  .okladka-p { font-size: 0.84rem; line-height: 1.5; }
  .okladka .ig-btn { padding: 0.75rem 1.3rem; }
  .rolka-karta { padding: 0.8rem 0.9rem; }
}

/* ============================================================
   Niskie ekrany (leżący telefon, okno przyklejone do połowy pulpitu)
   ============================================================
   Przy wysokości poniżej 520 px okładka na cały ekran zostawiałaby z treści
   sam tytuł wciśnięty między ramy — schodzi więc do samej esencji.
   ============================================================ */
@media (max-height: 520px) {
  .okladka { gap: 0.35rem; }
  .okladka-h { font-size: clamp(1.2rem, 4.4vh, 1.7rem); }
  .okladka-p { display: none; }
  /* przy tej wysokości zdjęcia w kafelku i tak nie mają gdzie się rozłożyć —
     zostaje sama nazwa pary, data i odnośnik do galerii */
  .rolka-kadry { display: none; }
}

/* ============================================================
   Ograniczony ruch
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  /* mozaika: kadr pod kursorem nadal się powiększa (to sedno paska), ale
     bez animacji — zmiana jest natychmiastowa, nic nie „jedzie" po ekranie */
  .mozaika-kafel { transition: none; }
  .mozaika-kafel img { transition: none; }
  .pasek { transition: none; }
  .pasek-postep { transition: none; }
  .kalk-total-val.bump { animation: none; }
  .ma-kroki .kalk-blok[data-krok].is-krok-on { animation: none; }
  /* ---- najazd na pakiet ----
     Zostaje ZAPALENIE (złoty obrys, poświata, ciepły tekst) — to jest
     informacja: „stoisz na tej karcie". Znika sam RUCH: uniesienie,
     powiększenie i przeciągany połysk. */
  .pak { transition: border-color 0.2s, box-shadow 0.2s; }
  .pak::before { transition: none; }
  .pak:hover, .pak:focus-within { scale: 1; translate: none; }
  .pak:hover::after, .pak:focus-within::after { opacity: 0; animation: none; }
  /* ---- przejście do wyceny ----
     Zostaje sama ZMIANA UKŁADU: karta po prostu jest już po lewej, a obok
     stoi kalkulator. Znika lot karty (`oferta.js` sam pomija FLIP przy
     `prefers-reduced-motion`), gaśnięcie odrzuconych kart i wjazd kolumn. */
  .pak.is-poza { transition: none; scale: 1; }
  .kalk.ma-pakiet .kalk-opts,
  .kalk.ma-pakiet .kalk-sum,
  .kalk.ma-pakiet .kalk-grupa { animation: none; }
  /* Karuzela pakietów przeskakuje do karty, zamiast do niej dojeżdżać.
     ⚠️ `oferta.js` podaje `behavior: "auto"` przy ograniczonym ruchu i tak,
     ale jawna opcja w skrypcie BIJE arkusz, a nie odwrotnie — więc obie
     drogi muszą być domknięte osobno: ta reguła obsługuje przewinięcia,
     których skrypt nie wywołał (gest, klawiatura, zatrzask). */
  .kalk:not(.ma-pakiet) .pak-karty { scroll-behavior: auto; }
  /* Panel podsumowania wchodzi bez animacji — po prostu jest. */
  .kalk-sum.is-panel { animation: none; }
}

/* ============================================================
   KALENDARZ WOLNYCH TERMINÓW (2026-09-03)
   ============================================================
   Siatka miesiąca, w której każdy dzień ma jeden z trzech stanów: wolny,
   zajęty albo miniony. Stan jest zakodowany W KSZTAŁCIE, nie tylko w kolorze
   — zajęty dzień dostaje przekreślenie, miniony gaśnie — bo na samym kolorze
   nie może opierać się informacja, od której zależy, czy ktoś napisze.

   ⚠️ TYDZIEŃ ZACZYNA SIĘ W PONIEDZIAŁEK. `Date.getDay()` liczy od niedzieli
   i to jest najczęstszy błąd w ręcznie robionych kalendarzach; przeliczenie
   siedzi w `oferta.js` przy budowaniu siatki.
   ⚠️ Siatka ma ZAWSZE 7 kolumn i całkowitą liczbę wierszy — dni z sąsiednich
   miesięcy nie są rysowane, tylko zostawiają puste miejsca. Kalendarz ma
   odpowiadać na pytanie o jeden miesiąc, a nie udawać terminarza.
   ============================================================ */
.of-termin[hidden] { display: none; }

.kal {
  /* Smuklejszy: węższa ramka, ciaśniejsza wyściółka i spłaszczone
     komórki dni. Kalendarz ma być drobnym narzędziem w kroku, a nie
     drugim panelem obok wyceny. */
  max-width: 25rem;
  margin: clamp(1.1rem, 2.8vh, 1.8rem) auto 0;
  padding: clamp(0.8rem, 2.2vw, 1.15rem);
  border: 1px solid var(--line);
  border-radius: 14px;
  background: rgba(255, 255, 255, 0.022);
}

.kal-gora {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.8rem; margin-bottom: 0.8rem;
}
.kal-miesiac {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(1.15rem, 3.4vw, 1.5rem);
  letter-spacing: 0.02em;
  text-align: center;
  flex: 1;
}
.kal-strzalka {
  width: 30px; height: 30px; padding: 0; flex: none;
  display: grid; place-items: center;
  border: 1px solid rgba(200, 176, 138, 0.4); border-radius: 50%;
  background: transparent;
  transition: border-color 0.35s var(--ease), background 0.35s var(--ease);
}
.kal-strzalka svg {
  width: 13px; height: 9px;
  fill: none; stroke: var(--gold); stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.kal-strzalka:hover:not([disabled]) { border-color: var(--gold); background: rgba(200, 176, 138, 0.1); }
.kal-strzalka[disabled] { opacity: 0.28; }

.kal-naglowki, .kal-siatka {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 3px;
}
.kal-naglowki {
  margin-bottom: 6px;
  font-size: 0.62rem; letter-spacing: 0.18em; text-transform: uppercase;
  color: var(--ink-dim); text-align: center;
}

/* Dzień: kwadrat, żeby siatka czytała się jak kalendarz, a nie jak lista. */
.kal-dzien {
  /* ⚠️ Komórka SPŁASZCZONA, nie kwadratowa — przy sześciu wierszach
     kwadrat robił z kalendarza najwyższy element całego kroku. */
  aspect-ratio: 1 / 0.8;
  /* ⚠️ Kotwica dla kółka „dziś" (pseudoelement ::before) — bez niej
     ustawiłoby się względem całej siatki, a nie swojego dnia. */
  position: relative;
  display: grid; place-items: center;
  padding: 0;
  border: 1px solid transparent; border-radius: 9px;
  background: rgba(255, 255, 255, 0.035);
  color: var(--ink);
  font: inherit; font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
  transition: border-color 0.3s var(--ease), background 0.3s var(--ease),
              color 0.3s var(--ease);
}
.kal-dzien--pusty { background: none; border-color: transparent; pointer-events: none; }

.kal-dzien--wolny:hover,
.kal-dzien--wolny:focus-visible { border-color: var(--gold); background: rgba(200, 176, 138, 0.14); }


.kal-dzien--wybrany { border-color: var(--gold); background: rgba(200, 176, 138, 0.2); }




/* ---- napis z wybranym terminem ---- */
.kal-wybor {
  margin: 0.7rem 0 0;
  text-align: center;
  font-family: var(--serif);
  font-size: 1.02rem;
  color: var(--gold);
  min-height: 1.5em;                 /* miejsce zarezerwowane — bez skoku układu */
}
.kalk-termin-lid { margin-bottom: 0.9rem; }

/* ============================================================
   ZAKŁADKI KALKULATORA — TECZKI W SZAFCE (2026-09-04)
   ============================================================
   Stepper był wcześniej trzema podpisami z cienką kreską u góry. Krzysztof
   chciał czegoś, co czyta się jak teczki w szafce: aktualna wysunięta
   i podświetlona, następne przygaszone obok.

   ⚠️ AKTYWNA ZAKŁADKA ZJADA LINIĘ POD SOBĄ (`margin-bottom: -1px` przy
   `border-bottom: 0`) — na tym stoi cały efekt teczki. Bez tego zakładka
   jest pudełkiem NAD panelem, a nie jego wysuniętą częścią.
   ⚠️ Kolejność w kodzie ma znaczenie: reguła `.is-on` musi stać PO
   `.is-zrobiony`, bo krok zrobiony i zarazem aktualny ma wyglądać jak
   aktualny.
   ⚠️ Na wąskim ekranie podpisy („Kiedy ślub") znikają — trzy teczki z opisem
   nie mieszczą się poniżej ~560 px i łamią się na cztery wiersze.
   ============================================================ */
.kalk-stepper {
  gap: 3px;
  margin-bottom: 0;
  border-bottom: 1px solid var(--line);
  align-items: end;
}
.kalk-stepper-btn {
  padding: 0.55rem 0.75rem 0.5rem;
  border: 1px solid var(--line);
  border-bottom: 0;
  border-radius: 10px 10px 0 0;
  background: rgba(255, 255, 255, 0.014);
  margin-bottom: -1px;
  opacity: 0.62;
  transition: background 0.4s var(--ease), border-color 0.4s var(--ease),
              opacity 0.4s var(--ease);
}
.kalk-stepper-btn:hover { opacity: 0.85; }
.kalk-stepper-btn.is-zrobiony {
  border-top-color: rgba(200, 176, 138, 0.4);
  opacity: 0.8;
}
.kalk-stepper-btn.is-on {
  background: rgba(200, 176, 138, 0.075);
  border-color: rgba(200, 176, 138, 0.5);
  border-top-color: var(--gold);
  opacity: 1;
}
.kalk-stepper-btn.is-on .kalk-stepper-nazwa { color: var(--ink); }
@media (max-width: 560px) {
  .kalk-stepper-opis { display: none; }
  .kalk-stepper-btn { padding: 0.5rem 0.5rem 0.45rem; }
}

/* ---- DZIŚ: kółko jak narysowane ręką (2026-09-04) ----
   Nie idealny okrąg, tylko lekko koślawa elipsa obrócona o kilka stopni —
   taka, jaką zakreśla się długopisem w papierowym kalendarzu. Robią to
   cztery różne promienie i cztery różne grubości krawędzi; idealne koło
   czytałoby się jak stan interfejsu, a to ma być odręczna wskazówka.
   ⚠️ To PSEUDOELEMENT, a nie krawędź samego przycisku — dzień dzisiejszy
   bywa jednocześnie wybrany, a wtedy ma pokazać OBA znaki naraz.
   ⚠️ `inset` z zapasem, żeby kółko obejmowało cyfrę, a nie leżało na niej. */
.kal-dzien--dzis::before {
  content: "";
  position: absolute;
  inset: 11%;
  border: 1.6px solid rgba(200, 176, 138, 0.72);
  border-width: 1.5px 2px 1.7px 1.3px;
  border-radius: 49% 51% 53% 47% / 52% 47% 53% 48%;
  transform: rotate(-7deg);
  pointer-events: none;
}
.kal-dzien--dzis { color: var(--gold); }

/* ---- DNI MINIONE: wyraźnie wygaszone ----
   ⚠️ Wcześniej miały samo przygaszone pismo i ŻADNEGO tła — przez co
   czytały się jak puste miejsca w siatce, a nie jak dni, których nie da się
   wybrać. Teraz zostaje ślad kafelka, ale wyraźnie cichszy od dni wolnych. */
.kal-dzien--minal {
  color: rgba(234, 229, 218, 0.26);
  background: rgba(255, 255, 255, 0.012);
  cursor: default;
}

/* ⚠️ Zakładki są celem przewijania przy zmianie kroku (`oferta.js`), więc
   muszą mieć zapas na przyklejony pasek menu — inaczej po dosunięciu
   chowają się pod nim. Wysokość paska mierzy skrypt i wpisuje w `--glowa`. */
.kalk-stepper { scroll-margin-top: calc(var(--glowa, 4.2rem) + 0.75rem); }
