/*
 * Warstwa własna na Tablerze — tylko to, czego Tabler nie daje.
 *
 * Zasada: jeśli coś da się zrobić klasą Tablera, robimy to klasą Tablera.
 * Ten plik ma zostać krótki, bo każda linijka tutaj to reguła, którą ktoś
 * kiedyś będzie musiał pogodzić z aktualizacją frameworka.
 *
 * (Było tu `body { background-color: skyblue }` — resztka szkieletu
 * z instalatora Symfony.)
 */

/* Pasek koloru kręgu przy wierszu listy — węższy niż badge, czytelny
   z odległości, nie zabiera szerokości tabeli. */
.krag-pasek {
    display: inline-block;
    width: .25rem;
    min-height: 1.4rem;
    border-radius: 1rem;
    background: var(--tblr-border-color);
    vertical-align: middle;
}

/* Karta rodziny: dane turnusowe mają być rozróżnialne od trwałych
   bez czytania nagłówków. */
.dane-turnusowe {
    border-left: 3px solid var(--tblr-primary);
}

/* Pusta wartość w karcie — kreska zamiast pustki, żeby było widać,
   że pole istnieje i czeka na uzupełnienie. */
.brak-danych {
    color: var(--tblr-secondary);
}

/*
 * Tablica podziału na kręgi.
 *
 * Problem, który to rozwiązuje: przy dwudziestu rodzinach lista
 * nieprzydzielonych jest dłuższa niż ekran. Kto przewinął do ostatniej
 * rodziny, miał kolumny kręgów gdzieś nad górną krawędzią i nie było
 * gdzie upuścić.
 *
 * Stąd dwa panele, każdy z własnym przewijaniem: strona jako całość
 * prawie nie rośnie, więc cel upuszczenia jest widoczny bez względu na to,
 * jak daleko w liście się zeszło. Na wąskim ekranie panele wracają
 * do układu jeden pod drugim — tam przewija się palcem i sticky
 * przeszkadzałby bardziej, niż pomagał.
 */
.tablica-lista {
    /* Pusta strefa musi zostać widocznym celem upuszczenia, ale pięć
       centymetrów pustki przy trzech kolumnach to pół ekranu niczego.
       Tyle wystarczy, żeby trafić palcem i myszą. */
    min-height: 2.5rem;
}

/* Nazwa rodziny nie zawija się na drugą linię — kolumna kręgu jest wąska,
   a wiersz ma zostać jednolinijkowy. */
.krag-rodzina {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

@media (min-width: 992px) {
    .tablica-kregow {
        display: grid;
        grid-template-columns: minmax(15rem, 21rem) 1fr;
        gap: 1rem;
        align-items: start;
    }

    .tablica-nieprzydzieleni {
        position: sticky;
        top: 1rem;
    }

    .tablica-lista {
        max-height: calc(100vh - 17rem);
        overflow-y: auto;
    }
}

/*
 * Nagłówek grupy w menu bocznym.
 *
 * Kilkanaście pozycji jedna pod drugą to lista, nie menu — dopiero
 * nagłówki mówią, które z nich należą do siebie i w jakiej kolejności
 * się te rzeczy robi.
 */
.menu-sekcja {
    padding: .45rem 1.25rem .1rem;
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--tblr-secondary);
}

.menu-sekcja:first-child { padding-top: .2rem; }

/* Logo w menu — przygaszone, żeby nie konkurowało z pozycjami, do
   których się je klika. */
.logo-panelu {
    width: 2rem;
    height: auto;
}

/* Ikona zachowuje się jak litera obok podpisu: skaluje się z tekstem
   i bierze jego kolor, więc nie trzeba jej osobno stroić do motywu. */
.menu-ikona {
    width: 1.15rem;
    height: 1.15rem;
    flex: none;
}

/*
 * Czytelność pozycji menu.
 *
 * Domyślny odstęp Tablera jest policzony pod menu poziome, gdzie pozycje
 * stoją obok siebie. W pionie kilkanaście wierszy jeden pod drugim zlewa
 * się w ścianę tekstu — stąd wyraźniejszy kolor i zaokrąglenie, po którym
 * widać, gdzie kończy się klikalny obszar. Odstęp pionowy zostaje ciasny:
 * przy kilkunastu pozycjach liczy się, ile mieści się bez przewijania.
 */
.navbar-vertical .nav-link {
    display: flex;
    align-items: center;
    gap: .55rem;
    padding: .05rem .75rem;
    margin: 0 .5rem;
    border-radius: .375rem;
    color: var(--tblr-body-color);
    line-height: 1.15;
}

/* Zwarte wiersze. Tabler daje kazdej pozycji min-height 2.5rem i padding
   .5rem selektorem `.navbar-expand-lg .navbar-collapse .navbar-nav
   .nav-link` — silniejszym niz reguła wyzej, wiec jej ciasny odstep nigdy
   nie dzialal i menu rozjezdzalo sie na cały ekran. Stąd selektor o pieciu
   klasach: przebija tamten i nie zależy od kolejnosci arkuszy. */
.navbar-vertical.navbar-expand-lg .navbar-collapse .navbar-nav .nav-link {
    min-height: 1.75rem;
    padding: .15rem .75rem;
}

.navbar-vertical .nav-link:hover {
    background: var(--tblr-bg-surface-secondary);
}

.navbar-vertical .nav-link-icon {
    display: inline-flex;
    opacity: .6;
}

.navbar-vertical .nav-item.active > .nav-link .nav-link-icon { opacity: 1; }

/* Pozycja aktywna ma być widoczna z drugiego końca pokoju — Tabler
   zaznacza ją samą krawędzią, co przy kilkunastu pozycjach ginie. */
.navbar-vertical .nav-item.active > .nav-link {
    background: var(--tblr-primary-lt);
    color: var(--tblr-primary);
    font-weight: 600;
}

/*
 * Panel użytkownika na dole menu.
 *
 * Osobny kafel, oddzielony krawędzią: to jedyne miejsce w menu, które nie
 * prowadzi do ekranu, tylko mówi, kto jest zalogowany — i pozwala wyjść.
 */
.menu-uzytkownik {
    padding: .6rem .75rem;
    border-top: 1px solid var(--tblr-border-color);
}

.menu-wspolnota {
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--tblr-secondary);
    margin-bottom: .4rem;
}

.menu-awatar {
    flex: none;
    width: 2rem;
    height: 2rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--tblr-primary-lt);
    color: var(--tblr-primary);
    font-size: .75rem;
    font-weight: 600;
}

/* Nazwa i adres ucinają się wielokropkiem — długi mail nie ma prawa
   rozepchnąć menu ani zepchnąć przycisku wylogowania poza krawędź. */
.menu-kto,
.menu-mail {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.menu-kto { font-size: .85rem; font-weight: 500; }
.menu-mail { font-size: .7rem; color: var(--tblr-secondary); }

/* Bootstrapowy flex nie skróci dziecka poniżej jego treści bez tego. */
.min-w-0 { min-width: 0; }

/* Stopka menu (wspólnota, użytkownik, wylogowanie) siada na dole,
   a lista pozycji przewija się nad nią.
   Kluczowe jest `min-height: 0` na elementach flex: bez tego lista nie
   daje się skrócić poniżej swojej treści i wypycha stopkę pod krawędź
   ekranu — czyli dokładnie tam, gdzie nie da się jej kliknąć. */
/* Poniższe display:flex MUSI zostać w media query: bez tego ograniczenia
   biło się z `.collapse:not(.show){display:none}`, które ma chować menu
   na wąskim ekranie — ta sama specyficzność, a ta reguła szła PO
   Tablerze, więc wygrywała. Efekt: menu boczne zajmowało cały ekran nad
   treścią, niezależnie od szerokości, i trzeba było przewinąć kilkanaście
   pozycji, zanim cokolwiek było widać na telefonie. */
@media (min-width: 992px) {
    .navbar-vertical > .container-fluid {
        height: 100%;
        align-items: stretch;
    }

    .navbar-vertical .navbar-collapse {
        display: flex;
        flex-direction: column;
        flex: 1 1 auto;
        min-height: 0;
    }

    .navbar-vertical .navbar-nav {
        flex: 1 1 auto;
        min-height: 0;
        overflow-y: auto;
    }
}

/* Ślad po przeciąganym elemencie — musi być widoczny także na kolumnie,
   która akurat jest przewinięta. */
.tablica-lista .sortable-ghost {
    outline: 2px dashed var(--tblr-primary);
    outline-offset: -2px;
}

/*
 * Zwarta lista słownikowa z edycją rozwijaną w miejscu.
 *
 * Powód: to jest ekran ustawień, na który zagląda się raz na turnus, żeby
 * poprawić jedną wartość. Rozłożone formularze wszystkich pozycji naraz
 * robiły z dwudziestu wierszy dwa metry strony i nie dało się przebiec
 * listy wzrokiem. Teraz wiersz to jedna linia, a formularz otwiera się
 * pod tym, co się klika.
 */
.slownik-wiersz {
    border-bottom: 1px solid var(--tblr-border-color);
}

.slownik-wiersz > summary {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .35rem .75rem;
    cursor: pointer;
    list-style: none;
}

.slownik-wiersz > summary::-webkit-details-marker { display: none; }

.slownik-wiersz > summary::before {
    content: "▸";
    flex: none;
    width: .7rem;
    color: var(--tblr-secondary);
    font-size: .7rem;
}

.slownik-wiersz[open] > summary::before { content: "▾"; }
.slownik-wiersz > summary:hover { background: var(--tblr-bg-surface-secondary); }
.slownik-wiersz[open] > summary { background: var(--tblr-bg-surface-secondary); }

.slownik-kropka {
    flex: none;
    width: .25rem;
    height: 1.1rem;
    border-radius: 1rem;
}

/* Nazwa zabiera całą wolną szerokość i ucina się wielokropkiem, żeby
   opisowe pozycje nie zawijały wiersza na dwie linie. */
.slownik-nazwa {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.slownik-meta {
    flex: none;
    color: var(--tblr-secondary);
    font-size: .8rem;
    white-space: nowrap;
}

/* Opis bierze tyle miejsca, ile zostanie, i ucina się wielokropkiem —
   pełną treść widać po rozwinięciu wiersza. */
.slownik-opis {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.slownik-opis + .slownik-nazwa,
.slownik-nazwa:has(+ .slownik-opis) { flex: 0 1 auto; }

/* Stała szerokość, żeby czasy tworzyły kolumnę, a nie schodki. */
.slownik-czas {
    width: 4.5rem;
    text-align: right;
}

.slownik-edycja {
    padding: .5rem .75rem .75rem 1.95rem;
    background: var(--tblr-bg-surface-secondary);
}

/* ── Galeria (panel) ─────────────────────────────────────────────── */
.galeria-siatka {
    display: grid;
    gap: .75rem;
    grid-template-columns: repeat(auto-fill, minmax(9.5rem, 1fr));
}

.galeria-kafelek img,
.galeria-wideo-ikona {
    aspect-ratio: 1;
    background: var(--tblr-bg-surface-secondary);
    border-radius: .4rem;
    display: flex;
    object-fit: cover;
    width: 100%;
}

.galeria-wideo-ikona {
    align-items: center;
    color: var(--tblr-body-color-secondary);
    font-size: 2rem;
    justify-content: center;
}

/* Z miniaturą (klatka wyciągnięta ffmpeg-iem) ikona to mały znaczek na
   środku kafelka, nie całe tło — inaczej miniatury by nie było widać. */
.galeria-kafelek a { display: block; position: relative; }
.galeria-kafelek-wideo:has(img) .galeria-wideo-ikona {
    aspect-ratio: auto;
    background: rgba(0,0,0,.5);
    border-radius: 50%;
    color: #fff;
    height: 2.2rem;
    inset: 0;
    margin: auto;
    position: absolute;
    width: 2.2rem;
}

.galeria-kafelek-meta { margin-top: .35rem; }

/* Zatwierdź/odrzuć/obróć/główny — wszystkie w jednej linijce pod
   kafelkiem, stąd same ikony i przycięty padding (kafelek ma tylko
   9.5rem szerokości, patrz .galeria-siatka). */
.galeria-akcje {
    display: flex;
    flex-wrap: nowrap;
    gap: .25rem;
    margin-top: .35rem;
}
.galeria-akcje form { flex: none; }
.galeria-akcje .btn {
    padding-left: .4rem;
    padding-right: .4rem;
}

/* Checkbox do masowego zatwierdzania — róg kafelka, nad miniaturą. */
.galeria-kafelek { position: relative; }
.galeria-zaznacz-otoczka {
    background: rgba(255,255,255,.85);
    border-radius: .3rem;
    cursor: pointer;
    left: .3rem;
    line-height: 0;
    padding: .15rem;
    position: absolute;
    top: .3rem;
    z-index: 2;
}
.galeria-zaznacz { cursor: pointer; height: 1.1rem; margin: 0; width: 1.1rem; }

/* Po zapisaniu formularza (podpis, obrót, zatwierdzenie...) wracamy pod
   kotwicę tej samej pozycji/karty, zamiast na sam początek strony —
   GalleryController::back(). Odstęp, żeby kafelek nie był styk w styk
   z górną krawędzią ekranu. */
[id^="galeria-poz-"],
#galeria-dodaj-karta,
#galeria-widok-karta,
#galeria-udostepnianie-karta {
    scroll-margin-top: 1rem;
}

.galeria-podsekcja {
    color: var(--tblr-body-color-secondary);
    font-size: .78rem;
    font-weight: 700;
    margin: 0 0 .5rem;
    text-transform: uppercase;
}

.galeria-glowny-znacznik {
    bottom: .3rem;
    left: .3rem;
    position: absolute;
}

/* Licznik wyświetleń — ciemna odznaka z białymi cyframi w rogu miniatury. */
.galeria-wyswietlenia {
    background: rgba(0,0,0,.65);
    border-radius: .3rem;
    color: #fff;
    font-size: .7rem;
    line-height: 1;
    padding: .2rem .35rem;
    position: absolute;
    right: .3rem;
    top: .3rem;
}

.slownik-edycja .form-label {
    margin-bottom: .15rem;
    font-size: .75rem;
    color: var(--tblr-secondary);
}

/* Wąski ekran: metryki schodzą pod nazwę, zamiast ściskać ją do zera. */
@media (max-width: 575px) {
    .slownik-wiersz > summary { flex-wrap: wrap; }
    .slownik-nazwa { flex: 1 0 100%; }
    .slownik-czas { width: auto; text-align: left; }
}

/* Ramka z podglądem wydruku. Wysokość ustawiona sztywno, bo iframe
   z innego dokumentu nie potrafi urosnąć do swojej treści — a strona A4
   jest wysoka i zwijanie jej do 150 px nie byłoby podglądem. */
.vademecum-podglad,
.wydruk-podglad {
    display: block;
    width: 100%;
    height: calc(100vh - 14rem);
    min-height: 30rem;
    border: 0;
    background: #fff;
}

/*
 * Wykaz melodii Jutrzni.
 *
 * Układ trójdzielny: co śpiewamy — czym to zagrać — co z tym zrobić.
 * Odtwarzacz ma stałą szerokość, żeby przyciski „play" stały w jednej
 * kolumnie; przy trzydziestu pozycjach to jest różnica między listą
 * a bałaganem.
 */
.melodie-czesc {
    border-top: 1px solid var(--tblr-border-color);
}

.melodie-naglowek {
    padding: .5rem .75rem .25rem;
    background: var(--tblr-bg-surface-secondary);
}

.melodie-tytul {
    font-weight: 600;
    text-transform: uppercase;
    font-size: .75rem;
    letter-spacing: .03em;
}

.melodie-podpowiedz {
    display: block;
    color: var(--tblr-secondary);
    font-size: .8rem;
}

.melodia {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .4rem .75rem;
    border-top: 1px solid var(--tblr-border-color);
}

.melodia-opis {
    flex: 1 1 auto;
    min-width: 0;
}

.melodia-nazwa {
    font-weight: 500;
}

.melodia-odtwarzacz {
    flex: none;
    width: 15rem;
    height: 2rem;
}

.melodia-jutrznia {
    flex: none;
    font-size: .8rem;
    white-space: nowrap;
}

.melodia-akcje {
    flex: none;
}

@media (max-width: 767px) {
    .melodia { flex-wrap: wrap; }
    .melodia-opis { flex: 1 0 100%; }
    .melodia-odtwarzacz { width: 100%; }
}

/*
 * Kreator planu dnia — siatka doby i klocki na niej.
 *
 * Cała geometria stoi na jednej zmiennej: --minuta, czyli ile pikseli ma
 * minuta. Blok dostaje --start (minuty od północy) i --ile (czas trwania),
 * resztę liczy przeglądarka. Dzięki temu powiększenie siatki to podmiana
 * jednej wartości, a nie przeliczanie wszystkich pozycji w javascripcie.
 */
.kreator {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
    align-items: start;
}

@media (min-width: 992px) {
    .kreator {
        grid-template-columns: minmax(14rem, 19rem) 1fr;
    }

    .kreator-bok {
        position: sticky;
        top: 1rem;
    }
}

/* Panel parametrów wybranego punktu dostaje własną, prawą kolumnę —
   tej samej szerokości co paleta po lewej — żeby siatka zostawała
   na środku i nie skakała w bok za każdym kliknięciem klocka. */
@media (min-width: 1400px) {
    .kreator.z-panelem {
        grid-template-columns: minmax(14rem, 19rem) 1fr minmax(14rem, 19rem);
    }

    .kreator-prawy {
        position: sticky;
        top: 1rem;
    }
}

.kreator-paleta {
    max-height: 26rem;
    overflow-y: auto;
}

/* Karta rozwijana bez javascriptu. Własna strzałka zamiast systemowego
   znacznika, bo ten w nagłówku karty Tablera raz się pokazuje, a raz nie. */
.kreator-rozwijane > summary {
    cursor: pointer;
    list-style: none;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.kreator-rozwijane > summary::-webkit-details-marker { display: none; }

.kreator-rozwijane > summary::after {
    content: "▾";
    color: var(--tblr-secondary);
    font-size: .8rem;
}

.kreator-rozwijane:not([open]) > summary::after { content: "▸"; }

.klocek-palety {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .5rem;
    padding: .3rem .5rem;
    margin-bottom: .25rem;
    border-radius: .25rem;
    border-left: 3px solid currentColor;
    background: var(--tblr-bg-surface-secondary);
    cursor: grab;
    touch-action: none;
    font-size: .875rem;
}

.klocek-palety:active { cursor: grabbing; }
.klocek-nazwa { color: var(--tblr-body-color); }
.klocek-ile { color: var(--tblr-secondary); font-size: .75rem; white-space: nowrap; }

/* Plansza przewija się sama — dzień od 6:00 do 22:00 nie mieści się
   na ekranie, a paleta ma zostać w zasięgu ręki. */
.kreator-plansza {
    max-height: calc(100vh - 16rem);
    overflow-y: auto;
}

.siatka {
    --minuta: 1.1px;
    --os: 3.25rem;

    position: relative;
    height: calc(var(--minut) * var(--minuta));
    padding-left: var(--os);
    user-select: none;
    touch-action: none;
}

.siatka-godzina {
    position: absolute;
    left: 0;
    top: calc((var(--start) - var(--od)) * var(--minuta));
    width: var(--os);
    padding-right: .35rem;
    text-align: right;
    font-size: .7rem;
    line-height: 1;
    color: var(--tblr-secondary);
    transform: translateY(-.35em);
}

/* Linie siatki rysują się na POLU, a nie na całej planszy — inaczej
   wchodzą pod podpisy godzin i utrudniają odczytanie tego, co mają
   objaśniać. Pełna godzina mocniej, kwadranse słabiej, kratka co 5 minut
   ledwo widocznie: ma podpowiadać, do czego przyskakuje klocek, a nie
   robić z planszy kartki w kratkę. */
.siatka-pole {
    position: relative;
    height: 100%;
    margin-right: .5rem;

    background-image:
        repeating-linear-gradient(to bottom,
            var(--tblr-border-color) 0 1px, transparent 1px calc(60 * var(--minuta))),
        repeating-linear-gradient(to bottom,
            rgba(128, 128, 128, .25) 0 1px, transparent 1px calc(15 * var(--minuta))),
        repeating-linear-gradient(to bottom,
            rgba(128, 128, 128, .1) 0 1px, transparent 1px calc(5 * var(--minuta)));
}

.blok {
    position: absolute;
    left: calc(var(--pas, 0) * var(--szer, 100%));
    width: var(--szer, 100%);
    top: calc((var(--start) - var(--od)) * var(--minuta));

    /* Blok pięciominutowy ma pięć pikseli wysokości i nie da się go złapać.
       Dolna granica jest po to, żeby najkrótszy punkt programu dało się
       przeczytać i chwycić — także ten „bez końca", który ma --ile: 0. */
    height: max(1.6rem, calc(var(--ile) * var(--minuta)));

    overflow: hidden;
    border-radius: .25rem;
    border-left: 3px solid currentColor;
    background: var(--tblr-bg-surface);
    box-shadow: inset 0 0 0 1px var(--tblr-border-color);
    cursor: grab;
    touch-action: none;
}

.blok:focus-visible {
    outline: 2px solid var(--tblr-primary);
    outline-offset: 1px;
}

.blok.jest-wybrany {
    box-shadow: inset 0 0 0 2px var(--tblr-primary);
    z-index: 3;
}

.blok.w-ruchu {
    cursor: grabbing;
    opacity: .85;
    z-index: 5;
    box-shadow: 0 .25rem .75rem rgba(0, 0, 0, .25);
}

/* Klocek bez końca to punkt na osi, nie prostokąt — „13:30 Obiad".
   Przerywana dolna krawędź mówi, że koniec nie został ustalony. */
.blok[data-ile=""] {
    border-bottom: 1px dashed var(--tblr-border-color);
    background-image: linear-gradient(to bottom, var(--tblr-bg-surface) 60%, transparent);
}

.blok-tresc {
    padding: .1rem .4rem;
    font-size: .75rem;
    line-height: 1.2;
    pointer-events: none;
}

/* Krótki klocek — „13:30 Obiad" albo kwadrans apelu — nie zmieści godzin
   i nazwy jeden pod drugim. Kładziemy je w jednej linii, zamiast przycinać
   nazwę w połowie. */
.blok-krotki .blok-tresc {
    display: flex;
    align-items: baseline;
    gap: .35rem;
    white-space: nowrap;
}

.blok-krotki .blok-znaki { display: none; }

.blok-godziny { color: var(--tblr-secondary); font-size: .7rem; }
.blok-tytul { font-weight: 600; color: var(--tblr-body-color); }
.blok-znaki { color: var(--tblr-secondary); font-size: .7rem; }

.blok-uchwyt {
    position: absolute;
    left: 0;
    right: 0;
    height: .5rem;
    cursor: ns-resize;
}

.blok-uchwyt-gora { top: 0; }
.blok-uchwyt-dol { bottom: 0; }

/* Krzyżyk pokazuje się dopiero pod kursorem albo przy klawiaturze —
   na planie z kilkunastoma punktami stały rząd krzyżyków byłby
   głośniejszy niż sam plan. */
.blok-kasuj {
    position: absolute;
    top: 1px;
    right: 1px;
    z-index: 2;
    width: 1.1rem;
    height: 1.1rem;
    padding: 0;
    line-height: 1;
    font-size: .95rem;
    border: 0;
    border-radius: .2rem;
    background: transparent;
    color: var(--tblr-secondary);
    cursor: pointer;
    opacity: 0;
}

.blok:hover .blok-kasuj,
.blok:focus-within .blok-kasuj,
.blok.jest-wybrany .blok-kasuj {
    opacity: 1;
}

.blok-kasuj:hover {
    background: var(--tblr-danger);
    color: #fff;
}

.blok:hover .blok-uchwyt::after {
    content: "";
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    width: 1.5rem;
    height: 2px;
    border-radius: 2px;
    background: var(--tblr-border-color-active, var(--tblr-secondary));
}

.blok-uchwyt-gora::after { top: 2px; }
.blok-uchwyt-dol::after { bottom: 2px; }

/* Podgląd klocka ciągniętego z palety — jeszcze nie istnieje w bazie,
   więc wygląda jak zamiar, a nie jak zapisany punkt. */
.blok-podglad {
    opacity: .7;
    border-style: dashed;
    pointer-events: none;
}

/* Kolory idą za zasięgiem bloku (BlockScope::color) — currentColor
   maluje lewą krawędź, tło zostaje spokojne. */
.blok-blue, .klocek-palety.blok-blue { color: var(--tblr-blue); }
.blok-purple, .klocek-palety.blok-purple { color: var(--tblr-purple); }
.blok-green, .klocek-palety.blok-green { color: var(--tblr-green); }
.blok-pink, .klocek-palety.blok-pink { color: var(--tblr-pink); }
.blok-teal, .klocek-palety.blok-teal { color: var(--tblr-teal); }

/*
 * Fragment Pisma pod sygnaturą — w panelu i na pulpicie.
 *
 * Nota o źródle jest częścią tego bloku, nie ozdobnikiem: przekład jest
 * cudzą własnością i nie powinien pojawić się na ekranie bez informacji,
 * czyj jest.
 */
.slowo-fragment {
    border-left: 3px solid var(--tblr-primary);
    padding: .4rem .75rem;
    background: var(--tblr-bg-surface-secondary);
    border-radius: .25rem;
}

.slowo-naglowek {
    font-size: .75rem;
    text-transform: uppercase;
    letter-spacing: .03em;
    color: var(--tblr-secondary);
}

.slowo-tekst {
    margin: .2rem 0 .3rem;
    line-height: 1.5;
}

.slowo-numer {
    color: var(--tblr-primary);
    font-weight: 600;
    margin-right: .1rem;
}

.slowo-nota {
    font-size: .7rem;
    color: var(--tblr-secondary);
}

/* Zakres szerszy niż sygnatura — patrz BiblePassage::$approximate. */
.slowo-uwaga {
    color: var(--tblr-orange);
    text-transform: none;
}

/*
 * Jutrznia — układ do śpiewania.
 *
 * To nie jest zwykły tekst i nie da się go złożyć jak akapitu. Gwiazdka
 * stoi w miejscu, w którym zmienia się ton, krzyżyk oznacza fleksę,
 * a wcięcie mówi, że wiersz jest dalszym ciągiem poprzedniego, a nie
 * nowym wersetem. Kto śpiewał psalm z kartki, w której to zgubiono, wie,
 * czym się to kończy.
 *
 * Klasy nadaje BreviaryHtml przy przepisywaniu strony brewiarza —
 * stamtąd bierze się ich nazewnictwo.
 */
.brw {
    font-size: .95rem;
    line-height: 1.55;
    max-width: 46rem;
}

.brw-czesc + .brw-czesc { margin-top: 1.4rem; }

.brw-naglowek {
    align-items: baseline;
    border-bottom: 1px solid var(--tblr-border-color);
    color: var(--tblr-secondary);
    display: flex;
    font-size: .75rem;
    justify-content: space-between;
    letter-spacing: .08em;
    margin-bottom: .5rem;
    padding-bottom: .2rem;
    text-transform: uppercase;
}

.brw-sygnatura {
    color: var(--tblr-body-color);
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
}

/* Odesłania do wydania książkowego — dla tych, którzy modlą się z książki. */
.brw-lg {
    color: var(--tblr-secondary);
    font-size: .7rem;
    margin-bottom: .5rem;
}

/* Czerwień rubryki. W księdze wszystko, co nie jest do wypowiedzenia,
   jest czerwone — i tak zostaje, bo tak się to czyta odruchowo. */
.brw-r { color: var(--tblr-red); }

.brw-tytul {
    font-weight: 600;
    margin: .9rem 0 .3rem;
    text-align: center;
}

/* Zdanie Ojca Kościoła nad psalmem — komentarz, nie modlitwa. */
.brw-cytat {
    color: var(--tblr-secondary);
    font-size: .85rem;
    margin-bottom: .5rem;
    text-align: center;
}

.brw-ant {
    font-style: italic;
    margin: .5rem 0;
}

/* Wcięcie wiszące: druga linia długiego wersetu ma być widocznie
   dalszym ciągiem, a nie osobnym wersetem. */
.brw-w,
.brw-hymn,
.brw-hymn-1 {
    padding-left: 1.4rem;
    text-indent: -1.4rem;
}

/* Strofy parzyste odrobinę odsunięte — tak samo jak w księdze, gdzie
   naprzemienne wcięcie pokazuje, kto teraz śpiewa. */
.brw-w2 { padding-left: 2.2rem; }

.brw-strofa { margin-bottom: .7rem; }

.brw-rubryka {
    color: var(--tblr-red);
    font-size: .85rem;
    font-style: italic;
}

.brw-zrodlo {
    color: var(--tblr-secondary);
    font-size: .75rem;
}

/* Antyfona jest ramą psalmu — śpiewa się ją przed nim i po nim, więc
   musi być widoczna z odległości ambony, a nie ginąć w tekście. */
.brw-ant {
    font-weight: 600;
    font-style: normal;
}

.brw-ant .brw-r { font-weight: 600; }

/*
 * Przyciski „posłuchaj" przy części Godziny.
 *
 * Pytanie „na jaką melodię to śpiewamy" pada wtedy, gdy patrzy się na
 * antyfonę — nie wtedy, gdy przegląda się wykaz melodii. Dlatego stoją
 * tutaj, przy tekście, a nie tylko w słowniku.
 */
.brw-melodie {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    margin-bottom: .6rem;
}

.brw-play {
    align-items: center;
    background: var(--tblr-bg-surface-secondary);
    border: 1px solid var(--tblr-border-color);
    border-radius: 2rem;
    color: var(--tblr-body-color);
    display: inline-flex;
    font-size: .78rem;
    gap: .3rem;
    padding: .1rem .6rem .1rem .35rem;
    text-decoration: none;
}

.brw-play:hover {
    background: var(--tblr-primary-lt);
    color: var(--tblr-primary);
}

.brw-play svg {
    fill: var(--tblr-primary);
    height: 1.1rem;
    width: 1.1rem;
}

/* Ikona mówi, co się stanie po kliknięciu: gra — zatrzymam, nie gra —
   włączę. Podmianę robi klasa `gra` z melodia_controller. */
.brw-play .ikona-pauza { display: none; }
.brw-play.gra .ikona-play { display: none; }
.brw-play.gra .ikona-pauza { display: inline; }

.brw-play.gra {
    background: var(--tblr-primary-lt);
    border-color: var(--tblr-primary);
    color: var(--tblr-primary);
}

/* Zwinięty zestaw melodii — patrz makro `melodie` w szablonie Jutrzni. */
.brw-wiecej { margin-bottom: .6rem; }

.brw-wiecej > summary {
    color: var(--tblr-primary);
    cursor: pointer;
    font-size: .78rem;
    width: fit-content;
}

.brw-wiecej[open] > summary { margin-bottom: .35rem; }

/*
 * Zakładki części Jutrzni.
 *
 * Godzina ma osiem części i przewijanie do próśb trwa dłużej niż samo
 * ich odmówienie. Zakładki idą w kolejności modlitwy, więc czyta się
 * je od lewej do prawej — a na wąskim ekranie przewijają się w poziomie
 * zamiast łamać na trzy rzędy.
 */
.brw-zakladki .nav-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: thin;
}

.brw-zakladki .nav-link {
    font-size: .82rem;
    padding: .5rem .8rem;
    white-space: nowrap;
}

/* Sygnatura i odesłanie do wydania książkowego nad tekstem części. */
.brw-metryka {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    gap: .2rem .8rem;
    margin-bottom: .6rem;
}

/*
 * Zasobnik pogodnego wieczoru.
 *
 * Nagłówek grupy w liście — rodzaje idą w kolejności przebiegu wieczoru,
 * więc sama lista czyta się jak scenariusz. Podpis obok mówi, po co dany
 * rodzaj stoi w tym miejscu; to jest ta wiedza, której nie ma ktoś,
 * kto prowadzi pierwszy raz.
 */
.wieczor-grupa {
    align-items: baseline;
    background: var(--tblr-bg-surface-secondary);
    border-top: 1px solid var(--tblr-border-color);
    display: flex;
    flex-wrap: wrap;
    gap: .1rem .6rem;
    padding: .35rem .75rem;
}

.wieczor-grupa-nazwa {
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
}

.wieczor-grupa-podpis {
    color: var(--tblr-secondary);
    font-size: .78rem;
}

/* Przebieg — to po niego się tu wchodzi, więc czyta się jak tekst,
   a nie jak pole formularza. */
.wieczor-przebieg {
    border-left: 3px solid var(--tblr-border-color);
    line-height: 1.55;
    margin-bottom: .6rem;
    padding-left: .75rem;
}

.wieczor-rekwizyty {
    color: var(--tblr-secondary);
    font-size: .85rem;
    margin-bottom: .6rem;
}

.wieczor-popraw > summary {
    color: var(--tblr-secondary);
    cursor: pointer;
    font-size: .8rem;
    width: fit-content;
}

/* Nagrania wgrane do propozycji — odtwarzacz, podpis i rozmiar w jednej linii. */
.wieczor-nagrania {
    display: flex;
    flex-direction: column;
    gap: .35rem;
    margin-bottom: .6rem;
}

.wieczor-nagranie {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
}

.wieczor-nagranie audio { height: 2rem; max-width: 18rem; }
.wieczor-nagranie-nazwa { font-size: .85rem; }

.wieczor-wgraj {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin-bottom: .6rem;
}

.wieczor-wgraj input[type="file"] { max-width: 17rem; }
.wieczor-wgraj input[type="text"] { max-width: 12rem; }

/* Zegar nad scenariuszem wieczoru — suma czasu i czy mieści się w bloku. */
.wieczor-zegar {
    align-items: baseline;
    display: flex;
    flex-wrap: wrap;
    font-size: .8rem;
    gap: .5rem;
}

.wieczor-godzina {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    width: 3rem;
}

.wieczor-uwaga {
    color: var(--tblr-orange);
    font-size: .85rem;
    margin-bottom: .5rem;
}

/* Wybór z zasobnika: wiersz to od razu formularz z jednym przyciskiem. */
.wieczor-wybor-wiersz {
    align-items: center;
    border-bottom: 1px solid var(--tblr-border-color);
    display: flex;
    gap: .5rem;
    padding: .3rem .75rem;
}

.wieczor-wybor-wiersz:hover { background: var(--tblr-bg-surface-secondary); }
.wieczor-wybor-wiersz .slownik-nazwa { flex: 1; }
.wieczor-wybor .slownik-meta { font-size: .72rem; }

/*
 * Pasek filtrów listy uczestników — jedna linia na szerokim ekranie.
 *
 * `w-auto` na <select> dopasowuje szerokość do NAJSZERSZEJ opcji, a wśród
 * funkcji jest „Odpowiedzialny za diakonię muzyczną" — szersza niż telefon.
 * Efekt: pasek rozpychał stronę w poziomie, choć tabela obok mieściła się
 * bez zarzutu. Stały udział plus sufit sprawiają, że pola zwężają się
 * razem z ekranem i zawijają, zamiast wypychać całą stronę.
 */
.filtr-pole {
    flex: 1 1 8.5rem;
    max-width: 100%;
    min-width: 0;
}

@media (min-width: 992px) {
    .filtr-pole { max-width: 15rem; }
}

/* Dostęp uczestnika do aplikacji — zwinięty pod imieniem na karcie rodziny. */
.dostep-pwa > summary {
    cursor: pointer;
    font-size: .82rem;
    width: fit-content;
}

.dostep-pwa input[readonly] {
    font-family: var(--tblr-font-monospace, monospace);
    font-size: .75rem;
}

/*
 * Lista czytań — wiersz na dzień, formularz dopiero po rozwinięciu.
 *
 * Czytania pobierają się same i w normalnym turnusie nikt ich nie tyka,
 * więc ekran jest do patrzenia. Sygnatury stoją bez podpisów: „1. czytanie",
 * „Psalm" i „Ewangelia" widać po samym kształcie zapisu, a cztery etykiety
 * w wierszu zabierały tyle miejsca, co treść.
 */
.czytania-data {
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    min-width: 3rem;
}

.czytania-sygnatury {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem;
    margin-left: auto;
}

.czytania-sygnatury .sygnatura {
    background: var(--tblr-bg-surface-secondary);
    border-radius: .25rem;
    font-size: .75rem;
    padding: .05rem .4rem;
    white-space: nowrap;
}

/* Obchód bywa długi („Dzień Powszedni albo wspomnienie…") i wypychał
   sygnatury poza wiersz — tu ucina się wielokropkiem zamiast rozpychać. */
.czytania-wiersz > summary .slownik-nazwa {
    flex: 1 1 12rem;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Kolorowa inicjałówka przy imieniu na karcie rodziny — mąż/żona w kolorach wspólnoty
   (tych samych, co na plakietkach), dzieci i reszta w neutralnym szarym.
   Sam tekst "Jan Mąż dorosły" długo skanuje się tak samo dla każdej
   osoby; okrągła plamka koloru łapie wzrok od razu i wiąże ten sam
   język wizualny co identyfikatory do druku. */
.osoba-avatar {
    align-items: center;
    background: var(--kolor, var(--tblr-secondary));
    border-radius: 50%;
    color: #fff;
    display: inline-flex;
    flex: 0 0 auto;
    font-size: .75rem;
    font-weight: 700;
    height: 1.6rem;
    justify-content: center;
    width: 1.6rem;
}

/* Lista osób na karcie rodziny przewija się sama, gdy rodzina jest duża —
   krąg, funkcje i dane trwałe obok mają się zmieścić na jednym ekranie
   zamiast być spychane w dół przez długą listę dzieci. */
.rodzina-lista {
    max-height: 60vh;
    overflow-y: auto;
}

/* Znacznik punktu checklisty "Konfiguracja rekolekcji" — pusty krążek,
   zielony z ptaszkiem po zrobieniu. */
.krok-znacznik {
    align-items: center;
    border: 2px solid var(--tblr-border-color);
    border-radius: 50%;
    color: #fff;
    display: inline-flex;
    flex: 0 0 auto;
    height: 1.75rem;
    justify-content: center;
    width: 1.75rem;
}

.krok-znacznik svg {
    height: 1rem;
    width: 1rem;
}

.krok-znacznik.zrobiony {
    background: var(--tblr-green);
    border-color: var(--tblr-green);
}

/* Moduły PWA — przeciąganie kolejności w ustawieniach turnusu. */
.pwa-modul-uchwyt {
    color: var(--tblr-secondary);
    cursor: grab;
    font-size: 1.1rem;
    line-height: 1;
}

.pwa-modul-uchwyt:active { cursor: grabbing; }

[data-pwa-modules-target="lista"] .sortable-ghost {
    outline: 2px dashed var(--tblr-primary);
    outline-offset: -2px;
}
