/* KRÓJ WŁASNY — `tools/font/generate_font.py`, rysowany kodem jak wszystko
   inne (ART-BIBLE §14). Systemowy `ui-sans-serif` znaczy co innego na każdym
   urządzeniu: ta sama karta przedmiotu łamała się inaczej na telefonie i na
   monitorze. Awaryjny stos zostaje — zanim plik dojedzie, tekst musi być
   czytelny, a nie niewidzialny (`font-display:swap`). */
@font-face{font-family:Lantern;src:url('fonts/lantern-regular.ttf') format('truetype');
  font-weight:100 600;font-style:normal;font-display:swap}
@font-face{font-family:Lantern;src:url('fonts/lantern-bold.ttf') format('truetype');
  font-weight:601 900;font-style:normal;font-display:swap}

/* CRATERBORN — warstwa interfejsu.
   Źródło prawdy: VISUAL-DESIGN-SYSTEM.md. Styl świata 3D: ART-BIBLE.md.

   Kierunek: ZJAZD. Ekran jest pionowym przekrojem krateru — ciepły,
   rozświetlony latarnią brzeg u góry, zimna głębia na dole. Pierścienie
   to warstwy lejka, a nie karty; ich szerokości biorą się wprost
   z promieni w `CFG.world.rings`. */

/* ─────────────────────────────────────────────── tokeny */
:root{
  --font:Lantern,ui-sans-serif,system-ui,"Segoe UI",Roboto,sans-serif;
  /* Ciepło u góry, chłód w dole — cała latarnia mieści się w tym gradiencie. */
  --rim:#3A2E24; --rim-lit:#4A3A2C; --void:#1B2029;
  --surface:#2B333D; --surface-hi:#39434F; --line:#4C5865;
  --flame:#FFC94A; --flame-dim:#C9922F;
  --teal:#2FB8A6; --teal-dk:#1E7F76; --teal-lt:#8FE7D6;
  --coral:#FF7A5C; --rose:#F2769B; --leaf:#7BC85F;
  --txt:#F0EADD; --txt-2:#AEB8C2; --txt-3:#7E8A96;

  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:24px; --s6:32px; --s7:48px;
  --r-sm:8px; --r:14px; --r-lg:22px; --r-pill:999px;
  --lift:0 10px 30px rgba(27,32,41,.48);
  --fast:120ms cubic-bezier(.2,.7,.3,1);
  --slow:220ms cubic-bezier(.2,.7,.3,1);
  --z-hud:14; --z-toast:15; --z-screen:20; --z-over:30;
}

/* ══ KURSOR ══════════════════════════════════════════════════════════════
   Systemowa strzałka to jedyny element na ekranie, którego nie narysowaliśmy
   — i widać to natychmiast: cienka, biało-czarna, z antyaliasingiem innym niż
   cała reszta. Kursor jest rysowany tą samą zasadą, co bryły w kraterze:
   płaskie wypełnienie, ciemny kontur, dwie ściany.

   SVG w `url()` jako data-URI. Nie jest to „pobrany asset" (ART-BIBLE §14) —
   to kilkanaście liczb wpisanych w arkusz, tak samo jak `UI_ICON` w kodzie.

   Dwa kształty, bo kursor niesie informację o tym, co się stanie:
     KLIN     domyślny — ostry grot w barwie latarni, ciemny obrys,
     CELOWNIK nad płótnem gry — cztery kreski wokół punktu, bo tam kursor
              jest CELOWNIKIEM, a nie wskaźnikiem; grot zasłaniałby cel.

   `hotspot` (dwie liczby na końcu `url()`) musi wypadać na czubku klina
   i w środku celownika — inaczej kliknięcie ląduje obok tego, co widać. */
:root{
  /* GRUBSZY OBRYS. Przy szybkim ruchu myszy kursor gubi się na tle —
     kilkanaście pikseli przesunięcia na klatkę znaczy, że oko łapie go
     rozmytego, a cienka kreska rozmywa się do niczego. Trzy piksele
     ciemnego obrysu przeżywają rozmycie. */
  --kursor:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32"><path d="M1.5 0.5 L1.5 25 L7.6 19.4 L11.6 28.5 L17.6 26 L13.7 17.2 L22 16.8 Z" fill="%231B2029" stroke="%231B2029" stroke-width="3" stroke-linejoin="round"/><path d="M4.5 5 L4.5 19 L8.8 15 L12.2 23 L14.6 22 L11.2 14 L16.6 13.7 Z" fill="%23FFC94A"/><path d="M4.5 5 L4.5 19 L8.8 15 L11.2 14 Z" fill="%23C9922F"/></svg>') 2 1;
  --kursor-cel:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="38" height="38" viewBox="0 0 38 38"><g stroke="%231B2029" stroke-width="9" stroke-linecap="round"><path d="M19 3 L19 11"/><path d="M19 27 L19 35"/><path d="M3 19 L11 19"/><path d="M27 19 L35 19"/></g><g stroke="%238FE7D6" stroke-width="3" stroke-linecap="round"><path d="M19 4 L19 11"/><path d="M19 27 L19 34"/><path d="M4 19 L11 19"/><path d="M27 19 L34 19"/></g><circle cx="19" cy="19" r="4" fill="%231B2029"/><circle cx="19" cy="19" r="1.8" fill="%23FFC94A"/></svg>') 19 19;
}
/* ══ LISTA KURSORÓW MUSI KOŃCZYĆ SIĘ SŁOWEM KLUCZOWYM ════════════════════
   `cursor: url(...) 2 1` jest według specyfikacji NIEPRAWIDŁOWE — po obrazku
   i punkcie zaczepienia musi stać zapasowy kursor systemowy. Bez niego
   przeglądarka odrzuca CAŁĄ deklarację po cichu, bez błędu w konsoli,
   i pokazuje zwykłą strzałkę.
   Dlatego własny kursor nie działał NIGDZIE poza płótnem gry, gdzie rysuje go
   kod — zgłoszone jako „w menu głównym też zamień kursor". Był zamieniony;
   po prostu nie wchodził w życie. */
html,body{cursor:var(--kursor),auto}
/* Nad plotnem gry kursor jest CELOWNIKIEM - tam wskazuje sie kierunek ciosu,
   a nie klika w element. W wyprawie rysuje go PLOTNO (`drawHud`), bo tam
   celownik odpowiada na to, co pod nim stoi, i na gotowosc ataku - a tego
   kursor systemowy nie umie. Poza wyprawa (`body:not(.in-run)`) zostaje
   wersja z arkusza: to samo, ale bez reakcji. */
#cv,#bg,#gl{cursor:var(--kursor-cel),crosshair}
body.in-run #cv,body.in-run #bg,body.in-run #gl{cursor:none}
/* Element, w ktory da sie kliknac, dostaje ten sam klin - nie systemowa
   lapke, bo ta znow bylaby jedyna rzecza narysowana nie przez nas. */
button,select,.cls,.tab,.chip,summary,[role="switch"],[role="tab"]{
  cursor:var(--kursor),pointer}
button:disabled,.cls:disabled,.chip:disabled{cursor:var(--kursor),default}
input,textarea{cursor:text}

*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}

/* ══ KONTUR NAPISÓW W MENU ═══════════════════════════════════════════════
   Ta sama zasada, co na płótnie: tekst leży na gradiencie od ciepłego brzegu
   krateru po zimną głębię, więc jeden kolor nie jest czytelny na całej
   wysokości ekranu. `paint-order:stroke fill` rysuje obrys POD literą, a nie
   na niej — bez tego kontur zjada cienkie kreski i krój robi się cięższy,
   niż jest.

   Dotyczy wyłącznie napisów NA TLE EKRANU (nagłówki, wielkie liczby,
   wordmark). Tekst w kartach i panelach ma własne, jednolite tło i obrys
   byłby tam wyłącznie brudem. */
.obrys{paint-order:stroke fill;-webkit-text-stroke:3px rgba(20,26,33,.85)}
.logo,.tag,.res,.sect>h2,.ledger-h,.hero-id b,.hero-id span,
.statline,.rar-name,#lbInfo .now,#lbInfo .ring,.strata .t{
  paint-order:stroke fill}
.logo{-webkit-text-stroke:5px rgba(20,26,33,.55)}
.res{-webkit-text-stroke:5px rgba(20,26,33,.7)}
/* ══ OBRYS NIE POWIĘKSZA PUDEŁKA ═════════════════════════════════════════
   `-webkit-text-stroke` maluje POŁOWĘ swojej grubości na zewnątrz glifu
   i NIGDY nie wchodzi do układu — pudełko wiersza zostaje takie, jakby
   obrysu nie było. Ten krój przy `line-height:normal` zostawia (zmierzone)
   3 px nad zwykłym wersalikiem, ale ZERO nad wersalikiem z diakrytykiem:
   „ŻÓŁĆ" sięga 11 px przy ascencie 11 px. Obrys 3 px potrzebuje 1,5 px
   ponad glifem, więc kropki nad Ż i Ó były ścinane płasko w KAŻDYM polskim
   nagłówku — zgłoszone jako „napisy ucięte u góry".
   Zapas robi się WYŁĄCZNIE wysokością wiersza; padding by nie pomógł, bo
   przycięcie następuje na krawędzi pudełka wiersza, nie pudełka elementu. */
.tag,.sect>h2,.ledger-h{-webkit-text-stroke:3px rgba(20,26,33,.5);line-height:1.5}
.obrys,.logo,.res,.hero-id b,.hero-id span,#lbInfo .now,#lbInfo .ring{line-height:1.4}
.hero-id b{-webkit-text-stroke:3.5px rgba(20,26,33,.7)}
.hero-id span,#lbInfo .now,#lbInfo .ring{-webkit-text-stroke:3px rgba(20,26,33,.6)}
html,body{height:100%;overflow:hidden;background:var(--void);color:var(--txt);
  font-family:var(--font);
  user-select:none;-webkit-user-select:none;touch-action:none;overscroll-behavior:none}
/* ══ FORMANTY NIE DZIEDZICZĄ KROJU ═══════════════════════════════════════
   `button`, `select` i `textarea` biorą krój od SYSTEMU, nie od rodzica —
   ustawienie go na `body` ich nie dotyczy. Efekt: cały interfejs stał
   w kroju gry, a każdy przycisk i każda zakładka renderowały się w Arialu.
   Widać to było najlepiej na największym przycisku i stamtąd przyszło
   zgłoszenie („nie ma czcionki gry"), ale dotyczyło wszystkich naraz.

   Reguła stoi tu, przy `body`, a nie przy `button` niżej: to jest ta sama
   decyzja co krój strony, tylko powtórzona tam, gdzie dziedziczenie nie
   działa. `input` miał już własne `font-family:inherit` — teraz nie musi. */
button,select,textarea,input,kbd{font-family:var(--font)}
canvas{display:block;position:absolute;inset:0;width:100%;height:100%}
/* Scena z postacią żyje W UKŁADZIE, a nie na całym ekranie — inaczej globalna
   reguła wyżej przykleiłaby ją do rogów i przykryła całe miasto. */
#hero3d{position:static;width:100%;height:100%}
:focus-visible{outline:3px solid var(--flame);outline-offset:2px;border-radius:var(--r-sm)}
/* ══ OGNISKO PADA WIDAĆ ZAWSZE ═══════════════════════════════════════════
   `:focus-visible` to reguła dla KLAWIATURY — przeglądarka sama decyduje,
   czy pokazać obwódkę, i przy ognisku ustawionym z kodu (a tak robi to pad)
   zwykle nie pokazuje. Gracz z padem widziałby wtedy, że coś się dzieje,
   ale nie gdzie stoi — czyli menu byłoby nadal nie do przejścia.

   Klasa na `<body>` włącza obwódkę bezwarunkowo i tylko wtedy, gdy pad jest
   podłączony: myszy nie ma po co obrysowywać przycisków, które właśnie
   kliknęła.

   Obwódka jest TURKUSOWA, nie bursztynowa: bursztyn na bursztynowym
   przycisku zjazdu byłby niewidzialny dokładnie tam, gdzie ognisko stoi
   najczęściej. Turkus czyta się i na ciemnym panelu, i na jasnej płycie. */
body.pad :focus{outline:3px solid var(--teal-lt);outline-offset:3px;
  border-radius:var(--r-sm)}

/* Sonda bezpiecznych marginesów: HUD na canvasie nie widzi env(). */
#safe{position:fixed;top:0;left:0;width:0;height:0;visibility:hidden;pointer-events:none;
  padding:env(safe-area-inset-top) env(safe-area-inset-right)
          env(safe-area-inset-bottom) env(safe-area-inset-left)}

/* ══ WSPÓLNY JĘZYK PANELI ════════════════════════════════════════════════
   Menu składało się z pudełek, które różniły się między sobą przypadkiem:
   jedne miały obrys 2 px, inne 1, jedne cień, inne nie, jedne promień 14,
   inne 8. Wszystkie dostają teraz ten sam zestaw:

     · ciemniejsze wnętrze niż tło ekranu (panel jest ZAGŁĘBIENIEM, nie
       naklejką — ta sama zasada, co przy studzience na ikonę przedmiotu),
     · obrys 2 px w kolorze linii,
     · jasny grzbiet na górnej krawędzi (jedno `inset` w cieniu) — po nim
       widać, że pudełko ma grubość,
     · cień pod spodem, ten sam dla wszystkich.

   Dzięki temu przełączanie zakładek przestaje wyglądać jak przejście między
   dwoma projektami. */
.panel,.gcell .gslot,.statchip,.purse-main,.purse-item,
.supply,.mate,.ledger,.tally .stat,.stat,.cls,.chip,.sortbox select{
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07), 0 6px 16px rgba(12,16,21,.35)}
/* ══ SKRZYNIA BEZ CIENIA ═════════════════════════════════════════════════
   Karty przedmiotów i ich siatka wypadły z reguły wyżej, i to nie jest
   wyjątek od zasady, tylko jej konsekwencja. Cień mówi „ta rzecz leży NAD
   tłem" — sensownie przy pojedynczym panelu, bezsensownie przy dwunastu
   kafelkach naraz: dwanaście cieni to dwanaście ciemnych obwódek, które
   zlewają się w kratę i zjadają odstępy między kartami.
   Sama siatka nie ma nawet tła, więc jej cień rysował ramkę wokół niczego —
   najlepiej było to widać przy pustej skrzyni, gdzie jedno zdanie stało
   w wielkim, ocieniowanym pudle. */
.sect .inv,.icard{box-shadow:none}
/* Aktywna zakładka i wybrana klasa świecą krawędzią zamiast zmieniać tło —
   przesunięcie tła przy przełączaniu czytało się jak przeładowanie ekranu. */
/* (podświetlenie aktywnej zakładki opisane niżej, przy samym pasku) */
.cls.on,.chip.on{box-shadow:inset 0 1px 0 rgba(255,255,255,.10),
  0 0 0 1px rgba(47,184,166,.45), 0 6px 16px rgba(12,16,21,.4)}

/* ══ NAROŻNIK LATARNI ════════════════════════════════════════════════════
   Jeden znak, który odróżnia panel tej gry od prostokąta z dowolnego innego
   interfejsu: dwie krótkie bursztynowe kreski w lewym górnym rogu, jak
   ślad po świetle padającym z góry pod kątem.

   Robi to jeden pseudoelement na panel, więc nie kosztuje ani jednego węzła
   w drzewie i znika razem z klasą. Wybrane są POJEMNIKI TREŚCI (panel, sekcja,
   rozliczenie), a nie każde pudełko — gdyby narożnik miał wszystko, przestałby
   cokolwiek znaczyć. */
.panel,.sect,.ledger,.verdict{position:relative}
.panel::before,.sect::before,.ledger::before{
  content:"";position:absolute;left:-1px;top:-1px;width:18px;height:18px;
  border-top:2px solid var(--flame);border-left:2px solid var(--flame);
  border-top-left-radius:var(--r);opacity:.55;pointer-events:none}
.sect::before{opacity:.4}
/* ══ NAGŁÓWEK OMIJA NAROŻNIK ══════════════════════════════════════════════
   Narożnik latarni siedzi w lewym górnym rogu i miał osiemnaście pikseli
   szerokości, a nagłówek zaczynał się na zerze — więc pierwsza litera każdego
   tytułu wchodziła na bursztynową kreskę i obie rzeczy stawały się nieczytelne
   naraz. Odsuwamy tekst, a nie narożnik: to on jest znakiem rozpoznawczym
   panelu i musi zostać na krawędzi. */
.panel>h2,.sect>h2,.ledger>.ledger-h,.party-box>h2{padding-left:16px}

/* ─────────────────────────────────────────────── ekrany */
.screen{position:absolute;inset:0;z-index:var(--z-screen);display:flex;flex-direction:column;
  align-items:center;overflow-y:auto;overscroll-behavior:contain;
  /* Przekrój krateru: ciepły brzeg, chłodna głębia. */
  background:linear-gradient(180deg,var(--rim) 0,#2A2B2E 18%,var(--surface) 42%,var(--void) 100%);
  padding:max(var(--s5),env(safe-area-inset-top)) max(var(--s4),env(safe-area-inset-right))
          max(var(--s7),env(safe-area-inset-bottom)) max(var(--s4),env(safe-area-inset-left))}
.screen.hidden,.hidden{display:none}
#scEnd{justify-content:safe center}
/* ZAKŁADKI SĄ GÓRNĄ KRAWĘDZIĄ EKRANU. Miasto nie ma już paska tytułowego,
   więc pierwszą rzeczą pod krawędzią jest wybór zakładki — i to on ma
   trzymać się góry, a nie pływać w środku kolumny. */
/* PASEK ZAKŁADEK IDZIE OD KRAWĘDZI DO KRAWĘDZI. Ekran ma boczne wypełnienie,
   więc pasek kończył się kilkanaście pikseli przed brzegiem i wisiał w środku
   jak wyspa. Ujemne marginesy wyprowadzają go poza to wypełnienie, a wewnętrzny
   padding trzyma etykiety z dala od krawędzi. */
#scLobby{padding-top:0}
#scLobby .tabs{position:sticky;top:0;z-index:2;max-width:none;
  /* `#scLobby` centruje dzieci (`align-items:center`), więc element o
     `width:auto` dostaje szerokość SWOJEJ TREŚCI, a nie kolumny — i ujemne
     marginesy przesuwały go, zamiast rozciągać. `align-self:stretch` znosi
     to centrowanie dla tego jednego elementu. */
  align-self:stretch;width:auto;
  /* I NIE DAJE SIĘ ŚCISNĄĆ. Jako element flexa w kolumnie, która przepełnia
     ekran (`.col` ma 909 px na 812 px widoku), pasek dostawał `flex-shrink:1`
     i kurczył się z 52 px do DZIEWIĘCIU — przyciski zostawały 44-piksełowe,
     ale wystawały poza swój własny pasek i znikały pod treścią. */
  flex:0 0 auto;
  margin:0 calc(-1 * max(var(--s4),env(safe-area-inset-right)))
         var(--s4) calc(-1 * max(var(--s4),env(safe-area-inset-left)));
  padding:max(var(--s2),env(safe-area-inset-top)) var(--s4) 0;
  /* Miejsce na przełączniki dźwięku i pełnego ekranu. Rezerwacja, nie
     nachodzenie: kółka siedzą W pasku, w jego prawym końcu, a nie na nim. */
  padding-right:calc(var(--s4) + 92px);
  background:linear-gradient(180deg,var(--void) 62%,rgba(27,32,41,0))}
/* Ikona w wierszu podsumowania jest mniejsza niż w skrzyni — wiersz ma
   pozostać wierszem, nie kartą. */
#endItems .ico{width:34px;height:34px;flex:0 0 auto}
#endItems .ico img{width:28px;height:28px}
#endItems .pips{display:none}
/* Cena po prawej stronie wiersza — kolumna liczb ma się wyrównywać. */
#endItems .val{margin-left:auto;font-variant-numeric:tabular-nums}
/* Łamie się nazwa przedmiotu, nie znacznik rzadkości — „RZADKI · / I18"
   czytało się jak dwa osobne pola. */
.rar-name{white-space:nowrap}
.screen::before{/* światło latarni od góry — jedno źródło na cały ekran */
  content:"";position:fixed;left:50%;top:-22vh;width:130vw;height:60vh;transform:translateX(-50%);
  background:radial-gradient(closest-side,rgba(255,201,74,.16),rgba(255,201,74,0));
  pointer-events:none}
.col{width:100%;max-width:560px;display:flex;flex-direction:column;gap:var(--s4)}

/* ─────────────────────────────────────────────── ekran startowy */
#scLogin{justify-content:center;gap:var(--s5)}
/* ══ ZNAK NAD KRATEREM ═══════════════════════════════════════════════════
   Sam znak wisiał na gradiencie i ginął — ciemna bryła na ciemnym tle. Pod
   spodem jest teraz poświata latarni: to samo źródło światła, które oświetla
   brzeg krateru u góry ekranu, tylko zebrane w punkt. Nie jest to obrazek —
   to jeden gradient promienisty, jak wszystko inne tutaj. */
.mark{position:relative;width:min(150px,32vw);height:auto;
  filter:drop-shadow(0 12px 28px rgba(27,32,41,.62))
         drop-shadow(0 0 26px rgba(255,201,74,.20))}
#scLogin>.mark{isolation:isolate}
#scLogin::after{content:"";position:absolute;left:50%;top:calc(50% - 190px);
  width:min(340px,72vw);aspect-ratio:1;transform:translate(-50%,-50%);
  background:radial-gradient(circle,rgba(255,201,74,.16) 0,rgba(255,201,74,0) 68%);
  pointer-events:none;z-index:-1}
.logo{font-size:clamp(2.3rem,9vw,4rem);font-weight:900;letter-spacing:-.035em;line-height:.88;
  color:var(--txt);text-align:center;text-shadow:0 0 42px rgba(255,201,74,.28)}
.tag{font-size:12px;letter-spacing:.2em;text-transform:uppercase;color:var(--flame-dim);
  text-align:center}

/* ─────────────────────────────────────────────── brzeg krateru (nagłówek) */
/* PASEK BEZ TREŚCI MA BYĆ WĄSKI. Odkąd poziom i XP przeniosły się na kartę
   postaci, w nagłówku został sam tytuł — a przy dawnej wysokości i 700 px
   pustki na monitorze czytał się jak miejsce, z którego coś wypadło.
   Wiersz, nie blok: tytuł i klasa obok siebie, oddzielone kreską. */
.rim{width:100%;max-width:560px;display:flex;align-items:baseline;gap:var(--s3);
  padding:var(--s2) 100px var(--s2) var(--s4);border-radius:var(--r);
  background:linear-gradient(180deg,var(--rim-lit),rgba(58,46,36,.55));
  border:2px solid #5A4634}
.rim .who{flex-direction:row;align-items:baseline;gap:var(--s3)}
.rim .who span::before{content:"";display:inline-block;width:1px;height:9px;
  margin-right:var(--s3);background:currentColor;opacity:.5;vertical-align:baseline}
.rim .who{display:flex;flex-direction:column;gap:2px;min-width:0}
.rim .who b{font-size:clamp(.95rem,3.4vw,1.25rem);font-weight:900;letter-spacing:-.02em;
  line-height:1;white-space:nowrap}
.rim .who span{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--flame-dim)}

/* Poziom jako płomień latarni; pasek XP jest jego knotem. */
/* Pasek poziomu żyje teraz NA KARCIE POSTACI (`.hero-xp`), nie w nagłówku. */
.hero-xp{display:flex;align-items:center;gap:var(--s3);flex:0 1 auto;min-width:0}
/* `line-height:1` ucinało cyfrę o 2 px na KAŻDEJ rozdzielczości — pudełko
   kroju to 1,20 em (patrz metryki w `tools/font/ttf.py`), więc jedynka
   z ogonkiem nie mieściła się w swoim wierszu. Przemiatanie po sześciu
   rozmiarach okna zgłaszało to sześć razy z rzędu. */
.hero-xp .lvl{font-size:22px;font-weight:900;color:var(--flame);font-variant-numeric:tabular-nums;
  line-height:1.2;text-shadow:0 0 18px rgba(255,201,74,.55)}
.hero-xp .wick{flex:1 1 auto;min-width:0}
.hero-xp .statline{white-space:nowrap}
.xpbar{height:7px;background:rgba(27,32,41,.55);border-radius:var(--r-pill);overflow:hidden}
.xpbar i{display:block;height:100%;background:linear-gradient(90deg,var(--flame-dim),var(--flame));
  transition:width var(--slow)}
.statline{font-size:10px;color:var(--txt-3);font-variant-numeric:tabular-nums;margin-top:3px}

/* Zapasy: trzy pigułki, nie trzy wiersze tabeli.
   Siatka, nie flex — przy `flex:1 1 0` z `min-width` pigułki wychodziły poza
   kontener na 375 px i nachodziły na siebie. */
/* Na wąskim ekranie jedna pigułka na wiersz. Dwie w rzędzie ścinały etykietę
   do „MIK…" — a etykieta jest tu jedyną informacją, czego dotyczy liczba. */
/* Jedna reguła zamiast progów: pigułka schodzi do jednej kolumny, gdy nie
   mieści liczby, etykiety i przycisku naraz. Ścięta etykieta („MIK…") jest
   gorsza niż dodatkowy wiersz. */
/* ── SAKIEWKA. Trzy pigułki jedna pod drugą zjadały trzy wiersze na dane,
   których się nie czyta, tylko sprawdza kątem oka. Jeden pasek: Marks
   prowadzi (największa liczba, ciepłe tło), zapasy stoją obok jako liczniki
   z przyciskiem. Zawija się dopiero wtedy, gdy naprawdę nie ma miejsca. */
.purse{display:flex;flex-wrap:wrap;gap:var(--s2);width:100%;max-width:720px}
/* LICZBA NAD ETYKIETĄ, nie obok. W jednym wierszu (znak, liczba, podpis,
   przycisk) na telefonie w poziomie zostawało 213 px na pigułkę i podpis
   ścinał się do „MIKST…" — czyli ginęła jedyna informacja mówiąca, czego
   dotyczy liczba. Siatka z dwoma wierszami potrzebuje połowy tej szerokości:
   znak stoi obok, przycisk po prawej, a liczba i podpis jeden pod drugim. */
.purse-main,.purse-item{display:grid;align-items:center;column-gap:var(--s2);min-width:0;
  grid-template-columns:auto minmax(0,1fr);
  grid-template-areas:"ico num" "ico lab";
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r-lg);
  padding:var(--s2) var(--s3);min-height:52px}
.purse-main{flex:1 1 170px;background:linear-gradient(180deg,#3A3527,#2F3239);
  border-color:#5A4E33}
.purse-item{flex:1 1 190px;grid-template-columns:auto minmax(0,1fr) auto;
  grid-template-areas:"ico num btn" "ico lab btn"}
.purse b{grid-area:num;font-weight:800;font-size:19px;line-height:1.2;
  font-variant-numeric:tabular-nums;color:var(--flame);min-width:0;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.purse-main b{font-size:25px}
.purse-lab{grid-area:lab;font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--txt-3);line-height:1.35;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.purse-ico{grid-area:ico;display:grid;place-items:center;width:26px;height:26px;
  color:var(--flame-dim)}
.purse-main .purse-ico{color:var(--flame);width:30px;height:30px}
.purse button{grid-area:btn;min-height:40px;padding:0 var(--s3);font-size:11px;
  border-radius:var(--r-sm);white-space:nowrap;width:auto;
  display:inline-flex;align-items:center;justify-content:center;gap:5px}
.purse button .uico{opacity:.85}
.kup-lab{white-space:nowrap}
/* Znak przy wartości przedmiotu na ekranie wyniku — ta sama moneta co
   w sakiewce, żeby liczba nie wymagała podpisu „Marks". */
#endItems .val{display:inline-flex;align-items:center;gap:5px;color:var(--flame-dim)}
.supplies{display:grid;grid-template-columns:1fr;gap:var(--s2);width:100%;max-width:560px}
.supply{min-width:0;display:grid;column-gap:var(--s3);align-items:center;
  grid-template-columns:minmax(0,1fr) auto;grid-template-areas:"num btn" "lab btn";
  padding:var(--s2) var(--s2) var(--s2) var(--s4);border-radius:var(--r-lg);text-align:start;
  background:var(--surface);border:2px solid var(--line)}
/* Marks to zasób, nie towar — bez przycisku i bez ramki towaru. */
.supply.hoard{background:linear-gradient(180deg,#3A3527,#2F3239);border-color:#5A4E33}
.supply b{grid-area:num;min-width:0;line-height:1.2;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* `overflow:hidden` obcina TAKŻE W PIONIE. Przy `line-height` mniejszym niż
   wysokość glifu ucinał litery przez środek — dlatego wszędzie, gdzie stoi
   wielokropek, musi stać też wysokość linii z zapasem. */
.supply span{grid-area:lab;min-width:0;line-height:1.35;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.supply button{grid-area:btn}
.descent{display:flex;flex-direction:column;gap:var(--s4);width:100%;max-width:560px}
/* Drużyna schodzi niżej, odkąd stan wyprawy stoi OBOK przycisku, a nie nad
   nim: rząd jest niższy od kolumny, więc nad sceną z postacią zrobiło się
   puste pole. */
#scLobby .pane[data-pane="run"] .party{margin-top:var(--s5)}
/* ══ `font:` NIE PRZYJMUJE `inherit` JAKO RODZINY ═════════════════════════
   Skrót `font` wymaga na końcu nazwy kroju. `inherit` jest tam nieprawidłowe,
   a nieprawidłowa wartość unieważnia CAŁĄ deklarację — po cichu, bez błędu
   w konsoli. Pięć reguł w tym arkuszu miało ten błąd i pięć elementów
   interfejsu renderowało się w odziedziczonych 16 px zamiast zaprojektowanej
   wielkości:

     .supply b        21 px → 16   (liczby Marks, mikstur, polis)
     .btn-descend     do 1,35 rem → 16   (zjazd do krateru — zgłoszone
                                          jako „zwiększ czcionkę")
     .gup             9,5 px → 16   (przycisk ulepszenia)
     button           14 px → 16
     #corner button   16 px → 16   (jedyna, która trafiła przypadkiem)

   Rozbite na osobne własności. Krój i tak dziedziczy się z `body`, więc
   skrót niczego tu nie oszczędzał — poza działaniem. */
.supply b{font-weight:800;font-size:21px;line-height:1.15;
  font-variant-numeric:tabular-nums;color:var(--flame)}
.supply span{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--txt-3)}
/* 44 px to minimalny cel dotykowy, a nie zaokrąglenie w górę: przyciski
   „Kup" miały 36 px wysokości i na telefonie trafiało się w nie co drugi raz.
   Pozostałe przyciski w grze mają 44 od początku — te wypadły z reguły przez
   własne `min-height`. */
.supply button{min-height:44px;padding:0 var(--s3);font-size:11px;
  border-radius:var(--r-sm);white-space:nowrap}

/* ─────────────────────────────────────────────── gardziel szybu */
/* NAJPIERW STAN, POTEM PRZYCISK — ale OBOK, nie nad. Kolejność czytania przed
   decyzją zostaje ta sama (ile czasu, dokąd wolno, potem rzecz do naciśnięcia),
   tylko idzie w poziomie: `row-reverse` stawia pierwszy w znacznikach przycisk
   po prawej, a stan po lewej. Przycisk zostaje PIERWSZY w kolejności
   tabulacji — dlatego odwrócenie robi układ, a nie przestawienie znaczników.

   Poniżej 560 px wraca kolumna: w rzędzie na telefonie przycisk zjazdu
   zszedłby do szerokości, w której nie mieści się jego własny napis. */
.maw{position:relative;width:100%;max-width:660px;display:flex;flex-direction:row-reverse;
  align-items:center;justify-content:center;gap:var(--s4);
  padding:var(--s5) var(--s4) var(--s4)}
@media (max-width:559px){
  .maw{flex-direction:column-reverse;gap:var(--s3)}
}
.maw::before{content:"";position:absolute;inset:-6% -4% 0;border-radius:50%;
  background:radial-gradient(closest-side,rgba(255,201,74,.20),rgba(255,201,74,0));
  animation:breathe 4.5s ease-in-out infinite;pointer-events:none}
@keyframes breathe{0%,100%{opacity:.55;transform:scale(.96)}50%{opacity:1;transform:scale(1.04)}}
/* Panel stanu MA MIEĆ SZEROKOŚĆ ZDANIA, nie resztki po przycisku. Bez
   `min-width` flex ściskał go do 26 px i tekst łamał się po jednej literze
   w wierszu — zmierzone, nie zgadnięte. */
.maw .state{display:flex;flex-direction:column;gap:3px;text-align:start;
  flex:1 1 auto;min-width:180px;max-width:280px;
  font-variant-numeric:tabular-nums}
@media (max-width:559px){ .maw .state{text-align:center} }
.maw .state .now{font-size:12.5px;font-weight:700;color:var(--txt-2)}
.maw .state .ring{font-size:11.5px;font-weight:700;color:var(--teal-lt)}
.maw .state .past{font-size:11px;color:var(--txt-3)}
/* Panel stanu ma własne tło: leży NA scenie z postacią, a tekst bez podkładki
   ginął na jasnym modelu dokładnie wtedy, gdy postać stanęła pod przyciskiem. */
#scLobby .pane[data-pane="run"] .descent .state{
  background:rgba(27,32,41,.82);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:var(--s2) var(--s3)}
.maw .warn{color:var(--rose)}

/* Jedna akcja na całą grę — dostaje własny wariant przycisku. */
.btn-descend{width:min(320px,100%);min-width:210px;padding:var(--s5) var(--s4);border:0;
  border-radius:var(--r-lg);
  background:linear-gradient(180deg,#FFD873,var(--flame));color:#3A2A08;
  /* Powiększone: zjazd do krateru jest JEDYNĄ akcją, która w tej grze coś
     znaczy, a renderował się w rozmiarze zwykłego przycisku. */
  font-weight:900;font-size:clamp(1.2rem,5.2vw,1.7rem);line-height:1.15;
  letter-spacing:.04em;cursor:var(--kursor),pointer;flex:0 1 auto;
  box-shadow:0 6px 0 var(--flame-dim),var(--lift),0 0 48px rgba(255,201,74,.30);
  transition:transform var(--fast),filter var(--fast),box-shadow var(--fast)}
.btn-descend:hover:not(:disabled){filter:brightness(1.06)}
.btn-descend:active:not(:disabled){transform:translateY(3px);
  box-shadow:0 3px 0 var(--flame-dim),var(--lift),0 0 48px rgba(255,201,74,.30)}
.btn-descend:disabled{background:var(--surface-hi);color:var(--txt-3);
  box-shadow:0 6px 0 #2B333D;cursor:var(--kursor),default}

/* ─────────────────────────────────────────────── lejek pierścieni */
.shaft{width:100%;max-width:560px;display:flex;flex-direction:column;align-items:center;gap:3px}
.strata{position:relative;display:flex;align-items:center;gap:var(--s3);
  padding:var(--s3) var(--s4);border-radius:var(--r-sm);
  border:2px solid rgba(27,32,41,.42);border-top-color:rgba(255,255,255,.14);
  color:#1D2228;transition:filter var(--fast)}
.strata.shut{color:var(--txt-2);border-color:rgba(27,32,41,.55);border-top-color:rgba(255,255,255,.06)}
.strata.shut .t{color:var(--txt-3)}
.strata .t{font-size:15px;font-weight:900;letter-spacing:.02em;flex:0 0 auto}
.strata .d{font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums;opacity:.75;
  flex:0 0 auto}
/* Wąski pas nie pomieści głębi i stanu naraz — a głębię i tak niesie sam
   kształt lejka. Tekst, który wychodzi poza pas, psuje sylwetkę. */
.strata.narrow .d{display:none}
.strata.narrow{padding-inline:var(--s3);gap:var(--s2)}
.strata .d:empty,.strata .s:empty{display:none}
.strata .s{margin-left:auto;font-size:10px;font-weight:800;letter-spacing:.1em;
  text-transform:uppercase;white-space:nowrap}
.shaft .cap{font-size:11px;color:var(--txt-3);text-align:center;max-width:44ch;
  margin-top:var(--s2);line-height:1.5}

/* ─────────────────────────────────────────────── obóz: sekcje */
.sect{width:100%;max-width:560px}
.sect>h2{font-size:11px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;
  color:var(--txt-3);margin-bottom:var(--s3);display:flex;align-items:baseline;gap:var(--s2)}
.sect>h2 span{color:var(--txt-3);font-weight:600;letter-spacing:.04em;text-transform:none}

/* Statystyki: duża liczba, mała etykieta. Bez pasków — nie mają maksimum. */
/* ── ZNAKI STATYSTYK. Rysowane w JS jako `<svg>` (`UI_ICON`), więc dziedziczą
   kolor tekstu. `.face` to druga, jaśniejsza ściana bryły — bez niej znak jest
   płaską plamą, a cała gra opiera się na tym, że bryła ma dwie ściany. */
/* `evenodd` robi OTWORY tam, gdzie ścieżka wraca w siebie: środek koła
   zębatego, źrenica oka. Bez tego wypełnienie zalewa je i znak traci to,
   co go rozpoznaje. */
.uico{width:100%;height:100%;display:block;fill:currentColor;fill-rule:evenodd}
.uico .face{fill:#fff;opacity:.22}
.uico.tiny{width:13px;height:13px;flex:0 0 13px;opacity:.75}
.uico.ghost-ico{width:26px;height:26px;opacity:.22}
.statchip .uico{width:22px;height:22px;flex:0 0 22px}
/* Kolor niesie ZNACZENIE, nie dekorację: zdrowie różowe, obrażenia bursztynowe,
   pancerz stalowy, prędkość zielona, krytyk złoty. Te same skojarzenia, co
   w liczbach nad głowami w kraterze. */
.statchip.s-hp{color:var(--rose)}
.statchip.s-dmg{color:var(--coral)}
.statchip.s-armor{color:var(--teal-lt)}
.statchip.s-spd{color:var(--leaf)}
.statchip.s-crit{color:var(--flame)}
/* 132 px, nie 112: przy 112 telefon 390 px mieścił trzy kolumny po 112, a po
   odjęciu znaku (22), odstępu (8) i wypełnienia (24) zostawało 58 px na
   etykietę — „OBRAŻENIA" ścinało się do „OBRAŻENI…". Przy 132 wychodzą dwie
   kolumny po 175 px i podpis mieści się w całości. */
.derived{display:grid;grid-template-columns:repeat(auto-fit,minmax(132px,1fr));gap:var(--s2);
  align-content:start}
/* ZNAK OBOK LICZBY, nie nad nią: kafelek jest wierszem (znak | liczba
   i etykieta w kolumnie). Przy `flex-direction:column` znak wchodził jako
   trzecie dziecko kolumny i liczba sklejała się z etykietą — „253ZDROWIE". */
.statchip{background:var(--surface);border:2px solid var(--line);border-radius:var(--r-sm);
  padding:var(--s2) var(--s3);display:flex;flex-direction:row;align-items:center;
  gap:var(--s2);text-align:start}
.statchip .sval{min-width:0;display:flex;flex-direction:column;gap:1px}
.statchip b{display:block;font-size:17px;font-weight:800;color:var(--flame);
  font-variant-numeric:tabular-nums;line-height:1.15;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.statchip span{display:block;font-size:9px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--txt-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}

/* Ekwipunek: broń jest slotem tożsamości, więc jest większa od reszty. */
/* ── PAPIEROWA LALKA. Kolumna gniazd po każdej stronie sylwetki. */
.doll{display:flex;flex-direction:column;gap:var(--s2);min-width:0}
.doll-r{justify-content:flex-start}
/* Reguła jest tu ZWIĄZANA Z `.doll`, i to nie jest kosmetyka: bazowy `.gslot`
   niżej w arkuszu ustawia `display:flex;flex-direction:column`, więc przy tej
   samej wadze wygrywał ten późniejszy i studzienka lądowała NAD opisem
   zamiast obok. */
.doll .gslot{display:grid;grid-template-columns:auto minmax(0,1fr);gap:var(--s3);
  align-items:center;text-align:start}
/* STUDZIENKA. Ciemniejsza od karty, z cieniem kontaktowym u dołu — bez niej
   ikona wisi w powietrzu, a to jest dokładnie ta skarga, która brzmiała
   „brak głębi". Zagłębienie robi wewnętrzny cień u góry i światło u dołu. */
/* SIATKA JEDEN NA JEDEN, i to nie jest ozdoba. Przy `display:grid` bez jawnych
   torów wiersz domyślny rośnie DO ZAWARTOŚCI — zmierzone: studzienka 58 px
   wysokości, a wiersz siatki 81,4 px, bo tyle ma młot po dopasowaniu
   szerokości. Procenty na obrazku liczą się od POLA SIATKI, nie od pudełka,
   więc `max-height:84%` dawało 68 px i przedmiot wystawał poza obrys.
   `100%` przycina tor do pudełka i procenty znów znaczą to, co powinny. */
.well{position:relative;flex:0 0 auto;width:58px;height:58px;border-radius:var(--r-sm);
  display:grid;grid-template-columns:100%;grid-template-rows:100%;
  place-items:center;overflow:visible;
  background:radial-gradient(120% 90% at 50% 12%,#232A33,#141A21);
  box-shadow:inset 0 2px 6px rgba(0,0,0,.55),inset 0 -1px 0 rgba(255,255,255,.05)}
.well::after{content:"";position:absolute;left:16%;right:16%;bottom:6%;height:12%;
  border-radius:50%;background:radial-gradient(50% 50% at 50% 50%,rgba(0,0,0,.55),transparent 72%)}
/* MAX, NIE WIDTH. `width:84%;height:84%` wyglądało na to samo, a nie było:
   procent wysokości nie miał się do czego odnieść w kratce o wysokości
   z siatki, więc przeglądarka liczyła go od WŁASNEJ wysokości obrazka po
   dopasowaniu szerokości. Zmierzone: młot 49×68 i napierśnik 49×77
   w studzience 58×58 — czyli dwa przedmioty wystawały poza obrys.
   `max-*` z `auto` gwarantuje zmieszczenie się przy każdych proporcjach. */
.well img{position:relative;z-index:1;max-width:84%;max-height:84%;
  width:auto;height:auto;object-fit:contain;
  filter:drop-shadow(0 3px 4px rgba(0,0,0,.45))}
.well.hollow{border:1px dashed rgba(122,134,148,.28);box-shadow:none;background:rgba(20,26,33,.45)}
.well.hollow::after{display:none}
.upbadge{position:absolute;z-index:2;right:-4px;top:-4px;font-style:normal;
  font-size:10px;font-weight:800;line-height:1;padding:3px 5px;border-radius:var(--r-pill);
  background:var(--flame);color:#2B333D}
.gtxt{min-width:0;display:flex;flex-direction:column;gap:2px}
.gcell.empty-slot .gslot{opacity:.72}
.loadout{display:grid;gap:var(--s2);grid-template-columns:repeat(2,1fr)}

.gcell:first-child{grid-column:1 / -1}
/* W papierowej lalce kazde gniazdo jest osobnym wierszem kolumny - nie ma
   siatki dwukolumnowej, wiec nie ma czego rozciagac na dwa pola. */
.doll .gcell:first-child{grid-column:auto}
/* Bez bocznej „zakładki" koloru. Gruby pasek z jednej strony zaokrąglonej
   karty to najbardziej rozpoznawalny szablon i przy okazji był tu JEDYNYM
   nośnikiem rzadkości — slot nie nazywał jej słowem, w przeciwieństwie do
   skrzyni. Rzadkość niesie teraz ta sama etykieta `.rar-name` co wszędzie. */
/* Slot ekwipunku to WIERSZ: co to jest, co daje, co można z tym zrobić.
   Wcześniej nazwa, statystyki i przycisk ulepszenia stały jedno pod drugim
   w kafelku o stałej wysokości — pusty slot był wtedy wysoką pustą kartą,
   a pełny rozjeżdżał się na cztery linijki. */
/* Pasek ulepszenia POD gniazdem, nie obok: przy dwóch wąskich kolumnach
   przycisk obok zjadał połowę szerokości opisu i nazwa przedmiotu łamała się
   na trzy wiersze. */
.doll .gcell{grid-template-columns:minmax(0,1fr)}
.doll .gup{align-self:stretch;width:100%;min-width:0}
.gcell{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--s2);
  align-items:stretch}
.gslot{width:100%;background:var(--surface);border:2px solid var(--line);
  border-radius:var(--r-sm);
  padding:var(--s3);min-height:64px;display:flex;flex-direction:column;gap:2px;
  cursor:var(--kursor),pointer;text-align:left;font:inherit;color:inherit;transition:border-color var(--fast)}
.gcell:first-child .gslot{min-height:76px}
.doll .gslot{min-height:82px}
.gslot:hover{border-color:var(--teal)}
.gslot em{font-style:normal;font-size:9px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--txt-3)}
.gslot strong{font-size:12px;font-weight:700;color:var(--c,var(--txt-3));line-height:1.3}
.gslot.free strong{font-weight:600;color:var(--txt-3);opacity:.75}
.gslot small{font-size:10px;color:var(--txt-2);font-variant-numeric:tabular-nums;line-height:1.4}
/* Ulepszenie jest akcją poboczną. Jako pasek na całą szerokość slotu
   krzyczało głośniej niż „Zejdź do krateru" — czyli głośniej niż jedyna
   akcja, która w tej grze coś znaczy. */
.gup{align-self:stretch;width:auto;min-width:62px;padding:7px var(--s3);
  font-weight:800;font-size:9.5px;line-height:1.25;
  letter-spacing:.06em;display:flex;align-items:center;
  justify-content:center;text-align:center;
  background:transparent;border:2px solid var(--teal-dk);color:var(--teal-lt);
  border-radius:var(--r-pill);cursor:var(--kursor),pointer;font-variant-numeric:tabular-nums;
  transition:background var(--fast),border-color var(--fast)}
.gup:hover:not(:disabled){background:var(--teal-dk);border-color:var(--teal)}
.gup:disabled{opacity:.4;cursor:var(--kursor),default}

/* ─────────────────────────────────────────────── skrzynia */
/* ── SKRZYNIA. Nagłówek z porządkiem, pasek gniazd, siatka kart. */
.stash-sect{max-width:960px}
.stash-head{display:flex;align-items:baseline;justify-content:space-between;
  gap:var(--s3);flex-wrap:wrap}
.stash-head>h2{margin-bottom:0}
.sortbox{display:flex;align-items:center;gap:var(--s2);min-width:0}
.sortbox>span{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;color:var(--txt-3)}
.sortbox select{font-family:inherit;font-size:11.5px;font-weight:700;color:var(--txt);
  background:var(--surface-hi);border:2px solid var(--line);border-radius:var(--r-sm);
  padding:7px var(--s2);min-height:36px;cursor:var(--kursor),pointer}
.chips{display:flex;flex-wrap:wrap;gap:var(--s1);margin:var(--s2) 0 var(--s3)}
.chip{display:inline-flex;align-items:center;gap:6px;width:auto;min-height:34px;
  padding:0 var(--s3);font-size:11.5px;font-weight:700;border-radius:var(--r-pill);
  background:var(--surface);border:2px solid var(--line);color:var(--txt-2)}
.chip i{font-style:normal;font-size:10px;font-weight:800;color:var(--txt-3);
  font-variant-numeric:tabular-nums}
.chip:hover:not(:disabled){border-color:var(--teal);color:var(--txt)}
.chip.on{background:var(--teal-dk);border-color:var(--teal);color:var(--txt)}
.chip.on i{color:var(--teal-lt)}
.chip:disabled{opacity:.38;cursor:var(--kursor),default}
/* KARTY, NIE WIERSZE. Wiersz na całą szerokość marnował 60 % ekranu na
   pustkę między nazwą a przyciskami; siatka mieści trzy przedmioty tam, gdzie
   mieścił się jeden, a każdy z nich ma miejsce na porównanie. */
.icard{display:flex;flex-direction:column;gap:var(--s2);min-width:0;
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  border-top-color:color-mix(in srgb, var(--c) 62%, var(--line));
  padding:var(--s3);transition:transform var(--fast),border-color var(--fast)}
.icard:hover{transform:translateY(-2px);border-color:color-mix(in srgb, var(--c) 45%, var(--line))}
.ihead{display:flex;align-items:center;gap:var(--s3);min-width:0}
.iinfo{min-width:0;display:flex;flex-direction:column;gap:2px}
.iinfo b{font-size:13px;font-weight:800;line-height:1.25;overflow-wrap:anywhere}
.iinfo .rar-name{color:var(--c)}
.idelta{list-style:none;display:flex;flex-direction:column;gap:3px;
  border-top:1px solid rgba(122,134,148,.18);padding-top:var(--s2)}
.idelta li{display:flex;align-items:center;gap:6px;min-width:0;font-size:11.5px;line-height:1.4}
.idelta .k{color:var(--txt-3);min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.idelta .v{margin-left:auto;color:var(--txt-2);font-variant-numeric:tabular-nums;white-space:nowrap}
/* RÓŻNICA. Kolor plus strzałka — samo zielone i czerwone nie wystarcza,
   bo to jedyny nośnik informacji dla ośmiu procent graczy. */
.idelta .d{flex:0 0 auto;font-size:10.5px;font-weight:800;padding:1px 5px;
  border-radius:var(--r-pill);font-variant-numeric:tabular-nums;white-space:nowrap}
.idelta .d.up{color:#9BE07A;background:rgba(123,200,95,.15)}
.idelta .d.down{color:#FF9C86;background:rgba(255,122,92,.15)}
.iacts{display:flex;gap:var(--s2);margin-top:auto}
.iacts button{width:auto;flex:1 1 auto;min-height:40px;padding:0 var(--s2);font-size:11.5px}
.iacts .sell{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;gap:5px;
  color:var(--flame-dim);font-variant-numeric:tabular-nums}
.inv{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));
  gap:var(--s2);max-height:56vh;overflow-y:auto;align-content:start;
  overscroll-behavior:contain}
.inv>.empty{grid-column:1 / -1}
.irow{display:grid;grid-template-columns:auto 1fr auto;gap:var(--s3);align-items:center;
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  padding:var(--s2) var(--s3);transition:transform var(--fast),border-color var(--fast)}
.irow:hover{transform:translateY(-1px);border-color:var(--line)}
.irow .mini{display:flex;align-items:center;gap:var(--s3);min-width:0}
.irow .mini>div{min-width:0}
.irow .nm{font-size:13px;font-weight:700;line-height:1.25}
.irow .acts{display:flex;gap:var(--s2);align-items:center}
.irow button{width:auto;min-height:38px;padding:0 var(--s3);font-size:10.5px}

/* Ikona przedmiotu: obwódka niesie kolor rzadkości, nacięcia u góry — jej
   stopień. Kolor nigdy nie jest jedynym nośnikiem. */
/* KRATKA JEST STUDZIENKĄ, tak samo jak gniazdo w papierowej lalce.
   Jasny gradient od góry robił z niej WYPUKŁY guzik, a przedmiot leżał na nim
   jak naklejka — to jest druga połowa zgłoszenia „brak głębi". Ciemniej
   w środku, cień wewnętrzny od góry, cień kontaktowy pod bryłą. */
.ico{position:relative;width:52px;height:52px;flex:0 0 52px;border:2px solid var(--c,var(--line));
  border-radius:var(--r-sm);
  background:radial-gradient(120% 90% at 50% 12%,#232A33,#141A21);
  box-shadow:inset 0 2px 6px rgba(0,0,0,.5),inset 0 -1px 0 rgba(255,255,255,.05);
  display:flex;align-items:center;justify-content:center;overflow:hidden}
.ico::after{content:"";position:absolute;left:18%;right:18%;bottom:5%;height:11%;
  border-radius:50%;pointer-events:none;
  background:radial-gradient(50% 50% at 50% 50%,rgba(0,0,0,.5),transparent 72%)}
/* Bryła RZUCA CIEŃ na dno studzienki. Jedna deklaracja, a to ona najmocniej
   odkleja przedmiot od tła — mocniej niż jakikolwiek gradient pod nim. */
.ico img{max-width:100%;max-height:100%;width:auto;height:auto;object-fit:contain;
  position:relative;z-index:1;filter:drop-shadow(0 2px 3px rgba(0,0,0,.5))}
/* ── MGŁA JAKOŚCI W KRATCE. Ten sam język, co na sylwetce w wyprawie:
   kolorowa poświata znaczy „to jest coś warte". Oddycha wolno (3,2 s),
   bo skrzynia to ekran do czytania, a nie do reagowania. */
.ico.rare-glow::before{content:"";position:absolute;inset:-2px;border-radius:inherit;
  background:radial-gradient(circle at 50% 58%,
    color-mix(in srgb, var(--c) 42%, transparent) 0%,
    color-mix(in srgb, var(--c) 14%, transparent) 46%,
    transparent 72%);
  animation:icoMgla 3.2s ease-in-out infinite;pointer-events:none;z-index:0}
@keyframes icoMgla{0%,100%{opacity:.62}50%{opacity:1}}
/* Poświata sięga też POZA kratkę — inaczej mityczny przedmiot wygląda tak
   samo jak zwykły, tylko z jaśniejszą ramką. */
.ico.rare-glow{box-shadow:0 0 14px -2px color-mix(in srgb, var(--c) 55%, transparent)}
/* ── ISKRY ULEPSZEŃ. Jedna na poziom, unoszą się i gasną. */
.ico .sparks{position:absolute;inset:0;overflow:hidden;border-radius:inherit;
  pointer-events:none;z-index:2}
.ico .sparks i{position:absolute;bottom:14%;width:3px;height:3px;border-radius:50%;
  background:var(--c);box-shadow:0 0 5px var(--c);
  animation:icoIskra 2.1s linear infinite;opacity:0}
@keyframes icoIskra{
  0%{transform:translateY(0) scale(.7);opacity:0}
  18%{opacity:1}
  100%{transform:translateY(-30px) scale(.35);opacity:0}}
.ico .pips{position:absolute;top:2px;left:0;right:0;display:flex;justify-content:center;gap:2px}
.ico .pips i{width:4px;height:3px;background:var(--c);border-radius:1px}
.rar-name{font-size:9.5px;font-weight:800;letter-spacing:.1em;text-transform:uppercase;
  color:var(--c)}

/* ─────────────────────────────────────────────── wybór klasy */
.classes{display:grid;grid-template-columns:1fr;gap:var(--s3)}
.cls{display:flex;align-items:center;gap:var(--s4);
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  padding:var(--s4);text-align:left;font:inherit;color:inherit;width:auto;cursor:var(--kursor),pointer;
  transition:border-color var(--fast),transform var(--fast)}
/* Broń klasy zamiast drugiego akapitu: sylwetka rozróżnia karty szybciej
   niż tekst, a model już istnieje. */
.clsart{flex:0 0 auto;width:60px;height:60px;display:grid;place-items:center;
  border-radius:var(--r-sm);background:#222932;border:2px solid var(--line)}
.clsart img{width:52px;height:52px;object-fit:contain;image-rendering:auto}
.clstxt{min-width:0}
.cls:hover:not(:disabled){border-color:var(--teal);transform:translateY(-2px)}
.cls.on{border-color:var(--teal);background:#294845}
.cls:disabled{cursor:var(--kursor),default;opacity:1}
.cls b{display:block;font-size:15px;font-weight:800;color:var(--teal);margin-bottom:var(--s1)}
.cls span{font-size:11.5px;line-height:1.5;color:var(--txt-2)}
.gate{color:var(--flame)}

/* ─────────────────────────────────────────────── przyciski ogólne */
/* Grzbiet u góry i ciemniejszy dół: przycisk jest PŁYTĄ oświetloną z góry,
   tą samą latarnią, co reszta ekranu. Płaskie wypełnienie czytało się jak
   naklejka — a wszystko inne w tej grze ma dwie ściany.
   Połysk siedzi w SKRÓCIE `background`, a nie w osobnym `background-image`,
   i to nie jest szczegół zapisu: osobna reguła nadpisywała samą warstwę
   obrazu w każdym wariancie, który ma własny gradient (`.btn-descend`),
   zostawiając przycisk przezroczysty. W skrócie każde późniejsze
   `background` wymienia całość naraz — czyli tak, jak się tego spodziewa
   ktoś, kto pisze wariant. */
button{width:100%;min-height:44px;padding:var(--s3) var(--s4);border:0;
  background:linear-gradient(180deg,rgba(255,255,255,.16) 0,
    rgba(255,255,255,0) 46%,rgba(0,0,0,.14) 100%) var(--teal);
  border-radius:var(--r-sm);color:#0E2E2A;box-shadow:0 4px 0 var(--teal-dk);
  font-weight:800;font-size:14px;line-height:1.2;
  letter-spacing:.05em;cursor:var(--kursor),pointer;
  transition:transform var(--fast),filter var(--fast),box-shadow var(--fast)}
button:hover:not(:disabled){filter:brightness(1.08)}
button:active:not(:disabled){transform:translateY(2px);box-shadow:0 2px 0 var(--teal-dk)}
/* Warianty z własnym pełnym obrysem nie dostają płyty — miałyby dwa konflikty
   naraz: obrys i bryłę pod spodem. */
button.ghost,.gup,.cls,.gslot,#mute{box-shadow:none}
button.ghost:active:not(:disabled),.gup:active:not(:disabled),
.cls:active:not(:disabled),.gslot:active{box-shadow:none}
button.ghost{background:transparent;border:2px solid var(--line);color:var(--txt-2)}
button.ghost:hover:not(:disabled){border-color:var(--teal);color:var(--txt)}
button.sec{background:linear-gradient(180deg,rgba(255,255,255,.14) 0,
    rgba(255,255,255,0) 46%,rgba(0,0,0,.16) 100%) var(--surface-hi);
  box-shadow:0 4px 0 #242C35;color:var(--txt)}
button.sec:active:not(:disabled){box-shadow:0 2px 0 #242C35}
button:disabled{opacity:.4;cursor:var(--kursor),default}
.row{display:flex;gap:var(--s3)}

/* ─────────────────────────────────────────────── panele, ekran końcowy */
/* Pole na nick jest STUDZIENKĄ, jak każde miejsce, w które coś się wkłada —
   ta sama zasada, co przy ikonie przedmiotu w ekwipunku. Wpisany tekst siedzi
   w zagłębieniu i dlatego widać, że da się go zmienić. */
#nameIn{background:rgba(20,26,33,.55);border:2px solid var(--line);
  border-radius:var(--r-sm);color:var(--txt);width:100%;min-height:46px;
  padding:0 var(--s4);font:800 16px var(--font);letter-spacing:.02em;
  box-shadow:inset 0 3px 8px rgba(12,16,21,.6), 0 1px 0 rgba(255,255,255,.05);
  transition:border-color var(--fast),box-shadow var(--fast)}
#nameIn:focus{outline:0;border-color:var(--teal);
  box-shadow:inset 0 3px 8px rgba(12,16,21,.6), 0 0 0 3px rgba(47,184,166,.22)}

.panel{background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  padding:var(--s5);width:100%;max-width:430px;box-shadow:var(--lift)}
input{width:100%;min-height:48px;padding:var(--s3) var(--s4);background:var(--void);
  border:2px solid var(--line);border-radius:var(--r-sm);color:var(--txt);font-size:16px;
  font-family:inherit}
input:focus{outline:none;border-color:var(--flame)}
h2{font-size:11px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;
  margin-bottom:var(--s3);color:var(--txt-3)}
.note{font-size:12.5px;line-height:1.6;color:var(--txt-2)}
.kbd{font-size:11.5px;color:var(--txt-3);line-height:1.9}
.kbd b{color:var(--txt-2);font-family:ui-monospace,monospace}
.res{font-size:clamp(1.6rem,7vw,2.6rem);font-weight:900;letter-spacing:-.02em;text-align:center}
.res.ok{color:var(--teal);text-shadow:0 0 34px rgba(47,184,166,.4)}
.res.bad{color:var(--coral);text-shadow:0 0 34px rgba(255,122,92,.35)}
/* Trzy kafle mieszczą się dopiero od ~420 px — niżej etykiety łamią się
   na dwie linie i kafle przestają mieć wspólną linię bazową. */
.stats{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s2);margin:var(--s3) 0}
@media (min-width:420px){.stats{grid-template-columns:repeat(3,minmax(0,1fr))}}
/* Nieparzysty ostatni kafel zajmuje cały wiersz — dziura obok niego
   wygląda jak brakująca dana. */
.stat:last-child:nth-child(odd){grid-column:1 / -1}
@media (min-width:420px){.stat:last-child:nth-child(odd){grid-column:auto}}
.stat b{overflow:hidden;text-overflow:ellipsis}
.stat span{overflow-wrap:anywhere}
.stat{background:var(--surface-hi);border-radius:var(--r-sm);padding:var(--s3)}
.stat b{display:block;font-size:22px;font-weight:800;color:var(--flame);
  font-variant-numeric:tabular-nums}
.stat span{font-size:9px;letter-spacing:.12em;text-transform:uppercase;color:var(--txt-3)}
.items{max-height:30vh;overflow-y:auto;display:flex;flex-direction:column;gap:var(--s1);
  margin:var(--s3) 0}
.item{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  padding:var(--s2) var(--s3);background:var(--surface-hi);border-radius:var(--r-sm);font-size:12.5px}
.item .nm{display:flex;align-items:center;gap:var(--s2);min-width:0}
.item i{font-style:normal;color:var(--txt-3);font-variant-numeric:tabular-nums}
.dot{width:10px;height:10px;flex:0 0 auto;background:var(--c);transform:rotate(45deg);border-radius:2px}
.grp{font-size:9.5px;letter-spacing:.12em;text-transform:uppercase;margin:var(--s2) 0 var(--s1)}
.grp:first-child{margin-top:0}
.empty{color:var(--txt-3);font-size:12.5px;padding:var(--s5) var(--s1);text-align:center;
  line-height:1.6}
/* ══ NAKŁADKI DRUŻYNY ════════════════════════════════════════════════════
   Zaproszenie i okno drużyny przykrywają miasto, a nie wsuwają się w układ:
   obie rzeczy są PRZERWANIEM, a przerwanie, które przesuwa resztę ekranu,
   sprawia, że gracz gubi to, na co patrzył. */
.over{position:fixed;inset:0;z-index:var(--z-over);display:grid;place-items:center;
  padding:var(--s4);background:rgba(12,16,21,.72);
  animation:wjazdMgla 160ms ease-out both}
/* `.hidden{display:none}` stoi w tym arkuszu WYŻEJ i ma tę samą specyficzność
   co `.over`, więc przy remisie wygrywała reguła późniejsza — czyli `display:
   grid`. Obie nakładki były przez to widoczne od startu, jedna na drugiej.
   Klasa łączona (0,2,0) domyka to raz i nie zależy od kolejności. */
.over.hidden{display:none}
@keyframes wjazdMgla{from{opacity:0}to{opacity:1}}
.over>.panel{max-width:380px;animation:wjazdOkno 200ms cubic-bezier(.2,.9,.3,1) both}
@keyframes wjazdOkno{from{opacity:0;transform:translateY(10px) scale(.98)}to{opacity:1;transform:none}}
.party-box .ptabs{display:flex;gap:var(--s2);margin-top:var(--s3)}
.party-box .ptabs button{flex:1 1 0;font-size:11.5px;padding:0 var(--s2);min-height:40px}
.plist{margin-top:var(--s3);display:flex;flex-direction:column;gap:var(--s2);
  max-height:220px;overflow-y:auto;overscroll-behavior:contain}
/* Wiersz drużyny do dołączenia — ta sama płyta, co przycisk, bo to JEST
   przycisk: jedyna rzecz, którą się z nim robi, to kliknięcie. */
.pjoin{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  width:100%;min-height:46px;padding:0 var(--s3);text-align:left;
  background:linear-gradient(180deg,rgba(255,255,255,.10) 0,rgba(255,255,255,0) 46%,
    rgba(0,0,0,.16) 100%) var(--surface-hi);
  border:2px solid var(--line);border-radius:var(--r-sm);color:var(--txt);
  box-shadow:0 3px 0 #242C35}
.pjoin:active{transform:translateY(2px);box-shadow:0 1px 0 #242C35}
.pjoin b{font-size:13px;font-weight:800}
.pjoin span{font-size:11px;color:var(--txt-2);font-variant-numeric:tabular-nums}
/* ══ LANTERN HOLD ════════════════════════════════════════════════════════
   Cztery karty w siatce, która sama dobiera liczbę kolumn. Karta jest płytą
   z grubością, tak samo jak reszta paneli — rozbudowa miasta ma wyglądać na
   rzecz trwałą, bo taka właśnie jest. */
.hold-sect{width:100%;max-width:560px;margin-top:var(--s4)}
.hold-grid{display:grid;gap:var(--s2);
  grid-template-columns:repeat(auto-fill,minmax(160px,1fr))}
.hcard{display:flex;flex-direction:column;gap:4px;padding:var(--s3);
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.07), 0 4px 12px rgba(12,16,21,.3)}
.hcard>b{font-size:13px;font-weight:800}
/* Opis rezerwuje DWA wiersze zawsze. Bez tego „Więcej miejsca w skrzyni"
   (jeden wiersz) i „Dodatkowa mikstura na wyprawę" (dwa) rozjeżdżały kropki,
   stan i przycisk o wysokość wiersza — cztery karty, cztery różne poziomy. */
.hopis{font-size:10.5px;color:var(--txt-3);line-height:1.35;
  min-height:calc(2 * 1.35 * 10.5px)}
/* Poziom jako kropki: przy czterech stopniach widać od razu, ile zostało,
   bez czytania „2/4". */
.hkropki{display:flex;gap:4px;margin-top:2px}
.hkropki i{width:9px;height:9px;border-radius:2px;transform:rotate(45deg);
  background:rgba(20,26,33,.6);border:1px solid var(--line)}
.hkropki i.on{background:var(--flame);border-color:var(--flame)}
.hstan{font-size:11px;font-weight:700;color:var(--teal-lt);
  font-variant-numeric:tabular-nums}
/* `margin-top:auto` dociska przycisk do dna karty, a karty i tak są równe
   (siatka rozciąga je do najwyższej). Dzięki temu trzeci wiersz opisu
   w przyszłości też niczego nie rozjedzie. */
.hcard button{width:100%;min-height:34px;margin-top:auto;font-size:11.5px;
  font-variant-numeric:tabular-nums}
.hcard .hstan{margin-bottom:var(--s2)}
.hcard.pelny{opacity:.6}

/* ══ KONTRAKTY ═══════════════════════════════════════════════════════════
   Cztery kolumny: zadanie, pasek, licznik, nagroda. Pasek dostaje całą wolną
   szerokość, bo to on niesie odpowiedź na pytanie „ile jeszcze". */
/* Podpis klawiszy pada na karcie przedmiotu. Widoczny TYLKO z padem —
   przy myszy jest szumem, bo tam się po prostu klika. */
.ipad{display:none;gap:var(--s3);margin-left:auto;align-items:center}
body.pad .ipad{display:flex}
.ipad span{display:flex;align-items:center;gap:4px;font-size:9.5px;
  letter-spacing:.1em;text-transform:uppercase;color:var(--txt-3)}
.ipad b{display:grid;place-items:center;min-width:16px;height:16px;padding:0 3px;
  border-radius:3px;background:var(--surface-hi);border:1px solid var(--line);
  font-size:9px;font-weight:800;color:var(--txt-2)}
/* Kafelek jest celem nawigacji, więc musi mieć własne ognisko — a że leży
   w siatce, obwódka nie może wychodzić poza niego. */
.icard[tabindex]{outline-offset:-2px}

/* ══ KONTRAKTY W PRAWYM GÓRNYM ROGU ══════════════════════════════════════
   Zadania na dziś czyta się RAZ, na wejściu do miasta, i potem już tylko
   sprawdza kątem oka. Pod gardzielą zabierały pierwsze miejsce w kolejności
   czytania w dół — a tam ma stać postać i przycisk zjazdu.

   KOLUMNĄ, NIE POZYCJONOWANIEM. Pierwsza wersja kładła je `position:absolute`
   w rogu i weszły prosto na trzecią postać w drużynie; rezerwowanie miejsca
   marginesem przesuwało układ, a panel razem z nim — bo kotwiczył się do tego
   samego pudełka, które właśnie zwęziłem. Siatka nie ma tego problemu
   z definicji: kolumna zajmuje miejsce, którego nikt inny nie dostanie. */
.kontrakty{width:100%;max-width:560px;margin:0}

.krow{display:grid;grid-template-columns:minmax(0,1.4fr) minmax(60px,1fr) auto auto;
  gap:var(--s3);align-items:center;min-height:46px;padding:0 var(--s3);
  margin-bottom:var(--s2);
  background:rgba(20,26,33,.34);border:1px solid rgba(20,26,33,.5);
  border-radius:var(--r-sm)}
.krow b{font-size:12px;font-weight:700;line-height:1.3;overflow:hidden;
  text-overflow:ellipsis}
.kpas{height:7px;background:rgba(12,16,21,.6);border-radius:var(--r-pill);
  overflow:hidden;box-shadow:inset 0 1px 2px rgba(0,0,0,.5)}
.kpas i{display:block;height:100%;background:linear-gradient(90deg,var(--flame-dim),var(--flame));
  border-radius:var(--r-pill);transition:width var(--slow)}
.krow>span{font-size:10.5px;color:var(--txt-2);font-variant-numeric:tabular-nums;
  white-space:nowrap}
.krow button{width:auto;min-height:32px;padding:0 var(--s3);font-size:11px;
  font-variant-numeric:tabular-nums}
/* Gotowy do odebrania świeci — to jedyna rzecz w tym wierszu, która ma
   przyciągnąć wzrok. Odebrany gaśnie razem z całym wierszem. */
.krow.gotowy{border-color:rgba(255,201,74,.45)}
.krow.gotowy .kpas i{background:var(--flame)}
.krow.gotowy button{background:linear-gradient(180deg,#FFD873,var(--flame));
  color:#3A2A08;box-shadow:0 3px 0 var(--flame-dim);animation:pulsKontrakt 1.8s ease-in-out infinite}
@keyframes pulsKontrakt{0%,100%{filter:brightness(1)}50%{filter:brightness(1.12)}}
.krow.odebrany{opacity:.45}
@media (prefers-reduced-motion:reduce){
  .krow.gotowy button{animation:none}
}

/* Wiersz znajomego: nazwa, stan, akcje. Trzy kolumny, bo to trzy różne
   rzeczy — a nie jeden napis, w którym trzeba szukać. */
.frow{display:grid;grid-template-columns:1fr auto auto;gap:var(--s3);
  align-items:center;min-height:42px;padding:0 var(--s3);
  background:rgba(20,26,33,.34);border:1px solid rgba(20,26,33,.5);
  border-radius:var(--r-sm)}
.frow b{font-size:12.5px;font-weight:800;overflow:hidden;text-overflow:ellipsis;
  white-space:nowrap}
.frow>span{font-size:10.5px;font-weight:700;font-variant-numeric:tabular-nums;
  white-space:nowrap}
.fakt{display:flex;gap:var(--s1)}
.fakt button{width:auto;min-height:30px;padding:0 var(--s2);font-size:10.5px}
.fakt .ghost{padding:0 10px;font-size:14px;line-height:1}
.invite-box .res{color:var(--flame);margin-top:var(--s2)}
.invite-box .note{text-align:center}
/* Zajęte miejsce w drużynie przestaje być zaproszeniem: pełny obrys zamiast
   kreskowanego, nazwa zamiast plusa. */
/* ══ MIEJSCE W DRUŻYNIE WYGLĄDA JAK KARTA BOHATERA ═══════════════════════
   Ta sama kolejność czytania, co u siebie: KTO (nazwa i klasa), JAK DALEKO
   (poziom), JAK WYGLĄDA (model). Kolega opisany inaczej niż własna postać
   zmuszałby do dwóch sposobów czytania tej samej informacji.

   Żadnej ramki i żadnego tła: bohater obok też ich nie ma, a „kwadraciki"
   robiły z drużyny listę pozycji zamiast trzech postaci stojących obok siebie. */
.mate{position:relative;display:flex;flex-direction:column;align-items:stretch;
  gap:var(--s2);aspect-ratio:auto;min-height:0;border-radius:0;padding:0;
  background:none;overflow:visible}
.mate-pusty{display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:var(--s2);width:100%;aspect-ratio:3/4;min-height:120px}
.mate-id,.mate-xp,.mate3d,.mate-stan{display:none}
/* PODPISY SIĘ NIE KURCZĄ. W kolumnie flex wszystkie elementy oddają wysokość
   po równo, kiedy jest jej za mało — a wtedy nazwa i pasek poziomu ściskają
   się do zera i zostaje samo płótno. Tekst dostaje `flex:0 0 auto`, model
   bierze całą resztę. */
.mate>.mate-id,.mate>.mate-xp,.mate>.mate-stan{flex:0 0 auto}
.mate3d{width:100%;flex:1 1 auto;min-height:150px}
.mate.zajete{background:none;border:0;box-shadow:none}
.mate.zajete .mate-pusty{display:none}
.mate.zajete .mate-id{display:flex;flex-direction:column;align-items:center;gap:1px}
.mate.zajete .mate-xp{display:flex;align-items:center;gap:var(--s2);
  padding:var(--s1) var(--s3);background:rgba(20,26,33,.42);
  border:2px solid var(--line);border-radius:var(--r-pill)}
.mate.zajete .mate3d{display:block}
.mate.zajete .mate-stan{display:block;text-align:center;font-size:10px;
  font-weight:800;letter-spacing:.14em;text-transform:uppercase;color:var(--txt-3)}
.mate-id b{font-size:14px;font-weight:900;letter-spacing:-.01em;color:var(--txt);
  paint-order:stroke fill;-webkit-text-stroke:3px rgba(20,26,33,.7)}
.mate-id>span{font-size:9.5px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--flame-dim)}
.mate-xp>b{font-size:15px;font-weight:900;color:var(--flame);
  font-variant-numeric:tabular-nums}
.mate-tor{flex:1 1 auto;height:6px;background:rgba(27,32,41,.55);
  border-radius:var(--r-pill);overflow:hidden}
.mate-tor i{display:block;height:100%;border-radius:var(--r-pill);
  background:linear-gradient(90deg,var(--flame-dim),var(--flame))}
/* Gotowość mówi SŁOWEM i BARWĄ — świecąca ramka zniknęła razem z ramką. */
.mate.gotowy .mate-stan{color:var(--leaf)}
.mate:not(.gotowy).zajete .mate-stan{color:var(--coral)}

/* Przycisk zjazdu w trybie drużyny. ZIELONY znaczy „czekam na resztę",
   CZERWONY „to na mnie czekają" — jedna barwa dla obu stanów kazałaby czytać
   napis, żeby dowiedzieć się, czyj jest ruch. */
.btn-descend.gotowosc{background:linear-gradient(180deg,#9BE07A,var(--leaf));
  color:#16300C;box-shadow:0 6px 0 #4C8A36,var(--lift),0 0 40px rgba(123,200,95,.28)}
.btn-descend.gotowosc.niegotowy{background:linear-gradient(180deg,#FF9C86,var(--coral));
  color:#3A1109;box-shadow:0 6px 0 #A8442F,var(--lift),0 0 40px rgba(255,122,92,.28)}

/* ── KOD POSTACI. Pole i przyciski w jednym rzędzie; pole jest studzienką,
   tak samo jak pole nicku — to jest miejsce, z którego się COŚ WYJMUJE.

   Oba rzędy mają IDENTYCZNĄ siatkę, więc pola i przyciski stoją w jednej
   linii pionowej niezależnie od tego, ile przycisków niesie rząd: dwa gniazda
   na przyciski, puste zostaje puste. Przy `flex` z automatyczną szerokością
   „Kopiuj" i „Użyj" miały różne szerokości i rząd wyglądał na przekrzywiony. */
/* ══ RZĄD Z POLEM I PRZYCISKIEM ══════════════════════════════════════════
   `.kodrz` powstał dla kodu postaci: pole + DWIE ikony po 44 px. Drużyna
   i znajomi mają pole + przycisk z NAPISEM, a ten trafiał w kolumnę 44 px
   i „Zaproś" było ucięte w połowie. Napisowy wariant dostaje własną klasę
   zamiast walczyć z szerokością kolumny. */
.kodrz.tekst{grid-template-columns:minmax(0,1fr) auto}
/* `.kodrz>button:last-child{grid-column:3}` wsadziłoby napisowy przycisk
   w trzecią kolumnę, której w tym wariancie nie ma — siatka utworzyłaby ją
   niejawnie i zostawiła pustą dziurę w środku. */
.kodrz.tekst>button:last-child{grid-column:2}
.kodrz.tekst button{width:auto;padding:0 var(--s3);white-space:nowrap}
.kodrz{display:grid;grid-template-columns:minmax(0,1fr) 44px 44px;gap:var(--s2);
  align-items:stretch}
.kodrz input{min-width:0;min-height:44px;padding:0 var(--s3);
  background:rgba(20,26,33,.55);border:2px solid var(--line);border-radius:var(--r-sm);
  color:var(--txt);font:700 12px ui-monospace,monospace;letter-spacing:.02em;
  box-shadow:inset 0 3px 8px rgba(12,16,21,.6)}
.kodrz input:focus{outline:0;border-color:var(--teal)}
.kodrz button{width:44px;min-height:44px;padding:0;display:grid;place-items:center}
.kodrz button .uico{width:20px;height:20px}
/* Rząd z jednym przyciskiem trzyma go w OSTATNIEJ kolumnie — pod przyciskiem
   kopiowania, a nie pod podglądem. */
.kodrz>button:last-child{grid-column:3}
/* ══ POLE WRAŻLIWE ══════════════════════════════════════════════════════
   Kod postaci jest w tej grze tym, czym hasło, i musi to być widać BEZ
   czytania podpisu. Koralowa krawędź i tło to ten sam sygnał, którym gra
   oznacza zagrożenie w kraterze. */
.kodrz.wrazliwe input{border-color:rgba(255,122,92,.55);
  background:rgba(70,26,22,.45);color:#FFC2B2}
.kodrz.wrazliwe input:focus{border-color:var(--coral)}
/* Komunikat odmowy na ekranie logowania — zostaje, dopóki gracz go nie
   naprawi, bo dotyczy decyzji, a nie zdarzenia. */
.blad{margin-top:var(--s3);padding:var(--s3);border-radius:var(--r-sm);
  background:rgba(255,122,92,.12);border:2px solid var(--coral);
  color:#FFC2B2;font-size:12.5px;font-weight:700;line-height:1.5}

/* ─────────────────────────────────────────────── nakładki */
/* Dwa przełączniki zawsze pod ręką — także w trakcie wyprawy, gdzie nie ma
   żadnego menu. Kółko 38 px to minimum, w które trafia kciuk bez celowania. */
/* ── PODPOWIEDZI PADA. Lewy dolny rog, nad bezpiecznym marginesem. Pokazuja
   sie same, kiedy pad sie zglosi, i znikaja w wyprawie - tam przyciski sa
   na HUD, a pasek zaslanialby dolna krawedz. */
#padHints{position:fixed;z-index:var(--z-over);display:flex;flex-wrap:wrap;
  gap:var(--s2) var(--s4);pointer-events:none;
  left:max(var(--s4),env(safe-area-inset-left));
  bottom:max(var(--s4),env(safe-area-inset-bottom))}
#padHints.hidden{display:none}
#padHints>div{display:flex;align-items:center;gap:6px}
#padHints b{display:grid;place-items:center;min-width:22px;height:22px;padding:0 6px;
  font-size:11px;font-weight:800;line-height:1;color:var(--txt);
  background:var(--surface-hi);border:2px solid var(--line);border-radius:var(--r-sm)}
#padHints span{font-size:11px;color:var(--txt-2)}

#corner{position:fixed;z-index:var(--z-over);display:flex;gap:var(--s2);
  top:calc(var(--s3) + env(safe-area-inset-top));right:calc(var(--s3) + env(safe-area-inset-right))}
/* W MIEŚCIE PRZEŁĄCZNIKI SIEDZĄ W PASKU ZAKŁADEK, wyrównane do jego wysokości.
   Pod paskiem nachodziły na pierwszy wiersz ekwipunku, a na pasku zasłaniały
   ostatnią zakładkę — jedyne miejsce, w którym niczego nie zasłaniają, to
   zarezerwowany koniec paska. W wyprawie paska nie ma, więc wracają do rogu. */
body:not(.in-run) #corner{top:calc(7px + env(safe-area-inset-top))}
#corner button{width:38px;height:38px;min-height:0;padding:0;
  background:rgba(43,51,61,.88);color:var(--txt-2);border:2px solid var(--line);
  border-radius:50%;font-weight:700;font-size:16px;line-height:1.2;box-shadow:none;
  transition:color var(--fast),border-color var(--fast)}
#corner button:hover{color:var(--txt);border-color:var(--flame-dim)}
#mute[aria-pressed="true"]{color:var(--txt-3);text-decoration:line-through}
#btnFull[aria-pressed="true"]{color:var(--flame);border-color:var(--flame-dim)}
/* ── POWIADOMIENIA. Były pigułką z kropką i napisem — czyli tym samym
   kształtem, co etykieta pierścienia i podpowiedź na dole. Trzy różne rzeczy
   wyglądały identycznie, a powiadomienie ma jedno zadanie: powiedzieć, CO
   właśnie wpadło, i zniknąć.

   Kształt niesie teraz informację: pasek koloru rzadkości przy lewej krawędzi
   (ta sama zasada, co obwódka ikony w skrzyni), ciemne tło z obrysem jak
   panele HUD, i lekki wjazd Z BOKU zamiast z góry — z góry przychodzą
   komunikaty systemowe, z boku rzeczy, które się zdarzyły w grze. */
#toasts{position:absolute;left:50%;top:88px;transform:translateX(-50%);z-index:var(--z-toast);
  display:flex;flex-direction:column;gap:6px;align-items:stretch;pointer-events:none;
  width:min(320px,74vw)}
.toast{position:relative;display:flex;align-items:center;gap:var(--s3);
  padding:9px var(--s4) 9px var(--s3);
  border-radius:var(--r-sm);background:rgba(20,26,33,.92);
  border:2px solid var(--line);border-left-width:5px;border-left-color:var(--c,var(--teal));
  box-shadow:0 6px 18px rgba(0,0,0,.45);
  font-size:13px;font-weight:700;color:var(--txt);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  animation:wjazd 220ms cubic-bezier(.2,.9,.3,1) both, zejscie 260ms ease-in 1.94s both}
/* Pasek czasu życia — powiadomienie mówi też, ile mu zostało, więc nie znika
   „nagle". Dwie sekundy to `setTimeout` w `toast()`. */
.toast::after{content:"";position:absolute;left:0;bottom:0;height:2px;
  background:var(--c,var(--teal));animation:toastCzas 2.2s linear both}
@keyframes toastCzas{from{width:100%}to{width:0}}
@keyframes wjazd{from{opacity:0;transform:translateX(26px)}to{opacity:1;transform:none}}
@keyframes zejscie{from{opacity:1}to{opacity:0;transform:translateX(-14px)}}
@keyframes pop{from{opacity:0;transform:translateY(-6px) scale(.96)}to{opacity:1;transform:none}}
#hint{position:absolute;left:50%;bottom:22%;transform:translateX(-50%);z-index:var(--z-hud);
  font-size:13px;color:var(--txt);background:rgba(43,51,61,.94);border:2px solid var(--line);
  padding:var(--s2) var(--s4);border-radius:var(--r-pill);pointer-events:none;text-align:center}
#hint.hidden{display:none}
#rotate{position:absolute;inset:0;z-index:var(--z-over);display:none;flex-direction:column;
  gap:var(--s3);align-items:center;justify-content:center;background:var(--void);
  padding:var(--s6);text-align:center}
#rotate b{font-size:18px;color:var(--txt)}
#rotate span{font-size:13px;line-height:1.6;color:var(--txt-2);max-width:34ch}
/* Bramka obrotu dotyczy WYŁĄCZNIE rozgrywki. Wcześniej zasłaniała też menu
   i skrzynię, czyli zmuszała gracza do obracania telefonu, żeby przeczytać
   własny ekwipunek. Hub jest projektowany pod pion. */
@media (orientation:portrait) and (pointer:coarse){body.in-run #rotate{display:flex}}


/* ─────────────────────────────────────────────── zakładki miasta
   Miasto było jedną długą kolumną: klasa, zjazd, pierścienie, zaopatrzenie,
   ekwipunek, skrzynia, sterowanie. Na telefonie to sześć przewinięć między
   „zjedź" a skrzynią — czyli między dwiema rzeczami, między którymi gracz
   skacze najczęściej. Zakładki mieszczą każdą decyzję na jednym ekranie
   i zostawiają nagłówek z poziomem widoczny cały czas. */
/* ZAKŁADKI TO JEDEN PASEK, NIE CZTERY PIGUŁKI. Ramka wokół każdej z osobna
   plus ramka wokół całości dawała sześć krawędzi na jeden element sterujący.
   Zostaje jedna linia pod paskiem i podkreślenie aktywnej — tyle wystarczy,
   żeby wiedzieć, gdzie się jest. */
/* ══ ZAKŁADKI ════════════════════════════════════════════════════════════
   Były czterema napisami z kreską pod aktywnym — czyli nawigacją strony
   internetowej. W tej grze każdy element interfejsu ma GRUBOŚĆ: skrytka jest
   bryłą, ikona siedzi w studzience, przycisk ma płytę pod spodem. Zakładki
   były jedynym miejscem, gdzie nie było nic do dotknięcia.

   Teraz pasek jest ZAGŁĘBIENIEM (cień do środka, ciemniejszy od tła), a
   aktywna zakładka WYSTAJĄCĄ Z NIEGO PŁYTKĄ w barwie latarni. Ta sama
   zasada, co przy studzience na ikonę: wklęsłe jest tłem, wypukłe jest
   rzeczą. */
/* PASEK ZAKŁADEK JEST KRAWĘDZIĄ EKRANU, nie kartą na nim. Zaokrąglone rogi
   robiły z niego pływające pudełko oderwane od góry okna — a to jest listwa
   przyklejona do krawędzi, tak samo jak pasek stanu systemu. Kwadratowo. */
.tabs{display:flex;gap:var(--s1);width:100%;max-width:560px;
  background:rgba(20,26,33,.42);border:1px solid rgba(20,26,33,.6);
  border-radius:0;padding:var(--s1);overflow-x:auto;scrollbar-width:none;
  box-shadow:inset 0 2px 6px rgba(12,16,21,.55), 0 1px 0 rgba(255,255,255,.05)}
.tabs::-webkit-scrollbar{display:none}
/* ZAKŁADKA MA SZEROKOŚĆ SWOJEJ NAZWY, nie równą ćwiartkę paska. Podział na
   cztery równe części dawał po 63 px przy 375 px okna, a „Ustawienia"
   potrzebuje 66 — czyli JEDNA etykieta z czterech była ucinana wielokropkiem
   na każdym telefonie. Przy szerokości z treści problem znika u źródła:
   krótkie nazwy oddają miejsce długiej, a podkreślenie aktywnej zakładki
   obejmuje słowo, a nie pustą ćwiartkę. */
.tab{flex:0 1 auto;min-width:0;width:auto;min-height:40px;padding:var(--s2) var(--s3);
  background:transparent;border:0;
  border-radius:0;color:var(--txt-2);box-shadow:none;
  font-size:clamp(10px,2.6vw,12px);font-weight:800;letter-spacing:.04em;
  /* ETYKIETA MA SIĘ ZMIEŚCIĆ ALBO SKRÓCIĆ, NIGDY WYLAĆ. Przy 380 px napisy
     wychodziły poza swoje przyciski i zlewały się w „SKRZYNIAUSTAWIENIA" —
     `white-space:nowrap` bez `overflow` nie ucina, tylko rozlewa. */
  text-transform:uppercase;white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis;
  cursor:var(--kursor),pointer;transition:background var(--fast),color var(--fast);
  display:flex;align-items:center;justify-content:center;gap:var(--s1)}
/* WERSALIKI SĄ SZEROKIE. Przy 380 px na cztery zakładki plus róg z
   przełącznikami zostaje po 51 px, a „USTAWIENIA" wersalikami potrzebuje 68 —
   napis wychodził poza swój przycisk i zlewał się z sąsiadem. Poniżej 560 px
   etykieta traci wersaliki i rozstrzelenie: te same słowa mieszczą się wtedy
   w tym samym miejscu, bez skracania i bez przewijania paska. */
@media (max-width:559px){
  /* Rozmiar liczony z NAJDŁUŻSZEJ etykiety, nie z upodobania: „Ustawienia"
     przy 11,5 px potrzebuje 65 px, a przy 320 px szerokości okna zakładka
     dostaje 61. Skala płynna po szerokości okna trafia w oba przypadki. */
  .tab{text-transform:none;letter-spacing:0;padding-inline:var(--s1);
    font-size:clamp(10px,3.2vw,11.5px)}
  /* Na wąskim ekranie pasek zakładek bierze CAŁĄ szerokość, a przełączniki
     schodzą pod niego. Sto pikseli rezerwy w rogu zostawiało po 51 px na
     zakładkę — mniej, niż potrzebuje najdłuższe słowo. W wyprawie róg
     zostaje na górze, bo tam nie ma paska zakładek. */

}
.tab:hover{color:var(--txt)}
/* Aktywna: płytka wysunięta ku graczowi. Jasny grzbiet u góry i cień pod
   spodem to te same dwie linie, którymi rysowany jest każdy przycisk — dzięki
   temu „gdzie jestem" czyta się tym samym odruchem, co „w co mogę kliknąć". */
/* Zakładka-ikona: kwadratowa, tej samej wysokości co pozostałe. Znak
   dziedziczy kolor tekstu, więc podświetlenie aktywnej działa bez wyjątku. */
.tab-ico{display:grid;place-items:center;min-width:40px;padding:0}
.tab-ico .uico{width:20px;height:20px}
.tab[aria-selected="true"]{color:#2A2118;
  background:linear-gradient(180deg,#FFD873 0,var(--flame) 62%,var(--flame-dim) 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.5), 0 2px 0 rgba(122,86,20,.85),
    0 6px 14px rgba(12,16,21,.45);
  -webkit-text-stroke:0}
.tab:hover:not([aria-selected="true"]){color:var(--txt);
  background:rgba(240,234,221,.06)}
/* Kropka „masz tu coś nowego". Bez niej łup wpadający do skrzyni w innej
   zakładce jest niewidzialny. */
.pip{width:7px;height:7px;flex:0 0 auto;border-radius:var(--r-pill);
  background:var(--flame);display:inline-block}
/* `display:inline-block` BIJE `[hidden]` — obie reguły mają tę samą wagę,
   a nasza jest później w kaskadzie niż arkusz przeglądarki. Kropka „masz tu
   coś nowego" świeciła więc ZAWSZE, czyli nie znaczyła nic. Znalezione przy
   pomiarze paska zakładek, nie przez oglądanie. */
.pip[hidden]{display:none}
.pane{display:flex;flex-direction:column;gap:var(--s4);width:100%;max-width:560px}
.pane.hidden{display:none}

/* ─────────────────────────────────────────────── drużyna i scena postaci */
/* Na wąskim ekranie scena idzie NAD miejscami drużyny. Trzy kafelki obok
   siebie przy 375 px dawały 112 px na sztukę, a `aspect-ratio` wypychało
   trzeci poza ekran — czyli układ, który wygląda na uszkodzony. */
/* TRZY RÓWNE MIEJSCA W JEDNYM RZĘDZIE. Bohater nad drużyną (osobny wiersz)
   stawiał go wyżej od reszty i sugerował hierarchię, której w tej drużynie
   nie ma — a przy okazji rozjeżdżał linię, na której stoją wszystkie postacie.
   Wyrównanie do GÓRY, nie do środka: karty mają różną wysokość podpisu
   (kolega bez klasy, bohater z paskiem XP), a stopy mają stać w jednej linii. */
.party{display:grid;gap:var(--s3);width:100%;max-width:720px;
  grid-template-columns:repeat(3,minmax(0,1fr));
  grid-template-areas:"hero m1 m2";align-items:start}
/* NAZWA OBSZARU MUSI BYĆ ZWIĄZANA ZE SWOJĄ SIATKĄ. Niescopowane
   `.hero-host{grid-area:hero}` łapało też gospodarza w zakładce „Postać",
   gdzie żadnego obszaru „hero" nie ma — przeglądarka dokładała wtedy puste
   kolumny domyślne i karta rozlewała się na całą szerokość. */
.party>.hero-host{grid-area:hero}
.mate#mate1{grid-area:m1}
.mate#mate2{grid-area:m2}
@media (min-width:520px){
  /* Trzy RÓWNE kolumny: miejsce w drużynie jest tyle samo warte, niezależnie
     od tego, kto na nim stoi. Przy 2fr dla siebie i 1fr dla reszty puste
     miejsca wychodziły o połowę mniejsze i czytały się jak przypis. */
  .party{grid-template-columns:repeat(3,minmax(0,1fr));
    grid-template-areas:"hero m1 m2"}
  .hero-stage{aspect-ratio:3/4}
  /* PUSTE miejsce wyrównuje się do DOŁU: karta ma nad sceną nazwę i pasek,
     więc równanie do góry ustawiałoby pustkę naprzeciw tekstu zamiast
     naprzeciw sylwetki.

     ZAJĘTE równa się do GÓRY, bo od tej tury jest pełną kartą postaci —
     z nazwą, klasą i poziomem dokładnie tam, gdzie ma je bohater. Ta reguła
     została po czasach, gdy miejsce było samym plusem, i to ona stawiała
     drużynę o trzysta pikseli niżej niż gracza. */
  .mate:not(.zajete){align-self:end;aspect-ratio:3/4;min-height:120px}
  .mate.zajete{align-self:start}
}

/* ─────────────────────────────────────── układ zakładek
   Wyprawa: drużyna po lewej, decyzja po prawej. Postać: co z niej wynika,
   ona sama, co ma na sobie. W obu przypadkach postać jest w środku kadru,
   a nie doklejona z boku. */
.run-lay{display:flex;flex-direction:column;gap:var(--s5);width:100%}
/* Na telefonie zjazd zostaje w potoku strony — przyklejony do dołu zasłaniałby
   drużynę na ekranie, na którym i tak wszystko się mieści. */
/* PAPIEROWA LALKA: obszary zamiast kolejności w potoku.
   Na wąskim ekranie sylwetka jest pierwsza (po nią gracz tu przyszedł),
   pod nią liczby, a gniazda na dole w dwóch kolumnach — pancerz po lewej,
   narzędzia po prawej, ta sama strona co przy szerokim układzie, więc
   przejście między telefonem a monitorem nie każe uczyć się na nowo. */
.hero-lay{display:grid;gap:var(--s4);width:100%;
  grid-template-columns:repeat(2,minmax(0,1fr));
  grid-template-areas:"hero hero" "stats stats" "l r";align-items:start}
.hero-lay .doll-l{grid-area:l}
.hero-lay .doll-r{grid-area:r}
.hero-lay .derived{grid-area:stats}
/* KARTA MA SZEROKOŚĆ KARTY, nie szerokość okna. W układzie jednokolumnowym
   (520-1280 px) karta rozciągała się na całą kolumnę, a scena 3/4 robiła się
   przez to wyższa niż ekran — postać wyglądała jak plakat, nie jak figurka
   w kadrze. Od 1280 px kolumna siatki i tak jest węższa niż ten limit. */
.hero-lay .hero-host{grid-area:hero;max-width:320px;margin-inline:auto}
/* Poniżej 520 px gniazdo obok gniazda daje 160 px na sztukę: studzienka
   zjada 58, zostaje 90 na nazwę przedmiotu. Jedna kolumna. */
@media (max-width:519px){
  .hero-lay{grid-template-columns:minmax(0,1fr);
    grid-template-areas:"hero" "stats" "l" "r"}
}
/* ─────────────────────────────────────── karta postaci
   Jedna karta na całe miasto, przenoszona między zakładkami. Kolejność
   czytania jest kolejnością pytań: KTO (nazwa), JAK DALEKO (poziom), JAK
   WYGLĄDA (scena). Odwrotna kolejność kazałaby zgadywać, czyja to sylwetka. */
/* Nazwa i pasek NAD sceną, ale wąskie: mają podpisywać postać, a nie ciągnąć
   się przez pół ekranu jak nagłówek sekcji. */
.hero-card{display:flex;flex-direction:column;gap:var(--s2);min-width:0;
  align-items:stretch}
.hero-card>.hero-id,.hero-card>.hero-xp{max-width:300px;align-self:center;width:100%}
.hero-id{display:flex;flex-direction:column;gap:1px;min-width:0}
.hero-id{text-align:center}
.hero-id b{font-size:clamp(1rem,3.6vw,1.35rem);font-weight:900;letter-spacing:-.02em;
  color:var(--txt);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;display:block}
.hero-id span{font-size:10px;letter-spacing:.16em;text-transform:uppercase;color:var(--flame-dim)}
.hero-card .hero-xp{background:linear-gradient(180deg,#3A3527,#2F3239);
  border:1px solid #5A4E33;border-radius:var(--r-sm);padding:var(--s2) var(--s3)}
.hero-host{display:flex;min-width:0}
.hero-host>.hero-card{flex:1 1 auto;min-width:0}

/* SCENA, NIE KAFELEK. Ramka i własne tło robiły z żywego modelu miniaturkę
   w katalogu — postać stoi teraz wprost na tle ekranu, a „podłogę" daje jej
   cień kontaktowy i łagodna poświata pod stopami, tak samo jak w krateru. */
.hero-stage{position:relative;flex:1 1 auto;aspect-ratio:16/11;min-height:170px;
  overflow:visible;
  /* Postać musi na czymś STAĆ. Bez ramki scena nie miała podłogi i model
     wisiał w gradiencie tła — ta sama skarga, co w kraterze. Krąg światła
     pod stopami robi grunt, a ciemna elipsa w jego środku robi kontakt. */
  /* KRĄG ŚWIATŁA MUSI SIĘ ZMIEŚCIĆ. Stopy stoją na 96 % wysokości płótna,
     więc poświata rysowana na 93 % miała dolną połowę POZA elementem i ucinała
     się prostą kreską tuż pod modelem. Scena dostaje 18 % zapasu na dole,
     a postać i światło przesuwają się w górę o tyle samo. */
  padding-bottom:18%;
  /* POŚWIATA MUSI STAĆ POD STOPAMI, a stopy przesunęły się w górę razem
     z kadrem, który dostał zapas na mgłę jakości (patrz `drawHeroStage`).
     Zmierzone w przeglądarce przy 1280x800: płótno zajmuje 316 z 416 px
     sceny, stopy stoją na 84,5 % płótna, czyli na 64,3 % wysokości `.hero-stage`.
     Poprzednie 78-79 % świeciło 60 px pod modelem. */
  background:
    radial-gradient(20% 5% at 50% 64%,rgba(27,32,41,.55),rgba(27,32,41,0) 70%),
    radial-gradient(42% 17% at 50% 65%,rgba(255,201,74,.17),rgba(255,201,74,0) 74%)}
/* ── ROZLICZENIE. Werdykt po lewej, księga po prawej; na wąskim ekranie
   jedno pod drugim, ale w tej samej kolejności czytania. */
.end-lay{display:flex;flex-direction:column;gap:var(--s4);width:100%;max-width:960px;
  margin-inline:auto}
.verdict{display:flex;flex-direction:column;align-items:center;gap:var(--s2);min-width:0}
/* Kreska pod werdyktem — rozdziela WYNIK od tego, co się stało. Rozjaśnia się
   ku środkowi, więc czyta się jak światło padające na napis, a nie jak
   przegroda w formularzu. */
.verdict .res+.note{padding-top:var(--s3);width:100%;
  border-top:1px solid transparent;
  border-image:linear-gradient(90deg,transparent,var(--line) 22%,
    var(--line) 78%,transparent) 1}
.verdict .note{text-align:center;max-width:44ch}
.ledger{display:flex;flex-direction:column;gap:var(--s3);min-width:0;
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  padding:var(--s4)}
.ledger-h{font-size:11px;font-weight:800;letter-spacing:.16em;text-transform:uppercase;
  color:var(--txt-3)}
.ledger-h span{color:var(--txt-2);font-weight:600;letter-spacing:.04em;text-transform:none}
.tally{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--s2)}
/* Liczby wyprawy siedzą w zagłębieniach — tak samo jak wszystko, co jest
   ODCZYTEM, a nie rzeczą do kliknięcia. */
.tally .stat{background:rgba(20,26,33,.34);border-radius:var(--r-sm);padding:var(--s3);
  border:1px solid rgba(20,26,33,.5);
  min-width:0;text-align:center}
.tally .stat b{display:block;font-size:22px;font-weight:800;color:var(--flame);
  font-variant-numeric:tabular-nums;line-height:1.2;overflow:hidden;text-overflow:ellipsis}
.tally .stat span{font-size:9px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--txt-3);overflow-wrap:anywhere}
.end-row{margin-top:auto}
@media (min-width:820px){
  .end-lay{display:grid;grid-template-columns:minmax(0,0.92fr) minmax(0,1.08fr);
    align-items:stretch;gap:var(--s5)}
  .verdict{justify-content:center}
  .end-stage{max-height:min(300px,42vh)}
}
/* Scena wyniku. Niższa niż kafelek drużyny — ma być nagłówkiem ekranu, nie
   jego treścią; liczby pod nią są tym, po co gracz tu przyszedł. */
.end-stage{position:relative;width:100%;max-width:430px;aspect-ratio:16/7;
  /* `flex:0 0 auto` NIE jest ozdobą: ekran końca jest kolumną flex, a element
     z samym `aspect-ratio` jest dla flexboxa ściśliwy — na ekranie 360x640
     kurczył się do ZERA i sceny po prostu nie było. Wysokość ograniczamy
     jawnie, żeby na niskim telefonie scena nie zjadła liczb pod sobą. */
  flex:0 0 auto;max-height:min(190px,23vh);margin-bottom:var(--s3);
  background:radial-gradient(120% 90% at 50% 100%,var(--rim-lit),var(--void) 78%);
  border:1px solid var(--line);border-radius:var(--r);overflow:hidden}
#end3d{position:static;width:100%;height:100%}
/* `.hero-cap` (podpis WEWNĄTRZ sceny) zniknął: nazwa i klasa stoją teraz nad
   sceną jako `.hero-id`. Napis na obrazku zasłaniał to, co opisywał. */
/* Puste miejsca w drużynie stoją tu CELOWO: mówią, że gra jest wieloosobowa,
   zanim nią będzie. Przerywana ramka odróżnia „jeszcze nikogo" od „usterki". */
/* Na wąskim ekranie puste miejsca leżą POD sceną, więc mają być NISKIE —
   przy 3/4 zjadały pół ekranu na komunikat „wolne miejsce". */
/* Puste miejsce jest ZAPROSZENIEM, nie brakiem. Kwadrat z napisem „wolne
   miejsce" czytał się jak dziura w układzie; plus czyta się jako czynność
   i nie wymaga języka. Kontur zostaje przerywany — miejsce jeszcze nie
   istnieje, więc nie ma pełnej ramki. */
/* ══ MIEJSCE W DRUŻYNIE ══════════════════════════════════════════════════
   Puste miejsce jest ZAPROSZENIEM, nie polem formularza — kreskowana ramka
   robiła z niego pudełko do wypełnienia. Zostaje sam plus z podpisem na tle
   menu; obrys pojawia się dopiero wtedy, gdy ktoś na tym miejscu STOI, bo
   wtedy jest co obramować. */
.mate{aspect-ratio:16/7;min-height:56px;border:0;
  border-radius:var(--r);display:flex;flex-direction:column;align-items:center;
  justify-content:center;gap:var(--s2);background:none;box-shadow:none;
  color:var(--txt-3);cursor:var(--kursor),default;padding:var(--s3)}
.mate .plus{position:relative;width:30px;height:30px;flex:0 0 auto;opacity:.5}
.mate .plus::before,.mate .plus::after{content:"";position:absolute;
  background:currentColor;border-radius:2px}
.mate .plus::before{left:50%;top:0;width:3px;height:100%;transform:translateX(-50%)}
.mate .plus::after{top:50%;left:0;height:3px;width:100%;transform:translateY(-50%)}
.mate span{font-size:10px;letter-spacing:.1em;text-transform:uppercase;
  color:var(--txt-3);opacity:.62;text-align:center;line-height:1.4}

/* ─────────────────────────────────────────────── ustawienia */
/* Przełącznik: po lewej co przełączasz, po prawej czy jest włączone.
   Cała płytka jest celem kliknięcia — na telefonie nikt nie trafia w sam
   suwak, a przełącznik, w który trzeba celować, jest przełącznikiem gorszym
   od przycisku. */
.switches{display:grid;grid-template-columns:1fr;gap:var(--s2)}
@media (min-width:560px){.switches{grid-template-columns:repeat(2,minmax(0,1fr))}}
.sw{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);
  width:100%;min-height:56px;padding:var(--s2) var(--s3);text-align:start;
  background:var(--surface);border:2px solid var(--line);border-radius:var(--r);
  color:var(--txt);cursor:var(--kursor),pointer;box-shadow:none;
  transition:border-color var(--fast),background var(--fast)}
.sw:hover{border-color:var(--teal-dk)}
.sw-l{display:flex;flex-direction:column;gap:1px;min-width:0}
.sw-l b{font-size:13px;font-weight:700}
.sw-l i{font-style:normal;font-size:10.5px;color:var(--txt-3)}
.sw-t{flex:0 0 auto;position:relative;width:44px;height:24px;border-radius:var(--r-pill);
  background:var(--void);border:2px solid var(--line);transition:background var(--fast),border-color var(--fast)}
.sw-t::after{content:"";position:absolute;top:2px;left:2px;width:16px;height:16px;
  border-radius:50%;background:var(--txt-3);transition:transform var(--fast),background var(--fast)}
.sw[aria-checked="true"]{border-color:var(--teal-dk)}
.sw[aria-checked="true"] .sw-t{background:var(--teal-dk);border-color:var(--teal)}
.sw[aria-checked="true"] .sw-t::after{transform:translateX(20px);background:var(--teal-lt)}

/* Dotykowy zestaw sterowania to inne urządzenie, nie inna sekcja — oddziela
   go kreska, a nie nagłówek, bo nagłówek sugerowałby osobne ustawienia. */
.keys.touch{margin-top:var(--s3);padding-top:var(--s3);border-top:1px solid var(--line)}
.keys{display:grid;grid-template-columns:1fr;gap:var(--s2)}
.keys>div{display:grid;grid-template-columns:auto 1fr;gap:var(--s3);align-items:center}
.keys kbd{background:var(--surface-hi);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:3px 8px;font:700 11px ui-monospace,monospace;
  color:var(--txt);min-width:58px;text-align:center}
.keys span{font-size:12px;color:var(--txt-2)}
@media (min-width:520px){.keys{grid-template-columns:repeat(2,minmax(0,1fr))}}

/* ─────────────────────────────────────────────── progi */
@media (min-width:720px){
  .supplies{grid-template-columns:repeat(3,minmax(0,1fr))}
}
@media (min-width:768px){
  .col,.rim,.supplies,.maw,.shaft,.sect,.descent,.tabs,.pane,.party{max-width:600px}
  /* Cztery elementy pancerza w jednym rzędzie — przy trzech kolumnach amulet
     zostawał sam w drugim rzędzie i wyglądał na pomyłkę. */
  .loadout{grid-template-columns:repeat(4,1fr)}
  .gcell:first-child{grid-column:1 / -1}
}
/* Od 1280 px hub rozkłada się na dwie kolumny: po lewej decyzja (gardziel
   i lejek), po prawej przygotowanie (ekwipunek i skrzynia). Scroll znika. */
/* Od 1280 px zakładka „Wyprawa" rozkłada się na dwie kolumny: po lewej
   drużyna, po prawej decyzja. Reszta zakładek zostaje jedną kolumną —
   ekwipunek i skrzynia i tak czytają się w pionie. */
/* Od 900 px miasto zajmuje CAŁY EKRAN, a nie kolumnę pośrodku. Zjazd siada
   w prawym dolnym rogu z marginesem, informacja o instancji NAD nim — bo to
   jest kolejność czytania przed decyzją: najpierw ile zostało czasu, potem
   przycisk. Scena z postacią dostaje całą resztę. */
@media (min-width:900px){
  #scLobby .col{max-width:none;width:100%;padding-inline:var(--s5)}
  #scLobby .pane{max-width:none}
  /* Szerzej, odkąd stan stoi OBOK przycisku: 306 px (min(360,34vw) przy
     900 px okna) mieściło kolumnę, ale nie rząd — przycisk wystawał
     24 px poza ekran. Zmierzone: przycisk 210 + stan 180 + odstęp 16
     + wypełnienie 32 = 438. */
  #scLobby .pane[data-pane="run"] .descent{
    position:fixed;right:var(--s5);bottom:var(--s5);width:min(560px,52vw);
    max-width:none;z-index:3;gap:var(--s3)}
  #scLobby .pane[data-pane="run"] .maw{padding-top:0;max-width:none;gap:var(--s3)}
  /* Drużyna dostaje CAŁĄ szerokość minus miejsce zarezerwowane na zjazd.
     `padding-right` liczy się do szerokości boksu, więc bez `width:100%`
     siatka kurczyła się do resztki i postać wychodziła wielkości ikony. */
  /* DRUŻYNA STOI POŚRODKU WOLNEGO MIEJSCA. Kolumny elastyczne rozciągały
     trójkę na całą szerokość i bohater lądował przy lewej krawędzi; stałe
     szerokości plus `justify-content:center` stawiają go tam, gdzie patrzy
     oko — w środku pola, które zostaje po odjęciu panelu zjazdu. */
  /* Bez rezerwy na panel zjazdu: panel jest przyklejony do DOŁU ekranu,
     a drużyna stoi u góry — nie mają jak na siebie wejść. Rezerwa tylko
     spychała bohatera do lewej krawędzi. */
  #scLobby .party{max-width:none;width:100%;box-sizing:border-box;
    justify-content:center;align-content:center;
    grid-template-columns:repeat(3,minmax(0,clamp(190px,21vw,300px)))}
  /* Scena bierze wysokość z EKRANU, nie z proporcji kafelka — postać ma stać
     w kadrze, a nie leżeć w miniaturce. */
  .party .hero-stage{aspect-ratio:auto;height:min(56vh,500px);min-height:0}
  .party .mate{aspect-ratio:auto;height:min(30vh,260px);min-height:0}
  /* PANCERZ — SYLWETKA — NARZĘDZIA. Trzy kolumny, liczby całą szerokością
     pod spodem: statystyki są SKUTKIEM sprzętu, więc czyta się je po nim. */
  .hero-lay{max-width:1280px;margin-inline:auto;column-gap:var(--s5);
    grid-template-columns:minmax(0,1fr) minmax(0,1.06fr) minmax(0,1fr);
    grid-template-areas:"l hero r" "stats stats stats"}
  .hero-lay .hero-host{max-width:none}
  .hero-lay .hero-stage{aspect-ratio:auto;height:min(52vh,460px);min-height:0}
  .hero-lay .derived{grid-template-columns:repeat(5,minmax(0,1fr))}
}
@media (min-width:1280px){
  #scLobby .col{max-width:none;margin-block:0}
  #scLobby .tabs,#scLobby .pane{max-width:none}
  /* Nagłówek ma na 1280 px trzy razy więcej miejsca niż na telefonie —
     pasek XP może wreszcie pokazać postęp, zamiast być kreską. */
  #scLobby .hero-xp .wick{width:auto}
  /* Dwukolumnowa siatka wyprawy zniknęła razem z panelem w potoku: zjazd
     jest teraz przyklejony do prawego dolnego rogu (`position:fixed`), więc
     rezerwowanie mu kolumny ścinało scenę do jednej trzeciej ekranu. */
  /* Na monitorze gniazda dostają stałą szerokość, a sylwetka całą resztę:
     kolumna sprzętu szersza niż 300 px to sam odstęp między ikoną a nazwą. */
  .hero-lay{grid-template-columns:minmax(0,300px) minmax(0,1fr) minmax(0,300px)}
  #scLobby .party{max-width:none}
  #scLobby .descent{max-width:none}
  #scLobby .sect,#scLobby .supplies{max-width:none}
  #scLobby .supplies{grid-template-columns:repeat(3,minmax(0,1fr))}
}
/* Telefon w poziomie: hub też idzie na dwie kolumny, inaczej wszystko
   ląduje pod zgięciem i gracz scrolluje przez cały ekwipunek do przycisku. */
/* Telefon w poziomie: mało wysokości, dużo szerokości. Zakładka wyprawy idzie
   na dwie kolumny, żeby przycisk zjazdu nie wylądował pod zgięciem. */
@media (orientation:landscape) and (max-height:560px){
  #scLobby .col{max-width:960px}
  #scLobby .rim,#scLobby .tabs,#scLobby .pane,#scLobby .party,
  #scLobby .descent,#scLobby .sect,#scLobby .supplies{max-width:none}
  /* W poziomie na telefonie zjazd też jest przyklejony do rogu. */
  /* W poziomie na telefonie wysokości jest 360-560 px, więc sylwetka musi
     stanąć MIĘDZY kolumnami gniazd, a nie nad nimi — inaczej wszystko poza
     nią ląduje pod zgięciem. Liczby w jednym rzędzie pod spodem. */
  .hero-lay{grid-template-columns:minmax(0,1fr) minmax(0,0.9fr) minmax(0,1fr);
    grid-template-areas:"l hero r" "stats stats stats";
    column-gap:var(--s4);align-items:start}
  .hero-lay .derived{grid-template-columns:repeat(5,minmax(0,1fr))}
  /* Studzienka schodzi do 46 px: przy 150 px kolumny 58 px zostawiało
     na nazwę przedmiotu 70 px, czyli jedno słowo na wiersz. */
  .doll .well{width:46px;height:46px}
  .doll .gslot{min-height:0;gap:var(--s2)}
  #scLobby .descent{gap:var(--s3)}
  #scLobby .maw{padding-top:var(--s3)}
  .hero-stage,.mate{min-height:0;aspect-ratio:auto;height:42vh}
  /* NA TELEFONIE W POZIOMIE STAN WRACA NAD PRZYCISK. Rząd wymaga 438 px
     (przycisk 210 + stan 180 + odstęp i wypełnienie), a przyklejony panel ma
     tu `min(320px, 40vw)` — przy oknie 640 px to 256. Przemiatanie po
     rozdzielczościach pokazało przycisk wystający 55 px za prawą krawędź.
     Kolumna nie jest tu gorsza: przy 360 px wysokości i tak liczy się każdy
     piksel szerokości, a kolejność czytania zostaje ta sama. */
  #scLobby .pane[data-pane="run"] .descent{position:fixed;right:var(--s4);
    bottom:var(--s4);width:min(320px,44vw);z-index:3}
  #scLobby .pane[data-pane="run"] .maw{gap:var(--s2);padding-top:0;
    flex-direction:column-reverse}
  #scLobby .pane[data-pane="run"] .maw .state{text-align:center;
    min-width:0;max-width:none}
  #scLobby .party{justify-content:center}
  .inv{max-height:30vh}
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
}

/* ══ MIEJSCE W DRUŻYNIE — DOMKNIĘCIE ═════════════════════════════════════
   Ten blok stoi NA KOŃCU arkusza celowo. Reguły `.mate` z czasów pustego
   zaproszenia (`aspect-ratio:16/7`, `justify-content:center`) i responsywne
   `.party .mate{height:...}` leżą kilkaset linii niżej niż nowa definicja
   karty, więc przy tej samej specyficzności wygrywały kolejnością: płótno
   dostawało całą wysokość kafelka, a nazwa i pasek poziomu lądowały POD nim
   i znikały pod obrazem.

   Zamiast podbijać specyficzność selektorami-łańcuchami, domykamy to tam,
   gdzie kaskada i tak kończy bieg. Puste miejsce zachowuje stary wygląd —
   zmienia się wyłącznie to, co ZAJĘTE. */
.party .mate.zajete{aspect-ratio:auto;height:auto;min-height:0;
  justify-content:flex-start;padding:0;gap:var(--s2)}
.party .mate.zajete .mate3d{flex:0 0 auto;height:auto;aspect-ratio:3/4;
  min-height:0;position:static}
/* Scena kolegi ma tę samą wysokość co scena bohatera, więc wszystkie trzy
   postacie stoją na jednej linii gruntu. */
@media (min-width:720px){
  .party .mate.zajete .mate3d{aspect-ratio:auto;height:min(56vh,500px)}
}
/* Poniżej progu kolumny kontrakty schodzą POD wyprawę — na górze mają stać
   postać i przycisk zjazdu, a nie lista zadań. */
/* Poniżej progu kolumny kontrakty schodzą POD wyprawę. `order` działa tylko
   w kontenerze flex/grid, a `.run-lay` jest flexem — więc wystarczy jedna
   liczba zamiast przenoszenia elementu w HTML-u przy każdej zmianie progu. */
@media (max-width:1099px){
  .run-lay{display:flex}
  .run-lay>.kontrakty{order:9}
  .run-lay>.party{order:1}
  .run-lay>.descent{order:2}
}

/* ══ SZEROKI UKŁAD WYPRAWY — NA KOŃCU ARKUSZA ════════════════════════════
   Ten blok musi stać PO bazowej regule `.run-lay{display:flex}`, która leży
   kilkaset linii niżej niż miejsce, w którym opisane są kontrakty. Przy
   równej specyficzności wygrywa reguła późniejsza — więc `display:grid`
   z media query nigdy nie wchodził w życie i kolumna zadań lądowała jako
   wiersz nad postacią.

   To już drugi raz w tym arkuszu, kiedy o wszystkim decyduje kolejność,
   a nie zamiar. Reguły, które mają NADPISYWAĆ układ, trzymamy odtąd tutaj. */
@media (min-width:1100px){
  .run-lay{display:grid;align-items:start;
    grid-template-columns:minmax(0,1fr) minmax(280px,340px);
    grid-template-areas:"party kontr" "descent kontr";
    column-gap:var(--s5)}
  .run-lay>.party{grid-area:party}
  .run-lay>.descent{grid-area:descent}
  .run-lay>.kontrakty{grid-area:kontr;max-width:none}
  /* Pasek postępu przechodzi pod spód: w wąskiej kolumnie cztery rzeczy
     w jednym wierszu zostawiają na treść zadania dwadzieścia znaków. */
  .kontrakty .krow{grid-template-columns:minmax(0,1fr) auto auto;gap:var(--s2)}
  .kontrakty .kpas{grid-column:1 / -1;order:9}
}

/* Wylogowanie: jedyna nieodwracalna akcja w ustawieniach, więc odsunięta
   od reszty i podpisana skutkiem, a nie samą nazwą. */
.wylog{display:flex;align-items:center;gap:var(--s3);flex-wrap:wrap;
  margin-top:var(--s4);padding-top:var(--s3);border-top:1px solid var(--line)}
/* Przycisk NIE rozciąga się na całą szerokość: pełna szerokość czyta się
   jak akcja główna zakładki, a to jest akcja ostatnia i nieodwracalna. */
.wylog>button{width:auto;flex:0 0 auto;padding:0 var(--s4)}
.wylog span{font-size:11px;color:var(--txt-3);line-height:1.4;flex:1 1 200px}
.ghost.groźny{border-color:rgba(255,122,92,.45);color:var(--coral)}
.ghost.groźny:hover{border-color:var(--coral);background:rgba(255,122,92,.10)}

/* ══ LOGOWANIE KODEM Z POCZTY ════════════════════════════════════════════
   Drugie wejście na ekranie startowym: wyraźnie ciszej niż „Wejdź do gry",
   bo pierwsza wizyta ma iść tamtędy. */
.wejscia{display:flex;flex-direction:column;align-items:stretch;gap:var(--s2);
  margin-top:var(--s4);padding-top:var(--s3);border-top:1px solid var(--line)}
.wejscia>span{font-size:10px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--txt-3);text-align:center}
.mail-box{width:min(420px,92vw)}
.mailkrok{display:flex;flex-direction:column;gap:var(--s2)}
/* Sześć cyfr czyta się jako liczbę, nie jako słowo — stąd odstęp między
   znakami i cyfry o równej szerokości. */
.kodpole{text-align:center;font-size:26px;letter-spacing:.42em;font-weight:800;
  font-variant-numeric:tabular-nums;padding-left:.42em}

/* Stopka z dokumentami. Cicha z rozmysłem — ma być znaleziona, kiedy ktoś
   jej szuka, i niewidoczna, kiedy nie. */
.dokumenty{display:flex;gap:var(--s4);justify-content:center;margin-top:var(--s4)}
.dokumenty a{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--txt-3);text-decoration:none;border-bottom:1px solid transparent;
  transition:color var(--fast),border-color var(--fast)}
.dokumenty a:hover,.dokumenty a:focus-visible{color:var(--txt-2);border-color:var(--line)}

/* ══ `.hidden` NA SAMYM KOŃCU ARKUSZA ════════════════════════════════════
   To jest poprawka systemowa, nie kolejna łatka. `.hidden{display:none}`
   stoi w linii 220, a NIŻEJ jest sto czterdzieści kilka reguł ustawiających
   `display` — każda z nich ma tę samą specyficzność i wygrywa samą
   kolejnością. Objaw za każdym razem wygląda tak samo: element z klasą
   `hidden` jest widoczny.

   Załatano tak już `.over`, `#padHints`, `#hint` i `.pane` — cztery razy ten
   sam błąd, cztery osobne reguły. Piąty raz (kroki logowania pocztą, gdzie
   wszystkie trzy pokazywały się naraz) wystarczył za dowód, że problemem jest
   MIEJSCE, a nie żaden z tych selektorów.

   Powtórzenie na końcu arkusza wygrywa z wszystkim powyżej. Cztery starsze
   łatki są teraz zbędne, ale nieszkodliwe — zostawiam je, bo ich usunięcie
   to ryzyko bez zysku. */
.hidden{display:none}
