/* tp_atelier — assets/css/styles.css
   PLIK GENEROWANY z partiali w template-parts/scss.
   Nie edytuj go ręcznie — poprawki idą do partiala, potem:
   python3 narzedzia/zbuduj-arkusz.py
   Kolejność partiali: main.scss */

/*
 * Kroje hostowane lokalnie — zero połączeń do CDN Google.
 *
 * Powód jest podwójny: RODO (brak wysyłania adresu IP czytelnika do
 * Google przy każdym wejściu) oraz wydajność — arkusz z fonts.googleapis.com
 * blokował renderowanie i kosztował dodatkowe połączenie do drugiego hosta.
 *
 * Subsety: latin + latin-ext (polskie znaki diakrytyczne są w latin-ext).
 * Pliki wygenerowane przez tools/makieta/fonts.cjs — nie edytować ręcznie.
 *
 * Lora i Public Sans są na licencji SIL Open Font License 1.1.
 */

/* ==========================================================================
   ATELIER — motyw blogowy moda / uroda dla sieci Traffic Peaks
   Makieta koncepcyjna. Nazwa robocza motywu: tp-atelier
   (nie `tp_theme_maker` — patrz pułapka podmiany src→data-src w TP WP plugin).

   Kolejność sekcji: tokeny → reset → typografia → układ → nagłówek →
   ściana (masonry) → kafel → sekcje strony głównej → archiwum → wpis →
   panel boczny → dane (skaner, rankingi, quiz) → stopka → panel kolorów → druk.

   Konfigurowalne są DWA kolory: --brand i --accent. Cała reszta palety
   liczy się z nich przez color-mix(). Szarości są stałe i nie podlegają
   konfiguracji, żeby bloga nie dało się zepsuć jednym kliknięciem.
   Bez trybu dzień/noc — jeden dopracowany wygląd.
   ========================================================================== */

/* ==========================================================================
   1. TOKENY
   ========================================================================== */

:root {
  /* --- DWA KOLORY Z CUSTOMIZERA ----------------------------------------- */
  --brand:  #5C2E3E;   /* śliwka   — identyfikacja, linki, nagłówki sekcji */
  --accent: #C0693F;   /* terakota — wyróżnienia, dane, stany aktywne      */

  /* Kolor tekstu NA kolorze liczy PHP z luminancji (w makiecie: app.js),
     więc przycisk zdaje WCAG AA niezależnie od tego, co wybierze klient.   */
  --brand-ink:  #fff;
  --accent-ink: #fff;

  /* --- pochodne — nic do ustawiania ręcznie ------------------------------ */
  --brand-900: color-mix(in oklab, var(--brand), #000 42%);
  --brand-700: color-mix(in oklab, var(--brand), #000 18%);
  --brand-300: color-mix(in oklab, var(--brand), #fff 55%);
  --brand-100: color-mix(in oklab, var(--brand), #fff 88%);
  --brand-050: color-mix(in oklab, var(--brand), #fff 95%);

  --accent-900: color-mix(in oklab, var(--accent), #000 40%);
  --accent-700: color-mix(in oklab, var(--accent), #000 18%);
  --accent-300: color-mix(in oklab, var(--accent), #fff 58%);
  --accent-100: color-mix(in oklab, var(--accent), #fff 88%);
  --accent-050: color-mix(in oklab, var(--accent), #fff 95%);

  /* akcent bywa jasny (musztarda, limonka) — wersja czytelna na papierze */
  --brand-text:  color-mix(in oklab, var(--brand), #000 12%);
  --accent-text: color-mix(in oklab, var(--accent), #000 30%);

  /* --- neutralne (stałe) ------------------------------------------------- */
  --paper:   #FFFFFF;
  --paper-2: #FAF9F7;   /* ciepła kość słoniowa — tło sekcji              */
  --paper-3: #F1EEEA;
  --ink:     #16141A;
  --ink-2:   #4A4650;
  --ink-3:   #6E6973;
  --rule:    #E6E2DD;
  --rule-2:  #D3CDC6;

  /* --- semantyczne ------------------------------------------------------- */
  --ok:   #2C6B4F;
  --uwaga:#8A5A12;
  --stop: #A32C1F;
  --mit:  #4A5A8A;

  /* --- kroje (hostowane lokalnie — zero połączeń do CDN Google) ---------- */
  --font-serif: 'Lora', Georgia, 'Times New Roman', serif;
  --font-sans:  'Public Sans', -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
  --font-mono:  ui-monospace, 'Cascadia Mono', Consolas, monospace;

  /* --- skala typograficzna ---------------------------------------------- */
  --fs-masthead: clamp(2.4rem, 7vw, 4.6rem);
  --fs-display:  clamp(2rem, 4.2vw, 3.4rem);
  --fs-h1:       clamp(1.75rem, 3.2vw, 2.6rem);
  --fs-h2:       clamp(1.35rem, 2.2vw, 1.85rem);
  --fs-h3:       clamp(1.1rem, 1.5vw, 1.3rem);
  --fs-lead:     clamp(1.0625rem, 1.4vw, 1.1875rem);
  --fs-body:     1.0625rem;
  --fs-sm:       0.875rem;
  --fs-xs:       0.75rem;
  --fs-micro:    0.6875rem;

  /* --- siatka 8 pt ------------------------------------------------------- */
  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;
  --s9: 96px; --s10: 128px;

  --wrap: 1360px;
  /* Miara kolumny tekstu. 720 px przy akapicie 17 px to 84 znaki w wierszu —
     powyżej progu, na którym oko gubi początek następnej linii (wygodnie
     czyta się 45–75). 620 px daje ~72 znaki i tyle zostaje. Jednostka ch nie
     nadaje się tutaj: liczy się od kroju .tresc, a akapity mają własny. */
  --wrap-tekst: 620px;

  /* --- ściana zdjęć ------------------------------------------------------ */
  --rytm: 8px;          /* wysokość jednego wiersza siatki masonry */
  --przerwa: 20px;      /* odstęp między kaflami                   */
  --kolumny: 4;

  --radius: 2px;
  --cien-1: 0 1px 2px rgba(22, 20, 26, .05);
  --cien-2: 0 4px 24px rgba(22, 20, 26, .10);
  --cien-3: 0 24px 64px rgba(22, 20, 26, .20);

  --ease: cubic-bezier(.22, .68, .3, 1);
}

/* ==========================================================================
   2. RESET
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }

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

@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img, svg, picture { display: block; max-width: 100%; }

img { height: auto; }

button, input, select, textarea { font: inherit; color: inherit; }

button { cursor: pointer; }

/* Hover NIE zmienia koloru tekstu. Zmiana barwy na kafelku ze zdjęciem
   robiła z białego tytułu ciemny napis na ciemnym kadrze — nieczytelny.
   Sygnałem najechania jest podkreślenie, które działa na każdym tle.      */

a { color: var(--brand-text); text-decoration-thickness: 1px; text-underline-offset: 3px; }

a:hover { text-decoration-thickness: 2px; }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 1px;
}

::selection { background: var(--accent-100); color: var(--ink); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--ink); color: #fff; padding: var(--s3) var(--s5);
  font-size: var(--fs-sm);
}

.skip:focus { left: 0; }

.tylko-czytnik {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ==========================================================================
   3. TYPOGRAFIA
   ========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--font-serif);
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
}

/* Baza rytmu, a po niej wyjątki. Wszystkie mają tę samą specyficzność,
   więc decyduje kolejność — od ogólnego do szczegółowego.            */

.tresc > * + * { margin-top: var(--s6); }

@media print {
  .nawigacja, .cfg, .baner, .baner-top, .panel, .pasek-czytania, .do-gory,
  .kafel--wiecej, .sek-glowa__link, .stopka__linki, .okruszki {
    display: none !important;
  }

  /* Druk czyta się z kartki: czarny tekst na bieli, bez tła i cieni. */
  :root { --paper: #fff; --paper-2: #fff; --ink: #000; --ink-2: #222; }
  body { background: #fff; color: #000; }
  .wrap, .wrap--wpis { width: auto; max-width: none; padding: 0; }
  .kafel, .karta, .cytat, .nota { box-shadow: none; break-inside: avoid; }
  img { max-width: 100%; }

  /* Adres linku obok treści — na papierze sam podkreślnik nic nie mówi. */
  .tresc a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 90%; }

  h1, h2, h3 { break-after: avoid; }
  p, li, figure { orphans: 3; widows: 3; }
}

/* Slot banerowy 1150×90 / 728×90 / 300×50 — wymiary z Journala.
   Gdy kampanii nie ma, motyw nie wypisuje slotu w ogóle: ani piksela.       */

.baner {
  display: flex; align-items: center; justify-content: center;
  margin: var(--s5) auto 0;
  border: 1px dashed var(--rule-2); background: var(--paper-2);
  color: var(--ink-3); font-family: var(--font-mono); font-size: var(--fs-xs);
  letter-spacing: .18em;
}

.baner--1150 { width: 1150px; height: 90px; }

.baner--728 { width: 728px; height: 90px; }

.baner--300 { width: 300px; height: 50px; }

/* Trzy warianty banera nad menu. `display` stoi WYŁĄCZNIE na klasach
   wariantów — reguła ogólniejsza (np. `.baner-top img { display: block }`)
   miałaby wyższą specyficzność i pokazałaby wszystkie trzy grafiki naraz. */

.baner-top { display: flex; justify-content: center; }

.baner-top__desktop { display: flex; }

.baner-top__tablet,
.baner-top__mobil { display: none; }

@media (max-width: 1210px) {
  .baner-top__desktop { display: none; }
  .baner-top__tablet { display: flex; }
}

@media (max-width: 780px) {
  .baner-top__tablet { display: none; }
  .baner-top__mobil { display: flex; }
}

.naglowek { background: var(--paper); }

.winieta {
  display: grid; justify-items: center; gap: var(--s2);
  padding-block: var(--s6) var(--s5);
  text-align: center;
}

/* Winieta na stronie głównej jest nagłówkiem h1, ale ma wyglądać tak samo
   jak link na pozostałych stronach — dlatego zeruje własną typografię. */

.winieta__h1 { margin: 0; font: inherit; line-height: inherit; }

.winieta__logo {
  font-family: var(--font-serif);
  font-size: var(--fs-masthead);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: .95;
  color: var(--ink);
  text-decoration: none;
}

.winieta__logo em {
  font-style: italic;
  font-weight: 400;
  color: var(--brand);
}

.winieta__motto {
  font-size: var(--fs-micro); letter-spacing: .3em; text-transform: uppercase;
  color: var(--ink-3);
}

/* Nawigacja — dwie cienkie linie i litery rozstrzelone jak w magazynie */

.nawigacja {
  border-block: 1px solid var(--ink);
  position: sticky; top: 0; z-index: 40;
  background: var(--paper);
}

.nawigacja__inner { display: flex; align-items: center; justify-content: center; gap: var(--s6); position: relative; }

.nawigacja__lista {
  display: flex; gap: var(--s6); list-style: none; margin: 0; padding: 0;
  flex-wrap: wrap; justify-content: center;
}

.nawigacja__link {
  display: block; padding: var(--s3) 0;
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .14em;
  text-transform: uppercase; text-decoration: none; color: var(--ink);
  position: relative;
}

.nawigacja__link::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -1px;
  height: 2px; background: var(--brand); transform: scaleX(0);
  transition: transform .25s var(--ease); transform-origin: left;
}

.nawigacja__link:hover::after,
.nawigacja__link[aria-current]::after { transform: scaleX(1); }

/* Slot sprzedażowy w menu. Kropka przed nazwą odróżnia go od działów bloga
   bez krzykliwej etykiety — czytelniczka widzi, że to inny rodzaj pozycji. */

.nawigacja__link--sprzedazowy { color: var(--ink-3); }

.nawigacja__link--sprzedazowy::before {
  content: ''; display: inline-block;
  width: 5px; height: 5px; border-radius: 50%;
  background: var(--accent); margin-right: 7px; vertical-align: 1px;
}

.nawigacja__link--sprzedazowy:hover { color: var(--ink); }

/* --- PODMENU (drugi poziom Wygląd → Menu) -----------------------------
   Pozycja z dziećmi zachowuje własny link — kategoria nadrzędna musi być
   klikalna. Rozwijaniem steruje osobny przycisk obok, bo na dotyku
   „najechanie" nie istnieje i pierwsze dotknięcie linku tylko
   otwierałoby listę zamiast wejść w kategorię.                          */

.nawigacja__poz { position: relative; display: flex; align-items: center; }

.nawigacja__rozwin {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 44px; padding: 0; margin-left: 2px;
  border: 0; background: none; color: var(--ink-3);
}

.nawigacja__rozwin svg { width: 12px; height: 12px; transition: transform .2s var(--ease); }

.nawigacja__poz--ma-pod:hover .nawigacja__rozwin svg,
.nawigacja__rozwin[aria-expanded="true"] svg { transform: rotate(180deg); }

.podmenu {
  position: absolute; top: 100%; left: calc(var(--s4) * -1);
  min-width: 220px; margin: 0; padding: var(--s3) 0;
  list-style: none; z-index: 50;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-top: 2px solid var(--brand);
  box-shadow: var(--cien-2);
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity .18s var(--ease), transform .18s var(--ease), visibility 0s linear .18s;
}

.nawigacja__poz--ma-pod:hover .podmenu,
.nawigacja__poz--ma-pod:focus-within .podmenu,
.podmenu[data-otwarte="true"] {
  opacity: 1; visibility: visible; transform: none; transition-delay: 0s;
}

.podmenu__link {
  display: block; padding: var(--s2) var(--s5);
  font-size: var(--fs-sm); letter-spacing: .01em;
  text-transform: none; text-decoration: none; color: var(--ink-2);
}

.podmenu__link:hover { background: var(--brand-050); color: var(--ink); }

@media (prefers-reduced-motion: reduce) {
  .podmenu { transition: none; }
  .nawigacja__rozwin svg { transition: none; }
}

.nawigacja__narzedzia { position: absolute; right: 0; display: flex; gap: var(--s2); }

.ikonka {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  min-width: 44px; height: 44px; padding: 0 var(--s2);
  border: 0; background: none; color: var(--ink);
  font-size: var(--fs-xs); font-weight: 700;
}

.ikonka svg { width: 18px; height: 18px; }

.menu-przelacz { display: none; }

@media (max-width: 900px) {
  .nawigacja__inner { justify-content: space-between; }
  .nawigacja__lista {
    position: absolute; top: 100%; left: 0; right: 0;
    flex-direction: column; gap: 0; align-items: stretch;
    background: var(--paper); border-bottom: 1px solid var(--ink);
    padding: var(--s2) var(--s4) var(--s4);
    display: none;
  }
  .nawigacja[data-otwarte="true"] .nawigacja__lista { display: flex; }
  .nawigacja__poz { flex-wrap: wrap; }
  .nawigacja__poz .nawigacja__link { flex: 1; }
  .nawigacja__link { padding: var(--s3) 0; border-bottom: 1px solid var(--rule); letter-spacing: .1em; }
  /* Na wąskim ekranie podmenu nie wisi nad treścią — rozwija się w miejscu
     i przesuwa resztę listy w dół. Sterowanie tylko przyciskiem.        */
  .podmenu {
    position: static; opacity: 1; visibility: visible; transform: none; transition-delay: 0s;
    display: none; width: 100%; min-width: 0;
    border: 0; border-left: 2px solid var(--brand); box-shadow: none;
    margin: 0 0 var(--s2) var(--s3); padding: var(--s2) 0;
  }
  .podmenu[data-otwarte="true"] { display: block; }
  .nawigacja__poz--ma-pod:hover .podmenu { display: none; }
  .nawigacja__poz--ma-pod:hover .podmenu[data-otwarte="true"] { display: block; }
  .podmenu__link { padding: var(--s2) var(--s4); }
  .nawigacja__narzedzia { position: static; }
  .menu-przelacz { display: inline-flex; }
}

/* ==========================================================================
   7. ŚCIANA (masonry)

   Dlaczego nie `columns:` — układ wielokolumnowy CSS-a układa elementy
   w dół pierwszej kolumny, potem drugiej, więc kolejność czytania rozjeżdża
   się z kolejnością wizualną. To błąd WCAG 1.3.2 i chaos dla robota.
   Stąd CSS Grid + `grid-row-end: span N` liczone z proporcji kafla:
   kolejność DOM = kolejność wizualna = kolejność w indeksie.
   ========================================================================== */

.sciana {
  display: grid;
  grid-template-columns: repeat(var(--kolumny), minmax(0, 1fr));
  gap: var(--przerwa);
  align-items: start;
}

/* ==========================================================================
   MENU WIELOPOZIOMOWE — trzeci poziom i głębiej

   Makieta znała dwa poziomy: dział i podmenu wiszące pod nim. Ten motyw
   obsługuje dowolną głębokość z „Wygląd → Menu”, bo redakcja układa działy
   drzewem (Pielęgnacja → Twarz → Kwasy), a walker nie ma prawa uciąć
   gałęzi, której nie przewidział arkusz.

   Trzeci poziom NIE powtarza zachowania drugiego. Drugi spada w dół pod
   pozycję w pasku; trzeci wysuwa się w BOK, bo pod nim nie ma już miejsca
   w pasku, a spadanie w dół nakładałoby listę na listę.

   Mieszczenie się w oknie liczy skrypt (funkcja `ustawKierunki`
   w assets/js/scripts.js), nie arkusz: przy dziale stojącym z prawej
   strony paska panel wyjechałby za krawędź okna. Skrypt mierzy pozycję
   i przesuwa panel ujemnym marginesem o brakującą liczbę pikseli. Bez
   JS-a panel zostaje po prawej i w skrajnym przypadku wymaga przewinięcia
   — na węższych ekranach nie ma to zastosowania, bo tam wszystkie poziomy
   schodzą do akordeonu.
   ========================================================================== */

/* Pozycja podmenu, która ma własne dzieci — jak .nawigacja__poz, tylko
   o poziom niżej. Bez position:relative panel trzeciego poziomu liczyłby
   swoje left:100% od panelu drugiego, nie od wiersza. */
.podmenu__poz {
  position: relative;
  display: flex;
  align-items: stretch;
}

.podmenu__poz .podmenu__link {
  flex: 1;
  min-width: 0;
}

.podmenu__rozwin {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 32px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-3);
}

/* Strzałka pokazuje kierunek wysuwania: w bok, nie w dół. */
.podmenu__rozwin svg {
  width: 12px;
  height: 12px;
  transform: rotate(-90deg);
  transition: transform .2s var(--ease);
}

.podmenu__poz:hover > .podmenu__rozwin,
.podmenu__rozwin[aria-expanded="true"] {
  color: var(--brand);
}

.podmenu--glebokie {
  top: calc(var(--s3) * -1);
  left: 100%;
  border-top: 2px solid var(--accent);
}

/* Gdy z prawej brakuje miejsca, skrypt (`atl_menu` w scripts.js) przesuwa
   panel ujemnym `margin-left` o dokładnie brakującą liczbę pikseli. Nie ma
   tu klasy „wysuń w lewo”: przerzucenie panelu na drugą stronę pozycji
   kładło go na liście, z której wyszedł, i ścieżka przestawała być
   czytelna. Bez JS panel zostaje po prawej i w skrajnym przypadku wymaga
   przewinięcia — czytelne, tylko niewygodne. */

.podmenu__poz:hover > .podmenu--glebokie,
.podmenu__poz:focus-within > .podmenu--glebokie,
.podmenu--glebokie[data-otwarte="true"] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition-delay: 0s;
}

/* Czwarty poziom i dalej dostają ten sam wygląd co trzeci. Nie budujemy
   dla nich osobnych reguł — jeśli redakcja zejdzie tak głęboko, lepiej,
   żeby menu wyglądało nudno, niż żeby się rozsypało. Skrypt nadal je
   otwiera, bo działa na dowolnym `.podmenu` z przyciskiem. */
.podmenu .podmenu .podmenu {
  border-top-color: var(--rule-2);
}

/* --------------------------------------------------------------------------
   AKORDEON NA WĄSKIM EKRANIE

   Tu wszystkie poziomy zachowują się tak samo: rozwijają się w miejscu
   i przesuwają resztę listy w dół. Zagnieżdżenie widać po wcięciu i po
   kolorze kreski, a nie po kierunku wysuwania — na 360 px nie ma boku,
   w który dałoby się wysunąć cokolwiek.
   -------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .podmenu__poz { flex-wrap: wrap; }

  .podmenu--glebokie {
    position: static;
    display: none;
    width: 100%;
    min-width: 0;
    top: auto;
    left: auto;
    right: auto;
    margin: 0 0 var(--s2) var(--s4);
    padding: var(--s1) 0;
    border: 0;
    border-left: 2px solid var(--accent);
    box-shadow: none;
    opacity: 1;
    visibility: visible;
    transform: none;
  }

  .podmenu--glebokie[data-otwarte="true"] { display: block; }

  /* Hover na dotyku „przykleja się” po tapnięciu i zostawiał otwartą listę,
     której nie da się zamknąć. Na tej szerokości steruje wyłącznie przycisk. */
  .podmenu__poz:hover > .podmenu--glebokie { display: none; }
  .podmenu__poz:hover > .podmenu--glebokie[data-otwarte="true"] { display: block; }

  .podmenu .podmenu .podmenu { border-left-color: var(--rule-2); }

  .podmenu__rozwin { width: 44px; }
  .podmenu__rozwin svg { transform: none; }
  .podmenu__rozwin[aria-expanded="true"] svg { transform: rotate(180deg); }
}

/* Kropka odróżniająca pozycję sprzedażową działa na każdym poziomie —
   link z wtyczki może wejść także do podmenu. */
.podmenu__link--sprzedazowy::before {
  content: "";
  display: inline-block;
  width: 4px;
  height: 4px;
  margin-right: 8px;
  border-radius: 50%;
  background: var(--accent);
  vertical-align: middle;
}

/* Znacznik kategorii na kaflu i w treści */

.tag {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--brand-text); text-decoration: none;
}

.tag::before { content: ''; width: 14px; height: 1px; background: var(--brand); }

.tag--akcent { color: var(--accent-text); }

.tag--akcent::before { background: var(--accent); }

/* Plakietka AI — meta załącznika isAiGenerated (AI Act).
   Na liście dyskretny skrót, na stronie wpisu pełne zdanie —
   tak samo jak w Journalu, żeby sieć mówiła jednym głosem.                  */

.ai-chip {
  position: absolute; left: var(--s2); bottom: var(--s2); z-index: 2;
  font-family: var(--font-sans); font-size: 10px; font-weight: 700;
  letter-spacing: .1em; line-height: 1;
  padding: 4px 5px; border-radius: 2px;
  background: rgba(22, 20, 26, .62); color: #fff;
}

.ai-pelne {
  position: absolute; left: 0; bottom: 0; z-index: 2;
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .06em;
  padding: 6px var(--s3);
  background: rgba(22, 20, 26, .72); color: #fff;
}

/* ==========================================================================
   6. NAGŁÓWEK
   ========================================================================== */

/* Etykieta materiału sponsorowanego — sam napis, bez wyjaśnień
   i bez nazwy partnera. Ustalenie sieciowe z Journala.                      */

.wpis-glowa__sponsor {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
}

/* Nadkreślenie sekcji: numer + nazwa działu, jak w spisie treści magazynu */

.nad {
  font-family: var(--font-sans);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.nad::before {
  content: attr(data-nr);
  font-family: var(--font-mono);
  font-weight: 400;
  color: var(--brand);
  letter-spacing: .04em;
}

.meta {
  font-size: var(--fs-xs);
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 500;
}

.lead {
  font-size: var(--fs-lead);
  line-height: 1.62;
  color: var(--ink-2);
  margin: 0;
  text-wrap: pretty;
}

/* ==========================================================================
   4. UKŁAD
   ========================================================================== */

.wrap { width: min(100% - 2 * var(--s5), var(--wrap)); margin-inline: auto; }

@media (max-width: 640px) { .wrap { width: min(100% - 2 * var(--s4), var(--wrap)); } }

.sekcja { padding-block: var(--s8); }

.sekcja--ciasna { padding-block: var(--s7); }

/* Pas kremowy zaczyna się włosową kreską, która gaśnie po bokach —
   twarda krawędź między dwoma odcieniami bieli wyglądała jak szew.  */

.sekcja--papier {
  background-color: var(--paper-2);
  background-image: linear-gradient(90deg, transparent,
    color-mix(in oklab, var(--brand), transparent 78%), transparent);
  background-repeat: no-repeat;
  background-size: 100% 1px;
  background-position: top center;
}

.sekcja + .sekcja--papier { margin-top: 0; }

/* Nagłówek sekcji: nadkreślenie, tytuł, link do archiwum w jednej linii */

.sek-glowa {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--s5);
  padding-bottom: var(--s4);
  margin-bottom: var(--s6);
  border-bottom: 1px solid var(--rule);
}

/* Blok tytułu ma rosnąć — inaczej opis kategorii łamie się w wąską kolumnę
   przy pustym pasie z prawej. Opisy kategorii bywają na kilka zdań. */

.sek-glowa > div { flex: 1 1 auto; min-width: 0; }

.sek-glowa__tytul { font-size: var(--fs-h2); margin-top: var(--s2); }

.sek-glowa__opis {
  color: var(--ink-2);
  font-size: var(--fs-body);
  line-height: 1.62;
  margin: var(--s3) 0 0;
  max-width: 72ch;
  text-wrap: pretty;
}

.sek-glowa__opis p { margin: 0; }

.sek-glowa__opis p + p { margin-top: var(--s3); }

/* Opis kategorii idzie na trzy czwarte szerokości separatora — dość szeroko,
   żeby nie zostawiał pustego pasa, i dość krótko, żeby oko wracało do
   początku wiersza bez gubienia się.                                        */

.sek-glowa--archiwum { display: block; }

.sek-glowa--archiwum .sek-glowa__opis { max-width: 75%; }

@media (max-width: 900px) { .sek-glowa--archiwum .sek-glowa__opis { max-width: none; } }

.sek-glowa__wiecej {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .1em;
  font-weight: 700; white-space: nowrap; text-decoration: none;
  color: var(--brand-text); padding-bottom: 2px;
  border-bottom: 1px solid var(--brand-300);
}

.sek-glowa__wiecej:hover { border-bottom-color: var(--accent); }

@media (max-width: 720px) {
  .sek-glowa { flex-direction: column; align-items: flex-start; gap: var(--s3); }
}

/* Pasek działów — skróty, każdy z własnym znakiem */

.dzialy {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  border: 1px solid var(--rule);
}

.dzialy__poz {
  background: var(--paper); padding: var(--s5) var(--s4);
  text-decoration: none; color: var(--ink);
  display: flex; flex-direction: column; gap: 6px;
  transition: background-color .2s var(--ease);
}

.dzialy__poz:hover { background: var(--brand-050); color: var(--ink); }

.dzialy__nr { font-family: var(--font-mono); font-size: var(--fs-micro); color: var(--brand); letter-spacing: .1em; }

.dzialy__nazwa { font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600; }

.dzialy__ile { font-size: var(--fs-micro); color: var(--ink-3); letter-spacing: .06em; }

/* ==========================================================================
   10. PASEK NARZĘDZI — to, czego nie ma konkurencja
   ========================================================================== */

.narzedzia { display: grid; gap: var(--przerwa); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

.narzedzie {
  display: flex; flex-direction: column; gap: var(--s3);
  padding: var(--s6) var(--s5);
  border: 1px solid var(--rule);
  background: var(--paper);
  text-decoration: none; color: inherit;
  position: relative; overflow: hidden;
  transition: border-color .25s var(--ease), transform .25s var(--ease);
}

.narzedzie::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 3px;
  background: var(--accent); transform: scaleX(0); transform-origin: left;
  transition: transform .3s var(--ease);
}

.narzedzie:hover { border-color: var(--rule-2); transform: translateY(-2px); color: inherit; }

.narzedzie:hover::before { transform: scaleX(1); }

.narzedzie__ikona { width: 26px; height: 26px; color: var(--brand); }

.narzedzie__tytul { font-family: var(--font-serif); font-size: var(--fs-h3); font-weight: 600; }

.narzedzie__opis { font-size: var(--fs-sm); color: var(--ink-2); margin: 0; }

.narzedzie__cta { font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase; font-weight: 700; color: var(--brand-text); margin-top: auto; }

@media (prefers-reduced-motion: reduce) { .narzedzie:hover { transform: none; } }

/* ==========================================================================
   11. MATERIAŁY SPONSOROWANE
   Na listach karta pokazuje kategorię, nie etykietę sponsorowania —
   oznaczenie zostaje tam, gdzie ma znaczenie dla czytelniczki,
   czyli na stronie samego wpisu. Jedna sekcja na stronie głównej.
   ========================================================================== */

.sponsor-sekcja { background: var(--paper-2); border-block: 1px solid var(--rule); }

.etykieta-sponsor {
  display: inline-block;
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink-3);
  margin-bottom: var(--s3);
}

/* ==========================================================================
   12. FILTRY ARCHIWUM
   ========================================================================== */

.filtry__etykieta {
  font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase;
  font-weight: 700; color: var(--ink-3); margin-right: var(--s2);
}

.chip {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: 34px; padding: 0 var(--s3);
  border: 1px solid var(--rule-2); border-radius: 17px;
  background: var(--paper); color: var(--ink-2);
  font-size: var(--fs-xs); font-weight: 500; letter-spacing: .02em;
  transition: border-color .18s var(--ease), background-color .18s var(--ease), color .18s var(--ease);
}

.chip:hover { border-color: var(--ink-3); color: var(--ink); }

.chip[aria-pressed="true"] { background: var(--ink); border-color: var(--ink); color: #fff; }

.chip__probka {
  width: 14px; height: 14px; border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, .16);
  background: var(--probka);
}

.filtry__czysc { margin-left: auto; font-size: var(--fs-xs); color: var(--ink-3); background: none; border: 0; text-decoration: underline; }

.wynik-info { font-size: var(--fs-sm); color: var(--ink-3); margin: 0 0 var(--s5); }

.wynik-info b { color: var(--ink); font-weight: 600; }

.stronicowanie { display: flex; gap: var(--s2); justify-content: center; padding-top: var(--s7); }

.stronicowanie a, .stronicowanie span {
  min-width: 40px; height: 40px; display: grid; place-items: center;
  border: 1px solid var(--rule); text-decoration: none; color: var(--ink-2);
  font-size: var(--fs-sm); font-variant-numeric: tabular-nums;
}

.stronicowanie [aria-current] { background: var(--ink); border-color: var(--ink); color: #fff; }

/* ==========================================================================
   13. PANEL BOCZNY
   ========================================================================== */

.panel { display: grid; gap: var(--s7); align-content: start; }

.sekcja[data-nr]::before {
  content: attr(data-nr);
  /* Znak wychodzi poza górną krawędź sekcji — widać z niego mniej więcej
     dwie trzecie. Pełna cyfra przy krawędzi zderzała się z linkiem
     „cała kategoria" i wyglądała jak drugi element interfejsu zamiast
     jak tło. Przycięty czyta się od razu jako ozdoba.                 */
  position: absolute; top: -.42em; right: 1.5vw;
  font-family: var(--font-serif); font-weight: 600;
  font-size: clamp(8rem, 16vw, 14rem); line-height: 1;
  color: var(--brand); opacity: .05;
  pointer-events: none; user-select: none; z-index: 0;
}

@media (max-width: 860px) { .sekcja[data-nr]::before { display: none; } }

/* --- poświata sekcji kremowych ---------------------------------------
   Pierwsza wersja miała tu ukośne włoski. Przy zdjęciach obok czytały
   się jak prążki z zepsutego wydruku, a nie jak faktura — wzór
   regularny zawsze wygrywa z fotografią o uwagę, choćby był blady.
   Zostaje miękka plama przy lewej krawędzi: daje głębię, nie ma
   rytmu, więc oko jej nie śledzi.                                     */

.sekcja--papier::after {
  content: ""; position: absolute; inset: 0;
  pointer-events: none; z-index: 0;
  background: radial-gradient(45% 70% at 0% 40%,
    color-mix(in oklab, var(--brand), transparent 94%), transparent 70%);
}

/* --- ornament pod winietą --------------------------------------------
   Włosowa kreska z rombem pośrodku — najstarszy znak z główki gazety.
   Zamyka winietę od dołu i oddziela ją od menu miękcziej niż sama
   linia. Romb bierze kolor akcentu, kreska — marki.                   */

.winieta::after {
  content: "";
  width: min(240px, 38%); height: 7px;
  /* dwie warstwy: włosowa kreska na całą szerokość i romb pośrodku */
  background-image:
    linear-gradient(90deg, transparent,
      color-mix(in oklab, var(--brand), transparent 62%) 22%,
      color-mix(in oklab, var(--brand), transparent 62%) 78%, transparent),
    linear-gradient(45deg, var(--accent), var(--accent));
  background-size: 100% 1px, 5px 5px;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
}

/* --- kreska pod tytułem sekcji ---------------------------------------
   Krótki gradient od koloru marki w nicość. Wiąże tytuł z sekcją
   i daje nagłówkom rytm, którego nie da sama typografia.              */

.sek-glowa__tytul::after {
  content: ""; display: block;
  width: 44px; height: 2px; margin-top: var(--s3);
  background: linear-gradient(90deg, var(--brand), transparent);
  opacity: .55;
}

/* --- siatka punktów na sekcjach białych ------------------------------
   Odpowiednik poświaty z sekcji kremowych, tylko na bieli: bardzo rzadkie
   punkty, wygaszane maską w dół, żeby nie leżały pod kaflami. Wzór jest
   na tyle rzadki, że oko czyta go jako fakturę papieru, a nie jako kratkę.
   Sekcje kremowe mają własną warstwę, więc :not() je omija.           */

.sekcja[data-nr]:not(.sekcja--papier)::after {
  content: ""; position: absolute; inset: 0;
  pointer-events: none; z-index: 0;
  background-image: radial-gradient(
    color-mix(in oklab, var(--brand), transparent 90%) 1px, transparent 1.4px);
  background-size: 28px 28px;
  -webkit-mask-image: linear-gradient(180deg, #000, transparent 45%);
          mask-image: linear-gradient(180deg, #000, transparent 45%);
}

/* Wyjście do archiwum przy nagłówku sekcji jest akcją nawigacyjną, nie
   przypisem — dostaje zapas ponad minimum i własne pole kliknięcia.   */

.sek-glowa__wiecej {
  display: inline-flex; align-items: center; min-height: 32px;
  padding-inline: var(--s2); margin-inline: calc(var(--s2) * -1);
}

/* Z JS-em: wiersze mają stały rytm, kafel dostaje wyliczony span.
   Bez JS-a (klasa nie zostanie dodana) siatka zostaje zwykłą siatką
   równych kafli — degradacja bez utraty treści.                            */

.sciana.jest-js { grid-auto-rows: var(--rytm); }

/* Punkty łamania ściany i klasy `sciana--kN` stoją w _poprawki.scss.

   NIE TUTAJ, bo ten partial jest ODTWARZANY Z MAKIETY przy każdym
   uruchomieniu narzedzia/wyciagnij-makiete.py — ręczna poprawka w nim ginie
   bez śladu. Zdarzyło się to już dwa razy (przyciemniony --ink-3 i usunięty
   @import), a objaw był cichy: arkusz budował się dalej.                  */

/* Ściana krótsza niż liczba kolumn. `auto-fit` zwija puste ścieżki, więc
   kafle dzielą rząd równo między siebie — dwa wpisy zajmują pół i pół,
   trzy po jednej trzeciej. Bez tego pół rzędu zostaje puste i sekcja
   wygląda na niedokończoną.                                               */

/* Rząd sekcji kategorii: jeden poziom, równe kadry 4:3, tytuł pod zdjęciem.
   Wszystkie kafle mają tę samą proporcję, więc masonry nie ma czego
   przesuwać i rząd kończy się równo. Rytm strony robi naprzemienne tło
   i numeracja sekcji, a nie zmiana siatki co dział.                      */

.sciana--rzad .kafel__tytul { -webkit-line-clamp: 2; }

/* Karta domykająca rząd w kategorii, która ma mniej wpisów niż kolumn.
   Zajmuje wszystkie wolne kolumny i stoi na kolorze marki — to jedyne
   miejsce w sekcji, gdzie paleta interfejsu wychodzi na wierzch. Dzięki
   temu rząd kończy się równo, a slot niesie treść zamiast powietrza.
   Nikt nie pomyli jej z wpisem: nie ma zdjęcia i ma inny kolor.        */

.kafel.kafel--wiecej {
  display: flex; flex-direction: column; justify-content: center;
  gap: var(--s3);
  padding: var(--s7) var(--s6);
  background: var(--brand);
  color: var(--brand-ink);
  border: 0;
  text-decoration: none;
  align-self: stretch;
  min-height: 100%;
  position: relative; overflow: hidden;
  transition: background-color .25s var(--ease);
}

/* delikatny znak wodny — nadaje kartę głębi bez dokładania grafiki */

.kafel--wiecej::after {
  content: ""; position: absolute; right: -60px; bottom: -80px;
  width: 240px; height: 240px; border-radius: 50%;
  background: rgba(255, 255, 255, .06);
}

.kafel--wiecej:hover { background: var(--brand-700); color: var(--brand-ink); }

.kafel--wiecej > * { position: relative; z-index: 1; }

.kafel--wiecej__nad {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; opacity: .72;
}

.kafel--wiecej__tytul {
  font-family: var(--font-serif); font-size: clamp(1.5rem, 2.4vw, 2rem);
  font-weight: 600; line-height: 1.15;
}

.kafel--wiecej__ile { font-size: var(--fs-xs); letter-spacing: .06em; opacity: .72; }

.kafel--wiecej__strzalka { font-size: 1.5rem; line-height: 1; margin-top: var(--s2); }

/* Kafel dwukolumnowy — jeden na jedenaście, żeby ściana miała rytm.
   Bez JS-a zajmuje dwie kolumny zwykłym `span`; z JS-em dokładną pozycję
   wylicza rozmieszczanie (patrz app.js → przeliczSciane).                  */

.sciana .kafel--duzy { grid-column: span 2; }

.sciana .kafel--duzy .kafel__kadr { aspect-ratio: 3 / 2; }

@media (max-width: 420px) { .sciana .kafel--duzy { grid-column: span 1; } }

/* ==========================================================================
   8. KAFEL
   ========================================================================== */

/* Kafel NIE jest kartą — nie ma własnego tła. Białe pudełko pod podpisem
   zostało po wcześniejszej wersji, w której kafel udawał kartę. Przy różnej
   długości tytułów te pudełka kończyły się na różnych wysokościach i rząd
   wyglądał na poszarpany. Podpis leży teraz wprost na tle sekcji, a jedynym
   prostokątem w rzędzie jest zdjęcie.

   Wyjątki mają własne tło i wyższą specyficzność: kafel okładkowy trzyma
   podpis na zdjęciu, a karta domykająca rząd stoi na kolorze marki.    */

.kafel {
  position: relative;
  display: flex; flex-direction: column;
  background: transparent;
  min-width: 0;
}

/* Podgląd LQIP leży jako TŁO kadru, nie jako osobny obrazek z `filter: blur`.
   Miniatura 20 px rozciągnięta do szerokości kafla jest rozmyta sama z siebie,
   bo przeglądarka wygładza skalowanie. Przy czterdziestu kaflach naraz różnica
   jest zasadnicza: zero dodatkowych warstw i zero filtrów do złożenia.      */

.kafel__kadr {
  position: relative;
  overflow: hidden;
  background-color: var(--dom, var(--paper-3));   /* kolor dominujący zdjęcia */
  background-image: var(--lqip, none);
  background-size: cover;
  background-position: var(--ognisko, 50% 35%);
  aspect-ratio: var(--prop, 3 / 4);
}

.kafel__foto {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: var(--ognisko, 50% 35%);
  opacity: 0;
  transition: opacity .5s var(--ease), transform .7s var(--ease);
}

.kafel__foto.zaladowane { opacity: 1; }

.kafel:hover .kafel__foto { transform: scale(1.035); }

.kafel__opis { padding-top: var(--s3); }

.kafel__tytul {
  font-family: var(--font-serif);
  font-size: 1.0625rem;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: -0.008em;
  margin: var(--s2) 0 0;
  /* Tytuł do dwóch linii — dzięki temu wysokość kafla jest przewidywalna
     jeszcze przed załadowaniem zdjęć i siatka nie przeskakuje.             */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.kafel--duzy .kafel__tytul { font-size: 1.375rem; -webkit-line-clamp: 3; }

/* Data i czas czytania muszą móc zejść do drugiej linii: przy 320 px
   pełna data po polsku (27 października 2022) zjada cały wiersz i minuty
   wystawały poza kafel. */

.kafel__stopka {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--s2);
  margin-top: var(--s2); min-width: 0;
  font-size: var(--fs-micro); letter-spacing: .06em; color: var(--ink-3);
}

.kafel__stopka span + span::before { content: '·'; margin-right: var(--s2); }

/* Cały kafel jest klikalny, ale przyciski w środku zostają osobnymi celami:
   link rozciąga się pseudo-elementem, przyciski stoją nad nim.
   Zagnieżdżanie <button> w <a> byłoby błędem w HTML i pułapką dla klawiatury. */

.kafel__link { text-decoration: none; color: inherit; }

.kafel__link::after { content: ''; position: absolute; inset: 0; z-index: 1; }

.kafel__link { color: inherit; }

.kafel__link:hover { color: inherit; }

.kafel__link:hover .kafel__tytul { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }

.kafel:focus-within { outline: 2px solid var(--brand); outline-offset: 4px; }

.kafel:focus-within .kafel__link::after { outline: none; }

.kafel__link:focus-visible { outline: none; }

/* Kafel-okładka: tytuł leży na zdjęciu. Tekst nigdy nie stoi bezpośrednio
   na fotografii — zawsze na policzonym przyciemnieniu.                     */

.kafel--okladka .kafel__kadr { aspect-ratio: var(--prop, 4 / 5); }

/* Kafel-okładka przycina zawartość: warstwa z tytułem rośnie w górę od dołu,
   więc na niskim kaflu jej górna krawędź wychodziła poza kadr i kładła się
   cieniem na sąsiedztwie.                                                  */

/* Podpis leży w TYM SAMYM polu siatki co kadr, a nie nad nim absolutnie.

   Wcześniej `.kafel__opis` był `position: absolute; inset: auto 0 0 0`,
   czyli przyklejony do dołu kafla, a treść rosła w dół od swojej górnej
   krawędzi. Gdy tytuł miał trzy wiersze, `max-height: 100%` przycinało
   pudełko i `overflow: hidden` ucinało OSTATNI wiersz — czyli datę,
   w połowie wysokości liter. Zmierzone na stronie głównej: nadmiar od
   32 do 96 px, zależnie od szerokości ekranu.

   Ułożenie obu warstw w jednej komórce siatki odwraca zależność: to podpis
   wyznacza minimalną wysokość kafla, a kadr rozciąga się do niej
   (`height: 100%` przy `object-fit: cover` nie zniekształca zdjęcia).
   Nic nie może zostać ucięte, bo nie ma już czego przycinać.           */

.kafel--okladka {
  display: grid; grid-template-columns: 1fr;
  overflow: hidden;
}

.kafel--okladka > .kafel__kadr {
  grid-area: 1 / 1; height: 100%; min-height: 0;
}

.kafel--okladka > .kafel__opis {
  grid-area: 1 / 1; align-self: end;
  max-height: none; overflow: visible;
}

/* Przyciemnienie pod tytułem na kaflu-okładce.

   Zasada nadrzędna: TYTUŁ MUSI BYĆ CZYTELNY. Lekko przygaszony dół zdjęcia
   jest mniejszym problemem niż biały napis, który znika na jasnym kadrze —
   dlatego domyślna warstwa jest mocna, a dane o jasności służą do jej
   ZDJĘCIA przy ciemnych zdjęciach, nie do dokładania przy jasnych.

   Wartość data-scrim liczy PHP przy uploadzie z pasa zdjęcia poniżej górnej
   trzeciej — bo kafel pokazuje kadr, a nie całą fotografię.                */

.kafel--okladka .kafel__opis {
  position: relative; z-index: 2;
  padding: min(var(--s8), 22%) var(--s5) var(--s5);
  color: #fff;
  text-shadow: 0 1px 3px rgba(8, 6, 10, .55);
  background: linear-gradient(to top,
    rgba(10, 8, 12, .95) 0%,
    rgba(10, 8, 12, .88) 34%,
    rgba(10, 8, 12, .60) 66%,
    rgba(10, 8, 12, 0) 100%);
}

/* zdjęcie ciemne w całym pasie — można oddać mu trochę powietrza */

.kafel--okladka[data-scrim="0"] .kafel__opis {
  padding-top: min(var(--s6), 16%);
  background: linear-gradient(to top,
    rgba(10, 8, 12, .88) 0%,
    rgba(10, 8, 12, .70) 40%,
    rgba(10, 8, 12, 0) 100%);
}

/* zdjęcie bardzo jasne — pełna płyta pod tekstem, zero ryzyka */

.kafel--okladka[data-scrim="2"] .kafel__opis {
  padding-top: min(var(--s9), 30%);
  text-shadow: 0 1px 3px rgba(8, 6, 10, .7);
  background: linear-gradient(to top,
    rgba(8, 6, 10, .97) 0%,
    rgba(8, 6, 10, .94) 42%,
    rgba(8, 6, 10, .72) 72%,
    rgba(8, 6, 10, 0) 100%);
}

.kafel--okladka .kafel__link, .kafel--okladka .kafel__link:hover { color: #fff; }

.kafel--okladka .kafel__tytul { color: #fff; font-size: clamp(1.25rem, 2.4vw, 2rem); -webkit-line-clamp: 3; }

.kafel--okladka .kafel__stopka { color: rgba(255, 255, 255, .82); }

.kafel--okladka .tag { color: #fff; }

.kafel--okladka .tag::before { background: var(--accent); width: 18px; height: 2px; }

.kafel--okladka .kafel__lead {
  margin: var(--s3) 0 0; font-size: var(--fs-sm); line-height: 1.55;
  color: rgba(255, 255, 255, .88); max-width: 56ch;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Wejście kafla. Opóźnienie zależy od kolumny, nie od indeksu — inaczej
   przy czterdziestu kaflach powstaje „fala", która wygląda jak zacięcie.   */

.kafel[data-wejscie] { opacity: 0; transform: translateY(10px); }

.kafel[data-wejscie].widoczny {
  opacity: 1; transform: none;
  transition: opacity .5s var(--ease) var(--zwloka, 0ms),
              transform .5s var(--ease) var(--zwloka, 0ms);
}

@media (prefers-reduced-motion: reduce) {
  .kafel[data-wejscie] { opacity: 1; transform: none; transition: none; }
  .kafel__foto, .kafel:hover .kafel__foto { transition: none; transform: none; }
}

/* ==========================================================================
   9. OTWARCIE STRONY GŁÓWNEJ
   ========================================================================== */

.otwarcie { padding-top: var(--s6); }

.otwarcie__siatka {
  display: grid; gap: var(--przerwa);
  grid-template-columns: 1fr;
}

.otwarcie__glowny .kafel__kadr { aspect-ratio: 4 / 3; }

@media (min-width: 900px) {
  .otwarcie__siatka { grid-template-columns: 1.62fr 1fr; align-items: stretch; }
  /* `1fr 1fr` dzieliło wysokość na pół niezależnie od tego, ile miejsca
     potrzebuje podpis — i to była druga połowa problemu z uciętą datą.
     `minmax(min-content, 1fr)` mówi: rząd nigdy nie mniejszy niż treść,
     a wolne miejsce nadal dzieli się po równo. Warunkiem jest to, że podpis
     w ogóle liczy się do treści — stąd zmiana wyżej.                    */
  .otwarcie__bok {
    display: grid; gap: var(--przerwa);
    grid-template-rows: minmax(min-content, 1fr) minmax(min-content, 1fr);
  }
  .otwarcie__bok .kafel__kadr { aspect-ratio: auto; height: 100%; min-height: 180px; }
  /* Zajawka zostaje przy kaflu wiodącym. W bocznym, o połowę niższym,
     dokładała dwa wiersze do tego samego pola i to ona wypychała datę.  */
  .otwarcie__bok .kafel__lead { display: none; }
}

/* Kafel okładkowy na wąskim ekranie ------------------------------------
   W kadrze 4:3 przy 375 px nie mieszczą się naraz: kategoria, trzywierszowy
   tytuł, dwuwierszowa zajawka i stopka z datą. Opis miał 287 px przy kaflu
   257 px — overflow: hidden ucinał datę w połowie wysokości liter.
   Na telefonie zajawka i tak niewiele wnosi: decyduje zdjęcie i tytuł,
   a pierwszy akapit jest o jedno dotknięcie dalej.                      */

@media (max-width: 700px) {
  .kafel--okladka .kafel__lead { display: none; }
}

/* --- pasek działów: cienka ramka w kolorze marki ---------------------
   Kafelki „od czego zaczynasz" siedzą na jednopikselowej siatce. Sama
   szarość gubiła się na bieli; odrobina marki wiąże je z resztą strony. */

.dzialy { background: color-mix(in oklab, var(--brand), transparent 88%); }

.dzialy { border-color: color-mix(in oklab, var(--brand), transparent 82%); }

/* --- delikatne rozjaśnienie nad stopką -------------------------------
   Stopka jest jasna, więc zamiast twardej kreski oddziela ją miękkie
   przejście w kolorze marki.                                          */

.stopka { position: relative; overflow: hidden; }

.stopka::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 240px;
  pointer-events: none; z-index: 0;
  background: radial-gradient(70% 100% at 50% 0%, color-mix(in oklab, var(--brand), transparent 93%), transparent 70%);
}

.stopka > * { position: relative; z-index: 1; }

@media (prefers-reduced-motion: reduce) {
  /* warstwy i tak się nie ruszają — nic do wyłączenia */
}

/* ==========================================================================
   18b. CELE DOTYKOWE
   ==========================================================================

   WCAG 2.2, kryterium 2.5.8 (AA): cel wskazywania ma mieć co najmniej
   24 × 24 px. Wyjątek „inline" obejmuje linki wewnątrz zdania — dlatego
   treść artykułu zostaje bez zmian. Poniższe linki stoją samodzielnie
   (okruszki, tagi, stopka, podpis autora), więc muszą mieć własną
   wysokość, a nie tylko wysokość swojego wiersza tekstu.

   Zmierzone przed poprawką na 390 px: okruszki 14 px, autor 14 px,
   stopka 16 px, tag 18 px, link autora 20 px, „cała kategoria" 23 px.  */

.meta > a,
.wpis-glowa__meta a,
.redakcja-glowa__inni a,
.stopka__lista > li > a,
.autor-box__link,
.tag {
  display: inline-flex; align-items: center; min-height: 24px;
}

/* Układ z panelem bocznym. W HTML treść stoi PRZED panelem —
   czytniki ekranu i roboty dostają ją pierwszą. Panel wchodzi
   na lewą stronę dopiero wizualnie, przez `order`.                          */

.z-panelem {
  display: grid;
  gap: var(--s7);
  grid-template-columns: 1fr;
}

/* min-width: 0 musi obowiązywać na KAŻDEJ szerokości, nie tylko na desktopie.
   Element siatki ma domyślnie min-width: auto, czyli nie zwęzi się poniżej
   swojej zawartości. Tabela porównawcza ma min-width: 560px, więc kolumna
   treści rozpychała się do 689 px i cały artykuł przewijał się w bok na
   telefonie. Z zerem tabela przewija się we własnej otoczce, tak jak miała. */

.z-panelem__tresc, .z-panelem__panel { min-width: 0; }

@media (min-width: 1000px) {
  .z-panelem { grid-template-columns: 280px minmax(0, 1fr); gap: var(--s8); }
  .z-panelem__tresc { order: 2; }
  .z-panelem__panel { order: 1; }
}

/* ==========================================================================
   5. PRZYCISKI I ZNACZNIKI
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--s2);
  min-height: 44px; padding: 0 var(--s5);
  font-family: var(--font-sans); font-size: var(--fs-sm); font-weight: 600;
  letter-spacing: .04em; text-decoration: none; border: 1px solid transparent;
  border-radius: var(--radius); background: none; color: var(--ink);
  transition: background-color .2s var(--ease), color .2s var(--ease), border-color .2s var(--ease);
}

.btn--brand { background: var(--brand); color: var(--brand-ink); }

.btn--brand:hover { background: var(--brand-700); color: var(--brand-ink); }

.btn--akcent { background: var(--accent); color: var(--accent-ink); }

.btn--akcent:hover { background: var(--accent-700); color: var(--accent-ink); }

.btn--kontur { border-color: var(--rule-2); color: var(--ink); }

.btn--kontur:hover { border-color: var(--ink); background: var(--paper-2); color: var(--ink); }

.btn--maly { min-height: 36px; padding: 0 var(--s4); font-size: var(--fs-xs); }

.btn--pelny { width: 100%; }

/* Węższy kontener na stronie wpisu: panel (280) + odstęp + kolumna tekstu
   wypełniają szerokość, zamiast zostawiać pusty pas z prawej.             */

.wrap--wpis { width: min(100% - 2 * var(--s5), 1120px); }

@media (max-width: 640px) { .wrap--wpis { width: min(100% - 2 * var(--s4), 1120px); } }

/* Lead stoi w treści, nad spisem — nie pod tytułem.

   Pod tytułem powtarzał to samo zdanie, które czytelnik ma zaraz niżej,
   i odsuwał treść o jeden ekran w dół. W treści robi to, do czego lead
   służy: wprowadza w tekst i daje wyszukiwarce akapit do zacytowania,
   a spis treści zostaje tuż nad pierwszym nagłówkiem, czyli tam, gdzie
   jest potrzebny.                                                     */

.tresc__lead {
  font-size: var(--fs-lead);
  color: var(--ink-2);
  margin: 0 0 var(--s6);
}

.tresc__lead + * { margin-top: var(--s6); }

.wpis-glowa__meta {
  display: flex; flex-wrap: wrap; gap: var(--s4); justify-content: center;
  margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--rule);
  font-size: var(--fs-xs); color: var(--ink-3); letter-spacing: .06em;
}

/* Na wąskim ekranie wyśrodkowany lead łamie się na sześć krótkich linii
   i czyta się źle — od 700 px w dół winieta wpisu wraca do lewej.
   Metryczka rozdziela się kropką zamiast rozpadać na kolumnę.              */

@media (max-width: 700px) {
  .wpis-glowa { padding-block: var(--s6) var(--s5); }
  .wpis-glowa__inner { text-align: left; }
  .wpis-glowa__lead { margin-inline: 0; }
  .wpis-glowa__meta {
    justify-content: flex-start;
    gap: var(--s2) var(--s3);
    margin-top: var(--s4);
  }
  .wpis-glowa__meta > span + span::before {
    content: '·'; margin-right: var(--s3); color: var(--rule-2);
  }
}

/* Zdjęcie wiodące ma robić wrażenie, ale nie zjadać całego pierwszego
   ekranu — stąd sufit wysokości. Plakietka AI Act siedzi w KADRZE, nie na
   figurze, żeby nie kładła się na podpisie.                                */

.wpis-foto { margin: 0 auto var(--s7); }

.wpis-foto__kadr {
  position: relative;
  background: var(--dom, var(--paper-3));
  overflow: hidden;
}

/* Zdjęcie wiodące w NATYWNYCH proporcjach generatora (1024×768 = 4:3).
   Figura jest zwężona tak, żeby przy tej proporcji wysokość nie przekroczyła
   560 px — dzięki temu nic nie jest przycinane i nic nie zjada pierwszego
   ekranu. Gdy redakcja wgra zdjęcie o innej proporcji, object-fit przytnie
   je do 4:3 z punktem ostrości nieco powyżej środka.                       */

.wpis-foto { max-width: 747px; margin-inline: auto; }

.wpis-foto__kadr img {
  width: 100%; height: auto;
  aspect-ratio: 4 / 3;
  object-fit: cover; object-position: 50% 42%;
}

.wpis-foto__podpis {
  display: flex; justify-content: space-between; gap: var(--s5);
  padding-top: var(--s3); font-size: var(--fs-xs); color: var(--ink-3);
  line-height: 1.5;
}

.wpis-foto__podpis span:last-child { white-space: nowrap; }

@media (max-width: 600px) {
  .wpis-foto__podpis { flex-direction: column; gap: var(--s2); }
  .wpis-foto__podpis span:last-child { white-space: normal; }
}

/* Kluczowa odpowiedź (BLUF) — konkret w pierwszym ekranie.
   To jest ten fragment, który cytują wyszukiwarki i modele.                 */

.bluf {
  border-left: 3px solid var(--accent);
  background: var(--accent-050);
  padding: var(--s5);
  margin: 0 0 var(--s6);
}

.bluf__etykieta {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .14em;
  text-transform: uppercase; color: var(--accent-text); margin-bottom: var(--s2);
}

.bluf p { margin: 0; font-size: var(--fs-lead); line-height: 1.55; }

/* overflow-wrap jest tu obowiązkowe, nie ozdobne: w tekstach prawnych stoją
   pełne adresy (help.opera.com/Windows/12.10/pl/cookies.html), a takiego
   ciągu bez spacji przeglądarka nie złamie sama — przy 320 px wypychał
   stronę o 72 px w bok. */

.tresc { max-width: var(--wrap-tekst); margin-inline: auto; overflow-wrap: break-word; }

.tresc a[href^="http"] { overflow-wrap: anywhere; }

/* --- rytm pionowy treści ---------------------------------------------

   Kolejność i specyficzność są tu istotne, bo poprzednia wersja miała
   błąd, który psuł cały tekst: `.tresc p { margin: 0 }` ma wyższą
   specyficzność niż `.tresc > * + *`, więc zerowało odstępy MIĘDZY
   akapitami — artykuł czytał się jak jeden zlepiony blok, a nagłówki
   przyklejały się do własnego tekstu.

   Dlatego domyślne marginesy przeglądarki zeruje się w :where(), które
   ma specyficzność zero i nigdy nie wygrywa z regułami rytmu poniżej. */

.tresc :where(p, ul, ol, figure, blockquote) { margin: 0; }

.tresc p { line-height: 1.72; }

.tresc ul, .tresc ol { padding-left: 1.25em; }

.tresc li + li { margin-top: var(--s2); }

.tresc strong { font-weight: 600; }

.tresc figcaption { font-size: var(--fs-xs); color: var(--ink-3); padding-top: var(--s2); }

/* Odstępy wokół nagłówków.

   Przed kreską było 64 px, a między kreską a tekstem nagłówka 16 px —
   czyli pusty pas nad separatorem i nagłówek doklejony do niego od dołu.
   Teraz: mniej powietrza przed kreską (48 px), więcej pod nią (24 px). */

.tresc h2 {
  font-size: var(--fs-h2); margin-top: var(--s7);
  padding-top: var(--s5); border-top: 1px solid var(--rule);
  line-height: 1.25;
  scroll-margin-top: 96px;
}

.tresc h3 { font-size: var(--fs-h3); margin-top: var(--s7); line-height: 1.3; scroll-margin-top: 96px; }

/* Element pod nagłówkiem stoi bliżej niż sąsiedni akapit: to ten odstęp
   mówi, że tekst należy DO tego nagłówka, a nie do poprzedniej sekcji. */

.tresc > :is(h2, h3) + * { margin-top: var(--s5); }

/* Figury dostają więcej powietrza z obu stron niż akapit. */

.tresc > figure { margin-block: var(--s7); }

/* Spis treści — wpisy w tej niszy mają 8–20 tys. znaków */

.spis {
  border: 1px solid var(--rule); padding: var(--s5);
  background: var(--paper-2);
}

.spis__tytul { font-size: var(--fs-micro); font-weight: 700; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 var(--s3); }

.spis ol { margin: 0; padding: 0; list-style: none; counter-reset: s; }

.spis li { counter-increment: s; }

.spis li + li { margin-top: 6px; }

.spis a { display: flex; gap: var(--s3); text-decoration: none; color: var(--ink-2); font-size: var(--fs-sm); }

.spis a::before { content: counter(s, decimal-leading-zero); font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--brand); }

.spis a:hover { color: var(--brand-text); text-decoration: underline; }

.spis a[aria-current] { color: var(--ink); font-weight: 600; }

/* Dymek składnika — nazwa w treści prowadzi do hasła w bazie */

.skladnik-link {
  border-bottom: 1px dashed var(--accent);
  text-decoration: none; color: inherit; cursor: help;
}

.skladnik-link:hover { background: var(--accent-050); color: inherit; }

/* Box produktu w treści — z zestawu „produkty" */

.produkt-box {
  display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: var(--s4);
  border: 1px solid var(--rule); padding: var(--s4);
  background: var(--paper);
}

.produkt-box__znak {
  aspect-ratio: 1; display: grid; place-items: center; text-align: center;
  background: var(--brand-050); color: var(--brand-900);
  font-family: var(--font-serif); font-size: 1.5rem; font-weight: 600;
}

.produkt-box__marka { font-size: var(--fs-micro); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }

.produkt-box__nazwa { font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600; margin: 2px 0 var(--s2); }

.produkt-box__werdykt { font-size: var(--fs-sm); color: var(--ink-2); margin: 0 0 var(--s3); }

.produkt-box__dol { display: flex; align-items: center; gap: var(--s4); flex-wrap: wrap; }

.produkt-box__cena { font-family: var(--font-mono); font-size: 1.0625rem; font-weight: 600; font-variant-numeric: tabular-nums; }

.produkt-box__info { font-size: var(--fs-micro); color: var(--ink-3); letter-spacing: .05em; }

/* FAQ — widoczny blok, z którego motyw buduje FAQPage */

.faq { border-top: 1px solid var(--rule); }

.faq__poz { border-bottom: 1px solid var(--rule); }

.faq__pyt {
  width: 100%; display: flex; justify-content: space-between; align-items: center; gap: var(--s4);
  padding: var(--s4) 0; background: none; border: 0; text-align: left;
  font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600; color: var(--ink);
}

.faq__pyt::after { content: '+'; font-family: var(--font-mono); font-size: 1.25rem; color: var(--brand); flex: none; }

.faq__pyt[aria-expanded="true"]::after { content: '−'; }

.faq__odp { padding: 0 0 var(--s4); color: var(--ink-2); font-size: var(--fs-body); }

.faq__odp[hidden] { display: none; }

/* Galeria we wpisie */

.galeria { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s2); }

.galeria__poz { position: relative; aspect-ratio: 1; overflow: hidden; border: 0; padding: 0; background: var(--dom, var(--paper-3)); }

.galeria__poz img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform .5s var(--ease); }

.galeria__poz:hover img { transform: scale(1.05); }

/* Podgląd pełnoekranowy */

.lupa { position: fixed; inset: 0; z-index: 90; background: rgba(14, 12, 16, .94); display: grid; grid-template-rows: 1fr auto; padding: var(--s5); }

.lupa[hidden] { display: none; }

.lupa__kadr { display: grid; place-items: center; min-height: 0; }

.lupa__kadr img { max-width: 100%; max-height: 100%; object-fit: contain; }

.lupa__pasek { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); color: rgba(255, 255, 255, .8); font-size: var(--fs-sm); padding-top: var(--s4); }

.lupa__zamknij, .lupa__nawig button {
  min-width: 44px; min-height: 44px; background: none; border: 1px solid rgba(255, 255, 255, .3);
  color: #fff; border-radius: 2px;
}

.lupa__nawig { display: flex; gap: var(--s2); }

/* Stopka wpisu: autorka i wpisy powiązane */

.autorka-box {
  display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: var(--s5);
  border: 1px solid var(--rule); padding: var(--s6);
  background: var(--paper-2);
}

.autorka-box__awatar {
  width: 76px; height: 76px; border-radius: 50%;
  background: var(--brand); color: var(--brand-ink);
  display: grid; place-items: center;
  font-family: var(--font-serif); font-size: 1.75rem; font-weight: 600;
}

.autorka-box__zasady { list-style: none; margin: var(--s3) 0 0; padding: 0; display: grid; gap: 6px; }

.autorka-box__zasady li { font-size: var(--fs-sm); color: var(--ink-2); padding-left: 20px; position: relative; }

.autorka-box__zasady li::before { content: '✓'; position: absolute; left: 0; color: var(--ok); font-weight: 700; }

@media (max-width: 600px) { .autorka-box { grid-template-columns: 1fr; } }

/* ==========================================================================
   15. DANE — skaner składu, rankingi, quiz
   ========================================================================== */

.karta-danych { border: 1px solid var(--rule); background: var(--paper); }

.karta-danych__glowa { padding: var(--s5); border-bottom: 1px solid var(--rule); display: flex; justify-content: space-between; align-items: baseline; gap: var(--s4); flex-wrap: wrap; }

.karta-danych__cialo { padding: var(--s5); }

/* Data aktualizacji — obowiązkowa i widoczna przy każdym zestawie z CSV.
   Bez niej tabela jest bezwartościowa dla czytelniczki i dla wyszukiwarki. */

.zrodlo { font-size: var(--fs-micro); color: var(--ink-3); padding-top: var(--s3); border-top: 1px solid var(--rule); margin-top: var(--s4); }

.lista-skladnikow { list-style: none; margin: 0; padding: 0; }

.lista-skladnikow > li { border-bottom: 1px solid var(--rule); padding: var(--s4) 0; display: grid; grid-template-columns: 28px minmax(0, 1fr) auto; gap: var(--s3); align-items: start; }

.poz-nr { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-3); padding-top: 3px; }

.poz-nazwa { font-family: var(--font-serif); font-weight: 600; font-size: 1.0625rem; }

.poz-inci { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--ink-3); }

.poz-opis { font-size: var(--fs-sm); color: var(--ink-2); margin: var(--s2) 0 0; }

.poz-flagi { display: flex; gap: 6px; flex-wrap: wrap; margin-top: var(--s2); }

.plakietka {
  font-size: var(--fs-micro); font-weight: 600; letter-spacing: .05em;
  padding: 3px 8px; border-radius: 2px; white-space: nowrap;
  border: 1px solid currentColor;
}

.plakietka--ok { color: var(--ok); }

.plakietka--uwaga { color: var(--uwaga); }

.plakietka--stop { color: var(--stop); }

.plakietka--mit { color: var(--mit); }

.plakietka--neutralna { color: var(--ink-3); }

.plakietka--pelna { border: 0; background: var(--accent); color: var(--accent-ink); }

.ostrzezenie { border-left: 3px solid; padding: var(--s4); background: var(--paper-2); }

.ostrzezenie--stop { border-color: var(--stop); }

.ostrzezenie--uwaga { border-color: var(--uwaga); }

.ostrzezenie--mit { border-color: var(--mit); }

.ostrzezenie__tytul { font-weight: 600; font-size: var(--fs-sm); margin: 0 0 4px; }

.ostrzezenie p { margin: 0; font-size: var(--fs-sm); color: var(--ink-2); }

/* Tabele danych */

/* position: relative jest tu potrzebne, nie kosmetyczne: bez niego opisy
   .tylko-czytnik wewnątrz komórek (position: absolute) zaczepiają się o dalszy
   kontener, wychodzą poza otoczkę i rozciągają szerokość przewijania całego
   dokumentu. Z nim przycina je ta sama otoczka, w której leży tabela. */

.tabela-otoczka { overflow-x: auto; -webkit-overflow-scrolling: touch; position: relative; }

table.dane { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); min-width: 560px; }

table.dane caption { text-align: left; font-size: var(--fs-xs); color: var(--ink-3); padding-bottom: var(--s3); }

table.dane th, table.dane td { padding: var(--s3) var(--s4); text-align: left; border-bottom: 1px solid var(--rule); }

table.dane thead th {
  font-family: var(--font-sans); font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3);
  border-bottom: 1px solid var(--ink);
  position: sticky; top: 0; background: var(--paper); z-index: 1;
}

table.dane tbody tr:hover { background: var(--paper-2); }

table.dane td.liczba { font-family: var(--font-mono); font-variant-numeric: tabular-nums; text-align: right; }

table.dane th[aria-sort] { cursor: pointer; }

table.dane th[aria-sort]::after { content: '↕'; margin-left: 6px; opacity: .4; }

table.dane th[aria-sort="ascending"]::after { content: '↑'; opacity: 1; color: var(--brand); }

table.dane th[aria-sort="descending"]::after { content: '↓'; opacity: 1; color: var(--brand); }

/* Pierwsza kolumna przyklejona — tabele porównawcze są szersze niż telefon */

table.dane--sticky td:first-child, table.dane--sticky th:first-child {
  position: sticky; left: 0; background: var(--paper); z-index: 2;
  border-right: 1px solid var(--rule);
}

/* ==========================================================================
   16. STOPKA
   ========================================================================== */

/* Panel przyklejony przy przewijaniu — TYLKO na stronie wpisu.

   `position: sticky` stało tu od początku i nie robiło nic: panel jest
   elementem siatki, a te domyślnie rozciągają się na całą wysokość rzędu.
   Na wpisie rząd ma prawie 7000 px, więc panel był tak samo wysoki jak
   treść i przyklejanie nie miało po czym jechać. Dopiero `align-self:
   start` daje mu własną, niską wysokość.

   `max-height` + `overflow-y` są zabezpieczeniem na wypadek panelu
   dłuższego niż ekran: bez nich jego dół byłby nie do obejrzenia.     */

@media (min-width: 1000px) {
  .wrap--wpis .z-panelem__panel {
    position: sticky;
    top: calc(46px + var(--s5));
    align-self: start;
    max-height: calc(100vh - 46px - var(--s6));
    overflow-y: auto;
    overscroll-behavior: contain;
    scrollbar-width: thin;
  }
}

.panel__blok { border-top: 2px solid var(--ink); padding-top: var(--s4); }

.panel__tytul {
  font-family: var(--font-sans); font-size: var(--fs-micro); font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; margin: 0 0 var(--s4);
}

.mini-lista { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s4); }

/* Cały wiersz jest celem kliknięcia, nie sam tytuł. Bez tego miniatura
   64 × 64 nie reaguje na dotyk, a jedynym celem zostaje 20-pikselowy pasek
   tekstu — dokładnie ta sytuacja, którą opisuje WCAG 2.5.8.            */

.mini {
  display: grid; grid-template-columns: 64px minmax(0, 1fr); gap: var(--s3);
  align-items: start; position: relative;
}

.mini__tytul::after { content: ''; position: absolute; inset: 0; }

.mini__kadr { aspect-ratio: 1; overflow: hidden; background: var(--dom, var(--paper-3)); position: relative; }

.mini__kadr img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }

.mini__tytul {
  font-family: var(--font-serif); font-size: .9375rem; font-weight: 600; line-height: 1.3;
  margin: 0; text-decoration: none; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

a.mini__tytul:hover { color: var(--brand-text); }

.mini__meta { font-size: var(--fs-micro); color: var(--ink-3); letter-spacing: .05em; margin-top: 4px; }

.mini__nr { font-family: var(--font-mono); font-size: var(--fs-sm); color: var(--brand); }

/* Powiązane wpisy pod artykułem. Bez nagłówka — etykieta jest akapitem,
   żeby nie zaśmiecać konspektu tekstu. Oddziela je mocny włos, nie h2.    */

.powiazane { margin-top: var(--s8); padding-top: var(--s5); border-top: 2px solid var(--ink); }

.powiazane__etykieta {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
  margin: 0 0 var(--s5);
}

/* Box autora w panelu bocznym wpisu. Świadomie bez nagłówka — to podpis pod
   tekstem, nie kolejna sekcja serwisu. Kadr zdjęcia ma stały rozmiar, więc
   wariant z monogramem zajmuje dokładnie tyle samo miejsca.                */

.panel__blok--autor { border-top-color: var(--rule-2); }

.autor-box { display: grid; gap: var(--s2); }

.autor-box__foto {
  width: 72px; height: 72px;
  border-radius: 50%; overflow: hidden;
  background: var(--brand-050);
  display: grid; place-items: center;
  margin-bottom: var(--s2);
}

.autor-box__foto img { width: 100%; height: 100%; object-fit: cover; }

.autor-box__foto[data-brak-zdjecia] { border: 1px dashed var(--rule-2); }

.autor-box__monogram {
  font-family: var(--font-serif); font-size: 1.75rem; font-weight: 600;
  color: var(--brand); line-height: 1;
}

.autor-box__imie { font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600; margin: 0; }

.autor-box__rola {
  font-size: var(--fs-micro); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); margin: 0;
}

.autor-box__opis { font-size: var(--fs-sm); color: var(--ink-2); margin: var(--s2) 0 0; }

.autor-box__link {
  font-size: var(--fs-xs); font-weight: 700; letter-spacing: .06em;
  text-decoration: none; color: var(--brand-text); margin-top: var(--s2);
}

.autor-box__link:hover { text-decoration: underline; }

/* Box z cytatem w panelu bocznym. Treść i autor to dwa pola w Customizerze;
   przy pustym polu motyw nie wypisuje bloku.

   Bez ozdobnego cudzysłowu w pseudo-elemencie — kładł się na pierwszej
   literze. Cytat wyróżnia pionowa linia w kolorze marki: działa przy każdej
   długości tekstu i nie wchodzi w słowa.                                   */

.panel__blok--cytat { border-top-color: var(--brand); }

.cytat {
  margin: 0;
  padding-left: var(--s4);
  border-left: 2px solid var(--brand);
}

.cytat__tresc {
  font-family: var(--font-serif);
  font-size: 1.125rem;
  font-style: italic;
  line-height: 1.5;
  color: var(--ink);
  margin: 0;
  text-wrap: pretty;
}

.cytat__autor {
  margin-top: var(--s3);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-style: normal;
}

/* Autorka w panelu — E-E-A-T ma stać wysoko, nie w stopce */

.autorka-panel { display: grid; gap: var(--s3); }

.autorka-panel__glowa { display: flex; gap: var(--s3); align-items: center; }

.autorka-panel__awatar {
  width: 56px; height: 56px; border-radius: 50%;
  background: var(--brand-100); color: var(--brand-900);
  display: grid; place-items: center;
  font-family: var(--font-serif); font-size: 1.25rem; font-weight: 600;
}

.autorka-panel__imie { font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600; }

.autorka-panel__rola { font-size: var(--fs-micro); color: var(--ink-3); letter-spacing: .05em; text-transform: uppercase; }

.autorka-panel__bio { font-size: var(--fs-sm); color: var(--ink-2); margin: 0; }

/* ==========================================================================
   14. WPIS
   ========================================================================== */

.pasek-czytania {
  position: fixed; top: 0; left: 0; right: 0; height: 2px; z-index: 60;
  background: transparent; pointer-events: none;
}

.pasek-czytania i { display: block; height: 100%; width: 0; background: var(--accent); }

.wpis-glowa { padding-block: var(--s7) var(--s6); }

.wpis-glowa__inner { max-width: var(--wrap-tekst); margin-inline: auto; text-align: center; }

.wpis-glowa__tytul { font-size: var(--fs-display); margin: var(--s4) 0 var(--s4); }

.wpis-glowa__lead { font-size: var(--fs-lead); color: var(--ink-2); margin: 0 auto; max-width: 60ch; }

/* Stopka jest JASNA, bo logo klienta bywa czarnym plikiem — na ciemnym tle
   winieta w stopce po prostu znika. Rozdziela ją od treści mocny włos,
   a nie kontrast tła.                                                     */

.stopka {
  background: var(--paper-2);
  color: var(--ink-2);
  margin-top: var(--s9);
  border-top: 2px solid var(--ink);
}

.stopka a { color: var(--ink); }

/* Liczbę TORÓW ustala klasa `stopka__gora--kN` (patrz _stopka-polecane.scss):
   kolumny stopki są warunkowe, a cztery tory na sztywno zostawiały pusty
   tor na portalu bez kolumny płatnej i bez wyboru redakcji. Tu zostaje
   tylko to, co od liczby kolumn nie zależy. Wartość poniżej jest
   awaryjna — dla stopki bez klasy `--kN`.                                */
.stopka__gora { display: grid; gap: var(--s7); padding-block: var(--s8); grid-template-columns: 1.6fr 1fr 1fr 1.1fr; }


@media (max-width: 620px) { .stopka__gora { gap: var(--s6); } }

.stopka__logo { font-family: var(--font-serif); font-size: 1.75rem; font-weight: 500; letter-spacing: -0.02em; color: var(--ink); text-decoration: none; }

.stopka__logo em { font-style: italic; color: var(--brand); }

.stopka__opis { font-size: var(--fs-sm); color: var(--ink-2); max-width: 46ch; margin: var(--s3) 0 0; }

.stopka__tytul { font-size: var(--fs-micro); font-weight: 700; letter-spacing: .16em; text-transform: uppercase; color: var(--ink-3); margin: 0 0 var(--s4); }

.stopka__lista { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s2); font-size: var(--fs-sm); }

.stopka__lista a { text-decoration: none; color: var(--ink-2); }

.stopka__lista a:hover { text-decoration: underline; color: var(--brand-text); }

/* Kolumna sprzedażowa stopki: do pięciu linków i do pięciu banerów 300×50.
   Banery leżą jeden pod drugim i skalują się do szerokości kolumny, żeby
   pełny komplet nie rozpychał stopki na wąskim ekranie.                   */

.stopka__sprzedaz .stopka__lista { gap: var(--s2); }

/* Pas banerowy: do pięciu slotów 300×50 w jednym rzędzie. Kreacje są
   rastrowe, więc przy węższym ekranie skalują się proporcjonalnie
   (aspect-ratio 6/1) zamiast łamać się do słupka.                        */

.stopka__pas {
  display: grid; gap: var(--s3);
  padding-block: var(--s6);
  border-top: 1px solid var(--rule);
  justify-items: center;
}

.stopka__pas-etykieta {
  font-size: var(--fs-micro); font-weight: 700; letter-spacing: .16em;
  text-transform: uppercase; color: var(--ink-3);
}

/* Pas banerów jest elementem siatki, więc bez min-width: 0 nie zwęzi się
   poniżej szerokości pojedynczego banera (300 px) i przy 320 px ekranu
   wypycha całą stopkę poza widok. */

.stopka__banery {
  display: flex; flex-wrap: wrap; gap: var(--s3);
  justify-content: center; width: 100%;
  min-width: 0; max-width: 100%;
}

.stopka__banery .baner {
  flex: 1 1 180px; max-width: 300px; min-width: 0;
  height: auto; aspect-ratio: 6 / 1; margin: 0;
}

.stopka__dol {
  border-top: 1px solid var(--rule);
  padding-block: var(--s5); display: flex; flex-wrap: wrap; gap: var(--s4);
  justify-content: space-between; font-size: var(--fs-xs); color: var(--ink-3);
}

.stopka__ai { font-size: var(--fs-xs); color: var(--ink-3); margin-top: var(--s5); }

/* ==========================================================================
   16a. STRONA REDAKTORA
   Nazwa, opis i wpisy — nic więcej. Zdjęcie jest opcjonalne: kadr ma stały
   rozmiar, więc jego brak nie przesuwa układu, a w miejscu zdjęcia zostaje
   monogram.
   ========================================================================== */

.redakcja-glowa {
  display: grid;
  grid-template-columns: 128px minmax(0, 1fr);
  gap: var(--s6);
  align-items: start;
  padding-bottom: var(--s6);
  border-bottom: 1px solid var(--rule);
}

.redakcja-glowa__foto {
  width: 128px; height: 128px;
  overflow: hidden; border-radius: 50%;
  background: var(--brand-050);
  display: grid; place-items: center;
}

.redakcja-glowa__foto img { width: 100%; height: 100%; object-fit: cover; }

/* stan bez zdjęcia — cienka kreskowana obwódka mówi, że slot istnieje */

.redakcja-glowa__foto[data-brak-zdjecia] {
  border: 1px dashed var(--rule-2);
  background: var(--brand-050);
}

.redakcja-glowa__monogram {
  font-family: var(--font-serif); font-size: 3rem; font-weight: 600;
  color: var(--brand); line-height: 1;
}

.redakcja-glowa__nazwa { font-size: var(--fs-h1); margin: var(--s3) 0 var(--s2); }

.redakcja-glowa__rola {
  font-size: var(--fs-xs); letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-3); margin: 0 0 var(--s4);
}

.redakcja-glowa__inni { font-size: var(--fs-sm); color: var(--ink-3); margin: var(--s5) 0 0; }

@media (max-width: 640px) {
  .redakcja-glowa { grid-template-columns: 1fr; gap: var(--s4); }
  .redakcja-glowa__foto { width: 96px; height: 96px; }
}

/* ==========================================================================
   16b. STRONA KONTAKTU
   Dane kontaktowe stoją na grafice, nie w treści HTML (ochrona przed
   robotami zbierającymi adresy) — dlatego ALT musi je powtarzać.
   ========================================================================== */

/* Adres kontaktowy jest tu jedyną treścią, po którą ktoś przyszedł —
   dostaje własny stopień pisma i sporo powietrza wokół.               */

.kontakt-adres {
  font-family: var(--font-serif);
  font-size: clamp(1.05rem, 2vw, 1.35rem);
  line-height: 1.3;
  margin: var(--s5) 0;
}

.kontakt-adres a { color: var(--brand-text); text-decoration-thickness: 1px; text-underline-offset: .18em; }

/* ==========================================================================
   WYBÓR REDAKCJI W STOPCE — wpisy polecane ręcznie

   W tej sieci wpisy polecane wskazuje redakcja checkboxem w edytorze.
   W tp_fundament stały w szynie obok materiału wiodącego na stronie
   głównej; tutaj — na życzenie — schodzą do stopki i pokazują się na
   KAŻDEJ podstronie. Stopka jest jedynym miejscem wspólnym dla wszystkich
   widoków, więc polecane trafiają też pod archiwum i pod dokument prawny.

   KOLUMNA, NIE PAS. Pierwsza wersja stawiała je w szerokim pasie
   z miniaturami NAD kolumnami stopki — układ, którego w makiecie nie ma.
   Makieta pokazuje stopkę jako rząd równych kolumn z listami odnośników,
   więc wybór redakcji jest po prostu kolejną taką kolumną: ten sam
   `.stopka__tytul` i `.stopka__lista`, co „Działy” i „Serwis”. Dlatego
   w tym pliku prawie nie ma już własnych reguł — cały wygląd przychodzi
   z `_stopka.scss` i to jest zamierzone. Zostaje tu tylko to, czego
   sąsiednie kolumny nie potrzebują: proporcje siatki przy piątej kolumnie
   i łamanie długich tytułów wpisów.

   NAZWA MA ZOSTAĆ RÓŻNA. Sąsiednia kolumna to PŁATNE linki klienta
   (`rel="sponsored nofollow"` z `tp_wp_get_backend_links`) pod nagłówkiem
   „Polecane”. Odkąd obie listy stoją obok siebie i wyglądają identycznie,
   nagłówek jest JEDYNĄ rzeczą, która mówi czytelniczce, gdzie kończy się
   redakcja, a zaczyna reklama. Oba nagłówki są w Customizerze (Stopka)
   i nie wolno ustawić ich na to samo słowo.

   Kolumna nie wypisuje się, gdy nie ma ani jednego oznaczonego wpisu. Nie
   ma podmiany na „najnowsze”: nagłówek obiecujący wybór redakcji nad listą,
   której nikt nie wybrał, to ta sama usterka, którą naprawialiśmy w szynie
   Fundamentu.
   ========================================================================== */

/* SIATKA STOPKI LICZY SIĘ Z LICZBY KOLUMN, KTÓRE FAKTYCZNIE SIĘ WYPISAŁY.

   Kolumny stopki są warunkowe: „Działy” i „Serwis” tylko z przypisanym
   menu, wybór redakcji tylko z oznaczonymi wpisami, kolumna płatna tylko
   z kampanią. Szablon dolicza je i dokłada klasę `stopka__gora--kN`
   (atl_klasa_stopki() w inc/sekcje.php).

   Wcześniej siatka miała na sztywno cztery tory. Na produkcji zantalo.pl
   wypisały się TRZY kolumny (portal nie ma jeszcze wpisów polecanych ani
   kampanii), więc czwarty tor stał pusty — jedna piąta szerokości stopki
   zostawała białą plamą po prawej, a nota o portalu ściskała się w węższej
   kolumnie, niż było miejsce.

   Proporcje, a nie `repeat(auto-fit, …)`: pierwsza kolumna (winieta i nota)
   musi zostać szersza od list, a auto-fit zrównałby wszystkie.           */

.stopka__gora--k1 { grid-template-columns: minmax(0, 46ch); }
.stopka__gora--k2 { grid-template-columns: 1.6fr 1fr; }
.stopka__gora--k3 { grid-template-columns: 1.6fr 1fr 1fr; }
.stopka__gora--k4 { grid-template-columns: 1.6fr 1fr 1fr 1.1fr; }
.stopka__gora--k5 { grid-template-columns: 1.5fr 1fr 1fr 1.2fr 1.2fr; }

/* Cztery tory na pięć kolumn wypchnęłyby piątą pod winietę, więc przy
   pięciu schodzimy od razu do trzech: 1–3 w pierwszym rzędzie, obie listy
   „polecanych” obok siebie w drugim. */
@media (max-width: 1200px) {
  .stopka__gora--k5 { grid-template-columns: 1.4fr 1fr 1fr; }
}

@media (max-width: 1000px) {
  .stopka__gora--k3, .stopka__gora--k4, .stopka__gora--k5 { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 620px) {
  .stopka__gora--k2, .stopka__gora--k3, .stopka__gora--k4, .stopka__gora--k5 { grid-template-columns: 1fr; }
}

/* Tytuły wpisów są dłuższe od nazw linków sprzedażowych obok („Kwasy AHA
   i BHA — charakterystyka i zastosowanie” kontra „Sklep z kosmetykami”),
   więc w wąskiej kolumnie łamią się na kilka linii. Odstęp między
   pozycjami musi być wtedy większy niż odstęp między liniami jednej
   pozycji — inaczej lista czyta się jak jeden blok tekstu.               */
.stopka__redakcja .stopka__lista { gap: var(--s3); }

/* Cztery linie to sufit: dłuższy tytuł rozpycha kolumnę i wypycha sąsiednie
   listy w dół. Ucięcie jest widoczne (wielokropek), więc nie udaje, że
   tytuł się skończył. Jedna reguła na `a`, nie dwie — `display` ustawiony
   dwa razy na tym samym selektorze to gotowa pułapka przy następnej
   edycji.                                                                */
.stopka__redakcja .stopka__lista a {
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  line-height: 1.35;
}

@media print {
  .stopka__redakcja { display: none; }
}

/* Strony prawne: treść przeniesiona dosłownie z .docx, więc bywa długa.
   Węższa miara i mniejszy stopień, żeby dało się to przeczytać.           */

.tresc--prawna { font-size: var(--fs-sm); }

.tresc--prawna h2 { font-size: var(--fs-h3); margin-top: var(--s7); }

.tresc--prawna li + li { margin-top: var(--s1); }

/* ==========================================================================
   16c. POWRÓT NA GÓRĘ
   Pojawia się dopiero po zjechaniu na drugi ekran — na krótkiej stronie
   byłby kolejnym elementem zasłaniającym treść.
   ========================================================================== */

.do-gory {
  position: fixed; right: var(--s5); bottom: 84px; z-index: 70;
  width: 46px; height: 46px;
  display: grid; place-items: center;
  border: 1px solid var(--rule-2); border-radius: 50%;
  background: var(--paper); color: var(--ink);
  box-shadow: var(--cien-2);
  opacity: 0; visibility: hidden; transform: translateY(8px);
  transition: opacity .25s var(--ease), transform .25s var(--ease), visibility 0s linear .25s;
}

.do-gory.widoczny { opacity: 1; visibility: visible; transform: none; transition-delay: 0s; }

.do-gory:hover { border-color: var(--ink); }

.do-gory svg { width: 20px; height: 20px; }

@media (max-width: 640px) { .do-gory { right: var(--s3); bottom: 76px; } }

@media (prefers-reduced-motion: reduce) { .do-gory { transition: none; } }

/* ==========================================================================
   17. PANEL KOLORÓW — symulacja Customizera
   To NIE jest element frontu bloga. Stoi w makiecie po to, żeby można było
   sprawdzić dowolną parę kolorów przed decyzją.
   ========================================================================== */

.cfg { position: fixed; right: var(--s5); bottom: var(--s5); z-index: 80; display: grid; justify-items: end; gap: var(--s2); }

.cfg__przelacz {
  display: inline-flex; align-items: center; gap: var(--s2);
  min-height: 44px; padding: 0 var(--s4);
  background: var(--ink); color: #fff; border: 0; border-radius: 22px;
  font-size: var(--fs-xs); font-weight: 600; letter-spacing: .06em;
  box-shadow: var(--cien-2);
}

.cfg__kropki { display: inline-flex; }

.cfg__kropki i { width: 13px; height: 13px; border-radius: 50%; border: 2px solid var(--ink); }

.cfg__kropki i + i { margin-left: -5px; }

.cfg__panel {
  width: 290px; padding: var(--s5);
  background: var(--paper); border: 1px solid var(--rule-2);
  box-shadow: var(--cien-3);
  display: none;
}

.cfg__panel[data-otwarte="true"] { display: block; }

.cfg__glowa { font-family: var(--font-serif); font-size: 1.0625rem; font-weight: 600; margin-bottom: var(--s2); }

.cfg__nota { font-size: var(--fs-xs); color: var(--ink-3); margin: 0 0 var(--s4); line-height: 1.5; }

.cfg__wiersz { display: flex; align-items: center; justify-content: space-between; gap: var(--s3); margin-bottom: var(--s3); }

.cfg__wiersz label { font-size: var(--fs-sm); }

.cfg__wiersz input[type="color"] { width: 46px; height: 32px; padding: 0; border: 1px solid var(--rule-2); background: none; cursor: pointer; }

.cfg__presety { display: grid; grid-template-columns: repeat(2, 1fr); gap: var(--s2); margin-top: var(--s4); }

.cfg__preset {
  display: flex; align-items: center; gap: var(--s2);
  padding: var(--s2) var(--s3); border: 1px solid var(--rule); background: var(--paper);
  font-size: var(--fs-xs); text-align: left;
}

.cfg__preset[aria-pressed="true"] { border-color: var(--ink); }

.cfg__preset i { width: 12px; height: 12px; border-radius: 50%; flex: none; }

.cfg__kontrast { margin-top: var(--s4); padding-top: var(--s3); border-top: 1px solid var(--rule); font-size: var(--fs-micro); color: var(--ink-3); display: grid; gap: 4px; }

.cfg__kontrast b { font-family: var(--font-mono); color: var(--ink); }

@media (max-width: 640px) { .cfg { right: var(--s3); bottom: var(--s3); } .cfg__panel { width: min(88vw, 290px); } }

/* ==========================================================================
   18. RÓŻNE
   ========================================================================== */

.nota {
  border: 1px dashed var(--rule-2); background: var(--paper-2);
  padding: var(--s4); font-size: var(--fs-sm); color: var(--ink-2);
}

.nota strong { color: var(--ink); }

.siatka-2 { display: grid; gap: var(--s6); grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }

/* Sekcje poniżej pierwszego ekranu nie muszą być renderowane od razu */

.leniwa { content-visibility: auto; contain-intrinsic-size: auto 800px; }

/* Wyściółka boksów w treści na wąskim ekranie ---------------------------
   24 px z każdej strony to na ekranie 320 px osiemnaście procent szerokości
   boksu. Wiersz w „Krótko" i w spisie treści spadał wtedy do 26 znaków —
   poniżej progu, przy którym tekst czyta się płynnie (wygodny zakres to
   45–75 znaków, na telefonie realnie 35–40). Zejście do 16 px oddaje pięć
   znaków na wiersz i nie odbiera boksowi wyrazistości.                   */

@media (max-width: 480px) {
  .bluf, .spis { padding: var(--s4); }
}

/* ==========================================================================
   18a. WSTAWKI GRAFICZNE
   ==========================================================================

   Trzy warstwy dekoracyjne na stronie głównej. Wszystkie:
   • rysowane wyłącznie z --brand i --accent, więc zmiana dwóch kolorów
     w Customizerze przestawia je razem z resztą motywu;
   • czystym CSS-em, zero plików do pobrania;
   • w pseudoelementach z pointer-events: none, więc nic nie łapią
     i nic nie przesuwają w układzie;
   • w kontenerach z overflow: hidden, więc nie mogą rozepchnąć strony.

   Zasada nadrzędna została ta sama, co w całym motywie: kolor niosą
   zdjęcia. Te warstwy mają dawać głębię, a nie rywalizować z kadrem —
   stąd krycie w okolicach kilku procent.                              */

/* --- poświata pod otwarciem ------------------------------------------
   Dwie miękkie plamy w rogach: cieplejsza z akcentu po prawej, chłodniejsza
   z marki po lewej. Górny ekran przestaje być płaską bielą, a zdjęcia
   dostają tło, z którego wychodzą.                                    */

.otwarcie { position: relative; overflow: hidden; }

.otwarcie::before {
  content: ""; position: absolute; inset: -25% 0 0 0;
  pointer-events: none; z-index: 0;
  background:
    radial-gradient(55% 60% at 85% 8%, color-mix(in oklab, var(--accent), transparent 88%), transparent 70%),
    radial-gradient(50% 55% at 8% 0%, color-mix(in oklab, var(--brand), transparent 90%), transparent 72%);
}

.otwarcie > .wrap { position: relative; z-index: 1; }

/* --- duży numer sekcji w tle -----------------------------------------
   Ten sam numer, który stoi w nadkreśleniu, powtórzony szeryfowo
   i wielko przy krawędzi. Motyw ma już numerowane sekcje, więc znak
   nie jest ozdobnikiem znikąd — to ta sama informacja, tylko czytana
   kątem oka. Na wąskim ekranie znika: tam każdy piksel szerokości
   jest potrzebny treści.                                              */

.sekcja[data-nr] { position: relative; overflow: hidden; }

.sekcja[data-nr] > .wrap { position: relative; z-index: 1; }

/* Na dotyku sąsiadujące linki stopki nie mogą się stykać — 24 px celu
   bez odstępu to nadal jeden duży obszar pomyłki.                     */

@media (hover: none) {
  .stopka__lista, .stopka__sprzedaz .stopka__lista { gap: var(--s3); }
}

/* ==========================================================================
   19. DRUK
   ========================================================================== */

/* ==========================================================================
   POPRAWKI PO PRZENIESIENIU Z MAKIETY

   Makieta składała kafle skryptem i tylko skryptem, więc jej arkusz mógł
   założyć, że każdy `<img class="kafel__foto">` leży w kadrze o narzuconej
   wysokości i czeka na klasę `.zaladowane`. W motywie ten sam znacznik
   wypisuje `atl_kadr()` również poza ścianą — pod zdjęciem wiodącym wpisu
   i w miniaturach list bocznych. Bez tych dwóch reguł kadr zapada się do zera
   (obrazek jest `position:absolute` w kontenerze bez wysokości) i zostaje
   niewidoczny (`opacity:0` do momentu, w którym skrypt doda klasę —
   a poza ścianą nikt jej nie dodaje).

   Reguły stoją w osobnym partialu, nie w przeniesionych, żeby przy
   ponownym uruchomieniu narzedzia/wyciagnij-makiete.py nie zniknęły
   razem z nadpisanym plikiem.
   ========================================================================== */

.wpis-foto__kadr .kafel__foto,
.mini__kadr .kafel__foto {
  position: static;
  inset: auto;
  opacity: 1;
  transform: none;
}

/* Zdjęcie wiodące wpisu idzie w natywnych proporcjach generatora, więc
   nie wolno mu narzucać wysokości ani przycinać. */
.wpis-foto__kadr .kafel__foto {
  width: 100%;
  height: auto;
  object-fit: contain;
}

/* Hover na ścianie powiększa kadr; w listach bocznych to ruch bez powodu —
   kafel nie jest tam bohaterem widoku. */
.mini__kadr .kafel__foto {
  transition: none;
}

/* ==========================================================================
   BELKA WP-ADMINA

   NIEAKTYWNE przy domyślnych ustawieniach: motyw zdejmuje belkę z frontu
   filtrem `show_admin_bar` (inc/setup.php), więc klasa `admin-bar` na
   <body> nie powstaje i żadna z tych reguł nie ma do czego się przyczepić.

   Zostają świadomie. Belka wraca jednym `remove_filter` — na portalu, gdzie
   redakcja będzie jej chciała, albo w motywie potomnym — i wtedy odstępy
   muszą już być na miejscu. Bez nich objaw jest taki, jaki widzieliśmy:
   pasek nawigacji traci pierwsze 32 px, w tym całą linię z nazwami działów.

   Poniżej opis dla tego przypadku:

   Belka jest `position: fixed`, więc przyklejona nawigacja z `top: 0`
   wjeżdża pod nią i traci pierwsze 32 px.

   Wysokości i zachowanie belki są takie same we wszystkich motywach
   WordPressa, więc progi są jej progami, nie naszymi:
     - od 783 px belka ma 32 px i jest przyklejona,
     - 601–782 px belka ma 46 px i nadal jest przyklejona,
     - do 600 px belka jest `position: absolute` i ODJEŻDŻA razem ze stroną,
       więc nawigacja wraca na `top: 0`.

   Reguły dotyczą wyłącznie widoku zalogowanego (`body.admin-bar`) —
   czytelniczka portalu nie widzi tu żadnej różnicy.
   ========================================================================== */

@media screen and (min-width: 783px) {
  body.admin-bar .nawigacja { top: 32px; }
}

@media screen and (min-width: 601px) and (max-width: 782px) {
  body.admin-bar .nawigacja { top: 46px; }
}

/* Panel boczny wpisu też przykleja się pod paskiem, więc też musi zejść
   niżej przy belce wp-admina. Makieta miała tu wpisane 46 px — wysokość
   paska nawigacji — i to zostaje, bo pasek nadal ma tyle. Dokładamy tylko
   wysokość belki, i to tam, gdzie belka faktycznie jest przyklejona.

   Bez tej poprawki panel startował 32 px za wysoko (etykieta „więcej
   w tym dziale” pod belką) i był o 32 px za wysoki, więc jego własny
   pasek przewijania pojawiał się wcześniej, niż powinien. */

@media screen and (min-width: 1000px) {
  body.admin-bar .wrap--wpis .z-panelem__panel {
    top: calc(46px + var(--s5) + 32px);
    max-height: calc(100vh - 46px - var(--s6) - 32px);
  }
}

/* Wariantu na belkę 46 px tu nie ma: panel boczny wchodzi od 1000 px,
   a belka jest wysoka na 46 px tylko do 782 px — te dwa zakresy nigdy się
   nie spotykają. Reguła „na wszelki wypadek” byłaby martwym selektorem,
   którego nikt później nie usunie. */

/* ==========================================================================
   BLOKI KODU

   W makiecie nie ma ani jednego bloku kodu, więc w przeniesionym arkuszu nie
   ma reguł na `pre` i `code`. Na portalu z poradnikami wystarczy jeden blok
   z edytora, żeby to zobaczyć: `pre` nie łamie linii i domyślnie ma
   `overflow: visible`, więc długa linia rozpycha nie siebie, a CAŁY
   dokument. Zmierzone na localhoście po wstawieniu jednej linii kodu:
   przy 320 px szerokość dokumentu 950 px, przy 768 px — 958 px. Cała
   strona jechała w poziomie.

   `pre` przewija się teraz sam, we własnym pudełku. Region przewijalny musi
   być osiągalny z klawiatury, więc `tabindex` i `role` dokłada PHP
   (atl_opakuj_kod() w inc/tresc.php) — tak samo jak przy tabelach.
   ========================================================================== */

.tresc pre {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
  margin: var(--s5) 0;
  padding: var(--s4);
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  line-height: 1.5;
  tab-size: 2;
}

/* Kod w bloku nie dostaje własnego tła ani ramki — miałby wtedy pudełko
   w pudełku. */
.tresc pre code {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  white-space: pre;
}

/* Kod w zdaniu ma się łamać w dowolnym miejscu: nazwy funkcji i ścieżki
   bywają dłuższe niż kolumna tekstu na telefonie. */
.tresc code {
  font-family: var(--font-mono);
  font-size: .92em;
  background: var(--paper-2);
  border: 1px solid var(--rule);
  border-radius: 4px;
  padding: .1em .35em;
  overflow-wrap: anywhere;
}

.tresc pre:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

/* ==========================================================================
   KAFEL-OKŁADKA SZERSZY OD SWOJEJ KOLUMNY

   `.kafel--okladka > .kafel__kadr` ma `height: 100%` (kadr wypełnia pole
   siatki, w którym leży też podpis) i jednocześnie `aspect-ratio`. Gdy
   podana jest tylko JEDNA oś, przeglądarka liczy z niej drugą — i liczyła
   SZEROKOŚĆ z wysokości wiersza. Zmierzone na produkcji zantalo.pl przy
   320 px: kadr 307 px w kolumnie 288 px, prawa krawędź na 323 px.
   Widać to było jako ucięty z prawej kafel wiodący na telefonie
   (`.kafel--okladka` ma `overflow: hidden`, więc strona się nie przewijała
   i usterka nie rzucała się w oczy).

   Podanie OBU osi wyłącza `aspect-ratio` z rachunku — kadr wypełnia pole
   siatki dokładnie, a o jego wysokości decyduje podpis, tak jak ma być
   na kaflu-okładce.
   ========================================================================== */

.kafel--okladka > .kafel__kadr { width: 100%; min-width: 0; }

/* LICZBA KOLUMN JEST KLASĄ, NIE ZMIENNĄ INLINE.

   Szablon mówi, ile kolumn ściana chce na szerokim ekranie, klasą
   `sciana--kN` (atl_klasa_sciany() w inc/sekcje.php). Wcześniej wpisywał
   to jako `style="--kolumny:N"` prosto na element — a deklaracja inline
   bije każdy selektor z arkusza, więc trzy zapytania niżej nie robiły NIC.
   Zmierzone na localhoście przy 320 px: cztery kolumny po 65 px, prawa
   krawędź kadru na 323 px, znacznik działu poza ekranem, tytuły przycięte.

   Klamry poniżej ZWĘŻAJĄ i nigdy nie rozszerzają. To nie jest kosmetyka:
   pierwsza próba naprawy dawała `--kolumny: 3 !important` całej klasie
   `.sciana`, więc ściana rekomendacji pod wpisem, która chce dwóch
   kolumn, dostawała przy 900 px trzy. Dlatego każde zapytanie wymienia
   tylko te warianty, które są od limitu SZERSZE.                         */

.sciana--k1 { --kolumny: 1; }
.sciana--k2 { --kolumny: 2; }
.sciana--k3 { --kolumny: 3; }
.sciana--k4 { --kolumny: 4; }
.sciana--k5 { --kolumny: 5; }

@media (max-width: 1200px) {
  .sciana--k4, .sciana--k5 { --kolumny: 3; }
}

@media (max-width: 860px) {
  .sciana { --przerwa: 14px; }
  .sciana--k3, .sciana--k4, .sciana--k5 { --kolumny: 2; }
}

@media (max-width: 420px) {
  .sciana--k2, .sciana--k3, .sciana--k4, .sciana--k5 { --kolumny: 1; }
}

/* ==========================================================================
   BLOK FAQ Z GENERATORA (`.faq-schema-container` + <details>)

   Motyw ma własny akordeon FAQ (`.faq__pyt` / `.faq__odp`) i to jego style
   stoją w _wpis.scss. Na produkcji generator sieci oddaje jednak CO INNEGO:
   `<div class="faq-schema-container">` z listą `<details><summary>`.
   Sprawdzone na zantalo.pl — siedem takich bloków w jednym wpisie.

   Motyw je ROZUMIE (atl_wyjmij_faq() ma zapasową ścieżkę na <details>
   i buduje z nich FAQPage), ale ich nie STYLIZOWAŁ: pytania szły domyślnym
   trójkątem przeglądarki, bez ramek, bez odstępów i bez kursora wskazującego,
   że da się je kliknąć. W środku wystylizowanego artykułu wyglądało to jak
   fragment strony bez arkusza.

   Znaczników nie przepisujemy na `.faq__*`: pochodzą z treści wpisu, więc
   ich zmiana wymagałaby przerabiania bazy przy każdym imporcie. Nadajemy im
   wygląd akordeonu motywu — tak samo jak `.tabela-otoczka` dostaje wygląd,
   choć jej klasę też dokłada warstwa treści.
   ========================================================================== */

.faq-schema-container {
  border-top: 1px solid var(--rule);
  margin: var(--s5) 0;
}

.faq-schema-container details {
  border-bottom: 1px solid var(--rule);
}

.faq-schema-container summary {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--s4);
  padding: var(--s4) 0;
  cursor: pointer;
  font-family: var(--font-serif);
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--ink);
  list-style: none;
}

/* Domyślny trójek ujawniania: w Chrome i Firefoksie zdejmuje go
   `list-style: none`, w Safari dopiero ten pseudo-element. Bez obu
   znacznik zostaje i stoi w osobnej linii pod pytaniem — bo `summary`
   zawiera nagłówek, czyli element blokowy. */
.faq-schema-container summary::-webkit-details-marker { display: none; }
.faq-schema-container summary::marker { content: ''; }

/* Znak rozwinięcia jak w akordeonie motywu: plus i minus, nie strzałka. */
.faq-schema-container summary::after {
  content: '+';
  font-family: var(--font-mono);
  font-size: 1.25rem;
  line-height: 1;
  color: var(--brand);
  flex: none;
}

.faq-schema-container details[open] > summary::after { content: '−'; }

/* Pytanie bywa opakowane w nagłówek — wtedy nie może wnosić własnych
   odstępów ani swojego stopnia pisma, bo rozbija wiersz akordeonu. */
.faq-schema-container summary > * {
  margin: 0;
  font: inherit;
  color: inherit;
  display: inline;
}

.faq-schema-container summary:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

.faq-schema-container details > *:not(summary) {
  margin: 0 0 var(--s4);
  color: var(--ink-2);
  font-size: var(--fs-body);
}
