/* ====================================================================
   HTML_Sharing — style (mobile-first, bez zależności zewnętrznych).
   Motyw: fioletowy.
   ==================================================================== */

/* ---------- FONTY ---------- */
@font-face{
  font-family:"Arya";
  src:url("fonts/Arya-Regular.ttf") format("truetype");
  font-weight:400; font-style:normal; font-display:swap;
}
@font-face{
  font-family:"Arya";
  src:url("fonts/Arya-Bold.ttf") format("truetype");
  font-weight:700; font-style:normal; font-display:swap;
}

:root{
  --bg:#f5f4fb; --card:#ffffff; --ink:#1e1b2e; --muted:#6b6785;
  --line:#e9e6f4; --line2:#d8d2ea;
  --brand:#7c3aed; --brand-dk:#5b21b6; --brand-soft:#ddd6fe; --brand-hint:#f5f3ff;
  --brand-grad:linear-gradient(135deg,#8b5cf6,#6d28d9);
  --pos:#15803d; --pos-soft:#dcfce7; --neg:#b91c1c; --neg-soft:#fee2e2;
  --warn:#b45309; --warn-soft:#fef3c7;
  --radius:14px; --radius-sm:10px;
  --shadow:0 1px 2px rgba(30,27,46,.05),0 6px 20px rgba(76,29,149,.07);
  --shadow-lg:0 10px 40px rgba(76,29,149,.18);
  --tap:46px; --maxw:1080px; --maxw-narrow:560px;
  --topbar-h:calc(env(safe-area-inset-top, 0px) + 2.95rem);
  /* Wysokosc paska nawigacji Androida — podstawia ja apka (ASH-00165). */
  --wga-nav:0px;
  /* Szpara w stopce pod srodkowa ikone paska Androida (ASH-00165). */
  --wga-navgap:30px;
  --font:"Segoe UI", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --font-brand:"Arya", var(--font);
}
*{box-sizing:border-box}
html,body{margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
/* Blokada "przeciagnij w dol = odswiez" na mobilce. Przypadkowy gest przerywal
   trwajaca wysylke, a przegladarka nie da sie o to zapytac (ASH-00074).
   WYLACZNIE na czas transferu (ASH-00076) - poza nim gest ma dzialac normalnie,
   bo to standardowe zachowanie przegladarki i nie ma powodu go odbierac. */
html.is-uploading,html.is-uploading body{overscroll-behavior-y:contain}
body{
  font-family:var(--font); background:var(--bg); color:var(--ink); line-height:1.5;
  min-height:100vh; display:flex; flex-direction:column;
  padding-bottom:env(safe-area-inset-bottom);
}
h1{font-size:1.5rem;margin:.2em 0;font-family:var(--font-brand)}
h2{font-size:1.12rem;margin:0 0 .6rem}
h3{font-size:1rem;margin:0 0 .4rem}
p{margin:.45rem 0}
a{color:var(--brand-dk)}
.muted{color:var(--muted)}
.spacer{flex:1}
.center-text{text-align:center}
[hidden]{display:none !important}
::selection{background:var(--brand-soft)}

/* ---------- TOPBAR ---------- */
.topbar{
  position:sticky;top:0;z-index:40;display:flex;align-items:center;gap:.6rem;
  background:var(--brand-grad);color:#fff;
  padding:calc(env(safe-area-inset-top) + .6rem) 1rem .6rem;
  box-shadow:0 2px 14px rgba(76,29,149,.28);
}
.topbar__home{background:none;border:0;color:#fff;display:flex;align-items:center;gap:.55rem;font:inherit;cursor:pointer;padding:.15rem}
.logo{display:inline-flex;align-items:center;opacity:.96}
.topbar__title{font-weight:800;font-size:1.15rem;font-family:var(--font-brand);letter-spacing:.3px}
/* ASH-00414: „gdzie jestem" — nazwa katalogu dopisana obok marki, gdy naglowek
   katalogu wyjedzie pod belke. Poza przyciskiem „Start", zeby klikniecie nazwy
   nie wyrzucalo na pulpit; scisniecie zalatwia wielokropek. */
.topbar__where{font-weight:700;font-size:1rem;opacity:.92;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto}
.topbar__where[hidden]{display:none}
.topbar__meta{font-size:.85rem;font-weight:600;opacity:.92;white-space:nowrap}

/* ---------- LAYOUT ---------- */
.app{flex:1;width:100%;max-width:var(--maxw);margin:0 auto;padding:1rem 1rem 2rem}
.view{animation:fade .18s ease}
@keyframes fade{from{opacity:0;transform:translateY(5px)}to{opacity:1;transform:none}}
.narrow{max-width:var(--maxw-narrow);margin-left:auto;margin-right:auto}

/* ---------- CARD ---------- */
.card{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:1.1rem;margin-bottom:1rem;box-shadow:var(--shadow);
}
.card--center{text-align:center;display:flex;flex-direction:column;align-items:center;gap:.6rem}
.hero{
  text-align:center;border:1px solid var(--line);
  background:linear-gradient(160deg,#ffffff,#f2ecff);
}
.hero h1{color:var(--brand-dk);margin-bottom:.3rem}
.hero .lead{font-size:1.05rem;color:var(--muted);max-width:42ch;margin:.2rem auto .9rem}
.hero__mark{
  width:64px;height:64px;border-radius:18px;margin:.2rem auto .7rem;
  display:flex;align-items:center;justify-content:center;color:#fff;background:var(--brand-grad);
  box-shadow:var(--shadow-lg);
}

/* ---------- ROWS ---------- */
.row{display:flex;gap:.6rem;align-items:center}
.row.spread{justify-content:space-between}
.row.wrap{flex-wrap:wrap}
.stack{display:flex;flex-direction:column;gap:.6rem}

/* ---------- BUTTONS ---------- */
.btn{
  appearance:none;border:1px solid var(--line2);background:#fff;color:var(--ink);
  border-radius:var(--radius-sm);padding:0 1.1rem;min-height:var(--tap);font:inherit;font-weight:600;
  cursor:pointer;display:inline-flex;align-items:center;justify-content:center;gap:.45rem;
  transition:transform .04s ease, background .15s ease, border-color .15s, box-shadow .15s;white-space:nowrap;
}
.btn:active{transform:scale(.97)}
.btn:hover{border-color:var(--brand)}
.btn:focus-visible{outline:none;box-shadow:0 0 0 3px var(--brand-soft)}
.btn--primary{background:var(--brand);border-color:var(--brand);color:#fff}
.btn--primary:hover{background:var(--brand-dk);border-color:var(--brand-dk)}
.btn--ghost{background:var(--brand-hint);border-style:dashed}
.btn--danger{background:#fff;border-color:#f2a3a3;color:var(--neg)}
.btn--danger:hover{background:var(--neg-soft);border-color:var(--neg)}
.btn--lg{min-height:52px;font-size:1.05rem;padding:0 1.4rem}
.btn--sm{min-height:36px;padding:0 .7rem;font-size:.85rem}
.btn--block{width:100%}
/* Dotyk (ASH-00076): przycisk wyboru plikow pod naglowkiem karty wysylki. */
.up-pick{margin-top:.7rem;min-height:44px}
/* Ikony MDI w przyciskach panelu administratora (ASH-00189). Sam .btn ma juz
   inline-flex i gap, wiec ikona wystarczy, ze nie kurczy sie i nie dokłada
   linii bazowej. Etykieta siedzi w .btn__t — busy() podmienia TYLKO ja. */
.btn .mdi{display:block;flex:0 0 auto}
.btn__t{display:inline-block}
.btn:disabled{opacity:.45;cursor:not-allowed}
.btn:disabled:hover{border-color:var(--line2)}

/* ---------- INPUTS ---------- */
.input{
  width:100%;min-height:42px;border:1px solid var(--line2);border-radius:var(--radius-sm);
  padding:.5rem .65rem;font:inherit;background:#fff;color:var(--ink);
}
.input:focus{outline:none;border-color:var(--brand);box-shadow:0 0 0 3px var(--brand-soft)}
textarea.input{min-height:6rem;resize:vertical;line-height:1.5}
.field{margin-bottom:.9rem}
.field>label{display:block;font-size:.85rem;font-weight:600;color:var(--muted);margin-bottom:.3rem}
.field-hint{color:var(--muted);font-size:.8rem;margin:.35rem 0 0}
.input--mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:.9rem}

/* ---------- BADGES / PILLS / CHIPS ---------- */
.badge{background:var(--brand-soft);color:var(--brand-dk);border-radius:999px;padding:.15rem .6rem;font-size:.78rem;font-weight:700;white-space:nowrap}
.pill{font-size:.78rem;font-weight:700;padding:.2rem .55rem;border-radius:999px;background:var(--pos-soft);color:var(--pos)}
.pill.warn{background:var(--warn-soft);color:var(--warn)}
.pill.bad{background:var(--neg-soft);color:var(--neg)}
.chip{background:var(--brand-hint);border:1px solid var(--line);border-radius:999px;padding:.28rem .6rem;font-size:.8rem;color:var(--ink)}

/* ---------- SPINNER ---------- */
.spinner{
  width:34px;height:34px;border-radius:50%;
  border:3px solid var(--brand-soft);border-top-color:var(--brand);
  animation:spin .8s linear infinite;
}
@keyframes spin{to{transform:rotate(360deg)}}

/* ---------- FOOT ---------- */
.foot{
  text-align:center;padding:1rem;font-size:.8rem;color:var(--muted);
  border-top:1px solid var(--line);background:#fff;
}
/* Dwie informacje i szpara miedzy nimi (ASH-00165). Szerokosc na cala stopke,
   bo po niej mierzymy, czy podpis „Aplikacja" sie miesci. */
#footVersion{display:flex;align-items:center;justify-content:center;width:100%}
.foot__i{white-space:nowrap}
.foot__gap{flex:0 0 auto;width:var(--wga-navgap)}

/* ---------- KOMUNIKATY ---------- */
.msg{border-radius:var(--radius-sm);padding:.6rem .8rem;margin:.2rem 0 .8rem;font-size:.9rem;border:1px solid var(--line2);background:#fff}
.msg--error{background:var(--neg-soft);border-color:#f2b8b8;color:var(--neg)}
.msg--success{background:var(--pos-soft);border-color:#bbe6c8;color:var(--pos)}
.msg--info{background:var(--brand-hint);border-color:var(--brand-soft);color:var(--brand-dk)}

/* ---------- PULPIT ADMINA ---------- */
.dash-head{display:flex;align-items:center;justify-content:space-between;gap:.8rem;flex-wrap:wrap}
.dash-head h2{margin:0}
.dash-head>div{min-width:0}

/* ---------- ZAKLADKI PANELU ADMINA (ASH-00174) ----------
   Zaokraglony pasek nad boxami, wzor z Tickets/Settlements: przelacza
   Katalogi / Uzytkownicy / Wydajnosc, aktywna podswietlona plynnym wskaznikiem. */
.tabs{position:relative;display:flex;background:var(--card);border:1px solid var(--line);
  border-radius:999px;padding:.25rem;margin:0 0 .9rem;gap:.2rem;box-shadow:var(--shadow)}
.tab-indicator{position:absolute;left:0;top:.25rem;bottom:.25rem;width:0;background:var(--brand-grad);
  border-radius:999px;transform:translateX(0);transition:transform .25s ease,width .25s ease;
  z-index:0;pointer-events:none}
/* ASH-00369: zakladka to ikona + napis; przy waskim oknie napis znika i zostaje
   sama ikona (opis zostaje w podpowiedzi i `aria-label`). */
.tab{display:flex;align-items:center;justify-content:center;gap:.4rem}
.tab svg{flex:0 0 auto;display:block}
@media (max-width:760px){
  .tab__t{display:none}
  .tab{gap:0;padding:0 .2rem}
}
.tab{position:relative;z-index:1;flex:1;border:0;background:none;font:inherit;font-weight:600;
  color:var(--muted);min-height:40px;border-radius:999px;cursor:pointer;transition:color .2s ease;
  white-space:nowrap;padding:0 .6rem}
.tab:hover{color:var(--brand-dk)}
.tab.is-active,.tab.is-active:hover{color:#fff}
.tab:focus-visible{outline:none;box-shadow:0 0 0 3px var(--brand-soft)}
@media (max-width:420px){.tab{font-size:.9rem;padding:0 .35rem}}
/* Nagłówek z licznikiem (ASH-00181): adnotacja szara, bez pogrubienia, mniejsza,
   wyśrodkowana w pionie do słowa i kropki dzięki flexowi. */
.head-title{display:flex;align-items:center;gap:.32rem;flex-wrap:wrap;min-width:0}
.head-title__count{font-weight:400;font-size:.72em;color:var(--muted);line-height:1.1;white-space:nowrap}

/* ---------- RESPONSIVE ---------- */
@media (max-width:640px){
  .app{padding:.85rem .85rem 2rem}
  h1{font-size:1.35rem}
  .row.stack-sm{flex-direction:column;align-items:stretch}
}

/* ---------- MODAL ---------- */
.modal-backdrop{position:fixed;inset:0;background:rgba(30,27,46,.5);display:flex;align-items:flex-start;justify-content:center;padding:1rem;z-index:100;overflow:auto}
.modal{background:var(--card);border-radius:var(--radius);box-shadow:var(--shadow-lg);width:100%;max-width:520px;margin:auto;padding:1.2rem}
.modal--form{max-width:min(780px,94vw)}
.modal h2{margin-top:0}
.modal__actions{display:flex;gap:.6rem;justify-content:flex-end;margin-top:.4rem;flex-wrap:wrap}

/* ---------- SEKCJE / LISTA KATALOGÓW ---------- */
.section-head{display:flex;align-items:center;justify-content:space-between;gap:.6rem;margin-bottom:.7rem}
.section-head h3{margin:0}
.empty{color:var(--muted);text-align:center;padding:1.2rem;border:1px dashed var(--line2);border-radius:var(--radius-sm)}
.dir-list{display:flex;flex-direction:column;gap:.55rem}
/* Naglowek grupy rodzaju na liscie katalogow (ASH-00333). Ma czytac sie jak
   etykieta sekcji, a nie jak tytul karty — stad wielkosc i kolor stonowane. */
/* ASH-00400: naglowek grupy to fioletowa belka o tym samym zaokragleniu
   i tym samym wcieciu bocznym co wiersz katalogu (.dir-item ma .85rem), wiec
   napis stoi w jednej osi z nazwami katalogow pod spodem. */
.dir-group__head{display:flex;align-items:center;gap:.45rem;margin:.9rem 0 .45rem;font-size:.78rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
  color:#fff;background:var(--brand);border-radius:var(--radius-sm);padding:.34rem .85rem}
.dir-group__head:first-child{margin-top:0}
.dir-group__cnt{font-weight:600;letter-spacing:0;color:#fff;background:rgba(255,255,255,.2);border:1px solid rgba(255,255,255,.5);border-radius:999px;padding:0 .4rem;font-size:.72rem}
/* ASH-00394: pole szukania na liscie katalogow — pelna szerokosc karty,
   miedzy przypieta wlasna galeria a grupami. */
/* ASH-00401: karta „Twoje katalogi" ma JEDEN rytm pionowy. Odstep miedzy
   wlasna galeria, polem szukania, naglowkiem kategorii i wierszami katalogow
   jest ten sam (`gap` z `.dir-list`), wiec zamiast marginesow per element
   ukladamy wszystko kolumnowym fleksem o tym samym odstepie. Marginesy
   `.dir-group__head` zostaja dla listy w panelu admina, ktora tego ukladu
   nie uzywa — dlatego zeruje je regula POTOMKA `.dir-stack`. */
.dir-stack{display:flex;flex-direction:column;gap:.55rem}
.dir-stack .dir-group__head{margin:0}
/* Akapity (komunikaty „nic nie pasuje", „brak katalogow") maja globalne
   `p{margin:.45rem 0}` — w kolumnie fleksowej dokladaloby sie do odstepu. */
.dir-stack > p{margin:0}
/* ASH-00403: krzyzyk czyszczacy siedzi W POLU, przy prawej krawedzi. Pole
   dostaje z tej strony zapas na jego szerokosc, zeby tekst pod niego nie wchodzil. */
.dir-srch{margin:0;position:relative}
.dir-srch .input{width:100%;padding-right:2.4rem}
.dir-srch__x{position:absolute;top:50%;right:.45rem;transform:translateY(-50%);
  display:flex;align-items:center;justify-content:center;width:1.7rem;height:1.7rem;
  padding:0;border:0;border-radius:999px;background:transparent;color:var(--muted);
  cursor:pointer;line-height:0}
/* Krzyzyk zostaje SZARY takze pod kursorem — to nie akcja pierwszego planu,
   tylko sprzatniecie po sobie (ASH-00404). */
.dir-srch__x:hover{color:var(--ink)}
.dir-srch__x:focus{outline:none}
/* ASH-00399: szukanie po nazwie pliku w oknie wyboru zdjecia profilowego. */
.av-srch{margin:.35rem 0 .5rem}
.av-srch .input{width:100%}
.dir-item{border:1px solid var(--line);border-radius:var(--radius-sm);padding:.7rem .85rem;display:flex;gap:.6rem;align-items:center;justify-content:space-between}
.dir-item__main{min-width:0;flex:1}
.dir-item__name{font-weight:700;display:flex;align-items:center;gap:.45rem;min-width:0}
.dir-item__nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:0 1 auto}
/* Flaga „Nowe" na katalogu (ASH-00332) — stoi PRZED nazwa, jak znacznik
   nieprzeczytanej wiadomosci. Ikona `creation` z lagodnym poswiatowaniem
   (ASH-00339): samo `opacity` bylo za ciche, samo `drop-shadow` za krzykliwe,
   wiec ida razem w jednym cyklu ~2,5 s. Poswiata to `--brand` wprost w rgba,
   bo `--brand-soft` (#ddd6fe) na bialej karcie w ogole nie widac, a osobnego
   tokenu z kanalem alfa motyw nie ma. Animujemy TYLKO te dwie wlasciwosci —
   nic sie nie przesuwa, wiec lista nie drga przy kilku flagach naraz. */
.dir-item__new{display:flex;flex:0 0 auto;align-items:center;color:var(--brand);animation:newGlow 2.5s ease-in-out infinite}
.dir-item__new svg{display:block}
@keyframes newGlow{
  0%,100%{opacity:.6;filter:drop-shadow(0 0 0 rgba(0,0,0,0))}
  50%{opacity:1;filter:drop-shadow(0 0 5px rgba(124,58,237,.55))}
}
/* Kto wylaczyl animacje w systemie, ten ich tu nie dostaje. */
@media (prefers-reduced-motion:reduce){
  .dir-item__new{animation:none;opacity:1}
}
.dir-item__span{font-size:.8rem;font-weight:500;color:var(--muted);flex:0 0 auto;white-space:nowrap}
.dir-item__meta{font-size:.8rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ---------- ASH-00364: wiersz katalogu na siatce ----------
   Szeroko dwie linie: [nazwa][daty] .... [awatary][typy] / [pliki+rozmiar] .... [operacje].
   Wasko cztery: nazwa+typy, daty+operacje, pliki+rozmiar, awatary (o 40% mniejsze).
   Kolumna z datami jest elastyczna (1fr) i to ona odpycha prawa strone. */
/* ASH-00367: prawa krawedz stosu awatarow ma stac w TEJ SAMEJ kolumnie w kazdym
   wierszu listy, niezaleznie od liczby ikon typow. Robi to `subgrid`: kolumny
   wyznacza lista, a wiersze je dziedzicza. Gdzie subgrid nie dziala (starszy
   WebView), kazdy wiersz liczy kolumny sam — uklad zostaje ten sam, tylko bez
   idealnego rownania miedzy wierszami. */
/* ASH-00379: pierwsza linia to [Nazwa] · [Daty] ——— [Awatary >] | [Ikony >].
   Daty NIE maja juz wlasnej kolumny (wczesniej rownaly sie miedzy wierszami
   i odskakiwaly od nazwy) — siedza wewnatrz `.dr__nm`, a kolumna nazwy zabiera
   cale wolne miejsce. Zostaja trzy kolumny: nazwa+daty (1fr), awatary i ikony
   typow — obie `auto`, wiec `subgrid` dalej rownia ich prawe krawedzie
   miedzy wierszami (ASH-00367). */
.dir-list--cols{display:grid;grid-template-columns:minmax(0,1fr) auto auto;
  row-gap:.55rem}
.dir-item--grid{display:grid;align-items:center;column-gap:.6rem;row-gap:.1rem;
  grid-template-columns:minmax(0,1fr) auto auto;
  grid-template-areas:"nm people kinds" "meta ops ops"}
@supports (grid-template-columns: subgrid) {
  .dir-list--cols > .dir-item--grid{grid-column:1 / -1;grid-template-columns:subgrid}
}
/* Przycisk „Wszystkie / Tylko nowe" (ASH-00368) — po prawej stronie rzedu akcji. */
.dir-onlynew{margin-left:auto}
/* ASH-00374: gdy rzad akcji przestaje sie miescic, z tego przycisku zostaje
   sama ikona. Klase nadaje `fitActs()` po POMIARZE — nie ma tu breakpointu,
   bo szerokosc rzedu zalezy od tego, ile przyciskow user w ogole dostal. */
.dash-head__acts--tight .dir-onlynew .btn__t{display:none}
.dr__nm{grid-area:nm;display:flex;align-items:center;gap:.45rem;min-width:0;font-weight:700}
.dr__nm .dir-item__nm{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex-shrink:1}
/* Kropka rozdzielajaca nazwe od dat — znika w ukladzie waskim, gdzie daty
   schodza do drugiej linii (ASH-00379). */
.dr__sep{color:var(--line2);font-weight:400;flex-shrink:0}
.dr__span{font-size:.8rem;font-weight:500;color:var(--muted);white-space:nowrap;flex-shrink:0}
.dr__meta{grid-area:meta;font-size:.8rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.dr__people{grid-area:people;display:flex;justify-content:flex-end}
.dr__kinds{grid-area:kinds;display:flex;align-items:center;justify-content:flex-end;color:var(--brand)}
.dr__ops{grid-area:ops;display:flex;align-items:center;justify-content:flex-end;gap:.35rem}
/* Ikony operacji tej samej wielkosci co ikony typow (zgloszenie Radka). */
.dr__ops svg{width:18px;height:18px;display:block}
.dr__kinds .dir-item__kinds{margin-left:0;padding-left:0}
/* Stos awatarow: pierwszy na wierzchu, kazdy nastepny podlozony 10% pod poprzedni. */
.dr-people{display:flex;align-items:center}
.dr-people .av{position:relative}
.dr-people .av + .av{margin-left:calc(var(--av) * -0.1 - 5px)}
.dr-people .av:hover{z-index:99!important}
.dr-people__more{margin-left:.3rem;font-size:.72rem;font-weight:700;color:var(--muted)}
/* Ikony dostepu i dopiski „mozesz wgrywac/usuwac" wykluczaja sie wzajemnie:
   szeroko zostaje tekst, wasko ikony (ASH-00370). */
.dr__acc{display:none}
/* ASH-00380: ikony uprawnień są informacją DRUGIEGO planu — „możesz wgrywać",
   „możesz usuwać" to nie akcja do kliknięcia, tylko przypis. Stąd blady odcień
   zamiast koloru motywu i rozmiar równy ikonom rodzajów plików (18/16 px);
   dotąd były o te 2 px większe w układzie wąskim, bo nie miały własnej reguły
   w media query. */
.dr-acc{display:flex;align-items:center;gap:.3rem;color:var(--brand-soft)}
.dr-acc__i{display:flex}
.dr-acc__i svg{width:18px;height:18px;display:block}
@media (max-width:560px){
  /* ASH-00373: kolumny przestawiamy na LISCIE, nie na wierszu. Wiersze dziedzicza
     je przez `subgrid`, a ta regula (`.dir-list--cols > .dir-item--grid`) ma
     wyzsza specyficznosc niz deklaracja w media query — dlatego wczesniej wiersz
     dalej bral cztery kolumny z listy, a nazwane obszary opisywaly trzy i uklad
     sie rozsypywal (daty ladowaly po prawej). */
  .dir-list--cols{grid-template-columns:minmax(0,1fr) auto auto}
  /* ASH-00370: trzy linie —
       [nazwa]            [operacje][typy]
       [daty]                    [dostep]
       [ilosc][rozmiar]         [awatary]
     Ikony operacji wskakuja do pierwszej linii, bo na raz pokazuje sie najwyzej
     jedna; awatary wracaja do linii z licznikami, gdzie jest na nie miejsce. */
  /* ASH-00379: daty siedza teraz WEWNATRZ komorki nazwy, wiec komorka `nm`
     rozciaga sie na dwa wiersze, a `flex-basis:100%` na datach wymusza zlamanie
     linii niezaleznie od dlugosci nazwy. Uklad na ekranie zostaje ten sam:
       [nazwa]            [operacje][typy]
       [daty]                    [dostep]
       [ilosc][rozmiar]         [awatary]  */
  .dir-item--grid{grid-template-columns:minmax(0,1fr) auto auto;
    grid-template-areas:"nm ops kinds" "nm acc acc" "meta people people"}
  .dr__nm{flex-wrap:wrap;row-gap:0;align-content:center}
  .dr__sep{display:none}
  .dr__span{flex-basis:100%}
  .dr__flags{display:none}
  /* Obszar trzeba nazwac jawnie — bez tego element trafial tu tylko przez
     auto-placement (bo `.dr__flags` znika) i po kazdej zmianie kolejnosci
     w markupie uklad by sie posypal. */
  .dr__acc{grid-area:acc;display:flex;align-items:center;justify-content:flex-end}
  .dr__people{justify-content:flex-end}
  /* „Awatary pomniejszone o 40%" — 44 px * 0,6 (ASH-00364). */
  .dr-people .av--sm{--av:17px}
  .dr__span{white-space:normal}
}

/* ---------- ASH-00362: komponent wyboru koloru (port z Dokumentow) ----------
   Klasy sa te same co w tamtej aplikacji, zeby `colors.js` dzialalo bez zmian. */
.color-panel{border:1px solid var(--line2);border-radius:var(--radius-sm);background:#fff;padding:.7rem}
.color-panel__lbl{font-size:.74rem;color:var(--muted);margin-bottom:.5rem;font-weight:600}
.color-swatches{display:flex;flex-wrap:wrap;gap:.4rem}
.swatch{width:28px;height:28px;border-radius:6px;border:1px solid rgba(30,27,46,.15);cursor:pointer;padding:0;transition:transform .1s}
.swatch:hover{transform:scale(1.06)}
.swatch.is-sel{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--brand)}
.swatch--none{background:#fff;border:1.5px dashed var(--line2);position:relative;overflow:hidden}
.swatch--none::after{content:"";position:absolute;top:50%;left:50%;width:140%;height:1.6px;background:var(--muted);border-radius:2px;transform:translate(-50%,-50%) rotate(-45deg)}
.swatch--custom{position:relative;overflow:hidden;border:1px solid rgba(30,27,46,.15);background:#fff}
.swatch--custom::before{content:"";position:absolute;inset:0;background:conic-gradient(from 90deg,#e53935,#fb8c00,#fdd835,#43a047,#00acc1,#1e88e5,#8e24aa,#d81b60,#e53935)}
.color-wheel{display:none;gap:.7rem;margin-top:.7rem}
.color-wheel.is-open{display:flex;flex-wrap:wrap}
.wheel-canvas-wrap{position:relative;width:176px;height:176px;flex:0 0 auto;touch-action:none}
.wheel-canvas{width:176px;height:176px;border-radius:50%;display:block;cursor:crosshair;touch-action:none;box-shadow:0 0 0 1px var(--line) inset}
.wheel-thumb{position:absolute;left:50%;top:50%;width:16px;height:16px;border-radius:50%;border:2px solid #fff;box-shadow:0 0 0 1.5px rgba(0,0,0,.5);transform:translate(-50%,-50%);pointer-events:none}
.wheel-side{flex:1;min-width:150px;display:flex;flex-direction:column;gap:.5rem}
.wheel-val{width:100%}
.wheel-preview-row{display:flex;align-items:center;gap:.5rem}
.wheel-preview{width:30px;height:30px;border-radius:6px;border:1px solid var(--line2);flex:0 0 auto;background:#fff}
.wheel-hex{flex:1;text-transform:lowercase;font-variant-numeric:tabular-nums}
/* Awatar w formularzu uzytkownika: podglad po lewej, paleta obok. */
/* ---------- ASH-00365: wybor zdjecia profilowego i kadrowanie ----------
   Warstwa nad modalem: formularz osoby zostaje pod spodem, wiec po skadrowaniu
   jest gdzie wrocic. */
.ovl{position:fixed;inset:0;z-index:290;background:rgba(30,27,46,.72);display:flex;
  align-items:center;justify-content:center;padding:1rem}
.ovl__box{background:var(--card);border-radius:var(--radius);padding:1rem 1.1rem;
  max-width:min(94vw,34rem);max-height:88vh;overflow:auto;box-shadow:var(--shadow-lg)}
.usr-av__ph{gap:.4rem;flex-wrap:wrap}
/* Siatka zdjec galerii w okienku wyboru — maly podglad, duzo pozycji naraz. */
.av-pick{display:grid;grid-template-columns:repeat(auto-fill,minmax(84px,1fr));gap:.4rem;
  max-height:46vh;overflow:auto;margin-top:.6rem}
.av-pick__it{padding:0;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--card);
  overflow:hidden;cursor:pointer;aspect-ratio:1/1}
.av-pick__it:hover{border-color:var(--brand)}
.av-pick__it img{width:100%;height:100%;object-fit:cover;display:block}
/* Kadrowanie (crop.js) — wlasna warstwa, bo modal aplikacji trzyma formularz. */
.crp{position:fixed;inset:0;z-index:300;background:rgba(30,27,46,.72);display:flex;
  align-items:center;justify-content:center;padding:1rem}
.crp__box{background:var(--card);border-radius:var(--radius);padding:1rem;max-width:min(92vw,30rem);
  box-shadow:var(--shadow-lg);display:flex;flex-direction:column;gap:.6rem;align-items:center}
.crp__ttl{font-weight:700;align-self:flex-start}
.crp__stage{position:relative;overflow:hidden;border-radius:50%;background:#000;touch-action:none;
  box-shadow:0 0 0 2px var(--brand-soft)}
.crp__img{position:absolute;left:0;top:0;transform-origin:0 0;display:block;max-width:none;user-select:none;
  -webkit-user-drag:none;pointer-events:none}
.crp__ring{position:absolute;inset:0;border-radius:50%;box-shadow:inset 0 0 0 2px rgba(255,255,255,.75);
  pointer-events:none}
.crp__zoom{width:100%}
.crp__hint{margin:0;font-size:.78rem;color:var(--muted);text-align:center}
.crp__acts{display:flex;gap:.5rem;align-self:stretch;justify-content:flex-end}

/* ASH-00371: dwa pola obok siebie po pol szerokosci (na waskim ekranie jedno
   pod drugim). */
.field-row{display:flex;gap:.6rem;flex-wrap:wrap}
.field-row > .field{flex:1 1 12rem;min-width:0}
.usr-av{align-items:flex-start;gap:.8rem;flex-wrap:wrap}
.usr-av__pick{flex:1 1 16rem;min-width:0}

/* ---------- ASH-00361/00362: awatar osoby ----------
   Kwadrat z zaokragleniem, obwodka 3 px (szara domyslnie, w kolorze osoby gdy
   ustawiony), litery wysrodkowane. Rozmiar dziedziczy sie z klasy wariantu,
   zeby ten sam element dzialal w wierszu listy i w stosie awatarow. */
.av{--av:40px;flex:0 0 auto;width:var(--av);height:var(--av);border-radius:50%;
  border:2px solid var(--line2);background:var(--card);display:inline-flex;
  align-items:center;justify-content:center;overflow:hidden;box-sizing:border-box;
  font-weight:700;color:var(--muted);user-select:none}
/* Pozycja inicjalow (zgloszenia Radka 2026-09-21, trzy podejscia):
   - pionowo: po korekcie „2 px w dol" od wersji -0.02 wychodzi +0.025 boku
     awatara (przy 44 px to dokladnie te 2 px, a male awatary w stosie dostaja
     proporcjonalnie mniej — stala wartosc rozjechalaby 17-px kolka),
   - poziomo: winowajca bylo `letter-spacing` z `.av` — odstep dokladany TAKZE
     po ostatniej literze przesuwal napis optycznie w lewo. Litery maja wiec
     odstep zerowy i sa centrowane przez flexa rodzica.
   Dostrojenie (trzecia runda): 1 px w gore i 1 px w prawo, liczone wzgledem
   awatara 44 px z wiersza listy — stad 0.002 w pionie (praktycznie sam srodek)
   i 0.023 w poziomie. Wartosci sa UAMKOWE, nie pikselowe, zeby 17-px kolka
   w stosie dostaly proporcjonalnie tyle samo, a nie caly piksel. */
.av__t{font-size:calc(var(--av) * .36);line-height:1;letter-spacing:normal;text-align:center;
  transform:translate(calc(var(--av) * 0.023), calc(var(--av) * 0.002))}
.av--fill{border-style:solid}
.av--img img{width:100%;height:100%;object-fit:cover;display:block}
.av--row{--av:44px}
.av--sm{--av:28px}
.av--lg{--av:72px}
/* Uczestnik bez wgranych plikow (ASH-00364) — obecny, ale przygaszony. */
.av--dim{filter:grayscale(1);opacity:.55}
/* Przycisk z sama ikona: pusta etykieta nie moze zostawiac odstepu po prawej
   (zgloszenie Radka 2026-09-21). */
.btn__t:empty{display:none}
.dir-item__actions{display:flex;gap:.4rem;flex-shrink:0}
.dir-item--link{cursor:pointer;transition:border-color .15s,background .15s}
.dir-item--link:hover{border-color:var(--brand-soft);background:var(--brand-hint)}
/* Galeria użytkownika = katalog domowy (ASH-00153): pierwsza pozycja listy,
   wyróżniona kolorem motywu, żeby nie mylić jej z katalogami udostępniania. */
.dir-item--home{border-color:var(--brand-soft);background:var(--brand-hint);box-shadow:inset 4px 0 0 var(--brand)}
.dir-item--home:hover{border-color:var(--brand);background:var(--brand-soft)}
.dir-item--home .dir-item__name{color:var(--brand-dk);margin-bottom:.35rem}
.dir-item__kinds{display:flex;align-items:center;flex-wrap:nowrap;gap:.4rem;margin-left:auto;padding-left:.6rem;flex:0 0 auto;color:var(--brand)}
.dir-item__kind{display:flex;flex:0 0 auto;opacity:.9}
.dir-item__kinds svg{display:block;width:18px;height:18px}
.dir-item__ic{flex:0 0 auto;color:var(--brand)}
.dir-item__tag{flex:0 0 auto;background:var(--brand);color:#fff;border-radius:999px;padding:.1rem .5rem;font-size:.7rem;font-weight:700;letter-spacing:.01em}
/* Znacznik jako jedyny napis pozycji galerii (ASH-00156) — musi czytać się
   jak tytuł, nie jak przypis. */
.dir-item__tag--lg{font-size:1rem;padding:.22rem .8rem}
.dir-head__title--home{color:var(--brand-dk);display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.modal__actions-left{margin-right:auto}

/* ---------- TOAST ---------- */
.toast{position:fixed;left:50%;bottom:1.2rem;transform:translate(-50%,1rem);opacity:0;background:var(--ink);color:#fff;padding:.6rem 1rem;border-radius:999px;font-size:.88rem;z-index:200;transition:opacity .2s,transform .2s;max-width:90vw;box-shadow:var(--shadow-lg)}
.toast--show{opacity:1;transform:translate(-50%,0)}
.toast--error{background:var(--neg)}
.toast--success{background:var(--pos)}
.toast--warn{background:#b45309}

/* ---------- RESPONSIVE (katalogi) ---------- */
@media (max-width:560px){
  .dir-item__kinds{gap:.3rem;padding-left:.4rem}
  .dir-item__kinds svg{width:16px;height:16px}
  /* ASH-00380: ten sam rozmiar co ikony rodzajów plików. */
  .dr-acc__i svg{width:16px;height:16px}
  .dir-item{flex-wrap:wrap}
  .dir-item__actions{width:100%;justify-content:flex-end;flex-wrap:wrap}
}

/* ---------- CHECKBOX ROW ---------- */
.check-row{display:flex;align-items:center;gap:.5rem;margin-bottom:.9rem;font-size:.95rem;cursor:pointer}
.check-row input{width:auto;min-height:0;accent-color:var(--brand)}

/* ---------- NADANIA (grant-box) ---------- */
.grant-box{border:1px solid var(--line2);border-radius:var(--radius-sm);padding:.5rem .6rem;max-height:190px;overflow:auto;display:flex;flex-direction:column;gap:.15rem}
.grant-box .check-row{margin-bottom:0}
/* Osobne okno „Uprawnienia" (ASH-00180) — cała treść to nadania, więc lista
   może zająć większość ekranu zamiast 190 px jak wtrącenie w formularzu. */
.grant-box--tall{max-height:52vh}
select.input{appearance:auto;-webkit-appearance:menulist}

/* ---------- WIERSZ NADANIA (podgląd/wgrywanie) ---------- */
.grant-row{display:flex;align-items:center;justify-content:space-between;gap:.6rem;padding:.32rem 0;border-bottom:1px solid var(--line)}
.grant-row:last-child{border-bottom:0}
.grant-row__label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.92rem}
.grant-row__chks{display:flex;gap:.35rem;flex-shrink:0;justify-content:flex-end}
.grant-row__hidden{display:none}
/* Przelaczniki ikonowe uprawnien (ASH-00184). */
.grant-ico{display:inline-flex;align-items:center;justify-content:center;width:2.15rem;height:2.15rem;padding:0;
  border:1px solid var(--line2);border-radius:var(--radius-sm);background:var(--card);color:var(--muted);
  opacity:.6;cursor:pointer;transition:color .15s,background .15s,border-color .15s,opacity .15s}
.grant-ico:hover{border-color:var(--brand-soft)}
.grant-ico.is-on{color:var(--brand);opacity:1;border-color:var(--brand-soft);background:var(--brand-hint)}
.grant-ico.is-locked{cursor:default}
.grant-ico.is-locked.is-on{opacity:.72}

/* ---------- WIDOK KATALOGU / GALERIA ---------- */
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:.35rem}
/* ASH-00341: kafel jest wlasna wyspa ukladu i rysowania — zmiana klasy na
   jednym kaflu nie ma prawa uniewazniac sasiadow. */
.tile{border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden;display:flex;flex-direction:column;background:#fff;contain:layout paint}
.tile__media{aspect-ratio:1/1;background:var(--brand-hint);display:flex;align-items:center;justify-content:center;overflow:hidden}
.tile__img{width:100%;height:100%;object-fit:cover;cursor:zoom-in;display:block}
.tile__file{font-weight:800;color:var(--brand-dk);font-size:1.05rem;letter-spacing:.05em}
.tile__name{font-size:.82rem;padding:.4rem .5rem 0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile__meta{font-size:.72rem;color:var(--muted);padding:.1rem .5rem .35rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.tile__actions{display:flex;gap:.35rem;padding:.4rem .5rem;margin-top:auto}
/* Plik usunięty — widoczny wyłącznie dla admina (ASH-00082). */
/* Kafel, ktory doszedl sam z pollingu (ASH-00213) — miekkie wejscie, zeby
   bylo widac, ze lista zaktualizowala sie bez odswiezania strony. */
@keyframes tileIn{from{opacity:0;transform:scale(.94)}to{opacity:1;transform:none}}
.tile--new{animation:tileIn .5s ease-out both}
@media (prefers-reduced-motion:reduce){.tile--new{animation:none}}
.tile--deleted{border-style:dashed;border-color:var(--line2);background:var(--brand-hint)}
.tile--deleted .tile__img,.tile--deleted .tile__file{opacity:.38;filter:grayscale(1)}
.tile--deleted .tile__check{display:none}
.tile--deleted .tile__name{text-decoration:line-through;color:var(--muted)}
.tile--deleted .tile__dl{display:none}
.tile__meta--del{color:var(--neg,#b3261e);font-weight:600}
.tile__badge{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:3;background:rgba(30,27,46,.78);color:#fff;font-size:.7rem;letter-spacing:.06em;text-transform:uppercase;padding:.18rem .5rem;border-radius:999px;white-space:nowrap}
.tile__actions .btn{flex:1;padding:0 .4rem}
.up-progress-host{margin-top:.6rem}
.up-bar{height:8px;background:var(--brand-soft);border-radius:999px;overflow:hidden;margin-top:.3rem}
.up-bar__fill{height:100%;width:0;background:var(--brand);transition:width .15s ease}
.up-label{font-size:.85rem}

/* ---------- DRAG & DROP ---------- */
.drop-zone{margin-top:.7rem;border:2px dashed var(--line2);border-radius:var(--radius-sm);padding:1.1rem;text-align:center;color:var(--muted);cursor:pointer;transition:border-color .15s,background .15s,color .15s;font-size:.9rem}
.drop-zone:hover{border-color:var(--brand)}
.drop-zone.is-over{border-color:var(--brand);background:var(--brand-hint);color:var(--brand-dk)}

/* ---------- LIGHTBOX (podgląd zdjęć) ---------- */
/* Stary lightbox (strzałki po bokach) usunięty w 0.34.0 — patrz sekcja .lb__ niżej. */

/* ---------- UPLOAD (bieżący plik) ---------- */
.up-box{margin-top:.6rem}
.up-counter{display:flex;justify-content:space-between;align-items:baseline;gap:.6rem;font-size:.85rem;font-weight:600;margin-bottom:.4rem}
.up-counter__main{white-space:nowrap}
.up-counter__rate{font-weight:500;font-size:.8rem;color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap;text-align:right}
/* ASH-00346: zrodla plikow w sekcji „Dodaj pliki" — jedno na cala szerokosc,
   dwa obok siebie w jednej linii (na waskim ekranie dziela ja po polowie). */
.up-src{margin-top:.55rem;gap:.5rem;flex-wrap:wrap}
.up-src .btn{flex:1 1 auto}
.up-current{display:flex;gap:.6rem;align-items:center;margin-top:.55rem}
.up-thumb{position:relative;flex:0 0 64px;width:64px;height:64px;border-radius:10px;overflow:hidden;background:var(--brand-hint);display:flex;align-items:center;justify-content:center;font-weight:800;color:var(--brand-dk);font-size:.72rem;letter-spacing:.03em}
.up-thumb img{width:100%;height:100%;object-fit:cover;display:block}
.up-current__info{flex:1;min-width:0}
.up-current__name{font-size:.85rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;margin-bottom:.3rem}
.up-status{font-size:.8rem;margin-top:.4rem}

/* ---------- KAFEL: gloss „pobierz" nad obrazem ---------- */
.tile__media{position:relative}
.tile__dl{position:absolute;top:6px;right:6px;width:36px;height:36px;border-radius:999px;display:flex;align-items:center;justify-content:center;color:#fff;background:rgba(30,27,46,.42);border:1px solid rgba(255,255,255,.3);box-shadow:0 2px 8px rgba(0,0,0,.28);text-decoration:none;transition:background .15s,transform .05s}
.tile__dl:hover{background:rgba(124,58,237,.82)}
.tile__dl:active{transform:scale(.94)}
@supports ((-webkit-backdrop-filter:blur(3px)) or (backdrop-filter:blur(3px))){ .tile__dl{backdrop-filter:blur(3px);-webkit-backdrop-filter:blur(3px)} }

/* v0.18.0 — miniatura z efektem podnoszącej się wody (szarość -> kolor) */
.up-thumb__img{position:absolute;left:0;bottom:0;width:64px;height:64px;object-fit:cover;display:block}
.up-thumb__img--gray{top:0;filter:grayscale(1) brightness(.9)}
.up-thumb__img--color{-webkit-mask-image:linear-gradient(#000 0%,transparent 0%);mask-image:linear-gradient(#000 0%,transparent 0%);-webkit-mask-size:100% 100%;mask-size:100% 100%;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat}
.up-thumb--file .up-thumb__img{display:none}

/* v0.20.0 — zaznaczanie i pobieranie wielu */
.gallery__bar{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center;margin-bottom:.7rem}
.gallery__selinfo{font-size:.85rem;font-weight:600;margin-right:.3rem}
/* ASH-00341: wejscie w tryb zaznaczania NIE MOZE zmieniac ukladu kafli.
   Wczesniej znacznik pojawial sie przez `display:none -> flex`, a rzad akcji
   znikal przez `display:none` — przy 4 tys. kafli to przeliczenie ukladu calej
   siatki i przerysowanie (a na telefonie ponowne dekodowanie) wszystkich
   miniatur naraz: „cala galeria sie przeladowuje". Teraz znacznik siedzi
   w ukladzie na stale i tylko sie odslania, a rzad akcji chowa sie przez
   `visibility` — jedno i drugie to sama warstwa rysowania, bez ukladu. */
.tile__check{position:absolute;top:6px;left:6px;width:24px;height:24px;border-radius:50%;background:rgba(255,255,255,.9);border:2px solid #fff;box-shadow:0 1px 4px rgba(0,0,0,.35);display:flex;align-items:center;justify-content:center;color:transparent;z-index:2;opacity:0;pointer-events:none}
.gallery--select .tile__check{opacity:1;pointer-events:auto}
.gallery--select .tile__media{cursor:pointer}
.gallery--select .tile__img{cursor:pointer}
.tile.is-selected .tile__check{background:var(--brand);border-color:#fff;color:#fff}
.tile.is-selected .tile__media{outline:3px solid var(--brand);outline-offset:-3px}
.gallery--select .tile__dl{opacity:0;pointer-events:none}
.gallery--select .tile__actions{visibility:hidden}

/* v0.21.0 — PIN / wzór dostępu */
.secpad{max-width:280px;margin:1rem auto 0}
.secpad__display{display:flex;gap:.5rem;justify-content:center;min-height:20px;margin-bottom:1.1rem}
.secdot{width:12px;height:12px;border-radius:50%;border:2px solid var(--brand);background:transparent}
.secdot.is-on{background:var(--brand)}
.secpad__keys{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}
.secpad__key{aspect-ratio:1/1;border:1px solid var(--line2);border-radius:50%;background:#fff;font-size:1.4rem;font-weight:600;color:var(--ink);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:background .1s,transform .05s;-webkit-user-select:none;user-select:none}
.secpad__key:hover{background:var(--brand-hint)}
.secpad__key:active{transform:scale(.94);background:var(--brand-soft)}
.secpad__key--ok{background:var(--brand);color:#fff;font-size:.9rem;border-color:var(--brand)}
.secpad__key--ok:hover{background:var(--brand-dk)}
.secpad__key--fn{font-size:1.25rem;color:var(--muted)}
.secpad--pattern .secpad__grid{position:relative;width:240px;height:240px;max-width:78vw;max-height:78vw;margin:.4rem auto 0;display:grid;grid-template-columns:repeat(3,1fr);grid-template-rows:repeat(3,1fr);place-items:center;touch-action:none;-webkit-user-select:none;user-select:none;cursor:pointer}
.secpad__lines{position:absolute;inset:0;width:100%;height:100%;pointer-events:none;color:var(--brand);z-index:1}
.secpad__dot{width:28px;height:28px;border-radius:50%;border:2px solid var(--brand);background:#fff;z-index:2;pointer-events:none;display:flex;align-items:center;justify-content:center;transition:transform .05s}
.secpad__dot.is-on{background:var(--brand);transform:scale(1.08)}
.secpad__dotnum{font-size:.75rem;font-weight:700;color:#fff;line-height:1}
.secpad__actions{display:flex;gap:.5rem;justify-content:center;margin-top:1.1rem}
.secpad__stage{text-align:center;font-weight:600;font-size:.9rem;margin:.5rem 0 .2rem;color:var(--brand-dk)}
.secpad.is-err .secpad__grid,.secpad.is-err .secpad__display{animation:secShake .38s}
.secpad.is-err .secpad__dot{border-color:var(--danger,#e5484d)}
.secpad.is-err .secpad__lines{color:var(--danger,#e5484d)}
@keyframes secShake{0%,100%{transform:translateX(0)}20%{transform:translateX(-7px)}40%{transform:translateX(6px)}60%{transform:translateX(-4px)}80%{transform:translateX(3px)}}

/* ---------- POMIAR ŁĄCZA (ASH-00068) ---------- */
.sp-wrap{display:flex;flex-direction:column;gap:.7rem}
.sp-sub{margin:0}
.sp-gauge{
  display:flex;flex-direction:column;align-items:center;justify-content:center;
  background:var(--brand-hint);border:1px solid var(--line);border-radius:var(--radius);
  padding:1rem .8rem .8rem;
}
.sp-gauge__phase{font-size:.82rem;color:var(--muted);letter-spacing:.02em;min-height:1.2em}
.sp-gauge__val{
  font-family:var(--font-brand);font-size:2.9rem;line-height:1.05;font-weight:700;
  color:var(--brand-dk);font-variant-numeric:tabular-nums;
}
.sp-gauge__unit{font-size:.8rem;color:var(--muted)}
.sp-chartbox{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:.35rem;overflow:hidden;
}
.sp-chart{display:block}
.sp-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:.5rem}
.sp-cell{
  background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:.5rem .6rem;
}
.sp-cell__val{font-weight:700;font-size:1.02rem;color:var(--ink);font-variant-numeric:tabular-nums}
.sp-cell__lab{font-size:.78rem;color:var(--muted)}
.sp-cell__hint{font-size:.7rem;color:var(--muted);opacity:.8}
.sp-row{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.sp-row__lab{font-size:.85rem;color:var(--muted)}
.sp-row__sel{flex:0 1 auto;min-width:9rem;padding:.4rem .5rem}
.sp-acts{display:flex;gap:.5rem;justify-content:flex-end;flex-wrap:wrap}
.sp-verdict{
  background:var(--brand-hint);border:1px solid var(--brand-soft);
  border-radius:var(--radius-sm);padding:.6rem .75rem;
}
.sp-verdict__head{font-weight:700;font-size:.9rem;margin-bottom:.3rem}
.sp-verdict__list{margin:0;padding-left:1.1rem;font-size:.87rem}
.sp-verdict__list li{margin:.2rem 0}
.sp-verdict__net{font-size:.75rem;color:var(--muted);margin-top:.4rem}
.sp-hist{margin-top:.5rem}
.sp-hist__tbl{display:flex;flex-direction:column;border:1px solid var(--line);border-radius:var(--radius-sm);overflow:hidden}
.sp-hist__row{
  display:grid;grid-template-columns:1.2fr .6fr 1.3fr 1.3fr .8fr;gap:.4rem;
  padding:.4rem .55rem;font-size:.8rem;border-top:1px solid var(--line);
  font-variant-numeric:tabular-nums;
}
.sp-hist__row:first-child{border-top:0}
.sp-hist__row--head{background:var(--brand-hint);font-weight:700;color:var(--brand-dk)}
.sp-hist__row span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* ---------- kolejka lekkich wersji filmow (ASH-00253) ---------- */
.vq-acts{display:flex;gap:.4rem;flex-wrap:wrap}
.vq-state{margin:.4rem 0 .2rem}
.vq-line{display:flex;align-items:center;gap:.45rem;font-weight:600}
/* Kropka stanu zamiast slowa „pracuje/stoi" — widac ja katem oka, a przy
   odswiezaniu co 3 s zmiana koloru rzuca sie bardziej niz zmiana tekstu. */
.vq-dot{width:10px;height:10px;border-radius:999px;background:var(--line2);flex:0 0 auto}
.vq-dot.is-run{background:#16a34a;box-shadow:0 0 0 3px rgba(22,163,74,.18)}
.vq-dot.is-pause{background:#f59e0b}
.vq-chips{display:flex;flex-wrap:wrap;gap:.35rem;margin:.45rem 0}
.vq-chip{border:1px solid var(--line);border-radius:999px;padding:.2rem .55rem;font-size:.8rem;
  background:#fff;color:var(--muted);font-variant-numeric:tabular-nums}
.vq-chip strong{color:var(--ink)}
.vq-chip.is-ok{border-color:#bbf7d0;background:#f0fdf4}
.vq-chip.is-bad{border-color:#fecaca;background:#fef2f2}
.vq-chip.is-bad strong{color:#b91c1c}
.vq-warn{color:#b45309;background:#fffbeb;border:1px solid #fde68a;border-radius:var(--radius-sm);
  padding:.4rem .6rem;font-size:.82rem;margin:.4rem 0}
.vq-now{border:1px solid var(--brand-soft);background:var(--brand-hint);border-radius:var(--radius-sm);
  padding:.45rem .6rem;margin:.35rem 0}
.vq-now__nm{display:flex;align-items:center;gap:.45rem;font-weight:600;min-width:0}
.vq-now__nm>span:first-child{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.vq-now__meta{font-size:.8rem;color:var(--muted);font-variant-numeric:tabular-nums}
.vq-tag{flex:0 0 auto;font-size:.72rem;font-weight:700;color:var(--brand-dk);
  border:1px solid var(--brand-soft);border-radius:999px;padding:.05rem .4rem;background:#fff}
.vq-add{margin:.7rem 0 .3rem}
.vq-tools{display:flex;gap:.4rem;flex-wrap:wrap;margin-top:.6rem}
.vq-bad{color:#b91c1c}
/* Nazwa pliku dostaje najwiecej miejsca — reszta kolumn to liczby. */
.sp-hist--vq .sp-hist__row{grid-template-columns:2fr .7fr 1.4fr .7fr 1fr}
@media (max-width:560px){
  .sp-hist--vq .sp-hist__row{grid-template-columns:1fr 1fr}
}

@media (max-width:560px){
  .sp-gauge__val{font-size:2.3rem}
  .sp-grid{grid-template-columns:1fr 1fr}
  .sp-hist__row{grid-template-columns:1fr 1fr;font-size:.75rem}
  .sp-hist__row--head{display:none}
}

/* ---------- BELKA POSTEPU WYSYLKI (globalna, ASH-00074) ---------- */
.upbar{
  position:sticky; top:0; z-index:35; cursor:pointer;
  background:var(--brand-hint); border-bottom:1px solid var(--brand-soft);
  box-shadow:0 2px 8px rgba(76,29,149,.10);
}
.upbar--warn{background:var(--warn-soft);border-bottom-color:#f5d78e}
.upbar__in{
  max-width:var(--maxw); margin:0 auto; padding:.4rem 1rem .45rem;
  display:grid; grid-template-columns:1fr auto; gap:.15rem .8rem; align-items:center;
}
.upbar__txt{
  font-size:.82rem; font-weight:700; color:var(--brand-dk);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
.upbar__rate{
  font-size:.78rem; color:var(--muted); text-align:right;
  font-variant-numeric:tabular-nums; white-space:nowrap;
}
.upbar__bar{
  grid-column:1 / -1; height:5px; border-radius:3px;
  background:rgba(124,58,237,.15); overflow:hidden;
}
.upbar__fill{height:100%;background:var(--brand-grad);border-radius:3px;transition:width .25s ease}
@media (max-width:560px){
  .upbar__in{padding:.35rem .8rem .4rem}
  .upbar__txt{font-size:.76rem}
  .upbar__rate{font-size:.72rem}
}

/* ---------- WSKAZNIKI RUCHU PRZY KATALOGACH (ASH-00079) ----------
   Strzalka w gore (animacja od dolu) = trwa wysylka, strzalka w dol (od gory)
   = trwa pobieranie, klepsydra = pliki czekaja w kolejce. Animacje sa CIAGLE,
   nie procentowe: procent jest jeden, na gornej belce, a dwa rozne jezyki
   wizualne w jednym widoku klocilyby sie ze soba. */
.dir-sig{position:relative;display:inline-flex;width:22px;height:22px;flex-shrink:0;align-self:center}
.dir-sig:empty{display:none}
.dir-sig svg{position:absolute;left:1px;top:1px}
.dir-sig__base{color:var(--line2)}
.dir-sig__fill{color:var(--brand)}
.dir-sig--up .dir-sig__base{color:var(--brand-soft)}
.dir-sig--down .dir-sig__base{color:var(--brand-soft)}
.dir-sig--up .dir-sig__fill{animation:sig-up 1.25s ease-in-out infinite}
.dir-sig--down .dir-sig__fill{animation:sig-down 1.25s ease-in-out infinite}
.dir-sig--wait .dir-sig__base{color:var(--warn);animation:sig-wait 1.8s ease-in-out infinite}
@keyframes sig-up{
  0%{clip-path:inset(100% 0 0 0)}
  70%{clip-path:inset(0 0 0 0)}
  100%{clip-path:inset(0 0 0 0);opacity:.25}
}
@keyframes sig-down{
  0%{clip-path:inset(0 0 100% 0)}
  70%{clip-path:inset(0 0 0 0)}
  100%{clip-path:inset(0 0 0 0);opacity:.25}
}
@keyframes sig-wait{
  0%,100%{opacity:.4;transform:rotate(0deg)}
  50%{opacity:1;transform:rotate(0deg)}
  85%{opacity:1;transform:rotate(180deg)}
}
@media (prefers-reduced-motion:reduce){
  .dir-sig--up .dir-sig__fill,.dir-sig--down .dir-sig__fill,
  .dir-sig--wait .dir-sig__base{animation:none;opacity:.85}
}


/* ---------- galeria: grupy dzienne, filtry autorów (ASH-00086/93) ---------- */
.gallery__body{display:flex;flex-direction:column;gap:1rem}
/* ASH-00341: dzien, ktorego nie widac, nie jest w ogole liczony ani rysowany
   (`content-visibility`, Baseline od Safari 18). Dzieki temu koszt kazdej
   operacji na galerii — wejscie w tryb zaznaczania, przelaczenie filtra,
   przewijanie — zalezy od tego, co widac, a nie od tego, ile zdjec ma katalog.
   `auto` w `contain-intrinsic-size` sprawia, ze przegladarka pamieta prawdziwa
   wysokosc raz obejrzanego dnia, wiec pasek przewijania sie nie skacze.
   700 px to wstepne oszacowanie dla dnia, ktorego jeszcze nie widzielismy. */
.daygroup{display:flex;flex-direction:column;gap:.5rem;
  scroll-margin-top:calc(var(--topbar-h) + var(--galbar-h, 0px) + .5rem)}
/* ASH-00410: ZAWIJAS, ktory kosztowal „belka dnia sie nie przykleja".
   `content-visibility:auto` na KAZDEJ grupie dziennej zapetlalo sie, gdy grupa
   byla jedyna: dopoki jest pominieta, liczy sie jako 700 px (szacunek nizej),
   wiec strona nie ma czego przewijac; skoro nie ma czego przewijac, grupa nigdy
   nie staje sie „istotna" i nie rozwija sie do prawdziwej wysokosci. Efekt:
   katalog z jednym dniem w ogole sie nie przewija, a wiec i nic sie nie klei.
   (Zmierzone w Chrome: jeden dzien, 300 kafli — `scrollHeight` 953 px przy
   siatce 5551 px.) Przy wielu dniach szacunki sie sumuja, strona przewija sie
   od razu i problem nie wychodzi — stad „w niektorych katalogach jest,
   w niektorych nie ma".
   Dlatego pomijanie dostaje KAZDA grupa POZA pierwsza widoczna (klase nadaje
   `paint()` w app.js): pierwsza i tak jest na ekranie, wiec nic na niej nie
   oszczedzamy, a to ona daje stronie prawdziwa wysokosc. */
.daygroup--lazy{content-visibility:auto;contain-intrinsic-size:auto 700px}
.daygroup__head{position:sticky;top:calc(var(--topbar-h) + var(--galbar-h, 0px));z-index:4;display:flex;align-items:center;gap:.6rem;
  padding:.4rem .1rem;margin:0 -.1rem;background:var(--card);box-shadow:0 8px 10px -10px rgba(30,27,46,.35)}
.daygroup__title{font-weight:800;font-size:.95rem;color:var(--ink);text-transform:capitalize;
  user-select:none;-webkit-user-select:none;-webkit-touch-callout:none}
/* Skoki o cały dzień (ASH-00183) — trzymają się prawej krawędzi belki. */
.daygroup__nav{margin-left:auto;display:flex;align-items:center;gap:.25rem}
.daygroup__jump{border:1px solid var(--line2);background:#fff;color:var(--brand-dk);border-radius:8px;
  width:1.7rem;height:1.7rem;padding:0;display:flex;align-items:center;justify-content:center;cursor:pointer}
.daygroup__jump:hover:not(:disabled){border-color:var(--brand);background:var(--brand-hint)}
.daygroup__jump:disabled{opacity:.35;cursor:default}
.daygroup__mark{border:1px solid var(--line2);background:#fff;color:var(--brand-dk);border-radius:999px;
  font:inherit;font-size:.74rem;padding:.14rem .55rem;cursor:pointer}
.daygroup__mark:hover{border-color:var(--brand);background:var(--brand-hint)}
.daygroup__head.is-on .daygroup__title{color:var(--brand-dk)}
/* Pasek akcji zostaje w zasięgu ręki przy przewijaniu — inaczej po zaznaczeniu
   trzeba było wracać na samą górę, żeby cokolwiek z zaznaczeniem zrobić. */
.gallery__bar{display:flex;flex-wrap:wrap;gap:.5rem .6rem;align-items:center;justify-content:space-between;
  position:sticky;top:var(--topbar-h);z-index:6;background:var(--card);
  padding:.45rem 0;margin:-.2rem 0 .35rem;box-shadow:0 8px 10px -10px rgba(30,27,46,.35)}
.gallery__acts{display:flex;flex-wrap:wrap;gap:.4rem;align-items:center}
/* ASH-00405: kopia „← Moje katalogi" w lepkim pasku. Odsunieta od reszty akcji,
   zeby nie mylila sie z przyciskami dotyczacymi zdjec. */
.gallery__back{margin-left:.35rem}
/* ---------- ASH-00407/00408: przyciski paska akcji katalogu ----------
   Kazdy ma ikone MDI, podpis w `.btn__t` i licznik w `.btn__n`. Szeroko wyglada
   jak dotad — „Pobierz (12)" — bo nawiasy dorysowuje CSS, a nie tresc elementu.
   Waski ekran: `.gallery__acts--tight` (klase nadaje pomiar w `fitActs`, nie
   breakpoint) chowa podpisy i przenosi licznik na plakietke przy ikonie, dzieki
   czemu caly rzad zostaje w JEDNEJ linii. Tresc podpisu niesie dalej `title`
   i `aria-label`. */
.btn--act .btn__n{font-weight:400;font-variant-numeric:tabular-nums}
.btn--act .btn__n:empty{display:none}
.btn--act .btn__n::before{content:"("}
.btn--act .btn__n::after{content:")"}
/* ASH-00413: rzad lamie sie normalnie i ma prawo zajac DWIE linie. Dopiero
   gdy i dwie nie starcza (`fitBarActs` liczy linie po `offsetTop`), podpis
   traci WYLACZNIE „Usun" — czerwony kosz czyta sie sam, reszta ikon nie.
   Licznik zaznaczenia siada wtedy plakietka w rogu kosza. */
.gallery__acts--tight{padding-top:.3rem;gap:.35rem}
/* Ostatnia deska ratunku dokłada jeszcze odrobinę: ciaśniejsze odstępy, węższe
   przyciski i ikony 16 px zamiast 18. Zmierzone w Chrome: rząd sześciu
   przycisków mieści się wtedy w dwóch liniach do ~390 px zamiast ~400 px. */
.gallery__acts--tight .btn{padding:0 .55rem}
.gallery__acts--tight .btn .mdi{width:16px;height:16px}
.gallery__acts--tight .btn--danger{position:relative;padding:0 .55rem;gap:0}
.gallery__acts--tight .btn--danger .btn__t{display:none}
.gallery__acts--tight .btn--danger .btn__n{position:absolute;top:-.28rem;right:-.28rem;
  min-width:.95rem;height:.95rem;padding:0 .16rem;border-radius:999px;font-weight:800;
  background:var(--neg);color:#fff;font-size:.62rem;line-height:1;
  display:flex;align-items:center;justify-content:center;box-shadow:0 0 0 2px var(--card)}
/* Bez zaznaczenia licznika nie ma — plakietka nie moze zostac pusta kropka.
   `display:flex` wyzej bije ogolne `:empty{display:none}`, wiec powtarzamy je
   tu, z ta sama moca. */
.gallery__acts--tight .btn--danger .btn__n:empty{display:none}
/* Przycisk wyszarzony = nic nie zaznaczono; czerwone „0" w rogu byloby
   halasem. W wariancie z podpisem „Usuń (0)" zostaje jak dotad. */
.gallery__acts--tight .btn--danger:disabled .btn__n{display:none}
.gallery__acts--tight .btn--danger .btn__n::before,
.gallery__acts--tight .btn--danger .btn__n::after{content:none}
/* Filtry idą do prawej w tej samej linii co akcje; gdy się nie mieszczą, łamią się
   do nowej linii i wtedy stoją do lewej (efekt space-between przy jednym elemencie). */
.gallery__filters{display:flex;flex-wrap:wrap;gap:.45rem;align-items:center}
/* ASH-00352: „Cofnij" w belce filtrow trybu udostepniania — po prawej, poza
   grupa filtrow, zeby nie mieszalo sie z pigulkami. */
.gallery__undo{margin-left:auto;flex:0 0 auto}
/* Grupa filtra = dwie kolumny: stała na ikonę czyszczenia (na całej wysokości,
   ale sama ikona zostaje w pierwszym wierszu) i zawijająca się na pigułki, przez co
   kolejne wiersze pigułek równają się do lewej z pierwszym (ASH-00157). */
/* Zaokrąglenie STAŁE (ASH-00178): 999px kleiło się do połowy wysokości, więc po złamaniu
   pigułek na drugi wiersz ramka robiła się balonem. 1rem = dokładnie tyle, ile przeglądarka
   i tak przycina przy jednym wierszu (~15,7px), więc wygląd jednolinijkowy się nie zmienia. */
.flt-group{display:inline-flex;flex-wrap:nowrap;gap:.25rem;align-items:stretch;max-width:100%;
  border:1px solid var(--line);border-radius:1rem;padding:.15rem .25rem;background:var(--brand-hint)}
.flt-group__items{display:flex;flex-wrap:wrap;gap:.25rem;align-items:center;min-width:0}
.flt{border:1px solid transparent;background:transparent;color:var(--muted);border-radius:999px;
  font:inherit;font-size:.78rem;line-height:1.5;padding:.12rem .55rem;cursor:pointer;white-space:nowrap;
  transition:background .12s,color .12s,border-color .12s;-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}
.flt:hover{border-color:var(--brand-soft)}
.flt.is-on{background:#fff;border-color:var(--brand-soft);color:var(--brand-dk);font-weight:600;
  box-shadow:0 1px 2px rgba(76,29,149,.12)}
.flt--all{display:inline-flex;align-items:flex-start;justify-content:center;color:var(--brand-dk);
  padding:.18rem .35rem;flex:0 0 auto;align-self:stretch}
.flt--all svg{margin-top:.1rem}
.flt--all.is-idle{color:var(--line2);cursor:default}
.flt--all:hover{border-color:transparent;background:#fff}

/* Kafel u użytkownika: samo zdjęcie (ASH-00087) */
.tile__media{-webkit-touch-callout:none;-webkit-user-select:none;user-select:none}
@media (hover:none){.lb__zone{display:none}}
.tile--plain{border:0;background:transparent;border-radius:var(--radius-sm)}
.tile--plain .tile__media{border-radius:var(--radius-sm)}
.tile--plain .tile__fname{position:absolute;left:0;right:0;bottom:0;padding:.3rem .4rem;font-size:.72rem;
  color:#fff;background:rgba(30,27,46,.55);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* Wybór katalogu docelowego przy udostępnianiu (ASH-00092) */
.pick-box{display:flex;flex-wrap:wrap;gap:.4rem;margin:.2rem 0 .6rem}
.pick{border:1px solid var(--line2);background:#fff;color:var(--ink);border-radius:var(--radius-sm);
  font:inherit;font-size:.86rem;padding:.4rem .7rem;cursor:pointer;text-align:left}
.pick:hover{border-color:var(--brand)}
.pick.is-on{border-color:var(--brand);background:var(--brand-hint);font-weight:600;box-shadow:inset 0 0 0 1px var(--brand)}
.pick--new{border-style:dashed;color:var(--brand-dk);
  display:inline-flex;align-items:center;gap:.35rem}
.pick--new .mdi{flex:0 0 auto}
/* ASH-00418: naglowek sekcji katalogow — kropka, krotka kreska, tytul i linia
   ciagnaca sie do konca okna. Wszystko fioletowe; tytul ciemniejszy, zeby dalo
   sie go czytac na bialym. */
.pick-sec{display:flex;align-items:center;gap:.45rem;margin:.9rem 0 .35rem}
.pick-sec:first-child{margin-top:.2rem}
.pick-sec__dot{width:10px;height:10px;border-radius:50%;background:var(--brand);flex:0 0 auto}
.pick-sec__t{font-size:.76rem;font-weight:800;letter-spacing:.03em;text-transform:uppercase;
  color:var(--brand-dk);white-space:nowrap;flex:0 0 auto}
.pick-sec__ln{height:0;border-top:2px solid var(--brand);flex:1 1 auto;min-width:0}
.pick-sec__ln--pre{flex:0 0 18px}

/* ---------- lightbox (ASH-00088/89/90/94) ---------- */
.lightbox{position:fixed;inset:0;z-index:60;background:rgba(12,10,20,.96);display:flex;flex-direction:column}
.lb__top{display:flex;align-items:center;gap:.5rem;padding:.5rem .6rem;color:#fff;flex:0 0 auto}
.lb__spacer{flex:1}
.lb__zoom{font-size:.8rem;color:rgba(255,255,255,.75);min-width:3rem;text-align:left}
.lb__btn{width:42px;height:42px;border-radius:999px;border:1px solid rgba(255,255,255,.22);
  background:rgba(255,255,255,.09);color:#fff;display:flex;align-items:center;justify-content:center;
  cursor:pointer;font-size:1.5rem;line-height:1;text-decoration:none;flex:0 0 auto}
.lb__btn:hover{background:rgba(255,255,255,.2)}
.lb__sel.is-on{background:var(--brand);border-color:var(--brand)}
.lb__del:hover{background:rgba(214,64,64,.55);border-color:rgba(255,150,150,.6)}
.lb__stage{position:relative;flex:1 1 auto;overflow:hidden;display:flex;align-items:center;justify-content:center;touch-action:none}
.lb__ph{position:absolute;inset:0;background-repeat:no-repeat;background-position:center;background-size:contain;
  filter:blur(14px);transform:scale(1.02);transition:opacity .18s;opacity:0}
.lb__img{max-width:100%;max-height:100%;object-fit:contain;display:block;transform-origin:center center;
  transition:opacity .18s;opacity:0;will-change:transform;user-select:none;-webkit-user-drag:none}
/* Połowa i połowa — żeby między „wstecz" a „dalej" nie było martwego pasa
   w środku zdjęcia, w który klika się bez skutku (ASH-00260). */
.lb__zone{position:absolute;top:0;bottom:0;width:50%;cursor:pointer;z-index:2}
/* ASH-00482: swipe góra/dół — nowe zdjęcie wjeżdża z kierunku ruchu palca. */
.lb__stage.lb-enter-up{animation:lbEnterUp .24s ease-out}
.lb__stage.lb-enter-down{animation:lbEnterDown .24s ease-out}
@keyframes lbEnterUp{from{transform:translateY(14%);opacity:.35}to{transform:none;opacity:1}}
@keyframes lbEnterDown{from{transform:translateY(-14%);opacity:.35}to{transform:none;opacity:1}}
@media (prefers-reduced-motion:reduce){.lb__stage.lb-enter-up,.lb__stage.lb-enter-down{animation:none}}
.lb__zone--l{left:0}
.lb__zone--r{right:0}
.lightbox.is-zoomed .lb__zone{display:none}
.lightbox.is-zoomed .lb__img{cursor:grab}
.lightbox.is-zoomed .lb__stage{cursor:grab}
.lightbox.is-panning .lb__img,.lightbox.is-panning .lb__stage{cursor:grabbing}
@media (hover:hover){
  .lb__zone--l:hover{background:linear-gradient(90deg,rgba(255,255,255,.10),transparent 55%)}
  .lb__zone--r:hover{background:linear-gradient(270deg,rgba(255,255,255,.10),transparent 55%)}
}
.lb__bottom{flex:0 0 auto;padding:.3rem .5rem .6rem;color:#fff}
.lb__strip{display:flex;gap:.35rem;justify-content:center;overflow:hidden;padding:.25rem .1rem}
.lb__thumb{flex:0 0 auto;width:46px;height:46px;border-radius:6px;overflow:hidden;opacity:.55;
  border:2px solid transparent;cursor:pointer;position:relative}
.lb__thumb img{width:100%;height:100%;object-fit:cover;display:block}
.lb__thumb.is-cur{opacity:1;border-color:#fff;transform:scale(1.06)}
.lb__thumb.is-sel::after{content:'';position:absolute;inset:0;box-shadow:inset 0 0 0 3px var(--brand);border-radius:4px}
.lb__cap{font-size:.8rem;color:rgba(255,255,255,.82);text-align:center;padding:.35rem .2rem 0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@media (max-width:600px){
  .lb__thumb{width:38px;height:38px}
  .lb__cap{font-size:.74rem}
}

/* ---------- lightbox: własny tryb pełnoekranowy (ASH-00260) ----------
   Do prezentacji (laptop + rzutnik). Paski przestają zabierać zdjęciu wysokość
   i kładą się NA nim półprzezroczyste: widać, że coś tam jest, pełną ostrość
   dostają dopiero pod kursorem. Nic nie znika samo — na rzutniku migotanie
   kontrolek przy każdym ruchu myszy byłoby gorsze niż stałe przygaszenie.   */
.lightbox.is-fs{background:#000}
.lightbox.is-fs .lb__stage{position:absolute;inset:0;flex:1 1 auto}
.lightbox.is-fs .lb__top{position:absolute;left:0;right:0;top:0;z-index:5;
  opacity:.8;transition:opacity .16s ease;background:none;padding:.7rem .8rem .55rem}
/* Gradient wychodzi POZA pasek (pseudoelement, nie padding): jest wyższy i łagodniej
   schodzi w zdjęcie, a przy tym nie zabiera klikalnej powierzchni obrazu. */
.lightbox.is-fs .lb__top::before{content:'';position:absolute;left:0;right:0;top:0;height:190%;
  pointer-events:none;z-index:-1;
  background:linear-gradient(180deg,rgba(0,0,0,.68),rgba(0,0,0,.3) 48%,rgba(0,0,0,0))}
.lightbox.is-fs .lb__top:hover,
.lightbox.is-fs .lb__top:focus-within{opacity:1}
.lightbox.is-fs .lb__bottom{position:absolute;left:0;right:0;bottom:0;z-index:5;
  text-align:center;padding:.5rem .5rem .6rem;
  background:linear-gradient(0deg,rgba(0,0,0,.5),rgba(0,0,0,0))}
/* ASH-00345: w pelnym ekranie pasek mikro-miniatur i przyciski byly za slabo
   widoczne — kazda z tych przezroczystosci idzie o 20 punktow w gore. */
.lightbox.is-fs .lb__strip{opacity:.8;transition:opacity .16s ease}
.lightbox.is-fs .lb__bottom:hover .lb__strip,
.lightbox.is-fs .lb__bottom:focus-within .lb__strip{opacity:1}
/* Podpis zostaje czytelny NIEZALEŻNIE od tego, co jest pod nim: szklana
   plakietka (przyciemnienie + rozmycie tła) plus cień liter. Dobieranie koloru
   do jasności zdjęcia byłoby ładniejsze, ale zawodzi na wzorzystym tle i kosztuje
   próbkowanie canvasem przy każdej zmianie slajdu. */
.lightbox.is-fs .lb__cap{display:inline-block;max-width:92%;margin:.35rem auto 0;
  padding:.26rem .8rem;border-radius:999px;color:#fff;
  background:rgba(10,8,16,.55);box-shadow:inset 0 0 0 1px rgba(255,255,255,.16);
  -webkit-backdrop-filter:blur(10px) saturate(1.3);backdrop-filter:blur(10px) saturate(1.3);
  text-shadow:0 1px 3px rgba(0,0,0,.95),0 0 12px rgba(0,0,0,.7)}
/* Powiększone zdjęcie ogląda się bez rozpraszaczy — tak samo jak panel „i". */
.lightbox.is-fs.is-zoomed .lb__top,
.lightbox.is-fs.is-zoomed .lb__bottom{opacity:.5}
.lightbox.is-fs.is-zoomed .lb__top:hover,
.lightbox.is-fs.is-zoomed .lb__bottom:hover{opacity:1}
/* Panel „Informacje" ustępuje miejsca plakietce z podpisem. */
.lightbox.is-fs .lb__info{bottom:5.2rem}
/* Przy filmie panel siedzi u góry — musi zejść pod wyższy pasek. */
.lightbox.is-fs .lb__info--vid{top:4.4rem;bottom:auto}
@media (max-width:600px){
  .lightbox.is-fs .lb__info{bottom:4.6rem}
}

/* Panel „Informacje" (ASH-00223) — szklany kafel w lewym dolnym rogu sceny.
   `pointer-events:none` jest tu ZASADA, nie ozdobnikiem: panel lezy na strefie
   nawigacyjnej (.lb__zone) i na kontrolkach filmu, wiec bez tego dotkniecie
   w jego obrebie przestaloby przewijac galerie i zatrzymywac film. Wyjatek
   dostaje tylko odsylacz do mapy. */
/* Przy filmie panel wedruje na GORE sceny — na dole stoja kontrolki odtwarzacza. */
.lb__info--vid{bottom:auto;top:.75rem}
.lb__info{position:absolute;left:.75rem;bottom:.75rem;z-index:3;max-width:23rem;max-height:48%;
  overflow:hidden;pointer-events:none;border-radius:12px;padding:.5rem .7rem;
  background:rgba(16,14,26,.62);border:1px solid rgba(255,255,255,.14);
  box-shadow:0 6px 22px rgba(0,0,0,.35);color:#fff;font-size:.72rem;line-height:1.45;
  -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
  transition:opacity .16s}
.lb__info-dl{display:grid;grid-template-columns:auto 1fr;gap:.1rem .7rem;margin:0}
.lb__info-dl dt{color:rgba(255,255,255,.55);white-space:nowrap}
/* `overflow-wrap:anywhere` rozumie dopiero Chrome 80 — stare WebView bramki
   zignorowaloby regule i dluga nazwa pliku zostalaby ucieta przez overflow. */
.lb__info-dl dd{margin:0;color:#fff;word-break:break-word;overflow-wrap:break-word}
.lb__info-lnk{color:#fff;text-decoration:underline;text-underline-offset:2px;pointer-events:auto}
.lb__info-wait{color:rgba(255,255,255,.5);font-style:italic;padding-top:.25rem}
/* Przelacznik jakosci filmu (ASH-00252). Panel „i" ma `pointer-events:none`
   na tle, wiec przyciski musza je wlaczyc u siebie — inaczej klikniecie
   przechodzi na scene i zamiast zmiany jakosci wychodzi przewiniecie slajdu. */
.lb__vqrow{display:flex;flex-wrap:wrap;gap:.25rem;padding:.1rem 0 .15rem;pointer-events:auto}
.lb__vq{appearance:none;-webkit-appearance:none;cursor:pointer;pointer-events:auto;
  font:inherit;line-height:1;padding:.25rem .5rem;border-radius:999px;
  border:1px solid rgba(255,255,255,.28);background:rgba(255,255,255,.08);color:#fff}
.lb__vq:hover:not(:disabled){background:rgba(255,255,255,.18)}
.lb__vq.is-on{background:var(--brand);border-color:var(--brand)}
.lb__vq:disabled{opacity:.35;cursor:default}
.lb__vqnow{color:rgba(255,255,255,.55);font-size:.92em}
.lb__ibtn.is-on{background:var(--brand);border-color:var(--brand)}
/* Przy powiekszeniu panel schodzi z drogi — po to sie powieksza, zeby patrzec
   na zdjecie. `display` steruje przelacznik, wiec gasimy inaczej; samo
   `opacity:0` NIE wylacza trafien i niewidzialny odsylacz do mapy dalej
   lapalby klikniecia zamiast przesuwania zdjecia. */
.lightbox.is-zoomed .lb__info{opacity:0;visibility:hidden}
@media (max-width:600px){
  .lb__info{left:.5rem;right:.5rem;bottom:.5rem;max-width:none;font-size:.7rem;padding:.45rem .6rem}
  .lb__info--vid{bottom:auto;top:.5rem}
  .lb__info-dl{gap:.05rem .55rem}
  /* Szosty krazek 42 px nie miescil sie na 360 px razem z polem zoomu:
     6x42 + odstepy + 48 przekraczalo szerokosc i „zamknij" wyjezdzalo poza ekran. */
  .lb__btn{width:38px;height:38px}
  .lb__zoom{min-width:2.2rem;font-size:.72rem}
}

/* Przygotowanie katalogu do przegladania (ASH-00219).
   Pasek postepu ZASTEPUJE przycisk w tym samym miejscu naglowka — nie
   rozpycha wiersza i widac, ze to ta sama akcja, tylko w toku. */
.prep{display:inline-flex;align-items:center}
.prep__box{min-width:15rem;max-width:22rem}
.prep__line{display:flex;align-items:center;gap:.4rem}
/* `min-width:0` jest WARUNKIEM dzialania wielokropka: bez niego element flex
   ma minimalna szerokosc rowna tresci i zamiast sie skrocic — rozpycha boks. */
.prep__txt{font-size:.78rem;color:var(--muted);font-variant-numeric:tabular-nums;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;min-width:0}
.prep__stop{flex:0 0 auto;width:22px;height:22px;line-height:1;border-radius:999px;
  border:1px solid var(--line2);background:#fff;color:var(--muted);cursor:pointer;font-size:1rem;
  display:flex;align-items:center;justify-content:center}
.prep__stop:hover{border-color:#fca5a5;color:#b91c1c;background:#fef2f2}
.prep__bar{height:6px;background:var(--brand-soft);border-radius:999px;overflow:hidden;margin-top:.25rem}
.prep__fill{height:100%;width:0;background:var(--brand-grad);border-radius:999px;transition:width .2s ease}
@media (max-width:600px){
  .prep,.prep__box{width:100%;min-width:0}
  /* Trzy przyciski wyboru zakresu nie mieszcza sie w wierszu — ida w slup,
     ale ODWROTNIE niz w DOM: zalecany wariant ma byc na gorze, „Anuluj" na dole. */
  .modal__actions--wrap{flex-direction:column-reverse}
  .modal__actions--wrap .btn{width:100%}
  /* Jedyny sposob przerwania poza wyjsciem z katalogu — na dotyku musi byc
     celem, w ktory da sie trafic kciukiem, a nie krazkiem 22 px. */
  .prep__stop{width:40px;height:40px;font-size:1.3rem}
}

/* Toast z przyciskiem — furtka dla pobrań wyciszonych przez przeglądarkę (ASH-00100) */
.toast--action{display:flex;align-items:center;gap:.6rem}
.toast__btn{border:1px solid rgba(255,255,255,.5);background:rgba(255,255,255,.14);color:inherit;
  border-radius:999px;font:inherit;font-size:.8rem;font-weight:600;padding:.2rem .7rem;cursor:pointer;white-space:nowrap}
.toast__btn:hover{background:rgba(255,255,255,.28)}

/* Więcej miejsca dla zdjęć: ciaśniejsza karta galerii i trzy kafle w rzędzie na telefonie (ASH-00102) */
.gallery__body{gap:.7rem}
.card--gallery{padding:.6rem}
@media (max-width:700px){
  .app{padding:.6rem .5rem 2rem}
  .card--gallery{padding:.4rem}
  .gallery{grid-template-columns:repeat(3,1fr);gap:.25rem}
  .tile--plain .tile__media{border-radius:6px}
}
@media (min-width:701px) and (max-width:1000px){
  .gallery{grid-template-columns:repeat(4,1fr)}
}

/* Panel kolejki pobierania (ASH-00101) */
.dlq{position:fixed;left:50%;transform:translateX(-50%);bottom:1rem;z-index:120;width:min(94vw,420px);
  background:var(--card);border:1px solid var(--line2);border-radius:var(--radius);box-shadow:var(--shadow-lg);
  padding:.7rem .8rem;display:flex;flex-direction:column;gap:.45rem}
.dlq__head{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.dlq__title{font-weight:700;font-size:.92rem}
.dlq__x{border:0;background:none;font-size:1.4rem;line-height:1;color:var(--muted);cursor:pointer;padding:0 .2rem}
.dlq__prog{height:6px;border-radius:999px;background:var(--brand-hint);overflow:hidden}
.dlq__bar{height:100%;width:0;background:var(--brand-grad);transition:width .25s}
.dlq__info{font-size:.78rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis}
.dlq__acts{display:flex;gap:.4rem;flex-wrap:wrap}
.dlq__acts .btn{flex:1;min-width:120px}

/* Anulowanie wysyłki (ASH-00128) */
.up-cancel { margin-top: .45rem; color: #b91c1c; border-color: #fca5a5; }
.up-cancel:hover { background: #fef2f2; }

/* Wstrzymaj / Wznów obok Anuluj (ASH-00161). Postój ma być widoczny na pierwszy
   rzut oka: pasek gaśnie do szarości, żeby nie udawał, że coś jeszcze leci. */
.up-acts { display: flex; gap: .5rem; align-items: center; margin-top: .45rem; }
.up-acts .up-cancel { margin-top: 0; }
.up-pause { flex: 0 0 auto; }
.up-box.is-paused .up-bar__fill { background: var(--muted); }
.up-box.is-paused .up-counter__rate { color: var(--muted); }
.upbar.is-paused .upbar__fill { background: var(--muted); }

/* Nowości WWW (ASH-00145) */
.news-list { margin: .2rem 0 .8rem 1.1rem; padding: 0; }
.news-list li { margin: .25rem 0; }

/* Nagłówek usera (ASH-00149/00150) */
.dash-head--col{flex-direction:column;align-items:stretch;gap:.55rem}
.dash-head__top{display:flex;justify-content:space-between;align-items:baseline;gap:.8rem;flex-wrap:wrap}
/* ASH-00376: prawa strona linii tytulu stoi pusta (napis „Zalogowano" zdjety —
   nazwa jest w naglowku strony). Regula zostaje pod przyszla tresc w tym miejscu. */
.dash-head__who{margin:0;white-space:nowrap}
.dash-head__acts{justify-content:flex-end}
.btn--icon{padding:.45rem .6rem;line-height:0;display:inline-flex;align-items:center}
.btn--icon svg{display:block}
/* Przycisk z ikoną PO LEWEJ i podpisem (ASH-00172) */
.btn--iconlabel{display:inline-flex;align-items:center;gap:.35rem}
.btn--iconlabel svg{display:block;flex:0 0 auto}

/* Kosz użytkownika (ASH-00166) */
.tile__badge--corner{left:auto;right:6px;top:6px;transform:none;font-size:.62rem;padding:.14rem .4rem}
.tile--trash .tile__meta{padding:.25rem .1rem 0;font-size:.72rem}
.trash-opt{display:flex;gap:.6rem;align-items:flex-start;border:1px solid var(--line2);background:#fff;
  border-radius:var(--radius-sm);padding:.6rem .7rem;margin:.4rem 0;cursor:pointer}
.trash-opt:hover{border-color:var(--brand)}
.trash-opt--off{opacity:.55;cursor:not-allowed}
.trash-opt input{margin-top:.2rem}
.trash-opt__title{font-weight:600}
.trash-opt__hint{color:var(--muted);font-size:.8rem;margin-top:.15rem}

/* ---------- filmy w galerii i podglądzie (ASH-00225 / ASH-00212) ---------- */
/* Znacznik „to film" na kaflu. Kółko z trójkątem zamiast napisu MP4 — czytelne
   także na jasnej klatce, bo ma własny cień i półprzezroczyste wypełnienie. */
.tile__play{position:absolute;left:50%;top:50%;width:44px;height:44px;margin:-22px 0 0 -22px;
  pointer-events:none;opacity:.92;filter:drop-shadow(0 1px 3px rgba(0,0,0,.55))}
.tile__play svg{width:100%;height:100%;display:block}
.tile__play circle{fill:rgba(0,0,0,.42);stroke:#fff;stroke-width:2.5}
.tile__play path{fill:#fff}
.tile--deleted .tile__play{opacity:.3}
@media (max-width:600px){.tile__play{width:34px;height:34px;margin:-17px 0 0 -17px}}

/* Odtwarzacz w lightboxie zajmuje tyle samo miejsca co zdjęcie. Bez zoomu
   i bez transformacji — kontrolki muszą trafiać tam, gdzie widać, że są. */
/* Film MUSI dostać rozmiar sceny wprost. Przy `max-width/max-height` przeglądarka
   bierze wymiar własny elementu — a przy `preload="none"` jest nim rozmiar PLAKATU
   (480 px), więc film wisiał jako okienko na środku ekranu i dopiero wczytanie
   pierwszej klatki rozciągało go do właściwych proporcji (ASH-00227). */
.lb__video{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;
  display:block;background:#000;outline:none;z-index:1}
/* Rozmyte tło jest przezroczyste, ale NADAL łapie kliknięcia — nad filmem
   zabierałoby je kontrolkom odtwarzacza (recenzja ASH-00212). */
.lb__ph{pointer-events:none}
.lb__vidmsg{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);z-index:3;
  max-width:min(90%,26rem);text-align:center;color:#fff;background:rgba(0,0,0,.72);
  border-radius:10px;padding:.7rem .9rem;font-size:.9rem;line-height:1.35}

/* Film w pasku miniatur — mały trójkąt w rogu, żeby dało się go odróżnić. */
.lb__thumb.is-vid::before{content:'';position:absolute;right:3px;bottom:3px;z-index:2;
  border-style:solid;border-width:4px 0 4px 7px;border-color:transparent transparent transparent #fff;
  filter:drop-shadow(0 0 2px rgba(0,0,0,.9))}

/* Operacje (ASH-00291): sekcje narzedzi admina */
.ops-sec{margin:0 0 1.4rem}
.ops-sec__title{margin:.2rem 0 .1rem;font-size:1.05rem}
.ops-sec__desc{margin:.1rem 0 .5rem}
.ops-prog{height:6px;border-radius:3px;background:rgba(127,127,127,.25);overflow:hidden;margin:.35rem 0 .3rem}
.ops-prog__fill{height:100%;width:0;background:var(--brand);transition:width .3s}
/* Naglowek pola w LEWEJ kolumnie zarezerwowanej na cala wysokosc wiersza —
   czipy zawijaja sie wylacznie we wlasnej kolumnie, nigdy pod naglowkiem. */
.ops-stats__row{display:flex;gap:.5rem;margin:.3rem 0}
.ops-stats__lab{flex:0 0 11rem}
.ops-stats__vals{display:flex;gap:.3rem;flex-wrap:wrap;flex:1;min-width:0;align-items:flex-start;align-content:flex-start}
@media (max-width:560px){
  .ops-stats__row{display:block}
  .ops-stats__lab{display:block;margin:0 0 .2rem}
}
.ops-chip{background:rgba(127,127,127,.14);border-radius:.6rem;padding:.05rem .5rem;font-size:.85em;white-space:nowrap}

/* ---------- KONTO ADMINA: 2FA (ASH-00301) ---------- */
/* QR musi byc na BIALYM tle niezaleznie od motywu — czytniki telefonow
   wymagaja jasnego tla i ciemnych modulow, a odwrocenie kolorow potrafi
   uniemozliwic odczyt. Szerokosc ograniczona, zeby na PC nie zajmowal
   pol ekranu. */
.qrbox{display:inline-block;background:#fff;padding:.6rem;border:1px solid var(--line2);
  border-radius:var(--radius-sm);margin:.4rem 0}
.qrbox svg{display:block;width:180px;height:180px}
/* Sekret do przepisania: staly odstep i lamanie, bo to 32 znaki w grupach. */
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:1rem;
  letter-spacing:.06em;word-break:break-all;background:var(--brand-hint);
  border:1px solid var(--brand-soft);border-radius:var(--radius-sm);padding:.5rem .7rem;margin:.2rem 0 .8rem}

/* ---------- ASH-00307: pigułka „udostępnione" (trzy stany) ---------- */
.flt--tri{display:inline-flex;align-items:center;gap:.3rem}
.flt--tri svg{flex-shrink:0}
/* ASH-00342: znacznik „to juz gdzies lezy" siedzi na kaflu zawsze, a o tym,
   czy zdjecie ma zgasnac czy zniknac, decyduje KLASA KONTENERA. Dzieki temu
   przelaczenie trybu to jedna zmiana klasy zamiast zbudowania siatki od nowa. */
.gallery--sh-dim .tile--shared{opacity:.38;transition:opacity .15s}
.gallery--sh-dim .tile--shared:hover{opacity:.7}
.gallery--sh-hide .tile--shared{display:none}

/* ---------- ASH-00309: propozycje zdjęć ze swojej galerii ---------- */
.card--suggest{margin-top:1rem}
.suggest__head h3{margin:0 0 .15rem;font-size:1.02rem}
.suggest__head p{margin:0 0 .7rem}
/* ASH-00351: naglowek sekcji trzyma akcje po prawej („Udostepnij wszystko",
   „Cofnij"), a na waskim ekranie schodza pod tytul i dziela linie po polowie. */
.suggest__top{display:flex;align-items:flex-start;justify-content:space-between;gap:.6rem;flex-wrap:wrap}
.suggest__ttl{min-width:0;flex:1 1 12rem}
.suggest__acts{flex:0 0 auto;gap:.4rem;margin-bottom:.7rem}
@media (max-width:560px){
  .suggest__acts{width:100%}
  .suggest__acts .btn{flex:1 1 0}
}
/* Przeskok o dzien: dwa przyciski w jednej linii pod zdjeciami. */
.sugg-days{display:flex;gap:.5rem}
.sugg-days .sugg-more{margin:0}
/* Kafel propozycji reaguje na klikniecie calej powierzchni (ASH-00351).
   ASH-00415: kursor jest NATYWNY (`cell`) zamiast rysowanej grafiki i ma byc
   STALY na calym kaflu. Selektor obejmuje potomkow, bo `.tile__img` niesie
   wlasne `cursor:zoom-in`, a `.tile__share` — `pointer`; bez tego kursor migal
   miedzy lupa a strzalka przy przejezdzaniu po kaflu. */
.tile--tap,.tile--tap *{cursor:cell}
.tile--tap:hover .tile__media{outline:3px solid var(--brand-soft);outline-offset:-3px}
.suggest__body{display:flex;flex-direction:column;gap:.6rem}
.sugg-more{display:block;width:100%;border:1px dashed var(--brand-soft);background:var(--brand-hint);
  color:var(--brand-dk);border-radius:var(--radius-sm);padding:.7rem .8rem;font:inherit;font-weight:600;
  cursor:pointer;transition:background .15s,border-color .15s}
.sugg-more:hover{background:#fff;border-color:var(--brand)}
.sugg-more:active{transform:scale(.995)}
/* Ikona udostępnienia jest WIĘKSZA niż znacznik zaznaczenia (wymóg ASH-00309) —
   w tej sekcji zaznaczania nie ma, liczy się jeden gest na zdjęciu. */
.tile__share{position:absolute;right:8px;bottom:8px;width:48px;height:48px;border-radius:999px;
  display:flex;align-items:center;justify-content:center;color:#fff;background:rgba(124,58,237,.85);
  border:2px solid rgba(255,255,255,.85);box-shadow:0 2px 10px rgba(0,0,0,.3);cursor:pointer;
  padding:0;transition:background .15s,transform .06s}
.tile__share:hover{background:var(--brand)}
.tile__share:active{transform:scale(.93)}
.tile--sugg.is-sharing{opacity:.55;pointer-events:none}
.tile--sugg.is-gone{opacity:0;transform:scale(.9);transition:opacity .25s,transform .25s}

/* ---------- ASH-00319: kafel czekający na miniaturę ----------
   Kafel bez gotowej miniatury ma wyglądać jak miejsce, w którym zaraz coś
   będzie — nie jak zepsuty obrazek. Stan gaśnie po wczytaniu, a przy błędzie
   zastępuje go kafelek z rozszerzeniem (patrz tileFallback w app.js). */
.tile__media.is-wait{background:var(--brand-hint)}
.tile__media.is-wait::before{content:'';position:absolute;inset:0;z-index:1;
  background:linear-gradient(90deg,rgba(255,255,255,0) 0%,rgba(255,255,255,.55) 45%,rgba(255,255,255,0) 90%);
  transform:translateX(-100%);animation:ash-shimmer 1.25s linear infinite}
@keyframes ash-shimmer{to{transform:translateX(100%)}}
@media (prefers-reduced-motion:reduce){ .tile__media.is-wait::before{animation:none;opacity:.35} }

/* ---------- ASH-00324: zakładki w belce po przewinięciu (desktop) ----------
   Ten sam kształt co pasek właściwy, ale kolorystyka odwrócona: pasek jest
   przezroczysty na fiolecie belki, a zaznaczenie białe z fioletowym napisem. */
/* Zakladki w belce stoja POZA ukladem (position:absolute) i sa wysrodkowane
   dokladnie tak, jak pasek wlasciwy — ta sama os i ta sama szerokosc (liczona
   w JS). Dzieki temu w chwili przelaczenia pigulki nie przeskakuja w bok,
   a belka nie zmienia wysokosci, bo rezerwuje ja `min-height`. */
.topbar__tabs{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  display:flex;align-items:center;justify-content:center;pointer-events:auto}
.topbar__tabs[hidden]{display:none}
.tabs--mini{margin:0;background:rgba(255,255,255,.14);border-color:rgba(255,255,255,.28);
  box-shadow:none;padding:.18rem}
.tabs--mini .tab{color:rgba(255,255,255,.86);min-height:30px;font-size:.86rem;padding:0 .7rem}
.tabs--mini .tab:hover{color:#fff}
.tabs--mini .tab.is-active,.tabs--mini .tab.is-active:hover{color:var(--brand-dk)}
.tabs--mini .tab-indicator{background:#fff;top:.18rem;bottom:.18rem}
.tabs--mini .tab:focus-visible{box-shadow:0 0 0 3px rgba(255,255,255,.45)}
@media (max-width:900px){ .topbar__tabs{display:none} }
/* Na desktopie belka ma z gory zarezerwowana wysokosc pod pigulki, wiec
   ich pojawienie sie niczego nie przesuwa (zmienna idzie tez do `--topbar-h`,
   bo pod nia podwieszaja sie naglowki dni w galerii). */
@media (min-width:901px){
  :root{ --topbar-h:calc(env(safe-area-inset-top, 0px) + 3.5rem) }
  .topbar{min-height:var(--topbar-h)}
}

/* ---------- ASH-00325: drugie menu w Operacjach ---------- */
.tabs--sub{padding:.2rem;margin:0 0 .8rem}
.tabs--sub .tab{font-size:.86rem;min-height:32px;padding:0 .7rem}
.ops-prog--thin{height:4px;margin:.2rem 0 .45rem}
.vq-when{font-size:.78rem;font-weight:400;white-space:nowrap}

/* ---------- ASH-00377/00378: nowe zdjęcia w katalogu ----------
   Kafel pliku dołożonego przez kogoś innego od poprzedniej wizyty dostaje
   ikonkę w rogu — ten sam znak („creation"), co katalog z nowościami na liście
   (ASH-00332). Obwódka na kaflu ZDJĘTA w ASH-00378: znacznik w rogu wystarczy,
   a ramka kłóciła się z zaznaczeniem, które wygląda tak samo.
   Znacznik jest lekko przezroczysty (30%) — ma być widoczny, a nie zasłaniać
   zdjęcie. Stoi w LEWYM górnym rogu, czyli tam, gdzie w trybie zaznaczania
   siedzi kółko wyboru — dlatego wtedy znika. */
.tile__fresh{position:absolute;left:6px;top:6px;z-index:3;width:24px;height:24px;border-radius:999px;
  display:flex;align-items:center;justify-content:center;color:#fff;background:var(--brand);
  box-shadow:0 2px 8px rgba(0,0,0,.3);pointer-events:none;opacity:.7}
.gallery--select .tile__fresh{display:none}

/* ---------- ASH-00165: pasek nawigacji Androida zawsze widoczny ----------
   Do WSA 1.18.0 apka chodziła w trybie immersive — trzy ikony Androida
   chowały się i trzeba je było wywoływać gestem PRZY KAŻDYM użyciu. Teraz
   pasek zostaje na wierzchu, ale bez własnego tła: okno rysuje stronę pod
   nim, a apka podaje jego wysokość w zmiennej `--wga-nav` (piksele CSS)
   i dokłada klasę `wga-nav` na <html>. W czystej przeglądarce ani zmiennej,
   ani klasy nie ma — wszystko poniżej jest więc wyłącznie dla bramki.     */
/* Ikony paska są białe i trafiają nad dowolną treść — także nad jasną kartę,
   na której zniknęłyby zupełnie. Dolna krawędź dostaje więc własny gradient
   (czarny → przezroczysty). Celowo NAD wszystkim, z lightboxem i kadrowaniem
   włącznie, bo pasek systemowy też jest nad wszystkim; `pointer-events:none`,
   żeby nie odbierał kliknięć temu, co pod nim widać. */
html.wga-nav body::after{
  content:'';position:fixed;left:0;right:0;bottom:0;pointer-events:none;z-index:500;
  height:var(--wga-nav);
  background:linear-gradient(0deg,rgba(0,0,0,.80),rgba(0,0,0,.52) 50%,rgba(0,0,0,0));
}
/* Pływające panele i podpisy przenoszą się NAD ikony — kafle galerii i zdjęcie
   w lightboxie zostają pod paskiem (widać je przez przezroczystość), ale nic,
   w co się celuje palcem, nie ma prawa się pod nim schować. */
html.wga-nav .toast{bottom:calc(1.2rem + var(--wga-nav))}
html.wga-nav .dlq{bottom:calc(1rem + var(--wga-nav))}
html.wga-nav .modal-backdrop,
html.wga-nav .ovl,
html.wga-nav .crp{padding-bottom:calc(1rem + var(--wga-nav))}
html.wga-nav .lb__bottom{padding-bottom:calc(.6rem + var(--wga-nav))}
/* Stopka zostaje na samym dole i kladzie sie w pasie paska nawigacji: wyglada
   jak zawsze (biale tlo, szary napis), tylko omija ikony — szpara po srodku
   i wciecia po bokach. Wysokosc paska jest JUZ w `env(safe-area-inset-bottom)`
   (strona ma `viewport-fit=cover`), wiec dolny padding body trzeba tu zdjac —
   inaczej odstep liczy sie dwa razy i stopka wisi nad paskiem.
   Stopka zostaje POD gradientem dolnej krawedzi (zadnego `z-index`): gradient
   ma przyciemnic wszystko, co jest pod paskiem, ze stopka wlacznie — inaczej
   biale ikony Androida zlewalyby sie z jej bialym tlem. */
html.wga-nav body{padding-bottom:0}
html.wga-nav .foot{
  min-height:var(--wga-nav);display:flex;align-items:center;justify-content:center;
  padding:.15rem var(--wga-nav);
}

/* ---------- ASH-00426: Zarządzanie → Import ---------- */
.imp-path{margin:.1rem 0 .3rem;font-family:ui-monospace,Consolas,monospace;font-size:.85em;word-break:break-all}
.imp-body{margin-top:.8rem}
.imp-soon{padding:1rem 0}
.imp-filter{margin:.6rem 0}
.imp-tblwrap{overflow-x:auto;margin:.4rem 0}
.imp-tbl{width:100%;border-collapse:collapse;font-size:.9rem}
.imp-tbl th{text-align:left;font-weight:600;color:var(--muted);padding:.4rem .5rem;border-bottom:1px solid var(--line2);white-space:nowrap}
.imp-tbl td{padding:.45rem .5rem;border-bottom:1px solid var(--line);vertical-align:top}
.imp-name{font-weight:600;word-break:break-all}
.imp-sub{font-size:.8em}
.imp-own{display:flex;gap:.35rem;align-items:center;flex-wrap:wrap}
.imp-ownn{font-weight:600}
.imp-gps--ok{color:var(--pos);font-weight:600}
.imp-gps--zero{color:var(--warn);font-weight:600}
.imp-verd{font-weight:600}
.imp-update .imp-verd{color:var(--brand-dk)}
.imp-conflict .imp-verd{color:var(--warn)}
.imp-noMatch .imp-verd{color:var(--muted)}
.ops-chip.imp-upd{background:var(--brand-soft);color:var(--brand-dk)}
.ops-chip.imp-warn{background:var(--warn-soft);color:var(--warn)}
.imp-more{margin:.3rem 0 .6rem}
.imp-actions{display:flex;gap:1rem;align-items:center;justify-content:space-between;flex-wrap:wrap;margin:.8rem 0 .3rem}
.imp-chk{display:flex;gap:.4rem;align-items:center;font-size:.9rem;cursor:pointer}
.imp-err{color:var(--neg);font-size:.85em}
.imp-errs{margin:.3rem 0}
/* ASH-00436: zadanie importu w tle */
.imp-job{border-top:1px solid var(--line);margin-top:.6rem;padding-top:.6rem}
.imp-job__head{display:flex;gap:.6rem;align-items:flex-start;justify-content:space-between;flex-wrap:wrap}
.imp-job__txt{flex:1;min-width:14rem;margin:0}
/* ASH-00427/00428: tryb 2 — paczki i słowniki */
.imp-mono{font-family:ui-monospace,Consolas,monospace;font-weight:600}
.imp-sel{max-width:16rem;width:100%}
.imp-warnt{color:var(--warn);font-size:.8em}
.imp-undo{margin-top:.25rem}
.imp-new{display:flex;gap:.35rem;flex-wrap:wrap;margin-top:.35rem}
.imp-new input{flex:1;min-width:8rem}
.imp-new .imp-err{flex-basis:100%}
.imp-dicts{margin-top:1rem;border-top:1px solid var(--line);padding-top:.6rem}
.imp-dicts h4{margin:.2rem 0 .4rem;font-size:.95rem}
.imp-dict{display:inline-flex;align-items:center;gap:.2rem}
.imp-x{border:0;background:none;color:var(--muted);cursor:pointer;font-size:1rem;line-height:1;padding:0 .1rem}
.imp-x:hover{color:var(--neg)}
/* ASH-00429/00430/00433: tryb 3 */
.imp-src{font-size:.85em;word-break:break-word;margin:.2rem 0}
.imp-back{margin-bottom:.5rem}
.imp-cand{margin:.6rem 0;padding:.6rem .8rem;border:1px solid var(--line);border-radius:var(--radius-sm);background:var(--brand-hint)}
.imp-cand:empty{display:none}
.imp-cand h4{margin:0 0 .4rem;font-size:.95rem}
.imp-radio{display:block;margin:.25rem 0;cursor:pointer}
.imp-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(11rem,1fr));gap:.6rem;align-items:end;margin:.8rem 0}
.imp-form>p{grid-column:1/-1;margin:0}
.imp-fld{display:flex;flex-direction:column;gap:.2rem}
.imp-fld__l{font-size:.8rem;color:var(--muted)}
.imp-srv p{margin:.4rem 0}


/* ASH-00462: karta „Filtry" admina i chip usunietego w podgladzie */
.adv-flt{display:flex;flex-direction:column;gap:.55rem}
.adv-flt__row{display:flex;align-items:flex-start;gap:.6rem;flex-wrap:nowrap}
.adv-flt__cap{flex:0 0 3.6rem;font-size:.8rem;color:var(--muted);padding-top:.32rem}
.adv-flt__row>.flt-group{min-width:0}
.lb__delchip{position:absolute;top:.8rem;left:50%;transform:translateX(-50%);z-index:4;pointer-events:none;
  background:rgba(200,40,40,.9);color:#fff;font-size:.75rem;font-weight:600;letter-spacing:.06em;text-transform:uppercase;
  padding:.25rem .7rem;border-radius:999px;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.35)}

/* ASH-00463: checkboxy plików skrzynki */
.imp-tbl .imp-cb{width:1.6rem;text-align:center;padding-left:.2rem;padding-right:.2rem}
.imp-tbl .imp-cb input{width:1rem;height:1rem;cursor:pointer}
.imp-tbl tr.imp-skipped td:not(.imp-cb){opacity:.45}
.imp-fdet{margin:.6rem 0}
.imp-fdet>summary{cursor:pointer;font-weight:600;padding:.3rem 0}

/* ASH-00465: szukanie po nazwie i dacie w karcie Filtry */
.adv-flt__dyn{display:flex;flex-direction:column;gap:.55rem}
.adv-flt__fields{display:flex;flex-wrap:wrap;gap:.5rem;flex:1 1 auto;min-width:0;align-items:flex-start}
.adv-flt__q{flex:1 1 14rem;min-width:0}
.adv-flt__dwrap{display:flex;flex-direction:column;gap:.15rem;flex:1 1 14rem;min-width:0}
.adv-flt__date{width:100%}
.adv-flt__hint{font-size:.75rem;color:var(--muted);min-height:1em}
.adv-flt__hint.is-bad{color:var(--neg)}
.adv-flt__search .adv-flt__cap{padding-top:.72rem}
.adv-flt__fields .input{width:100%;height:42px;font-size:1rem}
.adv-flt__q{align-self:flex-start}

/* ASH-00467: Zarządzanie -> Dziennik */
.applog__info{margin:.4rem 0}
.applog__list{display:flex;flex-direction:column;gap:.25rem}
.applog__row{border:1px solid var(--line);border-radius:8px;background:var(--card,#fff)}
.applog__row>summary{display:flex;gap:.5rem;align-items:baseline;padding:.4rem .6rem;cursor:pointer;flex-wrap:wrap;font-size:.85rem}
.applog__at{color:var(--muted);font-variant-numeric:tabular-nums;white-space:nowrap}
.applog__src{font-size:.7rem}
.applog--client .applog__src{background:#fdecc8}
.applog--server .applog__src,.applog--php .applog__src{background:#fbd5d5}
.applog__act{font-size:.75rem;color:var(--muted)}
.applog__msg{flex:1 1 18rem;min-width:0;word-break:break-word}
.applog__pre{margin:0;padding:.5rem .7rem;border-top:1px solid var(--line);font-size:.75rem;white-space:pre-wrap;word-break:break-word;max-height:22rem;overflow:auto}

/* ASH-00475: ustawienia konta — sekcja „Przeglądanie” */
.prefs__seg{gap:.4rem;flex-wrap:wrap}
.prefs--modal{margin-top:1.2rem;padding-top:1rem;border-top:1px solid var(--line)}

/* ASH-00477/00478: pokaz slajdow w podgladzie */
.lb__ap.is-on{background:rgba(124,92,255,.55);border-color:rgba(255,255,255,.5)}
.lb__apmenu{position:absolute;z-index:8;width:140px;padding:.35rem;border-radius:12px;
  background:rgba(20,20,28,.92);border:1px solid rgba(255,255,255,.18);box-shadow:0 8px 24px rgba(0,0,0,.45);
  display:flex;flex-direction:column;gap:.2rem;color:#fff;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}
.lb__apmenu-t{font-size:.75rem;opacity:.7;padding:.2rem .45rem}
.lb__apmenu-b{appearance:none;border:0;background:transparent;color:#fff;text-align:left;
  padding:.5rem .6rem;border-radius:8px;font:inherit;cursor:pointer}
.lb__apmenu-b:hover{background:rgba(255,255,255,.12)}
.lb__apmenu-b.is-cur{background:rgba(124,92,255,.55);font-weight:600}

/* ASH-00485: import katalogu — zdjecia z galerii, ktorych nie ma na dysku */
.imp-miss{margin:1rem 0}
.imp-miss__tools{gap:.5rem;align-items:center;flex-wrap:wrap;margin:.4rem 0 .6rem}
.imp-miss__who{font-weight:600;margin:.6rem 0 .3rem}
.imp-miss__grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(110px,1fr));gap:.45rem}
.imp-miss__t{position:relative;border-radius:10px;overflow:hidden;background:var(--line);outline:2px solid transparent;transition:outline-color .15s,opacity .15s}
.imp-miss__t img{display:block;width:100%;aspect-ratio:1/1;object-fit:cover;cursor:zoom-in}
.imp-miss__t.is-del{outline-color:#e5484d}
.imp-miss__t.is-del img{opacity:.55}
.imp-miss__chk{position:absolute;left:4px;bottom:4px;background:rgba(0,0,0,.6);color:#fff;border-radius:6px;padding:.1rem .35rem;font-size:.75rem;display:flex;align-items:center;gap:.2rem;cursor:pointer}
.imp-miss__in{position:absolute;right:4px;top:4px;background:rgba(0,0,0,.6);color:#fff;border-radius:6px;padding:0 .3rem;font-size:.68rem}
/* ASH-00489: pole filtru w karcie „Katalogi" admina — karta nie jest
   `.dir-stack`, wiec odstep do listy daje margines jak pod `.section-head`. */
.dir-srch--adm{margin:0 0 .7rem}
/* ASH-00492: wybor danych katalogu przy dolaczaniu (istniejace / z importu). */
.imp-take{margin:.6rem 0 .2rem;padding:.5rem .7rem;border:1px solid var(--line);border-radius:8px}
.imp-take__l{font-weight:600;margin-bottom:.3rem}
/* ASH-00493: Scal katalogi. */
.merge-out{margin-top:.6rem}
.merge-facts{margin:.3rem 0 .6rem;padding-left:1.2rem}
.merge-facts li{margin:.15rem 0}

/* ASH-00502: pigulka „Podglad" w belce, gdy admin oglada UI usera (tylko odczyt).
   Stoi obok nazwy usera w #topMeta — niczego nie przesuwa, uklad jak u usera. */
.pvpill{display:inline-flex;align-items:center;gap:.15rem;margin-left:.6rem;vertical-align:middle;
  background:var(--warn-soft);color:var(--warn);border-radius:999px;padding:.12rem .2rem .12rem .5rem;
  font-size:.78rem;font-weight:700;line-height:1;white-space:nowrap}
.pvpill__t{display:inline-flex;align-items:center;gap:.3rem}
.pvpill__t svg{display:block}
.pvpill__x{display:inline-flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;border:0;border-radius:999px;
  background:transparent;color:inherit;cursor:pointer;padding:0;margin-left:.15rem}
.pvpill__x:hover{background:rgba(180,83,9,.18)}
.pvpill__x svg{display:block}
