/* Fotomapa - style (wyjęte z index.html 23.10.2026) */
  /* ===== Paleta wzorowana na prosilver_dark forum.dawna.pila.pl ===== */
  :root{
    --bg:#131313; --panel:#1f1f1f; --panel-2:#262626; --line:#3a3a3a;
    --text:#cfcfcf; --text-dim:#8f8f8f;
    --accent:#c9a24b; --accent-2:#e0bb63; --link:#c9a24b;
    --shadow:0 4px 18px rgba(0,0,0,.5);
    /* ===== LUZ — jedna miara odstępu od krawędzi ekranu (10.09.2026) =====
       Wszystko, co wisi przy brzegu — panel warstw, legenda, okno
       ustawień, okno sesji, podziałka, słupek narzędziowy, licznik
       powiększenia, okienko współrzędnych — trzyma się TEJ liczby.
       Wcześniej każdy element miał własną (6, 10, 12 px) i przy zmianie
       trzeba było szukać po całym arkuszu. Na telefonie zjeżdża do 4 px:
       przy 375 px szerokości ekranu każdy odzyskany piksel idzie do
       treści panelu. Chcesz ciaśniej albo luźniej — zmień w tych dwóch
       miejscach (tu i w bloku @media (max-width:640px) niżej). */
    --luz:10px;
    /* ===== DÓŁ — odstęp nad paskiem źródeł (10.09.2026, wieczór) =====
       Wszystko, co siada nad pełnoszerokościowym paskiem atrybucji na
       telefonie — słupek narzędziowy z +/-, oś czasu, pasek prowadzenia,
       podziałka i dolna krawędź panelu warstw — trzyma TĘ SAMĄ liczbę.
       Wcześniej każdy element dochodził do niej własnym rachunkiem
       i wychodziło 6, 9 i 10 px; różnicę widać gołym okiem, bo elementy
       stoją w jednym rzędzie nad paskiem. */
    --dol:8px;
    /* wymiary MIERZONE ze strony (JS): wysokość górnego paska, wysokość
       paska źródeł Leafletu, szerokość słupka narzędziowego. Wartości tu
       to tylko bezpieczniki na czas przed pierwszym pomiarem. */
    --pasek:52px; --metka:22px; --slupek:38px; --znak:20px; --zoombar:72px;
  }
  /* Jasna paleta po audycie (08.2026): --text-dim i --accent przyciemnione,
     żeby każda para tekst/tło przekraczała WCAG 4,5:1 także dla drobnego
     pisma (pomiar: dim 4,79–5,89, akcent 4,56–5,61). */
  [data-theme="light"]{
    --bg:#e6e1d5; --panel:#faf8f2; --panel-2:#eeeade; --line:#cec7b4;
    --text:#33302a; --text-dim:#666052;
    --accent:#7d5f1e; --accent-2:#5f4712; --link:#7d5f1e;
    --shadow:0 4px 16px rgba(60,50,20,.18);
  }
  /* aktywne kontrolki w jasnym motywie: akcent jest tam CIEMNY, więc
     ciemny tekst #1a1a1a dawał 3,7:1 — na jasnym tekst musi być jasny */
  [data-theme="light"] .btn.active,
  [data-theme="light"] .mx-side.active,
  [data-theme="light"] #curtain-grip,
  [data-theme="light"] #sesja-okno .s-glowny,
  [data-theme="light"] #geo-toast .gt-akcja{color:#faf8f2;}
  [data-theme="light"] .leaflet-control-zoom a.active{color:#faf8f2 !important;}
  *{box-sizing:border-box;}
  html,body{margin:0;height:100%;background:var(--bg);color:var(--text);
    font-family:Verdana,Helvetica,Arial,sans-serif;font-size:13px;overflow:hidden;
    overscroll-behavior-y:none;}

  /* z-index:0 NIE jest kosmetyką — patrz drabina niżej. Nie usuwać. */
  #map{position:absolute;inset:0;z-index:0;background:var(--bg);}
  /* okno mapy (26.09.2026): przy obrocie mapa jest kwadratem większym od ekranu - bez przycięcia
     TUTAJ telefon powiększał stronę do rozmiaru kwadratu (układ strony puchł do 661 px na 390) */
  #mapa-okno{position:absolute;inset:0;overflow:hidden;z-index:0;}
  /* ================= DRABINA Z-INDEX — jedno miejsce prawdy =================
     #map ma WŁASNY KONTEKST UKŁADANIA (z-index:0). Dzięki temu wszystko,
     co Leaflet rysuje w środku — rastry, pinezki, etykiety, dymki — jest
     zamknięte w tym jednym pudełku i nigdy nie konkuruje z interfejsem.
     Cały interfejs leży nad mapą, niezależnie od tego, jak wysokie numery
     mają pane'y w środku.

     WEWNĄTRZ MAPY (numery liczą się tylko względem siebie):
        400+        rastry (warstwy kafelkowe)
        9500/9600   ramki zdjęć lotniczych i ich zakładki
        10000+      warstwy punktowe (10000 + numer panelu)
        10500       prowadzenie do obiektu (pierścień i linia)
        10600       pomiar (linijka na mapie)
        10800       tooltipPane — etykiety obiektów
        10900       popupPane — dymki

     INTERFEJS NAD MAPĄ:
        1050/1150   #curtain i jego uchwyt
        1090/1095   #timeline, #nawigacja
        1100        #sidebar, #zoom-indicator, #coord-indicator
        10800       narzędzia prawej kolumny: #fort-legenda, #linijka, #korekta
        10950       okna z topbaru: #ust-okno, #sesja-okno, #geo-toast
        11000/11001 #topbar i #topbar-cien
        11050       #ctx-menu — menu prawego przycisku; nad topbarem ŚWIADOMIE:
                    menu kontekstowe otwiera się przy kursorze i wolno mu
                    przykryć wszystko poza modalami, jak menu systemowe
        11100       modale z przyciemnieniem: #zrodla-overlay, #hist-overlay
        12000       #lupa (pełnoekranowy podgląd obrazu)
        13000       #loading (ekran wczytywania — nad wszystkim)

     Numery 10800+ w drugiej grupie są dziś tylko historyczne: po zamknięciu
     mapy w kontekście wystarczyłoby 1150–1400. Zostawione, bo działają
     i kolejność jest poprawna — kompaktować przy okazji, nie „przy okazji
     czegoś innego".

     Skoro dymki nie wychodzą już na panele, muszą OMIJAĆ zajęte krawędzie —
     robi to autoPan z marginesami liczonymi w marginesyDymkow().
     ========================================================================= */
  .leaflet-container{font:inherit;background:var(--bg);}
  /* ===== brak kafelka (12.09.2026) =====
     Gdy kafelka nie ma ani w sieci, ani w zapasie, Leaflet zostawia
     przezroczystą dziurę i widać samo tło — a gołe tło wygląda jak
     awaria aplikacji. Delikatna ukośna kreska mówi „tego kawałka nie
     pobrano", nie „mapa się zepsuła". Wzór jest w tle KONTENERA, więc
     bierze kolory motywu i nie wymaga obrazka z serwera (którego przy
     braku sieci i tak by nie było). */
  /* Selektor MUSI zawierać #map: samo `.leaflet-container` przegrywa
     z regułą `#map{background:var(--bg)}` wyżej (identyfikator bije klasy,
     a skrót `background` kasuje background-image). Złapane pomiarem:
     getComputedStyle pokazywał `none` mimo poprawnej reguły. */
  body.bez-sieci #map{
    background-image:repeating-linear-gradient(45deg,
      transparent 0 10px, rgba(255,255,255,.05) 10px 20px);
  }
  [data-theme="light"] body.bez-sieci #map{
    background-image:repeating-linear-gradient(45deg,
      transparent 0 10px, rgba(0,0,0,.055) 10px 20px);
  }
  /* ===== braki rocznika ortofoto (26.09.2026) =====
     pavvlo: rocznik 2013 jako jedyny nie pokrywa całego obszaru - w dziurze
     prześwituje to, co leży niżej, i wygląda jak zdjęcie z 2013. Ten sam
     ukośny wzór co przy braku mapy „W teren" (paski ok. 10 px, ten sam
     kierunek), podłożony POD obraz każdego kafelka rocznika ortofoto: gdzie
     kafelek ma zdjęcie, zdjęcie go zakrywa; gdzie jest przezroczysty (brzeg
     nalotu) albo go nie ma (bramka oddaje wtedy przezroczysty piksel) - widać
     paski. Co do piksela, na każdym przybliżeniu, bez liczenia czegokolwiek
     na serwerze; krycie, kurtynę i mikser bierze razem z warstwą. Poza
     zasięgiem warstwy kafelek przycina przytnijKafelek().
     DWA odcienie (jasny i ciemny): jeden z nich widać na każdym tle. 10%, nie
     5% jak w „W teren": przy 7% paski ginęły na drobnym, ruchliwym zdjęciu
     (zrzuty próbne 26.09). Okres = 1/18 długości gradientu, czyli równo
     9 pasków na bok kafelka tła: paski sąsiednich kafelków schodzą się bez
     uskoku. Bok kafelka tła (--kreski-bok, bokKresek) maleje o tyle, o ile
     Leaflet rozciąga kafelki ponad natywny poziom - na ekranie paski mają
     zawsze ok. 10 px. */
  /* 26.10.2026: paski NIE siedzą już w tle kafelków (przez to kafelki drżały i
     rozjeżdżały się przy ruchu) - rysuje je jeden prostokąt SVG pod warstwą,
     paskiBrakow() w js/04. */

  /* ===== nagłówek ===== */
  #topbar{
    position:absolute;top:0;left:0;right:0;z-index:11000;
    display:flex;align-items:center;gap:14px;padding:9px 14px;
    background:var(--panel);border-bottom:1px solid var(--line);box-shadow:var(--shadow);
  }
  #topbar .brand{font-weight:bold;color:var(--accent);font-size:14px;letter-spacing:.3px;white-space:nowrap;}
  /* BETA przy logo (27.08) — wyprowadzona z belki listy warstw, gdzie
     na telefonach tłoczyła się z „Zwiń" i łamała wiersz. Siedzi W LINII
     nazwy jak wykładnik potęgi: mała, podniesiona, przygaszona czerwień
     (pełna #b03434 była najjaskrawszym punktem całego ekranu). */
  #topbar .brand .brand-linia{display:inline-block;}
  #topbar .brand .beta-logo{
    background:#9c2f2f;color:#fff;
    /* czytelność przy 8,5 px: biel zamiast złamanej bieli i SZERSZE
       rozstrzelenie — przy tak drobnym stopniu litery zlewały się
       ze sobą bardziej niż z tłem */
    /* 30.08: plakietka była nieczytelna w realnej belce — stopień w górę
       (8,075 → 9,5 px), tło o ton jaśniejsze (#8f2b2b → #9c2f2f, wciąż
       poniżej progu, na którym czerwień przebijała złoto nazwy) i luźniej
       w środku, żeby litery nie dotykały krawędzi. */
    /* 3.09: ciaśniejsza ramka na prośbę użytkownika. Zmniejszone jest
       WYŁĄCZNIE pudełko — stopień pisma zostaje 9,5 px, bo to on decyduje
       o czytelności i był dobierany dwa razy. Zachowana asymetria
       pozioma (lewy większy od prawego): letter-spacing dokłada odstęp
       PO ostatniej literze, więc równe wartości dawałyby napis wizualnie
       dosunięty do lewej krawędzi. */
    /* WYŚRODKOWANIE W PIONIE — wartości ZMIERZONE, nie wyliczone na oko.
       Rozumowanie „wersaliki nie mają wydłużeń dolnych, więc siedzą za
       wysoko" jest intuicyjne i BŁĘDNE dla tego kroju: o położeniu linii
       pisma w pudełku decyduje fontBoundingBox, a Verdana ma go wysoki,
       przez co linia pisma leży nisko i tusz liter wypada PONIŻEJ środka.
       Napis trzeba więc podnieść, nie opuścić — dwie moje poprawki „na
       wyczucie" szły w złą stronę, zanim to zmierzyliśmy.

       Pomiar na żywo (Firefox, Verdana bold 9,5 px, line-height 11,88 px),
       przez canvas measureText: wysokość wersalika 6,91 px, różnica do
       wyrównania −1,09 px. Przy zachowanej sumie 2,6 px daje to 0,75 góra
       i 1,85 dół. Gdyby kiedyś zmienił się krój albo stopień — przeliczyć
       tak samo, bo te liczby są związane z KONKRETNYM krojem. */
    font-size:9.5px;font-weight:bold;letter-spacing:1px;
    padding:0.75px 4.2px 1.85px 5.2px;border-radius:2px;line-height:1.25;
    position:relative;top:-6px;vertical-align:baseline;
    /* ujemne marginesy pionowe: pudełko plakietki (≈15,7 px) jest wyższe
       niż litery nazwy i po powiększeniu zaczęło ROZPYCHAĆ wiersz, a za
       nim całą belkę. Ściągamy jego wkład do zera — o wysokości wiersza
       decydują wyłącznie litery FOTO|MAPA, jak przed powiększeniem. */
    margin:-8px 0 -8px 6.65px;
  }
  /* Odnośnik prowadzi TYLKO z adresu — klikanie napisu FOTOMAPA, żeby
     wyjść z Fotomapy, było mylące. Sam napis nie jest już linkiem. */
  /* UWAGA na wagę selektorów: `a.brand-d` bije `.brand-d`, więc kolor
     spoczynkowy trzeba podać tutaj — `inherit` brał złoto z `.brand`
     i adres świecił się na złoto bez najeżdżania */
  #topbar .brand a.brand-d{color:var(--text-dim);text-decoration:none;display:block;text-align:left;}@media (hover:hover){ #topbar .brand a.brand-d:hover{color:var(--accent);} }
  /* 30.08: 1.2 → 1.12 — po powrocie logo na 95% kolumna nazwa+adres
     urosła i to ONA dyktuje grubość belki (przyciski są niższe). Ciaśniejszy
     interlinia zwraca te piksele bez zmniejszania liter. */
  #topbar .brand .brand-txt{display:flex;flex-direction:column;line-height:1.12;}
  /* kurtyna typograficzna: FOTO w kolorze tekstu, MAPA w złocie,
     a złota kreska między nimi to kurtyna porównawcza */
  /* logo poszerzone po usunięciu okruszki (15.08) — miejsce po niej
     oddajemy znakowi; adres dopasuje się sam (dopasujLogo mierzy) */
  /* stopień i rozstrzelenie o 5% w dół (31.08) — cały znak zmniejszony
     proporcjonalnie, razem z kreską, adresem i plakietką; adres i tak
     przelicza się sam, bo dopasujLogo() mierzy, a nie zakłada.
     Najpierw było −10% (znak 123,7 px) — po dniu przerwy okazało się za
     drobne i wróciliśmy o pół kroku: 130,6 px zamiast wyjściowych 137,5.
     Wszystkie liczby niżej to wartości bazowe × 0,95 — gdyby kiedyś
     przyszło zmienić stopień jeszcze raz, mnożnik stosować do 100 %,
     a nie do tych wartości, bo błędy się kumulują. */
  #topbar .brand .brand-foto{color:var(--text);font-weight:normal;letter-spacing:4.75px;font-size:14.25px;}
  #topbar .brand .brand-kreska{
    /* 30.08: kreska ginęła w belce przy 1,9 px — pogrubiona do 2,6 px.
       To JEDYNY element, który świadomie łamie proporcję ×0,95: przy
       stopniu 14,25 px proporcjonalne 1,9 px wypadało cieńsze niż laska
       litery obok, więc kurtyna przestawała czytać się jako oś znaku. */
    display:inline-block;width:2.6px;height:13.3px;background:var(--accent);
    margin:0 7.6px 0 2.85px;vertical-align:-1.425px;
  }
  #topbar .brand .brand-mapa{color:var(--accent);letter-spacing:4.75px;font-size:14.25px;}
  #topbar .brand .brand-d{
    /* Adres ma kończyć się DOKŁADNIE tam, gdzie „A" w MAPA. Rozstrzelenia
       nie da się zapisać na sztywno: szerokość tekstu zależy od czcionki
       systemowej, więc liczba dobrana na jednym komputerze rozjeżdża się
       na innym. Wartość niżej jest tylko startowa — właściwą wylicza
       dopasujLogo() z faktycznego pomiaru w przeglądarce. */
    color:var(--text-dim);font-size:11.4px;font-weight:normal;letter-spacing:2.5px;
    visibility:hidden; /* odsłaniane po pomiarze — patrz dopasujLogo() */
  }
  #topbar .spacer{flex:1;}
  .btn{
    background:var(--panel-2);border:1px solid var(--line);color:var(--text);
    padding:6px 11px;border-radius:3px;cursor:pointer;font:inherit;font-size:12px;white-space:nowrap;
  }@media (hover:hover){ .btn:hover{border-color:var(--accent);color:var(--accent);} }
  .btn.active{background:var(--accent);border-color:var(--accent);color:#1a1a1a;text-shadow:0 0 .65px currentColor;}
  /* ===== KROPKA STANU na przycisku „W teren" (14.09.2026 wieczór, prośba
     pavvla: „zaznaczył jakoś przycisk kolorem, aby sugerował, czy tryb jest
     włączony"). Zielona = włączony i worker odpowiada, czerwona = wyłączony
     wyłącznikiem z okna, szara = jeszcze nie wiadomo. Klasy tryb-wl /
     tryb-wyl ustawia offlineBelka(); barwy te same, co licznik powiększenia
     (.native / .limit), więc w obu motywach czytają się tak samo. */
  #offline-btn::before{
    content:'';display:inline-block;width:8px;height:8px;border-radius:50%;
    margin-right:7px;vertical-align:0;background:var(--text-dim);
    box-shadow:0 0 0 1px rgba(0,0,0,.35);
  }
  #offline-btn.tryb-wl::before{background:#4f9d4f;box-shadow:0 0 0 1px rgba(0,0,0,.35),0 0 6px rgba(79,157,79,.55);}
  #offline-btn.tryb-wyl::before{background:#e05555;box-shadow:0 0 0 1px rgba(0,0,0,.35),0 0 6px rgba(224,85,85,.45);}
  /* ===== PRZEŁĄCZNIK TRYBU u góry okna „W teren" (14.09.2026 wieczór, pavvlo:
     „przycisk wł./wył. tej funkcji powinien być wyżej w okienku i też mieć
     kolory stanu"). Ta sama kropka i te same barwy, co w belce: jeden język
     dla jednego stanu. Klasy wl / wyl ustawia offlinePrzelacznik(). */
  .u-tryb{
    display:flex;align-items:center;gap:10px;margin:0 0 8px;padding:8px 10px 8px 12px;
    background:var(--panel-2);border:1px solid var(--line);border-left:4px solid var(--text-dim);border-radius:4px;
  }
  .u-tryb::before{content:'';flex-shrink:0;width:9px;height:9px;border-radius:50%;background:var(--text-dim);box-shadow:0 0 0 1px rgba(0,0,0,.35);}
  .u-tryb .u-tryb-t{flex:1;font-size:12px;color:var(--text);}
  .u-tryb .u-tryb-t b{text-transform:uppercase;letter-spacing:.4px;}
  .u-tryb .btn{flex-shrink:0;}
  .u-tryb.wl{border-left-color:#4f9d4f;}
  .u-tryb.wl::before{background:#4f9d4f;box-shadow:0 0 0 1px rgba(0,0,0,.35),0 0 6px rgba(79,157,79,.55);}
  .u-tryb.wl .u-tryb-t b{color:#4f9d4f;}
  .u-tryb.wyl{border-left-color:#e05555;background:rgba(224,85,85,.10);}
  .u-tryb.wyl::before{background:#e05555;box-shadow:0 0 0 1px rgba(0,0,0,.35),0 0 6px rgba(224,85,85,.45);}
  .u-tryb.wyl .u-tryb-t b{color:#e05555;}

  /* ===== narzędzia belki: rząd na monitorze, menu na telefonie =====
     Na monitorze ten pojemnik jest przezroczysty i tylko trzyma przyciski
     w rzędzie z takim samym odstępem, jaki daje belka (gap:14px) — wygląd
     bez zmian. Cała różnica siedzi w bloku @media niżej. */
  #topbar-narzedzia{display:flex;align-items:center;gap:14px;}
  #menu-btn{display:none;}          /* na monitorze menu nie jest potrzebne */
  #warstwy-plyw{display:none;}      /* pływający przycisk warstw: tylko telefon */
  /* ===== WĄSKIE OKNO NA MONITORZE (28.09.2026) - opis przy belkaDopasuj() =====
     Między 641 px a ok. 990 px (tablet pionowo, pół ekranu laptopa) ostatnie przyciski belki
     wychodziły poza ekran. JS mierzy belkę i wybiera stopień:
     .belka-ciasna - mniejsze odstępy i „Kopiuj link" zamiast „Kopiuj link do widoku";
     .belka-menu   - gdy i to za mało: logo i „⋯", przyciski w rozwijanej liście, wygląd jak na
                     telefonie (reguły skopiowane z bloku @media max-width:640px niżej). Warstwy i oś
                     czasu zostają w liście - pływające zastępstwa są tylko na telefonie. */
  body.belka-ciasna #topbar{gap:8px;padding-left:10px;padding-right:10px;}
  body.belka-ciasna #topbar-narzedzia{gap:6px;}
  body.belka-ciasna #topbar .btn{padding-left:8px;padding-right:8px;}
  body.belka-menu #topbar .spacer{display:none;}
  body.belka-menu #topbar #menu-btn{
    display:flex;align-items:center;justify-content:center;
    width:38px;height:32px;padding:0;flex-shrink:0;margin-left:auto;
  }
  body.belka-menu #topbar-narzedzia{
    position:fixed;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);
    z-index:10960;display:none;flex-direction:column;align-items:stretch;gap:0;
    min-width:186px;max-width:calc(100vw - var(--luz) * 2);
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);padding:5px;
  }
  body.belka-menu #topbar-narzedzia.otwarte{display:flex;}
  body.belka-menu #topbar #topbar-narzedzia .btn{
    width:100%;text-align:left;background:none;border:none;
    padding:0 10px;min-height:38px;font-size:12.5px;border-radius:3px;
  }
  body.belka-menu #topbar #topbar-narzedzia .btn + .btn{border-top:1px solid var(--line);}
  body.belka-menu #topbar #topbar-narzedzia .btn.active{background:var(--accent);border-color:transparent;}
  body.belka-menu #topbar #topbar-narzedzia .btn + .btn.active{border-top-color:var(--panel);}
  body.belka-menu #topbar #topbar-narzedzia #sesja-btn.wygasla{color:#e07070;font-weight:bold;}
  [data-theme="light"] body.belka-menu #topbar #topbar-narzedzia #sesja-btn.wygasla{color:#b03434;}

  /* ===== panel warstw ===== */
  /* ===== JEDNA MIARA GÓRNEGO PASKA: --pasek (audyt mobilny 10.09.2026) =====
     Wszystko pod paskiem stało na wpisanym na sztywno „52px". Na telefonie
     pasek ma jednak 53 px (większe pola dotyku przycisków), więc panele
     siadały PÓŁ PIKSELA POD nim — bez prześwitu, zlewając się z paskiem
     w jedną czarną płytę (zgłoszenie użytkownika 10.09). Teraz JS mierzy
     pasek i podaje jego wysokość w zmiennej --pasek, a panele trzymają się
     6 px pod nim — niezależnie od urządzenia, wielkości czcionki i tego,
     czy pasek kiedyś urośnie o kolejny przycisk. */
  #sidebar{
    position:absolute;top:calc(var(--pasek, 52px) + 6px);left:var(--luz);z-index:1100;width:340px;
    max-height:calc(100% - var(--pasek, 52px) - 34px);
    background:var(--panel);border:1px solid var(--line);border-radius:4px;box-shadow:var(--shadow);
    display:flex;flex-direction:column;transition:transform .2s,opacity .2s;
    /* overflow:visible (dawniej hidden) — metka ma WYSTAWAĆ spod dolnej
       krawędzi panelu; zaokrąglenia rogów przejmują skrajne dzieci:
       pierwsza widoczna sekcja u góry (mikser albo „Warstwy historyczne")
       i #base-picker na dole */
    overflow:visible;
  }
  #sidebar.hidden{transform:translateX(calc(-100% - 20px));}
  /* ===== NAGŁÓWKI SEKCJI PANELU (26.09.2026) =====
     pavvlo: belka tytułowa „Warstwy historyczne" znika, a „Aktywne warstwy"
     i „Wszystkie warstwy" mają być od teraz DOMINUJĄCE w całym panelu.
     Z trzech pokazanych wariantów wybrany B („mniej żółtego, którego i tak
     jest już dużo"): jasne wersaliki w kolorze tekstu, pogrubione
     i rozstrzelone, na tle panelu, ze złotą kreską 1 px pod spodem. Złoto
     zostaje belkom grup (MAPY, ORTOFOTO…), więc hierarchia czyta się sama:
     sekcja (jasna, podkreślona) > grupa (złota belka) > warstwa.
     Trzecia sekcja - „Podkład współczesny" - ma ten sam nagłówek.
     29 px (z kreską, border-box) = dawna belka tytułowa: pierwszy nagłówek
     trzyma jeden rząd z belką legendy i okienkami wskaźników. Stała
     wysokość + wyśrodkowanie zamiast paddingu, tekst nigdy się nie zawija.
     27.09.2026 - kreska ZŁOTA ŚREDNIO PRZYGASZONA (68% akcentu na tle panelu).
     pavvlo: pełna złota linia „jest zbyt intensywna i ciągle jako pierwsza
     przyciąga wzrok". Najpierw szara dla wszystkich + próba A/B/C dla redakcji,
     tego samego wieczoru doszedł stopień średni i pavvlo: „ten średnio przygaszony
     chyba najbardziej pasuje, ustawmy go też publicznie". Wybór dla redakcji
     zostaje na razie (Ustawienia -> Redakcja). Przeglądarka bez color-mix()
     (starsze niż 2023) dostaje szarą - druga deklaracja przepada, zostaje pierwsza. */
  /* ===== SKALA CZCIONEK PANELU (1.10.2026, audyt na prośbę pavvla: „wielkości czcionki
     w głównym panelu, hierarchia") =====
     Było 8 stopni (10, 10.5, 11, 11.5, 12, 12.5, 13, 15 px) z krokami co pół piksela -
     oko ich nie rozróżniało, a nagłówek sekcji (11.5) i nagłówek grupy (11) wyglądały na
     jeden poziom. Teraz TRZY stopnie, te same na komputerze i telefonie. Pierwsza wersja
     (23:08) szła w górę: 11 / 12 / 13 - pavvlo: „za duża", „słaby był ten audyt" - więc
     o stopień niżej, czyli tak gęsto jak przed audytem, tylko z porządkiem:
       10 px - podgrupy, rok, dpi, „zwiń", L/P, licznik grupy, plakietki, stopka;
               etykiety sekcji (rozstrzelone kapitaliki) 10.5 (pavvlo 2.10: „minimalnie
               powiększyć", z 10)
       11 px - nazwy w „Aktywnych warstwach", przyciski podkładu, opisy warstw
               i „zaloguj się" (tekst do czytania nie schodzi poniżej 11);
               nagłówki grup 10.5 (pavvlo 2.10: „trochę pomniejszyć", z 11)
       12 px - nazwy warstw (jedyny tekst, który się czyta w biegu; było 12.5)
     TELEFON (blok @media max-width:640px niżej) ZOSTAJE na razie przy 11 / 12 / 13
     z 23:08 - pavvlo 1.10: „zajmijmy się teraz pc"; do rozstrzygnięcia, gdy obejrzy
     telefon. Kolory, pogrubienia i układ bez zmian. Legenda fortyfikacji na mapie:
     nagłówek 11 (jak belki grup), jej „zwiń" 10 jak w panelu. */
  #mixer .mx-cap, #layers-cap, #base-picker .lbl{
    display:flex;align-items:center;gap:8px;height:29px;padding:0 12px;margin:0;
    background:var(--panel);border-bottom:1px solid var(--line);
    border-bottom-color:color-mix(in srgb, var(--accent) 68%, var(--panel));
    color:var(--text);font-size:10.5px;font-weight:bold;letter-spacing:1.4px; /* 2.10 00:2x, pavvlo: „warstwy historyczne minimalnie powiększyć" - z 10 */
    text-transform:uppercase;white-space:nowrap;
    flex-shrink:0;user-select:none;-webkit-user-select:none;
  }
  /* PRÓBA DLA REDAKCJI (27.09.2026, pavvlo: „zróbmy a, b, c do ustawienia w Ustawieniach
     i tylko dla redakcji; jak się zdecydujemy, to wtedy zmienimy"). Klasa na <body> tylko
     przy poziomie 3 (zastosujKreske); goście zawsze widzą średnio przygaszoną (od 27.09 wieczorem). */
  body.kreska-a #mixer .mx-cap, body.kreska-a #layers-cap, body.kreska-a #base-picker .lbl{
    border-bottom-color:var(--accent);}
  /* średnio przygaszona (68%) jest teraz regułą bazową (wyżej) - stopień między złotą (100%)
     a mocno przygaszoną (38%); redakcja porównuje jeszcze złotą, mocno przygaszoną i szarą */
  body.kreska-b #mixer .mx-cap, body.kreska-b #layers-cap, body.kreska-b #base-picker .lbl{
    border-bottom-color:color-mix(in srgb, var(--accent) 38%, var(--panel));}
  body.kreska-c #mixer .mx-cap, body.kreska-c #layers-cap, body.kreska-c #base-picker .lbl{
    border-bottom-color:var(--line);}
  /* najwęższe telefony (320-360 px): rozstrzelenie by wypchnęło „Warstwy
     historyczne" pod wielokropek obok „zwiń wszystkie" (na 320 px napis ma 155 px
     miejsca, przy 1.4 px rozstrzelenia zajmuje ok. 152 - za blisko) - ciaśniej, ten
     sam krój i ten sam stopień (do 1.10 malał tu z 11.5 na 11) */
  @media (max-width:360px){
    #mixer .mx-cap, #layers-cap, #base-picker .lbl{letter-spacing:.6px;}
  }
  /* górne rogi panelu: zaokrągla je pierwsza widoczna sekcja (panel ma
     overflow:visible, sam niczego nie przycina) */
  #mixer.show{border-radius:3px 3px 0 0;}
  #mixer:not(.show) ~ #layers-cap{border-radius:3px 3px 0 0;}
  #layers{overflow-y:auto;overflow-x:hidden;padding:6px 0;flex:1 1 auto;min-height:70px;}

  /* ===== zwijane grupy warstw =====
     Nagłówek OTWARTEJ grupy zlewał się optycznie z wierszami warstw
     (uwaga redakcji) — teraz: akcentowa belka 3px z lewej nagłówka,
     przechodząca przy otwartej grupie w cieńszą szynę wzdłuż całej
     zawartości (widać, gdzie grupa się zaczyna i kończy). Zamknięta
     grupa ma belkę przygaszoną — otwarte sekcje wybijają się mocniej.
     Zmiana CELOWO wspólna dla PC i mobile. */
  .grp-head{
    padding:7px 12px 7px 9px;font-size:10.5px;letter-spacing:.5px;color:var(--accent); /* 2.10 00:2x, pavvlo: „trochę pomniejszyć czcionkę podkategorii np. mapy" - z 11 */
    background:var(--panel-2);border-bottom:1px solid var(--line);cursor:pointer;
    text-transform:uppercase;user-select:none;font-weight:bold;
    border-left:3px solid var(--accent); /* 9px paddingu + 3px belki = 12px, tekst równo z resztą */
  }@media (hover:hover){ .grp-head:hover{color:var(--accent-2);} }
  .grp-head .cnt{color:var(--text-dim);font-weight:normal;letter-spacing:0;font-size:10px;}
  /* ===== ekspander +/− =====
     Obracana strzałka ▾ była ledwo widoczna; luźny plus/minus w akcencie
     czyta się od razu jako „to się otwiera" (decyzja z przeglądu: BEZ
     ramki — sam glif z delikatnym cieniem). Glif niesie ::before — tekst
     ▾ w DOM zostaje (czytniki, stary kod), gasi go font-size:0. */
  /* glif RYSOWANY z kresek CSS, nie z fontu: „+" i „−" Verdany siedzą
     na własnych osiach typograficznych i lądowały na RÓŻNYCH wysokościach
     (wypatrzone przez redakcję na powiększeniu). Kreski o całkowitych
     pikselach = identyczna geometria obu stanów i zero rozmycia.
     Kolor NEUTRALNY jak checkboxy — złoto niesie tożsamość tytułów. */
  .grp-head .arr{
    display:inline-block;position:relative;width:14px;height:14px;flex-shrink:0;
    font-size:0;margin-right:6px;vertical-align:-3px;color:var(--text);
    overflow:hidden; /* KLUCZOWE: baseline inline-blocka = dolna krawędź;
      bez tego tekst ▾ o font-size:0 degeneruje linię bazową i box
      zjeżdża 14px pod wiersz (przypadek z pomiaru 15.08) */
  }
  .grp-head .arr::before,.grp-head .arr::after{
    content:'';position:absolute;background:currentColor;border-radius:1px;
    box-shadow:0 1px 2px rgba(0,0,0,.45);
  }
  .grp-head .arr::before{left:3px;top:6px;width:8px;height:2px;}   /* pozioma kreska */
  .grp-head .arr::after{left:6px;top:3px;width:2px;height:8px;display:none;} /* pionowa = plus */
  .grp.closed .grp-head .arr::after{display:block;}
  @media (hover:hover){ .grp-head:hover .arr{color:var(--accent);} }
  .grp-body{border-left:3px solid var(--line);}
  /* podnagłówek podgrupy: złota kreska-akcent przed tekstem robi z niego
     młodszego brata nagłówka sekcji — czytelny priorytet wizualny bez
     konkurowania ze złotą belką grupy */
  .grp-sub{border-top:1px solid var(--line);}
  .grp-body > .grp-sub:first-child{border-top:none;}
  .grp-sub-head{
    display:flex;align-items:center;gap:8px;
    padding:9px 12px 5px;
    color:var(--text-dim);font-size:10px;font-weight:bold;
    text-transform:uppercase;letter-spacing:.5px;
  }
  .grp-sub-head{cursor:pointer;}@media (hover:hover){ .grp-sub-head:hover{color:var(--text);} }
  /* podgrupy: ten sam rysowany ekspander, oczko mniejszy */
  .grp-sub-head .arr{
    display:inline-block;position:relative;width:12px;height:12px;flex-shrink:0;
    font-size:0;color:var(--text);
  }
  .grp-sub-head .arr::before,.grp-sub-head .arr::after{
    content:'';position:absolute;background:currentColor;border-radius:1px;
    box-shadow:0 1px 2px rgba(0,0,0,.45);
  }
  .grp-sub-head .arr::before{left:2px;top:5px;width:8px;height:2px;}
  .grp-sub-head .arr::after{left:5px;top:2px;width:2px;height:8px;display:none;}
  .grp-sub.sub-closed .grp-sub-head .arr::after{display:block;}
  @media (hover:hover){ .grp-sub-head:hover .arr{color:var(--accent);} }
  .grp-sub.sub-closed .grp-sub-head .arr{transform:none;}
  .grp-sub.sub-closed .grp-sub-body{display:none;}
  .grp-sub-head .grp-sub-rok{
    margin-left:auto;color:var(--accent);font-weight:bold;
    letter-spacing:.4px;text-transform:none;
  }
  .grp-sub.rok-wspolny .grp-sub-body .layer .year{display:none;}
  /* podgrupa złożona z SAMYCH zapowiedzi: data zostaje (widać, czego
     dotyczy blok), ale przygaszona — tak samo jak wiersze WKRÓTCE.
     Pełne złoto obiecywałoby materiał, którego jeszcze nie ma. */
  .grp-sub.rok-zapowiedz .grp-sub-rok{opacity:.45;font-weight:normal;}
  .grp.closed .grp-head{border-left-color:var(--line);}
  /* mini-przełącznik RAMKI w nagłówku grupy zdjęć lotniczych */
  .grp-opt{
    float:right;font-size:10px;letter-spacing:.5px;font-weight:normal;
    color:var(--text-dim);border:1px solid var(--line);border-radius:3px;
    padding:1px 6px;margin:-1px 0 0 6px;cursor:pointer;
  }@media (hover:hover){ .grp-opt:hover{border-color:var(--accent);} }
  .grp-opt.active{color:var(--accent);border-color:var(--accent);}
  /* „zwiń/rozwiń" na belce grupy: KROPKA W KROPKĘ styl .fl-hint z legendy
     (te same wartości fontu, trackingu i koloru) — złote obramowania
     zarezerwowane dla opcji specjalnych */
  .grp-head .grp-tog{
    border:none;background:none;padding:0;margin:0 0 0 6px;float:right;
    font-weight:normal;letter-spacing:.4px;color:var(--text-dim);
    text-transform:none;font-size:10px;
  }
  /* 25.09.2026 (pavvlo: „optycznie zredukować te wszystkie zwiń/rozwiń"): na urządzeniach z myszą
     napis na belce działu pojawia się dopiero po najechaniu - znak +/− i licznik już mówią, że dział
     się otwiera, sześć powtórzonych „rozwiń" było szumem. Na dotyku (brak hovera) napisy zostają
     widoczne jak dotąd - tam to jedyne słowo mówiące „tu się klika". Krótkie przenikanie, żeby nie
     migało przy przejeżdżaniu myszą po liście. Napis „zwiń wszystkie" w wierszu „Warstwy historyczne"
     celowo widoczny stale (jeden, nie szum). */
  @media (hover:hover){
    .grp-head .grp-tog{opacity:0;transition:opacity .15s;}
    .grp-head:hover .grp-tog{opacity:1;color:var(--accent-2);}
  }
  /* ramka klatki zdjęcia lotniczego — celowo NIE kolor akcentu:
     złoty zlewał się z beżami OSM i sepią skanów. Malinowa czerwień
     praktycznie nie występuje ani na podkładach, ani na ortofoto,
     a ciemne halo (drop-shadow) odcina kreskę też na jasnych tłach.
     stroke w CSS przebija atrybut prezentacyjny Leafleta. */
  .foto-ramka{
    stroke:#ff4d6d;
    filter:drop-shadow(0 0 1.5px rgba(0,0,0,.7));
    transition:stroke-opacity .15s;
  }
  .grp.closed .grp-body{display:none;}
  .grp.closed .arr{transform:none;} /* ekspander +/− nie obraca się — zmienia glif */

  /* przycisk „Zwiń/Rozwiń" w nagłówku panelu — składa/rozkłada
     WSZYSTKIE grupy naraz; widoczny tylko gdy grup jest co najmniej 2
     (przy jednej nie ma czego zbiorczo zwijać) */
  /* plakietka BETA w nagłówku panelu — czerwona jak KALIBRACJA (spójny
     język plakietek w apce) i wyraźnie ODMIENNA od szarego obrysowego
     przycisku „Zwiń/Rozwiń" obok, żeby nie wyglądała na klikalną;
     top:-1px koryguje optyczne osiadanie poniżej linii tekstu */
  .beta-chip{
    display:inline-block;position:relative;top:-1px;vertical-align:middle;
    background:#b03434;color:#fff;border:none;font-size:10px;font-weight:bold;
    padding:2px 7px;border-radius:3px;letter-spacing:1px;line-height:1.4;
  }
  /* pasek gorących funkcji: między nagłówkiem a aktywnymi warstwami —
     dom dla przełączników działających na całą listę; złoto zarezerwowane
     dla stanu AKTYWNEGO opcji specjalnych (np. Ramki) */
  .hot-btn{
    background:none;border:1px solid var(--line);color:var(--text-dim);
    font:bold 9.5px Verdana,sans-serif;letter-spacing:.5px;text-transform:uppercase;
    padding:3px 10px;border-radius:3px;cursor:pointer;
  }
  /* hover TYLKO na urządzeniach, które hover naprawdę mają: przeglądarki
     dotykowe trzymają :hover po tapnięciu aż do dotknięcia czegoś innego,
     więc po wyłączeniu Ramek przycisk dalej świecił złotem, jakby były
     włączone — stan .active przestawał cokolwiek znaczyć */
  @media (hover:hover){
    .hot-btn:hover{color:var(--accent);border-color:var(--accent);}
  }
  .hot-btn.active{color:var(--accent);border-color:var(--accent);}
  /* „Zwiń/Rozwiń" dosunięty do prawej krawędzi paska — spójnie z belkami
     grup i legendą, gdzie zwijanie zawsze mieszka po prawej */
  #grp-all{margin-left:auto;}
  /* PODPIS LISTY „Warstwy historyczne" (do 26.09 „Wszystkie warstwy") + „zwiń/rozwiń wszystkie" (25.09.2026, pavvlo):
     wiersz nad pierwszą grupą, pod mikserem - podpis tym samym krojem co „Aktywne warstwy"
     (.mx-cap), zwijanie gołym tekstem KROPKA W KROPKĘ jak na belkach grup (.grp-tog) i w
     legendzie (.fl-hint). Poza #layers, więc nie przewija się z listą - „zwiń wszystkie"
     jest zawsze pod ręką, także przy rozwiniętych 22 mapach. */
  /* wygląd wiersza = wspólny nagłówek sekcji (wyżej); tu tylko napis
     i przycisk zwijania. Napis kurczy się z wielokropkiem, przycisk
     trzyma miejsce (wąski telefon) */
  #layers-cap .lc-tyt{min-width:0;overflow:hidden;text-overflow:ellipsis;}
  #layers-cap .lc-tog{
    margin-left:auto;border:none;background:none;padding:0;cursor:pointer;
    font-family:inherit;font-size:10px;font-weight:normal;letter-spacing:.4px;color:var(--text-dim);
    text-transform:none;white-space:nowrap;
  }
  @media (hover:hover){ #layers-cap .lc-tog:hover{color:var(--accent-2);} }


  /* ===== oś czasu ===== */
  #timeline{
    position:absolute;left:50%;transform:translateX(-50%);bottom:24px;z-index:1090;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);display:none;
    /* górne 22 px to rząd na krzyżyk — bez tego siadałby na skrajnej
       kropce osi (dodane 10.09.2026: oś zamyka się też krzyżykiem,
       nie tylko przyciskiem, po który trzeba wiedzieć, że się sięga) */
    padding:22px 12px 2px;
  }
  /* Krzyżyk osi czasu mówi tym samym językiem, co krzyżyki okienek.
     Selektor z #timeline NIE jest ozdobą: niżej w arkuszu stoi reguła
     powiększająca pola dotyku, która nadaje wszystkim .zamknij
     position:relative — przy równej wadze wygrałaby kolejnością
     i krzyżyk rozlałby się na całą szerokość osi (złapane pomiarem). */
  #timeline .tl-zamknij{
    position:absolute;top:3px;right:7px;z-index:2;
    color:var(--text-dim);cursor:pointer;font-size:17px;line-height:1;
    padding:0 3px;user-select:none;
  }
  @media (hover:hover){ #timeline .tl-zamknij:hover{color:#e05555;} }
  #timeline.show{display:block;}
  /* 17.10.2026: oś czasu nie wchodzi pod panel warstw - przy otwartym panelu
     JS ustawia jej środek w wolnym pasie na prawo od panelu (inline left) */
  #timeline{transition:left .2s;}
  /* podpis i cienie przewijania istnieją tylko w postaci „pasek" */
  #tl-podpis{display:none;}
  .tl-cien{display:none;}
  #tl-track{position:relative;height:46px;}
  #tl-track .linia{position:absolute;top:8px;left:6px;right:6px;height:2px;background:var(--line);}
  .tl-dot{
    position:absolute;top:8px;transform:translate(-50%,-50%);
    width:11px;height:11px;border-radius:50%;box-sizing:border-box;
    background:var(--panel);border:2px solid var(--text-dim);cursor:pointer;
    transition:width .15s,height .15s,border-color .15s,background .15s;
  }@media (hover:hover){ .tl-dot:hover{border-color:var(--accent);} }
  .tl-dot.act{width:16px;height:16px;background:var(--accent);border-color:var(--accent);}
  .tl-lbl{
    position:absolute;top:22px;transform:translateX(-50%);
    font-size:10px;color:var(--text-dim);white-space:nowrap;cursor:pointer;user-select:none;
  }@media (hover:hover){ .tl-lbl:hover{color:var(--accent);} }
  .tl-lbl.act{color:var(--accent);font-weight:bold;}
  @media (max-width:640px){
    /* metryka na wąskim ekranie: miniatura nad tekstem, pełna szerokość —
       float 46% zostawiałby kolumnę tekstu szerokości kciuka.
       AUDYT 08.2026: selektor z DWOMA id — ten blok media stoi w arkuszu
       WCZEŚNIEJ niż bazowa reguła #hist-tresc .hist-obraz, więc przy
       równej specyficzności przegrywał i telefon dostawał układ z PC
       (dokładnie ten, przed którym ostrzega komentarz wyżej). */
    #hist-okno #hist-tresc .hist-ramka{float:none;display:block;width:auto;max-width:100%;margin:0 auto 12px;}
    #hist-okno #hist-tresc .hist-obraz{width:100%;max-height:48vh;max-height:48dvh;object-fit:contain;}

    /* atrybucja: PEŁNA szerokość ekranu, jedna linia — dopiero gdy
       treść się nie mieści, wchodzi wielokropek (kropki na końcu).
       Stała wysokość jest tu kluczowa: reszta układu (oś czasu)
       liczy na to, że atrybucja nie urośnie nieprzewidywalnie. */
    .leaflet-control-attribution{
      position:fixed !important;left:0 !important;right:0 !important;
      bottom:0 !important;top:auto !important;
      width:auto !important;max-width:none !important;
      white-space:nowrap !important;text-align:center !important;
      padding:4px 10px !important;box-sizing:border-box !important;
      /* ===== PASEK ŹRÓDEŁ PRZEWIJANY W BOK (10.09.2026) =====
         Wcześniej nadmiar ucinał wielokropek: przy kilku włączonych
         warstwach kończyło się na „…" i nazwisk autorów po prostu nie
         dało się przeczytać. To jest podpis pod cudzą pracą, więc musi
         być DOSTĘPNY w całości — pasek przewija się teraz palcem.
         touch-action:pan-x — pionowy gest zostaje mapie. */
      overflow-x:auto !important;overflow-y:hidden !important;
      overscroll-behavior-x:contain;touch-action:pan-x;
      scrollbar-width:none;-webkit-overflow-scrolling:touch;
      /* iPhone z paskiem gestów: atrybucja przypięta do bottom:0
         wchodziłaby pod systemowy pasek — safe-area ją podnosi,
         na urządzeniach bez wcięcia env() daje 0 i nic się nie zmienia */
      padding-bottom:calc(4px + env(safe-area-inset-bottom)) !important;
    }
    .leaflet-control-attribution::-webkit-scrollbar{display:none;}
    /* Gdy jest co przewijać: tekst od lewej (wyśrodkowany chowałby
       początek w niedostępnym, ujemnym obszarze przewijania) i miękkie
       wygaszenie na tym końcu, po którym coś jeszcze zostało. Szerokości
       wygaszenia ustawia JS pomiarem — 0 px znaczy „tu już nic nie ma". */
    .leaflet-control-attribution.metka-przewijana{
      text-align:left !important;
      -webkit-mask-image:linear-gradient(to right, transparent 0,
        #000 var(--zanik-l, 0px), #000 calc(100% - var(--zanik-p, 0px)), transparent 100%);
      mask-image:linear-gradient(to right, transparent 0,
        #000 var(--zanik-l, 0px), #000 calc(100% - var(--zanik-p, 0px)), transparent 100%);
    }

    /* oś czasu: WŁASNY, osobny pasek (jak na desktopie) — zajmuje
       przestrzeń między lewą krawędzią a słupkiem nawigacyjnym po
       prawej. Odstęp 6px z OBU stron (spójnie ze ściśniętymi
       marginesami panelu i słupka): po lewej do krawędzi ekranu,
       po prawej do lewej krawędzi przycisku „−" (który stoi 6px od
       prawej krawędzi ekranu i ma 34px szerokości na mobile —
       więc 6+34+6=46px daje symetryczne 6px z każdej strony). */
    #timeline.show{left:var(--luz);right:calc(var(--luz) * 2 + var(--slupek, 38px));bottom:calc(var(--metka, 22px) + var(--dol));transform:none;}

    /* cała kolumna nawigacyjna (pełny ekran/zasięg/lokalizacja/zoom)
       jak na desktopie — jeden ciągły słupek, podniesiony tuż nad
       pełnoszerokościową atrybucję */
    /* Słupek: sam pasek Leafletu ma własne 10 px marginesu dolnego,
       więc róg podnosimy o (metka + dół - 10). Efekt: spód +/- stoi
       dokładnie --dol nad paskiem źródeł, tak samo jak oś czasu i panel. */
    .leaflet-bottom.leaflet-right{bottom:calc(var(--metka, 22px) + var(--dol) - 10px) !important;}
    /* podziałka jedzie w słupku prawego rogu — bottom:20px wyżej obejmuje ją razem z nim */
    /* dymek komunikatów GPS stoi w tym samym rzędzie — jego reguła siedzi
       przy geometrii panelu (szuka: „DYMEK: szerokość panelu"), bo to
       z panelem ma być równy */
    /* pasek prowadzenia: pełna szerokość między krawędzią a słupkiem */
    #nawigacja.show{left:var(--luz);right:calc(var(--luz) * 2 + var(--slupek, 38px));transform:none;max-width:none;}
    #nawigacja .nw-cel{max-width:none;}
  }

  /* ===== pasek prowadzenia do obiektu =====
     Nawigacja „po prostej" (jak w geocachingu): strzałka na cel, dystans,
     azymut i dokładność GPS. Do obiektów w lesie nie ma dróg, więc trasa
     drogowa nie ma sensu — liczy się kierunek i odległość. */
  #nawigacja{
    position:absolute;left:50%;transform:translateX(-50%);bottom:24px;z-index:1095;
    display:none;align-items:center;gap:12px;
    background:var(--panel);border:1px solid var(--accent);border-radius:4px;
    box-shadow:var(--shadow);padding:9px 10px 9px 12px;max-width:calc(100% - 24px);
  }
  #nawigacja.show{display:flex;}
  #nawigacja .nw-strzalka{
    width:38px;height:38px;flex-shrink:0;color:var(--accent);
    transition:transform .25s ease-out;
  }
  #nawigacja .nw-strzalka svg{display:block;}
  #nawigacja.blisko{border-color:#4f9d4f;}
  #nawigacja.blisko .nw-strzalka{color:#4f9d4f;}
  #nawigacja .nw-dane{flex:1;min-width:0;}
  #nawigacja .nw-cel{
    /* nazwa obiektu bywa długa („Einmannbunker (schron jednoosobowy)")
       — zawija się do drugiego wiersza zamiast urywać wielokropkiem */
    font-size:12.5px;font-weight:bold;color:var(--text);cursor:pointer;
    line-height:1.35;max-width:44vw;
  }@media (hover:hover){ #nawigacja .nw-cel:hover{color:var(--accent);} }
  #nawigacja .nw-info{
    font-size:11px;color:var(--text-dim);margin-top:2px;line-height:1.45;
  }
  #nawigacja .nw-dyst{color:var(--accent);font-size:13px;font-weight:bold;
    font-variant-numeric:tabular-nums;}
  #nawigacja .nw-skret{color:var(--text);font-weight:bold;}
  #nawigacja .nw-sygnal{white-space:nowrap;cursor:pointer;text-decoration:underline dotted;}
  #nawigacja .nw-stary{color:#c94b4b;}
  /* BRAK SYGNAŁU — stan, nie ostrzeżenie na marginesie. Odczyty z odbiornika
     przychodzą mniej więcej raz na sekundę; cisza dłuższa niż 15 s znaczy,
     że nasłuch zamilkł (las, wąwóz, wnętrze schronu, uśpiony odbiornik).
     Pasek mówi to wprost, a dystans SZARZEJE, bo policzony jest ze starej
     pozycji — w marszu byłby po prostu nieprawdziwy. */
  #nawigacja .nw-brak-gps{
    color:#e05555;font-weight:bold;text-transform:uppercase;letter-spacing:.4px;
    font-size:10px;border:1px solid #e05555;border-radius:3px;padding:1px 5px;
    background:rgba(224,85,85,.12);white-space:nowrap;
  }
  #nawigacja .nw-dyst.nw-martwy{color:var(--text-dim);}
  #nawigacja.bez-gps{border-color:#e05555;}
  #nawigacja.bez-gps .nw-strzalka{opacity:.35;}
  /* dopóki nie wiadomo, w którą stronę patrzysz — strzałka przygaszona,
     żeby nie sugerowała, że wskazuje „przed siebie" */
  #nawigacja.bez-kursu .nw-strzalka{opacity:.55;}
  #nawigacja.blisko .nw-dyst{color:#4f9d4f;}
  #nawigacja .nw-koniec{
    background:transparent;border:1px solid var(--line);color:var(--text-dim);
    font:inherit;font-size:15px;line-height:1;padding:5px 9px;border-radius:3px;
    cursor:pointer;flex-shrink:0;
  }@media (hover:hover){ #nawigacja .nw-koniec:hover{color:#e05555;border-color:#e05555;} }
  /* Pierścień na celu. Pulsuje ROZMIAREM, nie samą przezroczystością:
     wcześniej gasł do opacity .25 i na jasnym ortofoto znikał na pół
     sekundy w każdym cyklu. Teraz najsłabiej ma .5, rośnie o 22 % i ma
     ciemny cień jak obrys — trzyma się na każdym tle. Kolor magenta ten
     sam co linia prowadzenia: pierścień, linia i link „nawiguj tutaj"
     mówią jednym językiem, odrębnym od złota interfejsu. */
  @keyframes nwPuls{
    0%,100%{transform:scale(1);    opacity:1;}
    50%    {transform:scale(1.22); opacity:.5;}
  }
  .nw-puls{
    transform-box:fill-box;transform-origin:center;
    animation:nwPuls 1.6s ease-in-out infinite;
    filter:drop-shadow(0 0 2px rgba(0,0,0,.85));
  }
  @media (prefers-reduced-motion: reduce){ .nw-puls{animation:none;} }
  .fort-pop .nw-link{margin-top:5px;}
  .fort-pop .obj-link-w{margin-top:6px;padding-top:5px;border-top:1px solid var(--line);}
  .fort-pop .obj-link{color:var(--text-dim);font-size:10.5px;}
  @media (hover:hover){ .fort-pop .obj-link:hover{color:var(--accent);} }
  /* miejsce po „prowadź tutaj” w przeglądarce z odciętym GPS-em —
     szara linijka mówi wprost, czego brakuje i gdzie to zadziała */
  .fort-pop .nw-brak{margin-top:5px;color:var(--text-dim);font-size:10.5px;line-height:1.45;}
  .fort-pop .nw-link a{color:var(--accent);}@media (hover:hover){ .fort-pop .nw-link a:hover{color:var(--accent-2);} }

  /* ===== okno „Źródła i podziękowania" ===== */
  /* Przyciemnienie tła jest zarazem RAMĄ na okno: padding pilnuje, żeby
     okno nigdy nie weszło pod górną belkę ani na pasek źródeł, i trzyma
     te same marginesy boczne, co panel warstw. Jedna reguła dla PC
     i telefonu — na telefonie różni się tylko szerokością samego okna. */
  #zrodla-overlay{
    position:absolute;inset:0;z-index:11100;background:rgba(0,0,0,.55);
    display:none;align-items:center;justify-content:center;
    box-sizing:border-box;
    padding:calc(var(--pasek, 52px) + 6px) var(--luz) calc(var(--metka, 22px) + var(--dol));
  }
  #zrodla-overlay.show{display:flex;}
  #zrodla-okno{
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);max-width:560px;width:100%;
    max-height:100%;display:flex;flex-direction:column;overflow:hidden;
  }
  #zrodla-okno .naglowek{
    display:flex;align-items:center;padding:9px 12px;background:var(--panel-2);
    border-bottom:1px solid var(--line);
  }
  #zrodla-okno .naglowek .t{
    flex:1;font-size:12px;letter-spacing:.5px;color:var(--accent);
    text-transform:uppercase;font-weight:bold;
  }
  #zrodla-okno .zamknij{
    color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 4px;user-select:none;
  }@media (hover:hover){ #zrodla-okno .zamknij:hover{color:#e05555;} }
  #zrodla-tresc{
    overflow-y:auto;padding:14px 16px;font-size:12.5px;line-height:1.7;color:var(--text);
  }
  #zrodla-tresc h3{
    color:var(--accent);font-size:12.5px;margin:12px 0 4px;
  }
  #zrodla-tresc h3:not(:first-child){
    margin-top:18px;padding-top:14px;border-top:1px solid var(--line);
  }
  #zrodla-tresc h3:first-child{margin-top:0;}
  #zrodla-tresc p{margin:0 0 8px;}
  #zrodla-tresc a{color:var(--link);}

  /* ===== okno rysu historycznego warstwy ===== */
  #hist-overlay{
    position:absolute;inset:0;z-index:11100;background:rgba(0,0,0,.55);
    display:none;align-items:center;justify-content:center;
    box-sizing:border-box;
    padding:calc(var(--pasek, 52px) + 6px) var(--luz) calc(var(--metka, 22px) + var(--dol));
  }
  #hist-overlay.show{display:flex;}
  #hist-okno{
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);max-width:860px;width:100%;
    max-height:100%;display:flex;flex-direction:column;overflow:hidden;
  }
  #hist-okno .naglowek{
    display:flex;align-items:center;padding:9px 12px;background:var(--panel-2);
    border-bottom:1px solid var(--line);
  }
  #hist-okno .naglowek .t{
    flex:1;font-size:12px;letter-spacing:.5px;color:var(--accent);
    text-transform:uppercase;font-weight:bold;
  }
  #hist-okno .zamknij{
    color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 4px;user-select:none;
  }@media (hover:hover){ #hist-okno .zamknij:hover{color:#e05555;} }
  #hist-tresc{
    overflow-y:auto;padding:16px 18px;font-size:13px;line-height:1.75;color:var(--text);
  }
  /* zdjęcie w metryce = MINIATURA pływająca po prawej, opływana tekstem —
     wizualne wzbogacenie opisu; klik otwiera większą wersję. Gdy metryka
     nie ma tekstu, zdjęcie wraca do wyśrodkowanego bloku. */
  /* OPAKOWANIE niesie układ i nakładki; obraz w środku jest nietknięty */
  #hist-tresc .hist-ramka{
    float:right;width:min(46%, 280px);margin:3px 0 10px 16px;
    position:relative;display:block;line-height:0;overflow:hidden;
    border:1px solid var(--line);border-radius:3px;background:var(--bg);
    box-shadow:0 2px 8px rgba(0,0,0,.35);
  }
  #hist-tresc .hist-obraz{
    display:block;width:100%;height:auto;cursor:zoom-in;border-radius:2px;
  }
  /* winieta — jedyna nakładka nieruchoma, przyciemnia narożniki
     jak odbitka leżąca latami w albumie */
  #hist-tresc .hist-ramka::before{
    content:'';position:absolute;inset:0;pointer-events:none;z-index:2;
    border-radius:2px;
    box-shadow:inset 0 0 24px rgba(18,12,3,.34), inset 0 0 60px rgba(18,12,3,.16);
  }

  /* Najechanie unosi całą ramkę cieniem — nie koliduje z nakładkami */
  #hist-tresc a.hist-ramka{transition:box-shadow .18s ease;}
  @media (hover:hover){ #hist-tresc a.hist-ramka:hover{box-shadow:0 7px 18px rgba(0,0,0,.6);} }
  #hist-tresc .hist-obraz.bez-linku{cursor:default;}
  #hist-tresc .hist-ramka.solo{
    float:none;display:block;width:auto;max-width:100%;margin:0 auto 14px;
  }
  #hist-tresc .hist-ramka.solo .hist-obraz{max-height:58vh;max-height:58dvh;width:auto;margin:0 auto;}
  /* ===== okno zabytku =====
     Trzecia siostra okien modalnych (po źródłach i metryce warstwy) —
     ten sam szkielet, bo użytkownik ma je rozpoznawać jako jedną rodzinę.
     Różnice celowe:
       - tytuł NIE jest wersalikowany: to nazwa własna obiektu i wielkie
         litery zjadłyby pracę, którą redakcja wkłada w pisownię
         („Kościół pw. św. Antoniego” to nie „KOŚCIÓŁ PW. ŚW. ANTONIEGO”);
       - węższe niż metryka (620 px), bo treść to jedna kolumna tekstu
         i jedno zdjęcie, a nie tabela źródeł;
       - pasek akcji STOI POZA obszarem przewijania. Przy opisie na 1500
         znaków „nawiguj do obiektu” schowane pod tekstem byłoby nie do
         znalezienia akurat tam, gdzie jest najpotrzebniejsze — w terenie,
         na telefonie. Pusty pasek znika sam (:empty). */
  #zab-overlay{
    position:absolute;inset:0;z-index:11100;background:rgba(0,0,0,.55);
    display:none;align-items:center;justify-content:center;
    box-sizing:border-box;
    padding:calc(var(--pasek, 52px) + 6px) var(--luz) calc(var(--metka, 22px) + var(--dol));
  }
  #zab-overlay.show{display:flex;}
  #zab-okno{
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);max-width:720px;width:100%;
    max-height:100%;display:flex;flex-direction:column;overflow:hidden;
  }
  #zab-okno .naglowek{
    display:flex;align-items:flex-start;gap:8px;padding:9px 12px;
    background:var(--panel-2);border-bottom:1px solid var(--line);
  }
  #zab-okno .naglowek .t{
    flex:1;font-size:13px;line-height:1.35;color:var(--accent);
    font-weight:bold;text-transform:none;letter-spacing:0;
  }
  #zab-okno .zamknij{
    color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 4px;user-select:none;
  }@media (hover:hover){ #zab-okno .zamknij:hover{color:#e05555;} }
  /* ZBITY TEKST (7.09.2026, uwaga użytkownika przy pierwszym prawdziwym
     opisie pocztówki): 1,75 interlinii + 9 px między akapitami rozciągało
     1200 znaków na dwa ekrany. Teraz 1,5 i 6 px — gęstość książkowa; przy
     13 px czcionki nadal czytelnie. Wypunktowania (linie od „- ") składają
     się w zwartą listę zamiast osobnych akapitów. */
  #zab-tresc{
    overflow-y:auto;padding:12px 16px 14px;font-size:13px;line-height:1.5;color:var(--text);
  }
  #zab-tresc .zab-solo{margin:0 0 12px;line-height:0;}
  #zab-tresc .zab-solo img{
    display:block;width:100%;height:auto;max-height:44vh;max-height:44dvh;object-fit:contain;
    border:1px solid var(--line);border-radius:3px;background:var(--bg);cursor:zoom-in;
  }
  /* PARA ZDJĘĆ: ZDJĘCIE WIODĄCE NARZUCA RAMKĘ (7.09.2026, druga iteracja).
     Pierwsze podejście — dwie ramki o stałej wysokości z object-fit:contain
     — dało równe podpisy, ale wielkie ciemne pasy nad i pod zdjęciem
     (uwaga użytkownika: „rozciągamy dziś do parametrów przodu"). Teraz:
       - zdjęcie WIODĄCE (archiwalne „wtedy" / awers pocztówki) wyświetla
         się CAŁE, bez kadrowania, w ramce o własnych proporcjach
         (aspect-ratio z naturalWidth/naturalHeight, ustawiane po
         wczytaniu; do tego czasu 3:2), nie wyższej niż 40 vh i nie szerszej
         niż 62% okna;
       - zdjęcie TOWARZYSZĄCE („dziś", rewers) dostaje resztę szerokości
         i DOKŁADNIE tę samą wysokość, wypełniając ramkę kadrowaniem
         (object-fit: cover) — to zdjęcie pomocnicze, przycięcie brzegów
         nic mu nie odbiera, a skan artefaktu zostaje nietknięty.
     Podpisy stoją w jednej linii, ciemnych pasów nie ma. */
  #zab-tresc .zab-para{display:flex;gap:8px;margin:0 0 10px;align-items:stretch;}
  #zab-tresc .zab-para figure{margin:0;min-width:0;display:flex;flex-direction:column;--ar:1.5;}
  #zab-tresc .zab-para figure.wiodaca{flex:0 0 auto;width:min(62%, calc(40vh * var(--ar)));width:min(62%, calc(40dvh * var(--ar)));}
  #zab-tresc .zab-para figure.wiodaca .kadr{aspect-ratio:var(--ar);}
  #zab-tresc .zab-para figure:not(.wiodaca){flex:1 1 0;}
  #zab-tresc .zab-para .kadr{position:relative;flex:1 1 auto;min-height:0;border:1px solid var(--line);
    background:var(--bg);border-radius:3px;overflow:hidden;}
  #zab-tresc .zab-para .kadr img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
    cursor:zoom-in;display:block;border:0;border-radius:0;margin:0;}
  #zab-tresc .zab-para figure.wiodaca .kadr img{object-fit:contain;}
  /* trzecie zdjęcie pod parą (rewers pocztówki) — samo, węższe, wyśrodkowane */
  #zab-tresc .zab-para.zab-para-solo{justify-content:center;}
  #zab-tresc .zab-para.zab-para-solo figure.wiodaca{width:min(56%, calc(30vh * var(--ar)));width:min(56%, calc(30dvh * var(--ar)));}
  #zab-tresc .zab-opis p{margin:0 0 6px;}
  #zab-tresc .zab-opis p:last-child,#zab-tresc .zab-opis ul:last-child{margin-bottom:0;}
  #zab-tresc .zab-opis h3{color:var(--accent);font-size:12.5px;margin:10px 0 4px;}
  #zab-tresc .zab-opis ul,#hist-tresc ul{margin:0 0 6px;padding-left:1.15em;}
  #zab-tresc .zab-opis li,#hist-tresc li{margin:0 0 2px;}
  /* Wiersz dłuższy niż mniej więcej 75 znaków męczy przy czytaniu — oko
     gubi początek następnej linii. Przy zdjęciu pływającym problem znika
     sam (kolumna jest wąska), ale obiekt BEZ zdjęcia dostałby całą
     szerokość okna, więc kładziemy granicę. */
  #zab-tresc .zab-opis{max-width:74ch;}
  /* …ale pod PARĄ zdjęć tekst idzie na całą szerokość (7.09.2026, uwaga
     użytkownika „tekst nie nadąża za grafiką"): para zajmuje pełne okno,
     a kolumna tekstu urwana na 74ch zostawiała pod prawym zdjęciem pusty
     pas — wyglądało to na błąd, nie na typografię. 720 px okna to ok. 85
     znaków wiersza; więcej niż podręcznikowe 75, ale wyrównanie krawędzi
     ze zdjęciami jest tu ważniejsze. */
  #zab-tresc .zab-para ~ .zab-opis{max-width:none;}
  #zab-tresc .zab-pusto{color:var(--text-dim);font-style:italic;}
  /* ZDJĘCIE OPŁYWANE TEKSTEM na szerokim ekranie — to samo rozwiązanie,
     co w metryce warstwy (.hist-ramka). Pionowa kolumna „zdjęcie, pod nim
     tekst" jest właściwa na telefonie, ale na monitorze marnuje pół
     szerokości i spycha opis pod ekran.
     Klasę `plyw` dokłada JavaScript i TYLKO wtedy, gdy jest co opływać —
     przy pustym opisie zdjęcie wraca na środek jako blok, bo pływające
     zdjęcie bez tekstu obok wygląda jak błąd składu.
     Para „wtedy | dziś" NIE pływa: dwa kadry ściśnięte do 150 px nie
     pokazują już niczego poza tym, że coś tam jest — zostaje blokiem
     nad tekstem, w pełnej szerokości.
     Float mieści się w #zab-tresc, bo overflow-y:auto tworzy tam własny
     kontekst formatowania — nie wychodzi więc na pasek akcji. */
  @media (min-width:700px){
    #zab-tresc .zab-solo.plyw{
      float:right;width:min(44%, 320px);margin:2px 0 12px 18px;
    }
    #zab-tresc .zab-solo.plyw img{max-height:none;}
  }
  #zab-akcje{
    display:flex;flex-wrap:wrap;gap:6px 18px;align-items:center;
    padding:10px 16px;border-top:1px solid var(--line);background:var(--panel-2);
    font-size:12px;
  }
  #zab-akcje:empty{display:none;}
  #zab-akcje a{color:var(--link);}
  #zab-akcje .nw-brak{color:var(--text-dim);font-style:italic;}
  /* na wąskim ekranie para zdjęć jedno pod drugim — dwa kadry po 160 px
     szerokości nie pokazują już niczego poza tym, że coś tam jest */
  @media (max-width:520px){
    /* jedno pod drugim: wiodące pełną szerokością we własnych proporcjach,
       towarzyszące w ramce 3:2 (cover) — równanie wysokości zbędne */
    #zab-tresc .zab-para{flex-direction:column;}
    #zab-tresc .zab-para figure.wiodaca,#zab-tresc .zab-para.zab-para-solo figure.wiodaca{width:100%;flex:0 0 auto;}
    #zab-tresc .zab-para figure.wiodaca .kadr{max-height:40vh;max-height:40dvh;}
    #zab-tresc .zab-para figure:not(.wiodaca){flex:0 0 auto;}
    #zab-tresc .zab-para figure:not(.wiodaca) .kadr{aspect-ratio:3/2;}
  }

  /* ===== lupa: zdjęcie z dymka i z metryki w większym rozmiarze =====
     Obraz dostaje SAME ograniczenia (max-width / max-height), bez podanej
     szerokości — dzięki temu przeglądarka pokazuje go w rozmiarze własnym,
     a zmniejsza tylko wtedy, gdy nie mieści się na ekranie. Rozciągania
     w górę nie ma świadomie: w media/ leżą pliki 800 px i rozmyta plama
     przez pół monitora byłaby gorsza niż ostre zdjęcie. */
  #lupa{
    position:fixed;inset:0;z-index:12000;background:rgba(0,0,0,.86);
    display:none;align-items:center;justify-content:center;
    -webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px);
  }
  #lupa.show{display:flex;}
  #lupa-ramka{margin:0;padding:0;max-width:94vw;max-height:92vh;max-height:92dvh;
              display:flex;flex-direction:column;align-items:center;}
  #lupa-obraz{
    display:block;max-width:94vw;max-height:86vh;max-height:86dvh;width:auto;height:auto;
    border:1px solid var(--line);border-radius:3px;background:var(--panel);
    box-shadow:0 10px 40px rgba(0,0,0,.7);
  }
  #lupa-podpis{
    margin-top:9px;color:var(--text-dim);font-size:12px;text-align:center;
    max-width:94vw;line-height:1.5;
  }
  #lupa-podpis b{color:var(--accent);font-weight:bold;}
  #lupa .lupa-zamknij{
    position:absolute;top:10px;right:16px;color:var(--text-dim);
    font-size:30px;line-height:1;cursor:pointer;user-select:none;padding:2px 8px;
  }@media (hover:hover){ #lupa .lupa-zamknij:hover{color:#e05555;} }
  /* Lupka „+" na miniaturze otwiera, lupka „−" na powiększeniu zamyka
     (7.09.2026, pomysł użytkownika): kursor zoom-out nad zdjęciem i klik
     w nie zamyka lupę — tak samo jak ×, Esc i klik w tło. Strzałki
     przewijania leżą poza zdjęciem, więc nic im to nie psuje. */
  #lupa-obraz{cursor:zoom-out;}
  #lupa .lupa-strzalka{
    position:absolute;top:50%;transform:translateY(-50%);display:none;
    color:var(--text-dim);font-size:44px;line-height:1;cursor:pointer;
    user-select:none;padding:6px 14px;
  }
  #lupa.wiele .lupa-strzalka{display:block;}
  #lupa .lupa-strzalka.lewo{left:8px;}
  #lupa .lupa-strzalka.prawo{right:8px;}
  @media (hover:hover){ #lupa .lupa-strzalka:hover{color:var(--accent);} }
  /* miniatura w dymku ma mówić, że da się w nią kliknąć */
  .leaflet-popup-content .fort-pop img{cursor:zoom-in;}
  #hist-tresc .hist-meta{clear:both;}
  #hist-tresc h3{color:var(--accent);font-size:12.5px;margin:14px 0 4px;}
  #hist-tresc h3:first-child{margin-top:0;}
  /* ===== motyw kreski z logo w nagłówkach — ZDJĘTY 8.09.2026 =====
     Krótka złota kreska stała przed śródtytułami metryki „i", pozycjami
     w oknie Źródła i tytułami okien Ustawienia/Sesja (audyt 08.2026,
     miała powtarzać język belek grup). Na żywo czytała się jak długi
     żółty myślnik doklejony do nagłówka i rozbijała ich początek —
     nagłówki i tak wyróżnia złoto, wersaliki i odstęp, więc kreska nie
     niosła nic ponadto. Reguła usunięta w całości (mx-cap „Aktywne
     warstwy" nigdy jej nie miał: obok ekspanderów +/− czytała się jak
     minus czegoś niezwijalnego). Panel redakcyjny zostaje bez zmian —
     tam podnagłówki mają własną kreskę i to zostało świadomie. */
  /* pion w nazwach warstw („Mapa | Messtischblatt…") — w kolorze tekstu.
     Był złoty jako echo kreski z logo, ale przy kilkunastu warstwach na
     liście robiło się z tego pole złotych akcentów walczących o uwagę
     z belkami grup i latami. Separator ma rozdzielać, nie świecić. */
  .pion{color:inherit;}
  #hist-tresc p{margin:0 0 8px;}
  /* opis (metryka) jako pierwszy akapit okna — odstęp od rysu historycznego */
  #hist-tresc .hist-lead{margin:0 0 12px;}
  #hist-tresc .hist-lead p:last-child{margin-bottom:0;}
  #hist-tresc a{color:var(--link);}
  #hist-tresc .hist-meta{
    margin-top:14px;padding-top:10px;border-top:1px solid var(--line);
    color:var(--text-dim);font-size:12px;line-height:1.7;
  }
  /* separator między pozycjami „Źródła:" — złote podkreślone linki
     rozdzielone drobną kropką zlewały się w jeden ciąg; szara pionowa
     kreska z oddechem tnie listę wyraźnie, a kolorem NIE udaje złotego
     pionu z nazw warstw (tamten jest marką, ten jest interpunkcją).
     Krycie 1, nie .95: kreska ma być DOKŁADNIE w kolorze słowa „Źródła:",
     a przy jednopikselowym pionie każde ściemnienie widać od razu —
     cienki glif i tak wygląda lżej niż litery o pełnej grubości. */
  #hist-tresc .hist-meta .zr-sep{
    color:var(--text-dim);margin:0 5px;font-weight:normal;
  }

  /* ===== mikser aktywnych warstw ===== */
  #mixer{
    display:none;border-bottom:1px solid var(--line);background:var(--panel-2);padding-bottom:5px;
    flex-shrink:0;max-height:220px;overflow-y:auto;
  }
  #mixer.show{display:block;}
  /* uchwyt zmiany wysokości okna aktywnych warstw — wąska belka pod
     mikserem z pigułką po środku; widoczna tylko razem z mikserem.
     Przeciąganie pionowe zmienia max-height (pointer events — działa
     myszą i palcem; natywne CSS resize odpada, bo nie obsługuje
     dotyku), podwójny klik przywraca domyślną wysokość */
  #mixer-resize{
    display:none;height:13px;flex-shrink:0;cursor:ns-resize;touch-action:none;
    background:var(--panel-2);border-bottom:1px solid var(--line);
    align-items:center;justify-content:center;user-select:none;
  }
  #mixer.show + #mixer-resize{display:flex;}
  #mixer-resize span{width:34px;height:3px;border-radius:2px;background:var(--line);}#mixer-resize.rsz span{background:var(--accent);}
  /* Pole chwytu pod palec (11.09.2026): 13 px wysokości to połowa
     minimum, w które da się trafić opuszką (24 px wg WCAG 2.2). Na
     telefonie pasek jest wyższy, a sama kreska zostaje tej samej
     grubości — rośnie pole, nie ozdoba. */
  @media (max-width:640px){
    #mixer-resize{height:26px;}
    #mixer-resize span{width:44px;height:4px;}
  }
  @media (hover:hover){ #mixer-resize:hover span{background:var(--accent);} }
  /* „Aktywne warstwy" (wygląd: nagłówki sekcji) nie odjeżdża przy
     przewijaniu długiego miksera - wiersze chowają się pod nim */
  #mixer .mx-cap{position:sticky;top:0;z-index:2;}
  .mx-item{padding:5px 12px 6px;}
  .mx-item + .mx-item{border-top:1px solid var(--line);}
  .mx-item.dragging{opacity:.45;}
  /* oko tymczasowej widoczności: schowany wiersz zostaje w mikserze
     (suwak, kolejność, strony kurtyny — wszystko nietknięte), tylko
     przygasa; samo oko trzyma pełną widoczność, żeby dało się łatwo
     trafić z powrotem */
  .mx-eye{flex-shrink:0;color:var(--text-dim);cursor:pointer;line-height:0;padding:2px 3px;}@media (hover:hover){ .mx-eye:hover{color:var(--accent);} }
  .mx-item.mx-hidden .mx-name,
  .mx-item.mx-hidden .mx-ctrl,
  .mx-item.mx-hidden .mx-drag{opacity:.4;}
  .mx-item.mx-hidden .mx-eye{color:var(--accent);}
  .mx-head{display:flex;align-items:center;gap:7px;margin-bottom:4px;}
  .mx-drag{
    flex-shrink:0;color:var(--text-dim);cursor:grab;user-select:none;
    font-size:13px;line-height:1;padding:1px 2px;touch-action:none;
  }@media (hover:hover){ .mx-drag:hover{color:var(--accent);} }
  .mx-item.dragging .mx-drag{cursor:grabbing;}
  .mx-name{
    flex:1;min-width:0;display:block;font-size:11px;font-weight:bold;color:var(--accent);
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  }
  /* kropka „kafelki się wczytują" przy nazwie warstwy w mikserze */
  .mx-item.laduje .mx-name::after{
    content:'';display:inline-block;width:6px;height:6px;border-radius:50%;
    background:var(--accent);margin-left:7px;vertical-align:1px;
    animation:geoPuls 1.1s ease-in-out infinite;
  }
  @media (prefers-reduced-motion: reduce){
    .mx-item.laduje .mx-name::after{animation:none;opacity:.6;}
  }
  .mx-name.clickable{cursor:pointer;}@media (hover:hover){ .mx-name.clickable:hover{color:var(--accent-2);} }
  .mx-name.tracked{text-decoration:underline;text-underline-offset:3px;}
  .mx-ctrl{display:flex;align-items:center;gap:8px;}
  .mx-ctrl input[type=range]{flex:1;min-width:56px;accent-color:var(--accent);height:14px;margin:0;}
  /* suwak warstwy wybranej ramką/zakładką/nazwą — różowy jak jej obrys */
  /* wybrana warstwa (klik w obrys / zakładkę / nazwę): różowy guzik suwaka
     + podbicie CAŁEGO wiersza — sam kciuk był za subtelny, wiersz ma być
     znajdowalny kątem oka, bez czytania etykiet */
  .mx-item.mx-focus .mx-ctrl input[type=range]{accent-color:#ff4d6d;}
  .mx-item.mx-focus{
    background:rgba(255,77,109,.13);
    box-shadow:inset 3px 0 0 #ff4d6d; /* pasek przy lewej krawędzi bez ruszania layoutu */
    border-radius:3px;
  }
  .mx-sides{flex-shrink:0;display:flex;}
  .mx-side{
    font-size:10px;padding:3px 7px;background:transparent;
    border:1px solid var(--line);color:var(--text-dim);
    cursor:pointer;font-family:inherit;font-weight:bold;line-height:1.2;
  }
  .mx-side[data-side="L"]{border-radius:3px 0 0 3px;border-right:none;}
  .mx-side[data-side="R"]{border-radius:0 3px 3px 0;}@media (hover:hover){ .mx-side:hover{color:var(--accent);border-color:var(--accent);} }@media (hover:hover){ .mx-side:hover + .mx-side{border-left-color:var(--accent);} }
  .mx-side.active{background:var(--accent);color:#1a1a1a;border-color:var(--accent);text-shadow:0 0 .65px currentColor;}
  .mx-off{
    flex-shrink:0;color:var(--text-dim);cursor:pointer;font-size:15px;line-height:1;
    padding:0 4px;user-select:none;
  }@media (hover:hover){ .mx-off:hover{color:#e05555;} }

  /* ===== zwijane opisy warstw ===== */
  .layer .desc{display:none;}
  .layer.desc-open .desc{display:block;}
  .layer .dtog{
    flex-shrink:0;color:var(--text-dim);cursor:pointer;
    padding:0 7px;user-select:none;
    display:inline-flex;align-items:center; /* SVG idealnie w osi wiersza (na równi z datą) */
  }@media (hover:hover){ .layer .dtog:hover{color:var(--accent-2);} }
  /* ikonka z wypełnionym rysem historycznym świeci akcentem — widać,
     gdzie kliknięcie otworzy duże okno, a gdzie tylko krótki opis */
  .layer .dtog.ma-hist{color:var(--accent);}
  .layer{padding:9px 12px;border-bottom:1px solid var(--line);}
  .layer:last-child{border-bottom:none;}
  .layer .row{display:flex;align-items:center;gap:8px;}
  .layer .name{flex:1;font-weight:bold;color:var(--text);font-size:12px;cursor:default;}
  .layer.on .name{cursor:pointer;}@media (hover:hover){ .layer.on .name:hover{color:var(--accent);} }
  .layer .year{color:var(--accent);font-size:10px;font-weight:bold;}
  /* rozdzielczość źródła wprost w wierszu (31.08) — przy siedmiu rocznikach
     ortofoto różniących się pikselem terenowym porównanie wymagało otwierania
     metryki każdej warstwy po kolei. To jest jedna liczba i ma być widoczna
     od razu. Cicho: kolor przygaszony, bez pogrubienia, ten sam stopień co rok —
     data zostaje najmocniejszym elementem po nazwie. */
  .layer .jakosc{
    flex-shrink:0;color:var(--text-dim);font-size:10px;letter-spacing:.2px;
    white-space:nowrap;font-weight:normal;
  }
  .layer input[type=checkbox]{accent-color:var(--accent);width:15px;height:15px;cursor:pointer;}
  .layer .desc{color:var(--text-dim);font-size:11px;margin:4px 0 0 23px;line-height:1.5;}
  .layer .desc a{color:var(--accent);}@media (hover:hover){ .layer .desc a:hover{color:var(--accent-2);} }

  #base-picker{padding:0 12px 9px;border-top:1px solid var(--line);background:var(--panel-2);flex-shrink:0;
    border-radius:0 0 3px 3px;}
  /* nagłówek sekcji (wyżej) na całą szerokość panelu - ujemny margines
     zjada boczny padding, wnętrze zostaje tej samej szerokości, więc
     prostokąciki tła dalej stoją dokładnie nad „Brak" */
  #base-picker .lbl{margin:0 -12px 8px;justify-content:space-between;}
  /* TŁO MAPY (24.09.2026): dwa prostokąciki przy nagłówku - kolor motywu albo białe.
     Widać je przy podkładzie „Brak" i wszędzie, gdzie podkład nie sięga.
     25.09 (pavvlo): próba kółek odrzucona - na ekranie 1× łuk pikselował. Prostokąty wracają:
     PARA razem ma szerokość przycisku „Brak" i siedzi dokładnie nad nim (ta sama siatka: .tlo =
     ćwierć wiersza minus 3/4 odstępu 6 px z .opts, w środku dwa flex:1 z odstępem 4 px). Obwódka nieaktywnego w kolorze przygaszonego tekstu (--line ginęła przy ciemnym
     na ciemnym); aktywne = pełna 2 px złota obwódka - pośrednia między dawną 3 px ramą
     („przesadnie gruba") a 1 px pierścieniem („zbyt mała"). */
  #base-picker .lbl > span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  #base-picker .tlo{display:flex;gap:4px;align-items:center;width:calc(25% - 4.5px);flex-shrink:0;}
  body.bez-wyboru-tla #base-picker .tlo{display:none;}   /* 25.09: wybór tła schowany (TLO_WYBOR = false) - wraca kiedyś */   /* 25.09: OBA kolory razem szerokości przycisku „Brak" - para siedzi dokładnie nad nim (ćwierć wiersza minus 3/4 odstępu 6 px) */
  #base-picker .tlo-btn{flex:1;height:14px;box-sizing:border-box;padding:0;margin:0;border:1px solid var(--text-dim);border-radius:2px;background:var(--bg);cursor:pointer;}
  #base-picker .tlo-btn[data-tlo="biale"]{background:#f8f8f6;}
  [data-theme="light"] #base-picker .tlo-btn[data-tlo="biale"]{background:#fff;}   /* w jasnym motywie białe tło = czysta biel, prostokącik tak samo */
  #base-picker .tlo-btn.active{border-color:var(--accent);box-shadow:inset 0 0 0 1px var(--accent);}   /* 1 px obwódki + 1 px cienia do środka = 2 px złota bez zmiany rozmiaru (flex dzieliłby szerokość nierówno przy różnych grubościach obwódek) */
  @media (hover:hover){ #base-picker .tlo-btn:hover{border-color:var(--accent-2);} }
  #base-picker .tlo-btn:focus-visible{outline:1px solid var(--accent-2);outline-offset:2px;}
  @media (max-width:640px){ #base-picker .tlo-btn{height:18px;} }   /* palec: wyższe */
  body.tlo-biale #map{background-color:#f8f8f6;}   /* background-COLOR, nie skrót - skrót skasowałby kreskowanie „bez sieci" */
  [data-theme="light"] body.tlo-biale #map{background-color:#ffffff;}
  body.tlo-biale.bez-sieci #map{background-image:repeating-linear-gradient(45deg, transparent 0 10px, rgba(0,0,0,.055) 10px 20px);}
  #base-picker .opts{display:flex;gap:6px;}
  #base-picker .opts button{flex:1;font-size:11px;} /* stopień belek grup, nie 12 z .btn */

  /* ===== kurtyna ===== */
  #curtain{
    position:absolute;top:0;bottom:0;width:2px;background:var(--accent);z-index:1050;
    cursor:ew-resize;display:none;box-shadow:0 0 8px rgba(0,0,0,.6);touch-action:none;
    transition:opacity .2s;
  }
  #curtain.dragging{opacity:.25;}
  #curtain.dragging ~ .ctag{opacity:0;}
  #curtain::before{
    content:'';position:absolute;top:0;bottom:0;left:-6px;right:-6px;cursor:ew-resize;
  }
  /* uchwyt kurtyny — samodzielny element NAD panelem warstw (1150),
     żeby dało się go złapać nawet, gdy linia stoi pod panelem */
  #curtain-grip{
    position:absolute;top:50%;z-index:1150;display:none;transform:translate(-50%,-50%);
    width:34px;height:34px;border-radius:50%;background:var(--accent);color:#1a1a1a;
    align-items:center;justify-content:center;
    font-size:16px;font-weight:bold;line-height:1;padding-bottom:3px;box-sizing:border-box;
    cursor:ew-resize;touch-action:none;user-select:none;box-shadow:0 0 8px rgba(0,0,0,.55);
    transition:opacity .15s;
  }
  /* w trakcie przeciągania guzik znika całkiem — nie zasłania porównania;
     przezroczystość nie wyłącza zdarzeń, a wskaźnik jest i tak złapany
     (pointer capture), więc przeciąganie działa bez zakłóceń */
  #curtain-grip.dragging{opacity:0;}
  /* dymki kurtyny — samodzielne elementy NAD panelem warstw i licznikiem
     (z-index 1150 > 1100), pod górnym paskiem (11000); górna krawędź
     równo z licznikiem powiększenia. Pozycję względem linii ustawia
     applyCurtain(). */
  .ctag{
    position:absolute;top:52px;z-index:1150;display:none;
    background:var(--panel);border:1px solid var(--line);border-radius:3px;
    padding:3px 8px;font-size:10.5px;color:var(--text);box-shadow:var(--shadow);
    white-space:normal;width:max-content;max-width:300px;line-height:1.45;
    transition:opacity .2s;
  }
  #tag-l{text-align:right;}
  #tag-r{text-align:left;}

  /* ===== metka fotomapy =====
     Podpis wisi POD panelem warstw jak przyszyta metka: to dziecko
     #sidebara, więc jedzie z nim wszystkim, co panel robi — chowaniem
     przyciskiem „Warstwy", ucieczką przed kurtyną, startem na telefonie.
     Nic nie trzeba synchronizować, bo to jeden i ten sam ruch.
     Wystaje spod dolnej krawędzi (panel ma overflow:visible), przykleja
     się do niej bez szwu: brak górnej ramki i ujemny margines zjadają
     podwójną kreskę. pointer-events:none — metka niczego nie zasłania. */
  #znak{
    position:absolute;top:100%;left:-1px;right:-1px;margin-top:-1px;
    background:var(--panel);color:var(--text-dim);
    border:1px solid var(--line);border-top:none;border-radius:0 0 4px 4px;
    box-shadow:0 3px 8px rgba(0,0,0,.35);
    font-size:10px;line-height:1.4;padding:3px 9px 4px;white-space:nowrap;
    /* podpis dosunięty do prawej — tam, gdzie panel trzyma wszystkie
       elementy drugorzędne („rozwiń” na belkach grup, „zwiń” w nagłówku);
       wyśrodkowanie było jedynym centrowanym tekstem w całym panelu */
    text-align:right;
    /* pełne krycie — belka ma być tak samo „lita" jak reszta panelu
       (wcześniejsze .7 prześwitywało mapą i podpis tracił czytelność) */
    opacity:1;
    pointer-events:none;user-select:none;-webkit-user-select:none;
  }
  /* sam adres jest odnośnikiem na stronę główną — klikalny wyjątek
     w nieklikalnej metce (pointer-events wraca tylko na kotwicy) */
  #znak a{color:var(--link);text-decoration:none;pointer-events:auto;}
  @media (hover:hover){ #znak a:hover{color:var(--accent-2);text-decoration:underline;} }

  #loading{
    position:absolute;inset:0;z-index:13000;background:var(--bg);
    display:flex;align-items:center;justify-content:center;flex-direction:column;gap:12px;
  }
  #loading{transition:opacity .35s ease;}
  #loading.znika{opacity:0;pointer-events:none;}
  /* 17.10.2026 (pavvlo: „ograniczyć wyświetlanie logo wczytywania warstw", wybór
     „raz dziennie"): pełna choreografia FOTO|MAPA tylko przy pierwszym otwarciu
     danego dnia na urządzeniu; kolejne otwarcia - sam ciemny ekran ze statusem,
     znika, gdy warstwy są gotowe (klasa .krotko, nadawana zaraz pod znacznikiem) */
  #loading.krotko > div:first-child{display:none;}
  #loading.krotko .s{animation:none;opacity:1;}

  /* ===== PUNKTY Z TERENU (17.10.2026) — okno „Zaznacz punkt" =====
     Arkusz od dołu (telefon w ręku, kciuk), mapa nad nim zostaje widoczna,
     bo na niej stoi znacznik do ewentualnego przeciągnięcia. */
  #teren-okno{position:absolute;left:var(--luz, 10px);bottom:calc(var(--metka, 22px) + 8px);z-index:12000;
    width:min(380px, calc(100% - 3 * var(--luz, 10px) - var(--slupek, 38px)));max-height:62%;overflow:auto;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;box-shadow:var(--shadow);
    padding:12px 14px 12px;display:none;font-size:12.5px;}
  #teren-okno.show{display:block;}
  #teren-okno h3{margin:0 0 8px;font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--accent);}
  #teren-okno .t-zamknij{position:absolute;top:6px;right:9px;cursor:pointer;color:var(--text-dim);font-size:17px;line-height:1;}
  #teren-okno .t-gps{background:var(--panel-2, #262626);border:1px solid var(--line);border-radius:3px;padding:7px 9px;margin-bottom:8px;line-height:1.5;}
  #teren-okno .t-gps b{font-variant-numeric:tabular-nums;}
  #teren-okno .t-dobra{color:#6fbf6f;} #teren-okno .t-slaba{color:#e05555;} #teren-okno .t-srednia{color:var(--accent);}
  #teren-okno label{display:block;margin:7px 0 3px;font-size:10px;letter-spacing:.5px;text-transform:uppercase;color:var(--text-dim);}
  #teren-okno input[type=text],#teren-okno textarea,#teren-okno select{width:100%;box-sizing:border-box;background:var(--bg);
    border:1px solid var(--line);color:var(--text);border-radius:3px;padding:6px 8px;font:inherit;}
  #teren-okno textarea{min-height:58px;resize:vertical;}
  #teren-okno .t-kat{display:flex;gap:6px;}
  #teren-okno .t-kat button{flex:1;border-radius:14px;padding:7px 8px;}
  #teren-okno .t-kat button.akt{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  /* pole w przygotowaniu - czerwona ramka „nie zapomnieć" (tylko redakcja widzi to okno) */
  #teren-okno .t-wkrotce{margin-top:8px;padding:2px 8px 7px;border:1px dashed #e05555;border-radius:3px;}
  #teren-okno .t-wkrotce label{color:#e05555;}
  #teren-okno .t-wkrotce label b{font-weight:bold;}
  #teren-okno .t-wkrotce select{opacity:.5;cursor:not-allowed;}
  #teren-okno .t-wk-info{margin-top:4px;font-size:11px;color:#e05555;}
  #teren-okno .t-ist{display:flex;gap:6px;align-items:center;margin-top:8px;text-transform:none;letter-spacing:0;font-size:12px;color:var(--text);}
  #teren-okno .t-foto-prev{max-width:100%;max-height:120px;border-radius:3px;margin-top:6px;display:none;}
  #teren-okno .t-akcje{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap;}
  #teren-okno button{background:var(--panel-2, #262626);border:1px solid var(--line);color:var(--text);border-radius:3px;
    padding:7px 12px;cursor:pointer;font:inherit;font-size:12px;}
  #teren-okno button.gl{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  #teren-okno button:disabled{opacity:.4;cursor:default;}
  #teren-okno .t-meld{margin-top:8px;font-size:11.5px;color:var(--text-dim);}
  #teren-okno .t-meld.zle{color:#e05555;} #teren-okno .t-meld.ok{color:#6fbf6f;}
  #teren-btn{position:relative;}
  #teren-btn .t-licznik{position:absolute;top:-5px;right:-5px;min-width:15px;height:15px;border-radius:8px;background:var(--accent);
    color:#1a1a1a;font-size:9.5px;line-height:15px;text-align:center;font-weight:bold;padding:0 3px;box-sizing:border-box;}
  .slupek-korekta:has(#teren-btn.active){border-color:var(--accent) !important;}
  .slupek-korekta a#teren-btn.active{opacity:1;background:var(--accent) !important;color:#1a1a1a !important;}

  /* ===== NOTATNIK TERENOWY (17.10.2026) — tryb seryjny, dane tylko w telefonie ===== */
  #nt-panel{position:absolute;left:var(--luz, 10px);bottom:calc(var(--metka, 22px) + 8px);z-index:12000;
    /* pasmo jak oś czasu i dymki: luz | panel | luz | słupek | luz - nie wchodzi pod +/- */
    width:min(400px, calc(100% - 3 * var(--luz, 10px) - var(--slupek, 38px)));background:var(--panel);border:1px solid var(--accent);
    border-radius:6px;box-shadow:var(--shadow);padding:8px 10px 10px;display:none;font-size:12.5px;box-sizing:border-box;}
  #nt-panel.show{display:block;}
  #nt-panel .nt-gora{display:flex;align-items:center;gap:8px;margin-bottom:6px;}
  #nt-panel .nt-gps{flex:1;min-width:0;font-variant-numeric:tabular-nums;color:var(--text-dim);}
  #nt-panel .nt-gps b{color:var(--text);}
  #nt-panel .nt-gps .nt-wroc{color:var(--accent);text-decoration:none;white-space:nowrap;}
  #nt-panel .nt-gps .d{color:#6fbf6f;} #nt-panel .nt-gps .s{color:var(--accent);} #nt-panel .nt-gps .z{color:#e05555;}
  #nt-panel button,#nt-lista button{background:var(--panel-2, #262626);border:1px solid var(--line);color:var(--text);border-radius:3px;
    padding:6px 10px;cursor:pointer;font:inherit;font-size:12px;}
  #nt-panel .nt-x{background:none;border:none;color:var(--text-dim);font-size:18px;padding:0 4px;line-height:1;}
  /* KATEGORIE W JEDNYM WIERSZU (20.10.2026, 22:08, pavvlo: „jako główne kategorie
     zostawiłbym trzy pierwsze z listy… czwarta to dodaj kategorię z tym ołówkiem…
     fajnie jak zmieściłoby się to wszystko w jednym wersie"). Na pasku: 3 pierwsze
     z listy (+ wybrana spoza nich na miejscu trzeciej) i „✎ dodaj swoje" - otwiera okno
     z całą listą: wybór, dodawanie, kolejność, usuwanie. Długie nazwy skracane „…",
     żeby wiersz nigdy się nie łamał. (22:02 była wersja z łamaniem w wiersze.) */
  #nt-panel .nt-kat{display:flex;flex-wrap:nowrap;gap:5px;padding-bottom:4px;min-width:0;}
  #nt-panel .nt-kat button{flex:0 1 auto;min-width:0;padding:7px 10px;border-radius:14px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  #nt-panel .nt-kat button.akt{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  #nt-panel .nt-kat .nt-kat-ed{flex:none;margin-left:auto;color:var(--text-dim);}
  /* okno kategorii - nad notatnikiem, w stylu okien Fotomapy */
  #nt-kat-okno{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);z-index:12300;display:none;
    width:min(340px, calc(100% - 2 * var(--luz, 10px)));max-height:min(80vh, 560px);box-sizing:border-box;
    flex-direction:column;background:var(--panel);border:1px solid var(--accent);border-radius:6px;box-shadow:var(--shadow);
    padding:12px 12px 10px;font-size:12.5px;color:var(--text);}
  #nt-kat-okno.show{display:flex;}
  #nt-kat-okno h3{margin:0 0 4px;font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--accent);}
  #nt-kat-okno .nk-x{position:absolute;top:6px;right:8px;background:none;border:none;color:var(--text-dim);font-size:18px;cursor:pointer;line-height:1;padding:2px 4px;}
  #nt-kat-okno .nk-info{color:var(--text-dim);font-size:11.5px;margin-bottom:8px;line-height:1.4;}
  #nt-kat-okno .nk-lista{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:4px;}
  #nt-kat-okno .nk-w{display:flex;gap:4px;align-items:center;}
  #nt-kat-okno .nk-w.pasek .nk-nazwa{border-left:3px solid var(--accent);}
  #nt-kat-okno button{background:var(--panel-2, #262626);border:1px solid var(--line);color:var(--text);border-radius:3px;
    padding:7px 10px;cursor:pointer;font:inherit;font-size:12.5px;}
  #nt-kat-okno .nk-nazwa{flex:1;min-width:0;text-align:left;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
  #nt-kat-okno .nk-nazwa.akt{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  #nt-kat-okno .nk-gora,#nt-kat-okno .nk-us{flex:none;width:34px;padding:7px 0;color:var(--text-dim);}
  #nt-kat-okno .nk-gora:disabled,#nt-kat-okno .nk-us:disabled{opacity:.3;cursor:default;}
  #nt-kat-okno .nk-dodaj{display:flex;gap:6px;margin-bottom:8px;}
  #nt-kat-okno .nk-info b{color:var(--text);font-weight:normal;}
  #nt-kat-okno .nk-pole{flex:1;min-width:0;background:var(--bg);border:1px solid var(--line);color:var(--text);border-radius:3px;
    padding:8px;font:inherit;font-size:14px;}
  #nt-kat-okno .nk-stopka{display:flex;gap:6px;justify-content:space-between;margin-top:10px;padding-top:8px;border-top:1px solid var(--line);}
  #nt-kat-okno .nk-dom{color:var(--text-dim);font-size:11.5px;}
  #nt-kat-okno .nk-dom.pewny{border-color:#e05555;color:#e05555;}
  #nt-kat-okno .nk-gotowe{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  @media (hover:hover){ #nt-kat-okno .nk-us:not(:disabled):hover{color:#e05555;border-color:#e05555;}
    #nt-kat-okno .nk-gora:not(:disabled):hover{color:var(--accent);border-color:var(--accent);} }
  #nt-panel .nt-dol{display:flex;gap:6px;align-items:center;margin-top:6px;}
  #nt-panel .nt-opis{flex:1;min-width:0;background:var(--bg);border:1px solid var(--line);color:var(--text);border-radius:3px;
    padding:9px 8px;font:inherit;font-size:14px;}
  #nt-panel .nt-foto{position:relative;padding:8px 9px;}
  #nt-panel .nt-foto.ma{border-color:var(--accent);color:var(--accent);}
  #nt-panel .nt-plus{width:56px;height:56px;border-radius:50%;background:var(--accent);border:none;color:#1a1a1a;
    font-size:30px;font-weight:bold;line-height:1;padding:0;flex:none;box-shadow:var(--shadow);}
  #nt-panel .nt-plus:active{transform:scale(.94);}
  #nt-panel .nt-meld{margin-top:5px;font-size:11.5px;color:var(--text-dim);min-height:15px;display:flex;gap:8px;align-items:center;flex-wrap:wrap;}
  #nt-panel .nt-meld button{padding:2px 8px;font-size:11px;}
  #nt-panel .nt-gps .nt-ost{color:var(--text-dim);}
  #nt-panel .nt-gps .nt-strz{display:inline-block;transition:transform .3s;color:var(--accent);font-weight:bold;}
  #nt-panel .nt-powt{padding:6px 8px;}
  #nt-panel .nt-powt:disabled{opacity:.35;}
  #nt-lista .nl-stat{font-size:11px;color:var(--text-dim);margin-top:4px;}
  #nt-lista .nl-stat b{color:var(--text);}
  #nt-lista .nl-p .nl-meta a{color:var(--accent);text-decoration:none;}
  #nt-lista .nl-fotos{grid-column:2 / 4;display:flex;gap:4px;flex-wrap:wrap;}
  #nt-lista .nl-fotos img{height:54px;border-radius:3px;cursor:zoom-in;}
  #nt-lista .nl-fotos button{padding:2px 7px;font-size:11px;align-self:center;}
  #nt-panel .nt-meld.ok{color:#6fbf6f;} #nt-panel .nt-meld.zle{color:#e05555;}
  #nt-lista{position:absolute;inset:56px var(--luz, 10px) calc(var(--metka, 22px) + 8px);z-index:12100;background:var(--panel);
    border:1px solid var(--line);border-radius:6px;box-shadow:var(--shadow);display:none;flex-direction:column;font-size:12.5px;}
  #nt-lista.show{display:flex;}
  /* LISTA NOTATNIKA = OKNO NA WIERZCHU (20.10.2026, pavvlo: „klikam »lista« i pod spodem widać
     jednak okienka" - spod marginesów listy wystawały krawędzie notatnika, „Zaznacz punkt",
     licznika itd.). Na czas listy pływające okienka i przyciski mapy znikają, a reszta ekranu
     jest przygaszona - lista czyta się jak jedno okno nad mapą. */
  #nt-lista.show{box-shadow:0 0 0 100vmax rgba(0,0,0,.55), var(--shadow);}
  body:has(#nt-lista.show) :is(#nt-panel, #teren-okno, #zoom-indicator, #coord-indicator, #wsp-wpis, #linijka,
    #fort-legenda, #timeline, #nawigacja, #geo-toast, #korekta, #nt-kat-okno, #warstwy-plyw, #sidebar,
    #curtain-grip, .ctag, .leaflet-control-container){visibility:hidden;}
  #nt-lista .nl-gora{padding:10px 12px;border-bottom:1px solid var(--line);}
  #nt-lista .nl-gora h3{margin:0 0 6px;font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;color:var(--accent);}
  #nt-lista .nl-x{position:absolute;top:7px;right:10px;cursor:pointer;color:var(--text-dim);font-size:18px;}
  #nt-lista .nl-akcje{display:flex;gap:6px;flex-wrap:wrap;}
  #nt-lista .nl-info{font-size:11px;color:var(--text-dim);margin-top:6px;line-height:1.45;}
  #nt-lista .nl-tresc{overflow:auto;flex:1;padding:4px 12px 12px;}
  #nt-lista .nl-dzien{margin:10px 0 4px;font-size:10.5px;letter-spacing:.5px;text-transform:uppercase;color:var(--accent);display:flex;gap:8px;align-items:center;}
  #nt-lista .nl-dzien button{font-size:10.5px;padding:2px 7px;text-transform:none;letter-spacing:0;}
  #nt-lista .nl-p{display:grid;grid-template-columns:34px minmax(0,1fr) auto;gap:6px;align-items:center;padding:5px 0;border-bottom:1px solid var(--line);}
  #nt-lista .nl-nr{font-weight:bold;font-variant-numeric:tabular-nums;color:var(--accent);}
  #nt-lista .nl-p input,#nt-lista .nl-p select{background:var(--bg);border:1px solid var(--line);color:var(--text);border-radius:3px;padding:4px 6px;font:inherit;font-size:12px;}
  #nt-lista .nl-p .nl-pola{display:flex;gap:4px;min-width:0;}
  #nt-lista .nl-p .nl-pola select{flex:none;max-width:42%;}
  #nt-lista .nl-p .nl-pola input{flex:1;min-width:0;}
  #nt-lista .nl-p .nl-meta{grid-column:2 / 4;font-size:10.5px;color:var(--text-dim);}
  #nt-lista .nl-p .nl-btn{display:flex;gap:4px;}
  #nt-lista .nl-p .nl-btn button{padding:3px 7px;font-size:11px;}
  #nt-lista .nl-serwer{margin-top:8px;padding-top:8px;border-top:1px solid var(--line);font-size:11px;color:var(--text-dim);line-height:1.45;}
  #nt-lista .nl-serwer b{color:var(--text);}
  #nt-lista .nl-haslo{background:var(--bg);border:1px solid var(--line);color:var(--text);border-radius:3px;padding:5px 7px;font:inherit;font-size:12px;flex:1;min-width:150px;}
  #nt-lista .nl-sinfo{margin-top:5px;} #nt-lista .nl-sinfo.ok{color:#6fbf6f;} #nt-lista .nl-sinfo.zle{color:#e05555;}
  .nt-kropka{background:var(--accent);border:2px solid #1a1a1a;border-radius:50%;color:#1a1a1a;font:bold 9px/14px Verdana,sans-serif;
    text-align:center;box-sizing:border-box;}
  .slupek-korekta:has(#notatnik-btn.active){border-color:var(--accent) !important;}
  .slupek-korekta a#notatnik-btn.active{opacity:1;background:var(--accent) !important;color:#1a1a1a !important;}
  #loading .l-line{font-weight:bold;font-size:30px;letter-spacing:9px;white-space:nowrap;}
  /* Wejście w duchu całej aplikacji: najpierw staje złota KRESKA (ta sama
     kurtyna, którą przesuwa się po mapie), a potem rozsuwają się od niej
     oba słowa. Adres dopiero na końcu — rozstrzela się do docelowej
     szerokości (robi to JS, bo wartość jest mierzona). */
  /* BUCH: kreska wystrzeliwuje z punktu w wysoką, rozżarzoną kolumnę
     (×6,5 wysokości logo), przez mgnienie stoi w pełnej krasie — i OPADA.
     Właśnie na opadaniu wyłania się reszta: słowa rozsuwają się w takt
     malejącej kolumny, jakby to ona je odsłaniała. */
  /* PRZEMIANA KSZTAŁTU w obu osiach naraz: przy wystrzale kolumna nie
     tylko rośnie, ale i PĘCZNIEJE do podwójnej grubości — na szczycie stoi
     gruba i wysoka, a opadając równocześnie CHUDNIE, aż zbiegnie się
     w finalną, smukłą kreskę. Ruch wielkości jest tu całą treścią. */
  /* DWIE OSIE = DWA ELEMENTY, każdy ze swoją krzywą. Grubienie 3→6 px ma
     na ekranie ledwie kilka pośrednich szerokości — wciśnięte w szybką
     fazę wystrzału zawsze będzie wyglądać jak przeskok, niezależnie od
     krzywej. Dlatego oś pionowa (wystrzał) siedzi na obudowie, a grubość
     na rdzeniu: pęcznieje wolno i równomiernie przez CAŁY czas wzrostu,
     więc te kilka pikselowych stanów rozmywa się w płynny ruch. */
  /* NIŻSZA KOLUMNA, BEZ GRUBIENIA — leczenie przyczyny zamiast obejść:
     to pęcznienie wąskiego paska renderer przerastrowywał progami (skok
     widoczny gołym okiem), a duża skala dokładała rozmycie. Sam wystrzał
     w pionie do 4 wysokości skaluje się gładko i zostaje ostry. */
  @keyframes lKreskaWys{
    0%{transform:scaleY(0);opacity:0;animation-timing-function:cubic-bezier(.42,.22,.28,1);}
    14%{opacity:1;}
    40%{transform:scaleY(4);}
    52%{transform:scaleY(4);animation-timing-function:cubic-bezier(.6,.05,.3,1);}
    100%{transform:scaleY(1);opacity:1;}
  }
  @keyframes lFoto{ from{opacity:0;transform:translateX(-18px);filter:brightness(1.7);} to{opacity:1;transform:translateX(0);filter:brightness(1);} }
  @keyframes lMapa{ from{opacity:0;transform:translateX(18px);filter:brightness(1.7);} to{opacity:1;transform:translateX(0);filter:brightness(1);} }
  @keyframes lStatus{ from{opacity:0;} to{opacity:.999;} }
  /* 0,55 s CZERNI przed wystrzałem: samo tło zdąży się ustatkować i buch
     ma scenę — bez tej pauzy kolumna wyskakiwała, zanim oko usiadło */
  /* will-change: kreska dostaje WŁASNĄ teksturę na GPU na cały czas życia
     — bez tego przeglądarka w trakcie skalowania przerastrowywała warstwę
     „w locie" (zwykle na szczycie, gdy ruch ustaje) i podmiana bitmapy
     dawała jednoklatkowe mrugnięcie wyglądające jak przeskok. Koszt:
     krawędzie na szczycie minimalnie miększe — na jednolitym złocie
     niewidoczne. Element żyje tylko na ekranie wczytywania. */
  /* BEZ will-change/backface: wymuszona warstwa GPU trzymała JEDNĄ teksturę
     namalowaną w małej skali i rozciągała ją — stąd mgła na szczycie.
     Bez niej renderer domalowuje ostro w bieżącej skali; ostrość okazała
     się ważniejsza niż drobne mrugnięcie, które i tak zniknęło razem
     z crossfade'em grubości (skok brał się z kwantyzacji szerokości). */
  #loading .l-kreska{animation:lKreskaWys 1.45s cubic-bezier(.3,.85,.35,1) .55s both;transform-origin:50% 50%;}
  /* słowa startują W CHWILI, gdy kolumna zaczyna opadać (50% z 1,45 s
     ≈ 0,73 s) i dojeżdżają na miejsca tuż przed jej osadzeniem — opadanie
     i rozsuwanie to jeden ruch; wchodzą rozżarzone i stygną jak kreska */
  #loading .l-foto{display:inline-block;animation:lFoto .6s cubic-bezier(.2,.8,.3,1) 1.31s both;}
  #loading .l-mapa{display:inline-block;animation:lMapa .6s cubic-bezier(.2,.8,.3,1) 1.31s both;}
  /* „wczytywanie warstw…" wchodzi dopiero, gdy logo i adres są już
     w pełni na miejscu — wcześniej rozpraszało i odbierało adresowi
     jego moment */
  #loading .s{animation:lStatus .45s ease 3.65s both;}
  @media (prefers-reduced-motion: reduce){
    #loading .l-kreska,#loading .l-foto,#loading .l-mapa,#loading .s{animation:none;}
    #loading{transition:none;}
  }
  #loading .l-foto{color:var(--text);font-weight:normal;}
  #loading .l-kreska{
    display:inline-block;width:3px;height:27px;background:var(--accent);
    margin:0 14px 0 5px;vertical-align:-2px;
  }
  #loading .l-mapa{color:var(--accent);}
  #loading .l-dom{
    /* rozstrzelenie dobiera pomiarem dopasujLogoWczytywanie() — do 3/4
       szerokości napisu FOTO|MAPA; letter-spacing jest ustawiany NA SZTYWNO
       przed odsłonięciem (animowanie go przelicza układ strony co klatkę
       i tnie na słabszych urządzeniach), a ruch robią transformy liter
       i całości — te idą na kompozytorze, płynnie wszędzie */
    color:var(--text-dim);font-size:15px;letter-spacing:7px;text-align:center;
    margin-top:4px;white-space:nowrap;
    visibility:hidden; /* odsłaniane dopiero po pomiarze — patrz niżej */
    transform:scaleX(.9);
    transition:transform .8s cubic-bezier(.2,.8,.3,1);
  }
  #loading .l-dom.rozsun{transform:scaleX(1);}
  /* litery adresu wchodzą KLATKA PO KLATCE: każda unosi się z lekkiego
     zapadnięcia, opóźnienia nadaje JS (kolejno co ~45 ms) */
  #loading .l-dom span{
    display:inline-block;opacity:0;transform:translateY(7px);
    transition:opacity .38s ease, transform .38s cubic-bezier(.2,.8,.3,1);
  }
  #loading .l-dom.rozsun span{opacity:1;transform:translateY(0);}
  #loading .s{color:var(--text-dim);font-size:11px;max-width:400px;text-align:center;line-height:1.6;}

  .leaflet-control-attribution{
    background:var(--panel) !important;color:var(--text-dim) !important;font-size:10px !important;
  }
  .leaflet-control-attribution a{color:var(--link) !important;}
  /* kreska między wpisami paska autorstwa — ta sama co w metryce (.zr-sep) */
  .leaflet-control-attribution .metka-sep{color:var(--text-dim);margin:0 6px;font-weight:normal;}
  .leaflet-control-zoom a{
    background:var(--panel) !important;color:var(--text) !important;border-color:var(--line) !important;
  }@media (hover:hover){ .leaflet-control-zoom a:hover{color:var(--accent) !important;} }
  .leaflet-bar{border-color:var(--line) !important;}
  /* Podziałka mówi tym samym językiem, co licznik powiększenia i okienko
     współrzędnych: pudełko w kolorze panelu, ramka --line, promień 3px,
     ten sam cień. W środku zostaje sam wspornik miarowy — kreska
     z nóżkami, która NIESIE informację o długości, więc nie może zniknąć
     w dekoracji. Leaflet maluje domyślnie białe tło i BIAŁY cień tekstu
     (text-shadow:1px 1px #fff): na ciemnym motywie cyfry dublowały się
     i wyglądały na rozmyte — stąd twarde text-shadow:none. */
  .leaflet-control-scale{
    background:var(--panel);border:1px solid var(--line);border-radius:3px;
    box-shadow:var(--shadow);padding:5px 8px 4px;
  }
  .leaflet-control-scale-line{
    background:none !important;
    border:1px solid var(--text-dim) !important;border-top:none !important;
    border-radius:0 !important;
    color:var(--text-dim) !important;
    text-shadow:none !important;
    font:11px Verdana,sans-serif !important;letter-spacing:.3px;
    line-height:1.35 !important;padding:1px 5px 2px !important;
    text-align:center;
  }
  /* Lewy dolny róg: podziałka stoi w jednej pionowej linii z panelem
     warstw — 10px od krawędzi ekranu, dokładnie tyle co #sidebar.
     Leaflet daje własne 10px marginesu kontenerowi narożnika, więc
     zerujemy je i ustawiamy odstęp na samej podziałce. */
  .leaflet-bottom.leaflet-left{margin:0;}
  .leaflet-bottom.leaflet-left .leaflet-control-scale{
    /* Na monitorze pasek źródeł siedzi w PRAWYM dolnym rogu, więc
       podziałce po lewej nic nie wadzi i zostaje jak było: 10px.
       Na telefonie ten sam pasek jest pełnoszerokościowy — poprawka
       w bloku @media niżej. */
    margin:0 0 10px var(--luz);
  }
  /* Panel przy pełnej liście warstw sięga do calc(100% - 80px), a pod nim
     wisi jeszcze metka — bez rezerwacji pasa podziałka wpadłaby dokładnie
     pod nią. Skracamy panel o wysokość podziałki z odstępem, ale TYLKO
     wtedy, gdy podziałka jest włączona: wyłączona nie odbiera ani piksela
     (m.in. na telefonie, gdzie domyślnie jej nie ma). */
  /* TYLKO MONITOR (11.09.2026). Ta reguła ma wagę 1-1-1, więc do wczoraj
     wygrywała także na telefonie z regułą #sidebar w bloku mobilnym
     (1-0-0) i skracała panel o 15 px zawsze, gdy podziałka była włączona
     — panel nie mógł się w pełni rozwinąć. Na telefonie miejsca się nie
     rezerwuje: podziałka USTĘPUJE otwartemu panelowi (reguła niżej),
     tak samo jak legenda i linijka. */
  @media (min-width:641px){
    body:not(.ust-bez-skali) #sidebar{max-height:calc(100% - 122px);}
  }
  /* Oś czasu jest wyśrodkowana i rośnie wraz z liczbą dat — czasem
     dociera do lewego rogu, czasem nie. Dawniej podziałka ustępowała
     ZAWSZE po otwarciu osi (siedziała po prawej, tuż przy niej); po
     przeniesieniu w lewy róg to za dużo: na szerokim ekranie oba
     elementy spokojnie się mijają. Decyduje więc realny pomiar
     nachodzenia (JS niżej), a nie sam fakt otwarcia osi. */
  .leaflet-control-scale{transition:opacity .2s;}
  body.skala-ustepuje .leaflet-control-scale{opacity:0;pointer-events:none;}
  /* wyłączona w Ustawieniach — znika bez śladu, także z układu */
  body.ust-bez-skali .leaflet-control-scale{display:none;}
  /* okna terenowe (20.10.2026): podziałka spod nich znika, ręcznie otwarty panel warstw nad nimi */
  body.teren-otwarte .leaflet-control-scale{opacity:0;pointer-events:none;}
  body.teren-otwarte #sidebar{z-index:12050;}
  /* przycisk lokalizacji: „active" = śledzenie włączone (trwałe podświetlenie,
     jak przyciski Warstwy/Oś czasu), „searching" = czekamy na pierwszy odczyt GPS */
  .leaflet-control-zoom a.active{background:var(--accent) !important;color:#1a1a1a !important;}
  /* przycisk warstw w słupku nawigacyjnym istnieje tylko dla kciuka —
     na desktopie ukryty (panelem steruje przycisk w topbarze),
     odsłaniany w media query mobile niżej */
  /* ===== PASEK KOREKTY: CICHY W SPOCZYNKU, CZERWONY DOPIERO UZBROJONY =====
     Historia w dwóch krokach tego samego wieczoru (11.09.2026), bo to
     dobra lekcja: najpierw obwódka na czerwono NA STAŁE — miała mówić
     „to jedyne narzędzie, które zmienia dane". Efekt był odwrotny do
     zamierzonego: czerwona ramka stała się najgłośniejszym punktem
     kolumny i ZACHĘCAŁA do kliknięcia narzędzia, które ma być schowane
     i uruchamiane raz na jakiś czas.
     Teraz: w spoczynku pasek wygląda jak każdy inny (ramka --line),
     a sama ikona jest przygaszona do 45% — waga wizualna idzie za
     częstością użycia, tak jak przy kolorze wykopu pod Ringstand.
     Czerwień zostaje, ale WŁĄCZA SIĘ dopiero, gdy tryb korekty jest
     uruchomiony: ostrzeżenie ma sens wtedy, kiedy przeciąganie punktów
     naprawdę coś zmienia, a nie kiedy narzędzie śpi.
     Przygaszenie zwykle znaczy w tym interfejsie „zablokowane"
     (geo-blokada ma .4) — tu jednak przycisk widzi WYŁĄCZNIE redakcja,
     która wie, że działa, a jedno tapnięcie i tak to pokazuje. */
  .slupek-korekta a{opacity:.45;transition:opacity .15s;}
  @media (hover:hover){ .slupek-korekta a:hover{opacity:1;} }
  .slupek-korekta a:active{opacity:1;}
  /* tryb korekty uruchomiony — dopiero teraz czerwień i pełna siła
     (!important, bo .leaflet-bar wymusza wyżej border-color z motywu) */
  .slupek-korekta:has(a.active){border-color:#e05555 !important;}
  .slupek-korekta a.active{
    opacity:1;
    background:#e05555 !important;color:#fff !important;
  }
  /* przycisk „3D" (2.10.2026) w pasku redakcji: napis zamiast ikony - kostka w 15 px
     myliłaby się z pełnym widokiem; wysokość wiersza zostaje z Leafletu (30/34 px) */
  #b3d-btn{font-weight:bold;font-size:11px;letter-spacing:.3px;}
  #warstwy-btn-mobile{display:none;}
  /* SŁUPEK W TRZECH GRUPACH (20.10.2026, pavvlo: „wg użyteczności i intensywności
     używania posegregować … i leciutko rozdzielić"). Kolejność bez zmian (wzór
     z 1.10: rzadkie u góry, częste pod kciukiem), tylko 6 px prześwitu między:
     20.10 21:26 - także na komputerze („aby były te paski spójne”).
     1) widok raz na sesję: pełny ekran, pełny widok; 2) narzędzia: linijka,
     współrzędne; 3) teren: oś czasu, GPS, obrót. Ramkę zamiast paska rysują
     przyciski - klasy gr-pocz / gr-kon / gr-odstep nadaje slupekGrupy(),
     więc przycisk schowany (np. oś czasu przy jednej dacie) nie psuje grup. */
  .leaflet-bar.slupek-grupy{border:none !important;background:transparent;}
  .leaflet-bar.slupek-grupy a{box-sizing:content-box;border-left:2px solid var(--line);border-right:2px solid var(--line);border-radius:0 !important;}
  .leaflet-bar.slupek-grupy a.gr-pocz{border-top:2px solid var(--line);border-top-left-radius:4px !important;border-top-right-radius:4px !important;}
  .leaflet-bar.slupek-grupy a.gr-kon{border-bottom:2px solid var(--line);border-bottom-left-radius:4px !important;border-bottom-right-radius:4px !important;}
  .leaflet-bar.slupek-grupy a.gr-odstep{margin-top:6px;}
  /* współrzędne w słupku (20.10.2026) - tylko telefon; na monitorze jest okienko z ołówkiem */
  #wsp-btn-mobile{display:none;}
  /* krzyżyk środka mapy - widać go tylko przy otwartym polu współrzędnych na telefonie */
  #wsp-krzyz{display:none;position:absolute;left:50%;top:50%;width:34px;height:34px;margin:-17px 0 0 -17px;
    z-index:650;pointer-events:none;}
  #wsp-wpis .ww-srodek{display:none;}
  /* Oś czasu w słupku tylko na telefonie — na monitorze steruje nią
     przycisk w belce, który tam po prostu widać. */
  #os-btn{display:none;}
  .leaflet-control-zoom a.searching{animation:geoPuls 1.1s ease-in-out infinite;}
  /* ===== OBRÓT MAPY WG KIERUNKU MARSZU (26.09.2026, uwagi GPS pkt 1) - opis przy obrotUstaw() =====
     Kontener mapy: kwadrat o boku przekątnej ekranu, wyśrodkowany i obrócony o -azymut. To, co ma
     stać prosto, dostaje +azymut: kontrolki (cały ich kontener, rozmiar ekranu), pinezki, etykiety,
     dymki. Punkty obrotu (transform-origin) ustawia JS przy każdym położeniu, a przy animacji zoomu
     przechodzą razem z przesunięciem - inaczej pinezki odjeżdżałyby na ćwierć sekundy. */
  #map.obrot{inset:auto;left:50%;top:50%;width:var(--obr-d);height:var(--obr-d);
    margin:calc(var(--obr-d) / -2) 0 0 calc(var(--obr-d) / -2);transform:rotate(var(--obr-kat, 0deg));}
  /* z-index jawnie: obrót tworzy własny kontekst i bez tego kontrolki spadłyby pod mapę */
  #map.obrot > .leaflet-control-container{position:absolute;left:50%;top:50%;z-index:1000;
    width:var(--obr-w);height:var(--obr-h);margin:calc(var(--obr-h) / -2) 0 0 calc(var(--obr-w) / -2);
    transform:rotate(var(--obr-licz, 0deg));pointer-events:none;}
  #map.obrot .leaflet-marker-icon:not(.geo-icon),
  #map.obrot .leaflet-tooltip,
  #map.obrot .leaflet-popup{rotate:var(--obr-licz, 0deg);}
  #map.obrot .leaflet-zoom-anim .leaflet-zoom-animated{
    transition:transform .25s cubic-bezier(0,0,.25,1), transform-origin .25s cubic-bezier(0,0,.25,1);}
  #map.obrot .leaflet-cluster-anim .leaflet-marker-icon{
    transition:transform .3s ease-out, opacity .3s ease-in, transform-origin .3s ease-out;}
  /* przycisk: igła pokazuje północ; „stop" (mapa przesunięta palcem) = sama złota ikona */
  .obr-igla{transform-box:view-box;transform-origin:8px 8px;}
  .leaflet-control-zoom a.obrot-stop{color:var(--accent) !important;}
  /* GPS odcięty (Firefox na Androidzie): przycisk zostaje na miejscu,
     ale przygaszony — brak przycisku czytałby się jak awaria, a tak
     widać, że funkcja istnieje i tapnięcie powie, czemu tu nie działa */
  .leaflet-control-zoom a.geo-blokada{opacity:.4;}
  @media (hover:hover){ .leaflet-control-zoom a.geo-blokada:hover{color:var(--text) !important;} }
  @keyframes geoPuls{0%,100%{opacity:1;}50%{opacity:.3;}}

  /* własny marker GPS: kropka + opcjonalna strzałka kierunku (kompas) */
  .geo-wrap{position:relative;width:30px;height:30px;}
  /* sonar: dwie fale rozchodzące się z kropki pozycji co pół cyklu —
     natychmiastowy sygnał „śledzenie żyje", czytelny kątem oka;
     kolor dziedziczony z kropki przez currentColor (motyw/tryb celu
     przemalowuje kropkę, fale pójdą za nią same) */
  .geo-fala{
    position:absolute;left:50%;top:50%;width:12px;height:12px;margin:-6px;
    border:2.5px solid var(--accent);border-radius:50%;opacity:0;
    animation:geo-sonar 2.6s ease-out infinite;pointer-events:none;
    /* ciemny kontur fali — złoto na jasnym ortofoto i na cieniowaniu LIDAR
       ginęło; cień działa jak obrys, więc fala czyta się na obu tłach
       i w obu motywach, bez zmiany koloru „to ja" */
    filter:drop-shadow(0 0 1.5px rgba(0,0,0,.9));
  }
  .geo-fala:nth-child(2){animation-delay:1.3s;}
  @keyframes geo-sonar{
    0%  {transform:scale(1);   opacity:.95;}
    100%{transform:scale(4.6); opacity:0;}
  }
  @media (prefers-reduced-motion: reduce){ .geo-fala{animation:none;} }
  /* Cisza nasłuchu: fale gasną, kropka blednie. Znacznik pozycji nie ma
     udawać, że śledzenie żyje, skoro pasek prowadzenia mówi wprost, że nie.
     Ten sam próg co plakietka „brak sygnału GPS" — GEO_CISZA_MS. */
  body.gps-cisza .geo-fala{animation:none;opacity:0;}
  body.gps-cisza .geo-dot{opacity:.45;}
  body.gps-cisza .geo-heading{opacity:.35;}
  .geo-heading{
    position:absolute;inset:0;display:none;
    transition:transform .15s linear;
  }
  .geo-heading::after{
    content:'';position:absolute;top:-1px;left:50%;transform:translateX(-50%);
    width:0;height:0;border-left:6px solid transparent;border-right:6px solid transparent;
    border-bottom:11px solid var(--accent);opacity:.8;
  }
  .geo-dot{
    position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
    width:14px;height:14px;border-radius:50%;background:var(--accent);
    border:2.5px solid var(--panel);box-shadow:0 1px 4px rgba(0,0,0,.5);
  }

  /* zakładka-uchwyt ramki: chip z nazwą przy narożniku obrysu (jak uchwyty
     arkuszy w skoroszycie) — przy nachodzących zasięgach kaskada zakładek
     daje każdej warstwie jednoznaczny punkt wyboru */
  .ramka-tab{pointer-events:auto;transition:opacity .15s;}
  /* FOKUS skorowidza obejmuje też zakładki warstw (24.09.2026): zakładka klatki
     z zestawu dostaje złotą obwódkę, pozostałe przygasają; najechanie na
     zakładkę zdjęcia daje ten sam fokus, co najechanie na numer w skorowidzu */
  body.zb-fokus .ramka-tab:not(.zb-on){opacity:.18;}
  body.zb-fokus .ramka-tab.zb-on .ramka-tab-w{box-shadow:0 0 0 2px var(--accent),0 1px 4px rgba(0,0,0,.45);opacity:1;}
  /* opakowanie = jedna różowa belka: [ × | nazwa ]. Flex rozciąga segment
     krzyżyka na pełną wysokość chipa (także dwulinijkowego); wspólna
     przezroczystość i cień na całości, więc wygląda jak jeden przycisk
     z dwiema strefami */
  .ramka-tab-w{
    display:flex;align-items:stretch;width:max-content;
    border-radius:3px 0 0 3px;overflow:hidden;
    box-shadow:0 1px 4px rgba(0,0,0,.45);opacity:.85;
  }@media (hover:hover){ .ramka-tab-w:hover{opacity:1;} }
  .ramka-tab-in{
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
    overflow:hidden;max-width:190px;
    background:#ff4d6d;color:#fff;
    font:bold 10px/1.3 Verdana,Geneva,sans-serif;letter-spacing:.2px;
    padding:3px 8px 4px;white-space:normal;text-align:center;cursor:pointer;
  }
  .ramka-tab-x{
    display:flex;align-items:center;justify-content:center;flex-shrink:0;
    width:19px;background:#ff4d6d;color:#fff;
    border-right:1px solid rgba(0,0,0,.28); /* subtelny szew między segmentami */
    font:normal 13px/1 Verdana,sans-serif;cursor:pointer;
  }@media (hover:hover){ .ramka-tab-x:hover{background:#d13a56;} }
  /* METKA ZASIĘGU ORTOFOTO (2.10.2026, pavvlo: „zróbmy etykietę/metkę dla ortofoto. jest złoty
     to i metkę zróbmy złotą?"): kształt różowej zakładki warstwy, kolory złotej przerywanej
     ramki rocznika - złoto #c9a24b i ciemny tekst jak jej podkładka. Bez krzyżyka (podkład
     wyłącza się wyborem innego). Kolory stałe, jak sama ramka na mapie - nie idą za motywem
     panelu. Klik = rocznik 2025 na wierzch, jak klik w różową zakładkę (ortoNaWierzch). */
  .orto-metka .ramka-tab-in{background:#c9a24b;color:#1a1a1a;}

  /* (26.09.2026) pasek „Mapa z ostatniej wizyty" usunięty razem z odtwarzaniem
     ostatniego widoku - każda nowa wizyta zaczyna się od zera (readHash) */

  /* ===== JEDEN SZABLON OKIENEK (10.09.2026) =====
     Pięć okien mapy — Źródła, metryka warstwy, okno zabytku, Ustawienia
     i Sesja — miało dotąd trzy różne budowy. Od teraz każde ma ten sam
     pasek tytułowy z krzyżykiem, tę samą przewijaną treść pod nim
     i (na telefonie, blok @media niżej) te same marginesy od krawędzi
     ekranu i od paska źródeł, co panel warstw i oś czasu.
     Reguły wspólne stoją TUTAJ, przed regułami poszczególnych okien —
     tamte dopisują tylko to, co u nich naprawdę inne (np. tytuł okna
     zabytku nie jest wersalikami, bo to nazwa własna). */
  #ust-okno .naglowek, #sesja-okno .naglowek, #offline-okno .naglowek, #zbiorka-okno .naglowek{
    display:flex;align-items:center;padding:9px 12px;background:var(--panel-2);
    border-bottom:1px solid var(--line);flex-shrink:0;
  }
  #ust-okno .naglowek .t, #sesja-okno .naglowek .t, #offline-okno .naglowek .t, #zbiorka-okno .naglowek .t{
    flex:1;font-size:12px;letter-spacing:.5px;color:var(--accent);
    text-transform:uppercase;font-weight:bold;
  }
  #ust-okno .zamknij, #sesja-okno .zamknij, #offline-okno .zamknij, #zbiorka-okno .zamknij{
    color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 4px;user-select:none;
  }
  @media (hover:hover){
    #ust-okno .zamknij:hover, #sesja-okno .zamknij:hover, #offline-okno .zamknij:hover, #zbiorka-okno .zamknij:hover{color:#e05555;}
  }
  /* treść: to ONA się przewija, nie całe okno — pasek tytułowy
     z krzyżykiem ma zostać na wierzchu przy długiej liście opcji */
  #ust-okno .okno-tresc, #sesja-okno .okno-tresc, #offline-okno .okno-tresc, #zbiorka-okno .okno-tresc{
    overflow-y:auto;overscroll-behavior:contain;padding:13px 14px;
  }

  /* ===== ustawienia widoku ===== */
  #ust-okno{
    display:none;position:fixed;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);z-index:10950;
    width:min(300px, calc(100% - 20px));
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:12px;
    /* od 10.09.2026 okno pracuje jak pozostałe: pasek tytułowy z krzyżykiem
       zostaje na miejscu, przewija się tylko treść pod nim */
    flex-direction:column;overflow:hidden;
    /* Okno rośnie z każdą nową opcją, a stoi w rogu ekranu — bez tego
       ostatnie pozycje (Wygląd, reset) wychodzą pod dolną krawędź
       i po prostu ich nie widać. Objaw mylący: nie ma paska przewijania,
       więc wygląda, jakby funkcji nie było w ogóle. */
    max-height:calc(100vh - 120px);
    max-height:calc(100dvh - var(--pasek, 52px) - 6px - var(--metka, 22px) - var(--dol));
  }
  #ust-okno.show{display:flex;}
  #ust-okno .s-tytul{color:var(--accent);font-weight:bold;font-size:12.5px;margin-bottom:9px;}
  #ust-okno .u-check{display:flex;align-items:center;gap:8px;margin:7px 0;cursor:pointer;color:var(--text);}
  /* KWADRATOWE POLA WYBORU w Ustawieniach (26.09.2026, pavvlo: „zmiana okrągłych pinezek do
     zaznaczania na kwadratowe"). Wybór jednego z dwóch (motyw, oznaczenia dostępu) zostaje
     radiem - działa jak dotąd (wybór drugiego gasi pierwszy, strzałki, czytnik ekranu), zmienia
     się tylko wygląd. Żeby w oknie nie było dwóch rodzajów kwadratów, ptaszki i radia rysujemy
     JEDNYM stylem, wzorowanym na natywnym ptaszku z accent-color: biały kwadrat z szarą
     obwódką, po zaznaczeniu wypełniony akcentem z ptaszkiem - ciemnym w ciemnym motywie,
     białym w jasnym (tak kontrast dobiera przeglądarka). Wygląda tak samo w każdej przeglądarce. */
  #ust-okno .u-check input{
    -webkit-appearance:none;appearance:none;
    margin:3px 3px 3px 4px;   /* marginesy natywnego pola - wiersze zostają tej samej wysokości co dotąd */
    width:14px;height:14px;flex-shrink:0;box-sizing:border-box;
    border:1px solid #767676;border-radius:2px;background:#fff center/12px 12px no-repeat;
    cursor:pointer;
  }
  #ust-okno .u-check input:checked{
    background-color:var(--accent);border-color:var(--accent);
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.4 6.3 4.9 8.7 9.7 3.5' fill='none' stroke='%231a1a1a' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
  [data-theme="light"] #ust-okno .u-check input:checked{
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M2.4 6.3 4.9 8.7 9.7 3.5' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  }
  @media (hover:hover){ #ust-okno .u-check input:not(:checked):hover{border-color:var(--accent-2);} }
  #ust-okno .u-check input:focus-visible{outline:2px solid var(--accent-2);outline-offset:1px;}
  #ust-okno .u-sekcja{
    font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.4px;
    margin:12px 0 4px;padding-top:9px;border-top:1px solid var(--line);
  }
  #ust-okno .okno-tresc > .u-sekcja:first-child{margin-top:2px;padding-top:0;border-top:0;}   /* 25.09: pierwsza sekcja („Wygląd") bez drugiej kreski pod belką */
  #ust-okno .u-hint{color:var(--text-dim);font-size:10.5px;margin-top:8px;line-height:1.45;}
  /* opcja, której ta przeglądarka nie obsługuje (np. „Ekran nie gaśnie" bez Wake Lock API) */
  #ust-okno .u-check.u-niedostepne{color:var(--text-dim);cursor:default;}
  #ust-okno .u-check.u-niedostepne input{opacity:.45;cursor:default;}
  /* hinty w „GPS w terenie": każdy tuż pod swoim przełącznikiem, przed przyciskiem odstęp */
  #ust-okno #u-ekran-hint{margin:2px 0 4px;}
  #ust-okno #u-cel-hint{margin:2px 0 10px;}
  /* znacznik funkcji próbnej przy tytule sekcji — ten sam język, co
     plakietki KALIBRACJA/TESTY przy warstwach: neutralny, nie krzyczy */
  #ust-okno .u-proba{
    font-weight:normal;font-size:9px;letter-spacing:1px;text-transform:uppercase;
    color:var(--text-dim);border:1px solid var(--line);border-radius:3px;
    padding:1px 5px;margin-left:6px;vertical-align:1px;
  }
  #ust-okno #ust-reset{width:100%;margin-top:2px;}
  /* 25.09: podtytuł wewnątrz sekcji (oznaczenia dostępu w „Lista warstw") i stopka z resetem oddzielona kreską */
  #ust-okno .u-podtytul{font-size:10.5px;color:var(--text-dim);margin:9px 0 2px;}
  #ust-okno .u-stopka{margin-top:14px;padding-top:10px;border-top:1px solid var(--line);}
  /* Drugie kliknięcie zamiast systemowego „czy na pewno": okno ustawień
     jest własnoręcznie zrobione, a natywny confirm() wygląda w nim jak
     obca wtręta. Przycisk sam mówi, że czeka na potwierdzenie. */
  #ust-okno #ust-reset.pewny{border-color:#e05555;color:#e05555;}
  /* skutki ustawień */
  body.ust-bez-licznika #zoom-indicator{display:none !important;}
  body.ust-bez-koord #coord-indicator{display:none !important;}
  /* tryb „tylko paski koloru": wiersz plakietki znika, a status dostępu
     pokazuje krótka zaokrąglona PASTYLKA przy checkboksie — celowo NIE
     pasek na pełną wysokość przy samej krawędzi: tam biegną już złote
     belki kategorii i pion grupy, więc trzecia linia strukturalna
     w innym kolorze robiła wizualny zgrzyt. Pastylka to inny „byt":
     krótka, odsunięta, z promieniem — czyta się jak status, nie jak
     architektura panelu. */
  body.ust-badge-paski .robocza-row{display:none;}
  /* linia statusu PRZYKLEJONA do nazwy warstwy: rozciąga się dokładnie
     na tyle wersów, ile zajmuje nazwa (::before na 100% wysokości spana),
     odsunięta od osi złotych belek kategorii — status jest przy treści,
     architektura przy krawędzi */
  body.ust-badge-paski .layer.lay-kalibracja .row .name,
  body.ust-badge-paski .layer.lay-testy .row .name,
  body.ust-badge-paski .layer.lay-zalogowani .row .name,
  body.ust-badge-paski .layer.lay-archiwum .row .name{
    position:relative;padding-left:9px;
  }
  body.ust-badge-paski .layer.lay-kalibracja .row .name::before,
  body.ust-badge-paski .layer.lay-testy .row .name::before,
  body.ust-badge-paski .layer.lay-zalogowani .row .name::before,
  body.ust-badge-paski .layer.lay-archiwum .row .name::before{
    content:'';position:absolute;left:0;top:1px;bottom:1px;width:3px;
    border-radius:2px;
  }
  body.ust-badge-paski .layer.lay-kalibracja .row .name::before{background:#b03434;}
  body.ust-badge-paski .layer.lay-testy .row .name::before{background:#3f5e8a;}
  body.ust-badge-paski .layer.lay-archiwum .row .name::before{background:#7a5a24;}
  body.ust-badge-paski .layer.lay-zalogowani .row .name::before{background:#3f7a5e;}

  /* ===== okno „Na wyjazd" — te same reguły co okno ustawień ===== */
  #offline-okno{
    display:none;position:fixed;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);z-index:10950;
    width:min(320px, calc(100% - 20px));
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:12px;
    flex-direction:column;overflow:hidden;
    max-height:calc(100vh - 120px);
    max-height:calc(100dvh - var(--pasek, 52px) - 6px - var(--metka, 22px) - var(--dol));
  }
  #offline-okno.show{display:flex;}
  #offline-okno .okno-tresc > .u-hint:first-child{margin-top:0;}
  #offline-okno .u-sekcja{
    font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.4px;
    margin:12px 0 4px;padding-top:9px;border-top:1px solid var(--line);
  }
  #offline-okno .u-hint{color:var(--text-dim);font-size:10.5px;margin-top:8px;line-height:1.45;}
  /* trzy kroki dla świeżaków na górze okna (27.09.2026) - pełny kolor tekstu,
     bo to pierwsza rzecz do przeczytania, nie przypis */
  #offline-okno .u-kroki{font-size:11.5px;line-height:1.5;color:var(--text);margin:0 0 10px;}
  #offline-okno .u-kroki ol{margin:3px 0 0;padding-left:18px;}
  #offline-okno .u-kroki li{margin:2px 0;}
  #offline-okno .u-kroki li::marker{color:var(--accent);font-weight:bold;}
  #offline-okno #u-offline-stan{white-space:pre-line;color:var(--text);}
  #offline-okno .btn{margin-top:4px;}
  #offline-okno .btn:disabled{opacity:.45;cursor:default;}   /* „Zaznacz obszar" w trakcie pobierania */
  /* ===== PASEK POSTĘPU POBIERANIA (14.09.2026, prośba pavvla) =====
     Sam licznik „Pobrano 1240 z 4000" nie mówi, ILE TO JESZCZE potrwa —
     przy czterech tysiącach kafelków to kilka minut wpatrywania się
     w liczbę. Pasek daje to jednym spojrzeniem; pod nim procent i
     szacowany czas do końca, liczony z dotychczasowego tempa. */
  #offline-okno .u-postep{
    height:8px;margin-top:8px;border:1px solid var(--line);border-radius:4px;
    background:var(--panel-2);overflow:hidden;
  }
  #offline-okno .u-postep-wyp{height:100%;width:0;background:var(--accent);transition:width .25s;}
  /* po skończeniu pasek ZOSTAJE (pełny, zielony) razem z podsumowaniem -
     przy kilkunastu kafelkach pobieranie trwa pół sekundy i bez tego
     jedyny ślad znikał, zanim człowiek spojrzał (zgłoszenie pavvla 14.09) */
  #offline-okno .u-postep.gotowe .u-postep-wyp{background:#3f7a5e;}
  #offline-okno #u-offline-wynik{white-space:pre-line;}
  #offline-okno #u-offline-wynik.uwaga{color:var(--accent);}
  /* ===== „DO POBRANIA: …" - żywy podpis nad przyciskiem (14.09.2026, test
     nowicjusza): ZANIM klikniesz, widać ile kafelków i KTÓRE warstwy
     wejdą do zapasu - albo wprost, że nie ma czego pobierać i dlaczego. */
  #offline-okno .u-plan{margin-top:6px;font-size:11px;line-height:1.45;color:var(--text);}
  #offline-okno .u-plan.uwaga{color:var(--accent);}
  /* pytanie o zgodę W OKNIE zamiast okienka przeglądarki (confirm):
     okienko bywa blokowane, w aplikacji z ekranu telefonu nie zawsze
     wyskakuje, a w tekście nie da się niczego wyróżnić */
  #offline-okno .u-pytanie{
    margin-top:6px;padding:8px 10px;border:1px solid var(--accent);border-radius:4px;
    background:var(--panel-2);font-size:11.5px;line-height:1.45;color:var(--text);
  }
  #offline-okno .u-pytanie .u-zoomy{margin:8px 0 0;}
  #offline-okno .u-pytanie .glowny,#offline-okno .u-tryb .glowny{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  [data-theme="light"] #offline-okno .u-pytanie .glowny,[data-theme="light"] #offline-okno .u-tryb .glowny{color:#faf8f2;}
  /* długie objaśnienia schowane pod „Jak to działa?" - nowicjusz ma
     widzieć przyciski, nie ścianę tekstu */
  #offline-okno details{margin-top:8px;}
  #offline-okno details summary{cursor:pointer;color:var(--text-dim);font-size:10.5px;user-select:none;}
  #offline-okno details[open] summary{margin-bottom:2px;}
  /* lista warstw do pobrania i lista pobranych obszarów: własne podsumowania
     w kolorze tekstu (to są USTAWIENIA, nie objaśnienia) */
  #offline-okno #u-offline-warstwy summary, #offline-okno #u-offline-pobrane summary{color:var(--text);font-size:11px;}
  #offline-okno #u-offline-warstwy-lista{max-height:180px;overflow:auto;margin-top:4px;}
  #offline-okno #u-offline-warstwy-lista .u-check{display:flex;align-items:center;gap:8px;padding:4px 0;font-size:11px;line-height:1.35;cursor:pointer;color:var(--text);}
  #offline-okno #u-offline-warstwy-lista .u-check input{accent-color:var(--accent);width:14px;height:14px;flex-shrink:0;}
  #offline-okno #u-offline-warstwy-lista .u-check .rok{color:var(--text-dim);}
  /* ptaszek „Ze zdjęciami obiektów" - ten sam wygląd co ptaszki listy warstw
     (27.09.2026: dotąd domyślny niebieski i większe pismo niż reszta okna) */
  #offline-okno #u-offline-praca > .u-check{display:flex;align-items:flex-start;gap:8px;margin-top:8px;font-size:11px;line-height:1.4;color:var(--text);cursor:pointer;}
  #offline-okno #u-offline-praca > .u-check input{accent-color:var(--accent);width:14px;height:14px;flex-shrink:0;margin:1px 0 0;}
  #offline-okno .u-wpis{padding:5px 0;border-top:1px solid var(--line);font-size:11px;line-height:1.4;}
  #offline-okno .u-wpis:first-child{border-top:0;}
  #offline-okno .u-wpis .btn{padding:3px 8px;font-size:11px;margin:4px 4px 0 0;}
  /* ===== okno „Nalot 1944 - zbiórka na klatki" (WERSJA TESTOWA, 17.09.2026) =====
     Pomysł pavvla i Krzyśka: dokupić z archiwum kolejne klatki nalotu
     6 VIII 1944 za pieniądze zebrane wśród ludzi z forum. Okno pokazuje
     stan zbiórki (pasek, progi = partie klatek, fundatorzy), a na mapie
     rysuje SKOROWIDZ klatek: złote = mamy, zielone = opłacone, szare
     kreskowane = brakuje (klik → koszt zamówienia i link do zbiórki). Dane
     z dane/zbiorka.json przez dane.php (pole `zbiorka`), edycja w
     admin/zbiorka.php. Test: dane.php wysyła to tylko redakcji (dostep 3
     w pliku) - przycisk w belce w ogóle się nie pokazuje reszcie. */
  #zbiorka-okno{
    display:none;position:fixed;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);z-index:10950;
    width:min(320px, calc(100% - 20px));
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:12px;
    flex-direction:column;overflow:hidden;
    max-height:calc(100vh - 120px);
    max-height:calc(100dvh - var(--pasek, 52px) - 6px - var(--metka, 22px) - var(--dol));
  }
  #zbiorka-okno.show{display:flex;}
  /* 28.09.2026: ta sama plakietka w nagłówku okna „W teren" (pavvlo: „w «w teren» tak jak jest to w «nalot 1944»") */
  #zbiorka-okno .zb-test, #offline-okno .zb-test{
    font-size:9px;letter-spacing:1px;text-transform:uppercase;color:var(--text-dim);
    border:1px solid var(--line);border-radius:3px;padding:1px 5px;margin-right:8px;flex-shrink:0;
  }
  #zbiorka-okno .u-sekcja{
    font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.4px;
    margin:12px 0 4px;padding-top:9px;border-top:1px solid var(--line);
  }
  #zbiorka-okno .u-hint{color:var(--text-dim);font-size:10.5px;margin-top:8px;line-height:1.45;}
  #zbiorka-okno .u-hint a, #zbiorka-okno .u-hint a:visited, #zbiorka-okno .zb-opis a, #zbiorka-okno .zb-opis a:visited{color:var(--accent);}   /* audyt 24.09: był fiolet odwiedzonego linku */
  #zbiorka-okno .zb-opis{font-size:11.5px;line-height:1.5;color:var(--text);}
  #zbiorka-okno .zb-opis p{margin:0 0 8px;}
  #zbiorka-okno .zb-opis p:last-child{margin-bottom:0;}
  #zbiorka-okno .zb-pasek{
    height:10px;margin-top:10px;border:1px solid var(--line);border-radius:5px;
    background:var(--panel-2);overflow:hidden;
  }
  #zbiorka-okno .zb-pasek-wyp{height:100%;width:0;background:var(--accent);transition:width .4s;}
  #zbiorka-okno .zb-pasek.pelny .zb-pasek-wyp{background:#3f7a5e;}
  #zbiorka-okno .zb-liczby{margin-top:6px;font-size:12px;color:var(--text);}
  #zbiorka-okno .zb-liczby b{color:var(--accent);font-size:14px;}
  #zbiorka-okno .zb-liczby .zb-stan{display:block;color:var(--text-dim);font-size:10.5px;margin-top:2px;}
  #zbiorka-okno .btn{margin-top:6px;}
  #zbiorka-okno a.btn{display:inline-block;text-decoration:none;}
  #zbiorka-okno .glowny{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
  [data-theme="light"] #zbiorka-okno .glowny{color:#faf8f2;}
  #zbiorka-okno .zb-prog{padding:6px 0;border-top:1px solid var(--line);font-size:11.5px;line-height:1.4;}
  #zbiorka-okno .zb-prog:first-child{border-top:0;}
  #zbiorka-okno .zb-prog-n{color:var(--text);font-weight:bold;}
  #zbiorka-okno .zb-prog-k{color:var(--text-dim);font-weight:normal;font-size:10.5px;margin-left:4px;}
  #zbiorka-okno .zb-prog-s{color:var(--text-dim);}
  #zbiorka-okno .zb-prog.ok .zb-prog-s{color:#7dc57d;}
  #zbiorka-okno .zb-prog.toku .zb-prog-s{color:var(--accent);}
  #zbiorka-okno .zb-prog-o{color:var(--text-dim);font-size:10.5px;margin-top:2px;}
  #zbiorka-okno .u-check{display:flex;align-items:center;gap:8px;margin:7px 0;cursor:pointer;color:var(--text);}
  #zbiorka-okno .u-check input{accent-color:var(--accent);width:14px;height:14px;flex-shrink:0;}
  #zbiorka-okno .zb-leg{display:flex;flex-wrap:wrap;gap:4px 12px;font-size:10.5px;color:var(--text-dim);margin-top:4px;}
  #zbiorka-okno .zb-leg span, #zbiorka-okno .zb-leg label{display:inline-flex;align-items:center;gap:5px;}
  #zbiorka-okno .zb-leg i{display:inline-block;width:14px;height:10px;border:1.5px solid;border-radius:2px;}
  #zbiorka-okno .zb-leg .l-mamy i{border-color:#c9a24b;background:rgba(201,162,75,.32);}
  #zbiorka-okno .zb-leg .l-oplacona i{border-color:#4f9d4f;background:rgba(79,157,79,.18);}
  #zbiorka-okno .zb-leg .l-brakuje i{border-color:#e57373;border-style:dashed;background:rgba(229,115,115,.10);box-shadow:0 0 0 1.5px rgba(0,0,0,.45);}
  #zbiorka-okno .zb-leg .l-seria i{box-shadow:0 0 0 1.5px rgba(0,0,0,.45);}
  #zbiorka-okno .zb-leg label{cursor:pointer;}
  #zbiorka-okno .zb-leg label input{accent-color:var(--accent);width:12px;height:12px;margin:0 1px 0 0;}
  #zbiorka-okno .zb-leg label.wyl{opacity:.5;}
  /* ===== TAŚMA KLATEK (18.09.2026, pavvlo: „ciężko podejrzeć, co mamy a czego brakuje") =====
     Jedna kratka = jedna klatka, w kolejności numerów, wiersz na kamerę. Kolor =
     status jak na mapie: złota pełna = mamy, zielona = opłacona, czerwona
     kreskowana = brakuje (inna seria: jej kolor). Najechanie podświetla klatkę
     na mapie, klik dolatuje do niej. To samo robi najechanie/klik na próg. */
  #zbiorka-okno .zb-tasma{margin-top:2px;}
  #zbiorka-okno .zb-tasma-n{font-size:9.5px;color:var(--text-dim);letter-spacing:.3px;margin:7px 0 2px;}
  #zbiorka-okno .zb-tasma-n:first-child{margin-top:4px;}
  #zbiorka-okno .zb-tasma-r{display:flex;flex-wrap:wrap;gap:2px;}
  #zbiorka-okno .zb-k{
    width:18px;height:18px;box-sizing:border-box;border:1.5px dashed #e57373;border-radius:2px;
    background:rgba(229,115,115,.10);color:#f2a49e;font-size:10px;line-height:15px;text-align:center;
    font-weight:bold;letter-spacing:-.2px;cursor:pointer;user-select:none;
    /* 25.09 (Krzysiek: „numerki z klatkami troszkę większym fontem"): kratka 14 -> 18 px, cyfry 8 -> 10 px;
       przy okazji kratka bliżej zalecanych 24 px na dotyk (audyt 24.09, pkt 2) */
  }
  #zbiorka-okno .zb-k.mamy{border-style:solid;border-color:#c9a24b;background:rgba(201,162,75,.6);color:#1a1a1a;}
  #zbiorka-okno .zb-k.oplacona{border-style:solid;border-color:#4f9d4f;background:rgba(79,157,79,.55);color:#f2f2f2;}
  #zbiorka-okno .zb-k.wyroznij{box-shadow:0 0 0 2px var(--accent);}
  #zbiorka-okno .zb-k.ukryta{opacity:.3;}
  [data-theme="light"] #zbiorka-okno .zb-k{color:#a63a3a;}
  [data-theme="light"] #zbiorka-okno .zb-k.oplacona{color:#1a1a1a;}
  #zbiorka-okno .zb-prog{cursor:pointer;}
  #zbiorka-okno .zb-prog.wyroznij .zb-prog-n{color:var(--accent);}
  #zbiorka-okno .zb-prog.przypiety{border-left:3px solid var(--accent);padding-left:8px;margin-left:-11px;}
  #zbiorka-okno .zb-prog.przypiety .zb-prog-n::after{content:' · przypięty - klik w tło mapy lub Esc zdejmuje';color:var(--text-dim);font-weight:normal;font-size:10px;}
  #zbiorka-okno .zb-fund{padding:4px 0;border-top:1px solid var(--line);font-size:11.5px;color:var(--text);}
  #zbiorka-okno .zb-fund:first-child{border-top:0;}
  #zbiorka-okno .zb-fund-k{color:var(--text-dim);font-size:10.5px;margin-left:4px;}
  /* skorowidz klatek na mapie: własny pane nad rastrami i ramkami zdjęć
     (9500), pod zakładkami ramek (9600) i pinezkami (10000+) */
  .zb-etyk{
    text-align:center;line-height:18px;font-size:11.5px;font-weight:bold;letter-spacing:.3px;   /* 24.09 Krzysiek: „troszkę większym fontem" (było 10 px) */
    color:#c9a24b;text-shadow:0 0 3px #000,0 0 3px #000;cursor:pointer;   /* 24.09: numer łapie mysz - fokus i dymek */
  }
  .zb-etyk span{padding:0 3px;}
  .zb-etyk.zb-etyk-brakuje{color:#f2a49e;}
  .zb-etyk.zb-etyk-oplacona{color:#8fd08f;}
  [data-theme="light"] .zb-etyk{text-shadow:0 0 3px #fff,0 0 3px #fff;color:#8a6a1e;}   /* audyt 24.09: złoto na kremowym było za blade */
  [data-theme="light"] .zb-etyk.zb-etyk-brakuje{color:#a63a3a;}
  [data-theme="light"] .zb-etyk.zb-etyk-oplacona{color:#2f7a2f;}
  /* NUMERY WG ZOOMU (24.09.2026): z<12 żadnych, z12-13 tylko klatki „mamy/opłacone"
     (te są rzadkie i to o nie chodzi), od z13 wszystkie. Wcześniej wszystkie od z11 -
     przy 87 klatkach w dwu nachodzących pasach numery zlewały się w plamę. */
  .leaflet-pane.zb-daleko .zb-etyk{display:none;}
  .leaflet-pane.zb-srednio .zb-etyk:not(.zb-etyk-mamy):not(.zb-etyk-oplacona){display:none;}
  /* GRUBOŚĆ LINII WG ZOOMU (24.09.2026, pavvlo: „ramki ciut cieńsze w oddaleniu"):
     pełna grubość (1,8-2 px + halo 4,6) od z14; niżej stopniowo cieniej. CSS
     stroke-width wygrywa z atrybutem, który ustawia Leaflet - stąd najechanie
     na klatkę grubi ją własną klasą zb-hover, nie setStyle. */
  .leaflet-pane.zb-z13 .zb-w{stroke-width:1.5px;}            .leaflet-pane.zb-z13 .zb-h{stroke-width:3.8px;}
  .leaflet-pane.zb-srednio .zb-w{stroke-width:1.25px;}       .leaflet-pane.zb-srednio .zb-h{stroke-width:3.1px;}
  .leaflet-pane.zb-daleko .zb-w{stroke-width:1px;}           .leaflet-pane.zb-daleko .zb-h{stroke-width:2.4px;}
  .leaflet-pane.zb-bardzo-daleko .zb-w{stroke-width:.8px;}   .leaflet-pane.zb-bardzo-daleko .zb-h{stroke-width:1.9px;}
  .leaflet-pane .zb-w.zb-hover{stroke-width:3.2px;}
  /* FOKUS (24.09.2026, pomysł pavvla): po najechaniu na próg lub kratkę taśmy
     WSZYSTKO SPOZA zestawu gaśnie (linie, halo, numery), zestaw zostaje w zwykłym
     stylu i z numerami - także przy zoomie, który numery normalnie chowa. */
  .leaflet-pane .zb-w, .leaflet-pane .zb-h{transition:opacity .15s;}
  .leaflet-pane.zb-fokus .zb-w:not(.zb-on), .leaflet-pane.zb-fokus .zb-h:not(.zb-on){opacity:.09;}
  .leaflet-pane.zb-fokus .zb-etyk:not(.zb-on){display:none;}
  .leaflet-pane.zb-fokus .zb-etyk.zb-on{display:block !important;}
  #zbiorka-okno .zb-tasma.fokus .zb-k:not(.wyroznij){opacity:.25;}
  .zb-popup .zb-d-tyt{font-weight:bold;color:var(--accent);font-size:12.5px;margin-bottom:3px;}
  .zb-popup .zb-d-st{color:var(--text);}
  .zb-popup .zb-d-st.ok{color:#7dc57d;}
  .zb-popup .zb-d-u{color:var(--text-dim);font-size:11px;margin-top:4px;}
  .zb-popup .zb-d-f{margin-top:5px;color:var(--text);font-size:11px;}
  .zb-popup .zb-d-przyklad{border-top:1px dashed var(--line);padding-top:4px;}
  .zb-popup .zb-d-btn{margin-top:7px;display:inline-block;text-decoration:none;font-size:11px;padding:4px 9px;}

  /* ===== okno sesji forum ===== */
  #sesja-okno{
    display:none;position:fixed;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);z-index:10950;
    width:min(320px, calc(100% - 20px));
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:12px;
    flex-direction:column;overflow:hidden;
    /* to samo co przy oknie ustawień — okno sesji też potrafi urosnąć
       (dostęp partnerski, odliczanie, linki) */
    max-height:calc(100vh - 120px);
    max-height:calc(100dvh - var(--pasek, 52px) - 6px - var(--metka, 22px) - var(--dol));
  }
  #sesja-okno.show{display:flex;}
  #sesja-okno .s-tytul{color:var(--accent);font-weight:bold;font-size:12.5px;margin-bottom:9px;}
  #sesja-okno label{display:block;font-size:10px;color:var(--text-dim);text-transform:uppercase;letter-spacing:.4px;margin:8px 0 3px;}
  #sesja-okno input[type=text],#sesja-okno input[type=password]{
    width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--line);
    color:var(--text);padding:7px 9px;border-radius:3px;font:inherit;font-size:12.5px;
  }
  #sesja-okno input:focus{outline:none;border-color:var(--accent);}
  #sesja-okno .s-check{display:flex;align-items:center;gap:7px;text-transform:none;font-size:11.5px;color:var(--text);letter-spacing:0;margin:10px 0;}
  #sesja-okno .s-check input{accent-color:var(--accent);width:14px;height:14px;}
  #sesja-okno .s-glowny{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;width:100%;}@media (hover:hover){ #sesja-okno .s-glowny:hover{background:#e0bb63;color:#1a1a1a;} }
  #s-blad{color:#e07070;margin-top:8px;line-height:1.5;display:none;}
  #s-blad.show{display:block;}
  #sesja-okno .s-stopka{color:var(--text-dim);font-size:10.5px;line-height:1.55;margin-top:10px;border-top:1px solid var(--line);padding-top:8px;}
  #sesja-okno .s-stopka a{color:var(--accent);}
  #sesja-info{display:none;}
  #sesja-vip{display:none;}
  #sesja-okno.vip #sesja-vip{display:block;}
  #sesja-okno.vip #sesja-logowanie{display:none;}
  /* Odliczanie partnera dostaje ten sam oddech co odliczanie sesji (#s-czas):
     wcześniej ten div nie miał ŻADNEGO marginesu, więc „Wyloguj" kleił się
     do zdania „Aktywny jeszcze…" (zgłoszenie 13.09). Dół nieco większy niż
     w #s-czas — pod spodem stoi pojedynczy przycisk, nie para, więc bez tego
     odstępu całość czyta się jak jeden blok. */
  #s-vip-czas{margin:4px 0 16px;line-height:1.5;}
  #s-vip-det{margin-top:10px;border-top:1px solid var(--line);padding-top:8px;}
  #s-vip-det summary{cursor:pointer;color:var(--text-dim);font-size:11.5px;}@media (hover:hover){ #s-vip-det summary:hover{color:var(--accent);} }
  #s-vip-det[open] summary{color:var(--accent);margin-bottom:6px;}
  #s-vip-blad{color:#e05555;font-size:11px;margin-top:6px;min-height:14px;}
  #s-panel{
    display:block;margin-top:9px;color:var(--accent);font-size:12px;
    text-decoration:none;font-weight:bold;
  }@media (hover:hover){ #s-panel:hover{color:var(--accent-2);text-decoration:underline;} }
  #sesja-okno.zalogowany #sesja-info{display:block;}
  #sesja-okno.zalogowany #sesja-logowanie{display:none;}
  #s-rola{color:var(--text-dim);font-weight:normal;font-size:11px;}
  #s-czas{margin:4px 0 10px;line-height:1.5;}
  #s-czas b{color:var(--accent);}
  #s-czas.malo b{color:#e07070;}
  #sesja-okno .s-akcje{display:flex;gap:8px;}
  #sesja-okno .s-akcje .btn{flex:1;}
  /* przycisk w topbarze: mało czasu = ostrzegawcza czerwień */
  #sesja-btn.malo{border-color:#b03434;color:#e07070;}
  #sesja-btn.wygasla{background:#b03434;border-color:#b03434;color:#fff;}


  /* ===== komunikaty lokalizacji — od 11.09.2026 BEZ ZEGARKA =====
     Dymek zostaje na ekranie, aż człowiek go zamknie krzyżykiem. Powód
     z terenu: „każdy czyta w swoim tempie lub akurat nie patrzy na ekran,
     a czas mija i okienko się zamyka" — w lesie, z telefonem w kieszeni,
     komunikat liczony na sekundy po prostu nie dociera. Wyjątkiem są
     komunikaty O STANIE („szukam sygnału"), które gasną SAME, ale gdy
     stan przestaje być prawdą (przyjdzie pozycja), a nie po zegarku. */
  /* Szerokość: CELOWO `left/right` + `margin:auto` zamiast dawnego
     `left:50%` z przesunięciem. Przy `left:50%` element o szerokości
     „do treści" ma do dyspozycji tylko POŁOWĘ ekranu — na telefonie 390 px
     raport diagnostyczny mieścił się w 195 px i rozlewał na osiem wierszy,
     mimo max-width 280. Teraz dymek ma całą szerokość ekranu minus
     marginesy i zwęża się sam, gdy tekst jest krótki. */
  #geo-toast{
    /* ===== szerokość i położenie — wersja trzecia, 12.09.2026 =====
       Dwie prośby redakcji naraz: (1) dymek ma stać w PAŚMIE między lewą
       krawędzią ekranu a słupkiem narzędzi, nie na środku całego ekranu,
       (2) ma zajmować całą szerokość tego pasma, „aby okienka jak
       najmniej rosły do góry".

       Druga prośba zmienia podejście: dotąd dymek zwężał się do treści
       (`width:fit-content`), a teraz ROZPYCHA się na całe pasmo. Przy
       długim tekście to konkretny zysk — raport diagnostyczny z 216 px
       wysokości schodzi poniżej 170, bo każdy wiersz mieści więcej słów.
       Krótki komunikat jest wtedy szerszy, niż musi, ale ma jeden wiersz
       tak czy inaczej, a stała szerokość jest spokojniejsza dla oka niż
       dymek zmieniający rozmiar przy każdym komunikacie.

       Skoro dymek wypełnia pasmo, `margin:auto` nie ma już czego
       rozdzielać na telefonie — i dobrze, bo pasmo JEST tym, co miało
       być wypełnione. Na komputerze pasmo ma ponad tysiąc pikseli, więc
       tam max-width przycina dymek, a margines ustawia go na środku.
       (Tym razem to działa celowo; 12.09 ta sama sytuacja zdarzyła się
       przypadkiem i wyglądała jak przyklejenie do lewej krawędzi.) */
    /* PASMO liczone dokładnie tym samym wzorem, co #sidebar, #timeline
       i #nawigacja: luz | pasmo | luz | słupek | luz. Jeden wzór na cały
       dolny interfejs — zmiana marginesu albo szerokości słupka przesuwa
       wszystko naraz i nic się nie rozjeżdża. (Wcześniej dymek miał tu
       własny rachunek „słupek + luz + 8", przez co był o kilka pikseli
       węższy od panelu — widać to było na zrzucie z telefonu.) */
    position:absolute;left:var(--luz, 10px);
    right:calc(var(--luz, 10px) * 2 + var(--slupek, 38px));
    margin:0 auto;
    bottom:90px;z-index:10950;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    padding:8px 6px 8px 14px;font-size:12px;color:var(--text);box-shadow:var(--shadow);
    /* Na telefonie dymek WYPEŁNIA pasmo (max-width nigdy nie dobija do
       420 px), więc tekst łamie się na jak najmniejszą liczbę wierszy.
       Na komputerze pasmo ma ponad tysiąc pikseli i rozciągnięty na nie
       dymek byłby karykaturą — tam ogranicza go max-width, a `margin:auto`
       ustawia go na środku pasma. */
    max-width:420px;
    text-align:left;line-height:1.5;display:none;opacity:0;
    transition:opacity .3s;
    align-items:flex-start;gap:2px;
  }
  #geo-toast.show{opacity:1;}
  /* ===== RAMKA MÓWI, JAKIEGO RODZAJU JEST TO KOMUNIKAT (12.09.2026) =====
     Prośba redakcji: „może te monity otoczyć inną ramką, delikatnie
     czerwoną — coś na zasadzie, że jest to systemowa informacja".

     Ale NIE wszystkie: dymek jest jednym pudełkiem dla kilku różnych
     rzeczy. „Szukam sygnału GPS…" to spokojny stan, a „Zapas na wyjazd
     gotowy" to wręcz dobra wiadomość — obramowanie ich na czerwono
     krzyczałoby bez powodu i po tygodniu przestałoby cokolwiek znaczyć.
     Czerwień dostaje więc tylko rodzaj „coś jest nie tak i trzeba coś
     zrobić": brak położenia i blokady GPS-u.

     Kolor to ten sam #c94b4b, którym okrąg dokładności mówi „słaby
     odczyt" — jedna czerwień w całej aplikacji, nie dwie podobne. */
  #geo-toast.gt-uwaga{border-color:#c94b4b;}
  #geo-toast .gt-tresc{flex:1;min-width:0;white-space:pre-line;}  /* raport GPS łamie się w wiersze */
  /* rząd przycisków w Ustawieniach (wybór szczegółowości, akcje zapasu) */
  .u-zoomy{display:flex;flex-wrap:wrap;gap:6px;margin:6px 0;}
  .u-zoomy .btn{flex:0 0 auto;}
  /* krzyżyk: pole dotyku 40×40 nawet w rękawiczce, bez powiększania dymka */
  #geo-toast .gt-x{
    flex:0 0 auto;width:40px;height:40px;margin:-10px -6px -10px 0;
    background:none;border:0;padding:0;cursor:pointer;
    color:var(--text-dim);font-size:19px;line-height:1;font-family:inherit;
    display:flex;align-items:center;justify-content:center;
  }@media (hover:hover){ #geo-toast .gt-x:hover{color:#e05555;} }
  /* ===== PRZYCISK DZIAŁANIA W KOMUNIKACIE (27.09.2026) =====
     Pierwszy komunikat, po którym jest co kliknąć: „Sesja forum wygasła…"
     z przyciskiem „Zaloguj ponownie". Przycisk stoi w DRUGIM wierszu, pod
     tekstem (flex-wrap + podstawa 100%), więc tekst i krzyżyk zostają
     w pierwszym wierszu tak jak w każdym innym komunikacie. Bez działania
     wiersz jest schowany i nic się nie zmienia. */
  #geo-toast{flex-wrap:wrap;}
  #geo-toast .gt-akcje{display:none;flex:0 0 100%;padding:8px 0 2px;}
  #geo-toast.z-akcja .gt-akcje{display:block;}
  #geo-toast .gt-akcja{
    background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;
    min-height:36px;padding:6px 16px;
  }@media (hover:hover){ #geo-toast .gt-akcja:hover{background:#e0bb63;color:#1a1a1a;} }

  /* ===== menu prawego przycisku (12.09.2026) =====
     Prawy klik / długie przytrzymanie na mapie otwiera własne menu zamiast
     przeglądarkowego („zapisz obraz" na kafelku nikomu się nie przydało).
     Wygląd jak reszta paneli: --panel/--line/--shadow, jedna czcionka.
     Wiersze ≥40 px — menu otwiera się też palcem, więc obowiązuje ten sam
     rozmiar pola dotyku co przy krzyżyku dymka GPS. Pozycja liczona przy
     otwarciu i docinana do ekranu; position:fixed, bo menu ma stać przy
     kursorze niezależnie od tego, co przewija się pod spodem. */
  #ctx-menu{
    position:fixed;z-index:11050;display:none;
    min-width:210px;max-width:min(320px, calc(100vw - 16px));
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);padding:4px 0;font-size:12.5px;color:var(--text);
    /* max-height tu jest tylko ZAPASEM na wypadek braku JS — właściwą
       wysokość ustawia ctxUstaw() z window.innerHeight przy każdej zmianie
       treści, bo 100vh na telefonie bywa większe niż widoczny ekran */
    overflow-y:auto;max-height:calc(100vh - 90px);
    user-select:none;-webkit-user-select:none;
  }
  #ctx-menu.show{display:block;}
  #ctx-menu .cm-naglowek{
    padding:7px 14px 6px;color:var(--text-dim);font-size:11px;
    border-bottom:1px solid var(--line);margin-bottom:4px;white-space:nowrap;
    font-family:monospace; /* współrzędne — jak w okienku w rogu */
  }
  #ctx-menu .cm-poz{
    display:flex;align-items:center;gap:10px;
    min-height:36px;padding:3px 14px;cursor:pointer;line-height:1.3;
  }
  /* GĘSTOŚĆ ZALEŻNA OD URZĄDZENIA (uwaga pavvla 12.09: „odstępy między
     pozycjami są zbyt duże", potem „jeszcze bardziej bym zagęścił").
     Dotyk: 36 px (z 40) — wciąż pole na palec, ale bez luzu. Mysz: 26 px
     jak w systemowym menu — kursor trafia bez wysiłku, a lista 24 map robi
     się o jedną trzecią krótsza. Warunek: hover I precyzyjny wskaźnik —
     sam hover mają tablety z rysikiem, sam pointer:fine bywa fałszywy
     w emulacji. */
  @media (hover:hover) and (pointer:fine){
    #ctx-menu{padding:3px 0;font-size:12px;}
    #ctx-menu .cm-poz{min-height:26px;padding:2px 14px;}
    #ctx-menu .cm-info{min-height:24px;}
    #ctx-menu .cm-naglowek{padding:4px 14px 3px;margin-bottom:2px;}
    #ctx-menu .cm-kreska{margin:2px 0;}
  }
  @media (hover:hover){ #ctx-menu .cm-poz:hover{background:var(--bg);color:var(--accent);} }
  #ctx-menu .cm-poz:active{background:var(--bg);}
  #ctx-menu .cm-nazwa{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}
  /* dopisek po prawej (odległość do obiektu) — przygaszony, nie ucieka z wiersza */
  #ctx-menu .cm-dal{margin-left:auto;color:var(--text-dim);font-size:11px;flex:0 0 auto;padding-left:8px;}
  /* wiersz-informacja: „w pobliżu nic nie ma" — nie wygląda jak przycisk */
  #ctx-menu .cm-info{min-height:34px;color:var(--text-dim);cursor:default;font-size:11.5px;white-space:normal;}
  @media (hover:hover){ #ctx-menu .cm-info:hover{background:none;color:var(--text-dim);} }
  /* potwierdzenie kopiowania — ta sama zieleń co „bardzo dobra" dokładność
     GPS (#4f9d4f): jedna zieleń w całej aplikacji, jak jedna czerwień */
  #ctx-menu .cm-ok{color:#4f9d4f;}
  @media (hover:hover){ #ctx-menu .cm-ok:hover{background:none;color:#4f9d4f;} }
  /* kreska przed pozycjami redakcyjnymi (korekta, zapas na wyjazd) */
  #ctx-menu .cm-kreska{border-top:1px solid var(--line);margin:4px 0;}

  /* ===== pasek podpowiedzi przy rysowaniu obrysu „Na wyjazd" (14.09.2026) =====
     Jedno zdanie i dwa przyciski, u góry pod belką — okno „Na wyjazd" jest
     w tym czasie schowane, więc to jedyne miejsce, które mówi, co robić.
     Pasmo 10950 jak dymki i okna. Na telefonie zawija się do dwóch wierszy. */
  #zazn-pasek, #pobieranie-pasek{
    position:fixed;left:50%;top:calc(var(--pasek, 52px) + 8px);transform:translateX(-50%);
    z-index:10950;display:none;align-items:center;gap:8px;flex-wrap:wrap;justify-content:center;
    max-width:calc(100vw - 16px);padding:7px 12px;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:12px;color:var(--text);line-height:1.4;
  }
  #zazn-pasek.show, #pobieranie-pasek.show{display:flex;}
  #zazn-pasek .zp-t, #pobieranie-pasek .zp-t{flex:1 1 auto;min-width:160px;}
  #zazn-pasek .btn, #pobieranie-pasek .btn{flex:0 0 auto;}
  /* ===== mini-pasek pobierania przy ZAMKNIĘTYM oknie „Na wyjazd" (14.09.2026) =====
     Pobieranie trwa minuty, a okno zasłania mapę — naturalny odruch to je
     zamknąć. Dotąd postęp znikał wtedy z oczu, a na telefonie nawet napis
     na pozycji menu jest schowany pod „⋯". Ten sam kształt, co pasek
     rysowania obrysu: jedno zdanie, cienki pasek, przycisk „Przerwij";
     dotknięcie zdania otwiera okno z powrotem. */
  #pobieranie-pasek{width:min(420px, calc(100vw - 16px));}   /* stała szerokość: tekst i „Przerwij" w jednym rzędzie, pasek pod nimi */
  #pobieranie-pasek .zp-t{cursor:pointer;}
  #pobieranie-pasek .pp-tor{
    flex:1 1 100%;height:5px;border-radius:3px;background:var(--panel-2);
    border:1px solid var(--line);overflow:hidden;margin-top:-2px;
  }
  #pobieranie-pasek .pp-wyp{height:100%;width:0;background:var(--accent);transition:width .25s;}
  /* plakietka TEST w przyciskach belki (28.09.2026) - ten sam wygląd co TEST w nagłówku okna „Nalot 1944"
     (#zbiorka-okno .zb-test); ujemne marginesy pionowe, żeby nie podnosiła przycisku ponad sąsiadów w belce */
  /* ta sama plakietka przy „Nalot 1944" (28.09.2026, pavvlo: „do «nalot 1944» też dodaj «test»") */
  #topbar .btn .plak-test{
    display:inline-block;margin:-2px 0 -2px 7px;padding:1px 5px;vertical-align:1px;
    font-size:9px;line-height:1.15;letter-spacing:1px;text-transform:uppercase;font-weight:normal;
    color:var(--text-dim);border:1px solid var(--line);border-radius:3px;
  }
  /* przycisk wciśnięty (złote tło, okno otwarte): szary napis ginął na złocie - plakietka bierze kolor napisu */
  #topbar .btn.active .plak-test{color:inherit;border-color:currentColor;opacity:.75;}
  /* ===== karta postępu NA pobieranym terenie (28.09.2026) - opis przy postepNaMapiePokaz() =====
     Marker Leafleta w środku terenu; środek karty w tym punkcie (translate -50%). Znacznik bez
     rozmiaru i tła, klikalna jest sama karta. Wygląd jak mini-pasek u góry, obwódka złota
     jak ramka terenu, na koniec zielona jak obrys „w zapasie". */
  .pm-ikona{background:none;border:0;}
  .pm-karta{position:absolute;left:0;top:0;transform:translate(-50%,-50%);
    width:max-content;min-width:190px;max-width:260px;box-sizing:border-box;padding:7px 10px 8px;
    background:var(--panel);border:1px solid #d9b25a;border-radius:4px;box-shadow:var(--shadow);
    font-size:12px;line-height:1.4;color:var(--text);pointer-events:auto;cursor:default;transition:opacity .4s;}
  .pm-karta .pm-t{font-weight:bold;white-space:nowrap;cursor:pointer;}
  .pm-karta .pm-tor{height:5px;border-radius:3px;background:var(--panel-2);border:1px solid var(--line);overflow:hidden;margin-top:5px;}
  .pm-karta .pm-wyp{height:100%;width:0;background:#d9b25a;transition:width .25s;}   /* kolory = OBRYS_ZLOTY / OBRYS_ZIELONY (28.09) */
  .pm-karta .pm-dol{display:flex;align-items:center;gap:8px;margin-top:5px;}
  .pm-karta .pm-r{flex:1 1 auto;color:var(--text-dim);font-size:11px;white-space:nowrap;}
  .pm-karta .btn{flex:0 0 auto;margin:0;padding:2px 8px;font-size:11px;}
  .pm-karta.bez-przerwij .pm-przerwij{display:none;}
  .pm-karta.koniec .pm-dol{display:none;}
  .pm-karta.gotowe{border-color:#6dbd6d;}
  .pm-karta.gotowe .pm-wyp{background:#6dbd6d;}
  .pm-karta.znika{opacity:0;}

  #zoom-indicator{
    position:absolute;top:calc(var(--pasek, 52px) + 6px);left:360px;z-index:1100;min-height:30px;
    display:flex;align-items:center;
    background:var(--panel);border:1px solid var(--line);border-radius:3px;
    padding:0 11px;font-size:12px;line-height:16px;color:var(--text-dim);box-shadow:var(--shadow);
    font-family:monospace;transition:left .2s,opacity .25s;cursor:pointer;
  }
  #zoom-indicator.faded{opacity:0;pointer-events:none;}@media (hover:hover){ #zoom-indicator:hover{border-color:var(--accent);color:var(--accent);} }
  #zoom-indicator.limit{color:#e05555;border-color:#e05555;font-weight:bold;}@media (hover:hover){ #zoom-indicator.limit:hover{color:#e05555;border-color:#e05555;} }
  #zoom-indicator.native{color:#4f9d4f;border-color:#4f9d4f;font-weight:bold;}@media (hover:hover){ #zoom-indicator.native:hover{color:#4f9d4f;border-color:#4f9d4f;} }
  /* rocznik NASZEGO ortofoto w liczniku (2.10.2026): złoto ramki i zakładki „Ortofoto 2025"; w jasnym
     motywie --accent jest ciemniejszy - kontrast jak reszta akcentów. 5 cm GUGiK zostaje w zwykłym kolorze. */
  #zoom-indicator.orto-nasze{color:var(--accent);border-color:var(--accent);}@media (hover:hover){ #zoom-indicator.orto-nasze:hover{color:var(--accent-2);border-color:var(--accent-2);} }
  #coord-indicator{
    position:absolute;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);z-index:1100;height:30px;
    display:flex;align-items:center;
    background:var(--panel);border:1px solid var(--line);border-radius:3px;
    padding:0 11px;font-size:12px;line-height:16px;color:var(--text-dim);box-shadow:var(--shadow);
    font-family:monospace;cursor:pointer;white-space:nowrap;
    transition:transform .2s;
  }
  #coord-indicator.schowany{transform:translateX(calc(100% + 20px));}
  /* włączona warstwa z legendą: okienko przesiada się na jej lewą stronę
     (10px margines + 264px legendy + 8px odstępu) */
  body.legenda-obok #coord-indicator{right:282px;}
  body.legenda-obok #coord-indicator.schowany{transform:translateX(calc(100% + 292px));}@media (hover:hover){ #coord-indicator:hover{border-color:var(--accent);color:var(--accent);} }
  #coord-indicator.frozen{border-color:var(--accent);color:var(--accent);font-weight:bold;}
  /* ===== wpisywanie współrzędnych (1.10.2026) =====
     Okienko współrzędnych ma trzy stałe części: pinezkę (miejsce zawsze
     tej samej szerokości), tekst i ołówek. Ołówek otwiera pod okienkiem
     pole w tym samym stylu; klik w resztę okienka kopiuje, jak dotąd.
     2.10.2026 (pavvlo: „spójnie i w jednej osi"): pinezka i ołówek siedzą
     w DWÓCH JEDNAKOWYCH POLACH 24x24, lustrzanie - każde 2 px od ramki
     (z góry, z dołu i z boku; tło ołówka po najechaniu ma więc równe
     marginesy), 2 px od tekstu. Ikona 14 px na środku pola = środek na osi
     okienka. Ujemne marginesy zjadają 9 z 11 px paddingu, więc stan
     „Skopiowano…" (bez pinezki) dalej ma tekst 11 px od ramki. Kolor obu
     z okienka (szare / złote po przypięciu) - do 2.10 ołówek zostawał szary
     przy złotej pinezce. */
  #coord-indicator .ko-pin{
    display:flex;align-items:center;justify-content:center;flex:0 0 auto;
    width:24px;height:24px;margin:0 2px 0 -9px;
  }
  #coord-indicator.kopia .ko-pin{display:none;}
  /* tekst na środku swojego pola: pole ma szerokość zaokrągloną w górę do
     całego piksela (pokazWspolrzedne), nadwyżka dzieli się na dwie strony */
  #coord-indicator .ko-tekst{text-align:center;}
  #coord-indicator .ko-pin svg, #coord-indicator .ko-wpisz svg{display:block;}
  #coord-indicator .ko-wpisz{
    display:flex;align-items:center;justify-content:center;flex:0 0 auto;
    width:24px;height:24px;margin:0 -9px 0 2px;padding:0;
    background:none;border:none;border-radius:3px;color:inherit;cursor:pointer;
  }
  @media (hover:hover){ #coord-indicator .ko-wpisz:hover{color:var(--accent);background:var(--bg);} }
  #coord-indicator.wpis-otwarty .ko-wpisz{color:var(--accent);}
  #wsp-wpis{
    position:absolute;top:90px;right:var(--luz);z-index:10800;display:none;
    width:300px;box-sizing:border-box;font-size:11px;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;box-shadow:var(--shadow);
    transition:transform .2s;
  }
  #wsp-wpis.show{display:block;}
  #wsp-wpis.schowany{transform:translateX(calc(100% + 20px));}
  body.legenda-obok #wsp-wpis{right:282px;}
  body.legenda-obok #wsp-wpis.schowany{transform:translateX(calc(100% + 292px));}
  #wsp-wpis .ww-gora{display:flex;align-items:center;gap:6px;padding:7px 3px 5px 9px;}
  #wsp-pole{
    flex:1;min-width:0;height:26px;box-sizing:border-box;padding:0 7px;
    background:var(--bg);color:var(--text);border:1px solid var(--line);border-radius:3px;
    font:12px monospace;outline:none;
  }
  #wsp-pole:focus{border-color:var(--accent);}
  #wsp-pole::placeholder{color:var(--text-dim);opacity:.8;}
  #wsp-idz{
    flex:0 0 auto;height:26px;padding:0 10px;background:transparent;
    border:1px solid var(--line);border-radius:3px;color:var(--text-dim);cursor:pointer;
    font:inherit;font-size:10px;letter-spacing:.5px;text-transform:uppercase;
  }
  @media (hover:hover){ #wsp-idz:hover{color:var(--accent);border-color:var(--accent);} }
  #wsp-wpis .zamknij{
    flex:0 0 auto;color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 6px 2px 2px;user-select:none;-webkit-user-select:none;
  }
  @media (hover:hover){ #wsp-wpis .zamknij:hover{color:#e05555;} }
  #wsp-wpis .ww-info{padding:0 11px 8px;color:var(--text-dim);line-height:1.45;min-height:16px;}
  #wsp-wpis .ww-info b{color:var(--text);font-weight:normal;font-family:monospace;white-space:nowrap;}
  #wsp-wpis .ww-info.blad{color:#e05555;}
  /* pinezka wpisanego punktu: złoto i ciemna obwódka jak obrysy na mapie */
  .wsp-pinezka{background:none;border:none;}
  .wsp-dymek .wsp-dm{font-family:monospace;margin-top:3px;}
  .wsp-dymek .wsp-dz{font-family:monospace;color:var(--text-dim);}
  .wsp-dymek .wsp-obok{margin-top:5px;color:var(--text-dim);}
  .wsp-dymek .wsp-obok a{color:var(--accent);}
  .wsp-dymek .wsp-rozdz{color:var(--text-dim);margin:0 2px;}
  @media (max-width:640px){
    /* telefon: okienka współrzędnych nie ma — pole na całą szerokość pod
       paskiem; 16 px, bo przy mniejszym iPhone powiększa stronę przy pisaniu */
    #wsp-wpis{left:var(--luz);right:var(--luz);width:auto;}
    #wsp-pole{font-size:16px;height:36px;}
    #wsp-idz{height:36px;font-size:12px;padding:0 14px;}
    #wsp-wpis .ww-info{font-size:12px;}
  }
  /* celownik zamiast łapki — precyzyjne odczyty współrzędnych;
     podczas przeciągania wraca chwytająca dłoń dla czytelności gestu */
  #map.leaflet-grab{cursor:crosshair;}
  .leaflet-dragging #map.leaflet-grab{cursor:grabbing;}
  .robocza-row{margin:5px 0 0 23px;}
  .badge-robocza,.badge-archiwum,.badge-testy,.badge-zalogowani{
    display:inline-block;width:96px;box-sizing:border-box;
    font-size:10px;padding:2px 0;border-radius:3px;color:#fff;
    font-weight:bold;white-space:nowrap;text-align:center;
  }
  .badge-robocza{background:#b03434;letter-spacing:.6px;}
  .badge-archiwum{background:#7a5a24;letter-spacing:.6px;}
  .badge-testy{background:#3f5e8a;letter-spacing:.6px;}
  /* materiał odsłaniany po zalogowaniu na forum — zieleń, bo to nie jest
     ograniczenie „redakcyjne” jak KALIBRACJA czy ARCHIWUM, tylko zaproszenie:
     wystarczy mieć konto */
  .badge-zalogowani{background:#3f7a5e;letter-spacing:.6px;}

  /* ===== ZAPOWIEDZI — warstwy, których jeszcze nie ma (31.08) =====
     Rocznik w opracowaniu stoi w liście na swoim miejscu w czasie, wygaszony
     i nieklikalny. Dwa powody: widać, że zbiór rośnie, i widać, czemu w osi
     czasu jest luka między 2010 a 2014. Plakietka bez wypełnienia — to nie
     jest ograniczenie dostępu jak KALIBRACJA czy ARCHIWUM, tylko zapowiedź,
     więc mówi cieniej: sam obrys, bez tła. */
  .layer.zapowiedz{opacity:.5;}
  .layer.zapowiedz .name{cursor:default;font-weight:normal;font-style:italic;}
  .layer.zapowiedz .chk{pointer-events:none;}
  /* Plakietka siedzi W WIERSZU nazwy, w miejscu po ikonce „i" — zapowiedź
     jej nie ma, więc prawa strona i tak stała pusta. Osobny wiersz statusu
     (jak przy KALIBRACJA/ARCHIWUM) kosztowałby drugie tyle wysokości, a przy
     ośmiu zapowiedziach naraz to już połowa panelu.
     Szerokość WŁASNA, nie 96 px jak tamte plakietki: te układają się w kolumnę
     pod nazwami i muszą być równe, ta stoi w wierszu i ma tylko nie ściskać
     nazwy warstwy. */
  .badge-wkrotce{
    display:inline-block;flex-shrink:0;
    font-size:10px;padding:1px 7px;border-radius:3px; /* 1.10: jak pozostałe plakietki */
    color:var(--text-dim);border:1px dashed var(--line);background:none;
    font-weight:bold;white-space:nowrap;text-align:center;letter-spacing:.6px;
  }
  /* ===== ZAJAWKI DLA GOŚCI (24.09.2026, pavvlo) =====
     Warstwa „tylko dla zalogowanych" u niezalogowanego: szary wiersz bez
     działającego ptaszka i pod nim zaproszenie „Zaloguj się. Rejestracja
     bezpłatna" - pierwsze otwiera okno logowania, drugie rejestrację na forum.
     Sam wiersz przygaszony, zaproszenie w pełnym kolorze (to ono ma pracować).
     Zieleń jak plakietka ZALOGOWANI: nie ograniczenie, tylko zaproszenie. */
  .layer.zamknieta .row{opacity:.5;}
  .layer.zamknieta .name{cursor:default;font-weight:normal;}
  .layer.zamknieta .chk{pointer-events:none;}
  .layer.zamknieta .zaloguj-row{margin:3px 0 0 23px;font-size:11px;line-height:1.4;} /* 1.10: stopień 11 jak opis warstwy */
  .layer.zamknieta .zaloguj-row a{color:#6fbf93;text-decoration:none;font-weight:bold;}
  .layer.zamknieta .zaloguj-row a.rej{color:var(--text-dim);font-weight:normal;text-decoration:underline dotted;}
  [data-theme="light"] .layer.zamknieta .zaloguj-row a{color:#2f7a2f;}
  [data-theme="light"] .layer.zamknieta .zaloguj-row a.rej{color:var(--text-dim);}@media (hover:hover){ .layer.zamknieta .zaloguj-row a:hover{color:var(--accent);} }

  /* ===== pinezki fortyfikacji: popup i etykieta w kolorach motywu =====
     Domyślny popup Leaflet jest biały — w trybie ciemnym świeciłby jak
     latarka. Kolory idą z var(), więc przełącznik motywu działa od razu. */
  .leaflet-popup-content-wrapper,.leaflet-popup-tip{
    background:var(--panel);color:var(--text);box-shadow:var(--shadow);
  }
  .leaflet-popup-content-wrapper{border:1px solid var(--line);border-radius:4px;}
  .leaflet-popup-content{margin:10px 14px;font-family:inherit;font-size:12px;line-height:1.55;}
  .leaflet-popup-close-button{color:var(--text-dim) !important;}@media (hover:hover){ .leaflet-popup-close-button:hover{color:#e05555 !important;} }
  /* STAŁA szerokość dymka punktowego: Leaflet dopasowuje dymek do
     najdłuższej linijki tekstu, więc zdjęcia (width:100%) renderowały
     się w różnych skalach zależnie od długości opisu — ujednolicamy
     format wszystkich fotografii */
  .fort-pop{width:min(260px, calc(100vw - 62px));}
  .fort-pop b{color:var(--accent);font-size:12.5px;}
  .fort-pop .typ{color:var(--text-dim);font-size:11px;margin-bottom:4px;}
  .fort-pop a{color:var(--link);}
  /* podpis pod „wątek na forum” — CO w wątku jest (np. „zdjęcia z 2005 i 2012”).
     Notatka o źródle, nie opis obiektu; stąd drobna i przygaszona. */
  .fort-pop .pop-notka{color:var(--text-dim);font-size:10.5px;line-height:1.4;margin:1px 0 2px;}
  .leaflet-tooltip.fort-tip{
    background:var(--panel);border:1px solid var(--line);color:var(--text);
    font-size:10.5px;padding:2px 7px;box-shadow:var(--shadow);border-radius:3px;
  }
  .leaflet-tooltip.fort-tip::before{display:none;}
  /* podświetlenie pary: symbol rośnie, etykieta zmienia się na akcentową */
  .fort-sym svg{display:block;transform-origin:50% 50%;transition:transform .12s,filter .12s;}
  .fort-sym.hi{z-index:10000 !important;} /* Leaflet ustawia z-index ikon w stylu inline */
  .fort-sym.hi svg{
    transform:scale(1.45);
    filter:drop-shadow(0 0 2px var(--accent)) drop-shadow(0 0 5px var(--accent));
  }
  .leaflet-tooltip.fort-tip.hi{
    border-color:var(--accent);color:var(--accent);z-index:10;
    box-shadow:0 0 0 1px var(--accent);
  }

  /* ===== warstwa zabytków =====
     Pinezka: krążek w kolorze kategorii z BIAŁYM pierścieniem i jasnym
     rdzeniem. Biel zamiast dawnego ciemnego obrysu — patrz zabytekSymbolSVG().
     Najechanie pokazuje kartę z nazwą, opisem i zdjęciem — bez stałych
     etykiet, bo pełne nazwy zabytków zagłuszyłyby mapę. */
  .zab-sym svg,.pocz-sym svg{
    display:block;transform-origin:50% 50%;transition:transform .12s,filter .12s;
    /* cień odrywa pinezkę od tła — konieczny nad jasnym zdjęciem lotniczym,
       gdzie sam biały pierścień znika. Hover nadpisuje go własną poświatą. */
    filter:drop-shadow(0 1px 1.6px rgba(0,0,0,.65));
  }
  .zab-sym.hi svg,.pocz-sym.hi svg{
    transform:scale(1.4);
    filter:drop-shadow(0 0 2px var(--accent)) drop-shadow(0 0 5px var(--accent));
  }
  /* GRONO pocztówek (markercluster): kółko w kolorze najczęstszego okresu
     z liczbą w środku; rośnie z liczbą (14/16/19 px promienia). Biała
     obwódka i cień — ten sam język co pinezki, żeby grono wyglądało jak
     „duża pinezka", nie jak obcy element. */
  .pocz-grono div{
    display:flex;align-items:center;justify-content:center;border-radius:50%;
    color:#fff;font:bold 11px/1 system-ui,sans-serif;text-shadow:0 1px 1px rgba(0,0,0,.5);
    border:2px solid #fff;box-shadow:0 1px 3px rgba(0,0,0,.6);box-sizing:border-box;
    cursor:pointer;transition:transform .12s;
  }
  .pocz-grono:hover div{transform:scale(1.12);}
  /* markercluster (bez jego arkusza): animacje przejść gron */
  .leaflet-cluster-anim .leaflet-marker-icon,.leaflet-cluster-anim .leaflet-marker-shadow{
    transition:transform .3s ease-out,opacity .3s ease-in;
  }
  .leaflet-cluster-spider-leg{transition:stroke-dashoffset .3s ease-out,stroke-opacity .3s ease-in;}
  /* rok pod nazwą w dymku i w oknie (pocztówki) */
  .pop-rok{color:var(--text-dim);font-size:11px;margin-top:1px;font-variant-numeric:tabular-nums;}
  .zab-para{display:flex;gap:6px;margin-top:6px;}

  .zab-para figure{margin:0;flex:1;min-width:0;}
  .zab-para img{width:100%;height:auto;display:block;border-radius:3px;}
  .zab-para figcaption{
    text-align:center;font-size:10px;color:var(--text-dim);
    margin-top:2px;letter-spacing:.4px;text-transform:uppercase;
  }
  .zab-status{color:#c98a8a;font-size:10.5px;font-style:italic;margin-top:2px;}
  /* WYSOKOŚĆ STAŁA, nie max-height (6.09.2026). Leaflet liczy odsunięcie
     mapy (autoPan) RAZ, przy otwarciu dymka, z jego ówczesnej wysokości.
     Przy max-height nieprzybrany jeszcze obrazek zajmuje zero: mapa odsuwa
     się o dymek bez zdjęcia, zdjęcie dojeżdża, dymek rośnie i wychodzi za
     górną krawędź. Stała wysokość daje dymkowi ostateczny rozmiar, zanim
     cokolwiek się pobierze — autoPan liczy wtedy właściwą wartość. */
  .fort-pop img{
    display:block;width:100%;height:170px;object-fit:cover;
    border-radius:3px;margin:6px 0 2px;border:1px solid var(--line);
    background:var(--bg);
  }
  /* na wąskim ekranie 170 px zdjęcia + nazwa + dwa linki zjadały pół widoku
     mapy — niższy kadr zostawia miejsce, by widzieć, GDZIE ten obiekt jest.
     Nadal wysokość STAŁA (patrz wyżej — autoPan). */
  @media (max-width:520px){ .fort-pop img{height:120px;} }

  /* ===== legenda warstw punktowych (fortyfikacje + zabytki) =====
     Widoczna tylko przy włączonej warstwie punktowej; buduje się z danych
     (kolor wg prefiksu oznaczenia + najczęstsza nazwa typu), więc zmiany
     nazw w panelu odbijają się w niej same. Zwijana do samego nagłówka.
     JEDNO okienko obsługuje obie warstwy — mogą być włączone naraz, więc
     sekcje dostają nagłówki dopiero wtedy, gdy naprawdę są dwie. */
  #fort-legenda{
    /* prawy górny róg — TEN SAM wiersz co okienko współrzędnych, które
       ustępuje jej miejsca i przesuwa się na lewo (klasa body.legenda-obok).
       Szerokość własna, dobrana tak, żeby nazwy typów mieściły się w jednym
       wierszu — nic już nie synchronizuje jej z okienkiem. */
    /* z-index PONAD panelami warstw punktowych (10000+paneCount) —
       inaczej symbole i pinezki malują się na legendzie */
    /* POPRAWKA 14.09.2026 (pavvlo: „legenda fortyfikacji zjechała trochę na
       dół"): stało tu +42px, czyli wiersz POD okienkiem współrzędnych — a to
       jest wartość dla WĄSKIEGO okna (ustawia ją JS w pozycjonujFortLegende,
       gdy legenda nie mieści się obok). Przy szerokim oknie JS zdejmował
       swoją wartość i legenda spadała na ten arkuszowy +42, zostawiając
       pusty wiersz obok okienka współrzędnych, które właśnie się dla niej
       przesunęło w lewo. Wartość domyślna = ten sam wiersz co okienko. */
    position:absolute;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);z-index:10800;display:none;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:11px;box-sizing:border-box;width:264px;
    transition:transform .2s;
  }
  /* zsuwa się z ekranu razem z okienkiem współrzędnych (kurtyna) */
  #fort-legenda.schowany{transform:translateX(calc(100% + 20px));}
  #fort-legenda.show{display:block;}
  #fort-legenda .fl-head{
    /* 29px + 1px ramki okienka = 30px, czyli tyle co okienko współrzędnych */
    display:flex;align-items:center;gap:7px;height:29px;padding:0 12px;cursor:pointer;
    color:var(--accent);font-size:11px;text-transform:uppercase;letter-spacing:.6px;
    font-weight:bold;background:var(--panel-2);border-bottom:1px solid var(--line);
    border-radius:4px 4px 0 0;user-select:none;-webkit-user-select:none;
  }
  #fort-legenda.zwinieta .fl-head{border-bottom:none;border-radius:4px;}
  /* legenda: ten sam rysowany ekspander co grupy warstw */
  #fort-legenda .fl-head .arr{
    display:inline-block;position:relative;width:14px;height:14px;flex-shrink:0;
    font-size:0;color:var(--text);
  }
  #fort-legenda .fl-head .arr::before,#fort-legenda .fl-head .arr::after{
    content:'';position:absolute;background:currentColor;border-radius:1px;
    box-shadow:0 1px 2px rgba(0,0,0,.45);
  }
  #fort-legenda .fl-head .arr::before{left:3px;top:6px;width:8px;height:2px;}
  #fort-legenda .fl-head .arr::after{left:6px;top:3px;width:2px;height:8px;display:none;}
  #fort-legenda.zwinieta .fl-head .arr::after{display:block;}
  #fort-legenda.zwinieta .fl-head .arr{transform:none;}
  #fort-legenda .fl-body{padding:7px 12px 8px;}
  #fort-legenda.zwinieta .fl-body{display:none;}
  #fort-legenda .fl-tgl{
    display:flex;align-items:center;gap:7px;padding:7px 12px;cursor:pointer;
    color:var(--text-dim);border-top:1px solid var(--line);
    background:var(--panel-2);border-radius:0 0 4px 4px; /* jak „podkład współczesny" w panelu */
    user-select:none;-webkit-user-select:none;
  }@media (hover:hover){ #fort-legenda .fl-tgl:hover{color:var(--text);} }
  #fort-legenda .fl-tgl input{accent-color:var(--accent);width:15px;height:15px;margin:0;cursor:pointer;}
  #fort-legenda.zwinieta .fl-tgl{display:none;}
  .leaflet-tooltip.fort-tip.fort-lbl{padding:1px 6px;font-size:10px;}
  /* Nagłówek mówi wprost, co zrobi kliknięcie — „rozwiń" albo „zwiń",
     symetrycznie do belki panelu warstw. Sama strzałka okazała się
     w terenie zbyt subtelna, zwłaszcza na telefonie. */
  #fort-legenda .fl-head .fl-hint{
    margin-left:auto;font-weight:normal;letter-spacing:.4px;color:var(--text-dim);
    text-transform:none;font-size:10px; /* kropka w kropkę jak .grp-tog w panelu */
  }
  #fort-legenda .fl-head #fl-rozwin{display:none;}
  #fort-legenda.zwinieta .fl-head #fl-rozwin{display:inline;}
  #fort-legenda.zwinieta .fl-head #fl-zwin{display:none;}@media (hover:hover){ #fort-legenda .fl-head:hover{color:var(--accent-2);} }@media (hover:hover){ #fort-legenda .fl-head:hover .fl-hint{color:var(--accent-2);} }
  /* „pokaż wszystkie" dotyczy grup obiektów, więc siedzi przy nich —
     pod listą, nad przełącznikiem oznaczeń, nie w belce okna. */
  #fort-legenda .fl-akcje{padding:0 12px 9px;}
  #fort-legenda.zwinieta .fl-akcje{display:none !important;}
  #fort-legenda #fl-reset{
    width:100%;background:transparent;border:1px solid var(--line);
    color:var(--text-dim);font:inherit;font-size:10px;letter-spacing:.5px;
    padding:5px 8px;border-radius:3px;cursor:pointer;text-transform:uppercase;
  }@media (hover:hover){ #fort-legenda #fl-reset:hover{color:var(--accent);border-color:var(--accent);} }
  /* spis obiektów: rozwijany inwentarz pod legendą */
  #fort-legenda .fl-spis-head{
    display:flex;align-items:center;gap:7px;padding:7px 12px;cursor:pointer;
    border-top:1px solid var(--line);font-size:11.5px;font-weight:bold;
  }@media (hover:hover){ #fort-legenda .fl-spis-head:hover{color:var(--accent-2);} }
  #fort-legenda .fl-spis-head .arr{
    display:inline-block;position:relative;width:12px;height:12px;flex-shrink:0;
    font-size:0;color:var(--text);
  }
  #fort-legenda .fl-spis-head .arr::before,#fort-legenda .fl-spis-head .arr::after{
    content:'';position:absolute;background:currentColor;border-radius:1px;
    box-shadow:0 1px 2px rgba(0,0,0,.45);
  }
  #fort-legenda .fl-spis-head .arr::before{left:2px;top:5px;width:8px;height:2px;}
  #fort-legenda .fl-spis-head .arr::after{left:5px;top:2px;width:2px;height:8px;} /* domyślnie + (spis zwinięty) */
  #fort-legenda.spis-otwarty .fl-spis-head .arr::after{display:none;}
  #fort-legenda.spis-otwarty .fl-spis-head .arr{transform:none;}
  #fort-legenda .fl-spis-head .fl-n{margin-left:auto;color:var(--text-dim);font-weight:normal;}
  #fort-legenda .fl-spis-body{display:none;max-height:36vh;max-height:36dvh;overflow:auto;padding:2px 0 7px;}
  #fort-legenda.spis-otwarty .fl-spis-body{display:block;}
  /* SZUKAJ W SPISIE (6.09.2026): przy trzech warstwach spis ma setki pozycji
     i przewijanie przestaje być metodą. Pole żyje POZA przebudowywaną listą
     (innerHTML przy każdej zmianie warstw), więc nie traci wpisanego tekstu.
     Pokazuje się dopiero, gdy pozycji jest więcej niż mieści jeden ekran. */
  #fort-legenda .fl-spis-szukaj{display:none;padding:4px 12px 2px;}
  #fort-legenda.spis-otwarty.spis-dlugi .fl-spis-szukaj{display:block;}
  #fort-legenda .fl-spis-szukaj input{
    width:100%;box-sizing:border-box;background:var(--bg);border:1px solid var(--line);
    color:var(--text);font:inherit;font-size:11.5px;padding:4px 8px;border-radius:3px;
  }
  #fort-legenda .fl-spis-szukaj input:focus{outline:none;border-color:var(--accent);}
  #fort-legenda .fl-spoz.ukryta,#fort-legenda .fl-sgrupa.ukryta{display:none;}
  #fort-legenda.zwinieta .fl-spis-head,
  #fort-legenda.zwinieta .fl-spis-szukaj,
  #fort-legenda.zwinieta .fl-spis-body{display:none;}
  #fort-legenda .fl-sgrupa{
    display:flex;align-items:center;gap:7px;padding:6px 12px 2px;
    color:var(--text-dim);font-size:10px;text-transform:uppercase;letter-spacing:.3px;
  }
  #fort-legenda .fl-spoz{
    padding:3px 12px 3px 33px;font-size:11.5px;cursor:pointer;color:var(--text);
  }@media (hover:hover){ #fort-legenda .fl-spoz:hover{background:rgba(255,255,255,.06);color:var(--accent);} }
  /* wiersz legendy = przełącznik widoczności grupy obiektów */
  .fl-row{
    display:flex;align-items:center;gap:8px;padding:3px 0;color:var(--text);
    line-height:1.35;cursor:pointer;user-select:none;-webkit-user-select:none;
  }@media (hover:hover){ .fl-row:hover{color:var(--accent);} }
  .fl-row .fl-txt{flex:1;}
  .fl-row .fl-n{color:var(--text-dim);font-size:11px;font-variant-numeric:tabular-nums;}
  .fl-row.off{opacity:.42;} /* samo wygaszenie — przekreślenie utrudniało czytanie */
  /* SPRZĘŻENIE Z MAPĄ (6.09.2026, pomysł użytkownika): najechanie na obiekt
     podświetla w legendzie JEGO wiersz — i od razu wiadomo, czym jest „H08",
     bez etykiety typu w dymku. Na telefonie najechania nie ma, więc wiersz
     świeci przez cały czas, gdy dymek obiektu jest otwarty (druga klasa,
     żeby zjechanie kursorem nie gasiło podświetlenia od dymka).
     Tło wyciągnięte ujemnym marginesem do krawędzi legendy (fl-body ma
     12 px odstępu w bok), żeby nie kończyło się w połowie słowa. */
  .fl-row.hl-otw{
    background:rgba(255,255,255,.08);color:var(--accent);
    margin-left:-12px;margin-right:-12px;padding-left:12px;padding-right:12px;
    border-radius:3px;
  }
  /* podświetlenie od najechania tylko tam, gdzie kursor istnieje — po dotknięciu
     przeglądarka też wysyła mouseover, ale mouseout dopiero przy następnym
     dotknięciu, i wiersz zostałby zapalony na dobre */
  @media (hover:hover){ .fl-row.hl{
    background:rgba(255,255,255,.08);color:var(--accent);
    margin-left:-12px;margin-right:-12px;padding-left:12px;padding-right:12px;
    border-radius:3px;
  } }
  /* nagłówek sekcji w legendzie — pokazywany TYLKO gdy obie warstwy
     punktowe są włączone (przy jednej legenda wygląda jak dawniej) */
  #fort-legenda .fl-dzial{
    color:var(--text-dim);font-size:10px;text-transform:uppercase;letter-spacing:.5px;
    padding:2px 0 3px;
  }
  #fort-legenda .fl-dzial + .fl-row{margin-top:0;}
  #fort-legenda .fl-dzial.druga{margin-top:7px;border-top:1px solid var(--line);padding-top:7px;}
  /* wiersz objaśniający (pusty krążek = obiekt niezachowany) — nie filtruje,
     więc nie udaje przycisku */
  .fl-row.fl-info{cursor:default;color:var(--text-dim);font-size:10.5px;padding-top:5px;}
  @media (hover:hover){ .fl-row.fl-info:hover{color:var(--text-dim);} }
  /* „pusty symbol" świeci razem z kategorią, gdy kursor stoi na obiekcie
     zniszczonym albo jego dymek jest otwarty (26.09.2026) - tło daje .hl,
     kolor trzeba podbić, bo .fl-info stoi niżej i wygrywa szarością */
  .fl-row.fl-info.hl-otw{color:var(--accent);}
  @media (hover:hover){ .fl-row.fl-info.hl, .fl-row.fl-info.hl:hover{color:var(--accent);} }
  /* przełącznik stałych etykiet dotyczy tylko fortyfikacji — zabytki
     celowo nie mają oznaczeń (pełne nazwy zagłuszyłyby mapę) */
  #fort-legenda.bez-oznaczen .fl-tgl{display:none;}
  .fl-sym{width:14px;height:14px;flex-shrink:0;display:flex;align-items:center;justify-content:center;}
  .fl-sym svg{display:block;}
  .fl-line{width:16px;height:3px;border-radius:2px;flex-shrink:0;}
  @media (max-width:640px){
    /* okienka współrzędnych nie ma na telefonie — legenda siada pod samym
       topbarem, a gdy widoczny jest licznik powiększenia, JS zsuwa ją
       tuż pod niego; przy otwartym panelu chowa się razem z licznikiem */
    #fort-legenda{top:calc(var(--pasek, 52px) + 6px);right:var(--luz);width:auto;min-width:0;max-width:210px;}
  }

  /* ===== linijka — pomiar odległości =====
     Okienko zajmuje SLOT okienka współrzędnych: przy włączonym pomiarze
     klik w mapę nie przypina punktu, więc tamto i tak nic nie robi.
     Ta sama geometria i te same reguły ustępowania legendzie. */
  #linijka{
    /* SZEROKOŚĆ STAŁA, nie dopasowana do treści: przy każdym kolejnym
       kliknięciu okienko inaczej by się rozpychało i skakało pod kursorem.
       Wysokość trzyma min-height na wierszach szczegółów (niżej).
       Pozycję w pionie ustawia JS — siada POD okienkiem współrzędnych,
       a gdy legenda jest w tej samej kolumnie, to pod legendą. */
    position:absolute;top:90px;right:var(--luz);z-index:10800;display:none;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:11px;box-sizing:border-box;
    width:180px;transition:transform .2s;
  }
  #linijka.show{display:block;}
  #linijka.schowany{transform:translateX(calc(100% + 20px));}
  body.legenda-obok #linijka{right:282px;}
  body.legenda-obok #linijka.schowany{transform:translateX(calc(100% + 292px));}
  /* suma jest przyciskiem — klik kopiuje, jak w okienku współrzędnych */
  /* wiersz sumy dzieli miejsce ze strzałką cofania — dzięki temu przybywa
     akcji, a rząd przycisków na dole zostaje dwuprzyciskowy i czytelny */
  #linijka .li-gora{display:flex;align-items:center;gap:6px;}
  /* krzyżyk jak w oknach rysu historycznego i źródeł — jedno kliknięcie
     odkłada narzędzie, bez szukania właściwego przycisku na dole */
  #linijka .zamknij{
    flex:0 0 auto;color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 9px 2px 3px;user-select:none;-webkit-user-select:none;
  }@media (hover:hover){ #linijka .zamknij:hover{color:#e05555;} }
  #linijka .li-cofnij{
    flex:0 0 auto;width:27px;height:23px;margin-right:0;padding:0;
    display:flex;align-items:center;justify-content:center;
    background:transparent;border:1px solid var(--line);border-radius:3px;
    color:var(--text-dim);cursor:pointer;
  }@media (hover:hover){ #linijka .li-cofnij:hover{color:var(--accent);border-color:var(--accent);} }
  #linijka .li-cofnij[disabled]{opacity:.3;cursor:default;}
  @media (hover:hover){ #linijka .li-cofnij[disabled]:hover{color:var(--text-dim);border-color:var(--line);} }
  #linijka .li-suma{
    display:block;flex:1;min-width:0;box-sizing:border-box;text-align:left;
    padding:7px 0 5px 11px;background:none;border:none;font:inherit;
    font-size:14px;font-weight:bold;letter-spacing:.3px;color:var(--accent);
    cursor:pointer;
  }
  /* przed pierwszym pomiarem: wygaszone „0 m", nie akcentowany myślnik —
     myślnik w kolorze akcentu czytało się jak komunikat o błędzie */
  #linijka .li-suma.pusto{color:var(--text-dim);font-weight:normal;}@media (hover:hover){ #linijka .li-suma:hover{color:var(--accent-2);} }
  #linijka .li-szczegoly{
    /* zawsze DWA wiersze — min-height trzyma wysokość okienka niezależnie
       od tego, czy akurat jest powierzchnia, odległość do kursora, czy nic */
    padding:0 11px 7px;color:var(--text-dim);line-height:1.5;
    font-variant-numeric:tabular-nums;min-height:33px;box-sizing:content-box;
  }
  #linijka .li-pole{color:var(--text);}
  #linijka .li-akcje{
    display:flex;gap:6px;padding:7px 11px;border-top:1px solid var(--line);
    background:var(--panel-2);border-radius:0 0 4px 4px;
  }
  #linijka .li-akcje button{
    flex:1;background:transparent;border:1px solid var(--line);color:var(--text-dim);
    font:inherit;font-size:10px;letter-spacing:.5px;padding:5px 6px;border-radius:3px;
    cursor:pointer;text-transform:uppercase;white-space:nowrap;
  }@media (hover:hover){ #linijka .li-akcje button:hover{color:var(--accent);border-color:var(--accent);} }
  /* etykieta odcinka — czyta się nad zdjęciem lotniczym i nad mapą,
     więc tło pełne, nie półprzezroczyste */
  .leaflet-tooltip.lin-etyk{
    background:var(--panel);border:1px solid var(--line);color:var(--text);
    box-shadow:var(--shadow);padding:1px 5px;font-size:10.5px;font-weight:bold;
    letter-spacing:.2px;white-space:nowrap;font-variant-numeric:tabular-nums;
  }
  .leaflet-tooltip.lin-etyk::before{display:none;} /* bez dzióbka: etykieta siedzi NA odcinku */
  /* w trybie pomiaru kursor mówi, że mapa czeka na punkt */
  body.mierze .leaflet-container{cursor:crosshair;}

  /* ===== tryb korekty położenia punktów =====
     Narzędzie redakcyjne, nie dla zwiedzających: przycisk odsłania się
     dopiero przy najwyższym poziomie dostępu. Cała praca dzieje się
     w przeglądarce — mapa NIE zapisuje niczego na serwer, tylko wydaje
     pliki do pobrania. */
  /* Pozycja: dolna krawędź w jednej linii ze SPODEM słupka przycisków,
     a prawa 10 px od jego lewej krawędzi — ten sam odstęp, co legenda
     i podziałka trzymają od brzegu mapy. Wartości niżej są punktem
     wyjścia; dokładne ustawia pozycjonujKorekte(), bo słupek zmienia
     wysokość i odsunięcie od dołu razem z motywem i szerokością ekranu. */
  #korekta{
    position:absolute;right:54px;bottom:24px;z-index:10800;display:none;
    width:252px;box-sizing:border-box;
    background:var(--panel);border:1px solid var(--line);border-radius:4px;
    box-shadow:var(--shadow);font-size:11px;
  }
  #korekta.show{display:block;}
  #korekta .ko-head{
    display:flex;align-items:center;gap:7px;height:29px;padding:0 6px 0 12px;
    color:var(--accent);font-size:11px;text-transform:uppercase;letter-spacing:.6px;
    font-weight:bold;background:var(--panel-2);border-bottom:1px solid var(--line);
    border-radius:4px 4px 0 0;user-select:none;-webkit-user-select:none;
  }
  #korekta .ko-head .zamknij{
    margin-left:auto;color:var(--text-dim);cursor:pointer;font-size:18px;line-height:1;
    padding:0 4px;
  }@media (hover:hover){ #korekta .ko-head .zamknij:hover{color:#e05555;} }
  #korekta .ko-tresc{padding:8px 12px 6px;color:var(--text-dim);line-height:1.6;}
  #korekta .ko-licz{color:var(--accent-2);font-weight:bold;}
  #korekta .ko-lista{
    max-height:132px;overflow:auto;margin:5px 0 2px;padding:0;
    font-variant-numeric:tabular-nums;
  }
  #korekta .ko-poz{
    display:flex;gap:8px;padding:2px 0;color:var(--text);cursor:pointer;
  }@media (hover:hover){ #korekta .ko-poz:hover{color:var(--accent);} }
  #korekta .ko-poz b{font-weight:bold;min-width:42px;}
  #korekta .ko-poz span{margin-left:auto;color:var(--text-dim);}
  #korekta .ko-akcje{
    display:flex;flex-wrap:wrap;gap:6px;padding:8px 12px;
    border-top:1px solid var(--line);background:var(--panel-2);border-radius:0 0 4px 4px;
  }
  #korekta .ko-akcje button{
    flex:1 1 auto;background:transparent;border:1px solid var(--line);color:var(--text-dim);
    font:inherit;font-size:10px;letter-spacing:.5px;padding:5px 6px;border-radius:3px;
    cursor:pointer;text-transform:uppercase;white-space:nowrap;
  }@media (hover:hover){ #korekta .ko-akcje button:hover{color:var(--accent);border-color:var(--accent);} }
  #korekta .ko-akcje button[disabled]{opacity:.35;cursor:default;}
  @media (hover:hover){ #korekta .ko-akcje button[disabled]:hover{color:var(--text-dim);border-color:var(--line);} }
  /* skrót po zapisie: „Popraw też na forum" (2.10.2026) - link w meldunku pod listą */
  #korekta .ko-forum{color:var(--accent);font-weight:bold;text-decoration:none;white-space:nowrap;}
  @media (hover:hover){ #korekta .ko-forum:hover{color:var(--accent-2);text-decoration:underline;} }
  /* Wysyłka na serwer to jedyny przycisk, który COKOLWIEK zmienia poza tą
     kartą — stoi więc osobno, na całą szerokość i w kolorze akcentu, żeby
     nie dało się go pomylić z zapisem pliku obok. */
  #korekta .ko-akcje button.ko-glowna{
    flex:1 1 100%;color:var(--accent);border-color:var(--accent);
    background:rgba(201,162,75,.09);font-weight:bold;
  }
  @media (hover:hover){ #korekta .ko-akcje button.ko-glowna:hover{
    background:rgba(201,162,75,.2);color:var(--accent);} }
  #korekta .ko-akcje button.ko-glowna[disabled]{
    color:var(--text-dim);border-color:var(--line);background:transparent;font-weight:normal;
  }
  /* przesunięty punkt świeci — widać na pierwszy rzut oka, co już ruszone */
  .fort-sym.ruszony svg,.zab-sym.ruszony svg,.pocz-sym.ruszony svg{
    filter:drop-shadow(0 0 3px #ffd24a) drop-shadow(0 0 7px #ffd24a);
  }
  body.korekta .fort-sym,body.korekta .zab-sym,body.korekta .pocz-sym{cursor:grab;}
  body.korekta .leaflet-marker-draggable{cursor:grab;}
  .leaflet-dragging body.korekta .fort-sym{cursor:grabbing;}
  @media (max-width:640px){
    /* palcem nie da się trafić w metr — narzędzie jest desktopowe */
    #korekta{display:none !important;}
  }
  @media (max-width:640px){
    #linijka{right:var(--luz);width:180px;}
    /* przy otwartym panelu ustępuje tak samo jak legenda */
    body:has(#sidebar:not(.hidden)) #linijka{opacity:0;pointer-events:none;transition:opacity .2s;}
    /* podziałka ustępuje otwartemu panelowi — obie siedzą przy lewej
       krawędzi, a panel jest ważniejszy (11.09.2026) */
    body:has(#sidebar:not(.hidden)) .leaflet-control-scale{opacity:0;pointer-events:none;}
  }

  @media (max-width:640px){
    /* ===== ciaśniej przy krawędziach (10.09.2026) =====
       Na telefonie wszystkie panele odsuwają się od brzegu ekranu o 4 px
       zamiast 6–12 px. Przy 375 px szerokości każdy odzyskany piksel idzie
       do treści panelu, a odstęp nadal widać. Jedna zmiana tutaj rusza
       WSZYSTKIM naraz: panelem, legendą, oknami, podziałką, słupkiem,
       licznikiem, osią czasu i nawigacją. */
    :root{ --luz:4px; }
    /* pasek tytułowy też oddycha ciaśniej: 14 px z desktopu to na
       telefonie 28 px zjedzone na sam margines belki */
    #topbar{padding-left:10px;padding-right:10px;}

    /* ===== OKNA: te same marginesy, co panel warstw i oś czasu =====
       Do 10.09 każde okno trzymało własne liczby (20 px na boki
       z overlaya, 60–80 px w pionie, 6 px przy oknie ustawień) i przy
       pasku źródeł kończyły się na różnych wysokościach. Teraz wszystkie
       stoją --luz od krawędzi bocznych, zaczynają się pod belką i kończą
       --dol nad paskiem źródeł — dokładnie jak reszta interfejsu. */
    /* na telefonie okna idą na pełną szerokość między marginesami —
       wysokość i marginesy są już wspólne dla PC i telefonu (wyżej) */
    #ust-okno, #sesja-okno{ left:var(--luz);right:var(--luz);width:auto; }
    #zrodla-okno, #hist-okno, #zab-okno{ max-width:none; }

    /* PODZIAŁKA NAD PASKIEM ŹRÓDEŁ (zgłoszenie 10.09.2026: „podziałka
       przyklejona do atrybucji"). Na telefonie pasek atrybucji jest
       pełnoszerokościowy i ma 22 px, a podziałka stała 10 px nad dolną
       krawędzią — czyli 12 px WEWNĄTRZ niego (pomiar 375x812: podziałka
       772..802, pasek 790..812). Nie były sklejone, tylko nachodziły
       na siebie. Teraz dół liczy się od MIERZONEJ wysokości paska. */
    .leaflet-bottom.leaflet-left .leaflet-control-scale{
      margin-bottom:calc(var(--metka, 22px) + var(--dol));
    }

    /* ===== BELKA ZWINIĘTA DO MENU „⋯" (10.09.2026) =====
       Do tej pory belka przewijała się w bok i trzy przyciski (Kopiuj
       link, Ustawienia, Zaloguj) leżały poza ekranem — 190 px treści
       „dla wtajemniczonych", sygnalizowane tylko cieniem przy krawędzi.
       Teraz w belce zostaje logo i jeden przycisk „⋯", a pod nim
       rozwija się pionowa lista wszystkich narzędzi. Belka przestaje
       się przewijać, więc cień nie ma czego zdradzać i gaśnie sam
       (JS liczy scrollWidth - clientWidth, a to jest teraz zero). */
    /* overflow-x:auto ZOSTAJE jako bezpiecznik: przy bardzo dużej
       czcionce systemowej samo logo z przyciskiem „⋯" też potrafi nie
       zmieścić się w 320 px, a wtedy lepiej, żeby belka dała się
       przesunąć palcem, niż żeby „⋯" wyjechało poza ekran. W normalnych
       warunkach nie ma czego przewijać i cień gaśnie sam (JS liczy
       scrollWidth - clientWidth = 0). Lista menu jest position:fixed,
       więc TEGO przycinania nie łapie — sprawdzone pomiarem. */
    /* podwójny #topbar w selektorze NIE jest ozdobą: niżej w arkuszu
       stoi #topbar .btn{padding:9px 12px}, o tej samej wadze co samo
       #menu-btn — i wygrywałoby kolejnością, rozpychając ikonę */
    #topbar #menu-btn{
      display:flex;align-items:center;justify-content:center;
      width:38px;height:32px;padding:0;flex-shrink:0;
      margin-left:auto;   /* .spacer jest na telefonie schowany — to dosuwa „⋯" do prawej */
    }
    /* stan „menu otwarte" wygląda jak każdy inny stan aktywny — złote
       wypełnienie z reguły .btn.active (razem z poprawką kontrastu
       w motywie jasnym); wcześniej była tu sama złota ramka, czyli
       jedyny wyjątek od zasady „aktywny = żółty" */
    #topbar-narzedzia{
      /* position:fixed — dzięki temu lista NIE jest przycinana przez
         belkę ani przez nic innego, i nie musi się mieścić w jej
         wysokości. Stoi tam, gdzie okno ustawień i okno sesji, więc
         wszystkie trzy czytają się jako jedna rodzina. */
      position:fixed;top:calc(var(--pasek, 52px) + 6px);right:var(--luz);
      z-index:10960;display:none;flex-direction:column;align-items:stretch;gap:0;
      min-width:186px;max-width:calc(100vw - var(--luz) * 2);
      background:var(--panel);border:1px solid var(--line);border-radius:4px;
      box-shadow:var(--shadow);padding:5px;
    }
    #topbar-narzedzia.otwarte{display:flex;}
    /* przyciski w menu: pełna szerokość, bez ramek, wiersz pod palec
       (36 px — powyżej minimum 24 px z WCAG 2.2) */
    #topbar #topbar-narzedzia .btn{
      width:100%;text-align:left;background:none;border:none;
      padding:0 10px;min-height:38px;font-size:12.5px;border-radius:3px;
    }
    #topbar #topbar-narzedzia .btn + .btn{border-top:1px solid var(--line);}
    /* BEZ border-color: reguła .btn.active z góry arkusza ustawia ramkę na
       złoto — a że separatorem jest górna ramka wiersza, dwie sąsiadujące
       pozycje na żółto zlewały się w jedną płytę (zgłoszenie 10.09). */
    #topbar #topbar-narzedzia .btn.active{background:var(--accent);border-color:transparent;}
    /* separator NAD pozycją podświetloną musi być widoczny na złocie —
       bierzemy kolor panelu, więc działa w obu motywach: ciemna kreska
       na jasnym złocie, jasna na ciemnym */
    #topbar #topbar-narzedzia .btn + .btn.active{border-top-color:var(--panel);}
    /* „Sesja wygasła" w menu: wiersz menu nie ma tła, więc czerwone
       wypełnienie z belki komputera tu znika - czerwień idzie w napis
       (27.09.2026; tak samo jak ostrzeżenie „mało czasu") */
    #topbar #topbar-narzedzia #sesja-btn.wygasla{color:#e07070;font-weight:bold;}
    [data-theme="light"] #topbar #topbar-narzedzia #sesja-btn.wygasla{color:#b03434;}

    /* ===== PŁYWAJĄCY PRZYCISK WARSTW =====
       Panel warstw otwiera się i zamyka częściej niż wszystko inne razem
       wzięte, a przycisk siedział na dole ekranu, w słupku razem
       z narzędziami używanymi raz na jakiś czas. Teraz stoi osobno,
       w połowie wysokości — tam, gdzie kciuk trzymanej ręki jest bez
       przekładania telefonu.
       Szerokość celowo RÓWNA szerokości słupka: pas przy prawej krawędzi
       jest już zarezerwowany (panel się do niego nie wsuwa), więc większy
       przycisk zabrałby szerokość panelowi. Wysokość 52 px daje pole
       dotyku wyraźnie większe niż dotychczasowe 34 px. */
    #warstwy-plyw{
      display:flex;align-items:center;justify-content:center;
      position:fixed;right:var(--luz);top:50%;transform:translateY(-50%);
      z-index:10700;width:var(--slupek, 38px);height:52px;padding:0;
      background:var(--panel);color:var(--text);
      border:1px solid var(--line);border-radius:5px;box-shadow:var(--shadow);
      font:inherit;cursor:pointer;-webkit-tap-highlight-color:transparent;
    }
    #warstwy-plyw svg{width:19px;height:19px;}
    #warstwy-plyw.active{background:var(--accent);border-color:var(--accent);color:#1a1a1a;}
    /* podczas podglądu przenikania znika razem ze słupkiem i panelem —
       czysty widok mapy w trakcie regulacji suwakiem */
    body:has(#sidebar.previewing) #warstwy-plyw{opacity:0;pointer-events:none;transition:opacity .15s;}
    /* stary bliźniak w słupku znika — po to była cała ta przeprowadzka */
    #warstwy-btn-mobile{display:none !important;}
    /* ===== CO JEST NA EKRANIE, A CO W MENU „⋯" (10.09.2026, noc) =====
       Zasada: na ekranie stoi to, czym zmienia się WIDOK i po co sięga
       się stale — warstwy (pływający przycisk) i oś czasu (słupek).
       W menu zostaje to, co robi się rzadko i co widoku nie zmienia:
       źródła, kopiowanie linku, ustawienia, logowanie. Dublowanie tych
       dwóch w menu uczyłoby drogi na dwa tapnięcia zamiast jednego. */
    #os-btn{display:block;}
    /* WSPÓŁRZĘDNE NA TELEFONIE (20.10.2026, redaktor nie mógł znaleźć wpisywania;
       pavvlo: „wybierz to co najbardziej ergonomiczne"). Okienka na stałe nie ma
       (zabiera miejsce, a bez kursora nie ma czego pokazywać) - jest przycisk
       w słupku pod kciukiem: otwiera pole wpisywania i pokazuje współrzędne
       ŚRODKA mapy (krzyżyk) z kopiowaniem. Zamknięte - nic nie zasłania. */
    #wsp-btn-mobile{display:block;}
    body.wsp-tel-otwarte #wsp-krzyz{display:block;}
    #wsp-wpis .ww-srodek{
      display:flex;align-items:center;gap:8px;padding:0 6px 8px 11px;font-size:12px;color:var(--text-dim);
    }
    #wsp-wpis .ww-srodek b{flex:1;min-width:0;color:var(--text);font-weight:normal;font-family:monospace;font-size:13px;white-space:nowrap;}
    #wsp-kopiuj-srodek{
      flex:0 0 auto;height:32px;padding:0 12px;background:transparent;border:1px solid var(--line);border-radius:3px;
      color:var(--text-dim);font:inherit;font-size:12px;cursor:pointer;-webkit-tap-highlight-color:transparent;
    }
    #wsp-kopiuj-srodek.ok{color:var(--accent);border-color:var(--accent);}
    #os-btn.niedostepny{display:none;}
    #topbar #topbar-narzedzia #toggle-sidebar,
    #topbar #topbar-narzedzia #toggle-timeline{display:none !important;}
    #sidebar{
      /* panel NIE dochodzi do prawej krawędzi — zostawia pas na słupek
         nawigacyjny. Marginesy na mobile ściśnięte do 6px (krawędź
         ekranu) i 4px (odstęp panel–słupek): 6+4+34+6 = 50px pasa.
         Dzięki temu słupek jest ZAWSZE widoczny i klikalny obok
         otwartego panelu, a przycisk warstw nie zmienia pozycji —
         wcześniejsze podnoszenie słupka nad panel (z-index) z redukcją
         do samego przycisku warstw zostało wycofane: przycisk skakał
         po ekranie, bo pasek kurczył się po schowaniu sąsiadów */
      /* 10.09.2026: koniec z rachunkiem na palcach. Margines od krawędzi
         ekranu jest teraz JEDNĄ liczbą (--luz) dla wszystkich paneli,
         a szerokość słupka jest MIERZONA (--slupek). Wcześniejsze
         „6+4+34+6 = 50" zakładało słupek 34 px — Leaflet dokłada ramkę
         i wychodzi 38, więc obiecany prześwit schodził do zera i panel
         dotykał słupka. Wzór: luz | panel | luz | słupek | luz. */
      left:var(--luz);
      width:calc(100% - var(--luz) * 3 - var(--slupek, 38px));
      /* pełna wysokość jak na desktopie — podgląd mapy pod suwakiem
         załatwia teraz mechanika "dotknij suwaka = panel przezroczysty"
         (patrz .previewing niżej), więc nie trzeba już na stałe kroić
         panelowi miejsca. Dołem rezerwujemy MIERZONĄ wysokość paska
         źródeł (--metka) plus miejsce na metkę panelu: atrybucja Leaflet
         jest na telefonie pełnoszerokościowa i bez tego metka lądowałaby
         na napisie „Leaflet | © OpenStreetMap”. */
      max-height:calc(100% - var(--pasek, 52px) - 6px - var(--znak, 24px) - var(--metka, 22px) - var(--dol));
    }
    /* ===== DYMEK: szerokość panelu, spód równo z „−" (12.09.2026) =====
       Prośba z testów: „zróbmy dokładnie takiej samej szerokości jak panel
       warstw i dołem wyrównajmy z przyciskiem −". Reguła stoi TUTAJ, tuż
       pod geometrią panelu, bo to z nim ma być równa — a nie w bloku GPS,
       gdzie nikt by jej nie znalazł przy następnej zmianie panelu.

       SZEROKOŚĆ: wystarczy zdjąć max-width. Pasmo liczy już reguła
       podstawowa tym samym wzorem, co #sidebar wyżej (luz | pasmo | luz |
       słupek | luz), więc szerokości są równe z definicji, nie z rachunku:
       na telefonie 390 px oba dają 340. Tyle samo mają oś czasu i pasek
       prowadzenia — cały dolny interfejs stoi w jednej kolumnie.

       SPÓD: pudełko +/− kończy się dokładnie --dol nad paskiem źródeł
       (robi to reguła .leaflet-bottom.leaflet-right wyżej: podnosi róg
       o metka + dół − 10, bo Leaflet dokłada własne 10 px marginesu).
       Ta sama wartość ustawia więc dymek równo z dolną krawędzią „−".

       UWAGA: to jest pozycja SPOCZYNKOWA — gdy pod spodem nic nie stoi.
       Oś czasu i pasek prowadzenia zajmują DOKŁADNIE to samo miejsce, więc
       gdy któreś jest otwarte, dymek podnosi nad nie ustawDolnyRzad()
       (styl inline bije arkusz). Wysokości tych pasków zależą od treści,
       więc są MIERZONE, a nie wpisane tutaj. */
    #geo-toast{
      left:var(--luz);
      right:calc(var(--luz) * 2 + var(--slupek, 38px));
      max-width:none;
      bottom:calc(var(--metka, 22px) + var(--dol));
    }
    /* Dotknięcie suwaka przenikania W MIKSERZE: dotknięty wiersz
       (nazwa + suwak) zostaje w pełni widoczny jako plakietka nad
       mapą, cała reszta panelu znika — widać mapę pod spodem.
       Uwaga techniczna: opacity na rodzicu obejmuje NIEODWOŁALNIE
       wszystkie dzieci (nie da się "wyjąć" jednego wiersza z
       przezroczystego panelu), więc nie gasimy #sidebar jedną
       wartością — panel traci tylko tło/ramkę/cień, a opacity:0
       dostają osobno wszystkie elementy POZA dotkniętym wierszem.
       Wygaszone elementy dostają też pointer-events:none, żeby
       przypadkowe muśnięcie drugim palcem niczego nie przełączyło. */
    #sidebar.previewing{background:transparent;border-color:transparent;box-shadow:none;}
    #sidebar.previewing > :not(#mixer){opacity:0;pointer-events:none;transition:opacity .15s;}
    /* suwak, który ZAINICJOWAŁ podgląd (może leżeć na wygaszonej
       liście głównej), musi dalej łapać zdarzenia — pointer-events:auto
       na dziecku przebija none z przodka; klasę nadaje i zdejmuje JS
       na czas gestu, więc pozostałe niewidoczne suwaki są martwe */
    #sidebar.previewing .preview-zrodlo{pointer-events:auto;}
    #sidebar.previewing #mixer{background:transparent;border-color:transparent;}
    #sidebar.previewing #mixer .mx-cap{opacity:0;pointer-events:none;transition:opacity .15s;}
    #sidebar.previewing .mx-item:not(.preview-focus){opacity:0;pointer-events:none;transition:opacity .15s;}
    /* dotknięty wiersz: własne tło-plakietka dla czytelności na tle
       mapy; na czas przeciągania zostaje TYLKO nazwa + suwak
       (uchwyt ≡, przyciski L/P i × znikają — mniej szumu nad mapą) */
    /* outline zamiast border — border wchodzi do layoutu i wiersz
       skoczyłby o piksel pod palcem dokładnie w chwili dotknięcia */
    #sidebar.previewing .mx-item.preview-focus{
      background:var(--panel);outline:1px solid var(--line);border-radius:4px;
      box-shadow:var(--shadow);
    }
    #sidebar.previewing .mx-item.preview-focus .mx-drag,
    #sidebar.previewing .mx-item.preview-focus .mx-sides,
    #sidebar.previewing .mx-item.preview-focus .mx-off{opacity:0;pointer-events:none;}

    /* okienko współrzędnych GPS zbędne na telefonie — użytkownik ma
       już własną lokalizację (przycisk celownika), a okienko tylko
       zabiera miejsce. !important, bo JS ustawia display inline przy
       każdym ruchu/kliku na mapie. */
    #coord-indicator{display:none !important;}
    /* 5 przycisków w jednym wierszu nie mieści się na telefonie —
       body ma overflow:hidden, więc bez tego skrajne przyciski
       ("Tryb jasny") stawałyby się fizycznie nieosiągalne. Pasek
       przewijany w poziomie zamiast łamania na dwa wiersze — dzięki
       temu wysokość topbara (i wszystkie pozycje "top:52px" w reszcie
       interfejsu) zostaje bez zmian. */
    #topbar{overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;touch-action:pan-x;}
    #topbar::-webkit-scrollbar{display:none;}
    #topbar .spacer{display:none;}
    #topbar .brand,#topbar .btn{flex-shrink:0;}
    /* pion 9px zamiast 7 — przyciski rosną do ~32px pola dotyku, a pasek
       zostaje pod progiem 52px, od którego liczy się reszta interfejsu */
    #topbar .btn{padding:9px 12px;font-size:11.5px;}
    /* ===== affordance przewijania topbara =====
       Pasek przewija się w poziomie, ale nic tego nie zdradzało — trzy
       przyciski (Kopiuj link, Ustawienia, Zaloguj) żyły poza ekranem
       „dla wtajemniczonych". Gradientowe ściemnienie przy prawej
       krawędzi mówi „tu jest więcej"; JS gasi je po doprzewijaniu. */
    #topbar-cien{
      position:fixed;top:0;right:0;width:44px;z-index:11001;pointer-events:none;
      background:linear-gradient(to right, transparent, var(--panel));
      opacity:0;transition:opacity .2s;
    }
    #topbar-cien.widoczny{opacity:1;}
    /* na telefonie adres odrobinę większy — rozstrzelenie i tak dobiera
       dopasujLogo() pomiarem, więc obie linie nadal kończą się równo */
    #topbar .brand .brand-d{font-size:11.4px;}

    /* mikser i podkład ciut ciaśniej — odzyskane piksele idą do listy
       warstw, która i tak musi się zmieścić w 50vh razem z nimi */
    #mixer{max-height:25vh;max-height:25dvh;}
    /* Pole dotyku przełączników w Ustawieniach: wiersz miał 20 px wysokości,
       czyli mniej niż minimum, w które da się trafić palcem (24 px wg WCAG
       2.2). Etykieta jest klikalna na całej szerokości, więc rośnie tylko
       w pionie — układ okna zostaje ten sam, przybywa mu ok. 70 px, co
       mieści się w max-height liczonym z dvh. */
    #ust-okno .u-check{min-height:28px;}
    /* podziałka na tej samej osi co panel (6px od krawędzi ekranu) */

    #base-picker{padding:0 12px 7px;}
    #base-picker .lbl{margin-bottom:6px;}
    /* przyciski podkładu: 12 px (niżej, blok „telefon zostaje") - „Ortofoto" ma 43 px,
       a ćwiartka wiersza nawet na 320 px 55 px */
    #base-picker .opts button{padding:5px 4px;}

    /* pola dotykowe powiększone tam, gdzie na desktopie były gęste —
       gęstość dobra pod mysz, za ciasna pod palec */
    .layer{padding:11px 12px;}
    .layer input[type=checkbox]{width:20px;height:20px;}
    .mx-drag{font-size:17px;padding:4px 7px;}
    .mx-side{padding:6px 10px;font-size:11.5px;}
    .mx-off{font-size:18px;padding:3px 8px;}
    /* drobne szare napisy („zwiń", „zwiń wszystkie") pół piksela większe pod palec -
       jak L/P wyżej */
    .grp-head .grp-tog,#layers-cap .lc-tog{font-size:11.5px;}
    /* TELEFON ZOSTAJE PRZY SKALI 11 / 12 / 13 z 23:08 (komputer zszedł na 10 / 11 / 12 -
       pavvlo 1.10: „za duża", „zajmijmy się teraz pc"). Te same selektory co w regułach
       bazowych, więc wygrywają kolejnością. Do rozstrzygnięcia, gdy pavvlo obejrzy telefon:
       wtedy albo skasować ten blok (telefon = komputer), albo zostawić. */
    #mixer .mx-cap, #layers-cap, #base-picker .lbl{font-size:11px;}
    .grp-head{font-size:12px;}
    .grp-head .cnt{font-size:11px;}
    .grp-sub-head{font-size:11px;}
    .grp-opt{font-size:11px;}
    .layer .name{font-size:13px;}
    .layer .year{font-size:11px;}
    .layer .jakosc{font-size:11px;}
    .mx-name{font-size:12px;}
    #base-picker .opts button{font-size:12px;}
    #fort-legenda .fl-head .fl-hint{font-size:11px;}
    /* kontrolki Leaflet pod kciuk — selektor MUSI zawierać .leaflet-touch:
       leaflet.css ma regułę .leaflet-touch .leaflet-bar a{30px} o wyższej
       specyficzności i gołe .leaflet-bar a przegrywało dokładnie na
       urządzeniach dotykowych, dla których powstało (audyt 08.2026) */
    .leaflet-touch .leaflet-bar a{width:34px;height:34px;line-height:34px;}
    #curtain-grip{width:40px;height:40px;}

    /* przycisk warstw w słupku nawigacyjnym — w zasięgu kciuka,
       nad pełnym ekranem/zasięgiem/lokalizacją/zoomem; panel jest
       zwężony (patrz #sidebar wyżej), więc słupek nigdy nie ląduje
       pod panelem i nie potrzebuje żadnych sztuczek z z-index */
    #warstwy-btn-mobile{display:block;}
    /* słupek dosunięty do 6px od prawej krawędzi (Leaflet daje
       domyślnie 10px) — spójnie ze ściśniętymi marginesami panelu;
       celowo tylko .leaflet-bar, żeby nie ruszyć atrybucji, która
       też mieszka w tym rogu */
    .leaflet-bottom.leaflet-right .leaflet-bar{margin-right:var(--luz);}
    /* NAPRAWA uciętego przycisku "Kurtyna": suwak flex:1 ma domyślne
       min-width:auto, więc nie umiał się skurczyć poniżej wrodzonej
       szerokości (~130px) i WYPYCHAŁ przycisk poza panel (obcinany
       przez overflow-x:hidden). min-width:0 pozwala flexowi ścisnąć
       suwak — przycisk mieści się zawsze, suwak bierze całą resztę */
    /* podczas podglądu przenikania słupek znika razem z panelem —
       czysty widok mapy bez szumu w trakcie regulacji suwakiem */
    body:has(#sidebar.previewing) .leaflet-bottom.leaflet-right{opacity:0;pointer-events:none;transition:opacity .15s;}
    /* Licznik powiększenia: na mobile przypięty do prawego górnego
       rogu (left:auto !important przebija inline'owe left z JS-owego
       pozycjonowania pisanego pod desktop). Przy otwartym panelu
       licznik wystawałby zza panelu w pas słupka jako ucięty ogryzek —
       chowamy go, a podczas podglądu przenikania (panel wygaszony,
       mapa widoczna) wraca; reguła .previewing stoi NIŻEJ, więc
       wygrywa przy równej specyficzności */
    /* Licznik rośnie w lewo (prawa krawędź przypięta), więc przy długiej
       nazwie warstwy dobijał do samego brzegu ekranu — zmierzone: lewa
       krawędź na 0 px przy oknie 375 px. Ograniczamy szerokość do ekranu
       minus dwa marginesy.
       11.09 wieczorem: pierwsza wersja ucinała nadmiar wielokropkiem —
       i to było gorsze niż problem, bo znikała nazwa warstwy. Teraz
       tekst ZAWIJA SIĘ do kolejnego wiersza, a okienko rośnie w dół
       (min-height zamiast height w regule bazowej). Rosnąć w dół może
       bezpiecznie: legenda fortyfikacji i okienko współrzędnych liczą
       swoje położenie z JEGO ZMIERZONEJ wysokości, nie ze stałej. */
    #zoom-indicator{
      left:auto !important;right:var(--luz);
      max-width:calc(100% - var(--luz) * 2);
      white-space:normal;text-align:right;
      padding:5px 11px;line-height:1.4;
    }
    body:has(#sidebar:not(.hidden)) #zoom-indicator{opacity:0;pointer-events:none;}
    body:has(#sidebar:not(.hidden)) #fort-legenda{opacity:0;pointer-events:none;transition:opacity .2s;}
    body:has(#sidebar.previewing) #zoom-indicator{opacity:1;pointer-events:auto;}

    /* kolejność przycisków (Warstwy → Oś czasu → Źródła → Kopiuj
       link → Tryb jasny) siedzi wprost w DOM topbara — wspólna dla
       PC i telefonu, narzędzia codzienne pierwsze */



    /* suwaki przenikania pod palec: wyższe pole dotykowe — 14-16px
       z desktopu jest zbyt precyzyjne pod opuszkę (kciuk suwaka
       zostaje natywny przez accent-color, ale cała belka łapie dotyk) */
    /* touch-action:pan-y (11.09.2026, zgłoszenie: „chcę poskrolować
       warstwy, a prawie zawsze włącza mi się suwak i obraz migocze"):
       suwak zajmuje niemal całą szerokość wiersza, więc palec startujący
       z przewijaniem prawie zawsze lądował na nim i to ON łapał gest.
       pan-y oddaje ruch PIONOWY przeglądarce (czyli liście), a suwak
       dostaje tylko ruch w poziomie — czyli dokładnie ten, do którego
       służy. Po prawej, poza suwakiem, przewijanie działało od zawsze
       i to była wskazówka, gdzie leży przyczyna. */
    .mx-ctrl input[type=range]{height:28px;touch-action:pan-y;}

    /* ===== powiększone POLA DOTYKU drobnych kontrolek (audyt 08.2026) =====
       Wygląd zostaje drobny, rośnie tylko niewidzialne pole trafień:
       przezroczysty pseudo-element wystaje poza kontrolkę. Zmierzone
       przed zmianą: „zwiń" 23×12, ikonka „i" 30×16, oko/×/L-P w mikserze
       18–28px — wytyczna to ≥40px. */
    /* UWAGA: kropki i etykiety osi (.tl-dot/.tl-lbl) są pozycjonowane
       absolutnie — im position:relative by ZEPSUŁO układ (sprawdzone);
       pseudo-element działa na position:absolute bez zmian */
    .grp-tog,.grp-opt,.dtog,.mx-eye,.mx-off,.mx-drag,.mx-side,.zamknij,
    .fl-hint,.hot-btn,.lc-tog{position:relative;}
    .grp-tog::after,.grp-opt::after,.dtog::after,.mx-eye::after,.mx-off::after,
    .mx-drag::after,.zamknij::after,.fl-hint::after,.hot-btn::after,.lc-tog::after{
      content:'';position:absolute;inset:-11px;
    }
    .mx-side::after{content:'';position:absolute;inset:-7px 0;} /* L|P sąsiadują — bez poszerzania w bok */
    .tl-dot::after,.tl-lbl::after{content:'';position:absolute;inset:-9px;}
    /* oś czasu: wyższy tor i większe kropki — najmniejsze cele aplikacji (11px) */
    #tl-track{height:56px;}
    .tl-dot{width:15px;height:15px;}
    .tl-dot.act{width:20px;height:20px;}
    .tl-lbl{top:26px;font-size:11px;}

    /* ===== OŚ CZASU JAKO PRZEWIJANY PASEK (10.09.2026) =====
       Przy 19 datach na oś zostawało 286 px, czyli 14,3 px na datę —
       kropka ma 15, podpis roku 26, więc kropki stykały się, a podpisy
       nachodziły na siebie. Dat będzie przybywać, więc zamiast ściskać
       dalej: kafelki stałej szerokości, przewijane palcem. Każdy rok
       czytelny niezależnie od tego, ile ich będzie.
       Postać włącza klasa .os-pasek, którą nadaje renderOs() — dzięki
       temu monitor korzysta z tego samego HTML-a bez żadnej zmiany. */
    /* Wysokość RÓWNA pudełku z +/- (mierzona), bo oba stoją w jednym
       rzędzie nad paskiem źródeł. Padding boczny przenosi się na sam
       pasek kafelków, żeby wjeżdżały pod ściemnienie przy krawędzi,
       a nie kończyły się przed nim. */
    #timeline.os-pasek{
      height:var(--zoombar, 72px);box-sizing:border-box;padding:0;
      flex-direction:column;justify-content:center;overflow:hidden;
    }
    /* display TYLKO razem z .show — sama .os-pasek nie może odsłaniać osi
       (renderOs nadaje ją zawsze na telefonie, także przy schowanej osi;
       bez tego warunku pasek stał niewidocznie rozciągnięty na 1296 px
       i rozpychał stronę w poziomie) */
    #timeline.os-pasek.show{display:flex;}
    /* Podpis mówi, co jest wybrane — ale NIE krzyczy: złoto należy do
       kafelka z rokiem i dwa złote napisy o tym samym obok siebie biły
       się wzajemnie. Język drobnej etykiety, ten sam co „PODKŁAD
       WSPÓŁCZESNY" w panelu: wersaliki, 10 px, kolor przygaszony. */
    /* w postaci „pasek" krzyżyk siedzi w rzędzie podpisu, po prawej */
    #timeline.os-pasek .tl-zamknij{top:5px;right:9px;}
    #timeline.os-pasek #tl-podpis{
      display:block;flex:0 0 auto;padding:0 34px 6px 12px;
      font-size:10px;font-weight:normal;letter-spacing:.4px;
      text-transform:uppercase;color:var(--text-dim);
      white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
    }
    #timeline.os-pasek #tl-track{
      flex:0 0 auto;height:auto;display:flex;align-items:center;gap:6px;padding:0 12px;
      overflow-x:auto;overscroll-behavior-x:contain;
      -webkit-overflow-scrolling:touch;scrollbar-width:none;
      /* przewijamy tylko w poziomie — pion zostaje mapie */
      touch-action:pan-x;
      /* wybrany kafelek ma się zatrzymywać na środku, gdy JS go dowozi */
      scroll-behavior:smooth;
    }
    #timeline.os-pasek #tl-track::-webkit-scrollbar{display:none;}
    #timeline.os-pasek .linia{display:none;}   /* pasek nie udaje osi */
    .tl-chip{
      flex:0 0 auto;min-width:52px;min-height:34px;padding:0 10px;
      background:var(--panel-2);border:1px solid var(--line);border-radius:4px;
      color:var(--text);font:inherit;font-size:12px;letter-spacing:.2px;
      white-space:nowrap;cursor:pointer;-webkit-tap-highlight-color:transparent;
    }
    .tl-chip.act{
      background:var(--accent);border-color:var(--accent);color:#1a1a1a;
      font-weight:bold;text-shadow:0 0 .65px currentColor;
    }
    /* ściemnienie przy krawędziach — jedyny sygnał, że pasek ma ciąg
       dalszy; ten sam język, co przy przewijanej belce tytułowej */
    #timeline.os-pasek .tl-cien{
      /* tylko na wysokości rzędu kafelków — podpis nad nim ma zostać
         czytelny do ostatniej litery */
      display:block;position:absolute;bottom:7px;height:34px;width:26px;
      pointer-events:none;opacity:0;transition:opacity .18s;
    }
    #timeline.os-pasek .tl-cien-l{left:0;background:linear-gradient(to left, transparent, var(--panel));}
    #timeline.os-pasek .tl-cien-p{right:0;background:linear-gradient(to right, transparent, var(--panel));}
    #timeline.os-pasek.cien-l .tl-cien-l{opacity:1;}
    #timeline.os-pasek.cien-p .tl-cien-p{opacity:1;}
  }

/* ===== okienko „Nowość: Fotomapa 3D” (23.10.2026) ===== */
#nowosc3d{position:fixed;inset:0;z-index:12000;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;padding:16px;}
#nowosc3d .n3d-okno{width:min(640px,100%);max-height:calc(100% - 8px);overflow:auto;background:var(--panel);border:1px solid var(--line);
  border-radius:6px;box-shadow:0 10px 40px rgba(0,0,0,.6);}
#nowosc3d .n3d-kadr{display:block;line-height:0;}
#nowosc3d .n3d-kadr img{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:6px 6px 0 0;}
#nowosc3d .n3d-tresc{padding:14px 18px 16px;}
#nowosc3d .n3d-plak{display:inline-block;background:var(--accent);color:#1a1a1a;font-size:10px;font-weight:bold;letter-spacing:1.2px;padding:2px 7px;border-radius:2px;}
#nowosc3d h2{margin:8px 0 6px;font-size:20px;color:var(--text);letter-spacing:.5px;}
#nowosc3d p{margin:0 0 14px;color:var(--text-dim);font-size:13px;line-height:1.55;}
#nowosc3d .n3d-przyciski{display:flex;gap:10px;flex-wrap:wrap;}
#nowosc3d .n3d-tak{background:var(--accent);color:#1a1a1a;font-weight:bold;text-decoration:none;padding:9px 18px;border-radius:3px;font-size:13px;}
#nowosc3d .n3d-nie{background:transparent;color:var(--text-dim);border:1px solid var(--line);padding:8px 16px;border-radius:3px;font:inherit;font-size:13px;cursor:pointer;}
@media (hover:hover){ #nowosc3d .n3d-tak:hover{filter:brightness(1.08);} #nowosc3d .n3d-nie:hover{color:var(--text);border-color:var(--text-dim);} }

/* ===== „Co tu było?" (23.10.2026) ===== */
#co-tu{position:fixed;top:calc(var(--pasek, 52px) + 46px);right:58px;   /* prawa kolumna narzędzi zostaje widoczna obok */
  z-index:1150;width:340px;max-height:calc(100% - var(--pasek, 52px) - 76px);
  overflow:auto;background:var(--panel);border:1px solid var(--line);border-radius:5px;box-shadow:0 8px 28px rgba(0,0,0,.5);display:none;
  font-size:12px;color:var(--text);}
#co-tu.show{display:block;}
#co-tu .ct-glowa{display:flex;justify-content:space-between;align-items:flex-start;padding:10px 12px 8px;border-bottom:1px solid var(--line);
  position:sticky;top:0;background:var(--panel);z-index:1;}
#co-tu .ct-glowa b{display:block;font-size:14px;color:var(--accent);letter-spacing:.3px;}
#co-tu .ct-wsp{display:block;color:var(--text-dim);font-size:11px;margin-top:2px;font-family:monospace;}
#co-tu .ct-x{background:none;border:0;color:var(--text-dim);font-size:20px;line-height:1;cursor:pointer;padding:0 2px;}
#co-tu .ct-sekcja{color:var(--accent);font-size:10.5px;letter-spacing:.6px;text-transform:uppercase;margin:12px 12px 4px;}
#co-tu .ct-sekcja span{color:var(--text-dim);margin-left:4px;}
#co-tu .ct-pusto{color:var(--text-dim);margin:2px 12px 6px;line-height:1.4;}
#co-tu .ct-lista{padding:0 6px;}
#co-tu .ct-poz{display:flex;align-items:center;gap:10px;padding:6px 6px;border-radius:3px;cursor:pointer;}
@media (hover:hover){ #co-tu .ct-poz:hover{background:var(--panel-2);} }
#co-tu .ct-rok{flex:0 0 74px;font-weight:bold;color:var(--text);font-size:11.5px;line-height:1.25;}
#co-tu .ct-nazwa{flex:1;min-width:0;line-height:1.3;}
#co-tu .ct-nazwa small{display:block;color:var(--text-dim);font-size:10.5px;}
#co-tu .ct-stan{flex:0 0 auto;width:20px;height:20px;border-radius:50%;border:1px solid var(--line);display:flex;align-items:center;justify-content:center;
  color:var(--text-dim);font-size:12px;}
#co-tu .ct-mapa.wl .ct-stan{background:var(--accent);border-color:var(--accent);color:#1a1a1a;font-weight:bold;}
#co-tu .ct-os{position:relative;}
#co-tu .ct-os .ct-poz{position:relative;}
#co-tu .ct-dal{color:var(--text-dim);font-size:11px;white-space:nowrap;}
#co-tu .ct-skroty{display:flex;flex-wrap:wrap;gap:6px;padding:12px;border-top:1px solid var(--line);margin-top:10px;}
#co-tu .ct-skroty button{flex:1 1 auto;background:var(--panel-2);color:var(--text);border:1px solid var(--line);border-radius:3px;padding:6px 8px;font:inherit;font-size:11.5px;cursor:pointer;}
@media (hover:hover){ #co-tu .ct-skroty button:hover{border-color:var(--accent);color:var(--accent);} }
.co-tu-pkt span{display:block;width:14px;height:14px;margin:4px;border-radius:50%;background:var(--accent, #c9a24b);border:2px solid #fff;
  box-shadow:0 0 0 2px rgba(0,0,0,.45);animation:co-tu-puls 1.8s ease-out infinite;}
@keyframes co-tu-puls{0%{box-shadow:0 0 0 2px rgba(0,0,0,.45), 0 0 0 0 rgba(201,162,75,.7);}100%{box-shadow:0 0 0 2px rgba(0,0,0,.45), 0 0 0 16px rgba(201,162,75,0);}}
#ctx-menu .cm-glowna .cm-nazwa{font-weight:bold;color:var(--accent);}
@media (max-width:640px){
  #co-tu{top:auto;bottom:0;left:0;right:0;width:auto;max-height:62%;border-radius:10px 10px 0 0;z-index:10950;}   /* nad pływającym przyciskiem warstw */
}
/* „Co tu było?" - piktogramy i opisy (23.10, 23:45) */
#co-tu .ct-poz{align-items:flex-start;}
#co-tu .ct-ikona{flex:0 0 22px;height:22px;display:flex;align-items:center;justify-content:center;color:var(--text-dim);margin-top:1px;}
#co-tu .ct-mapa.wl .ct-ikona{color:var(--accent);}
#co-tu .ct-nazwa b{color:var(--text);}
#co-tu .ct-nazwa .ct-grupa{display:inline;font-size:10.5px;}
#co-tu .ct-opis{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;color:var(--text-dim);font-size:11px;line-height:1.4;margin-top:2px;}
#co-tu .ct-wiecej{display:inline-flex;align-items:center;gap:4px;margin-top:3px;color:var(--accent);font-size:10.5px;cursor:pointer;}
#co-tu .ct-wiecej svg{width:12px;height:12px;}
#co-tu .ct-stan{margin-top:1px;}

/* „Co tu było?" etap 2 - posty z forum (23.10.2026) */
#co-tu a.ct-post{color:inherit;text-decoration:none;}
#co-tu .ct-post .ct-nazwa{color:var(--text);}
#co-tu .ct-post .ct-wiecej{cursor:inherit;}
#co-tu .ct-ikona-mini{flex:0 0 40px;height:40px;margin-top:2px;}
#co-tu .ct-mini{width:40px;height:40px;object-fit:cover;border-radius:3px;display:block;background:var(--panel-2);}
#co-tu .ct-zaloguj{display:block;width:calc(100% - 24px);margin:4px 12px 2px;background:none;border:1px dashed var(--accent);color:var(--accent);
  border-radius:3px;padding:7px 8px;font:inherit;font-size:11.5px;cursor:pointer;text-align:center;}
@media (hover:hover){ #co-tu .ct-zaloguj:hover{background:var(--panel-2);} }
/* „Co tu było?" - ✓ jako przycisk wyłączania (25.10.2026) */
#co-tu .ct-stan{cursor:pointer;}
@media (hover:hover){ #co-tu .ct-mapa.wl .ct-stan:hover{background:var(--panel-2);border-color:#e05555;color:#e05555;} #co-tu .ct-mapa.wl .ct-stan:hover::before{content:'×';} #co-tu .ct-mapa.wl .ct-stan:hover{font-size:0;} #co-tu .ct-mapa.wl .ct-stan:hover::before{font-size:14px;} }

/* ===== porównywarka map (25-26.10.2026): dwie jednakowe mapy nad zwykłą ===== */
#poro-okno{display:none;position:fixed;inset:0;z-index:10800;background:var(--bg);}
body.porownanie #poro-okno{display:block;}
.poro-strona{position:absolute;top:0;bottom:0;width:50%;overflow:hidden;}
.poro-strona.poro-L{left:0;} .poro-strona.poro-P{left:50%;}
.poro-mapa{position:absolute;inset:0;background:var(--bg);}
/* linia podziału nad prawą mapą (nie border): obie mapy równej szerokości, krzyżyki co do piksela */
.poro-strona.poro-P::after{content:"";position:absolute;left:0;top:0;bottom:0;width:2px;background:var(--accent);z-index:1001;pointer-events:none;}
.poro-strona .m2-pasek{position:absolute;z-index:1100;top:calc(var(--m2-gora, 46px) + 8px);left:10px;max-width:calc(100% - 20px);
  display:flex;align-items:center;gap:6px;padding:5px 6px;
  background:var(--panel);border:1px solid var(--line);border-radius:6px;box-shadow:var(--shadow);font-size:12px;}
.m2-pasek select{max-width:230px;min-width:0;background:var(--panel);color:var(--text, #ddd);border:1px solid var(--line);border-radius:4px;padding:4px 6px;font:inherit;}
.m2-pasek .m2-pk{display:flex;gap:2px;}
.m2-pasek button{background:transparent;color:inherit;border:1px solid var(--line);border-radius:4px;padding:4px 7px;font:inherit;cursor:pointer;white-space:nowrap;}
.m2-pasek button:hover{border-color:var(--accent);}
.m2-pasek .m2-pk button.active{background:var(--accent);color:#131313;border-color:var(--accent);}
.m2-pasek .m2-x{font-size:16px;line-height:1;padding:2px 8px;}
.poro-pe a{font-size:15px;}
.poro-krzyz{display:none;position:absolute;left:0;top:0;width:0;height:0;z-index:1500;pointer-events:none;}
.poro-krzyz::before,.poro-krzyz::after{content:"";position:absolute;background:#fff;box-shadow:0 0 0 1px rgba(0,0,0,.65);}
.poro-krzyz::before{left:-9px;top:-0.75px;width:18px;height:1.5px;}
.poro-krzyz::after{top:-9px;left:-0.75px;height:18px;width:1.5px;}
.poro-krzyz.prowadzi::before,.poro-krzyz.prowadzi::after{background:#5fe36a;}
/* strzałkę myszy nad tłem mapy zastępują krzyżyki; pinezki, kształty i przyciski mają swoją łapkę */
#poro-okno .poro-mapa.leaflet-container{cursor:none !important;}
/* w porównywarce z belki znika to, co dotyczy zwykłej mapy pod spodem */
body.porownanie #toggle-sidebar, body.porownanie #toggle-timeline, body.porownanie #btn-zrodla, body.porownanie #offline-btn,
body.porownanie #zbiorka-btn, body.porownanie #warstwy-plyw{display:none !important;}
