/* ==========================================================================
   Czas Cykliczny - Widok 3D
   base.css - style bazowe (uklad desktopowy + wspolne dla wszystkich
   szerokosci ekranu).

   Ten plik powstal z wydzielenia zawartosci znacznika <style> z index.html
   (faza 0 refaktoryzacji na wiele plikow, bez zadnej zmiany wygladu:
   plik jest bajt-w-bajt tym samym CSS, tylko bez czterech blokow
   @media (max-width: 700px), ktore przeniesiono do mobile.css w
   niezmienionej kolejnosci wzgledem siebie).
   ========================================================================== */

html {
            overflow-x: hidden;
        }
        body {
            margin: 0;
            overflow: hidden;
            background: #0a0a0a;
            font-family: monospace;
        }
        /* #info NIE dostaje tu już pointer-events:none - w odróżnieniu od
           poprzedniej wersji (osobna, mała "ikonka" ⤢ do powiększania, bo
           tło miało przepuszczać kliknięcia do sceny 3D pod spodem), ta
           ramka jest teraz ujednolicona z 6 ramkami bocznymi: klasa
           .panel-zoomable (patrz niżej, sekcja "POWIĘKSZANIE RAMEK
           BOCZNYCH") włącza jej pointer-events:auto na stałe i całe jej
           tło jest klikalne - kliknięcie otwiera powiększenie na środek
           ekranu, tak samo jak w ramkach bocznych (patrz JS:
           openInfoZoom/closeInfoZoom, sekcja "4c-quater"). Rezygnujemy
           świadomie z przepuszczania kliknięć do sceny 3D w tym miejscu
           ekranu - ta ramka i tak stoi nad środkiem sceny, ale obracanie
           widoku jest dostępne wszędzie indziej. Kliknięcia we właściwe
           przyciski w środku (-1000/TERAZ/Odeh/Yallop/tryb czasu) są
           wyłączone z tej logiki w JS (sprawdzenie e.target.closest
           ('button')), więc nie otwierają przy okazji powiększenia. */
        #info {
            position: absolute;
            top: 10px;
            left: 50%;
            transform: translateX(-50%);
            min-width: 440px;
            color: #5ab8cc;
            background: #0a0a0a;
            padding: 8px 20px;
            border-radius: 8px;
            border: 1px solid #00d4e844;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
            z-index: 20;
            text-align: center;
            box-sizing: border-box;
        }
        /* Stan powiększony: #info (REALNA ramka, nie duplikat - patrz
           komentarz przy openInfoZoom w JS) trafia na środek ekranu przez
           zwykły CSS transform:scale(), a nie przez zmianę width/height
           jak w przypadku ramek bocznych. Dzięki temu, że #info nie ma w
           środku żadnych canvasów (tylko tekst/przyciski), zwykłe
           transform:scale() wystarcza - tekst przy skalowaniu wektorowym
           renderuje się ostro, bez sztuczek z osobnym buforem pikseli czy
           dubkowaniem font-size (patrz --pz-font-scale przy ramkach
           bocznych). Kluczowe: to wciąż TEN SAM węzeł DOM co zawsze - więc
           wszystkie podpięte wcześniej listenery (-1000/+1/TERAZ/Odeh/
           Yallop/tryb czasu) dalej działają, bez żadnej dodatkowej pracy.
           Ta różnica w TECHNICE animacji (scale zamiast realnego
           width/height) jest niezależna od ujednoliconego sposobu
           OTWIERANIA (klik w całą ramkę) - patrz komentarz przy #info
           wyżej. */
        #info.info-zoomed {
            position: fixed !important;
            top: var(--info-zoom-y, 50%) !important;
            left: 50% !important;
            transform: translate(-50%, -50%) scale(var(--info-zoom-k, 1));
            z-index: 200 !important;
            box-shadow: 0 0 50px 10px rgba(0, 212, 232, 0.35);
            opacity: 1;
            cursor: zoom-out;
            transition: transform 0.42s cubic-bezier(.22,.75,.24,1), opacity 0.24s ease;
            will-change: transform, opacity;
            transform-origin: center center;
        }
        #info.info-zoomed.info-zoom-entering {
            opacity: 0;
        }
        #info.info-zoom-closing {
            pointer-events: auto;
        }
        #syncCounterValue {
            color: #ff0000;
            font-weight: bold;
            font-size: 0.85em;
        }
        #calDatePanel {
            font-size: 16px;
            letter-spacing: 0.3px;
            color: #5ab8ccbb;
            white-space: nowrap;
        }
        /* Każde z tych 4 pól to teraz osobny, "zablokowany" slot o stałej
           min-width (patrz lockCalSegmentWidths() w JS, wołane z
           updateCalendarPanel() PRZED lockInfoPanelWidth()) - zamiast, jak
           dawniej, być tylko fragmentem jednego wyśrodkowanego wiersza
           tekstu. Bez tego: gdy zmieniała się długość SŁOWA w którymś polu
           (np. dzień tygodnia "środa" -> "poniedziałek"), CAŁY wiersz
           zmieniał naturalną szerokość i - będąc wyśrodkowany
           (text-align:center na #calDatePanel) - "zjeżdżał" w poziomie,
           przesuwając też sąsiednie pola (rok, JD...), mimo że zewnętrzna
           ramka #info miała już ustaloną szerokość (patrz
           infoPanelContentMinWidth). display:inline-block jest tu
           konieczny, żeby min-width w ogóle zadziałało (zwykły span w
           trybie inline go ignoruje); text-align:center centruje treść
           WEWNĄTRZ zarezerwowanego miejsca, więc krótsza/dłuższa treść
           przesuwa się co najwyżej sama w sobie, nigdy sąsiadów. */
        #calJulianDate, #calTime, #calWeekday, #calJdNumber {
            color: #00d4e8;
            font-weight: bold;
            display: inline-block;
            text-align: center;
        }
        /* Link do dokumentacji przeniesiony do centralnego pola pierścieni -
           patrz .center-label-docslink niżej oraz centerLabelDiv w JS.
           (Poprzednio: osobny, stały element #docsLink w rogu ekranu.) */
        /* Podświetlenie cyfr, które właśnie się zmieniły - patrz
           calRenderDigitFlash w JS, użyte przez WSZYSTKIE pola ramki
           kalendarza, w których zmieniają się cyfry (data, godzina, JD,
           rok/dzień/godzina biblijna...). Krótki, delikatny "flash": cyfra
           rozjaśnia się (przez filter:brightness/saturate, NIE przez
           przełączenie na biały/inny kolor - dzięki temu błysk zostaje w
           tej samej barwie co reszta tekstu, tylko w jaśniejszej wersji) i
           lekko rośnie, po czym płynnie wraca do normalnego wyglądu - ma to
           unaocznić płynący czas, bez odrywania uwagi (stąd krótki czas
           trwania i skromna amplituda). text-shadow używa currentColor,
           więc poświata też automatycznie dopasowuje się do barwy danego
           pola (cyjan w górnym wierszu, złoto w wierszu biblijnym), zamiast
           być na sztywno zakodowana pod jeden konkretny kolor. */
        .calDigitChanged {
            display: inline-block;
            animation: calDigitFlash 1s ease-out;
        }
        @keyframes calDigitFlash {
            0% {
                filter: brightness(1.7) saturate(1.3);
                text-shadow: 0 0 5px currentColor, 0 0 11px currentColor;
                transform: scale(1.25);
            }
            25% {
                /* Krótkie "zatrzymanie" na szczycie jasności zaraz po
                   błysku, zanim zacznie się właściwe, długie dogasanie
                   niżej - błysk ma być zauważalny, a nie migać i od razu
                   znikać. */
                filter: brightness(1.7) saturate(1.3);
                text-shadow: 0 0 5px currentColor, 0 0 11px currentColor;
                transform: scale(1.2);
            }
            100% {
                filter: brightness(1) saturate(1);
                text-shadow: none;
                transform: scale(1);
            }
        }
        #timeModeRow {
            margin-top: 3px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            font-size: 14px;
            color: #5ab8ccbb;
            white-space: nowrap;
            pointer-events: auto;
        }
        #timeModeRow .cal-row-label {
            display: inline-flex;
        }
        /* Notatka wyjaśniająca, pojawiająca się WYŁĄCZNIE gdy: tryb "czas
           cywilny strefowy" jest włączony ORAZ bieżąca data jest sprzed
           wprowadzenia w Jerozolimie jakiejkolwiek formalnej strefy czasowej
           (1 stycznia 1918 - patrz JERUSALEM_ZONE_INTRO_JD w JS, oparte na
           realnych danych IANA tzdata dla Asia/Jerusalem). W odróżnieniu od
           #timeModeRow (nowrap, bo to krótka etykieta + przełącznik), ta
           notatka może być dłuższa - stąd normalny zawijany tekst zamiast
           nowrap, i węższa, czytelna szerokość maksymalna. */
        #timeModeNote {
            display: none;
            position: relative;
            margin: 3px auto 0;
            width: 100%;
            font-size: 13px;
            line-height: 1.4;
            color: #5ab8cc99;
            white-space: normal;
            text-align: center;
            pointer-events: none;
        }
        #timeModeNote.active {
            display: block;
        }
        #timeModeNote.dismissed {
            display: none !important;
        }
        #timeModeNoteText {
            padding: 0 20px;
            display: inline-block;
        }
        #timeModeNoteClose {
            position: absolute;
            top: -2px;
            right: 0;
            width: 16px;
            height: 16px;
            line-height: 14px;
            padding: 0;
            border: 1px solid #5ab8cc55;
            border-radius: 50%;
            background: transparent;
            color: #5ab8ccbb;
            font-size: 12px;
            font-family: inherit;
            cursor: pointer;
            pointer-events: auto;
            transition: color 0.15s, border-color 0.15s;
        }
        #timeModeNoteClose:hover {
            color: #00d4e8;
            border-color: #00d4e8aa;
        }
        /* Subtelny separator między poszczególnymi składnikami daty/czasu
           (data, dzień tygodnia, godzina, JD...) - kropka pośrednia (·),
           standardowa konwencja UI do rozdzielania jednorodnych,
           samodzielnych "pól" w jednej linii (np. znaczniki czasu, okruszki
           nawigacyjne). Kolor dziedziczony po rodzicu (currentColor) +
           przyciemnienie przez opacity, więc pasuje zarówno do cyjanowego
           panelu juliańskiego, jak i żółtawego panelu biblijnego, bez
           osobnych reguł na kolor. Odstęp w "em", żeby skalował się razem
           z font-size (także w wariancie mobilnym niżej).
        */
        .calSep {
            opacity: 0.4;
            margin: 0 0.5em;
            font-weight: normal;
        }
        /* Kolor ramki biblijnej ujednolicony z ramką juliańsko-gregoriańską
           (patrz #calDatePanel / #calJulianDate wyżej) - ta sama para barw
           (przygaszony cyjan dla tła/separatorów, jaskrawy cyjan dla
           wyróżnionych wartości), zamiast dawnego odrębnego kremowego
           odcienia (#fff3c4). */
        #calBiblicalPanel {
            font-size: 16px;
            letter-spacing: 0.3px;
            color: #5ab8ccbb;
            white-space: nowrap;
            margin-top: 3px;
        }
        /* Ta sama blokada slotów co #calJulianDate/#calTime/#calWeekday/
           #calJdNumber wyżej (patrz komentarz tam) - stosowana też do
           wiersza biblijnego, bo tu wahania długości treści są jeszcze
           większe (np. etykieta godziny "godzina 9" vs "IV straż nocna",
           nazwa miesiąca "Ziw" vs "Kislew/Sziwan"). */
        #calBiblicalYear, #calBiblicalMonth, #calBiblicalDay, #calBiblicalHour, #calBiblicalWeekday {
            color: #00d4e8;
            font-weight: bold;
            display: inline-block;
            text-align: center;
        }
        /* #calBiblicalYear to JEDYNE pole w całym panelu (górnym i
           biblijnym razem), które jest GOŁĄ liczbą - bez dopełniających
           zer jak w #calJulianDate ("30" zawsze w kontekście "-04-12"),
           bez towarzyszącego słowa jak pozostałe 3 pola biblijne ("19
           Abib (1)", "III straż nocna", "Jom Rewi'i (4)"). To dlatego
           TYLKO tu widać skakanie mimo działającej blokady szerokości
           (lockCalSegmentWidths): text-align:center w zablokowanym slocie
           centruje treść WEWNĄTRZ niego, więc gdy liczba cyfr się zmienia
           (np. rok 3790 -> 790 po -1000 x3, patrz przyciski
           #biblicalYearJumpRow) - CAŁA liczba przesuwa się o pół znaku w
           obie strony na raz, bo dopełniające puste miejsce w slocie
           rozkłada się symetrycznie. Sąsiednie pola się nie ruszają (to
           już naprawione), ale SAMA liczba w swoim polu - owszem.
           text-align:right naprawia to do końca: przy stałej (monospace)
           szerokości znaku, dopisanie/ubycie NAJBARDZIEJ znaczącej cyfry
           (zawsze na początku liczby) przesuwa tylko tę jedną, nową
           cyfrę - wszystkie pozostałe, już wyświetlane cyfry zostają
           dokładnie w tym samym miejscu w pikselach. Dokładnie tak
           zachowuje się licznik/zegar cyfrowy: rosnąca liczba "dopisuje
           się" po lewej, zamiast przesuwać resztę. (Ta sama zasada
           dotyczyłaby też #calJdNumber przy zmianie liczby cyfr części
           całkowitej JD - ale tam, dzięki prefiksowi "JD " i stałym 5
           miejscom po przecinku, granica cyfr wypada raz na ok. 2700 lat,
           więc w praktyce nieobserwowalne - stąd brak analogicznej zmiany
           tam, żeby nie ruszać czegoś, co nie sprawia problemu.) */
        #calBiblicalYear {
            text-align: right;
        }
        #biblicalYearJumpRow {
            margin-top: 7px; margin-bottom: 5px; display: flex; align-items: center;
            justify-content: center; gap: 6px; flex-wrap: wrap; pointer-events: auto;
        }
        #biblicalYearJumpRow button {
            background: none; border: 1px solid #00d4e8; color: #00d4e8; border-radius: 6px;
            padding: 0 10px; cursor: pointer; font-family: monospace; font-size: 13px;
            transition: background 0.2s; box-sizing: border-box; height: 26px;
            display: inline-flex; align-items: center; justify-content: center; line-height: 1;
            white-space: nowrap;
        }
        #biblicalYearJumpRow button:hover { background: #00d4e822; }
        #biblicalYearJumpRow #biblicalNowBtn {
            border-color: #ffe066;
            color: #ffe066;
            font-weight: bold;
            padding: 0 14px;
            text-shadow: 0 0 5px #ffe06688;
        }
        #biblicalYearJumpRow #biblicalNowBtn:hover { background: #ffe06622; }
        #biblicalYearJumpRow button:disabled { opacity: 0.4; cursor: default; }
        #timeJumpRow {
            margin-top: 5px;
            margin-bottom: 5px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 6px;
            flex-wrap: wrap;
            pointer-events: auto;
        }
        #timeJumpRow button {
            background: none;
            border: 1px solid #00d4e8;
            color: #00d4e8;
            border-radius: 6px;
            padding: 0 10px;
            cursor: pointer;
            font-family: monospace;
            font-size: 13px;
            transition: background 0.2s;
            box-sizing: border-box;
            height: 26px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            line-height: 1;
            white-space: nowrap;
        }
        #timeJumpRow button:hover {
            background: #00d4e822;
        }
        #timeJumpRow button:disabled {
            opacity: 0.4;
            cursor: default;
        }
        #timeJumpRow #nowBtn {
            border-color: #ffe066;
            color: #ffe066;
            font-weight: bold;
            padding: 0 14px;
        }
        #timeJumpRow #nowBtn:hover {
            background: #ffe06622;
        }
        #jumpProgressWrap {
            display: none;
            margin-top: 8px;
            flex-direction: column;
            /* flex-start (NIE center) - etykieta jest juz wyrownana do
               lewej (patrz text-align:left w #jumpProgressLabel), wiec
               pasek postepu wyrownany do srodka wygladalby niespojnie
               (inny punkt startowy niz tekst nad nim). flex-start ustawia
               oba elementy (etykiete i pasek) do tej samej, lewej krawedzi. */
            align-items: flex-start;
            gap: 5px;
            pointer-events: none;
        }
        #jumpProgressWrap.active {
            display: flex;
        }
        #jumpProgressLabel {
            font-size: 12px;
            color: #ffe066;
            letter-spacing: 0.3px;
            white-space: pre-line;
            /* text-align:left (NIE center) - to celowe. Nawet przy stalej
               szerokosci kontenera (patrz width nizej) tekst wysrodkowany
               nadal "skacze" w poziomie przy kazdej aktualizacji, bo srodek
               kazdej linii zalezy od jej BIEZACEJ dlugosci (np. "9 s" vs
               "1 min 30 s", "30 n.e." vs "871 p.n.e." maja rozna dlugosc) -
               wiec mimo stabilnego kontenera, sam tekst nadal wizualnie
               "tanczy" lewo-prawo. Wyrownanie do lewej daje jedyny w pelni
               stabilny punkt odniesienia: poczatek kazdej linii siedzi
               zawsze w tym samym miejscu, niezaleznie od tego, jak dluga
               akurat jest jej tresc - zmienia sie tylko prawy kraniec
               linii, ktory dla oka jest duzo mniej zauwazalny niz
               przesuwajacy sie poczatek. */
            text-align: left;
            line-height: 1.4;
            /* Szeroko, bo #info i tak juz ma realna szerokosc wyznaczona
               przez inne wiersze (data/godzina, rok biblijny) - ograniczenie
               do sztywnych 280px lamalo druga linie (zakres lat/predkosc/ETA)
               bez potrzeby, mimo wolnego miejsca w poziomie. min(...) zamiast
               sztywnej liczby: nie rozsadza layoutu na waskich ekranach, ale
               na szerokich nie marnuje dostepnej przestrzeni. Patrz tez
               white-space:nowrap na segmentach w setCalcProgress (JS) -
               dzieki niej, jesli lamanie linii mimo wszystko jest konieczne
               (waski ekran / dlugi tekst), nastapi ono WYLACZNIE miedzy
               segmentami (przy " • "), nigdy w srodku jednego (np.
               "170 n.e.)" albo "~25 lat/s").
               WIDTH (nie tylko max-width!) - bez tego element kurczy/rosnie
               "shrink-to-fit" do biezacej dlugosci tekstu (np. "9 s" vs
               "1 min 30 s", "30 n.e." vs "1234 n.e."), a poniewaz jest
               wysrodkowany w #jumpProgressWrap (align-items:center), kazda
               taka zmiana dlugosci przesuwala caly blok w poziomie -
               widoczny "skok" tekstu przy kazdej aktualizacji. Sztywne width
               (ta sama wartosc, co max-width mialo wczesniej) daje STABILNY
               box: caly kontener jest niezmienny, a tekst wewnatrz (dzieki
               text-align:left powyzej) startuje zawsze z tego samego
               miejsca. */
            width: min(90vw, 460px);
            /* tabular-nums: cyfry o STALEJ szerokosci (normalnie np. "1" i
               "8" moga miec inna szerokosc w danym foncie) - eliminuje
               dodatkowe, drobne "drganie" tekstu przy kazdej zmianie liczby
               (procent, rok, predkosc, ETA), niezalezne od zmiany width
               powyzej (ktora zapobiega skokowi CALEGO bloku). */
            font-variant-numeric: tabular-nums;
        }
        /* jpSeg: jeden "kawalek" etykiety postepu (np. caly zakres lat,
           cala predkosc, cale ETA) - patrz setCalcProgress (JS). Segmenty sa
           laczone zwyklymi, LAMLIWYMI spacjami dookola " • ", ale kazdy
           segment sam w sobie ma nowrap, wiec przegladarka moze zlamac
           linie tylko MIEDZY segmentami, nigdy w ich srodku. */
        .jpSeg {
            white-space: nowrap;
        }
        /* jumpProgressVenusLine: patrz komentarz w HTML przy tym elemencie -
           trwaly element (nie tworzony na nowo co klatke jak reszta
           etykiety), zeby animacja spinnera nizej nie restartowala sie w
           kolko. Domyslnie ukryty (display:none) - JS pokazuje go tylko w
           fazie 2 skoku (blok Wenus/oktaeterydy), patrz setCalcProgress. */
        #jumpProgressVenusLine {
            display: none;
            align-items: center;
            gap: 6px;
            font-size: 12px;
            color: #ffe066;
            letter-spacing: 0.3px;
            white-space: nowrap;
        }
        #jumpProgressVenusLine.active {
            display: flex;
        }
        /* Spinner CSS-owy (obracajacy sie okrag z jednym jasniejszym
           lukiem) - zamiast obrazka/SVG, zeby nie dokladac zadnego zasobu;
           kolor spojny z reszta etykiety (#ffe066). animation:infinite -
           dziala niezaleznie od tego, jak czesto/rzadko silnik zglasza
           faktyczny postep fazy 2 (ktora, w odroznieniu od fazy 1, nie ma
           dokladnej metryki "lat na sekunde" - blok Wenus liczy sie w
           koniunkcjach, nie latach), wiec spinner daje uzytkownikowi
           widoczny sygnal "to nadal dziala", nawet gdy pasek/procent
           poruszaja sie wolno lub nierowno. */
        #jumpProgressVenusSpinner {
            display: inline-block;
            width: 11px;
            height: 11px;
            border-radius: 50%;
            border: 2px solid #ffe06655;
            border-top-color: #ffe066;
            animation: jpVenusSpin 0.8s linear infinite;
            flex: none;
        }
        @keyframes jpVenusSpin {
            to { transform: rotate(360deg); }
        }
        #jumpProgressBarOuter {
            width: 220px;
            max-width: 80vw;
            height: 6px;
            border-radius: 3px;
            background: #00d4e822;
            border: 1px solid #00d4e844;
            overflow: hidden;
        }
        #jumpProgressBarInner {
            height: 100%;
            width: 0%;
            background: linear-gradient(90deg, #00d4e8, #ffe066);
            transition: width 0.12s linear;
        }
        #controls {
            position: absolute;
            bottom: 10px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            align-items: center;
            gap: 16px;
            padding: 8px 22px;
            background: #0a0a0a;
            border-radius: 12px;
            border: 1px solid #00d4e844;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
            z-index: 20;
            flex-wrap: wrap;
            justify-content: center;
            pointer-events: auto;
        }
        #controls button {
            background: none;
            border: 1px solid #00d4e8;
            color: #00d4e8;
            border-radius: 6px;
            padding: 0 14px;
            cursor: pointer;
            font-family: monospace;
            font-size: 16px;
            transition: background 0.2s;
            box-sizing: border-box;
            height: 32px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            line-height: 1;
        }
        /* NAPRAWA (v3.36.1): PLAY/RESET zajmowały za dużo miejsca (szerokie
           przyciski tekstowe "⏸ PAUSE" / "↺ RESET"). Zamieniono treść na
           same symbole (patrz HTML) i przyciski przestały wymuszać szeroki
           min-width - teraz to małe, kwadratowe "ikonki", więc więcej
           miejsca zostaje dla samego paska prędkości. */
        #playBtn, #controls .reset {
            min-width: 74px;
            width: 74px;
            padding: 0;
            font-size: 18px;
        }
        /* NAPRAWA: glify PLAY/PAUSE/RESET dawniej wstawiane jako tekst
           (Unicode ⏸/▶/↺) bezpośrednio jako textContent przycisku -
           geometrycznie (flex + justify-content:center) wyglądały
           wyśrodkowane wg komórki znaku, ale centrowanie TEKSTU w flexboksie
           opiera się na metrykach fontu (wysokość linii wg ascent/descent
           glifu), a nie na rzeczywistym kształcie znaku - część symboli
           (zwłaszcza ↺, ale też ▶) renderowała się przez to zauważalnie
           przesunięta w pionie i/lub w poziomie względem środka przycisku,
           niezależnie od fontu/przeglądarki.
           Rozwiązanie: zamiast tekstu, każdy przycisk dostaje mały, ręcznie
           zaprojektowany inline <svg> (patrz HTML) o stałym rozmiarze
           (18×18) - to gwarantuje piksel-idealne centrowanie przez flexbox
           (centrowany jest teraz REALNY box elementu, a nie umowna linia
           tekstu), niezależnie od fontu/platformy. `display:block` na svg
           usuwa dodatkowo domyślny, mały "podpis" pod linią bazową, jaki
           przeglądarki dają elementom inline (dokładnie ten sam powód, dla
           którego <img> w praktyce też zwykle dostaje display:block). */
        .btn-icon {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 100%;
            height: 100%;
        }
        .btn-icon svg {
            display: block;
            color: inherit;
        }
        #controls button:hover {
            background: #00d4e822;
        }
        #controls .reset:disabled {
            cursor: default;
            opacity: 1;
        }
        /* NAPRAWA (v3.36.1): opakowanie suwaka - musi być `position:
           relative`, żeby móc w nim pozycjonować bezwzględnie zarówno
           znacznik środka (#speedCenterTick), jak i pływającą etykietę
           mnożnika (#speedValFloat, patrz updateSpeed() w JS). Stały
           `padding-top` robi miejsce nad paskiem na tę etykietę, żeby
           nigdy nie zachodziła na sam suwak. NAPRAWA (v3.36.2): zwiększono
           padding-top (20px -> 30px), żeby unieść etykietę wyraźnie wyżej
           nad uchwyt suwaka - patrz też #speedValFloat.top niżej. */
        #speedTrackWrap {
            position: relative;
            flex: 3;
            min-width: 360px;
            height: 32px;
            padding-top: 12px;
            box-sizing: border-box;
        }
        #controls input[type="range"] {
            display: block;
            width: 100%;
            accent-color: #00d4e8;
            height: 16px;
            -webkit-appearance: none;
            appearance: none;
            background: transparent;
            cursor: pointer;
            /* NAPRAWA (v3.37.4): w niektórych silnikach (webview) tor
               suwaka ze stylowanym ::-...-runnable-track potrafił mimo
               wszystko renderować się NAD uchwytem (::-...-slider-thumb),
               niezależnie od z-index nadawanego samym pseudo-elementom -
               ich wzajemna kolejność malowania jest częścią wewnętrznego
               "shadow DOM" przeglądarki dla <input type=range> i author
               z-index na TYCH pseudo-elementach bywa tam ignorowany.
               Rozwiązanie: prowadnica przestaje być rysowana jako
               pseudo-element toru (który teraz jest całkowicie
               przezroczysty, patrz niżej) - zamiast tego identyczny
               wizualnie pasek to zwykły, osobny element #speedTrackVisual
               (patrz HTML/CSS niżej), leżący POD samym <input> w zwykłym,
               globalnym kontekście stosu (tam z-index działa niezawodnie
               we wszystkich przeglądarkach). Sam <input> (a więc i jego
               naturalny uchwyt) dostaje wyższy z-index niż ten pasek, więc
               uchwyt zawsze wygrywa. */
            position: relative;
            top: -4px;
            z-index: 2;
        }
        /* Wizualny odpowiednik toru (patrz komentarz wyżej) - zwykły div,
           nie pseudo-element, więc jego z-index jest w pełni respektowany
           względem <input> leżącego nad nim. pointer-events:none, żeby nie
           przechwytywał kliknięć/przeciągania należących do suwaka. */
        #speedTrackVisual {
            position: absolute;
            left: 0;
            right: 0;
            top: 10px;
            height: 12px;
            background: linear-gradient(90deg, #00d4e888, #00d4e8ee);
            clip-path: polygon(0% 50%, 100% 0%, 100% 100%);
            pointer-events: none;
            z-index: 1;
        }
        /* Cieniowanie paska JEDNOKIERUNKOWE (v3.37.0: suwak działa tylko
           wprzód) - ciemniej po lewej (1×, realny czas), jaśniej po prawej
           (duża prędkość, do 1 000 000×).
           NAPRAWA: oprócz cieniowania kolorem, sama prowadnica teraz
           fizycznie ROŚNIE na grubość od lewej do prawej - box pseudo-
           elementu ma stałą wysokość (12px, tyle co maksymalna grubość),
           ale clip-path przycina go do klina: w x=0% widoczny jest tylko
           pojedynczy punkt (środek wysokości), w x=100% widoczna jest cała
           wysokość. Ponieważ oba brzegi klina (0% 50% -> 100% 0%/100%)
           są liniami prostymi, widoczna grubość w dowolnym punkcie x rośnie
           dokładnie PROPORCJONALNIE do x - czyli tak samo jak mnożnik
           prędkości wzdłuż suwaka. Uchwyt (thumb) ma własny, stały rozmiar
           i nie jest tym przycinany - patrz przeliczony margin-top niżej,
           żeby zostawał wyśrodkowany względem PEŁNEJ wysokości boxu toru
           (12px), a nie względem lokalnie widocznej (przyciętej) grubości. */
        #controls input[type="range"]::-webkit-slider-runnable-track {
            height: 100%;
            background: transparent;
        }
        /* NAPRAWA: uchwyt (thumb) w tym samym odcieniu cyjanu co gradient
           toru - przy wysokich mnożnikach (jasny, prawy koniec gradientu)
           uchwyt wizualnie zlewał się z prowadnicą, zwłaszcza że od
           niedawna prowadnica jest tam też najgrubsza (patrz clip-path
           wyżej). Zamiast zmieniać kolor uchwytu (musiałby różnić się od
           CAŁEJ palety interfejsu, nie tylko końca gradientu), dodajemy mu
           wąską, ciemną "obwódkę" w kolorze tła (pierwsza warstwa
           box-shadow, 0 blur = twarda, pierścieniowata linia) - to
           odcina go wizualnie od prowadnicy niezależnie od tego, jak
           jasny jest akurat gradient pod spodem. Druga warstwa box-shadow
           to już tylko dotychczasowa poświata. */
        /* NAPRAWA (v3.37.5): niezależnie od wartości margin-top, natywny
           uchwyt suwaka w niektórych silnikach (webview) renderował się
           konsekwentnie kilka pikseli za nisko względem toru/przycisków -
           margin-top był w praktyce ignorowany przez pozycjonowanie
           natywnego uchwytu w tym środowisku, więc dalsze "dostrajanie"
           tej wartości nie miało żadnego efektu. Zamiast tego: natywny
           uchwyt staje się całkowicie NIEWIDOCZNY (zero tła/obwódki/
           cienia, ale ZACHOWUJE swój rozmiar, więc nadal łapie kliknięcia
           i przeciąganie - patrz #speedThumbVisual niżej, który jest
           osobnym, zwykłym divem rysującym to, co widać, w pozycji w
           pełni kontrolowanej przez JS (positionSpeedLabel), tak samo jak
           już wcześniej działająca etykieta mnożnika #speedValFloat. */
        #controls input[type="range"]::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 24px;
            height: 24px;
            margin-top: -7px;
            border-radius: 50%;
            background: transparent;
            border: none;
            box-shadow: none;
            cursor: pointer;
        }
        #controls input[type="range"]::-moz-range-track {
            height: 100%;
            background: transparent;
        }
        #controls input[type="range"]::-moz-range-thumb {
            width: 24px;
            height: 24px;
            border-radius: 50%;
            background: transparent;
            border: none;
            box-shadow: none;
            cursor: pointer;
        }
        /* Własny, w pełni kontrolowany "uchwyt" - zwykły div rysowany NAD
           niewidocznym natywnym uchwytem, którego jedyną rolą zostaje już
           tylko łapanie kliknięć/przeciągania. Pozycję pozioma ustawia JS
           w positionSpeedLabel() - dokładnie tym samym wzorem, co dla
           #speedValFloat (który od dawna poprawnie trafia nad środek
           uchwytu), więc nie ma tu żadnej nowej niewiadomej. Pozycja
           pionowa jest stałą wartością wyliczoną wprost ze środka
           #speedTrackVisual (top:10px + height:12px => środek=16px),
           więc uchwyt zawsze jest idealnie na wysokości toru/przycisków,
           niezależnie od kaprysów natywnego renderowania inputa. */
        #speedThumbVisual {
            position: absolute;
            top: 4px;
            width: 24px;
            height: 24px;
            box-sizing: border-box;
            border-radius: 50%;
            background: #eafdff;
            border: 3px solid #00838f;
            box-shadow: 0 0 0 3px #0a0a0a, 0 0 10px 2px #00d4e8cc;
            pointer-events: none;
            transform: translateX(-50%);
            z-index: 3;
        }
        /* NAPRAWA (v3.36.1): mnożnik dawniej wyświetlany w stałym miejscu
           OBOK suwaka (span.speedVal) - przy wielocyfrowych wartościach
           (np. "1 000 000×") zmieniał szerokość i szarpał całą ramką
           sterowania (przesuwał RESET, zmieniał jej całkowitą szerokość/
           wyśrodkowanie). Teraz #speedValFloat: (1) ma stałą szerokość
           (min-width + text-align:center, więc jego WŁASNY rozmiar się nie
           zmienia, tylko treść w środku), (2) jest pozycjonowany bezwzględnie
           NAD uchwytem suwaka (position:absolute, left ustawiane w JS w
           updateSpeed() na podstawie realnej pozycji uchwytu w pikselach) -
           dzięki position:absolute w ogóle nie wpływa na layout reszty
           paska sterowania, więc nic obok niego nie może "skoczyć".
           transform: translateX(-50%) centruje etykietę nad uchwytem.
           NAPRAWA (v3.36.2): podniesiono etykietę wyżej (top: -2px -> -14px,
           razem ze zwiększonym padding-top w #speedTrackWrap) i wyrównano
           rozmiar czcionki do licznika u góry ramki (#timeDisplay,
           font-size: 15px), żeby oba napisy wyglądały spójnie. */
        #speedValFloat.speedVal {
            position: absolute;
            top: -22px;
            min-width: 92px;
            text-align: center;
            font-size: 15px;
            color: #00d4e8;
            font-variant-numeric: tabular-nums;
            white-space: nowrap;
            transform: translateX(-50%);
            pointer-events: none;
        }
        #rightPanelsColumn {
            position: absolute;
            top: 10px;
            right: 30px;
            display: flex;
            flex-direction: column;
            align-items: flex-end;
            gap: 16px;
            z-index: 20;
            pointer-events: none;
            box-sizing: border-box;
            /* top i height ustawiane w JS (layoutRightPanels), analogicznie do
               #leftPanelsColumn, żeby kolumna bezpiecznie dopasowywała się do
               dostępnej wysokości ekranu między nagłówkiem a paskiem sterowania. */
        }
        #legend {
            flex: 0 0 auto;
            color: #5ab8cc;
            background: #0a0a0a;
            padding: 10px 16px;
            border-radius: 8px;
            border: 1px solid #00d4e844;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
            font-size: calc(14px * var(--pz-font-scale, 1));
            pointer-events: none;
            min-width: 170px;
            box-sizing: border-box;
        }
        #legend .dot {
            display: inline-block;
            width: calc(12px * var(--pz-font-scale, 1));
            height: calc(12px * var(--pz-font-scale, 1));
            border-radius: 50%;
            margin-right: 6px;
        }
        #legend .line-sample {
            display: inline-block;
            width: calc(24px * var(--pz-font-scale, 1));
            height: calc(2px * var(--pz-font-scale, 1));
            background: #ff3333;
            box-shadow: 0 0 6px #ff333388;
            border-radius: 2px;
            margin-right: 6px;
        }
        #legend div {
            margin: 4px 0;
            display: flex;
            align-items: center;
            gap: 6px;
        }
        #legend .legend-sep {
            height: 1px;
            background: #00d4e833;
            margin: 8px 0;
            width: 100%;
        }
        #legend .ring-legend-title {
            color: #5ab8cc;
            justify-content: flex-start;
            margin-bottom: 4px;
        }
        #ringLegendList {
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            gap: 3px;
            width: 100%;
        }
        #legend .ring-row {
            display: flex;
            align-items: center;
            gap: 6px;
            margin: 0;
            width: 100%;
        }
        #legend .ring-row .idx {
            color: #3a7080;
            font-size: calc(12px * var(--pz-font-scale, 1));
            min-width: 14px;
            text-align: left;
        }
        #legend .ring-row .ring-name {
            color: #cdeef5;
        }
        #leftPanelsColumn {
            position: absolute;
            left: 30px;
            width: auto;
            max-width: calc(100vw - 60px);
            display: flex;
            flex-direction: column;
            gap: 16px;
            z-index: 20;
            pointer-events: none;
            box-sizing: border-box;
            /* Szerokość wraca do NATURALNEJ szerokości z wersji bazowej.
               Stabilizacja po resize jest robiona w JS: naturalna szerokość
               jest zapamiętywana zanim stare rozmiary canvasów będą mogły
               wpłynąć na intrinsic sizing. Dzięki temu nie powiększamy
               już paneli tylko dlatego, że wcześniej były wywołane na środek. */
        }
        #desyncPanel,
        #moonPhasePanel,
        #sunAltPanel {
            color: #5ab8cc;
            background: #0a0a0a;
            padding: 10px 16px;
            border-radius: 8px;
            border: 1px solid #00d4e844;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
            font-size: calc(14px * var(--pz-font-scale, 1));
            pointer-events: none;
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            /* Wszystkie 3 ramki dostają równy udział w wysokości kontenera. */
            flex: 1 1 0;
            min-height: 0;
            width: 100%;
        }
        #desyncPanel .desync-title {
            color: #ff0000;
            margin-bottom: 6px;
            white-space: nowrap;
            flex: 0 0 auto;
        }
        #desyncPctLabel {
            font-weight: bold;
            font-size: 1.1em;
        }
        /* Wykresy synchronizacji: dwa widoki w tej samej ramce. */
        .sync-chart-canvas {
            display: block;
            width: 100%;
            flex: 1 1 auto;
            min-height: 0;
            border-radius: 4px;
        }

        #syncVectorCanvas {
            display: none;
        }

        /* Kwadratowe przełączniki widoku przy wszystkich ramkach. */
        .panel-selectors {
            position: absolute;
            display: flex;
            flex-direction: column;
            gap: calc(7px * var(--pz-font-scale, 1));
            z-index: 25;
            pointer-events: auto;
            /* W stanie normalnym pozycja przełączników ma być
               NATYCHMIASTOWA. Globalna animacja top/left/right powodowała,
               że podczas resize przełącznik przez kilkaset ms podążał
               za starą geometrią panelu i przy kolejnych zmianach
               rozmiaru mógł wyglądać jakby "przesuwał się" po ekranie.
               Podczas zoomu przełącznik jest zamiast tego śledzony klatka
               po klatce za pomocą getBoundingClientRect(). */
            /* Pozycja jest aktualizowana synchronicznie z bieżącym rectem
               ramki; nie stosujemy transition, bo powodowałby lag. */
            transition: none;
        }
        .panel-selectors.left { left: 5px; }
        .panel-selectors.right { right: 5px; }
        /* Skala przełączników podąża za powiększeniem ramki, do której są
           przypisane - patrz JS: positionPanelSelector() ustawia tu tę samą
           zmienną --pz-font-scale, która skaluje resztę treści powiększonej
           ramki (patrz komentarz przy --pz-font-scale wyżej w pliku). Bez
           tego przełączniki zostawały małe (18x18px) nawet przy ramce
           powiększonej na środek ekranu kilkukrotnie. */
        .panel-selectors button {
            width: calc(18px * var(--pz-font-scale, 1));
            height: calc(18px * var(--pz-font-scale, 1));
            padding: 0;
            margin: 0;
            border: calc(1px * var(--pz-font-scale, 1)) solid #5a5a5a;
            border-radius: calc(3px * var(--pz-font-scale, 1));
            background: rgba(50, 50, 50, 0.82);
            box-sizing: border-box;
            cursor: pointer;
            transition: background 0.15s, border-color 0.15s, box-shadow 0.15s;
        }
        .panel-selectors button:hover {
            border-color: #00d4e8;
            background: #0d2b30;
        }
        .panel-selectors button.active {
            border-color: #00d4e8;
            background: #123a42;
            box-shadow: none;
        }
        .panel-selectors button:focus-visible {
            outline: 1px solid #00d4e8;
            outline-offset: 1px;
        }
        /* ================================================================
           POWIĘKSZANIE RAMEK BOCZNYCH na środek ekranu (patrz JS:
           openPanelZoom/closePanelZoom, sekcja "4c-ter"). Ramki mają
           domyślnie pointer-events:none (żeby nie przeszkadzały w
           obracaniu/zoomie sceny 3D pod spodem) - klasa .panel-zoomable
           włącza im pointer-events:auto na stałe (obszar tych ramek i tak
           leży poza samą sceną 3D, więc to bezpieczne) i dodaje kursor
           sugerujący klikalność.

           WAŻNE: kliknięcie przenosi PRAWDZIWĄ ramkę (.panel-zoom-moved,
           ten sam węzeł DOM, appendChild do <body> w JS) - nie ma tu
           żadnego duplikatu/cloneNode. Ramka dostaje realnie większe
           wymiary CSS (width/height w px, ustawiane z JS) zamiast
           transformu scale() - dzięki temu treść (canvasy, tekst)
           renderuje się od razu w docelowym rozmiarze, bez rozmycia
           charakterystycznego dla powiększania gotowego, już
           wyrenderowanego obrazu. Miejsce w kolumnie zajmuje w tym czasie
           placeholder (patrz openPanelZoom w JS).

           #panelZoomBackdrop to NIEWIDOCZNA (bez tła/przyciemnienia -
           świadoma decyzja, patrz historia zmian) warstwa-"łapacz
           kliknięć" pod przeniesioną ramką: klik w nią zamyka powiększenie,
           tak samo jak klik w samą ramkę (patrz openPanelZoom/closePanelZoom)
           albo klawisz Escape. */
        .panel-zoomable {
            /* !important konieczne: reguły #desyncPanel/#moonPhasePanel/
               #sunAltPanel/#legend/#earthPentagramPanel/#sunEclipticPanel
               ustawiają pointer-events:none selektorem PO ID, który ma
               wyższą specyficzność niż zwykła klasa - bez !important ta
               reguła by przegrywała i klik nigdy nie docierałby do ramki. */
            pointer-events: auto !important;
            cursor: zoom-in;
            transition: box-shadow 0.15s ease;
        }
        .panel-zoomable:hover {
            box-shadow: 0 0 0 1px #00d4e8aa, 0 0 18px 2px #00d4e833;
        }
        #panelZoomBackdrop {
            position: fixed;
            inset: 0;
            /* CELOWO poniżej #controls/#leftPanelsColumn/#rightPanelsColumn
               (z-index: 20) - patrz komentarz przy suwaku prędkości w JS
               (sekcja "4c-quater"): backdrop ma łapać kliknięcia TYLKO w
               pustą scenę 3D pod spodem (i w przezroczyste tło aktualnie
               powiększonej ramki), a nie zasłaniać sobą pasek sterowania
               (suwak prędkości) ani pozostałe ramki/przełączniki, które
               mają zostać klikalne również w trakcie powiększenia. Wciąż
               wystarczająco wysoko, by przykryć samą scenę 3D (bez
               jawnego z-index, więc efektywnie 0/auto) i każdy element bez
               własnego z-index. Sama powiększona ramka (#info.info-zoomed
               / .panel-zoom-moved) ma z-index: 200, więc i tak zawsze
               zostaje NAD backdropem, niezależnie od tej wartości. */
            z-index: 15;
            pointer-events: none;
        }
        #panelZoomBackdrop.active {
            pointer-events: auto;
        }
        /* Powiększona (przeniesiona na środek) ramka - position:fixed i
           wyśrodkowanie, ale BEZ scale(): szerokość/wysokość to zwykłe
           piksele CSS (ustawiane z JS w openPanelZoom na podstawie
           realnego rozmiaru ramki sprzed powiększenia razy
           PANEL_ZOOM_SCALE, przycięte do okna), więc canvasy i tekst w
           środku renderują się natywnie w tym większym rozmiarze zamiast
           być rozciągane. Krótka animacja wejścia/wyjścia (scale 0.92→1,
           opacity) zostaje - w spoczynku (stan ustalony, w którym ramka
           jest oglądana) transform to zawsze dokładnie
           translate(-50%,-50%) scale(1), więc nie rozmywa finalnego
           obrazu. */
        .panel-zoom-moved {
            position: fixed !important;
            top: var(--panel-zoom-y, 50%) !important;
            left: 50% !important;
            margin: 0 !important;
            z-index: 200 !important;
            cursor: zoom-out;
            pointer-events: auto;
            box-shadow: 0 0 50px 10px rgba(0, 212, 232, 0.35);
            transition: transform 0.22s ease, opacity 0.22s ease;
            transform: translate(-50%, -50%) scale(1);
            opacity: 1;
            /* Powiększona (przeniesiona na środek) ramka NIE ma dostawać
               rozmytego, półprzezroczystego tła (backdrop-filter blur) po
               ramkach bocznych - w dużym rozmiarze rozmycie sceny 3D pod
               spodem jest niepożądane. Tło zostaje takie samo (rgba(...)),
               tylko sam blur jest wyłączony dla stanu wyciągniętego na
               środek. */
            backdrop-filter: none !important;
            -webkit-backdrop-filter: none !important;
        }
        .panel-zoom-moved.panel-zoom-entering {
            opacity: 0;
        }
        .panel-zoom-moved.panel-zoom-moving {
            transition: transform 0.42s cubic-bezier(.22,.75,.24,1), opacity 0.24s ease;
            will-change: transform, opacity;
            transform-origin: center center;
        }
        #moonPhasePanel {
            padding: 10px 16px 14px;
            align-items: center;
            gap: 8px;
        }
        #moonPhasePanel .moonphase-title {
            color: #a8bcd0;
            white-space: nowrap;
            align-self: flex-start;
            flex: 0 0 auto;
        }
        /* Status okna poszukiwań sierpa nad wykresem: krótki i wyśrodkowany,
           bez dopisywania informacji typu „ocena aktywna”. */
        #moonPhasePanel #moonCriteriaWindowNote {
            align-self: stretch;
            width: 100%;
            box-sizing: border-box;
            white-space: nowrap;
            text-align: center;
        }
        #moonPhasePanel #moonCriteriaWindowNote.mc-window-inactive { color: #8a94a6; }
        #moonPhasePanel #moonCriteriaWindowNote.mc-window-active { color: #3ba55a; }
        #moonCriteriaStatusLabel.mc-status-inactive { color: #8a94a6; font-weight: bold; letter-spacing: 0.02em; }
        /* odeh-row/yallop-row: flex (nie zwykly inline tekst). UWAGA: te
           wiersze trzymaja juz TYLKO etykiete + diode ("kontrolke") -
           sam przelacznik (button.cal-toggle) zostal przeniesiony do
           #timeModeRow w gornej ramce kalendarza (#info), w jedna linie z
           przelacznikiem trybu czasu (patrz tam). justify-content:
           flex-start - kontrolka (etykieta + dioda) wyrównana do lewej
           krawędzi ramki, nie wyśrodkowana. white-space: normal (NIE
           nowrap) - pelna nazwa ("Widocznosc w/g Odeha/Yallopa") moze byc
           dluzsza niz szerokosc ramki, wiec przy waskiej ramce moze
           potrzebowac zlamania na 2 linie. */
        #moonPhasePanel .odeh-row {
            color: #a8bcd0;
            display: flex;
            align-items: center;
            justify-content: flex-start;
            gap: 10px;
            white-space: normal;
            align-self: stretch;
            flex: 0 0 auto;
        }
        .cal-row-label {
            display: inline-flex;
            align-items: center;
        }
        .odeh-led {
            display: inline-block;
            width: calc(15px * var(--pz-font-scale, 1));
            height: calc(15px * var(--pz-font-scale, 1));
            border-radius: 50%;
            background: #222222;
            border: 1px solid #555555;
            box-sizing: border-box;
            margin-left: 14px;
            flex: none;
            vertical-align: middle;
            transition: background-color 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
        }
        .odeh-led.on {
            background: #2ecc40;
            border-color: #2ecc40;
            box-shadow: 0 0 8px 2px #2ecc40aa;
        }
        #moonPhasePanel .yallop-row {
            color: #a8bcd0;
            display: flex;
            align-items: center;
            justify-content: flex-start;
            gap: 10px;
            white-space: normal;
            align-self: stretch;
            flex: 0 0 auto;
        }
        .yallop-led {
            display: inline-block;
            width: calc(15px * var(--pz-font-scale, 1));
            height: calc(15px * var(--pz-font-scale, 1));
            border-radius: 50%;
            background: #222222;
            border: 1px solid #555555;
            box-sizing: border-box;
            margin-left: 14px;
            flex: none;
            vertical-align: middle;
            transition: background-color 0.4s ease, border-color 0.4s ease, box-shadow 0.4s ease;
        }
        .yallop-led.on {
            background: #2ecc40;
            border-color: #2ecc40;
            box-shadow: 0 0 8px 2px #2ecc40aa;
        }
        .cal-toggle {
            display: inline-block;
            width: 34px;
            height: 18px;
            border-radius: 9px;
            background: #333333;
            border: 1px solid #555555;
            box-sizing: border-box;
            flex: none;
            padding: 0;
            position: relative;
            vertical-align: middle;
            cursor: pointer;
            /* Rodzice (#moonPhasePanel, #leftPanelsColumn) maja
               pointer-events: none (caly panel jest "przezroczysty" dla
               klikniec, zeby nie przeszkadzac w obracaniu kamera 3D pod
               spodem) - bez jawnego przywrocenia pointer-events tutaj,
               klikniecia w przelacznik przelatywalyby na wylot do canvasu
               i listener 'click' w JS nigdy by sie nie odpalal. */
            pointer-events: auto;
            transition: background-color 0.2s ease, border-color 0.2s ease;
        }
        .cal-toggle .cal-toggle-knob {
            position: absolute;
            top: 1px;
            left: 1px;
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #999999;
            transition: transform 0.2s ease, background-color 0.2s ease;
        }
        .cal-toggle.on {
            background: #2a5d34;
            border-color: #3ba55a;
        }
        .cal-toggle.on .cal-toggle-knob {
            transform: translateX(16px);
            background: #3ba55a;
        }
        .cal-toggle:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }
        #moonPhasePctLabel {
            font-weight: bold;
            font-size: 1.1em;
            color: #d8e4f0;
        }
        /* Wrapper centrujący canvas i chroniący jego proporcje 1:1 w dowolnej
           dostępnej przestrzeni – tak canvas bezpiecznie się przeskaluje
           niezależnie od wysokości/szerokości panelu. */
        .canvas-wrap {
            flex: 1 1 auto;
            min-height: 0;
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            overflow: hidden;
        }
        #moonPhaseCanvas {
            display: block;
            max-width: 100%;
            max-height: 100%;
            width: auto;
            height: auto;
            aspect-ratio: 1 / 1;
        }
        #sunAltCanvas {
            display: block;
            max-width: 100%;
            max-height: 100%;
            width: auto;
            height: auto;
        }
        #moonCriteriaCanvas {
            display: block;
            max-width: 100%;
            max-height: 100%;
            width: auto;
            height: auto;
            border-radius: 4px;
        }
        #moonCriteriaStatusLabel {
            color: #5ab8ccbb;
            white-space: normal;
            text-align: center;
            font-size: calc(12px * var(--pz-font-scale, 1));
            line-height: 1.35;
            flex: 0 0 auto;
        }
        /* W/ARCV są wspólne dla obu kryteriów (to współrzędne tego samego
           punktu na wykresie), więc stoją osobno nad tabelką porównawczą,
           zamiast być wymieszane z wartościami specyficznymi dla Odeha/Yallopa. */
        #moonCriteriaStatusLabel .mc-shared {
            margin-bottom: 4px;
        }
        /* Tabelka porównawcza Odeh/Yallop: KAŻDE kryterium to osobny .mc-row
           (flex), a nie wspólny grid po wszystkich elementach na raz - dzięki
           temu wiersz Odeh i wiersz Yallop zawsze lądują jeden pod drugim,
           NIEZALEŻNIE od tego, czy któryś ma 2 czy 3 elementy (np. gdy litera
           strefy jest ukryta poza oknem poszukiwań - patrz JS). Wspólny grid
           o ustalonej liczbie kolumn "pływałby" wtedy między wierszami. Stałe
           min-width na .mc-name/.mc-val wyrównuje kolumny (nazwa i wartość
           jednego kryterium stoją pod nazwą/wartością drugiego) tak samo jak
           poprzednio grid, tylko w sposób odporny na różną liczbę elementów.
           inline-flex + column, żeby cała tabelka jako całość wyśrodkowała
           się w panelu (dziedziczy text-align:center z rodzica), a wiersze
           w środku były wyrównane do lewej. */
        #moonCriteriaStatusLabel .mc-compare {
            display: inline-flex;
            flex-direction: column;
            align-items: flex-start;
            row-gap: 2px;
            font-family: 'Courier New', monospace;
        }
        #moonCriteriaStatusLabel .mc-row {
            display: flex;
            align-items: baseline;
            gap: 10px;
        }
        #moonCriteriaStatusLabel .mc-name {
            font-weight: bold;
            display: inline-block;
            min-width: 5.6em;
        }
        #moonCriteriaStatusLabel .mc-val {
            display: inline-block;
            min-width: 6.5em;
            text-align: left;
        }
        /* Kolory nazw kryteriów dopasowane do linii na wykresie powyżej:
           Odeh = zielona linia ciągła (granica strefy A), Yallop = żółta
           linia przerywana - dzięki temu etykieta i wykres używają tego
           samego kodu kolorystycznego. */
        /* Kolorowanie jest celowo ograniczone do nazwy kryterium i jego
           aktywnej strefy A. Wartości V/q pozostają neutralne. */
        #moonCriteriaStatusLabel .mc-row { color: #5ab8ccbb; }
        #moonCriteriaStatusLabel .mc-row .mc-name { color: #5ab8ccbb; }
        #moonCriteriaStatusLabel .mc-row.mc-on .mc-name { color: #3ba55a; }
        #moonCriteriaStatusLabel .mc-zone { color: #5ab8ccbb; }
        #moonCriteriaStatusLabel .mc-zone-active { color: #3ba55a !important; }
        /* mc-zone-bold: wyróżnienie litery strefy WYŁĄCZNIE na podstawie
           tego, czy to strefa A (niezależnie od tego, czy dane kryterium
           akurat bierze udział w wyznaczaniu Chodesz) - w odróżnieniu od
           mc-zone-active (KOLOR, patrz wyżej), które zależy też od
           calOdehEnabled/calYallopEnabled. Dzięki rozdzieleniu litera (A)
           jest wyróżniona zawsze, gdy wystąpi, a kolor sygnalizuje już
           tylko realny wpływ na decyzję.
           Zwykłe font-weight:bold (700) na monospace przy 12px jest w
           praktyce ledwo zauważalne (różnica grubości kreski to 1px),
           więc dla czytelnej różnicy używamy cięższej wagi (900) razem z
           lekkim powiększeniem i odstępem między literami - to właśnie
           ta kombinacja, nie sam font-weight, robi wyróżnienie faktycznie
           widocznym na pierwszy rzut oka. */
        #moonCriteriaStatusLabel .mc-zone-bold {
            font-weight: 900;
            font-size: 1.08em;
            letter-spacing: 0.02em;
        }
        #moonCriteriaStatusLabel .mc-val { color: #5ab8ccbb; }
        /* mc-line-sample: mała próbka linii (ciągła/przerywana) przy nazwie
           kryterium w tabelce Odeh/Yallop - dokładnie w tym samym stylu co
           linie na wykresie powyżej (patrz odehLineColor/yallopLineColor w
           drawMoonCriteriaChart), żeby od razu było jasne, która linia na
           wykresie odpowiada któremu kryterium. */
        #moonCriteriaStatusLabel .mc-line-sample {
            display: inline-block;
            width: 14px;
            height: 0;
            margin-right: 5px;
            border-top: 2px solid #3ba55a;
            vertical-align: middle;
        }
        #moonCriteriaStatusLabel .mc-line-sample.mc-line-yallop {
            border-top-style: dashed;
            border-top-color: #3ba55acc;
        }
        #moonPhaseNameLabel {
            color: #5ab8ccbb;
            white-space: nowrap;
            flex: 0 0 auto;
        }
        
        #sunAltPanel {
            padding: 10px 16px 14px;
            align-items: center;
            gap: 8px;
        }
        #sunAltPanel .sunalt-title {
            color: #ffe066;
            white-space: nowrap;
            align-self: flex-start;
            flex: 0 0 auto;
        }
        #sunAltDegLabel {
            font-weight: bold;
            font-size: 1.1em;
            color: #ffe066;
        }
        #sunAltPanel .moonalt-title {
            color: #a8bcd0;
            white-space: nowrap;
            align-self: flex-start;
            flex: 0 0 auto;
        }
        #moonAltDegLabel {
            font-weight: bold;
            font-size: 1.1em;
            color: #d8e4f0;
        }
        #sunAltPanel .venusalt-title {
            color: #ffd7c2;
            white-space: nowrap;
            align-self: flex-start;
            flex: 0 0 auto;
        }
        #venusAltDegLabel {
            font-weight: bold;
            font-size: 1.1em;
            color: #ffe9d6;
        }
        #sunAltStatusLabel {
            color: #5ab8ccbb;
            white-space: nowrap;
            flex: 0 0 auto;
        }
        #venusHelioSubLabel {
            color: #5ab8ccbb;
            font-size: calc(12px * var(--pz-font-scale, 1));
            text-align: center;
            max-width: 100%;
            line-height: 1.3;
            min-height: 1.3em;
            display: flex;
            align-items: center;
            justify-content: center;
            align-self: center;
            flex: 0 0 auto;
        }
        #earthPentagramPanel {
            color: #5ab8cc;
            background: #0a0a0a;
            padding: 10px 16px 14px;
            border-radius: 8px;
            border: 1px solid #00d4e844;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
            font-size: calc(13px * var(--pz-font-scale, 1));
            pointer-events: none;
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            min-width: 170px;
            /* Wypełnia dokładnie tyle miejsca w kolumnie, ile zostaje po ramce
               legendy (autoskalowanie wysokości). */
            flex: 1 1 0;
            min-height: 0;
            width: 100%;
        }
        #earthPentagramPanel .earthpentagram-title {
            color: #ffd7c2;
            align-self: flex-start;
            white-space: nowrap;
            font-size: calc(14px * var(--pz-font-scale, 1));
            flex: 0 0 auto;
        }
        #earthPentagramPanel .earthpentagram-pct {
            font-weight: bold;
            font-size: 1.1em;
            color: #ffe9d6;
        }
        #earthPentagramCanvas {
            display: block;
            max-width: 100%;
            max-height: 100%;
            width: auto;
            height: auto;
            aspect-ratio: 1 / 1;
        }
        #earthPentagramSubLabel {
            color: #5ab8ccbb;
            font-size: calc(12px * var(--pz-font-scale, 1));
            text-align: center;
            max-width: 100%;
            line-height: 1.3;
            min-height: 1.3em;
            display: flex;
            align-items: center;
            justify-content: center;
            align-self: center;
            flex: 0 0 auto;
        }
        #sunEclipticPanel {
            color: #5ab8cc;
            background: #0a0a0a;
            padding: 10px 16px 14px;
            border-radius: 8px;
            border: 1px solid #00d4e844;
            backdrop-filter: none;
            -webkit-backdrop-filter: none;
            font-size: calc(13px * var(--pz-font-scale, 1));
            pointer-events: none;
            box-sizing: border-box;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
            min-width: 170px;
            /* Wypełnia dokładnie tyle miejsca w kolumnie, ile zostaje po ramce
               legendy i ramce pentagramu Wenus (autoskalowanie wysokości,
               dzielone po równo z #earthPentagramPanel). */
            flex: 1 1 0;
            min-height: 0;
            width: 100%;
        }
        #sunEclipticPanel .sunecliptic-title {
            color: #ffe066;
            align-self: flex-start;
            white-space: nowrap;
            font-size: calc(14px * var(--pz-font-scale, 1));
            flex: 0 0 auto;
        }
        #sunEclipticPanel .sunecliptic-pct {
            font-weight: bold;
            font-size: 1.1em;
        }
        #sunEclipticCanvas {
            display: block;
            max-width: 100%;
            max-height: 100%;
            width: auto;
            height: auto;
        }
        #sunEclipticStatusLabel {
            color: #ffe066;
            font-size: calc(14px * var(--pz-font-scale, 1));
            text-align: left;
            align-self: flex-start;
            white-space: nowrap;
            flex: 0 0 auto;
        }
        #sunEclipticStatusLabel .sunecliptic-season {
            font-weight: bold;
            font-size: 1.1em;
        }
        #sunEclipticSubLabel {
            color: #5ab8ccbb;
            font-size: calc(12px * var(--pz-font-scale, 1));
            text-align: center;
            max-width: 100%;
            line-height: 1.3;
            min-height: 1.3em;
            display: flex;
            align-items: center;
            justify-content: center;
            align-self: center;
            flex: 0 0 auto;
        }
        
        /* NAPRAWA v2 (zgłoszenie: panele nadal puchły mimo flex-shrink/
           min-width/overflow z poprzedniej poprawki). Powód: #controls
           jest position:absolute; width:auto, więc przeglądarka liczy
           jego szerokość algorytmem "shrink-to-fit" na bazie PREFEROWANEJ
           (max-content) szerokości treści - a flex-shrink/min-width/
           overflow:hidden wpływają WYŁĄCZNIE na zachowanie przy braku
           miejsca, nie na to, ile miejsca element "chce" mieć, gdy go nie
           brakuje (a przy typowej szerokości okna nigdy nie brakuje).
           Jedyna właściwość, która realnie ogranicza wkład elementu do
           preferowanej szerokości rodzica, to max-width - stąd max-width
           niżej.

           NAPRAWA v3 (zgłoszenie: zawijanie linii licznika na 2-3 wiersze,
           wprowadzone w v2 jako obejście problemu wyżej, zostało cofnięte -
           w panelu sterowania linia MUSI zostać jednowierszowa, zero
           wyjątków). Zamiast łamać wiersz (white-space: normal),
           #timeDisplay wraca do white-space: nowrap, a dopasowanie do
           max-width odbywa się teraz przez ZMNIEJSZANIE CZCIONKI, nie
           przez zawijanie - trzy uzupełniające się środki:
             - etykiety jednostek skrócono do 3 liter (dni/tyg/mie/lat/sie/
               pen/jub) i zwężono separator między polami (patrz
               updateTimeDisplay() w JS),
             - font-family dostaje węższy, bardziej "kondensowany" stos
               fontów monospace (niżej) zamiast ogólnego 'monospace'
               odziedziczonego po <body>, a letter-spacing jest węższy niż
               poprzednio,
             - sam budżet max-width podniesiono z dawnych 480px do 900px
               (przy typowej szerokości ekranu 90-94vw nie ma znaczenia -
               ogranicza dopiero na węższych oknach/desktopach), bo przy
               realistycznych wartościach `t` (aplikacja pozwala swobodnie
               skakać o tysiące lat) sama skrócona linia i tak zwykle
               przekracza dawny limit - 480px wystarczało tylko na `t`
               bliskie zeru.
           Nawet po tych trzech zmianach `t` jest matematycznie
           nieograniczone (przyciski ±1000 lat można klikać w
           nieskończoność), więc same skróty/węższy font/szerszy budżet
           NIE dają twardej gwarancji jednowierszowości same w sobie. Tę
           gwarancję daje dopiero fitTimeDisplayFont() w JS (wołane z końca
           updateTimeDisplay()): po każdej zmianie treści mierzy naturalną
           (nieprzeskalowaną) szerokość linii i - TYLKO gdy przekracza
           dostępny max-width - zmniejsza zmienną CSS
           --time-display-scale, którą mnożą font-size i letter-spacing
           niżej. W typowym zakresie eksploracji (rzędu tysięcy-dziesiątek
           tysięcy lat) scale zostaje bliskie 1, czyli wygląda niemal
           dokładnie tak jak dotychczas; kurczy się zauważalnie dopiero
           przy naprawdę skrajnych skokach w czasie. overflow: hidden
           niżej to już czysto techniczne zabezpieczenie na wypadek, gdyby
           nawet przy minimalnej dozwolonej skali linia wciąż była za
           szeroka - w normalnym działaniu prawie nigdy się nie
           uaktywnia. */
        #timeDisplay {
            flex: 1 1 100%;
            min-width: 0;
            max-width: min(94vw, 900px);
            white-space: nowrap;
            overflow: hidden;
            order: -1;
            color: #3a7080;
            font-family: Consolas, 'SF Mono', Menlo, 'Liberation Mono', 'Courier New', monospace;
            font-size: calc(15px * var(--time-display-scale, 1));
            letter-spacing: calc(0.5px * var(--time-display-scale, 1));
            text-align: center;
            padding-bottom: 6px;
            margin-bottom: 6px;
            border-bottom: 1px solid #00d4e822;
            pointer-events: none;
        }
        .segment-label {
            color: #ffffff;
            font-weight: bold;
            text-shadow: 0 0 6px rgba(0, 0, 0, 0.9), 0 0 2px #000;
            pointer-events: none;
            user-select: none;
            font-family: monospace;
        }
        .segment-label.now-label {
            color: #ffe066;
            font-weight: 900;
            text-shadow: 0 0 9px #ffe066cc, 0 0 3px #000;
        }
        .center-label {
            font-weight: bold;
            font-family: monospace;
            text-align: center;
            line-height: 1.3;
            white-space: pre-line;
            text-shadow: 0 0 12px rgba(0, 212, 232, 0.4), 0 0 4px #000000cc;
            pointer-events: none;
            user-select: none;
        }
        /* Dyskretna linia autorska (wersja + pseudonim) pod głównym napisem
           "CZAS CYKLICZNY" - mniejsza, przygaszona (opacity), żeby wizualnie
           nie konkurowała z tytułem, ale była czytelna po zbliżeniu/screenie.
           font-size w em, więc skaluje się razem z resztą napisu (patrz
           centerLabelElement.style.fontSize w pętli animacji). */
        .center-label-address { display:block; font-weight:normal; font-size:1em; letter-spacing:0.3px; opacity:0.85; margin-top:3px; }
        .center-label-watermark {
            display: block;
            font-size: 1em;
            font-weight: normal;
            letter-spacing: 0.4px;
            opacity: 0.85;
            margin-top: 3px;
            pointer-events: auto;
            cursor: pointer;
            transition: opacity 0.2s ease, transform 0.2s ease, text-shadow 0.2s ease;
        }
        .center-label-watermark:hover {
            opacity: 1;
            transform: scale(1.08);
            text-shadow: 0 0 6px currentColor;
        }
        /* Link do dokumentacji - druga linia pod wersją/pseudonimem
           (.center-label-watermark), w tym samym centralnym polu
           pierścieni. Ta sama logika przygaszenia/skalowania co linia
           wyżej (opacity + em, żeby rosło/malało razem z resztą napisu
           przy zoomie), ale z wyraźnym stanem hover jak dawny #docsLink,
           bo to jedyny klikalny element w tym miejscu. */
        .center-label-docslink {
            display: block;
            font-size: 1em;
            font-weight: normal;
            letter-spacing: 0.3px;
            opacity: 0.85;
            margin-top: 4px;
            color: inherit;
            text-decoration: none;
            pointer-events: auto;
            cursor: pointer;
            transition: opacity 0.2s ease, text-shadow 0.2s ease;
        }
        .center-label-docslink:hover {
            opacity: 1;
            text-shadow: 0 0 6px currentColor;
        }
        /* Ikonka dokumentacji (obrazek z załącznika) zastępująca dawny
           tekst "📖 Dokumentacja". Wysokość w em, żeby skalowała się
           razem z resztą centralnego napisu (ten sam mechanizm co
           .center-label-watermark / .center-label-docslink powyżej). */
        .center-label-docs-icon {
            display: inline-block;
            height: 1.6em;
            width: auto;
            vertical-align: middle;
            filter: drop-shadow(0 0 4px currentColor);
            transition: filter 0.2s ease, transform 0.2s ease;
        }
        .center-label-docslink:hover .center-label-docs-icon {
            filter: drop-shadow(0 0 8px currentColor);
            transform: scale(1.08);
        }
        
        /* ===== POPRAWKA: brak poziomego overflow na mobile =====
           Diagnoza: #speedTrackWrap (min-width: 360px) i #timeDisplay
           (white-space: nowrap) rozszerzały #controls/#info ponad
           szerokość viewportu na wąskich ekranach (<= ok. 500px).
           Mobilna przeglądarka reagowała na to powiększeniem layout
           viewportu / poziomym scrollem, co przesuwało i ucinało
           warstwy position: fixed (#startupOverlay, #mobileWarnOverlay).
           Zamiast centrować #info/#controls przez left:50% +
           translateX(-50%) (co pozwala im "wystawać" poza ekran w obie
           strony), kotwiczymy je do krawędzi (left/right) z width: auto -
           wtedy fizycznie nie mogą przekroczyć viewportu, niezależnie od
           zawartości. Ta reguła musi być PO poprzednim bloku
           @media (max-width: 700px), żeby nadpisać min-width: 94vw na
           #info. */
        
        #startupOverlay {
            position: fixed;
            inset: 0;
            z-index: 9999;
            display: flex;
            align-items: center;
            justify-content: center;
            background: #0a0a0a;
            transition: opacity 0.4s ease;
        }
        #startupOverlay.hidden {
            opacity: 0;
            pointer-events: none;
        }
        #startupBox {
            text-align: center;
            font-family: monospace;
            color: #5ab8cc;
        }
        #startupSpinner {
            width: 40px;
            height: 40px;
            margin: 0 auto 18px;
            border-radius: 50%;
            border: 3px solid #0a4a58;
            border-top-color: #00d4e8;
            animation: startupSpin 0.9s linear infinite;
        }
        @keyframes startupSpin {
            to { transform: rotate(360deg); }
        }
        #startupTitle {
            font-size: 16px;
            font-weight: bold;
            color: #00d4e8;
            letter-spacing: 0.5px;
            margin-bottom: 8px;
        }
        #startupStage {
            font-size: 13px;
            color: #5ab8ccbb;
            min-height: 18px;
        }
        /* Modal z treścią warunków użytkowania - otwierany po kliknięciu w
           numer wersji obok logo (patrz .center-label-watermark w JS,
           funkcje showLicenseModal/hideLicenseModal). Kliknięcie w
           tło (poza oknem) lub w przycisk "×" zamyka modal; nic nie jest
           przy tym pobierane ani otwierane w nowej karcie. */
        #licenseModalOverlay {
            position: fixed;
            inset: 0;
            z-index: 10050;
            display: none;
            align-items: center;
            justify-content: center;
            background: rgba(0, 0, 0, 0.75);
            padding: 24px;
            box-sizing: border-box;
        }
        #licenseModalOverlay.visible {
            display: flex;
        }
        #licenseModalBox {
            position: relative;
            width: 100%;
            max-width: 640px;
            max-height: 82vh;
            overflow-y: auto;
            background: #0a0a0a;
            border: 1px solid #0a4a58;
            border-radius: 8px;
            padding: 26px 30px;
            font-family: monospace;
            color: #bfe9f2;
            box-shadow: 0 0 40px rgba(0, 212, 232, 0.18);
            box-sizing: border-box;
        }
        #licenseModalBox h2 {
            font-size: 18px;
            font-weight: bold;
            color: #00d4e8;
            letter-spacing: 0.3px;
            margin: 0 0 14px 0;
            padding-right: 24px;
        }
        #licenseModalText {
            white-space: pre-wrap;
            word-wrap: break-word;
            font-size: 15px;
            line-height: 1.6;
            margin: 0;
            font-family: monospace;
        }
        #licenseModalText a {
            color: #00d4e8;
            text-decoration: underline;
        }
        #licenseModalText a:hover {
            color: #bfe9f2;
        }
        #licenseModalClose {
            position: absolute;
            top: 8px;
            right: 10px;
            width: 30px;
            height: 30px;
            background: none;
            border: none;
            color: #5ab8cc;
            font-size: 22px;
            line-height: 1;
            cursor: pointer;
        }
        #licenseModalClose:hover {
            color: #00d4e8;
        }

        /* Modal informujący o braku wsparcia dla urządzeń mobilnych -
           patrz funkcja checkMobileWarning() niżej. Celowo NIE ma
           przycisku "×" ani zamykania kliknięciem w tło - jedyny sposób
           zamknięcia to świadome kliknięcie przycisku "Rozumiem", żeby
           komunikat nie zniknął przypadkowym dotknięciem. Warstwa wizualna
           spójna z #licenseModalOverlay/#licenseModalBox. */
        #mobileWarnOverlay {
            position: fixed;
            inset: 0;
            z-index: 10060;
            display: none;
            align-items: center;
            justify-content: center;
            background: rgba(0, 0, 0, 0.8);
            padding: 20px;
            box-sizing: border-box;
        }
        #mobileWarnOverlay.visible {
            display: flex;
        }
        #mobileWarnBox {
            width: 100%;
            max-width: 440px;
            max-height: 82vh;
            overflow-y: auto;
            background: #0a0a0a;
            border: 1px solid #6a4a0a;
            border-radius: 8px;
            padding: 22px 24px;
            font-family: monospace;
            color: #f0e0c0;
            box-shadow: 0 0 40px rgba(232, 160, 0, 0.16);
            text-align: center;
            box-sizing: border-box;
        }
        #mobileWarnBox .mobilewarn-icon {
            font-size: 34px;
            line-height: 1;
            margin-bottom: 10px;
        }
        #mobileWarnBox h2 {
            font-size: 17px;
            font-weight: bold;
            color: #f0b400;
            letter-spacing: 0.2px;
            margin: 0 0 12px 0;
        }
        #mobileWarnBox p {
            font-size: 14px;
            line-height: 1.6;
            margin: 0 0 10px 0;
        }
        /* Wiersz przycisków modala mobilnego - kolejność w HTML/wizualna:
           Dokumentacja, Rozumiem-kontynuuj, Wyjdź. flex-wrap na wypadek
           bardzo wąskich telefonów, gdzie 3 przyciski obok siebie by się
           nie zmieściły (patrz też ogólna poprawka overflow wyżej). */
        #mobileWarnButtons {
            display: flex;
            flex-wrap: wrap;
            justify-content: center;
            gap: 10px;
            margin-top: 14px;
        }
        #mobileWarnButtons .mobilewarn-btn {
            padding: 10px 20px;
            background: #1a1a1a;
            border-radius: 4px;
            font-family: monospace;
            font-size: 14px;
            font-weight: bold;
            cursor: pointer;
            text-decoration: none;
            display: inline-block;
            transition: background 0.15s, color 0.15s;
            box-sizing: border-box;
        }
        /* "Rozumiem, kontynuuj" - akcja domyślna/pozytywna, ten sam
           bursztynowy akcent co dotąd. */
        #mobileWarnAck {
            border: 1px solid #f0b400;
            color: #f0b400;
        }
        #mobileWarnAck:hover {
            background: #f0b400;
            color: #0a0a0a;
        }
        /* "Dokumentacja" - kolor zielony #3ecfbf zaczerpnięty z akcentu
           (--accent) używanego w pliku dokumentacji (docs/), żeby przycisk
           wizualnie zapowiadał docelową stronę. */
        #mobileWarnDocsLink {
            border: 1px solid #3ecfbf;
            color: #3ecfbf;
        }
        #mobileWarnDocsLink:hover {
            background: #3ecfbf;
            color: #0a0a0a;
        }
        /* "Wyjdź" - akcja destrukcyjna/kończąca, przygaszona, żeby nie
           konkurowała wizualnie z "Rozumiem" (to nie ma być domyślny wybór). */
        #mobileWarnExit {
            border: 1px solid #6a6a6a;
            color: #a0a0a0;
        }
        #mobileWarnExit:hover {
            background: #a0a0a0;
            color: #0a0a0a;
        }
        /* Stan po nieudanej próbie zamknięcia karty (patrz JS) - komunikat
           zastępujący przyciski, więc bez dodatkowego stylowania przycisku. */
        #mobileWarnExitNotice {
            margin-top: 14px;
            font-size: 13px;
            color: #a0a0a0;
        }

        /* Faza 2 (v3.40.x): pasek zakladek dla paneli analitycznych na
           telefonie. Domyslnie (desktop i kazda inna szerokosc) ukryty -
           pokazywany WYLACZNIE przez regule w css/mobile.css
           (@media max-width: 700px). Trzymane tutaj (a nie w mobile.css)
           z tego samego powodu co reszta base.css: to jest baza wspolna
           dla wszystkich szerokosci ekranu, mobile.css tylko nadpisuje. */
        #mobileTabBar {
            display: none;
        }
