/* ==========================================================================
   WILCZY ŁUP — HUB-MANIFEST v4. Warstwa ruchu i sceny.
   Ładowany WYŁĄCZNIE na „/” (site.css niesie tokeny i resztę serwisu).

   ŹRÓDŁO: polecenie właściciela 2026-09-11 (po stykówce v3) nadpisujące otwarcie
   partytury KONCEPCJA_NARRACJI_hub_v3.md §3/§4. Reszta v3 (SEN 1–5, S6–S9, linia
   produktów) obowiązuje bez zmian i jest przeniesiona 1:1.

   ── CO ZOSTAŁO SKASOWANE ────────────────────────────────────────────────────
   S1 (Alfa 09 SIEDZI na bieli), T1 (cięcie na 04 SKOK i skok do dymka) oraz
   czarny wjazd kadru KV. Wraz z nimi: `.saga__veil`, `.scene--meet`, grupa G1
   i klatki t1-*. Strona zaczyna się kadrem KV — pierwsze malowanie JEST sceną.

   ── KONSTRUKCJA ─────────────────────────────────────────────────────────────
   KV, ZOOM, SEN 1–5 i IRIS leżą w JEDNEJ przypiętej scenie („saga”, 675 svh).

   DYMEK JEST JEDEN — ten WPALONY W ZDJĘCIE. Warstwa wektorowa (okno `.saga__bubble`
   przycięte `clip-path` do zwektoryzowanego obrysu chmurki + `.saga__outline`)
   leży na nim 1:1 przy skali 1,0 i jest wtedy PRZEZROCZYSTA: widz widzi raster.
   Dopiero w zoomie zapala się wypełnienie — i tym samym gasi tekst „ŚNI, ŻE JEST
   MNĄ” oraz łeb wilka, bo oba są pikselami zdjęcia, nie osobnymi elementami.
   To jest cała mechanika przejścia, dosłownie wg polecenia właściciela.

   ZOOM ROBI KADR, NIE DYMEK. `transform` (skala + dryf na środek ekranu) siedzi
   na `.saga__frame`, a `transform-origin` stoi w ŚRODKU DYMKA (`--bu-ox/--bu-oy`,
   w procentach kadru, z danych zdjęcia). Okno dymka i obrys są DZIEĆMI kadru, więc
   dziedziczą tę samą transformację — raster i wektor nie mogą się rozjechać ani
   o piksel, bo jadą jednym transformem. Wnętrze snu dostaje przeciwskalę 1/k i
   jest wyśrodkowane na (50 %, 44,2 %) okna, czyli DOKŁADNIE na punkcie stałym
   skalowania — inaczej sen dryfowałby z ekranu przy dużych k.

   ── PARTYTURA v4 ────────────────────────────────────────────────────────────
   Budżet ekranów: KV 100 · ZOOM 70 · SEN 460 · IRIS 45 = 675 svh (v3: 775).

   KV ·100 svh· kadr z puli (content/pages/home.json#copy.kv_pool)
       Nic się nie rusza i nie ma ani jednego słowa spoza zdjęcia. Nawigacja
       widoczna od pierwszej klatki. Pasy letterboksu mają kolor krawędzi
       zdjęcia, więc na telefonie kadr czyta się jako pełnoekranowy.

   ZOOM · KV → SEN · „zbliżenie na dymek” ·70 svh· (oś lokalna 0–100 %)
       0–10 %   cisza — kadr bez ruchu. Tyle trwa przeczytanie dymka.
      10–30 %   wypełnienie dymka + obrys opacity 0 → 1: tekst i wilk GASNĄ,
                zostaje jednolita pomarańczowa bryła z czarną kreską
      10–100 %  skala kadru wokół środka dymka: 1 → 1,6 (30 %) → 3,4 (60 %)
                → `--bk-full` (100 %), równolegle dryf `--bu-tx/--bu-ty`,
                który sadza środek dymka na środku ekranu do 62 %
      58–74 %   fotografia opacity 1 → 0 (ekran jest już kryty pomarańczem;
                gasimy ją, żeby nie płacić za malowanie rastra w skali 9×)
      66–80 %   obrys opacity 1 → 0 (jest wtedy poza kadrem; to polisa na
                wypadek, gdyby `--bk-full` okazał się dla jakiegoś ekranu ciasny)
      88 %      CIĘCIE: wnętrze snu opacity 0 → 1 na jednolitym pomarańczu
     100 %      cały ekran jednolicie pomarańczowy

       `--bk-full` jest PER ZDJĘCIE (dane, nie CSS): to najmniejsza skala, przy
       której prostokąt wpisany w chmurkę (0,852 × 0,580 okna, liczone
       z rastra ścieżki) kryje viewport — sprawdzone dla 17 rozmiarów ekranu od
       320×700 do 3440×1440, z zapasem 12 %. Wartości 7,0–9,2.

   SEN — 5 beatów WEWNĄTRZ dymka. Kolor, pozy i typografia PRZENIESIONE Z v2/v3
       BEZ ZMIAN — mają zamkniętą bramkę compliance i własną oś procentową.
       Maska nie rusza się przez cały sen (stoi na `--bk-full`): ani jednego
       przerysowania kształtu na 460 svh.

   IRIS · SEN 5 → S6 · „ekran zamyka się kołem” ·45 svh· (oś lokalna 0–100 %)
       0–16 %   pod spodem stoi już `wybudzenie.jpg` (wszedł w zoomie, kiedy
                ekran był kryty — widz nie widział podmiany)
      16–88 %   `clip-path: circle(var(--iris) at 50 % 50 %)`, 75 % → 0 %.
                75 % kryje róg na każdej proporcji (√2/2 ≈ 70,7 % z zapasem).
      88–100 %  cisza: pełnoekranowy kadr śpiącego psa

       ⚠️ ODSTĘPSTWO OD v3 §4.3, z polecenia właściciela: dymek NIE zwija się
       nad psem i NIE pęka. Ta animacja („wychodzi źle”) jest skasowana razem
       z `--bk-70`, `--bk-130`, `bubble-tail` i punktem lądowania `--bu-wx/wy`.

   ── SEN: OŚ WEWNĘTRZNA (bez zmian wobec v2) ─────────────────────────────────
   Granice beatów wynikają z wag vh (100+100+80+100+80 = 460vh):
       SEN 1  0      – 21,7 %   SEN 2  21,7 – 43,5 %   SEN 3  43,5 – 60,9 %
       SEN 4  60,9   – 82,6 %   SEN 5  82,6 – 100 %

   ── BUDŻET I ZAKAZY ─────────────────────────────────────────────────────────
   Wyłącznie `transform` i `opacity` (+ `clip-path`: chmurka statyczna, koło
   irysa animowane jednym promieniem). Zero animacji właściwości layoutu, zero
   filtrów per klatkę, zero animacji `background-color`. Zero rotacji na Alfie.
   Podmiana pozy NIGDY tweenem.
   prefers-reduced-motion / brak JS: cała saga rozpada się na statyczne karty
   (kadr KV z własnym, rastrowym dymkiem + pięć kart snu).
   ========================================================================== */

/* ---------- 0. ZMIENNE SCENY ---------- */

:root{
  --ease-out:cubic-bezier(0.22,1,0.36,1);
  --hub-pad:20px;
  /* Szerokość kadru KV. Cała pula ma proporcję 9:16, więc kadr jest jeden na
     wszystkie zdjęcia — dzięki temu okno dymka można trzymać w PROCENTACH kadru
     i przy skali 1,0 kryje ono raster 1:1 na każdej szerokości, bez ani jednego
     przeliczenia w JS. `--frame-h` liczy się z niej, nie odwrotnie. */
  --frame-w:min(100vw, calc(100svh * 9 / 16));
  --frame-h:calc(var(--frame-w) * 16 / 9);
  /* Domyślka na wypadek braku danych zdjęcia; realną wartość (7,0–9,2) wstawia
     szablon/skrypt rotacji per zdjęcie, bo zależy od tego, jaką część kadru
     zajmuje na nim dymek. */
  --bk-full:9.2;
}

@property --bk{syntax:"<number>";inherits:true;initial-value:1;}
@property --btx{syntax:"<length-percentage>";inherits:true;initial-value:0%;}
@property --bty{syntax:"<length-percentage>";inherits:true;initial-value:0%;}
@property --iris{syntax:"<length-percentage>";inherits:true;initial-value:75%;}

/* `clip`, nie `hidden`: `overflow-x:hidden` robi z <html>/<body> KONTENER
   SCROLLA, a wtedy view-timeline mierzy postęp względem czegoś, co się nie
   przewija — oś zastyga na 100 % i sen nigdy nie rusza (zdiagnozowane
   2026-09-08 w Chrome 140). `overflow-anchor:none` — scroll anchoring inaczej
   cofa viewport na scenach transformowanych scrollem. */
html.hub, html.hub body{overflow-x:clip;}
html.hub{overflow-anchor:none;-webkit-text-size-adjust:100%;}
html.hub body{background:var(--wl-black);}

.hub main{display:block;}
.wl-defs{position:absolute;width:0;height:0;overflow:hidden;}

/* ---------- 1. TYPOGRAFIA SCEN ---------- */

.hub-display{
  font-family:var(--wl-display);font-weight:900;text-transform:uppercase;
  line-height:0.92;letter-spacing:-0.01em;margin:0;overflow-wrap:break-word;
  font-size:clamp(2.5rem,1.5rem + 4.6vw,5rem);
  max-width:13ch;color:var(--wl-black);
}
.hub-display--big{font-size:clamp(3.25rem,2rem + 6.4vw,7rem);max-width:9ch;}
.hub-eyebrow{
  display:block;font-family:var(--wl-mono);font-weight:600;
  font-size:0.8125rem;letter-spacing:0.16em;text-transform:uppercase;margin:0;
}
.hub-sub{font-size:1.0625rem;line-height:1.45;max-width:32ch;margin:14px 0 0;}

/* ---------- 2. PLAKIETKA + NAWIGACJA (Z4) ---------- */
/* ⚠️ ZMIANA 2026-09-11 (ux-ui-director poz. 14), nazwana wprost jako odstępstwo od
   partytury §6.2/Z4: nawigacja jest widoczna OD PIERWSZEJ KLATKI, nie od S8/S9.
   Powód jest użytkowy, nie estetyczny: hub ma ~15 ekranów, a wejście z kodu QR na
   słoiku to użytkownik, który przyszedł po produkt — ukrycie jedynego wyjścia na
   jedenaście ekranów zostawia go bez skrótu. Kompromis z partyturą: PIERWSZY EKRAN
   NADAL NIE MA BELKI — plakietka i link stoją jako dwa osobne, białe kafelki na
   przezroczystym tle, więc „nagłówka” jako paska nie ma. Klasa `nav-on` (IO na S8)
   zmienia już WYŁĄCZNIE TŁO: kafelki zlewają się w białą belkę z kreską.
   Bez JS: dokładnie ten sam stan, tylko bez zmiany tła. */
.hub .wl-header{
  position:fixed;top:0;left:0;right:0;z-index:50;
  border-bottom:0;background:transparent;
}
.hub .wl-header__inner{padding:12px 16px;align-items:flex-start;}
.hub .wl-logo{background:var(--wl-white);padding:6px;gap:0;}
.hub .wl-logo img{height:30px;}
.hub .wl-logo__word{
  position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;
}
.hub .wl-nav a{background:var(--wl-white);padding:9px 12px;}
.js.hub .wl-header{transition:background .32s var(--ease-out);}
.js.hub.nav-on .wl-header{background:var(--wl-white);border-bottom:var(--wl-rule);}
.js.hub.nav-on .wl-logo,.js.hub.nav-on .wl-nav a{background:transparent;}
.js.hub.nav-on .wl-header__inner{padding:10px 16px;align-items:center;}

/* ---------- 3. SCENA — wspólny szkielet ---------- */

.scene{
  position:relative;min-height:calc(var(--vh,100) * 1svh);
  overflow:clip;display:grid;align-content:center;
  padding:88px var(--hub-pad) 56px;
}
.scene__inner{position:relative;z-index:2;width:100%;max-width:1120px;margin:0 auto;}
.scene__gate{margin:10px 0 0;}

/* wejścia narracyjne — TRIGGER (czas), nie scrub */
.js .fx{transition:opacity .58s var(--ease-out) var(--d,0ms),transform .58s var(--ease-out) var(--d,0ms);}
.js .scene:not(.on) .fx,
.js .manifest:not(.on) .fx,
.js .linia:not(.on) .fx,
.js .pas:not(.on) .fx,
.js .stado:not(.on) .fx{opacity:0;transform:translate3d(0,18px,0);}
.js .scene:not(.on) .alfa{transform:translate3d(0,10px,0) scale(0.94);}
.js .scene:not(.on) .photo{transform:scale(1.05);}

/* ==========================================================================
   4. SAGA — KV · ZOOM · SEN · IRIS na jednej przypiętej scenie
   ========================================================================== */

/* ── STAN BAZOWY = STATYCZNY (bez JS). Saga jest zwykłym stosem: kadr KV
      (z własnym, rastrowym dymkiem — to jest „dymek jako zwykła sekcja”)
      i pięć kart snu. Nic nie jest ukryte, nic nie wymaga skryptu. ── */

.saga{position:relative;background:var(--wl-black);}
.saga__back,.saga__band{display:none;}
.saga__iris{position:relative;}
.saga__frame{position:relative;background:var(--wl-black);}
.saga__photo{margin:0;}
.saga__photo img{display:block;width:100%;height:auto;}
.saga__wake{display:none;}              /* to samo zdjęcie niesie S6 */
.saga__outline{display:none;}           /* raster KV ma własny obrys */
.saga__bubble{position:relative;}
.saga__bubble-fill{display:none;}

/* ── STAN ANIMOWANY (tylko z JS) ───────────────────────────────────────────── */

.js .saga{height:calc(var(--saga-vh,775) * 1svh);background:var(--wl-black);}
.js .saga__stage{
  position:sticky;top:0;height:100svh;overflow:clip;background:var(--wl-black);
}
.js .saga__back{display:block;position:absolute;inset:0;z-index:0;background:var(--wl-black);}

/* Pasy letterboksu w kolorze krawędzi zdjęcia. Na szerokim ekranie kadr jest
   ograniczony WYSOKOŚCIĄ, więc `100svh - --frame-h` schodzi do zera i pasy
   znikają same — boki zostają czarne, bez ani jednego media query. */
.js .saga__band{
  display:block;position:absolute;left:0;right:0;z-index:0;
  height:max(0px, calc((100svh - var(--frame-h)) / 2));
}
.js .saga__band--top{top:0;background:var(--kv-top,#000);}
.js .saga__band--bottom{bottom:0;background:var(--kv-bottom,#000);}

/* Kadr lądowania — pełny ekran, POD irysem. Wchodzi w trakcie zoomu. */
.js .saga__wake{
  display:block;position:absolute;inset:0;z-index:1;margin:0;opacity:0;
}
.js .saga__wake picture{display:block;width:100%;height:100%;}
.js .saga__wake img{width:100%;height:100%;object-fit:cover;object-position:center 40%;}

/* IRIS — przycina wszystko powyżej kurczącym się kołem. Osobny element, bo na
   jednym nie da się mieć dwóch clip-path (chmurka na oknie, koło na scenie). */
.js .saga__iris{
  position:absolute;inset:0;z-index:2;
  clip-path:circle(var(--iris,75%) at 50% 50%);
}

/* Kadr: prostokąt 9:16 wpisany w ekran, wyśrodkowany MARGINESAMI, nie
   transformem — `transform` jest w całości zarezerwowany dla zoomu. */
.js .saga__frame{
  position:absolute;top:50%;left:50%;
  width:var(--frame-w);height:var(--frame-h);
  margin-left:calc(var(--frame-w) / -2);margin-top:calc(var(--frame-h) / -2);
  background:transparent;aspect-ratio:auto;
  transform-origin:var(--bu-ox,50%) var(--bu-oy,50%);
  transform:translate(var(--btx),var(--bty)) scale(var(--bk));
}
.js .saga__photo{position:absolute;inset:0;}
.js .saga__photo picture{display:block;width:100%;height:100%;}
.js .saga__photo img{width:100%;height:100%;object-fit:cover;object-position:center;}

/* OKNO DYMKA — dziecko kadru, więc dziedziczy zoom. Przy skali 1,0 leży
   dokładnie na dymku wpalonym w zdjęcie i jest przezroczyste. */
.js .saga__bubble{
  position:absolute;
  left:var(--bu-left);top:var(--bu-top);width:var(--bu-w);height:var(--bu-h);
  clip-path:url(#wl-dymek);
  transform:scaleX(var(--bu-mirror,1));transform-origin:50% 50%;
}
.js .saga__bubble-fill{
  display:block;position:absolute;inset:-2%;background:var(--wl-orange);opacity:0;
}
/* Przeciwskala: wnętrze jest pudełkiem wielkości ekranu, wyśrodkowanym na
   PUNKCIE STAŁYM skalowania (50 %, 44,2 % okna = `--bu-ox/--bu-oy` w układzie
   okna) i pomniejszonym 1/k. Przy okazji odwraca lustro okna, żeby sen nigdy
   nie był odbity. */
.js .saga__bubble-inner{
  position:absolute;left:50%;top:44.2%;
  width:100vw;height:100svh;margin-left:-50vw;margin-top:-50svh;
  transform-origin:50% 50%;
  transform:scaleX(var(--bu-mirror,1)) scale(calc(1 / max(var(--bk),0.02)));
  opacity:0;
}

/* OBRYS — ta sama ścieżka i ten sam rodzic co okno, ale grubość kreski dzielona
   przez skalę: stała grubość w pikselach ekranu. Kryje kreskę rastra 1:1. */
.js .saga__outline{
  display:block;position:absolute;overflow:visible;pointer-events:none;
  left:var(--bu-left);top:var(--bu-top);width:var(--bu-w);height:var(--bu-h);
  transform:scaleX(var(--bu-mirror,1));transform-origin:50% 50%;
  opacity:0;
}
.js .saga__outline path{
  fill:none;stroke:#0D0D0D;stroke-linejoin:round;stroke-linecap:round;
  stroke-width:calc(14.32 / max(var(--bk),0.05));
}

/* ==========================================================================
   6. SEN — pięć beatów wewnątrz okna dymka.
   Struktura i WSZYSTKIE klatki kluczowe przeniesione z v2 bez zmian: Alfa jest
   przypięta, świat przewija się pod nią, zmiana pozy to CIĘCIE, nigdy tween.
   ========================================================================== */

/* stan bazowy (bez JS): pięć statycznych kart na pomarańczu */
.dream{position:relative;background:var(--wl-orange);}
.dream__stage{position:relative;background:var(--wl-orange);}
.dream__layer,.dream__ground{display:none;}
.beat{padding:40px 0 8px;}
.beat + .beat{border-top:2px solid rgba(0,0,0,0.18);}
.beat__alfa{
  display:flex;flex-wrap:wrap;align-items:flex-end;justify-content:center;
  gap:20px;padding:0 var(--hub-pad);
}
.pose{margin:0;}
.pose img{max-height:26svh;max-width:min(70vw,420px);width:auto;height:auto;}
.line--3b{display:none;}

/* stan animowany */
.js .dream{position:absolute;inset:0;height:auto;background:var(--wl-orange);}
.js .dream__stage{position:absolute;inset:0;overflow:clip;background:var(--wl-orange);}
.js .dream__layer{display:block;position:absolute;inset:0;z-index:0;}
/* ZMIANA v4: pomarańcz NIE wjeżdża już od dołu. W v2/v3 był to gest „sen się
   zaczyna”, bo T2 kończyło się na czerni. W v4 zoom oddaje sen na GOTOWYM,
   jednolitym pomarańczu — wjazd drugiego pomarańczu po nim dawał błysk czerni
   między przejściem a snem. Płaszczyzna jest więc statyczna, a beat SEN 3→4
   nadal ma swoje czernienie (`dream__night`). */
.js .dream__orange{background:var(--wl-orange);}
.js .dream__night{background:var(--wl-black);opacity:0;}
.js .dream__ground{
  display:block;position:absolute;left:0;bottom:var(--ground-y,32%);z-index:1;
  width:400vw;height:14px;opacity:0;
  background-image:url("/assets/alfa/ziemia.svg");
  background-repeat:repeat-x;background-size:auto 100%;
}
.js .beat{position:absolute;inset:0;padding:0;border-top:0;}
.js .beat__alfa{
  display:block;position:absolute;z-index:2;padding:0;
  left:50%;bottom:var(--ground-y,32%);
  width:min(84vw,560px);height:min(34svh,270px);
  margin-left:calc(min(84vw,560px) / -2);
  transform-origin:bottom center;
}
.js .pose{position:absolute;inset:0;margin:0;opacity:0;display:grid;place-items:end center;}
.js .pose img{max-width:100%;max-height:100%;}
.js .line--3b{display:block;}

.beat__line{padding:18px var(--hub-pad) 24px;}
.js .beat__line{
  position:absolute;z-index:3;left:0;right:0;bottom:0;
  padding:0 var(--hub-pad) 46px;opacity:0;pointer-events:none;
}
.beat__line .hub-display{max-width:12ch;}
.beat__gate{margin:8px 0 0;}
.js .beat__gate{position:absolute;left:var(--hub-pad);bottom:20px;margin:0;}
.line--3b .hub-display{color:var(--wl-white);}

/* ==========================================================================
   DWA SILNIKI, JEDNA PARTYTURA, TRZY GRUPY.
   Klatki kluczowe są JEDYNYM źródłem prawdy o ruchu. Napędza je:
   (a) natywna oś scrolla — `animation-timeline: --saga` (Chrome/Edge 115+,
       Safari 26+), animacja idzie wtedy poza głównym wątkiem;
   (b) fallback dla przeglądarek bez osi (Firefox stable, 2026-09) — ta SAMA
       animacja jest `paused`, a rAF przesuwa ją ujemnym `animation-delay`.
   Nie ma tu drugiej implementacji ruchu — jest jedna partytura i dwa zegary.

   Grupy istnieją, żeby każdy odcinek mógł mieć SWOJE 0–100 %:
     GZ  ZOOM  (--b1 … --b2) — kadr, wypełnienie dymka, obrys, fotografia,
                               kadr lądowania. Ostatnia klatka HOLDUJE przez
                               cały sen (`fill-mode:both`), więc maska stoi
                               nieruchomo na `--bk-full` przez 460 svh.
     GD  SEN   (--b2 … --b3) — kolor, pozy i typografia snu (oś v2 BEZ ZMIAN)
     GI  IRIS  (--b3 … 100 %) — promień koła
   Element należy do dokładnie jednej grupy — inaczej `fill-mode:both` z ostatniej
   animacji nadpisywałby pozostałe poza ich zakresem.
   ========================================================================== */

.js .saga__frame,.js .saga__bubble-fill,.js .saga__bubble-inner,
.js .saga__outline,.js .saga__photo--kv,.js .saga__wake,
.js .dream__night,.js .dream__ground,.js .beat__alfa,.js .pose,.js .beat__line,
.js .saga__iris{
  animation-duration:1s;animation-timing-function:linear;animation-fill-mode:both;
  animation-play-state:paused;
}
/* GZ */
.js .saga__frame,.js .saga__bubble-fill,.js .saga__bubble-inner,
.js .saga__outline,.js .saga__photo--kv,.js .saga__wake{
  animation-delay:calc(var(--pz,0) * -1s);
}
/* GD */
.js .dream__night,.js .dream__ground,.js .beat__alfa,.js .pose,.js .beat__line{
  animation-delay:calc(var(--pd,0) * -1s);
}
/* GI */
.js .saga__iris{animation-delay:calc(var(--pi,0) * -1s);}

.js .saga__frame{animation-name:zoom-tf;}
.js .saga__bubble-fill{animation-name:zoom-fill;}
.js .saga__bubble-inner{animation-name:zoom-inner;}
.js .saga__outline{animation-name:zoom-outline;}
.js .saga__photo--kv{animation-name:zoom-photo;}
.js .saga__wake{animation-name:zoom-wake;}
.js .saga__iris{animation-name:iris-out;}

.js .dream__night{animation-name:dream-night;}
.js .dream__ground{animation-name:dream-ground;}
.js .beat__alfa{animation-name:dream-alfa;}
.js .pose--1{animation-name:pose-1;}
.js .pose--2{animation-name:pose-2;}
.js .pose--3{animation-name:pose-3;}
.js .pose--4{animation-name:pose-4;}
.js .pose--5{animation-name:pose-5;}
.js .pose--6{animation-name:pose-6;}
.js .pose--7{animation-name:pose-7;}
.js .pose--8{animation-name:pose-8;}
.js .pose--9{animation-name:pose-9;}
.js .line--1{animation-name:line-1;}
.js .line--2{animation-name:line-2;}
.js .line--3a{animation-name:line-3a;}
.js .line--3b{animation-name:line-3b;}
.js .line--4{animation-name:line-4;}
.js .line--5{animation-name:line-5;}

@supports (animation-timeline:view()){
  .js:not(.reveal) .saga{view-timeline-name:--saga;view-timeline-axis:block;}
  .js:not(.reveal) .saga__frame,.js:not(.reveal) .saga__bubble-fill,
  .js:not(.reveal) .saga__bubble-inner,.js:not(.reveal) .saga__outline,
  .js:not(.reveal) .saga__photo--kv,.js:not(.reveal) .saga__wake,
  .js:not(.reveal) .dream__night,.js:not(.reveal) .dream__ground,
  .js:not(.reveal) .beat__alfa,.js:not(.reveal) .pose,.js:not(.reveal) .beat__line,
  .js:not(.reveal) .saga__iris{
    animation-timeline:--saga;animation-delay:0s;animation-duration:auto;animation-play-state:running;
  }
  .js:not(.reveal) .saga__frame,.js:not(.reveal) .saga__bubble-fill,
  .js:not(.reveal) .saga__bubble-inner,.js:not(.reveal) .saga__outline,
  .js:not(.reveal) .saga__photo--kv,.js:not(.reveal) .saga__wake{
    animation-range:contain var(--b1) contain var(--b2);
  }
  .js:not(.reveal) .dream__night,.js:not(.reveal) .dream__ground,
  .js:not(.reveal) .beat__alfa,.js:not(.reveal) .pose,.js:not(.reveal) .beat__line{
    animation-range:contain var(--b2) contain var(--b3);
  }
  .js:not(.reveal) .saga__iris{animation-range:contain var(--b3) contain 100%;}
}

/* ── GZ · ZOOM (oś lokalna 0–100 % = 70 svh) ──────────────────────────────── */
/* Kadr rośnie wokół środka dymka i jednocześnie sadza ten środek na środku
   ekranu. Krzywa jest łamana, nie liniowa: start wolno (widz ma zauważyć, że to
   jego zdjęcie się przybliża), koniec szybko (nie ma już czego oglądać). */
@keyframes zoom-tf{
  0%,10%{--bk:1;--btx:0%;--bty:0%;}
  30%{--bk:1.6;--btx:calc(var(--bu-tx) * 0.42);--bty:calc(var(--bu-ty) * 0.42);}
  62%{--bk:3.8;--btx:var(--bu-tx);--bty:var(--bu-ty);}
  100%{--bk:var(--bk-full);--btx:var(--bu-tx);--bty:var(--bu-ty);}
}
/* Wypełnienie: to ONO gasi tekst „ŚNI, ŻE JEST MNĄ” i łeb wilka — oba są
   pikselami zdjęcia, więc nie da się ich zgasić inaczej niż przykryciem. */
@keyframes zoom-fill{
  0%,10%{opacity:0;}
  30%,100%{opacity:1;}
}
/* Obrys wchodzi razem z wypełnieniem (kryje kreskę rastra), wychodzi, kiedy jest
   już poza kadrem — polisa na ciasny `--bk-full`, nie efekt. */
@keyframes zoom-outline{
  0%,10%{opacity:0;}
  30%,66%{opacity:1;}
  80%,100%{opacity:0;}
}
/* Fotografia gaśnie dopiero wtedy, gdy pomarańcz kryje już ekran. */
@keyframes zoom-photo{
  0%,58%{opacity:1;}
  74%,100%{opacity:0;}
}
/* Kadr lądowania wchodzi pod spodem, kiedy ekran jest kryty — podmiany nie widać. */
@keyframes zoom-wake{
  0%,58%{opacity:0;}
  74%,100%{opacity:1;}
}
/* Wnętrze snu: CIĘCIE na jednolitym pomarańczu, nie przenikanie. */
@keyframes zoom-inner{
  0%,87.9%{opacity:0;}
  88%,100%{opacity:1;}
}

/* ── GI · IRIS (oś lokalna 0–100 % = 45 svh) ──────────────────────────────── */
/* 75 % promienia kryje róg na każdej proporcji (√2/2 ≈ 70,7 % + zapas).
   Liniowo i bez easingu: koło ma się zamykać, nie odbijać. */
@keyframes iris-out{
  0%,16%{--iris:75%;}
  88%,100%{--iris:0%;}
}

/* ── G3 · SEN (oś lokalna 0–100 % = 460 svh) — PRZENIESIONE Z v2 ─────────── */
@keyframes dream-night{
  0%,48%{opacity:0;}
  60%,60.8%{opacity:1;}
  60.9%,100%{opacity:0;}
}
@keyframes dream-ground{
  0%,9%{opacity:0;transform:translate3d(0,0,0);}
  12%,21.7%{opacity:1;transform:translate3d(0,0,0);}
  39%,43.5%{opacity:1;transform:translate3d(-30%,0,0);}
  55%{opacity:1;transform:translate3d(-31.5%,0,0);}
  60%{opacity:0;transform:translate3d(-32%,0,0);}
  86%{opacity:0;transform:translate3d(-32%,0,0);}
  90%,100%{opacity:1;transform:translate3d(-33%,0,0);}
}
@keyframes dream-alfa{
  0%{transform:translate3d(0,0,0) scale(0.98);}
  10%{transform:translate3d(0,0,0) scale(1);}
  21.7%{transform:translate3d(0,0,0) scale(1.08);}
  43.5%{transform:translate3d(0,0,0) scale(1.2);}
  52%{transform:translate3d(0,4%,0) scale(1.14);}
  60.9%{transform:translate3d(0,6%,0) scale(1.05);}
  /* SEN 4 — SKOK. Poprawka 2026-09-11 wobec v3: przesunięcie w prawo (17 %/21 %)
     przy skali 1,6 wyrzucało ŁEB Alfy poza prawą krawędź (QA v3: oko na x≈355 przy
     ekranie 375). Przy tej skali nie da się zmieścić łba, pchając pudełko w prawo —
     więc kadr jedzie w LEWO: łeb zostaje przy prawej krawędzi, a ogon wychodzi poza
     lewą, co czyta się jako pęd. Wartość jest zmienną, bo pudełko beatu ma inną
     szerokość i inną oś na desktopie (§16). */
  72%{transform:translate3d(var(--s4-x1,-28%),15%,0) scale(1.6);}
  82.6%{transform:translate3d(var(--s4-x2,-24%),19%,0) scale(1.6);}
  92%,100%{transform:translate3d(0,0,0) scale(1);}
}
@keyframes pose-1{0%,9.4%{opacity:1;} 10%,100%{opacity:0;}}
@keyframes pose-2{0%,9.4%{opacity:0;} 10%,21.1%{opacity:1;} 21.7%,100%{opacity:0;}}
@keyframes pose-3{0%,21.1%{opacity:0;} 21.7%,38.4%{opacity:1;} 39%,100%{opacity:0;}}
@keyframes pose-4{0%,38.4%{opacity:0;} 39%,42.9%{opacity:1;} 43.5%,100%{opacity:0;}}
@keyframes pose-5{0%,42.9%{opacity:0;} 43.5%,51.4%{opacity:1;} 52%,100%{opacity:0;}}
@keyframes pose-6{0%,51.4%{opacity:0;} 52%,60.3%{opacity:1;} 60.9%,100%{opacity:0;}}
@keyframes pose-7{0%,60.3%{opacity:0;} 60.9%,82%{opacity:1;} 82.6%,100%{opacity:0;}}
@keyframes pose-8{0%,82%{opacity:0;} 82.6%,91.4%{opacity:1;} 92%,100%{opacity:0;}}
@keyframes pose-9{0%,91.4%{opacity:0;} 92%,100%{opacity:1;}}
@keyframes line-1{
  0%,11%{opacity:0;transform:translate3d(0,12px,0);}
  14.5%,20.5%{opacity:1;transform:translate3d(0,0,0);}
  21.7%,100%{opacity:0;transform:translate3d(0,0,0);}
}
@keyframes line-2{
  0%,22.5%{opacity:0;transform:translate3d(0,12px,0);}
  27%,41%{opacity:1;transform:translate3d(0,0,0);}
  43.5%,100%{opacity:0;transform:translate3d(0,0,0);}
}
@keyframes line-3a{
  0%,44.5%{opacity:0;transform:translate3d(0,12px,0);}
  48%,51.8%{opacity:1;transform:translate3d(0,0,0);}
  52.2%,100%{opacity:0;transform:translate3d(0,0,0);}
}
@keyframes line-3b{
  0%,51.8%{opacity:0;transform:translate3d(0,0,0);}
  52.2%,59%{opacity:1;transform:translate3d(0,0,0);}
  60.9%,100%{opacity:0;transform:translate3d(0,0,0);}
}
@keyframes line-4{
  0%,61.4%{opacity:0;transform:translate3d(0,12px,0);}
  65%,80%{opacity:1;transform:translate3d(0,0,0);}
  82.6%,100%{opacity:0;transform:translate3d(0,0,0);}
}
/* ZMIANA v4: zdanie SEN 5 gaśnie jeszcze NA OSI SNU (96 → 100 %), a nie dopiero
   pod irysem. Inaczej kurczące się koło przecinało je w pół i przez pół sekundy
   na ekranie stało „IĄ”. Zostaje cichy beat: pomarańcz i wilk, potem zamknięcie. */
@keyframes line-5{
  0%,83.5%{opacity:0;transform:translate3d(0,12px,0);}
  88%,96%{opacity:1;transform:translate3d(0,0,0);}
  100%{opacity:0;transform:translate3d(0,0,0);}
}

/* ---------- 7. S6 WYBUDZENIE ---------- */
.scene--wake{background:var(--wl-black);padding:0;align-content:stretch;}
.scene--wake .scene__inner{display:grid;grid-template-rows:1fr auto;height:calc(var(--vh,100) * 1svh);max-width:none;}
.scene--wake .photo{margin:0;min-height:0;overflow:clip;}
.photo picture{display:block;height:100%;min-height:0;}
.scene--wake .photo img{width:100%;height:100%;object-fit:cover;object-position:center 40%;}
.scene--wake .wake-copy{background:var(--wl-black);padding:26px var(--hub-pad) 34px;}
.scene--wake .hub-display{color:var(--wl-white);max-width:14ch;}

/* ---------- 8. S7 TWOJA CZĘŚĆ ---------- */
/* Kadr startuje ciasno na ŁAPIE przy dolnej krawędzi i jedzie w górę do miski
   i słoika (partytura v3 §3/S7): ruchem robimy to, czego nie ma na zdjęciu —
   dojście do miski. `object-position` jest STATYCZNE, jedzie `translateY`
   wewnątrz przyciętego kadru, więc budżet (transform/opacity) zostaje cały. */
.scene--bowl{background:var(--wl-white);padding:0;align-content:stretch;}
.scene--bowl .scene__inner{display:grid;grid-template-rows:1fr auto;height:calc(var(--vh,100) * 1svh);max-width:none;}
.scene--bowl .photo{margin:0;min-height:0;overflow:clip;}
.scene--bowl .photo img{width:100%;height:100%;object-fit:cover;object-position:center 78%;transition:object-position 0s;}
.js .scene--bowl .photo img{transform:translate3d(0,6%,0);transition:transform 1.1s var(--ease-out) 120ms;}
.js .scene--bowl.on .photo img{transform:translate3d(0,0,0);}
.scene--bowl .bowl-copy{
  background:var(--wl-white);padding:24px var(--hub-pad) 30px;
  display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;column-gap:14px;
}
.scene--bowl .hub-display{max-width:12ch;}
.scene--bowl .hub-sub{font-size:1rem;}
.bowl-alfa{grid-column:2;grid-row:1/3;align-self:end;margin:0;}
.bowl-alfa img{width:min(20vw,84px);height:auto;}

/* ---------- 9. S8 FAKTY ---------- */
.scene--facts{background:var(--wl-white);padding:116px var(--hub-pad) 48px;overflow:visible;align-content:start;}
.scene--facts .scene__inner{
  display:grid;grid-template-columns:minmax(0,1fr) 30%;
  column-gap:16px;row-gap:20px;align-items:start;max-width:1000px;
}
.scene--facts .hub-display{grid-column:1;max-width:11ch;}
.facts-shot{grid-column:2;grid-row:1/3;margin:0;}
.facts-shot img{width:100%;height:auto;max-height:56svh;object-fit:contain;object-position:top center;}
.facts{grid-column:1;display:grid;gap:12px;margin:0;padding:0;list-style:none;}
.facts li{
  font-size:0.9375rem;line-height:1.45;max-width:44ch;
  border-left:3px solid var(--wl-orange);padding-left:12px;color:var(--wl-black);
}

/* ---------- 10. S9 WYZWANIE ---------- */
.scene--dare{background:var(--wl-orange);}
.scene--dare .scene__inner{display:grid;justify-items:start;gap:22px;}
.scene--dare .hub-display{max-width:12ch;}
.alfa--dare{margin:0;}
.js .scene--dare:not(.on) .alfa--dare{transform:translate3d(0,15%,0);}
.alfa--dare img{width:min(56vw,260px);height:auto;}
.dare-seal{width:min(78vw,320px);height:auto;}
.dare-link{
  font-family:var(--wl-mono);font-weight:700;font-size:0.8125rem;
  letter-spacing:0.12em;text-transform:uppercase;
  background:var(--wl-black);color:var(--wl-white);text-decoration:none;
  padding:14px 18px;display:inline-block;
}
.dare-link:hover,.dare-link:focus-visible{background:var(--wl-white);color:var(--wl-black);}

/* ---------- 11. MANIFEST ---------- */
.manifest{background:var(--wl-white);color:var(--wl-black);padding:72px var(--hub-pad) 56px;}
.manifest__inner{max-width:1120px;margin:0 auto;}
.manifest .hub-eyebrow{color:var(--wl-black);margin-bottom:16px;}
.manifest__text{
  font-family:var(--wl-body);font-weight:300;font-size:1.1875rem;line-height:1.5;
  max-width:34ch;margin:0;
}

/* ==========================================================================
   12. LINIA PRODUKTÓW — idiom decku (Deck.html slajd 06), przeniesiony
   Biel jest tu drugim (po S8) „wyjściem z opowieści”: po dziewięciu ekranach
   fabuły wchodzi rzecz i sekcja ma wyglądać jak KATALOG, nie jak dalszy ciąg.
   ========================================================================== */

.linia{background:var(--wl-white);color:var(--wl-black);padding:0 var(--hub-pad) 8px;scroll-margin-top:72px;}
/* Czarna kreska nad nagłówkiem: to jest miejsce, w którym opowieść się kończy
   i zaczyna półka. Bez niej manifest i katalog zlewają się w jedną białą płachtę. */
.linia__head{max-width:1120px;margin:0 auto 22px;border-top:var(--wl-rule);padding-top:20px;}
.linia .hub-eyebrow{color:var(--wl-black);margin-bottom:10px;}
.linia__sub{font-size:1rem;line-height:1.45;max-width:36ch;margin:12px 0 0;}
.linia__grid{
  max-width:1120px;margin:0 auto;padding:0;list-style:none;
  display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px;
}
.linia__cell{display:flex;}
.linia__card{
  display:flex;flex-direction:column;gap:10px;width:100%;
  text-decoration:none;color:var(--wl-black);
}
.linia__card--static{cursor:default;}
/* Pasek koloru SKU nad kaflem — `border-top:3mm solid <kolor>` z decku. */
.linia__bar{display:block;height:8px;background:var(--sku);}
.linia__shot{
  display:block;background:var(--sku);overflow:hidden;
  aspect-ratio:3 / 4;
}
/* FALLBACK PACKSHOTU — partytura §5.4 A3: „apla w kolorze SKU + wordmark”.
   Ten sam idiom, którym posługuje się strona produktu (.wl-product-header__media
   --placeholder) — pole koloru SKU i wordmark marki, bez ramki i bez ikony.
   Wordmark jest TEKSTEM, nie obrazkiem: kafel bez packshotu nie ma czego opisać
   altem, a czytnik ekranu dostaje nazwę marki zamiast opisu nieistniejącego zdjęcia. */
.linia__shot--apla{display:grid;place-items:center;padding:10px;}
.linia__apla-word{
  font-family:var(--wl-display);font-weight:900;text-transform:uppercase;
  font-size:clamp(1rem,0.55rem + 2.1vw,1.5rem);line-height:0.86;letter-spacing:-0.01em;
  color:var(--wl-black);text-align:center;max-width:6ch;
}
.linia__img{display:block;width:100%;height:100%;}
.linia__img--contain{object-fit:contain;}
.linia__img--cover{object-fit:cover;}
.linia__body{display:grid;gap:5px;justify-items:start;}
.linia__name{
  font-family:var(--wl-display);font-weight:800;text-transform:uppercase;
  font-size:1.0625rem;line-height:1;letter-spacing:-0.005em;
}
.linia__meta{font-family:var(--wl-mono);font-size:0.6875rem;letter-spacing:0.08em;text-transform:uppercase;color:var(--wl-muted);}
/* .klasa-chip — komponent decku (deck_components.md §2), przeniesiony 1:1:
   czarna piguła z ivory tekstem, jedyny sposób odróżnienia karmy
   pełnoporcjowej od uzupełniającej w linii. */
.klasa-chip{
  display:inline-block;background:#0D0D0D;color:#FAF7F2;
  padding:3px 7px;font-family:var(--wl-mono);font-size:0.625rem;font-weight:700;
  letter-spacing:0.08em;text-transform:uppercase;line-height:1.25;
}
.linia__pending{font-size:0.75rem;line-height:1.35;color:var(--wl-muted);}
a.linia__card:hover .linia__name,a.linia__card:focus-visible .linia__name{text-decoration:underline;text-underline-offset:3px;}

/* ---------- 13. NIEZBĘDNIK — pas, nie kafel ---------- */
.pas{background:var(--wl-white);color:var(--wl-black);padding:44px var(--hub-pad) 36px;}
.pas__inner{max-width:1120px;margin:0 auto;border-top:var(--wl-rule);padding-top:18px;}
.pas__name{font-family:var(--wl-display);font-weight:900;text-transform:uppercase;font-size:1.75rem;line-height:0.95;margin:0;}
.pas__sub{font-size:0.9375rem;margin:6px 0 0;}
.pas__label{font-family:var(--wl-mono);font-size:0.6875rem;letter-spacing:0.1em;text-transform:uppercase;margin:16px 0 0;color:var(--wl-muted);}
.pas__links{list-style:none;margin:8px 0 0;padding:0;display:grid;gap:6px;}
.pas__links a{
  font-family:var(--wl-mono);font-weight:700;font-size:0.6875rem;letter-spacing:0.1em;
  text-transform:uppercase;color:var(--wl-black);text-decoration:underline;text-underline-offset:3px;
}

/* ---------- 14. STADO ---------- */
.stado{background:var(--wl-white);color:var(--wl-black);padding:0 var(--hub-pad) 56px;}
.stado__inner{max-width:1120px;margin:0 auto;border-top:var(--wl-rule);padding-top:18px;}
.stado__name{font-family:var(--wl-display);font-weight:900;text-transform:uppercase;font-size:1.75rem;line-height:0.95;margin:0;}
.stado__sub{font-size:0.9375rem;margin:6px 0 0;}
.stado-form{display:grid;gap:12px;margin-top:16px;max-width:520px;}
.stado-form__row{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;}
.stado-form input[type="email"]{
  font-family:var(--wl-body);font-size:16px;padding:12px;
  border:var(--wl-rule);background:var(--wl-white);color:var(--wl-black);min-width:0;
}
.stado-form button{
  font-family:var(--wl-mono);font-weight:700;font-size:0.75rem;letter-spacing:0.12em;
  text-transform:uppercase;background:var(--wl-black);color:var(--wl-white);
  border:var(--wl-rule);padding:12px 16px;cursor:pointer;
}
.stado-form button:hover{background:var(--wl-orange);border-color:var(--wl-orange);}
.stado-consent{
  display:grid;grid-template-columns:auto minmax(0,1fr);gap:8px;align-items:start;
  font-family:var(--wl-body);font-size:0.8125rem;line-height:1.45;
}
.stado-consent input{margin-top:3px;}
.stado-form__note{font-size:0.8125rem;color:var(--wl-muted);margin:0;}

/* ---------- 15. STOPKA HUBU ---------- */
.hub .wl-footer{border-top:1px solid #E4E0D8;margin-top:0;}

/* ---------- 16. DESKTOP ---------- */

@media (min-width:560px){
  .linia__grid{grid-template-columns:repeat(3,minmax(0,1fr));}
}
@media (min-width:800px){
  :root{--hub-pad:40px;}
  .scene{padding:112px var(--hub-pad) 72px;}
  .scene--wake,.scene--bowl{padding:0;}
  .hub .wl-header__inner{padding:20px 24px;}
  .hub .wl-logo img{height:36px;}
  /* Na desktopie sylwetka schodzi z osi w prawo, a zdanie zajmuje lewą połowę:
     inaczej SKOK (skala 1,6) kładł się czarną masą na czarnej typografii. */
  .js .beat__alfa{width:min(52vw,720px);height:min(44svh,420px);left:64%;
    margin-left:calc(min(52vw,720px) / -2);--s4-x1:2%;--s4-x2:6%;}
  .js .beat__line{padding-bottom:76px;max-width:52%;}
  .dream__ground{width:300vw;height:18px;}
  .scene--wake .wake-copy,.scene--bowl .bowl-copy{padding:34px var(--hub-pad) 44px;}
  .scene--bowl .bowl-copy{max-width:1120px;margin:0 auto;width:100%;}
  .bowl-alfa img{width:120px;}
  .scene--facts .scene__inner{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);column-gap:56px;}
  .scene--dare .scene__inner{grid-template-columns:minmax(0,1fr) minmax(0,1fr);align-items:center;gap:40px;}
  .scene--dare .alfa--dare{grid-row:1/4;}
  .alfa--dare img{width:100%;max-width:420px;}
  .manifest{padding:112px var(--hub-pad) 72px;}
  .manifest__text{font-size:1.375rem;max-width:46ch;}
  .linia{padding:0 var(--hub-pad) 12px;}
  .linia__grid{grid-template-columns:repeat(6,minmax(0,1fr));gap:18px;}
  .linia__name{font-size:1rem;}
  .pas__inner,.stado__inner{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.2fr);column-gap:40px;}
  .pas__name,.stado__name{grid-column:1;}
  .pas__sub,.stado__sub{grid-column:1;}
  .pas__label,.pas__links{grid-column:2;grid-row:1/4;}
  .pas__links{grid-row:2/4;align-content:start;}
  .stado-form{grid-column:2;grid-row:1/4;margin-top:0;}
}

/* ==========================================================================
   17. DOSTĘPNOŚĆ — prefers-reduced-motion: KOMPLETNA strona statyczna.
   Saga przestaje być przypięta i rozpada się na karty: S1, kadr KV (dymek jako
   ZWYKŁA SEKCJA — raster niesie go sam), pięć kart snu. Żadna treść nie znika.
   ========================================================================== */

@media (prefers-reduced-motion:reduce){
  .js .fx,
  .js .scene:not(.on) .fx,
  .js .manifest:not(.on) .fx,
  .js .linia:not(.on) .fx,
  .js .pas:not(.on) .fx,
  .js .stado:not(.on) .fx,
  .js .scene:not(.on) .alfa,
  .js .scene:not(.on) .photo,
  .js .scene--dare:not(.on) .alfa--dare{opacity:1 !important;transform:none !important;transition:none !important;}
  .js .scene--bowl .photo img{transform:none !important;transition:none !important;}
  *,*::before,*::after{animation:none !important;scroll-behavior:auto !important;}

  /* Powrót DOKŁADNIE do stanu bazowego (tego samego, który widzi przeglądarka
     bez JS): zwykły stos sekcji, zero przypięcia, zero animacji. */
  .js .saga{height:auto !important;background:var(--wl-white) !important;}
  .js .saga__stage{position:static !important;height:auto !important;overflow:visible !important;background:transparent !important;}
  .js .saga__back,.js .saga__band{display:none !important;}
  .js .saga__wake{display:none !important;}
  .js .saga__iris{position:static !important;clip-path:none !important;}
  .js .saga__frame{position:relative !important;inset:auto !important;top:auto !important;left:auto !important;
    margin:0 !important;transform:none !important;height:auto !important;
    width:100% !important;background:var(--wl-black) !important;}
  .js .saga__photo{position:static !important;opacity:1 !important;transform:none !important;}
  .js .saga__photo picture{height:auto !important;}
  .js .saga__photo img{height:auto !important;object-fit:contain !important;}
  .js .saga__outline{display:none !important;}
  .js .saga__bubble{
    position:static !important;width:auto !important;height:auto !important;
    clip-path:none !important;transform:none !important;opacity:1 !important;
  }
  .js .saga__bubble-fill{display:none !important;}
  .js .saga__bubble-inner{
    position:static !important;width:auto !important;height:auto !important;
    margin:0 !important;transform:none !important;opacity:1 !important;
  }
  .js .dream{position:static !important;height:auto !important;background:var(--wl-orange) !important;}
  .js .dream__stage{position:static !important;height:auto !important;overflow:visible !important;background:var(--wl-orange) !important;}
  .js .dream__layer,.js .dream__ground{display:none !important;}
  .js .beat{position:static !important;padding:40px 0 8px !important;}
  .js .beat + .beat{border-top:2px solid rgba(0,0,0,0.18) !important;}
  .js .beat__alfa{
    display:flex !important;position:static !important;width:auto !important;height:auto !important;
    margin:0 !important;transform:none !important;flex-wrap:wrap;align-items:flex-end;
    justify-content:center;gap:20px;padding:0 var(--hub-pad) !important;
  }
  .js .pose{position:static !important;opacity:1 !important;display:block !important;}
  .js .pose img{max-height:26svh !important;max-width:min(70vw,420px) !important;}
  .js .beat__line{
    position:static !important;opacity:1 !important;transform:none !important;
    padding:18px var(--hub-pad) 24px !important;
  }
  .js .line--3b{display:none !important;}
  .js .beat__line .hub-display{color:var(--wl-black) !important;}
}

/* ---------- 18. HAK PODGLĄDU — tylko do zrzutów ----------------------------
   ?reveal=1 wyłącza natywną oś scrolla i zamraża sagę na zadanym postępie:
     &P=0..1   postęp CAŁEJ sagi (jedna liczba = jedna klatka partytury)
     &z= &d= &i=  nadpisanie pojedynczego odcinka (zoom / sen / iris)
     &kv=<stem>   wymuszenie konkretnego psa z puli
     &y=<ekrany>  przewinięcie przed zrzutem (do scen poza sagą)
   Zrzuty robi scripts/shot.mjs (CDP) — NIE `--window-size`, który na tej
   maszynie nie schodzi poniżej 500 px szerokości.                          */
.reveal .fx{opacity:1 !important;transform:none !important;transition:none !important;}
.reveal .scene:not(.on) .alfa--dare,
.reveal .scene:not(.on) .photo{transform:none !important;}
.reveal .scene--bowl .photo img{transition:none !important;}
/* (stan nawigacji nie wymaga już haka podglądu — belka jest widoczna od klatki 1) */
