:root {
    color-scheme: light dark;
    --bg: #ffffff;
    --surface: #f6f6f7;
    --surface-2: #ececee;
    --border: #e2e2e5;
    --text: #1c1c1f;
    --text-muted: #75757f;
    --accent: #8a8f98;
    --select: #3b82f6;
    --danger: #e5484d;
    --success: #2ecc71;
    --warning: #f5a623;
    --tile-size: 190px;
    --tree-width: 240px;
    --topbar-h: 64px;
    --thumb-radius: 0px;
    --lightbox-radius: 0px;
}

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        --bg: #111214;
        --surface: #1b1c1f;
        --surface-2: #232427;
        --border: #2c2d31;
        --text: #eceef0;
        --text-muted: #9a9da3;
        --select: #5b9dff;
    }
}

:root[data-theme="dark"] {
    --bg: #111214;
    --surface: #1b1c1f;
    --surface-2: #232427;
    --border: #2c2d31;
    --text: #eceef0;
    --text-muted: #9a9da3;
    --select: #5b9dff;
}

* {
    box-sizing: border-box;
}

html {
    overflow-y: scroll;
    scrollbar-gutter: stable;
    /* Blokuje natywny pinch-zoom/double-tap-zoom przegladarki - viewport
       meta (maximum-scale=1, user-scalable=no) robi to samo, ale np. iOS
       Safari go ignoruje dla pinch, wiec dublujemy blokade tutaj + w JS
       (gesturestart/touchmove, patrz gallery.js) zamiast polegac na
       jednym mechanizmie. */
    touch-action: manipulation;
}

/* Bez tego, komponenty z wlasnym "display" (dropzone, lightbox - oba
   flex) maja taka sama specyficznosc jak domyslna regula przegladarki
   dla [hidden], wiec przy remisie wygrywa nasza regula i element zostaje
   widoczny na stale, niezaleznie od atrybutu hidden ustawianego przez JS. */
[hidden] {
    display: none !important;
}

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
}

button {
    font: inherit;
    cursor: pointer;
    border: none;
    border-radius: 999px;
    padding: 0.5rem 1.1rem;
    background: var(--text);
    color: var(--bg);
    font-size: 0.9rem;
    transition: background-color 0.15s, opacity 0.15s;
}

button:hover {
    opacity: 0.85;
}

button.secondary {
    background: var(--surface);
    border: 1px solid var(--border);
    color: var(--text);
}

button.secondary:hover {
    background: var(--surface-2);
}

.icon-btn {
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: var(--text-muted);
    padding: 0;
    font-size: 1rem;
    flex-shrink: 0;
}

.icon-btn:hover {
    background: var(--surface-2);
    color: var(--text);
}

.btn-icon-label {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
}

.btn-icon-label svg {
    flex-shrink: 0;
}

.btn-icon-label .btn-label {
    white-space: nowrap;
}

.btn-danger {
    background: var(--danger);
    color: white;
}

/* --- Layout: sidebar + main --- */

.app {
    display: flex;
    min-height: 100vh;
}

.sidebar {
    width: 180px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border-right: 1px solid var(--border);
    transition: width 0.15s ease;
    overflow: hidden;
    position: sticky;
    top: 0;
    height: 100vh;
    align-self: flex-start;
}

.sidebar.collapsed {
    width: 4rem;
}

.sidebar.collapsed .sidebar-brand-name,
.sidebar.collapsed .nav-link-label {
    display: none;
}

.sidebar.collapsed .sidebar-brand {
    justify-content: center;
}

.sidebar.collapsed .nav-link {
    justify-content: center;
}

.sidebar.collapsed .sidebar-footer {
    justify-content: center;
}

/* Nazwa pozycji menu przy zwinietym sidebarze - pokazywana z opoznieniem
   (patrz sidebarTooltipTimer w gallery.js: 500ms "przytrzymania" najazdu,
   zanim tooltip sie pojawi) jako osobny element position:fixed (NIE
   dziecko .sidebar, ktory ma overflow:hidden pod animacje szerokosci -
   tooltip wychodzacy poza 4rem zostalby przez to przyciety). */
.sidebar-tooltip {
    position: fixed;
    transform: translateY(-50%);
    background: var(--surface-2);
    border: 1px solid var(--border);
    padding: 0.35rem 0.7rem;
    border-radius: 6px;
    font-size: 0.85rem;
    white-space: nowrap;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    pointer-events: none;
    z-index: 200;
}

.sidebar-brand {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem 1rem 0.5rem;
    white-space: nowrap;
}

.sidebar-brand-name {
    font-weight: 600;
    font-size: 1rem;
}

.sidebar-nav {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.5rem;
    flex: 1;
}

.nav-link {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    text-align: left;
    background: transparent;
    color: var(--text-muted);
    border: none;
    border-radius: 8px;
    padding: 0.55rem 0.75rem;
    font-size: 0.9rem;
    white-space: nowrap;
}

.nav-link svg {
    flex-shrink: 0;
}

.nav-link:hover {
    background: var(--surface-2);
    color: var(--text);
}

.nav-link.active {
    background: var(--surface-2);
    color: var(--text);
    font-weight: 600;
}

.sidebar-footer {
    padding: 0.75rem;
    border-top: 1px solid var(--border);
    display: flex;
    justify-content: flex-end;
    gap: 0.25rem;
}

.app-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.sidebar-mobile-toggle {
    display: none;
}

.sidebar-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 70;
    touch-action: none;
}

.topbar {
    position: sticky;
    top: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.75rem 1.25rem;
    background: var(--bg);
    border-bottom: 1px solid var(--border);
}

.breadcrumb {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: calc(0.9rem + 2pt);
    color: var(--text-muted);
    min-width: 0;
    overflow: hidden;
}

.breadcrumb-item {
    background: transparent;
    border: none;
    color: inherit;
    font: inherit;
    padding: 0.2rem 0.4rem;
    border-radius: 6px;
    white-space: nowrap;
}

button.breadcrumb-item {
    cursor: pointer;
}

button.breadcrumb-item:hover {
    background: var(--surface-2);
    color: var(--text);
}

.breadcrumb-item:last-child {
    color: var(--text);
    font-weight: 600;
}

.breadcrumb-sep {
    opacity: 0.5;
}

.topbar-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-shrink: 0;
}

.view-switcher {
    position: relative;
}

/* position: fixed (nie absolute wzgledem .view-switcher) - top/left
   ustawia JS (patrz positionDropdownMenu w gallery.js), pozycjonujac
   wzgledem viewportu. Potrzebne, bo .topbar-actions (rodzic .view-switcher
   na waskim ekranie) ma overflow-x: auto - z tego powodu przegladarka
   wymusza tez overflow-y: auto na tym samym elemencie (nie da sie miec
   jednej osi scrollowalnej a drugiej "visible"), co przycinalo/ukrywalo
   te menu, mimo ze technicznie bylo "otwarte" (hidden=false) - przyciski
   widoku/sortowania/opcji sprawialy wrazenie, ze "nie reaguja". */
.view-menu {
    position: fixed;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 0.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 170px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
    z-index: 30;
}

.view-menu-item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    text-align: left;
    background: transparent;
    color: var(--text);
    border: none;
    border-radius: 8px;
    padding: 0.45rem 0.6rem;
    font-size: 0.85rem;
}

/* Ikonka przed etykieta - w menu kontekstowych dodawana przez JS
   (contextMenuIconSvg w gallery.js), w #view-menu/#sort-menu/#options-menu
   wpisana wprost w index.php. Kolor bierze sie z currentColor (dziedziczy
   po przycisku, wiec .view-menu-item-danger automatycznie farbuje tez
   ikonke na czerwono). */
.view-menu-item svg {
    flex-shrink: 0;
    opacity: 0.7;
}

.view-menu-item:hover {
    background: var(--surface-2);
}

.view-menu-item.active {
    background: var(--surface-2);
    font-weight: 600;
}

.view-menu-item-danger {
    color: var(--danger);
}

/* Wiersz z przyciskiem glownym (np. "Szczegoly zdjecia") + strzalka obok
   otwierajaca podmenu wyboru wierszy (patrz detail-rows-submenu w
   gallery.js) - sama strzalka NIE jest .view-menu-item, wiec nie laduje w
   optionsMenuItems (ktore przelaczaja widocznosc calej sekcji). */
.view-menu-item-row {
    display: flex;
    align-items: center;
    gap: 0.1rem;
}

.view-menu-item-row .view-menu-item {
    flex: 1 1 auto;
}

.view-menu-item-expand {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: var(--text-muted);
    border: none;
    border-radius: 8px;
    padding: 0.45rem 0.5rem;
}

.view-menu-item-expand:hover {
    background: var(--surface-2);
    color: var(--text);
}

.view-menu-divider {
    height: 1px;
    margin: 0.3rem 0.25rem;
    background: var(--border);
}

.view-menu-section-label {
    padding: 0.3rem 0.6rem 0.15rem;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: var(--text-muted);
}

/* Menu kontekstowe (prawy klawisz / przycisk "...") na karcie folderu/
   albumu i na miniaturze zdjecia - ten sam wyglad co .view-menu (menu w
   topbarze), ale pozycjonowane w miejscu klikniecia zamiast pod
   przyciskiem. */
.context-menu {
    position: fixed;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 0.35rem;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 190px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
    /* Wyzej niz .lightbox (z-index: 200) - menu otwierane tez z przycisku
       "..." w gornym pasku lightboxa (patrz #lightbox-more w gallery.js),
       musi renderowac sie NAD nim, nie pod. */
    z-index: 210;
}

.item-menu-btn {
    position: absolute;
    top: 0.4rem;
    right: 0.4rem;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.35);
    color: white;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 2;
}

.item-menu-btn.active {
    opacity: 1;
}

/* Na urzadzeniach z prawdziwym hover (mysz/touchpad) przycisk "..." jest
   ukryty, dopoki kursor nie najedzie na karte - na dotyku hover: hover
   nigdy nie jest prawdziwy, wiec ta regula w ogole tu nie wchodzi w gre
   (patrz nizej). Gdyby ja zostawic bez tego zawezenia, przegladarka na
   dotyku i tak probowalaby "wejsc" w :hover (zeby zdazyc odslonic ten
   przycisk) przy PIERWSZYM tapnieciu w karte, zanim wyslala prawdziwy
   klik - a dopiero DRUGIE tapniecie otwieralo zdjecie/folder/album. */
@media (hover: hover) {
    .browse-card:hover .item-menu-btn,
    .gallery-item:hover .item-menu-btn {
        opacity: 1;
    }
}

/* Na dotyku nie ma "najechania" zeby cokolwiek odslonic, ale przycisk
   NIE jest tu stale widoczny (tak bylo wczesniej - nieeleganckie, bo
   zajmowal miejsce na kazdej karcie przez caly czas). Zamiast tego
   dlugie przytrzymanie karty otwiera menu bezposrednio, bez potrzeby
   najpierw "trafiac" w maly przycisk (patrz dlugie przytrzymanie w
   makeItemMenuButton w gallery.js, ten sam mechanizm co LONG_PRESS_MS
   w lightboxie). Przycisk i tak dostaje .active (opacity: 1 wyzej) w
   te same momenty, kiedy menu jest otwarte. */

.item-menu-btn:hover {
    background: rgba(0, 0, 0, 0.55);
}

.thumb-size-slider {
    position: relative;
    display: flex;
    align-items: center;
    width: 90px;
    padding: 0 0.3rem;
}

.thumb-size-dots {
    position: absolute;
    left: 0.55rem;
    right: 0.55rem;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    justify-content: space-between;
    pointer-events: none;
}

.thumb-size-dots span {
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: var(--text-muted);
}

.thumb-size-slider input[type="range"] {
    -webkit-appearance: none;
    appearance: none;
    position: relative;
    z-index: 1;
    width: 100%;
    height: 1.1rem;
    background: transparent;
    margin: 0;
}

.thumb-size-slider input[type="range"]::-webkit-slider-runnable-track {
    height: 2px;
    background: var(--text-muted);
    border-radius: 999px;
}

.thumb-size-slider input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 11px;
    height: 11px;
    margin-top: -4.5px;
    border-radius: 50%;
    background: var(--text-muted);
    border: none;
    cursor: pointer;
}

.thumb-size-slider input[type="range"]::-moz-range-track {
    height: 2px;
    background: var(--text-muted);
    border-radius: 999px;
}

.thumb-size-slider input[type="range"]::-moz-range-thumb {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--text-muted);
    border: none;
    cursor: pointer;
}

.upload-concurrency-control {
    display: flex;
    align-items: center;
    gap: 0.6rem;
}

.upload-concurrency-slider {
    width: 150px;
}

.upload-concurrency-value {
    min-width: 1.2rem;
    text-align: center;
    font-size: 0.85rem;
    color: var(--text-muted);
}

/* --- Ustawienia --- */

/* Uklad: boczne menu sekcji + jeden widoczny panel (gallery.js,
   showSettingsPanel). Na waskim ekranie menu zamienia sie w poziomy,
   przewijany pasek nad panelem. */
.settings-layout {
    display: flex;
    align-items: flex-start;
    gap: 2.5rem;
    padding-top: 1.5rem;
}

.settings-nav {
    position: sticky;
    top: calc(var(--topbar-h) + 1rem);
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    width: 230px;
    flex-shrink: 0;
}

.settings-nav-item {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    width: 100%;
    background: transparent;
    color: var(--text-muted);
    padding: 0.55rem 0.9rem;
    font-size: 0.875rem;
    text-align: left;
    white-space: nowrap;
}

.settings-nav-item svg {
    flex-shrink: 0;
}

.settings-nav-item:hover {
    background: var(--surface);
    color: var(--text);
    opacity: 1;
}

.settings-nav-item.active {
    background: var(--surface-2);
    color: var(--text);
    font-weight: 600;
}

.settings-nav-group {
    margin: 1rem 0 0.35rem;
    padding: 0 0.9rem;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.settings-layout:not(.is-admin) .settings-admin-only {
    display: none;
}

.settings-panels {
    flex: 1;
    min-width: 0;
    max-width: 700px;
}

.settings-panel-title {
    font-size: 1.25rem;
    margin: 0 0 0.75rem;
}

.settings-panel-subtitle {
    margin: -0.5rem 0 0.5rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.settings-panel > .settings-section-title {
    margin-top: 1rem;
}

.settings-panel > .settings-section:first-of-type {
    padding-top: 0.25rem;
}

@media (max-width: 760px) {
    .settings-layout {
        flex-direction: column;
        gap: 1rem;
        padding-top: 0.75rem;
    }

    .settings-nav {
        position: static;
        flex-direction: row;
        width: 100%;
        overflow-x: auto;
        scrollbar-width: none;
        gap: 0.25rem;
        padding-bottom: 0.25rem;
        border-bottom: 1px solid var(--border);
    }

    .settings-nav::-webkit-scrollbar {
        display: none;
    }

    .settings-nav-item {
        width: auto;
        padding: 0.45rem 0.8rem;
        font-size: 0.8rem;
    }

    .settings-nav-item svg {
        width: 16px;
        height: 16px;
    }

    .settings-nav-group {
        display: none;
    }

    .settings-panels {
        width: 100%;
    }
}

.settings-section {
    max-width: 700px;
    padding: 1rem 0 2rem;
}

.settings-section-wide {
    border-top: 1px solid var(--border);
    padding-top: 1.5rem;
}

.settings-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.5rem;
    padding: 1rem 0;
    border-bottom: 1px solid var(--border);
}

.settings-row:last-child {
    border-bottom: none;
}

.settings-row input[type="text"],
.settings-row input[type="password"] {
    width: 260px;
    max-width: 100%;
    font: inherit;
    padding: 0.5rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
}

.settings-row input:disabled {
    color: var(--text-muted);
    background: var(--surface);
}

.settings-row-label {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.settings-row-label strong {
    font-size: 0.9rem;
    font-weight: 600;
}

.settings-row-label span {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.settings-section-title {
    font-size: 1rem;
    margin: 0 0 0.75rem;
}

.settings-shortcuts-list {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    margin: 0;
}

.settings-shortcuts-list > div {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-size: 0.85rem;
}

.settings-shortcuts-list dt {
    flex-shrink: 0;
    min-width: 3.5rem;
}

.settings-shortcuts-list dd {
    margin: 0;
    color: var(--text-muted);
    white-space: nowrap;
}

.settings-shortcuts-list kbd {
    display: inline-block;
    padding: 0.15rem 0.45rem;
    border-radius: 5px;
    border: 1px solid var(--border);
    background: var(--surface-2);
    font: inherit;
    font-size: 0.75rem;
}

.cf-stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 0.75rem;
    max-width: 700px;
}

.cf-stat-tile {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
}

.cf-stat-label {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.cf-stat-value {
    font-size: 1.3rem;
    font-weight: 600;
}

.cf-stats-error {
    margin-top: 0.75rem;
    font-size: 0.85rem;
    color: var(--danger);
    max-width: 700px;
    word-break: break-word;
}

.cf-stats-note {
    margin-top: 0.75rem;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.cf-stats-hint {
    margin-top: 0.75rem;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.cf-stats-hint a {
    color: var(--accent);
}

.accounts-list {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    max-width: 700px;
}

.account-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.5rem 0.75rem;
    border-radius: 8px;
    background: var(--surface);
    border: 1px solid var(--border);
    cursor: pointer;
}

.account-row:hover {
    background: var(--surface-2);
}

/* Lista zapisanych rozdzielczosci (Ustawienia) - ta sama "karta w rzedzie"
   co .account-row, ale bez klikalnosci calego wiersza (tu klika sie tylko
   przycisk usuniecia). */
.resolution-row {
    cursor: default;
}

.resolution-row:hover {
    background: var(--surface);
}

.saved-resolution-add-row {
    display: flex;
    gap: 0.5rem;
    max-width: 700px;
}

.saved-resolution-input {
    flex: 1;
    min-width: 0;
    box-sizing: border-box;
    font: inherit;
    font-size: 0.9rem;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.5rem 0.75rem;
}

.saved-resolution-input:focus {
    outline: none;
    border-color: var(--select);
}

.account-name {
    flex: 1;
    min-width: 0;
    font-size: 0.9rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.account-username {
    color: var(--text-muted);
    font-size: 0.8rem;
}

.account-badge {
    font-size: 0.7rem;
    color: var(--text-muted);
    background: var(--surface-2);
    padding: 0.2rem 0.5rem;
    border-radius: 999px;
    flex-shrink: 0;
}

.accounts-form {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    max-width: 700px;
}

.accounts-form input {
    flex: 1;
    min-width: 140px;
    font: inherit;
    padding: 0.5rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
}

.accounts-form button {
    flex-shrink: 0;
}

.settings-theme-options {
    display: flex;
    gap: 0.2rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.2rem;
}

.settings-theme-btn,
.settings-transition-btn,
.settings-interval-btn,
.settings-loop-btn,
.settings-thumb-radius-btn,
.settings-lightbox-radius-btn,
.settings-admin-btn,
.share-dialog-permission-btn,
.share-dialog-user-btn {
    background: transparent;
    color: var(--text-muted);
    padding: 0.35rem 0.75rem;
    font-size: 0.8rem;
}

.settings-theme-btn:hover,
.settings-transition-btn:hover,
.settings-interval-btn:hover,
.settings-loop-btn:hover,
.settings-thumb-radius-btn:hover,
.settings-lightbox-radius-btn:hover,
.settings-admin-btn:hover,
.share-dialog-permission-btn:hover,
.share-dialog-user-btn:hover {
    background: var(--surface-2);
    opacity: 1;
}

.settings-theme-btn.active,
.settings-transition-btn.active,
.settings-interval-btn.active,
.settings-loop-btn.active,
.settings-thumb-radius-btn.active,
.settings-lightbox-radius-btn.active,
.settings-admin-btn.active,
.share-dialog-permission-btn.active,
.share-dialog-user-btn.active {
    background: var(--surface-2);
    color: var(--text);
    font-weight: 600;
    opacity: 1;
}

.account-form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    max-width: 700px;
    margin-top: 0.5rem;
}

/* --- Widoki przegladania: foldery / albumy --- */

.browse-view {
    padding: 1rem 1.25rem 0;
}

/* Wewnatrz konkretnego folderu #folders-view dubluje "podfoldery" -
   gdy ich nie ma, siatka jest pusta, ale nadal rezerwuje wlasny padding
   (ten sam co .cards-grid ponizej) - zostawia martwa przerwe przed
   siatka zdjec. Zwijamy caly padding w tym przypadku (patrz
   renderFoldersBrowse() w gallery.js). */
.browse-view.is-empty-grid {
    padding-top: 0;
}

.browse-view.is-empty-grid .cards-grid {
    padding-bottom: 0;
}

/* Drzewo i glowna tresc jako wiersz na calej wysokosci - dzieki temu
   panel drzewa obejmuje zarowno siatke podfolderow, jak i galerie zdjec
   ponizej, zamiast konczyc sie na pierwszym wierszu. */
.content-row {
    display: flex;
    align-items: stretch;
}

.content-main {
    flex: 1;
    min-width: 0;
}

.browse-tree {
    width: var(--tree-width, 240px);
    flex-shrink: 0;
    box-sizing: border-box;
    padding: 1rem 0.75rem 1rem 1.25rem;
    border-right: 1px solid var(--border);
    transition: width 0.2s ease, opacity 0.2s ease, padding 0.2s ease;
    position: sticky;
    top: var(--topbar-h, 0px);
    align-self: flex-start;
    height: calc(100vh - var(--topbar-h, 0px));
    overflow-y: auto;
}

.browse-tree.resizing {
    transition: none;
    user-select: none;
}

.browse-tree-resize-handle {
    position: absolute;
    top: 0;
    right: 0;
    width: 6px;
    height: 100%;
    cursor: col-resize;
    z-index: 5;
}

.browse-tree-resize-handle:hover,
.browse-tree.resizing .browse-tree-resize-handle {
    background: var(--select);
    opacity: 0.35;
}

.browse-tree.collapsed {
    width: 0;
    padding-left: 0;
    padding-right: 0;
    border-right: 0;
    opacity: 0;
    overflow: hidden;
}

.browse-tree-list {
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}

.browse-tree-root-row {
    display: flex;
    align-items: center;
    gap: 0.2rem;
    margin-bottom: 0.4rem;
    padding-bottom: 0.55rem;
    border-bottom: 1px solid var(--border);
}

.browse-tree-filter {
    position: relative;
    flex-shrink: 0;
}

.browse-tree-filter-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    flex-shrink: 0;
    background: none;
    border: none;
    border-radius: 6px;
    padding: 0;
    color: var(--text-muted);
    cursor: pointer;
}

.browse-tree-filter-btn:hover {
    background: var(--surface-2);
    color: var(--text);
}

.browse-tree-filter-btn.active {
    color: var(--select);
}

.browse-tree-filter-menu {
    /* left/top ustawia JS (positionDropdownMenu w gallery.js), tak samo
       jak dla #view-menu/#sort-menu/#options-menu - patrz komentarz przy
       .view-menu. Bez left:auto/right:0 (stara wersja pozycjonowania,
       kolidujaca z inline left ustawianym przez JS). */
    min-width: 180px;
    max-height: 260px;
    overflow-y: auto;
}

.browse-tree-node {
    display: flex;
    flex-direction: column;
}

.browse-tree-row {
    display: flex;
    align-items: center;
    gap: 0.1rem;
    /* Zakotwicza .browse-tree-row .browse-tree-menu-btn (position:
       absolute, patrz nizej) - przycisk "..." nie zajmuje juz stale
       miejsca w ukladzie flex, dzieki czemu licznik/kolumny moga siegac
       az do prawej krawedzi wiersza, tak jak ikonki w wierszu naglowka. */
    position: relative;
}

.browse-tree-toggle,
.browse-tree-toggle-spacer {
    width: 1.2rem;
    height: 1.2rem;
    flex-shrink: 0;
}

.browse-tree-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    padding: 0;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: 4px;
}

.browse-tree-toggle:hover {
    background: var(--surface-2);
    color: var(--text);
}

.browse-tree-toggle svg {
    transition: transform 0.15s ease;
}

.browse-tree-node.collapsed > .browse-tree-row .browse-tree-toggle svg {
    transform: rotate(-90deg);
}

.browse-tree-item {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex: 1;
    min-width: 0;
    text-align: left;
    background: none;
    border: none;
    border-radius: 8px;
    /* Prawy margines zmniejszony (z 0.6rem) - .browse-tree-menu-btn jest
       teraz position:absolute (patrz .browse-tree-row), wiec nie trzeba
       juz rezerwowac dla niego miejsca w tym paddingu; licznik/kolumny
       moga wiec siegac dalej w prawo, blizej krawedzi wiersza. */
    padding: 0.4rem 0.3rem 0.4rem 0.2rem;
    font-size: 0.85rem;
    color: var(--text-muted);
    cursor: pointer;
}

.browse-tree-item-icon {
    flex-shrink: 0;
    opacity: 0.6;
}

.browse-tree-item-icon-wrap {
    position: relative;
    display: inline-flex;
    flex-shrink: 0;
}

.browse-tree-item-status {
    position: absolute;
    right: -3px;
    bottom: -3px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    border: 1.5px solid var(--surface);
}

.browse-tree-item-status-edit {
    background: var(--success);
}

.browse-tree-item-status-view {
    background: var(--warning);
}

.browse-tree-item-status-blocked {
    background: var(--danger);
}

.browse-tree-item-label {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.browse-tree-item-count {
    flex-shrink: 0;
    font-size: 0.7rem;
    opacity: 0.35;
    text-align: right;
}

.browse-tree-item:hover {
    background: var(--surface-2);
    color: var(--text);
}

.browse-tree-item.active,
.browse-tree-item.kbd-active {
    background: var(--surface-2);
    color: var(--text);
    font-weight: 600;
}


.browse-tree-children {
    margin-left: 0.6rem;
    padding-left: 0.5rem;
    border-left: 1px solid var(--border);
}

.browse-tree-node.collapsed > .browse-tree-children {
    display: none;
}

.browse-tree-node.drag-over > .browse-tree-row .browse-tree-item,
.browse-tree-item.drag-over {
    background: var(--select);
    color: white;
}

.browse-tree-item[draggable="true"] {
    cursor: grab;
}

/* Widok szczegolowy drzewa folderow (przelacznik obok ikony filtra) -
   DOKLADNIE to samo drzewo co kompaktowe (ten sam .browse-tree-node/
   .browse-tree-row/.browse-tree-children, ta sama logika w
   renderTreeChildren() w gallery.js - wciecia, ikonki, strzalki,
   drag&drop, menu kontekstowe, dblclik dzialaja identycznie), tylko
   kazdy wiersz ma doklejone widoczne kolumny danych z prawej
   (.browse-tree-detailed-col-*, ktore sa widoczne wybiera uzytkownik -
   patrz menu kontekstowe na wierszu naglowka, openDetailColumnsMenu w
   gallery.js). Wyrownuja sie idealnie na KAZDEJ glebokosci zagniezdzenia
   bez CSS subgrid: .browse-tree-item ma flex:1 (pochlania cala zmienna
   przestrzen wynikajaca z wciecia), kolumny maja STALA (ale policzona w
   JS z rzeczywistej tresci - patrz computeDetailColumnWidths -  zamiast
   ryczaltowego zgadywania) szerokosc przez zmienne CSS --tree-col-w-*, a
   .browse-tree-children dodaje margines TYLKO z lewej (nigdy z prawej) -
   wiec prawa krawedz kazdego wiersza jest zawsze w tym samym miejscu. */
.browse-tree-detailed-col {
    flex-shrink: 0;
    /* .browse-tree-row ma "gap: 0.1rem" (dobrany pod ciasny odstep
       strzalka->ikonka, patrz wyzej) - za malo miedzy kolumnami danych,
       stad wlasny, wiekszy odstep z lewej zamiast polegania na tym gap. */
    margin-left: 0.6rem;
    font-size: 0.7rem;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.browse-tree-detailed-col-count {
    width: var(--tree-col-w-count, 2.2rem);
    text-align: right;
}

.browse-tree-detailed-col-size {
    width: var(--tree-col-w-size, 3.4rem);
    text-align: right;
}

.browse-tree-detailed-col-created {
    width: var(--tree-col-w-created, 4.2rem);
}

.browse-tree-detailed-col-updated {
    width: var(--tree-col-w-updated, 4.2rem);
}

.browse-tree-detailed-col-owner {
    width: var(--tree-col-w-owner, 4.4rem);
}

.browse-tree-detailed-header-row {
    margin-bottom: 0.3rem;
    padding-bottom: 0.35rem;
    border-bottom: 1px solid var(--border);
    /* Prawy klik na tym wierszu otwiera menu wyboru widocznych kolumn
       (patrz openDetailColumnsMenu w gallery.js) - kursor podpowiada, ze
       wiersz reaguje na wiecej niz zwykle hover. */
    cursor: context-menu;
}

.browse-tree-detailed-header-row .browse-tree-detailed-col {
    font-size: 0.65rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    opacity: 0.6;
}

.browse-tree-detailed-header-spacer {
    flex: 1;
    min-width: 0;
}

/* "..." menu kontekstowy w wierszu drzewa - ten sam mechanizm co
   .item-menu-btn na kartach/miniaturach. Domyslnie plaski/w przeplywie
   flex (position:static) - uzywane tak w .folders-column-item (widok
   kolumnowy folderow), gdzie wiersz jest za waski na nakladke w rogu.
   W samym drzewie (.browse-tree-row, patrz nizej) nadpisane na
   position:absolute - przycisk, ktory i tak jest niewidoczny poza
   hover/aktywnym stanem, nie musi tam stale rezerwowac miejsca w
   ukladzie; dzieki temu licznik/kolumny danych moga siegac dalej w
   prawo, az pod krawedz, pod ktora stoi ten przycisk. */
.browse-tree-menu-btn {
    position: static;
    width: 1.2rem;
    height: 1.2rem;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border-radius: 4px;
    padding: 0;
    color: var(--text-muted);
    opacity: 0;
    transition: opacity 0.15s;
}

.browse-tree-row .browse-tree-menu-btn {
    position: absolute;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    /* Niewidoczny (opacity:0) przycisk nadal przechwytywalby kliknieca -
       licznik/kolumny danych siegaja teraz pod to samo miejsce (patrz
       wyzej), wiec bez tego klik na nich czasem trafialby w ten ukryty
       przycisk zamiast nawigowac. Wlaczone z powrotem dopiero razem z
       opacity, kiedy przycisk faktycznie jest widoczny. */
    pointer-events: none;
}

.browse-tree-row:hover .browse-tree-menu-btn,
.browse-tree-menu-btn.active {
    opacity: 1;
    pointer-events: auto;
}

.browse-tree-menu-btn:hover {
    background: var(--surface-2);
    color: var(--text);
}

.cards-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(var(--tile-size), 1fr));
    gap: 0.75rem;
    padding-bottom: 1rem;
}

.search-input-row {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.6rem 1rem;
    margin-bottom: 1.25rem;
    max-width: 480px;
}

.search-input-icon {
    flex-shrink: 0;
    color: var(--text-muted);
}

#search-input {
    flex: 1;
    min-width: 0;
    border: none;
    background: transparent;
    font: inherit;
    color: var(--text);
    outline: none;
}

.search-hint {
    color: var(--text-muted);
    font-size: 0.9rem;
}

.search-section {
    margin-bottom: 2rem;
}

.search-section-title {
    font-size: 1rem;
    margin: 0 0 0.75rem;
}

/* Foldery i albumy w wynikach wyszukiwania moga byc z roznych miejsc w
   drzewie - zbiorcze zaznaczanie/kasowanie (zaprojektowane dla jednego
   rodzaju na raz) nie ma tu dobrze zdefiniowanego znaczenia. */
#search-view .browse-card-select {
    display: none;
}

.browse-card {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.browse-card-media {
    position: relative;
    aspect-ratio: 1 / 1;
    overflow: hidden;
    border-radius: 12px;
    background: var(--surface);
    border: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.browse-card:hover .browse-card-media {
    background: var(--surface-2);
    border-color: var(--accent);
}

.browse-card[draggable="true"] {
    cursor: grab;
}

.browse-card.drag-over .browse-card-media {
    border-color: var(--select);
    border-width: 2px;
    background: var(--surface-2);
}

/* Folder/album aktualnie wypelniany uploadem - spinner NA WIERZCHU okladki
   (pseudo-elementy, zero dodatkowych wezlow DOM) - sama okladka (<img> albo
   placeholder) stoi caly czas nieruszona pod spodem, bo prawdziwe
   cover_url jest ustawiane dopiero PO zakonczeniu calego batcha (patrz
   bumpContainerCoverAndCount w gallery.js) - zero migotania w trakcie. */
@keyframes winlook-spin {
    to { transform: rotate(360deg); }
}

/* Brak okladki (widac placeholder-ikonke) - pierscien OTACZA ikonke
   (srednica wyraznie wieksza niz ikonka), zeby sie z nia wizualnie nie
   "krzyzowac". */
.browse-card-media.uploading:not(:has(img))::after {
    content: '';
    position: absolute;
    top: 50%;
    left: 50%;
    width: 52px;
    height: 52px;
    margin: -26px 0 0 -26px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: winlook-spin 0.8s linear infinite;
    z-index: 2;
}

/* Okladka juz jest (prawdziwe zdjecie) - maly znacznik w rogu, zeby nie
   zaslaniac tresci zdjecia. */
.browse-card-media.uploading:has(img)::before {
    content: '';
    position: absolute;
    top: 6px;
    right: 6px;
    width: 22px;
    height: 22px;
    background: rgba(0, 0, 0, 0.55);
    border-radius: 50%;
    z-index: 1;
}

.browse-card-media.uploading:has(img)::after {
    content: '';
    position: absolute;
    top: 11px;
    right: 11px;
    width: 12px;
    height: 12px;
    border: 2px solid rgba(255, 255, 255, 0.35);
    border-top-color: #fff;
    border-radius: 50%;
    animation: winlook-spin 0.8s linear infinite;
    z-index: 2;
}

.browse-tree-item-icon-wrap.uploading::after {
    content: '';
    position: absolute;
    right: -3px;
    top: -3px;
    width: 8px;
    height: 8px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: winlook-spin 0.7s linear infinite;
}

.browse-card-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    opacity: 0;
    transition: opacity 0.35s ease;
}

.browse-card-media img.loaded {
    opacity: 1;
}

.browse-card-placeholder {
    color: var(--text-muted);
}

.browse-card-badge {
    position: absolute;
    bottom: 0.4rem;
    right: 0.4rem;
    background: rgba(0, 0, 0, 0.6);
    color: white;
    font-size: 0.7rem;
    line-height: 1;
    padding: 0.3rem 0.55rem;
    border-radius: 999px;
    white-space: nowrap;
    z-index: 2;
}

/* Status cudzego folderu/albumu - patrz itemShareStatus() w gallery.js.
   Folder bez prawa "view" na zawartosc wyglada jak pusty (patrz
   api/folders.php), czerwona kropka odroznia to od naprawde pustego
   folderu (dla albumow ten stan nigdy nie wystapi). */
.browse-card-status {
    position: absolute;
    top: 0.5rem;
    left: 0.5rem;
    width: 0.65rem;
    height: 0.65rem;
    border-radius: 50%;
    border: 2px solid var(--surface);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);
    z-index: 2;
}

.browse-card-status-edit {
    background: var(--success);
}

.browse-card-status-view {
    background: var(--warning);
}

.browse-card-status-blocked {
    background: var(--danger);
}

/* Tryb sortowania "Recznie" (przycisk sortowania w topbarze) - karta
   przeciagnieta na inna karte wstawia sie przed/po niej (jak zdjecia w
   albumie), zamiast przenosic sie w inne miejsce drzewa (kursor "grab"
   ustawiony juz wyzej dla wszystkich kart, patrz [draggable="true"]). */
.browse-card.drop-before,
.browse-card.drop-after {
    position: relative;
}

.browse-card.drop-before::before,
.browse-card.drop-after::after {
    content: '';
    position: absolute;
    top: 0.25rem;
    bottom: 0.25rem;
    width: 3px;
    border-radius: 999px;
    background: var(--select);
    z-index: 3;
}

.browse-card.drop-before::before {
    left: -0.35rem;
}

.browse-card.drop-after::after {
    right: -0.35rem;
}

.browse-card-name {
    color: var(--text);
    font-size: 0.9rem;
    font-weight: 500;
    padding: 0 0.1rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    cursor: pointer;
}

.browse-card-details {
    display: none;
    gap: 1.25rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.browse-card-details .field {
    display: none;
}

/* Liczba elementow jest zawsze widoczna w trybie listy (jak dotad) -
   data ma dodatkowo wlasny przelacznik z menu opcji "...", dzialajacy
   w kazdym trybie widoku, nie tylko liscie. */
.cards-grid.view-list .browse-card-details .field-count {
    display: inline;
}

.cards-grid.view-list .browse-card-details .field-date,
.cards-grid.show-date-created .browse-card-details .field-date {
    display: inline;
}

.cards-grid.view-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.cards-grid.view-list .browse-card {
    flex-direction: row;
    align-items: center;
    gap: 0.75rem;
    padding: 0.4rem 0.5rem;
    border-radius: 8px;
}

.cards-grid.view-list .browse-card:hover {
    background: var(--surface);
}

.cards-grid.view-list .browse-card-media {
    width: 48px;
    height: 48px;
    flex-shrink: 0;
}

.cards-grid.view-list .browse-card-badge {
    display: none;
}

.cards-grid.view-list .browse-card-name {
    flex: 1;
    min-width: 0;
}

.cards-grid.view-list .browse-card-details,
.cards-grid.show-date-created .browse-card-details {
    display: flex;
    flex-shrink: 0;
}

/* --- Widok kolumnowy folderow (jak Finder na macOS) --- */

/* Stala, ograniczona wysokosc (nie 100vh) - w widoku konkretnego
   folderu ponizej kolumn nadal pokazuja sie jego zdjecia (ten sam
   #gallery, co w trybie kafelkowym), wiec kolumny musza zostawic na to
   miejsce, zamiast zajmowac caly ekran. */
.folders-columns {
    display: flex;
    align-items: stretch;
    gap: 0;
    overflow-x: auto;
    height: 340px;
    margin: 0 -1.25rem 1rem;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
}

.folders-column {
    flex: 0 0 260px;
    min-width: 260px;
    overflow-y: auto;
    padding: 0.5rem;
    border-right: 1px solid var(--border);
}

.folders-column-empty {
    padding: 0.75rem 0.6rem;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* Div (nie <button>) - zawiera przycisk otwierajacy folder + osobny
   przycisk "..." obok (patrz .browse-tree-menu-btn, ten sam plaski
   wzorzec co w wierszu drzewa) - dwa zagniezdzone <button> w jednym nie
   sa poprawnym HTML. */
.folders-column-item {
    display: flex;
    align-items: center;
    border-radius: 8px;
    padding-right: 0.4rem;
}

.folders-column-item:hover {
    background: var(--surface);
}

.folders-column-item.active {
    background: var(--select);
    color: #fff;
}

.folders-column-item-open {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: 1;
    min-width: 0;
    text-align: left;
    background: transparent;
    color: inherit;
    border: none;
    padding: 0.45rem 0.5rem;
    font-size: 0.85rem;
}

.folders-column-item:hover .browse-tree-menu-btn,
.folders-column-item .browse-tree-menu-btn.active {
    opacity: 1;
}

.folders-column-item-icon {
    position: relative;
    flex-shrink: 0;
    display: flex;
}

.folders-column-item-status {
    position: absolute;
    bottom: -2px;
    right: -2px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    border: 2px solid var(--surface);
}

.folders-column-item-status-edit {
    background: var(--success);
}

.folders-column-item-status-view {
    background: var(--warning);
}

.folders-column-item-status-blocked {
    background: var(--danger);
}

.folders-column-item-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.folders-column-item-chevron {
    flex-shrink: 0;
    opacity: 0.5;
}

.folders-column-item.active .folders-column-item-chevron {
    opacity: 0.9;
}

.browse-card-select {
    position: absolute;
    top: 0.4rem;
    left: 0.4rem;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.85);
    background: rgba(0, 0, 0, 0.35);
    padding: 0;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 2;
}

.cards-grid.selecting .browse-card-select,
.browse-card.selected .browse-card-select {
    opacity: 1;
}

.browse-card.selected .browse-card-select {
    background: var(--select);
    border-color: var(--select);
}

.browse-card.selected .browse-card-media {
    outline: 3px solid var(--select);
    outline-offset: -3px;
}

/* --- Strumien / galeria --- */

.gallery {
    padding: 0.5rem 1.25rem 1.5rem;
    --tile-gap: 6px;
}

.gallery.view-square {
    display: grid;
    gap: var(--tile-gap);
    grid-template-columns: repeat(auto-fill, minmax(var(--tile-size), 1fr));
}

.gallery.view-compact {
    display: grid;
    gap: var(--tile-gap);
    /* Tak samo jak Kwadraty (minmax(...,1fr)) - kolumny rozciagaja sie na
       pelna szerokosc ekranu zamiast zostawiac pusty pas z prawej strony
       przed zawinieciem do kolejnej kolumny. Zdjecie w komorce nadal nie
       jest przycinane (auto/max-* na <img> nizej) - rozciagniecie kolumny
       pozwala mu urosnac az do naturalnej rozdzielczosci pliku miniatury,
       a nie tylko powieksza puste tlo wokol niego. */
    grid-template-columns: repeat(auto-fill, minmax(var(--tile-size), 1fr));
}

.gallery.view-natural {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--tile-gap);
}

.gallery.view-masonry {
    columns: var(--tile-size);
    column-gap: var(--tile-gap);
}

.gallery.view-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.gallery.view-list .gallery-item {
    flex-direction: row;
    align-items: center;
    gap: 0.75rem;
    padding: 0.4rem 0.5rem;
    border-radius: 8px;
}

.gallery.view-list .gallery-item:hover {
    background: var(--surface);
}

.gallery.view-list .gallery-item-media {
    width: 56px;
    height: 56px;
    flex-shrink: 0;
    aspect-ratio: 1 / 1;
    border-radius: 6px;
}

.gallery.view-list .gallery-item-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.gallery.view-list .gallery-item-caption {
    flex: 1;
    min-width: 0;
    padding: 0;
    font-size: 0.85rem;
    color: var(--text);
}

.gallery.view-list .gallery-item-details {
    display: flex;
}

.gallery-date-header {
    padding: 1rem 0.25rem 0.25rem;
    font-weight: 600;
    color: var(--text-muted);
    font-size: 0.95rem;
    text-transform: capitalize;
}

.gallery.selecting .gallery-date-header {
    cursor: pointer;
    user-select: none;
}

.gallery.selecting .gallery-date-header:hover {
    color: var(--text);
}

.gallery.view-square .gallery-date-header,
.gallery.view-compact .gallery-date-header {
    grid-column: 1 / -1;
}

.gallery.view-natural .gallery-date-header {
    flex-basis: 100%;
}

.gallery.view-masonry .gallery-date-header {
    column-span: all;
}

.gallery-item {
    position: relative;
    display: flex;
    flex-direction: column;
}

@keyframes item-enter {
    from { opacity: 0; transform: scale(0.94); }
    to { opacity: 1; transform: scale(1); }
}

@keyframes item-leave {
    from { opacity: 1; transform: scale(1); }
    to { opacity: 0; transform: scale(0.9); }
}

.gallery-item.enter,
.upload-item.enter {
    animation: item-enter 0.25s ease;
}

.gallery-item.leaving,
.upload-item.leaving {
    animation: item-leave 0.2s ease forwards;
    pointer-events: none;
}

.gallery-item-media {
    position: relative;
    overflow: hidden;
    background: var(--surface);
    border-radius: var(--thumb-radius);
}

.gallery-item-media img {
    cursor: zoom-in;
    opacity: 0;
    /* Krotszy czas niz gdzie indziej (0.35s) - w trybach Bez przycinania/
       Masonry zdjecia ladujace sie z sieci (preview 1920px, patrz
       galleryImageSrc) koncza fade w mocno rozstrzelonych momentach
       (rozne czasy pobrania), co przy dlugim przejsciu wygladalo jak
       "migotanie" calej siatki - kilkanascie kafelkow jasniejacych w
       niezgranych falach. Krotsze przejscie nie usuwa rozrzutu w czasie
       (to kwestia sieci), ale kazdy pojedynczy "doskok" jest szybszy i
       mniej widoczny, wiec calosc wyglada bardziej jak kolejne,
       pojedyncze pojawienia sie niz ciagle, nakladajace sie gaszenie. */
    transition: opacity 0.18s ease;
}

.gallery-item-media img.loaded {
    opacity: 1;
}

/* Kazdy ".field" to WIERSZ (patrz renderDetailRows w gallery.js) - zwykle
   jeden segment (ikonka+tekst), ale aparat+obiektyw i migawka+przeslona+ISO
   dziela jeden wspolny wiersz, stad dodatkowy poziom ".field-segment". */
.gallery-item-caption {
    display: none;
    flex-direction: column;
    gap: 0.2rem;
    padding: 0.3rem 0.1rem 0;
    font-size: 0.75rem;
    color: var(--text-muted);
    overflow: hidden;
}

.gallery-item-caption .field {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
}

.gallery-item-caption .field-segment {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.gallery-item-caption .field-segment svg {
    flex-shrink: 0;
    opacity: 0.7;
}

/* "Szczegoly zdjecia" - pojedynczy przelacznik w menu opcji "..." (patrz
   OPTION_TOGGLES w gallery.js), w miejsce dawnych trzech osobnych (nazwa
   pliku / data dodania / data utworzenia). */
.gallery.show-photo-details .gallery-item-caption {
    display: flex;
}

/* Opis pod miniatura - wlaczany "Pokaz opisy" w menu Opcji (patrz
   OPTION_TOGGLES w gallery.js). Zawsze <textarea>, zero ramki/tla na kazdym
   etapie (rowniez w trakcie edycji). Wpisany opis ma byc widoczny OD RAZU w
   tym trybie (patrz :not(:placeholder-shown) nizej) - tylko PUSTY placeholder
   "Dodaj opis..." zostaje niewidoczny (opacity:0) dopoki kafelek nie jest
   hover/focus, jako delikatne zaproszenie do edycji bez zasmiecania widoku
   kafelkow bez opisu. Bez transparentnej ramki rezerwujacej miejsce (nie ma
   juz czego "odslaniac" przy hover), stad border: none zamiast 1px solid
   transparent. */
.gallery-item-description {
    display: none;
    width: 100%;
    box-sizing: border-box;
    margin: 0.3rem 0 0;
    font: inherit;
    font-size: 0.75rem;
    line-height: 1.35;
    color: var(--text);
    background: transparent;
    border: none;
    border-radius: 8px;
    padding: 0.25rem 0.4rem;
    resize: none;
    overflow: hidden;
    opacity: 0;
    transition: opacity 0.15s ease;
}

.gallery.show-description .gallery-item-description {
    display: block;
}

.gallery-item-description:focus {
    opacity: 1;
}

/* Hover tylko dla myszki - na dotyku pierwsze tapniecie pokazywaloby
   ukryte elementy zamiast otwierac zdjecie. */
@media (hover: hover) {
    .gallery-item:hover .gallery-item-description {
        opacity: 1;
    }
}

.gallery.show-description .gallery-item-description:not(:placeholder-shown) {
    opacity: 1;
}

.gallery-item-description:focus {
    outline: none;
}

.gallery-item-description[readonly] {
    cursor: default;
}

/* Placeholder "Dodaj opis..." ma zostac delikatny nawet po odslonieciu na
   hover (rodzic dochodzi do opacity:1, placeholder mnozy to swoimi 40%) -
   to tylko podpowiedz ze pole istnieje, nie ma przyciagac uwagi jak
   prawdziwy opis. */
.gallery-item-description::placeholder {
    color: var(--text);
    opacity: 0.4;
}

/* Widok Lista ma wlasny, ciasny uklad wiersza (patrz nizej) - wieloliniowy
   opis by go rozsadzil, wiec zostaje tylko w widokach siatki. */
.gallery.view-list .gallery-item-description {
    display: none;
}

.gallery-item-details {
    display: none;
    gap: 1.25rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.gallery-item-details span {
    min-width: 70px;
}

.gallery-item.dragging {
    opacity: 0.4;
}

/* --- Blok opisowy w albumie (album_blocks, migracja 015) - wstawiany w
   dowolnym miejscu miedzy zdjecia, jak w Google Photos. Bazuje na
   .gallery-item (ta sama klasa na elemencie), wiec dziedziczy pozycje/
   przeciaganie/drop-indicator za darmo - tylko wlasny wyglad i dwa
   tryby wyswietlania nizej. --- */
.gallery-item-block {
    background: var(--surface);
    border-radius: var(--thumb-radius);
    justify-content: center;
}

.gallery-item-block-text {
    width: 100%;
    box-sizing: border-box;
    border: none;
    background: transparent;
    resize: none;
    font: inherit;
    color: var(--text);
    padding: 0.7rem 0.9rem;
}

.gallery-item-block-text:focus {
    outline: none;
}

.gallery-item-block-text[readonly] {
    cursor: default;
}

/* Przycisk "..." bloku sluzy tez za uchwyt do przeciagania - <textarea>
   zajmuje caly srodek karty, a natywny drag nie startuje z wnetrza pola
   tekstowego (patrz komentarz przy tworzeniu przycisku w gallery.js), wiec
   to jedyne miejsce, z ktorego da sie zlapac blok myszka. Kursor "grab"
   sygnalizuje te druga funkcje - tylko tutaj, nie przy zwyklym "..." na
   zdjeciu (tam przeciaganie dziala z calej miniatury). */
.gallery-item-block-menu-btn {
    cursor: grab;
}

.gallery-item-block-menu-btn:active {
    cursor: grabbing;
}

/* Edycja blokow tylko w trybie "Pokaz opisy" (olowek) - poza nim bez
   "+", bez "..." i bez pustych blokow (patrz blockTextEditable). */
.gallery:not(.show-description) .gallery-insert-zone,
.gallery:not(.show-description) .gallery-item-block-menu-btn,
.gallery:not(.show-description) .gallery-item-block.is-empty {
    display: none;
}

/* Tryb "akapit" - pelna szerokosc tresci, ten sam zabieg co naglowek
   daty w strumieniu (patrz .gallery-date-header wyzej) - jeden wpis na
   kazdy uklad siatki/flex/columns uzywany przez widoki Pulpitu. */
.gallery.view-square .gallery-item-block.mode-paragraph,
.gallery.view-compact .gallery-item-block.mode-paragraph {
    grid-column: 1 / -1;
}

.gallery.view-natural .gallery-item-block.mode-paragraph {
    flex-basis: 100%;
}

.gallery.view-masonry .gallery-item-block.mode-paragraph {
    column-span: all;
    break-inside: avoid;
    margin-bottom: var(--tile-gap);
}

.gallery-item-block.mode-paragraph .gallery-item-block-text {
    font-size: 1.05rem;
    line-height: 1.5;
    min-height: 2.75rem;
}

/* Tryb "kafelek" - udaje zwykla miniature (ten sam kwadratowy ksztalt co
   .gallery-item-media w widokach Kwadraty/Kompakt/Masonry), tekst
   wysrodkowany i przyciety, bez specjalnego traktowania w widoku Listy
   (tam i tak kazdy element jest juz pelnoszerokim wierszem). */
.gallery-item-block.mode-tile {
    aspect-ratio: 1 / 1;
}

.gallery.view-list .gallery-item-block.mode-tile {
    aspect-ratio: auto;
}

.gallery-item-block.mode-tile .gallery-item-block-text {
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    height: 100%;
    overflow: hidden;
    font-size: 0.85rem;
}

/* "+" na krawedzi elementu (zdjecia lub bloku), widoczny na hover -
   wstawia nowy blok opisowy przed/po tym elemencie. Prawa krawedz
   elementu N to ta sama "szczelina" co lewa krawedz elementu N+1, wiec
   dwie strefy NA KAZDYM elemencie pokrywaja razem cala siatke, wlaczajac
   mozliwosc dopisania na samym koncu (prawa krawedz ostatniego elementu) -
   bez osobnego, dedykowanego "kafelka" na koncu. */
.gallery-insert-zone {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 28px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    cursor: pointer;
    z-index: 4;
    opacity: 0;
    /* Niewidoczna strefa MUSI byc tez nieklikalna - inaczej (opacity:0 samo
       w sobie nie wylacza trafien myszy) zajmuje "niewidzialnie" spory kawalek
       ekranu (28px x cala wysokosc kafla, na KAZDYM elemencie siatki) i lapie
       przypadkowe klikniecia w pobliskie miejsca, ktore wizualnie nie maja z
       nia nic wspolnego. Wlacza sie dopiero razem z opacity, na hover. */
    pointer-events: none;
    transition: opacity 0.15s ease;
}

.gallery-insert-zone-before {
    left: -14px;
}

.gallery-insert-zone-after {
    right: -14px;
}

/* Strefy istnieja tylko w trybie edycji opisow (poza nim display:none),
   wiec na dotyku pierwsze tapniecie dziala tu jak hover - pokazuje plusy. */
.gallery-item:hover .gallery-insert-zone,
.gallery-insert-zone:hover,
.gallery-insert-zone:focus-visible {
    opacity: 1;
    pointer-events: auto;
}

/* Nad trescia bloku strefa "+" nie moze lapac myszy - zaczynajac
   zaznaczanie tekstu przy krawedzi trafialo sie w nia i przeciagalo caly
   kafelek zamiast zaznaczac tekst (przy zdjeciu strefy sa przyciete do
   miniatury w JS, patrz addBlockInsertZones). */
.gallery-item:has(.gallery-item-block-text:hover) .gallery-insert-zone,
.gallery-item:has(.gallery-item-block-text:focus) .gallery-insert-zone {
    opacity: 0;
    pointer-events: none;
}

.gallery-insert-plus {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--accent);
    color: #fff;
    font-size: 1rem;
    line-height: 1;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
    transition: transform 0.15s ease;
}

.gallery-insert-zone:hover .gallery-insert-plus {
    transform: scale(1.15);
}

/* Widok Listy - elementy to pelnoszerokie wiersze uloze w pionie (patrz
   .gallery.view-list wyzej), wiec "miedzy elementami" oznacza gorna/dolna
   krawedz, nie lewa/prawa. */
.gallery.view-list .gallery-insert-zone {
    top: auto;
    bottom: auto;
    left: 0;
    right: 0;
    width: auto;
    height: 10px;
}

.gallery.view-list .gallery-insert-zone-before {
    top: -5px;
}

.gallery.view-list .gallery-insert-zone-after {
    bottom: -5px;
}

.gallery-item.drop-before,
.gallery-item.drop-after {
    position: relative;
}

.gallery-item.drop-before::before,
.gallery-item.drop-after::after {
    content: '';
    position: absolute;
    top: 0.25rem;
    bottom: 0.25rem;
    width: 3px;
    border-radius: 999px;
    background: var(--select);
    z-index: 3;
}

.gallery-item.drop-before::before {
    left: -0.35rem;
}

.gallery-item.drop-after::after {
    right: -0.35rem;
}

.gallery.view-square .gallery-item-media {
    aspect-ratio: 1 / 1;
}

.gallery.view-compact .gallery-item-media {
    aspect-ratio: 1 / 1;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
}

.gallery.view-natural .gallery-item-media {
    height: var(--tile-size);
}

.gallery.view-masonry .gallery-item {
    break-inside: avoid;
    margin-bottom: 14px;
}

.gallery.view-square .gallery-item-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.gallery.view-compact .gallery-item-media img {
    /* Fallback dla przypadku bez znanych wymiarow (photos.width/height sa
       NOT NULL, wiec w praktyce nie powinno sie zdarzyc) - auto/max-* jak
       wczesniej. Realne zdjecia dostaja jedna z klas ponizej
       (photo-portrait/photo-landscape, ustawianych w createGalleryItem w
       gallery.js razem z jawnym inline aspect-ratio). */
    width: auto;
    height: auto;
    max-width: 100%;
    max-height: 100%;
    border-radius: var(--thumb-radius);
    display: block;
}

/* Orientacja (klasa) + jawny inline aspect-ratio (oba ustawiane przez JS
   z photo.width/height, PRZED zaladowaniem pliku) razem daja <img>
   docelowy rozmiar NATYCHMIAST, bez czekania az przegladarka pozna
   prawdziwe piksele - eliminuje "skok" przy leniwym ladowaniu
   (loading="lazy"). Sam atrybut width/height na <img> (bez jawnego CSS
   aspect-ratio) w tym ukladzie (flex + width/height:auto + max-*) NIE
   wystarczyl przegladarce - box renderowal sie jako 0x0 az do
   zaladowania. Ktora os jest "pelna 100%" (a druga wyliczona z
   aspect-ratio) musi zalezec od orientacji zdjecia w KWADRATOWYM
   kontenerze - jedna wspolna regula zniekstalcalaby drugi wariant
   (potwierdzone empirycznie: "landscape" na width:100%+max-height dziala
   poprawnie, ale to samo dla "portrait" rozciaga zdjecie do kwadratu,
   bo przegladarka nie doliczala z powrotem szerokosci po zadzialaniu
   max-height). */
.gallery.view-compact .gallery-item-media img.photo-portrait {
    width: auto;
    height: 100%;
    max-width: 100%;
    max-height: none;
}

.gallery.view-compact .gallery-item-media img.photo-landscape {
    width: 100%;
    height: auto;
    max-width: none;
    max-height: 100%;
}

.gallery.view-masonry .gallery-item-media img {
    width: 100%;
    height: auto;
    display: block;
    cursor: zoom-in;
}

.gallery.view-natural .gallery-item-media img {
    height: 100%;
    width: auto;
    object-fit: cover;
    display: block;
    cursor: zoom-in;
}

.gallery-item-select {
    position: absolute;
    top: 0.4rem;
    left: 0.4rem;
    width: 1.5rem;
    height: 1.5rem;
    border-radius: 50%;
    border: 2px solid rgba(255, 255, 255, 0.85);
    background: rgba(0, 0, 0, 0.35);
    padding: 0;
    opacity: 0;
    transition: opacity 0.15s;
    z-index: 2;
}

.gallery.selecting .gallery-item-select,
.gallery-item.selected .gallery-item-select {
    opacity: 1;
}

.gallery.selecting .gallery-item img {
    cursor: pointer;
}

#select-mode-btn.active,
#caption-toggle-btn.active {
    background: var(--accent);
    color: white;
}

.gallery-item.selected .gallery-item-select {
    background: var(--select);
    border-color: var(--select);
}

.gallery-item.selected img {
    outline: 3px solid var(--select);
    outline-offset: -3px;
}

.selection-bar {
    position: fixed;
    bottom: 1.25rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 0.6rem;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.6rem 1.1rem;
    z-index: 60;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
    max-width: calc(100vw - 2rem);
    flex-wrap: nowrap;
}

/* Ponizej progu, na ktorym etykiety przyciskow zaczelyby sie zawijac,
   chowamy same napisy (ikony zostaja w pelnym rozmiarze) zamiast pozwolic
   im skurczyc sie lub przejsc na dwie linie. */
@media (max-width: 700px) {
    .upload-queue {
        left: 1rem;
        right: 1rem;
        width: auto;
    }

    .selection-bar .btn-label {
        display: none;
    }

    .selection-bar button.btn-icon-label {
        padding-left: 0.6rem;
        padding-right: 0.6rem;
    }

    /* Na waskim ekranie boczne menu na stale zajmowaloby polowe
       szerokosci - zamiast tego staje sie chowana szuflada nad trescia,
       otwierana przyciskiem-hamburgerem w topbarze. */
    .sidebar {
        position: fixed;
        top: 0;
        left: 0;
        bottom: 0;
        width: 240px;
        max-width: 80vw;
        height: auto;
        z-index: 80;
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        box-shadow: 0 0 24px rgba(0, 0, 0, 0.25);
    }

    .sidebar.mobile-open {
        transform: translateX(0);
    }

    /* Stan "zwiniete" ma byc bez znaczenia na waskim ekranie - szuflada
       zawsze pokazuje pelne etykiety, niezaleznie od domyslnego stanu
       zapisanego dla widoku desktopowego (patrz SIDEBAR_COLLAPSE_STORAGE_KEY
       w gallery.js, domyslnie wlaczone). */
    .sidebar.collapsed {
        width: 240px;
    }

    .sidebar.collapsed .sidebar-brand-name,
    .sidebar.collapsed .nav-link-label {
        display: inline;
    }

    .sidebar.collapsed .sidebar-brand {
        justify-content: space-between;
    }

    .sidebar.collapsed .nav-link {
        justify-content: flex-start;
    }

    .sidebar.collapsed .sidebar-footer {
        justify-content: flex-end;
    }

    #sidebar-collapse {
        display: none;
    }

    .sidebar-mobile-toggle {
        display: flex;
    }

    /* Drzewo folderow/albumow na waskim ekranie zajmuje cala szerokosc
       (zamiast dawnych max. 75vw, zostawiajacych wasny, bezuzyteczny
       pasek tresci z boku) - i tak nie da sie go zwezic dotykiem (uchwyt
       do zmiany szerokosci dziala tylko myszka), a klikniecie w
       folder/album chowa je automatycznie (patrz renderTreeChildren w
       gallery.js), wiec pelna szerokosc nie przeszkadza w dotarciu do
       tresci. */
    .browse-tree {
        width: 100%;
        max-width: 100%;
    }

    .browse-tree-resize-handle {
        display: none;
    }

    /* Ikony w topbarze nie zawijaja sie (nie mieszcza sie wszystkie razem
       na waskim ekranie) - zamiast obcinac je poza ekran, pozwalamy
       przewinac ten pasek w poziomie. Samo overflow-x: auto NIE
       wystarczylo - .topbar-actions ma (na szerokim ekranie celowo)
       flex-shrink: 0, wiec zamiast dac sie scisnac do dostepnego miejsca,
       caly rzad renderowal sie na pelna, naturalna szerokosc tresci i to
       ONA rozpychala .topbar (i cala strone) w poziomie - overflow-x nie
       mial czego przewijac, bo wewnatrz elementu nic nie przekraczalo
       jego (i tak juz nadmiarowej) wlasnej szerokosci. flex-shrink: 1 +
       min-width: 0 (nadpisuje domyslne auto, ktore i tak blokowaloby
       skurczenie ponizej tresci) pozwalaja elementowi realnie zmiescic
       sie w dostepnej przestrzeni - dopiero wtedy jest co przewijac. */
    /* Bez tego .breadcrumb (tez flex:1; min-width:0) oddawal CALA swoja
       szerokosc akcjom obok i znikal calkowicie, gdy oba nie mieszcily sie
       razem - a wtedy nie widac juz w jakim folderze/albumie jest sie
       aktualnie. Wymuszony minimalny pasek zostawia chociaz kawalek nazwy
       widoczny, reszte miejsca oddajac (nadal przewijalnym) ikonom. */
    .breadcrumb {
        min-width: 4.5rem;
    }

    .topbar-actions {
        flex-shrink: 1;
        min-width: 0;
        overflow-x: auto;
        scrollbar-width: none;
    }

    .topbar-actions::-webkit-scrollbar {
        display: none;
    }

    /* Na szerokim ekranie 4rem zostawia miejsce na strzalki nawigacji -
       na telefonie tylko marnuje przestrzen na zdjecie (nawigacja dziala
       tu przez przeciagniecie palcem). */
    .lightbox-stage {
        padding: 0 0.5rem;
    }

}

.empty-state {
    text-align: center;
    color: var(--text-muted);
    margin-top: 3rem;
}

/* Wskaznik "trwa ladowanie" - odrozniaj puste miejsce (Brak zdjec/Brak
   wynikow) od miejsca, gdzie tresc jeszcze sie laduje. Uzywany zarowno
   przy doladowywaniu kolejnych stron (pod siatka/przy sentinelu), jak i
   przy pierwszym wejsciu w widok (foldery/albumy/wyszukiwarka). */
.loading-indicator {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    color: var(--text-muted);
    font-size: 0.85rem;
    padding: 1.5rem 0;
}

.spinner {
    display: inline-block;
    width: 30px;
    height: 30px;
    border: 3px solid var(--border);
    border-top-color: var(--text-muted);
    border-radius: 50%;
    animation: spinner-spin 0.7s linear infinite;
}

@keyframes spinner-spin {
    to { transform: rotate(360deg); }
}

.dropzone {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    border: 3px dashed var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 0.5rem;
    font-size: 1.5rem;
    z-index: 100;
    cursor: pointer;
    color: var(--text);
}

.dropzone small {
    font-size: 0.9rem;
    font-weight: normal;
    opacity: 0.7;
}

.upload-queue {
    position: fixed;
    bottom: 1rem;
    right: 1rem;
    width: 300px;
    max-height: 60vh;
    display: flex;
    flex-direction: column;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
    z-index: 50;
    overflow: hidden;
}

.upload-queue-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.6rem 0.75rem;
    border-bottom: 1px solid var(--border);
    font-size: 0.85rem;
    font-weight: 600;
    flex-shrink: 0;
}

.upload-queue-header-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-shrink: 0;
}

.upload-queue-cancel-all {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.8rem;
    font-weight: normal;
    cursor: pointer;
    padding: 0;
}

.upload-queue-cancel-all:hover {
    color: var(--danger);
}

.upload-queue-collapse-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.2rem;
    height: 1.2rem;
    flex-shrink: 0;
    background: none;
    border: none;
    border-radius: 4px;
    padding: 0;
    color: var(--text-muted);
    cursor: pointer;
}

.upload-queue-collapse-btn:hover {
    background: var(--surface-2);
    color: var(--text);
}

.upload-queue-collapse-btn svg {
    transition: transform 0.15s ease;
}

.upload-queue.collapsed .upload-queue-collapse-btn svg {
    transform: rotate(-180deg);
}

.upload-queue.collapsed .upload-queue-list {
    display: none;
}

.upload-queue-list {
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    /* ~5 wierszy (padding+nazwa+pasek postepu kazdego, patrz .upload-item
       nizej) - przy wiekszej liczbie plikow lista przewija sie w srodku,
       panel nie rosnie w nieskonczonosc na cala wysokosc ekranu. */
    max-height: 262px;
}

.upload-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    font-size: 0.85rem;
    border-bottom: 1px solid var(--border);
}

.upload-item:last-child {
    border-bottom: none;
}

.upload-item-info {
    flex: 1;
    min-width: 0;
}

.upload-item .name {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    display: block;
    margin-bottom: 0.3rem;
}

.upload-item progress {
    width: 100%;
}

.upload-item-cancel {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: none;
    border: none;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    padding: 0;
}

.upload-item-cancel:hover {
    background: var(--surface-2);
    color: var(--danger);
}

.upload-item.error {
    color: var(--danger);
}

/* --- Dialogi wyboru (album / folder) --- */

.picker {
    background: var(--surface);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 1.5rem;
    width: 440px;
    max-width: 90vw;
}

.picker::backdrop {
    background: rgba(0, 0, 0, 0.5);
}

/* Okna wyboru folderu/albumu (przenoszenie, dodawanie do albumu) - duzo
   wiecej miejsca niz zwykly .picker (np. #prompt-dialog, ktory ma zostac
   maly), bo lista potrafi byc dluga/glboko zagniezdzona. */
.picker-large {
    width: 600px;
    max-width: 92vw;
}

.picker-large .picker-list {
    max-height: 60vh;
}

.picker h2 {
    margin: 0 0 1rem;
    font-size: 1.05rem;
}

.picker-new {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 1rem;
}

.picker-new input {
    flex: 1;
    min-width: 0;
    font: inherit;
    padding: 0.5rem 0.75rem;
    border-radius: 999px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
}

.picker-new button {
    white-space: nowrap;
}

.picker-list {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0;
    max-height: 240px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
}

.picker-item {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    text-align: left;
    background: transparent;
    color: var(--text-muted);
    border: none;
    border-radius: 8px;
    padding: 0.5rem 0.75rem;
    font-size: 0.9rem;
    cursor: pointer;
}

.picker-item:hover {
    background: var(--surface-2);
    color: var(--text);
}

.picker-item-label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.picker-empty {
    color: var(--text-muted);
    font-size: 0.85rem;
    padding: 0.5rem;
}

.confirm-dialog-message {
    margin: 0 0 1.25rem;
    color: var(--text-muted);
    font-size: 0.9rem;
    line-height: 1.5;
}

.info-dialog-body {
    margin: 0 0 1.25rem;
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.5rem 1rem;
    font-size: 0.9rem;
}

.info-dialog-body dt {
    color: var(--text-muted);
}

.info-dialog-body dd {
    margin: 0;
    color: var(--text);
    word-break: break-word;
}

.info-dialog-name-input,
.info-dialog-taken-at-input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 0.3rem 0.5rem;
    font: inherit;
    font-size: 0.9rem;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
}

.info-dialog-description-label {
    display: block;
    margin: 0 0 1.25rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.info-dialog-description-label textarea {
    display: block;
    width: 100%;
    margin-top: 0.35rem;
    padding: 0.5rem 0.75rem;
    font: inherit;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 10px;
    resize: vertical;
    box-sizing: border-box;
}

.info-dialog-description-readonly {
    margin: 0 0 1.25rem;
    font-size: 0.9rem;
    color: var(--text);
    white-space: pre-wrap;
    word-break: break-word;
}

/* "Publikuj w galerii" - private/friends/public (tylko albumy, patrz Faza 0
   w SESSION.md) - ten sam odstep/kolor co reszta dialogu Wlasciwosci. */
.info-dialog-public {
    margin: 0 0 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.info-dialog-public-select-label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: var(--text);
}

.info-dialog-public-select-label select {
    padding: 0.3rem 0.5rem;
    font: inherit;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-sizing: border-box;
}

.info-dialog-public-order-label {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    color: var(--text-muted);
}

.info-dialog-public-order-label input {
    width: 70px;
    padding: 0.3rem 0.5rem;
    font: inherit;
    color: var(--text);
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-sizing: border-box;
}

.info-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
}

/* Opis folderu/albumu pokazany jako wstep nad siatka (jak w Google
   Photos) - edytowalny wprost tutaj (bez osobnego dialogu), zapisywany
   przy odkliknieciu pola (blur), nie na kazde nacisniecie klawisza. */
.collection-description {
    padding: 0.25rem 1.25rem 0.75rem;
}

.collection-description-input {
    display: block;
    width: 100%;
    box-sizing: border-box;
    font: inherit;
    font-size: 0.9rem;
    color: var(--text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 10px;
    padding: 0.4rem 0.6rem;
    resize: none;
    overflow: hidden;
}

.collection-description-input:hover,
.collection-description-input:focus {
    background: var(--surface);
    border-color: var(--border);
}

.collection-description-input:focus {
    outline: none;
}

.collection-description-readonly {
    margin: 0;
    padding: 0.4rem 0.6rem;
    font-size: 0.9rem;
    color: var(--text-muted);
    white-space: pre-wrap;
    word-break: break-word;
}

/* Brak opisu (ale canEdit, patrz updateCollectionDescriptionEmptyState()
   w gallery.js) - caly wiersz zwiniety do cienkiej, niewidocznej linii
   zamiast rezerwowac pelna wysokosc pola z placeholderem "Dodaj opis..."
   (na wyrazne zyczenie: miniatury maja sie zaczynac od razu, jakby opisu
   nie bylo). Prawdziwe pole (textarea) zostaje CALKOWICIE niewidoczne w
   tym stanie (tekst placeholdera nigdy sie nie pokazuje - przy 10px
   wysokosci i tak by sie nie zmiescil i wylewal nad wiersz, stad
   .collection-description-add-btn ponizej jako jedyna, czysto
   dekoracyjna podpowiedz na hover: pozioma kreska + "+" na srodku, ten
   sam wzorzec co .gallery-insert-zone przy blokach opisowych w albumie.
   Klikniecie w ten przycisk (nie w sama textarea) rozwija prawdziwe pole
   do edycji - patrz listener w gallery.js. */
.collection-description.is-empty {
    position: relative;
    padding-top: 0.25rem;
    padding-bottom: 0.25rem;
}

.collection-description.is-empty .collection-description-input {
    height: 24px;
    min-height: 0;
    padding: 0;
    border: none;
    opacity: 0;
    pointer-events: none;
}

.collection-description.is-empty .collection-description-input::placeholder {
    opacity: 0;
}

.collection-description.is-empty .collection-description-input:focus {
    position: relative;
    height: auto;
    min-height: 2rem;
    padding: 0.4rem 0.6rem;
    border: 1px solid var(--border);
    border-radius: 10px;
    opacity: 1;
    pointer-events: auto;
    background: var(--surface);
}

.collection-description-add-btn {
    display: none;
    position: absolute;
    left: 1.25rem;
    right: 1.25rem;
    /* "top" liczy sie od GORNEJ KRAWEDZI PADDING BOXA rodzica, nie od konca
       jego padding-top (patrz Pulapki w SESSION.md) - stad jawny offset
       zamiast polegania na padding-top .collection-description.is-empty. */
    top: 4px;
    height: 24px;
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    cursor: pointer;
}

.collection-description-add-btn::before {
    content: '';
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 2px;
    background: var(--select);
    transform: translateY(-50%);
    opacity: 0;
    transition: opacity 0.15s ease;
}

.collection-description-add-plus {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--select);
    color: #fff;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1rem;
    line-height: 1;
    box-shadow: 0 1px 4px rgba(0, 0, 0, 0.25);
    opacity: 0;
    transition: opacity 0.15s ease;
}

.collection-description.is-empty .collection-description-add-btn {
    display: block;
}

.collection-description.is-empty:hover .collection-description-add-btn::before,
.collection-description.is-empty:hover .collection-description-add-plus,
.collection-description-add-btn:focus-visible::before,
.collection-description-add-btn:focus-visible .collection-description-add-plus {
    opacity: 1;
}

/* Pole juz w trybie edycji (focus) - przycisk-podpowiedz znika, zostaje
   tylko prawdziwa textarea. */
.collection-description.is-empty:focus-within .collection-description-add-btn {
    display: none;
}

.share-dialog-status {
    margin: 0 0 1.25rem;
    color: var(--text-muted);
    font-size: 0.85rem;
    min-height: 1.2em;
}

.share-dialog-controls-toggle {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: 0 0 1.25rem;
    font-size: 0.85rem;
    color: var(--text);
    cursor: pointer;
}

.share-dialog-grants {
    border-top: 1px solid var(--border);
    padding-top: 1rem;
    margin-bottom: 1.25rem;
}

.share-dialog-grants-title {
    font-size: 0.85rem;
    margin: 0 0 0.6rem;
    color: var(--text-muted);
}

.share-dialog-grants .accounts-list {
    max-width: none;
}

.share-dialog-grant-form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.confirm-dialog-checkbox-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin: -0.5rem 0 1.25rem;
    font-size: 0.85rem;
    color: var(--text);
    cursor: pointer;
}

.confirm-dialog-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.5rem;
}

/* --- Lightbox --- */

.lightbox {
    position: fixed;
    inset: 0;
    background: #08080a;
    z-index: 200;
    /* Bez tego html { touch-action: manipulation } (patrz wyzej w pliku)
       "przeswiecal" przez ten pelnoekranowy overlay - przegladarka
       jednoczesnie ze swipe/pan/pinch obslugiwanym w JS probowala tez
       przewinac/oddalic STRONE POD spodem. touch-action: none oddaje
       obsluge kazdego gestu dotykowego w calosci wlasnej logice
       gallery.js (swipeState/panState/pinchState). */
    touch-action: none;
    transition: background-color 0.3s ease;
}

/* SAMO tlo gasnie/pojawia sie plynnie przy otwarciu/zamknieciu (patrz
   openLightboxAt/closeLightbox w gallery.js) - zamiast skokowego
   pojawienia/zniknieca w momencie przelaczenia atrybutu hidden.
   Celowo background-color, NIE opacity - opacity na .lightbox
   "przeciekaloby" w dol na zdjecie (ten sam element jest jego
   przodkiem), gaszac je razem z tlem; zdjecie ma zostac w pelni
   widoczne przez caly czas, samo tylko animuje zoom (transform). */
.lightbox.lightbox-entering {
    background-color: transparent;
}

/* Domyslnie (bez "Ramki") zdjecie zajmuje CALY ekran - topbar i podpis
   pokazuja sie NAD nim (position: absolute, na gradiencie dla
   czytelnosci), zamiast zabierac wlasny wiersz w ukladzie flex. "Ramka"
   (patrz .lightbox.framed nizej) przywraca dawny, stonowany uklad, w
   ktorym topbar/podpis maja wlasne miejsce, a zdjecie nie zachodzi pod
   nie. */
.lightbox-topbar {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    display: flex;
    /* flex-start, nie center - gdy "Szczegoly zdjecia" robi lewa strone
       wieloliniowa (wyzsza niz prawa), center wyśrodkowywalby przyciski po
       prawej (w tym X) w pionie w srodku calego (teraz wyzszego) paska,
       zamiast zostawic je przy samej gorze okna. */
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 1.25rem;
    flex-wrap: wrap;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.55), transparent);
    z-index: 3;
    transition: opacity 0.4s ease;
}

.lightbox.chrome-hidden .lightbox-topbar,
.lightbox.chrome-hidden .lightbox-caption,
.lightbox.chrome-hidden .lightbox-nav {
    opacity: 0;
    pointer-events: none;
}

.lightbox-topbar-left {
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
    min-width: 0;
}

.lightbox-icon-btn {
    background: transparent;
    color: white;
    font-size: 1.6rem;
    line-height: 1;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
}

.lightbox-icon-btn:hover {
    background: rgba(255, 255, 255, 0.12);
    opacity: 1;
}

.lightbox-icon-btn.active {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    opacity: 1;
}

/* "Szczegoly zdjecia" (przelacznik w menu ustawien) - nazwa/daty/
   rozdzielczosc/aparat+obiektyw/ekspozycja, kazde we wlasnym wierszu
   (aparat+obiektyw i migawka+przeslona+ISO dziela jeden wspolny wiersz -
   patrz renderDetailRows/photoDetailRows w gallery.js). Ukryte domyslnie
   (atrybut hidden, patrz applyLightboxDetails w gallery.js). */
.lightbox-details {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.82rem;
    min-width: 0;
}

.lightbox-details-row {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.35rem 0.9rem;
}

.lightbox-details-segment {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    white-space: nowrap;
}

.lightbox-details-segment svg {
    flex-shrink: 0;
    opacity: 0.7;
}

.lightbox-topbar-right {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    justify-content: flex-end;
}

.lightbox-stage {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    overflow: hidden;
}

/* "Ramka" (menu "..." w lightboxie) przywraca dawny, stonowany uklad -
   topbar/podpis dostaja z powrotem wlasne miejsce w kolumnie flex (juz
   nie zachodza na zdjecie), a stage odstep po bokach. Bez tej klasy
   (domyslnie) topbar/podpis "unosza sie" nad zdjeciem, ktore wypelnia
   caly ekran (patrz .lightbox-stage/.lightbox-topbar/.lightbox-caption
   wyzej/nizej). */
.lightbox.framed {
    display: flex;
    flex-direction: column;
}

.lightbox.framed .lightbox-topbar {
    position: relative;
    background: none;
}

.lightbox.framed .lightbox-stage {
    position: relative;
    flex: 1;
    min-height: 0;
    padding: 0 4rem;
}

.lightbox.framed .lightbox-caption {
    position: relative;
    background: none;
}

.lightbox-stage img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--lightbox-radius);
    transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.35s ease;
}

/* W trakcie pinch-zoom/swipe (gallery.js) transform aktualizuje sie co
   klatke, kazda zmiana probowalaby animowac przez powyzsze 0.35s -
   obrazek gonilby palce z opoznieniem i "dojezdzal" po ich puszczeniu.
   Ta klasa wlacza sie tylko na czas trwania gestu. */
.lightbox-stage img.gesture-active {
    transition: none;
}

#lightbox-img-crossfade {
    position: absolute;
    inset: 0;
    margin: auto;
    pointer-events: none;
    z-index: 1;
}

@keyframes lightbox-crossfade-out {
    from { opacity: 1; }
    to { opacity: 0; }
}

#lightbox-img-crossfade.anim-crossfade-out {
    animation: lightbox-crossfade-out 0.9s ease-in-out forwards;
}

.lightbox-caption {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    text-align: center;
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.85rem;
    padding: 1.5rem 1.25rem 1rem;
    min-height: 1.2em;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.55), transparent);
    z-index: 3;
    transition: opacity 0.4s ease;
}

@keyframes lightbox-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes lightbox-slide-in-right {
    from { transform: translateX(60px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

@keyframes lightbox-slide-in-left {
    from { transform: translateX(-60px); opacity: 0; }
    to { transform: translateX(0); opacity: 1; }
}

#lightbox-img.anim-fade {
    animation: lightbox-fade-in 0.9s ease-in-out;
}

#lightbox-img.anim-slide-right {
    animation: lightbox-slide-in-right 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

#lightbox-img.anim-slide-left {
    animation: lightbox-slide-in-left 0.7s cubic-bezier(0.22, 1, 0.36, 1);
}

.lightbox-close {
    position: absolute;
    top: 1rem;
    right: 1.25rem;
    background: transparent;
    font-size: 2rem;
    line-height: 1;
    color: white;
}

.lightbox-toolbar {
    position: absolute;
    top: 1.25rem;
    left: 1.25rem;
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.lightbox-pill-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.9);
    font-size: 0.85rem;
    padding: 0.45rem 0.85rem;
}

.lightbox-pill-btn:hover {
    background: rgba(255, 255, 255, 0.18);
    opacity: 1;
}

.lightbox-dropdown {
    position: relative;
}

.lightbox-dropdown-menu {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    background: rgba(32, 32, 34, 0.97);
    border-radius: 14px;
    padding: 0.4rem;
    min-width: 150px;
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
    z-index: 10;
}

.lightbox-dropdown-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.55rem 0.75rem;
    border-radius: 8px;
    background: transparent;
    color: rgba(255, 255, 255, 0.88);
    font-size: 0.88rem;
    text-align: left;
}

.lightbox-dropdown-item:hover {
    background: rgba(255, 255, 255, 0.1);
    opacity: 1;
}

.lightbox-dropdown-item.active::after {
    content: '\2713';
    color: rgba(255, 255, 255, 0.9);
}

/* Warianty dla menu "Wiecej opcji" (photoContextMenuItems) - w
   odroznieniu od statycznych list wyboru (zoom/ustawienia), te pozycje
   maja ikonke PRZED etykieta, wiec potrzebuja flex-start zamiast
   dziedziczonego z .lightbox-dropdown-item space-between. Kolor na sztywno
   (nie var(--text)) - ta sama logika co .lightbox-dropdown-item: tlo
   zawsze ciemne (lightbox jest zawsze dark), niezaleznie od motywu calej
   strony. var(--danger) jest bezpieczny (ta sama czerwien w obu motywach,
   patrz definicja w :root). */
#lightbox-more-menu {
    /* Dluzsze etykiety (np. "Przenies do folderu...") zawijaly sie do
       dwoch linii przy domyslnym min-width: 150px odziedziczonym z
       .lightbox-dropdown-menu. */
    min-width: 230px;
}

.lightbox-dropdown-item-icon {
    justify-content: flex-start;
    gap: 0.6rem;
}

.lightbox-dropdown-item-icon svg {
    flex-shrink: 0;
    opacity: 0.7;
}

.lightbox-dropdown-item-danger {
    color: var(--danger);
}

/* Wiersz "Szczegoly zdjecia" + strzalka otwierajaca podmenu wyboru
   wierszy - ten sam wzorzec co .view-menu-item-row w widoku miniatur. */
.lightbox-dropdown-item-row {
    display: flex;
    align-items: center;
    gap: 0.1rem;
}

.lightbox-dropdown-item-row .lightbox-dropdown-item {
    flex: 1 1 auto;
}

.lightbox-dropdown-item-expand {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    color: rgba(255, 255, 255, 0.6);
    border: none;
    border-radius: 8px;
    padding: 0.45rem 0.5rem;
}

.lightbox-dropdown-item-expand:hover {
    background: rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.9);
}

/* Podmenu boczne z wyborem, ktore wiersze "Szczegolow zdjecia" pokazywac -
   JEDEN wspolny element (patrz ensureDetailRowsSubmenu w gallery.js),
   przenoszony miedzy wywolaniem z widoku miniatur (jasny motyw, klasa
   .view-menu) i z lightboxa (zawsze ciemny, klasa .lightbox-dropdown-menu)
   - stad position:fixed na sztywno (JS i tak liczy left/top wzgledem
   przycisku, ktory go otworzyl), zamiast dziedziczonego z ktorejkolwiek
   bazowej klasy position:absolute/top/right. Element jest dzieckiem <body>
   (NIE lightboxa), wiec w wariancie ciemnym nie dziedziczy stacking
   contextu lightboxa - z-index musi samodzielnie przebic .lightbox (200). */
.detail-rows-submenu {
    position: fixed !important;
    top: 0;
    left: 0;
    right: auto;
    z-index: 210;
}

.lightbox-settings-menu {
    min-width: 190px;
}

.lightbox-dropdown-divider {
    height: 1px;
    margin: 0.35rem 0.25rem;
    background: rgba(255, 255, 255, 0.12);
}

.lightbox-dropdown-section-label {
    padding: 0.3rem 0.75rem 0.1rem;
    font-size: 0.72rem;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: rgba(255, 255, 255, 0.5);
}

.lightbox-nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 3rem;
    height: 3rem;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.1);
    color: white;
    font-size: 1.25rem;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: opacity 0.4s ease, background-color 0.15s;
}

.lightbox-nav:hover {
    background: rgba(255, 255, 255, 0.25);
}

.lightbox-nav:disabled {
    opacity: 0.25;
    cursor: default;
}

.lightbox-prev {
    left: 1rem;
}

.lightbox-next {
    right: 1rem;
}

/* Strzalki nawigacji chowane na dotykowych ekranach - jedyny sposob
   zmiany zdjecia to przeciagniecie palcem (patrz gallery.js, swipe).
   pointer: coarse (nie szerokosc ekranu) - duzy telefon w poziomie albo
   tablet moze byc szerszy niz 700px z bloku #sidebar/#browse-tree wyzej,
   a nadal jest dotykowy. Regula MUSI byc PO bazowej .lightbox-nav (display:
   flex) - przy rownej specyficznosci wygrywa kolejnosc w pliku, wczesniej
   umieszczona tutaj regula byla nadpisywana. */
@media (pointer: coarse) {
    .lightbox-nav {
        display: none;
    }

    /* Suwak rozmiaru miniatur - male kropki i cienki pasek sa za trudne do
       trafienia palcem (dzialaja porzadnie tylko myszka) - na dotyku i tak
       jest pinch (patrz PINCH_GRIDS w gallery.js), ktory robi dokladnie to
       samo, wygodniej. */
    .thumb-size-slider {
        display: none;
    }
}

/* --- Logowanie --- */

.login-page {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100vh;
}

.login-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 2rem;
    width: 280px;
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.login-card label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.9rem;
    color: var(--text-muted);
}

.login-card input {
    font: inherit;
    padding: 0.5rem;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--bg);
    color: var(--text);
}

.login-card .error {
    color: var(--danger);
    font-size: 0.85rem;
    margin: 0;
}

/* Checkbox obok tekstu (nie nad nim, jak w .login-card label wyzej) -
   selektor z dodatkowa klasa, zeby przebic specyficznosc ".login-card
   label" powyzej bez !important. */
.login-card label.login-remember {
    flex-direction: row;
    align-items: center;
    gap: 0.5rem;
}

.login-links {
    text-align: center;
    font-size: 0.85rem;
    margin: 0;
}

.login-links a {
    color: var(--accent);
}

/* forgot-password.php/reset-password.php - opis nad polami i komunikat po
   udanym wyslaniu/zmianie hasla. #reset-fields grupuje pola + przycisk
   reset-password.php w jeden flex-item .login-card, zeby ukryc je razem
   (jednym hidden) po udanej zmianie hasla, bez ukrywania calego <form> (w
   ktorym zagniezdzony jest tez link powrotu do logowania). */
.login-hint {
    font-size: 0.85rem;
    color: var(--text-muted);
    margin: 0;
}

.login-success {
    color: var(--success);
    font-size: 0.85rem;
    margin: 0;
}

#reset-fields {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

/* --- Kregi odbiorcow (migracja 023): kropki na miniaturach, pasek grup
   ("Pokaz jako" / przypisywanie), wybor kregu w oknie udostepniania --- */
.audience-dot {
    display: inline-block;
    width: 0.6rem;
    height: 0.6rem;
    border-radius: 50%;
    flex: none;
}

.gallery-item-audiences {
    position: absolute;
    bottom: 0.4rem;
    left: 0.4rem;
    display: flex;
    gap: 0.2rem;
    padding: 0.2rem 0.3rem;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.35);
    z-index: 2;
    pointer-events: auto;
}

/* Kropki widoczne tylko w trybie grup (przycisk "Grupy" wlaczony). */
.gallery:not(.audience-bar-on) .gallery-item-audiences {
    display: none;
}

.gallery-item-audiences .audience-dot {
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.7);
}

.gallery-item.audience-dimmed .gallery-item-media {
    opacity: 0.2;
    filter: grayscale(1);
    transition: opacity 0.15s, filter 0.15s;
}

.audience-preview-bar {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    padding: 0 1.25rem 0.75rem;
    font-size: 0.8rem;
    color: var(--text-muted);
}

.audience-preview-options {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
}

.audience-preview-btn,
.share-dialog-audience-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.audience-preview-btn {
    background: transparent;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 0.25rem 0.65rem;
    font-size: 0.8rem;
}

.audience-preview-btn:hover {
    background: var(--surface-2);
    opacity: 1;
}

.audience-preview-btn.active {
    background: var(--surface-2);
    color: var(--text);
    font-weight: 600;
}

.audience-name {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.share-dialog-audience {
    margin-bottom: 1rem;
}

.share-dialog-audience .settings-theme-options {
    border-radius: 14px;
    flex-wrap: wrap;
}

.share-dialog-audience-btn.has-link::after {
    content: '';
    width: 0.35rem;
    height: 0.35rem;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.6;
}

.share-dialog-revoke {
    display: block;
    margin-bottom: 1rem;
    margin-top: 0.5rem;
    font-size: 0.8rem;
}

/* Krag przypisany tylko czesci zaznaczonych zdjec. */
.audience-preview-btn.partial {
    color: var(--text);
    border-style: dashed;
}

#audience-toggle-btn.active,
#lightbox-audience-btn.active {
    background: var(--accent);
    color: white;
}

.lightbox-audience-bar {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 3.25rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.4rem;
    padding: 0 1rem;
    z-index: 4;
    transition: opacity 0.4s ease;
}

.lightbox.chrome-hidden .lightbox-audience-bar {
    opacity: 0;
    pointer-events: none;
}

.lightbox-audience-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: rgba(0, 0, 0, 0.45);
    color: rgba(255, 255, 255, 0.8);
    border: 1px solid rgba(255, 255, 255, 0.3);
    border-radius: 999px;
    padding: 0.3rem 0.75rem;
    font-size: 0.8rem;
}

.lightbox-audience-btn.active {
    background: rgba(255, 255, 255, 0.92);
    color: #111;
    font-weight: 600;
}

/* Opcje wyswietlania (menu "oczka") wyciagniete jako osobne ikony w gornym
   pasku - tylko gdy jest na nie miejsce. Na wezszym oknie ikony znikaja, a
   te same przelaczniki (razem z "Grupy odbiorcow") zostaja w menu. */
.options-inline {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.options-inline-btn.active {
    background: var(--accent);
    color: white;
}

.options-inline-expand {
    width: 1.1rem;
    margin-left: -0.45rem;
    padding: 0;
}

/* .options-collapsed ustawia gallery.js (updateOptionsInlineLayout), gdy
   ikony nie mieszcza sie obok sciezki (breadcrumb) w gornym pasku. */
.topbar:not(.options-collapsed) #options-switcher {
    display: none !important;
}

.topbar.options-collapsed .options-inline {
    display: none !important;
}

/* Tryb grup z wybranym tagiem - klik w zdjecie przelacza tag. */
.gallery.audience-tagging .gallery-item img {
    cursor: cell;
}

/* Okno zmiany daty wykonania (#date-dialog) - trzy kolumny: lata,
   miesiace, dni + godzina (flatpickr inline bez wlasnego naglowka).
   Przyciski lat/miesiecy w stylu przelacznikow z Ustawien (szary tekst,
   wybrany = tlo --surface-2 + pogrubienie). Na waskim ekranie kolumny
   ukladaja sie jedna pod druga (media query nizej). */
.date-dialog {
    width: fit-content;
    max-width: 94vw;
}

.date-picker {
    display: flex;
    align-items: stretch;
}

.date-picker > * + * {
    border-left: 1px solid var(--border);
}

.date-picker-years {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    padding-right: 1rem;
}

.date-picker-years-nav:disabled {
    visibility: hidden;
}

.date-picker-years-grid {
    display: grid;
    grid-template-rows: repeat(10, auto);
    grid-auto-flow: column;
    grid-auto-columns: 4rem;
    gap: 0.15rem 0.25rem;
    align-content: center;
}

.date-picker-months {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 0.15rem;
    padding: 0 1rem;
    min-width: 9.5rem;
}

.date-picker-option {
    background: transparent;
    color: var(--text-muted);
    padding: 0.3rem 0.6rem;
    font-size: 0.85rem;
    text-align: center;
}

.date-picker-option:hover {
    background: var(--surface-2);
    color: var(--text);
    opacity: 1;
}

.date-picker-option.active {
    background: var(--surface-2);
    color: var(--text);
    font-weight: 600;
}

.date-picker-days {
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-left: 1rem;
}

.date-dialog-calendar {
    display: none;
}

.date-dialog .flatpickr-calendar.inline {
    margin: 0 auto;
    box-shadow: none;
    border: none;
    background: transparent;
}

.date-dialog .flatpickr-months {
    display: none;
}

.date-dialog .flatpickr-calendar .flatpickr-weekdays,
.date-dialog .flatpickr-calendar span.flatpickr-weekday {
    background: transparent;
    color: var(--text-muted);
    font-weight: 500;
}

.date-dialog .flatpickr-calendar .flatpickr-day {
    border-radius: 999px;
    font-size: 0.85rem;
}

.date-dialog .flatpickr-calendar .flatpickr-day.selected,
.date-dialog .flatpickr-calendar .flatpickr-day.selected:hover {
    background: var(--surface-2);
    border-color: var(--surface-2);
    color: var(--text);
    font-weight: 600;
}

.date-dialog .flatpickr-calendar .flatpickr-day.today:not(.selected) {
    border-color: var(--border);
}

.date-dialog .flatpickr-calendar .flatpickr-time {
    margin-top: 0.5rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    max-width: 10rem;
    margin-left: auto;
    margin-right: auto;
}

.date-dialog .flatpickr-calendar .flatpickr-time input,
.date-dialog .flatpickr-calendar .flatpickr-time .flatpickr-time-separator {
    background: transparent;
    font-size: 0.95rem;
}

.date-dialog .flatpickr-calendar .flatpickr-time input:hover,
.date-dialog .flatpickr-calendar .flatpickr-time input:focus {
    background: var(--surface-2);
}

.date-dialog-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 1.25rem;
}

@media (max-width: 760px) {
    .date-dialog {
        padding: 1rem;
        max-height: 94vh;
    }

    .date-picker {
        flex-direction: column;
        gap: 0.75rem;
    }

    .date-picker > * + * {
        border-left: none;
        border-top: 1px solid var(--border);
        padding: 0.75rem 0 0;
    }

    .date-picker-years {
        padding-right: 0;
    }

    .date-picker-years-grid {
        grid-template-rows: none;
        grid-auto-flow: row;
        grid-template-columns: repeat(5, 1fr);
        grid-auto-columns: auto;
        flex: 1;
    }

    .date-picker-months {
        display: grid;
        grid-template-columns: repeat(4, 1fr);
        min-width: 0;
    }

    .date-picker-option {
        padding: 0.3rem 0.2rem;
        font-size: 0.8rem;
    }
}

.info-dialog-taken-at-btn {
    text-align: left;
}

.flatpickr-calendar,
.flatpickr-calendar .flatpickr-months .flatpickr-month,
.flatpickr-calendar .flatpickr-current-month .flatpickr-monthDropdown-months,
.flatpickr-calendar .flatpickr-current-month .flatpickr-monthDropdown-months option,
.flatpickr-calendar span.flatpickr-weekday,
.flatpickr-calendar .flatpickr-time input,
.flatpickr-calendar .flatpickr-time .flatpickr-time-separator,
.flatpickr-calendar .flatpickr-current-month input.cur-year {
    background: var(--bg);
    color: var(--text);
    fill: var(--text);
}

.flatpickr-calendar .flatpickr-months .flatpickr-prev-month,
.flatpickr-calendar .flatpickr-months .flatpickr-next-month {
    color: var(--text);
    fill: var(--text);
}

.flatpickr-calendar .flatpickr-day {
    color: var(--text);
}

.flatpickr-calendar .flatpickr-day.prevMonthDay,
.flatpickr-calendar .flatpickr-day.nextMonthDay {
    color: var(--text-muted);
}

.flatpickr-calendar .flatpickr-day:hover,
.flatpickr-calendar .flatpickr-time input:hover,
.flatpickr-calendar .flatpickr-time input:focus {
    background: var(--surface-2);
    border-color: var(--surface-2);
}

.flatpickr-calendar .flatpickr-day.today {
    border-color: var(--text-muted);
}

.flatpickr-calendar .flatpickr-day.selected,
.flatpickr-calendar .flatpickr-day.selected:hover {
    background: var(--select);
    border-color: var(--select);
    color: #fff;
}

.flatpickr-calendar .flatpickr-time {
    border-top: 1px solid var(--border);
}

.flatpickr-calendar .numInputWrapper span.arrowUp::after {
    border-bottom-color: var(--text);
}

.flatpickr-calendar .numInputWrapper span.arrowDown::after {
    border-top-color: var(--text);
}


.settings-panel .settings-section {
    padding-bottom: 0.5rem;
}

/* --- Zoom w lightboxie: panel w rogu = miniaturka-nawigator + suwak --- */
.lightbox-zoom-dock {
    position: absolute;
    right: 1rem;
    bottom: 4.5rem;
    z-index: 4;
    box-sizing: content-box;
    padding: 0.5rem;
    border-radius: 14px;
    background: rgba(32, 32, 34, 0.92);
    box-shadow: 0 12px 30px rgba(0, 0, 0, 0.45);
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    color: #fff;
    touch-action: none;
}

.lightbox-zoom-dock[hidden] {
    display: none;
}

.lightbox-navigator {
    position: relative;
    align-self: center;
    border-radius: 8px;
    overflow: hidden;
    background: #000;
    cursor: pointer;
}

.lightbox-navigator img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    pointer-events: none;
    user-select: none;
}

.lightbox-navigator-frame {
    position: absolute;
    border: 2px solid #fff;
    border-radius: 3px;
    box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.4);
    cursor: grab;
}

.lightbox-zoom-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.lightbox-zoom-step {
    flex: none;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.1);
    color: #fff;
    font-size: 1rem;
    line-height: 1;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}

.lightbox-zoom-step:hover {
    background: rgba(255, 255, 255, 0.2);
}

.lightbox-zoom-range {
    flex: 1;
    min-width: 0;
    margin: 0;
    accent-color: #fff;
    touch-action: none;
}

.lightbox-zoom-footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    font-size: 0.8rem;
    color: rgba(255, 255, 255, 0.75);
    padding: 0 0.15rem;
}

.lightbox-zoom-fit {
    border: none;
    background: none;
    color: rgba(255, 255, 255, 0.85);
    font-size: 0.8rem;
    padding: 0.15rem 0.3rem;
    border-radius: 6px;
    cursor: pointer;
}

.lightbox-zoom-fit:hover {
    background: rgba(255, 255, 255, 0.12);
}

.lightbox-pill-btn.active {
    background: rgba(255, 255, 255, 0.22);
}

.lightbox.zoomed .lightbox-stage img {
    cursor: grab;
}

.lightbox.zoomed .lightbox-stage img.panning {
    cursor: grabbing;
}

@media (max-width: 760px) {
    .lightbox-zoom-dock {
        right: 0.75rem;
        bottom: 4rem;
    }
}

/* Na dotyku (telefon/tablet) zoom robi sie gestem dwoch palcow - panel
   zoomu i przycisk skali na gornym pasku tylko zaslanialyby zdjecie. */
@media (hover: none) {
    .lightbox-zoom-dock,
    .lightbox-zoom-btn-wrap {
        display: none !important;
    }
}

/* Filtr formatow przy uploadzie (Ustawienia -> Wgrywanie) */
.upload-format-filter {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 0.5rem;
}

@media (max-width: 640px) {
    .settings-row-wrap {
        flex-wrap: wrap;
    }
    .upload-format-filter {
        align-items: stretch;
        width: 100%;
    }
}

/* Krotki komunikat na dole ekranu (np. pominiete pliki przy uploadzie) */
.app-notice {
    position: fixed;
    left: 50%;
    bottom: 1.5rem;
    transform: translateX(-50%);
    z-index: 1000;
    max-width: calc(100vw - 2rem);
    padding: 0.6rem 1rem;
    border-radius: 999px;
    background: var(--text);
    color: var(--bg);
    font-size: 0.85rem;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

.upload-queue-pause[hidden] {
    display: none;
}

/* Ikona pauzy nie obraca sie razem ze zwinietym panelem */
.upload-queue.collapsed .upload-queue-pause svg {
    transform: none;
}
