/* ==========================================================================
   JK Beauty Clinic — arkusz stylów

   Układ pliku:
     1. Tokeny
     2. Reset i podstawy
     3. Typografia
     4. Układ i narzędzia
     5. Komponenty współdzielone
     6. Nagłówek i nawigacja
     7. Sekcje strony głównej
     8. Zabiegi
     9. Kontakt
    10. Stopka
    11. Animacje wejścia

   Breakpoint: 900px — jedyny w projekcie. Poniżej tej szerokości nawigacja
   zwija się do menu mobilnego, a lista zabiegów działa jako akordeon.
   Reguły mobilne trzymamy przy komponencie, którego dotyczą, nie w jednym
   zbiorczym bloku na końcu.
   ========================================================================== */

/* ==========================================================================
   1. Tokeny
   ========================================================================== */
:root {
    /* Paleta */
    --bg-base: #FFFFFF;
    --bg-surface: #F7F6F3;
    --text-main: #2A2A2A;
    --text-sub: #6E6E6E;
    --text-hover: #4A4A4A;
    --line-light: #EAEAEA;

    /* Składowe RGB przyciemnień nakładanych na zdjęcia (hero, sekcja CTA) */
    --scrim-rgb: 20, 18, 16;

    /* Kroje */
    /* Tenor Sans istnieje wyłącznie w wadze 400. Przy 600/700 przeglądarka
       pogrubia go sztucznie, a polskie znaki przychodzą z osobnego pliku
       (latin-ext) niż reszta liter (latin) — sztuczne pogrubienie kładzie się
       na te dwa pliki inaczej i „ą", „ć", „ł" wychodzą jakby obrysowane.
       Nagłówki mają bold domyślnie z arkusza przeglądarki, więc każda reguła
       sięgająca po ten krój musi jawnie ustawić font-weight: 400. */
    --font-head: 'Tenor Sans', sans-serif;
    --font-body: 'Lato', sans-serif;

    /* Skala odstępów */
    --space-sm: clamp(1rem, 2vw, 1.5rem);
    --space-md: clamp(2rem, 4vw, 3rem);
    --space-lg: clamp(4rem, 8vw, 6rem);
    --space-xl: clamp(3.5rem, 7vw, 7rem);

    /* Wymiary interfejsu */
    --header-h: 90px;
    --logo-h: 38px;
    --tap-min: 44px;               /* minimalny cel dotykowy (WCAG 2.5.5) */

    /* Prześwity przy skokach do kotwic — muszą przekraczać wysokość
       elementów przyklejonych, inaczej cel chowa się pod nimi */
    --anchor-offset: 110px;        /* nagłówek 90px + oddech */
    --subpage-offset: 130px;       /* prześwit <main> na podstronach */
    --category-offset: 120px;      /* desktop: nagłówek + oddech */
    --category-offset-mobile: 175px; /* nagłówek 90px + pasek pigułek ~76px */

    /* Warstwy */
    --z-category-bar: 90;
    --z-mobile-menu: 999;
    --z-header: 1000;

    /* Ruch */
    --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
    --accordion-ms: 280ms;
}

/* ==========================================================================
   2. Reset i podstawy
   ========================================================================== */
* { margin: 0; padding: 0; box-sizing: border-box; }

body {
    font-family: var(--font-body);
    color: var(--text-main);
    background-color: var(--bg-base);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: hidden;
}

a { color: inherit; text-decoration: none; }
img { display: block; max-width: 100%; height: auto; }

:target, h1, h2, h3 { scroll-margin-top: var(--anchor-offset); }

:focus-visible {
    outline: 2px solid var(--text-main);
    outline-offset: 4px;
}

/* Użytkownik z wyłączonymi animacjami musi zobaczyć treść od razu — elementy
   wejściowe startują z opacity:0, więc samo skrócenie czasu nie wystarcza. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
    .reveal, .hero-animate {
        opacity: 1 !important;
        transform: none !important;
        animation: none !important;
    }
}

/* ==========================================================================
   3. Typografia
   ========================================================================== */
p { font-size: 1rem; color: var(--text-sub); margin-bottom: 1.5rem; }

.eyebrow {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.25em;
    color: var(--text-sub);
    margin-bottom: 1rem;
}

.hero-title {
    font-family: var(--font-head);
    font-size: clamp(2.25rem, 4.5vw, 4rem);
    line-height: 1.0;
    letter-spacing: 0.02em;
    font-weight: 400;
    margin-bottom: 1.25rem;
}

.section-title {
    font-family: var(--font-head);
    font-size: clamp(2rem, 5vw, 4rem);
    line-height: 1.1;
    font-weight: 400;
    margin-bottom: 2rem;
}

.text-large {
    font-size: clamp(1.1rem, 2vw, 1.25rem);
    color: var(--text-main);
    line-height: 1.5;
}

@media (max-width: 900px) {
    /* 11px to za drobno na telefonie */
    .eyebrow { font-size: 12px; }
}

/* ==========================================================================
   4. Układ i narzędzia
   ========================================================================== */
.container {
    width: 100%;
    max-width: 1440px;
    margin: 0 auto;
    padding: 0 var(--space-md);
}

/* Podstrony zaczynają się pod przyklejonym nagłówkiem */
.page-body { padding-top: var(--subpage-offset); }

.section-padding { padding: var(--space-xl) 0; }
/* Sekcja otwierająca podstronę — mniejszy odstęp górny, bo .page-body
   dał już prześwit na nagłówek. Trzy warianty, po jednym na podstronę. */
.section-padding--intro { padding-top: var(--space-md); }
.section-padding--intro-flush { padding-top: var(--space-md); padding-bottom: 0; }
.section-padding--intro-tight { padding-top: var(--space-sm); }
.section-padding--intro-tight .section-title { margin-bottom: var(--space-sm); }

.bg-surface { background-color: var(--bg-surface); }

.aspect-3-4 { aspect-ratio: 3 / 4; }
.aspect-16-9 { aspect-ratio: 16 / 9; }

/* ==========================================================================
   5. Komponenty współdzielone
   ========================================================================== */

/* --- Przyciski --- */
.btn-main {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--tap-min);
    min-height: var(--tap-min);
    padding: 18px 40px;
    border: none;
    background-color: var(--text-main);
    color: var(--bg-base);
    font-family: var(--font-body);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 1px;
    cursor: pointer;
    transition: background-color 0.3s ease;
}
.btn-main:hover { background-color: var(--text-hover); }

.btn-sub {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-min);
    padding-bottom: 4px;
    border-bottom: 1px solid var(--text-main);
    color: var(--text-main);
    font-size: 0.9rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    transition: color 0.3s, border-color 0.3s;
}
.btn-sub:hover { color: var(--text-sub); border-color: transparent; }

@media (max-width: 900px) {
    .btn-main, .btn-sub { font-size: 0.95rem; }
}

/* --- Kadry zdjęć --- */
.img-wrapper {
    position: relative;
    overflow: hidden;
}
.img-zoom {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform 0.6s var(--ease-out);
}
.img-wrapper:hover .img-zoom { transform: scale(1.03); }

/* ==========================================================================
   6. Nagłówek i nawigacja
   ========================================================================== */
.header {
    position: fixed;
    top: 0; left: 0; right: 0;
    /* Nad menu mobilnym: .header tworzy własny kontekst stackingu, więc
       z-index na samym hamburgerze nie wystarczy — przycisk zamknięcia
       chowałby się pod otwartym menu. */
    z-index: var(--z-header);
    transition: background-color 0.4s ease, border-bottom 0.4s ease;
}

.nav {
    display: flex;
    justify-content: space-between;
    align-items: center;
    height: var(--header-h);
}
.nav > a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-min);
    padding-right: 12px;
}

.logo-black { height: var(--logo-h); width: auto; }

/* Stan przezroczysty — tylko nad sekcją hero na stronie głównej.
   Hero to jasne zdjęcie studyjne bez przyciemnienia, więc nawigacja jest
   ciemna; biała byłaby na nim niewidoczna. */
.header--transparent {
    background-color: transparent;
    border-bottom: 1px solid transparent;
}
.header--transparent .nav-link { color: var(--text-main); }
.header--transparent .logo-black { display: block; }
.header--transparent .mobile-toggle span { background-color: var(--text-main); }

/* Stan biały — po przewinięciu i na podstronach */
.header--solid {
    background-color: var(--bg-base);
    border-bottom: 1px solid var(--line-light);
}
.header--solid .nav-link { color: var(--text-main); }
.header--solid .logo-black { display: block; }
.header--solid .mobile-toggle span { background-color: var(--text-main); }

.nav-links { display: flex; gap: 3rem; align-items: center; }
.nav-link {
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    transition: opacity 0.3s;
}
.nav-link:hover { opacity: 0.6; }
.nav-links .nav-link {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-min);
}

/* --- Hamburger --- */
.mobile-toggle {
    display: none;
    flex-direction: column;
    justify-content: space-between;
    /* Pole dotyku 44x44; padding zostawia same paski w rozmiarze 30x20 */
    width: var(--tap-min);
    height: var(--tap-min);
    padding: 12px 7px;
    background: none;
    border: none;
    cursor: pointer;
}
.mobile-toggle span {
    display: block;
    width: 100%;
    height: 2px;
    transform-origin: center;
    transition: 0.3s;
}
.mobile-toggle[aria-expanded="true"] span:nth-child(1) { transform: translateY(9px) rotate(45deg); }
.mobile-toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.mobile-toggle[aria-expanded="true"] span:nth-child(3) { transform: translateY(-9px) rotate(-45deg); }

/* --- Menu mobilne --- */
.mobile-menu {
    position: fixed;
    top: 0; left: 0;
    width: 100%;
    height: 100vh;
    z-index: var(--z-mobile-menu);
    background-color: var(--bg-surface);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 2rem;
    opacity: 0;
    pointer-events: none;
    /* Samo opacity:0 zostawia linki w kolejności TAB i w drzewie dostępności.
       visibility je stamtąd usuwa; opóźnienie równe animacji, żeby zanikanie
       menu pozostało widoczne. */
    visibility: hidden;
    transition: opacity 0.4s var(--ease-out), visibility 0s linear 0.4s;
}
@supports (height: 100dvh) { .mobile-menu { height: 100dvh; } }

.mobile-menu.is-active {
    opacity: 1;
    pointer-events: auto;
    visibility: visible;
    transition-delay: 0s;
}
.mobile-menu .nav-link {
    font-family: var(--font-head);
    font-size: 2.5rem;
    color: var(--text-main);
    text-transform: none;
    letter-spacing: 0;
}
.mobile-menu-cta { margin-top: 1.5rem; }

@media (max-width: 900px) {
    .nav-links { display: none; }
    .mobile-toggle { display: flex; }
}

/* ==========================================================================
   7. Sekcje strony głównej
   ========================================================================== */

/* --- Hero --- */
.hero {
    position: relative;
    isolation: isolate;            /* własny kontekst stackingu dla warstw tła */
    height: 100vh;
    min-height: 600px;
    display: flex;
    align-items: flex-start;
    padding-top: calc(var(--header-h) + 5vh);
    overflow: hidden;
}
/* svh, nie dvh: svh to wysokość okna przy rozwiniętym pasku adresu, więc
   nagłówek i oba CTA mieszczą się od razu po wejściu. dvh zmieniałoby
   wysokość hero w trakcie przewijania, co daje skok układu. */
@supports (height: 100svh) { .hero { height: 100svh; } }

.hero-bg {
    position: absolute;
    top: -5%; left: 0;
    width: 100%; height: 110%;
    z-index: 0;
}
.hero-bg img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center center;
}


.hero-content {
    position: relative;
    z-index: 2;
    color: var(--text-main);
}
/* Zdjęcie studyjne jest jasne i nie ma nakładki, więc tekst jest ciemny i siedzi
   w pustym prawym górnym rogu kadru — modelka zajmuje lewą i środkową część. */
.hero-content > * {
    max-width: min(460px, 40vw);
    margin-left: auto;
}
/* Tło studyjne nie jest czysto białe — szarość --text-sub dawała na nim
   3,6:1, poniżej progu. Cały tekst hero jest w kolorze --text-main. */
/* Klientka: nazwa kliniki musi być widoczna od razu po wejściu — druga
   prośba o powiększenie (runda 16), poprzedni krok to 20px z rundy 12.
   Powyżej ~23px tekst nie mieści się już w jednej linii na 375px niezależnie
   od odstępu liter (zmierzone: nawet letter-spacing:0 nie ratuje przy 24px),
   więc na wąskim telefonie łamie się na dwie linie — zaakceptowane świadomie,
   klientka wybrała ten wariant spośród trzech pokazanych, wyraźny krok był
   ważniejszy niż utrzymanie jednej linii. Odstęp liter zdjęty do zera, bo
   przy tym rozmiarze i tak nie ratuje jednej linii, a węższe tracking lepiej
   wypełnia szerokość karty na desktopie. Wersaliki i pogrubienie zostają —
   to wciąż etykieta nad H1, nie drugi nagłówek. */
.hero-content .eyebrow {
    color: var(--text-main);
    font-size: 24px;
    font-weight: 700;
    letter-spacing: 0;
    margin-bottom: 1rem;
}
.hero-content p {
    color: var(--text-main);
    font-size: clamp(1.05rem, 1.5vw, 1.25rem);
    margin-bottom: 1.75rem;
}
.hero-actions { display: flex; gap: 2rem; align-items: center; flex-wrap: wrap; }
.hero-actions .btn-sub { color: var(--text-main); border-color: var(--text-main); }

/* Na telefonie kadr pokazuje tylko wąski pionowy wycinek zdjęcia 3:2 — puste
   tło z prawego górnego rogu wypada wtedy poza kadr, a tekst nałożony na obraz
   ląduje na modelce. Dlatego poniżej 900px zdjęcie i tekst układają się jedno
   pod drugim zamiast na sobie. */
@media (max-width: 900px) {
    .hero {
        display: block;
        height: auto;
        min-height: 0;
        padding-top: var(--header-h);
        padding-bottom: var(--space-lg);
        overflow: visible;
    }
    .hero-bg {
        position: static;
        width: 100%;
        height: auto;
        aspect-ratio: 5 / 4;
        margin-bottom: var(--space-md);
    }
    .hero-bg img { object-position: center 40%; }
    .hero-content > * { max-width: 100%; margin-left: 0; }
}

/* --- Blok tekst + zdjęcie (O klinice, bio na stronie O nas) ---
   Zdjęcie dochodzi do krawędzi ekranu po swojej stronie. Kierunek sterowany
   zmiennymi, nie nadpisaniami — dzięki temu reset mobilny to jedna reguła
   o tej samej specyficzności, bez wydłużania selektorów. */
.about-grid {
    --bleed-left: 0;
    --bleed-right: calc(-50vw + 50%);
    display: flex;
    align-items: center;
    gap: var(--space-lg);
}
.about-grid--reverse {
    --bleed-left: calc(-50vw + 50%);
    --bleed-right: 0;
    flex-direction: row-reverse;
}
.about-text { flex: 0 0 auto; width: 100%; max-width: 480px; }
.about-text .btn-sub { margin-top: 1rem; }
/* Bloki wieloakapitowe (HI-TECH) — pojedyncze akapity nigdzie tego nie ruszają */
.about-text p + p { margin-top: 1.25rem; }
.about-image {
    flex: 1;
    min-width: 0;
    margin-left: var(--bleed-left);
    margin-right: var(--bleed-right);
}

/* Bloki bio: szersza kolumna tekstu (ok. 70 znaków) i węższy odstęp, żeby
   między tekstem a zdjęciem nie powstawała pustka rosnąca z szerokością ekranu.
   Kadr 1:1 — przy tej szerokości 3:4 dałoby ponad 1000px wysokości. */
.about-grid--bio { gap: 56px; margin-bottom: var(--space-xl); }
.about-grid--bio:last-child { margin-bottom: 0; }
.about-grid--bio .about-text { max-width: 580px; }
.about-grid--bio .section-title { margin-bottom: 0.5rem; }
.about-grid--bio .eyebrow { margin-bottom: 2rem; }
.about-grid--bio .about-image { aspect-ratio: 1 / 1; }
.about-grid--bio .about-image img { object-position: center 22%; }
/* Julia jest w kadrze źródłowym wykadrowana wyżej niż pozostałe dwie: czubek
   głowy ma na y=123, podczas gdy Knyszyńska 158, a Końpa 186. Wspólne 22%
   wypada na y=132, więc jej głowę ucinało o 9 px. 15% wypada na y=90, co daje
   33 px zapasu nad głową — pomiędzy Knyszyńską (26 px) a Końpą (54 px), więc
   trzy portrety mają zbliżony prześwit. Selektor zawężony do samego zdjęcia
   Julii, bo reguła wyżej jest wspólna dla całej trójki. */
.about-grid--bio .about-image img[src*="julia"] { object-position: center 15%; }

@media (max-width: 900px) {
    .about-grid { --bleed-left: 0; --bleed-right: 0; flex-direction: column; }
    .about-image { width: 100%; }
    /* 16:9 przy szerokości 326px daje pasek 183px — za nisko na telefonie */
    .about-image.aspect-16-9 { aspect-ratio: 3 / 2; }
}

/* --- Naprzemienne wideo i zdjęcie (sekcja O klinice) ---
   Bez JS widać samo zdjęcie: wideo nie ma atrybutu autoplay, a warstwą
   domyślnie widoczną jest <img>. */
.media-swap-video,
.media-swap-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* Nagranie jest pionowe (1080x1920), a ramka pozioma — kadr celuje w pas
   ze stołem i aparaturą, bo nad nim jest pusta ściana, a pod nim podłoga. */
.media-swap-video { object-position: center 55%; }
.media-swap-photo { object-position: center 28%; }
.media-swap-video { opacity: 0; }
.media-swap-photo { opacity: 1; }
.media-swap-video,
.media-swap-photo { transition: opacity 700ms ease; }
.media-swap.is-video .media-swap-video { opacity: 1; }
.media-swap.is-video .media-swap-photo { opacity: 0; }

/* --- Oferta --- */
.offer-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-md);
    margin-bottom: var(--space-md);
}
/* Karty oferty na przyciemnionym zdjęciu. Warstwy dokładnie jak w sekcji
   „Umów wizytę online": zdjęcie na spodzie, jednolita nakładka rgba nad nim,
   treść na wierzchu. Krycie nakładki jest zmienną, bo trzy zdjęcia mają różną
   jasność i dobrane jest per karta pomiarem kontrastu, nie jedną wartością. */
.offer-block {
    --scrim: 0.55;
    position: relative;
    isolation: isolate;
    overflow: hidden;
    min-height: 340px;
    display: flex;
    align-items: flex-end;
    padding: var(--space-sm);
}
.offer-bg { position: absolute; inset: 0; z-index: 0; }
.offer-bg img { width: 100%; height: 100%; object-fit: cover; }
.offer-overlay { position: absolute; inset: 0; z-index: 1; background: rgba(var(--scrim-rgb), var(--scrim)); }
.offer-content { position: relative; z-index: 2; }
.offer-block h3 { font-family: var(--font-head); font-weight: 400; font-size: 1.5rem; margin-bottom: 1rem; color: #FFFFFF; }
.offer-block p { color: rgba(255, 255, 255, 0.92); margin: 0; }
/* Krycie nakładki dobrane pomiarem: każda karta ma najsłabszy kontrast tekstu
   w okolicy 5,4 (próg AA to 4,5), przy najjaśniejszej możliwej nakładce, żeby
   zdjęcie zostało czytelne. Zdjęcie medycyny jest najjaśniejsze i potrzebuje
   najmocniejszego przyciemnienia, makijażu najsłabszego. */
.offer-block--medycyna { --scrim: 0.65; }
.offer-block--makijaz  { --scrim: 0.63; }
.offer-block--masaz    { --scrim: 0.64; }

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

/* --- Zespół --- */
.team-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-md);
    align-items: start;
}
/* Kaskada: środkowa kolumna celowo obniżona.
   Próg jest wyższy niż 900 px z rozmysłem — kaskada potrzebuje szerszych
   kolumn niż sam układ trzykolumnowy. Poniżej 1145 px podpisy ról łamią się
   na dwie linie, odstęp między kolumnami spada z 48 do 36 px, a stałe 80 px
   przesunięcia rośnie z 16% do 25% wysokości zdjęcia. Wtedy nazwisko
   z bocznej kolumny wypada dokładnie na wysokości zdjęcia Julii i układ
   zaczyna mylić, kto jest kto. Włączamy kaskadę dopiero, gdy jest na nią
   miejsce; niżej trzy kolumny stoją równo. */
@media (min-width: 1150px) {
    .team-grid > :nth-child(2) { margin-top: 80px; }
}
/* max-height domyka budżet wysokości tak, by nagłówek, zdjęcia i podpisy
   zmieściły się na jednym ekranie 1440x900 mimo tego przesunięcia */
.team-member .img-wrapper { aspect-ratio: 4 / 5; max-height: 495px; }
/* Kadr 4:5 z pionowego źródła obcina 99 px; przy wyśrodkowaniu ucinało to
   czubek głowy na zdjęciu Julii. Kadrowanie dobierane per zdjęcie. */
.team-member img[src*="julia"] { object-position: center 10%; }
.team-member h3 {
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 1.5rem;
    margin: 1rem 0 0.25rem 0;
}

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

/* Blok tekstu bez towarzyszącego zdjęcia (HI-TECH, podstrony prawne) —
   .about-text jest projektowany pod układ obok obrazu (480 px), tutaj
   potrzebna szersza, ale wciąż czytelna miara wiersza. */
.text-column { max-width: 720px; }
/* Numerowane sekcje na podstronach prawnych. Tenor Sans ma tylko wagę 400 —
   bez jawnego font-weight przeglądarka pogrubiałaby h2 sama, co przy tym
   kroju psuje renderowanie polskich znaków (patrz uwagi techniczne w
   README). */
.text-column h2 {
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 1.375rem;
    margin: var(--space-md) 0 0.75rem;
}
.text-column h2:first-child { margin-top: 0; }
.text-column .legal-updated { color: var(--text-sub); margin-top: var(--space-sm); }

/* Nagłówek + wstęp na HI-TECH: po usunięciu zdjęcia w rundzie 12 kolumna
   tekstu (720px) zostawiała na szerokich ekranach dużą pustą przestrzeń po
   prawej (672px na 1440px, 46,7% szerokości) — nagłówek i tekst stały przy
   lewej krawędzi pełnego kontenera 1440px, tekst nigdzie się nie kończył
   naturalnie. Zamiast poszerzać samą kolumnę tekstu (linia wtedy rośnie do
   ~96 znaków — powyżej sensownego zakresu 60–75) albo centrować tylko
   kolumnę pod lewo wyrównanym nagłówkiem (rozjazd punktów odniesienia),
   cały blok — nagłówek i tekst — dostaje wspólny, węższy kontener
   wyśrodkowany na stronie. Nagłówek i tekst zostają wyrównane do tej samej
   lewej krawędzi, a luka po prawej spada do 192px (-71%) bez zmiany
   długości linii. */
.tech-intro { max-width: 960px; margin-left: auto; margin-right: auto; }

/* Nagłówek sekcji podrzędnej — pełny .section-title dobija na desktopie do 4rem
   i konkurowałby z H1 na górze strony. */
.section-title--sub { font-size: clamp(1.75rem, 3vw, 2.5rem); }

/* --- Galeria urządzeń --- */
/* Zdjęcia produktowe mają różne proporcje (933/1400, 900/848, 700/1050),
   więc każde dostaje wspólną ramkę 3:4 i object-fit: contain — nic nie jest
   przycinane, a urządzenia stoją w jednej linii. Bez cieni i ramek, tak jak
   dotychczasowe zdjęcie lasera. Tło białe, bo zdjęcie Eau Sante ma białe tło
   wtopione w plik, a Dermapen jest wycięty na przezroczystości. */
.tech-devices {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-md);
    margin-top: var(--space-md);
}
.tech-device { margin: 0; }
.tech-device .img-wrapper {
    aspect-ratio: 3 / 4;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Wspólna ramka 3:4 z object-fit:contain skalowała każde zdjęcie do pełnej
   wysokości niezależnie od tego, ile w kadrze zajmuje samo urządzenie —
   pomiar pokazał, że w efekcie Pico (laser stacjonarny, fizycznie
   największe) wypełniał ramkę w 97% wysokości, ale Dermapen (ręczny
   wkłuwacz, fizycznie najmniejszy) też w 96,5%, więc oba wyglądały na tej
   samej stronie tak samo duże. Każde zdjęcie ma teraz osobną wysokość
   dobraną do realnej skali sprzętu; szerokość skaluje się proporcjonalnie
   (bez object-fit — samo height + width:auto). */
.tech-device img { width: auto; max-width: 100%; height: 92%; object-fit: contain; }
/* Eau Sante ma niemal kwadratowe źródło (900×848), więc ta sama wysokość co
   pozostałe przekłada się na dużo większą szerokość niż u wąskich, pionowych
   Pico i Dermapena — przy 58% jej szerokość dorównywała szerokości Pico
   (341 vs 340px, czyli 100%), mimo że to średniej wielkości sprzęt stołowy,
   nie największe urządzenie w gabinecie. 52% sprowadza szerokość do ~90%
   szerokości Pico — wyraźnie węziej, bez zmiany proporcji zdjęcia. */
.tech-device img[src*="tech-eau-sante"] { height: 52%; }
.tech-device img[src*="tech-dermapen"] { height: 46%; }
.tech-device figcaption {
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 1.125rem;
    margin-top: 0.75rem;
}
.tech-device figcaption span { display: block; font-family: var(--font-body); font-size: 0.9rem; color: var(--text-sub); }

@media (max-width: 900px) {
    .tech-devices { grid-template-columns: 1fr; gap: var(--space-sm); }
    .tech-device .img-wrapper { aspect-ratio: 4 / 3; }
}

/* --- Opinie: karuzela --- */
/* Przewijanie jest wewnątrz .reviews (overflow: hidden), więc ruch nie tworzy
   poziomego paska na całej stronie. Ścieżka jedzie transformem, a nie
   scrollLeft — transform nie wpływa na układ i nie przelicza się co klatkę.
   Bez gwiazdek i ikon: wyróżnienie niesie sam układ i typografia. */
.reviews {
    overflow: hidden;
    margin-top: var(--space-md);
    /* Krawędzie wygaszone, żeby karty nie ucinały się twardo na brzegu ekranu */
    -webkit-mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
    mask-image: linear-gradient(to right, transparent, #000 6%, #000 94%, transparent);
}
.reviews-track {
    display: flex;
    gap: var(--space-md);
    width: max-content;
    padding: 0 var(--space-md);
    will-change: transform;
}
.review-card {
    flex: 0 0 auto;
    width: min(420px, 78vw);
    margin: 0;
    padding: var(--space-sm);
    background-color: #FFFFFF;
    border: 1px solid var(--line-light);
    display: flex;
    flex-direction: column;
    /* Karty równają się do najdłuższej opinii (ścieżka jest flexem, więc
       domyślne align-items: stretch). Przy space-between cały ten luz zbierał
       się w jednym miejscu — między tekstem a podpisem — i przy krótkich
       opiniach dawał dziurę do 242 px, przy najdłuższej tylko 20 px.
       Wyśrodkowanie rozkłada luz na górę i dół, a odstęp tekst–podpis zostaje
       stały (margines spod blockquote). */
    justify-content: center;
}
.review-card blockquote {
    margin: 0 0 1.25rem 0;
    font-family: var(--font-body);
    font-size: 0.95rem;
    line-height: 1.7;
    color: var(--text-main);
}
.review-card figcaption { display: block; }
.review-who {
    display: block;
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 1.125rem;
    color: var(--text-main);
}
.review-meta {
    display: block;
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 0.8rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-sub);
    margin-top: 0.35rem;
}
/* prefers-reduced-motion: bez ruchu, ale opinie mają zostać dostępne —
   zamiast animacji zwykłe przewijanie palcem. */
.reviews--static { overflow-x: auto; }
/* Bez JavaScriptu ścieżka zostaje pusta — wtedy chowamy całą sekcję, żeby nie
   został sam nagłówek „Opinie" nad niczym. */
section:has(> .reviews > .reviews-track:empty) { display: none; }
.reviews--static .reviews-track { transform: none !important; }

@media (max-width: 900px) {
    .review-card { width: min(320px, 82vw); }
}

/* --- Sekcja zamykająca --- */
.cta-band {
    position: relative;
    isolation: isolate;
    min-height: 60vh;
    display: flex;
    align-items: center;
    padding: var(--space-lg) 0;
    overflow: hidden;
}
.cta-bg { position: absolute; inset: 0; z-index: 0; }
/* Kadr celuje w moment zabiegu — środek zdjęcia to sama tkanina i włosy */
.cta-bg img {
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center 68%;
}
.cta-overlay { position: absolute; inset: 0; z-index: 1; background: rgba(var(--scrim-rgb), 0.62); }
.cta-band > .container {
    position: relative;
    z-index: 2;
    max-width: 600px;
    margin: 0 auto;
    text-align: center;
}
.cta-band .section-title { color: #FFFFFF; margin-bottom: 1.25rem; }
.cta-band p { color: rgba(255,255,255,0.92); margin-bottom: 2.5rem; }
/* Ciemny przycisk zniknąłby na ciemnym zdjęciu */
.cta-band .btn-main { background-color: #FFFFFF; color: var(--text-main); }
.cta-band .btn-main:hover { background-color: var(--bg-surface); }

/* ==========================================================================
   8. Zabiegi
   ========================================================================== */
.treatments-layout {
    display: flex;
    gap: var(--space-xl);
    align-items: flex-start;
    margin-top: var(--space-lg);
}
.treatments-sidebar {
    position: sticky;
    top: var(--category-offset);
    width: 280px;
    flex-shrink: 0;
}
.treatments-list { flex: 1; }

.category-link {
    display: block;
    padding: 0.5rem 0;
    color: var(--text-sub);
    font-size: 0.95rem;
    transition: color 0.3s;
}
.category-link.active,
.category-link:hover { color: var(--text-main); }

.treatment-category {
    margin-bottom: var(--space-xl);
    scroll-margin-top: var(--category-offset);
}
.treatment-category h2 {
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 2.5rem;
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--text-main);
}

/* Nagłówek kategorii jest przyciskiem, żeby akordeon działał z klawiatury.
   Powyżej 900px przycisk nie ma stanu rozwinięcia i wygląda jak zwykły tekst. */
.category-toggle {
    display: block;
    width: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: default;
}
.category-count,
.category-mark { display: none; }

.treatment-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: 0 -1rem;               /* kompensacja paddingu, by linia sięgała krawędzi */
    padding: 1.5rem 1rem;
    border-bottom: 1px solid var(--line-light);
    transition: background-color 0.3s;
}
.treatment-row:hover { background-color: var(--bg-surface); }
.treatment-info { max-width: 70%; }
.treatment-info h3 { font-family: var(--font-head); font-weight: 400; font-size: 18px; margin-bottom: 0.25rem; }
.treatment-info p { font-size: 14px; color: var(--text-sub); margin: 0; }
/* Runda 16: "Umów" jest teraz osobnym, realnym linkiem (patrz script.js) —
   wraca do niego pełny cel dotykowy z bazowego .btn-sub, zdjęty wcześniej,
   bo cały wiersz był linkiem i wewnętrzny span nie musiał mieć własnego. */
.treatment-action { display: flex; align-items: center; gap: 0.75rem; flex-shrink: 0; }
.treatment-action .btn-sub { border-color: transparent; }
.treatment-row:hover .treatment-action .btn-sub { border-color: var(--text-main); }
.treatment-price { font-size: 14px; color: var(--text-sub); white-space: nowrap; }

/* Pozycje z opisem z Booksy (97 z 103) mają nazwę+opis jako <button>, żeby
   kliknięcie otwierało okno ze szczegółami — 6 usług manicure nie ma opisu
   na Booksy i zostaje zwykłym, nieklikalnym <div> (bez przycisku, bez
   napisu-wyzwalacza). Reset stylów przycisku, żeby wyglądał identycznie
   jak wcześniejszy <div>. */
button.treatment-info {
    display: block;
    width: 100%;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    text-align: left;
    font: inherit;
    color: inherit;
    cursor: pointer;
}
button.treatment-info:focus-visible { outline: 2px solid var(--text-main); outline-offset: 4px; }
/* Runda 17: klientka poprosiła o czytelny napis zamiast ikony "+" — sam
   symbol ginął przy skanowaniu strony wzrokiem. Celowo lżejszy od "Umów"
   (bez wersalików/liter rozstrzelonych z .btn-sub), żeby dwa różne
   działania w wierszu nie wyglądały na tę samą rangę przycisku. */
.treatment-info-trigger {
    display: inline-block;
    margin-top: 0.5rem;
    font-size: 0.85rem;
    color: var(--text-main);
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: var(--line-light);
    transition: text-decoration-color 0.3s;
}
button.treatment-info:hover .treatment-info-trigger,
button.treatment-info:focus-visible .treatment-info-trigger {
    text-decoration-color: var(--text-main);
}

/* --- Okno ze szczegółami zabiegu --- */
/* <dialog> renderuje się we własnej "top layer" przeglądarki — nie trzeba
   z-index. showModal() daje za darmo pułapkę fokusu i zamykanie po Esc.
   Domyślne wyśrodkowanie (position:fixed + margin:auto z arkusza UA)
   zerowałby globalny reset "* { margin: 0 }" — przywracamy margin jawnie. */
.treatment-modal {
    /* Runda 19: powiększone na życzenie klientki (560×720 → 640×800) —
       umiarkowany wariant z dwóch pokazanych, linie tekstu zostają
       w komfortowym zakresie ~70-80 znaków. Poniżej ~680px szerokości
       (i tak) i tak przejmuje ograniczenie z calc(100vw...), więc na
       375/390/430px wygląda identycznie jak przed zmianą. */
    width: min(640px, calc(100vw - 2 * var(--space-sm)));
    max-height: min(800px, calc(100vh - 2 * var(--space-sm)));
    margin: auto;
    padding: 0;
    border: none;
    background: var(--bg-base);
    color: var(--text-main);
}
.treatment-modal::backdrop { background: rgba(var(--scrim-rgb), 0.55); }
.treatment-modal-body { padding: var(--space-sm); overflow-y: auto; max-height: inherit; }
.treatment-modal-title {
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 1.75rem;
    /* Miejsce na przycisk zamknięcia: sam przycisk ma szerokość --tap-min
       (44px) i wystaje poza padding .treatment-modal-body o tyle samo,
       ile ten padding wynosi (oba liczone od tej samej krawędzi dialogu:
       "right: var(--space-sm)" na przycisku i "padding: var(--space-sm)"
       na body) — więc tytułowi trzeba zarezerwować co najmniej całą
       szerokość przycisku, nie dowolny stały odstęp. Za mało tego
       marginesu (dawniej 2rem = 32px < 44px) łamało się dopiero przy
       zawinięciu do drugiej linii, gdzie tekst wchodził pod "X".
       padding-right ogranicza WSZYSTKIE zawinięte linie jednakowo,
       więc kolizja jest wykluczona niezależnie od liczby linii. */
    padding-right: calc(var(--tap-min) + 0.75rem);
    margin-bottom: 0.5rem;
}
.treatment-modal-price { color: var(--text-sub); margin-bottom: 1.5rem; }
.treatment-modal-details p { margin-bottom: 1rem; line-height: 1.6; }
.treatment-modal-details p:last-child { margin-bottom: 0; }
.treatment-modal-cta { display: inline-flex; margin-top: 1.5rem; }
.treatment-modal-close {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-sm);
    width: var(--tap-min);
    height: var(--tap-min);
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    cursor: pointer;
}
/* X z dwóch kresek pod 45° — ta sama "bez plików ikon" logika jak wyżej */
.treatment-modal-close span { position: relative; width: 16px; height: 16px; }
.treatment-modal-close span::before,
.treatment-modal-close span::after {
    content: '';
    position: absolute;
    top: 7px; left: 0;
    width: 16px; height: 1.5px;
    background-color: var(--text-main);
}
.treatment-modal-close span::before { transform: rotate(45deg); }
.treatment-modal-close span::after { transform: rotate(-45deg); }
.treatment-modal-close:hover span::before,
.treatment-modal-close:hover span::after { background-color: var(--text-sub); }

@media (max-width: 900px) {
    .treatment-modal-title { font-size: 1.5rem; }
}

@media (max-width: 900px) {
    /* Pasek kategorii przykleja się pod nagłówkiem i przewija w poziomie */
    .treatments-layout { flex-direction: column; }
    .treatments-sidebar {
        position: sticky;
        top: var(--header-h);
        z-index: var(--z-category-bar);
        width: 100vw;
        margin-left: calc(-50vw + 50%);
        padding: 1rem 0;
        background: var(--bg-base);
        border-bottom: 1px solid var(--line-light);
    }
    .treatments-sidebar nav {
        display: flex;
        gap: 1rem;
        padding: 0 var(--space-md);
        overflow-x: auto;
        white-space: nowrap;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: none;
    }
    .treatments-sidebar nav::-webkit-scrollbar { display: none; }
    .category-link {
        display: inline-flex;
        align-items: center;
        min-height: var(--tap-min);
        padding: 0 20px;
        border-radius: 40px;
        background: var(--bg-surface);
    }
    .category-link.active { background: var(--text-main); color: var(--bg-base); }

    /* --- Akordeon ---
       Tylko poniżej 900px: pełna lista to 102 pozycje, czyli ponad 20 ekranów
       przewijania na telefonie. Na desktopie miejsca wystarcza, a sticky
       nawigacja boczna spełnia tę samą rolę.
       Cała mechanika zwijania mieści się w tym media query — dzięki temu po
       powiększeniu okna treść jest widoczna nawet wtedy, gdy użytkownik
       wcześniej pozwijał wszystkie kategorie. */
    .treatment-category {
        margin-bottom: 0;
        scroll-margin-top: var(--category-offset-mobile);
    }
    .treatment-category h2 {
        font-size: 1.5rem;
        margin-bottom: 0;
        padding-bottom: 0;
        border-bottom: 1px solid var(--line-light);
    }
    .category-toggle {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        min-height: 56px;
        padding: 0.5rem 0;
        cursor: pointer;
    }
    .category-name { flex: 1 1 auto; }
    .category-count {
        display: inline-block;
        flex: 0 0 auto;
        font-family: var(--font-body);
        font-size: 0.85rem;
        letter-spacing: 0.05em;
        color: var(--text-sub);
    }
    /* Wskaźnik plus/minus z dwóch kresek — bez plików ikon */
    .category-mark {
        display: block;
        flex: 0 0 auto;
        position: relative;
        width: 14px;
        height: 14px;
    }
    .category-mark::before,
    .category-mark::after {
        content: '';
        position: absolute;
        background-color: var(--text-main);
    }
    .category-mark::before { left: 0; top: 6px; width: 14px; height: 2px; }
    .category-mark::after  { left: 6px; top: 0; width: 2px; height: 14px; transition: transform var(--accordion-ms) ease; }
    .treatment-category.is-open .category-mark::after { transform: scaleY(0); }

    .category-panel {
        display: grid;
        grid-template-rows: 0fr;
        transition: grid-template-rows var(--accordion-ms) ease;
    }
    .treatment-category.is-open .category-panel { grid-template-rows: 1fr; }
    .category-panel-inner {
        min-height: 0;
        overflow: hidden;
        /* Samo zerowanie wysokości zostawiłoby zwinięte pozycje w kolejności TAB
           i w drzewie dostępności — visibility je stamtąd usuwa. Opóźnienie
           równe animacji, żeby zwijanie pozostało widoczne. */
        visibility: hidden;
        transition: visibility 0s linear var(--accordion-ms);
    }
    .treatment-category.is-open .category-panel-inner {
        visibility: visible;
        transition-delay: 0s;
    }

    .treatment-row {
        flex-direction: column;
        align-items: flex-start;
        gap: 0.5rem;
        margin: 0;
        padding: 1.15rem 0;
    }
    .treatment-info { max-width: 100%; }
    /* Opis zabiegu to treść, nie etykieta — minimum 16px */
    .treatment-info p { font-size: 1rem; }
    .treatment-info h3 { font-size: 1.125rem; }
}

/* Odnośnik ze strony zabiegów do strony ze sprzętem */
.tech-hint { margin-bottom: 1.5rem; }

/* --- HI-TECH: grupy zabiegów laserowych --- */
.tech-group { margin-bottom: var(--space-xl); }
.tech-group:last-child { margin-bottom: 0; }
.tech-group h2 {
    font-family: var(--font-head);
    font-weight: 400;
    font-size: 2.5rem;
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid var(--text-main);
}

@media (max-width: 900px) {
    .tech-group h2 { font-size: 1.75rem; margin-bottom: 1.25rem; padding-bottom: 0.75rem; }
}

/* ==========================================================================
   9. Kontakt
   ========================================================================== */
.contact-cols {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-lg);
}
.contact-info-block { margin-bottom: 1.25rem; padding-bottom: 1.25rem; }
.contact-info-block:not(:last-child) { border-bottom: 1px solid var(--line-light); }
.contact-info-block h2,
.contact-info-block h3 {
    font-size: 0.8rem;
    text-transform: uppercase;
    letter-spacing: 0.14em;
    color: var(--text-sub);
    margin-bottom: 0.35rem;
}
.contact-info-block p { font-size: 1.25rem; color: var(--text-main); margin-bottom: 0; }
.contact-info-block a {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-min);
}

.contact-actions {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-md);
    margin-top: var(--space-md);
    padding-top: var(--space-md);
    border-top: 1px solid var(--line-light);
}
.contact-social { display: flex; gap: 2.5rem; flex-wrap: wrap; margin-left: auto; }

.contact-map { margin-top: var(--space-md); }
.map-embed {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 24 / 9;
    border: 0;
    /* Znaczniki POI Google są najbardziej nasyconym elementem strony */
    filter: saturate(0.55);
}

@media (max-width: 900px) {
    .contact-cols { grid-template-columns: 1fr; gap: 0; }
    .contact-actions { flex-direction: column; align-items: stretch; gap: var(--space-sm); }
    /* Przy pełnej szerokości padding 40px łamał etykietę na dwie linie */
    .contact-actions .btn-main { width: 100%; padding-left: 20px; padding-right: 20px; }
    .contact-social { margin-left: 0; }
    .map-embed { aspect-ratio: 4 / 3; }
}

/* ==========================================================================
   10. Stopka
   ========================================================================== */
.footer { background-color: var(--bg-surface); padding: var(--space-xl) 0 var(--space-md); }
/* Strona zabiegów kończy sekcję bez dolnego odstępu, stopka musi go dodać */
.footer--spaced { margin-top: var(--space-xl); }
.footer-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--space-md);
}
/* "Umów wizytę przez Booksy" w kolumnie "Rezerwacje" łamał się do dwóch linii
   na większości szerokości desktopowych (nie tylko 1440px — zmierzone w
   paśmie 1000–1600px). Przyczyna: .footer a ma display:block (wyższa
   specyficzność niż .btn-sub, więc wygrywa), a naturalna szerokość tekstu to
   233px, podczas gdy kolumna .footer-grid (5 kolumn, minmax(200px, 1fr))
   bywa węższa — spada nawet do dokładnie 200px. Podniesienie minmax do
   ~240px naprawiłoby to, ale przy 1440px zmieniłoby układ z 5 na 4 kolumny w
   całej stopce — więcej niż wymagała poprawka. Zamiast tego przycisk w
   stopce dostaje mniejszy rozmiar i nieco luźniejszy odstęp liter: naturalna
   szerokość spada do 186px, z 14 px zapasu poniżej najwęższej możliwej
   kolumny (200px). */
.footer .btn-sub {
    white-space: nowrap;
    font-size: 0.76rem;
    letter-spacing: 0.01em;
}
.footer h4 { font-family: var(--font-head); font-weight: 400; font-size: 1.25rem; margin-bottom: 1.5rem; }
.footer p, .footer a { color: var(--text-sub); display: block; margin-bottom: 0.5rem; }
/* Dane rejestrowe — drobniejsze niż reszta stopki */
.footer-legal { font-size: 0.8rem; line-height: 1.5; margin-top: 1rem; }
/* Pasek na uboczu pod siatką kolumn — oddzielony cienką linią, wyciszony,
   nie konkuruje uwagą z żadną kolumną stopki. */
.footer-bottom {
    margin-top: var(--space-md);
    padding-top: var(--space-sm);
    border-top: 1px solid var(--line-light);
    text-align: right;
}
/* Podpis wykonawcy — ta sama waga co dane rejestrowe: ten sam rozmiar, ten sam
   kolor --text-sub, bez wyróżnienia. Link musi być inline, bo .footer a jest
   domyślnie blokowy (pozycje w kolumnach stopki stoją jedna pod drugą). */
.footer-credit { margin: 0; }
/* Podpis to zdanie, nie pozycja nawigacji: link zostaje w linii tekstu.
   Pionowy padding powiększa obszar kliknięcia, nie rozpychając wiersza —
   padding na elemencie inline nie odsuwa od siebie linii. */
.footer-credit a { display: inline; margin: 0; padding: 0.35rem 0; font-size: inherit; color: inherit; }
.footer-credit a:hover { color: var(--text-main); }
/* "Operated by byMajkel.com" nie może się rozłamać w miejscu, gdzie "by"
   wygląda jak przyimek osierocony na końcu linii, przy zawijaniu paska na
   wąskich ekranach. */
.footer-credit-nowrap { white-space: nowrap; }
.footer a:hover { color: var(--text-main); }

@media (max-width: 900px) {
    /* Reguła celu dotykowego dotyczy odnośników nawigacyjnych stopki.
       Podpis wykonawcy jest linkiem wewnątrz zdania — powiększony do 44 px
       łamał wiersz i dokładał pustą linię, dlatego jest wyłączony. */
    .footer a:not(.btn-sub):not(.footer-credit-link) {
        display: flex;
        align-items: center;
        min-height: var(--tap-min);
        margin-bottom: 0;
    }
}

/* ==========================================================================
   11. Animacje wejścia
   ========================================================================== */
/* Klasę .no-js zdejmuje skrypt inline w <head>, więc ta reguła zadziała
   tylko wtedy, gdy JavaScript w ogóle nie wystartował. */
.no-js .reveal,
.no-js .hero-animate {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
}

.reveal {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 0.8s var(--ease-out), transform 0.8s var(--ease-out);
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }

.hero-animate {
    opacity: 0;
    transform: translateY(30px);
    animation: heroFadeUp 1s var(--ease-out) forwards;
}
.hero-animate.delay-1 { animation-delay: 0.1s; }
.hero-animate.delay-2 { animation-delay: 0.2s; }
.hero-animate.delay-3 { animation-delay: 0.3s; }

@keyframes heroFadeUp {
    to { opacity: 1; transform: translateY(0); }
}
