.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    padding: 24px;
    box-shadow: var(--shadow-card);
}

/* Wariant .card bez wewnętrznego paddingu — biały kontener na listę
   wierszy, gdzie padding jest na każdym wierszu z osobna (overflow:hidden
   przycina rogi ostatniego/pierwszego wiersza do border-radius). */
/* Wariant .card z mniejszym promieniem/paddingiem — kompaktowa karta
   pojedynczego elementu listy (np. wiersz terminu zajęć). */
.card-compact {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    padding: 12px 16px;
}

/* Panel informacyjny na tle strony (nie białe tło jak .card) — banery
   "zaloguj się, aby..." itp. Bez position:sticky (w odróżnieniu od
   .summary-panel), bo tu nie chodzi o boczny panel przy przewijaniu. */
.notice-box {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 16px 20px;
    font-size: 13px;
    color: var(--color-text-muted);
}
.info-panel {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 24px;
}

.card-list {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-card);
    overflow: hidden;
}

/* display:flex tutaj obsługuje zarówno dotychczasowy przypadek (pojedynczy
   tekst) jak i nowy wariant z ikoną (mirror .su-alert ze wzorca logowania,
   np. <i>...</i><p>...</p>) — dla samego tekstu flex na jednym dziecku nic
   wizualnie nie zmienia. */
.flash {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    border-radius: var(--radius-control);
    padding: 12px 16px;
    font-size: 13.5px;
}
.flash > i { flex-shrink: 0; margin-top: 1px; font-size: 15px; }
.flash > p { margin: 0; }
/* Obramowanie w tym samym (ink) kolorze co tekst — mirror .form-errors
   (już miała border, .flash go dotąd nie miała mimo komentarza wyżej,
   który błędnie zakładał, że ma — stąd "zupełnie inny styl" komunikatów). */
.flash-success { background: var(--color-success-soft); color: var(--color-success-ink); border: 1px solid var(--color-success-ink); }
.flash-error { background: var(--color-danger-soft); color: var(--color-danger-ink); border: 1px solid var(--color-danger-ink); }
.flash-info { background: var(--color-pending-soft); color: var(--color-pending-ink); border: 1px solid var(--color-pending-ink); }

/* Blok błędów walidacji formularza (lista komunikatów pod jednym
   obramowaniem) — inny wzorzec niż .flash-error (ta ma własne obramowanie
   i mieści wiele linii błędów, .flash to pojedynczy komunikat z sesji). */
.form-errors {
    background: var(--color-danger-soft);
    border: 1px solid var(--color-danger);
    border-radius: var(--radius-control);
    padding: 14px 16px;
}
.form-errors-item {
    font-size: 13px;
    color: var(--color-danger-ink);
}

.section-eyebrow {
    font-size: 13px;
    font-weight: 600;
    color: var(--color-brand);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
/* Wariant stosowany tam, gdzie oryginał miał letter-spacing:0.6px zamiast
   0.5px — różnica niezauważalna wizualnie, celowo ujednolicona. */
.section-eyebrow--muted { color: var(--color-text-muted); }

.form-input {
    width: 100%;
    box-sizing: border-box;
    background: var(--color-bg);
    border: 1px solid var(--color-border-input);
    border-radius: var(--radius-control);
    padding: 13px 14px;
    color: inherit;
    font-size: 14px;
    font-family: inherit;
}

.btn-primary {
    display: inline-block;
    background: var(--color-brand-strong);
    border: none;
    color: #fff;
    padding: 9px 16px;
    border-radius: var(--radius-control);
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    text-decoration: none;
}

/* Nadpisuje globalne a:hover (base.html.twig), które zmienia kolor tekstu
   linku na --color-brand-strong — to ten sam kolor co tło tego przycisku,
   więc bez tego napis staje się nieczytelny po najechaniu. */
.btn-primary:hover {
    color: #fff;
}

.btn-cta {
    display: block;
    width: 100%;
    margin-top: 28px;
    background: var(--color-brand-strong);
    color: #FFFFFF;
    font-weight: 600;
    text-align: center;
    padding: 16px;
    border-radius: var(--radius-control);
    border: none;
    cursor: pointer;
    font-size: 15px;
    font-family: inherit;
}

.summary-panel {
    position: sticky;
    top: 0;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: 12px;
    padding: 24px;
}

/* Powłoka strony w panelu admina (grafik, formularze CRUD, listy) —
   ten sam wzorzec: szare tło strony, biały pasek nagłówka, wyściełana
   treść. Znaleziony identyczny w wielu szablonach admin/*.html.twig. */
.admin-shell {
    flex: 1;
    overflow-y: auto;
    background: var(--color-bg);
    font-family: var(--font-body);
}
.admin-topbar {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 18px 40px;
    display: flex;
    align-items: center;
    justify-content: space-between;
}
.admin-topbar-title {
    font-family: var(--font-display);
    font-size: 19px;
    font-weight: 600;
    color: var(--color-ink);
}
.admin-content { padding: 32px 40px; }

/* Tabela na siatce CSS Grid w listach admina — kontener to .card-list
   (te same właściwości), tu tylko nagłówek i wiersze. Liczba/szerokości
   kolumn różnią się per strona, więc grid-template-columns zostaje jako
   inline override obok tej klasy. */
.admin-table-head {
    display: grid;
    gap: 12px;
    padding: 12px 20px;
    font-size: 11.5px;
    font-weight: 600;
    color: var(--color-text-faint);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    background: var(--color-bg);
    border-bottom: 1px solid var(--color-border);
}
.admin-table-row {
    display: grid;
    gap: 12px;
    padding: 14px 20px;
    font-size: 13.5px;
    color: var(--color-ink-soft);
    border-bottom: 1px solid var(--color-border);
    align-items: center;
}
.admin-table-empty {
    padding: 20px;
    font-size: 13.5px;
    color: var(--color-text-muted);
}

/* .admin-table-head/.admin-table-row dostają grid-template-columns inline,
   różne na każdej stronie (patrz komentarz wyżej) — na wąskich ekranach te
   kolumny kurczą się poniżej czytelnej szerokości i łamią wiersz (zawijający
   się tekst, nachodzące na siebie odznaki/przyciski). Zamiast tego na mobile
   .card-list przewija się poziomo w obrębie własnej karty (nie całej
   strony) — min-width wymusza sensowną minimalną szerokość wiersza, więc
   kolumny nie kurczą się do nieczytelnych szczelin. Dotyczy KAŻDEJ listy w
   panelu admina na raz (wydarzenia, organizatorzy, użytkownicy, sekcje...),
   bo wszystkie współdzielą te same klasy. */
@media (max-width: 860px) {
    .card-list {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
    .admin-table-head,
    .admin-table-row {
        min-width: 720px;
    }
}

/* Wariant .card-list dla list, gdzie poziomy scroll (wyżej) byłby nieczytelny
   przez dużą liczbę kolumn (np. zamówienia, bilety/zapisy w zamówieniu) —
   wiersz zamienia się w pionową kartę, z etykietą przed każdą wartością
   (.admin-table-mobile-label), bo nagłówek (.admin-table-head) znika i nie
   ma inaczej skąd wiedzieć, co dana wartość oznacza. Wydzielone (2026-09-15)
   z dwóch identycznych kopii tego samego bloku w admin/orders.html.twig i
   admin/order_detail.html.twig, które cicho nadpisywały regułę wyżej przez
   kolejność ładowania zamiast być jawnym, nazwanym wariantem. Strona MUSI
   dodać klasę "card-list--stacked-mobile" na kontenerze ORAZ oznaczyć każdą
   komórkę <span class="admin-table-mobile-label">Etykieta</span> — inaczej
   stackowanie pokaże same wartości bez kontekstu. */
.admin-table-mobile-label {
    display: none;
}

@media (max-width: 900px) {
    .card-list--stacked-mobile .admin-table-head {
        display: none;
    }
    .card-list--stacked-mobile .admin-table-row {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        gap: 8px;
        min-width: 0;
    }
    .card-list--stacked-mobile .admin-table-mobile-label {
        display: inline;
        font-size: 11px;
        font-weight: 600;
        color: var(--color-text-faint);
        text-transform: uppercase;
        letter-spacing: 0.3px;
        margin-right: 6px;
    }
}

/* Przycisk zapisu formularza w adminie — inny wariant niż .btn-cta
   (mniejszy padding/font-size) i niż .btn-primary (pełna szerokość). */
.btn-submit {
    display: block;
    width: 100%;
    background: var(--color-brand-strong);
    border: none;
    color: #fff;
    text-align: center;
    padding: 12px;
    border-radius: var(--radius-control);
    font-weight: 600;
    font-size: 13.5px;
    cursor: pointer;
    font-family: inherit;
}

.link-muted {
    font-size: 12.5px;
    color: var(--color-text-muted);
}

/* Przycisk drugorzędny (np. "+ Dodaj wiersz") — obrys zamiast wypełnienia. */
.btn-secondary {
    background: var(--color-bg);
    border: 1px solid var(--color-border-input);
    color: var(--color-ink-soft);
    padding: 9px 14px;
    border-radius: var(--radius-control);
    font-size: 12.5px;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
}

/* Etykieta pola formularza (nad inputem) w adminie — inna niż
   .section-eyebrow: mniejsza, jaśniejszy szary zamiast koloru marki. */
.field-label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: var(--color-text-faint);
    text-transform: uppercase;
    letter-spacing: 0.4px;
    margin-bottom: 6px;
}

/* Pole formularza w adminie (input/select/textarea) — inny wariant niż
   .form-input: bez tła, mniejszy padding/font-size. */
.admin-input {
    border: 1px solid var(--color-border-input);
    border-radius: var(--radius-control);
    padding: 11px 13px;
    font-size: 13.5px;
    font-family: inherit;
}

/* Kompaktowy wariant .admin-input — wiersze-repeatery (terminy, cenniki). */
/* Grupa pól/checkboxów wydzielona wizualnie w obrębie formularza
   (np. "Powiadom uczestników", "Wydaj kredyt"). */
.field-group {
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-control);
    padding: 14px 16px;
}

.admin-input-sm {
    border: 1px solid var(--color-border-input);
    border-radius: var(--radius-control);
    padding: 9px 11px;
    font-size: 13px;
    font-family: inherit;
}

/* Widoczny stan fokusu dla pól formularzy — token --color-focus istniał od
   początku redesignu, ale nic go dotąd nie używało (pola nie miały żadnego
   customowego :focus, tylko domyślny obrys przeglądarki). :focus-visible
   (nie zwykłe :focus) — obrys pojawia się przy nawigacji klawiaturą, nie przy
   kliknięciu myszą, zgodnie ze standardowym zachowaniem tego selektora. */
.form-input:focus-visible,
.admin-input:focus-visible,
.admin-input-sm:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 1px;
}

/* Przycisk wyglądający jak link, w kolorze ostrzegawczym (Usuń, Wyłącz). */
.btn-link-danger {
    background: none;
    border: none;
    padding: 0;
    font-size: 12.5px;
    color: var(--color-danger);
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
}

/* Wariant "sama ikona" .btn-link-danger (kosz bez tekstu) — wydzielone
   (2026-09-15) z inline style="..." wklejanego ręcznie w 6+ szablonach list
   admina. Modyfikator .is-disabled zastępuje inline
   color/cursor warunkowe na podstawie stanu (np. "nie można usunąć, bo ma
   powiązane dane") — reszta atrybutów (disabled/title) zostaje w markupie
   szablonu, to nie jest część stylu. */
.btn-icon-danger {
    background: none;
    border: none;
    padding: 0;
    font-size: 16px;
    font-family: inherit;
    color: var(--color-danger);
    cursor: pointer;
}
.btn-icon-danger.is-disabled {
    color: var(--color-text-faint);
    cursor: not-allowed;
}

.pager-link { color: var(--color-brand); font-weight: 600; }
.pager-link:hover { color: var(--color-brand-strong); }

/* Wyświetlanie treści z edytora WYSIWYG (patrz base.html.twig,
   .rich-editor-surface — TA reguła obsługuje tryb edycji, ta klasa niżej
   obsługuje tryb WYŚWIETLANIA zapisanej treści, np. opis sekcji, regulamin
   organizatora, treść FAQ/ogłoszenia). Wydzielone (2026-09-15) z 6 osobnych,
   ręcznie wklejonych kopii w szablonach, które już zdążyły się rozjechać
   (różne rozmiary/kolory/marginesy) — teraz jedno źródło prawdy. Admin ma
   nieco mniejszą skalę niż strony publiczne (patrz lokalny override w
   admin/announcement.html.twig) — to świadoma różnica gęstości UI, nie dług. */
.rich-text { font-size: 14px; color: var(--color-ink); line-height: 1.6; }
.rich-text p { margin: 0 0 12px; }
.rich-text p:last-child { margin-bottom: 0; }
.rich-text .text-align-center { text-align: center; }
.rich-text .text-align-right { text-align: right; }
.rich-text ul, .rich-text ol { margin: 0 0 12px; padding-left: 22px; }
.rich-text li { margin-bottom: 6px; }
.rich-text h1 { font-family: var(--font-display); font-weight: 600; font-size: 1.5em; margin: 0 0 16px; }
.rich-text h2, .rich-text h3, .rich-text h4 { font-family: var(--font-display); font-weight: 600; margin: 20px 0 10px; }
.rich-text blockquote { margin: 0 0 12px; padding-left: 14px; border-left: 3px solid var(--color-border); color: var(--color-text-muted); }

/* Dymek podpowiedzi przy etykiecie pola formularza (ikona "i" + tekst na
   hover/focus) — wydzielone (2026-09-15) z dwóch identycznych kopii w
   admin/event_form.html.twig i admin/class_series_form.html.twig. Makra Twig
   renderujące markup (fieldLabel/fieldError) zostają lokalne w obu plikach —
   to duplikacja kodu szablonu, nie CSS. */
.field-tooltip { position: relative; display: inline-flex; align-items: center; }
.field-tooltip i { font-size: 12px; color: var(--color-text-faint); cursor: help; }
.field-tooltip .field-tooltip-text {
    visibility: hidden;
    opacity: 0;
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--color-ink);
    color: #FFFFFF;
    font-size: 11.5px;
    font-weight: 400;
    line-height: 1.4;
    text-transform: none;
    letter-spacing: normal;
    padding: 8px 10px;
    border-radius: 6px;
    width: 230px;
    z-index: 20;
    transition: opacity 0.15s ease;
    pointer-events: none;
}
.field-tooltip .field-tooltip-text::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    border: 5px solid transparent;
    border-top-color: var(--color-ink);
}
.field-tooltip:hover .field-tooltip-text,
.field-tooltip:focus-within .field-tooltip-text {
    visibility: visible;
    opacity: 1;
}

.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 12px;
    border-radius: 999px;
    font-size: 12px;
    font-weight: 600;
}
.badge-success { background: var(--color-success-soft); color: var(--color-success-ink); }
.badge-error { background: var(--color-danger-soft); color: var(--color-danger-ink); }
.badge-pending { background: var(--color-pending-soft); color: var(--color-pending-ink); }
.badge-neutral, .flash-neutral { background: var(--color-bg); color: var(--color-text-muted); border: 1px solid var(--color-border-input); }
.badge-info { background: var(--color-info-soft); color: var(--color-info-ink); }

/* Redesign "Strefa Uczestnika" — przyciski filtrów (mirror .su-chip). */
.chip {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0 16px;
    border-radius: var(--radius-control);
    border: 1.5px solid var(--color-border-input);
    background: var(--color-surface);
    color: var(--color-ink);
    font: inherit;
    font-weight: 600;
    font-size: 14px;
    cursor: pointer;
}
.chip:hover { border-color: var(--color-brand-strong); color: var(--color-brand); }
.chip.is-active { background: var(--color-brand-strong); border-color: var(--color-brand-strong); color: #fff; }

/* Redesign "Strefa Uczestnika" — responsywna siatka kart (mirror .su-grid). */
.grid-cards {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 16px;
}

/* Redesign "Strefa Uczestnika" — pusty stan z przerywaną ramką (mirror .su-empty). */
.empty-state {
    border: 1.5px dashed var(--color-border-input);
    border-radius: var(--radius-card);
    padding: 32px;
    text-align: center;
    color: var(--color-ink-soft);
}

/* Redesign "Strefa Uczestnika" — wyśrodkowany kontener treści strony (mirror
   .su-main). Zastępuje powtarzany na każdej stronie publicznej inline
   "padding:48px clamp(20px,4vw,64px)" bez ograniczenia szerokości — na
   bardzo szerokich ekranach treść rozciągała się na cały ekran. */
.page-container {
    max-width: 1120px;
    margin: 0 auto;
    padding: var(--space-6) var(--space-5) var(--space-7);
    box-sizing: border-box;
}

/* Redesign "Strefa Uczestnika" — nagłówek strony: tytuł+opis z lewej,
   opcjonalna akcja z prawej (mirror .su-page-head). */
.page-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: var(--space-4);
    flex-wrap: wrap;
    margin-bottom: var(--space-5);
}
.page-head h1 {
    font-family: var(--font-display);
    font-size: 28px;
    font-weight: 600;
    margin: 0 0 var(--space-1);
}
.page-head p {
    color: var(--color-ink-soft);
    margin: 0;
    font-size: 13.5px;
}

/* Redesign "Strefa Uczestnika" — nagłówek strony detalu (plakat/logo +
   tytuł+opis), np. wydarzenie, organizator. Sam kontener elastyczny —
   rozmiar/kształt obrazka po lewej zostaje bespoke per strona (plakat
   3:4 vs okrągłe logo), bo się różnią, ale gap/wrap są wspólne. */
.page-hero {
    display: flex;
    flex-wrap: wrap;
    gap: 24px;
}

/* Redesign "Strefa Uczestnika" — pełnoekranowy komunikat statusu (ikona w
   kółku + tytuł + opis + CTA), mirror powtarzającego się wzorca z
   payment_success/pending/failed.html.twig. */
.status-panel {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-6) var(--space-4);
    box-sizing: border-box;
}
.status-panel-inner {
    max-width: 420px;
    text-align: center;
}
.status-panel-icon {
    width: 64px;
    height: 64px;
    border-radius: 999px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 28px;
    margin: 0 auto;
}
.status-panel-icon--success { background: var(--color-success-soft); color: var(--color-success-ink); }
.status-panel-icon--pending { background: var(--color-pending-soft); color: var(--color-pending-ink); }
.status-panel-icon--danger { background: var(--color-danger-soft); color: var(--color-danger-ink); }

/* Redesign "Strefa Uczestnika" — duża liczba w karcie statystyki (mirror
   .su-stat__value ze wzorca panelu ośrodka), używana razem z już
   istniejącym .section-eyebrow jako etykietą nad liczbą. */
.stat-value {
    font-family: var(--font-display);
    font-size: 32px;
    font-weight: 600;
    color: var(--color-ink);
    margin-top: 10px;
}
.stat-note {
    font-size: 12.5px;
    color: var(--color-text-muted);
    margin-top: 2px;
}

/* Przycisk wyglądający jak link, w kolorze marki (np. "Pokaż kod QR"). */
.btn-link {
    background: none;
    border: none;
    padding: 0;
    font-size: 12.5px;
    color: var(--color-brand);
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
}

/* Skip-link ("Przejdź do treści") — ze wzorca "Strefa Uczestnika" (.su-skip),
   ukryty poza ekranem, pojawia się dopiero po wejściu focusem (Tab) jako
   pierwszy element strony. Globalny, patrz base.html.twig. */
.skip-link {
    position: absolute;
    left: var(--space-3);
    top: -64px;
    z-index: 2000;
    background: var(--color-brand-strong);
    color: #fff;
    font-weight: 600;
    padding: var(--space-3) var(--space-4);
    border-radius: var(--radius-control);
    text-decoration: none;
    transition: top 0.15s ease;
}
.skip-link:focus {
    top: var(--space-3);
    color: #fff;
}

/* Blok marki (logo/inicjały + nazwa[+podtytuł]) — reużywalny wyciąg z
   nagłówka (_navigation.html.twig, .app-topbar-mark) do użycia też poza
   topbarem, np. w karcie logowania (mirror .su-header__brand). */
.brand-block {
    display: flex;
    align-items: center;
    gap: var(--space-3);
}
.brand-mark {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-control);
    background: var(--color-ink);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: 0.04em;
}
.brand-mark img {
    width: 100%;
    height: 100%;
    object-fit: contain;
    border-radius: inherit;
}
.brand-names {
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}
.brand-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--color-ink);
}
.brand-tagline {
    font-size: 12px;
    color: var(--color-text-muted);
}

/* Layout strony logowania/rejestracji — dwie kolumny od tabletu wzwyż
   (formularz + panel marketingowy), jedna kolumna na telefonie (mirror
   .su-auth ze wzorca). min-height zamiast height, żeby długa treść (np.
   błąd + formularz) nigdy nie ucinała się na niskich ekranach. Pełne
   100vh — te strony renderują się bez .app-topbar (body.no-chrome, patrz
   base.html.twig), więc nie ma 56px paska do odjęcia. */
.auth-shell {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    /* Widoczne po bokach .auth-panel poniżej 900px (patrz max-width tam) —
       bez tego pusta przestrzeń wokół wyśrodkowanej karty byłaby bielą na
       bieli, sprawiając wrażenie niedokończonej/pustej strony. */
    background: var(--color-bg);
}
@media (min-width: 900px) {
    .auth-shell {
        flex-direction: row;
    }
}
/* Poniżej 900px .auth-aside znika (patrz niżej) i .auth-panel zostaje
   SAMO w kolumnowym .auth-shell — bez max-width/cienia rozciągnęłoby się
   na całą (potencjalnie bardzo szeroką, np. tablet/laptop) szerokość,
   zostawiając ogromne puste białe marginesy wokół wąskiej 380px karty.
   Zamiast tego: ograniczona, wyśrodkowana "karta" z cieniem na tle
   --color-bg (jak .card gdzie indziej w apce) — od 900px wzwyż wraca do
   pełnej szerokości panelu w układzie dwukolumnowym (mirror wzorca). */
.auth-panel {
    flex: 1 1 480px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-6) var(--space-4);
    box-sizing: border-box;
    background: var(--color-surface);
    width: 100%;
    max-width: 640px;
    margin: 0 auto;
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-card);
}
@media (min-width: 900px) {
    .auth-panel {
        max-width: none;
        margin: 0;
        border-radius: 0;
        box-shadow: none;
    }
}
.auth-panel-inner {
    width: 100%;
    max-width: 380px;
}
.auth-head {
    margin-top: var(--space-5);
    margin-bottom: var(--space-5);
}
.auth-head h1 {
    font-size: 26px;
}
.auth-head p {
    color: var(--color-ink-soft);
    margin-top: var(--space-1);
}
.auth-legal {
    margin-top: var(--space-6);
    display: flex;
    gap: var(--space-4);
    flex-wrap: wrap;
    font-size: 12.5px;
}
.auth-legal a {
    color: var(--color-text-muted);
}

/* Panel marketingowy — ukryty poniżej 900px (mirror braku odpowiednika w
   wzorcu na wąskim ekranie; formularz logowania to jedyna rzecz, która się
   liczy na telefonie, panel to dodatek na szerszych ekranach). */
.auth-aside {
    display: none;
    flex: 1 1 420px;
    flex-direction: column;
    justify-content: center;
    gap: var(--space-4);
    padding: var(--space-7) var(--space-6);
    box-sizing: border-box;
    background: var(--color-brand-strong);
    color: #fff;
}
@media (min-width: 900px) {
    .auth-aside {
        display: flex;
    }
}
.auth-kicker {
    font-size: 12.5px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.6px;
    color: rgba(255, 255, 255, 0.6);
}
.auth-claim {
    font-family: var(--font-display);
    font-size: 26px;
    font-weight: 600;
    line-height: 1.3;
    max-width: 380px;
}
.auth-list {
    list-style: none;
    margin: var(--space-3) 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.auth-list li {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3);
    font-size: 14px;
    color: rgba(255, 255, 255, 0.85);
}
.auth-list i {
    flex-shrink: 0;
    margin-top: 2px;
    font-size: 17px;
    color: #fff;
}

/* Pole formularza (etykieta + input), np. w karcie logowania — wrapper na
   .field-label (już istnieje) + .form-input (już istnieje). */
.field {
    margin-top: var(--space-4);
}
.field:first-child {
    margin-top: 0;
}

/* Input z przyciskiem w środku (np. pokaż/ukryj hasło) — mirror
   .su-input-wrap/.su-input-btn. */
.input-group {
    position: relative;
}
.input-group .form-input {
    padding-right: 44px;
}
.input-group-btn {
    position: absolute;
    top: 50%;
    right: 4px;
    transform: translateY(-50%);
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    border-radius: var(--radius-control);
    color: var(--color-text-muted);
    cursor: pointer;
}
.input-group-btn:hover {
    background: var(--color-bg);
    color: var(--color-ink-soft);
}

/* Wiersz checkbox+etykieta (np. "nie wylogowuj mnie") — mirror .su-check. */
.check-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    margin-top: var(--space-4);
    font-size: 13.5px;
    color: var(--color-ink-soft);
    cursor: pointer;
}
.check-row input {
    width: 18px;
    height: 18px;
    accent-color: var(--color-brand-strong);
    cursor: pointer;
    flex-shrink: 0;
}

/* Wariant dla dłuższych, zawijających się etykiet (zgody RODO/regulamin na
   rejestracji) — checkbox wyrównany do PIERWSZEJ linii tekstu, nie do
   środka całego, wielowierszowego bloku. */
.check-row--align-start {
    align-items: flex-start;
}
.check-row--align-start input {
    margin-top: 3px;
}

/* --- Listy publiczne ze złożonym wyszukiwaniem/sortowaniem po stronie
   klienta (bez przeładowania strony) — WSPÓLNE dla classes.html.twig,
   organizers.html.twig, events.html.twig (na życzenie: spójny wygląd
   wszystkich trzech), zamiast osobnych, zduplikowanych bloków <style> w
   każdym szablonie. */
.listing-toolbar { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-card); padding: 16px; display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end; margin-bottom: var(--space-5); }
.listing-toolbar .field { flex: 1 1 260px; min-width: 0; }
.listing-toolbar .field--sort { flex: 0 1 220px; }
.listing-search-wrap { position: relative; display: flex; }
.listing-search-wrap i { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--color-text-muted); pointer-events: none; }
.listing-search-wrap input { padding-left: 38px; }
.listing-result-count { font-size: 12.5px; color: var(--color-text-muted); margin: 4px 0 var(--space-4); }

.listing-card { display: flex; flex-direction: column; gap: 12px; color: inherit; text-decoration: none; }
.listing-card-head { display: flex; gap: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--color-border); }
.listing-card-icon { width: 44px; height: 44px; border-radius: var(--radius-control); background: var(--color-brand-weak); color: var(--color-brand-strong); display: flex; align-items: center; justify-content: center; font-size: 19px; flex: none; overflow: hidden; }
.listing-card-icon img { width: 100%; height: 100%; object-fit: cover; }
.listing-card-title { font-family: var(--font-display); font-size: 17px; font-weight: 600; color: var(--color-ink); }
.listing-card-subtitle { font-size: 12.5px; color: var(--color-text-muted); margin-top: 2px; }
.listing-card-meta { font-size: 12px; color: var(--color-text-muted); margin-top: 2px; }
.listing-card-stats { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 5px 10px; font-size: 13px; align-items: center; }
.listing-card-stats dt { color: var(--color-text-muted); }
.listing-card-stats dt i { width: 16px; text-align: center; margin-right: 4px; }
.listing-card-stats dd { margin: 0; font-weight: 600; color: var(--color-ink); }
.listing-card-foot { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-top: auto; }
.listing-card-cta { margin-left: auto; }

@media (max-width: 560px) {
    .listing-toolbar { flex-direction: column; align-items: stretch; }
    .listing-toolbar .field--sort { flex-basis: auto; }
}
