/* =========================================================================
   MÓJ DOM — warstwa ruchu
   Wczytywana PO styles.css. Archetyp: architektoniczny / premium.

   Jeden system zamiast zbioru efektów:
   - wejścia małe i spokojne (12–18 px, 0,8–0,9 s, krzywa „quint out"),
   - jeden mocniejszy moment na stronę (hero na głównej, maska nagłówka
     sekcji gdzie indziej), reszta tylko się pojawia,
   - mikroruch przy najechaniu: 2 px w górę, cień o stopień głębiej, 180 ms,
   - zdjęcia przy najechaniu najwyżej 1.03, nigdy dalej.

   Zasada, która trzyma to w kupie: stany ukrycia obowiązują wyłącznie pod
   html.motion, którą ustawia skrypt startowy w <head>. Bez JS, przy
   zablokowanym CDN, przy awarii silnika i przy ograniczonym ruchu cała
   treść jest po prostu widoczna. Nigdy pusty ekran.
   ========================================================================= */

:root {
  /* czas */
  --dur-micro: 180ms;      /* najechanie, wciśnięcie, kolor */
  --dur-component: 280ms;  /* rozwinięcie, przełącznik, fokus */
  --dur-reveal: 850ms;     /* wejście treści */
  --dur-hero: 1000ms;      /* pierwszy ekran */

  /* krzywe — odpowiedniki w GSAP: quint.out / power2.in / power2.inOut */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-calm: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in: cubic-bezier(0.7, 0, 0.84, 0);
  --ease-inout: cubic-bezier(0.65, 0, 0.35, 1);

  /* dystans i rytm — segment premium znosi tylko małe ruchy */
  --dist-reveal: 18px;
  --dist-intro: 14px;
  --lift: -2px;            /* uniesienie karty / przycisku przy najechaniu */
  --zoom: 1.03;            /* powiększenie zdjęcia przy najechaniu */
  --nudge: 3px;            /* strzałka dojeżdża w stronę celu */
  --stagger-item: 70ms;
  --stagger-line: 90ms;
}

@media (max-width: 767px) {
  :root { --dist-reveal: 12px; --dist-intro: 10px; }
}

/* -------------------------------------------------- stany startowe (R1)
   Tylko pod .motion. Element z data-reveal-stagger ukrywa dzieci, nie siebie.
   Samo krycie, bez transform — stan ukrycia nie przesuwa układu (CLS 0). */
.motion [data-reveal]:not([data-reveal-stagger]):not([data-shown]),
.motion [data-reveal-stagger]:not([data-shown]) > * { opacity: 0; }
/* Maski na każdej szerokości. Słabszy sprzęt („lite") dostaje data-shown
   od razu, więc tam stan ukrycia nigdy nie obowiązuje. */
.motion [data-clip]:not([data-shown]) { clip-path: inset(0 0 100% 0); }
/* Na czas kurtyny zdjęcie skaluje GSAP — przejście CSS z hovera ciągnęłoby
   każdą klatkę za sobą i ruch by się rozmazywał. */
.motion [data-clip]:not([data-shown]) img { transition: none; }

/* ----------------------------------------------------------- klatki */
@keyframes mx-hero-rise {
  from { transform: translateY(0.35em); opacity: 0.01; }
  to   { transform: none; opacity: 1; }
}
@keyframes mx-hero-fade {
  from { opacity: 0.01; }
  to   { opacity: 1; }
}
/* Linia hasła wysuwa się w całości spod maski (.hero__nameLine ma
   overflow: hidden) — pełne 105%, żeby było widać krawędź, nie drganie. */
@keyframes mx-hero-mask {
  from { transform: translateY(105%); opacity: 0.01; }
  30%  { opacity: 1; }
  to   { transform: none; opacity: 1; }
}
/* Zdjęcie przy wejściu „osiada" z lekkiego zbliżenia — skala na <img>,
   bo kontener przesuwa paralaksa z GSAP (dwa silniki na jednym transform
   by się gryzły). */
@keyframes mx-hero-settle {
  from { transform: scale(1.05); }
  to   { transform: none; }
}
@keyframes mx-rise-soft {
  from { transform: translateY(var(--dist-intro)); opacity: 0.01; }
  to   { transform: none; opacity: 1; }
}
@keyframes mx-header-in {
  from { transform: translateY(-8px); opacity: 0.01; }
  to   { transform: none; opacity: 1; }
}

/* ------------------------------------------------------- hero (R5)
   Animacja w czystym CSS, startuje przy pierwszym malowaniu, więc nagłówek
   nie czeka na GSAP z CDN. Krycie startowe to 0.01, nie 0: w Chromium tekst
   namalowany pierwszy raz przy 0 nie jest w ogóle raportowany jako LCP.
   Cała sekwencja mieści się w ~1,4 s: hasło → kicker i przyciski →
   wyszukiwarka. Wcześniej ostatni element ruszał po 0,7 s i jechał 1,1 s. */
@media (prefers-reduced-motion: no-preference) {
  [data-hero-line] {
    animation: mx-hero-rise var(--dur-hero) var(--ease-calm) both;
    animation-delay: calc(var(--i, 0) * var(--stagger-line));
  }
  .hero__nameLine [data-hero-line] {
    animation: mx-hero-mask 1.1s cubic-bezier(0.19, 1, 0.22, 1) both;
    animation-delay: calc(100ms + var(--i, 0) * 110ms);
  }
  .hero__media img { animation: mx-hero-settle 1.8s var(--ease-calm) both; }
  [data-hero-fade] {
    animation: mx-hero-fade 0.8s var(--ease-calm) both;
    animation-delay: calc(380ms + var(--i, 0) * 90ms);
  }
  /* Kicker stoi nad hasłem, więc pojawia się pierwszy — razem z pierwszą
     linią, nie po przyciskach. */
  .hero__kicker[data-hero-fade] {
    animation: mx-hero-fade 0.9s var(--ease-calm) both;
    animation-delay: 60ms;
  }
  /* Panel wyszukiwarki wjeżdża z dołu, nie tylko się rozjaśnia. */
  .finder__panel[data-hero-fade] {
    animation: mx-rise-soft 0.9s var(--ease-calm) both;
    animation-delay: 560ms;
  }
  /* Nagłówek opada tylko na stronie głównej, razem z hero. Na podstronach
     stoi — to stały element, który ma być „pod ręką", nie wjeżdżać przy
     każdym kliknięciu w menu. */
  .site-header--onHero .topbar { animation: mx-hero-fade 0.7s var(--ease-calm) 200ms both; }
  .site-header--onHero .site-header__in { animation: mx-header-in 0.8s var(--ease-calm) 120ms both; }
}

/* ------------------------------------------- pierwszy ekran podstron
   Nagłówek podstrony (okruszki, tytuł, lead) i górna część oferty wchodzą
   w CSS, od pierwszego malowania — jak hero. Wcześniej tytuł stał
   nieruchomo, a okruszki i zdjęcie oferty czekały na GSAP z CDN, więc
   pierwszy ekran pojawiał się kawałkami i z opóźnieniem. app.js oznacza
   te elementy jako pokazane, żeby nie wjeżdżały drugi raz. */
@media (prefers-reduced-motion: no-preference) {
  .page-head .wrap > *,
  .offer-top__head > *,
  .offer-top__visual {
    animation: mx-rise-soft var(--dur-reveal) var(--ease-calm) both;
    animation-delay: calc(60ms + var(--n, 0) * var(--stagger-item));
  }
  .page-head .wrap > :nth-child(2), .offer-top__head > :nth-child(2) { --n: 1; }
  .page-head .wrap > :nth-child(3), .offer-top__head > :nth-child(3) { --n: 2; }
  .page-head .wrap > :nth-child(4), .offer-top__head > :nth-child(4) { --n: 3; }
  .page-head .wrap > :nth-child(n+5), .offer-top__head > :nth-child(n+5) { --n: 4; }
  /* Zdjęcie oferty (LCP) tylko się rozjaśnia — bez przesuwu i krótko. */
  .offer-top__visual { animation-name: mx-hero-fade; animation-duration: 0.7s; --n: 1; }
}

/* ------------------------------------------------------ menu pełnoekranowe
   Pozycje wysuwają się spod maski (li ma overflow: hidden) za kurtyną
   overlayu. Własność `translate`, nie `transform` — transform należy do
   hovera (przesunięcie w bok) i oba ruchy nie mogą się nadpisywać.
   Przy zamykaniu bez opóźnień: kurtyna i tak zakrywa listę. */
@media (prefers-reduced-motion: no-preference) {
  .nav-list a {
    translate: 0 105%;
    transition: color 0.3s var(--ease), transform 0.4s var(--ease-out), translate 0.25s var(--ease-in);
  }
  .nav-overlay[data-open="true"] .nav-list a {
    translate: 0 0;
    transition: color 0.3s var(--ease), transform 0.4s var(--ease-out), translate 0.75s var(--ease-out);
    transition-delay: 0s, 0s, calc(160ms + var(--i, 0) * 50ms);
  }
}

/* ------------------------------------------------ przejścia między stronami
   View Transitions między dokumentami: nagłówek stoi w miejscu, treść
   przechodzi krótkim przenikaniem zamiast twardego przeładowania. Samo
   przenikanie, bez przesuwu — ruch w górę daje już wejście pierwszego
   ekranu (wyżej), dwa naraz dawały wrażenie „podskoku" całej strony.
   Przeglądarka bez wsparcia po prostu przeładowuje. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  .site-header { view-transition-name: site-header; }
  ::view-transition-old(root) { animation: mx-vt-out 160ms var(--ease-in) both; }
  ::view-transition-new(root) { animation: mx-vt-in 280ms var(--ease-calm) 40ms both; }
}
@keyframes mx-vt-out { to { opacity: 0; } }
@keyframes mx-vt-in { from { opacity: 0; } }

/* ------------------------------------------------------------ parallax
   Warstwa ruchoma dostaje will-change tylko na czas działania (ustawia GSAP).
   Stałe will-change na wielu elementach zjada pamięć GPU na telefonach. */
[data-parallax-bg] { backface-visibility: hidden; }

/* ------------------------------------------------------ mikrointerakcje
   Rzeczy, które dotąd nie reagowały wcale. Tylko transform/opacity/kolor. */
@media (prefers-reduced-motion: no-preference) {
  /* FAQ: odpowiedź dochodzi do pełnego krycia, gdy wysokość już się
     otwiera (wysokość animuje styles.css, ::details-content). */
  /* Zamknięta odpowiedź nie jest renderowana, więc wejście potrzebuje
     @starting-style (zwykłe przejście nie ma stanu „przed"). */
  .faq details[open] .faq__a { opacity: 1; transition: opacity 0.42s var(--ease-calm) 0.06s; }
  @starting-style { .faq details[open] .faq__a { opacity: 0; } }
  .faq details:not([open]) .faq__a { opacity: 0; transition: opacity 0.2s var(--ease); }
}

/* --------------------------------------------------- ograniczony ruch (R19)
   „Bez ruchu" nie znaczy „bez informacji zwrotnej": stany najechania,
   fokusu i wciśnięcia zostają, znika przemieszczanie. */
@media (prefers-reduced-motion: reduce) {
  :root { --lift: 0px; --zoom: 1; --nudge: 0px; }
  [data-hero-line],
  [data-hero-fade] { animation: none !important; }

  .motion [data-reveal]:not([data-reveal-stagger]),
  .motion [data-reveal-stagger] > *,
  [data-reveal],
  [data-reveal-stagger] > * { opacity: 1 !important; transform: none !important; }

  .motion [data-clip] { clip-path: none !important; }
}

/* Awaria silnika albo wyłączony JS: bezpiecznik zdejmuje .motion, a te
   reguły domykają sprawę na wypadek, gdyby cokolwiek zostało ukryte. */
.no-js [data-reveal],
.no-js [data-reveal-stagger] > * { opacity: 1 !important; transform: none !important; }
.no-js [data-clip] { clip-path: none !important; }
