/* ══════════════════════════════════════════════════════════════════════
   Panel AIC CMS — warstwa APLIKACJI.

   Wszystko, co jest systemem, siedzi w ds.css i jest przeniesione 1:1
   z Design guidelines 0.1.32. Panel jest zbudowany z KOMPONENTÓW tamtego
   dokumentu, nie z jego makiet:

       .app-view   pole pracy — 24 tory, rynna 8, przewijanie w bok
       .app-bar    pasek akcji nad kontenerami
       .frame      kontener o stałej wysokości
       .fhead      nagłówek kontenera, pierwszy moduł
       .fbody      przewijane ciało kontenera
       .splitter   ruchoma granica w rynnie
       .abar       rząd odpowiedzi przy dolnej krawędzi

   Tutaj wchodzi wyłącznie to, czego system nie rozstrzyga, bo nie może:
   ile wysokości ma pole pracy w oknie przeglądarki, gdzie stoi stempel
   z nazwą aplikacji i gdzie lądują komunikaty. Każda reguła poniżej to
   dług wobec systemu — im ich mniej, tym lepiej, i każda ma napisane,
   dlaczego istnieje.
   ══════════════════════════════════════════════════════════════════════ */

html, body { height: 100%; }
body.panel { overflow: hidden; }

/* Odnośnik jest w tym panelu zwykłym elementem — bierze kolor stąd, gdzie
   stoi, i nie podkreśla się sam. Podkreślenie ma w systemie własne miejsce
   (.link) i to ono o nim mówi. */
a { color: inherit; text-decoration: none; }

/* ── WYSOKOŚĆ KONTENERA ──────────────────────────────────────────────
   `.frame` liczy swoją wysokość sam: okno minus margines górny i dolny,
   minus pasek dokumentu (--bar-h), minus pasek akcji z rynną pod nim
   (--top-bar). Panel nie ma paska dokumentu — guidelines mają go, bo są
   dokumentem — więc --bar-h schodzi do zera i wzór komponentu wychodzi
   na swoje bez jednej zmiany w nim samym. */
body.panel { --bar-h: 0px; }

/* Przełącznik widoku nigdy się nie ściska. Reguła paska mówi wprost:
   szerokości przycisków biorą się z etykiet i nie rozciągają się w wolne
   miejsce — a skoro tak, to i nie kurczą się poniżej etykiety. Kiedy
   prawa strona ma za dużo narzędzi, to ona chowa je w menu, a nie
   przełącznik oddaje litery. */
/* Przełącznik stoi przy lewej krawędzi pola pracy, bo nic go już stamtąd
   nie wypycha. Nie ściska się: szerokości biorą się z etykiet i nie
   rozciągają się w wolne miejsce, więc i nie kurczą poniżej etykiety. */
.app-bar .switch { flex: none; }
.app-bar .right { margin-left: auto; display: flex; align-items: center; gap: var(--el-gap); min-width: 0; }

/* Plakietka nieprzeczytanych siada w pozycji przełącznika. Odstęp bierze
   z gapu elementu, nic nowego nie wchodzi do skali. */
.switch .sw-opt .badge { margin-left: var(--el-gap); }
.switch .sw-opt[aria-selected="true"] .badge { background: var(--panel); color: var(--ink); }

/* ── KOLUMNA ZWINIĘTA DO SZYNY ───────────────────────────────────────
   Rozdział 16 opisuje ten stan na własnej makiecie (.lay-box), a nie na
   komponencie, bo to tam go pokazuje. Reguły są przepisane 1:1, tylko
   pod nazwę komponentu — i to jedyne miejsce w całym systemie, gdzie
   zachowanie zostało opisane na makiecie zamiast na rzeczy.

   Minimalizacja to nie zwężenie. Sześć torów to podłoga dla kontenera,
   KTÓRY PRACUJE; zwinięty przestaje pracować, więc ta podłoga go nie
   dotyczy — nie schodzi pod nią, tylko spod niej wychodzi. Rama 20
   zostaje, bo szyna nie jest pusta: niesie jedną rzecz, przycisk. */
.frame[data-min="true"] {
  min-width: 0;
  cursor: pointer;
  transition: background var(--dur-1) var(--ease);
}
.frame[data-min="true"] > .fhead > .n { display: none; }
.frame[data-min="true"] > .fbody,
.frame[data-min="true"] > .abar { display: none; }
/* W szynie zostaje JEDEN przycisk — ten, który ją otwiera. Narzędzia
   treści idą razem z treścią, bo bez niej nie mają czym rządzić. */
.frame[data-min="true"] > .fhead > .tools > :not(.mini) { display: none; }
.frame[data-min="true"]:hover { background: var(--el-hover); }

/* ── SZYNA NAWIGACJI ZOSTAJE NAWIGACJĄ ───────────────────────────────
   Wyjątek od reguły wyżej, i jedyny: zwinięty kontener TREŚCI przestaje
   pracować, więc chowa ciało. Nawigacja nie przestaje — jej praca polega
   na tym, żeby dało się stąd wyjść. Zwinięta do szyny oddaje słowa,
   zostawia glify: nadal widać, gdzie się jest i dokąd można pójść, a
   szerokość spada z ćwiartki pola do jednego elementu.

   Glif nie zna nazwy, więc nazwę oddaje `title` — kto nie rozpozna
   kształtu, dowie się po zatrzymaniu kursora. Kliknięcie w glif prowadzi
   dalej (ds.js nie rozwija kolumny, gdy trafiono w odnośnik); rozwija ją
   kliknięcie w puste miejsce szyny albo jej przycisk. */
.frame.is-nav[data-min="true"] > .fbody { display: block; }
/* Nagłówki grup („Treść”, „Serwis”) to same słowa — w szynie nie ma dla
   nich miejsca ani powodu. Zostaje po nich odstęp, żeby grupy nadal były
   trzema grupami, a nie jednym słupkiem. */
.frame.is-nav[data-min="true"] .ghead { display: none; }
.frame.is-nav[data-min="true"] .stack + .stack { margin-top: var(--sp-3); }
.frame.is-nav[data-min="true"] .row {
  width: var(--row-h); padding: 0;
  justify-content: center;
}
.frame.is-nav[data-min="true"] .row .txt,
.frame.is-nav[data-min="true"] .row .rt { display: none; }
.frame.is-nav[data-min="true"] .row .l { flex: none; justify-content: center; }
.frame.is-nav[data-min="true"] .row .ic-n { margin: 0; }
/* Liczba w plakietce nie zmieści się przy glifie, ale sam FAKT, że coś
   czeka, musi zostać — inaczej zwinięcie panelu ukrywałoby powiadomienia.
   Zostaje więc kropka w tonie sygnału, w rogu glifu. */
.frame.is-nav[data-min="true"] .row .l { position: relative; }
.frame.is-nav[data-min="true"] .row:has(.badge) .l::after {
  content: '';
  position: absolute; top: -1px; right: -1px;
  width: var(--sp-2); height: var(--sp-2);
  border-radius: 50%;
  background: var(--sig-2);
  box-shadow: 0 0 0 2px var(--panel);
}

/* Nazwa kontenera nie może rozpychać nagłówka — narzędzia mają swoje
   miejsce po prawej i trzymają je niezależnie od długości nazwy.
   Nagłówek w guidelines ma dwoje dzieci i wystarczy mu space-between;
   panel wkłada tam czasem troje (nazwa, wartość, narzędzia), więc luz
   bierze nazwa i wszystko po niej zostaje przy prawej krawędzi. */
.frame > .fhead > .n { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; margin-right: auto; }
.frame > .fhead > .v { flex: none; }
/* Nazwa kontenera z plakietką stanu tuż obok. Luz przejmuje opakowanie,
   żeby plakietka trzymała się nazwy, a nie odjeżdżała do narzędzi; nazwa
   w środku dalej ustępuje wielokropkiem, plakietka nigdy się nie zgniata. */
.frame > .fhead > .npill { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; margin-right: auto; }
.frame > .fhead > .npill > .n { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.frame > .fhead > .npill > .pill { flex: none; }
.frame > .fhead > .tools { flex: none; }

/* Przełącznik dwustanowy z podpisem — w narzędziach nagłówka. System daje
   sam tor (`.toggle`, 32 × 20) i nie mówi, skąd wiadomo, czego dotyczy;
   podpis staje więc przed nim, w tonie drugoplanowym i rozmiarze uwagi,
   bo to etykieta, a nie treść. Odstęp elementu (4) z jednej strony toru
   i pełny odstęp (8) z drugiej byłby fałszem — jedna miara dookoła. */
.tgl { display: inline-flex; align-items: center; gap: var(--sp-2); }
.tgl > .nm { font-size: var(--fs-1); line-height: var(--lh-1); color: var(--ink-2); white-space: nowrap; }
/* Ten sam przełącznik jako pierwszy wiersz ciała kontenera: bierze pełną
   szerokość, podpis po lewej, tor po prawej — czyli tak, jak stoi wiersz
   nastawy w tabeli. Wysokość elementu, żeby nie wypaść z rytmu modułów,
   i pełny odstęp pod spodem, bo to osobny blok, a nie pozycja listy. */
.tgl.is-row {
  display: flex; width: 100%;
  justify-content: space-between;
  height: var(--row-h); padding: 0 var(--el-pad);
  margin-bottom: var(--sp-4);
}

/* ── KOMUNIKATY ──────────────────────────────────────────────────────
   Alert systemu w roli snackbara. System opisuje, jak alert wygląda,
   ale nie mówi, gdzie leży, kiedy zjawia się sam — bo to zależy od
   aplikacji. Tutaj: lewy dolny róg pola pracy, na marginesie aplikacji,
   szerokość ośmiu torów jak modal. */
#says {
  position: fixed; z-index: 320;
  left: var(--m); bottom: var(--m);
  width: min(calc(8 * var(--col) + 7 * var(--gut)), calc(100vw - 2 * var(--m)));
  display: grid; gap: var(--row-gap);
  pointer-events: none;
}
#says .alert {
  pointer-events: auto;
  box-shadow: var(--shadow-2);
  opacity: 1;
  transition: opacity var(--dur-2) var(--ease);
}

/* ── EKRAN LOGOWANIA ────────────────────────────────────────────────
   Rozdział „Authentication” opisuje widok o szerokości 400 stojący na
   płótnie. Nie mówi, gdzie stoi na ekranie — tutaj: w środku okna. */
body.auth {
  display: grid; place-items: center;
  min-height: 100vh;
  overflow: auto;
}
body.auth .auth-view { margin: var(--sp-8) 0; }

/* ── ZDJĘCIE NA CAŁYM EKRANIE LOGOWANIA ──────────────────────────────
   Jedyne miejsce w panelu, gdzie wolno postawić fotografię: ekran
   logowania nie jest narzędziem pracy, tylko progiem, i może wyglądać jak
   próg. Zdjęcie kryje CAŁE okno (`cover`), stoi środkiem, nie powtarza
   się i nie jedzie przy przewijaniu — kiedy okienko urośnie na małym
   ekranie, tło ma zostać tłem, a nie wędrować.
   Nad zdjęciem kładziemy welon w barwie płótna: nie po to, żeby
   przyciemnić dla ozdoby, ale po to, żeby okienko o barwie panelu miało
   od czego odbić krawędź na KAŻDYM zdjęciu — jasnym i ciemnym. Kolor
   bierzemy z płótna, więc w trybie ciemnym ciemnieje razem z resztą.
   Trzydzieści procent to najmniej, ile wystarcza: zdjęcie ma zostać
   zdjęciem.
   Okienko dostaje przy tym cień — jedyny raz, kiedy go tu używamy, i z
   tego samego powodu, co przy przeciąganiu wiersza: rzecz UNIESIONA nad
   czymś rzuca cień, a karta logowania stoi nad fotografią, nie na
   płótnie.
   Zmienną `--auth-bg` wstawia PHP; bez niej cała reguła nie ma czego
   pokazać i ekran zostaje taki, jak był. */
body.auth[style*="--auth-bg"]::before {
  content: '';
  position: fixed; inset: 0; z-index: -1;
  background-image: linear-gradient(color-mix(in srgb, var(--canvas) 30%, transparent),
                                    color-mix(in srgb, var(--canvas) 30%, transparent)),
                    var(--auth-bg);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}
body.auth[style*="--auth-bg"] .auth-view { box-shadow: var(--shadow-2); }
/* Gniazdo znaku system wymierzył na napis wysoki na wiersz (36 px); nasz
   znak jest kwadratem 56 × 56, więc gniazdo musi mu ustąpić wysokość.
   PROMIEŃ ZERO, NA STAŁE: znak firmowy nie jest elementem interfejsu,
   tylko cudzą własnością o ustalonym kształcie. Nastawa „Promień" zmienia
   panel, nie logo — dlatego liczba stoi tu wprost, a nie przez `--r`. */
.auth-view .mark { height: auto; }
.auth-view .mark svg { display: block; width: 56px; height: 56px; border-radius: 0; }

/* ── MATERIAŁ PRZYCISKU WYGRYWA Z TONEM PODŁOŻA ──────────────────────
   Reguła „przycisk bierze ton przeciwny do tego, na czym stoi” dotyczy
   materiału DOMYŚLNEGO. Aktywny, sygnałowy i główny to materiały, które
   niosą znaczenie, więc muszą wygrywać z domyślnym. W ds.css reguła
   z rozdziału 16 stoi niżej i ma tę samą wagę, przez co je zjadała —
   to kolizja kolejności w źródle, nie decyzja projektowa.
   DO ZGŁOSZENIA w guidelines. */
.frame .button { background: var(--canvas); }
.frame .button.is-active,
.frame .button[aria-pressed="true"] { background: var(--ink); color: var(--panel); }
.frame .button.is-primary { background: var(--ink); color: var(--panel); }
.frame .button.is-signal { background: var(--s-1); color: var(--s-1-ink); }
.frame .button.is-panel { background: var(--panel); color: var(--ink); }
.frame .button.is-outline { background: none; }
.frame .button[disabled] { opacity: var(--off); cursor: default; pointer-events: none; }

/* ── NARZĘDZIE ───────────────────────────────────────────────────────
   System opisuje je tylko przy wierszu pliku (.frow .tool, rozdział 19),
   ale sytuacja jest ta sama wszędzie, gdzie stoi glif do klikania obok
   treści, a nie nad nią: bok równy wysokości wiersza, brak własnej
   powierzchni, zasłona 6% pod kursorem i 12% przy wciśnięciu. Definicja
   jest tu jedna i nie zna swojego rodzica — inaczej trzeba by ją pisać
   od nowa przy każdym nowym miejscu. */
.tool {
  width: var(--row-h); height: var(--row-h); flex: none;
  display: inline-grid; place-items: center;
  background: none; border: 0; padding: 0;
  color: var(--ink); cursor: pointer; border-radius: var(--r);
  transition: background var(--dur-1) ease;
}
.tool svg { width: var(--ic-m); height: var(--ic-m); display: block; }
.tool:hover { background: var(--veil-6); }
.tool:active,
.tool[aria-expanded="true"] { background: var(--veil-12); }
.tool:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
.tool[disabled] { opacity: var(--off); cursor: default; pointer-events: none; }

/* Rząd narzędzi przy prawej krawędzi wiersza oddaje ramę typu — rzecz
   o własnym kształcie staje przy samej krawędzi. */
.row .rt > .tools { display: flex; align-items: center; margin-right: calc(-1 * var(--el-pad)); }
/* Na wierszu wybranym narzędzia biorą atrament powierzchni, jak reszta. */
.row.is-live[aria-selected="true"] .tool { color: inherit; }
.row.is-live[aria-selected="true"] .tool:hover { background: color-mix(in srgb, var(--panel) 12%, transparent); }
/* W tabeli wiersz nie ma powierzchni, a komórka dokłada swoje 3 px pola —
   i tyle trzeba jej oddać, żeby glif stanął przy krawędzi tabeli. */
.trow .tools { display: flex; align-items: center; justify-content: flex-end; margin-right: calc(-1 * var(--cell-pad)); }

/* ── PUSTY KONTENER ──────────────────────────────────────────────────
   Mówi to słowem, nie pustką. */
.empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-2); padding: var(--sp-8) var(--el-pad);
  color: var(--ink-2); text-align: center;
  font-size: var(--fs-2); line-height: var(--lh-2);
}
.empty .gl { width: var(--ic-l); height: var(--ic-l); }

/* ── ZAKŁADKI W NAGŁÓWKU KONTENERA ───────────────────────────────────
   Most dla stron, które mają jeszcze własną podnawigację. Pasek zakładek
   bierze miejsce nazwy, więc musi umieć oddać je narzędziom po prawej. */

/* Ton metryczny tam, gdzie nie ma czego nazwać komponentem. */
.mut { color: var(--ink-2); }

/* ══ EDYTOR SEKCJI ═══════════════════════════════════════════════════
   Slot, klocek i pole obrazu to pojęcia APLIKACJI, nie systemu — nie ma
   ich w guidelines i nie ma czego stąd wziąć gotowego. Zbudowane więc
   z tego, co system ma: element, powierzchnia, moduł, wcięcie typu,
   ton z rampy. Ani jednej nowej liczby.
   ══════════════════════════════════════════════════════════════════ */

/* ── POLE WIELOWIERSZOWE ──
   System opisuje pole jednowierszowe (.f-box, rozdział 17) i osobno
   obszar tekstu przy starszym komponencie (.input, rozdział 3), gdzie
   pisze: „a whole number of modules, nothing in between”. Tutaj obie
   rzeczy spotykają się w jednej: anatomia z rozdziału 17, wysokość
   liczona wzorem 36n − 4 z rozdziału 3. Żadnej nowej wartości. */
/* Wysokość startowa zostaje modułowa (36n − 4), ale przestaje być
   sztywna: `height` zamienia się w `min-height`, a pole tekstowe dostaje
   uchwyt do ciągnięcia w pionie. To świadome odstępstwo od rytmu modułów
   — dopóki wysokość ustala system, trzyma się siatki; kiedy ciągnie ją
   człowiek, ważniejsze jest, żeby zobaczył całość tego, co pisze.
   W poziomie uchwytu nie ma: szerokość należy do kolumny formularza
   i nie wolno jej ruszać, bo wypadłaby z torów. */
.f-box.is-area {
  min-height: calc(var(--rows, 3) * var(--mod) - var(--row-gap));
  align-items: stretch;
  padding: var(--sp-2) var(--el-pad);
}
.f-box.is-area textarea {
  appearance: none; border: 0; background: none; outline: none; padding: 0;
  flex: 1; min-width: 0; width: 100%;
  resize: vertical;
  min-height: calc(var(--rows, 3) * var(--mod) - var(--row-gap) - 2 * var(--sp-2));
  color: var(--ink);
  font: var(--fw-reg) var(--fs-2)/var(--lh-2) var(--fam); letter-spacing: -.011em;
  user-select: text; -webkit-user-select: text;
}
.f-box.is-area textarea::placeholder { color: var(--ink-2); opacity: 1; }
/* Pole wyboru w formularzu bierze pełną szerokość kolumny, tak jak reszta. */
.f .menu.is-field, .blk .menu.is-field { width: 100%; }
.f .menu.is-field .sel, .blk .menu.is-field .sel { width: 100%; }

/* ── SLOT ──
   Slot jest GRUPĄ, więc bierze formę grupy: nagłówek `.ghead` z liczbą
   po prawej i lista pod nim. Powierzchni własnej nie ma — grupa w tym
   systemie nigdy jej nie ma. */
.slot { padding-top: var(--row-gap); }
.slot > .f-msg { padding-inline: var(--el-pad); }

/* ── ZAGADNIENIE WSADU ──
   Grupa, którą da się usunąć. Nagłówek zwija ją na całą szerokość, więc
   narzędzie nie może w nim stać — kładzie się na jego prawym końcu,
   w tym samym rzędzie wysokości elementu. Nagłówek oddaje mu miejsce
   wcięciem, żeby długa nazwa nie weszła kosza pod spód. */
.zag { position: relative; }
.zag > .ghead { padding-right: calc(var(--row-h) + var(--sp-2)); }

.zag > .zx { position: absolute; top: 0; right: 0; }

/* ── KLOCEK ──
   Element wpuszczony w powierzchnię kontenera: ton panel-2, wcięcie
   typu 12, promień systemu, odstęp wiersza między polami. */
.blk {
  background: var(--panel-2); border-radius: var(--r);
  padding: var(--el-pad);
  display: flex; flex-direction: column; gap: var(--row-gap);
}
/* Rząd nagłówkowy klocka to zwykły wiersz: 32, nazwa po lewej,
   narzędzie po prawej przy samej krawędzi. */
.blk > .blk-head {
  height: var(--row-h); flex: none;
  display: flex; align-items: center; justify-content: space-between;
  margin: calc(-1 * var(--el-pad)) calc(-1 * var(--el-pad)) 0;
  padding-left: var(--el-pad);
}
.blk > .blk-head .nm { font-size: var(--fs-1); line-height: var(--lh-1); color: var(--ink-2); }
.blk .f { margin: 0; }
.addblk { display: flex; align-items: flex-end; gap: var(--row-gap); }
.addblk .menu.is-field { flex: 1; min-width: 0; }
/* „Dodaj" nie należy do klocka nad sobą — zaczyna następny. Stoi więc
   32 px niżej (`--sp-7`, wysokość elementu), żeby było widać, że kończy
   listę, a nie dopisuje się do ostatniej pozycji. */
.addblk { margin-top: var(--sp-7); }

/* ── POLE OBRAZU ──
   Strefa `.drop` i wiersz pliku `.frow` to komponenty rozdziału 19,
   wzięte bez zmian. Dokłada się jedno: podgląd z punktem skupienia,
   bo obraz zawsze wypełnia obszar i ktoś musi powiedzieć, co w kadrze
   jest ważne. Podgląd ma pięć modułów wysokości — 5 × 36 − 4 = 176 —
   i ton płótna, bo jest powierzchnią wpuszczoną w kontener, tak samo
   jak strefa nad nim. */
.imgfield { display: flex; flex-direction: column; gap: var(--row-gap); }
.i-shot { display: flex; flex-direction: column; gap: var(--row-gap); }
.i-shot[hidden], .i-drop[hidden] { display: none; }
.i-stage {
  position: relative;
  height: calc(5 * var(--mod) - var(--row-gap));
  border-radius: var(--r); overflow: hidden;
  background: var(--canvas); cursor: crosshair;
}
/* Wyrównanie stoi POD podglądem — najpierw widać, co się wyrównuje.
   Pięć skrótów plus „własny" mieści się w wierszu; przy wąskim panelu
   przełącznik zawija się, zamiast wypychać kolumnę formularza. */
.i-align { max-width: var(--measure); }
.i-align .switch { width: 100%; flex-wrap: wrap; height: auto; }
.i-align .sw-opt { flex: 1 0 auto; height: calc(var(--row-h) - 2 * var(--sp-1)); }
/* „Własny" nie jest wyborem, tylko stwierdzeniem faktu: zapala się, kiedy
   punkt postawiono kliknięciem. Klikać go nie ma po co. */
.i-align .i-own { pointer-events: none; opacity: var(--off); }
.i-align .i-own[aria-selected="true"] { opacity: 1; }
.i-stage img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Punkt skupienia: koło wielkości glifu, w tonie powierzchni, obwiedzione
   najciemniejszym tonem rampy — czytelne i na jasnym, i na ciemnym
   zdjęciu, bo zdjęcie nie zna trybu. */
.i-dot {
  position: absolute; width: var(--ic-m); height: var(--ic-m);
  border: 2px solid var(--t1); border-radius: 50%;
  box-shadow: 0 0 0 1px var(--t10);
  transform: translate(-50%, -50%); pointer-events: none;
}
.i-tools { display: flex; align-items: center; gap: var(--row-gap); }
.i-up { cursor: pointer; }

/* ── MIARA KOLUMNY FORMULARZA ────────────────────────────────────────
   System ma na to własny token: `--measure`, czyli dwanaście torów
   z rynnami — miara wiersza tekstu. Pole rozciągnięte na osiemnaście
   torów przestaje być polem, a 420 px z rozdziału 17 to miara widoku
   logowania, nie panelu. Bierzemy tę, która skaluje się razem z polem
   pracy. */
.frame .f, .frame .chk { max-width: var(--measure); }
.blk .f { max-width: none; }

/* ── WIĘCEJ POWIETRZA W FORMULARZU ───────────────────────────────────
   Stos rozdziela swoje dzieci rynną elementu (4 px) — dobrą miarą dla
   wierszy listy, które są jednym ciągiem rzeczy tego samego rodzaju.
   Pole formularza jest czymś innym: ma nad sobą etykietę, a pod sobą
   bywa uwagę, więc cztery piksele zlepiały etykietę następnego pola
   z polem poprzednim.

   Odstępy niesie ten, KTO SIĘ KOŃCZY, a nie ten, kto się zaczyna:
   pole i checkbox oddzielają się od tego, co pod nimi, własnym
   wypełnieniem (16), stos domyka się ósemką, a wnętrze grupy — znów
   szesnastką. Dzięki temu nic nie zależy od sąsiedztwa i nie ma
   marginesów, które trzeba by potem znosić przy pierwszym albo ostatnim
   elemencie. Górny margines grupy z nagłówkiem znika: odstęp nad nią
   należy do bloku, który stoi wyżej. */
.frame .f, .frame .chk { padding-bottom: var(--sp-4); }
/* Uwaga pod polem należy do TEGO pola, więc domyka się mniejszą miarą
   (12) niż samo pole (16) — inaczej odklejałaby się od rzeczy, którą
   objaśnia, i zaczynała wyglądać na osobny akapit. */
.f-msg { padding-bottom: var(--sp-3); }
.stack + .stack.titled { margin-top: 0; }
.stack { padding-bottom: var(--sp-2); }
.stack .fold > .inner { gap: var(--sp-4); padding-bottom: var(--sp-4); }

/* ── NAWIGACJA TO NIE FORMULARZ ──────────────────────────────────────
   Ta sama klasa, inna treść: w grupie nawigacji stoją WIERSZE — rzeczy
   jednego rodzaju w ciągu, między którymi obowiązuje rynna elementu (4).
   Szesnastka rozsypywała listę pozycji na osobne klocki i kazała wodzić
   okiem po pustym panelu. Odstęp POD grupą zostaje pełny, bo rozdziela
   „Treść" od „Serwisu" — czyli dwie różne rzeczy, a nie dwie pozycje
   tej samej. */
.frame.is-nav .stack .fold > .inner { gap: var(--sp-1); }

/* ── NAGŁÓWEK GRUPY CZYTELNY ─────────────────────────────────────────
   System daje mu 11 px, bo widzi w nim etykietę kilku pól. W tym panelu
   nagłówek grupy nazywa CZĘŚĆ TREŚCI — sekcję wpisu, blok ustawień,
   zagadnienie wsadu — i po tych nazwach człowiek się porusza, więc musi
   je czytać, a nie odcyfrowywać. Idzie na rozmiar tekstu bieżącego
   (14/20); wysokość wiersza nagłówka i ton zostają systemowe. */
.ghead { font-size: var(--fs-2); line-height: var(--lh-2); }

/* ── PASEK ODPOWIEDZI JEST SZEROKI NA TYLE, ILE NIESIE ───────────────
   `.abar` rozciągał się na całą szerokość kontenera i dosuwał przyciski
   do prawej krawędzi wyrównaniem. Wynik był ten sam, ale sam pasek
   przykrywał całą szerokość i łapał kliknięcia tam, gdzie nic nie stoi.
   Bierze więc szerokość swojej treści, a do prawej krawędzi dochodzi
   marginesem — to samo miejsce, mniej pola. */
.abar { width: max-content; max-width: 100%; margin-left: auto; }

/* ── …A KIEDY NIE MIEŚCI SIĘ W JEDNYM RZĘDZIE, ŁAMIE SIĘ ─────────────
   Panel szczegółów wpisu potrafi teraz podać pięć odpowiedzi naraz
   (Podgląd · Edytuj · Usuń · Zapisz · Cofnij publikację), a kontener
   ma tam sześć torów. Bez łamania ostatni przycisk był ścinany krawędzią.
   Rzędy schodzą w dół z tym samym odstępem co przyciski obok siebie,
   a `justify-content` trzyma je przy prawej krawędzi — czyli tam,
   gdzie stały. */
.abar { flex-wrap: wrap; row-gap: var(--row-gap); }

/* ── OKIENKO SZEROKIE NA TYLE, ILE NIESIE ────────────────────────────
   Ośmiotorowa szerokość na sztywno robiła z pytania „czy na pewno?"
   płachtę z dwoma zdaniami pośrodku. Szerokość jest więc automatyczna:
   okienko mierzy się do własnej treści. Podłoga zostaje — ćwiartka pola
   (6 torów, tyle co podłoga kontenera) — bo formularz węższy od niej
   przestaje być formularzem. Sufitu z torów nie ma; jedyne ograniczenie
   to szerokość okna pomniejszona o margines strony, i to nie jest
   decyzja projektowa, tylko warunek, żeby okienko w ogóle się zmieściło
   (system liczy tak samo w swojej regule). */
.modal {
  width: auto;
  min-width: min(calc(6 * var(--col) + 5 * var(--gut)), calc(100vw - 2 * var(--m)));
  max-width: calc(100vw - 2 * var(--m));
}

/* ── PRAWA STRONA WIERSZA ODDYCHA ÓSEMKĄ ─────────────────────────────
   Plakietka, metryka i glif stoją obok siebie z rynną elementu (4) —
   tyle, ile dzieli części JEDNEJ rzeczy. To są jednak trzy osobne
   informacje o wierszu, nie trzy kawałki tej samej, więc dostają pełny
   odstęp elementu (8) i przestają się czytać jak jeden ciąg. */
.row .rt { gap: var(--sp-2); }

/* ── OBRAMOWANIE FOCUSU MA GDZIE STANĄĆ ──────────────────────────────
   System rysuje pierścień focusu NA ZEWNĄTRZ pola: 1,5 px w polu, 2 px
   przerwy w tonie podłoża i 2 px pierścienia — razem 4 px poza krawędzią.
   Ciało kontenera przewija się, a element przewijany przycina wszystko,
   co wychodzi poza jego pole wypełnienia: pierwsze i ostatnie pole
   traciło pierścień od góry i od dołu, a każde — od lewej i prawej.

   Nie ruszamy pierścienia: dokładamy ciału cztery piksele wypełnienia
   i odbieramy je marginesem ujemnym. Ciało robi się o osiem pikseli
   szersze i wyższe, ale jego TREŚĆ stoi dokładnie tam, gdzie stała —
   więc siatka torów i rytm modułów zostają nietknięte. Ta sama rzecz
   dotyczy ciała okienka, które też się przewija.

   Jedyny skutek uboczny: zapytania kontenerowe (`.fbody` nazywa się
   `body`) mierzą teraz o 8 px więcej, czyli ustępowanie metryki i
   plakietek zaczyna się o 8 px wcześniej. */
.fbody, .modal .mbody { margin: calc(-1 * var(--el-gap)); padding: var(--el-gap); }

/* ── PODGLĄD SEKCJI ──────────────────────────────────────────────────
   Kawałek STRONY wpuszczony w panel: bierze powierzchnię panelu i linię
   dookoła, żeby było widać, gdzie kończy się narzędzie, a zaczyna to, co
   zobaczy czytelnik. Bez tej granicy recenzent ocenia kompozycję na tle,
   którego na stronie nie będzie. */
.secprev {
  border-radius: var(--r); overflow: hidden;
  background: var(--panel);
  outline: var(--line-w) solid var(--line); outline-offset: calc(-1 * var(--line-w));
}
.secprev > * { max-width: 100%; }
.secprev img { max-width: 100%; height: auto; }
/* Ramka z prawdziwą stroną bierze wysokość modułami — dwanaście modułów
   to tyle, ile mieści się nad polem uwag bez chowania go pod zgięciem. */
.secprev iframe { display: block; width: 100%; height: calc(12 * var(--mod)); border: 0; background: var(--panel); }

/* ── WIERSZ ZAGNIEŻDŻONY ─────────────────────────────────────────────
   Drzewo kategorii to zwykła lista wierszy, a poziom zagnieżdżenia —
   wcięcie o jeden moduł typu. Bez własnego gatunku elementu: gałąź nie
   jest czymś innym niż liść, stoi tylko dalej od krawędzi. */
.row.is-nest { padding-left: calc(var(--sp-3) + var(--depth, 0) * var(--sp-5)); }

/* ── BLOKI W CIELE OKIENKA ───────────────────────────────────────────
   Okienko bywa złożone z kilku osobnych formularzy — każdy odpowiada za
   jedną czynność, bo jedna czynność to jeden zapis. Rozdziela je ta sama
   rynna, co pola w stosie; dopiero tabela i uwaga biorą pełny odstęp
   bloku, bo mówią o czymś innym niż pola nad nimi. */
.modal .mbody > form + form { margin-top: var(--row-gap); }

/* ── PRZEŁĄCZNIK NA CAŁĄ SZEROKOŚĆ ───────────────────────────────────
   Przełącznik bierze u siebie `width: max-content`, bo zwykle stoi obok
   czegoś i ma się nie rozpychać. Tutaj jest inaczej: trzy drogi do
   adresu to jedyna treść swojego wiersza i stoją nad polem, które
   opisują. Rozciągnięty na szerokość pola wiąże się z nim wzrokowo,
   a jego pozycje dzielą się po równo — nie trzeba było poszerzać
   okienka, bo problemem była szerokość przełącznika, nie okna.
   (Wcześniejsza próba `.modal.is-wide` na 12 torów robiła okno za duże.) */
.switch.lm-src { width: 100%; }
.modal .mbody > form + .table,
.modal .mbody > .table + .f-msg,
.modal .mbody > form + .f-msg { margin-top: calc(var(--mod) + var(--row-gap)); }

/* ── FORMULARZ JAKO BLOK CIAŁA KONTENERA ─────────────────────────────
   Reguła z czasów, kiedy odstępy niósł ten, kto się ZACZYNAŁ: formularz
   po ostrzeżeniu albo po stosie dostawał górny margines, bo nic nie
   odsuwało go od poprzednika. Dziś odstęp niesie ten, kto się KOŃCZY —
   stos domyka się sam (`padding-bottom`), pole i checkbox też — więc
   górny margines dokładał drugą miarę do tej samej przerwy. Zostaje
   zerowy; selektor trzymamy, żeby było widać, że to decyzja, a nie
   przeoczenie. */
.fbody > .alert + form,
.fbody > .f-msg + form,
.fbody > .stack + form,
.fbody > form + .stack { margin-top: 0; }
/* Uwaga pod ostrzeżeniem to nadal ta sama wiadomość — oddziela je rynna
   wiersza, a nie pominięty moduł. */
.fbody > .alert + .f-msg,
.fbody > .f-msg + .f-msg { margin-top: var(--row-gap); }
/* Uwaga pod listą mówi o niej, ale nie należy do niej — oddziela ją
   pominięty moduł, tak jak każdy inny blok. */
.fbody > .stack + .f-msg { margin-top: calc(var(--mod) + var(--row-gap)); }

/* ── WIERSZ, KTÓRY JEST PRZYCISKIEM ──────────────────────────────────
   `.row` bywa w systemie elementem klikalnym i wtedy jest <button> albo
   <a> — tak jest w spisie treści samych guidelines. Reset stoi tam
   w rozdziale dokumentu (`#toc .row{border:0}`), więc przy przenoszeniu
   został po tamtej stronie i wiersz-przycisk zostawał z ramką i krojem
   przeglądarki. Reset należy do komponentu, nie do dokumentu. */
button.row, a.row, button.trow, a.trow {
  border: 0; margin: 0; width: 100%;
  font: var(--fw-reg) var(--fs-2)/var(--lh-2) var(--fam);
  letter-spacing: -.011em;
  color: var(--ink); text-align: left; text-decoration: none;
  -webkit-appearance: none; appearance: none;
}
button.row, a.row { background: var(--panel-2); }
button.trow, a.trow { background: none; }

/* ── NAWIGACJA JAKO KONTENER ─────────────────────────────────────────
   Glif pozycji nawigacji stoi tam, gdzie każda rzecz o własnym kształcie
   w wierszu: (32 − 16) / 2 od krawędzi powierzchni, a etykieta odsuwa się
   od niego o tę samą miarę — glif waży wzrokowo mniej niż koło awatara,
   więc przy podwojonym odstępie odkleiłby się od słowa. */
.ic-n {
  width: var(--st-size); height: var(--st-size); flex: none;
  display: grid; place-items: center; color: var(--ink-2);
  margin-left: calc((var(--row-h) - var(--st-size)) / 2 - var(--el-pad));
  margin-right: calc((var(--row-h) - var(--st-size)) / 2 - var(--el-gap));
}
.ic-n svg { width: var(--ic-m); height: var(--ic-m); display: block; }
.row[aria-selected="true"] .ic-n { color: inherit; }
.frame.is-nav .rt .badge { margin-right: calc((var(--row-h) - var(--st-size)) / 2 - var(--el-pad)); }
/* Nawigacja nie potrzebuje liczby w nagłówku ani narzędzi treści —
   zostaje sama nazwa i przycisk kontenera. */
.frame.is-nav .fbody { scrollbar-width: none; }

/* ── OKRUSZKI W PASKU ────────────────────────────────────────────────
   Pasek leży na płótnie, więc ścieżka bierze ton metryczny, a ostatni
   człon — pełny atrament, bo to on mówi, gdzie się stoi. */
.app-bar .crumbs { flex: none; min-height: var(--row-h); padding-right: var(--sp-3); }
/* Ścieżka miesza człony klikalne i nieklikalne — grupa („Treść") nigdzie
   nie prowadzi. System daje `.crumb` kursor łapki i podkreślenie pod
   kursorem, bo zakłada odnośnik; człon, który nie jest odnośnikiem ani
   miejscem, w którym się stoi, musi to obietnicę cofnąć. */
.app-bar .crumb:not(a):not([aria-current="page"]) { cursor: default; }
.app-bar .crumb:not(a):not([aria-current="page"]):hover { color: var(--ink-2); text-decoration: none; }

/* ── WIERSZ NASTAWY ──────────────────────────────────────────────────
   Etykieta po lewej, sterownik po prawej. Przełącznik ma wysokość
   elementu, więc jego wcięcie graficzne wynosi zero — staje przy samej
   krawędzi i oddaje ramę typu. */
.modal .row .rt > .switch,
.modal .row .rt > .menu { margin-right: calc(-1 * var(--el-pad)); }
.modal .row .rt > .menu .sel { min-width: calc(6 * var(--sp-5)); }

/* ── ZAZNACZONY WIERSZ POD KURSOREM ──────────────────────────────────
   BŁĄD W ŹRÓDLE GUIDELINES, i to widoczny gołym okiem.

   `.row.is-live:not(.is-lift):hover` ma wagę (0,4,0), bo `:not()` dolicza
   swój argument, a `.row.is-live[aria-selected="true"]` tylko (0,3,0).
   Najechanie wygrywa więc TŁO, ale nie wygrywa ATRAMENTU — i zaznaczony
   wiersz pod kursorem dostaje jasny ton t3 pod jasnym atramentem t1.
   Zmierzone: 1,35 : 1. Wiersz, na który się właśnie patrzy, przestaje
   być czytelny dokładnie w chwili, gdy się w niego celuje.

   Rozstrzygnięcie jest w samym systemie, tylko napisane dla panelu menu:
   „naraz świeci jedna rzecz”. Tam ustępuje zaznaczenie, bo w menu wybiera
   się coś nowego. W liście jest odwrotnie: zaznaczenie mówi, nad czym
   pracuję TERAZ, a najechanie tylko, nad czym mógłbym za chwilę — więc to
   teraźniejszość wygrywa i wiersz zostaje na swoim tonie.
   DO ZGŁOSZENIA w guidelines. */
.row.is-live[aria-selected="true"]:hover,
.tile.is-live[aria-selected="true"]:hover {
  background: var(--el-sel);
  color: var(--panel);
}
.row.is-live[aria-selected="true"]:hover .m,
.row.is-live[aria-selected="true"]:hover .s,
.tile.is-live[aria-selected="true"]:hover .m,
.tile.is-live[aria-selected="true"]:hover .s { color: inherit; opacity: .65; }

/* ── CO USTĘPUJE PRZY SKALI 1,5× ─────────────────────────────────────
   LUKA W ŹRÓDLE GUIDELINES. Reguła „co ustępuje, gdy brakuje miejsca”
   jest w ds.css zapisana z twardym wyłączeniem dla dużej skali:

       @container body (max-width: 300px){
         body:not([data-scale="large"]) .row .rt .m{display:none} }

   Zamiar był słuszny — progi 300 / 250 / 200 są liczone dla elementu
   32 px i przy elemencie 48 px znaczyłyby co innego. Skutek jest jednak
   taki, że przy 1,5× nie ustępuje NIC: wiersz przestaje się mieścić
   i kontener zaczyna przewijać się w bok, czego system nigdzie nie
   przewiduje wewnątrz kontenera.

   Progi wracają, przemnożone przez ten sam współczynnik, co reszta skali:
   300 → 450, 250 → 375, 200 → 300. Kolejność ustępowania bez zmian —
   najpierw metryka, potem plakietki, na końcu mały podpis; nazwa nigdy.
   DO ZGŁOSZENIA w guidelines. */
@container body (max-width: 450px) {
  body[data-scale="large"] .row .rt .m { display: none; }
}
@container body (max-width: 375px) {
  body[data-scale="large"] .row .rt .pill { display: none; }
}
@container body (max-width: 300px) {
  body[data-scale="large"] .row .txt .s { display: none; }
}
/* Kontener nigdy nie przewija się w bok — od tego jest ustępowanie.
   W poziomie zostaje przycięcie, żeby jedna za długa rzecz nie zamieniła
   panelu w karuzelę. */
.frame > .fbody { overflow-x: hidden; }

/* ── LEWA STRONA WIERSZA MUSI UMIEĆ USTĄPIĆ ──────────────────────────
   CZWARTA LUKA W ŹRÓDLE. `.row .txt` dostało `min-width:0`, ale `.row .l`
   — kontener, w którym `.txt` stoi — już nie. Element elastyczny bez tego
   nie schodzi poniżej rozmiaru swojej treści, więc nazwa nie oddaje
   miejsca i to PRAWA strona wiersza wychodzi poza kontener: przy skali
   1,5× o 34 px, przy 1× wszędzie tam, gdzie tytuł jest długi.

   Reguła „nazwa jest ostatnia, która zaczyna się skracać” działa dopiero
   wtedy, kiedy jest czym się skracać. Ten sam brak dotyczy `.rt`, więc
   dostaje `flex:none` — prawa strona niesie plakietkę i liczbę, a te mają
   nie ustępować miejsca, tylko znikać w kolejności opisanej przez system.
   DO ZGŁOSZENIA w guidelines. */
.row .l { min-width: 0; }
.row .rt { flex: none; }
.tile .top .l { min-width: 0; }

/* ── LISTA, KTÓREJ SIĘ NIE KLIKA ─────────────────────────────────────
   Powierzchnia elementu znaczy w tym systemie „to się klika”. Rzecz,
   która tylko niesie informację, nie może jej mieć — inaczej obiecuje
   ruch, którego nie wykona. System ma na to gotową odpowiedź i nazywa ją
   tabelą: „lista, która dzieli się KRESKĄ zamiast odstępem”, a wiersz
   tabeli nie ma własnej powierzchni, bo powierzchnia i kreska dzieliłyby
   to samo dwa razy.

   Dlatego wszystkie pary nazwa → wartość — metryka wpisu, stan, nastawy
   wyglądu — stoją w `.table`, a nie w `.stack` wierszy. Sterownik po
   prawej stronie takiego wiersza oddaje ramę typu, jak każda rzecz
   o własnym kształcie przy krawędzi. */
/* Kolumna wartości bierze tyle, ile potrzebuje — ale musi umieć ustąpić.
   Samo `max-content` żąda pełnej szerokości tekstu i w wąskim kontenerze
   zgniata nazwę do zera; `minmax(0, max-content)` daje to samo, kiedy jest
   miejsce, i pozwala się skurczyć, kiedy go nie ma. */
/* Wiersz tabeli ma stałą wysokość elementu (32) i kreskę u góry — treść
   siedziała więc tuż pod kreską, przyklejona do wiersza wyżej. Ósemka
   wypełnienia u góry odsuwa ją od granicy; pierwszy wiersz kreski nie ma,
   więc i wypełnienia nie dostaje.
   Wysokość rośnie o tyle samo: pudełko liczy się od krawędzi
   (`box-sizing: border-box`), więc samo wypełnienie ZJADŁOBY osiem
   pikseli z pola elementu i sterownik 32 wyszedłby poza wiersz. */
.trow + .trow {
  padding-top: var(--sp-2);
  height: calc(var(--row-h) + var(--sp-2));
}
.table.is-kv { grid-template-columns: minmax(0, auto) minmax(0, max-content); }
.table.is-kv .trow > *:last-child { text-align: right; }
.table.is-kv .trow .ctl { display: flex; align-items: center; justify-content: flex-end; }
.table.is-kv .trow .ctl > * { margin-right: calc(-1 * var(--cell-pad)); }
/* Wiersz stanu niesie glif, nazwę i plakietkę — glif staje przy krawędzi
   tabeli, więc oddaje jej pole komórki. */
.table.is-kv .trow > .lbl { display: flex; align-items: center; gap: var(--el-gap); min-width: 0; }
.table.is-kv .trow > .lbl > .ic {
  flex: none;
  margin-left: calc(-1 * var(--cell-pad));
  margin-right: calc((var(--row-h) - var(--st-size)) / 2 - var(--el-gap));
}

/* Nastawy wyglądu to jedyna tabela, w której KAŻDY wiersz niesie
   sterownik o własnym kształcie — przełącznik albo pole wyboru. Sześć
   takich kształtów jeden pod drugim, stykających się krawędziami, czyta
   się jak jedna plama, bo kreska między wierszami biegnie tuż przy nich.
   Odstępem rozdzielamy kształty, a kreska zostaje — dzieli treść,
   odstęp daje jej oddech. Kreska rysuje się cieniem wewnętrznym u góry
   wiersza, więc po rozsunięciu siada w połowie przerwy i nadal wygląda
   jak granica, a nie jak podkreślenie.

   Szerokość: to okienko trzyma sześć krótkich wierszy i jedną uwagę na
   dole. Bez sufitu mierzy się do najdłuższego zdania tej uwagi i robi
   się szerokie na pół ekranu — a wtedy między nazwą nastawy a jej
   sterownikiem zieje pustka. Wracamy więc do miary okienka z systemu
   (osiem torów) — punktowo, dla tego jednego okienka, bo tu o szerokości
   decyduje formularz, a nie akapit pod nim. */
#mPrefs { max-width: min(calc(8 * var(--col) + 7 * var(--gut)), calc(100vw - 2 * var(--m))); }
#mPrefs .table.is-kv { row-gap: var(--sp-2); }

/* ── TRZY DROGI DO ADRESU ────────────────────────────────────────────
   Pola źródła adresu chowają się atrybutem `hidden`, ale `hidden` to
   tylko `display:none` z arkusza przeglądarki — każda własna reguła
   `display` je bije, a `.f` i `.drop` takie mają. System rozwiązuje to
   u siebie tak samo (`.stack > [hidden]`), więc i tutaj wystarczy reguła
   o wyższej wadze, bez `!important`. */
.lm-adres [data-src][hidden] { display: none; }

/* ── MINIATURY WSADU ─────────────────────────────────────────────────
   Materiały redaktora oglądamy w siatce dwóch kolumn: miniatura wysoka
   na dwa moduły, pod nią nazwa i narzędzia. Ostatnia rzecz przeniesiona
   z mostu — most zniknął razem z nią. */
.thumb {
  display: inline-flex; align-items: center; justify-content: center;
  width: 100%; height: calc(2 * var(--mod) - var(--row-gap));
  border-radius: var(--r); overflow: hidden;
  background: var(--canvas); flex: 0 0 auto;
}
.thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.thumb .vid { font-size: var(--fs-1); line-height: var(--lh-1); color: var(--ink-2); }
.medgrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--row-gap); }
.medcell { display: flex; flex-direction: column; gap: var(--el-gap); min-width: 0; }

/* ── WSAD DO SKOPIOWANIA ─────────────────────────────────────────────
   Tekst wsadu jest po to, żeby go wziąć i wkleić w sekcję. Skoro jego
   jedynym przeznaczeniem jest kliknięcie, to musi wyglądać jak rzecz do
   kliknięcia: bierze powierzchnię elementu (`--panel-2`, ten sam ton,
   co wiersz listy), promień systemu i ton najechania. Nie jest wierszem
   — wiersz ma jedną wysokość, a tu tekst ma tyle linijek, ile ma myśl —
   więc bierze tylko jego materiał, nie jego kształt.

   Zachowuje łamania wpisane przez redaktora: to on decyduje, gdzie
   kończy się zdanie. */
.brief-field { display: flex; flex-direction: column; gap: var(--sp-1); }
.brief-text {
  white-space: pre-line; margin: 0;
  font: var(--fw-reg) var(--fs-2)/var(--lh-2) var(--fam); letter-spacing: -.011em;
  text-align: left; color: var(--ink);
  padding: var(--sp-2) var(--el-pad);
  background: var(--panel-2); border: 0; border-radius: var(--r);
  display: block; width: 100%;
}
button.brief-text {
  cursor: copy;
  transition: background var(--dur-1) ease;
}
button.brief-text:hover { background: var(--el-hover); }
button.brief-text:active { background: var(--el-hover); }
button.brief-text:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
/* Ślad po skopiowaniu — jedno mrugnięcie tonem zaznaczenia, żeby było
   wiadomo, że kliknięcie zrobiło cokolwiek. Komunikat i tak przychodzi
   snackbarem, ale on stoi w rogu, a potwierdzenie ma być tam, gdzie
   patrzy oko. */
button.brief-text.is-copied { background: var(--el-sel); color: var(--panel); }
.medcell .i-tools { justify-content: flex-start; }
