/* Roboto hostowane lokalnie; polskie znaki w osobnym podzbiorze. */
@font-face { font-family: 'ZP Panel Roboto'; font-style: normal; font-weight: 400; font-display: swap; src: url('../../fonts/roboto/roboto-latin-ext-400.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'ZP Panel Roboto'; font-style: normal; font-weight: 400; font-display: swap; src: url('../../fonts/roboto/roboto-latin-400.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'ZP Panel Roboto'; font-style: normal; font-weight: 600; font-display: swap; src: url('../../fonts/roboto/roboto-latin-ext-600.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'ZP Panel Roboto'; font-style: normal; font-weight: 600; font-display: swap; src: url('../../fonts/roboto/roboto-latin-600.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }
@font-face { font-family: 'ZP Panel Roboto'; font-style: normal; font-weight: 700; font-display: swap; src: url('../../fonts/roboto/roboto-latin-ext-700.woff2') format('woff2'); unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF; }
@font-face { font-family: 'ZP Panel Roboto'; font-style: normal; font-weight: 700; font-display: swap; src: url('../../fonts/roboto/roboto-latin-700.woff2') format('woff2'); unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD; }

/**
 * Zapisy.pro – Rama panelu /panel/{slug}
 *
 * Styluje WYŁĄCZNIE to, co otacza ekran: dokument, kolumnę menu na pełną wysokość okna
 * (z logo na jej szczycie), biały pasek 56 px nad treścią, <main> w dwóch wariantach
 * szerokości, stopkę, strony 403/404 i komunikat o błędzie ekranu. Wygląd samych ekranów
 * pozostaje w zp-admin.css / zp-schedule.css i NIE jest tu ruszany.
 *
 * UKŁAD — zmiana z 2026-09-28 (makieta zaakceptowana przez właściciela produktu). Menu jest
 * pełnej wysokości i niesie logo, pasek górny jest BIAŁY i stoi tylko nad treścią. Wcześniej
 * pasek był granatowy i szedł przez całą szerokość, a menu zaczynało się pod nim. Z koloru
 * paska wynikają DWIE zmiany kontrastu, obie niżej: wszystkie napisy paska są granatowe,
 * a cyan — który na granacie był kolorem pisma (rola w chipie) — zniknął z paska jako pismo
 * i został w nim wyłącznie wypełnieniem kółka z inicjałem.
 *
 * Kolory bierzemy z assets/shared/zp-tokens.css (uchwyt 'zp-tokens' jest zadeklarowany jako
 * zależność 'zp-panel' — bez niej wszystkie var(--zp-*) byłyby puste).
 *
 * Zmierzone pary kolorów użyte w tym pliku (kontrast WCAG):
 *   --zp-text  #14233a na --zp-bg #f4f6fb ......... 14,6:1  tekst treści
 *   #fff na --zp-navy #1d1c57 .................... 15,5:1  menu, przycisk główny
 *   --zp-accent #00c3f2 na --zp-navy ..............  7,4:1  akcent nazwy w menu
 *   --zp-navy #1d1c57 na --zp-accent #00c3f2 ......  7,4:1  inicjał w chipie, znak „z", pozycja aktywna
 *   #fff na --zp-navy-light #35347a ............... 10,9:1  hover przycisku
 *   --zp-accent-ink #05485c na #fff .............. 10,1:1  kod błędu 403/404, akcent nazwy na bieli
 *   --zp-navy na --zp-surface #fff ............... 15,5:1  nagłówki, linki, napisy BIAŁEGO paska
 *   --zp-text-2 #3d5068 na #fff ...................  8,3:1  opisy
 *   --zp-text-m #5b6d84 na #fff ...................  5,3:1  rola w chipie, podpis marki, stopka
 *   --zp-text-m na --zp-bg ........................  4,9:1  stopka na tle strony
 *   --zp-navy-light na #fff ....................... 10,9:1  obramowanie fokusu na bieli
 * Menu JASNE (domyślne od 2026-09-29, tło #fff, narożnik z logo granatowy):
 *   --zp-navy na #fff .............................. 15,5:1  pozycja menu
 *   --zp-text-m #5b6d84 na #fff ....................  5,3:1  nagłówek grupy
 *   --zp-navy na --zp-bg #f4f6fb ................... 14,3:1  pozycja pod kursorem
 *   --zp-navy na --zp-accent-soft #e6f8fe .......... 14,2:1  pozycja BIEŻĄCEGO ekranu (oba warianty)
 *   --zp-navy-light na #fff ........................ 10,9:1  obramowanie fokusu
 * Narożnik z logo = odwrotność menu: granatowy przy jasnym (pary jak „Menu (tło granatowe)"),
 * biały przy granatowym (--zp-navy 15,5:1, --zp-accent-ink 10,1:1, --zp-text-m 5,3:1).
 * Menu (tło granatowe --zp-navy):
 *   #e8ecf5 na --zp-navy .......................... 13,1:1  pozycja menu, przycisk „Zwiń"
 *   #aeb4d6 na --zp-navy ..........................  7,6:1  nagłówek grupy, podpis pod logo
 *   #e8ecf5 na --zp-navy-light #35347a ............  9,2:1  pozycja pod kursorem
 *   --zp-navy na --zp-accent-soft ................. 14,2:1  pozycja BIEŻĄCEGO ekranu
 *   --zp-accent na --zp-navy ......................  7,4:1  obramowanie fokusu w menu
 * Cyanu NIE używamy jako tekstu ani cienkiej ikony na bieli (2,1:1) — wyłącznie jako
 * wypełnienia i akcentu na granacie.
 *
 * @package ZP_Pro
 */

/* ================================================================ ZMIENNE RAMY */
.zp-panel {
  /* Wysokość nagłówka. KOSZT STAŁY odejmowany od harmonogramu na każdym ekranie — dlatego
     56 px, nie 64. Zmienna, a nie liczba, bo reguły niżej (i ekrany z własnym sticky)
     muszą tę wartość odjąć. */
  --zp-panel-header-h: 56px;
  /* Szerokość kolumny menu. Kolumna istnieje od zadania 3 (pusta) po to, żeby pomiar
     szerokości harmonogramu nie zmienił się po wejściu zadania 4.
     Rachunek przy 1920 CSS: 1920 - 236 (menu) - 2x20 (marginesy) = 1644 px dla treści. */
  --zp-panel-nav-w: 236px;
  /* Szerokość paska zwiniętego: tylko ikona (18 px) wyśrodkowana w polu dotyku. */
  --zp-panel-nav-w-zwinieta: 64px;
  --zp-panel-gutter: 20px;

  /* ── Kolory menu ──────────────────────────────────────────────────────────
     Dwa warianty, wybór w Ustawieniach → Ogólne → „Wygląd panelu" (opcja
     zp_panel_menu_wariant). JASNE (domyślne, makieta pulpitu 2026-09-29) — tutaj;
     GRANATOWE — klasa .zp-panel--menu-granatowe niżej, która nadpisuje WYŁĄCZNIE te
     zmienne. Reguły menu czytają tylko zmienne, więc wariant nie duplikuje żadnej reguły.
     Pozycja bieżącego ekranu w OBU wariantach wygląda tak samo: jasnoniebieskie tło,
     granatowy pogrubiony napis i pasek w cyanie przy lewej krawędzi (dekoracja, nie pismo). */
  --zp-panel-nav-bg: var(--zp-surface);
  --zp-panel-nav-txt: var(--zp-navy);                 /* 15,5:1 na bieli */
  --zp-panel-nav-txt-2: var(--zp-text-m);             /*  5,3:1 na bieli – nagłówki grup, podpis */
  --zp-panel-nav-hover: var(--zp-bg);                 /* granat na #f4f6fb: 14,3:1 */
  --zp-panel-nav-aktywne: var(--zp-accent-soft);      /* granat na #e6f8fe: 14,2:1 */
  --zp-panel-nav-aktywne-txt: var(--zp-navy);
  --zp-panel-nav-aktywne-znacznik: var(--zp-accent);  /* pasek 3 px – dekoracja */
  --zp-panel-nav-linia: var(--zp-border);             /* separatory – dekoracja */
  --zp-panel-nav-krawedz: var(--zp-border);           /* prawa krawędź białej kolumny */
  --zp-panel-nav-fokus: var(--zp-navy-light);         /* 10,9:1 na bieli */
  --zp-panel-nav-suwak: rgba(29, 28, 87, .22);
  /* Narożnik z logo jest ODWROTNOŚCIĄ menu (makieta): przy jasnym menu granatowy
     z białym logo (logo_dark), przy granatowym menu biały ze zwykłym logo. */
  --zp-panel-marka-bg: var(--zp-navy);
  --zp-panel-marka-txt: #fff;                         /* 15,5:1 na granacie – napis awaryjny */
  --zp-panel-marka-txt-2: #aeb4d6;                    /*  7,6:1 na granacie – podpis „Panel ośrodka" */
  --zp-panel-marka-akcent: var(--zp-accent);          /*  7,4:1 na granacie – „.pro" */
  --zp-panel-marka-linia: transparent;                /* granatowy blok sam odcina się od menu */
  --zp-panel-marka-fokus: var(--zp-accent);           /*  7,4:1 na granacie */
}

/* Wariant GRANATOWY menu (opcja zp_panel_menu_wariant = granatowe). Klasę na <body>
   stawia ZP_Panel_Shell::render(). Specyficzność (0,2,0) wygrywa z `.zp-panel` wyżej. */
.zp-panel.zp-panel--menu-granatowe {
  --zp-panel-nav-bg: var(--zp-navy);
  --zp-panel-nav-txt: #e8ecf5;                        /* 13,1:1 na granacie */
  --zp-panel-nav-txt-2: #aeb4d6;                      /*  7,6:1 na granacie */
  --zp-panel-nav-hover: var(--zp-navy-light);         /* #e8ecf5 na #35347a: 9,2:1 */
  --zp-panel-nav-aktywne: var(--zp-accent-soft);      /* jak w wariancie jasnym (14,2:1) */
  --zp-panel-nav-aktywne-txt: var(--zp-navy);
  --zp-panel-nav-aktywne-znacznik: var(--zp-accent);
  --zp-panel-nav-linia: rgba(255, 255, 255, .14);
  --zp-panel-nav-krawedz: transparent;
  --zp-panel-nav-fokus: var(--zp-accent);             /* 7,4:1 na granacie */
  --zp-panel-nav-suwak: rgba(255, 255, 255, .26);
  --zp-panel-marka-bg: var(--zp-surface);             /* narożnik biały, zwykłe logo */
  --zp-panel-marka-txt: var(--zp-navy);               /* 15,5:1 na bieli */
  --zp-panel-marka-txt-2: var(--zp-text-m);           /*  5,3:1 na bieli */
  --zp-panel-marka-akcent: var(--zp-accent-ink);      /* 10,1:1 na bieli */
  --zp-panel-marka-linia: var(--zp-border);
  --zp-panel-marka-fokus: var(--zp-navy-light);       /* 10,9:1 na bieli */
}

/* Granatowe menu nie potrzebuje krawędzi; przezroczysta ramka pokazywała granat obok białego narożnika. */
.zp-panel--menu-granatowe .zp-panel-nav {
  border-right-width: 0;
}

/* Stan zwinięty. Klasę na <html> ustawia skrypt inline w <head> (przed pierwszym
   malowaniem), a przełącza zp-panel.js. Zmieniamy TYLKO zmienną szerokości — układ siatki
   zostaje ten sam, więc nic się nie przebudowuje.
   Specyficzność (0,2,1) jest wyższa niż `.zp-panel` w zapytaniach medialnych na dole pliku
   (0,1,0), dlatego wybór użytkownika wygrywa z każdą szerokością progową. */
html.zp-nav-zwinieta .zp-panel { --zp-panel-nav-w: var(--zp-panel-nav-w-zwinieta); }

/* ================================================================ DOKUMENT */
html.zp-panel-html { background: var(--zp-bg); }

body.zp-panel {
  --zp-font: 'ZP Panel Roboto', Roboto, Arial, sans-serif;
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--zp-bg);
  color: var(--zp-text);
  font-family: var(--zp-font);
  font-size: var(--zp-fs);
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}
body.zp-panel *, body.zp-panel *::before, body.zp-panel *::after { box-sizing: border-box; }

/* Panel jest aplikacją: rama nie woła wp_head(), więc arkusz motywu tu nie wchodzi i nie ma
   z czym walczyć. Zerujemy tylko to, co przeglądarka daje sama. */
body.zp-panel h1, body.zp-panel h2, body.zp-panel h3 { color: var(--zp-navy); }
body.zp-panel img { max-width: 100%; }

/* Rama panelu nie woła wp_head(), więc arkusz admina (i jego .screen-reader-text) tu nie
   wchodzi — bez tej reguły nagłówki „tylko dla czytnika ekranu" wyświetlają się na widoku. */
body.zp-panel .screen-reader-text {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
  word-wrap: normal !important;
}

/* Link „Przejdź do treści" – widoczny dopiero po fokusie klawiaturą. */
.zp-panel-skip {
  position: absolute;
  left: -9999px;
  top: 0;
}
.zp-panel-skip:focus {
  left: var(--zp-space-2);
  top: var(--zp-space-2);
  z-index: 200;
  padding: 8px 14px;
  background: var(--zp-surface);
  color: var(--zp-navy);
  font-weight: 700;
  border-radius: var(--zp-r);
  box-shadow: var(--zp-sh);
}

/* ================================================================ BIAŁY PASEK (56 px)
   Pasek stoi WEWNĄTRZ kolumny treści (.zp-panel-kolumna), więc kończy się tam, gdzie zaczyna
   się menu — nie idzie przez całą szerokość okna. `top: 0` przykleja go do góry okna, bo
   kolumna menu obok jest pełnej wysokości i nic go stamtąd nie spycha.

   KONTRAST. Tło jest białe, więc każdy napis w pasku jest granatowy (15,5:1) albo przygaszony
   (--zp-text-m, 5,3:1). Cyan marki na bieli ma 2,1:1 i NIE występuje tu jako pismo ani cienka
   ikona — wyłącznie jako wypełnienie kółka z inicjałem, na którym litera jest granatowa. */
.zp-panel-header {
  flex: none;
  position: sticky;
  top: 0;
  /* Nad treścią ekranów (ich własne sticky paski mają z-index do 55), ale POD oknami
     modalnymi (--zp-z-modal 9500) — okno dialogowe musi zakrywać pasek. */
  z-index: 100;
  /* box-sizing: border-box (wyżej) + padding tylko w poziomie + border w dole =
     dokładnie 56 px wysokości. Warunek weryfikacji: pasek ma być co do piksela 56. */
  height: var(--zp-panel-header-h);
  display: flex;
  align-items: center;
  gap: var(--zp-space-4);
  padding: 0 var(--zp-panel-gutter);
  background: var(--zp-surface);
  /* 1 px zwykłej kreski, nie 2 px cyanu: cyanowa linia pod białym paskiem czytałaby się jako
     stan („coś się ładuje"), a wysokość musi zostać dokładnie 56 px razem z obramowaniem. */
  border-bottom: 1px solid var(--zp-border);
  box-shadow: var(--zp-sh-sm);
  color: var(--zp-navy);
}

/* ================================================================ MARKA (LOGO)
   Ten sam komponent na dwóch tłach: normalnie na szczycie menu (granat), awaryjnie w białym
   pasku, gdy rola nie ma ani jednej pozycji menu i kolumna menu wcale nie powstała. Kolory
   zależą więc od RODZICA, a nie od dodatkowej klasy. */
.zp-panel-brand {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: var(--zp-space-2);
  min-width: 0;
  max-width: 100%;
  color: var(--zp-panel-marka-txt, #fff);
  text-decoration: none;
}
.zp-panel-brand:hover { text-decoration: none; }
.zp-panel-brand__logo { display: block; max-height: 32px; width: auto; }
.zp-panel-brand__tekst {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.15;
}
.zp-panel-brand__nazwa {
  font-size: var(--zp-fs-md);
  font-weight: 800;
  letter-spacing: .2px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Końcówka nazwy: cyan tylko na granacie (7,4:1); na bieli --zp-accent-ink (10,1:1). */
.zp-panel-brand__akcent { color: var(--zp-panel-marka-akcent, var(--zp-accent)); }
/* Podpis pod nazwą. Jest TYLKO przy napisie awaryjnym: logo wgrane przez szkołę dostaje całe
   56 px bloku i żadnego podpisu, bo „Panel ośrodka" obok cudzego wordmarku konkuruje z nim. */
.zp-panel-brand__podpis {
  margin-top: 2px;
  color: var(--zp-panel-marka-txt-2, var(--zp-panel-nav-txt-2));
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .8px;
  text-transform: uppercase;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Znak jednoliterowy dla menu ZWINIĘTEGO do 64 px — w stanie rozwiniętym niepotrzebny,
   bo obok stoi pełna nazwa. Widoczność przełącza sekcja „Stan zwinięty". */
.zp-panel-brand__znak { display: none; }

/* Marka w BIAŁYM pasku (tylko gdy nie ma kolumny menu). */
.zp-panel-header .zp-panel-brand { color: var(--zp-navy); max-width: 280px; }
.zp-panel-header .zp-panel-brand__akcent { color: var(--zp-accent-ink); } /* 10,1:1 na bieli */
.zp-panel-header .zp-panel-brand__podpis { color: var(--zp-text-m); }     /*  5,3:1 na bieli */

/* MIEJSCE ZAREZERWOWANE: wyszukiwarka globalna i dzwonek powiadomień (świadomie poza
   zakresem wydania). Element jest pusty i rozpycha nagłówek, żeby chip użytkownika stał
   po prawej — kiedy te funkcje wejdą, wystarczy wypełnić ten kontener. */
.zp-panel-header__slot { flex: 1 1 auto; min-width: 0; }

/* ── Chip użytkownika ─────────────────────────────────────────── */
.zp-panel-user {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--zp-space-2);
}
.zp-panel-user__inicjal {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Cyan jako WYPEŁNIENIE z granatowym napisem (7,4:1). Odwrotnie — biały napis na cyanie —
     dałoby 2,1:1, czyli tekst nieczytelny. Na białym pasku ta para zostaje bez zmian: liczy
     się kontrast LITERY DO WYPEŁNIENIA, a nie wypełnienia do tła paska (kółko jest kształtem,
     nie pismem). To jedyne miejsce, w którym cyan marki wchodzi na biały pasek. */
  background: var(--zp-accent);
  color: var(--zp-navy);
  font-size: 13px;
  font-weight: 800;
  line-height: 1;
}
.zp-panel-user__dane {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
  min-width: 0;
}
.zp-panel-user__nazwa {
  color: var(--zp-navy);                /* 15,5:1 na bieli */
  font-size: 13px;
  font-weight: 600;
  max-width: 180px;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
/* Rola BYŁA cyanowa — na granatowym pasku miała 7,4:1. Na bieli ten sam cyan ma 2,1:1, czyli
   podpis nieczytelny, i to jest jedyny napis, który po przeniesieniu paska na biel MUSIAŁ
   zmienić kolor. Przygaszony granat --zp-text-m ma 5,3:1, więc przechodzi AA także dla
   11 px (progiem dla zwykłego pisma jest 4,5:1). */
.zp-panel-user__rola {
  color: var(--zp-text-m);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .2px;
}
.zp-panel-user__wyloguj {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 32px;
  padding: 0 10px;
  margin-left: var(--zp-space-2);
  border: 1px solid var(--zp-border-s);
  border-radius: var(--zp-r);
  background: transparent;
  color: var(--zp-navy);                /* 15,5:1 — dotyczy też ikony (currentColor) */
  font-size: 12px;
  font-weight: 600;
  text-decoration: none;
  transition: background var(--zp-transition), border-color var(--zp-transition), color var(--zp-transition);
}
/* Hover wypełnia przycisk granatem z białym napisem (15,5:1) — na białym pasku samo
   przyciemnienie tła byłoby zmianą, której prawie nie widać. */
.zp-panel-user__wyloguj:hover {
  background: var(--zp-navy);
  border-color: var(--zp-navy);
  color: #fff;
}

/* Fokus w pasku: granat (10,9:1 na bieli). Cyan zostaje na ciemnym — patrz sekcja „MENU
   BOCZNE", która ma własną regułę. */
.zp-panel-header a:focus-visible {
  outline: 3px solid var(--zp-navy-light);
  outline-offset: 2px;
}

/* ================================================================ UKŁAD: MENU + TREŚĆ
   Siatka dwukolumnowa jest teraz NAJWYŻSZYM poziomem układu: kolumna menu idzie przez całą
   wysokość okna, a wszystko, co było „nad" i „pod" nią (pasek, stopka), siedzi w kolumnie
   obok. Dzięki temu pasek i stopka kończą się na krawędzi menu. */
.zp-panel-body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  /* minmax(0, 1fr), NIE 1fr: domyślne `auto` minimum pozwoliłoby szerokiej tabeli rozepchać
     kolumnę i cała STRONA dostałaby poziomy pasek przewijania. */
  grid-template-columns: var(--zp-panel-nav-w) minmax(0, 1fr);
  /* Menu jest PRZYKLEJONE (position: sticky) i wysokie na jedno okno (100vh), a wiersz siatki
     jest wysoki tyle, ile treść obok. Na długim ekranie pod menu zostałby więc jasny pas —
     granat kończyłby się dokładnie tam, gdzie kończy się pierwsze okno. Tło kolumny malujemy
     na siatce, dokładnie na szerokość zmiennej menu, i problem znika bez względu na to,
     ile treści jest obok. */
  background-image: linear-gradient(
    to right,
    var(--zp-panel-nav-bg) var(--zp-panel-nav-w),
    transparent var(--zp-panel-nav-w)
  );
  /* Szerokość kolumny zmienia się BEZ animacji i to jest decyzja, nie przeoczenie: siatka
     i to tło musiałyby animować się co do milisekundy zgodnie, a rozjazd między nimi
     oznacza treść ekranu na granatowym pasie przez czas trwania animacji. */
}

/* Rola, która w panelu ma wyłącznie własny ekran (instruktor: oba jego wpisy mają
   'w_menu' => false), nie dostaje ANI JEDNEJ pozycji — rama nie wypisuje wtedy <nav> wcale
   i dokłada tę klasę. Zwijamy całą kolumnę do zera: pusty granatowy pas wyglądałby jak
   zepsute menu, a nie jak menu, którego nie ma. Logo idzie wtedy do białego paska (PHP).

   Klasa, a nie :has(.zp-panel-nav:empty) jak wcześniej: od kiedy <nav> niesie logo, nigdy
   nie jest pusty, a stan „bez menu" i tak zna PHP, które o układzie decyduje. Jeden warunek
   mniej zależny od wsparcia :has() w przeglądarce. */
.zp-panel-body--bez-menu {
  grid-template-columns: minmax(0, 1fr);
  background-image: none;
}

/* Kolumna treści: wszystko na PRAWO od menu. Pasek i stopka są tu elementami o stałej
   wysokości, <main> rośnie. min-width: 0 (obok minmax(0, 1fr) na torze siatki) jest
   konieczne — bez niego szeroka tabela rozpycha kolumnę i strona dostaje poziomy pasek. */
.zp-panel-kolumna {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* ================================================================ MENU BOCZNE
   Pasek idzie przez CAŁĄ wysokość okna, od samej góry (`top: 0`, `height: 100vh`), i jest
   przyklejony: przy przewijaniu długiej treści menu zostaje na miejscu, lista przewija się
   sama, a grupa „System" z przyciskiem zwijania stoi przy dolnej krawędzi OKNA — nie tuż pod
   ostatnią pozycją, jak było, kiedy wysokość paska brała się z liczby pozycji.

   Wysokość 100vh, a nie 100%: wiersz siatki jest wysoki tyle, ile treść obok (na Harmonogramie
   potrafi mieć kilka tysięcy pikseli), więc 100% dałoby pasek wystający daleko poza okno.
   `align-self: start` zostaje, żeby siatka nie rozciągała paska na cały wiersz wbrew tej
   wysokości. */
.zp-panel-nav {
  min-width: 0;
  position: sticky;
  top: 0;
  /* O jeden wyżej niż pasek (100): pasek ma cień, który rozlewa się także w lewo, czyli na
     prawą krawędź menu. Bez tego krawędź kolumny byłaby u góry przybrudzona. Okna modalne
     (--zp-z-modal 9500) są nadal wyżej. */
  z-index: 101;
  align-self: start;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--zp-panel-nav-bg);
  color: var(--zp-panel-nav-txt);
  border-right: 1px solid var(--zp-panel-nav-krawedz);
  overflow: hidden;
}

/* ── Blok marki na szczycie menu ─────────────────────────────────────────────
   DOKŁADNIE te same 56 px, co biały pasek obok, i kreska u dołu w tym samym miejscu: linia
   pod logo i linia pod paskiem mają być jedną linią przez całą szerokość okna. Stała
   wysokość (nie min-height) właśnie dlatego — przy min-height wyższe logo albo dłuższy
   podpis rozjechałyby te dwie kreski o kilka pikseli. */
/* Tło narożnika jest odwrotnością menu (makieta 2026-09-29): jasne menu → granatowy narożnik
   z logo_dark, granatowe menu → biały narożnik ze zwykłym logo. */
.zp-panel-nav__marka {
  flex: none;
  display: flex;
  align-items: center;
  height: var(--zp-panel-header-h);
  padding: 0 var(--zp-space-3);
  background: var(--zp-panel-marka-bg);
  border-bottom: 1px solid var(--zp-panel-marka-linia);
  overflow: hidden;
}
/* Odstęp listy od bloku marki — wcześniej dawał go padding-top całego paska. MARGINES, nie
   padding: padding wewnątrz kontenera z przewijaniem zniknąłby po pierwszym przewinięciu. */
.zp-panel-nav__marka + .zp-panel-nav__przewijane { margin-top: var(--zp-space-3); }

/* overflow-y NA LIŚCIE, nie na pasku: pasek zawiera też przyklejony dół (grupa „System”
   + przycisk zwijania), który ma zostać widoczny.
   min-height: 0 — bez tego element flex nie chce zejść poniżej wysokości swojej treści
   i przewijanie nigdy się nie włącza. */
.zp-panel-nav__przewijane {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--zp-panel-nav-suwak) transparent;
}
.zp-panel-nav__przewijane::-webkit-scrollbar { width: 8px; }
.zp-panel-nav__przewijane::-webkit-scrollbar-track { background: transparent; }
.zp-panel-nav__przewijane::-webkit-scrollbar-thumb {
  background: var(--zp-panel-nav-suwak);
  border-radius: var(--zp-r-pill);
}

.zp-panel-nav__dol {
  flex: none;
  border-top: 1px solid var(--zp-panel-nav-linia);
  padding-top: var(--zp-space-2);
}

.zp-panel-nav__lista { list-style: none; margin: 0; padding: 0 var(--zp-space-2); }
.zp-panel-nav__poz { margin: 1px 0; }

/* ── Nagłówek grupy ──────────────────────────────────────────────────────────
   Wersaliki z rozstrzeleniem, 11 px: nagłówek ma się odróżniać od pozycji na pierwszy rzut
   oka, a nie konkurować z nimi o uwagę. Kolor #aeb4d6 daje 7,6:1, czyli powyżej progu AA
   także dla małego pisma. */
.zp-panel-nav__naglowek {
  margin: var(--zp-space-4) 0 var(--zp-space-1);
  padding: 0 calc(var(--zp-space-2) + 10px);
  color: var(--zp-panel-nav-txt-2);
  font-size: 11px;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: .9px;
  text-transform: uppercase;
}
/* Nadpisuje `body.zp-panel h2 { color: var(--zp-navy) }` z sekcji dokumentu — granat na
   granacie byłby nagłówkiem niewidocznym. */
body.zp-panel .zp-panel-nav__naglowek { color: var(--zp-panel-nav-txt-2); }
/* Pierwszy nagłówek stoi bezpośrednio pod Pulpitem — bez tego miałby podwójny odstęp. */
.zp-panel-nav__przewijane > .zp-panel-nav__grupa:first-child .zp-panel-nav__naglowek,
.zp-panel-nav__dol .zp-panel-nav__naglowek { margin-top: var(--zp-space-2); }

/* ── Pozycja ────────────────────────────────────────────────────────────────
   36 px wysokości to kompromis zmierzony na liczbie pozycji: 18 pozycji, 5 nagłówków
   i przycisk zwijania mieszczą się wtedy w 1080 px bez przewijania, a przy 864 px
   (1080 ze skalowaniem 125%) przewija się sama lista. Niżej niż 36 px pole dotyku
   przestaje być wygodne dla kogoś, kto klika w to przez cały dzień. */
.zp-panel-nav__link {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 36px;
  padding: 6px 10px;
  border-radius: var(--zp-r);
  color: var(--zp-panel-nav-txt);
  font-size: var(--zp-fs-sm);
  font-weight: 600;
  line-height: 1.25;
  text-decoration: none;
  transition: background var(--zp-transition), color var(--zp-transition);
}
.zp-panel-nav__link:hover,
.zp-panel-nav__link:focus {
  background: var(--zp-panel-nav-hover);
  color: var(--zp-panel-nav-txt);
  text-decoration: none;
}

.zp-panel-nav__ikona {
  flex: none;
  display: inline-flex;
  width: 18px;
  height: 18px;
  align-items: center;
  justify-content: center;
}
.zp-panel-nav__ikona .zp-icon { display: block; }

/* Długie etykiety („Harmonogram praktyczny") ŁAMIĄ SIĘ na dwie linie, a nie urywają
   wielokropkiem: przy 192 px (próg 1366) „Harmonogram praktyczn…" nie odpowiada na pytanie,
   czym ta pozycja jest. */
.zp-panel-nav__tekst { min-width: 0; }

/* ── Bieżący ekran ──────────────────────────────────────────────────────────
   Makieta pulpitu (2026-09-29, doprecyzowanie właściciela 2026-09-30): podświetlenie
   zaczyna się OD KRAWĘDZI EKRANU — ujemny margines zjada wcięcie listy (padding
   --zp-space-2), a padding oddaje je treści, więc ikona i napis stoją w tej samej kolumnie
   co w pozostałych pozycjach. Lewe rogi proste, prawe zaokrąglone; pasek 4 px w cyanie
   przy krawędzi. W OBU wariantach menu tak samo (granat na #e6f8fe 14,2:1). Ikona zostaje
   granatowa — cyan na #e6f8fe ma ok. 1,9:1. Pasek to znacznik czytelny kątem oka także
   w menu zwiniętym do 64 px, gdzie etykiet nie ma. */
.zp-panel-nav__link.is-aktywny,
.zp-panel-nav__link.is-aktywny:hover,
.zp-panel-nav__link.is-aktywny:focus {
  margin-left: calc(-1 * var(--zp-space-2));
  padding-left: calc(10px + var(--zp-space-2));
  border-radius: 0 var(--zp-r) var(--zp-r) 0;
  background: var(--zp-panel-nav-aktywne);
  color: var(--zp-panel-nav-aktywne-txt);
  font-weight: 700;
  box-shadow: inset 4px 0 0 var(--zp-panel-nav-aktywne-znacznik);
}

/* ── Przycisk zwijania ──────────────────────────────────────────────────────
   Na dole, pod grupą „System": to sterowanie paskiem, nie pozycja menu, więc nie ma prawa
   odbierać miejsca pozycjom na górze. */
.zp-panel-nav__zwin {
  display: flex;
  align-items: center;
  gap: 10px;
  width: calc(100% - 2 * var(--zp-space-2));
  min-height: 36px;
  margin: var(--zp-space-1) var(--zp-space-2) var(--zp-space-2);
  padding: 6px 10px;
  border: 0;
  border-radius: var(--zp-r);
  background: transparent;
  color: var(--zp-panel-nav-txt);
  font-family: inherit;
  font-size: var(--zp-fs-xs);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  transition: background var(--zp-transition);
}
.zp-panel-nav__zwin:hover { background: var(--zp-panel-nav-hover); }
.zp-panel-nav__zwin .zp-panel-nav__ikona { transition: transform var(--zp-transition); }

/* ── Stan zwinięty ──────────────────────────────────────────────────────────
   Etykiety CHOWAMY, ale zostawiamy w drzewie dostępności (clip-path, nie display: none) —
   inaczej pozycja menu straciłaby nazwę dla czytnika ekranu i została samą ikoną. */
html.zp-nav-zwinieta .zp-panel-nav__tekst {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}
html.zp-nav-zwinieta .zp-panel-nav__link,
html.zp-nav-zwinieta .zp-panel-nav__zwin {
  justify-content: center;
  gap: 0;
  padding-left: 0;
  padding-right: 0;
}
/* Zwinięte: pozycja bieżąca też sięga krawędzi, a lewy padding równy ujemnemu marginesowi
   trzyma ikonę na tej samej osi co ikony pozostałych pozycji. */
html.zp-nav-zwinieta .zp-panel-nav__link.is-aktywny {
  padding-left: var(--zp-space-2);
}
/* Nagłówek grupy zamienia się w cienką linię: podział na grupy zostaje widoczny, a nazwa
   grupy jest nadal odczytywana przez czytnik ekranu (tekst tylko przycięty, patrz wyżej). */
html.zp-nav-zwinieta .zp-panel-nav__naglowek {
  height: 1px;
  margin: var(--zp-space-3) 14px var(--zp-space-2);
  padding: 0;
  background: var(--zp-panel-nav-linia);
  position: relative;
}
html.zp-nav-zwinieta .zp-panel-nav__zwin .zp-panel-nav__ikona { transform: rotate(180deg); }

/* ── Marka w stanie zwiniętym ────────────────────────────────────────────────
   64 px kolumny to za mało na napis „zapisy.pro" z podpisem, a rozpychanie kolumny logiem
   jest wykluczone (szerokość menu jest tym, co oddajemy Harmonogramowi). Degradacja:

   • napis awaryjny → pełna nazwa i podpis zostają w drzewie dostępności (clip-path, nie
     display: none — nazwa dostępna linku musi przeżyć zwinięcie), a NA ICH MIEJSCU pokazuje
     się jednoliterowy znak: granatowe „z" na cyanowym kwadracie 28 px (7,4:1);
   • logo wgrane przez szkołę → kadr jego LEWEGO kwadratu 28 × 28 px (object-fit), a nie
     miniatura całości: poziomy logotyp ściśnięty do 40 px był nieczytelną kreską. Znak
     zwykle stoi na początku logo (Zapisy.pro: strzałka „Z”), więc kadr pokazuje właśnie jego —
     odpowiednik jednoliterowego znaku napisu awaryjnego.

   Wszystkie trzy reguły są ZAWĘŻONE do .zp-panel-nav__marka. Klasa stanu siedzi na <html>
   i zostaje w localStorage także dla konta bez menu (instruktor), gdzie marka jest w BIAŁYM
   pasku — bez tego zawężenia taki pasek pokazywałby cyanowy kwadrat zamiast nazwy. */
html.zp-nav-zwinieta .zp-panel-nav__marka {
  justify-content: center;
  padding: 0;
}
html.zp-nav-zwinieta .zp-panel-nav__marka .zp-panel-brand__tekst {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  white-space: nowrap;
  clip-path: inset(50%);
}
html.zp-nav-zwinieta .zp-panel-nav__marka .zp-panel-brand__znak {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: var(--zp-r);
  background: var(--zp-accent);
  color: var(--zp-navy);
  font-size: 15px;
  font-weight: 800;
  line-height: 1;
}
html.zp-nav-zwinieta .zp-panel-nav__marka .zp-panel-brand__logo {
  width: 28px;
  height: 28px;
  max-height: none;
  object-fit: cover;
  object-position: left center;
}

/* Fokus klawiaturą w menu: granat-light na bieli (10,9:1), cyan na granacie (7,4:1) — zmienna wariantu. */
.zp-panel-nav a:focus-visible,
.zp-panel-nav button:focus-visible {
  outline: 3px solid var(--zp-panel-nav-fokus);
  outline-offset: -2px;
}
/* Fokus na logo: kolor pod tło narożnika, nie menu. */
.zp-panel-nav__marka a:focus-visible { outline-color: var(--zp-panel-marka-fokus); }

/* flex: 1 1 auto — treść zajmuje w kolumnie całą wysokość między paskiem a stopką, żeby
   stopka stała przy dolnej krawędzi okna także na krótkim ekranie (403/404 to jeden akapit). */
.zp-panel-main {
  flex: 1 1 auto;
  min-width: 0;
  padding: var(--zp-panel-gutter);
}

/* Dwa warianty szerokości, sterowane polem 'szerokosc' wpisu rejestru. */
.zp-panel-main--pelna { max-width: none; }          /* harmonogram, kiosk, tabele */
.zp-panel-main--waska { max-width: 1100px; }        /* formularze: długie linie tekstu męczą */

/* Ekrany renderują <div class="wrap zp-admin-wrap"> z max-width: 1340px i marginesem 20 px —
   limit z wp-admina, gdzie nie było kolumny menu panelu. W ramie ten limit MUSI zniknąć,
   inaczej wariant pełny nic nie daje (harmonogram zostałby przy 1282 px zamiast >1600). */
.zp-panel-main .zp-admin-wrap,
.zp-panel-main .wrap {
  max-width: none;
  margin: 0;
  padding: 0;
}

/* Linki wewnątrz ekranów. W wp-adminie kolor dawał arkusz rdzenia (#2271b1), którego na
   froncie nie ma — bez tej reguły ekrany mają domyślne, granatowo-fioletowe linki
   przeglądarki. :where() ma specyficzność ZERO, więc każda własna reguła komponentu
   (np. .zp-attendee-name a:hover) nadal wygrywa i nic nie zostaje przemalowane siłą. */
.zp-panel-main :where(a) { color: var(--zp-navy); }
.zp-panel-main :where(a:hover) { color: var(--zp-navy-light); }

/* Ekrany pisane dla wp-admina przyklejają własne paski pod paskiem administratora
   (top: 46px) albo do samej góry (top: 0). Pod ramą górę zajmuje nagłówek 56 px, więc
   przesuwamy je pod niego — inaczej wjeżdżałyby pod spód i były nieklikalne. */
.zp-panel-main .zp-builder-palette,
.zp-panel-main .zp-builder-inspector { top: calc(var(--zp-panel-header-h) + var(--zp-space-2)); }
.zp-panel-main .zp-mobile-instr { top: var(--zp-panel-header-h); }

/* ================================================================ STOPKA */
.zp-panel-footer {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--zp-space-4);
  padding: var(--zp-space-3) var(--zp-panel-gutter);
  background: var(--zp-surface);
  border-top: 1px solid var(--zp-border);
  color: var(--zp-text-m);
  font-size: var(--zp-fs-xs);
}
.zp-panel-footer__wersja { flex: 1 1 auto; }
.zp-panel-footer__link { color: var(--zp-navy); font-weight: 600; text-decoration: none; }
.zp-panel-footer__link:hover { text-decoration: underline; }

/* ================================================================ KARTY, 403/404, BŁĄD */
.zp-panel-karta {
  background: var(--zp-surface);
  border: 1px solid var(--zp-border);
  border-radius: var(--zp-r-lg);
  box-shadow: var(--zp-sh-xs);
  padding: var(--zp-space-7);
}

.zp-panel-blad { max-width: 620px; }
.zp-panel-blad__kod {
  /* Ciemny wariant cyanu (10,1:1 na bieli). Sam cyan miałby tu 2,1:1 — czyli liczbę,
     której nie da się przeczytać. */
  color: var(--zp-accent-ink);
  font-size: 40px;
  font-weight: 800;
  line-height: 1;
  margin: 0;
  font-variant-numeric: tabular-nums;
}
.zp-panel-blad__tytul { font-size: var(--zp-fs-xl); margin: var(--zp-space-2) 0 var(--zp-space-3); }
.zp-panel-blad__opis { color: var(--zp-text-2); margin: 0 0 var(--zp-space-6); }

.zp-panel-przycisk {
  display: inline-flex;
  align-items: center;
  gap: var(--zp-space-2);
  height: 40px;
  padding: 0 20px;
  border-radius: var(--zp-r);
  background: var(--zp-navy);
  color: #fff;
  font-size: var(--zp-fs);
  font-weight: 700;
  text-decoration: none;
  transition: background var(--zp-transition);
}
.zp-panel-przycisk:hover { background: var(--zp-navy-light); color: #fff; }
.zp-panel-przycisk--maly { height: 32px; padding: 0 14px; font-size: 12px; }

/* Fokus na jasnym tle: granat (10,9:1 na bieli). Cyan zostaje na ciemnym — menu ma
   własną regułę w sekcji „MENU BOCZNE" i CELOWO nie jest tu wymienione: od zadania 4
   pasek menu jest granatowy, więc granatowa ramka fokusu byłaby na nim niewidoczna. */
.zp-panel-main a:focus-visible,
.zp-panel-footer a:focus-visible {
  outline: 3px solid var(--zp-navy-light);
  outline-offset: 2px;
}

.zp-panel-komunikat {
  border-left: 4px solid var(--zp-red);
  max-width: 820px;
}
.zp-panel-komunikat__tytul {
  margin: 0 0 var(--zp-space-2);
  font-size: var(--zp-fs-lg);
  font-weight: 700;
  color: var(--zp-navy);
}
.zp-panel-komunikat__opis {
  margin: 0;
  color: var(--zp-text-2);
  /* Komunikat wyjątku dla administratora zawiera ścieżkę pliku — bez tego rozpychałby układ. */
  overflow-wrap: anywhere;
}

/* ================================================================ KOMUNIKATY EKRANÓW
   `.notice` to klasy WordPressa i wypisuje je 26 miejsc w ekranach („Twoje konto nie ma
   przypisanego oddziału", brak klucza szyfrowania, błąd zapisu) oraz settings_errors()
   po zapisie terminu. W panelu arkusze wp-admina NIE są wczytane, więc bez tych reguł
   komunikat wyglądał jak zwykły akapit zgubiony nad treścią — najgorzej trafione jest
   potwierdzenie zapisu, bo pani z biura nie widzi wtedy żadnego sygnału, że termin
   faktycznie się zapisał.

   Forma ta sama, co na ekranie logowania (zp-panel-login.css): 4 px paska stanu z lewej
   i przygaszone tło. Kolor stanu trzymamy w zmiennej, żeby warianty ustawiały JEDNĄ
   wartość i nie powtarzały całego pudełka. */
.zp-panel-main .notice {
  --zp-notice-stan: var(--zp-border-s);
  --zp-notice-tlo: var(--zp-surface-2);
  max-width: 820px;
  margin: 0 0 var(--zp-space-5);
  padding: var(--zp-space-3) var(--zp-space-4);
  background: var(--zp-notice-tlo);
  border: 1px solid var(--zp-border);
  border-left: 4px solid var(--zp-notice-stan);
  border-radius: var(--zp-r);
  color: var(--zp-text);
  font-size: var(--zp-fs);
}
/* Rdzeń nie daje akapitom w komunikacie własnych marginesów — odstęp robimy między nimi,
   żeby jednoakapitowy komunikat (czyli 25 z 26 przypadków) nie miał luk u góry i u dołu. */
.zp-panel-main .notice p { margin: 0; }
.zp-panel-main .notice p + p { margin-top: var(--zp-space-2); }
.zp-panel-main .notice a { color: var(--zp-navy); }

.zp-panel-main .notice-success { --zp-notice-stan: var(--zp-green);  --zp-notice-tlo: var(--zp-green-soft); }
.zp-panel-main .notice-error   { --zp-notice-stan: var(--zp-red);    --zp-notice-tlo: var(--zp-red-soft); }
.zp-panel-main .notice-warning { --zp-notice-stan: var(--zp-yellow); --zp-notice-tlo: var(--zp-yellow-soft); }
.zp-panel-main .notice-info    { --zp-notice-stan: var(--zp-blue);   --zp-notice-tlo: var(--zp-blue-soft); }

/* W wp-adminie `inline` znaczy „komunikat w treści, nie u góry strony". W panelu każdy
   komunikat i tak stoi tam, gdzie go wypisano, więc różnica zostaje tylko w marginesie. */
.zp-panel-main .notice.inline { margin: var(--zp-space-3) 0; }

/* ================================================================ SZEROKOŚCI EKRANU
   Punkt odniesienia to 1920 px fizycznie, ale układ musi być poprawny od 1536 px CSS
   (1080p przy skalowaniu 125% — typowy laptop 15") i używalny przy 1280. */

/* 1536 i 1440: menu i marginesy węższe, żeby treść nie traciła szerokości. */
@media (max-width: 1600px) {
  .zp-panel { --zp-panel-nav-w: 212px; --zp-panel-gutter: 16px; }
}

/* 1280: jeszcze węższe menu — 1280 - 192 - 24 = 1064 px na treść. */
@media (max-width: 1366px) {
  .zp-panel { --zp-panel-nav-w: 192px; --zp-panel-gutter: 12px; }
}

/* Tablet i telefon: menu przestaje być kolumną. Z JavaScriptem (klasa .zp-szuflada na <html>,
   ustawiana w <head>) jest SZUFLADĄ wysuwaną przyciskiem w pasku — blok niżej, „SZUFLADA".
   Bez JavaScriptu zostaje BLOKIEM nad treścią: pozycje w kolumnach po ~170 px (grid
   auto-fill), cała nawigacja widoczna i osiągalna. Reguły bloku są więc za
   `html:not(.zp-szuflada)`. Wspólne dla obu: jedna kolumna siatki, brak przycisku zwijania
   i wyzerowany stan „zwinięte" — inaczej konto, które zwinęło menu na desktopie,
   zobaczyłoby na tablecie rząd ikon bez podpisów. */
@media (max-width: 1024px) {
  .zp-panel-body {
    grid-template-columns: minmax(0, 1fr);
    background-image: none;
  }
  html:not(.zp-szuflada) .zp-panel-nav {
    position: static;
    /* height: auto zamiast 100vh — blok nad treścią ma być wysoki na tyle, ile ma pozycji;
       100vh oddałoby całe okno samej nawigacji. */
    height: auto;
    padding: 0 var(--zp-panel-gutter) var(--zp-space-3);
    border-bottom: 2px solid var(--zp-accent);
  }
  /* Blok marki zostaje na górze nawigacji, ale bez własnego wcięcia (ma je już cały blok)
     i bez kreski: pasek treści jest tu POD nawigacją, więc nie ma z czym jej łączyć. */
  html:not(.zp-szuflada) .zp-panel-nav__marka {
    justify-content: flex-start;
    padding: 0 var(--zp-panel-gutter);
    margin: 0 calc(-1 * var(--zp-panel-gutter)) var(--zp-space-2);
    border-bottom: 0;
  }
  html:not(.zp-szuflada) .zp-panel-nav__przewijane { overflow: visible; }
  html:not(.zp-szuflada) .zp-panel-nav__dol { border-top: 0; padding-top: 0; }
  html:not(.zp-szuflada) .zp-panel-nav__lista {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(170px, 1fr));
    gap: 1px var(--zp-space-2);
    padding: 0;
  }
  .zp-panel-nav__zwin { display: none; }
  /* Przywrócenie widoczności etykiet i nagłówków, gdy stan „zwinięte" przyszedł z desktopu. */
  html.zp-nav-zwinieta .zp-panel-nav__tekst {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
  }
  html.zp-nav-zwinieta .zp-panel-nav__link {
    justify-content: flex-start;
    gap: 10px;
    padding-left: 10px;
    padding-right: 10px;
  }
  /* Siatka pozycji nad treścią: bez krawędzi ekranu obok, więc bieżąca pozycja wraca do
     zwykłego kafelka z zaokrągleniem ze wszystkich stron. */
  html:not(.zp-szuflada) .zp-panel-nav__link.is-aktywny,
  html:not(.zp-szuflada) .zp-panel-nav__link.is-aktywny:hover,
  html:not(.zp-szuflada) .zp-panel-nav__link.is-aktywny:focus {
    margin-left: 0;
    padding-left: 10px;
    border-radius: var(--zp-r);
  }
  html.zp-nav-zwinieta .zp-panel-nav__naglowek {
    height: auto;
    margin: var(--zp-space-3) 0 var(--zp-space-1);
    padding: 0;
    background: none;
  }
  /* To samo dla marki: pełna nazwa z podpisem wraca, znak jednoliterowy znika. */
  html.zp-nav-zwinieta .zp-panel-nav__marka .zp-panel-brand__tekst {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip-path: none;
  }
  html.zp-nav-zwinieta .zp-panel-nav__marka .zp-panel-brand__znak { display: none; }
  html.zp-nav-zwinieta .zp-panel-nav__marka .zp-panel-brand__logo {
    width: auto;
    height: auto;
    max-height: 32px;
    max-width: none;
    object-fit: fill;
  }
}

/* ================================================================ SZUFLADA (≤ 1024 px)
   Menu na telefonie i tablecie: zamknięte domyślnie, wysuwane od lewej przyciskiem w pasku.
   Wygląda jak kolumna z desktopu (te same grupy, ikony, znacznik bieżącej pozycji) — to ta
   sama <nav>, tylko przypięta do okna (position: fixed) i schowana za lewą krawędzią.
   Stan otwarty = klasa .zp-szuflada-otwarta na <html> (zp-panel.js).

   Warstwy: zasłona 9000, szuflada 9010 — nad paskiem (100), przyklejonymi paskami ekranów
   i toastami (--zp-z-toast 9000), ale POD oknami modalnymi (--zp-z-modal 9500). */

/* Elementy szuflady nie istnieją na desktopie. */
.zp-panel-header__menu,
.zp-panel-header__marka,
.zp-panel-nav__zamknij,
.zp-panel-zaslona { display: none; }

@media (max-width: 1024px) {
  html.zp-szuflada .zp-panel-header__menu {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* 44 × 44 — minimalny cel dotyku. Ujemny margines wyrównuje ikonę z treścią pod paskiem. */
    width: 44px;
    height: 44px;
    margin-left: -10px;
    padding: 0;
    border: 0;
    border-radius: var(--zp-r);
    background: transparent;
    color: var(--zp-navy);
    cursor: pointer;
  }
  html.zp-szuflada .zp-panel-header__menu:hover { background: var(--zp-bg); }
  html.zp-szuflada .zp-panel-header__menu:focus-visible {
    outline: 3px solid var(--zp-navy-light);
    outline-offset: 0;
  }
  html.zp-szuflada .zp-panel-header__marka {
    display: flex;
    align-items: center;
    min-width: 0;
  }
  /* Pasek na telefonie ma mało miejsca: zostaje sama nazwa, bez podpisu „Panel ośrodka". */
  html.zp-szuflada .zp-panel-header__marka .zp-panel-brand__podpis { display: none; }
  html.zp-szuflada .zp-panel-header__marka .zp-panel-brand__logo { max-height: 32px; }

  html.zp-szuflada .zp-panel-nav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 9010;
    width: min(300px, 85vw);
    height: 100vh;
    height: 100dvh;
    transform: translateX(-100%);
    /* visibility zamiast samego przesunięcia: schowana szuflada nie może przyjmować fokusu
       z klawiatury ani być czytana przez czytnik ekranu. Opóźnienie visibility = czas
       animacji, żeby przy zamykaniu nie znikała w pół ruchu. */
    visibility: hidden;
    transition: transform .22s ease-out, visibility 0s linear .22s;
    box-shadow: none;
    /* Na telefonie przewija się CAŁA szuflada, a nie sama lista nad przyklejoną grupą
       „System": przy 844 px wysokości przyklejony dół zjadał połowę ekranu, a lista
       nad nim kończyła się w pół zestawu bez śladu, że jest coś dalej. */
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  html.zp-szuflada .zp-panel-nav__przewijane {
    flex: none;
    overflow: visible;
  }
  /* Ostatnia pozycja nad paskiem gestów iPhone'a, nie pod nim. */
  html.zp-szuflada .zp-panel-nav__dol {
    padding-bottom: calc(var(--zp-space-2) + env(safe-area-inset-bottom, 0px));
  }
  /* Logo z krzyżykiem zostaje u góry przy przewijaniu — zamknięcie zawsze pod palcem. */
  html.zp-szuflada .zp-panel-nav__marka {
    position: sticky;
    top: 0;
    z-index: 1;
  }
  html.zp-szuflada-otwarta .zp-panel-nav {
    transform: none;
    visibility: visible;
    transition: transform .22s ease-out, visibility 0s;
    box-shadow: 0 0 40px rgba(29, 28, 87, .28);
  }

  /* Blok marki: logo po lewej, krzyżyk po prawej. Stan „zwinięte" z desktopu tu nie działa. */
  html.zp-szuflada .zp-panel-nav__marka,
  html.zp-szuflada.zp-nav-zwinieta .zp-panel-nav__marka {
    justify-content: space-between;
    gap: var(--zp-space-2);
    padding: 0 var(--zp-space-2) 0 var(--zp-space-3);
  }
  html.zp-szuflada .zp-panel-nav__zamknij {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    border: 0;
    border-radius: var(--zp-r);
    background: transparent;
    /* Krzyżyk stoi na tle narożnika (odwrotność menu), więc bierze kolor napisu marki. */
    color: var(--zp-panel-marka-txt);
    cursor: pointer;
  }
  html.zp-szuflada .zp-panel-nav__zamknij:focus-visible {
    outline: 3px solid var(--zp-panel-marka-fokus);
    outline-offset: -3px;
  }
  /* Bieżąca pozycja w stanie „zwinięte" z desktopu: wspólna reguła wyżej zeruje padding
     linków, a znacznik ma dalej sięgać krawędzi — przywracamy wcięcie z desktopu. */
  html.zp-szuflada.zp-nav-zwinieta .zp-panel-nav__link.is-aktywny {
    padding-left: calc(10px + var(--zp-space-2));
  }
  /* To samo dla nagłówków grup: wspólna reguła wyżej (pisana pod blok nad treścią, gdzie
     lista nie ma wcięcia) zeruje im padding — w szufladzie wracają wcięcia z desktopu.
     Dotyczy ekranów domyślnie zwiniętych (Harmonogram) i kont, które zwinęły menu. */
  html.zp-szuflada.zp-nav-zwinieta .zp-panel-nav__naglowek {
    margin: var(--zp-space-4) 0 var(--zp-space-1);
    padding: 0 calc(var(--zp-space-2) + 10px);
  }

  html.zp-szuflada-otwarta .zp-panel-zaslona {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 9000;
    background: rgba(17, 16, 52, .45);
  }
  /* Treść pod otwartą szufladą nie przewija się razem z palcem. */
  html.zp-szuflada-otwarta,
  html.zp-szuflada-otwarta body { overflow: hidden; }
}

@media (max-width: 1024px) and (prefers-reduced-motion: reduce) {
  html.zp-szuflada .zp-panel-nav,
  html.zp-szuflada-otwarta .zp-panel-nav { transition: none; }
}

/* Wąski pasek: zostają inicjał i ikona wylogowania (oraz logo, jeśli awaryjnie jest w pasku). */
@media (max-width: 720px) {
  .zp-panel-user__dane,
  .zp-panel-user__wyloguj-txt { display: none; }
  .zp-panel-header .zp-panel-brand { max-width: 180px; }
}
