/* ============================================================================
   Keepino — landing keepino.com
   ----------------------------------------------------------------------------
   Powierzchnia publiczna. Zero JS, zero zależności z sieci, zero trackerów.
   Kolejność wczytywania: brand.css → kit.css → landing.css (bez styles.css —
   ten jest tylko dla apki).

   Warstwa własna landingu, bo strona ma typografię PLAKATOWĄ, której kit nie
   opisuje (kit celuje w gęsty interfejs). Komponentów z kitu używam wprost:
   .kp-btn, .kp-card, .kp-table, .kp-badge, .kp-pre/.kp-codeblock, .kp-nav,
   .kp-eyebrow, .kp-link, .kp-meta, .kp-num. Nowe klasy mają prefiks .lp-,
   żeby nie kolidowały z .kp-.
   ============================================================================ */

/* ────────────────────────────────────────────────────────────────────────────
   0. Landing jest TYLKO JASNY — decyzja właściciela (2026-07-26, docs/messaging.md p. 6)
   Wcześniej stąd wychodziła „Noc" z `prefers-color-scheme: dark`, przepisana 1:1 z brand.css.
   Usunięte świadomie: strona sprzedażowa ma jeden, przewidywalny wygląd, ten sam na każdym
   ekranie i na zrzutach. `color-scheme: light` mówi to też przeglądarce, więc formanty
   (paski przewijania, autofill) nie przechodzą w ciemny wbrew stronie.
   UWAGA: `brand.css` w tym katalogu włącza Noc atrybutem [data-theme=dark], którego statyczny
   HTML nigdy nie ustawia — więc sam plik tokenów niczego tu nie zaciemni.
   To NIE dotyczy apki ani panelu admina: tam Noc zostaje.
   UTRZYMANIE: landing/css/brand.fa45fb48.css?d=9b04846 i kit.css to KOPIE plików z /css (żeby katalog dał się
   wdrożyć samodzielnie na Pages). Przed deployem: diff -q css/brand.fa45fb48.css?d=9b04846 landing/css/brand.fa45fb48.css?d=9b04846
   ──────────────────────────────────────────────────────────────────────────── */

html { color-scheme: light; }
/* ────────────────────────────────────────────────────────────────────────────
   1. Strona
   ──────────────────────────────────────────────────────────────────────────── */

:root {
  /* 1310, nie 1120. Reguła marginesu kosztuje SZEROKOŚĆ, nie wysokość: linia zabiera
     `--lp-rail` = 190 px z kolumny, więc przy 1120 czytelna kolumna spadała
     1032 → 842 px i proza łamała się na więcej linii — desktop wyrósł o 155 px
     (zmierzone). Arytmetyka: `--lp-gutter` (44 × 2) leży WEWNĄTRZ `--lp-maxw`, więc
     1032 czytelnej + 190 marginesu + 88 wyściółki = 1310. Tyle wystarcza, żeby
     margines pojawił się POZA kolumną, a nie ją zjadł.
     Górna granica jest twarda: 1310 + 2 × 44 zostawia jeszcze oddech na 1440 px.
     Nie podnoś do 1416 (kolumna 1138 z karty rytmu) — tam strona zaczyna dotykać
     krawędzi okna na najczęstszym laptopie. */
  --lp-maxw: 1310px;
  --lp-gutter: clamp(18px, 5vw, 44px);
  /* Dolny próg 40 px, nie 56: na 390 px `8vw` = 31 px, więc clamp brał zawsze
     minimum, a SIEDEM sekcji × 56 px = 392 px samego powietrza między nimi przy
     budżecie przewijania 9173 px (zmierzone). 40 px zostawia rytm czytelny
     i oddaje 112 px budżetu. Na desktopie nic się nie zmienia — tam wygrywa 8vw. */
  --lp-sect: clamp(40px, 8vw, 104px);

  /* ── REGUŁA MARGINESU — sygnatura strony (design/ds/README.md) ─────────────
     Włosowa linia na STAŁYM odstępie od prawej krawędzi kolumny, a na niej
     etykiety sekcji wyrównane do prawej: margines zeszytu laboratoryjnego,
     ten sam przyrząd co margines metadanych w apce.
     Trzy liczby, jedna zależność — pozycja linii WYNIKA z szerokości kolumny
     etykiety i odstępu, więc linia zawsze stoi 18 px od etykiety i nie trzeba
     jej dostrajać osobno przy każdej zmianie. W design/ds/landing/rhythm.html
     to samo zapisane bezwzględnie jako `right: 246px` przy 56 px wyściółki
     i 172 px etykiety (246 = 56 + 172 + 18). */
  --lp-rail-label: 172px;
  --lp-rail-gap: 18px;
  --lp-rail: calc(var(--lp-rail-label) + var(--lp-rail-gap));   /* = 190px */
}

html { -webkit-text-size-adjust: 100%; }

.lp {
  /* .kp-page daje tło, tusz, mono i box-sizing — tu tylko rytm strony */
  overflow-x: clip;               /* pas bezpieczeństwa: body nigdy nie jedzie w poziomie */

  /* KONTRAST — poprawka policzona, nie estetyczna.
     Cały drobny tekst landingu (akapity, punkty, podpisy, etykiety sekcji,
     .kp-label/.kp-hint/.kp-meta z kitu) jedzie przez --muted. Na Papierze
     #ECEBE3 (Y=0,828) grafit --kp-n-600 #6B6D66 (Y=0,150) daje 4,38:1 — czyli
     PONIŻEJ 4,5:1 z WCAG 1.4.3 dla tekstu. Kit liczył ten token na białej
     karcie (5,24:1 ✓), a landing stoi na Papierze i traci na nim 0,12.
     Podmieniam token LOKALNIE dla strony na --kp-n-700 #4A4C50 (Y=0,072):
       na Papierze ....... 7,19:1  ✓ AA (i AAA dla ≥18,66 px)
       na białej karcie .. 8,60:1  ✓ AAA
     Tej samej wartości używają zatwierdzone karty projektowe
     (design/ds/landing/*.html: `.lede`, `.body`, `.lb` → --n700).
     Apki to NIE dotyczy: podmiana siedzi na body.lp, nie w brand.css. */
  --muted: var(--kp-n-700);
  /* --faint zostaje jaśniejszy od --muted, bo jest w JEDNYM miejscu: skrót ⌘K
     w makiecie telefonu (aria-hidden, tekst będący częścią obrazka interfejsu —
     wyjątek „incidental text" z WCAG 1.4.3). Ale --kp-n-500 na Papierze to
     2,37:1, czyli nieczytelne także jako obrazek; --kp-n-600 daje 4,38:1. */
  --faint: var(--kp-n-600);
}

/* Siatka kropek — ten sam znak firmowy „papieru milimetrowego", co w design/.
   Fixed, więc nie rośnie z treścią; pod treścią (z-index 0) i nieklikalna. */
.lp::before {
  content: "";
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  background-image: radial-gradient(var(--dot) 1px, transparent 1px);
  background-size: 23px 23px;
}
.lp > * { position: relative; z-index: 1; }

.lp-wrap {
  max-width: var(--lp-maxw);
  margin-inline: auto;
  padding-inline: var(--lp-gutter);
  min-width: 0;
  /* układ odniesienia dla linii marginesu i dla bleedu ciemnego pasa; obie
     rzeczy są pseudoelementami, więc nic tu nie zmienia się w layoucie */
  position: relative;
}

/* --lp-pad-top zamiast wprost --lp-sect: ciemny pas ma własną wyściółkę,
   a linia marginesu musi startować dokładnie na kresce nagłówka — jedna
   zmienna trzyma obie liczby zgodne, bez drugiego miejsca do pamiętania. */
.lp section { padding-top: var(--lp-pad-top, var(--lp-sect)); }

/* ── Nagłówek sekcji = tytuł + etykieta na marginesie ───────────────────────
   Bazowo (telefon, tablet) JEDNA kolumna i etykieta NAD tytułem: 190 px
   marginesu to przy 390 px połowa szerokości treści, a mikroskopijna etykieta
   dosunięta do prawej pod dużym tytułem czyta się jak zabłąkana.
   Margines włącza się dopiero w @media (min-width: 1000px) na końcu pliku. */
.lp-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: baseline;
  column-gap: var(--lp-rail-gap);
  row-gap: 2px;
  border-top: 1px solid var(--border);
  padding-top: 18px;
  margin-bottom: var(--kp-sp-5);
}
.lp-head h2 {
  margin: 0;
  font-family: var(--kp-font-mono);
  /* dolny próg 22, nie 20: na 390 px tytuł sekcji był o 2,5 px mniejszy od
     nagłówka karty w tej samej sekcji, czyli hierarchia szła w drugą stronę */
  font-size: clamp(22px, 3.1vw, 30px);
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.15;
  max-width: 28ch;
}
/* Etykieta sekcji: 10,5 px mono, wersaliki, tracking .14em — dokładnie jak
   `.sec>.m` w design/ds/landing/rhythm.html. To jest ta sama etykieta, która
   dziś pływa bez zaczepienia; od tego commita wisi na linii marginesu. */
.lp-head__meta {
  order: -1;                       /* nad tytułem, dopóki nie ma marginesu */
  font-family: var(--kp-font-mono);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  line-height: 1.6;
  color: var(--muted);             /* --kp-n-700 → 7,19:1 na Papierze ✓ AA */
}

/* Linia marginesu. Wisi z POZIOMEJ kreski nagłówka sekcji (border-top na
   .lp-head) i biegnie do końca sekcji — złącze w kształcie T, jak pion
   spuszczony z linijki. `top` = wyściółka sekcji, bo pseudoelement statycznie
   ustawionego .lp-head pozycjonuje się względem PADDING-BOKSU .lp-wrap,
   a .lp-head jest jej pierwszym dzieckiem, więc kreska jest dokładnie tam.
   Widoczna tylko od 1000 px (blok na końcu pliku) — tu jest wyłączona, żeby
   nie trzeba było jej gasić w każdym wariancie mobilnym osobno. */
.lp-head::after {
  content: "";
  position: absolute;
  top: var(--lp-pad-top, var(--lp-sect));
  bottom: 0;
  right: calc(var(--lp-gutter) + var(--lp-rail));
  width: 1px;
  background: var(--border);
  pointer-events: none;
  display: none;
}

/* Typografia treści: nagłówki i etykiety mono (interfejs), akapity proporcjonalne.
   Rozdzielenie jest w brand.css celowe — mono na dłuższym tekście męczy oczy. */
.lp p, .lp li, .lp dd {
  font-family: var(--kp-font-doc);
  letter-spacing: 0;
}
.lp p {
  margin: 0 0 var(--kp-sp-3);
  font-size: 15px;
  line-height: 1.68;
  color: var(--muted);
  max-width: 62ch;
}
.lp p:last-child { margin-bottom: 0; }
.lp p b, .lp li b { color: var(--ink); font-weight: 600; }

/* .kp-meta użyte na AKAPICIE: bez tej reguły `.lp p` (klasa+typ) bije `.kp-meta`
   (sama klasa) i adnotacja czytała się jak zwykły tekst, tym samym stopniem.
   Adnotacja ma być mono i mniejsza — inaczej zastrzeżenie udaje treść. */
.lp p.kp-meta {
  font-family: var(--kp-font-mono);
  font-size: var(--kp-fs-sm);
  line-height: 1.6;
  color: var(--muted);
}

/* `p.` w selektorze jest KONIECZNE i to nie jest ostrożność na zapas:
   do 2026-07-26 stało tu `.lp-lede` (0,1,0), a `.lp p` wyżej ma (0,1,1) — klasa
   + typ — więc BIŁO wszystkie trzy deklaracje. Zmierzone w przeglądarce przed
   poprawką: lede miał 15px/25,2px/62ch, czyli wartości z `.lp p`, a nie
   18px/1,62/52ch stąd. Cała ta reguła była martwa. Podbicie specyficzności
   przez `p.` jest tanie i nie zaczyna wojny na !important. */
p.lp-lede {
  font-size: clamp(15.5px, 1.5vw, 18px);
  line-height: 1.62;
  max-width: 52ch;
}

/* Skok do treści — dla klawiatury i czytnika. */
.lp-skip {
  position: absolute; left: -9999px; top: 0; z-index: 100;
  padding: 10px 14px;
  font-family: var(--kp-font-mono); font-size: var(--kp-fs-sm); font-weight: 600;
  color: var(--fill-ink); background: var(--fill);
  border-radius: 0 0 var(--kp-radius-sm) 0;
}
.lp-skip:focus { left: 0; }

/* CEL SKIPU — ognisko bez pierścienia, i to jest decyzja, nie przeoczenie.
   Od 2026-07-28 `#plakat` ma `tabindex="-1"`, żeby „Przejdź do treści" NAPRAWDĘ
   przenosiło ognisko (przedtem zmierzone: `document.activeElement` zostawał `BODY`,
   więc czytnik ekranu nie ruszał się z góry dokumentu). Skutkiem ubocznym Chrome
   zapala na sekcji `:focus-visible` i rysuje SWÓJ domyślny niebieski prostokąt wokół
   CAŁEGO pierwszego ekranu (sprawdzone na zrzucie).
   Gaszę go, bo obie alternatywy są gorsze:
     • domyślny niebieski to nie jest kolor tej strony;
     • własny pierścień w kobalcie postawiłby drugą kobaltową plamę na plakacie,
       na którym kobalt ma znaczyć JEDNĄ rzecz — zachętę (patrz sekcja „plakat").
   WCAG 2.4.7 nie jest tu naruszone: wymaga wskaźnika dla komponentów OBSŁUGIWANYCH
   z klawiatury, a sekcja z ujemnym `tabindex` jest z kolejności tabulacji wyjęta —
   nie da się na nią wejść inaczej niż tym skokiem, a sam skok potwierdza się
   przewinięciem strony na górę. Fokusowalne dzieci plakatu (zachęta, cichy link)
   mają swoje pierścienie i tej reguły nie dotyka.
   Selektor celuje wyłącznie w tę sekcję — NIE rób z tego reguły ogólnej na
   `[tabindex="-1"]:focus`. */
.lp-poster:focus { outline: none; }

/* Fokus dla linków, których kit nie obsługuje z nazwy. */
.lp a:focus-visible {
  outline: var(--kp-ring-w) solid var(--focus);
  outline-offset: var(--kp-ring-off);
  border-radius: 3px;
}

/* ────────────────────────────────────────────────────────────────────────────
   2. Pasek górny (.kp-nav z kitu + poprawki dla lockupu)
   ──────────────────────────────────────────────────────────────────────────── */

.lp-nav { padding-inline: var(--lp-gutter); gap: var(--kp-sp-5); }
/* kit skaluje obraz w marce do 22×22 (kwadratowa ikona) — tu jedzie wordmark 282×62.
   22 px wysokości = 100 px szerokości, czyli minimum z brand/README (96 px). */
.lp-nav .kp-nav__brand img { width: auto; height: 22px; }
/* Cel dotykowy marki. Zmierzone przed poprawką: link „keepino → góra strony" miał
   100×22 px, czyli 22 px WYSOKOŚCI — poniżej 24×24 z WCAG 2.5.8 i o połowę mniej niż
   44 px, które ma obok ikonka logowania. Znak jest jedynym powrotem na górę na
   telefonie (linki sekcji są tam ukryte), więc trafia się w niego kciukiem najczęściej.
   ZERO ZMIANY WIZUALNEJ: `.kp-nav__brand` jest inline-flex z `align-items: center`,
   a pasek ma 52 px (56 na telefonie) — obrazek zostaje na 22 px i w tym samym miejscu,
   rośnie tylko pole klikalne. Sprawdzone na zrzutach przed/po: identyczne. */
.lp-nav .kp-nav__brand { min-height: 44px; }
.lp-nav .kp-nav__items { gap: 2px; }
@media (max-width: 860px) {
  .lp-nav .kp-nav__items { display: none; }   /* linki zostają w treści strony */
}

/* ────────────────────────────────────────────────────────────────────────────
   3. Hero — teza po lewej, dziennik nocy po prawej
   ──────────────────────────────────────────────────────────────────────────── */

.lp-hero {
  display: grid;
  grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr);
  gap: clamp(30px, 4.4vw, 60px);
  align-items: center;
  /* tylko padding-block — skrót `padding` zjadał padding-inline z .lp-wrap
     i hero jechał wtedy na styk z krawędzią ekranu (widziane na 390 i 820 px) */
  padding-block: clamp(26px, 5vw, 60px) clamp(10px, 2vw, 20px);
}
@media (max-width: 920px) {
  .lp-hero { grid-template-columns: 1fr; align-items: start; gap: 34px; }
}

.lp-eyebrow {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin: 0 0 var(--kp-sp-5);
  font-family: var(--kp-font-mono);
  font-size: 11.5px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--muted);
}
.lp-eyebrow::before {
  content: ""; flex: none; width: 22px; height: 1px; background: var(--border-strong);
}
/* Poniżej ~380 px etykieta nie mieści się obok kreski i kreska zostawała sama
   na pierwszej linii — czytało się jak błąd składu. Na 390 px jeszcze wchodzi,
   więc próg jest tuż pod tą szerokością, a nie „na zapas". */
@media (max-width: 379px) { .lp-eyebrow::before { display: none; } }

.lp-h1 {
  margin: 0 0 var(--kp-sp-4);
  font-family: var(--kp-font-mono);
  font-size: clamp(31px, 5.6vw, 58px);
  font-weight: 600;
  letter-spacing: var(--kp-tracking-display);
  line-height: 1.04;
  text-wrap: balance;
  max-width: 19ch;
}
/* Kursor marki = podkreślnik na linii bazowej (nigdy pionowa belka). */
.lp-cur {
  display: inline-block;
  width: .52em; height: .28em;
  margin-left: .1em;
  border-radius: 1px;
  background: var(--accent);
  vertical-align: baseline;
}
/* Kursor w H1 mruga BEZ KOŃCA — to jest teza tej strony („gotowa złapać myśl"), a nie ozdoba,
   i po trzech cyklach zamieniał się w statyczną kreskę, czyli w nic. WCAG 2.2.2 tego nie zakazuje:
   wymaga mechanizmu zatrzymania, a na stronie bez interfejsu tym mechanizmem jest systemowe
   „ogranicz ruch" (obsłużone niżej). 1/1.1 s ≈ 0.9 Hz, więc daleko pod progiem 3 błysków/s
   z WCAG 2.3.1 — to nie jest ryzyko fotoczułości, to wolne pulsowanie. */
.lp-h1 .lp-cur { animation: lp-blink 1.1s step-end infinite; }

/* ── plakat ze znakiem: pierwszy ekran ──────────────────────────────────────
   Wysokość liczona w svh, nie vh: na telefonie vh odnosi się do okna RAZEM ze
   zwijanym paskiem adresu, więc kotwica „↓" wypadała pod zgięcie i plakat
   wyglądał na ucięty. vh zostaje wierszem wyżej jako zapas dla przeglądarek
   bez svh — jeśli je rozumieją, druga deklaracja nadpisuje pierwszą.
   PEŁNE svh, bez odejmowania 52 px i BEZ SUFITU — i to jest teraz zadanie tej
   reguły, nie kosmetyka. Pasek nawigacji stoi w DOM-ie ZA plakatem i jest sticky,
   więc jedyne, co trzyma go poza pierwszym ekranem, to wysokość plakatu.
   Zmierzone, gdy było `min(660px, calc(100svh - 52px))`: treść plakatu ma 745 px,
   więc sufit 660 w ogóle nie wiązał, plakat miał 745 px, a przy oknie 900 px pasek
   lądował na y=745 — czyli WIDOCZNY na pierwszym ekranie, razem z drugim
   wordmarkiem. To jest dokładnie ten błąd, dla którego pasek został przeniesiony
   pod plakat, i ten sam, za który wyleciał kafel z logo z pustego stanu apki.
   Odejmowanie 52 px też straciło sens: pasek nie stoi już nad plakatem, więc nie
   ma czego oddawać.
   Sufit nie jest potrzebny dla widoczności zachęty — zmierzone przy 1440×720
   (najniższy realny laptop): dolna krawędź przycisku na y=669, czyli nad zgięciem.
   Wcześniejszy argument („na wysokim ekranie svh oddaje zapas na pustkę") napisano,
   gdy plakat miał sam wordmark; teraz ma znak, zdanie i przycisk, więc wypełnia
   sobą ekran zamiast go rozciągać.
   svh, nie vh: na telefonie vh odnosi się do okna RAZEM ze zwijanym paskiem adresu,
   więc zachęta wypadała pod zgięcie. vh zostaje wierszem wyżej jako zapas dla
   przeglądarek bez svh — jeśli je rozumieją, druga deklaracja nadpisuje pierwszą. */
.lp-poster {
  max-width: var(--lp-maxw);
  margin-inline: auto;
  padding-inline: var(--lp-gutter);
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  align-content: center;
  /* DO ŚRODKA — ale tylko na telefonie. Na wąskiej kolumnie oś pionowa jest jedyną,
     jaką da się zbudować, a wyrównanie do lewej zostawia po prawej poszarpaną
     krawędź. Na desktopie plakat wraca do lewej i rośnie — patrz blok od 861 px
     niżej (decyzja właściciela, 2026-07-27). */
  justify-items: center;
  text-align: center;
  gap: var(--kp-sp-5);
}

/* ── DESKTOP: plakat wraca DO LEWEJ i rośnie ────────────────────────────────────
   Właściciel wolał układ sprzed wyśrodkowania: „na PC fajnie było, jak było takie
   większe i po lewej". Wyśrodkowanie zostaje na telefonie.
   Lewa krawędź plakatu = lewa krawędź każdej sekcji pod nim, więc pierwszy ekran
   i reszta strony stoją na tej samej pionowej linii — to działa na korzyść reguły
   marginesu, która jest sygnaturą tej strony.
   Rozmiary rosną o ~⅓ względem telefonu, ale PROPORCJA ZOSTAJE: znak jest wyższy
   od wordmarku. To ta relacja, nie sam rozmiar, decyduje, czy czyta się to jako
   para znak + nazwa, czy jako napis z doklejoną ikoną.
   Próg 861 px, nie 1000: to ta sama granica, na której `.lp-split` przechodzi
   w dwie kolumny, więc plakat i sekcje zmieniają układ w tym samym momencie. */
/* Blok wykonawczy tej reguły stoi ZA wszystkimi regułami `.lp-poster__*`, a nie tu —
   zapytanie medialne NIE podnosi specyficzności, więc postawiony w tym miejscu
   przegrywałby remis 0,1,0 z regułami bazowymi po prostu dlatego, że jest wcześniej.
   Sprawdzone: wyrównanie się zmieniało (bo `.lp-poster` nie ma konkurenta), a rozmiary
   nie. Szukaj „DESKTOP: plakat rośnie" niżej w tej sekcji. */

/* ── HIERARCHIA PLAKATU: znak nad nazwą, nie odwrotnie ─────────────────────────
   Było odwrotnie i to nie była decyzja, tylko skutek uboczny: `.lp-poster__mark`
   ma `font-size: clamp(52px, 18vw, 168px)`, a `img` w środku `height: 1em` — czyli
   na monitorze wordmark renderował się jako obraz 168 px wysokości i ~683 px
   szerokości (proporcja pliku 252×62), podczas gdy znak stał obok w 64 px z atrybutu
   HTML, bez żadnej reguły. Wordmark przygniatał znak trzykrotnie.
   Karta design/ds/landing/hero.html: znak 96 px, wordmark 64 px. Wordmark jest
   szeroki i niski, znak jest wysoki i wąski — dopiero w tych proporcjach czytają się
   jako para, a nie jako napis z doklejoną ikoną. */
.lp-poster__k {
  width: clamp(72px, 9vw, 96px);
  height: auto;
}

/* `h1.` (0,1,1), nie sama klasa: na tym elemencie siedzi też `.lp-h1` (0,1,0),
   który markup zostawił jako stopień awaryjny. Przy remisie rozstrzygałaby
   KOLEJNOŚĆ w pliku, a to jest dokładnie ten rodzaj zależności, który psuje się
   po cichu przy pierwszym porządkowaniu arkusza. Ta sama lekcja co `.lp p`. */
h1.lp-poster__title {
  font-size: clamp(21px, 2.4vw, 31px);
  font-weight: 400;
  line-height: 1.34;
  letter-spacing: -.03em;
  max-width: 30ch;
  color: var(--ink-2, var(--muted));
  margin: 0;
}
/* Pogrubiona jest DRUGA połowa zdania, bo to ona jest obietnicą — pierwsza to samo
   pytanie. 600, nie 900: przy 31 px waga 900 w monospace robi z tego nagłówek
   plakatu reklamowego, a to ma być zdanie wypowiedziane spokojnie. */
h1.lp-poster__title b { font-weight: 600; color: var(--ink); }

.lp-poster__cue { margin-top: var(--kp-sp-3); }
/* `__next` zostało w atrybucie jako stopień (mono, 44 px celu, gotowy pierścień),
   ale ten link nie prowadzi już „dalej" — prowadzi w bok, do logowania. Nazwa
   `__quiet` jest prawdziwa i to ona ma ostatnie słowo. */
a.lp-poster__quiet { margin-top: var(--kp-sp-4); color: var(--muted); }
a.lp-poster__quiet:hover { color: var(--accent); }


/* font-size steruje całym plakatem: wysokość znaku to dokładnie 1em, więc kursor
   podany w em skaluje się razem z nim. Dzięki temu jest JEDEN clamp, a nie dwa
   niezależne, które przy pośrednich szerokościach rozjeżdżały się względem siebie. */
.lp-poster__mark {
  /* 42→64 px, nie 52→168. Tamten clamp powstał, gdy wordmark był na plakacie SAM
     i miał wypełnić ekran. Odkąd stoi pod znakiem, 168 px robiło z niego obraz
     683×168 (proporcja pliku 252×62) górujący nad znakiem 96 px — czyli napis
     z doklejoną ikoną zamiast pary znak + nazwa.
     Wartości z karty design/ds/landing/hero.html: 64 px na desktopie, 42 na telefonie.
     6vw trafia w 42 dokładnie przy 390 px, więc dolny próg nie jest zgadywany. */
  font-size: clamp(42px, 6vw, 64px);
  display: flex;
  align-items: flex-end;
  margin: 0;
}
.lp-poster__mark img { height: 1em; width: auto; display: block; }

/* Proporcje z brand/wordmark.svg (rect 30×16 przy viewBoksie 252×62) — kursor
   siada w tym samym miejscu, w którym rysuje go plik marki, tylko mruga. */
.lp-poster__cur {
  width: .484em; height: .258em;
  margin-bottom: .226em;
  border-radius: 1px;
  background: var(--accent);
  animation: lp-blink 1.1s step-end infinite;
}

.lp-poster__next {
  display: inline-flex; align-items: center; gap: var(--kp-sp-2);
  min-height: 44px;
  font-family: var(--kp-font-mono);
  font-size: var(--kp-fs-sm);
  color: var(--muted);
  text-decoration: none;
}
.lp-poster__next:hover { color: var(--ink); }
.lp-poster__arr { animation: lp-nudge 2.4s ease-in-out infinite; }

/* ── DESKTOP: plakat rośnie i wraca DO LEWEJ ────────────────────────────────────
   Właściciel wolał układ sprzed wyśrodkowania: „na PC fajnie było, jak było takie
   większe i po lewej". Do środka zostaje na telefonie, gdzie wąska kolumna nie daje
   innej osi niż pionowa, a wyrównanie do lewej zostawia poszarpaną prawą krawędź.

   Lewa krawędź plakatu siada na lewej krawędzi każdej sekcji pod nim, więc pierwszy
   ekran i reszta strony stoją na tej samej pionowej linii — to gra na korzyść reguły
   marginesu, która jest sygnaturą tej strony.

   Rozmiary rosną o ~⅓, ale PROPORCJA ZOSTAJE: znak wyższy od wordmarku. To ta
   relacja, nie sam rozmiar, decyduje, czy czyta się to jako para znak + nazwa,
   czy jako napis z doklejoną ikoną — i to była pierwotna usterka tego plakatu.

   Próg 861 px, nie 1000: ta sama granica, na której `.lp-split` przechodzi w dwie
   kolumny, więc plakat i sekcje zmieniają układ w tym samym momencie.

   Ten blok MUSI stać za regułami bazowymi `.lp-poster__*`. Zapytanie medialne nie
   podnosi specyficzności, więc przy remisie 0,1,0 rozstrzyga kolejność w pliku —
   postawiony wyżej zmieniał wyrównanie, ale nie rozmiary. Nie przenoś go w górę
   „przy porządkach". */
@media (min-width: 861px) {
  .lp-poster {
    justify-items: start;
    text-align: left;
    gap: var(--kp-sp-6);
  }
  .lp-poster__k { width: 128px; }
  .lp-poster__mark { font-size: 96px; }
  /* 30ch, nie 26: przy wyrównaniu DO LEWEJ ciasna miara zachowuje się inaczej niż
     przy wyśrodkowanym. Wyśrodkowane 26ch daje zwarty blok w osi strony; to samo
     26ch dosunięte do lewej łamie zdanie na trzy krótkie linie i zostawia obok nie
     margines, tylko 600 px pustki — czyta się jak tekst, któremu zabrakło miejsca.
     30ch przy 42 px to dwie pełne linie: zdanie ma rytm, a plakat nadal oddycha. */
  h1.lp-poster__title { font-size: 42px; max-width: 30ch; }
  .lp-poster__cue { margin-top: var(--kp-sp-4); }
}

/* ── ikonka logowania w pasku ───────────────────────────────────────────────
   Kolor tuszu, nie kobalt: kobalt należy do głównej akcji („Otwórz keepino.app"
   w hero), a dwie równie mocne plamy w jednym rzędzie znoszą hierarchię.
   44×44 to cel dotykowy z WCAG 2.5.8 — sama ikonka ma 22px, resztę robi pole.  */
.lp-login {
  display: inline-grid; place-items: center;
  inline-size: 44px; block-size: 44px;
  border-radius: var(--kp-radius);
  color: var(--ink);
}
.lp-login:hover { background: var(--inset); }
.lp-login__i {
  width: 22px; height: 22px;
  fill: none; stroke: currentColor; stroke-width: 2;
  stroke-linecap: butt; stroke-linejoin: round;
}

/* Ten sam pierścień, co w kit.css. Powtórzony tutaj, a nie dopisany tam, bo
   kit.css w tym katalogu jest KOPIĄ pliku z /css dla całej apki — landing nie
   wstrzykuje swoich klas w plik współdzielony. */
.lp-poster__next:focus-visible,
.lp-login:focus-visible {
  outline: var(--kp-ring-w) solid var(--focus);
  outline-offset: var(--kp-ring-off);
  box-shadow: none;
}

/* Zwykły link zamiast widgetu: landing nadal działa bez JavaScriptu.
   Pełne 44 px utrzymuje wygodny cel dotykowy także w pasku mobilnym. */
.lp-lang {
  min-width: 44px;
  min-height: 44px;
  display: inline-grid;
  place-items: center;
  color: var(--muted);
  font-family: var(--kp-font-mono);
  font-size: var(--kp-fs-xs);
  font-weight: 650;
  letter-spacing: .08em;
  text-decoration: none;
  border-radius: 6px;
}
/* PARA JĘZYKÓW: bieżący i drugi stoją obok siebie. Odstęp zerowy, bo dwa pudełka
   44 px same się rozdzielają — kreska albo kropka między nimi byłaby trzecim
   elementem do przeczytania w rogu, w którym ma być cicho. */
.lp-langs { display: inline-flex; align-items: center; }
/* Bieżący język: tusz zamiast szarości i zero reakcji na kursor — to nie jest
   przycisk, tylko etykieta „tu jesteś". `cursor: default` domyka to dla myszy,
   bo <span> i tak nie dostaje wskaźnika odnośnika. */
.lp-lang--on { color: var(--ink); cursor: default; }
.lp-lang:hover { color: var(--ink); background: var(--inset); }
.lp-lang--on:hover { background: none; }
.lp-lang:focus-visible {
  outline: var(--kp-ring-w) solid var(--focus);
  outline-offset: var(--kp-ring-off);
}

@keyframes lp-nudge { 50% { transform: translateY(3px); } }

.lp-actions {
  display: flex; align-items: center; gap: var(--kp-sp-3); flex-wrap: wrap;
  margin-top: var(--kp-sp-5);
}
.lp-note {
  display: flex; align-items: center; gap: var(--kp-sp-3); flex-wrap: wrap;
  margin-top: var(--kp-sp-4);
}
.lp-note .kp-meta { font-family: var(--kp-font-mono); font-size: var(--kp-fs-sm); }

/* ── dziennik nocy ──────────────────────────────────────────────────────────
   Jedna zorkiestrowana animacja na całej stronie: wiersze wchodzą po kolei,
   jakby log dopisywał się sam, i kończą kursorem. Bez ruchu (reduced-motion)
   log jest po prostu w całości widoczny — nic nie ginie.                     */

.lp-log {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--kp-radius-lg);
  box-shadow: var(--shadow);
  overflow: hidden;
  min-width: 0;
}
.lp-log__head {
  display: flex; align-items: center; gap: var(--kp-sp-2); flex-wrap: wrap;
  padding: 11px var(--kp-sp-4);
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--canvas) 55%, var(--inset));
}
.lp-log__dot {
  width: 8px; height: 8px; border-radius: 50%; flex: none;
  background: var(--accent);
}
.lp-log__body {
  display: grid;
  padding: var(--kp-sp-3) var(--kp-sp-4) var(--kp-sp-4);
  font-family: var(--kp-font-mono);
  font-size: var(--kp-fs-sm);
  line-height: 1.5;
}
.lp-log__row {
  display: grid;
  grid-template-columns: 4.4em 5.2em minmax(0, 1fr);
  gap: 4px var(--kp-sp-3);
  padding: 7px 0;
  border-top: 1px solid var(--border-soft);
  animation: lp-row-in .42s var(--kp-ease) both;
  animation-delay: calc(var(--i, 0) * 460ms);
}
/* Numer wiersza z CSS, nie z atrybutu style — dzięki temu w całym dokumencie nie
   ma ANI JEDNEGO stylu inline i statyk może jechać ze ścisłym CSP
   (`style-src 'self'`, patrz _headers). Wcześniej było style="--i:N". */
.lp-log__row:nth-child(2) { --i: 1; }
.lp-log__row:nth-child(3) { --i: 2; }
.lp-log__row:nth-child(4) { --i: 3; }
.lp-log__row:nth-child(5) { --i: 4; }
.lp-log__row:nth-child(6) { --i: 5; }
.lp-log__row:first-child { border-top: 0; }
.lp-log__t   { color: var(--muted); font-variant-numeric: tabular-nums; }
.lp-log__tag {
  font-size: var(--kp-fs-xs); font-weight: 600;
  letter-spacing: var(--kp-tracking-label); text-transform: uppercase;
  color: var(--muted);
  align-self: baseline;
}
.lp-log__m { color: var(--ink); overflow-wrap: anywhere; min-width: 0; }
.lp-log__m .lp-path { color: var(--muted); }
.lp-log__m .lp-warn { color: var(--warn-ink); font-weight: 600; }
.lp-log__row:last-child .lp-log__m { color: var(--ink); }
/* Kursor w ostatnim wierszu dziennika też bez końca, i tu argument jest najmocniejszy: to
   imitacja karetki w terminalu, a karetka, która przestaje mrugać, wygląda na zawieszony proces —
   czyli mówi coś nieprawdziwego o produkcie. Opóźnienie 2.76 s czeka, aż wiersze skończą wjeżdżać. */
.lp-log__row:last-child .lp-cur { animation: lp-blink 1.1s step-end infinite; animation-delay: 2.76s; }

@keyframes lp-row-in { from { opacity: 0; transform: translateY(5px); } }
@keyframes lp-blink  { 50% { opacity: 0; } }

@media (max-width: 620px) {
  /* DZIENNIK NA TELEFONIE — zamiana kompromisu, nie kosmetyka.
     Było: wiersz łamał się na dwie linie (czas + znacznik, treść pod nimi).
     Sześć wierszy × 2 linie = 493 px zmierzone przy 390 px, a godzina i akcja
     traciły związek z treścią, którą opisują — czyta się jak dwa wykazy.
     Jest: wiersz zostaje JEDNĄ linią, a przewijanie w poziomie dzieje się we
     WŁASNYM kontenerze (.lp-log__body jest scrollerem, nie body), więc żadna
     godzina się nie łamie, a strona nie jedzie w bok. Dokładnie ten wariant
     projektuje design/ds/landing/hero.html (`.m .lscroll`).
     Zmierzone po zmianie: ~270 px, czyli −220 px budżetu przewijania. */
  .lp-log__body {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
  }
  .lp-log__row {
    grid-template-columns: 4.4em 5.6em minmax(0, 1fr);
    /* `max-content`, nie stała liczba pikseli: .lp-log__body jest gridem
       jednokolumnowym, więc kolumna bierze max-content NAJSZERSZEGO wiersza
       i WSZYSTKIE wiersze dostają tę samą szerokość — kreski między nimi kończą
       się równo. Przy stałych 400 px tekst wychodził poza wiersz (zmierzone:
       treść 578 px, pudełko wiersza 400 px), więc po przewinięciu kreski
       urywały się w połowie zdania. */
    min-width: max-content;
    white-space: nowrap;
  }
  /* overflow-wrap: normal zdejmuje `anywhere` z reguły bazowej — przy nowraps
     `anywhere` i tak nie działa, ale zostawione mówiłoby nieprawdę o wierszu */
  .lp-log__m { overflow-wrap: normal; }
  /* Pierścień ostrości scrollera: kontener jest fokusowalny z klawiatury
     (scrollowanie strzałkami), więc musi być widać, że jest zaznaczony. */
  .lp-log__body:focus-visible {
    outline: var(--kp-ring-w) solid var(--focus);
    outline-offset: calc(-1 * var(--kp-ring-w));
  }
}
@media (max-width: 430px) {
  /* przy 360 px tytuł dziennika zrzucał znacznik „przykład" do drugiej linii;
     ciaśniejszy tracking mieści całość w jednym wierszu */
  .lp-log__head { padding-inline: var(--kp-sp-3); }
  .lp-log__head .kp-eyebrow { letter-spacing: .04em; font-size: 10.5px; }
  .lp-log__body { padding-inline: var(--kp-sp-3); }
}

/* ────────────────────────────────────────────────────────────────────────────
   4. Siatki i karty
   ──────────────────────────────────────────────────────────────────────────── */

.lp-grid   { display: grid; gap: var(--kp-sp-3); grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }
/* Odstęp poziomy większy od pionowego: po zdjęciu ramek (niżej) to jedyna rzecz,
   która mówi „to dwie osobne kolumny, nie jeden akapit w dwóch łamach". */
.lp-grid--2 {
  grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: var(--kp-sp-5) clamp(24px, 3.4vw, 44px);
}
.lp-split {
  display: grid; gap: clamp(22px, 3.4vw, 46px);
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 860px) { .lp-split { grid-template-columns: 1fr; } }

/* Odwrócenie kolumn BEZ zmiany kolejności w źródle: sekcje „Graf, nie lista"
   i „Jak to wygląda w ręce" mają w markupie <figure> jako pierwsze, więc obie
   wychodziły jako „artefakt | proza" jedna pod drugą — czyli dokładnie to
   powtórzenie kształtu, które karta rytmu nazywa problemem. --flip stawia
   artefakt po prawej i tempo B przestaje się dublować.
   `order` na elementach gridu, nie `direction`: kierunek pisma zmieniałby też
   wyrównanie tekstu w środku kolumn. */
.lp-split--flip > .lp-figure { order: 1; }
/* USUNIĘTA 2026-07-28 reguła awaryjna `.lp-split:has(> .lp-figure--center) > .lp-figure
   { order: 1 }`. Rozpoznawała sekcję „w ręce" po wyśrodkowanej figurze, dopóki markup
   nie miał klasy `--flip` — a ma ją od dawna (`index.html`, sekcja #praktyka), więc
   reguła nie robiła już nic poza jednym: łapała KAŻDĄ przyszłą wyśrodkowaną figurę.
   Zmierzone na drugiej takiej figurze (makieta rolki w #rolki): przestawiała ją na
   prawo, czyli w kształt „proza | artefakt" — dokładnie ten, który następna sekcja
   („Format zostaje Twój") już ma, a którego to `--flip` miało nie dublować.
   Wniosek na przyszłość: warunek „po zawartości" ma termin ważności do wklejenia
   klasy. Po wklejeniu jest już tylko pułapką na następny element tego samego typu. */

.lp-card__title {
  margin: 0 0 var(--kp-sp-3);
  font-family: var(--kp-font-mono);
  font-size: var(--kp-fs-lg); font-weight: 600;
  letter-spacing: var(--kp-tracking-tight);
}

/* ── RAMKĘ MA TO, CO MOŻNA WZIĄĆ DO RĘKI — NIE TO, CO MOŻNA PRZECZYTAĆ ──────
   .kp-card w siatce sekcji trzyma PROZĘ („To jest" / „To nie jest"), więc traci
   powierzchnię i obrys. Ramka zostaje przy trzech rzeczach, które są
   przedmiotami z tego świata: dziennik nocy (.lp-log), źródło markdown
   (.kp-codeblock) i panel zaproszenia (.lp-cta). Uzasadnienie i diagnoza
   „osiem sekcji o identycznym kształcie": design/ds/landing/rhythm.html.
   (0,2,0) bije (0,1,0) z kit.css — bez !important i bez ID. */
.lp-grid .kp-card {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  /* Głowa wykazu w TUSZU (14,83:1 na Papierze), nie w kolorze linii: to nie
     separator wiersza, to kreska, pod którą zaczyna się wykaz. */
  border-top: 1px solid var(--ink);
  padding-top: var(--kp-sp-3);
}
.lp-grid .lp-card__title {
  margin-bottom: 0;
  font-size: var(--kp-fs-md);
  letter-spacing: var(--kp-tracking-label);
  text-transform: uppercase;
}
/* Wykaz na włosowych liniach: wiersze na border-bottom, zero kart.
   9 px, nie 12: wiersz dostaje wyściółkę Z DWÓCH STRON, więc każdy piksel liczy
   się tu podwójnie i sześć punktów zapłaciłoby 36 px za odstęp, który wcześniej
   dawał `gap` — a budżet przewijania na telefonie jest głównym celem tej zmiany. */
.lp-grid .lp-list { gap: 0; }
.lp-grid .lp-list li { padding-block: 9px; border-bottom: 1px solid var(--border); }
.lp-grid .lp-list li:first-child { padding-top: 6px; }
.lp-grid .lp-list li:last-child { border-bottom: 0; }
/* Marker jedzie w dół o tę samą wyściółkę, którą dostał wiersz — `top` liczy się
   od górnej krawędzi <li>, więc bez tego kropka wisiałaby 9 px NAD swoją
   pierwszą linią tekstu (ten sam błąd co „mikroskopijny plakat", tylko cichszy). */
.lp-grid .lp-list--is  li::before { top: calc(9px + .52em); }
.lp-grid .lp-list--not li::before { top: calc(9px + .82em); }
.lp-grid .lp-list--is  li:first-child::before { top: calc(6px + .52em); }
.lp-grid .lp-list--not li:first-child::before { top: calc(6px + .82em); }

/* Lista z markerem: koło = węzeł (to jest), kreska = brak (tego nie ma).
   Kobalt zostaje sygnałem, więc markery są tuszem i grafitem, nie kobaltem. */
.lp-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--kp-sp-3); }
/* marker pozycjonowany bezwzględnie, a nie kolumną gridu — inaczej każdy węzeł
   tekstowy w <li> stałby się osobnym elementem siatki i zdanie rozsypałoby się
   na słowa (sprawdzone na zrzucie) */
.lp-list li {
  position: relative;
  padding-left: 21px;
  font-size: 14.5px; line-height: 1.6; color: var(--muted);
}
.lp-list li::before { content: ""; position: absolute; left: 0; }
.lp-list--is  li::before { top: .52em; width: 8px; height: 8px; border-radius: 50%; background: var(--ink); }
.lp-list--not li::before { top: .82em; width: 10px; height: 2px; background: var(--kp-n-500); }

/* ── kroki workera: wykaz na włosowych liniach, numer jako etykieta ─────────
   Numerowanie 01–04 zostaje, bo to naprawdę sekwencja — ale kółka i łącząca
   szyna znikają (design/ds/landing/rhythm.html i .../mobile.html):
   1. kółko było TRZECIM okręgiem na stronie po węźle marki i węźle grafu,
      a żaden z nich nie znaczy tego samego, co pozostałe;
   2. na jednej kolumnie (telefon) szyna „łączyła" rzeczy, które i tak leżą
      pod sobą, czyli rysowała informację, której nie ma.
   Zostaje kreska nad krokiem i numer w kobalcie — kobalt jest tu na miejscu,
   bo to jedna droga wrzutki przez system, czyli to samo, co znaczy kobaltowy
   węzeł w grafie: „to robi worker".
   Kontrast numeru: --accent-text = --kp-c-500 #2743E8 na Papierze 5,75:1 ✓ AA;
   na tuszu ciemnego pasa token podmienia się na --kp-c-300 #8894FF → 6,94:1 ✓. */
.lp-steps {
  display: grid; gap: 0 clamp(20px, 2.6vw, 34px);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
.lp-step {
  min-width: 0;
  border-top: 1px solid var(--border);
  padding-top: var(--kp-sp-3);
  padding-bottom: var(--kp-sp-3);
}
.lp-step__n {
  display: block;
  font-family: var(--kp-font-mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: .1em;
  font-variant-numeric: tabular-nums;
  color: var(--accent-text);
}
.lp-step h3 {
  margin: 5px 0 6px;
  font-family: var(--kp-font-mono); font-size: 14.5px; font-weight: 600;
  letter-spacing: -.015em;
}
.lp-step p { font-size: 13.5px; max-width: 42ch; }
@media (max-width: 900px) {
  .lp-steps { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  /* Jedna kolumna: numer schodzi do RYNIENKI obok treści, a nie nad nią —
     cztery wiersze wykazu zamiast czterech bloków. Zmierzone przy 390 px:
     466 px → ~360 px. */
  .lp-steps { grid-template-columns: 1fr; }
  .lp-step {
    display: grid; grid-template-columns: 30px minmax(0, 1fr);
    gap: 0 var(--kp-sp-2);
    /* Tylko GÓRA, bo separuje już kreska nad krokiem, a `.lp p:last-child`
       zeruje dolny margines akapitu — wyściółka z dołu byłaby drugim odstępem
       liczonym cztery razy (4 × 12 px = 48 px strony za nic). */
    padding-block: 12px 2px;
  }
  .lp-step__n { line-height: 1.75; }
  .lp-step h3 { margin: 0 0 3px; }
  .lp-step p { grid-column: 2; }
}

/* ────────────────────────────────────────────────────────────────────────────
   5. Graf — ilustracja (SVG rysowany w HTML, bez pliku)
   ──────────────────────────────────────────────────────────────────────────── */

.lp-graph { width: 100%; height: auto; display: block; }
.lp-graph__e { stroke: var(--border-strong); stroke-width: 1; fill: none; }

/* Skupiska rozróżnia JASNOŚĆ TUSZU, nie druga barwa — color-mix z płótnem, więc
   ta sama reguła działa w Dniu i w Nocy (w Nocy tusz jest jasny, płótno ciemne). */
.lp-graph__n--1 { fill: var(--ink); }
.lp-graph__n--2 { fill: color-mix(in srgb, var(--ink) 68%, var(--canvas)); }
.lp-graph__n--3 { fill: color-mix(in srgb, var(--ink) 46%, var(--canvas)); }

/* Krawędzie workera są kobaltowe: to ten sam sygnał, co węzeł w środku
   („to robi worker”), a nie nowy akcent. */
.lp-graph__e--hub { stroke: var(--accent); stroke-width: 1.4; fill: none; opacity: .55; }
.lp-graph__halo { fill: color-mix(in srgb, var(--accent) 15%, transparent); }
.lp-graph__hub  { fill: var(--accent); }

.lp-figure {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--kp-radius);
  padding: var(--kp-sp-4);
  min-width: 0;
  margin: 0;
}
/* --bare: ilustracja stoi wprost na papierze. Karta pod czymś, co samo ma ramkę
   (telefon, schemat na własnym tle), dawała podwójne obramowanie. */
.lp-figure--bare { background: none; border: 0; padding: 0; }
.lp-figure--center { display: grid; justify-items: center; }
.lp-figure--center figcaption { text-align: center; }
.lp-figure figcaption {
  margin-top: var(--kp-sp-3);
  font-family: var(--kp-font-mono); font-size: var(--kp-fs-xs);
  line-height: 1.55;
  color: var(--muted);
}

/* Liczby — mono, tabelarycznie, etykieta pod spodem. W źródle <dt> jest przed
   <dd> (wymóg HTML), a column-reverse stawia liczbę nad etykietą. */
.lp-stats {
  display: flex; flex-wrap: wrap;
  gap: var(--kp-sp-3) var(--kp-sp-5);
  margin: var(--kp-sp-5) 0 0;
}
.lp-stat { display: flex; flex-direction: column-reverse; min-width: 0; }
/* pionowa kreska rozdziela liczby — bez niej „117 522 14" czytało się jak jedna */
.lp-stat + .lp-stat {
  padding-left: var(--kp-sp-5);
  border-left: 1px solid var(--border);
}
.lp-stat dd {
  margin: 0;
  font-family: var(--kp-font-mono); font-size: clamp(24px, 3.4vw, 32px); font-weight: 600;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
  line-height: 1.05;
  color: var(--ink);
}
.lp-stat dt {
  margin-top: 5px;
  font-family: var(--kp-font-mono); font-size: var(--kp-fs-xs);
  letter-spacing: var(--kp-tracking-label); text-transform: uppercase;
  color: var(--muted);
}
/* `p.` w selektorze jest konieczne: `.lp p` ustawia margin skrótem z tą samą
   wagą klasy + typ, więc goła klasa nie przebiłaby marginesu. */
p.lp-stats__note { margin-top: var(--kp-sp-5); }

/* ────────────────────────────────────────────────────────────────────────────
   6. Makieta telefonu (dekoracja: aria-hidden, tekst alternatywny w podpisie)
   ──────────────────────────────────────────────────────────────────────────── */

.lp-phone {
  width: 292px; max-width: 100%;
  padding: 7px;
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 30px;
  box-shadow: var(--shadow);
}
.lp-phone__scr {
  background: var(--canvas);
  border: 1px solid var(--border);
  border-radius: 24px;
  overflow: hidden;
  position: relative;
}
.lp-phone__top {
  display: flex; align-items: center; gap: 10px;
  padding: 14px var(--kp-sp-3) 10px;
  font-family: var(--kp-font-mono); font-size: 13px; font-weight: 600;
  border-bottom: 1px solid var(--border-soft);
}
.lp-phone__top svg { width: 17px; height: 17px; stroke: var(--muted); stroke-width: 1.7; fill: none; }
.lp-phone__q {
  display: flex; align-items: center; gap: 8px;
  margin: var(--kp-sp-3);
  padding: 0 10px;
  min-height: 34px;
  font-family: var(--kp-font-mono); font-size: 12.5px;
  color: var(--muted);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--kp-radius-sm);
}
.lp-phone__q svg { width: 14px; height: 14px; stroke: var(--muted); stroke-width: 1.8; fill: none; flex: none; }
.lp-phone__q .lp-phone__k { margin-left: auto; font-size: 11px; color: var(--faint); }
.lp-phone__lbl {
  padding: 2px var(--kp-sp-3) 8px;
  font-family: var(--kp-font-mono); font-size: 10.5px; font-weight: 600;
  letter-spacing: var(--kp-tracking-label); text-transform: uppercase;
  color: var(--muted);
}
.lp-phone__row {
  padding: 9px var(--kp-sp-3);
  border-top: 1px solid var(--border-soft);
}
.lp-phone__row .p {
  font-family: var(--kp-font-mono); font-size: 10px;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted);
}
.lp-phone__row .t {
  font-family: var(--kp-font-mono); font-size: 12.5px; color: var(--ink);
  margin-top: 3px; overflow-wrap: anywhere;
}
.lp-phone__fab {
  position: absolute; right: 14px; bottom: 14px;
  width: 44px; height: 44px; border-radius: 50%;
  display: grid; place-items: center;
  color: var(--fill-ink); background: var(--fill);
  box-shadow: var(--shadow);
}
.lp-phone__fab svg { width: 19px; height: 19px; stroke: currentColor; stroke-width: 2; fill: none; }
.lp-phone__pad { height: 62px; }

/* ────────────────────────────────────────────────────────────────────────────
   6b. Makieta ROLKI briefu (dekoracja: aria-hidden, opis w podpisie)
   ----------------------------------------------------------------------------
   Numer „6b", a nie 7 — makieta należy do tej samej rodziny co telefon wyżej,
   a przenumerowanie sekcji 7–13 zamieniłoby jedną nową sekcję w diff przez cały
   plik.
   Makieta jest CIEMNA na jasnej stronie i nie jest to złamanie sekcji 0 — z tego
   samego powodu, co ciemny pas w sekcji 9: zakaz dotyczy motywu sterowanego
   `prefers-color-scheme`, czyli tego, że strona wygląda inaczej u dwóch osób.
   Ta makieta wygląda tak samo u każdego, a pokazuje EKRAN APKI, a apka jest
   ciemna. Jasna makieta rolki pokazywałaby ekran, którego nie ma.
   Rytmu typów kart z apki (osiem kolorów po emoji) tu NIE MA świadomie —
   „kobalt zostaje jedynym kolorem, który coś znaczy" obowiązuje dalej, więc
   z apki wchodzi tylko to, co w niej też jest kobaltem: pasek postępu.
   ──────────────────────────────────────────────────────────────────────────── */

/* KOLUMNY TEJ SEKCJI ODWRÓCONE WZGLĘDEM TEMPA B. `.lp-t-b > .lp-split` (sekcja 10)
   daje sufit 420 px DRUGIEJ kolumnie, bo w tempie B przedmiot stoi po prawej. Tutaj
   przedmiot stoi po LEWEJ (żeby nie dublować kształtu następnej sekcji), a przedmiotem
   jest makieta o STAŁEJ szerokości 252 px — bez tej reguły dostawałaby `1fr`, czyli
   pływała w ~600 px pustego miejsca, a proza dusiła się w 420 px.
   Specyficzność (0,3,0), nie (0,2,0): reguła tempa B jest w pliku PÓŹNIEJ, więc przy
   remisie wygrałaby ona. I dlatego mobilny powrót do jednej kolumny musi być tu obok
   z tą samą wagą — zapytanie medialne NIE podnosi specyficzności (ta sama pułapka jest
   opisana przy `.lp-t-b > .lp-split` w sekcji 10; tam kosztowała kolumnę o zerowej
   szerokości). */
.lp-t-b > .lp-split.lp-split--reel { grid-template-columns: minmax(0, 264px) minmax(0, 1fr); }
@media (max-width: 860px) {
  .lp-t-b > .lp-split.lp-split--reel { grid-template-columns: 1fr; }
}

.lp-reel {
  /* Tokeny Nocy podmienione LOKALNIE, nie drugim zestawem reguł — te same
     wartości i te same zmierzone kontrasty, co w sekcji 9 (tusz #101115):
       #E8E7E0 …… 15,08:1  ✓ AAA  — tytuł i treść karty
       #9A9A93 ……  6,60:1  ✓ AA   — data, pozycja, źródło
       #5468FF ……  4,31:1  ✓ 1.4.11 — pasek postępu (grafika, nie tekst)
     Trzymanie ich w jednym miejscu znaczy, że przyszła zmiana Nocy nie rozjedzie
     makiety z pasem. */
  --ink: #E8E7E0;
  --muted: #9A9A93;

  width: 252px; max-width: 100%;
  /* Proporcja ekranu telefonu, nie kafla: cała obietnica tej sekcji brzmi „jedna
     karta na CAŁY ekran", a kwadratowa makieta mówiłaby coś innego. */
  aspect-ratio: 9 / 14.5;
  position: relative;
  display: grid; grid-template-rows: auto 1fr auto;
  overflow: hidden;
  color: var(--ink);
  border: 1px solid var(--kp-noc-700);
  border-radius: 22px;
  box-shadow: var(--shadow);
  /* Cztery warstwy jak w apce, z jedną różnicą: tu nie ma zdjęcia (landing nie
     ściąga niczego z sieci), więc kadr udaje miękka poświata w lewym górnym
     narożniku, a nad nią jedzie ta sama KURTYNA, która w apce trzyma czytelność
     tekstu nad cudzym zdjęciem. */
  background-color: var(--kp-noc-950);
  background-image:
    radial-gradient(118% 62% at 20% 0%, var(--kp-noc-700), transparent 62%),
    linear-gradient(180deg, transparent, var(--kp-noc-950) 76%);
}
/* Znak wodny z emoji TYPU karty — w apce to ten sam atrybut, z którego bierze się
   kolor. Tu jest wprost w CSS, bo makieta pokazuje jeden, konkretny typ (🌐 sieć).
   Wychodzi za prawą krawędź i jest obcinany przez `overflow: hidden` — dokładnie
   jak w apce, gdzie znak wodny nie jest ilustracją do oglądania. */
.lp-reel::after {
  content: "🌐";
  position: absolute; right: -14px; bottom: 13%;
  font-size: 118px; line-height: 1;
  opacity: .07; filter: saturate(.5);
}

/* Pasek dnia BEZ TŁA — sam cień tekstu. W apce to była poprawka po zgłoszeniu:
   nad kadrem ze zdjęcia nawet miękkie zejście koloru kanwy widać jako jaśniejszą
   wstęgę, a cień trzyma czytelność daty nad dowolnym tłem, nie będąc kształtem. */
.lp-reel__day {
  display: grid; justify-items: center; gap: 1px;
  padding: 13px 10px 0;
  text-shadow: 0 1px 2px rgba(16, 17, 21, .92), 0 0 12px rgba(16, 17, 21, .72);
}
.lp-reel__date { font-family: var(--kp-font-mono); font-size: 12.5px; font-weight: 600; }
.lp-reel__pos  { font-family: var(--kp-font-mono); font-size: 10px; color: var(--muted); }

/* Karta stoi w PIONOWYM ŚRODKU ekranu (`1fr` + align-self), jak w apce: rolka
   ma jedną rzecz do przeczytania, więc nie ma powodu, żeby zaczynała się u góry. */
.lp-reel__card { align-self: center; padding: 0 16px; }
.lp-reel__t { font-size: 13.5px; font-weight: 650; line-height: 1.32; letter-spacing: -.01em; }
.lp-reel__b { margin-top: 9px; font-size: 11.5px; line-height: 1.66; }
/* Kropkowane podkreślenie, nie ciągłe: w apce `[[wikilink]]` otwiera stronę
   w bazie, a odnośnik ciągły wychodzi z apki do przeglądarki — dwie różne rzeczy
   nie mogą wyglądać identycznie. */
.lp-reel__wl { text-decoration: underline dotted; text-underline-offset: 2px; }
.lp-reel__src {
  margin-top: 11px;
  font-family: var(--kp-font-mono); font-size: 10px; color: var(--muted);
}

/* PASEK POSTĘPU U DOŁU — segment na kartę, jak w relacjach. */
.lp-reel__bar { display: flex; gap: 3px; padding: 0 12px 15px; }
.lp-reel__seg {
  flex: 1 1 0; height: 3px; border-radius: 2px;
  position: relative; overflow: hidden;
  background: color-mix(in srgb, var(--ink) 20%, transparent);
}
.lp-reel__seg--done { background: color-mix(in srgb, var(--kp-c-400) 50%, transparent); }
.lp-reel__seg--on   { background: color-mix(in srgb, var(--kp-c-400) 22%, transparent); }
/* Wypełnienie idzie RAZ i zostaje — nie w pętli. Rolka w apce też nie zawija na
   początek („w kółko" to pętla, z której nie widać wyjścia), a pętla na landingu
   dodatkowo ciągnęłaby wzrok w nieskończoność w sekcji, która ma się przeczytać.
   Stan spoczynkowy jest AUTORSKI (`scaleX(1)`), więc animacja tylko dojeżdża do
   tego, co i tak jest w arkuszu — dzięki temu wariant bez ruchu (sekcja 11)
   wystarczy zgasić jedną linią, bez `forwards` i bez drugiej wartości. */
.lp-reel__fill {
  position: absolute; inset: 0; border-radius: 2px;
  background: var(--kp-c-400);
  transform: scaleX(1); transform-origin: left;
  animation: lp-reel-fill 5.2s linear;
}
@keyframes lp-reel-fill { from { transform: scaleX(0); } }

p.lp-views__note { margin-top: var(--kp-sp-5); }

.lp-views { list-style: none; margin: 0; padding: 0; display: grid; gap: 0; }
.lp-views li {
  display: grid; grid-template-columns: 7.4em minmax(0, 1fr); gap: var(--kp-sp-3);
  padding: 11px 0;
  border-top: 1px solid var(--border-soft);
  font-size: 14px; color: var(--muted); line-height: 1.55;
}
.lp-views li:first-child { border-top: 0; }
.lp-views b {
  font-family: var(--kp-font-mono); font-size: var(--kp-fs-sm); font-weight: 600;
  letter-spacing: -.01em; color: var(--ink);
}
@media (max-width: 420px) {
  .lp-views li { grid-template-columns: 1fr; gap: 3px; }
}

/* ────────────────────────────────────────────────────────────────────────────
   7. Tabela stanu, CTA, stopka
   ──────────────────────────────────────────────────────────────────────────── */

p.lp-state__lede { margin-bottom: var(--kp-sp-5); }
.lp-state td .kp-badge { margin-right: var(--kp-sp-2); }
/* `.lp-fold` w selektorze, bo po przejściu wykazu stanu na <details> nota nie ma
   już nad sobą `.lp-state` — a nota bez tej reguły czyta się tym samym stopniem
   co nazwa funkcji, czyli zastrzeżenie udaje treść (ten sam błąd, co opisany
   przy `.lp p.kp-meta` w sekcji 1). */
.lp-state .lp-state__note,
.lp-fold .lp-state__note {
  display: block; margin-top: 4px;
  font-size: var(--kp-fs-xs); line-height: 1.55; color: var(--muted);
}
.lp-state th:first-child, .lp-state td:first-child { width: 46%; }

/* ── TEMPO C: arkusz stanu, nie kolejna karta ───────────────────────────────
   Kit rysuje .kp-table-wrap jako powierzchnię z obrysem i promieniem — słusznie,
   bo w apce tabela leży NA tle. Tu treść jest wykazem i to ona ma nieść linie,
   więc rama znika, a wiersze zostają na włosowych kreskach. Ta sama treść
   czyta się wtedy jak arkusz stanu, a nie jak ósmy slab pod rząd. */
.lp-state.kp-table-wrap {
  border: 0;
  border-radius: 0;
  background: none;
  /* overflow: visible jest tu WYMUSZONE zdjęciem ramki — ale samo w sobie
     rozbiłoby przyklejony nagłówek: `.kp-table th` ma position:sticky, a bez
     scrollowanego przodka przykleja się do OKNA i wjeżdża pod pasek nawigacji.
     Dlatego nagłówek wraca do static (niżej), a nie „bo tak ładniej". */
  overflow: visible;
}
.lp-state .kp-table th {
  position: static;
  padding-block: 0 8px;
  background: none;
  /* głowa wykazu w tuszu (14,83:1), tak jak w .lp-grid .kp-card — jedna zasada
     na całej stronie: pierwsza kreska wykazu jest mocniejsza od separatorów */
  box-shadow: none;
  border-bottom: 1px solid var(--ink);
}
.lp-state .kp-table td { border-top: 1px solid var(--border); }
.lp-state .kp-table tbody tr:first-child td { border-top: 0; }
/* Skrajne komórki bez wyściółki bocznej: wykaz stoi na krawędzi kolumny treści,
   inaczej pierwsza kolumna byłaby wcięta o 12 px względem nagłówka sekcji. */
.lp-state .kp-table th:first-child,
.lp-state .kp-table td:first-child { padding-left: 0; }
.lp-state .kp-table th:last-child,
.lp-state .kp-table td:last-child { padding-right: 0; }
/* hover kitu malował komórkę na tle karty; bez karty maluje plamę na Papierze */
.lp-state .kp-table tbody tr:hover td { background: none; }

/* ── Zwijanie wykazu stanu — REGUŁY GOTOWE, CZEKAJĄ NA MARKUP ───────────────
   Jedenaście wierszy to najdroższa sekcja strony na telefonie (1508 px z 9173).
   Zwijanie idzie na NATYWNYM <details>/<summary>, bo CSP landingu nie ma
   `script-src` (landing/_headers) — rozwiązanie z JS nie wejdzie tu nigdy,
   a nie tylko „na razie".
   Markup do wklejenia jest w raporcie sesji DESIGN; te reguły działają bez
   żadnej zmiany w CSS w momencie, w którym markup się pojawi. */
.lp-fold { border-top: 1px solid var(--ink); }
.lp-fold + .lp-fold { border-top-color: var(--border); }
.lp-fold > summary {
  display: flex; align-items: center; gap: var(--kp-sp-3);
  min-height: 52px;                 /* cel dotykowy 52 > 44 px z WCAG 2.5.8 */
  padding-block: var(--kp-sp-2);
  font-family: var(--kp-font-mono); font-size: var(--kp-fs-md); font-weight: 600;
  color: var(--ink);
  cursor: pointer;
  /* trzy deklaracje na jeden trójkącik: `list-style` dla Firefoksa, `::marker`
     dla przeglądarek, które go liczą pomimo display:flex, `-webkit-` dla Safari */
  list-style: none;
}
.lp-fold > summary::marker { content: ""; }
.lp-fold > summary::-webkit-details-marker { display: none; }
.lp-fold > summary:focus-visible {
  outline: var(--kp-ring-w) solid var(--focus);
  outline-offset: calc(-1 * var(--kp-ring-off));
  border-radius: var(--kp-radius-sm);
}
/* Grot rysowany z krawędzi elementu: bez pliku, bez data-URI i bez SVG w HTML.
   Zwinięte = grot w prawo, rozwinięte = w dół; to jedyny sygnał stanu poza
   samą treścią, więc musi być widoczny — 1,6 px kreska w kolorze --muted
   (7,19:1 na Papierze, a jako grafika wystarczy 3:1 z WCAG 1.4.11). */
.lp-fold > summary::before {
  content: ""; flex: none;
  width: 7px; height: 7px;
  margin-left: 3px;
  border-right: 1.6px solid var(--muted);
  border-bottom: 1.6px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform var(--kp-dur-2) var(--kp-ease);
}
.lp-fold[open] > summary::before { transform: rotate(45deg); }
.lp-fold__count { margin-left: auto; font-size: var(--kp-fs-sm); color: var(--muted); }
.lp-fold__list { list-style: none; margin: 0; padding: 0 0 var(--kp-sp-3); }
.lp-fold__list li {
  position: relative;
  padding: 9px 0 9px 22px;
  border-top: 1px solid var(--border);
  font-size: 14px; line-height: 1.5;
}
/* Kreska, nie kropka: kropka jest w .lp-list--is znaczeniem („węzeł, to jest"),
   więc ten sam znak w innym miejscu z innym znaczeniem byłby kłamstwem. Tu
   marker tylko dzieli wiersze wzrokowo — stan niesie nagłówek grupy. */
.lp-fold__list li::before {
  content: ""; position: absolute; left: 1px; top: 1.1em;
  width: 9px; height: 1px; background: var(--kp-n-500);
}

/* Wąsko tabela ROZKŁADA SIĘ NA BLOKI, zamiast zwężać kolumny do dwóch słów
   na linię (przy 360 px nazwa funkcji szła na pięć wierszy) albo scrollować
   w poziomie — a scroll w poziomie na najważniejszej treści strony to zła
   zamiana. Nagłówek znika, bo w układzie blokowym nie ma czego opisywać;
   sens niesie sama nazwa funkcji i znacznik przy niej. */
@media (max-width: 640px) {
  .lp-state .kp-table,
  .lp-state .kp-table tbody,
  .lp-state .kp-table tr,
  .lp-state .kp-table td { display: block; width: auto; }
  .lp-state .kp-table thead { display: none; }
  .lp-state .kp-table tr {
    padding: var(--kp-sp-3) var(--kp-sp-4);
    border-top: 1px solid var(--border-soft);
  }
  .lp-state .kp-table tbody tr:first-child { border-top: 0; }
  .lp-state .kp-table td { padding: 0; border-top: 0; }
  .lp-state .kp-table td:first-child {
    width: auto; font-weight: 600;
    margin-bottom: var(--kp-sp-2);
  }
  /* hover kitu maluje komórkę — w układzie blokowym maluje cały wiersz */
  .lp-state .kp-table tbody tr:hover td { background: none; }
}

.lp-cta {
  display: grid; gap: var(--kp-sp-4);
  padding: clamp(22px, 3.6vw, 40px);
  max-width: 780px;         /* karta na całą szerokość zostawiała pustą prawą połowę */
  text-align: left;
}
/* Ścieżka pliku nie jest etykietą — kit domyślnie wersalikuje nagłówek bloku kodu,
   a wielkość liter w ścieżce jest znacząca. */
.lp-filehead { text-transform: none; letter-spacing: .01em; }
.lp-cta img { width: 34px; height: 34px; }
.lp-cta h3 {
  margin: 0;
  font-family: var(--kp-font-mono); font-size: clamp(18px, 2.4vw, 23px); font-weight: 600;
  letter-spacing: -.03em;
}
.lp-cta p { max-width: 58ch; }
.lp-actions--flush { margin-top: 0; }

.lp-foot {
  margin-top: var(--lp-sect);
  border-top: 1px solid var(--border);
  padding: var(--kp-sp-5) 0 calc(var(--kp-sp-6) + env(safe-area-inset-bottom, 0px));
}
.lp-foot__in {
  display: flex; align-items: flex-end; gap: var(--kp-sp-5) var(--kp-sp-6); flex-wrap: wrap;
}
.lp-foot img { width: 128px; height: auto; }
.lp-foot__meta { display: grid; gap: 5px; font-family: var(--kp-font-mono); font-size: var(--kp-fs-xs); color: var(--muted); }
.lp-foot__links {
  margin-left: auto;
  display: flex; gap: var(--kp-sp-4); flex-wrap: wrap;
  font-family: var(--kp-font-mono); font-size: var(--kp-fs-sm);
}

/* ────────────────────────────────────────────────────────────────────────────
   8. Lista oczekujących — jedyna prośba tej strony
   ----------------------------------------------------------------------------
   `.lp-wl` była w markupie HOOKIEM BEZ ANI JEDNEJ REGUŁY (zostawionym świadomie,
   żeby sesja od treści nie wchodziła w arkusz). Skutek był mierzalny: `.kp-input`
   z kitu ma `width: 100%`, więc pole zajmowało 491 px na 1440 i 351 px na 390 —
   całą kolumnę hero. Pole na całą szerokość kolumny czyta się jak formularz
   W APLIKACJI („wypełnij tabelkę"), a nie jak jedna prośba na stronie
   sprzedażowej. Projekt: design/ds/landing/hero.html, karta „Ekran 2 — prośba".
   ──────────────────────────────────────────────────────────────────────────── */

.lp-wl {
  display: grid;
  gap: var(--kp-sp-4);
  /* 460 px = szerokość formularza z karty projektowej. Liczba nie jest okrągła
     przez przypadek: przy 12,5 px mono oba przyciski („Zapisz się na listę
     oczekujących" ≈ 268 px + „Co już działa" ≈ 126 px + 12 px odstępu = 406 px)
     mieszczą się w JEDNYM rzędzie z zapasem 54 px, a poniżej ~420 px zaczęłyby
     się zawijać jeden pod drugi. */
  max-width: 460px;
  margin-top: var(--kp-sp-5);
}
/* Wysokość 48 px, nie 40 z kitu: to główna akcja strony, a nie pole w gęstym
   interfejsie. Podnoszę ZMIENNĄ kitu (--_h, kit.css §5), nie `min-height` —
   dzięki temu nie dubluję reszty wyglądu pola i nie rozjeżdżam go przy zmianie
   kitu. (0,2,0) bije (0,1,0), także wewnątrz media query kitu.
   OBRYS zostaje z kitu (--border-strong = --kp-n-600 #6B6D66): 5,24:1 na białej
   karcie i 4,38:1 na Papierze — w obu przypadkach ponad 3:1 z WCAG 1.4.11, więc
   SAMA ramka niesie informację „tu się pisze" i pole nie potrzebuje wypełnienia
   innego niż powierzchnia karty. Etykieta jest widoczna nad polem (.kp-field
   z kitu) — placeholder znika przy pisaniu i przestaje tłumaczyć, co jest w polu.
   Kolor etykiety i podpowiedzi bierze się z --muted, podniesionego dla landingu
   w sekcji 1 do 7,19:1 na Papierze. */
.lp-wl .kp-input { --_h: 48px; font-size: 15px; }
/* Odstęp niesie już grid formularza; margines z .lp-actions dokładałby 24 px */
.lp-wl .lp-actions { margin-top: 0; }
/* Podpowiedź pod polem ma prowadzić do przycisków, nie stać w powietrzu */
.lp-wl .kp-hint { line-height: 1.55; }

/* ────────────────────────────────────────────────────────────────────────────
   9. Ciemny pas „Worker" — jedyny ciemny pas na jasnej stronie
   ----------------------------------------------------------------------------
   ZATWIERDZONY (PRECYZJA, 2026-07-26) i NIE jest to złamanie sekcji 0. Zakaz
   z sekcji 0 dotyczy MOTYWU sterowanego `prefers-color-scheme` — czyli tego, że
   strona wygląda inaczej u dwóch osób. Pas jako sekcja wygląda tak samo
   u każdego i na każdym zrzucie, więc uzasadnienie z sekcji 0 („jeden,
   przewidywalny wygląd") jest tu SPEŁNIONE, nie naruszone. W tym pliku nie ma
   ani jednego `prefers-color-scheme` i nie wolno go dodać.
   Znaku marki na tuszu NIE MA i nie ma go czym zastąpić: `assets/mark-adaptive.b3c7c75f.svg?d=9b04846`
   trzyma własne `prefers-color-scheme` W ŚRODKU PLIKU i na ciemnym systemie
   przechodzi na papierowy tusz, czyli znika na tym pasie. Pas to nagłówek,
   etykieta i wykaz kroków — grafiki znaku nie potrzebuje.
   ──────────────────────────────────────────────────────────────────────────── */

/* Druga postać selektora rozpoznaje pas po ZAWARTOŚCI (wykaz kroków workera stoi
   tylko w tej jednej sekcji), więc pas działa JUŻ DZIŚ, bez czekania na klasę
   `lp-ink` w markupie — sesja DESIGN nie pisze do landing/index.html. Po
   wklejeniu klasy z raportu wariant `:has()` można stąd usunąć. */
section.lp-ink,
.lp section.lp-wrap:has(> .lp-steps) {
  /* Tokeny semantyczne PODMIENIONE LOKALNIE, zamiast drugiego zestawu reguł:
     .lp-head, .lp-steps i .lp p same trafiają wtedy na właściwe wartości i nie
     ma dwóch miejsc, które trzeba pamiętać przy każdej przyszłej zmianie.
     Policzone na tuszu #101115 (Y = 0,00617):
       #E8E7E0 …… 15,08:1  ✓ AAA  — tytuł, treść kroku
       #9A9A93 ……  6,60:1  ✓ AA   — proza, etykieta marginesu 10,5 px
       #8894FF ……  6,94:1  ✓ AA   — kobalt 300, numery kroków
       #5468FF ……  4,31:1  ✓ 1.4.11 / ✗ AA dla tekstu → TYLKO pierścień ostrości
       #2743E8 ……  2,50:1  ✗ wszystko  → na tuszu nie wchodzi wcale
       #6A6B75 ……  3,54:1  ✓ 1.4.11 dla obrysu kontrolki
       #2B2C33 ……  1,52:1  — linie: grafika dekoracyjna, nie nośnik informacji
     Podmiana --muted jest OBOWIĄZKOWA, nie kosmetyczna: dzienna wartość
     (#4A4C50 z sekcji 1, a pod nią #6B6D66 z kitu) ma na tuszu 1,35:1 i 3,57:1,
     czyli tekst byłby nieczytelny albo pod progiem. */
  --canvas: var(--kp-noc-950);
  --surface: var(--kp-noc-850);
  --surface-2: var(--kp-noc-800);
  --inset: var(--kp-noc-900);
  --ink: #E8E7E0;
  --muted: #9A9A93;
  --faint: #9A9A93;
  --border: var(--kp-noc-700);
  --border-soft: var(--kp-noc-800);
  --border-strong: var(--kp-noc-500);
  --accent-text: var(--kp-c-300);
  --focus: var(--kp-c-400);

  /* Własna wyściółka pasa: 56 px z --lp-sect to odstęp MIĘDZY sekcjami na
     Papierze, a wewnątrz pasa byłby ciemnym powietrzem. Odstęp od poprzedniej
     sekcji przenosi się więc na margin-top, żeby papierowa przerwa została
     na Papierze, a nie zamieniła się w tusz. */
  --lp-pad-top: clamp(34px, 5.2vw, 56px);
  margin-top: var(--lp-sect);
  padding-bottom: clamp(38px, 5.6vw, 60px);
  color: var(--ink);
}
/* Pas idzie od krawędzi do krawędzi okna, bo pas zatrzymany na kolumnie treści
   nie jest pasem — jest wielką kartą, czyli dokładnie tym, czego cała ta
   poprawka się pozbywa.
   `50% - 50vw`: 50% liczy się od kolumny (≤1120 px), 50vw od okna, więc różnica
   to dokładnie papierowy margines z jednej strony. Przy węższym oknie niż
   kolumna wychodzi 0 i nic się nie dzieje. Ewentualną szerokość paska
   przewijania łapie `overflow-x: clip` z sekcji 1 — sprawdzone: scrollWidth
   zostaje równy clientWidth przy 390 i 1440 px.
   z-index: -1 zamiast tła na samej sekcji, bo tło sekcji nie umie wyjść za jej
   krawędź; ujemna warstwa siedzi w kontekście <main> (z-index: 1 z sekcji 1),
   więc pas zakrywa siatkę kropek, a treść sekcji zostaje nad nim. */
section.lp-ink::before,
.lp section.lp-wrap:has(> .lp-steps)::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  margin-inline: calc(50% - 50vw);
  background: var(--kp-noc-950);
}

/* ────────────────────────────────────────────────────────────────────────────
   10. Trzy tempa sekcji — A / B / C, nigdy dwa te same pod rząd
   ----------------------------------------------------------------------------
   Diagnoza (design/ds/landing/rhythm.html): osiem sekcji o IDENTYCZNYM
   kształcie — nagłówek do lewej, karta w ramce obok albo pod. Każda z osobna
   w porządku, ale osiem z rzędu czyta się jak stos jednakowych płyt, bez
   miejsca, na którym oko odpoczywa. Poprawka nie dodaje treści: nadaje sekcjom
   trzy tempa i zdejmuje ramki.
     A — zdanie w powietrzu:  nagłówek 38 px, jeden akapit, 76 px góra/dół, zero ramek
     B — proza | artefakt:    dwie kolumny, po prawej PRZEDMIOT (dziennik, źródło, graf)
     C — wykaz na liniach:    pełna szerokość, wiersze na border-bottom, zero kart
   Klasy są gotowe dla sesji PRECYZJA (markup w raporcie). Zmiany, które dają
   rytm już dziś, bez markupu, siedzą wyżej: zdjęte ramki z prozy (sekcja 4),
   wykaz kroków (sekcja 4), arkusz stanu (sekcja 7), ciemny pas (sekcja 9).
   ──────────────────────────────────────────────────────────────────────────── */

/* TEMPO A — sekcja, która nic nie pokazuje, tylko coś MÓWI. Bez niej strona
   nie ma gdzie oddychać. Marginesy 76 px są tu treścią, nie odstępem. */
section.lp-t-a {
  --lp-pad-top: clamp(48px, 7.6vw, 76px);
  padding-bottom: clamp(48px, 7.6vw, 76px);
}
.lp-t-a .lp-head h2 { font-size: clamp(26px, 4.2vw, 38px); max-width: 22ch; }
.lp-t-a .lp-head { margin-bottom: var(--kp-sp-4); }

/* TEMPO B — proza po lewej, przedmiot po prawej. Kolumna przedmiotu ma SUFIT:
   dziennik i źródło markdown są obiektami o naturalnej szerokości (~420 px),
   a rozciągnięte na pół kolumny przestają wyglądać jak przedmioty i zaczynają
   jak panel interfejsu. Proza bierze resztę. */
.lp-t-b > .lp-split { grid-template-columns: minmax(0, 1fr) minmax(0, 420px); }
/* …i NATYCHMIAST cofnięcie tego na telefonie. Bez tej reguły `.lp-t-b > .lp-split`
   (0,2,0) bije `@media (max-width: 860px) .lp-split { 1fr }` (0,1,0), bo
   ZAPYTANIE MEDIALNE NIE PODNOSI SPECYFICZNOŚCI — to jest cała pułapka i łatwo
   ją przegapić, bo reguła mobilna wygląda na „późniejszą i węższą".
   Zmierzone skutki, zanim to weszło: computed `grid-template-columns: 0px 329px`
   na 390 px, czyli kolumna prozy miała ZERO — tekst łamał się po jednym słowie
   i nachodził na blok kodu. scrollHeight 8208 → 9227 (+1019) na 390 i 7198 → 8733
   (+1535) na 620. Sekcja „własność" 992 → 2309 px.
   Trzyma się `.lp-t-b`, a nie `.lp-split`, żeby nie ruszać sekcji, które wchodzą
   w dwie kolumny z innego powodu. */
@media (max-width: 860px) {
  .lp-t-b > .lp-split { grid-template-columns: 1fr; }
}

/* TEMPO C — wykaz na pełną szerokość. Linia marginesu USTĘPUJE, bo przecinałaby
   wiersze wykazu w poprzek, a etykieta wraca nad tytuł. Dopóki markup nie ma
   `.lp-t-c`, rozpoznaję tempo C po tym, co w sekcji stoi: siatka prozy
   („co to jest") albo arkusz stanu. `:has()` jest w tej samej liście selektorów
   co `.lp-t-c` świadomie — gdyby przeglądarka go nie znała, padłaby cała reguła,
   ale wtedy `.lp-t-c` też jeszcze nie istnieje w markupie, więc nic nie tracimy;
   po wklejeniu klas z raportu warianty `:has()` można stąd usunąć. */
.lp-t-c > .lp-head::after,
.lp-wrap:has(> .lp-grid) > .lp-head::after,
.lp-wrap:has(> .lp-state) > .lp-head::after { display: none; }

.lp-t-c > .lp-head,
.lp-wrap:has(> .lp-grid) > .lp-head,
.lp-wrap:has(> .lp-state) > .lp-head { grid-template-columns: minmax(0, 1fr); }

/* Etykieta wraca NAD tytuł (order: -1) i do lewej: w tempie C nie ma marginesu,
   na którym mogłaby wisieć, a mikroskopijny tekst POD dużym tytułem czyta się
   jak podtytuł, czyli obiecuje treść, której tam nie ma. */
.lp-t-c > .lp-head > .lp-head__meta,
.lp-wrap:has(> .lp-grid) > .lp-head > .lp-head__meta,
.lp-wrap:has(> .lp-state) > .lp-head > .lp-head__meta {
  order: -1;
  text-align: left;
  margin-bottom: 6px;
}

/* ────────────────────────────────────────────────────────────────────────────
   11. Mniej ruchu — cała animacja strony się zatrzymuje, treść zostaje
   ──────────────────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .lp-log__row { animation: none; }
  .lp-h1 .lp-cur, .lp-log__row:last-child .lp-cur { animation: none; }
  /* Plakat: kursor przestaje mrugać, strzałka przestaje się kołysać. Znak zostaje
     w pełni widoczny — „ogranicz ruch" gasi ruch, nie treść. */
  .lp-poster__cur, .lp-poster__arr { animation: none; }
  /* Obrót grotu przy zwijaniu wykazu: stan zmienia się natychmiast, nie w ruchu.
     Sam grot ZOSTAJE — to jedyny sygnał „tu jest coś schowane". */
  .lp-fold > summary::before { transition: none; }
  /* Pasek postępu makiety rolki: segment zostaje PEŁNY (stan autorski), więc
     makieta nadal pokazuje kartę 3 z 7 — gaśnie ruch, nie informacja. */
  .lp-reel__fill { animation: none; }
}

/* ────────────────────────────────────────────────────────────────────────────
   12. Telefon — budżet przewijania i cele dotykowe
   ----------------------------------------------------------------------------
   Strona miała przy 390 px 9173 px wysokości (zmierzone, nie oszacowane), czyli
   ~22 ekrany. Ten blok jest wyłącznie ZMIANĄ GEOMETRII I DOMYŚLNEGO STANU —
   żadne zdanie nie znika, poza jedną makietą, która na telefonie odpowiada na
   pytanie, którego czytelnik już nie ma. Rachunek w design/ds/landing/mobile.html.
   ──────────────────────────────────────────────────────────────────────────── */

/* Próg 860 px to DOKŁADNIE ten, na którym .lp-split przestaje być dwiema
   kolumnami (sekcja 4) — i to jest cała reguła: makieta istnieje po to, żeby
   stać OBOK wykazu widoków. Kiedy nie ma obok czego stać, wraca do bycia
   533-pikselowym objazdem. Przy progu 760 px pasmo 760–860 zostawało z makietą
   ułożoną PONAD wykazem, czyli w najgorszym z trzech możliwych układów
   (zmierzone: 7500 px przy 760 px szerokości, przy 7198 px na 620 px). */
@media (max-width: 860px) {
  /* MAKIETA TELEFONU — jedyne uzasadnione ukrycie na całej tej stronie.
     Sekcja „Jak to wygląda w ręce" pokazuje RYSUNEK TELEFONU — na telefonie.
     Czytelnik trzyma prawdziwy ekran w dłoni i jeden przycisk dalej ma
     prawdziwą apkę, więc makieta odpowiada na pytanie, które już nie istnieje.
     Zmierzone: figura z podpisem to 533 px z 9173 px strony.
     Ukrywam CAŁĄ FIGURĘ, nie sam .lp-phone: podpis („Makieta widoku Szukaj…")
     bez rysunku opisywałby nieistniejący obrazek — a to gorsze niż brak obu.
     Lista widoków .lp-views ZOSTAJE: to treść sekcji, nie ilustracja
     (spec mówi o „.lp-phone / .lp-views", ale .lp-views to wykaz widoków
     apki — sześciu od 2026-07-28, gdy doszedł Brief — a jego ukrycie
     byłoby zdjęciem treści).
     TO UKRYCIE NIE DOTYCZY MAKIETY ROLKI (.lp-reel, sekcja 6b): tam rysunkiem
     jest FORMAT (jedna karta na ekran, pasek postępu), nie urządzenie, więc
     argument „telefon na telefonie" go nie obejmuje. Selektor celuje w telefon,
     nie w figurę, właśnie dlatego.
     Dwie osobne reguły, nie lista: nieznane `:has()` unieważniłoby też wariant
     z klasą, którą doda PRECYZJA. */
  .lp-figure--phone { display: none; }
  .lp-figure:has(> .lp-phone) { display: none; }
}

@media (max-width: 620px) {
  /* Skrócenie plakatu na telefonie ZDJĘTE (było `min(600px, calc(100svh - 52px))`).
     Argument „pełny svh dawał 792 px, czyli prawie cały ekran na sam znak" był
     słuszny, dopóki plakat MIAŁ sam znak. Teraz ma znak, nazwę, zdanie i przycisk,
     więc wypełnia ten ekran treścią, a nie pustką.
     Ważniejsze: pasek nawigacji jest teraz w DOM-ie ZA plakatem i sticky, więc każde
     skrócenie plakatu poniżej wysokości okna wpuszcza go na pierwszy ekran razem
     z drugim wordmarkiem — czyli kasuje cały powód, dla którego został przeniesiony.
     Reguła bazowa (`min-height: 100svh`) obowiązuje na każdej szerokości. */
  /* UWAGA dla następnego agenta: NIE dawaj tu `padding` na `.lp-state td`.
     Poniżej 640 px tabela rozkłada się na BLOKI (sekcja 7) i wyściółkę niesie
     wtedy <tr>, a nie komórka — każde 9 px na komórce mnoży się przez DWIE
     komórki × 11 wierszy = +198 px strony. Zmierzone i cofnięte. */
}

@media (max-width: 520px) {
  .lp-actions .kp-btn { flex: 1 1 auto; }
  .lp-head { padding-top: 15px; margin-bottom: var(--kp-sp-4); }
  .lp-foot__links { margin-left: 0; width: 100%; }
  /* Pole listy oczekujących: 52 px, nie 44 z kitu — 44 px to MINIMUM celu
     dotykowego z WCAG 2.5.8, a nie miara dla głównej akcji strony.
     Font 16 px jest twardym wymogiem, nie preferencją: pod 16 px iOS Safari
     przybliża stronę przy wejściu w pole i zostawia użytkownika z powiększonym
     layoutem, z którego musi wyjść sam. Powtarzam tę wartość, bo reguła
     `.lp-wl .kp-input` wyżej (0,2,0) bije mobilne 16 px z kitu (0,1,0). */
  .lp-wl .kp-input { --_h: 52px; font-size: 16px; }
  .lp-wl { max-width: none; margin-top: var(--kp-sp-4); gap: var(--kp-sp-3); }
  .lp-wl .lp-actions .kp-btn { --_h: 52px; }
}

/* ────────────────────────────────────────────────────────────────────────────
   13. Desktop — reguła marginesu wchodzi dopiero, gdy jest z czego ją wykroić
   ----------------------------------------------------------------------------
   190 px marginesu ma sens, kiedy zostaje co najmniej ~600 px na treść. Przy
   1000 px okna kolumna ma 912 px, więc treść dostaje 722 px — jeszcze uczciwa
   miara wiersza. Niżej margines zabierałby prozie po 40 znaków w wierszu,
   dlatego zamiast go zwężać, znika, a etykieta wraca nad tytuł (stan bazowy).
   ──────────────────────────────────────────────────────────────────────────── */

@media (min-width: 1000px) {
  .lp-head { grid-template-columns: minmax(0, 1fr) var(--lp-rail-label); }
  .lp-head::after { display: block; }
  .lp-head__meta { order: 0; text-align: right; }
  /* Treść oddaje 190 px, żeby nic nie przechodziło przez linię. Bez tego
     dwukolumnowy .lp-split i czterokolumnowy .lp-steps przecinałyby margines
     w poprzek i linia zamiast porządkować, wyglądałaby na pomyłkę składu. */
  .lp-split, .lp-steps { padding-right: var(--lp-rail); }
}
