/**
 * scroll-reveal.css — stan ukryty/ujawniony dla data-hbt-reveal
 * =========================================================================
 * CZYTAJ NAGŁÓWEK presentation/scroll-reveal.php PRZED EDYCJĄ TEGO PLIKU.
 *
 * ŻELAZNE ZASADY (opłacone dwoma incydentami produkcyjnymi):
 *
 *   1. ZERO @keyframes. Wyłącznie transition.
 *      Animacja, która utknie na klatce 0%, trzyma opacity:0 na stałe i bije
 *      nawet !important. Transition, która nigdy nie wystartuje, zostawia
 *      element w stanie wynikającym z klas — czyli widoczny.
 *
 *   2. ZERO domyślnego opacity:0.
 *      Stan ukryty jest ZAWSZE zagnieżdżony pod `html.hbt-sr`, a tę klasę
 *      dodaje JS — i to tylko wtedy, gdy: jest IntersectionObserver, NIE ma
 *      prefers-reduced-motion i jest co ujawniać. Brak JS / błąd JS / JS
 *      zablokowany = brak `.hbt-sr` = strona w 100% widoczna.
 *
 *   3. Selektor ukrywający i ujawniający MUSZĄ mieszkać w tym samym pliku,
 *      obok siebie. Nigdy nie rozdzielaj ich między pliki — wycięcie jednego
 *      z nich (UCSS, minifikacja, merge) to trwale niewidoczna treść.
 *
 * Jeśli musisz coś tu zmienić i zastanawiasz się nad @keyframes — nie.
 *
 * @since 8.3.0 (2026-07-17)
 */

/* ── Stan ukryty ───────────────────────────────────────────────────
   Warunkowany klasą html.hbt-sr dodawaną przez JS.
   JS nadaje data-hbt-reveal WYŁĄCZNIE elementom, które w chwili startu są
   poniżej folda — więc ten opacity:0 nigdy nie dotyka tego, co użytkownik
   ma już na ekranie.

   UWAGA — TU CELOWO NIE MA WŁAŚCIWOŚCI `transition`.
   Deklaracja transition musi siedzieć w regule stanu DOCELOWEGO (.is-in),
   bo przeglądarka uruchamia przejście na podstawie stylu PO zmianie:
     • dodanie data-hbt-reveal (1 → 0) czyta tę regułę: brak transition
       → ukrycie NATYCHMIASTOWE, bez widocznego zanikania,
     • dodanie .is-in (0 → 1) czyta regułę niżej: jest transition
       → ujawnienie płynne.
   Gdyby transition stało tutaj, każdy element przy starcie ZANIKAŁBY przez
   420 ms — niewidoczne dla użytkownika (elementy są pod foldem), ale przy
   szybkim scrollu w dół widać byłoby sekcję gasnącą i zapalającą się z
   powrotem. Nie przenoś tej deklaracji wyżej. */
html.hbt-sr [data-hbt-reveal] {
    opacity: 0;
    transform: translateY(14px);
}

/* ── Stan ujawniony ───────────────────────────────────────────────
   Dodaje IntersectionObserver albo failsafe (1500 ms po DOMContentLoaded).
   `transform: none` zamiast translateY(0) — zdejmuje warstwę kompozytora
   po zakończeniu przejścia zamiast trzymać ją w nieskończoność.

   Stagger — JS ustawia --hbt-sr-d = (index % 5) * 45ms.
   Brak zmiennej (failsafe zeruje ją jawnie) → 0ms, ujawnienie natychmiast. */
html.hbt-sr [data-hbt-reveal].is-in {
    opacity: 1;
    transform: none;
    transition:
        opacity 420ms cubic-bezier(0.22, 0.61, 0.36, 1),
        transform 420ms cubic-bezier(0.22, 0.61, 0.36, 1);
    transition-delay: var(--hbt-sr-d, 0ms);
}

/* ── Bezpiecznik: reduced-motion ──────────────────────────────────
   JS i tak nie doda `.hbt-sr` przy reduced-motion, więc ten blok nie powinien
   mieć okazji zadziałać. Jest na wypadek, gdyby ktoś w przyszłości dodał tę
   klasę ręcznie/serwerowo albo użytkownik zmienił preferencję już po starcie
   strony (matchMedia zmienia się w locie, klasa nie). Wtedy: zero ruchu,
   pełna widoczność, natychmiast. */
@media (prefers-reduced-motion: reduce) {
    html.hbt-sr [data-hbt-reveal],
    html.hbt-sr [data-hbt-reveal].is-in {
        opacity: 1;
        transform: none;
        transition: none;
        transition-delay: 0ms;
    }
}

/* ── Bezpiecznik: druk ─────────────────────────────────────────────
   Wydruk nigdy nie może zgubić treści, która akurat nie została ujawniona. */
@media print {
    html.hbt-sr [data-hbt-reveal],
    html.hbt-sr [data-hbt-reveal].is-in {
        opacity: 1;
        transform: none;
        transition: none;
    }
}
