/* Dok szczegółów statku w widoku trajektorii.
 *
 * Panel jest kolumną flex o wysokości ustawianej uchwytem (`detal-uchwyt`).
 * Żeby rozciągnięcie panelu powiększało WYKRES, a nie puste tło pod nim,
 * kontener zakładek i wszystko po drodze do wykresu musi przejąć pozostałą
 * wysokość. Inline'owe `style` tego nie załatwi: te węzły renderuje
 * dash-bootstrap-components i `dcc.Loading`, więc nie mamy do nich dostępu
 * z Pythona.
 *
 * Struktura sprawdzona w przeglądarce (`dbc.Tabs` NIE opakowuje się w żaden
 * dodatkowy element — nav i treść są bezpośrednimi dziećmi panelu):
 *
 *   #panel-detal
 *     div.d-flex           ← nagłówek (tytuł, przyciski)
 *     ul.nav.nav-tabs      ← paski zakładek
 *     div.tab-content
 *       div.tab-pane.active
 *         div > div > div  ← trzy anonimowe opakowania z dcc.Loading
 *           #detal-wykresy.dash-graph
 */

#panel-detal > .nav-tabs {
    flex-shrink: 0;
}

#panel-detal > .tab-content {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

#panel-detal > .tab-content > .tab-pane.active {
    height: 100%;
}

/* Trzy bezklasowe opakowania między zakładką a wykresem. Selektor po
 * strukturze, nie po klasach — `dcc.Loading` ich nie nadaje, a przypadkowe
 * trafienie w cudzy element ogranicza zakotwiczenie w `#panel-detal`. */
#panel-detal > .tab-content > .tab-pane.active > div,
#panel-detal > .tab-content > .tab-pane.active > div > div,
#panel-detal > .tab-content > .tab-pane.active > div > div > div {
    height: 100%;
}

/* Zakładki tekstowe (Anomalie / Statystyki / Dane) mają scrollować swoją
 * treść, a nie rozpychać panel. */
#detal-lista-anomalii,
#detal-statystyki,
#detal-dane {
    max-height: 100%;
    overflow-y: auto;
}

/* ── Lista statków obok mapy ───────────────────────────────────────────────
 *
 * Wierszy jest tyle, ile statków w analizie (2948 w paczce 500 MB) i wszystkie
 * są w DOM-ie, bo filtrowanie i sortowanie robi przeglądarka po atrybutach
 * `data-*`. Stąd te reguły: to, co powtarzalne, ma być raz w CSS, a nie
 * kilkanaście tysięcy razy w JSON-ie odpowiedzi.
 */
.anom-item {
    cursor: crosshair;
    /* Styl i układ liczony tylko dla wierszy, które faktycznie widać. Przy
     * ~2900 wierszach to najtańszy sposób, żeby lista nie kosztowała ~0,8 s
     * pracy przeglądarki przy każdym przerysowaniu — a wiersze ZOSTAJĄ w DOM-ie,
     * więc clientside'owe filtrowanie i podświetlanie działają jak dotąd.
     * `contain-intrinsic-size` podaje wysokość zastępczą, żeby pasek przewijania
     * nie skakał. */
    content-visibility: auto;
    contain-intrinsic-size: auto 34px;
}

/* `.anom-plain` usunięte razem z osobnym wariantem wiersza: statki bez
 * anomalii mają teraz DOKŁADNIE tę samą strukturę co pozostałe (nazwa,
 * ewentualne plakietki, linijka z danymi trasy i znacznik przeglądu).
 * Wcześniej były płaskim napisem, więc gubiły długość trasy, obszar i czas —
 * dane, które API zwraca dla wszystkich statków, nie tylko anomalnych. */

/* Pola liczbowe suwaka zakresu czasu.
 *
 * `dcc.RangeSlider` w tej wersji Dasha rysuje obok suwaka DWA pola liczbowe
 * z surowymi wartościami — a naszymi wartościami są sekundy epoki, więc
 * użytkownik widział „1775088000" i „1775101524". Nie ma na to właściwości
 * komponentu, a liczby są bez znaczenia dla człowieka (godzinę widać na osi
 * wykresu nad suwakiem), więc chowamy je stylem.
 *
 * Zawężone do TEGO suwaka: gdyby kiedyś doszedł inny, z sensownymi
 * jednostkami, ma prawo te pola pokazywać. */
#live-zakres-suwak .dash-range-slider-input {
    display: none;
}

/* Suwak zakresu ściśnięty w pionie.
 *
 * Selektor celuje w `.dash-slider-wrapper`, a NIE w `.rc-slider`: Dash 4 ma
 * własną implementację suwaka i klasy `rc-slider-*` w ogóle w niej nie
 * występują. Poprzednia wersja tej reguły nie pasowała do niczego — wyglądała
 * na działającą tylko dlatego, że pasek i tak jest niski.
 *
 * Górny panel jest w większości pustym miejscem, a każdy zabrany mu piksel
 * dostaje mapa. Tor zostaje pełnej szerokości, więc trafialność gałek się nie
 * zmienia. */
#live-zakres-suwak .dash-slider-wrapper {
    margin-top: -2px;
    padding: 4px 0;
}

/* Filtry ilościowe w panelu listy statków: relacja + wartość.
 *
 * Panel ma 300 px szerokości i konkuruje o nie z mapą, więc rozwijka relacji
 * musi być wąska (mieści dwa znaki), a pole na wartość brać całą resztę.
 * Bootstrapowa `input-group` sama z siebie rozdziela szerokość po równo. */
.filtr-ilosciowy .form-select,
.filtr-ilosciowy .form-control {
    font-size: 0.75rem;
    padding: 0.15rem 0.35rem;
}

/* Natywne strzałki chowamy — mają swoje ±1, którego nie da się przestawić,
 * a obok stoją nasze, chodzące po drabinie 1-2-5. Dwie pary strzałek robiące
 * co innego to gorsze rozwiązanie niż brak jednej z nich. */
.filtr-ilosciowy input[type=number]::-webkit-outer-spin-button,
.filtr-ilosciowy input[type=number]::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.filtr-ilosciowy input[type=number] {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Własny spinbox: dwa przyciski jeden nad drugim, w szerokości jednego znaku.
 * Panel ma 300 px i dzieli je z rozwijką relacji, polem i jednostką. */
.strzalki-filtra {
    display: flex;
    flex-direction: column;
    flex: 0 0 auto;
    border: 1px solid var(--bs-border-color, #dee2e6);
    border-left: 0;
}

.strzalki-filtra .krok-filtra {
    border: 0;
    background: #f8f9fa;
    color: #495057;
    font-size: 0.55rem;
    line-height: 1;
    padding: 0 0.25rem;
    flex: 1 1 50%;
    cursor: pointer;
}

.strzalki-filtra .krok-filtra:hover {
    background: #e9ecef;
    color: #212529;
}

/* Rozwijka relacji: same znaki „≥" / „≤" wyśrodkowane, bez miejsca na tekst.
 * Bootstrap rezerwuje po prawej ~1,5rem na strzałkę — przy tak wąskim polu
 * zjadałoby to cały znak, więc strzałkę przysuwamy do krawędzi. */
.filtr-ilosciowy .form-select {
    background-position: right 0.15rem center;
    padding-right: 0.95rem;
    padding-left: 0.4rem;
    text-align: center;
}

/* Wybór trybu cięcia: dwie możliwości OBOK SIEBIE, nie jedna pod drugą.
 *
 * Ułożone w pionie czytają się jak lista, w której pierwsza pozycja jest
 * domyślna, a druga to wariant. To nieprawda — „tylko punkty" i „całe trasy"
 * odpowiadają na dwa różne pytania i żadne z nich nie jest ważniejsze. Obok
 * siebie, o równej szerokości i wyśrodkowane pod przyciskiem, widać tę
 * równorzędność bez czytania.
 *
 * Szerokość musi być wymuszona w DWÓCH miejscach: `.popover` ma w Bootstrapie
 * `max-width: 276px`, a bez `min-width` obie kolumny ścisnęłyby się do treści.
 * Wyśrodkowanie pod celem daje samo `placement="bottom"`. */
.popover:has(.tryby-ciecia) {
    min-width: 34rem;
    max-width: 34rem;
}

/* Kropka legendy, która jest jednocześnie wyborem koloru.
 *
 * `input[type=color]` niesie własny wygląd przeglądarki: prostokąt z ramką
 * i wewnętrznym marginesem. Sprowadzamy go do kółka wielkości dawnej kropki,
 * żeby rząd przełączników wyglądał tak samo jak przedtem — zmienia się to,
 * co po kliknięciu, a nie to, co widać. */
.wybor-koloru.form-control,
.wybor-koloru {
    width: 0.9rem;
    height: 0.9rem;
    min-height: 0;
    padding: 0;
    border: 1px solid rgba(128, 128, 128, 0.6);
    border-radius: 50%;
    overflow: hidden;
    cursor: pointer;
}

.wybor-koloru::-webkit-color-swatch-wrapper { padding: 0; }
.wybor-koloru::-webkit-color-swatch { border: none; border-radius: 50%; }
.wybor-koloru::-moz-color-swatch { border: none; border-radius: 50%; }

/* Etykieta pozycji w `dcc.Dropdown` na PEŁNĄ szerokość.
 *
 * Dash zawija etykietę w `span.dash-options-list-option-text`, który domyślnie
 * dopasowuje się do treści — zmierzone: 109 px przy pozycji szerokiej na 281.
 * Etykieta z `justify-content-between` odmierzała więc prawą krawędź od końca
 * TEKSTU, a nie od krawędzi listy, i liczniki w filtrze typów stały schodkami
 * (prawe krawędzie 1371 / 1331 / 1315 zamiast jednej).
 *
 * Reguła jest globalna, bo popup rozwijki renderuje się poza drzewem samej
 * kontrolki i nie ma go jak zawęzić selektorem. Pozycjom z etykietą tekstową
 * pełna szerokość niczego nie zmienia. */
.dash-options-list-option-text {
    flex: 1 1 auto;
    min-width: 0;
}

/* Nazwana grupa kontrolek w pasku nad mapą.
 *
 * Przerywana, nie ciągła: to grupowanie elementów, które i tak leżą w tym samym
 * pasku, a nie osobny panel. Ciągła ramka czytałaby się jak druga warstwa
 * interfejsu. */
.sekcja-paska {
    /* `#adb5bd`, nie `--bs-border-color` (#dee2e6). Ta druga jest przewidziana
     * pod ramki CIĄGŁE, które i tak rysują pełną linię; kreskowana ma o połowę
     * mniej pikseli na tej samej długości i w tym odcieniu po prostu nie było
     * jej widać na jasnym tle panelu. */
    border: 1px dashed #adb5bd;
}

/* Sekcja jednego detektora w formularzu parametrów.
 *
 * Panel „⚙ Parametry detekcji" ma tło `bg-light`; sekcje na tym samym tle
 * zlewały się w jeden pas i przy kilku rozwiniętych naraz nie było widać,
 * gdzie kończy się jeden zestaw parametrów. Białe tło z ramką odgranicza je
 * bez dokładania nagłówków ani separatorów. */
.sekcja-detektora {
    background: #fff;
    border: 1px solid var(--bs-border-color, #dee2e6);
}

/* Zanikanie treści przy krawędziach przewijanego rzędu detektorów.
 *
 * Rząd jest przewijalny w poziomie, ale pasek przewijania bywa schowany do
 * zera pikseli (macOS, nakładkowe paski w Linuksie), więc nic nie mówiło,
 * że po prawej jest coś jeszcze. Maska wygasza kilkanaście pikseli treści przy
 * tej krawędzi, po której faktycznie da się przewinąć — klasy `ma-lewo`
 * i `ma-prawo` dokłada `podepnijZanikanie` w `assets/anomais.js`.
 *
 * `mask-image` na OPAKOWANIU, nie na elemencie przewijanym: maska nałożona na
 * ten drugi przesuwałaby się razem z treścią i wygaszała zawsze te same
 * punkty zawartości zamiast krawędzi okna. */
.rzad-detektorow {
    --wygaszenie: 1.5rem;
}

.rzad-detektorow.ma-prawo {
    mask-image: linear-gradient(to right, #000 calc(100% - var(--wygaszenie)), transparent 100%);
}

.rzad-detektorow.ma-lewo {
    mask-image: linear-gradient(to right, transparent 0, #000 var(--wygaszenie));
}

.rzad-detektorow.ma-lewo.ma-prawo {
    mask-image: linear-gradient(to right, transparent 0, #000 var(--wygaszenie),
                #000 calc(100% - var(--wygaszenie)), transparent 100%);
}

.tryby-ciecia .btn {
    border: 1px solid #dee2e6;
}

.tryby-ciecia .btn:hover {
    border-color: #0d6efd;
}

/* ── Znacznik „przejrzane" na kafelku statku ─────────────────────────────────
   Jednocześnie stan i przełącznik: pusty okrąg = nieprzejrzany, wypełniony
   z ptaszkiem = przejrzany. Osobny przycisk obok kropki znaczyłby dwa elementy
   na to samo, a przy 3372 wierszach każdy dodatkowy węzeł kosztuje.

   `flex-shrink: 0` — wiersz z długą nazwą statku ściskał znacznik do zera. */
.znacznik-przegladu {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.05rem;
    height: 1.05rem;
    margin-left: 0.4rem;
    flex-shrink: 0;
    border: 1px solid #b9c2cc;
    border-radius: 50%;
    font-size: 0.6rem;
    line-height: 1;
    color: transparent;      /* ptaszek niewidoczny, dopóki nieoznaczony */
    cursor: pointer;
    user-select: none;
    transition: background-color .1s, color .1s, border-color .1s;
}
.znacznik-przegladu:hover {
    border-color: #0d6efd;
    color: #adb5bd;          /* podpowiedź, co się stanie po kliknięciu */
}
[data-przejrzany="1"] .znacznik-przegladu {
    background: #198754;
    border-color: #198754;
    color: #fff;
}
/* Przejrzany wiersz przygaszony — lista ma pokazywać, ile pracy ZOSTAŁO,
   a nie ile jej wykonano. Nie chowamy go: od tego jest filtr grupy. */
[data-przejrzany="1"] {
    opacity: 0.55;
}
[data-przejrzany="1"]:hover {
    opacity: 1;
}
/* Zakładki grupy przeglądu na górze kolumny ze statkami.
   Trzy etykiety („wszystkie", „nieprzejrzane", „przejrzane") nie mieszczą się
   w 300 px przy domyślnym rozmiarze Bootstrapa — zawijają się do dwóch rzędów
   i podwajają wysokość paska. Stąd mniejszy font i ciaśniejszy padding;
   `flex: 1 1 0` rozkłada je równo, więc pasek wygląda jak jeden element,
   a nie jak trzy przyciski różnej długości. */
.przeglad-zakladki {
    flex-wrap: nowrap;
}
/* Szerokość WEDŁUG TREŚCI, nie równe trzecie. Po dopisaniu liczników
   najdłuższa etykieta („nieprzejrzane (518)") przestała się mieścić w jednej
   trzeciej z 300 px i aktywna zakładka pokazywała „nieprzeirzane …" — czyli
   ucięte słowo, które wygląda na błąd, a nie na skrót. Bez `ellipsis`
   ewentualne przepełnienie będzie widoczne zamiast ciche. */
.przeglad-zakladki .nav-item {
    flex: 0 1 auto;
    min-width: 0;
}
.przeglad-zakladki .nav-link {
    padding: 0.25rem 0.35rem;
    font-size: 0.68rem;
    white-space: nowrap;
}

/* Gesty na mapie należą do mapy, nie do strony.

   Na ekranie dotykowym pinch bez tej deklaracji powiększa CAŁĄ stronę:
   przeglądarka stosuje domyślne zachowanie dotyku, bo nikt jej nie powiedział,
   że element pod palcem sam obsłuży gest. `manipulation` zostawia przewijanie
   i stuknięcie, a odbiera wyłącznie gesty powiększania oraz podwójne stuknięcie
   (którym mapa i tak zoomuje sama).

   Trackpadowego pincha to NIE dotyczy — tamten przychodzi jako `wheel`
   z `ctrlKey` i wymaga nasłuchu nie-pasywnego, patrz `_pilnujGestow`
   w `anomais.js`. Obie drogi trzeba obsłużyć osobno, bo są to dwa różne
   mechanizmy przeglądarki prowadzące do tego samego objawu. */
#map-live {
    touch-action: manipulation;
}
