/* app.news60.pl — pionowy feed pełnoekranowy.
   Układ celowo bliski aplikacjom wideo: jedna karta = jeden ekran, przewijanie
   zatrzaskowe, akcje kciukiem po prawej stronie. Ciemne tło, bo zdjęcie jest
   tłem karty i każdy jaśniejszy interfejs by z nim konkurował. */

/* ── Paleta ─────────────────────────────────────────────────────────────────
   Kolory były wpisane na sztywno w blisko stu miejscach (#0b0b0d, #ff2b55,
   rgba(255,255,255,.x)…), więc każda zmiana wyglądu oznaczała przeszukiwanie
   całego arkusza. Tu są raz; skorka.js nadpisuje je na `documentElement`.

   NAZWY SĄ TE SAME CO W STREFIE STATYCZNEJ (news60.pl/wspolne/skorka.js):
   --tlo, --powierzchnia, --karta, --tekst, --przygas, --akcent, --akcent2,
   --kreska, --rad. Aplikacja i strefa mają mówić jednym językiem — inaczej
   przenoszenie skórki między nimi byłoby tłumaczeniem słownika.

   ── Dwie warstwy, nie jedna ───────────────────────────────────────────────
   Aplikacja różni się od strefy jedną istotną rzeczą: połowa interfejsu leży
   NA ZDJĘCIU materiału, którego koloru nie znamy. Czytelność zapewnia tam nie
   tło, tylko WELON — gradient kładziony na zdjęcie. Stąd druga rodzina tokenów:

     --welon-rgb       kolor welonu (trójka RGB, bo używamy go z wieloma alfami)
     --na-welonie-rgb  tekst i ikony leżące na welonie
     --plyta           nieprzezroczysta podkładka pod DROBNY tekst nad zdjęciem
     --na-plycie       tekst na tej podkładce

   Sam welon z alfą nie wystarcza dla 13-pikselowych etykiet: przy jasnej
   skórce 42-procentowa biel na ciemnym zdjęciu daje kontrast 3,2 — poniżej
   progu. Zakładki, lupa i pigułka „źródło / temat" dostają więc mocniejszą
   płytę zamiast tej samej alfy co reszta.

   ── Akcent podlega przełącznikowi TAK SAMO jak tekst ──────────────────────
   Lekcja ze strefy, której nie wolno powtórzyć: akcent niesie treść (aktywna
   zakładka, licznik, stan wyboru), więc skórka MUSI go nadpisywać. Limonka
   #d8ff3e na bieli ma kontrast 1,15 przy wymaganych 4,5 — zostawiona jako
   „kolor marki" po prostu znika. Dlatego są trzy osobne tokeny:
     --akcent        kolor WYPEŁNIENIA (pigułka, przycisk)
     --na-akcencie   tekst na tym wypełnieniu
     --akcent-tekst  ten sam akcent użyty JAKO TEKST na tle (inny próg: 4,5)

   Świadomie POZA paletą zostają cienie (`box-shadow: … rgba(0,0,0,…)`) i dwie
   zasłony przyciemniające (`.zaslona`, `.arkusz-zaslona`). Cień jest brakiem
   światła, a nie kolorem skórki — jasny cień na jasnym tle nie istnieje,
   a zasłona ma przyciemniać także wtedy, gdy interfejs pod nią jest biały. */
:root{
  /* Powierzchnie */
  --tlo:#0b0b0d;            /* tło aplikacji */
  --powierzchnia:#262631;   /* pola formularzy, listy rozwijane */
  --karta:#1c1c26;          /* arkusze, szuflada, dymki */
  --poza:#000;              /* margines poza kadrem telefonu (ekran ≥820 px) */
  /* Tekst */
  --tekst:#fff;
  --tekst-rgb:255,255,255;  /* do delikatnych podświetleń: rgba(var(--tekst-rgb),.1) */
  --nagl:#fff;              /* nagłówki — osobno, bo skórka własna pozwala je ustawić */
  --przygas:#b6b6bf;        /* tekst drugorzędny, podpowiedzi w polach */
  /* Akcent */
  /* Wypełnienia akcentem są CIEMNIEJSZE niż dawne #ff2b55: biel na tamtej
     czerwieni miała kontrast 3,67 przy wymaganych 4,5, a leżą na niej napisy
     13-pikselowe. Wartości tutaj muszą być kopią skórki standardowej ze
     skorka.js — rozjazd widać jako drgnięcie koloru przy pierwszym rysowaniu. */
  --akcent:#e0143f;
  --akcent-rgb:224,20,63;
  --akcent-tekst:#ff4f70;
  --na-akcencie:#fff;
  --na-akcencie-rgb:255,255,255;
  --akcent2:#d8ff3e;        /* „60" w logo — druga barwa marki */
  /* Tekst NA drugiej barwie. Potrzebny, odkąd `--akcent2` jest także
     wypełnieniem przycisku (karta zachęty konta), a nie tylko kolorem znaku.
     Wartość ustala skórka: na standardowej i monochromatycznej limonka/szarość
     niosą czerń, na jasnej `--akcent2` jest ciemną oliwką i niesie biel. */
  --na-akcencie2:#000;
  --zapis:#facc15;          /* materiał zapisany: osobny kolor, bo to inny stan niż polubienie */
  --na-zapisie:#0b0b0d;
  --uwaga:#e8ff00;          /* nota „odmowa niczego nie psuje" — ma kłuć w oczy */
  /* Kreska i promień */
  --kreska:rgba(255,255,255,.14);
  --rad:22px;               /* promień arkusza dolnego */
  /* Warstwa nad zdjęciem */
  --welon-rgb:0,0,0;
  --na-welonie-rgb:255,255,255;
  --plyta:rgba(0,0,0,.42);
  --na-plycie:rgba(255,255,255,.72);
  /* Plansza celowo kontrastująca z feedem (pasek „Pokazać wiadomości z okolicy?").
     Nie jest tym samym co --karta: ma się ODCINAĆ od materiału, a nie wtapiać. */
  --plansza:#fff;
  --na-planszy:#15151a;
  /* Zastępczy gradient karty bez zdjęcia — odcień liczy JS z identyfikatora
     materiału, nasycenie i jasność bierze ze skórki (mono ma 0% nasycenia). */
  --g-nas:28%;
  --g-jasn1:22%;
  --g-jasn2:10%;
}

*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
/* Reguła `display` z klasy wygrywa ze stylem przeglądarki dla [hidden], więc
   element z atrybutem hidden i własnym display byłby MIMO TO widoczny.
   Bez tego ekran błędu przykrywał poprawnie wczytany feed. */
[hidden]{display:none !important}
html,body{margin:0;padding:0;height:100%;overflow:hidden;background:var(--tlo);color:var(--tekst)}
body{
  font-family:system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  overscroll-behavior:none;   /* bez „pull to refresh” w środku feedu */
}
img{display:block;max-width:100%}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}

/* ── Górny pasek ─────────────────────────────────────────────────────── */
.top{
  position:fixed;top:0;left:0;right:0;z-index:30;
  display:flex;align-items:center;justify-content:space-between;
  padding:calc(env(safe-area-inset-top) + 12px) 16px 12px;
  background:linear-gradient(180deg,rgba(var(--welon-rgb),.75),rgba(var(--welon-rgb),0));
  pointer-events:none;
}
.top > *{pointer-events:auto}
.logo{font-weight:800;font-size:19px;letter-spacing:-.5px;text-shadow:0 2px 8px rgba(var(--welon-rgb),.6)}
/* „60" limonką, nie czerwienią. Czerwień akcentu jest kolorem AKCJI w tej
   aplikacji (aktywna zakładka, punktory, przyciski), więc logo w tym samym
   kolorze zlewało się z interfejsem zamiast go otwierać. Limonka to kanon
   floty (ten sam odcień co w panelu redakcji) i na niemal czarnym tle daje
   najostrzejszy kontrast, jaki mamy w palecie. */
.logo span{color:var(--akcent2)}
.top-right{display:flex;gap:8px;align-items:center}
.lang-btn,.icon-btn{
  display:inline-flex;align-items:center;gap:6px;height:36px;padding:0 12px;
  border-radius:999px;background:rgba(var(--na-welonie-rgb),.16);backdrop-filter:blur(8px);
  font-size:13px;font-weight:700;letter-spacing:.04em
}
.icon-btn{width:36px;padding:0;justify-content:center}
.icon-btn svg{width:19px;height:19px}
.icon-btn.on{background:var(--akcent);color:var(--na-akcencie)}

.lang-menu{
  position:fixed;inset:0 auto 0 0;z-index:60;width:min(84vw,300px);
  background:var(--karta);border-right:1px solid var(--kreska);
  padding:calc(env(safe-area-inset-top) + 60px) 10px calc(env(safe-area-inset-bottom) + 16px);
  display:flex;flex-direction:column;gap:2px;box-shadow:18px 0 44px rgba(0,0,0,.55);
  overflow-y:auto;animation:szuflada .18s ease-out
}
@keyframes szuflada{from{transform:translateX(-100%)}to{transform:translateX(0)}}
/* Przyciemnienie jako OSOBNY element, nie pseudo-element szuflady: klik
   w pseudo-element trafia w menu, więc „kliknij obok, żeby zamknąć" nie
   działało — a to główny sposób zamykania szuflady na telefonie. */
.zaslona{position:fixed;inset:0;z-index:59;background:rgba(0,0,0,.55);
  animation:zaslona-poj .18s ease-out}
@keyframes zaslona-poj{from{opacity:0}to{opacity:1}}
/* ── ROZMIAR PISMA W SZUFLADZIE (życzenie operatora: „stosunkowo duże") ─────
   Pozycje menu miały 14–15 px, czyli MNIEJ niż treść materiału w feedzie (15 px)
   i mniej niż pole języka pod nimi (16 px) — a to jest lista poleceń, w którą
   się celuje kciukiem, nie tekst do czytania ciągiem. 17 px stawia je nad
   progiem, poniżej którego Safari na iPhonie powiększa stronę przy dotknięciu,
   i zostawia zapas na najdłuższą pozycję („Zapisane materiały (12)") bez
   zawijania w szufladzie szerokiej na 300 px. Wysokość celu dotykowego (44 px)
   trzyma osobna reguła niżej i po powiększeniu pozycje są od niej wyższe. */
.lang-menu button{text-align:left;padding:12px 14px;border-radius:10px;font-size:17px}
.lang-menu .menu-link{font-size:17px;opacity:.9}
.lang-menu button{
  display:flex;align-items:center;gap:10px;padding:12px 14px;border-radius:10px;
  font-size:17px;text-align:left;width:100%
}
.lang-menu button:hover,.lang-menu button.on{background:rgba(var(--tekst-rgb),.1)}
.lang-menu button.on{color:var(--akcent-tekst);font-weight:700}

/* ── Zakładki feedów ─────────────────────────────────────────────────── */
.tabs{
  position:fixed;top:calc(env(safe-area-inset-top) + 58px);left:0;right:0;z-index:29;
  display:flex;gap:6px;justify-content:flex-start;padding:0 12px;pointer-events:none
}
.tabs button{
  /* `nowrap` niezbędny po dołożeniu języka do rzędu: bez niego „Dla Ciebie"
     łamało się na dwa wiersze i rozpychało cały pasek w pionie. */
  pointer-events:auto;white-space:nowrap;flex:0 0 auto;
  padding:7px 13px;border-radius:999px;font-size:13px;font-weight:700;
  color:var(--na-plycie);background:var(--plyta);backdrop-filter:blur(8px);
  text-shadow:0 1px 6px rgba(var(--welon-rgb),.6);transition:background .18s,color .18s
}
.tabs button.on{background:var(--akcent);color:var(--na-akcencie)}

/* Rozwinięcie treści w karcie — „więcej" bez opuszczania feedu. */
.card-actions-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.more-btn{
  display:inline-flex;align-items:center;gap:6px;margin:0;padding:6px 14px;
  border:1px solid rgba(var(--na-welonie-rgb),.3);border-radius:999px;font-size:12px;font-weight:700;
  color:rgba(var(--na-welonie-rgb),.9)
}
.card.open .points li{-webkit-line-clamp:unset}
/* Rozwinięcie „więcej". Prawy margines ZOSTAJE — pasek akcji stoi po prawej
   i tekst wchodzący pod niego jest nieczytelny dokładnie w miejscu, w którym
   czytelnik właśnie poprosił o więcej treści. Zamiast odzyskiwać te 76 px
   wszerz, dajemy tekstowi więcej miejsca w PIONIE: karta rozwija się w górę
   (84dvh zamiast 72), a lead ma dokończyć zdanie, nie zmieścić się w kolumnie. */
.card.open .card-body{max-height:84dvh;overflow-y:auto;padding-right:84px}

.card.open .card-body::-webkit-scrollbar{width:3px}
.card.open .card-body::-webkit-scrollbar-thumb{background:rgba(var(--na-welonie-rgb),.3);border-radius:99px}

/* ── Feed: jedna karta = jeden ekran ─────────────────────────────────── */
.feed{
  height:100dvh;overflow-y:auto;scroll-snap-type:y mandatory;
  scroll-behavior:smooth;-webkit-overflow-scrolling:touch;
}
.feed::-webkit-scrollbar{display:none}
.feed{scrollbar-width:none}

.card{
  position:relative;height:100dvh;scroll-snap-align:start;scroll-snap-stop:always;
  display:flex;flex-direction:column;justify-content:flex-end;overflow:hidden;
}
.card-bg{position:absolute;inset:0;z-index:0;background:var(--karta)}
.card-bg img{width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .5s}
.card-bg img.ready{opacity:1}
/* Gradient jest warunkiem czytelności tekstu na dowolnym zdjęciu. */
.card-bg::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(180deg,rgba(var(--welon-rgb),.55) 0%,rgba(var(--welon-rgb),.1) 32%,rgba(var(--welon-rgb),.72) 68%,rgba(var(--welon-rgb),.94) 100%)
}
/* Bez zdjęcia karta dostaje deterministyczny gradient — nigdy nie jest pusta. */
.card-bg.noimg{background:linear-gradient(150deg,var(--g1,var(--karta)),var(--g2,var(--tlo)))}

.card-body{
  position:relative;z-index:2;
  /* Dolny odstęp przez max(): gdy widać pasek zachęty lokalizacji, JS podaje
     w `--pasek-geo-zapas` zmierzony zapas od dołu ekranu (zmierzPasekGeo)
     i treść — w tym przycisk „Czytaj dalej"/„Obejrzyj" — podnosi się NAD
     pasek; po jego zniknięciu zapas wraca do 0 i wygrywa dotychczasowa
     wartość. Bez tego pasek leżał na przycisku (zmierzone na produkcji). */
  padding:0 84px max(calc(env(safe-area-inset-bottom) + 30px), var(--pasek-geo-zapas, 0px)) 20px;
  max-width:760px;
}
.tags{display:flex;gap:6px;flex-wrap:nowrap;margin-bottom:12px;align-items:center}
.tag{
  font-size:11px;font-weight:700;letter-spacing:.06em;text-transform:uppercase;
  padding:5px 9px;border-radius:999px;background:rgba(var(--na-welonie-rgb),.18);backdrop-filter:blur(6px);
  white-space:nowrap;flex:0 0 auto
}
/* Nazwa wydawcy NIGDY nie jest skracana: „WP Wiadomo…" nie mówi czytelnikowi
   nic, a to właśnie po nazwie rozpoznaje, komu ufa. Miejsce robimy, pokazując
   jeden temat zamiast dwóch — temat da się odzyskać kliknięciem, a uciętej
   nazwy nie da się odgadnąć. */
.tag.src{max-width:none;overflow:visible}
/* Temat ustępuje pierwszy, gdy zabraknie miejsca. */
.tag.temat{overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto}
.tag.src{background:var(--akcent);color:var(--na-akcencie)}

/* ── HASZTAGI AUTORA ────────────────────────────────────────────────────────
   Osobny wiersz pod zajawką, a NIE dosypka do `.tags`: tamten rząd ma
   `flex-wrap:nowrap`, więc każdy dodatkowy element wypychał z niego nazwę
   wydawcy — a to po niej czytelnik rozpoznaje, komu ufa.

   Wygląd celowo LŻEJSZY od pigułki działu: hasztag to słowo autora, nie
   nawigacja po serwisie. Bez wersalików (`#warszawapamięta` w wersalikach
   przestaje być hasztagiem i zaczyna wyglądać jak nagłówek) i bez tła
   w kolorze akcentu, który jest zarezerwowany dla nazwy wydawcy.

   `flex-wrap:wrap` z ograniczeniem wysokości do dwóch wierszy: czterech
   hasztagów nie da się zmieścić w jednym, a trzeci wiersz zaczynałby spychać
   tytuł spod górnej krawędzi karty. */
.hasztagi{display:flex;flex-wrap:wrap;gap:6px;margin:10px 0 0;max-height:56px;overflow:hidden}
.hasztag{
  font-size:12px;font-weight:600;letter-spacing:0;padding:4px 9px;border-radius:999px;
  background:rgba(var(--na-welonie-rgb),.13);color:rgb(var(--na-welonie-rgb));
  border:0;font-family:inherit;cursor:pointer;white-space:nowrap;max-width:100%;
  overflow:hidden;text-overflow:ellipsis
}
.hasztag:hover{background:rgba(var(--na-welonie-rgb),.22)}
/* TYTUŁ TRZYMA SIĘ KAFLA — obcięcie do pięciu wierszy.
   Karta ma sztywną wysokość (`height:100dvh`) i układa treść od dołu
   (`justify-content:flex-end`), więc tytuł bez ograniczenia rośnie W GÓRĘ:
   przy 272-znakowym tytule (id 23262102, „Informator Stolicy") zmierzono
   h2 = 530 px, płytę `.card-body` = 848 px przy karcie 844 px, a sam tytuł
   startował na y=31 px i wchodził 37 px POD pasek brandingu — logo, zakładki
   feedu i pinezka okolicy znikały pod pismem. Zgłoszenie „tytuł wyjeżdża poza
   kafelek" opisuje dokładnie to.
   Obcinamy REGUŁĄ, nie skracaniem tekstu w JS: pełny tytuł zostaje w drzewie
   (czytniki ekranu, zaznaczanie, `share`), a po rozwinięciu „więcej" wraca
   w całości — `.card.open .card-body` ma wtedy własne przewijanie.
   `overflow-wrap:anywhere` jest DRUGĄ, niezależną zaporą: line-clamp liczy
   wiersze, ale pojedyncze bardzo długie słowo (adres, sklejka bez spacji)
   rozpycha kafel W POZIOMIE, zanim w ogóle powstanie drugi wiersz. */
.card h2{
  margin:0 0 10px;font-size:clamp(23px,6.4vw,34px);line-height:1.18;font-weight:800;color:var(--nagl);
  letter-spacing:-.02em;text-shadow:0 2px 14px rgba(var(--welon-rgb),.7);
  overflow-wrap:anywhere;
  display:-webkit-box;-webkit-line-clamp:5;-webkit-box-orient:vertical;overflow:hidden
}
.card.open h2{-webkit-line-clamp:unset}
.card p{
  margin:0 0 16px;font-size:15px;line-height:1.5;color:rgba(var(--na-welonie-rgb),.88);
  text-shadow:0 1px 10px rgba(var(--welon-rgb),.7);
  display:-webkit-box;-webkit-line-clamp:4;-webkit-box-orient:vertical;overflow:hidden
}
/* Trzy punkty skrótu — sedno karty. Większe niż lead, bo to jest treść. */
.points{margin:0 0 16px;padding:0 0 0 18px;list-style:none;display:grid;gap:9px}
.points li{
  position:relative;font-size:15px;line-height:1.45;color:rgba(var(--na-welonie-rgb),.94);
  text-shadow:0 1px 10px rgba(var(--welon-rgb),.75)
}
.points li::before{
  content:"";position:absolute;left:-18px;top:.55em;width:7px;height:7px;
  /* Limonka („60" z logo), nie czerwień akcentu: na slajdzie powitalno-reklamowym
     akcentem marki jest limonka, a magenta gryzła się z żółtym logo tuż obok.
     Ten sam token, którym świecą pin, lupa i „ZALOGUJ SIĘ". */
  border-radius:50%;background:var(--akcent2)
}
.read-sec{
  display:inline-flex;align-items:center;font-weight:700;color:rgb(var(--na-welonie-rgb));
  background:rgba(var(--na-welonie-rgb),.2);border-radius:999px;padding:3px 9px
}
/* Nazwa miejsca obok daty jest PRZYCISKIEM — zawęża feed do tej okolicy, tak
   samo jak klik w temat. Wygląd bez zmian (ta sama pigułka), doszło tylko
   podkreślenie kropkowane: element klikalny, który niczym się nie różni od
   etykiety, jest klikalny tylko dla tego, kto już wie. Wysokość celu dotykowego
   podbita do 32 px — pełne 44 px rozepchnęłoby wiersz metadanych na dwa
   wiersze, a cel stoi w rzędzie osobno stojących pigułek, nie w gęstej liście. */
.region-tag{
  display:inline-flex;align-items:center;gap:4px;min-height:32px;
  border:1px solid rgba(var(--na-welonie-rgb),.28);
  border-radius:999px;padding:3px 9px;color:rgba(var(--na-welonie-rgb),.85);
  background:none;font:inherit;font-size:inherit;cursor:pointer;
  text-decoration:underline dotted;text-underline-offset:3px
}
/* Oznaczenie karty spoza okna świeżości. Świadomie BEZ własnego koloru z palety
   ostrzeżeń: to nie jest błąd ani alarm, tylko informacja „w Twojej okolicy nie
   było dziś nic nowego". Kolory biorą się ze skórki (welon/na-welonie), więc
   oznaczenie zostaje czytelne w każdej z nich. */
.starszy-tag{
  display:inline-flex;align-items:center;font-weight:700;text-transform:lowercase;
  border:1px dashed rgba(var(--na-welonie-rgb),.45);border-radius:999px;padding:3px 9px;
  color:rgba(var(--na-welonie-rgb),.78)
}
.meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;font-size:12px;color:rgba(var(--na-welonie-rgb),.62);margin-bottom:16px}
/* Plakietka terminu wydarzenia — staje ZAMIAST daty publikacji („za 8 miesięcy",
   „trwa do 13 grudnia"). Kolor „60" z logo (`--akcent2`): to wskazówka „kiedy
   to się dzieje", nie alarm, a token ma kontrast na welonie skalibrowany
   w każdej skórce (pomiar „Logo nad zdjęciem" w skorka.js). */
.wydarzenie-plakietka{
  display:inline-flex;align-items:center;font-weight:700;
  border:1px solid rgba(var(--na-welonie-rgb),.28);border-radius:999px;padding:3px 9px;
  color:var(--akcent2)
}
.trans-note{
  display:inline-flex;align-items:center;gap:5px;font-size:11px;color:rgba(var(--na-welonie-rgb),.55);
  border:1px solid rgba(var(--na-welonie-rgb),.2);border-radius:999px;padding:3px 9px
}
/* „CZYTAJ DALEJ" W BARWIE MARKI (decyzja operatora 2026-08-08).
   Wcześniej brał kolor z pary welonu — czyli biel na ciemnym zdjęciu. Biały
   przycisk jest neutralny i ginie wśród innych białych elementów karty (tytuł,
   ikony akcji); limonka wskazuje JEDNO działanie, po które czytelnik tu przyszedł.

   TOKENEM, nie wartością: w instancji ukraińskiej ten sam przycisk stanie się
   złoty, bo `--akcent2` niesie tam barwę tamtej marki. Wpisana limonka
   wymagałaby drugiej reguły i rozdzieliłaby obie wersje. */
.read{
  display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:0 22px;border-radius:999px;
  background:var(--akcent2);color:var(--na-akcencie2);font-weight:800;font-size:14px;white-space:nowrap;text-decoration:none
}
/* Bez jawnego rozmiaru SVG dziedziczy wysokość wiersza i rozpycha przycisk. */
.read svg{width:16px;height:16px;flex:none}
.read:active{transform:scale(.97)}

/* ── Kolumna akcji (kciuk prawej dłoni) ──────────────────────────────── */
.actions{
  position:absolute;right:10px;bottom:calc(env(safe-area-inset-bottom) + 30px);z-index:3;
  display:flex;flex-direction:column;gap:18px;align-items:center
}
.act{display:flex;flex-direction:column;align-items:center;gap:4px}
.act-ic{
  width:48px;height:48px;border-radius:50%;display:grid;place-items:center;
  background:rgba(var(--na-welonie-rgb),.14);backdrop-filter:blur(8px);transition:transform .18s,background .18s
}
.act-ic svg{width:24px;height:24px}
.act:active .act-ic{transform:scale(.9)}
.act.on .act-ic{background:var(--akcent);color:var(--na-akcencie)}
.act.on.save .act-ic{background:var(--zapis);color:var(--na-zapisie)}
/* Licznik REZERWUJE miejsce, nawet gdy jest pusty. Zero nie jest rysowane
   (napis „0" pod sercem zniechęca do materiału), ale bez tej rezerwacji pusty
   element miał wysokość 0 i pojawienie się pierwszej cyfry przesuwało cały
   słupek akcji — serce i zakładka drgały w chwili polubienia, czyli dokładnie
   wtedy, gdy czytelnik na nie patrzy. `em` zamiast pikseli, bo skórka „jasna"
   powiększa ten tekst i sztywna wartość znów by się rozjechała. */
.act-n{font-size:11px;font-weight:700;color:rgba(var(--na-welonie-rgb),.85);
  line-height:1.2;min-height:1.2em}

/* ── Stany: ładowanie, błąd, podpowiedź, powiadomienie ───────────────── */
.loader{position:fixed;inset:auto 0 24px;display:flex;justify-content:center;z-index:20}
.spin{width:26px;height:26px;border:3px solid rgba(var(--na-welonie-rgb),.25);border-top-color:rgb(var(--na-welonie-rgb));border-radius:50%;animation:sp .8s linear infinite}
@keyframes sp{to{transform:rotate(360deg)}}

.msg{position:fixed;inset:0;z-index:50;display:grid;place-content:center;gap:16px;justify-items:center;padding:32px;text-align:center;background:var(--tlo)}
.msg p{margin:0;font-size:16px;color:var(--przygas);max-width:34ch}
.btn{height:44px;padding:0 24px;border-radius:999px;background:var(--akcent);color:var(--na-akcencie);font-weight:700}

.hint{
  /* JEDEN RZĄD tuż nad dolną krawędzią, nie kolumna na 22 px: pionowy układ
     (strzałka + napis, ~45 px) wchodził dokładnie w dolny przycisk karty
     („Czytaj dalej" siedzi ~30 px od dołu) i przycisk go zasłaniał. Rząd ma
     ~20 px wysokości i mieści się POD przyciskiem. Kolor tokenem `--akcent2`
     („60" w logo) zamiast półprzezroczystej bieli — podpowiedź ginęła na
     jasnych zdjęciach; wartości tokenu per skórka są już skalibrowane. */
  position:fixed;left:50%;bottom:calc(env(safe-area-inset-bottom) + 6px);transform:translateX(-50%);
  z-index:15;display:flex;flex-direction:row;align-items:center;gap:6px;
  font-size:12px;font-weight:700;color:var(--akcent2);animation:bob 1.9s ease-in-out infinite;pointer-events:none
}
.hint svg{width:18px;height:18px}
@keyframes bob{0%,100%{transform:translate(-50%,0)}50%{transform:translate(-50%,-8px)}}

/* BEZ `white-space:nowrap` i ZAWSZE w granicach ekranu. Dymek był pigułką w jednej
   linii, wyśrodkowaną przez translateX(-50%) — krótkie „Zapisano" mieściło się, ale
   instrukcja w rodzaju „Ustawienia → Safari → Lokalizacja → Zapytaj" rozjeżdżała się
   poza OBA brzegi telefonu i nie dało się jej doczytać. Tekst ma się łamać, a nie
   rozpychać: stąd `max-width` w jednostkach ekranu i zawijanie. */
.toast{
  position:fixed;left:50%;bottom:calc(env(safe-area-inset-bottom) + 90px);transform:translateX(-50%);
  /* Powyżej arkusza dolnego (z-index 120). Dymek potwierdza akcję wykonaną
     WEWNĄTRZ arkusza („Link skopiowany"), więc schowany pod nim nie istnieje
     dla użytkownika — komunikat się ustawiał, tylko nikt go nie widział. */
  z-index:130;background:var(--karta);color:var(--tekst);border:1px solid var(--kreska);
  padding:11px 18px;border-radius:16px;font-size:13px;line-height:1.4;text-align:center;
  max-width:min(92vw,430px);white-space:normal;overflow-wrap:anywhere;
  box-shadow:0 12px 30px rgba(0,0,0,.5)
}

/* Na szerokim ekranie feed dostaje format telefonu — treść jest pionowa. */
@media (min-width:820px){
  /* JEDNO ŹRÓDŁO PRAWDY o szerokości kolumny. Wartość była wpisana z palca
     przy `.feed` i przy `.top`, a każdy kolejny element `position:fixed`
     dopisywał ją trzeci i czwarty raz — pierwsza rozjechana kopia byłaby
     niewidoczna do zrzutu z produkcji. */
  :root{--kolumna:460px}
  body{background:var(--poza)}
  .feed{max-width:var(--kolumna);margin:0 auto;box-shadow:0 0 80px rgba(0,0,0,.9)}
  .top{max-width:var(--kolumna);left:50%;transform:translateX(-50%)}

  /* ── Elementy `fixed` wracają do kolumny ─────────────────────────────────
     ZGŁOSZENIE ZE ZRZUTU: pigułka okolicy i dopisek „nic nowego z Twojej
     okolicy" ciągnęły się przez CAŁY ekran (zmierzone: 1440 px przy kolumnie
     460 px), bo `position:fixed` liczy `left/right` od okna, a nie od feedu.
     Wyglądało to jak pasek innej strony doklejony nad treścią.

     Zamiast `translateX(-50%)` — jak przy `.top` — dosuwamy same `left`/`right`
     do krawędzi kolumny. Powód: część tych elementów ma własne animacje
     operujące na `transform` (`bob` przy podpowiedzi gestu, `szuflada` przy
     menu języka). Wyśrodkowanie schowane w `transform` znika na czas animacji
     albo trzeba je powtarzać w każdej klatce — a `left`/`right` są od
     `transform` niezależne i nic nie mają do zepsucia.

     Poniżej progu NIC się nie zmienia: tam kolumna = ekran, więc pasek
     rozciągnięty od krawędzi do krawędzi jest poprawny.

     PRZEDROSTEK `body ` NIE JEST OZDOBNIKIEM. Reguły bazowe połowy tych
     elementów (`.pasek-okolica`, `.pasek-geo`, `.pozycja`, chipy filtru) stoją
     w tym pliku NIŻEJ niż to zapytanie medialne, a przy równej wadze wygrywa
     reguła późniejsza — bez podbicia wagi poprawka byłaby martwa dokładnie tak,
     jak martwe było powiększenie pisma w szufladzie (patrz komentarz przy
     `.lang-menu hr`). Waga, nie kolejność linijek, trzyma ten blok przy życiu. */
  body .tabs,
  body .pasek-okolica,
  body .loader{left:calc(50% - var(--kolumna) / 2);right:calc(50% - var(--kolumna) / 2)}
  /* Pasek zachęty do lokalizacji trzyma swoje 12 px luzu — tyle że od
     krawędzi KOLUMNY, nie od krawędzi monitora (było: 1416 px szerokości). */
  body .pasek-geo{left:calc(50% - var(--kolumna) / 2 + 12px);right:calc(50% - var(--kolumna) / 2 + 12px)}
  /* Wskaźnik pozycji siedział przyklejony do prawej krawędzi okna, ~480 px od
     materiału, którego numer pokazuje. Ten sam odstęp 10 px, od kolumny. */
  body .pozycja{right:calc(50% - var(--kolumna) / 2 + 10px)}
  /* Szuflada języka wjeżdżała od lewej krawędzi MONITORA. Animacja `szuflada`
     używa `translateX`, więc ruszamy wyłącznie `left` — start i koniec przejazdu
     zostają nienaruszone. */
  body .lang-menu{left:calc(50% - var(--kolumna) / 2)}
  /* Rząd chipów filtru jest już wyśrodkowany (`left:50%` + `translateX(-50%)`),
     ale przy kilku wybranych tematach mógł urosnąć do szerokości okna. Sufit
     przycięty do kolumny; `transform` zostaje jego. Selektor musi być cięższy
     od `body > .pasek-filtru` niżej w pliku — stąd `html`. */
  html body > .pasek-filtru{max-width:calc(var(--kolumna) - 24px)}
}
@media (prefers-reduced-motion:reduce){
  .feed{scroll-behavior:auto}
  .hint{animation:none}
  .card-bg img{transition:none}
}


.lang-menu hr{border:0;border-top:1px solid var(--kreska);margin:6px 0}
/* Druga, PÓŹNIEJSZA deklaracja rozmiaru pozycji menu (13 px) USUNIĘTA. Miała tę
   samą wagę co ta przy `.lang-menu button` wyżej, więc wygrywała samym
   położeniem w pliku — i to ona rządziła wyglądem. Powiększenie pisma zrobione
   „u źródła" nie dawało żadnego skutku (zmierzone: 13 px mimo reguły 17 px),
   a rozmiar szuflady zależał od kolejności linijek w arkuszu. */

/* Kod przeniesienia historii — duży, jednoznaczny, łatwy do przepisania. */
/* ── Arkusz dolny (okno dialogowe) ─────────────────────────────────────────
   PRZYCZYNA PRZEBUDOWY: te okna miały klasę `.consent`, ale ta klasa została
   przejęta przez PEŁNOEKRANOWĄ kartę zgody w feedzie. Reguły bazowej dla
   okna nie było wcale — więc panel logowania renderował się jako goły <div>
   doklejony do <body>: bez tła, bez marginesów, bez zaokrągleń, treść od
   krawędzi do krawędzi, nachodząca na kartę pod spodem.

   Arkusz wjeżdża od dołu, bo tam sięga kciuk. Zasłona pod spodem odcina go
   od feedu — bez niej nie było widać, gdzie kończy się okno, a zaczyna
   materiał. */
.arkusz-zaslona{position:fixed;inset:0;z-index:120;background:rgba(0,0,0,.62);
  backdrop-filter:blur(2px);display:flex;align-items:flex-end;justify-content:center}
.arkusz{width:min(520px,100%);max-height:88vh;overflow-y:auto;box-sizing:border-box;
  background:var(--karta);color:var(--tekst);
  border:1px solid var(--kreska);border-bottom:0;
  border-radius:var(--rad) var(--rad) 0 0;
  padding:22px 20px calc(env(safe-area-inset-bottom) + 22px);
  box-shadow:0 -18px 48px rgba(0,0,0,.5);
  animation:arkusz-wjazd .22s ease-out}
@keyframes arkusz-wjazd{from{transform:translateY(14px);opacity:.6}to{transform:none;opacity:1}}
/* Uchwyt: sygnał „to się zamyka gestem", ten sam, co w natywnych arkuszach. */
.arkusz::before{content:"";display:block;width:38px;height:4px;border-radius:99px;
  background:var(--kreska);margin:-6px auto 16px}
/* ── Dlaczego nagłówki arkuszy są rozpisane na osobne własności ────────────
   Stało tu `font:800 19px/1.25 inherit`. Taki zapis jest NIEWAŻNY: `inherit`
   to słowo kluczowe całej deklaracji, a nie nazwa rodziny pisma, więc nie ma
   prawa stać w środku skrótu. Przeglądarka nie poprawia takiego zapisu — po
   cichu wyrzuca CAŁĄ deklarację, bez śladu w konsoli. Nagłówki arkuszy
   dostawały więc przez cały czas wartości domyślne przeglądarki dla <h2>
   (24 px, waga 700), a nie zamierzone 19 px w wadze 800. Wyglądało to na
   działający arkusz, bo domyślny <h2> też jest duży i pogrubiony — tyle że
   wypadał z rytmu reszty panelu (akapit ma 14 px).
   Rodziny pisma tu nie ustawiamy: nagłówek dziedziczy ją po <body> sam
   z siebie, a `font-family:inherit` byłoby pustym zapisem. */
.arkusz h2{margin:0 0 6px;font-weight:800;font-size:19px;line-height:1.25;color:var(--nagl)}
.arkusz p{margin:0 0 14px;font-size:14px;line-height:1.5;opacity:.88}
/* Klawiatura ekranowa zabiera dolną połowę telefonu. Wtedy wyjaśnienie ustępuje
   polom — bo pola bez wyjaśnienia da się wypełnić, a wyjaśnienie bez pól jest
   bezużyteczne. Klasę zdejmuje się razem z klawiaturą; pełne uzasadnienie stoi
   przy `pilnujKlawiatury` w app.js. Wysokość arkusza i przyklejenie zasłony do
   WIDOCZNEGO obszaru (nie do okna) ustawia tamten kod stylem bezpośrednim:
   `visualViewport` jest jedynym źródłem tej miary, a CSS go nie widzi. */
.arkusz.klawiatura .arkusz-opis{display:none}

/* Pole zwykłe — NIE styl kodu transferu. Wcześniej numer telefonu i hasło
   dziedziczyły `.kod-input`: monospace, wersaliki i rozstrzelenie 0,1em,
   przez co podpowiedź wyglądała jak „N U M E R  T E L E F O N U". */
.arkusz .pole{font:inherit;font-size:16px;width:100%;box-sizing:border-box;
  min-height:48px;padding:12px 14px;margin:0 0 10px;border-radius:12px;
  border:1px solid var(--kreska);
  background:var(--powierzchnia);color:inherit}
.arkusz .pole::placeholder{opacity:.55;letter-spacing:normal;text-transform:none}
.arkusz .pole:focus{outline:2px solid var(--akcent);outline-offset:1px}

.consent .kod,.arkusz .kod{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:30px;
  font-weight:700;letter-spacing:.12em;text-align:center;padding:14px 0;user-select:all}
.consent .kod-input,.arkusz .kod-input{font:inherit;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  font-size:22px;letter-spacing:.1em;text-align:center;text-transform:uppercase;
  padding:11px;border-radius:9px;border:1px solid var(--kreska);
  background:var(--powierzchnia);color:var(--tekst);width:100%}
.consent .kod-info,.arkusz .kod-info{font-size:12px;min-height:16px;margin:2px 0 0;opacity:.8}

/* ── Karta zgody: element feedu, nie pasek ────────────────────────────────
   Dziedziczy .card (pełny ekran, scroll-snap), więc odpowiada się na nią tym
   samym gestem co na materiał. Różni się tylko tym, co musi: brak zdjęcia,
   treść wyżej (jest jej więcej) i przyciski w potoku, a nie w rogu. */
.consent-card .card-body{
  padding:0 20px calc(env(safe-area-inset-bottom) + 30px) 20px;
  justify-content:flex-end;
}
.consent-card h2{margin-bottom:10px}
.consent-card .points li{-webkit-line-clamp:unset;font-size:14px;opacity:.92}
.consent-opts{display:flex;flex-direction:column;gap:11px;margin:16px 0 4px}
.consent-opt{display:flex;gap:11px;align-items:flex-start;cursor:pointer}
.consent-opt input{margin-top:2px;flex:0 0 auto;width:18px;height:18px;accent-color:var(--akcent)}
.consent-opt input:disabled{opacity:.45;cursor:default}
.consent-opt b{display:block;font-size:14px;font-weight:600}
.consent-opt span{display:block;font-size:12px;opacity:.65;line-height:1.35}
.consent-row,.arkusz-row{display:flex;gap:8px;flex-wrap:wrap;margin-top:16px}
/* `min-height:44px` — kanon celu dotykowego. Zmierzone: „Anuluj" i „Zaloguj
   się" miały 38 px (14 px pisma + 2×11 px odstępu), czyli o 6 px za mało,
   i to przy otwartej klawiaturze, gdy pomyłka kosztuje najwięcej. */
.consent-row button,.arkusz-row button{font:inherit;font-size:14px;font-weight:600;padding:11px 16px;border:0;
  min-height:44px;
  border-radius:10px;cursor:pointer;background:rgba(var(--tekst-rgb),.16);color:var(--tekst);flex:1 1 auto}
.consent-row .consent-yes,.arkusz-row .consent-yes{background:var(--akcent);color:var(--na-akcencie);flex-basis:100%;order:-1}
.consent-foot{font-size:11.5px;opacity:.55;margin:14px 0 0;line-height:1.4}
/* Podpowiedź przewijania jest na karcie zgody myląca — tu się odpowiada. */
.consent-card ~ .hint{display:none}

/* ── Karta zgody: interfejs sprowadzony do logo ───────────────────────────
   Dopóki nie ma decyzji, zakładki feedów i „zapisane" znikają, a feedu nie
   da się przewinąć. Powód jest prosty: pytanie, które można ominąć gestem,
   nie jest pytaniem — a zakładki prowadziłyby do widoków, których i tak
   jeszcze nie wolno personalizować. Zostaje logo i trzy przyciski. */
/* Ekran reklamy: zostaje samo logo w pasku, jak na ekranie zgody.
   Chowamy REGUŁĄ, nie usuwaniem węzłów — zakładki i lupa muszą wrócić
   w tym samym stanie, gdy czytelnik przewinie dalej. */
.na-reklamie .tabs,
.na-reklamie .szukaj-pin{display:none !important}
/* ── CO NA REKLAMIE ZOSTAJE, I DLACZEGO ────────────────────────────────────
   Reguła wyżej ma obejmować NAWIGACJĘ (zakładki feedu, lupa) i nic więcej.
   Pasek okolicy, pasek wybranych tematów i pinezka to WSKAŹNIKI STANU —
   mówią, co jest ustawione, a nie dokąd można pójść. Migotanie tej informacji
   co kilka kart wygląda na awarię i odbiera jedyną wskazówkę, skąd biorą się
   materiały; było to zresztą sedno zgłoszenia o „skaczącej lokalizacji".

   Zapis jest JAWNY, choć w chwili pisania żadna reguła ich nie chowała
   (zmierzone: przy klasie `na-reklamie` pasek ma `display:flex`, pin też,
   znikają tylko `.tabs` i `.szukaj-btn`). Stoi tu jako zabezpieczenie: gdyby
   ktoś kiedyś dopisał do reguły wyżej kolejny selektor „żeby na reklamie było
   czysto", te trzy elementy mają się obronić same. */
.na-reklamie #pasek-okolica,
.na-reklamie .pasek-filtru{display:flex !important}
/* Pinezka i „#" to WSKAŹNIKI STANU — zostają. Lupa jest nawigacją i znika
   (reguła wyżej). Selektory po identyfikatorze i klasie własnej, nie po
   wspólnej `.okolica-pin`: ta obejmuje dziś także lupę, więc odsłoniłaby
   z powrotem to, co reguła wyżej chowa. */
.na-reklamie #okolica-pin,
.na-reklamie .tematy-pin{display:flex !important}

.czeka-na-zgode .tabs,
.czeka-na-zgode .top-right,
.czeka-na-zgode .top-akcje,
.czeka-na-zgode .hint,
.czeka-na-zgode .loader{display:none !important}
.czeka-na-zgode .feed{overflow:hidden;scroll-snap-type:none}
.czeka-na-zgode .card:not(.consent-card){display:none}

/* Znak wodny w tle karty zgody — karta ma czytać się jak materiał. */
.consent-znak{
  position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:clamp(56px,19vw,104px);letter-spacing:-.04em;
  color:rgba(var(--na-welonie-rgb),.05);user-select:none;pointer-events:none;
  /* Znak siedzi w PUSTEJ górnej części karty, nie za tekstem. Przebijający
     przez akapit wygląda jak defekt renderowania, a nie jak tło. */
  align-items:flex-start;padding-top:18vh;
}
.consent-znak .akcent{color:rgba(var(--akcent-rgb),.13)}

/* Lead pokazywany zamiast punktów (skrót jeszcze się liczy) — obcięty do
   czterech wierszy, żeby karta nie rozjechała się na materiale z długim
   wstępem. Rozwinięcie „więcej" zdejmuje obcięcie zamiast dokładać drugą
   kopię tego samego tekstu. */
.card-body > p:not(.full-lead){
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:4;overflow:hidden
}
.card.open .card-body > p:not(.full-lead){-webkit-line-clamp:unset}

/* ── Język w rzędzie filtrów ──────────────────────────────────────────────
   Wybór języka to filtr treści, nie ustawienie aplikacji — stoi więc obok
   „Główne / Dla Ciebie / Śledzone", a nie w pasku brandingu. Odsunięty
   `margin-left:auto`, żeby wzrok nie mylił go z czwartą zakładką. */
.tabs .lang-btn{margin-left:auto;flex:0 0 auto;padding-left:11px;padding-right:11px}
/* Na wąskich ekranach oddajemy piksele z odstępów, nie z czytelności etykiet. */
@media (max-width:400px){
  .tabs{gap:4px;padding:0 8px}
  .tabs button{padding:7px 10px;font-size:12.5px}
}
/* Najwęższe telefony (320 px): język zostaje samą flagą — kod „PL" jest
   redundantny obok niej, a to jedyne miejsce, w którym rząd nie mieści się
   w szerokości ekranu. */
@media (max-width:340px){
  .tabs .lang-btn #lang-code{display:none}
  .tabs button{padding:7px 9px;font-size:12px}
}
/* Górny pasek to już wyłącznie logo. */
.top{justify-content:flex-start}

/* ── Profil redakcji ──────────────────────────────────────────────────────
   Jeden ekran: kim jest ta redakcja, jeden przycisk decyzji i próbka tego,
   co wydaje. Profil ma odpowiedzieć na pytanie „obserwować czy nie", a nie
   zastępować feedu. */
/* Profil zaczyna się U GÓRY. `.card` dociska treść do dołu (feed tak ma działać),
   ale profil to nie karta materiału — przy krótkim opisie zostawiało to ~40%
   pustego ekranu nad logotypem, a siatka materiałów lądowała pod krawędzią. */
.card.profil{height:100dvh;justify-content:flex-start}
.profil-body{padding:calc(env(safe-area-inset-top) + 66px) 20px calc(env(safe-area-inset-bottom) + 24px);
  justify-content:flex-start;display:flex;flex-direction:column;gap:14px;overflow-y:auto}
.profil-wroc{align-self:flex-start;background:rgba(var(--na-welonie-rgb),.14);color:rgb(var(--na-welonie-rgb));border:0;
  border-radius:999px;padding:7px 14px;font:inherit;font-size:13px;font-weight:600;cursor:pointer}
/* Nagłówek wyśrodkowany: logotyp, nazwa, metryki i zdanie o redakcji tworzą
   jedną kolumnę nad przyciskiem „Obserwuj”. Układ w rzędzie (logo z lewej,
   tekst z prawej) rozjeżdżał się przy długich nazwach i zostawiał przycisk
   samotnie na pełnej szerokości, bez związku z tym, co jest nad nim. */
.profil-glowa{display:flex;flex-direction:column;gap:10px;align-items:center;text-align:center}
.profil-logo{flex:0 0 auto;width:66px;height:66px;border-radius:18px;overflow:hidden;
  background:rgba(var(--na-welonie-rgb),.12);display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:24px;letter-spacing:-.02em;color:rgb(var(--na-welonie-rgb))}
.profil-logo img{width:100%;height:100%;object-fit:cover}
.profil-opis{min-width:0;display:flex;flex-direction:column;align-items:center;gap:6px}
.profil-opis h2{margin:0;font-size:23px;line-height:1.15}
.profil-meta{display:flex;gap:8px;flex-wrap:wrap;font-size:12px;opacity:.75;align-items:center;justify-content:center}
.profil-zdanie{margin:2px 0 0;font-size:13.5px;line-height:1.45;opacity:.85;max-width:34ch}
.profil-obs{background:var(--akcent);color:var(--na-akcencie);border:0;border-radius:12px;padding:12px;
  font:inherit;font-size:15px;font-weight:700;cursor:pointer;width:100%}
.profil-obs.on{background:rgba(var(--na-welonie-rgb),.16);color:rgb(var(--na-welonie-rgb))}
/* „Udostępnij" pod „Obserwuj”: druga akcja profilu, więc wygląd drugorzędny —
   sama ramka, bez wypełnienia. Obserwowanie zmienia feed czytelnika,
   udostępnienie dotyczy kogoś innego; równe wypełnienia mówiłyby, że to dwie
   tak samo ważne decyzje. Ikona ta sama co na karcie materiału. */
.profil-udostepnij{display:flex;align-items:center;justify-content:center;gap:8px;
  width:100%;margin-top:8px;padding:11px;min-height:44px;border-radius:12px;
  border:1px solid rgba(var(--na-welonie-rgb),.28);background:none;
  color:rgb(var(--na-welonie-rgb));font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.profil-udostepnij svg{width:17px;height:17px;flex:0 0 auto}
/* Siatka 3×2 — sześć kafli, z których CO NAJWYŻEJ jeden jest promocyjny
   (reguła układu: src/siatka.ts). Pusty katalog = kafel dostaje materiał. */
.profil-siatka{display:grid;grid-template-columns:repeat(3,1fr);gap:7px}
.kafel{position:relative;aspect-ratio:9/13;border-radius:11px;overflow:hidden;display:block;
  background:rgba(var(--na-welonie-rgb),.07);text-decoration:none;color:rgb(var(--na-welonie-rgb))}
.kafel img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:.72}
.kafel-tyt{position:absolute;left:0;right:0;bottom:0;padding:20px 7px 7px;font-size:10.5px;
  line-height:1.25;font-weight:600;background:linear-gradient(180deg,transparent,rgba(var(--welon-rgb),.9));
  /* `max-height` obok obcięcia do trzech wierszy: sam `-webkit-line-clamp`
     na elemencie pozycjonowanym absolutnie nie ogranicza wysokości pudełka,
     więc czwarty wiersz wychodził POZA kafelek i nachodził na następny. */
  display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;overflow:hidden;
  max-height:calc(3 * 1.25em + 27px);box-sizing:border-box}
.kafel.pusty{opacity:.35}
/* Reguły `.kafel.reklama` (przerywana ramka wokół planszy „Miejsce na treść
   własną") ZNIKNĘŁY razem z atrapą. Kafel bez kreacji nie jest już pustym
   miejscem reklamowym — dostaje materiał, a oznaczenie promocyjne rysuje
   `.kafel-promocja` niżej. */
button.tag.src{border:0;font:inherit;cursor:pointer}

/* ── Ikona profilu i wyśrodkowane filtry ──────────────────────────────────
   Konto i język to sprawy CZYTELNIKA, więc siedzą pod jedną ikoną w pasku
   brandingu. Rząd filtrów wraca do wyśrodkowania — dotyczy wyłącznie treści. */
.top{display:flex;align-items:center;gap:10px}
.profil-btn{pointer-events:auto;width:36px;height:36px;flex:0 0 auto;border:0;border-radius:999px;
  background:var(--plyta);backdrop-filter:blur(8px);color:var(--na-plycie);cursor:pointer;
  display:flex;align-items:center;justify-content:center;padding:0}
.profil-btn svg{width:20px;height:20px}
.tabs{justify-content:center}
/* Reguły `.szukaj-btn` USUNIĘTE razem z przeniesieniem lupy do górnego paska:
   ustawiały ją bezwzględnie w rzędzie zakładek, którego już nie zajmuje.
   Wygląd bierze teraz ze wspólnej klasy `.okolica-pin` — jeden przycisk
   ikonowy, trzy zastosowania. */
/* NAZWA ZALOGOWANEGO CZYTELNIKA (decyzja operatora 2026-08-08).
   Wcześniej 12 px przy 60% krycia — czyli podpis techniczny nad przyciskami,
   nie nazwa człowieka. Teraz ten sam stopień pisma co pozycje menu (17 px),
   pogrubiona i w kolorze „60" z logo. To NIE jest przycisk i nie ma nim
   wyglądać: kolor bierze na siebie rolę wyróżnienia, a brak `text-transform`
   odróżnia nazwę od „ZALOGUJ SIĘ" niżej — czyjegoś nicka nie wersalikujemy.
   `--akcent2` jako kolor tekstu jest tu bezpieczny na obu skórkach: na jasnej
   token jest ciemną oliwką (zmierzone 8,68 przy „ZALOGUJ SIĘ", ten sam ton). */
.menu-naglowek{font-size:17px;font-weight:800;color:var(--akcent2);opacity:1;
  padding:8px 10px 4px;line-height:1.25;word-break:break-word}
.menu-konto{display:grid;gap:2px}
/* WYLOGOWANIE — na samym dole szuflady, w limonce.
   Odstęp górny oddziela je od listy poleceń: to nie jest kolejna pozycja menu,
   tylko wyjście. Kreska nad nim byłaby trzecią kreską w tym menu i zlałaby się
   z podziałem przed językiem. */
.menu-wyloguj{display:grid;gap:2px;margin-top:10px}
.lang-menu .menu-wyloguj-btn{color:var(--akcent2);opacity:1;font-weight:700}
/* Cel dotykowy 44 px (kanon floty). Zmierzone przed poprawką: pozycje menu
   miały 39 px — mieściły się w oku, ale nie w kciuku. */
.lang-menu .menu-link,.lang-menu select{min-height:44px}
/* Jedyna pozycja menu, która czytelnikowi coś DAJE, a nie tylko przestawia.
   Wersaliki przez `text-transform`, nie w treści: czytnik ekranu ma przeczytać
   „Zaloguj się", a nie literować. */
/* „ZALOGUJ SIĘ" w kolorze „60" z logo (`--akcent2`), nie w czerwieni akcentu:
   czerwień jest w tej aplikacji kolorem AKCJI (aktywna zakładka, pigułka
   źródła), więc jedyna pozycja menu, która czytelnikowi coś DAJE, ginęła wśród
   nich. Token, nie wartość z palca — bo w skórce jasnej limonka na bieli ma
   1,15, a `--akcent2` jest tam ciemną oliwką i daje 8,68 (zmierzone we
   wszystkich czterech skórkach na tle szuflady, czyli na `--karta`).
   Wersaliki przez `text-transform`, nie w treści: czytnik ekranu ma przeczytać
   „Zaloguj się", a nie literować. */
.lang-menu .menu-zaloguj{font-weight:800;text-transform:uppercase;letter-spacing:.04em;
  color:var(--akcent2);opacity:1}
/* Etykieta ukryta WZROKOWO, wciąż obecna dla czytnika ekranu. Bez tego lista
   wyboru języka jest dla niego „lista wyboru" i nic więcej. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}

/* ── Pinezka okolicy w górnym pasku ────────────────────────────────────────
   Prawa strona paska, naprzeciwko ikony konta. 44 px celu dotykowego przy
   36 px rysunku — pole dotyku rozszerzamy paddingiem, żeby nie rozpychać
   optycznie paska; ikona zostaje tej samej wielkości co ikona konta. */
/* Trzy ikony w jednym rzędzie po prawej: „#", lupa, pinezka. Wspólna klasa,
   bo to jeden wzorzec — okrągły przycisk 44 px na płycie, ikona 20 px. */
.top-akcje{display:flex;align-items:center;gap:6px;margin-left:auto;pointer-events:auto}
.okolica-pin{pointer-events:auto;position:relative;flex:0 0 auto;
  width:44px;height:44px;padding:4px;border:0;background:none;cursor:pointer;
  display:flex;align-items:center;justify-content:center}
/* PŁYTKA NIEPRZEZROCZYSTA (`--karta`), nie półprzezroczysta `--plyta`. Ta
   druga jest 42-procentową czernią NA ZDJĘCIU materiału — pod jasnym kadrem
   kontrast ikony spada do 2,6 (zmierzone), czyli poniżej progu dokładnie tam,
   gdzie ikona jest potrzebna. Tę samą decyzję podjęto wcześniej dla pigułki
   okolicy, z tego samego powodu. Na własnej płytce kolor „60" ma od 8 do 16
   w każdej skórce, niezależnie od zdjęcia pod spodem. */
.okolica-pin::before{content:"";position:absolute;width:36px;height:36px;border-radius:999px;
  background:var(--karta);border:1px solid var(--kreska);box-shadow:0 6px 18px rgba(0,0,0,.32)}
/* IKONY W KOLORZE „60" Z LOGO (`--akcent2`). To jest ten sam token, którym
   świeci znak marki — a nie wartość wpisana z palca, bo ikona jest KRESKĄ na
   welonie nad zdjęciem materiału i musi się bronić w każdej skórce. Token jest
   już liczony wobec welonu z progiem 4,5 (patrz `ocena` w skorka.js), więc na
   skórce jasnej dostaje ciemną oliwkę zamiast limonki, a na monochromatycznej
   jasną szarość: żółć w skórce „czerń, biel i szarości" byłaby złamaniem
   obietnicy, którą ta skórka składa w swojej nazwie. */
.okolica-pin svg{position:relative;width:20px;height:20px;color:var(--akcent2)}
/* Okolica USTAWIONA — obwódka akcentem WOKÓŁ płytki, a nie przemalowanie
   ikony: kolor kreski jest teraz barwą marki i ma nią zostać (o to prosił
   operator). Stan ma zresztą wyraz słowny — nazwa okolicy stoi w pasku pod
   zakładkami — więc obwódka jest wzmocnieniem, nie jedynym sygnałem. */
.okolica-pin.ustawiona::before{box-shadow:0 0 0 2px var(--akcent),0 6px 18px rgba(0,0,0,.32)}

/* ── PINEZKA NIESIE STAN LOKALIZACJI ───────────────────────────────────────
   Prośba operatora: „szara = lokalizacja niedostępna albo zablokowana, żółta
   = dostępna i działa — żeby użytkownik wiedział, że przeglądarka obsługuje
   lokalizację i na pewno jest odczytywana".

   Różnicę robi WYPEŁNIENIE, nie sam odcień: pinezka pusta (kreska) to stan
   neutralny, pinezka pełna to „zgoda jest i pozycja się czyta". Dwa odcienie
   żółci obok siebie byłyby nie do rozróżnienia na słońcu, a wypełnienie widać
   kątem oka. Kolory wyłącznie tokenami — `--akcent2` to ten sam token, którym
   świeci „60" w logo, więc w skórce jasnej zrobi się z niego ciemna oliwka,
   a w monochromatycznej jasna szarość, i obietnica żadnej skórki nie zostaje
   złamana. Wielkość celu dotykowego (44 px) nie zmienia się w żadnym stanie:
   ruszamy kolorem i wypełnieniem, nigdy geometrią.

   TRZY STANY, NIE DWA. Brak stanu („nie pytaliśmy") ma wyglądać inaczej niż
   „zablokowana" — inaczej aplikacja zgadywałaby za przeglądarkę, która
   w części przypadków stanu zgody po prostu nie podaje. */
#okolica-pin.geo-dziala svg{fill:var(--akcent2);color:var(--akcent2)}
/* WYGASZONA, nie czerwona: to nie jest błąd czytelnika ani awaria — to stan,
   w którym po prostu idzie się drugą drogą (wybór miasta). Kolor tekstu
   drugorzędnego, ten sam, którym opisane są rzeczy nieaktywne. */
#okolica-pin.geo-brak svg{color:var(--przygas);opacity:.8}
/* Trwa ustalanie pozycji. Puls, a nie kręcące się kółko: kółko w nagłówku
   czyta się jak „ładuje się cała aplikacja", a chodzi o jedną, konkretną
   rzecz — i o tę samą, o której mówi napis „Szukam Twojej okolicy…" pod
   zakładkami. */
#okolica-pin.geo-szuka svg{animation:pin-puls 1.15s ease-in-out infinite}
@keyframes pin-puls{0%,100%{opacity:1}50%{opacity:.4}}
@media (prefers-reduced-motion:reduce){
  #okolica-pin.geo-szuka svg{animation:none;opacity:.7}
}

/* Wiersz diagnostyki na dole arkusza okolicy — drobnym pismem, bo to odpowiedź
   na pytanie „jak sprawdzić, czy lokalizacja jest włączona", a nie treść, przez
   którą czytelnik ma się przebijać do przycisków. Kolor tekstu drugorzędnego
   (`--przygas`) jest liczony wobec tła z progiem 4,5 — drobne pismo nie może
   znaczyć nieczytelne. */
.okolica-diag{margin:14px 0 0;font-size:11px;line-height:1.5;color:var(--przygas);
  text-align:left;word-break:break-word}
/* Liczba wybranych działów na ikonie „#". Zastępuje rząd chipów pod
   zakładkami: ta sama informacja („filtr działa i obejmuje N działów") za
   kilkanaście pikseli zamiast całego wiersza ekranu. */
.pin-liczba{position:absolute;top:1px;right:1px;min-width:17px;height:17px;padding:0 4px;
  border-radius:999px;background:var(--akcent);color:var(--na-akcencie);
  font-size:11px;font-weight:800;line-height:17px;text-align:center}
/* „Twoja lokalizacja" w arkuszu — akcja główna, z pinezką, żeby wiązała się
   wzrokowo z przyciskiem, którym została otwarta. */
/* Odstęp OD POLA PONIŻEJ: przycisk „Ustal z lokalizacji" (.konto-zapisz,
   margines dolny 0) stał tuż nad polem „Wpisz gminę" (.konto-pole, margines
   górny 0) — 0+0 = zero odstępu, pola się zlewały (zgłoszone z produkcji).
   Zasada: między polami arkusza ZAWSZE ma być odstęp; nie polegać na tym,
   że sąsiad go doda. */
.okolica-gps{display:flex;align-items:center;justify-content:center;gap:9px;margin-bottom:12px}
.okolica-gps svg{width:18px;height:18px;flex:0 0 auto}

/* Pasek włączonego filtru tematycznego — filtr, którego nie widać i nie da
   się wyłączyć, wygląda jak zepsuty feed. */
/* Rząd chipów, nie jedna pigułka: feed potrafi być zawężony kilkoma tematami
   naraz, a każdy musi dać się zdjąć osobno. */
/* Rząd chipów siedzi WEWNĄTRZ paska okolicy (patrz `pokazPasekFiltru`), więc
   nie potrzebuje własnego pozycjonowania — dziedziczy je z kontenera i układa
   się pod pigułką okolicy zamiast na niej. `flex-basis:100%` daje mu własny
   wiersz, tak samo jak dopiskowi o braku materiałów. */
.pasek-filtru{flex:1 0 100%;z-index:28;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:6px;
  max-width:100%;font-size:13px;font-weight:700}
/* Wariant awaryjny: gdyby pasek okolicy nie istniał (widok bez feedu), chipy
   nadal muszą się gdzieś zaczepić — wtedy stoją same, tak jak dawniej. */
body > .pasek-filtru{position:fixed;left:50%;transform:translateX(-50%);
  top:calc(env(safe-area-inset-top) + 104px);max-width:calc(100% - 24px)}
/* `pointer-events:auto` — TO JEST NAPRAWA ZGŁOSZENIA „nie mogę usunąć wybranych
   tematów, klikanie na ✕ ich nie usuwa". Chipy siedzą wewnątrz paska okolicy,
   a ten ma `pointer-events:none`, żeby dało się przewijać feed pod nim; każdy
   klikalny element w środku musi więc włączyć zdarzenia SAM (tak robi pigułka
   okolicy i przycisk „cofnij"). Rząd chipów tego nie robił, więc kliknięcie
   przelatywało przez krzyżyk na kartę pod spodem — do serwera nie szło ŻADNE
   żądanie. Zdarzenia włączamy na samej pigułce, nie na rzędzie: rząd zajmuje
   całą szerokość ekranu i przechwytywałby przewijanie feedu palcem. */
.pasek-filtru-chip{display:inline-flex;align-items:center;gap:8px;pointer-events:auto;
  background:var(--akcent);color:var(--na-akcencie);border-radius:999px;
  padding:6px 8px 6px 14px;box-shadow:0 8px 24px rgba(0,0,0,.4)}
/* 32 px RYSOWANE, 44 px DOTYKANE. Widoczne kółko zostaje małe, bo pełnych 44 px
   rozepchnęłoby chip ponad wysokość etykiety, a chipów bywa kilka w rzędzie na
   szerokości telefonu — ale pole dotyku powiększa niewidoczna nakładka poniżej.
   Kanon floty mówi o CELU DOTYKOWYM, nie o średnicy rysunku. */
.pasek-filtru button{position:relative;background:rgba(var(--na-akcencie-rgb),.25);color:var(--na-akcencie);border:0;border-radius:999px;
  width:32px;height:32px;line-height:1;cursor:pointer;flex:0 0 auto;
  display:flex;align-items:center;justify-content:center;padding:0}
.pasek-filtru button::after{content:"";position:absolute;inset:-6px;border-radius:999px}
.pasek-filtru button svg{width:14px;height:14px}

/* ── Pasek okolicy ─────────────────────────────────────────────────────────
   Czytelnik zgłosił „raz mam newsy z Krakowa, raz z Lublina, raz z Gorlic".
   Okolica była trwała, tylko NIEWIDOCZNA — nie było czego sprawdzić ani jak
   zmienić. Pasek stoi pod zakładkami, czyli w treści strony, a nie w górnym
   pasku: tam zostaje samo logo.

   Tło nieprzezroczyste, bo leży na zdjęciu materiału — półprzezroczysta pigułka
   na jasnym zdjęciu przestaje być czytelna dokładnie wtedy, gdy jest potrzebna. */
/* Wyśrodkowany, jak rząd zakładek nad nim (`.tabs{justify-content:center}`).
   Wariant do lewej krawędzi był zmierzony i odrzucony: powyżej 820 px feed jest
   kolumną 460 px pośrodku ekranu, a pasek przyklejony do lewej lądował 478 px
   od treści, której dotyczy — wyglądał jak element innej strony. */
.pasek-okolica{position:fixed;top:calc(env(safe-area-inset-top) + 100px);left:0;right:0;z-index:28;
  display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:6px;
  padding:0 12px;pointer-events:none}
/* Dopisek o braku materiałów z okolicy idzie do WŁASNEGO wiersza — inaczej
   przy dwóch pigułkach (okolica + cofnij) rozpychałby pasek w bok. */
.pasek-okolica-uwaga{flex:1 0 100%;text-align:center}
.pasek-okolica-btn{pointer-events:auto;display:inline-flex;align-items:center;gap:7px;
  /* 44 px celu dotykowego — kanon floty. Pigułka wygląda na niższą, bo padding
     pionowy jest mały, ale `min-height` trzyma pole dotyku. */
  min-height:44px;padding:6px 14px;max-width:100%;
  border-radius:999px;border:1px solid var(--kreska);background:var(--karta);color:var(--tekst);
  font:inherit;font-size:13px;font-weight:700;cursor:pointer;
  box-shadow:0 6px 18px rgba(0,0,0,.32)}
.pasek-okolica-btn svg{width:15px;height:15px;flex:0 0 auto;opacity:.8}
.pasek-okolica-nazwa{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Reguła `.pasek-okolica-zmien` USUNIĘTA razem z dopiskiem „zmień": pigułka
   pokazuje teraz samą nazwę okolicy (decyzja operatora), a wskazówkę o tym,
   że jest klikalna, niosą pinezka i kształt przycisku. Pełne zdanie „Okolica:
   Warszawa — zmień" zostaje w `aria-label`, bo czytnik ekranu kształtu nie
   widzi. Martwej reguły nie zostawiamy — przeglądarka i tak by jej nie użyła,
   a następna osoba szukałaby elementu, którego nie ma. */
/* Wyjście z decyzji podjętej jednym kliknięciem w miejscowość na karcie.
   Osobny przycisk obok pigułki, nie jej część: to druga, odrębna decyzja,
   a wciśnięta do środka byłaby drugim celem dotykowym w jednym polu. */
.pasek-okolica-cofnij{pointer-events:auto;min-height:44px;padding:6px 12px;
  border-radius:999px;border:1px solid var(--kreska);background:var(--karta);
  color:var(--akcent-tekst);font:inherit;font-size:12px;font-weight:700;cursor:pointer;
  box-shadow:0 6px 18px rgba(0,0,0,.32)}
/* Wyjaśnienie, dlaczego na tej stronie nie ma nic z okolicy. Osobny wiersz,
   nie dopisek w pigułce: pigułka ma zostać krótka i klikalna. */
.pasek-okolica-uwaga{pointer-events:none;max-width:min(420px,100%);
  padding:4px 10px;border-radius:8px;background:var(--karta);color:var(--przygas);
  font-size:11.5px;line-height:1.35;box-shadow:0 4px 14px rgba(0,0,0,.28);
  opacity:1;transition:opacity .35s ease}
/* Dopisek ustępuje po trzech kartach materiału — wygaszeniem, nie zniknięciem
   w kadrze. Skokowe zniknięcie tekstu w polu widzenia czyta się jak usterka. */
.pasek-okolica-uwaga.gasnie{opacity:0}
@media (prefers-reduced-motion:reduce){
  .pasek-okolica-uwaga{transition:none}
}

/* ── Karty-zachęty w feedzie ───────────────────────────────────────────────
   Zwykłe karty feedu, nie nakładki: przewinięcie dalej pomija je jednym
   gestem, tak jak każdą inną kartę. Świadomie BEZ zdjęcia i bez blokady
   przewijania — to jest propozycja, a nie reklama. */
.zacheta-karta{height:100dvh;scroll-snap-align:start;scroll-snap-stop:always;
  position:relative;display:flex;flex-direction:column;justify-content:center;overflow:hidden}
/* Zapas u góry z REALNEJ wysokości pasków (`--paski-dol` ustawia `zmierzPaski`
   w app.js przy każdej przebudowie paska okolicy, chipów i migawki). Wpisany
   na sztywno byłby za mały dokładnie wtedy, gdy pasek urośnie o dopisek „nic
   nowego z Twojej okolicy" albo o rząd chipów — a wtedy nagłówek karty chowa
   się pod paskiem, co widać na zrzucie z produkcji. Wartość zapasowa 150 px
   odpowiada samej pigułce okolicy pod zakładkami.
   Treść zostaje WYŚRODKOWANA (`justify-content:center`), ale w tym, co zostało
   pod paskami — stąd zniknięcie pustych 40% ekranu pod przyciskiem.
   `overflow-y:auto`: przy najdłuższym wariancie (chipy + dopisek + trzy rzędy
   działów) karta ma się przewijać W ŚRODKU, a nie chować treść pod paskiem. */
.zacheta-karta .card-body{position:relative;z-index:2;
  /* Dół tym samym max() co karty materiału — przycisk „Nie teraz" też nie ma
     prawa wjechać pod pasek zachęty lokalizacji. */
  padding:calc(var(--paski-dol, 150px) + 14px) 20px
    max(calc(env(safe-area-inset-bottom) + 30px), var(--pasek-geo-zapas, 0px));
  justify-content:center;overflow-y:auto}
.zacheta-karta h2{margin:0 0 10px}
.zacheta-tematy{display:flex;flex-wrap:wrap;gap:8px;margin:6px 0 4px}
/* 44 px celu dotykowego — pigułki stoją gęsto obok siebie, więc tu pełny
   kanon, bez ustępstwa zrobionego przy plakietce miejsca. */
.zacheta-temat{min-height:44px;padding:10px 14px;border-radius:999px;
  border:1px solid var(--kreska);background:var(--powierzchnia);color:var(--tekst);
  font:inherit;font-size:14px;font-weight:600;cursor:pointer}
.zacheta-temat.on{background:var(--akcent);color:var(--na-akcencie);border-color:transparent}

/* Filtr tematyczny schodzi niżej, gdy pasek okolicy zajął swoje miejsce —
   inaczej obie pigułki lądują w tym samym wierszu i nachodzą na siebie. */

/* ── Lista tematów w arkuszu „Preferencje" ─────────────────────────────────
   Wiersz z polem wyboru, nazwą i liczbą materiałów. Cały wiersz jest etykietą,
   więc dotknięcie gdziekolwiek przełącza pole — 44 px celu dotykowego bez
   celowania w sam kwadracik. */
.pref-temat{display:flex;align-items:center;gap:10px;min-height:44px;
  padding:8px 12px;border-radius:10px;border:1px solid var(--kreska);
  background:var(--powierzchnia);cursor:pointer}
.pref-temat input{width:20px;height:20px;flex:0 0 auto;accent-color:var(--akcent)}
.pref-temat-nazwa{flex:1 1 auto;font-size:14px;font-weight:600}
.pref-temat-n{font-size:11.5px;opacity:.6;white-space:nowrap}

/* ── Chipy wyboru w arkuszu (miasta i tematy powiadomień) ──────────────────
   Rząd zdejmowalnych pigułek + rząd pigułek „dodaj". Wybór wielu miast musi
   być WIDOCZNY jednym rzutem oka i dawać się cofnąć bez wchodzenia w drugie
   okno — arkusz nad arkuszem jest w kanonie floty zakazany.

   `pointer-events:auto` NIE jest tu ozdobą, tylko zabezpieczeniem po
   zgłoszeniu „klikam ✕ i nic się nie dzieje": identyczny rząd chipów pod
   zakładkami leżał w kontenerze z `pointer-events:none`, sam zdarzeń nie
   włączał i kliknięcie w krzyżyk przelatywało na kartę pod spodem — do
   serwera nie szło żadne żądanie. Chip włącza je U SIEBIE, nie licząc na to,
   jaki rodzic go kiedyś obejmie. */
.arkusz-chipy{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 10px}
.arkusz-chipy:empty{display:none}
.arkusz-chip{display:inline-flex;align-items:center;gap:6px;pointer-events:auto;max-width:100%;
  background:var(--akcent);color:var(--na-akcencie);border-radius:999px;
  padding:6px 6px 6px 14px;font-size:13px;font-weight:700}
/* Długa nazwa gminy („Nowe Miasto nad Pilicą") nie może rozepchnąć arkusza
   na wąskim telefonie — chip skraca etykietę, a nie łamie układ. */
.arkusz-chip>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* 32 px RYSOWANE, 44 px DOTYKANE — ta sama zasada, co przy chipach filtru:
   pełne 44 px rysunku rozpycha pigułkę ponad wysokość wiersza, a kanon floty
   mówi o CELU DOTYKOWYM, nie o średnicy kółka. Powiększa go nakładka `::after`. */
.arkusz-chip button{position:relative;flex:0 0 auto;width:32px;height:32px;padding:0;
  border:0;border-radius:999px;pointer-events:auto;cursor:pointer;
  background:rgba(var(--na-akcencie-rgb),.25);color:var(--na-akcencie);
  display:flex;align-items:center;justify-content:center}
.arkusz-chip button::after{content:"";position:absolute;inset:-6px;border-radius:999px}
.arkusz-chip button svg{width:14px;height:14px}
/* Pigułka „dodaj" jest OBRYSEM, nie wypełnieniem: wybrane i niewybrane muszą
   różnić się na pierwszy rzut oka, a nie samym znakiem w środku. Plusik bierze
   kolor „60" z logo (`--akcent2`) — tokenem, bo skórka jasna zamienia limonkę
   na ciemną oliwkę i wpisana na sztywno po prostu by zniknęła. */
.arkusz-chip-dodaj{display:inline-flex;align-items:center;gap:7px;min-height:44px;
  padding:6px 14px;border-radius:999px;border:1px solid var(--kreska);
  background:var(--powierzchnia);color:var(--tekst);
  font:inherit;font-size:13px;font-weight:600;cursor:pointer}
.arkusz-chip-dodaj svg{width:14px;height:14px;flex:0 0 auto;color:var(--akcent2)}
/* Nagłówki sekcji arkusza powiadomień w barwie „60" — ten sam token, którym
   świecą pinezka okolicy i „ZALOGUJ SIĘ". */
.arkusz .konto-sekcja h3.pow-sekcja-tytul{color:var(--akcent2)}
/* Kreska MUSI stać także nad pierwszą sekcją. `.konto-sekcja:first-of-type`
   ją zdejmuje, bo w zakładce Konto sekcje zaczynają arkusz — a tutaj stoją
   POD dwoma przełącznikami źródeł i bez kreski „Miasta" czytało się jak podpis
   do „Z Twojej okolicy" (zmierzone na zrzucie 390 px). */
.arkusz .konto-sekcja.pow-sekcja{border-top:1px solid var(--kreska);padding-top:16px;margin-top:14px}
/* Nota „co znaczy pusto" — stoi nad przyciskami i ma się czytać jak zdanie,
   a nie jak komunikat błędu, więc dostaje wyższy interlinię niż `.kod-info`. */
.arkusz .arkusz-nota{margin:14px 0 0;line-height:1.45;opacity:.72}

/* Pola i komunikaty w arkuszach spoza zakładki Konto (okolica, preferencje) —
   te same reguły, tylko bez wymogu `.konto-sekcja` wokół. */
.arkusz>.konto-wartosc{margin:0 0 12px;font-size:17px;font-weight:700;color:var(--tekst)}
.arkusz>.konto-stan{margin:0 0 10px;font-size:12.5px;line-height:1.4;min-height:16px;opacity:.8}
.arkusz>.konto-stan.ok{color:#3ec98a;opacity:1}
.arkusz>.konto-stan.zle{color:#ff6b6b;opacity:1}
.konto-pole{width:100%;box-sizing:border-box;margin:0 0 10px;padding:12px 14px;min-height:44px;
  border-radius:10px;border:1px solid var(--kreska);background:var(--powierzchnia);
  color:var(--tekst);font:inherit;
  /* 16 px, nie mniej: Safari na iPhonie przybliża stronę przy wejściu w pole
     o mniejszym foncie i już z niej nie wraca. */
  font-size:16px}
.konto-zapisz{width:100%;margin:12px 0 0;padding:11px 16px;min-height:46px;
  border:0;border-radius:10px;background:var(--akcent);color:var(--na-akcencie);
  font:inherit;font-size:14px;font-weight:600;cursor:pointer}

/* KOLEJNOSC MA ZNACZENIE: reguly nizej maja te sama wage (jedna klasa) co
   `.konto-zapisz`, wiec musza stac PO niej. Pierwsza wersja lezala 80 linii
   wyzej, przy karcie zachety, i przegrywala o kolejnosc - przyciski wychodzily
   w kolorze akcentu mimo poprawnej reguly (zmierzone na zrzucie E2E). */
/* ── Dwa wyjścia z karty „Załóż konto" ─────────────────────────────────────
   DRUGA BARWA MARKI, nie akcent (decyzja operatora): to ten sam kolor, którym
   świeci „60" w logo i pozycja „ZALOGUJ SIĘ" w szufladzie — czytelnik zna go
   już jako „tędy coś dostajesz", a czerwień akcentu niesie w tej aplikacji
   stan wyboru (aktywna zakładka, pigułka źródła).

   Tekst tokenem `--na-akcencie2`, NIE gołą czernią: na skórce jasnej
   `--akcent2` jest ciemną oliwką i czarny napis miałby na niej kontrast 2,0.
   Token trzyma czerń tam, gdzie druga barwa jest limonką (standardowa,
   monochromatyczna, własna z jasnym logo), a biel tam, gdzie jest ciemna —
   i skórka „Własna" liczy go sobie sama, tą samą regułą co tekst na akcencie.

   Klasy WŁASNE, a nie przemalowanie `.konto-zapisz` w obrębie `.zacheta-karta`:
   tej samej klasy używa przycisk „Zapisz" na karcie zachęty tematów i tamten
   ma zostać w kolorze akcentu.

   Hierarchia bez zmiany koloru: oba przyciski limonkowe (o to prosił
   operator), a który jest główny, mówi kolejność, waga pisma i wcięty obrys
   drugiego — nie druga barwa. */
.zacheta-konto-glowny,
.zacheta-konto-drugi{background:var(--akcent2);color:var(--na-akcencie2)}
.zacheta-konto-glowny{font-weight:800;font-size:15px}
/* Obrys WEWNĘTRZNY (`inset`), nie `border`: zewnętrzna ramka zmieniłaby
   wysokość przycisku o 2 px i dwa przyciski jeden pod drugim przestałyby być
   równe. Kolor obrysu z tekstu, czyli z tokenu — na każdej skórce jest to ten
   sam kontrast, który już przeszedł ocenę. */
.zacheta-konto-drugi{font-weight:600;margin-top:8px;
  box-shadow:inset 0 0 0 2px color-mix(in srgb, var(--na-akcencie2) 55%, transparent)}

/* Pasek zachęty do lokalizacji. Siedzi NAD dolną nawigacją i nad wcięciem
   bezpiecznym iPhone'a — inaczej „Pokaż" trafiałby pod pasek gestów systemu
   i nie dałoby się go dotknąć. Przyciski mają 44 px wysokości (kanon floty). */
/* BIAŁE tło, nie ciemne. Pasek leży na zdjęciu artykułu, a te bywają ciemne i
   kontrastowe — ciemna plansza na ciemnym kadrze ginęła i czytała się jak część
   zdjęcia, nie jak pytanie do kliknięcia. Biel odcina go od treści jednoznacznie. */
.pasek-geo{position:fixed;left:12px;right:12px;z-index:29;
  bottom:calc(env(safe-area-inset-bottom) + 74px);
  display:flex;align-items:center;gap:8px;
  background:var(--plansza);color:var(--na-planszy);border:1px solid var(--kreska);
  border-radius:14px;padding:10px 10px 10px 14px;
  box-shadow:0 12px 34px rgba(0,0,0,.45)}
.pasek-geo-txt{flex:1 1 auto;font-size:14px;font-weight:600;line-height:1.25;color:var(--na-planszy)}
.pasek-geo button{flex:0 0 auto;min-height:44px;padding:0 14px;border-radius:11px;
  font:inherit;font-size:14px;font-weight:700;cursor:pointer}
.pasek-geo-tak{background:var(--akcent);color:var(--na-akcencie);border:0}
.pasek-geo-nie{background:transparent;color:var(--na-planszy);opacity:.72;border:0;padding:0 10px}

/* Klikalne obszary karty prowadzące do materiału. */
.card-body .klik{cursor:pointer}
button.tag.temat{border:0;font:inherit;cursor:pointer}

/* ── Wyszukiwarka redakcji ─────────────────────────────────────────────── */
/* Wyszukiwarka zaczyna U GÓRY. `.card` dosuwa treść do dołu (feed tak ma
   działać), więc z podniesioną klawiaturą pole lądowało w połowie ekranu,
   z pustką nad sobą — wyglądało to na przypadek, nie na układ. */
.card.szukaj{height:100dvh;justify-content:flex-start}
/* BEZ górnego odstępu — przejmuje go przyklejona podkładka. Gdy odstęp był
   tutaj, treść przewijała się przez ten pas nad polem i wyniki prześwitywały
   nad wyszukiwarką. */
.szukaj-body{padding:0 16px calc(env(safe-area-inset-bottom) + 20px);
  justify-content:flex-start;display:flex;flex-direction:column;gap:12px;overflow-y:auto;
  /* Przyklejone pole musi mieć na czym leżeć — bez tła wyniki byłyby pod nim widoczne. */
  background:var(--tlo)}
/* POLE ZOSTAJE NA WIDOKU. Siedziało wewnątrz przewijanego obszaru razem
   z wynikami, więc po wpisaniu dwóch znaków lista wypychała je poza ekran
   i trzeba było przewijać w górę, żeby poprawić zapytanie. `sticky` przykleja
   je do górnej krawędzi — przewijają się TYLKO wyniki.
   Tło i ujemne marginesy: bez nich wyniki prześwitywałyby pod polem, bo
   `.szukaj-body` ma własny padding poziomy. */
.szukaj-pole{font:inherit;font-size:16px;padding:13px 15px;border-radius:12px;
  border:1px solid var(--kreska);background:var(--powierzchnia);color:var(--tekst);width:100%;
  }
/* Opakowanie, nie samo pole: input ma półprzezroczyste tło, więc wyniki
   przewijające się pod nim byłyby przez nie widoczne. Ujemne marginesy
   rozciągają podkładkę na pełną szerokość karty (body ma padding 16 px). */
.szukaj-przyklejone{position:sticky;top:0;z-index:3;background:var(--tlo);
  margin:0 -16px;padding:calc(env(safe-area-inset-top) + 62px) 16px 10px}
.szukaj-pole::placeholder{color:var(--przygas)}
.szukaj-info{font-size:13px;opacity:.6;text-align:center;margin:18px 0}
.szukaj-wyniki{display:flex;flex-direction:column;gap:6px}
.wynik{display:flex;gap:11px;align-items:center;text-align:left;background:var(--karta);
  border:1px solid var(--kreska);border-radius:12px;padding:10px;cursor:pointer;color:var(--tekst);font:inherit}
.wynik-logo{flex:0 0 auto;width:42px;height:42px;border-radius:11px;overflow:hidden;
  background:rgba(var(--tekst-rgb),.14);display:flex;align-items:center;justify-content:center;
  font-weight:800;font-size:15px}
.wynik-logo img{width:100%;height:100%;object-fit:cover}
.wynik-opis{min-width:0}
.wynik-opis b{display:block;font-size:14.5px}
.wynik-opis span{display:block;font-size:12px;opacity:.6}

/* Czas czytania z zegarem — bez ikony „14 s" obok daty czytało się jak
   długość materiału wideo albo odliczanie do czegoś. */
.read-sec{display:inline-flex;align-items:center;gap:4px}
.read-sec svg{width:12px;height:12px;opacity:.8;flex:0 0 auto}

/* Poza feedem (profil, wyszukiwarka) zakładki nie mają czego przełączać —
   kliknięcie w „Główne" na profilu redakcji to obietnica bez pokrycia. */
.poza-feedem .tabs{display:none}
/* Pasek okolicy też znika poza feedem — i to nie jest kosmetyka. Pasek stoi
   `position:fixed` na wysokości 100 px od góry, czyli dokładnie tam, gdzie na
   profilu redakcji jest znak wydawcy: pigułka „Warszawa" ZASŁANIAŁA logo
   (zgłoszone ze zrzutu z produkcji). Merytorycznie też nie ma tu czego
   opisywać — profil redakcji pokazuje materiały TEJ redakcji, a nie wycinek
   z okolicy czytelnika, więc pasek mówiłby nieprawdę o tym, co widać niżej.
   `!important` z tego samego powodu co przy `.na-reklamie`: pasek bywa
   pokazywany jawną regułą z wyższą wagą. */
.poza-feedem #pasek-okolica,
.poza-feedem .pasek-filtru{display:none !important}

/* Karta reklamowa — pełnoekranowa jak materiał, ale OZNACZONA. Reklama, której
   nie da się odróżnić od treści redakcyjnej, jest problemem prawnym, a nie
   sprytnym pomysłem. */
.reklama-karta .tag.oznaczenie{background:rgba(var(--na-welonie-rgb),.28);letter-spacing:.14em}
.reklama-karta h2{opacity:.5;font-weight:600}
/* Kreacja (natywna albo z mediaclustera) dostaje typografię karty materiału —
   wyciszenie wyżej zostaje TYLKO dla pustej planszy „Miejsce na treść własną".
   Kreacja ma czytać się jak materiał; odróżnia ją oznaczenie „Reklama". */
.reklama-karta.reklama-kreacja h2{opacity:1;font-weight:800}

/* ── „PROMOCJA": ŻÓŁTE TŁO, CZARNY TEKST ────────────────────────────────────
   Reklama WŁASNA (house ad) dostaje inne oznaczenie niż sprzedana — „Reklama"
   znaczy „ktoś nam za to zapłacił" i podpisanie tak własnej zachęty byłoby
   informacją nieprawdziwą.

   Kolory TOKENAMI `--zapis`/`--na-zapisie`, a nie zapisane wprost: to ta sama
   para, którą oznaczony jest zapisany materiał, i na obu skórkach daje kontrast
   ~15:1 (zmierzone: #facc15 na #0b0b0d → 15,1:1). Nowy żółty wprost w tym
   miejscu rozjechałby się ze skórką mono i z pierwszą zmianą palety. */
.reklama-karta .tag.oznaczenie.promocja{
  background:var(--zapis);color:var(--na-zapisie);font-weight:800
}
/* Przycisk „Udostępnij" na karcie promocyjnej: ten sam kształt co „Czytaj",
   bo pełni tę samą rolę — jedyne wezwanie do działania na karcie. */
.reklama-udostepnij{border:0;font:inherit;cursor:pointer}

/* Kafel promocyjny w siatce profilu redakcji. Wygląda jak kafel materiału
   (i tak ma być — to reklama natywna), odróżnia go PASEK NA DOLE. Pasek jest
   pod tytułem, nie nad nim: czytelnik czyta kafel od góry, więc oznaczenie
   napotkane po treści zamyka ją podpisem, zamiast konkurować z nagłówkiem. */
.kafel-promocja .kafel-tyt{bottom:17px;max-height:calc(2 * 1.25em + 27px);-webkit-line-clamp:2}
.kafel-promo-pasek{
  position:absolute;left:0;right:0;bottom:0;height:17px;display:flex;
  align-items:center;justify-content:center;
  background:var(--zapis);color:var(--na-zapisie);
  font-size:8.5px;font-weight:800;letter-spacing:.14em;text-transform:uppercase
}

/* ── Karta WIDEO (pilotaż TikTok) ─────────────────────────────────────────
   Badge w kolorze akcentu (ten sam duet co .tag.src) — materiał do obejrzenia
   ma być rozpoznawalny zanim czytelnik przeczyta tytuł. */
.tag.wideo{display:inline-flex;align-items:center;gap:6px;background:var(--akcent);
  color:var(--na-akcencie);font-weight:800;letter-spacing:.1em;text-transform:uppercase}
.tag.wideo svg{width:11px;height:11px;flex:0 0 auto}
/* Kółko „play" na środku miniatury JEST PRZYCISKIEM (64 px, znacznie powyżej
   celu dotyku 44 px). Wcześniej miało `pointer-events:none` i było wyłącznie
   afordancją — czyli największy, najbardziej oczywisty cel na karcie nie
   robił nic. Lekka płyta z rozmyciem, żeby trójkąt był widoczny i na jasnym,
   i na ciemnym kadrze. */
.wideo-play{position:absolute;left:50%;top:38%;transform:translate(-50%,-50%);
  width:64px;height:64px;border-radius:50%;background:rgba(0,0,0,.45);border:0;padding:0;
  backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;
  z-index:1;color:#fff;cursor:pointer;-webkit-tap-highlight-color:transparent}
.wideo-play:active{transform:translate(-50%,-50%) scale(.94)}
.wideo-play svg{width:26px;height:26px;margin-left:3px}
/* Czekanie na osadzenie: trójkąt gaśnie i wraca, żeby dotknięcie miało
   natychmiastową odpowiedź, zanim TikTok cokolwiek przyśle. */
.wideo-play.czeka{animation:wideo-puls 1.1s ease-in-out infinite}
@keyframes wideo-puls{0%,100%{opacity:1}50%{opacity:.45}}

/* ODTWARZACZ W KARCIE (jeden dotyk). Ramka leży ABSOLUTNIE nad miniaturą —
   nic w układzie się nie przesuwa (zero skoku), a do czasu wczytania jest
   przezroczysta, więc pod spodem widać dalej miniaturę zamiast czarnej
   dziury. Górny pasek 56 px zostaje wolny: mieści krzyżyk i zostawia miejsce
   na przewinięcie feedu palcem obok ramki. */
/* WYSOKOŚĆ JAWNIE, nie samo `inset:0`: iframe to element zastępowany i przy
   automatycznych wymiarach zostaje przy swoim wewnętrznym 300×150 — zmierzone
   w przeglądarce, ramka miała 150 px wysokości na karcie o 844 px. */
.wideo-ramka{position:absolute;inset:0;width:100%;height:100%;border:0;
  z-index:2;background:transparent;opacity:0;transition:opacity .25s}
.wideo-ramka.gotowa{opacity:1;background:#000}
/* Podczas odtwarzania tekst karty i pasek akcji ustępują wideo: nasza kolumna
   ikon nachodziłaby na własną kolumnę TikToka wewnątrz ramki. */
.card.wideo-gra .card-body,
.card.wideo-gra .actions,
.card.wideo-gra .wideo-play{opacity:0;pointer-events:none;transition:opacity .2s}
/* Wideo gra = ekran należy do wideo. Chowamy własne paski dokładnie tak, jak
   robi to karta reklamowa (`.na-reklamie`) i widoki poza feedem
   (`.poza-feedem`) — inaczej górny pasek aplikacji leży NA krzyżyku
   zamknięcia (zmierzone w przeglądarce: `.top` ma z-index 30). */
.na-wideo .top,
.na-wideo .tabs,
.na-wideo .szukaj-pin,
.na-wideo .hint,
.na-wideo .pasek-geo{display:none !important}
.na-wideo #pasek-okolica,
.na-wideo .pasek-filtru{display:none !important}
.wideo-zamknij{position:absolute;top:calc(env(safe-area-inset-top) + 10px);right:12px;
  width:44px;height:44px;border:0;padding:0;
  border-radius:50%;background:rgba(0,0,0,.5);backdrop-filter:blur(4px);color:#fff;
  display:flex;align-items:center;justify-content:center;z-index:31;cursor:pointer}
.wideo-zamknij svg{width:20px;height:20px}
/* Osadzenie nie wstało w rozsądnym czasie: jedno zdanie zamiast dziury. */
.wideo-info{position:absolute;left:50%;top:52%;transform:translateX(-50%);z-index:3;
  max-width:80%;text-align:center;font-size:13px;font-weight:700;color:#fff;
  background:rgba(0,0,0,.6);backdrop-filter:blur(4px);padding:10px 14px;border-radius:12px}
/* Podpowiedź o dźwięku siada NAD dolną krawędzią, nie na środku obrazu:
   na środku zasłania twarz mówiącego przez pierwsze sekundy filmu, czyli
   dokładnie to, po co czytelnik go włączył. Waga pisma niższa niż przy
   komunikacie o błędzie — to wskazówka, nie usterka. */
.wideo-info.wideo-dzwiek{top:auto;bottom:calc(env(safe-area-inset-bottom) + 22px);
  font-weight:600;transition:opacity .5s ease}
.wideo-info.wideo-dzwiek.gasnie{opacity:0}
@media (prefers-reduced-motion: reduce){.wideo-info.wideo-dzwiek{transition:none}}

/* Strona materiału wideo: pionowa ramka osadzenia zajmuje większość ekranu,
   tytuł (często zupa hashtagów z TikToka) przycięty do dwóch linii. */
.wideo-osadzenie{width:100%;height:min(66dvh,760px);border:0;border-radius:14px;
  background:#000;margin:10px 0 14px;display:block}
.wideo-widok h2{font-size:clamp(16px,4.4vw,21px);
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}

/* Źródło i temat w jednej pigułce. Jeden element wizualny, dwa cele kliknięcia:
   nazwa wydawcy → profil, temat → filtr. Rozdzielone tła zjadały szerokość
   na własne marginesy i nazwa wydawcy przestawała się mieścić. */
.tag.zrodlo-temat{display:inline-flex;align-items:center;gap:7px;background:var(--plyta);color:var(--na-plycie);
  padding:5px 12px;max-width:100%;overflow:hidden}
.tag.zrodlo-temat button{border:0;background:none;font:inherit;font-size:11px;font-weight:700;
  letter-spacing:.06em;text-transform:uppercase;cursor:pointer;padding:0;white-space:nowrap}
/* Nazwa źródła w kolorze „60" z logo (`--akcent2`), NIE w magencie akcentu:
   magenta na półprzezroczystej płycie zlewała się z tłem zdjęcia. `--akcent2`
   ma wartości per skórka już skalibrowane na kontrast (ciemna: limonka,
   jasna: ciemna oliwka 8,68 na białej płycie, mono: #d6d6d6) — ten sam token,
   którym świecą „ZALOGUJ SIĘ", pinezka i lupa. Pomiar: skorka.js, para
   „Źródło na pigułce". */
.cz-zrodlo{color:var(--akcent2);flex:0 0 auto}
.cz-sep{opacity:.4;font-size:11px;flex:0 0 auto}
.cz-temat{color:var(--na-plycie);overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto}

/* Nota o zgodzie na jaskrawożółto — ma rzucać się w oczy, bo mówi rzecz
   najważniejszą: odmowa niczego nie psuje. */
.consent-foot{color:var(--uwaga);opacity:1;font-weight:600;font-size:12.5px}

/* Odliczanie na karcie reklamowej — czytelnik ma WIEDZIEĆ, ile trwa blokada.
   Zablokowane przewijanie bez wyjaśnienia wygląda jak zawieszona aplikacja. */
.reklama-licznik{margin-top:14px;font-size:12.5px;font-weight:700;letter-spacing:.04em;
  color:rgba(var(--na-welonie-rgb),.62);background:rgba(var(--na-welonie-rgb),.1);border-radius:99px;
  padding:7px 14px;align-self:flex-start}

/* Pole języka w menu — etykieta i lista w jednym rzędzie. Wysokość 44 px,
   bo to dolna granica celu dotykowego; niższe pole na telefonie wymusza
   celowanie. */
.menu-pole{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:10px 12px;font-weight:600;font-size:14px;line-height:1.2;color:var(--tekst)}
/* SKRÓT `font:600 14px/1.2 inherit` BYŁ NIEWAŻNY i przeglądarka wyrzucała go
   w całości: `inherit` jest słowem kluczowym całej deklaracji, a nie wartością
   rodziny pisma w skrócie. Skutek widać było tylko na iPhonie i tylko przy
   dotknięciu listy języka: pole zostawało przy domyślnych 13,3 px, a Safari
   powiększa całą stronę, gdy dotknięte pole ma mniej niż 16 px — czytelnik
   wychodził z menu w rozjechanym widoku i musiał odsuwać go palcami.
   Rozpisane na osobne własności; rozmiar podniesiony do progu 16 px. */
/* PEŁNA SZEROKOŚĆ szuflady, jak pozostałe pozycje. Wąska lista przyklejona do
   prawej krawędzi wyglądała jak element innego widoku, a etykieta obok niej
   jest schowana wzrokowo (`.sr-only`), więc miejsca po lewej nikt nie zajmuje.
   Rozmiar 16 px zostaje bez zmian: niżej Safari na iPhonie powiększa stronę
   przy dotknięciu pola — usterka naprawiona tu wcześniej. */
.menu-pole select{flex:1 1 auto;width:100%;min-height:44px;padding:8px 12px;border-radius:12px;
  background:var(--powierzchnia);color:var(--tekst);border:1px solid var(--kreska);
  font-family:inherit;font-weight:600;font-size:16px;line-height:1.2;cursor:pointer}

/* ── Ekran powitalny ────────────────────────────────────────────────────────
   Pełny ekran, nie arkusz: to jest przejście do aplikacji, a nie pytanie
   zadane w jej trakcie. Przewijalny, bo krok z tematami ma dwanaście pozycji
   i na małym telefonie nie mieści się bez przewijania. */
.powitanie-otwarte .feed{overflow:hidden}
.powitanie{position:fixed;inset:0;z-index:140;overflow-y:auto;box-sizing:border-box;
  background:var(--tlo);color:var(--tekst);
  padding:calc(env(safe-area-inset-top) + 26px) 20px calc(env(safe-area-inset-bottom) + 22px);
  display:flex;flex-direction:column;gap:18px}
.pow-postep{display:flex;gap:6px;justify-content:center}
.pow-kropka{width:26px;height:4px;border-radius:99px;background:var(--kreska)}
/* EKRAN POWITALNY NOSI DRUGĄ BARWĘ MARKI, nie czerwień. Czerwony `--akcent`
   znaczy w tej aplikacji „stan włączony przez czytelnika" (zakładka, obserwuję,
   zapisane) i wraca potem na każdym ekranie. Powitanie jest jednorazowe i nic
   z niego nie zostaje na widoku, więc te same wypełnienia obiecywałyby stan,
   którego czytelnik nigdy więcej nie zobaczy.
   Para tokenów, nie sam kolor: na limonce (i na złocie w wariancie ua) biel
   z `--na-akcencie` znika, dlatego wszędzie niżej idzie `--na-akcencie2`.
   Na skórce jasnej `--akcent2` jest ciemną oliwką i ta sama para niesie biel —
   dlatego kontrast trzyma się w obu skórkach bez osobnej reguły. */
.pow-kropka.on{background:var(--akcent2)}
.pow-krok{flex:1 1 auto}
/* Wszystkie reguły ekranu powitalnego niżej miały skrót `font:… inherit`,
   czyli zapis nieważny (patrz komentarz przy `.arkusz h2`). Były martwe
   w całości, więc ekran powitalny renderował się od miesięcy wartościami
   domyślnymi: nagłówek jako zwykły <h2>, a WSZYSTKIE przyciski w wadze 400 —
   „Dalej" nie różnił się krojem od „Pomiń ten krok", choć jeden jest akcją
   główną, a drugi wyjściem awaryjnym. Rozpisane na osobne własności. */
.pow-krok h2{margin:0 0 8px;font-weight:800;font-size:24px;line-height:1.15;color:var(--nagl)}
.pow-opis{margin:0 0 14px;font-size:14px;line-height:1.5;opacity:.82}
.pow-stan{margin:0 0 10px;font-size:13.5px;font-weight:600}
.pow-siatka{display:grid;grid-template-columns:repeat(auto-fill,minmax(88px,1fr));gap:9px}
.pow-siatka-szeroka{grid-template-columns:repeat(auto-fill,minmax(136px,1fr))}
/* 48 px, bo poniżej tej wysokości cel dotykowy wymusza celowanie. */
.pow-opcja{min-height:48px;padding:10px 12px;border-radius:14px;cursor:pointer;
  font-family:inherit;font-weight:600;font-size:14px;line-height:1.2;text-align:center;
  background:var(--karta);color:inherit;
  border:1px solid var(--kreska)}
.pow-opcja.on{background:var(--akcent2);color:var(--na-akcencie2);
  border-color:var(--akcent2)}
.pow-rzad{display:flex;gap:10px;align-items:center}
.pow-glowny{flex:1 1 auto;min-height:50px;border:0;border-radius:14px;cursor:pointer;
  font-family:inherit;font-weight:800;font-size:15px;line-height:1.2;
  background:var(--akcent2);color:var(--na-akcencie2)}
.pow-pomin{flex:0 0 auto;min-height:50px;padding:0 16px;border-radius:14px;cursor:pointer;
  font-family:inherit;font-weight:600;font-size:14px;line-height:1.2;
  background:transparent;color:inherit;
  border:1px solid var(--kreska)}
.powitanie .pole{font:inherit;font-size:16px;width:100%;box-sizing:border-box;min-height:48px;
  padding:12px 14px;margin:10px 0 0;border-radius:12px;color:inherit;
  border:1px solid var(--kreska);background:var(--powierzchnia)}
.pow-lista{margin-top:12px;display:flex;flex-direction:column;gap:8px}
.pow-redakcja{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:11px 13px;border-radius:14px;background:var(--karta);
  border:1px solid var(--kreska)}
.pow-redakcja-nazwa{font-weight:700;font-size:14px;line-height:1.25}
/* 44 px celu dotykowego (kanon floty). Zmierzone przed poprawką: 40 px —
   mieściło się w oku, nie mieściło w kciuku, a to jest przycisk, od którego
   zależy, czy serwis w ogóle dostanie okolicę. */
.pow-obserwuj{flex:0 0 auto;min-height:44px;padding:0 14px;border-radius:99px;cursor:pointer;
  font-family:inherit;font-weight:700;font-size:13px;line-height:1.2;
  background:transparent;color:inherit;
  border:1px solid var(--akcent2)}
.pow-obserwuj.on{background:var(--akcent2);color:var(--na-akcencie2)}
/* Stan „nie ma czego klikać" — „Niedostępne" i „Zablokowane". Wygaszamy
   TOKENAMI (kreska + tekst drugorzędny), a nie czerwienią: to nie jest błąd
   czytelnika ani awaria, tylko informacja, że tą drogą się nie da i trzeba
   pójść drugą (wybór miasta). Czerwona obwódka przy nieklikalnym przycisku
   wygląda jak zepsuty przycisk. */
/* `:not(.on)` — po UDANYM ustawieniu okolicy przycisk też zostaje nieaktywny
   („✓ Kraków"), ale to jest potwierdzenie, nie odmowa: ma świecić akcentem,
   a nie gasnąć razem z „Zablokowane". */
.pow-obserwuj[disabled]:not(.on){border-color:var(--kreska);color:var(--przygas);cursor:default}

/* ── Ilustracja karty powitalnej ────────────────────────────────────────────
   Wypełnia kadr, który wcześniej był pustą, czarną połową ekranu przy pierwszym
   wejściu. Wysokość w jednostkach ekranu, nie w pikselach: na małym telefonie
   grafika ma ustąpić miejsca tekstowi, a nie zepchnąć punkty poniżej krawędzi. */
.grafika-scroll{width:100%;max-width:340px;margin:0 auto 16px}
.grafika-scroll svg{width:100%;height:auto;max-height:min(34vh,250px);display:block}

/* Ruch w górę — dokładnie ten, o który prosimy czytelnika. Krótka pętla z długą
   przerwą: ma podpowiedzieć gest, a nie migać pod tekstem przez cały czas. */
@media (prefers-reduced-motion: no-preference){
  .grafika-scroll .gs-karty rect,
  .grafika-scroll .gs-tresc{animation:gs-plyn 3.6s ease-in-out infinite}
  .grafika-scroll .gs-k2{animation-delay:.08s}
  .grafika-scroll .gs-k3{animation-delay:.16s}
  .grafika-scroll .gs-strzalka{animation:gs-skok 3.6s ease-in-out infinite}
}
@keyframes gs-plyn{
  0%,55%,100%{transform:translateY(0)}
  22%{transform:translateY(-7px)}
}
@keyframes gs-skok{
  0%,55%,100%{transform:translateY(0);opacity:.85}
  22%{transform:translateY(-10px);opacity:1}
}

/* Przejście logowanie ↔ zakładanie konta wewnątrz panelu. Wygląda jak odnośnik,
   bo to zmiana zdania, a nie akcja główna — te są w rzędzie przycisków wyżej. */
.konto-przelacz{display:block;width:100%;margin:14px 0 0;padding:10px;min-height:44px;
  background:none;border:0;color:var(--przygas);font:inherit;font-size:13.5px;
  text-decoration:underline;text-underline-offset:3px;cursor:pointer}
.konto-przelacz:hover{color:var(--tekst)}

/* ── Zakładka Konto ────────────────────────────────────────────────────────
   Cztery osobne sprawy (nick, numer, hasło, miasto) w jednym arkuszu. Kreska
   między sekcjami jest tu treścią, nie ozdobą: bez niej pola z trzech różnych
   formularzy stały w jednym słupku i „Zapisz" pod hasłem wyglądał, jakby
   zapisywał także numer wpisany wyżej. */
.konto-sekcja{border-top:1px solid var(--kreska);padding:16px 0 4px;margin:0}
.konto-sekcja:first-of-type{border-top:0;padding-top:2px}
/* Ten nagłówek też był martwy przez `inherit` w skrócie `font` (patrz
   `.arkusz h2`): sekcje konta czytały się domyślnym <h3> w 18,72 px, czyli
   prawie tak mocno jak tytuł całego arkusza — a mają być stopniem NIŻEJ. */
.arkusz .konto-sekcja h3{margin:0 0 6px;font-weight:700;font-size:15px;line-height:1.3;color:var(--nagl)}
.arkusz .konto-sekcja .konto-opis{margin:0 0 12px;font-size:12.5px;line-height:1.45;opacity:.72}
/* Wartość obecna (numer telefonu, wybrane miasto) — to jest DANA, nie podpis,
   więc czyta się mocniej niż opis nad nią. */
.arkusz .konto-sekcja .konto-wartosc{margin:0 0 12px;font-size:17px;font-weight:700;
  letter-spacing:.02em;color:var(--tekst);opacity:1}
.arkusz .konto-sekcja .konto-stan{margin:0 0 10px;font-size:12.5px;line-height:1.4;min-height:16px;opacity:.8}
/* Zielony/czerwony NIE jest jedynym nośnikiem — komunikat zawsze mówi słowami,
   co jest nie tak (daltonizm, jasne słońce na ekranie telefonu). */
.arkusz .konto-sekcja .konto-stan.ok{color:#3ec98a;opacity:1}
.arkusz .konto-sekcja .konto-stan.zle{color:#ff6b6b;opacity:1}
.konto-sekcja .consent-yes{font:inherit;font-size:14px;font-weight:600;width:100%;
  min-height:46px;padding:11px 16px;border:0;border-radius:10px;cursor:pointer;
  background:var(--akcent);color:var(--na-akcencie)}
.konto-sekcja .consent-yes:disabled{opacity:.45;cursor:default}
.konto-lista{display:flex;flex-direction:column;gap:6px;margin:0 0 10px}
.konto-podpowiedz{display:flex;flex-direction:column;gap:2px;text-align:left;
  padding:10px 12px;min-height:44px;border-radius:10px;border:1px solid var(--kreska);
  background:var(--powierzchnia);color:inherit;font:inherit;cursor:pointer}
.konto-podpowiedz-nazwa{font-size:14px;font-weight:600}
.konto-podpowiedz-opis{font-size:12px;opacity:.65}

/* Przycisk pobrania lokalizacji na kroku „Gdzie mieszkasz?". Pełna szerokość,
   bo to JEDYNA akcja tego kroku — wariant przylegający do treści czytał się
   jak jedna z kilku równorzędnych opcji obok pola tekstowego. */
.pow-lokalizacja{display:flex;width:100%;align-items:center;justify-content:center;gap:9px;
  padding:0 18px;margin:0 0 10px}
.pow-lokalizacja svg{flex:0 0 auto}

/* ── Skórki: co zależy od wyboru poza samą paletą ─────────────────────────
   Zdecydowana większość różnic między skórkami mieści się w zmiennych na
   :root (ustawia je skorka.js). Zostają dwie rzeczy, których kolorem nie da
   się załatwić — i one są tutaj. */

/* MONOCHROMATYCZNA. Sama paleta nie wystarczy: feed w 90% składa się ze zdjęć
   wydawców, więc „czarno-biała" z kolorowymi fotografiami byłaby obietnicą
   złamaną przy pierwszej karcie. Filtr obejmuje też miniatury na profilu
   redakcji i logotypy — inaczej szara karta miałaby kolorową plamkę w rogu. */
html[data-skorka="mono"] .card-bg img,
html[data-skorka="mono"] .kafel img,
html[data-skorka="mono"] .profil-logo img,
html[data-skorka="mono"] .wynik-logo img{filter:grayscale(1)}

/* JASNA — skórka „dla starszych oczu". Kontrast załatwia paleta, ale sam
   kontrast nie czyni tekstu czytelnym, jeśli ma 11 px. Podnosimy rozmiary
   tam, gdzie stoi TREŚĆ (skrót, lead, etykiety), zostawiając nietknięte
   nagłówki — te są już duże i wzrost rozpychałby karty.
   Zdejmujemy też przygaszenie pozycji menu: `opacity:.75` odbiera realny
   kontrast dokładnie tym elementom, których ktoś szuka po omacku. */
html[data-skorka="jasna"] .card p,
html[data-skorka="jasna"] .points li{font-size:17px;line-height:1.5}
html[data-skorka="jasna"] .meta,
html[data-skorka="jasna"] .reklama-licznik{font-size:13.5px}
html[data-skorka="jasna"] .tag,
html[data-skorka="jasna"] .tag.zrodlo-temat button,
html[data-skorka="jasna"] .act-n{font-size:12.5px}
/* Skórka jasna jest „dla starszych oczu" i podnosi rozmiary wszędzie; po
   powiększeniu bazy do 17 px trzyma ten sam skok o ~1 px, żeby nie rozepchnąć
   szuflady ponad jej 300 px. */
html[data-skorka="jasna"] .lang-menu .menu-link{font-size:18px;opacity:1}
html[data-skorka="jasna"] .lang-menu button{font-size:18px}
html[data-skorka="jasna"] .arkusz p,
html[data-skorka="jasna"] .szukaj-info{font-size:15.5px}
/* Ekran powitalny w skorce jasnej. Skorka obiecuje „wieksze litery", wiec musi
   objac takze PIERWSZY ekran aplikacji — a nie obejmowala go wcale. Do wczoraj
   nie bylo tego widac, bo reguly `.pow-*` mialy niepoprawny skrot `font:`
   i przegladarka odrzucala je w calosci: powitanie renderowalo sie PRZYPADKIEM
   w 16 px. Po naprawie skrotu zeszlo do zadeklarowanych 13-15 px i czytelnik,
   ktory wybral skorke dla slabszego wzroku, dostawal na wejsciu drobniejszy
   tekst niz wczesniej. Ponizsze rozmiary przywracaja obietnice skorki. */
html[data-skorka="jasna"] .pow-krok h2{font-size:26px}
html[data-skorka="jasna"] .pow-krok p{font-size:16.5px;line-height:1.5}
html[data-skorka="jasna"] .pow-opcja{font-size:16px}
html[data-skorka="jasna"] .pow-glowny{font-size:17px}
html[data-skorka="jasna"] .pow-pomin{font-size:15.5px}
html[data-skorka="jasna"] .pow-redakcja-nazwa{font-size:16px}
html[data-skorka="jasna"] .pow-obserwuj{font-size:14.5px}
/* Cień pod tekstem na zdjęciu jest przy jasnym welonie ŚWIATŁEM, nie cieniem —
   rozlewa się i zjada ostrość liter. Welon 94% i tak niesie czytelność. */
html[data-skorka="jasna"] .card h2,
html[data-skorka="jasna"] .card p,
html[data-skorka="jasna"] .points li{text-shadow:none}

/* ── Panel wyboru skórki ──────────────────────────────────────────────────
   Lista wyborów z PRÓBKĄ, nie sama nazwa: „monochromatyczna" i „stonowana"
   nic nie mówią, dopóki się ich nie zobaczy, a przełączanie w ciemno po to,
   żeby sprawdzić, jak wygląda, to nie jest wybór. */
.skorka-lista{display:grid;gap:8px}
.skorka-opcja{display:flex;align-items:center;gap:12px;width:100%;min-height:56px;
  padding:9px 12px;border-radius:14px;border:1px solid var(--kreska);
  background:var(--powierzchnia);color:inherit;cursor:pointer;text-align:left;font:inherit}
.skorka-opcja.on{border-color:var(--akcent);box-shadow:inset 0 0 0 1px var(--akcent)}
/* Próbka pokazuje trzy kolory naraz — tło, tekst na nim i akcent. To dokładnie
   te trzy, których dotyczą progi kontrastu niżej. */
/* Napis „Aa" w próbce był martwy z tego samego powodu (`inherit` w skrócie
   `font`) i rysował się w wadze 400. Próbka ma pokazywać, jak w danej skórce
   wygląda TEKST na jej tle — a pokazywała cieńszy krój niż jakikolwiek napis
   w aplikacji. Rozmiar 13 px z interlinią 1 mieści się w pudełku 46×34 px. */
.skorka-probka{flex:0 0 auto;width:46px;height:34px;border-radius:10px;
  display:flex;align-items:center;justify-content:center;
  font-family:inherit;font-weight:800;font-size:13px;line-height:1}
.skorka-tresc{min-width:0;flex:1 1 auto}
.skorka-nazwa{display:block;font-size:14.5px;font-weight:700}
.skorka-opis{display:block;font-size:12px;opacity:.72;line-height:1.3;margin-top:2px}
/* Ptaszek z dwóch krawędzi obróconego pudełka — bez zależności od kroju pisma. */
.skorka-ptaszek{flex:0 0 auto;width:15px;height:8px;margin:0 5px 6px 0;
  border-left:3px solid var(--akcent-tekst);border-bottom:3px solid var(--akcent-tekst);
  transform:rotate(-45deg)}

.skorka-edytor{margin:14px 0 0;display:grid;gap:4px}
.skorka-rzad{display:flex;align-items:center;justify-content:space-between;gap:12px;
  min-height:46px;font-size:14.5px}
.skorka-rzad em{display:block;font-style:normal;font-size:11.5px;opacity:.6;line-height:1.3}
/* 52×36 px, bo natywny próbnik koloru to cel dotykowy jak każdy inny — poniżej
   44 px trzeba w niego celować. */
.skorka-rzad input[type=color]{flex:0 0 auto;width:52px;height:36px;padding:0;
  border:1px solid var(--kreska);border-radius:10px;background:none;cursor:pointer}
.skorka-kontrast{margin:12px 0 0;font-size:12px;line-height:1.5;opacity:.78}
.skorka-kontrast b{font-weight:700}
/* Ostrzeżenie NIE BLOKUJE wyboru — mówi, co się stanie. Kolor `--uwaga`, ten
   sam, którym mówimy „odmowa niczego nie psuje": to jest informacja, a nie błąd. */
.skorka-alarm{margin:10px 0 0;padding:9px 11px;border-radius:10px;
  border:1px solid var(--uwaga);color:var(--uwaga);font-size:12.5px;line-height:1.45}
.skorka-alarm:empty{display:none}

/* Rząd wyszukiwarki: wyjście, pole, czyszczenie. Ikony mają 44 px pola dotyku
   (kanon floty) mimo mniejszego rysunku — inaczej trafienie w krzyżyk kciukiem
   przy trzymaniu telefonu jedną ręką jest loterią. */
.szukaj-rzad{display:flex;align-items:center;gap:8px}
.szukaj-rzad .szukaj-pole{flex:1 1 auto;min-width:0}
.szukaj-ikona{flex:0 0 auto;width:44px;height:44px;display:flex;align-items:center;
  justify-content:center;border:0;border-radius:12px;background:transparent;
  color:var(--tekst,#f4f2ef);cursor:pointer}
.szukaj-ikona svg{width:22px;height:22px}
.szukaj-ikona:active{background:rgba(255,255,255,.12)}
/* Natywny krzyżyk przeglądarki chowamy — mamy własny, ten sam na każdym systemie. */
.szukaj-pole::-webkit-search-cancel-button{display:none}

/* Krzyżyk zamknięcia arkusza. Prawy górny róg, 44 px pola dotyku (kanon floty),
   nad treścią — arkusze bywają przewijane i przycisk musi zostać na widoku. */
.arkusz-zamknij{position:sticky;top:0;float:right;z-index:2;width:44px;height:44px;
  margin:-6px -6px 0 0;display:flex;align-items:center;justify-content:center;
  border:0;border-radius:12px;background:transparent;color:var(--tekst,#f4f2ef);cursor:pointer}
.arkusz-zamknij svg{width:20px;height:20px}
.arkusz-zamknij:active{background:rgba(127,127,127,.22)}

/* WSKAŹNIK POZYCJI ------------------------------------------------------- */
.pozycja{
  position:fixed; right:10px; top:calc(var(--top-h,52px) + var(--tabs-h,44px) + 8px);
  z-index:32; padding:4px 10px; border-radius:999px;
  background:rgba(0,0,0,.62); color:#fff; font-size:12px; font-weight:600;
  font-variant-numeric:tabular-nums; letter-spacing:.02em;
  backdrop-filter:blur(6px); -webkit-backdrop-filter:blur(6px);
  pointer-events:none; opacity:0; transition:opacity .18s ease;
}
.pozycja.widac{opacity:1}
@media (prefers-reduced-motion:reduce){.pozycja{transition:none}}

/* Karta pustego stanu wyśrodkowana w pionie. Zwykłe karty dosuwają treść do
   DOŁU (tekst ma stać nad kciukiem, pod zdjęciem), ale komunikat „nie masz tu
   jeszcze nic" nie ma nad sobą zdjęcia — dziedziczone dosunięcie zostawiało
   trzy czwarte ekranu pustki i wyglądało na niedoładowany widok. */
.card.pusty{justify-content:center}

/* ── NAZWANE KOLEKCJE ─────────────────────────────────────────────────────
   Trzy podstrony (lista kolekcji, jedna kolekcja, wybór kolekcji dla
   materiału) stoją na tym samym szkielecie co wyszukiwarka: jedna karta na
   cały ekran, przyklejony nagłówek, przewija się tylko treść. Nic tu nie jest
   modalem — klik prowadzi do widoku, gest wstecz wraca.

   KOLORY WYŁĄCZNIE TOKENAMI, ani jednego gołego hexa. `--akcent` to kolor
   AKCJI (przycisk główny). Stan „materiał jest w tej kolekcji" idzie tokenem
   `--zapis`/`--na-zapisie` — tym samym, którym świeci zapalona zakładka na
   karcie feedu (`.act.on.save`), więc ten sam kolor znaczy w całej aplikacji
   to samo. `--akcent2` („60" z logo) obrysowuje klikalny dymek. */
.kolekcje-tytul{font-size:17px;font-weight:800;margin:0;flex:1 1 auto;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kolekcje-opis{font-size:13px;opacity:.65;margin:12px 0 4px;line-height:1.45}
.kolekcje-tresc{display:flex;flex-direction:column;gap:10px;padding-bottom:24px}
.kolekcje-lista{display:flex;flex-direction:column;gap:6px}

/* Wiersz „nowa kolekcja": pole i przycisk w jednej linii. Przycisk nie zwęża
   się poniżej własnego tekstu (flex:0 0 auto) — inaczej przy dłuższym napisie
   w ukraińskim łamał się na dwie linie i tracił wysokość celu dotykowego. */
.kolekcja-nowa{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.kolekcja-nowa .szukaj-pole{flex:1 1 140px;min-width:0}

/* Cel dotykowy 44 px — wszystkie przyciski kolekcji, bez wyjątku. */
.kolekcja-btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  min-height:44px;padding:0 16px;border-radius:12px;flex:0 0 auto;
  background:rgba(127,127,127,.16);color:var(--tekst);font-size:14px;font-weight:700}
.kolekcja-btn svg{width:17px;height:17px;flex:0 0 auto}
.kolekcja-btn:active{background:rgba(127,127,127,.28)}
.kolekcja-btn.glowny{background:var(--akcent);color:var(--na-akcencie)}
.kolekcja-btn.ostrzega{color:var(--akcent-tekst)}
.kolekcja-btn[disabled]{opacity:.55}

.kolekcja-narzedzia{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:2px 0 6px}
.kolekcja-narzedzia .szukaj-pole{flex:1 1 160px;min-width:0}
.kolekcja-pytanie{flex:1 0 100%;margin:0;font-size:13px;line-height:1.45;opacity:.8}

/* Wiersz kolekcji na liście. 56 px wysokości, cała powierzchnia klikalna. */
.kolekcja-wiersz{display:flex;align-items:center;gap:12px;width:100%;
  min-height:56px;padding:8px 12px;border-radius:14px;text-align:left;
  background:rgba(127,127,127,.12)}
.kolekcja-wiersz:active{background:rgba(127,127,127,.24)}
.kolekcja-wiersz > svg{width:18px;height:18px;flex:0 0 auto;opacity:.5}
.kolekcja-ikona{flex:0 0 auto;width:38px;height:38px;border-radius:12px;
  display:flex;align-items:center;justify-content:center;background:rgba(127,127,127,.18)}
.kolekcja-ikona svg{width:19px;height:19px}
.kolekcja-opis{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;gap:2px}
.kolekcja-opis b{font-size:15px;font-weight:700;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.kolekcja-opis span{font-size:12px;opacity:.6;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Przełącznik w widoku wyboru: stan „materiał jest w tej kolekcji" niesie
   ZARÓWNO kolor, JAK I ikonę (ptaszek). Sam kolor byłby niewidoczny dla osoby
   nierozróżniającej barw, a to jest jedyna informacja na tym ekranie. */
.kolekcja-wiersz.przelacznik.on{background:rgba(127,127,127,.2)}
.kolekcja-wiersz.przelacznik.on .kolekcja-ikona{background:var(--zapis);color:var(--na-zapisie)}
.kolekcja-wiersz.przelacznik.on .kolekcja-opis b{color:var(--zapis)}

/* Materiał w kolekcji: miniatura + tytuł, obok osobny przycisk wyjęcia.
   Dwa osobne cele dotykowe zamiast gestu przesunięcia — gest byłby niewidoczny
   i kolidował z przewijaniem listy. */
.kolekcja-material{display:flex;align-items:center;gap:6px;
  border-radius:14px;background:rgba(127,127,127,.12)}
.kolekcja-material-klik{display:flex;align-items:center;gap:12px;flex:1 1 auto;min-width:0;
  min-height:56px;padding:8px 4px 8px 8px;text-align:left}
.kolekcja-mini{flex:0 0 auto;width:52px;height:52px;border-radius:10px;overflow:hidden;
  background:rgba(127,127,127,.18)}
.kolekcja-mini.noimg{background:linear-gradient(150deg,var(--g1,var(--karta)),var(--g2,var(--tlo)))}
.kolekcja-mini img{width:100%;height:100%;object-fit:cover}
.kolekcja-material .kolekcja-opis b{white-space:normal;display:-webkit-box;
  -webkit-line-clamp:2;-webkit-box-orient:vertical;font-size:14px;line-height:1.3}
.kolekcja-wyjmij{flex:0 0 auto;width:44px;height:44px;margin-right:4px;border-radius:12px;
  display:flex;align-items:center;justify-content:center;opacity:.6}
.kolekcja-wyjmij svg{width:18px;height:18px}
.kolekcja-wyjmij:active{background:rgba(127,127,127,.24);opacity:1}
/* Ta sama zapora, co przy `.card h2`: to również jest SUROWY tytuł materiału,
   a nie tekst pisany przez nas. Bez obcięcia 272-znakowy tytuł spycha listę
   kolekcji poniżej krawędzi ekranu — czytelnik widzi nagłówek „co odkładasz"
   i żadnej kolekcji do wyboru. Trzy wiersze wystarczą do rozpoznania materiału. */
.kolekcja-material-tytul{margin:10px 0 2px;font-size:14px;font-weight:700;line-height:1.35;
  overflow-wrap:anywhere;
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.kolekcja-material .kolekcja-opis b{overflow-wrap:anywhere}

/* Dymek, który jest DROGĄ DALEJ („Zapisano · Wybierz kolekcję"), a nie samym
   komunikatem: obrys akcentem mówi, że da się go dotknąć, a 44 px wysokości
   robi z niego prawdziwy cel dotykowy. */
.toast-klik{cursor:pointer;min-height:44px;display:flex;align-items:center;justify-content:center;
  border-color:var(--akcent2)}
.toast-klik:active{background:var(--kreska)}

/* ── Wersja wdrożenia (stopka szuflady) ─────────────────────────────────────
   Napis techniczny w interfejsie czytelnika, więc świadomie NAJCICHSZY element
   menu: mała czcionka, przygaszony kolor, kreska oddzielająca go od poleceń.
   Ma być do znalezienia, kiedy się go szuka, i niewidoczny, kiedy się go nie
   szuka.

   Selektor celowo z `html` na początku. Skórka jasna podnosi rozmiar pisma
   regułą `html[data-skorka="jasna"] .lang-menu button{font-size:18px}` — bez
   wyrównania wagi wersja rozpychałaby się w niej na 18 px, czyli tak samo jak
   „Polubione". Ta sama pułapka co z kolejnością reguł opisana wyżej w pliku.

   `min-height` NIE ustawiamy na 44 px z rozmysłem: cel dotykowy 44 px należy
   się rzeczom, które czytelnik ma trafić, a tę pozycję dotyka się wyłącznie
   po to, żeby skopiować numer — i ma ona wtedy trzy linijki tekstu, więc
   naturalną wysokość i tak przekracza. */
html .lang-menu button.menu-wersja{
  display:flex;flex-direction:column;gap:2px;align-items:flex-start;
  margin-top:6px;padding:10px 14px;border-top:1px solid var(--kreska);
  border-radius:0;font-size:12px;line-height:1.45;opacity:.62;
  background:none;text-align:left;
}
html .lang-menu button.menu-wersja:hover{background:rgba(var(--tekst-rgb),.06);opacity:.9}
html .lang-menu button.menu-wersja:active{background:rgba(var(--tekst-rgb),.12);opacity:1}
/* Skrót commita i numer powłoki — to JEST treść tej pozycji, więc czcionka
   o stałej szerokości: `d2efdb3` czyta się z ekranu telefonu i przepisuje do
   `git show` bez zgadywania, czy to „l" czy „1". */
/* `overflow-wrap:anywhere`, NIE `word-break:break-all`. To drugie łamie gdzie
   popadnie i zmierzone dawało „n60-shel / l-v56" — numer powłoki przecięty
   w środku, czyli dokładnie ta jedna rzecz, którą się z tego napisu przepisuje.
   `anywhere` najpierw korzysta ze spacji, a w środek wyrazu wchodzi dopiero
   wtedy, gdy inaczej się nie da. */
.menu-wersja-glowna{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  font-size:12.5px;font-weight:600;letter-spacing:.01em;overflow-wrap:anywhere}
.menu-wersja-drobne{font-size:11.5px;opacity:.8}
/* Ostrzeżenia w kolorze akcentu, nie na czerwono: rozjazd obrazu z assetami
   jest normalnym skutkiem poprawki interfejsu bez przebudowy, a nie awarią.
   Czerwień kazałaby szukać usterki tam, gdzie jej nie ma. */
.menu-wersja-uwaga{font-size:11.5px;color:var(--akcent-tekst);opacity:.95;word-break:break-word}


/* ── WIDOK LISTOWY „ZAPISANYCH" I „POLUBIONYCH" ─────────────────────────────
   Feed jest stosem pełnoekranowych kart, bo tam się PRZEGLĄDA. Do własnej listy
   wchodzi się po JEDNĄ rzecz, którą się tam wcześniej odłożyło — a wtedy
   dziesięć tytułów na ekranie bije jeden. Ta sama zasada, którą kierują się
   kolekcje; wybór zostaje jednak przy czytelniku, bo „Zapisane" są w aplikacji
   od zawsze i nie wolno ich komuś zabrać jedną zmianą wydania. */
/* PASEK STERUJĄCY PRZYKLEJONY POD GÓRNYM PASKIEM.
   Górny pasek aplikacji jest `position:fixed`, więc pierwszy element treści
   wsuwa się pod niego — zmierzone na produkcji: przełącznik „Karty/Lista"
   zniknął całkowicie za logo. Odstęp liczony tą samą formułą co wysokość
   paska (`safe-area` + 12 + 12 + wysokość wiersza ikon ≈ 44 px), a nie
   wpisaną liczbą: na telefonie z wcięciem ekranu stała wartość rozjeżdża się
   dokładnie na tych urządzeniach, na których błąd najbardziej przeszkadza.
   `sticky`, nie `static` — przy 39 pozycjach przełącznik i sprzątanie mają
   zostać pod ręką, a nie odjechać w górę po pierwszym przewinięciu. */
.lista-pasek{position:sticky;top:0;z-index:20;background:var(--tlo);
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
  padding:calc(env(safe-area-inset-top) + 68px) 14px 12px;
  border-bottom:1px solid var(--kreska)}
.lista-przel{display:flex;gap:6px}
.lista-przel-btn{min-height:44px;padding:8px 16px;border-radius:99px;
  border:1px solid var(--kreska);background:none;color:var(--tekst);
  font:700 13px Archivo,system-ui,sans-serif;cursor:pointer}
.lista-przel-btn[aria-pressed="true"]{background:var(--akcent2);
  color:var(--na-akcencie2);border-color:var(--akcent2)}
/* Sprzątanie NIE jest limonkowe: limonka w tej aplikacji znaczy „to jest
   właściwe wyjście", a usuwanie własnych rzeczy nie ma być zaproszeniem.
   Zwykła obwódka, pełne brzmienie na przycisku, potwierdzenie w oknie. */
.lista-sprzataj{margin-left:auto;min-height:44px;padding:8px 14px;border-radius:99px;
  border:1px solid var(--kreska);background:none;color:var(--przygas);
  font:600 12.5px Archivo,system-ui,sans-serif;cursor:pointer}
.lista-sprzataj:disabled{opacity:.5}
.lista-zbior{display:flex;flex-direction:column}
.lista-wiersz{display:flex;align-items:flex-start;gap:12px;width:100%;
  min-height:44px;padding:12px 14px;border:0;border-bottom:1px solid var(--kreska);
  background:none;color:inherit;text-align:left;cursor:pointer;font:inherit}
/* Numer cyframi tabelarycznymi — inaczej „1" i „10" mają różną szerokość
   i tytuły w kolejnych wierszach zaczynają się w innych miejscach. */
.lista-numer{flex:0 0 auto;min-width:26px;font-variant-numeric:tabular-nums;
  font:800 15px Archivo,system-ui,sans-serif;color:var(--przygas);padding-top:1px}
.lista-tresc{display:flex;flex-direction:column;gap:4px;min-width:0}
.lista-tytul{font:700 15.5px/1.3 Archivo,system-ui,sans-serif;overflow-wrap:anywhere}
.lista-meta{display:flex;gap:10px;flex-wrap:wrap;color:var(--przygas);
  font:600 12px Archivo,system-ui,sans-serif}
.lista-kiedy{white-space:nowrap}

/* ── MENU ZGŁOSZENIA NA KARCIE ───────────────────────────────────────────────
   Wysuwa się przy kolumnie akcji, a nie na środku ekranu: kciuk jest już tam,
   gdzie stuknął w „⋯", i nie musi wracać. Nad kartą, ale BEZ zasłony całego
   ekranu — zasłona przy karcie pełnoekranowej czyta się jak zablokowana
   aplikacja, a to jest menu, nie decyzja nie do cofnięcia. */
/* „−" zamiast „⋯": ten sam rozmiar celu, inny znak. Minus rysowany fontem
   bywa cienki i na okrągłym tle ginie — stąd waga 900 i lekkie podniesienie
   stopnia pisma względem poprzedniej ikony. */
.act-wiecej .act-ic{font-size:26px;line-height:1;font-weight:900}
/* Pozycja „mniej takich" wyróżniona: to jedyna rzecz w tym menu, która działa
   NATYCHMIAST i widocznie (karta znika). Zgłoszenia nie dają efektu na ekranie,
   więc gdyby wyglądały tak samo, czytelnik szukałby po nich zmiany. */
.karta-menu-mniej{font-weight:800}
/* Drugi nagłówek dostaje kreskę nad sobą — bez niej „Zgłoś ten materiał"
   wyglądałby na podpis pozycji wyżej, a nie na początek innej grupy. */
.karta-menu-tyt2{border-top:1px solid var(--kreska);margin-top:2px;padding-top:11px}
.karta-menu{position:absolute;right:64px;bottom:96px;z-index:40;
  min-width:212px;max-width:min(78vw,300px);
  background:var(--powierzchnia);border:1px solid var(--kreska);border-radius:14px;
  box-shadow:0 12px 34px rgba(0,0,0,.45);overflow:hidden;
  display:flex;flex-direction:column}
.karta-menu-tyt{padding:11px 14px 7px;font:800 12px Archivo,system-ui,sans-serif;
  letter-spacing:.04em;text-transform:uppercase;color:var(--przygas)}
.karta-menu-poz{min-height:44px;padding:11px 14px;border:0;background:none;
  color:var(--tekst);text-align:left;font:600 15px Archivo,system-ui,sans-serif;
  cursor:pointer;border-top:1px solid var(--kreska)}
.karta-menu-poz:hover,.karta-menu-poz:focus-visible{background:var(--karta)}
/* Przypis, nie pozycja menu: wyjaśnia, co się stanie, i nie da się w niego
   kliknąć. Bez tego zdania czytelnik zgłasza w ciemno i wraca sprawdzać,
   czy materiał zniknął. */
.karta-menu-stopka{padding:9px 14px 11px;border-top:1px solid var(--kreska);
  font:500 11.5px/1.4 Archivo,system-ui,sans-serif;color:var(--przygas)}
@media (max-width:420px){ .karta-menu{right:56px;bottom:88px} }

/* ── KARTA ROZDZIELAJĄCA „POZA TWOJĄ OKOLICĄ" ───────────────────────────────
   NIŻSZA NIŻ KARTA MATERIAŁU i celowo: to jest drogowskaz, nie treść. Gdyby
   zajmowała cały ekran, czytelnik przewijałby przez nią jak przez materiał
   i miałby wrażenie, że feed wstawia mu puste karty. Zatrzymanie kadru
   (`scroll-snap-align`) zostaje, żeby nie przelatywała niezauważona. */
.rozdzielnik{scroll-snap-align:start;scroll-snap-stop:normal;
  min-height:46dvh;display:flex;flex-direction:column;justify-content:center;
  gap:8px;padding:28px 22px calc(env(safe-area-inset-bottom) + 24px);
  background:var(--powierzchnia);border-top:1px solid var(--kreska);
  border-bottom:1px solid var(--kreska)}
.rozdzielnik-nad{font:700 11.5px Archivo,system-ui,sans-serif;letter-spacing:.09em;
  text-transform:uppercase;color:var(--przygas)}
.rozdzielnik-tyt{font:800 24px/1.2 Archivo,system-ui,sans-serif;letter-spacing:-.4px;
  text-wrap:balance}
.rozdzielnik-opis{font:500 14.5px/1.45 Archivo,system-ui,sans-serif;color:var(--przygas);
  max-width:34ch}
.rozdzielnik-btn{align-self:flex-start;margin-top:8px;min-height:44px;
  padding:11px 20px;border-radius:99px;border:0;cursor:pointer;
  background:var(--akcent2);color:var(--na-akcencie2);
  font:800 14px Archivo,system-ui,sans-serif}
/* Powrót jest KRÓTSZY i cichszy — to potwierdzenie, że wracamy, a nie nowy
   rozdział. Wyrównany rozmiar z „wyjściem" sugerowałby drugą decyzję. */
.rozdzielnik.wraca{min-height:22dvh;padding:20px 22px}
.rozdzielnik.wraca .rozdzielnik-tyt{font-size:18px;color:var(--przygas);font-weight:700}
