/* ==========================================================================
   RefBoost - fragmenty silnika
   ==========================================================================

   `style.css` jest arkuszem DESIGNERA i nie należy go tu ruszać. Ten plik
   pokrywa wyłącznie znaczniki, które dokłada silnik: baner zgód, ujawnienie
   afiliacji, bylinię, promocje, FAQ, formularze, paginację.

   ----------------------------------------------------------------------
    DLACZEGO TO MUSI ISTNIEĆ W KAŻDYM MOTYWIE
   ----------------------------------------------------------------------

   Fragmenty silnika używają WŁASNYCH nazw klas (`cookie-banner`, `byline`,
   `offer-list`…). Motyw, który ich nie pokryje, renderuje je jako gołe
   elementy przeglądarki - bez błędu, bez ostrzeżenia, po prostu brzydko.

   Przy tej paczce zliczenie klas z HTML-a bez pokrycia w CSS znalazło 23
   takie przypadki, w tym trzy, które nie są kosmetyką:

     · `cookie-banner`  - baner zgód RODO renderował się jako surowy tekst
     · `affiliate-disclosure` - wymagane ujawnienie, nie do przeoczenia
     · `hp-field`       - HONEYPOT formularza. Bez reguły chowającej pole
                          jest WIDOCZNE: czytelnik je wypełnia i dostaje
                          odrzucenie zgłoszenia jako bot.

   Zmienne pochodzą z `theme.json` przez `:root`, więc przemalowanie motywu
   w panelu działa też tutaj.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. HONEYPOT - NAJPIERW, BO TO JEDYNA REGUŁA O SKUTKACH FUNKCJONALNYCH
   -------------------------------------------------------------------------- */
.hp-field {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

/* Treść wyłącznie dla czytnika ekranu. */
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* Link pomijający nawigację - widoczny dopiero po tabulacji. */
.skip-link {
    position: absolute;
    left: 1rem; top: -4rem;
    z-index: 200;
    padding: .7rem 1.1rem;
    border-radius: 10px;
    background: var(--mint);
    color: #06231a;
    font-family: var(--font-label);
    font-weight: 700;
    transition: top .15s ease;
}
.skip-link:focus { top: 1rem; }

/* --------------------------------------------------------------------------
   2. BANER ZGÓD

   Oba przyciski mają CELOWO tę samą wagę wizualną. Baner, w którym odmowa
   jest szara i mniejsza od zgody, nie zbiera zgody dobrowolnej - a to jest
   warunek jej ważności, nie kwestia gustu.
   -------------------------------------------------------------------------- */
.cookie-banner {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 120;
    padding: 1rem var(--gap, 1.25rem);
    background: var(--bg-surface);
    border-top: 1px solid var(--line-strong);
    box-shadow: 0 -18px 40px -24px rgb(0 0 0 / .8);
}

.cookie-banner-inner {
    max-width: 1140px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    gap: 1.25rem;
    flex-wrap: wrap;
}

.cookie-banner-title {
    margin: 0 0 .3rem;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 1rem;
    color: var(--text-primary);
}

.cookie-banner-text {
    margin: 0;
    font-size: .88rem;
    line-height: 1.5;
    color: var(--text-muted);
    max-width: 70ch;
}
.cookie-banner-text a { color: var(--mint); text-decoration: underline; }

.cookie-banner-actions {
    display: flex;
    gap: .6rem;
    margin-left: auto;
    flex-wrap: wrap;
}

.cookie-btn {
    padding: .6rem 1.2rem;
    border-radius: 10px;
    border: 1px solid var(--line-strong);
    background: var(--bg-card);
    color: var(--text-primary);
    font-family: var(--font-label);
    font-weight: 600;
    font-size: .88rem;
    cursor: pointer;
    transition: border-color .16s ease, color .16s ease;
}
.cookie-btn:hover { border-color: var(--mint); color: var(--mint); }

/* --------------------------------------------------------------------------
   3. UJAWNIENIE AFILIACJI
   -------------------------------------------------------------------------- */
.affiliate-disclosure {
    margin: 0 0 1.25rem;
    padding: .7rem .95rem;
    border-left: 3px solid var(--gold);
    border-radius: 0 8px 8px 0;
    background: rgb(226 176 74 / .06);
    color: var(--text-muted);
    font-size: .84rem;
    line-height: 1.55;
}
.affiliate-disclosure a { color: var(--gold); text-decoration: underline; }

/* --------------------------------------------------------------------------
   4. BYLINIA - kto napisał i kiedy sprawdził
   -------------------------------------------------------------------------- */
.byline {
    display: flex;
    align-items: center;
    gap: .8rem;
    flex-wrap: wrap;
    margin: 0 0 1.5rem;
    padding: .9rem 1rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--bg-card);
    font-size: .88rem;
    color: var(--text-muted);
}
.byline-photo { width: 40px; height: 40px; border-radius: 50%; object-fit: cover; }
.byline-author { font-weight: 700; color: var(--text-primary); font-family: var(--font-display); }
.byline-author a { color: inherit; }
.byline-author a:hover { color: var(--mint); }
.byline-role { display: block; font-size: .8rem; }
.byline-reviewer { color: var(--mint); }
.byline-dates { margin-left: auto; text-align: right; font-size: .8rem; }
.byline-modified { display: block; }

/* --------------------------------------------------------------------------
   5. PROMOCJE
   -------------------------------------------------------------------------- */
.offers { margin: 0 0 2rem; }
.offer-list { display: grid; gap: .8rem; padding: 0; margin: 0; list-style: none; }

.offer-list > li,
.bonus-row {
    padding: 1rem 1.1rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--bg-card);
}

.offer-head { display: flex; align-items: baseline; gap: .7rem; flex-wrap: wrap; }
.offer-title { margin: 0; font-family: var(--font-display); font-size: 1.02rem; color: var(--text-primary); }
.offer-type {
    padding: .15rem .5rem;
    border-radius: 6px;
    background: rgb(43 217 166 / .14);
    color: var(--mint);
    font-family: var(--font-label);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
}
.offer-desc { margin: .5rem 0 0; color: var(--text-secondary); font-size: .9rem; }
.offer-facts {
    display: flex; gap: 1.1rem; flex-wrap: wrap;
    margin: .7rem 0 0; padding: 0; list-style: none;
    font-size: .85rem; color: var(--text-muted);
}
.offer-facts strong { color: var(--text-primary); font-family: var(--font-display); }
.offer-terms { margin: .6rem 0 0; font-size: .78rem; color: var(--text-muted); }

/* --------------------------------------------------------------------------
   6. FAQ - paczka ma własny `.faq-item`, silnik dokłada `.faq` i `.faq-list`
   -------------------------------------------------------------------------- */
.faq { margin: 2rem 0 0; }

/* `.faq-list` i `.faq-item` NALEŻĄ DO PACZKI i wyglądają lepiej niż cokolwiek,
   co bym tu dopisał - nie dotykamy. Różni się tylko nazwa kontenera odpowiedzi:
   paczka styluje `.answer`, a silnik renderuje `.faq-answer`. Bez tej reguły
   treść odpowiedzi leżałaby bez marginesów, przyklejona do krawędzi karty. */
.faq-item .faq-answer {
    padding: 0 1.35rem 1.25rem;
    color: var(--text-secondary);
    line-height: 1.65;
    font-size: .92rem;
}
.faq-item .faq-answer p:first-child { margin-top: 0; }
.faq-item .faq-answer p:last-child { margin-bottom: 0; }

/* --------------------------------------------------------------------------
   7. FORMULARZE SILNIKA
   -------------------------------------------------------------------------- */
.form-consent {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    margin: .7rem 0;
    font-size: .82rem;
    line-height: 1.45;
    color: var(--text-muted);
}
.form-consent input { margin-top: .2rem; flex-shrink: 0; }

/* --------------------------------------------------------------------------
   8. LISTY I STANY PUSTE
   -------------------------------------------------------------------------- */
.article-list { display: grid; gap: 1rem; }

.empty {
    padding: 2rem 1rem;
    border: 1px dashed var(--line-strong);
    border-radius: 12px;
    text-align: center;
    color: var(--text-muted);
}

.sort-chip {
    padding: .35rem .8rem;
    border: 1px solid var(--line-strong);
    border-radius: 999px;
    font-size: .82rem;
    color: var(--text-muted);
}

/* --------------------------------------------------------------------------
   9. WŁASNE OPAKOWANIA UKŁADU

   Neutralne z założenia: mają nie ruszać siatki designera, tylko dać
   nazwanym miejscom przewidywalne odstępy.
   -------------------------------------------------------------------------- */
.rank-rows { display: contents; }
.affiliate-disclosure-slot { grid-column: 1 / -1; }
.byline-slot, .offers-slot { margin-bottom: 1.5rem; }

.footer-brand { margin-bottom: 1rem; }
.footer-tagline { margin: 0 0 1rem; color: var(--text-muted); font-size: .85rem; line-height: 1.5; }

.review-hero-main { display: flex; align-items: center; gap: 1.1rem; margin-bottom: 1.5rem; }
.review-hero-text { flex: 1; min-width: 0; }

@media (max-width: 720px) {
    .cookie-banner-actions { margin-left: 0; width: 100%; }
    .cookie-btn { flex: 1; }
    .byline-dates { margin-left: 0; text-align: left; width: 100%; }
}

/* --------------------------------------------------------------------------
   10. FORMULARZE SILNIKA - KOLIZJA NAZW KLAS Z PACZKĄ

   `style.css` ma WŁASNĄ regułę `.newsletter-form`, napisaną pod zupełnie
   inny komponent: `display:flex` z polem e-mail i przyciskiem obok siebie.

   Formularz silnika pod tą samą nazwą ma siedem elementów potomnych -
   trzy pola ukryte, honeypot, etykietę, pole, zgodę i przycisk. Wrzucone
   w `flex-direction: row` ustawiły się w rzędzie: wysokie wąskie prostokąty
   i tekst zgody uciekający poza kontener. Dokładnie to widać w stopce.

   Kolizja jest nie do uniknięcia przy imporcie cudzych paczek: designer
   nie zna nazw klas silnika, a silnik nie zna jego. Rozstrzyga kolejność -
   `engine.css` wczytuje się jako ostatni, więc to jest właściwe miejsce,
   żeby taką kolizję rozbroić, zamiast edytować arkusz designera.
   -------------------------------------------------------------------------- */
.newsletter-form,
.contact-form {
    display: grid;
    gap: .7rem;
    margin-top: 1rem;
    max-width: 30rem;
}

/* Zdejmuje `flex: 1` z reguły paczki - w siatce nie znaczy nic dobrego. */
.newsletter-form input[type="email"],
.contact-form input,
.contact-form select,
.contact-form textarea {
    flex: none;
    width: 100%;
    padding: .7rem .85rem;
    border: 1px solid var(--line-strong);
    border-radius: 10px;
    background: var(--bg-pure);
    color: var(--text-primary);
    font: inherit;
}

.newsletter-form input[type="email"]:focus,
.contact-form input:focus,
.contact-form select:focus,
.contact-form textarea:focus {
    outline: none;
    border-color: var(--mint);
}

.contact-form textarea { min-height: 8rem; resize: vertical; }

/* `:not(.form-consent)` TAKZE tutaj. Bez tego etykieta zgody - ktora jest
   bezposrednim dzieckiem formularza - dostawala styl etykiety pola:
   wersaliki i odstepy miedzy literami. W waskiej kolumnie stopki
   lamalo to zdanie na jedno slowo w linii. */
.newsletter-form > label:not(.form-consent),
.contact-form label:not(.form-consent) {
    font-family: var(--font-label);
    font-size: .78rem;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.newsletter-form button[type="submit"],
.contact-form button[type="submit"] {
    justify-self: start;
    padding: .7rem 1.5rem;
    border: 0;
    border-radius: 10px;
    background: var(--mint);
    color: #06231a;
    font-family: var(--font-label);
    font-weight: 700;
    font-size: .9rem;
    cursor: pointer;
    white-space: nowrap;
}
.newsletter-form button[type="submit"]:hover,
.contact-form button[type="submit"]:hover { background: var(--mint-deep); }

.form-error { color: #f87171; font-size: .85rem; }
.form-success { color: var(--mint); font-size: .9rem; }

/* Stopka jest wąska - formularz nie ma się w niej rozpychać. */
.footer-col .newsletter-form { max-width: none; margin-top: 0; }

/* --------------------------------------------------------------------------
   11. `.form-row` - DRUGA KOLIZJA TEGO SAMEGO RODZAJU

   W paczce `.form-row` układa kilka pól OBOK SIEBIE (`display:flex`,
   `align-items:flex-end`). W formularzu kontaktowym silnika to jest para
   etykieta + pole, która ma stać JEDNO POD DRUGIM.

   Bez tej reguły etykieta „Twój e-mail" wylądowałaby obok pola i formularz
   wyglądałby tak samo jak zepsuty newsletter w stopce. Strona kontaktowa
   jeszcze nie istnieje na tej witrynie, więc nikt by tego nie zauważył
   aż do jej dodania.
   -------------------------------------------------------------------------- */
.contact-form .form-row,
.newsletter-form .form-row {
    display: grid;
    gap: .35rem;
    align-items: stretch;
}


/* --------------------------------------------------------------------------
   NEWSLETTER W STOPCE - ostatnia kolumna siatki
   --------------------------------------------------------------------------
   Paczka ma `1.5fr repeat(4, 1fr)`, czyli PIĘĆ kolumn, a wypełnione są
   cztery: marka i trzy listy linków. Piąta stała pusta - przez całą
   wysokość stopki.

   Formularz wpychany w kolumnę `1fr` łamał zgodę na jedno słowo w linii,
   więc wcześniej wylądował pod siatką. Zamiast tego siatka dostaje
   pod niego kolumnę SZERSZĄ: `1.7fr` to około 340 px przy pełnej
   szerokości kontenera - tyle, ile potrzebuje rząd „pole + przycisk".

   Listy linków są i tak wyższe, więc kolumna nic nie kosztuje pionowo.
   -------------------------------------------------------------------------- */
.footer-grid {
    grid-template-columns: 1.4fr 1fr 1fr 1fr 1.7fr;
}

/*
   PONIŻEJ 1024 px formularz dostaje własny rząd na pełną szerokość.

   Kolumna, która przy 1600 px ma 340 px, przy 900 px ma 250 - czyli
   dokładnie tyle, ile łamało zgodę na jedno słowo w linii. Zamiast
   ścieśniać formularz, przenosimy go pod listy linków.

   Listy zostają wtedy w czterech kolumnach zamiast pięciu z jedną pustą -
   czyli w układzie, który paczka faktycznie wypełniała.
*/
@media (max-width: 1023px) {
    .footer-grid { grid-template-columns: 1.5fr repeat(3, 1fr); }
    .footer-newsletter { grid-column: 1 / -1; }
}

/* Próg paczki dla wąskich ekranów zostaje bez zmian. */
@media (max-width: 768px) {
    .footer-grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 560px) {
    .footer-grid { grid-template-columns: 1fr; }
}

.footer-newsletter {
    margin: 0;
}

.footer-newsletter h4 {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0 0 1rem;
    font-weight: 500;
}

/* ==========================================================================
   FORMULARZ NEWSLETTERA

   Poprzednia wersja robiła `display: grid` na samym `<form>`. Elementami
   siatki stawały się wtedy TAKŻE `@csrf`, pola ukryte i pułapka na boty,
   więc checkbox zgody lądował w innej komórce niż jego tekst, a zgoda
   łamała się na jedno słowo w linii.

   Teraz układ niesie jawny `<div class="newsletter-row">`, a formularz
   jest zwykłym blokiem - kolejność pól ukrytych przestaje mieć znaczenie.
   ========================================================================== */

.footer-newsletter .newsletter-form {
    display: block;
    max-width: none;
    margin-top: 0;
}

.newsletter-row {
    display: flex;
    align-items: center;
    gap: .6rem;
}

.newsletter-row input[type="email"] {
    flex: 1 1 auto;
    min-width: 0;
    padding: .7rem .9rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, .04);
    border: 1px solid var(--line-strong);
    color: var(--text-primary);
    font-family: 'Inter', sans-serif;
    font-size: .9rem;
}

.newsletter-row input[type="email"]::placeholder { color: var(--text-muted); }

.newsletter-row input[type="email"]:focus {
    outline: none;
    border-color: rgba(43, 217, 166, .45);
}

.newsletter-row .btn-primary {
    flex: 0 0 auto;
    white-space: nowrap;
}

/* Zgoda: checkbox i tekst w jednej linii, tekst na pełną szerokość.
   To ten element rozjeżdżał się najbardziej - stąd jawny `flex`
   i `normal-case`, bo `.footer-col h4` narzuca w tej stopce wersaliki. */
.footer-newsletter .form-consent {
    display: flex;
    align-items: flex-start;
    gap: .55rem;
    margin-top: .85rem;
    font-family: 'Inter', sans-serif;
    font-size: .8rem;
    font-weight: 400;
    line-height: 1.5;
    letter-spacing: normal;
    text-transform: none;
    color: var(--text-muted);
    cursor: pointer;
}

.footer-newsletter .form-consent input[type="checkbox"] {
    flex: 0 0 auto;
    margin-top: .15rem;
}

.footer-newsletter .form-consent span { flex: 1 1 auto; }

/* Etykieta pola e-mail: obecna dla czytnika ekranu, niewidoczna dla oka. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ==========================================================================
   TABELA PORÓWNAWCZA SILNIKA W JĘZYKU TEJ PACZKI
   ==========================================================================

   Paczka buduje porównanie z samych `<div>` w siatce (`.compare-grid`).
   Wygląda tak samo, a dla czytnika ekranu jest ciągiem luźnych liczb
   bez związku z kolumną i wierszem. Silnik oddaje więc prawdziwą
   `<table>` ze `scope`, a te reguły dają jej wygląd `.compare-grid`:
   te same tła, ta sama ramka, ten sam rytm padding-u.

   Liczba kolumn jest zmienna (redaktor wybiera je w panelu), więc
   `grid-template-columns` z paczki nie ma tu zastosowania - tabela
   rozkłada kolumny sama. */

.table-scroll .compare-table {
    min-width: 760px;
    width: 100%;
    border-collapse: separate;
    border-spacing: 1px;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 16px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.06);
}

.compare-table th,
.compare-table td {
    padding: 1rem 1.25rem;
    background: rgba(15, 19, 18, 0.95);
    font-size: .9rem;
    color: var(--text-secondary);
    text-align: left;
    vertical-align: middle;
}

.compare-table thead th {
    background: rgba(21, 27, 25, 0.95);
    font-family: var(--font-label);
    font-size: 11px;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: 500;
}

.compare-table .compare-name {
    background: rgba(19, 24, 22, 0.95);
    color: #fff;
    font-weight: 600;
    white-space: nowrap;
}

.compare-table .compare-name .logo {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    margin-right: .5rem;
    background: var(--bg-card);
    border: 1px solid var(--line-strong);
    overflow: hidden;
}

.compare-table .compare-name .logo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: inherit;
}

.compare-table .compare-name a { color: inherit; text-decoration: none; }
.compare-table .compare-name a:hover { color: var(--mint); }

/* Pierwszy wiersz wyróżniony tak jak `.winner` w paczce - to najwyżej
   oceniona pozycja tabeli, a nie „zwycięzca" wybrany ręcznie. */
.compare-table tbody tr.top1 td { background: rgba(43, 217, 166, 0.05); color: var(--mint); font-weight: 600; }

/* Brak danych to kreska. Wyszarzona, żeby nie czytało się jej jak wartości. */
.compare-table .compare-empty { color: var(--text-muted); }

/* ==========================================================================
   PRZEŁĄCZNIK JĘZYKA - ROZWIJANA LISTA
   ==========================================================================

   Paczka ma tu `<button class="lang-pill">` z listą obsługiwaną w JS, więc
   arkusz zna wygląd samej pigułki, ale nie zna menu. Silnik oddaje
   `<details>` (lista w DOM, działa bez JS), a te reguły dokładają wygląd
   rozwinięcia w języku tej paczki.

   Powód zmiany: przy sześciu językach rząd kodów „EN DE FI NO ES PT-BR"
   rozsadzał nagłówek. */

.lang-switch {
    position: relative;
}

/* Znacznik `<details>` w przeglądarce to trójkącik - pigułka ma własną
   strzałkę z paczki. */
.lang-switch > summary {
    list-style: none;
    cursor: pointer;
}

.lang-switch > summary::-webkit-details-marker { display: none; }
.lang-switch > summary::marker { content: ""; }

/* Strzałka obraca się przy rozwinięciu - jedyny sygnał stanu, jaki ma
   ten element. */
.lang-switch > summary svg:last-child {
    transition: transform .2s ease;
}

.lang-switch[open] > summary svg:last-child {
    transform: rotate(180deg);
}

.lang-menu {
    position: absolute;
    top: calc(100% + .4rem);
    right: 0;
    z-index: 60;
    min-width: 6rem;
    display: flex;
    flex-direction: column;
    padding: .35rem;
    border-radius: 12px;
    background: var(--bg-card);
    border: 1px solid var(--line-strong);
    box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
}

.lang-menu a {
    padding: .45rem .7rem;
    border-radius: 8px;
    font-family: 'Inter', sans-serif;
    font-weight: 600;
    font-size: .8rem;
    color: var(--text-secondary);
    text-decoration: none;
    white-space: nowrap;
}

.lang-menu a:hover { background: rgba(255, 255, 255, .06); color: #fff; }
.lang-menu a.is-active { color: var(--mint); }

/* Mini-flaga w przełączniku języka. Ramka jest konieczna: flagi z białym
   polem (Finlandia, Japonia) na ciemnym tle rozpływają się bez obrysu. */
.lang-flag {
    width: 16px;
    height: 12px;
    border-radius: 2px;
    flex: 0 0 auto;
    object-fit: cover;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .14);
}

/* Pozycja listy: flaga i kod w jednej linii, wyrównane do środka. */
.lang-menu a {
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* ==========================================================================
   WYSZUKIWARKA

   Paczka nie ma wyszukiwarki, więc arkusz nie zna żadnej z tych klas.
   Wygląd trzyma się języka paczki: te same promienie, ta sama ramka,
   ten sam mięta-akcent co w pigułce języka.
   ========================================================================== */

.site-search {
    position: relative;
    display: none;               /* na wąskich ekranach pole zabiera cały nagłówek */
}

@media (min-width: 1100px) {
    .site-search { display: block; }
}

.site-search-field {
    display: flex;
    align-items: center;
    gap: .45rem;
    padding: .4rem .7rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, 0.04);
    border: 1px solid rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    transition: border-color .2s ease;
}

.site-search-field:focus-within {
    border-color: rgba(43, 217, 166, .35);
    color: var(--text-secondary);
}

.site-search-field input {
    width: 9rem;
    border: 0;
    background: transparent;
    color: var(--text-primary);
    font-family: 'Inter', sans-serif;
    font-size: .82rem;
    outline: none;
}

.site-search-field input::placeholder { color: var(--text-muted); }

/* Krzyżyk czyszczenia w Chrome jest jasny i na ciemnym tle wygląda
   jak artefakt - pole i tak zamyka się Escape'em. */
.site-search-field input::-webkit-search-cancel-button { display: none; }

.site-search-results {
    position: absolute;
    top: calc(100% + .4rem);
    right: 0;
    z-index: 60;
    width: 22rem;
    max-height: 20rem;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    padding: .35rem;
    border-radius: 12px;
    background: var(--bg-card);
    border: 1px solid var(--line-strong);
    box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
}

.site-search-hit {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .5rem .6rem;
    border-radius: 8px;
    color: var(--text-secondary);
    text-decoration: none;
}

.site-search-hit:hover { background: rgba(255, 255, 255, .06); color: #fff; }

.site-search-hit-title {
    flex: 1 1 auto;
    font-size: .85rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ===== Strona wyników ===== */

.search-form {
    display: flex;
    gap: .6rem;
    margin-top: 1.5rem;
    max-width: 34rem;
}

.search-form input {
    flex: 1 1 auto;
    min-width: 0;
    padding: .7rem .9rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, .04);
    border: 1px solid var(--line-strong);
    color: var(--text-primary);
    font-family: 'Inter', sans-serif;
    font-size: .9rem;
}

.search-form input:focus {
    outline: none;
    border-color: rgba(43, 217, 166, .45);
}

.search-hit {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-radius: 12px;
    background: rgba(15, 19, 18, .95);
    border: 1px solid var(--line);
    color: var(--text-secondary);
    text-decoration: none;
    transition: border-color .2s ease;
}

.search-hit + .search-hit { margin-top: .6rem; }
.search-hit:hover { border-color: rgba(43, 217, 166, .25); }

.search-hit-body {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: .2rem;
}

.search-hit-body strong { color: #fff; font-weight: 600; }
.search-hit-body span { font-size: .85rem; color: var(--text-muted); }

/* Odznaka typu wyniku - kasyno, artykuł i poradnik prowadzą do zupełnie
   różnych stron i czytelnik musi je rozróżnić przed kliknięciem. */
.type-tag.casino   { background: rgba(43, 217, 166, .1); border-color: rgba(43, 217, 166, .3); color: var(--mint); }
.type-tag.category { background: rgba(122, 162, 247, .12); border-color: rgba(122, 162, 247, .3); color: #7aa2f7; }
.type-tag.article  { background: rgba(226, 176, 74, .12); border-color: rgba(226, 176, 74, .3); color: var(--gold); }
.type-tag.guide    { background: rgba(255, 255, 255, .06); border-color: var(--line-strong); color: var(--text-secondary); }

/* ==========================================================================
   PODPOWIEDŹ JĘZYKA

   Pasek u dołu, nie modal: to podpowiedź, a nie decyzja do podjęcia.
   Modal blokujący treść przy pierwszym wejściu z wyszukiwarki kosztuje
   więcej czytelników, niż ratuje.

   Element startuje z `hidden` - pokazuje go dopiero skrypt, gdy strona
   naprawdę prowadzi język, którego czytelnik chce.
   ========================================================================== */

.lang-suggestion {
    position: fixed;
    left: 50%;
    bottom: 1rem;
    z-index: 80;
    transform: translateX(-50%);
    width: calc(100% - 2rem);
    max-width: 34rem;
    border-radius: 14px;
    background: var(--bg-card);
    border: 1px solid var(--line-strong);
    box-shadow: 0 16px 40px rgba(0, 0, 0, .5);
}

.lang-suggestion-inner {
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
    padding: .9rem 1.1rem;
}

.lang-suggestion-text {
    flex: 1 1 14rem;
    margin: 0;
    font-family: 'Inter', sans-serif;
    font-size: .88rem;
    line-height: 1.45;
    color: var(--text-secondary);
}

.lang-suggestion-actions {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex: 0 0 auto;
}

.lang-suggestion-switch {
    padding: .5rem .9rem;
    border-radius: 9px;
    background: var(--mint);
    color: #06231b;
    font-family: 'Inter', sans-serif;
    font-size: .82rem;
    font-weight: 700;
    text-decoration: none;
    white-space: nowrap;
}

.lang-suggestion-switch:hover { background: var(--mint-deep); color: #06231b; }

.lang-suggestion-dismiss {
    padding: .5rem .8rem;
    border: 1px solid var(--line-strong);
    border-radius: 9px;
    background: transparent;
    color: var(--text-muted);
    font-family: 'Inter', sans-serif;
    font-size: .82rem;
    cursor: pointer;
    white-space: nowrap;
}

.lang-suggestion-dismiss:hover { color: var(--text-secondary); border-color: rgba(255, 255, 255, .2); }

/* ==========================================================================
   CHECKBOX ZGODY - ZDJĘCIE `width: 100%`

   Reguła silnika `.newsletter-form input, .contact-form input` nadaje
   `width: 100%` KAŻDEMU polu, bo pisano ją pod pola tekstowe. Łapie przez
   to również `input[type="checkbox"]`: pudełko kontrolki rozciąga się na
   całą szerokość formularza, sam kwadracik renderuje się na jego środku,
   a tekst zgody dostaje wąski pasek po prawej i łamie się na jedno słowo
   w linii.

   Dokładnie to było widać w stopce. Poprzednia próba naprawy ustawiała
   `flex: 0 0 auto`, co nie ma znaczenia, dopóki element ma zadaną
   szerokość - `flex-basis: auto` bierze wtedy `width`.
   ========================================================================== */
.form-consent input[type="checkbox"],
.exit-popup-consent input[type="checkbox"] {
    width: auto;
    min-width: 0;
    flex: 0 0 auto;
    padding: 0;
    margin-top: .15rem;
}

/* Znak kasyna w wynikach i w podpowiedziach. Ramka jak przy flagach:
   logo na jasnym tle rozpływa się bez obrysu. */
.site-search-hit-logo,
.search-hit-logo img {
    width: 20px;
    height: 20px;
    border-radius: 5px;
    flex: 0 0 auto;
    object-fit: cover;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, .12);
}

.search-hit-logo {
    display: inline-flex;
    flex: 0 0 auto;
}

.search-hit-logo img { width: 32px; height: 32px; border-radius: 8px; }

/* ==========================================================================
   PROMOCJE NA STRONIE KASYNA

   Paczka ma `bonus-block` z siatką warunków, ale style `terms-grid`, `term`
   i `code-box` trzyma w atrybutach `style` na elementach, nie w arkuszu -
   przy generowaniu z bazy nie ma gdzie ich powtarzać, więc trafiają tutaj.
   ========================================================================== */

.bonus-block .terms-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: .85rem;
    margin-bottom: 1.5rem;
}

.bonus-block .term {
    padding: .85rem 1rem;
    background: rgba(255, 255, 255, .03);
    border: 1px solid rgba(255, 255, 255, .06);
    border-radius: 10px;
}

.bonus-block .term strong {
    display: block;
    margin-top: .25rem;
    font-family: 'Poppins', sans-serif;
    font-size: 1.1rem;
    color: #fff;
}

.bonus-block-actions {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
}

.bonus-block .code-box {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .5rem .75rem;
    border: 1px dashed var(--line-strong);
    border-radius: 10px;
}

.bonus-block .code-box code {
    font-family: var(--font-mono);
    font-size: .9rem;
    letter-spacing: .04em;
    color: var(--mint);
}

/* Wyróżniona oferta dostaje obrys w kolorze akcentu - w paczce
   `featured` znaczy to samo przy wierszach listy. */
.bonus-block.featured { border-color: rgba(43, 217, 166, .3); }

.offer-terms {
    margin-top: 1.25rem;
    padding-top: 1rem;
    border-top: 1px solid var(--line);
}

.offer-terms summary {
    cursor: pointer;
    font-family: var(--font-label);
    font-size: .78rem;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.offer-terms[open] summary { color: var(--text-secondary); }

/* ================================================================
   ZNAKI ZAUFANIA W STOPCE
   ================================================================

   Pasek trzyma znaki w jednym rzędzie i zawija je na wąskich ekranach.
   Wysokość ustawiona na obrazku, nie na kontenerze: znaki przychodzą
   w różnych proporcjach, a wspólna wysokość jest jedyną rzeczą,
   która sprawia, że rząd wygląda na złożony, a nie zebrany z internetu. */
.trust-strip {
    border-top: 1px solid var(--line);
    margin-top: 2rem;
    padding: 1.5rem 0 .5rem;
    text-align: center;
}

.trust-strip-label {
    margin: 0 0 .9rem;
    font-family: 'Inter', sans-serif;
    font-size: .72rem;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.trust-marks {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 1.25rem 2rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.trust-mark img {
    display: block;
    height: 28px;
    width: auto;
    max-width: 150px;
    object-fit: contain;

    /* Znaki przychodzą w różnych kolorach - organ licencyjny na granatowo,
       płatności na niebiesko. Wyszarzone siedzą spokojnie w stopce
       i wracają do koloru pod kursorem, więc nadal da się je rozpoznać. */
    filter: grayscale(1);
    opacity: .65;
    transition: filter .18s ease, opacity .18s ease;
}

.trust-mark a:hover img,
.trust-mark a:focus-visible img {
    filter: none;
    opacity: 1;
}

.trust-mark-name {
    font-family: 'Inter', sans-serif;
    font-size: .82rem;
    color: var(--text-secondary);
}

/* ================================================================
   WERDYKT W 30 SEKUND - plusy i minusy
   ================================================================

   Paczka stylowała `.pros-cons` w `style.css`, ale wyłącznie w wariancie
   z OBIEMA kolumnami. Silnik dopuszcza recenzję z samymi plusami albo
   samymi minusami - wtedy `grid-template-columns: 1fr 1fr` zostawiał
   pustą połowę ekranu. */
.pros-cons:has(.col:only-child) {
    grid-template-columns: 1fr;
}

/* ================================================================
   ZWYCIĘZCA KOLUMNY W TABELI PORÓWNAWCZEJ
   ================================================================

   Paczka miała klasę `.winner` w `compare.html`, ale stylowała ją tylko
   w wariancie siatki (`.compare-grid > .winner`), a silnik renderuje
   prawdziwą tabelę - z powodów opisanych w partialu.

   Kolor + waga + delikatne tło: samo pogrubienie ginie w rzędzie liczb,
   a sam kolor nic nie mówi osobie, która go nie rozróżnia (dlatego
   w komórce siedzi też tekst dla czytników ekranu). */
.compare-table td.winner {
    color: var(--mint);
    font-weight: 700;
    background: rgba(43, 217, 166, .07);
}

/* ================================================================
   SORTOWANIE LISTY BONUSÓW
   ================================================================

   Paczka miała tu `<select class="sort-select">`, silnik daje linki -
   bo wybór z listy bez JavaScriptu niczego nie robi, a skrypt w atrybucie
   łamie CSP. `sort-wrap` zostaje, żeby układ zgadzał się z paczką. */
.sort-wrap {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
}

.sort-wrap .sort-label {
    font-family: 'Inter', sans-serif;
    font-size: .78rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-right: .25rem;
}

/* ================================================================
   PRZYPIS POD LISTĄ KASYN
   ================================================================

   Paczka stylowała `.list-footnote` w `style.css`, ale `.inline-link`
   tylko w kontekście, którego silnik nie renderuje. */
.list-footnote .inline-link {
    color: var(--mint);
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ================================================================
   OKŁADKA WPISU
   ================================================================

   Paczka rysowała `.cover` jako płaski prostokąt z gradientem i nigdy
   nie wstawiała tam obrazka - bo makieta nie miała skąd go wziąć.
   Silnik ma kolumnę `cover_image`, więc obrazek musi wypełnić kafelek
   bez rozciągania: `object-fit: cover` przycina, `absolute` trzyma go
   w ramce razem z odznaką tematu. */
.blog-card .cover img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;

    /* POD poświatą i POD odznaką. Bez tego obrazek - jako element
       pozycjonowany później w drzewie - zasłania `::before`, czyli
       przyciemnienie, na którym stoi czytelność odznaki tematu. */
    z-index: 0;
}

.blog-card .cover::before { z-index: 1; }
.blog-card .cover .badge { z-index: 2; }

.article-cover img {
    display: block;
    width: 100%;
    height: auto;
    border-radius: 16px;
    border: 1px solid var(--line);
}

/* ================================================================
   IKONA RAMKI WYRÓŻNIONEJ
   ================================================================

   Paczka ma tu WŁASNĄ niezgodność: arkusz stylizuje `.callout .icon`,
   a jej HTML wypisuje `class="callout-icon"`. Efekt w samej makiecie -
   ikona bez tła i bez koloru wariantu.

   Silnik renderuje `callout-icon` (tak jak makieta), więc reguły muszą
   trafić w tę nazwę. Wartości te same, żeby wygląd zgadzał się z resztą
   paczki. */
.callout-icon {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: rgba(43, 217, 166, .1);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--mint);
}

.callout.warn .callout-icon { background: rgba(245, 184, 46, .1); color: var(--gold); }
.callout.danger .callout-icon { background: rgba(200, 16, 46, .1); color: var(--red); }

/* ================================================================
   PRZYKLEJONY PRZYCISK NA WĄSKICH EKRANACH
   ================================================================

   Powód w partialu `mobile-cta`: poniżej 1024 px siatka `review-layout`
   zwija się do jednej kolumny i karta z przyciskiem ląduje POD całą
   recenzją. Pasek przywraca przycisk tam, gdzie czytelnik akurat jest.

   Wysokość trzymana w zmiennej, bo zależy od niej i rozpórka pod stroną,
   i baner wyboru języka - trzy miejsca z tą samą liczbą wpisaną ręcznie
   rozjeżdżają się przy pierwszej zmianie wyglądu. */
:root { --mobile-cta-h: 68px; }

.mobile-cta,
.mobile-cta-spacer { display: none; }

@media (max-width: 1023px) {
    .mobile-cta {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 90;
        display: flex;
        align-items: center;
        gap: 1rem;
        min-height: var(--mobile-cta-h);
        padding: .7rem 1rem;

        /* Nieprzezroczyste tło, nie półprzezroczyste: pod paskiem przewija
           się tekst recenzji, a przycisk afiliacyjny na migającym tle
           czyta się jak reklama, którą trzeba zamknąć. */
        background: var(--bg-card);
        border-top: 1px solid var(--line-strong);
        box-shadow: 0 -12px 32px -20px rgba(0, 0, 0, .9);

        /* Pasek nawigacji iOS-a wchodzi na dolne 34 px ekranu. */
        padding-bottom: max(.7rem, env(safe-area-inset-bottom));
    }

    .mobile-cta-text {
        min-width: 0;
        line-height: 1.25;
    }

    .mobile-cta-text strong {
        display: block;
        font-size: .9rem;
        color: #fff;
    }

    .mobile-cta-text span {
        display: block;
        font-size: .78rem;
        color: var(--text-muted);

        /* Jedna linia z wielokropkiem: bonus bywa długi, a pasek rosnący
           do trzech linii zjada pół ekranu telefonu. */
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .mobile-cta-button {
        margin-left: auto;
        flex-shrink: 0;
        white-space: nowrap;
    }

    /* Miejsce pod paskiem - bez tego zasłania koniec strony, a tam stoją
       noty prawne i 18+. */
    .mobile-cta-spacer {
        display: block;
        height: calc(var(--mobile-cta-h) + env(safe-area-inset-bottom));
    }

    /* Baner wyboru języka też wisi przy dolnej krawędzi. Na stronie
       recenzji podnosimy go ponad pasek, zamiast pozwolić im się nakładać. */
    body:has(.mobile-cta) .lang-suggestion {
        bottom: calc(1rem + var(--mobile-cta-h) + env(safe-area-inset-bottom));
    }
}

/* Zaproszenie nad polem newslettera. Jedno zdanie, przygaszone -
   ma wyjaśniać, a nie konkurować z nagłówkiem sekcji. */
.newsletter-pitch {
    margin: 0 0 .75rem;
    font-family: 'Inter', sans-serif;
    font-size: .82rem;
    line-height: 1.5;
    color: var(--text-muted);
}

/* ================================================================
   PASEK PRAWNY NA DOLE STOPKI
   ================================================================

   `inline-flex` z paczki zwezal ramke do szerokosci tekstu i dzielil
   rzad z notka o prawach autorskich. Przy tresci, ktora niesie cztery
   wymagane informacje, zostawalo na nia jakies 900 px i lamala sie
   na dwie linie.

   Wlasny rzad na pelna szerokosc daje okolo 1200 px - tyle, ile
   potrzebuje najdluzszy z szesciu przekladow. Ponizej 1100 px zdanie
   i tak sie zawija i tak ma byc: skracanie tekstu prawnego pod waski
   ekran znaczyloby wyrzucenie jednej z czterech informacji. */
.footer-bottom .responsibility {
    flex: 1 1 100%;

    /* `flex-start`, nie `center`: przy zawinieciu na dwie linie
       wysrodkowanie w pionie odsuwa odznake od pierwszej linii tekstu. */
    align-items: flex-start;
    line-height: 1.5;
}

.footer-bottom .responsibility strong {
    flex-shrink: 0;
    line-height: inherit;
}

/* ================================================================
   WIERSZ LISTY KASYN - KOLUMNY LICZB I PRZYCISKI
   ================================================================

   Siatka paczki ma siedem kolumn, w tym DWIE po 90 px na liczby.
   Silnik oddawał jej sześcioro dzieci (obie liczby w jednym pudełku),
   więc kolumna przycisków lądowała w torze szerokim na 90 px przy
   `min-width: 140px` - przycisk wychodził poza ramkę karty.

   Markup jest już poprawiony; tu zostaje to, czego paczka nie
   przewidziała dla NASZYCH danych. */

/* 100 px zamiast 90: „25 EUR" w foncie 1rem nie mieści się w 90 px
   i łamie się na „25" i „EUR" pod spodem. */
.list-row {
    grid-template-columns: 50px 60px 1.5fr 1fr 100px 100px auto;
}

.list-row .stat-val {
    /* Wartość nigdy się nie łamie. Lepiej, żeby wystawała o kilka
       pikseli, niż żeby „2 h" stało w dwóch liniach. */
    white-space: nowrap;
    font-size: .95rem;
}

@media (max-width: 1024px) {
    /* Reguła paczki ustawia tu `flex-direction: row` i kolejność
       `order`, ale nie włącza `display: flex` - bez tego etykieta
       i wartość zostają jedna pod drugą, a `order` nic nie robi. */
    .list-row .stat-col {
        display: flex;
    }
}

/* Stan podmiany listy przy filtrowaniu bez przeładowania.
   Przygaszenie zamiast kręcącego się kółka: odpowiedź idzie z cache'u
   stron i wraca w kilkadziesiąt milisekund, więc spinner zdążyłby
   tylko mrugnąć. `pointer-events` blokuje drugie kliknięcie w trakcie. */
[data-filter-target] {
    transition: opacity .12s ease;
}

[data-filter-target].is-swapping {
    opacity: .55;
    pointer-events: none;
}

/* ================================================================
   PODIUM RANKINGU
   ================================================================

   Paczka nie ma podium - rankingiem jest tam strona glowna, wiec nie ma
   czego kopiowac. Znaczniki i style sa nasze, ale klasy wspolne
   (`card-strong`, `btn-primary`, `score-circle`, `oc-code`) zostaja,
   zeby wyglad nie odjechal od reszty witryny. */
.podium {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    align-items: end;
    gap: 1rem;
    margin: 2rem 0 2.5rem;
}

.podium-place {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: .6rem;
    padding: 2rem 1.1rem 1.25rem;
    border-radius: 16px;
    background: linear-gradient(180deg, rgba(21, 27, 25, .8) 0%, rgba(15, 19, 18, .8) 100%);
    border: 1px solid rgba(255, 255, 255, .07);
}

/*
   KOLEJNOSC WIZUALNA: drugie, PIERWSZE, trzecie - jak na prawdziwym
   podium. W dokumencie kolejnosc zostaje 1-2-3, bo tak czyta ja czytnik
   ekranu i tak wyglada po zwinieciu na telefonie. Przestawia to CSS.
*/
.podium-place[data-place="1"] { order: 2; }
.podium-place[data-place="2"] { order: 1; }
.podium-place[data-place="3"] { order: 3; }

/* Zwyciezca wyzszy i wyrozniony - inaczej „podium" jest trzema
   identycznymi kartami obok siebie. */
.podium-first {
    padding-top: 2.75rem;
    border-color: rgba(43, 217, 166, .35);
    background:
        linear-gradient(180deg, rgba(43, 217, 166, .07) 0%, transparent 55%),
        linear-gradient(180deg, rgba(21, 27, 25, .9) 0%, rgba(15, 19, 18, .9) 100%);
    box-shadow: 0 24px 48px -32px rgba(43, 217, 166, .5);
}

.podium-medal {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    width: 30px;
    height: 30px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .9rem;
    color: #06231b;
    background: var(--text-muted);
    border: 2px solid var(--bg-body);
}

.podium-first .podium-medal { background: var(--mint); }
.podium-place[data-place="3"] .podium-medal { background: #b08d57; color: #1a1206; }

.podium-logo img {
    width: 56px;
    height: 56px;
    border-radius: 14px;
    object-fit: cover;
    background: var(--bg-card);
    border: 1px solid var(--line-strong);
}

.podium-name {
    margin: 0;
    font-size: 1.05rem;
}

.podium-name a { color: #fff; text-decoration: none; }
.podium-name a:hover { color: var(--mint); }

.podium-bonus {
    margin: 0;
    font-weight: 600;
    font-size: .92rem;
    color: var(--text-secondary);
}

.podium-note {
    margin: 0;
    font-size: .82rem;
    line-height: 1.5;
    color: var(--text-muted);
}

.podium-code { width: 100%; }

.podium-actions {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: .4rem;
    margin-top: auto;
}

.podium-actions .btn-primary { justify-content: center; }

.podium-actions .review-link {
    font-size: .78rem;
    color: var(--text-muted);
    text-align: center;
}

@media (max-width: 720px) {
    /* Na telefonie podium zwija sie w kolumne i wraca do kolejnosci
       1-2-3 - przestawienie ma sens tylko wtedy, gdy karty stoja obok
       siebie. */
    .podium { grid-template-columns: 1fr; }
    .podium-place[data-place="1"],
    .podium-place[data-place="2"],
    .podium-place[data-place="3"] { order: 0; }
    .podium-first { padding-top: 2rem; }
}

/* ================================================================
   WIERSZ RANKINGU - PRZYCISK ZAMIAST STRZALKI
   ================================================================

   Ostatnia kolumna miala 20 px i mieszcila tylko strzalke, bo caly
   wiersz byl jednym odsylaczem. Wiersz jest teraz zwyklym pudelkiem
   (odsylacz w odsylaczu to nieprawidlowy HTML), a w tej kolumnie stoi
   przycisk afiliacyjny. */
.rank-row {
    /*
     * ================================================================
     *  KOLUMNY ELASTYCZNE, NIE STALE
     * ================================================================
     *
     * Paczka ma `50px 50px 1fr 180px 80px 70px 20px`. Kolumny stale
     * sumuja sie z odstepami do ~530 px, wiec w karcie „Top 5" na stronie
     * glownej - szerokiej na jakies 570 px - na `1fr` z nazwa zostawalo
     * kilka pikseli. Nazwa wychodzila poza swoja komorke i nachodzila
     * na tekst bonusu.
     *
     * `minmax` daje obu kolumnom dolna granice i pozwala im rosnac
     * proporcjonalnie: to samo dziala w waskiej karcie i na pelnej
     * szerokosci strony rankingu.
     */
    grid-template-columns:
        40px
        40px
        minmax(96px, 1.1fr)
        minmax(130px, 1.6fr)
        minmax(56px, auto)
        60px
        auto;
    gap: .85rem;
}

.rank-row.rank-head {
    padding: .25rem .75rem;
    border: none;
}

.rank-row.rank-head:hover {
    background: none;
    border-color: transparent;
}

.rank-cta .btn-primary {
    padding: .55rem .9rem;
    font-size: .8rem;
    white-space: nowrap;
}

.rank-name a {
    color: #fff;
    text-decoration: none;
    font-weight: 600;
}

.rank-name a:hover { color: var(--mint); }

@media (max-width: 900px) {
    .rank-row { grid-template-columns: 40px 40px 1fr 70px auto; }
}

/* ================================================================
   PODGLAD PIERWSZEJ TROJKI NA LISCIE RANKINGOW
   ================================================================

   Karta rankingu pokazywala ikone, tytul i zajawke - czyli nic o tym,
   co jest w srodku. Trzy nazwy z ocenami zamieniaja spis w zapowiedz. */
.ranking-preview {
    list-style: none;
    margin: 1rem 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}

.ranking-preview li {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .4rem .6rem;
    border-radius: 10px;
    background: rgba(255, 255, 255, .02);
    border: 1px solid rgba(255, 255, 255, .05);
    font-size: .85rem;
}

.ranking-preview-place {
    flex-shrink: 0;
    width: 18px;
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--text-muted);
    text-align: center;
}

.ranking-preview li:first-child .ranking-preview-place { color: var(--mint); }

.ranking-preview img {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    object-fit: cover;
    flex-shrink: 0;
    background: var(--bg-card);
}

.ranking-preview-name {
    color: var(--text-secondary);

    /* Dluga nazwa nie moze rozepchnac karty ani zepchnac oceny poza nia. */
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ranking-preview-score {
    flex-shrink: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .82rem;
    color: var(--mint);
}

/* ================================================================
   LISTA RANKINGOW
   ================================================================

   `grid-2` z paczki zostawialo pol ekranu pustego, gdy ranking byl
   jeden - a na nowej stronie zwykle jest. `auto-fit` z minimalna
   szerokoscia daje jedna karte na cala szerokosc, dwie obok siebie,
   trzy w rzedzie na szerokim ekranie. */
.ranking-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 1.25rem;
    margin-top: 1rem;
}

/* Tytul wyroznionego rankingu jest odsylaczem - ma prowadzic do pelnej
   listy tak samo jak przycisk pod podium. */
.section-title a {
    color: inherit;
    text-decoration: none;
}

.section-title a:hover { color: var(--mint); }

.ranking-featured-more {
    display: flex;
    justify-content: center;
    margin-top: .5rem;
}

/* ================================================================
   TEKST WLASNY SEKCJI
   ================================================================

   Pod listingiem, w szerokosci czytelnej dla oka - nie na cala
   szerokosc kontenera, bo wiersz na 1200 px czyta sie zle.
   `article-body` z paczki niesie typografie, tu zostaje odstep
   i ograniczenie szerokosci. */
.section-copy {
    max-width: 46rem;
    margin: 3rem auto 0;
    padding-top: 2.5rem;
    border-top: 1px solid var(--line);
}

/* ================================================================
   ATRYBUT `hidden` MUSI WYGRYWAC Z KLASA
   ================================================================

   Lista podpowiedzi wyszukiwarki ma w znacznikach `hidden` i skrypt
   zdejmuje go dopiero, gdy sa wyniki. Regula `.site-search-results
   { display: flex }` jest jednak BARDZIEJ SZCZEGOLOWA niz `[hidden]
   { display: none }` z arkusza przegladarki - wiec pusta ramka wisiala
   pod polem wyszukiwania na kazdej podstronie, zanim ktokolwiek cokolwiek
   wpisal.

   To nie jest problem jednego elementu. Kazdy nastepny blok chowany
   atrybutem `hidden`, ktoremu ktos ustawi `display`, odslonilby sie tak
   samo - i tak samo nikt by tego nie zauwazyl, bo pusty prostokat na
   ciemnym tle wyglada jak element ukladu.

   Stad straznik na cala paczke, a nie poprawka jednej klasy. */
[hidden] {
    display: none !important;
}

/* ================================================================
   ODSTEP MIEDZY HERO A KAFLAMI
   ================================================================

   `.hero-inner` ma na szerokim ekranie `padding: 6rem 0 7rem`, a sekcja
   kafli dokłada 2,5rem od gory - razem ponad 150 px pustki pod obrazkiem
   podium, ktory sam w sobie jest szeroki i niski.

   Dol hero schodzi do 3rem: hero konczy sie obrazkiem, a nie trescia,
   wiec nie potrzebuje takiego marginesu jak sekcja z tekstem. Gora sekcji
   kafli zostaje bez zmian, zeby naglowek nie kleil sie do obrazka. */
@media (min-width: 1024px) {
    .hero-inner { padding-bottom: 1.5rem; }
}

.hero-inner { padding-bottom: 1.5rem; }

/* Sekcja kafli tez schodzi blizej: 2,5rem z paczki bylo liczone pod hero
   zakonczone tekstem, a nasze konczy sie obrazkiem, ktory ma wlasny
   przezroczysty margines u dolu. */
.tiles-section { padding-top: 1rem; }

/* ================================================================
   KONIEC SEKCJI KAFLI NA STRONIE GLOWNEJ
   ================================================================

   Ujawnienie afiliacji przyklejalo sie do ostatniego rzedu kafli -
   wygladalo jak czesc karty, a jest przypisem do calej listy.

   Przycisk pod lista jest dla tego, kto przewinal szesc pozycji: odsylacz
   w naglowku widzi tylko ten, kto patrzy na naglowek. */
.tiles-more {
    display: flex;
    justify-content: center;
    margin-top: 2rem;
}

.affiliate-disclosure-slot {
    margin-top: 1.75rem;
}

/* Odsylacz w naglowku byl `<span>`, wiec nie mial stanu najechania.
   Teraz jest linkiem i ma sie zachowywac jak link. */
.tiles-more-link {
    text-decoration: none;
    transition: opacity .18s ease;
}

.tiles-more-link:hover { opacity: .75; }

/* Tresc komorek wiersza rankingu nie moze wychodzic poza swoja kolumne.
   `min-width: 0` jest tu konieczne, bo domyslne `min-width: auto` na
   elemencie siatki KAZE komorce byc co najmniej tak szerokiej jak jej
   najdluzsze slowo - i wtedy siatka rozpycha sie ponad zadeklarowane
   kolumny, a sasiedzi na siebie nachodza. */
.rank-row > * { min-width: 0; }

.rank-row .col-val,
.rank-row .col-sub {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Zajawka pod kwota bonusu do JEDNEJ linii: w karcie „Top 5" pelne zdanie
   rozpychalo wiersz na trzy linie i lamalo rowny rytm listy. */
.rank-row .col-sub {
    display: -webkit-box;
    -webkit-line-clamp: 1;
    -webkit-box-orient: vertical;
}

/* ================================================================
   NADTYTUL I NAGLOWEK ZAWSZE JEDNO POD DRUGIM
   ================================================================

   `style.css` z paczki ma regule:

       .section > .container > .eyebrow,
       .section > .container > h2 { display: inline-block; }

   Skutek: wszedzie tam, gdzie nadtytul („QUESTIONS", „THIS MONTH ON TOP")
   i naglowek sa BEZPOSREDNIMI dziecmi kontenera, obydwa staja sie
   elementami liniowymi i ladują OBOK SIEBIE. Wyglada to na tekst bez
   stylu - i tak wlasnie zglosil to wlasciciel przy dwoch roznych
   podstronach.

   Paczka uzywa tego ukladu w osiemnastu widokach, wiec poprawianie po
   jednym znaczyloby osiemnascie okazji, zeby ktorys pominac. Regula
   wraca tu do zachowania blokowego dla CALEJ paczki.

   Wysrodkowane naglowki (`section-head-center`) maja wlasne reguly
   i tej zmiany nie widza - ich nadtytul nie jest dzieckiem kontenera. */
.section > .container > .eyebrow,
.section > .container > h1,
.section > .container > h2 {
    display: block;
}

/* ================================================================
   SIATKA WPISOW BLOGA - TYLKO STRONA GLOWNA
   ================================================================

   Cztery kafle zamiast trzech: rzad czterech wypelnia szerokosc bez
   rozciagania kart, a wezsze karty zajmuja mniej wysokosci - okladka
   i tytul lamią sie na mniej linii.

   WLASNA NAZWA, nie `.blog-grid`. Tamta klasa jest z paczki i uzywaja jej
   takze lista blogow, strony autorow i sekcja „powiazane" pod wpisem -
   nadpisanie jej zmienialoby cztery miejsca zamiast jednego. */
.home-blog-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 1.25rem;
}

@media (max-width: 1100px) { .home-blog-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 620px)  { .home-blog-grid { grid-template-columns: 1fr; } }

/* Okladka nizsza niz w siatce trzykolumnowej: przy wezszej karcie
   proporcja 16:9 dawala pasek zajmujacy polowe kafla. */
.home-blog-grid .blog-card .cover { aspect-ratio: 3 / 2; }

.home-blog-grid .blog-card h3 {
    font-size: 1rem;
    line-height: 1.35;
}

.home-blog-grid .blog-card .excerpt {
    font-size: .85rem;

    /* Dwie linie zajawki: przy czterech kaflach pelne zdanie robi
       z rownego rzedu schodki. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/* ================================================================
   WPIS BLOGA: TEKST I PASEK BOCZNY
   ================================================================

   Wpis byl jedna wysrodkowana kolumna szeroka na 760 px, a po prawej
   zostawal pusty pas na cala wysokosc tekstu. Czytelnik, ktory doczytal
   artykul, nie mial stamtad dokad pojsc poza powrotem na liste.

   Pasek jest PO tekscie w dokumencie, a obok przesuwa go dopiero siatka:
   czytnik ekranu i telefon dostaja najpierw artykul, po ktory czytelnik
   przyszedl. Ponizej 1100 px wraca uklad jednokolumnowy. */
.article-layout {
    display: grid;
    grid-template-columns: minmax(0, 760px) minmax(280px, 320px);
    justify-content: center;
    gap: 2.5rem;
    align-items: start;
}

@media (max-width: 1100px) {
    .article-layout { grid-template-columns: minmax(0, 760px); }
}

.article-layout .article-body { max-width: 760px; }

.article-sidebar {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;

    /* Pasek jedzie z tekstem: przy artykule na trzy ekrany oferta
       widoczna tylko na gorze jest oferta widoczna raz. */
    position: sticky;
    top: 6rem;
}

@media (max-width: 1100px) {
    .article-sidebar { position: static; }
}

.sidebar-card {
    padding: 1.1rem;
    border-radius: 14px;
    background: var(--bg-card);
    border: 1px solid var(--line);
}

.sidebar-card .eyebrow { margin-bottom: .85rem; display: block; }

.sidebar-casinos,
.sidebar-articles {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: .85rem;
}

.sidebar-casinos li {
    display: flex;
    flex-direction: column;
    gap: .5rem;
    padding-bottom: .85rem;
    border-bottom: 1px solid var(--line);
}

.sidebar-casinos li:last-child { border-bottom: none; padding-bottom: 0; }

.sidebar-casino {
    display: flex;
    align-items: center;
    gap: .6rem;
    text-decoration: none;
}

.sidebar-casino img {
    width: 32px;
    height: 32px;
    border-radius: 8px;
    object-fit: cover;
    flex-shrink: 0;
    background: var(--bg-body);
}

.sidebar-casino-text {
    /* `min-width: 0` na elemencie zwijanym: bez tego dluga nazwa rozpycha
       rzad i ocena wypada poza karte. */
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}

.sidebar-casino-text strong {
    color: #fff;
    font-size: .9rem;
}

.sidebar-casino-text span {
    font-size: .78rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sidebar-casino-score {
    margin-left: auto;
    flex-shrink: 0;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: .9rem;
    color: var(--mint);
}

.sidebar-casino-cta {
    display: block;
    text-align: center;
    padding: .45rem .6rem;
    border-radius: 8px;
    font-size: .8rem;
    font-weight: 600;
    text-decoration: none;
    color: var(--mint);
    border: 1px solid rgba(43, 217, 166, .3);
    background: rgba(43, 217, 166, .06);
}

.sidebar-casino-cta:hover { background: rgba(43, 217, 166, .12); }

.sidebar-articles li {
    display: flex;
    flex-direction: column;
    gap: .15rem;
}

.sidebar-articles a {
    color: var(--text-secondary);
    text-decoration: none;
    font-size: .88rem;
    line-height: 1.35;
}

.sidebar-articles a:hover { color: var(--mint); }

.sidebar-articles span {
    font-size: .72rem;
    color: var(--text-muted);
}

.sidebar-more {
    display: inline-block;
    margin-top: .9rem;
    font-size: .82rem;
    color: var(--mint);
    text-decoration: none;
}

/* Okladka wewnatrz kolumny tekstu: `margin: 0 auto` z poprzedniej wersji
   centrowalo ja nad cala siatka i spychalo pasek boczny w dol. */
.article-layout .article-cover {
    margin: 0 0 2rem;
}

/* --------------------------------------------------------------------------
   HIERARCHIA NAGLOWKOW - z audytu SEO 2026-09-11
   --------------------------------------------------------------------------
   Stopka miala `<h4>` (skok h2 -> h4 na kazdej stronie), a kafelki na
   listach `<h3>` wprost pod `<h1>`. Znaczniki poprawione, wyglad zostaje:
   te reguly kopiuja style paczki dla h3 na h2 i dla `.footer-col h4`
   na `.footer-heading`. */
.footer-col .footer-heading {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 0 0 1rem;
    font-weight: 500;
}
.blog-card h2 { font-family: var(--font-display); font-weight: 700; font-size: 1.15rem; color: #fff; margin: 0 0 .65rem; line-height: 1.3; }
.blog-card.featured h2 { font-size: 1.8rem; }
.list-row .name-col h2 { margin: 0; font-family: var(--font-display); font-weight: 700; font-size: 1.1rem; color: #fff; }
.tool-card h2 { font-family: var(--font-display); font-weight: 700; color: #fff; font-size: 1.15rem; margin: 0 0 .5rem; }
.card h2 { font-family: var(--font-display); font-weight: 700; color: #fff; font-size: 1.1rem; margin: 0 0 .5rem; }
h2.podium-name { margin: 0; }
/* Nazwa wylosowanego kasyna: wyglad `.reveal h3` z paczki, ale bez
   znacznika naglowka - wynik losowania nie jest naglowkiem tresci. */
.reveal .reveal-title { font-family: var(--font-display); font-size: 1.4rem; font-weight: 700; color: #fff; margin: 0 0 .35rem; }
