/* Wygenerowano automatycznie: 2026-09-02 10:28:26 */

/* --- File: 01_fonts.css --- */
/**
 * 01_fonts.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-23
 */

/* Ładowanie fontów */

/* Dosis - Regular (400) - Treść główna */
@font-face {
  font-family: 'Dosis';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/dosis-v34-latin_latin-ext-regular.woff2') format('woff2');
}

/* Dosis - SemiBold (600) - Pogrubienia i przyciski */
@font-face {
  font-family: 'Dosis';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/dosis-v34-latin_latin-ext-600.woff2') format('woff2');
}

/* Dosis - ExtraBold (800) - Nagłówki */
@font-face {
  font-family: 'Dosis';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('../fonts/dosis-v34-latin_latin-ext-800.woff2') format('woff2');
}


/* --- File: 02_colors.css --- */
/**
 * 02_colors.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-24 (--color-bg-main dark mode: #101010)
 */

/* ==========================================================================
   2. COLORS.CSS - Definicje kolorów (Dark Mode Default & Light Theme)
   Klimat: Szkoła Tańca (Salsa, Bachata, Kizomba) - Zgodne z oryginalnym Logo
   ========================================================================== */

/* ==========================================================================
   JAK KORZYSTAĆ Z MACIERZY KOLORÓW (Primary, Secondary, Success, Error, itd.)
   ==========================================================================
   --color-[nazwa]:           Główne tło elementu (np. żółty przycisk akcji).
   --color-[nazwa]-hover:     Stan po najechaniu myszką na element bazowy (:hover).
   --color-[nazwa]-contrast:  Kolor tekstu/ikony leżącej BEZPOŚREDNIO na elemencie bazowym 
                              (np. czarny tekst na żółtym przycisku zachowuje WCAG).
   --color-[nazwa]-alpha:     Półprzezroczyste tło (15-20%) - idealne pod delikatne alerty, 
                              etykiety (badges) i podświetlenia w menu.
   --color-[nazwa]-text:      Kolor tekstu do czytania na standardowym tle strony 
                              (np. czerwony komunikat błędu pod inputem).
   --color-[nazwa]-muted:     Ciemne/zgaszone obramowanie do delikatnych alertów.
   ========================================================================== 
*/

:root {
    /* =========================================
       DARK MODE (Domyślny - Klubowy Parkiet)
       ========================================= */
    
    /* --- BRAND: PRIMARY (Żółty z logo) --- */
    /* Użycie: Główne przyciski Call-to-Action ("Zapisz się", "Kup karnet"), mocne wyróżnienia. */
    --color-primary: #FFCC00; 
    --color-primary-hover: #FFD633;
    --color-primary-contrast: #000000;
    --color-primary-alpha: rgba(255, 204, 0, 0.15); 
    --color-primary-text: #FFD633; 
    --color-primary-muted: #3E320E; 

    /* --- BRAND: SECONDARY (Klubowa Fuksja - Nocny Vibe) --- */
    /* Użycie: Elementy budujące klimat, przyciski drugorzędne, podświetlenia aktywnych zakładek, efekty glow (cienie pod elementami). */
    --color-secondary: #D946EF; 
    --color-secondary-hover: #E879F9;
    --color-secondary-contrast: #000000;
    --color-secondary-alpha: rgba(217, 70, 239, 0.15);
    --color-secondary-text: #F0ABFC;
    --color-secondary-muted: #3D1244;

    /* --- STATUS: SUCCESS (Zielony z logo) --- */
    /* Użycie: Komunikaty powodzenia ("Zapisano na zajęcia", "Płatność przeszła"), tagi "Aktywny". */
    --color-success: #6BA443; 
    --color-success-hover: #7EBB53; 
    --color-success-contrast: #FFFFFF; 
    --color-success-alpha: rgba(107, 164, 67, 0.15);
    --color-success-text: #95D16A; 
    --color-success-muted: #1A2E0F;

    /* --- STATUS: ERROR (Czerwony z logo) --- */
    /* Użycie: Walidacja formularzy ("Błędne hasło"), przyciski destrukcyjne ("Usuń konto"), tagi "Odrzucono". */
    --color-error: #DB2C29; 
    --color-error-hover: #EF3E3B; 
    --color-error-contrast: #FFFFFF; 
    --color-error-alpha: rgba(219, 44, 41, 0.15);
    --color-error-text: #FF8A88; 
    --color-error-muted: #3D0A08;

    /* --- STATUS: WARNING (Pomarańczowy) --- */
    /* Użycie: Ostrzeżenia nietrafne (np. "Karnet wygasa za 2 dni"), alerty wymagające uwagi. */
    --color-warning: #F59E0B; 
    --color-warning-hover: #FBBF24; 
    --color-warning-contrast: #000000; 
    --color-warning-alpha: rgba(245, 158, 11, 0.15);
    --color-warning-text: #FCD34D; 
    --color-warning-muted: #452902; 

    /* --- STATUS: INFO (Niebieski z logo) --- */
    /* Użycie: Komunikaty neutralne ("Masz 1 nową wiadomość"), paski informacyjne. */
    --color-info: #005A8C; 
    --color-info-hover: #0073B3; 
    --color-info-contrast: #FFFFFF;
    --color-info-alpha: rgba(0, 90, 140, 0.2); 
    --color-info-text: #66BDEB; 
    --color-info-muted: #001C2E;

    /* --- LINKI --- */
    /* Użycie: Standardowe linki w tekście (<a>). Dziedziczą klubową fuksję dla zachowania klimatu. */
    --color-link: #E879F9; 
    --color-link-muted: #3D1244;

    /* --- TŁA (SURFACE ARCHITECTURE) --- */
    /* Głęboka czerń na pasek nawigacji idealnie wyeksponuje oryginalne logo bez ramek */
    --color-bg-nav: #000000; 
	--color-avatar-nav: #FFFFFF; 
	--color-bg-nav-bottom: #202020;
    
	--color-bg-table: #161616; /* Kolor tła tabeli */
	--color-bg-table-hover: #14212c; /* Hover wiersza - tło tabeli lekko zabarwione błękitem (--color-info) */
	
    /* Parter: Główna 'podłoga' aplikacji (body). Zgaszona czerń nie męczy oczu przy czytaniu */
    --color-bg-main: #121212;
    
    /* Pierwsze piętro: Tło dla komponentów leżących na stronie (Karty, Panele, Artykuły) */
    --color-bg-surface: #242424; 
    
    /* Drugie piętro: Elementy 'oderwane' od strony i pływające (Dropdowny, Tooltipy, Modale) */
    --color-bg-surface-alt: #363636; 
    
    /* Zasłona: Półprzezroczysta czerń wrzucana ZA modala, aby przyciemnić aplikację pod spodem */
    --color-bg-overlay: rgba(0, 0, 0, 0.75); 

    /* --- TYPOGRAFIA I IKONY --- */
    /* Base: Jasny, ale nie 100% biały. Do głównych nagłówków (H1-H6) i podstawowych paragrafów. */
    --color-text: #F9FAFB; 
    
    /* Tekst w tabeli (.data-table td): ta sama biel co --color-text, ale przygaszona do 80% - czysta biel na dużych powierzchniach tabeli męczy wzrok. */
    --color-text-table: rgba(249, 250, 251, 0.8); 
    
    /* Dimmed: Tekst drugorzędny. Używaj do podtytułów, okruszków, małych opisów pod polami. */
    --color-text-dimmed: #D1D5DB; 
    
    /* Muted: Najmniej ważny tekst. Używaj do placeholderów w inputach, stopek praw autorskich, stanów disabled. */
    --color-text-muted: #6B7280;
    
    /* Icon: Kolor ikon w menu i interfejsie. Zapobiega "krzyczeniu" ikon na równi z tekstem. */
    --color-icon: #A1A1AA; 

    /* --- INTERAKCJE I LINIE --- */
    /* Border: Cienkie, standardowe linie podziału (tabelki, granice kart, <hr>). */
    --color-border: #3f3f3f;
    
    /* Focus: Ramka aktywacji (Accessibility). Odpala się gdy klikniesz input lub używasz klawisza Tab. Jaskrawy żółty. */
    --color-border-focus: var(--color-primary); 
    
    /* Strong: Wyraźna ramka, np. granica aktywnego inputa na hover, lub wydzielenie głównego sidebaru. */
   --color-border-strong: #595959; 

    /* --- CIENIE --- */
    /* Sm: Delikatny cień dla kart (surface) podnoszący je lekko z tła. */
    --shadow-sm: 0.125em 0.0625em 0.125em 0 rgb(0 0 0 / 0.5);
    
    /* Md: Mocny cień dla elementów pływających (modale, dropdowny), aby wybiły się mocno do przodu. */
    --shadow-md: 0.25em 0.5em 0.375em -0.0625em rgb(0 0 0 / 0.5); 

    /* --- WYKRESY (Chart.js) --- */
    /* CELOWO osobne od --color-text-dimmed/--color-border: canvas (bez
       wygładzania czcionek jak w HTML, przy małych 9-12px ticks) potrzebuje
       mocniejszego kontrastu niż zwykły przygaszony tekst UI, żeby opisy
       osi były dobrze czytelne - patrz ChartTheme.resolveColor() w
       02_2_chart-helpers.js. W dark mode wartość identyczna jak dotychczas
       (tu problemu nie było), w light mode - patrz [data-theme="light"]. */
    --color-chart-axis-text: #D1D5DB;
    --color-chart-grid: #3f3f3f;
}

/* =========================================
   LIGHT MODE (Opcjonalny)
   Komentarze strukturalne takie same jak w Dark Mode.
   ========================================= */
[data-theme="light"] {
    
    /* --- BRAND: PRIMARY --- */
    --color-primary: #FFCC00; 
    --color-primary-hover: #E6B800;
    --color-primary-contrast: #000000; 
    --color-primary-alpha: #FEF08A; 
    --color-primary-text: #A16207; 
    --color-primary-muted: #FFF6D4; 

    /* --- BRAND: SECONDARY --- */
    --color-secondary: #C026D3; 
    --color-secondary-hover: #A21CAF;
    --color-secondary-contrast: #FFFFFF; 
    --color-secondary-alpha: #F5D0FE; 
    --color-secondary-text: #86198F;
    --color-secondary-muted: #FDF4FF;
    
    /* --- STATUS: SUCCESS --- */
    --color-success: #6BA443;
    --color-success-hover: #558732;
    --color-success-contrast: #FFFFFF;
    --color-success-alpha: #DCFCE7; 
    --color-success-text: #2A4518; 
    --color-success-muted: #F0FDF4;
    
    /* --- STATUS: ERROR --- */
    --color-error: #DB2C29;
    --color-error-hover: #A81F1E;
    --color-error-contrast: #FFFFFF;
    --color-error-alpha: #FFE4E6;
    --color-error-text: #881337;
    --color-error-muted: #FFF1F2;

    /* --- STATUS: WARNING --- */
    --color-warning: #F59E0B; 
    --color-warning-hover: #D97706; 
    --color-warning-contrast: #FFFFFF; 
    --color-warning-alpha: #FFEDD5;
    --color-warning-text: #92400E; 
    --color-warning-muted: #FFF7ED; 

    /* --- STATUS: INFO --- */
    --color-info: #005A8C; 
    --color-info-hover: #00436B; 
    --color-info-contrast: #FFFFFF;
    --color-info-alpha: #E0F2FE;
    --color-info-text: #002D47; 
    --color-info-muted: #F0F9FF;

    /* --- LINKI --- */
    --color-link: #C026D3;
    --color-link-muted: #FDF4FF;

    /* --- TŁA (SURFACE) --- */
	--color-bg-table: #FFFFFF; /* Kolor tła tabeli */
	--color-bg-table-hover: #E2F0F4; /* Hover wiersza - tło tabeli lekko zabarwione błękitem (--color-info) */
    --color-bg-nav: #FFFFFF; /* Zmień na #000000, jeśli górna belka ma być czarna również w dzień */
    --color-bg-nav-bottom: #202020;
    --color-bg-main: #F5F5F5; 
    --color-bg-surface: #FFFFFF; 
    --color-bg-surface-alt: #EFF0F2; 
    --color-bg-overlay: rgba(0, 0, 0, 0.5); 

    /* --- TYPOGRAFIA I IKONY --- */
    --color-text: #18181B; 
    --color-text-table: rgba(24, 24, 27, 0.8); 
    --color-text-dimmed: #52525B; 
    --color-text-muted: #A1A1AA;
	--color-avatar-nav: #FFFFFF;
    --color-icon: #71717A; 

    /* --- INTERAKCJE I LINIE --- */
    --color-border: #E0E0E0;
    --color-border-focus: var(--color-primary);
    --color-border-strong: #A1A1AA; 

    /* --- CIENIE --- */
    --shadow-sm: 0.0625rem 0.125rem 0.125rem 0 rgb(0 0 0 / 0.05);
    --shadow-md: 0.125rem 0.25rem 0.375rem -0.0625rem rgb(0 0 0 / 0.1);

    /* --- WYKRESY (Chart.js) --- */
    /* Świadomie CIEMNIEJSZE niż --color-text-dimmed (#52525B) - ticks na
       canvasie przy małym rozmiarze fontu (9-12px, Dosis) wypadały słabo
       widoczne na białym tle mimo formalnie poprawnego kontrastu tekstu
       HTML. Zinc-700 daje wyraźnie mocniejszy, "ciężki" odczyt liczb/dat
       na osiach. Siatka (--color-chart-grid) lekko przyciemniona względem
       --color-border (#E0E0E0), żeby linie poziome też nie ginęły. */
    --color-chart-axis-text: #3F3F46;
    --color-chart-grid: #D4D4D8;
}


/* --- File: 03_base.css --- */
/**
 * 03_base.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-23
 */

/* 03_BASE.CSS - Normalizacja, Reset i Zmienne strukturalne. */

/* --- NOWA NORMALIZACJA --- */

html {
	box-sizing: border-box;
    /* Zapobiega systemowym gestom nawigacji na poziomie HTML */
    overscroll-behavior: none;

    /* POPRAWKA: usunięte z :active (tam nie działa, bo tap-highlight
       renderuje się na touchstart, zanim :active zdąży się dopasować).
       Właściwość musi siedzieć na html/elementach klikalnych. */
    -webkit-tap-highlight-color: transparent;
}

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

/* ==========================================================================
   UKRYCIE SUWAKÓW (Przewijanie działa kółkiem/dotykiem, ale brak paska)
   ========================================================================== */
* {
    /* Obsługa Firefox */
    scrollbar-width: none; 
    
    /* Obsługa starszych wersji IE / Edge */
    -ms-overflow-style: none; 
}

/* Obsługa Chrome, Safari, Edge, Opera */
*::-webkit-scrollbar {
    display: none; 
}

/* Reguła `body` (wymiary, tło, typografia, scroll) znajduje się w
   04_layout.css razem z systemem --width-index, żeby nie mieć dwóch
   konkurujących definicji tego samego selektora. */

/* Kolor zaznaczonego tekstu (np. przy kopiowaniu) spójny z systemem kolorów */
::selection {
    background-color: var(--color-primary);
    color: var(--color-primary-contrast);
}

/* Wyjątek dla pól formularzy - tam zaznaczanie i gesty muszą działać domyślnie */
input, textarea, select, [contenteditable] {
    -webkit-user-select: text;
    user-select: text;
    cursor: text;
    touch-action: manipulation; 
}

button, input, optgroup, select, textarea {
    font-family: inherit;
    font-size: 100%;
    line-height: 1.15;
    margin: 0;
}

button, select {
	text-transform: none;
}

button, [type="button"], [type="reset"], [type="submit"] {
	-webkit-appearance: button;
}

button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
	border-style: none;
	padding: 0;
}

button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
    outline: 1px dotted ButtonText;
}

h1, h2, h3, h4, h5, h6, p {
	margin: 0;
	font-size: 1rem; /* Pełna kontrola w REM */
	font-weight: 400;
}

b { font-weight: 600; }
strong { font-weight: 800; }
button { font-weight: 600; }

a {
	text-decoration: none;
    color: var(--color-link); /* Spójne z kolorami z 02_colors.css */
    transition: color 0.2s ease;
}

a:hover {
    color: var(--color-primary);
}

img, video, iframe {
    display: block;
    max-width: 100%;
    height: auto;
}

/* Zmodyfikowany reset tylko dla przycisków i inputów (bez globalnego hover z błędem) */
button, input {
    background-color: transparent;
    border: none;
}

/* ==========================================================================
   GLOBALNE ZARZĄDZANIE FOCUS
   POPRAWKA: zamiast twardego `outline: none !important` na wszystkim
   (co całkowicie zabijało dostępność klawiaturową — screen readery
   i nawigacja Tab traciły jakikolwiek sygnał fokusu), używamy
   natywnego :focus-visible. Działa dokładnie tak jak chciałeś:
   brak outline przy kliknięciu myszką/dotykiem, ale widoczny outline
   przy nawigacji klawiaturą. Wsparcie w 2026 jest pełne we wszystkich
   silnikach, więc nie trzeba już ręcznego przełącznika w komentarzu.
   ========================================================================== */

*:focus:not(:focus-visible) {
    outline: none;
}

*:focus-visible {
    outline: 0.125rem solid var(--color-border-focus);
    outline-offset: 0.125rem;
}

/* ========================================================================== */

[data-column] {
	display: flex;
	flex-direction: column;
	position: relative;
}

[data-row] {
	display: flex;
	flex-direction: row;
	position: relative;
    align-items: center;
}

/* ==========================================================================
   NOWOCZESNE EFEKTY SCROLLOWANIA (Scroll-driven Animations CSS)
   Uwaga: wsparcie animation-timeline: scroll() w Safari jest wciąż
   świeże/częściowe. Degradacja jest bezpieczna — bez wsparcia po prostu
   nie ma animacji cienia (box-shadow: none pozostaje) — ale warto
   przetestować na docelowych wersjach iOS/Safari.
   ========================================================================== */

/* Definicja animacji - z niczego w delikatny cień z Twojego Themingu */
@keyframes sticky-shadow-appear {
    from { box-shadow: none; }
    to   { box-shadow: var(--shadow-md); }
}

/* UNIWERSALNA KLASA: .sticky-shadow
  Dodaj ją do dowolnego nagłówka (np. <header class="sticky-shadow">), 
  aby przykleił się do góry i rzucał cień, gdy zawartość pod nim jest przewijana.
*/
.sticky-shadow {
    position: sticky;
    top: 0;
    z-index: 50; /* Gwarantuje, że pasek będzie nad scrollowanym tekstem */
    
    /* Natywny CSS Scroll Timeline (standard 2026) */
    animation: sticky-shadow-appear linear both;
    animation-timeline: scroll(nearest block); /* Nasłuchuje najbliższego scrolla */
    animation-range: 0 1.5rem; /* Cień płynnie pojawia się przez pierwsze 1.5rem scrollowania */
}

/* --- NOWOŚĆ: CIEŃ DOLNY --- */
@keyframes sticky-shadow-bottom-appear {
    0%, 95% { box-shadow: var(--shadow-md); }
    100% { box-shadow: none; }
}

/* AUTOMATYCZNY CIEŃ DOLNY DLA PANELI
   Dzięki ::after omijamy potrzebę wklejania pustych divów do HTMLa.
   Zadziała automatycznie na każdym komponencie z klasą .panel
*/
.panel::after {
    content: ''; /* Wymagane dla pseudoelementów */
    position: sticky;
    bottom: 0;
    height: 0;
    width: 100%;
    flex-shrink: 0; /* Zapobiega ewentualnemu ściskaniu we flexboxie */
    z-index: 50;
    pointer-events: none; /* Nie blokuje kliknięć pod spodem */
    
    /* Genialny trik: odwracamy element w osi Y. 
       Dzięki temu gotowy cień z Themingu (skierowany w dół) rzuca cień do GÓRY! */
    transform: scaleY(-1); 
    
    /* Domyślnie brak cienia (gdy nie ma paska przewijania) */
    box-shadow: none; 
    
    animation: sticky-shadow-bottom-appear linear both;
    animation-timeline: scroll(nearest block);
}

/* --- EKRAN BLOKADY (Orientation Lock) --- */
body::after {
    content: "Obróć urządzenie";
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    width: 100dvw;
    height: 100vh;
    height: 100dvh;
    background-color: #000000; /* Twarda czerń do zablokowania tła */
    color: #FFFFFF;
    z-index: 9999;
    
    display: flex; 
    justify-content: center;
    align-items: center;
    
    font-size: 2rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.25rem;
    
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s ease;
}

body.orientation-locked::after {
    opacity: 1;
    pointer-events: all;
}


/* --- File: 04_layout.css --- */
/**
 * 04_layout.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-09-22 (scroll-behavior: smooth na html - płynne przewijanie do kotwic)
 */

:root {	--width-index: 1; /* Domyślnie 1 (mobile) */	}
@media (min-width: 45rem)		{ :root { --width-index: 2; } }
@media (min-width: 67.5rem) 	{ :root { --width-index: 3; } }
@media (min-width: 90rem) 		{ :root { --width-index: 4; } }
@media (min-width: 112.5rem) 	{ :root { --width-index: 5; } }

html {
	font-size: calc(100dvw / (var(--width-index) * 22.5));
	/* Płynne przewijanie przy nawigacji do kotwic (#anchor) - np. CTA
	   "Sprawdź aktualne starty" w Hero. Respektuje scroll-margin-top
	   ustawiony na elemencie docelowym (np. .zx-kurs-section w
	   09_kurs.css), więc offset na sticky pasek nawigacji działa
	   automatycznie, bez JS. */
	scroll-behavior: smooth;
}

:root {
	/* Obliczenia szerokości w zależności od zmiennej --width-index */
	--w1to2: calc(22.5rem * min(var(--width-index), 2));
	--w1to3: calc(22.5rem * min(var(--width-index), 3));
	--w1to4: calc(22.5rem * min(var(--width-index), 4));
	--w1to5: calc(22.5rem * min(var(--width-index), 5));
}

/* Klasy szerokości kontenerów jako 1/6, 1/5, 1/4, 1/3, 1/2 i 1 względem szerokości minimalnego ekranu */
.w-1of6     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 3.75rem;  width: 3.75rem;  max-width: 3.75rem; }
.w-1of5     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 4.5rem;   width: 4.5rem;   max-width: 4.5rem; }
.w-1of4     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 5.625rem; width: 5.625rem; max-width: 5.625rem; }
.w-1of3     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 7.5rem;   width: 7.5rem;   max-width: 7.5rem; }
.w-1of2     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 11.25rem; width: 11.25rem; max-width: 11.25rem; }
.w-1        { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 22.5rem;  width: 22.5rem;  max-width: 22.5rem; }

 /* Klasy szerokości kontenerów na telefonie scrollowane w poziomie */
.w-2        { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 45rem;  width: 45rem;  max-width: 45rem; }
.w-3        { display: flex; flex-direction: row; flex-wrap: wrap; min-width: 67.5rem;  width: 67.5rem;  max-width: 67.5rem; }

/* Dynamiczne szerokości kontenerów, które na szerszych ekranach się automatycznie rozszerzają*/
.w-1to2     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: min(var(--w1to2), 100%); width: var(--w1to2); max-width: 100%; }
.w-1to3     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: min(var(--w1to3), 100%); width: var(--w1to3); max-width: 100%; }
.w-1to4     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: min(var(--w1to4), 100%); width: var(--w1to4); max-width: 100%; }
.w-1to5     { display: flex; flex-direction: row; flex-wrap: wrap; min-width: min(var(--w1to5), 100%); width: var(--w1to5); max-width: 100%; }

/* Strona publiczna (nie app-shell CRM): body ma się swobodnie przewijać
   wraz z dokumentem, dlatego min-height (nie sztywne height) - krótkie
   podstrony nadal wypełniają cały ekran (i flex space-between przybija
   stopkę do dołu), a długie treści (oferta, artykuły, 06_prose.css) same
   rosną i scrollują naturalnie, bez owijania w osobny kontener. */
body {
	margin: 0;
	min-height: 100vh;
	min-height: 100dvh;
	width: 100vw;
	width: 100dvw;

	display: flex;
	flex-direction: column;
	justify-content: space-between;

	background-color: var(--color-bg-main);
	color: var(--color-text);

	font-family: 'Dosis', sans-serif;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
	font-weight: 400;
	line-height: 1.6;

	/* BLOKADA GESTÓW SYSTEMOWYCH - blokujemy pinch-zoom i odbijanie
	   (pull-to-refresh), zostawiamy naturalny pionowy scroll strony. */
	overscroll-behavior: none;
	touch-action: pan-y;
}


/* --- File: 05_forms.css --- */
/**
 * 05_forms.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-28 (11) (.form-row: min-width 15rem)
 */

/* ======================== */
/* ===      KARTA       === */
/* ======================== */
.card {
    background-color: var(--color-bg-surface-alt);
    padding: 1rem;
    border-radius: 0.75rem;
    border: 0.0625rem solid var(--color-border);
    box-shadow: var(--shadow-md);
    margin-bottom: 1.5rem;
}

.card h3 {
    color: var(--color-text);
    margin-bottom: 0.5rem;
}

.card p {
    color: var(--color-text-dimmed);
    line-height: 1.5;
}

/* ======================== */
/* ===  FORM LAYOUT     === */
/* ======================== */
form {
    display: flex;
    flex-wrap: wrap;
}

.form-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    flex: 1;
    gap: 2rem;
    padding: 2rem 1rem 0rem 1rem;
    align-items: flex-start; /* Zapobiega rozciąganiu sąsiadujących kolumn w pionie */
}

/* Kolumna formularza - domyślnie chowa się pod siebie na wąskim ekranie */
.form-col {
    display: flex;
    flex-direction: column;
    align-items: center;
    flex: 1;
    min-width: 15rem;
}

/* Wariant .form-col z mniejszym min-width - do par pól, które mają
   zostać "pół na pół" obok siebie (np. Imię/Nazwisko). */
.form-col-half {
    display: flex;
    flex-direction: column;
    flex: 1;
    min-width: 9.5rem;
}

/* Wiersz kodu pocztowego i miasta */
.zip-city-row {
    display: flex;
    gap: 1rem;
    margin: 0;
    flex: 1;
    min-width: 20.5rem;
}
.zip-city-row .input-text {
    margin: 0;
}
.zip-city-row .input-text:first-child {
    min-width: 7.5rem;
    flex: 1;
}
.zip-city-row .input-text:last-child {
    min-width: 12rem;
    flex: 2;
}

.input-text-zip input {
    padding-left: 0.5rem;
    text-align: center;
}

/* ======================== */
/* ===     BUTTONS      === */
/* ======================== */
.btn {
    display: inline-flex;
    padding: 0.75rem 1.5rem;
    border-radius: 0.5rem;
    font-weight: 800;
    text-decoration: none;
    cursor: pointer;
    border: none;
    font-size: 0.95rem;
    text-align: center;
    transition: all 0.2s ease;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    width: max-content;
	text-transform: uppercase;
}

.btn iconify-icon {
    font-size: 1.25rem;
}

/* Stan disabled - !important świadomie, ma nadpisać KAŻDY wariant koloru
   (.btn-primary/.btn-secondary/.btn-outline). */
.btn:disabled {
    background-color: var(--color-bg-surface-alt) !important;
    color: var(--color-text-dimmed) !important;
    border-color: var(--color-border) !important;
    cursor: not-allowed;
    opacity: 0.6;
}

.btn-primary {
    background-color: var(--color-primary);
    color: var(--color-primary-contrast);
}

.btn-primary:hover {
    background-color: var(--color-primary-hover);
	color: var(--color-primary-contrast);
}

.btn-secondary {
    background-color: var(--color-secondary);
    color: var(--color-secondary-contrast);
}

.btn-secondary:hover {
    background-color: var(--color-secondary-hover);
	color: var(--color-secondary-contrast);
}

.btn-outline {
    background-color: transparent;
    border: 0.125rem solid var(--color-border);
    color: var(--color-text);
}

.btn-outline:hover {
    border-color: var(--color-text-dimmed);
    background-color: var(--color-bg-surface-alt);
	color: var(--color-text);
}

/* ======================== */
/* ===  TAGS & ALERTS   === */
/* ======================== */
.tag {
    display: inline-block;
    padding: 0.25rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 700;
    text-transform: uppercase;
}

.tag-success { background-color: var(--color-success-alpha); color: var(--color-success-text); }
.tag-error { background-color: var(--color-error-alpha); color: var(--color-error-text); }
.tag-info { background-color: var(--color-info-alpha); color: var(--color-info-text); }
.tag-warning { background-color: var(--color-warning-alpha); color: var(--color-warning-text); }
.tag-muted { background-color: var(--color-bg-surface-alt); color: var(--color-text-muted); }
/* Dwie zmienne potwierdzone w 06_prose.css (--color-secondary,
   --color-secondary-alpha, użyte przy stylach linków .prose a). Jeśli w
   02_colors.css istnieje dedykowany --color-secondary-text (analogicznie
   do -success-text/-error-text/itd.), podmień tu drugą wartość dla
   pełnej spójności z resztą tagów. */
.tag-secondary { background-color: var(--color-secondary-alpha); color: var(--color-secondary); }

.alert {
    position: relative;
    padding: 1rem;
    border-radius: 0.5rem;
    margin-bottom: 1rem;
    font-size: 0.95rem;
}

.alert-sm {
    margin-bottom: 1rem;
    font-size: 0.8rem;
    width: calc(100% - 2rem);
}

/* Narożniki alertu (4 "łapki" zamiast grubego border-left). Kolor łapek
   pochodzi ze zmiennej --alert-accent, nadawanej per wariant niżej. */
.alert::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-repeat: no-repeat;
    background-image:
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent)),
        linear-gradient(var(--alert-accent), var(--alert-accent));
    background-size:
        1rem 0.25rem,
        0.25rem 1rem,
        1rem 0.25rem,
        0.25rem 1rem,
        1rem 0.25rem,
        0.25rem 1rem,
        1rem 0.25rem,
        0.25rem 1rem;
    background-position:
        top left, top left,
        top right, top right,
        bottom right, bottom right,
        bottom left, bottom left;
}

.alert-success { background-color: var(--color-success-alpha); color: var(--color-success-text); --alert-accent: var(--color-success); }
.alert-error { background-color: var(--color-error-alpha); color: var(--color-error-text); --alert-accent: var(--color-error); }
.alert-info { background-color: var(--color-info-alpha); color: var(--color-info-text); --alert-accent: var(--color-info); }
.alert-warning { background-color: var(--color-warning-alpha); color: var(--color-warning-text); --alert-accent: var(--color-warning); }

/* ======================== */
/* ===    INPUT TEXT    === */
/* ======================== */
.input-text {
    position: relative;
    display: grid;
    flex: 1;
    grid-template-rows: auto 1fr;
    grid-template-columns: 1fr;
    height: auto;
    margin: 0;
    width: calc(100% - 2rem);
}

/* Klasy min-width dla .input-text - domyślnie brak, nadawać jawnie jedną
   z tych trzech klas gdy pole ma nie kurczyć się poniżej pewnej szerokości. */
.input-3-min { min-width: 13rem; }
.input-2-min { min-width: 9rem; }
.input-1-min { min-width: 18.5rem; }

.input-text:has(textarea) {
    position: relative;
    height: 100%;
    margin: 1.5rem 1rem 0 1rem;
}

.input-text input,
.input-text textarea,
.input-text select {
    grid-row: 2;
    grid-column: 1;
    resize: vertical;
    display: block;
    width: 100%;
    height: 2.4rem;
    padding: 0rem 1rem 0.1rem 2.25rem;
    font-family: 'Dosis', sans-serif;
    font-weight: 600;
    font-size: 1.2rem;
    color: var(--color-text);
    border: 0.0625rem solid var(--color-border);
    border-radius: 0;
    box-sizing: border-box;
    outline: none;
    transition: border-color 0.3s, background-color 0.3s;
    background-color: transparent;

    /* Aktywuje natywny ciemny tryb dla systemowych kontrolek (w tym ikony kalendarza) */
    color-scheme: dark;
}

/* Wymusza jasne kontrolki systemowe, gdy użytkownik przełączy główny motyw na Light */
[data-theme="light"] .input-text input,
[data-theme="light"] .input-text textarea,
[data-theme="light"] .input-text select {
    color-scheme: light;
}

/* Ukrywa natywną ikonkę kalendarza/zegara na rzecz własnej ikonki po lewej
   (.input-icon) - pseudoelement zostaje niewidoczny, ale rozciągnięty na
   całą powierzchnię pola, więc kliknięcie GDZIEKOLWIEK w input nadal
   otwiera systemowy kalendarz/zegar. Działa w przeglądarkach WebKit/Blink
   (Chrome, Edge); Firefox pokaże swój standardowy widget - brak regresji. */
.input-text input[type="date"]::-webkit-calendar-picker-indicator,
.input-text input[type="time"]::-webkit-calendar-picker-indicator {
    position: absolute;
    inset: 0;
    width: auto;
    height: auto;
    margin: 0;
    padding: 0;
    background: transparent;
    color: transparent;
    opacity: 0;
    cursor: pointer;
}

/* Wygląd "placeholdera" dd.mm.rrrr / gg:mm - natywne segmenty daty/czasu
   nie są prawdziwym ::placeholder, więc "puste" pole musi wyglądać
   jaśniej/cieniej ręcznie. Klasa "date-has-value" jest dodawana/usuwana
   przez JS w tych samych miejscach, gdzie zarządzany jest przycisk "X". */
.input-text input[type="date"],
.input-text input[type="time"] {
    color: var(--color-text-muted);
    font-weight: 400;
    padding-left: 2rem;
    padding-right: 2.05rem;
}

.input-text input[type="date"].date-has-value,
.input-text input[type="time"].date-has-value {
    color: var(--color-text);
    font-weight: 600;
    background-color: var(--color-bg-table);
}

.input-text input[type="date"] ~ .input-clear,
.input-text input[type="time"] ~ .input-clear {
    right: 0.4rem;
}

.input-text select {
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    padding-right: 2.5rem;
}

/* Usunięcie domyślnego niebieskiego tła selectów na korzyść nowego koloru */
.input-text select option {
    background-color: var(--color-bg-surface-alt);
    color: var(--color-text);
    font-weight: 600;
    border: none;
    outline: none;
}

.input-text input iconify-icon { font-size: 1.5rem; }

.input-text textarea {
    padding-top: 0.75rem;
    font-size: 1.2rem;
    padding-left: 3.2rem;
    min-height: 6rem;
    height: 100%;
}

.input-text textarea::-webkit-resizer {
    background-color: transparent;
    background-image: linear-gradient(135deg, transparent 50%, var(--color-border-strong) 50%);
}

.input-text:focus-within textarea::-webkit-resizer {
    background-image: linear-gradient(135deg, transparent 50%, var(--color-primary) 50%);
}

.input-text input::placeholder,
.input-text textarea::placeholder {
    color: var(--color-text-muted);
    opacity: 1;
    font-weight: 400;
}

/* =========================================================
   LOGIKA HOVER I FOCUS DLA INPUTÓW
   ========================================================= */

/* HOVER: Tylko przyciemnia/rozjaśnia główne ramki i zasieczki */
.input-text:hover input,
.input-text:hover textarea,
.input-text:hover select {
    border-color: var(--color-border-strong);
    background-color: var(--color-bg-table);
}
.input-text:hover::after {
    border-color: var(--color-border-strong);
}

/* Pole disabled nie ma reagować wizualnie na hover - cofa efekt reguły
   wyżej z powrotem do wyglądu spoczynkowego. */
.input-text:hover input:disabled,
.input-text:hover textarea:disabled,
.input-text:hover select:disabled {
    border-color: var(--color-border);
    background-color: transparent;
}

/* ACTIVE/FOCUS: Główna ramka przyciemnia/rozjaśnia się, zasieczki na żółto */
.input-text:focus-within input,
.input-text:focus-within textarea,
.input-text:focus-within select {
    border-color: var(--color-border-strong);
    background-color: var(--color-bg-surface);
}
.input-text:focus-within::after {
    border-color: var(--color-primary);
}

/* BŁĄD WALIDACJI: dotyka WYŁĄCZNIE zasieczek i dolnego podkreślenia (::after) */
.input-text.input-error::after {
    border-color: var(--color-error) !important;
}

/* Malutki komunikat błędu pod inputem (generowany/zarządzany przez
   ZxForms w 05_forms.js, patrz validateField()) - position: absolute
   CELOWO, żeby pojawienie się/zniknięcie NIGDY nie przesuwało reszty
   formularza (input-text ma height: auto, więc dolna krawędź = dolna
   krawędź inputa, dokładnie tam gdzie jest zwykle trochę wolnej
   przestrzeni do następnego wiersza formularza). :empty ukrywa go
   całkowicie, gdy pole jest poprawne (textContent wyczyszczony w JS). */
.input-text .input-error-text {
    display: block;
    position: absolute;
    left: 0;
    top: 100%;
    margin-top: 0.25rem;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--color-error);
    pointer-events: none;
}

.input-text .input-error-text:empty {
    display: none;
}

/* Ikonka wewnątrz inputa na focus zmienia się na tekstowy kolor */
.input-text:focus-within .input-icon {
    color: var(--color-text);
    fill: var(--color-text);
}

/* Wypełnione pole - tło takie samo jak przy hover, niezależnie od tego,
   czy pole jest akurat aktywne. Specyficzność selektora celowo WYŻSZA niż
   ".input-text:focus-within input", więc wypełnione pole zachowuje to tło
   również podczas aktywnej interakcji. Bez pól date/time (patrz reguła
   date/time wyżej - tam :placeholder-shown nie działa wiarygodnie) i bez
   <select> (tam "wypełnione" wykrywane jest inaczej, patrz niżej). */
.input-text input:not([type="date"]):not([type="time"]):not(:placeholder-shown),
.input-text textarea:not(:placeholder-shown) {
    background-color: var(--color-bg-table);
}

/* <select> - :placeholder-shown nie istnieje dla tego elementu, więc
   "wypełnione" wykrywane jest przez :has() sprawdzające, czy AKTUALNIE
   zaznaczona <option> to NIE ta z value="" (pusta opcja placeholder). */
.input-text select:not(:has(option[value=""]:checked)) {
    background-color: var(--color-bg-table);
}

/* Pseudoelement budujący "Zasieczki" i dolną grubą ramkę */
.input-text::after {
    grid-row: 2;
    grid-column: 1;
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;
    height: 0.375rem;
    border-left: 0.135rem solid var(--color-border-strong);
    border-right: 0.135rem solid var(--color-border-strong);
    border-bottom: 0.135rem solid var(--color-border-strong);
    border-radius: 0;
    box-sizing: border-box;
    pointer-events: none;
    z-index: 3;
    transition: border-color 0.3s;
}

.input-text .input-icon {
    grid-row: 2;
    grid-column: 1;
    display: flex;
    justify-content: center;
    align-items: center;
    position: absolute;
    left: 0.35rem;
    top: 48%;
    transform: translateY(-50%);
    width: 1.5rem;
    height: 1.5rem;
    fill: var(--color-icon);
    pointer-events: none;
    z-index: 2;
    transition: fill 0.3s, color 0.3s;
    font-size: 1.5rem;
    color: var(--color-icon);
}

.input-text:has(textarea) .input-icon {
    top: 1.2rem;
    transform: translateY(-50%);
}

.input-label {
    position: static;
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    text-transform: uppercase;
    color: var(--color-text-dimmed);
    font-weight: 600;
    pointer-events: none;
    transition: color 0.3s;
    font-family: 'Dosis', sans-serif;
    line-height: 1.3;
}

.input-text .input-clear,
.input-text .input-action {
    grid-row: 2;
    grid-column: 1;
    display: flex;
    position: absolute;
    right: 0.35rem;
    top: 50%;
    transform: translateY(-50%);
    width: 1.5rem;
    height: 1.5rem;
    cursor: pointer;
    color: var(--color-text-muted);
    z-index: 4;
    align-items: center;
    justify-content: center;
    transition: color 0.2s;
    font-size: 1.25rem;
}

.input-text .input-clear { display: none; }

.input-text .input-clear:hover,
.input-text .input-action:hover {
    color: var(--color-text);
}

.input-text .input-action:disabled {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}

.input-text .input-clear svg {
    width: 1.25rem;
    height: 1.25rem;
    fill: currentColor;
}

.input-text:has(textarea) .input-clear {
    top: 0.75rem;
    transform: none;
}

.input-text input:not(:placeholder-shown) ~ .input-clear,
.input-text textarea:not(:placeholder-shown) ~ .input-clear {
    display: flex;
}

.input-text input:not(:placeholder-shown) {
    padding-right: 2rem;
}

.input-text .select-arrow {
    grid-row: 2;
    grid-column: 1;
    position: absolute;
    right: 0.75rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--color-text-muted);
    pointer-events: none;
    z-index: 4;
    display: flex;
    font-size: 1.5rem;
}

.input-text.full {
    width: 100%;
    min-width: 0; /* Bezpieczne zerowanie min-width dla optymalizacji flexbox */
    margin: 1rem 0 0 0;
}

/* Czerwona gwiazdka wymaganego pola */
.required-star {
    font-size: 0.7rem;
    color: var(--color-error);
}

/* ======================== */
/* ===      RADIO       === */
/* ======================== */
.radio-group {
    display: flex;
    flex-direction: column;
    position: relative;
    width: calc(100% - 2rem);
    margin: 0;
}

.radio-group .radio-options {
    display: flex;
    flex-direction: column;
    position: relative;
    margin-top: 0.5rem;
}

.radio-group .radio-main-label {
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: uppercase;
    color: var(--color-text-dimmed);
}

/* Błąd walidacji grupy radio (generowany/zarządzany przez ZxForms w
   05_forms.js, patrz validateRadioGroup()) - ta sama konwencja co
   .input-error-text: position: absolute, żeby pojawienie się/zniknięcie
   nie przesuwało reszty formularza. .radio-group ma position: relative
   i height: auto, więc top: 100% zawsze ląduje tuż pod grupą, niezależnie
   od tego, ile opcji radio akurat ma. */
.radio-group .radio-error-text {
    display: block;
    position: absolute;
    left: 1rem;
    top: 100%;
    margin-top: 0.25rem;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--color-error);
    pointer-events: none;
}

.radio-group .radio-error-text:empty {
    display: none;
}

/* Błąd walidacji NIE zmienia koloru .radio-main-label - konsekwentnie z
   .input-text, gdzie błąd też nie rusza etykiety (input-label), tylko
   zasieczek i tekstu komunikatu. Tu odpowiednikiem "zasieczek" jest
   kółeczko radio i łącząca je kreska przerywana. */
.radio-group.radio-error .checkmark {
    border-color: var(--color-error);
}

.radio-group.radio-error .custom-radio-label:not(:last-child)::before {
    border-left-color: var(--color-error);
}

.custom-radio-label {
    display: flex;
    align-items: flex-start;
    cursor: pointer;
    padding: 0.625rem;
    border-radius: 0.5rem;
    transition: background-color 0.2s;
    position: relative;
    z-index: 1;
}

.custom-radio-label:not(:last-child)::before {
    content: '';
    position: absolute;
    left: 1.25rem;
    top: 1.3125rem;
    height: 100%;
    width: 0;
    border-left: 0.125rem dashed var(--color-border-strong);
    z-index: 0;
    transition: border-color 0.3s;
}

.custom-radio-input {
    position: absolute;
    opacity: 0;
    cursor: pointer;
    height: 0;
    width: 0;
}

.checkmark {
    position: relative;
    height: 1.375rem;
    width: 1.375rem;
    background-color: var(--color-bg-surface);
    border: 0.125rem solid var(--color-border-strong);
    border-radius: 50%;
    margin-top: 0.13rem;
    margin-right: 1rem;
    transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
    flex-shrink: 0;
    box-sizing: border-box;
    z-index: 2;
}

.custom-radio-label:hover .checkmark {
    background-color: var(--color-bg-surface-alt);
}

.checkmark::after {
    content: "";
    position: absolute;
    display: none;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%) scale(0);
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 50%;
    background-color: var(--color-primary);
    transition: transform 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.custom-radio-input:checked ~ .checkmark::after {
    display: block;
    animation: popIn 0.3s forwards;
}

.custom-radio-input:checked ~ .checkmark {
    border-color: var(--color-text);
}

/* Wyższa specyficzność niż reguła wyżej - błąd ma wygrywać z kolorem
   zaznaczonej opcji, inaczej zaznaczone (ale niepoprawne) kółeczko
   zostawałoby w --color-text zamiast pokazać błąd na czerwono. */
.radio-group.radio-error .custom-radio-input:checked ~ .checkmark {
    border-color: var(--color-error);
}

.label-text {
    font-size: 1.125rem;
    font-weight: 400;
    color: var(--color-text-dimmed);
    transition: color 0.3s;
    line-height: 1.4;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.custom-radio-input:checked ~ .label-text {
    color: var(--color-text);
    font-weight: 600;
}

@keyframes popIn {
    0% { transform: translate(-50%, -50%) scale(0); }
    70% { transform: translate(-50%, -50%) scale(1.2); }
    100% { transform: translate(-50%, -50%) scale(1); }
}

/* ======================== */
/* ===   CHECKBOXES     === */
/* ======================== */
.checkbox-group {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    position: relative;
    width: calc(100% - 2rem);
    margin: 0;
	flex:1;
}

/* Błąd walidacji grupy checkbox (generowany/zarządzany przez ZxForms w
   05_forms.js, patrz validateCheckboxGroup()) - ta sama konwencja co
   .radio-group .radio-error-text: position: absolute, żeby pojawienie
   się/zniknięcie nie przesuwało reszty formularza. .checkbox-group ma
   position: relative, więc top: 100% zawsze ląduje tuż pod grupą. */
.checkbox-group .checkbox-error-text {
    display: block;
    position: absolute;
    left: 1rem;
    top: 100%;
    margin-top: 0.25rem;
    font-size: 0.7rem;
    font-weight: 600;
    line-height: 1.2;
    color: var(--color-error);
    pointer-events: none;
}

.checkbox-group .checkbox-error-text:empty {
    display: none;
}

.checkbox-group.checkbox-error .checkbox-mark {
    border-color: var(--color-error);
}

/* Wyższa specyficzność niż reguła zaznaczenia niżej - błąd (na wypadek
   zaznaczenia niepoprawnej kombinacji w przyszłości, np. grupy z kilkoma
   checkboxami) ma wygrywać z kolorem zaznaczonej opcji - ta sama logika
   co .radio-group.radio-error .custom-radio-input:checked ~ .checkmark. */
.checkbox-group.checkbox-error .custom-checkbox-input:checked ~ .checkbox-mark {
    border-color: var(--color-error);
}

.custom-checkbox-label {
    display: flex;
    align-items: flex-start;
    cursor: pointer;
    padding: 0.625rem;
    border-radius: 0.5rem;
    transition: background-color 0.2s;
    position: relative;
    z-index: 1;
}

.custom-checkbox-input {
    position: absolute;
    opacity: 0;
    cursor: pointer;
    height: 0;
    width: 0;
}

.checkbox-mark {
    position: relative;
    height: 1.25rem;
    width: 1.25rem;
    background-color: var(--color-bg-surface);
    border: 0.125rem solid var(--color-border-strong);
    border-radius: 0.2rem;
    margin-top: 0.17rem;
    margin-right: 1rem;
    transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
    flex-shrink: 0;
    box-sizing: border-box;
    z-index: 2;
}

.custom-checkbox-label:hover .checkbox-mark {
    background-color: var(--color-bg-surface-alt);
}

.checkbox-mark::after {
    content: "";
    position: absolute;
    display: none;
    left: 0.4rem;
    top: -0.1rem;
    width: 0.4rem;
    height: 0.9rem;
    border: solid var(--color-primary);
    border-width: 0.15rem;
    border-top: 0;
    border-left: 0;
    transform: rotate(45deg) scale(0);
    transition: transform 0.2s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.custom-checkbox-input:checked ~ .checkbox-mark::after {
    display: block;
    animation: checkPopIn 0.3s forwards;
}

.custom-checkbox-input:checked ~ .checkbox-mark {
    border-color: var(--color-text);
    background-color: var(--color-bg-surface);
}

.checkbox-label-text {
    font-size: 1.125rem;
    font-weight: 400;
    color: var(--color-text-dimmed);
    transition: color 0.3s;
    line-height: 1.4;
}

.custom-checkbox-input:checked ~ .checkbox-label-text {
    color: var(--color-text);
    font-weight: 600;
}

/* Checkbox zgody RODO (____zx_zapisy-od-zera.php) - dłuższy tekst z linkiem
   do polityki prywatności, mniejszy font-size niż domyślny .checkbox-label-text
   (1.125rem), żeby nie dominował wizualnie nad resztą formularza. */
.zx-zapisy-zgoda-text {
    font-size: 0.9rem;
}

/* Delikatna linia oddzielająca zgodę RODO od reszty formularza - TYLKO ten
   jeden .checkbox-group (klasa dodatkowa, nie ruszamy generycznego
   .checkbox-group, którego mogą używać inne, przyszłe checkboxy). */
.zx-zapisy-zgoda-group {
    border-top: solid 0.0625rem gray;
    padding-top: 1rem;
}

/* Przycisk "Wróć" (strzałka, cofnięcie w historii przeglądarki) - .btn ma
   asymetryczny padding (0.75rem 1.5rem), dobry pod tekst, ale przy samej
   ikonie robi zbyt szeroki, nierówny przycisk - wyrównujemy do kwadratu. */
.zx-zapisy-back-btn {
    padding: 0.75rem;
}

@keyframes checkPopIn {
    0% { transform: rotate(45deg) scale(0); }
    70% { transform: rotate(45deg) scale(1.2); }
    100% { transform: rotate(45deg) scale(1); }
}

/* ======================== */
/* === COMMON DESC TEXT === */
/* ======================== */
.label-desc {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    margin-top: 0.15rem;
    font-weight: 400;
    line-height: 1.3;
    transition: color 0.3s;
}

.custom-radio-input:checked ~ .label-text .label-desc,
.custom-checkbox-input:checked ~ .checkbox-label-text .label-desc {
    color: var(--color-text-dimmed);
    font-weight: 400;
}


/* --- File: 06_prose.css --- */
/**
 * 06_prose.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-23
 */

/* Klasa .prose służy do stylowania "czystego tekstu" np. z CMS/Markdown */
.prose {
    color: var(--color-text);
    line-height: 1.6;
    margin-left: auto; 
    margin-right: auto;
}

.prose h1, .prose h2, .prose h3, .prose h4 {
    color: var(--color-text);
    margin-top: 1.5rem;
    margin-bottom: 0.6rem;
    line-height: 1.3;
}

.prose h1 {
    font-size: 2.0rem; /*Orginalnie 2.2rem */
    letter-spacing: -0.02rem;
    font-weight: 800;
}

.prose h2 { 
    font-size: 1.7rem; 
    padding-bottom: 0.3rem;
    font-weight: 800;
    width: 100%;
}

.prose h3 {
    font-size: 1.35rem;
    font-weight: 800;
    width: 100%;
}

.prose p {
    font-size: 1rem;
    font-weight: 400;
    margin-bottom: 1.25rem;
}

/* Linki w tekście */
.prose a {
    color: var(--color-secondary);
    text-decoration: underline;
    text-decoration-thickness: 0.125rem;
    text-underline-offset: 0.125rem;
    transition: all 0.2s ease;
}
.prose a:hover {
    color: var(--color-secondary-hover);
    background-color: var(--color-secondary-alpha);
    text-decoration: none;
}

/* Listy */
.prose ul, .prose ol {
    margin-bottom: 1.25rem;
    padding-left: 1.5rem;
}
.prose li { margin-bottom: 0.5rem; }

.prose ul li::marker {
    color: var(--color-primary); 
    font-size: 1.2rem;
}
.prose ol li::marker {
    color: var(--color-text-dimmed);
    font-weight: bold;
}

/* Cytaty */
.prose blockquote {
    border-left: 0.25rem solid var(--color-primary);
    margin: 1.5rem 0;
    padding: 1rem 1.5rem;
    background-color: var(--color-bg-surface-alt);
    border-radius: 0 0.5rem 0.5rem 0;
    font-style: italic;
    color: var(--color-text-dimmed);
}

/* Kod śródliniowy */
.prose code {
    font-family: monospace;
    background-color: var(--color-bg-surface-alt);
    padding: 0.2rem 0.4rem;
    border-radius: 0.25rem;
    font-size: 0.9rem;
    color: var(--color-secondary);
    border: 0.0625rem solid var(--color-border);
}

.prose strong {
    color: var(--color-text);
    font-weight: 800;
}

.prose hr {
    width: 100%;
    border: 0;
    border-top: 0.0625rem solid var(--color-border);
    margin: 2rem 0;
}

/* =======================================================
   ROZSZERZENIA REDAKCYJNE
   ======================================================= */

.prose .lead {
    font-size: 1.15rem;
    color: var(--color-text);
    font-weight: 600;
    line-height: 1.5;
    margin-bottom: 2rem;
}

.prose figure {
    margin: 2.5rem 0;
    width: 100%;
}

.prose figure img {
    width: 100%;
    height: auto;
    border-radius: 0.5rem;
    border: 0.0625rem solid var(--color-border);
    box-shadow: var(--shadow-sm);
    display: block;
}

.prose figcaption {
    font-size: 0.85rem;
    color: var(--color-text-muted);
    text-align: center;
    margin-top: 0.75rem;
    font-style: italic;
}

.prose iframe {
    width: 100%;
    aspect-ratio: 16 / 9;
    border-radius: 0.5rem;
    border: 0.0625rem solid var(--color-border);
    margin: 2.5rem 0;
    display: block;
}

.prose table {
    width: 100%;
    border-collapse: collapse;
    margin: 2.5rem 0;
    font-size: 0.95rem;
    display: block;
    overflow-x: auto;
    white-space: nowrap; 
    scrollbar-width: thin;
    scrollbar-color: var(--color-border) transparent;
}

.prose table::-webkit-scrollbar { height: 0.35rem; display: block; }
.prose table::-webkit-scrollbar-thumb { background-color: var(--color-border); border-radius: 1rem; }
.prose table::-webkit-scrollbar-thumb:hover { background-color: var(--color-primary); }

.prose th, .prose td {
    padding: 0.75rem 1rem;
    border-bottom: 0.0625rem solid var(--color-border);
}

.prose th {
    font-weight: 800;
    color: var(--color-text);
    background-color: var(--color-bg-surface-alt);
}

.prose tr:hover td { background-color: var(--color-bg-surface); }

.article-meta {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 2rem;
    padding-bottom: 1rem;
    border-bottom: 0.0625rem solid var(--color-border);
}

.meta-avatar {
    width: 3rem; height: 3rem;
    border-radius: 50%;
    object-fit: cover;
    border: 0.125rem solid var(--color-border);
}

.meta-author { font-weight: 800; color: var(--color-text); }
.meta-details { font-size: 0.85rem; color: var(--color-text-muted); }

.prose .drop-cap::first-letter {
    float: left;
    font-size: 3.5rem;
    line-height: 0.8;
    font-weight: 800;
    margin-right: 0.5rem;
    margin-top: 0.2rem;
    color: var(--color-primary);
}

/* --- CTA BOX --- */
.prose-cta {
    display: flex;
    flex-direction: column;
    background-color: var(--color-bg-surface-alt);
    border: 0.0625rem solid var(--color-border);
    border-left: 0.35rem solid var(--color-primary);
    padding: 1.5rem;
    border-radius: 0.5rem;
    margin: 2.5rem 0;
}

.prose-cta h3 { margin-top: 0 !important; color: var(--color-primary) !important; }
.prose-cta p { margin-bottom: 1.5rem !important; }

/* Przycisk (a lub button) wypchnięty do prawej */
.prose-cta .btn {
    align-self: flex-end;
}

/* Ochrona przycisku przed kaskadą linków .prose a */
.prose .btn-primary {
    color: var(--color-primary-contrast) !important;
    text-decoration: none !important;
    background-color: var(--color-primary) !important;
}

.prose .btn-primary:hover {
    background-color: var(--color-primary-hover) !important;
    color: var(--color-primary-contrast) !important;
}

/* ========================================= */
/* === KARTA SZCZEGÓŁÓW (WIDOK BOCZNY)   === */
/* ========================================= */

.detail-card {
    width: 22.5rem;
    display: flex;
    flex-direction: column;
    background-color: var(--color-bg-surface);
    border: 0.0625rem solid var(--color-border);
    border-radius: 0.75rem; 
    box-shadow: var(--shadow-md);
    overflow: hidden;
}

.detail-photo-wrapper {
    width: 100%; height: 20rem;
    background-color: var(--color-bg-surface-alt);
    border-bottom: 0.0625rem solid var(--color-border);
}

.detail-photo-wrapper img { width: 100%; height: 100%; object-fit: cover; }

.detail-header {
    padding: 1.5rem;
    text-align: center;
    border-bottom: 0.0625rem solid var(--color-border);
}

.detail-title {
    display: block;
    font-size: 0.8rem;
    color: var(--color-primary-text);
    font-weight: 700;
    text-transform: uppercase;
    margin-bottom: 0.5rem;
}

.detail-name {
    font-size: 1.75rem;
    font-weight: 800;
    color: var(--color-text);
    line-height: 1.1;
}

.detail-shortcuts {
    background-color: var(--color-bg-surface-alt);
    padding: 1rem 1.5rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    border-bottom: 0.0625rem solid var(--color-border);
}

.shortcuts-row {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    color: var(--color-text-dimmed);
    font-size: 0.9rem;
    transition: color 0.2s;
}

.shortcuts-row:hover { color: var(--color-primary); }
.shortcuts-row iconify-icon { font-size: 1.5rem; color: var(--color-icon); }

.detail-body { padding: 1rem; }
.detail-body .prose { font-size: 0.95rem; }


/* --- File: 07_navigation.css --- */
/**
 * 07_navigation.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-31 (9) (:hover na menu tylko dla urządzeń z myszą - naprawa zawieszonego tła primary po tapnięciu na dotyku)
 *
 * ZASADA: ten plik NIGDY nie zmienia layoutu przez @media. Jedyne
 * miejsce, gdzie --width-index jest liczone z fizycznej szerokości
 * ekranu, to media queries w 04_layout.css. Tutaj wszystko reaguje
 * wyłącznie na atrybut [data-width-index="1".."5"] na <html>, który
 * jest ustawiany natychmiast (przed pierwszym renderem) przez wczesny
 * inline-script w Html.php::Head(), więc nie potrzeba żadnych
 * fallbacków @media "na wypadek gdyby JS jeszcze nie zdążył".
 */

/* ==========================================================================
   PASEK GÓRNY - wspólne dla obu wariantów (a: width-index > 3, b: <= 3)
   ========================================================================== */

.zx-nav-top {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 4rem;
    z-index: 500;
    display: flex;
    align-items: center;
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    backface-visibility: hidden;
}

/* Tło paska na osobnym pseudoelemencie - jego opacity animuje JS (scroll),
   treść paska (logo, menu, avatar) zawsze w pełni czytelna. */
.zx-nav-top::before {
    content: '';
    position: absolute;
    inset: 0;
    background-color: var(--color-bg-nav);
    box-shadow: var(--shadow-sm);
    opacity: var(--zx-nav-opacity, 0);
    transition: opacity 0.1s linear;
    z-index: -1;
}

.zx-nav-top-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    height: 100%;
    padding: 0 1rem;
}

.zx-nav-logo {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    color: var(--color-text);
    transition: transform 0.2s ease;
}

.zx-nav-logo:hover {
    color: var(--color-text);
    transform: scale(1.06);
}

.zx-nav-logo-svg {
    height: 3rem;
    width: auto;
}

/* --- Kolor logo w trybie light, wariant mobilny (width-index 1-3) ---
   Pasek startuje od pełnej przezroczystości (patrz --zx-nav-opacity w JS),
   więc pod nim może być ciemne zdjęcie/tło - białe logo daje kontrast.
   Gdy pasek staje się w pełni nieprzezroczysty (biały w trybie light),
   JS dokleja klasę .zx-nav-scrolled na <html> i logo wraca do ciemnego. */
html[data-theme="light"]:is([data-width-index="1"], [data-width-index="2"], [data-width-index="3"]) .zx-nav-logo,
html[data-theme="light"]:is([data-width-index="1"], [data-width-index="2"], [data-width-index="3"]) .zx-nav-logo:hover {
    color: #FFFFFF;
}

html[data-theme="light"].zx-nav-scrolled:is([data-width-index="1"], [data-width-index="2"], [data-width-index="3"]) .zx-nav-logo,
html[data-theme="light"].zx-nav-scrolled:is([data-width-index="1"], [data-width-index="2"], [data-width-index="3"]) .zx-nav-logo:hover {
    color: var(--color-text);
}

/* --- Menu poziome (desktop) --- */

.zx-nav-menu-desktop {
    display: none; /* domyślnie ukryte - patrz reguły width-index niżej */
}

.zx-nav-menu-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.zx-nav-menu-item {
    position: relative;
}

.zx-nav-menu-link {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0.75rem 0.9rem;
    color: var(--color-text);
    text-transform: uppercase;
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    line-height: 1;
    background: transparent;
    border: none;
    cursor: pointer;
    white-space: nowrap;
}

/* :hover ograniczony do urządzeń z myszą (hover: hover) - na ekranach
   dotykowych po tapnięciu stan :hover potrafi się "zawiesić" aż do
   dotknięcia gdzie indziej, więc np. po zwinięciu podmenu w accordionie
   przycisk zostawałby wizualnie podświetlony pełnym --color-primary mimo
   braku faktycznego hovera. To NIE jest media query do layoutu (patrz
   nota na górze pliku) - sprawdza możliwości urządzenia, nie szerokość. */
@media (hover: hover) and (pointer: fine) {
    .zx-nav-menu-link:hover {
        background-color: var(--color-primary);
        color: var(--color-primary-contrast);
    }
}

.zx-nav-menu-item.zx-nav-open > .zx-nav-menu-link {
    background-color: var(--color-primary-alpha);
    color: var(--color-primary-text);
}

.zx-nav-menu-icon {
    font-size: 1.25rem;
    flex-shrink: 0;
}

.zx-nav-menu-icon-img {
    width: 1.25rem;
    height: 1.25rem;
    object-fit: contain;
}

.zx-nav-menu-arrow {
    font-size: 1rem;
    transition: transform 0.2s;
}

.zx-nav-menu-item.zx-nav-open > .zx-nav-menu-link .zx-nav-menu-arrow {
    transform: rotate(180deg);
}

.zx-nav-submenu {
    list-style: none;
    margin: 0;
    padding: 0.5rem 0;
    position: absolute;
    top: 100%;
    left: 0;
    min-width: 18rem;
    background-color: var(--color-bg-surface);
    border: 0.0625rem solid var(--color-border);
    border-radius: 0;
    box-shadow: var(--shadow-md);
    opacity: 0;
    pointer-events: none;
    transform: translateY(-0.25rem);
    transition: opacity 0.15s ease, transform 0.15s ease;
    z-index: 10;
}

.zx-nav-menu-item.zx-nav-open > .zx-nav-submenu {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}

.zx-nav-submenu-link {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.65rem 1.25rem;
    color: var(--color-text-dimmed);
    font-size: 0.85rem;
    font-weight: 600;
    text-transform: uppercase;
    white-space: nowrap;
    border-left: 0.1875rem solid transparent;
}

@media (hover: hover) and (pointer: fine) {
    .zx-nav-submenu-link:hover {
        background-color: var(--color-primary);
        color: var(--color-primary-contrast);
    }
}

.zx-nav-submenu-link.zx-nav-active {
    border-left-color: var(--color-primary);
}

/* --- Prawa strona paska --- */

.zx-nav-right {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-shrink: 0;
    position: relative;
    height: 4rem;
}

.zx-nav-settings-trigger {
    width: 2.75rem;
    height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: 50%;
    color: var(--color-text-muted);
    font-size: 1.3rem;
    opacity: 0.8;
    cursor: pointer;
    transition: background-color 0.2s, color 0.2s, opacity 0.2s;
}

.zx-nav-settings-trigger:hover {
    background-color: var(--color-bg-surface-alt);
    color: var(--color-text);
    opacity: 1;
}

.zx-nav-course-zone {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    background-color: var(--color-primary);
    color: var(--color-primary-contrast);
    border-radius: 50%;
    transition: background-color 0.2s;
}

.zx-nav-course-zone:hover {
    background-color: var(--color-primary-hover);
    color: var(--color-primary-contrast);
}

.zx-nav-course-zone-icon {
    font-size: 1.4rem;
}

.zx-nav-course-zone-label {
    display: none;
}

.zx-nav-user-trigger {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: transparent;
    border: none;
    cursor: pointer;
    padding: 0.25rem;
    border-radius: 2rem;
    transition: background-color 0.2s;
}

.zx-nav-user-trigger:hover {
    background-color: var(--color-bg-surface-alt);
}

.zx-nav-user-trigger img {
    border: 0.125rem solid var(--color-avatar-nav);
}

.zx-nav-user-name {
    display: none; /* pokazywane tylko w wariancie a - patrz niżej */
    color: var(--color-text);
    font-weight: 600;
    font-size: 0.9rem;
    white-space: nowrap;
    margin-left: 1.5rem;
}

/* --- Dropdown ustawień / usera (wspólny dla obu wariantów) --- */

.zx-nav-dropdown {
    display: none;
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    min-width: 17rem;
    flex-direction: column;
    align-items: center;
    background-color: var(--color-bg-surface);
    border: 0.0625rem solid var(--color-border);
    border-radius: 0;
    padding: 1rem;
    box-shadow: var(--shadow-md);
    z-index: 20;
}

.zx-nav-dropdown.zx-nav-open {
    display: flex;
}

.zx-nav-dropdown-section {
    width: 100%;
    margin-bottom: 1rem;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.zx-nav-dropdown-section:last-of-type {
    margin-bottom: 0;
}

.zx-nav-dropdown-section p {
    width: 100%;
    color: var(--color-text-dimmed);
    margin-bottom: 0.5rem;
    font-size: 0.85rem;
    text-transform: uppercase;
    font-weight: 600;
}

.zx-nav-opt-group {
    display: inline-flex;
    gap: 0.35rem;
    padding: 0.4rem;
    background-color: var(--color-bg-main);
    border-radius: 9999px;
    border: solid var(--color-border) 0.125rem;
    justify-content: space-between;
}

.zx-nav-opt-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    flex: none;
    font-size: 1rem;
    font-weight: 700;
    background: var(--color-border);
    color: var(--color-text);
    border: none;
    border-radius: 50%;
    cursor: pointer;
    transition: all 0.2s ease;
}

.zx-nav-opt-btn:hover {
    background: var(--color-primary-alpha);
    color: var(--color-primary);
}

.zx-nav-opt-btn.zx-nav-active {
    background: var(--color-primary);
    color: var(--color-primary-contrast);
    font-weight: bold;
    box-shadow: inset 0 0.1rem 0.225rem rgba(0, 0, 0, 0.5);
    cursor: default;
}

.zx-nav-opt-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
    pointer-events: none;
}

.zx-nav-dropdown-divider {
    height: 0.0625rem;
    background-color: var(--color-border);
    margin: 1rem 0 0.75rem 0;
}

.zx-nav-dropdown-link {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    width: 100%;
    padding: 0.6rem 0.75rem;
    border-radius: 0.5rem;
    border: none;
    background: transparent;
    color: var(--color-text-dimmed);
    font-family: inherit;
    font-weight: 600;
    font-size: 0.85rem;
    line-height: 1;
    margin: 0;
    cursor: pointer;
    transition: background-color 0.2s, color 0.2s;
    text-align: left;
}

.zx-nav-dropdown-link iconify-icon {
    font-size: 1.25rem;
    flex-shrink: 0;
}

.zx-nav-dropdown-link:hover {
    background-color: var(--color-bg-surface-alt);
    color: var(--color-text);
}

.zx-nav-logout-btn:hover {
    background-color: var(--color-error-alpha);
    color: var(--color-error-text);
}

/* --- Zasłona pod wszystkimi rozwijanymi panelami --- */

.zx-nav-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(0.25rem);
    -webkit-backdrop-filter: blur(0.25rem);
    opacity: 0;
    pointer-events: none;
    z-index: 15;
    transition: opacity 0.2s ease;
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
}

.zx-nav-overlay.zx-nav-open {
    opacity: 1;
    pointer-events: auto;
}

/* ==========================================================================
   PEŁNE MENU MOBILNE (accordion) - wywoływane przyciskiem burger
   ========================================================================== */

.zx-nav-fullmenu {
    position: fixed;
    left: 50%;
    bottom: 0;
    width: 22.5rem;
    max-width: 100%;
    transform: translateX(-50%) translateZ(0);
    -webkit-transform: translateX(-50%) translateZ(0);
    max-height: 0;
    overflow-x: hidden;
    overflow-y: auto;
    background-color: var(--color-bg-nav-bottom);
    z-index: 498;
    transition: max-height 0.35s ease;
}

.zx-nav-fullmenu.zx-nav-open {
    max-height: 75vh;
    max-height: 75dvh;
}

.zx-nav-menu-list--accordion {
    flex-direction: column;
    align-items: stretch;
    padding-bottom: 5.25rem;
}

/* Wysuwane menu dolne (.zx-nav-fullmenu) ma zawsze ciemne tło
   (--color-bg-nav-bottom: #202020 - identyczne w obu motywach, patrz
   02_colors.css), więc kolory tekstu/obramowań w środku muszą być
   zahardkodowane na wartości trybu dark i NIE reagować na [data-theme] -
   inaczej w trybie light --color-text/--color-text-dimmed przełączają się
   na ciemne wartości i tekst znika na ciemnym tle. Wartości poniżej to
   dokładnie --color-text / --color-text-dimmed z dark mode w 02_colors.css. */

.zx-nav-menu-list--accordion .zx-nav-menu-link {
    width: 100%;
    padding: 1rem 1.5rem;
    justify-content: space-between;
    border-bottom: 0.0625rem solid rgba(0, 0, 0, 0.35);
    color: #F9FAFB;
}

.zx-nav-menu-list--accordion .zx-nav-submenu {
    position: static;
    box-shadow: none;
    border: none;
    border-radius: 0;
    background-color: rgba(0, 0, 0, 0.25);
    max-height: 0;
    padding: 0;
    opacity: 1;
    pointer-events: auto;
    transform: none;
    overflow: hidden;
    transition: max-height 0.25s ease;
}

.zx-nav-menu-list--accordion .zx-nav-submenu-link {
    padding: 0.75rem 2.25rem;
    color: #D1D5DB;
}

.zx-nav-menu-list--accordion .zx-nav-menu-item.zx-nav-open > .zx-nav-submenu {
    max-height: 25rem;
    padding: 0.5rem 0;
}

/* ==========================================================================
   PASEK DOLNY (tylko wariant b: width-index <= 3)
   ========================================================================== */

.zx-nav-bottom {
    display: none; /* domyślnie ukryty - patrz reguły width-index niżej */
    position: fixed;
    left: 0;
    bottom: 0;
    width: 100%;
    z-index: 500;
    flex-direction: column;
    align-items: center;
    transform: translateZ(0);
    -webkit-transform: translateZ(0);
    backface-visibility: hidden;
}

.zx-nav-bottom-bar {
    width: 100dvw;
    display: flex;
    justify-content: center;
    padding: 0 0.5rem;
    height: 3.75rem;
    box-shadow: 0 -0.1rem 0.6rem rgba(0, 0, 0, 0.3);
    position: relative;
    z-index: 2;
}

/* Tło paska na osobnym pseudoelemencie (analogicznie do .zx-nav-top::before).
   DOMYŚLNIE zawsze w pełni wypełnione (opacity: 1) - dobre wszędzie poza
   stronami z pełnoekranowym hero pod paskiem. Strony, które chcą
   przezroczystego paska u góry (jak dawniej, płynne wypełnianie przy
   scrollu) - patrz opt-in .zx-nav-bottom-transparent niżej. Pasek GÓRNY
   (.zx-nav-top) tego nie dotyczy - zawsze zaczyna przezroczyście, bez zmian. */
.zx-nav-bottom-bar::before {
    content: '';
    position: absolute;
    inset: 0;
    background-color: var(--color-bg-nav-bottom);
    border-top: 0.0625rem solid #707070;
    opacity: 1;
    transition: opacity 0.1s linear;
    z-index: -1;
}

/* Opt-in: strona dodaje klasę .zx-nav-bottom-transparent na <body> (np.
   ____zx_template.php - hero ze zdjęciem pod paskiem), żeby przywrócić
   dawne zachowanie: przezroczysty u góry, płynnie wypełnia się przy
   scrollu (--zx-nav-bottom-opacity liczone w 07_navigation.js niezależnie
   od tego, czy ktoś z tej klasy korzysta - JS nie wie i nie musi wiedzieć,
   które strony są opt-in, to rozstrzyga wyłącznie CSS). */
body.zx-nav-bottom-transparent .zx-nav-bottom-bar::before {
    opacity: var(--zx-nav-bottom-opacity, 0);
}

.zx-nav-bottom-bar-inner {
    width: 100%;
    max-width: 22.5rem;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
}

.zx-nav-bottom-tool,
.zx-nav-bottom-slot-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 3.75rem;
    color: var(--color-text-dimmed);
    border-radius: 0.5rem;
    transition: color 0.2s, background-color 0.2s;
}

.zx-nav-bottom-tool iconify-icon {
    font-size: 1.5rem;
    margin-bottom: 0.2rem;
}

.zx-nav-bottom-tool:hover {
    color: var(--color-primary-text);
    background-color: var(--color-bg-surface-alt);
}

.zx-nav-bottom-tool.zx-nav-active {
    color: var(--color-primary-text);
    background-color: var(--color-bg-surface-alt);
}

/* Tło paska dolnego jest ZAWSZE ciemne (--color-bg-nav-bottom to stała
   #202020 w obu motywach, patrz 02_colors.css) - niezależnie od tego,
   czy pasek jest akurat przezroczysty (opt-in, patrz niżej) czy od razu
   wypełniony (domyślnie). W trybie light trzeba więc ZAWSZE nadpisać
   var(--color-text-dimmed) (jasny w dark mode, ale ciemny w light mode -
   źle dobrany do stale ciemnego tła paska). */
html[data-theme="light"] .zx-nav-bottom-tool,
html[data-theme="light"] .zx-nav-bottom-slot-empty,
html[data-theme="light"] .zx-nav-bottom-burger,
html[data-theme="light"] .zx-nav-bottom-center,
html[data-theme="light"] .zx-nav-flyout-item {
    color: #D1D5DB;
}

/* Strony z opt-in .zx-nav-bottom-transparent (patrz .zx-nav-bottom-bar::before
   niżej) - dopóki pasek jest jeszcze faktycznie przezroczysty (u góry
   strony, przed .zx-nav-scrolled), ikony na chwilę stają się maksymalnie
   jasne (czysta biel), żeby kontrastować z DOWOLNYM tłem pod spodem (np.
   zdjęcie hero) - nie tylko ze stałym ciemnym tłem paska. Wyższa
   specyficzność niż reguła wyżej, więc wygrywa tylko w tym oknie czasowym. */
html[data-theme="light"]:not(.zx-nav-scrolled) body.zx-nav-bottom-transparent .zx-nav-bottom-tool,
html[data-theme="light"]:not(.zx-nav-scrolled) body.zx-nav-bottom-transparent .zx-nav-bottom-slot-empty,
html[data-theme="light"]:not(.zx-nav-scrolled) body.zx-nav-bottom-transparent .zx-nav-bottom-burger,
html[data-theme="light"]:not(.zx-nav-scrolled) body.zx-nav-bottom-transparent .zx-nav-bottom-center,
html[data-theme="light"]:not(.zx-nav-scrolled) body.zx-nav-bottom-transparent .zx-nav-flyout-item {
    color: rgba(255, 255, 255, 0.87);
}

.zx-nav-bottom-label {
    font-size: 0.65rem;
    font-weight: 400;
    text-align: center;
    line-height: 1.1;
}

.zx-nav-bottom-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    width: 4rem;
    height: 3.75rem;
    background: transparent;
    border: none;
    color: var(--color-text-dimmed);
    cursor: pointer;
    font-family: inherit;
    line-height: 1;
    margin: 0;
    padding: 0 0 0.63rem 0;
}

.zx-nav-bottom-center-icon {
    position: absolute;
    top: -2rem;
    width: 4rem;
    height: 4rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-primary);
    color: var(--color-primary-contrast);
    border-radius: 50%;
    box-shadow: var(--shadow-md);
    transition: transform 0.15s;
}

.zx-nav-bottom-center-icon iconify-icon {
    width: 2rem;
    height: 2rem;
    font-size: 2rem;
}

.zx-nav-bottom-center:active .zx-nav-bottom-center-icon {
    transform: scale(0.95);
}

/* --- Warianty środkowego przycisku wg width-index ---
   ZxNav::renderBottomBar() w trybie "split" (centerOverride z kluczami
   'mobile'/'wide') renderuje OBA przyciski naraz i przełącza je tymi
   klasami. Dolny pasek istnieje tylko dla width-index 1-3 (patrz sekcja
   PRZEŁĄCZANIE WARIANTU niżej), więc tu rozróżniamy TYLKO index=1
   (najwęższy telefon) od index=2/3 ("reszta" zakresu mobilnego) - index
   4/5 nie ma znaczenia, bo tam cały .zx-nav-bottom jest ukryty. */

.zx-nav-bottom-center-idxrest {
    display: none;
}

html[data-width-index="2"] .zx-nav-bottom-center-idx1,
html[data-width-index="3"] .zx-nav-bottom-center-idx1 {
    display: none;
}

html[data-width-index="2"] .zx-nav-bottom-center-idxrest,
html[data-width-index="3"] .zx-nav-bottom-center-idxrest {
    display: flex;
}

.zx-nav-bottom-burger {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 3.75rem;
    background: transparent;
    border: none;
    color: var(--color-text-dimmed);
    font-family: inherit;
    line-height: 1;
    margin: 0;
    padding: 0;
    font-size: 1.5rem;
    cursor: pointer;
    border-radius: 0.5rem;
}

.zx-nav-burger-icon-close { display: none; }

#zxNavBottom.zx-nav-menu-open .zx-nav-burger-icon-open { display: none; }
#zxNavBottom.zx-nav-menu-open .zx-nav-burger-icon-close { display: block; }

/* --- Flyout (skróty pod przyciskiem Grafik) --- */

.zx-nav-flyout {
    position: absolute;
    bottom: 4.5rem;
    left: 50%;
    width: 0;
    height: 0;
    z-index: 1;
}

.zx-nav-flyout-item {
    position: absolute;
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 4rem;
    color: var(--color-text-dimmed);
    left: -2rem;
    top: 0;
    opacity: 0;
    pointer-events: none;
    transform: scale(0.5);
    transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275);
}

.zx-nav-flyout-icon {
    width: 2.5rem;
    height: 2.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background-color: var(--color-primary);
    color: var(--color-primary-contrast);
    border-radius: 50%;
    font-size: 1.4rem;
    box-shadow: 0 0.2rem 0.4rem rgba(0, 0, 0, 0.3);
    margin-bottom: 0.25rem;
}

#zxNavFlyout.zx-nav-open .zx-nav-flyout-item {
    opacity: 1;
    pointer-events: auto;
    transform: scale(1);
}

/* Wachlarz pozycji flyoutu wg liczby elementów - jedna spójna formuła
   (łuk nad przyciskiem, promień rośnie z liczbą pozycji, elementy równo
   rozłożone kątowo), więc każda liczba 2-5 wygląda symetrycznie i nie
   nakłada się na sąsiednie ikony paska (sąsiedzi są ok. 4.5-4.6rem od
   środka NA WYSOKOŚCI paska - wachlarz zamiast rozjeżdżać się w bok,
   rośnie w górę). Współrzędne to punkt startowy - do ew. dostrojenia na
   żywym telefonie. Więcej niż 5 pozycji nie jest tu obsługiwane, patrz
   limit w ZxNav::renderBottomBar(). */

#zxNavFlyout.zx-nav-open[data-count="2"] .zx-nav-flyout-item--1 { left: -4.75rem; top: -4.75rem; }
#zxNavFlyout.zx-nav-open[data-count="2"] .zx-nav-flyout-item--2 { left: 0.75rem;  top: -4.75rem; }

#zxNavFlyout.zx-nav-open[data-count="3"] .zx-nav-flyout-item--1 { left: -6.25rem; top: -4.25rem; }
#zxNavFlyout.zx-nav-open[data-count="3"] .zx-nav-flyout-item--2 { left: -2rem;    top: -6rem; }
#zxNavFlyout.zx-nav-open[data-count="3"] .zx-nav-flyout-item--3 { left: 2.25rem;  top: -4.25rem; }

#zxNavFlyout.zx-nav-open[data-count="4"] .zx-nav-flyout-item--1 { left: -7.25rem; top: -3.8rem; }
#zxNavFlyout.zx-nav-open[data-count="4"] .zx-nav-flyout-item--2 { left: -4rem;    top: -6.2rem; }
#zxNavFlyout.zx-nav-open[data-count="4"] .zx-nav-flyout-item--3 { left: 0rem;     top: -6.2rem; }
#zxNavFlyout.zx-nav-open[data-count="4"] .zx-nav-flyout-item--4 { left: 3.25rem;  top: -3.8rem; }

#zxNavFlyout.zx-nav-open[data-count="5"] .zx-nav-flyout-item--1 { left: -8.05rem; top: -3.5rem; }
#zxNavFlyout.zx-nav-open[data-count="5"] .zx-nav-flyout-item--2 { left: -5.5rem;  top: -6.05rem; }
#zxNavFlyout.zx-nav-open[data-count="5"] .zx-nav-flyout-item--3 { left: -2rem;    top: -7rem; }
#zxNavFlyout.zx-nav-open[data-count="5"] .zx-nav-flyout-item--4 { left: 1.5rem;   top: -6.05rem; }
#zxNavFlyout.zx-nav-open[data-count="5"] .zx-nav-flyout-item--5 { left: 4.05rem;  top: -3.5rem; }

/* ==========================================================================
   PRZEŁĄCZANIE WARIANTU a) / b) WG width-index
   Wariant a) (top-menu desktopowe, brak dolnego paska) = width-index 4-5.
   Wariant b) (dolny pasek, menu w accordionie) = width-index 1-3.
   Atrybut [data-width-index] na <html> jest ustawiany natychmiast (przed
   pierwszym renderem) przez inline-script w Html.php::Head(), więc nie
   potrzeba tu żadnego fallbacku @media - patrz nota na górze pliku.
   ========================================================================== */

html[data-width-index="1"] .zx-nav-menu-desktop,
html[data-width-index="2"] .zx-nav-menu-desktop,
html[data-width-index="3"] .zx-nav-menu-desktop {
    display: none;
}

html[data-width-index="1"] .zx-nav-user-name {
    display: none;
}

html[data-width-index="2"] .zx-nav-user-name,
html[data-width-index="3"] .zx-nav-user-name {
    display: block;
}

html[data-width-index="1"] .zx-nav-bottom,
html[data-width-index="2"] .zx-nav-bottom,
html[data-width-index="3"] .zx-nav-bottom {
    display: flex;
}

html[data-width-index="1"] .zx-nav-fullmenu,
html[data-width-index="2"] .zx-nav-fullmenu,
html[data-width-index="3"] .zx-nav-fullmenu {
    display: block;
}

html[data-width-index="4"] .zx-nav-menu-desktop,
html[data-width-index="5"] .zx-nav-menu-desktop {
    display: block;
}

html[data-width-index="4"] .zx-nav-user-name,
html[data-width-index="5"] .zx-nav-user-name {
    display: block;
}

html[data-width-index="4"] .zx-nav-bottom,
html[data-width-index="5"] .zx-nav-bottom {
    display: none;
}

html[data-width-index="4"] .zx-nav-fullmenu,
html[data-width-index="5"] .zx-nav-fullmenu {
    display: none;
}

html[data-width-index="4"] .zx-nav-course-zone,
html[data-width-index="5"] .zx-nav-course-zone {
    width: auto;
    height: auto;
    padding: 0.6rem 1.2rem;
    border-radius: 0.5rem;
    gap: 0.5rem;
}

html[data-width-index="4"] .zx-nav-course-zone-icon,
html[data-width-index="5"] .zx-nav-course-zone-icon {
    font-size: 1.1rem;
}

html[data-width-index="4"] .zx-nav-course-zone-label,
html[data-width-index="5"] .zx-nav-course-zone-label {
    display: inline;
    font-weight: 800;
    font-size: 0.85rem;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Odstęp na treść strony pod stałym paskiem górnym (i nad dolnym w b) -
   do naniesienia przez konkretną stronę/layout na głównym kontenerze,
   np. padding-top: 4rem na <main>. Klasa pomocnicza poniżej: */

.zx-nav-spacer-top {
    height: 4rem;
    flex-shrink: 0;
}

html[data-width-index="1"] .zx-nav-spacer-bottom,
html[data-width-index="2"] .zx-nav-spacer-bottom,
html[data-width-index="3"] .zx-nav-spacer-bottom {
    height: 3.75rem;
    flex-shrink: 0;
}


/* --- File: 08_home.css --- */
/**
 * 08_home.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-09-05
 */

.zx-hero {
	position: relative;
	width: 100%;
	height: 100vh;
	height: 100dvh;
	flex-shrink: 0;
	overflow: hidden;
	display: flex;
	justify-content: center;
}

.zx-hero-media {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	object-position: center center;
	display: block;
}

/* Gradient od ciemnego koloru paska nawigacji (--color-bg-nav z dark mode,
   #000000) do pełnej przezroczystości, pod kątem 70deg (w notacji CSS: 20
   stopni od poziomu), rozciągnięty na całą szerokość Hero. Kolor wpisany
   na sztywno (nie przez var(--color-bg-nav)), bo w light mode ta zmienna
   zmienia się na biały - a tu ma zostać zawsze ciemny, niezależnie od
   aktywnego motywu. */
.zx-hero::before {
	content: '';
	position: absolute;
	inset: 0;
	background: linear-gradient(70deg, #000000 -20%, transparent 100%);
	z-index: 1;
	pointer-events: none;
}

/* Uniwersalny, wyśrodkowany kontener treści sekcji - szerokość nadawana
   w HTML przez klasę .w-1toN (system --width-index). Centrowanie przez
   margin:auto (kontener jest display:flex z .w-1toN, czyli block-level
   na zewnątrz), więc działa identycznie w każdej sekcji strony. */
.zx-page {
	margin: 0 auto;
}

/* Wariant specyficzny dla Hero: kontener treści przyklejony 7rem od dołu,
   nad wideo/gradientem. .zx-hero-cta wewnątrz kotwiczy się do jego
   prawego dolnego rogu (bottom:0; right:0). */
.zx-hero .zx-page {
	position: absolute;
	bottom: 7rem;
	z-index: 10;
}

.zx-hero-content {
	display: flex;
	flex-direction: column;
	align-items: flex-start;
	gap: 0;
}

.zx-hero-content > * {
	padding: 1rem;
	text-align: left;
}

/* Etykieta nad głównym tytułem ("Szkoła tańca w Łodzi") - to ONA jest
   teraz jedynym <h1> na stronie (SEO - lokalna nazwa usługi), a
   dotychczasowy duży tytuł zjechał do <div class="zx-hero-title">
   (patrz szablon) - ustalone z Pawłem 2026-09-05. Własny padding (NIE
   dziedziczone 1rem z .zx-hero-content > * wyżej) - ciasny "badge"
   dopasowany do tekstu (spacje &nbsp; w treści <h1> w szablonie dają
   dodatkowy odstęp wewnątrz tła), margin-left:1rem odsuwa go od lewej
   krawędzi (gap:0 na .zx-hero-content wyżej - odstępy między elementami
   Hero ustala teraz każdy z osobna, nie wspólny gap). */
.zx-hero-pretitle {
	padding: 0rem 0.25rem;
	margin-left: 1rem;
	font-size: 0.85rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.05rem;
	color: var(--color-primary-contrast);
	background-color: var(--color-primary);
}

.zx-hero-title {
	font-size: 2.75rem;
	font-weight: 800;
	line-height: 1.1;
	color: #FFFFFF;
	text-shadow: 0 0.125rem 0.75rem rgba(0, 0, 0, 0.55);
}

.zx-hero-subtitle {
	font-size: 1rem;
	font-weight: 400;
	line-height: 1.5;
	color: #FFFFFF;
	text-shadow: 0 0.0625rem 0.375rem rgba(0, 0, 0, 0.5);
	border-left: 1rem solid var(--color-primary);
}

.zx-hero-cta {
	position: absolute;
	bottom: 0;
	right: 0;
	z-index: 10;
	width: 9rem;
	height: 9rem;
	margin-right: 1rem;
	text-transform: uppercase;
	background-color: rgba(0, 0, 0, 0.5);
	color: #FFFFFF;
	font-size: 1.5rem;
	display: none; /* Domyślnie (width-index 1) CTA ukryte */
}

.zx-hero-cta:hover {
	background-color: #000000;
	color: #FFFFFF; /* Nadpisuje globalne a:hover (03_base.css), które inaczej zmieniłoby kolor na --color-primary */
}

/* Ikona łapki (wskaźnika myszki, plik graficzny) nałożona na dolny prawy
   róg CTA, w połowie wystająca poza jego krawędzie. z-index (wartość
   jawna, nie auto) gwarantuje pierwszeństwo nad narożnymi kreskami
   .zx-hero-cta::after (z-index:auto). */
.zx-hero-cta-icon {
	position: absolute;
	bottom: -1.8rem;
	right: 1rem;
	z-index: 2;
	width: 2.5rem;
	height: auto;
	pointer-events: none;
}

/* ==========================================================================
   2. SEKCJA "START TOnDANCE" - trzy ścieżki wejścia (solo / para / grupa)
   ========================================================================== */

.zx-start {
	width: 100%;
	padding: 4rem 0;
}

/* W tej sekcji .zx-page ma ułożyć dzieci w kolumnie z wyśrodkowaniem -
   tytuł i siatka kart mają być scentrowane, w przeciwieństwie do
   .zx-styles .zx-page (nagłówek wyrównany do lewej). */
.zx-start .zx-page {
	flex-direction: column;
	align-items: center;
	gap: 2rem;
}

.zx-start-title {
	width: 100%;
	margin: 0;
	text-align: center;
	font-size: 2rem;
	font-weight: 800;
	text-transform: uppercase;
	color: var(--color-text);
}

/* Litera "n" nawiązująca do loga "TONdance" - celowo półprzezroczysta */
.zx-start-title-n {
	text-transform: lowercase;
	opacity: 0.5;
}

.zx-start-subline {
	width: 100%;
	margin: -1rem 0 0 0;
	padding: 0 1rem;
	text-align: center;
	font-size: 0.9rem;
	color: var(--color-text-dimmed);
}

.zx-start-subline-bullet {
	color: var(--color-primary);
	font-weight: 800;
}

.zx-start-grid {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	display: grid;
	grid-template-columns: repeat(2, 1fr); /* width-index 1: układ 2 + 1 */
	gap: 0.5rem; /* width-index 1: gap węższy niż na szerszych ekranach */
}

/* width-index 1: pierwsze dwie karty po 50%, trzecia pod spodem na 100% */
.zx-start-card:nth-child(3) {
	grid-column: 1 / -1;
}

@media (min-width: 45rem) { /* width-index 2, 3, 4, 5: trzy karty obok siebie */
	.zx-start-grid {
		grid-template-columns: repeat(3, 1fr);
		gap: 1.5rem;
	}

	.zx-start-card:nth-child(3) {
		grid-column: auto;
	}
}

.zx-start-card {
	display: flex;
	flex-direction: column;
	gap: 0.75rem;
	background-color: var(--color-bg-surface-alt);
	padding: 1rem;
	border-radius: 0.75rem;
	border: 0.0625rem solid var(--color-border);
	box-shadow: var(--shadow-md);
	cursor: pointer;
}

.zx-start-card-top {
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.zx-start-card-icon {
	font-size: 2.25rem;
	color: var(--color-icon);
}

.zx-start-card-title {
	font-size: 1.15rem;
	font-weight: 800;
	text-transform: uppercase;
	color: var(--color-text);
}

.zx-start-card-text {
	flex: 1;
	font-size: 0.95rem;
	line-height: 1.5;
	color: var(--color-text-dimmed);
}

.zx-start-card-link {
	display: inline-flex;
	align-items: center;
	gap: 0.35rem;
	margin-top: auto;
	font-weight: 700;
	color: var(--color-primary);
	transition: color 0.2s ease;
}

.zx-start-card-link:hover {
	color: var(--color-primary-hover);
}

.zx-start-card-link iconify-icon {
	font-size: 1.1rem;
	transition: transform 0.2s ease;
}

.zx-start-card-link:hover iconify-icon {
	transform: translateX(0.2rem);
}

/* ==========================================================================
   3. KAFELKI STYLÓW TANECZNYCH
   ========================================================================== */

.zx-styles {
	width: 100%;
	padding: 4rem 0;
}

/* W tej sekcji .zx-page ma ułożyć dzieci w kolumnie (nagłówek nad siatką),
   w przeciwieństwie do wariantu w Hero. */
.zx-styles .zx-page {
	flex-direction: column;
	align-items: flex-start;
	gap: 2rem;
}

.zx-styles-title {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	font-size: 1.75rem;
	font-weight: 800;
	color: var(--color-text);
}

.zx-styles-intro {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--color-text-dimmed);
}

.zx-style-grid {
	width: calc(100% - 0.5rem);
	margin: 0 0.25rem;
	display: grid;
	grid-template-columns: repeat(3, 1fr);
	gap: 0.25rem;
}

/* Przy 3 kolumnach i 10 kafelkach ostatni wypada samotnie w 4. rzędzie
   (10 = 3+3+3+1) - wymuszamy mu środkową kolumnę zamiast domyślnego
   wyrównania do lewej. Reset w @media niżej, bo przy 5 kolumnach 10
   kafelków wypełnia dokładnie 2 pełne rzędy (10 = 5+5) i nic nie trzeba
   centrować. */
.zx-style-tile:nth-child(10) {
	grid-column: 2 / 3;
}

@media (min-width: 45rem) {
	.zx-style-grid { grid-template-columns: repeat(5, 1fr); } /* width-index 2, 3, 4, 5 */

	.zx-style-tile:nth-child(10) {
		grid-column: auto;
	}
}

.zx-style-tile {
	position: relative;
	display: block;
	aspect-ratio: 1 / 1;
	overflow: hidden;
	background-color: var(--color-bg-surface-alt);
}

.zx-style-tile img {
	position: absolute;
	inset: 0;
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform 0.3s ease;
}

.zx-style-tile:hover img {
	transform: scale(1.05);
}

/* Gradient przyciemniający pod nazwą stylu */
.zx-style-tile::after {
	content: '';
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	height: 55%;
	background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
	pointer-events: none;
}

.zx-style-tile-name {
	position: absolute;
	left: 0;
	right: 0;
	bottom: 0;
	padding: 0.75rem;
	z-index: 2;
	display: flex;
	flex-direction: column;
	gap: 0.35rem;
	line-height: 1;
}

.zx-style-tile-title {
	color: #FFFFFF;
	font-weight: 800;
	font-size: 1rem; /* width-index 1 */
	text-transform: uppercase;
	text-shadow: 0 0.0625rem 0.25rem rgba(0, 0, 0, 0.5);
}

.zx-style-tile-desc {
	color: rgba(255, 255, 255, 0.85);
	font-weight: 400;
	font-size: 0.55rem; /* width-index 1 */
	text-shadow: 0 0.0625rem 0.25rem rgba(0, 0, 0, 0.5);
}

@media (min-width: 67.5rem) { /* width-index 3, 4, 5 */
	.zx-style-tile-title {
		font-size: 1.5rem;
	}

	.zx-style-tile-desc {
		font-size: 1rem;
	}
}

/* Narożne kreski w kolorze primary - ten sam trik co .alert::after w
   05_forms.css, przeniesiony na przycisk CTA Hero. */
.zx-hero-cta::after {
	content: '';
	position: absolute;
	inset: 0;
	pointer-events: none;
	background-repeat: no-repeat;
	background-image:
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary)),
		linear-gradient(var(--color-primary), var(--color-primary));
	background-size:
		1rem 0.25rem,
		0.25rem 1rem,
		1rem 0.25rem,
		0.25rem 1rem,
		1rem 0.25rem,
		0.25rem 1rem,
		1rem 0.25rem,
		0.25rem 1rem;
	background-position:
		top left, top left,
		top right, top right,
		bottom right, bottom right,
		bottom left, bottom left;
}

/* width-index 2: stała szerokość hero-content (zamiast płynnej z .w-1to2),
   i pokazanie CTA. Progi identyczne jak w 04_layout.css. */
@media (min-width: 45rem) {
	.zx-hero-cta {
		display: inline-flex;
	}
}

@media (min-width: 45rem) and (max-width: 67.4375rem) {
	.zx-hero-content {
		min-width: 33.75rem;
		width: 33.75rem;
		max-width: 33.75rem;
	}
}

/* width-index 4 i 5: fonty w hero-content powiększone x1.5 */
@media (min-width: 90rem) {
	.zx-hero-title {
		font-size: 4.125rem;
	}

	.zx-hero-subtitle {
		font-size: 1.5rem;
	}
}


/* --- File: 09_kurs.css --- */
/**
 * 09_kurs.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-31 (2) (zasłona modala startu animuje się - opacity+blur zamiast twardego display:none/flex)
 *
 * Sekcja "Aktualne starty" na stronie głównej - karty kursów poziomu
 * Copper. Wygląd karty wzorowany 1:1 na buildKursCardHtml() z CRM
 * (02_5_card.js), przepisany z inline-styli na klasy zgodnie z architekturą
 * CSS tego projektu. Różnice względem CRM (ustalone z Pawłem):
 * - wszystkie 4 rogi karty zaokrąglone (w CRM tylko prawe, bo tam karta
 *   "dotyka" lewej krawędzi panelu bocznego - tu jest samodzielna),
 *   avatary instruktorów, poziom kursu ZAWSZE Copper, nie
 *   pokazujemy ani ikony poziomu.
 */

/* scroll-margin-top: 4rem - żeby po przewinięciu z CTA "Sprawdź aktualne
   starty" w Hero (href="#aktualne-starty") sekcja nie chowała się pod
   paskiem nawigacji. Ta sama wartość co reszta miejsc w projekcie, gdzie
   przewijamy do sekcji ze scroll-margin-top (patrz też 10_faq.css). */
.zx-kurs-section {
	scroll-margin-top: 4rem;
	width: 100%;
	padding: 4rem 0;
}

.zx-kurs-title {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	font-size: 1.75rem;
	font-weight: 800;
	color: var(--color-text);
}

/* Kontener karty instrukcji - width: calc(100% - 2rem) gwarantuje, że blok
   ZAWSZE zajmuje cały wiersz .zx-page (rodzic jest flex-row z flex-wrap),
   więc nic nie może wylądować obok karty; align-items:center centruje
   samą kartę (jej właściwa szerokość liczona jest niżej z var(--width-index),
   bez @media, zgodnie z konwencją "width management w layout system"). */
.zx-kurs-instrukcja-wrap {
	width: calc(100% - 2rem);
	margin: 0 1rem 1.5rem 1rem;
	display: flex;
	flex-direction: column;
	align-items: center;
}

/* Szerokość karty: 22.5rem przy width-index 1, 33.75rem od width-index 2 */
.zx-kurs-instrukcja-card {
	width: calc(22.5rem + min(1, var(--width-index) - 1) * 11.25rem);
	min-width: 20.5rem;
	max-width: 100%;
}

.zx-kurs-instrukcja {
	display: block;
	min-width: calc(100% + 2rem); /* rekompensuje boczny padding karty (.card: padding 1rem) - obrazek ma własny wewnętrzny odstęp, więc dochodzi do bocznych krawędzi karty */
	margin: 0 -1rem;
	height: auto;
	border-radius: 0.5rem;
}

/* Domyślnie (tryb CIEMNY - to :root jest wariantem domyślnym w
   02_colors.css, "DARK MODE (Domyślny)", [data-theme="light"] to jawny
   override) widoczna wersja "-dark", ukryta "-light" - i odwrotnie pod
   [data-theme="light"]. CELOWO nie [data-theme="dark"] jako selektor
   włączający - ten atrybut bywa w ogóle nieustawiony (np. tryb "auto"
   podążający za systemem), więc reguła zależna od jego OBECNOŚCI by nie
   zadziałała; [data-theme="light"] jest ustawiane jawnie i niezawodnie
   (patrz Html.php - domyślne i explicit "light" zawsze je ustawiają). */
.zx-kurs-instrukcja-light {
	display: none;
}

[data-theme="light"] .zx-kurs-instrukcja-light {
	display: block;
}

[data-theme="light"] .zx-kurs-instrukcja-dark {
	display: none;
}

/* ======================== */
/* ===  PRZEŁĄCZNIKI FILTRU  === */
/* ======================== */

/* Wspólny wiersz obu przełączników (typ + styl tańca) - z tego samego
   powodu co .zx-kurs-instrukcja-wrap wyżej: pełna szerokość wiersza
   .zx-page, żeby nic obcego nie wylądowało obok. flex-wrap wewnątrz
   pozwala przełącznikom ułożyć się obok siebie na szerokim ekranie, a
   spaść pod siebie, gdy zabraknie miejsca (np. wąski mobile albo dużo
   opcji stylu). */
.zx-kurs-filters-row {
	width: calc(100% - 2rem);
	margin: 0 1rem 1.5rem 1rem;
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	justify-content: center;
	gap: 1rem;
}

/* Grupa "etykieta + przełącznik" - jeden element w .zx-kurs-filters-row.
   flex-basis/max-width (rozmiar w wierszu obok drugiej grupy) siedzi TU,
   a nie na .zx-kurs-filter-switch, bo teraz w kolumnie nad przełącznikiem
   dochodzi etykieta. */
.zx-kurs-filter-group {
	flex: 1 1 20.5rem;
	max-width: 20.5rem;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
}

/* Grupa stylu tańca może mieć więcej niż 3 opcje (zależnie od tego, ile
   stylów ma aktualnie jakiś kurs poniżej) - w przeciwieństwie do grupy
   typu (zawsze 3 opcje) nie ograniczamy jej do 20.5rem. */
.zx-kurs-filter-group-styl {
	max-width: 100%;
}

/* Etykieta nad przełącznikiem - te same wartości co .radio-main-label
   z 05_forms.css (font-size/weight, uppercase, kolor dimmed). */
.zx-kurs-filter-label {
	width: 100%;
	text-align: left;
	font-size: 0.85rem;
	font-weight: 600;
	text-transform: uppercase;
	color: var(--color-text-dimmed);
}

/* Ta sama mechanika co .custom-radio-input z 05_forms.css (ukryty input
   radio + label, stan przez :checked) - tu jednak BEZ .checkmark i kropki:
   wariant poziomy, wyglądający jak pigułka z segmentami. Szerokość 100%
   grupy-rodzica (.zx-kurs-filter-group) - to grupa, nie przełącznik,
   decyduje o rozmiarze w wierszu (patrz wyżej). */
.zx-kurs-filter-switch {
	width: 100%;
	min-height: 3rem;
	display: flex;
	gap: 0.25rem;
	padding: 0.25rem;
	background-color: var(--color-bg-surface-alt);
	border: 0.0625rem solid var(--color-border);
	border-radius: 1.5rem;
}

/* Przełącznik stylu tańca może mieć więcej niż 3 opcje (zależnie od tego,
   ile stylów ma aktualnie jakiś kurs poniżej) - w przeciwieństwie do
   przełącznika typu (zawsze 3 opcje) pozwalamy opcjom zawijać się do
   kolejnych wierszy wewnątrz pigułki. */
.zx-kurs-filter-switch-styl {
	flex-wrap: wrap;
}

.zx-kurs-filter-input {
	position: absolute;
	opacity: 0;
	height: 0;
	width: 0;
	pointer-events: none;
}

.zx-kurs-filter-option {
	flex: 1;
	display: flex;
	align-items: center;
	justify-content: center;
	text-align: center;
	height: 2.5rem;
	padding: 0.5rem 0.5rem;
	border-radius: 9999px;
	font-size: 0.9rem;
	font-weight: 600;
	color: var(--color-text-dimmed);
	cursor: pointer;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.zx-kurs-filter-option:hover {
	color: var(--color-text);
}

.zx-kurs-filter-input:checked + .zx-kurs-filter-option {
	background-color: var(--color-primary);
	color: var(--color-primary-contrast);
	font-weight: 800;
	box-shadow: var(--shadow-sm);
}

.zx-kurs-filter-input:focus-visible + .zx-kurs-filter-option {
	outline: 0.125rem solid var(--color-border-focus);
	outline-offset: 0.125rem;
}

.zx-kurs-intro {
	width: calc(100% - 2rem);
	margin: 0 1rem 2rem 1rem;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--color-text-dimmed);
}

.zx-kurs-empty {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	color: var(--color-text-muted);
	font-size: 0.95rem;
}

/* ======================== */
/* === PRZEŁĄCZNIK WIDOKU (KAFELKI/LISTA) === */
/* ======================== */

/* Dwie okrągłe ikony nad siatką kursów, pod przełącznikami filtru - stan
   (który widok aktywny) trzyma atrybut data-zx-kurs-view na .zx-kurs-grid
   niżej (patrz zxKursSetView() w szablonie), NIE localStorage - strona
   celowo zawsze wraca do kafelków przy kolejnym wejściu. */
.zx-kurs-view-switch {
	width: calc(100% - 2rem);
	margin: 0 1rem 1.5rem 1rem;
	display: flex;
	justify-content: center;
	gap: 0.5rem;
}

.zx-kurs-view-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.75rem;
	height: 2.75rem;
	border-radius: 50%;
	background-color: var(--color-bg-surface-alt);
	border: 0.0625rem solid var(--color-border);
	color: var(--color-icon);
	font-size: 1.3rem;
	cursor: pointer;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.zx-kurs-view-btn:hover {
	color: var(--color-primary);
}

.zx-kurs-view-btn-active {
	background-color: var(--color-primary);
	border-color: var(--color-primary);
	color: var(--color-primary-contrast);
}

.zx-kurs-view-btn-active:hover {
	color: var(--color-primary-contrast);
}

.zx-kurs-grid {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(20.5rem, 1fr));
	gap: 1rem;
}

/* min-width: 0 nadpisuje domyślne "auto" - bez tego przeglądarka liczy
   minimalną szerokość tej kolumny siatki (.zx-kurs-grid) na podstawie
   NAJSZERSZEJ możliwej zawartości w środku (np. długie słowo w opisie,
   tabela w kurs_opis, link bez łamania) - NAWET jeśli ta treść jest
   wizualnie ukryta/przycięta akordeonem (zjawisko znane jako "grid
   blowout"). To właśnie rozpychało kolumnę (a więc i wysunięty opis)
   szerzej niż zakładane 20.5rem karty. */
/* scroll-margin-top: przesunięcie punktu przewinięcia w dół, tak żeby
   karta po scrollIntoView() (JS, zxKursToggleOpis() w ____zx_template.php)
   nie chowała się pod sticky paskiem nawigacji (07_navigation.css) - 5rem,
   ta sama wartość co .zx-faq-item w 10_faq.css. */
.zx-kurs-item {
	scroll-margin-top: 5rem;
	width: 100%;
	min-width: 0;
}

/* Widok listy: siatka DOKŁADNIE jak przy kafelkach wyżej (grid,
   auto-fit + minmax(min, 1fr)) - ustalone z Pawłem 2026-08-31.

   WAŻNE: minmax(18.5rem, 1fr), NIE minmax(18.5rem, 22.5rem) - błąd
   znaleziony przez Pawła 2026-08-31 (przy --width-index:3 wychodziły
   2 kolumny zamiast 3). Gdy górna granica minmax() jest wartością STAŁĄ
   (22.5rem), przeglądarka liczy DOSTĘPNĄ LICZBĘ KOLUMN na podstawie TEJ
   górnej granicy, nie dolnej - 3 kolumny po 22.5rem + odstępy nie
   mieściły się w kontenerze (~65.5rem), więc cofało do 2. Gdy górna
   granica jest ELASTYCZNA (1fr), liczenie kolumn opiera się na DOLNEJ
   granicy (18.5rem) - dokładnie to, czego chcemy - a nadmiar miejsca
   rozkłada się równo pomiędzy kolumny przez fr. Twardy górny limit
   22.5rem pilnowany jest OSOBNO przez max-width na samym .zx-kurs-bar
   niżej, na wypadek gdyby przy małej liczbie kursów w wierszu kolumna
   chciała urosnąć powyżej 22.5rem.

   auto-fit (nie auto-fill!) - puste kolumny są zwijane do 0, więc
   istniejące paski rozciągają się i wypełniają CAŁĄ szerokość kontenera,
   zamiast zostawiać pustą przestrzeń z prawej strony ostatniego rzędu.
   justify-items:center - gdy max-width na pasku faktycznie przytnie go
   poniżej szerokości kolumny (patrz wyżej), pasek zostaje wyśrodkowany w
   komórce zamiast przyklejony do lewej krawędzi.

   .zx-kurs-item NIE ma tu własnej reguły width - bazowe width:100%
   (patrz wyżej) wystarcza, bo w trybie grid to KOMÓRKA (grid-template-
   columns) dyktuje szerokość, a item ją tylko wypełnia - dokładnie tak
   samo jak w siatce kafelków. */
.zx-kurs-grid[data-zx-kurs-view="lista"] {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(18.5rem, 1fr));
	justify-items: center;
	gap: 0.25rem;
}

.zx-kurs-grid[data-zx-kurs-view="lista"] .zx-kurs-card {
	display: none;
}

.zx-kurs-grid[data-zx-kurs-view="lista"] .zx-kurs-bar {
	display: flex;
}

/* ======================== */
/* ===       KARTA       === */
/* ======================== */

.zx-kurs-card {
	width: 100%;
	height: 8.5rem;
	box-sizing: border-box;
	display: flex;
	align-items: stretch;
	cursor: pointer;
	border: 0.0625rem solid var(--color-border);
	overflow: hidden;
	background-color: var(--color-bg-surface);
	box-shadow: var(--shadow-md);
}

.zx-kurs-cover-wrap {
	width: 4.5rem;
	flex-shrink: 0;
	margin: 0.25rem 0 0.25rem 0.25rem;
	overflow: hidden;
	background-color: var(--color-bg-surface-alt);
	display: flex;
	align-items: center;
	justify-content: center;
}

.zx-kurs-middle {
	flex: 1;
	min-width: 0;
	display: flex;
	flex-direction: column;
}

.zx-kurs-name-row {
	flex: 1 1 50%;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.15rem;
	padding: 0.25rem 0.5rem 0 0.5rem;
	text-align: center;
}

.zx-kurs-name {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: normal;
	word-break: break-word;
	font-weight: 800;
	font-size: 1.2rem;
	line-height: 1;
	text-transform: uppercase;
	max-width: 100%;
	color: var(--color-text);
}

.zx-kurs-subtitle {
	display: block;
	font-weight: 400;
	font-size: 0.8rem;
	color: var(--color-text-dimmed);
	white-space: nowrap;
	overflow: hidden;
	text-overflow: ellipsis;
	max-width: 100%;
}

.zx-kurs-instruktorzy-row {
	flex: 1 1 50%;
	box-sizing: border-box;
	display: flex;
	align-items: center;
	justify-content: center;
	padding: 0 0.5rem 0.25rem 0.5rem;
}

.zx-kurs-instruktorzy {
	display: flex;
	flex-direction: column;
	align-items: center;
}

.zx-kurs-avatars {
	display: flex;
	align-items: center;
	justify-content: center;
	gap: 0.25rem;
}

.zx-kurs-avatar {
	width: 2rem;
	height: 2rem;
	flex-shrink: 0;
	border-radius: 50%;
	overflow: hidden;
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: var(--color-bg-surface-alt);
	box-shadow: 0 0 0 0.0625rem transparent;
	transition: box-shadow 0.15s ease;
	color: var(--color-icon);
	font-size: 1.3rem;
}

.zx-kurs-avatar:hover {
	box-shadow: 0 0 0 0.0625rem var(--color-primary);
	color: var(--color-icon);
}

.zx-kurs-names {
	font-size: 0.7rem;
	color: var(--color-text);
	text-align: center;
	max-width: 11.5rem;
	white-space: normal;
	line-height: normal;
	margin-top: 0.25rem;
}

.zx-kurs-names a {
	color: var(--color-text);
}

.zx-kurs-names a:hover {
	color: var(--color-primary);
	text-decoration: underline;
}

.zx-kurs-names-sep {
	color: var(--color-text-muted);
	font-weight: 400;
}

/* ======================== */
/* ===   PASEK (WIDOK LISTY)   === */
/* ======================== */

/* Alternatywa dla .zx-kurs-card - sibling w tym samym .zx-kurs-item,
   widoczność przełącza .zx-kurs-grid[data-zx-kurs-view] (patrz wyżej).
   width:100% + max-width:22.5rem (NIE sztywne 20.5rem!) - pasek wypełnia
   całą szerokość komórki grida (elastycznej dzięki minmax(18.5rem, 1fr) -
   patrz komentarz przy .zx-kurs-grid[data-zx-kurs-view="lista"] wyżej,
   WŁĄCZNIE z wyjaśnieniem, dlaczego górny limit NIE siedzi w samym
   minmax()), ale nigdy nie urośnie powyżej 22.5rem - ustalone z Pawłem
   2026-08-31. Dolny limit (18.5rem) pilnuje sam grid (minmax min), górny
   (22.5rem) pilnuje ten max-width. Wysokość 4rem STAŁA (nie skaluje się
   z szerokością) - podział na kolumny wewnątrz (4rem dzień / 4rem cover /
   elastyczny tytuł / 2.25rem akcja) - projekt z Pawłem 2026-08-31.
   display:none domyślnie (widok kafelków) - reguła
   .zx-kurs-grid[data-zx-kurs-view="lista"] .zx-kurs-bar wyżej włącza flex. */
.zx-kurs-bar {
	width: 100%;
	max-width: 22.5rem;
	height: 4rem;
	box-sizing: border-box;
	display: none;
	align-items: stretch;
	cursor: pointer;
	border: 0.0625rem solid var(--color-border);
	overflow: hidden;
	background-color: var(--color-bg-surface);
	box-shadow: var(--shadow-md);
}

/* Kolumna "dzień" - dwuliterowy skrót dnia tygodnia + data startu + godzina
   (patrz zx_kurs_dzien_skrot() w szablonie), albo placeholder "WKRÓTCE" dla
   kursów bez ustalonego terminu (typ "zbieramy grupę"). */
.zx-kurs-bar-day {
	width: 4rem;
	flex-shrink: 0;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: 0.1rem;
	padding: 0.25rem;
}

.zx-kurs-bar-day-name {
	font-size: 0.95rem;
	font-weight: 800;
	line-height: 1;
	text-transform: uppercase;
	color: var(--color-text);
}

.zx-kurs-bar-day-date {
	font-size: 0.8rem;
	font-weight: 600;
	line-height: 1.2;
	color: var(--color-text-dimmed);
}

.zx-kurs-bar-day-hour {
	font-size: 0.7rem;
	line-height: 1.2;
	color: var(--color-text-muted);
}

.zx-kurs-bar-day-soon {
	font-size: 0.7rem;
	font-weight: 800;
	line-height: 1.2;
	text-align: center;
	text-transform: uppercase;
	color: var(--color-text-dimmed);
}

/* Cover kwadratowy 3.5rem x 3.5rem - nadpisuje .zx-kurs-cover-wrap (klasa
   dodana OBOK, nie zamiast, na tym samym elemencie w szablonie). Rozmiar
   ustawiony WPROST (width/height), nie przez padding na większym slocie -
   tło .zx-kurs-cover-wrap (--color-bg-surface-alt, widoczne gdy brak
   coveru) ma dzięki temu DOKŁADNIE wymiary obrazka, tak jak na kafelku
   (tam też margin, nie padding) - błąd znaleziony przez Pawła 2026-08-31:
   przy padding tło "wystawało" poza obrazek o 0.25rem z każdej strony.
   margin: auto 0.25rem - auto pionowo centruje kwadrat w wysokości paska
   (4rem bar - 3.5rem kwadrat = 0.5rem, flexbox rozkłada to po równo jako
   marginesy auto góra/dół), 0.25rem poziomo zachowuje odstęp od sąsiednich
   kolumn (dzień/tytuł), razem dając ten sam całkowity slot 4rem szerokości
   co kolumna dnia. */
.zx-kurs-bar-cover {
	width: 3.5rem;
	height: 3.5rem;
	flex-shrink: 0;
	margin: auto 0.25rem;
}

.zx-kurs-bar-title {
	flex: 1;
	min-width: 0;
	box-sizing: border-box;
	display: flex;
	flex-direction: column;
	justify-content: center;
	gap: 0.15rem;
	padding: 0.25rem 0.75rem;
}

.zx-kurs-bar-name {
	display: -webkit-box;
	-webkit-line-clamp: 2;
	-webkit-box-orient: vertical;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: normal;
	word-break: break-word;
	font-weight: 800;
	font-size: 0.95rem;
	line-height: 1.15;
	text-transform: uppercase;
	color: var(--color-text);
}

/* Widoczny TYLKO na pasku kursów "zbieramy grupę" (patrz $terminTekst w
   szablonie, pętla $kursyZbieramy) - "mniejszymi literami" pod tytułem. */
.zx-kurs-bar-subtitle {
	display: block;
	font-weight: 400;
	font-size: 0.75rem;
	line-height: 1.2;
	color: var(--color-text-dimmed);
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	max-width: 100%;
}

/* Kolumna akcji (przycisk "Zapisz się") - ten sam .zx-kurs-icon-btn co w
   kolumnie ikon kafelka, tu bez drugiego przycisku (chevron rozwijania
   opisu) - na pasku CAŁY wiersz i cover już rozwijają opis po kliknięciu
   (patrz zxKursCardClick()/zxKursBarCoverClick() w szablonie), więc osobny
   przycisk "Więcej" byłby zbędny. */
.zx-kurs-bar-action {
	width: 2.25rem;
	flex-shrink: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	border-left: 0.0625rem solid var(--color-border);
}

/* ======================== */
/* === MODAL START TOnDANCE (SOLO/PARA/EKIPA) === */
/* ======================== */

/* Ten sam wzorzec co .zx-cover-modal niżej (pełnoekranowe tło, domyślnie
   display:none, klasa .zx-start-modal-open włącza flex) - ustalone z
   Pawłem 2026-09-05. z-index:900 (NIE 9999 jak .zx-cover-modal) - ten
   modal celowo nie otwiera dużego podglądu covera (patrz komentarz w
   szablonie przy .zx-kurs-bar-cover w tym modalu), więc nie ma potrzeby
   rywalizować o warstwę z .zx-cover-modal. */
/* Element ZAWSZE jest w display:flex (nie display:none) - widocznością
   steruje opacity/visibility, bo "display" nie podlega przejściom CSS.
   Dzięki temu blur (backdrop-filter) i przyciemnienie tła faktycznie się
   animują przy otwieraniu/zamykaniu, zamiast włączać/wyłączać się na
   twardo. pointer-events:none blokuje kliknięcia przez zamkniętą (ale
   wciąż obecną w layoucie jako fixed, więc niezajmującą miejsca) zasłonę.
   visibility z opóźnieniem (transition-delay) usuwa element z drzewa
   dostępności/tabulacji DOPIERO po zakończeniu animacji zamykania - przy
   otwieraniu włącza się natychmiast (delay 0s), żeby blur był widoczny od
   razu. */
.zx-start-modal {
	display: flex;
	position: fixed;
	inset: 0;
	z-index: 900;
	background-color: rgba(255, 255, 255, 0.15);
	align-items: center;
	justify-content: center;
	padding: 1rem;
	backdrop-filter: blur(0);
    -webkit-backdrop-filter: blur(0);
	opacity: 0;
	visibility: hidden;
	pointer-events: none;
	transition: opacity 0.25s ease, backdrop-filter 0.25s ease, -webkit-backdrop-filter 0.25s ease, visibility 0s linear 0.25s;
}

/* Light mode: zasłona PRZYCIEMNIA (jak typowy modal) - ramka ma jasne tło
   (--color-bg-main w light mode), więc kontrastuje z ciemniejszym tłem
   strony pod spodem. W dark mode (reguła wyżej, domyślny motyw) jest
   odwrotnie: ramka ma CIEMNE tło, więc przyciemniona zasłona zlewałaby
   się z nią bez widocznej granicy między oknem a resztą strony - zamiast
   tego zasłona ROZJAŚNIA, żeby ciemna ramka odcinała się od tła -
   błąd zgłoszony przez Pawła 2026-09-06. */
[data-theme="light"] .zx-start-modal {
	background-color: rgba(0, 0, 0, 0.6);
}

.zx-start-modal.zx-start-modal-open {
	opacity: 1;
	visibility: visible;
	pointer-events: auto;
	backdrop-filter: blur(0.25rem);
	-webkit-backdrop-filter: blur(0.25rem);
	transition: opacity 0.25s ease, backdrop-filter 0.25s ease, -webkit-backdrop-filter 0.25s ease, visibility 0s linear 0s;
}

/* Szerokość 21.5rem, BEZ paddingu na samej ramce (patrz .zx-start-modal-header/
   -body niżej - padding:1rem tam zamiast tu) - ramka to teraz WYŁĄCZNIE
   scrollujący się kontener (overflow-y:auto), a header wewnątrz niej jest
   position:sticky, więc musi sam sięgać do samej górnej krawędzi ramki
   (top:0), żeby faktycznie "przykleić się" bez szczeliny nad sobą przy
   przewijaniu - ustalone z Pawłem 2026-09-05.

   .zx-start-modal-body ma padding:1rem z każdej strony -> treść w środku
   (m.in. .zx-kurs-grid) ma dokładnie 19.5rem, mieści się w zakresie
   minmax(18.5rem, 1fr) paska (patrz sekcja PASEK wyżej), więc siatka sama
   z siebie układa jedną kolumnę bez dodatkowych reguł. max-height +
   overflow-y:auto na ramce - lista bywa dłuższa niż ekran, ramka
   scrolluje się NIEZALEŻNIE od reszty strony (position:fixed nie
   przewija się razem z tłem pod spodem). */
.zx-start-modal-frame {
	position: relative;
	width: 21.5rem;
	max-width: 100%;
	max-height: calc(100dvh - 2rem);
	overflow-y: auto;
	box-sizing: border-box;
	border-radius: 0.75rem;
	background-color: var(--color-bg-main);
	box-shadow: var(--shadow-md);
}

/* Nagłówek (tytuł + X) PRZYKLEJONY do góry ramki podczas przewijania listy
   pod spodem - position:sticky wewnątrz scrollującego się .zx-start-modal-frame
   (ten sam trik co .sticky-shadow w 03_base.css). Własne tło (KONIECZNE -
   inaczej przewijana treść "prześwitywałaby" przez sticky header) +
   border-bottom jako wizualny separator od reszty. z-index:2 - nad
   zawartością body podczas przewijania. */
.zx-start-modal-header {
	position: sticky;
	top: 0;
	z-index: 2;
	display: flex;
	align-items: center;
	justify-content: space-between;
	gap: 0.5rem;
	padding: 1rem;
	background-color: var(--color-bg-main);
	border-bottom: 0.0625rem solid var(--color-border);
	border-radius: 0.75rem 0.75rem 0 0;
}

.zx-start-modal-title {
	margin: 0;
	font-size: 1.15rem;
	font-weight: 800;
	color: var(--color-text);
}

.zx-start-modal-close {
	flex-shrink: 0;
	width: 2rem;
	height: 2rem;
	display: flex;
	align-items: center;
	justify-content: center;
	background: none;
	border: none;
	padding: 0;
	color: var(--color-icon);
	font-size: 1.5rem;
	cursor: pointer;
	transition: color 0.15s ease;
}

.zx-start-modal-close:hover {
	color: var(--color-primary);
}

.zx-start-modal-body {
	padding: 1rem;
}

.zx-start-modal-gender-label {
	margin: 0 0 1rem 0;
	font-size: 0.95rem;
	font-weight: 600;
	color: var(--color-text);
	text-align: center;
}

.zx-start-modal-gender-buttons {
	display: flex;
	gap: 0.75rem;
}

.zx-start-modal-gender-btn {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	padding: 1.25rem 0.5rem;
	box-sizing: border-box;
	border: 0.0625rem solid var(--color-border);
	border-radius: 0.75rem;
	background-color: var(--color-bg-surface-alt);
	color: var(--color-text);
	font-size: 0.95rem;
	font-weight: 600;
	cursor: pointer;
	transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.zx-start-modal-gender-btn iconify-icon {
	font-size: 2.25rem;
	color: var(--color-icon);
	transition: color 0.15s ease;
}

.zx-start-modal-gender-btn:hover {
	background-color: var(--color-primary);
	border-color: var(--color-primary);
	color: var(--color-primary-contrast);
}

.zx-start-modal-gender-btn:hover iconify-icon {
	color: var(--color-primary-contrast);
}

/* Dwie grupy wyników (solo/w parach, patrz komentarz w szablonie przy
   .zx-start-modal-group) - odstęp między nimi TYLKO gdy obie widoczne
   naraz (+ zamiast margin na obu, żeby chowana przez JS grupa (hidden)
   nie zostawiała po sobie martwego odstępu). */
.zx-start-modal-group + .zx-start-modal-group {
	margin-top: 1.5rem;
}

.zx-start-modal-group-title {
	margin: 0 0 0.5rem 0;
	font-size: 0.85rem;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.03rem;
	color: var(--color-text-dimmed);
}

/* Wygląd (tło, kolor, padding, narożne "łapki") dają klasy .alert
   .alert-success z 05_forms.css - CELOWO alert, nie własny styl na
   twardym tle .color-primary jak poprzednio: na twardym tle notka
   wyglądała jak klikalny przycisk, co myliło (zgłoszone przez Pawła
   2026-09-05). Tu zostaje WYŁĄCZNIE layout ikona+tekst (flex) specyficzny
   dla tego miejsca - ikona + tekst (<span id="...Text">) jako OSOBNE
   elementy w szablonie, JS podmienia tylko tekst (odmiana przez płeć,
   patrz zxStartApplyFiltr()), ikona zostaje na stałe. */
.zx-start-modal-group-note {
	align-items: center;
	gap: 0.5rem;
}

/* display:flex osobno, tylko gdy NIE ma atrybutu [hidden] - inaczej
   `display: flex` na .zx-start-modal-group-note nadpisuje domyślne
   `display: none` z [hidden] (ten sam znany problem co gdzie indziej w
   projekcie: "display: flex overrides [hidden]") - błąd znaleziony przez
   Pawła 2026-09-05: notka renderowała się (pusta albo ze STARYM tekstem
   z poprzedniego otwarcia modala) mimo hidden=true ustawianego w JS dla
   kategorii PARA (patrz zxStartApplyFiltr() w szablonie). */
.zx-start-modal-group-note:not([hidden]) {
	display: flex;
}

.zx-start-modal-group-note-icon {
	flex-shrink: 0;
	font-size: 1.25rem;
}

/* .zx-kurs-grid/.zx-kurs-empty mają domyślnie własny margines 1rem z
   boków (patrz sekcje wyżej) - w tym modalu zbędny, bo .zx-start-modal-body
   ma już swój padding:1rem dokoła całej treści (dublowałby się na 2rem
   łącznie, zwężając pasek poniżej zakładanych 18.5rem-22.5rem). */
.zx-start-modal-results .zx-kurs-grid,
.zx-start-modal-results .zx-kurs-empty {
	width: 100%;
	margin: 0;
}

.zx-start-modal-results .zx-kurs-empty {
	text-align: center;
}

/* ======================== */
/* === KARTA "LEAD" (ZBIERAMY GRUPĘ) === */
/* ======================== */

/* Zaczep dla nalepki - position:relative na CAŁYM .zx-kurs-item (nie tylko
   .zx-kurs-card), żeby nalepka była widoczna w tym samym miejscu zarówno
   przy zwiniętej, jak i rozwiniętej karcie (rozwinięcie dokłada
   .zx-kurs-description POD kartą, nie rusza samej .zx-kurs-card). */
.zx-kurs-item-lead {
	position: relative;
}

.zx-kurs-lead-sticker {
	position: absolute;
	top: 0.5rem;
	left: 0rem;
	z-index: 5;
	transform: rotate(20deg);
	transform-origin: left top;

	display: block;
	padding: 0.298rem 0.744rem;
	border: 0.2rem solid var(--color-error);
	border-radius: 0.372rem;
	background-color: #FFFFFF;

	color: var(--color-error);
	font-size: 0.818rem;
	font-weight: 800;
	line-height: 1.2;
	text-align: center;
	text-transform: uppercase;
	white-space: nowrap;

	box-shadow: var(--shadow-sm);
}

.zx-kurs-lead-sticker:hover {
	color: #FFFFFF;
	background-color: var(--color-error);
}

/* ======================== */
/* ===  KOLUMNA IKON     === */
/* ======================== */

.zx-kurs-icons {
	width: 2.25rem;
	flex-shrink: 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: space-between;
	padding: 0.25rem;
	border-left: 0.0625rem solid var(--color-border);
}

.zx-kurs-icons-top,
.zx-kurs-icons-bottom {
	display: flex;
	flex-direction: column;
	align-items: center;
}

.zx-kurs-icon {
	font-size: 1.4rem;
	color: var(--color-icon);
	margin: 0.3rem;
}

.zx-kurs-icon-btn {
	display: flex;
	align-items: center;
	justify-content: center;
	margin: 0.3rem;
	font-size: 1.4rem;
	color: var(--color-icon);
	cursor: pointer;
	background: none;
	border: none;
	padding: 0;
	transition: color 0.15s ease;
}

.zx-kurs-icon-btn:hover {
	color: var(--color-primary);
}

.zx-kurs-toggle-icon {
	transition: transform 0.2s ease;
}

.zx-kurs-item-open .zx-kurs-toggle-icon {
	transform: rotate(180deg);
}

.zx-kurs-item-open .zx-kurs-toggle-btn {
	color: var(--color-primary);
}

/* ======================== */
/* ===  OPIS (AKORDEON)  === */
/* ======================== */

/* Trik grid-template-rows 0fr -> 1fr zamiast max-height: rząd gridu o
   wysokości "0fr" faktycznie zajmuje zero miejsca, ale nadal jest
   animowalny (w przeciwieństwie do "auto"). Po otwarciu "1fr" rozciąga
   rząd dokładnie do wysokości realnej zawartości - niezależnie od
   długości opisu, bez potrzeby zgadywania żadnej sztywnej wartości rem
   (jak poprzednie max-height: 40rem, które obcinało dłuższe opisy). */
.zx-kurs-description {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows 0.3s ease;
}

.zx-kurs-item-open .zx-kurs-description {
	grid-template-rows: 1fr;
}

/* min-height: 0 pozwala elementowi gridu skurczyć się poniżej wysokości
   treści przy rzędzie 0fr. Sam trik gridowy zeruje wysokość TREŚCI, ale
   border i padding to część box modelu, nie treści - bez animowania ich
   razem zostałaby widoczna cienka belka (border-bottom + padding) nawet
   przy zamkniętej karcie. Dlatego padding pionowy schodzi do 0, a opacity
   do 0 chowa też border/tło - dopiero w stanie otwartym wraca normalny
   wygląd. */
.zx-kurs-description-inner {
	min-height: 0;
	overflow: hidden;
	padding: 0 1rem;
	border: 0.0625rem solid var(--color-border);
	border-top: none;
	background-color: var(--color-bg-surface);
	opacity: 0;
	transition: padding 0.3s ease, opacity 0.2s ease;
}

.zx-kurs-item-open .zx-kurs-description-inner {
	padding: 1rem;
	opacity: 1;
}

/* Zabezpieczenie dodatkowe (poza właściwą przyczyną - patrz min-width:0 na
   .zx-kurs-item niżej): wymusza, że opis zawsze zajmuje dokładnie 100%
   przydzielonej kolumny i łamie nawet bardzo długie słowa, zamiast
   pozwolić im rozpychać layout. */
.zx-kurs-description-inner.prose {
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	overflow-wrap: break-word;
}

/* ======================== */
/* ===   META (TERMIN)   === */
/* ======================== */

/* Blok widoczny nad opisem kursu (rozwinięty akordeon): termin + liczba
   lekcji tego dnia, wyśrodkowane, a pod spodem dwie pigułki (typ kursu,
   warunki zapisu). Oddzielone linią od właściwego opisu poniżej. */
.zx-kurs-meta {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.75rem;
	text-align: center;
	margin-bottom: 1.5rem;
	padding-bottom: 1.5rem;
	border-bottom: 0.0625rem solid var(--color-border);
}

.zx-kurs-meta-termin {
	font-size: 1.05rem;
	font-weight: 600;
	color: var(--color-text);
}

.zx-kurs-meta-tags {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 0.5rem;
}

.zx-kurs-meta-tag {
	display: inline-flex;
	align-items: center;
	gap: 0.3rem;
}

.zx-kurs-meta-tag iconify-icon {
	font-size: 1rem;
}

/* ======================== */
/* ===   CTA ZAPISU      === */
/* ======================== */

.zx-kurs-cta-wrap {
	display: flex;
	justify-content: center;
	margin-top: 1.5rem;
}

.zx-kurs-cta {
	width: 100%;
	max-width: 20.5rem;
}

/* Napis "Grupa zamknięta" (brak CTA) - specyficzność ".prose .zx-kurs-cta-text"
   (dwie klasy) jest wyższa niż ".prose p" (klasa+element) z 06_prose.css,
   więc nadpisuje domyślny wygląd akapitu bez !important. Celowo NIE ma
   wyglądu przycisku (border/tło/cień) - to świadoma decyzja, żeby nie
   sugerować klikalnej akcji tam, gdzie żadna nie jest możliwa. */
.prose .zx-kurs-cta-text {
	margin-top: 1.5rem;
	margin-bottom: 0;
	text-align: center;
	font-weight: 800;
	text-transform: uppercase;
	font-size: 0.85rem;
	letter-spacing: 0.05rem;
	color: var(--color-text-muted);
}

/* ======================== */
/* ===  MODAL COVERA     === */
/* ======================== */

/* Pełnoekranowe tło - domyślnie ukryte (display:none), JS dodaje klasę
   .zx-cover-modal-open, która włącza display:flex (potrzebne display:flex
   żeby wyśrodkować .zx-cover-modal-frame - samo display:none wystarczyłoby
   do ukrycia, ale flex jest potrzebny dopiero PO otwarciu, stąd dwie
   osobne reguły zamiast jednej). */
.zx-cover-modal {
	display: none;
	position: fixed;
	inset: 0;
	z-index: 9999;
	background-color: rgba(0, 0, 0, 0.85);
	align-items: center;
	justify-content: center;
}

.zx-cover-modal.zx-cover-modal-open {
	display: flex;
}

/* Rozmiar (width/height) ustawia JS na sztywno w pikselach PRZED
   ustawieniem src obrazka (patrz zxKursComputeCoverModalSize() w
   szablonie) - stąd brak width/height tutaj. Liczony z proporcji
   relacja/event, więc ramka ma docelowy rozmiar OD RAZU, bez "skoku"
   layoutu gdy obrazek się doładuje - stąd też tło i widoczny loader
   (poniżej), żeby to nie było puste, ciemne pole podczas ładowania.
   overflow:hidden przycina obrazek (object-fit:cover) do zaokrąglonych
   rogów ramki. */
.zx-cover-modal-frame {
	position: relative;
	overflow: hidden;
	border-radius: 0.5rem;
	background-color: var(--color-bg-surface-alt);
	box-shadow: var(--shadow-md);
}

/* Obrazek wypełnia CAŁĄ ramkę (ramka ma już policzone, poprawne proporcje -
   patrz wyżej), object-fit:cover zabezpiecza przed ewentualnym,
   milimetrowym niedopasowaniem z zaokrągleń. Fade-in (opacity 0 -> 1) po
   załadowaniu (klasa .zx-cover-modal-img-loaded dodawana w JS przy
   img.onload) - bez tego obrazek "wyskakiwałby" na twardo w trakcie
   dekodowania. */
.zx-cover-modal-img {
	display: block;
	width: 100%;
	height: 100%;
	object-fit: cover;
	opacity: 0;
	transition: opacity 0.25s ease;
}

.zx-cover-modal-img.zx-cover-modal-img-loaded {
	opacity: 1;
}

/* Wskaźnik ładowania - widoczny domyślnie (JS chowa go w img.onload/onerror),
   wyśrodkowany nad tłem ramki (.zx-cover-modal-frame ma już właściwy,
   docelowy rozmiar, więc spinner stoi dokładnie tam, gdzie zaraz pojawi
   się obrazek). */
.zx-cover-modal-loader {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
	color: var(--color-text-muted);
	font-size: 2.5rem;
}

.zx-cover-modal-loader-icon {
	animation: zx-cover-modal-spin 1s linear infinite;
}

@keyframes zx-cover-modal-spin {
	from { transform: rotate(0deg); }
	to { transform: rotate(360deg); }
}

/* Przycisk zamknięcia (X) - NA obrazku, prawy górny róg, kolor biały na
   sztywno (nie zmienna motywu) - wymaganie "biały na obrazku" niezależnie
   od jasnego/ciemnego motywu strony, bo tłem przycisku jest tu ZAWSZE
   zdjęcie, nie powierzchnia UI. text-shadow poprawia czytelność na jasnych
   fragmentach zdjęcia (bez tego biały X potrafi zniknąć na jasnym niebie
   itp.). */
.zx-cover-modal-close {
	position: absolute;
	top: 0.75rem;
	right: 0.75rem;
	width: 2.5rem;
	height: 2.5rem;
	display: flex;
	align-items: center;
	justify-content: center;
	background: none;
	border: none;
	padding: 0;
	color: #FFFFFF;
	font-size: 1.75rem;
	cursor: pointer;
	text-shadow: 0 0 0.375rem rgba(0, 0, 0, 0.7);
	z-index: 1;
}

.zx-cover-modal-close iconify-icon {
	font-size: 1.75rem;
}

/* Etykieta "START: ..." - widoczna TYLKO w trybie "event" (patrz JS,
   zxKursDisplayCoverInModal() przełącza klasę na .zx-cover-modal-frame).
   Kolor/cień skopiowane z .zx-cover-modal-close wyżej (ten sam problem:
   czytelny biały tekst na DOWOLNYM zdjęciu w tle) - nie mam pliku z Hero,
   więc nie mogłem literalnie skopiować stamtąd wartości cienia; jeśli Hero
   używa innej, podmień tu text-shadow na tę samą wartość. */
.zx-cover-modal-start {
	display: none;
	position: absolute;
	top: 0.5rem;
	left: 0.75rem;
	max-width: calc(100% - 1.5rem);
	font-size: 1.5rem;
	font-weight: 800;
	color: #FFFFFF;
	text-shadow: 0 0 0.375rem rgba(0, 0, 0, 0.7);
	z-index: 1;
}

.zx-cover-modal-frame-event .zx-cover-modal-start {
	display: block;
}

/* ======================== */
/* ===  NAWIGACJA (< >)  === */
/* ======================== */

/* Półprzezroczyste przyciski na bokach obrazka - przełączają na
   poprzedni/następny kurs z coverem (zxKursShowCoverModalStep() w JS).
   JS chowa je (display:none), gdy na stronie jest tylko jeden kurs z
   coverem - nawigacja wtedy nie ma sensu. */
.zx-cover-modal-nav {
	position: absolute;
	top: 50%;
	transform: translateY(-50%);
	width: 2.75rem;
	height: 2.75rem;
	border-radius: 50%;
	display: flex;
	align-items: center;
	justify-content: center;
	background-color: rgba(0, 0, 0, 0.35);
	border: none;
	padding: 0;
	color: #FFFFFF;
	font-size: 1.75rem;
	cursor: pointer;
	transition: background-color 0.2s ease;
	z-index: 1;
}

.zx-cover-modal-nav:hover {
	background-color: rgba(0, 0, 0, 0.55);
}

.zx-cover-modal-nav-prev {
	left: 0.75rem;
}

.zx-cover-modal-nav-next {
	right: 0.75rem;
}

/* ======================== */
/* ===  CTA "ZAPISZ SIĘ" === */
/* ======================== */

/* Pozycja zależy od trybu ramki (klasa przełączana w JS wg aktualnie
   wyświetlanego typu covera - "relacja" albo "event", patrz
   zxKursDisplayCoverInModal()), ustalone z Pawłem 2026-09-03:
   - na "relacji" (portret 9:16): na środku, 1rem od DOLNEJ krawędzi.
   - na "evencie" (poziomy 1920:1005): tuż obok X, wyrównany z nim w osi
     (ten sam top i ta sama wysokość co .zx-cover-modal-close, żeby oba
     przyciski trzymały wspólną linię). */
.zx-cover-modal-signup {
	position: absolute;
	z-index: 1;
	white-space: nowrap;
}

.zx-cover-modal-frame-relacja .zx-cover-modal-signup {
	left: 50%;
	bottom: 1rem;
	transform: translateX(-50%);
}

.zx-cover-modal-frame-event .zx-cover-modal-signup {
	top: 0.75rem;
	/* 0.75rem (odstęp X od krawędzi) + 2.5rem (szerokość X) + 0.5rem
	   (odstęp między przyciskami) = 3.75rem od prawej krawędzi ramki. */
	right: 3.75rem;
	height: 2.5rem;
	padding: 0 1.25rem;
	display: inline-flex;
	align-items: center;
}

/* ======================== */
/* ===  NASI INSTRUKTORZY  === */
/* ======================== */

/* Sekcja na końcu strony głównej (po FAQ) - "ściana" małych, klikalnych
   awatarów WSZYSTKICH obecnie zatrudnionych instruktorów (instruktor_status
   = 'Obecny'), bez podpisów imion - patrz $instruktorzyObecni w szablonie.
   Umieszczona tu (nie w 08_home.css), bo kontekstowo sąsiaduje z resztą
   sekcji strony głównej w tym pliku i już ma gotowy wzorzec .zx-kurs-avatar
   do naśladowania. */
.zx-instruktorzy-section {
	width: 100%;
	padding: 4rem 0;
}

.zx-instruktorzy-title {
	width: calc(100% - 2rem);
	margin: 0 1rem 2rem 1rem;
	font-size: 1.75rem;
	font-weight: 800;
	color: var(--color-text);
	text-align: center;
}

.zx-instruktorzy-grid {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	justify-content: center;
	gap: 0.25rem;
}

/* 3.5rem = ok. 56px przy standardowym rem - powyżej minimalnego, zalecanego
   rozmiaru strefy dotykowej (44px/2.75rem wg WCAG), więc małe kółka są
   nadal wygodnie klikalne na telefonie mimo braku podpisów. title=
   (atrybut na <a> w szablonie) pokazuje imię i nazwisko w tooltipie na
   hover - jedyny "podpis" w tej sekcji, celowo bez widocznego tekstu. */
/* position:relative - potrzebne jako kontekst pozycjonowania dla nałożonego
   imienia (.zx-instruktorzy-avatar-imie) niżej. Celowo BEZ overflow:hidden
   - samo zdjęcie ma już własne border-radius:50% (inline style z
   InstruktorHtmlHelper::renderAvatar()), więc nie potrzebuje obcinania od
   rodzica, a dzięki temu dłuższe imię może swobodnie wystawać poza okrąg
   zamiast być brutalnie ucięte w połowie litery. */
.zx-instruktorzy-avatar {
	position: relative;
	display: flex;
	align-items: center;
	justify-content: center;
	width: 3.5rem;
	height: 3.5rem;
	flex-shrink: 0;
	border-radius: 50%;
	background-color: var(--color-bg-surface-alt);
	box-shadow: 0 0 0 0.0625rem transparent;
	transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.zx-instruktorzy-avatar:hover {
	box-shadow: 0 0 0 0.125rem var(--color-primary);
	transform: scale(1.06);
}

.zx-instruktorzy-avatar-fallback {
	font-size: 1.75rem;
	color: var(--color-icon);
}

/* Imię instruktora nałożone na zdjęcie, 0.5rem od dolnej krawędzi awatara -
   biały tekst z cieniem (ten sam wzorzec co etykiety na coverach w modalu,
   patrz .zx-cover-modal-close/.zx-cover-modal-start wyżej) dla czytelności
   niezależnie od jasności zdjęcia pod spodem. pointer-events:none - to
   czysto dekoracyjna etykieta, klik ma trafiać w cały awatar (<a>), nie w
   sam tekst. */
.zx-instruktorzy-avatar-imie {
	position: absolute;
	bottom: 0.5rem;
	left: 50%;
	transform: translateX(-50%);
	font-size: 0.55rem;
	font-weight: 800;
	line-height: 1;
	text-transform: uppercase;
	color: #FFFFFF;
	text-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.8);
	white-space: nowrap;
	pointer-events: none;
	z-index: 1;
}


/* --- File: 10_faq.css --- */
/**
 * 10_faq.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-09-12 (scroll-margin-top: powrót do 4rem)
 *
 * Sekcja FAQ na końcu strony głównej - cztery "działy" (nagłówki,
 * nieklikalne, wizualnie wyróżnione akcentem koloru), każdy z listą pytań.
 * Każde pytanie to osobny element akordeonu (zxFaqToggle() w ____zx_template.php)
 * - tak jak w kartach kursów (09_kurs.css), tylko JEDNO pytanie może być
 * otwarte naraz w całej sekcji; otwarcie kolejnego zwija poprzednie. Ten
 * sam sprawdzony trik CSS co w kartach kursów (grid-template-rows: 0fr ->
 * 1fr + padding/opacity zamiast max-height), ale jako osobne klasy
 * .zx-faq-*, żeby nie mieszać z kodem kursów.
 */

.zx-faq-section {
	width: 100%;
	padding: 4rem 0;
}

.zx-faq-title {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	font-size: 1.75rem;
	font-weight: 800;
	color: var(--color-text);
}

.zx-faq-intro {
	width: calc(100% - 2rem);
	margin: 0.75rem 1rem 2rem 1rem;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--color-text-dimmed);
}

/* ======================== */
/* ===      DZIAŁ        === */
/* ======================== */

/* Odstęp między działami - większy niż wewnątrz działu (odstępy między
   pytaniami), żeby wizualnie grupować pytania w danym dziale. */
.zx-faq-dzial {
	width: calc(100% - 2rem);
	margin: 0 1rem 3rem 1rem;
}

.zx-faq-dzial:last-child {
	margin-bottom: 0;
}

/* Akcent koloru z lewej strony (ten sam wzorzec co .prose-cta w
   06_prose.css) - to jest "wyróżnienie" działu, o które prosił Paweł:
   nagłówek działu wyraźnie odcina się od zwykłej treści/pytań poniżej. */
.zx-faq-dzial-header {
	display: flex;
	flex-direction: column;
	gap: 0.25rem;
	padding: 0.25rem 0 0.25rem 1rem;
	margin-bottom: 0.5rem;
	border-left: 0.25rem solid var(--color-primary);
}

.zx-faq-dzial-eyebrow {
	font-size: 0.85rem;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.05rem;
	color: var(--color-primary);
}

.zx-faq-dzial-title {
	font-size: 1.35rem;
	font-weight: 800;
	color: var(--color-text);
}

/* ======================== */
/* ===  PYTANIE (ITEM)   === */
/* ======================== */

/* scroll-margin-top: przesunięcie punktu przewinięcia w dół, tak żeby
   pytanie po scrollIntoView() (JS, zxFaqToggle() w ____zx_template.php)
   nie chowało się pod sticky paskiem nawigacji (07_navigation.css) - 4rem
   (wysokość paska, ustalone z Pawłem). */
.zx-faq-item {
	scroll-margin-top: 4rem;
	border-bottom: 0.0625rem solid var(--color-border);
}

.zx-faq-item:first-of-type {
	border-top: 0.0625rem solid var(--color-border);
}

.zx-faq-question {
	width: 100%;
	display: flex;
	align-items: center;
	gap: 0.5rem;
	padding: 1rem 0;
	background: none;
	border: none;
	text-align: left;
	cursor: pointer;

	/* Pytania ZAWSZE pogrubione (wymaganie Pawła "elegancko, łatwo się
	   czyta") - to jedna, spójna reguła, a nie ręczne <strong> w treści. */
	font-size: 1.2rem;
	font-weight: 800;
	color: var(--color-text);
}

/* Numer pytania (ciągła numeracja 1-11 przez wszystkie działy, patrz
   $faqNumer w szablonie) - lekko przygaszony, żeby nie konkurował wizualnie
   z treścią pytania, ale ułatwiał orientację/odwoływanie się do numeru. */
.zx-faq-question-numer {
	flex-shrink: 0;
	color: var(--color-text-dimmed);
}

.zx-faq-question-text {
	flex: 1;
}

.zx-faq-question:hover {
	color: var(--color-primary);
}

.zx-faq-toggle-icon {
	flex-shrink: 0;
	font-size: 1.5rem;
	color: var(--color-icon);
	transition: transform 0.2s ease, color 0.2s ease;
}

.zx-faq-item-open .zx-faq-toggle-icon {
	transform: rotate(180deg);
	color: var(--color-primary);
}

/* ======================== */
/* ===  ODPOWIEDŹ        === */
/* ======================== */

.zx-faq-answer {
	display: grid;
	grid-template-rows: 0fr;
	transition: grid-template-rows 0.3s ease;
}

.zx-faq-item-open .zx-faq-answer {
	grid-template-rows: 1fr;
}

/* min-height:0 - pozwala elementowi gridu skurczyć się poniżej wysokości
   treści przy rzędzie 0fr (ten sam mechanizm co .zx-kurs-description-inner
   w 09_kurs.css). Padding-bottom i opacity idą do zera razem z rzędem
   gridu, zamiast samego overflow:hidden - bez tego przy zamkniętym
   pytaniu byłaby widoczna cienka "belka" (ten sam błąd, który już raz
   naprawiałem w kartach kursów). */
.zx-faq-answer-inner {
	min-height: 0;
	overflow: hidden;
	padding-bottom: 0;
	opacity: 0;
	transition: padding-bottom 0.3s ease, opacity 0.2s ease;
}

.zx-faq-item-open .zx-faq-answer-inner {
	padding-bottom: 1.5rem;
	opacity: 1;
}

/* Odpowiedzi używają klasy .prose (06_prose.css) dla stylu akapitów/list/
   linków - ale .prose ma domyślnie font-size:1rem, font-weight:400 na <p>,
   co jest OK; jedyna lokalna poprawka to nieco mniejszy odstęp pod
   ostatnim elementem (.prose p domyślnie ma margin-bottom - zostawiamy,
   bo padding-bottom z .zx-faq-answer-inner i tak domyka spację na dole). */
.zx-faq-answer-inner.prose {
	width: 100%;
	max-width: 100%;
	box-sizing: border-box;
	overflow-wrap: break-word;
}


/* --- File: 11_cennik.css --- */
/**
 * 11_cennik.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-08-27 (ikonki korzyści powiększone x1.5: 3rem -> 4.5rem)
 *
 * Sekcja "Cennik" na stronie głównej (między kartami kursów a FAQ) -
 * streszczenie pełnego cennika (tondance.pl/cennik): pakiety lekcji,
 * 4 "korzyści" (własne ikonki SVG), pasek logo kart partnerskich, CTA do
 * pełnego cennika. Osobny plik (nie 09_kurs.css) - to samodzielna sekcja
 * strony głównej, nie część systemu kart kursów.
 */

.zx-cennik-section {
	width: 100%;
	padding: 4rem 0;
}

.zx-cennik-title {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	font-size: 1.75rem;
	font-weight: 800;
	color: var(--color-text);
	text-align: center;
}

.zx-cennik-intro {
	width: calc(100% - 2rem);
	margin: 0.75rem 1rem 2.5rem 1rem;
	font-size: 1rem;
	line-height: 1.5;
	color: var(--color-text-dimmed);
	text-align: center;
}

/* ======================== */
/* ===     PAKIETY       === */
/* ======================== */

.zx-cennik-pakiety {
	width: calc(100% - 2rem);
	margin: 0 1rem 3rem 1rem;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 1rem;
}

.zx-cennik-pakiet {
	display: flex;
	flex-direction: column;
	align-items: center;
	width: 9.5rem;
	text-align: center;
	padding: 0.5rem;
}

.zx-cennik-pakiet-img {
	width: 100%;
	height: auto;
	border-radius: 0.5rem;
	border: 0.0625rem solid var(--color-border);
	box-shadow: var(--shadow-sm);
	margin-bottom: 0.5rem;
}

.zx-cennik-pakiet-info {
	display: flex;
	flex-direction: column;
	gap: 0.15rem;
}

.zx-cennik-pakiet-lekcje {
	font-size: 0.85rem;
	color: var(--color-text-dimmed);
}

.zx-cennik-pakiet-cena {
	font-size: 1.35rem;
	font-weight: 800;
	color: var(--color-text);
}

.zx-cennik-pakiet-cena-jednostkowa {
	font-size: 0.8rem;
	color: var(--color-text-muted);
}

/* ======================== */
/* ===     KORZYŚCI      === */
/* ======================== */

.zx-cennik-korzysci {
	width: calc(100% - 2rem);
	margin: 0 1rem 3rem 1rem;
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	gap: 1.5rem;
}

.zx-cennik-korzysc {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 0.5rem;
	width: 10.5rem;
	text-align: center;
}

/* SVG inline w szablonie (nie CSS mask, nie <img>) - dzięki temu w jednym
   pliku mogą współistnieć DWA rodzaje koloru: fill="currentColor" (na
   ścieżkach, które w oryginale były białe) dziedziczy stąd `color`, więc
   podąża za motywem light/dark - i fill="#FFCC00" (żółte akcenty), który
   zostaje na sztywno niezależnie od koloru tekstu. CSS mask nie potrafiłby
   tego rozróżnić (spłaszcza cały kształt do JEDNEGO koloru). */
.zx-cennik-korzysc-ikona {
	display: block;
	width: 4.5rem;
	height: 4.5rem;
	color: var(--color-icon);
}

.zx-cennik-korzysc-ikona svg {
	display: block;
	width: 100%;
	height: 100%;
}

.zx-cennik-korzysc-tekst {
	font-size: 0.85rem;
	font-weight: 600;
	color: var(--color-text-dimmed);
	line-height: 1.3;
}

/* ======================== */
/* ===  KARTY PARTNERSKIE  === */
/* ======================== */

.zx-cennik-karty-wrap {
	width: calc(100% - 2rem);
	margin: 0 1rem 3rem 1rem;
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.25rem;
}

.zx-cennik-karty-intro {
	max-width: 40rem;
	font-size: 0.95rem;
	line-height: 1.5;
	color: var(--color-text-dimmed);
	text-align: center;
}

.zx-cennik-karty {
	display: flex;
	flex-wrap: wrap;
	justify-content: center;
	align-items: center;
	gap: 0.75rem;
}

.zx-cennik-karta-img {
	height: 2.75rem;
	width: auto;
	border-radius: 0.35rem;
	border: 0.0625rem solid var(--color-border);
}

/* ======================== */
/* ===       CTA         === */
/* ======================== */

.zx-cennik-cta-wrap {
	width: calc(100% - 2rem);
	margin: 0 1rem;
	display: flex;
	justify-content: center;
}


/* --- File: 12_footer.css --- */
/**
 * 12_footer.css
 * ZYXAK WWW by Paweł Pijanowski dla TONdance Szkoła Tańca w Łodzi
 * 2026-09-06
 *
 * Stopka - komponent WSPÓLNY dla wszystkich stron WWW (nie tylko
 * kursy-dla-poczatkujacych.php), wizualnie wzorowany na stopce maili
 * (WiadomoscEmailHtmlHelper.php): ciemne tło, rząd ikon kontaktowych
 * zamiast linków tekstowych - ustalone z Pawłem 2026-09-06. Tło
 * --color-border-strong (na życzenie Pawła, 2026-09-06) - nie mam pliku
 * 02_colors.css, więc ufam podanej nazwie zmiennej bez weryfikacji.
 *
 * KOLOR TEKSTU NA CIEMNYM TLE: hex na sztywno (#F9FAFB / #D1D5DB) - te
 * same wartości, które WiadomoscEmailHtmlHelper.php dokumentuje jako
 * "kolory DARK MODE z 2_colors.css" (tekst ma zostać jasny niezależnie
 * od aktywnego motywu strony, tak jak w mailu). Nie znam nazwy właściwej
 * zmiennej CSS na "tekst zawsze jasny na ciemnym tle" (jeśli taka
 * istnieje, np. używana w 07_navigation.css) - PODMIEŃ, jeśli istnieje.
 */

.zx-footer {
	width: 100%;
	margin-bottom: 6rem;
	background-color: var(--color-border-strong);
	color: #F9FAFB;
}

.zx-footer a {
	color: #F9FAFB;
}

.zx-footer a:hover {
	color: var(--color-primary);
}

.zx-footer-top {
	display: flex;
	align-items: center;
	justify-content: space-between;
	flex-wrap: wrap;
	gap: 1rem;
	padding: 1.5rem 1rem;
	border-bottom: 0.0625rem solid rgba(255, 255, 255, 0.15);
}

/* Logo - ten sam SVG co ZxNav::renderLogoSvg() (viewBox 0 0 650.72 209.05,
   proporcje ok. 3.11:1) - height ustala rozmiar, width:auto zachowuje
   proporcje. display:block na linku (nie inline) - inaczej <a> dostaje
   dodatkową "szczelinę" pod spodem (domyślne line-height obrazów
   inline). */
.zx-footer-logo {
	display: block;
	flex-shrink: 0;
}

/* Bez hovera - inaczej globalne .zx-footer a:hover (patrz wyżej) zmienia
   kolor na primary, co przez fill="currentColor" na wordmarku SVG
   podbarwiałoby napis TONdance na złoto przy najechaniu - kolor ma
   zostać STAŁY, tak samo jak kolorowy "wiatraczek" obok (własne hex-y,
   niezależne od hovera). */
.zx-footer-logo:hover {
	color: #F9FAFB;
}

.zx-footer-logo-svg {
	display: block;
	height: 3.375rem;
	width: auto;
}

.zx-footer-social {
	display: flex;
	align-items: center;
	gap: 0.75rem;
}

.zx-footer-social-icon {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 2.5rem;
	height: 2.5rem;
	border-radius: 50%;
	background-color: rgba(255, 255, 255, 0.1);
	font-size: 1.3rem;
	transition: background-color 0.15s ease, color 0.15s ease;
}

.zx-footer-social-icon:hover {
	background-color: var(--color-primary);
	color: #000000;
}

.zx-footer-columns {
	display: flex;
	flex-direction: row;
	flex-wrap: wrap;
	gap: 2rem;
	padding: 2rem 1rem;
}

.zx-footer-col {
	flex: 1 1 12rem;
	min-width: 0;
	display: flex;
	flex-direction: column;
	gap: 0.5rem;
}

.zx-footer-col-title {
	margin: 0 0 0.25rem 0;
	font-size: 0.8rem;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: 0.03rem;
	color: #D1D5DB;
}

.zx-footer-col p {
	margin: 0;
	font-size: 0.85rem;
	line-height: 1.5;
	color: #D1D5DB;
}

.zx-footer-col a {
	text-decoration: none;
}

.zx-footer-col a:hover {
	text-decoration: underline;
}

/* flex-direction:column nadpisuje "row" dziedziczone z klasy w-1to3 (patrz
   04_layout.css) - dwie linie (copyright + autor strony) mają zawsze
   stać jedna pod drugą, niezależnie od szerokości ekranu, a nie próbować
   zmieścić się obok siebie w rzędzie. */
.zx-footer-bottom {
	flex-direction: column;
	align-items: center;
	gap: 0.25rem;
	padding: 1rem;
	border-top: 0.0625rem solid rgba(255, 255, 255, 0.15);
}

.zx-footer-bottom p {
	margin: 0;
	font-size: 0.75rem;
	color: #D1D5DB;
	text-align: center;
}


