/* learn — konsola do mowienia.
 *
 * Pomysl: czarna plyta czolowa z jednym zrodlem swiatla. Swieci wylacznie przycisk
 * nadawania; zdanie do wypowiedzenia jest wysrodkowane i skladane szeryfem, bo to
 * material jezykowy, a nie element interfejsu. Cala reszta chromu jest wyciszona.
 * Kolor swiatla niesie informacje: zielen = angielski, bursztyn = hiszpanski.
 *
 * Czern, wysrodkowanie i zielen odpowiedzi sa przejete ze starszej strony uzytkownika
 * (~/old_www/angielski), ktorej uklad sprawdzil sie w praktyce.
 *
 * ZASADY I TOKENY: ../DESIGN.md. Nie dobieraj tu wartosci na oko — powierzchnie,
 * promienie i barwy znaczen maja tokeny i tylko one wchodza do regul.
 */

:root {
  /* Powierzchnie. Skok miedzy warstwami liczony w L* (CIELab), bo stosunek kontrastu
     miedzy dwiema czerniami zawsze wychodzi ~1,1:1 i nie mowi nic. Tlo 3,6 -> karta 10,6
     (skok 7,0, tyle co we wzorcu z DESIGN.md) -> powierzchnia podniesiona 16,4.
     Do 2026-09-09 bylo #000 / #101010, czyli skok 4,7 — praktycznie niewidoczny na
     telefonie. Dlatego karty musialy miec obrysy, a sekcje raportu wlasne, jasniejsze
     tlo. Elewacja jest teraz realna i te protezy zniknely. */
  --bg: #0B0D0F;
  --bg-2: #191D22;
  --bg-3: #242930;
  --line: #313740;
  --text: #FFF;
  --muted: #8E9297;      /* 6,22:1 na tle, 5,41:1 na karcie, 4,68:1 na --bg-3 */

  /* Barwy znaczen. Jeden token na znaczenie, nie powtarzany hex przy kazdej regule —
     tryb jasny podmienia wtedy jedna linijke zamiast szesciu. */
  --good: #2ECC40;
  --half: #FFA724;
  --rec: #FF5252;

  /* Geometria: siatka 4 px, trzy promienie i pigulka. */
  --r-s: 12px;
  --r-m: 16px;
  --r-l: 20px;
  --r-pill: 999px;

  /* Jeden akcent na cala aplikacje. Do 2026-09-09 barwa szla za jezykiem (zielen =
     angielski, bursztyn = hiszpanski) — interfejs zmienial sie wiec pod uzytkownikiem
     i zielen zdominowala wszystko. Jezyk mowi teraz plakietka w pasku sesji, a nie
     kolor calego ekranu. */
  --orb-hi: #FFA35C;     /* jasny koniec gradientu tarczy */
  --orb-lo: #C4551A;     /* ciemny koniec */
  --orb-ink: #1A0F06;    /* tekst i ikony NA akcencie — 5,84:1 */
  --accent: #E86A1F;     /* 6,04:1 na tle, 5,25:1 na karcie */

  /* Aplikacja jest ciemna zawsze. Bez tego przegladarka na komputerze rysuje wlasnym
     jasnym motywem pola formularza, paski przewijania i tlo poza obszarem strony. */
  color-scheme: dark;

  --serif: "Newsreader", Georgia, "Times New Roman", serif;
  --sans: -apple-system, "Segoe UI", Roboto, system-ui, sans-serif;

  /* Barwy belki (uklad siedzi w belka.css, wspolnym z panelem). Tutaj wariant ciemny. */
  --belka-bg: var(--bg);
  --belka-panel: var(--bg-2);
  --belka-fg: var(--text);
  --belka-muted: var(--muted);
  --belka-line: var(--line);
  --belka-hover: rgba(255, 255, 255, .08);
  --belka-cien: rgba(0, 0, 0, .6);
}

* { box-sizing: border-box; }

/* Atrybut `hidden` ukrywa element regula przegladarki (display:none), ale KAZDA
   wlasna regula z `display` ja przebija — style autora maja pierwszenstwo nad
   wbudowanymi. Bez tego `.screen { display:flex }` pokazywalo wszystkie ekrany naraz. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 var(--sans);
  -webkit-text-size-adjust: 100%;
  overscroll-behavior: none;
}

#app { min-height: 100%; }
/* Z belka nad #app suma 44 px i 100% dalaby strone wyzsza niz widok, czyli pasek
   przewijania na kazdym ekranie. */
.z-belka #app { min-height: calc(100% - var(--belka-pelna)); }

/* Plakietka jezyka na prawym koncu belki: pigulka w barwie akcentu — ten sam kolor
   co swiatlo pod tarcza, wiec sciezke nauki widac bez czytania. Do 2026-09-10 stala
   w pasku ekranu sesji i tylko tam; teraz jest na kazdym ekranie, a pasek sesji jej
   nie powtarza. Barwy sa tutaj, bo `belka.css` trzyma sam uklad i nie zna `--accent`. */
.belka-lang {
  display: inline-block;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  font-weight: 600;
  letter-spacing: .06em;
  font-size: 12px;
  padding: 4px 10px;
  border-radius: var(--r-pill);
}

/* Gdy uczen ma wiecej niz jeden jezyk, plakietka jest przyciskiem rozwijajacym liste
   sciezek (uklad w `belka.css`). Grot potrzebuje mniej miejsca po prawej niz litera,
   a dotkniecie ma byc widoczne — stad jasniejsze tlo przy wskazaniu i po otwarciu. */
.belka-jezyki > summary { padding-right: 6px; }
.belka-jezyki > summary:hover,
.belka-jezyki[open] > summary {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
}


.screen {
  min-height: 100dvh;
  padding: max(16px, env(safe-area-inset-top)) 20px max(18px, env(safe-area-inset-bottom));
  display: flex;
  flex-direction: column;
  gap: 16px;
}

/* Ekran sesji ma wypelniac dokladnie widok, wiec pod belka musi o nia zmalec — inaczej
   strona zaczyna sie przewijac i konsola z przyciskiem „Mow" ucieka pod krawedz.
   Wciecie na notch przejmuje belka, wiec gornemu paddingowi wystarcza zwykle 16 px.
   Ekran logowania nie ma belki i nie ma tej klasy na <body>. */
.z-belka .screen {
  min-height: calc(100dvh - var(--belka-pelna));
  padding-top: 16px;
}

/* `h1` jest w calej aplikacji jeden - na ekranie logowania - i nie niesie tekstu,
   tylko logo; jego reguly stoja nizej, przy tym ekranie. Ekrany aplikacji naglowka
   nie maja od 2026-09-10: nazwa ekranu stoi na belce, po imieniu. */
h2 { font: 500 17px/1.3 var(--sans); margin: 20px 0 6px; }
h3 { font: 500 14px/1.3 var(--sans); margin: 16px 0 4px; color: var(--muted); }
p { margin: 0; }
.muted { color: var(--muted); font-size: 15px; }
.err { color: var(--rec); }

/* ---------------------------------------------------------------- pasek postepu */

.track {
  height: 3px;
  background: rgba(255, 255, 255, .09);
  border-radius: 2px;
  overflow: hidden;
  margin-bottom: -4px;
}
.track i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--accent);
  transition: width .3s ease;
}

/* ---------------------------------------------------------------- pasek gorny */

.bar {
  display: flex;
  align-items: baseline;
  gap: 12px;
  font-size: 13px;
  color: var(--muted);
}
.clock {
  font-variant-numeric: tabular-nums;
  letter-spacing: .02em;
  color: var(--muted);
}
.clock.running { color: var(--text); }
/* Zegar stoi na linii pisma, krazki maja srodki na tej samej wysokosci co on:
   przycisk bez tekstu nie ma linii pisma, wiec `baseline` paska ustawilby go
   dolna krawedzia. */
.bar-right { margin-left: auto; align-self: center; display: flex; gap: 10px; }
.quit {
  background: var(--bg-2);
  border: 0;
  padding: 5px 12px;
  border-radius: var(--r-pill);
  color: var(--muted);
  font: inherit;
  font-size: 13px;
}
.quit:active { background: var(--bg-3); }
/* Sterowanie sesja (pauza, przerwij) mowi ikona, nie slowem: na ekranie, na ktorym
   liczy sie zdanie i tarcza, dwa napisy w rogu czytalo sie zanim zdazyly cos znaczyc.
   Pigulka staje sie wtedy krazkiem — pole 34 px, glif 18 px w srodku. Nazwe niesie
   `aria-label`, bo dla czytnika ekranu ikona nie mowi nic. */
.quit--ico {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border-radius: 50%;
}
.quit-ico {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* ---------------------------------------------------------------- zdanie */

/* Pauza zaslania zdanie: czas ma stac, a nie plynac przy otwartej tresci. */
.paused { gap: 20px; }
.pause-title { font: 400 clamp(30px, 8vw, 42px)/1.1 var(--serif); }
.paused .wide { max-width: 260px; }
.console.frozen { opacity: .3; pointer-events: none; }

.stage {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: 18px;
  min-height: 0;
}
.context {
  font-size: 14px;
  color: var(--muted);
  letter-spacing: .01em;
  margin-bottom: -4px;
}
.sentence {
  font: 400 clamp(27px, 7.6vw, 40px)/1.24 var(--serif);
  letter-spacing: -0.01em;
  max-width: 20ch;
  text-wrap: balance;
}
.reveal {
  font: 300 clamp(19px, 5.4vw, 27px)/1.32 var(--serif);
  color: var(--accent);
  max-width: 26ch;
}
/* Co aplikacja uslyszala. To material jezykowy — wlasne slowa ucznia — wiec szeryfem,
   tak jak zdanie i wzorzec; wyciszony i mniejszy, bo jest odpowiedzia na zdanie, a nie
   zdaniem. Etykieta nad tekstem daje stanowi drugi nosnik obok samej obecnosci tekstu. */
.live {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  max-width: 32ch;
  word-break: break-word;
}
.live-etykieta {
  font: 400 11.5px/1 var(--sans);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Czekanie na transkrypcje: kolowrotek i zdanie zamiast wersalikowej etykiety. Mediana to
   11 s, wiec pustka pod zdaniem zdazy wygladac jak zgubione nagranie. */
.live--czeka .live-etykieta {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  text-transform: none;
  letter-spacing: normal;
  font-size: 13px;
}
.live--czeka .live-tekst { display: none; }
.live-tekst {
  font: 400 clamp(16px, 4.4vw, 20px)/1.35 var(--serif);
  color: var(--muted);
}
.status {
  font-size: 13.5px;
  color: var(--muted);
  min-height: 1.4em;
  text-align: center;
}
.status.live { color: var(--rec); }
.status.ok { color: var(--text); }
.status.err { color: var(--rec); }

/* ---------------------------------------------------------------- konsola */

.console {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  gap: 10px;
}
.side {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 7px;
}
.side--left { justify-self: start; }
.side-label {
  font-size: 11.5px;
  color: var(--muted);
  letter-spacing: .01em;
}

.mic, .orb {
  border: 0;
  border-radius: 50%;
  font: inherit;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}

/* PUSTY = nic jeszcze nie nagrano, PELNY = nagranie jest. Ta jedna roznica niesie caly
   stan, dlatego przy przycisku nie ma juz zadnego podpisu. Zapalona tarcza zostaje
   jedynym zrodlem swiatla na ekranie — tyle ze dopiero wtedy, gdy jest co pokazac. */
.mic {
  /* Wysokosc fali jest tu, a nie przy `.fala`, bo czyta ja takze pozycja ikony
     mikrofonu w trakcie nagrywania — ikona ma stac POD falą, na kazdej z trzech tarcz. */
  --fala-h: 40px;
  width: min(56vw, 232px);
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  color: var(--accent);
  background: none;
  border: 2px dashed color-mix(in srgb, var(--accent) 42%, transparent);
  box-shadow: none;
  transition: transform .14s ease, box-shadow .18s ease, background .18s ease,
              border-color .18s ease, color .18s ease;
  position: relative;
}
.mic:active { transform: scale(.985); }

/* Podpis w srodku tarczy: „zapisuje", „zapisane", „wzorzec odkryty" — czyli WYLACZNIE
   stany, w ktorych przycisku nie da sie nacisnac. W spoczynku i w nasluchu jest pusty
   (mowi wtedy ikona mikrofonu i fala) i wtedy ma zniknac z ukladu — inaczej odsuwalby
   fale od srodka. */
.mic-podpis {
  font-family: var(--sans);
  font-size: 17px;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: .01em;
  max-width: 76%;
  text-align: center;
}
.mic-podpis:empty { display: none; }

/* IKONA MIKROFONU. Jest w tarczy DOKLADNIE wtedy, gdy tarcza cos z mikrofonem robi:
   da sie ja nacisnac (spoczynek) albo wlasnie slucha (nagrywanie). Gdy przycisk jest
   nieczynny — „zapisuje", „zapisane", „wzorzec odkryty" — mikrofon nie znaczy juz nic
   i jego miejsce zajmuje slowo, ktore znaczy.

   Lezy POZA siatka przycisku (`position: absolute`), zeby zjazd w dol i zmniejszenie
   byly `top` i `transform` — dwiema wlasnosciami, ktore przechodza plynnie. W siatce
   ta sama zmiana bylaby przeskokiem ukladu, a fala i tak ma zostac na srodku.

   56% srednicy: w kolo wpisuje sie kwadrat o boku 70,7% srednicy, wiec zostaje margines.
   Glif zajmuje w polu 24x24 mniej wiecej 13x17,6, czyli jego wysokosc to 41% srednicy
   tarczy — duza czesc przycisku, a nie caly przycisk. Procent, bo dwie z trzech tarcz
   maja szerokosc z `min()` i na waskim telefonie sa mniejsze. */
.mic-ikona {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 56%;
  transform: translate(-50%, -50%);
  transition: top .18s ease, transform .18s ease;
  pointer-events: none;
}
/* Dwuczlonowo, bo bazowe `.ico` (17 px, `translateY(3px)`) lezy w tym arkuszu nizej
   i przy jednej klasie wygralby kaskada — ta sama pulapka co przy `.sesja-ikona
   .ico-rodzaj`. Kreska idzie w jednostkach pola 24x24, wiec skaluje sie razem z glifem. */
.mic-ikona .ico {
  display: block;          /* inaczej linia tekstu dokladalaby pusty pasek pod glifem */
  width: 100%;
  height: auto;
  aspect-ratio: 1;         /* pole 24x24 jest kwadratem — nie zgadujemy go z viewBox */
  stroke-width: 1.2;
  transform: none;
}
/* Nasluch: ikona schodzi pod fale i maleje do ~20% srednicy. `60%` to srodek tarczy
   plus polowa zmniejszonej ikony (0,18 x 56%), dalej polowa fali i przerwa z siatki —
   jedna formula dla wszystkich trzech tarcz, bo rozni je tylko `--fala-h`. */
.mic.rec .mic-ikona {
  top: calc(60% + var(--fala-h) / 2 + 6px);
  transform: translate(-50%, -50%) scale(.36);
}
/* Puls mowi to samo co pierscien i fala — „slysze cie" — tylko w srodku tarczy, tam
   gdzie patrzy oko. Ten sam takt co `ping`, zeby oba ruchy szly do jednego rytmu. */
.mic.rec .mic-ikona .ico { animation: mic-puls 1.5s ease-in-out infinite; }
@keyframes mic-puls {
  0%, 100% { transform: scale(1);    opacity: .88; }
  50%      { transform: scale(1.09); opacity: 1; }
}
.mic.busy .mic-ikona,
.mic.done .mic-ikona,
.mic.locked .mic-ikona { display: none; }

/* Nasluch i gotowe nagranie zapalaja tarcze. */
.mic.rec, .mic.done {
  color: var(--orb-ink);
  border-color: transparent;
  background: radial-gradient(118% 118% at 50% 16%, var(--orb-hi), var(--orb-lo) 72%);
}
/* Halo rosnie z glosnoscia (--poziom ustawia rAF), wiec przycisk „oddycha" glosem
   nawet katem oka. Bez dzwieku zmienna jest pusta i zostaje sam waski pierscien. */
.mic.rec {
  transform: scale(.975);
  box-shadow:
    0 0 0 calc(2px + var(--poziom, 0) * 16px)
      color-mix(in srgb, var(--rec) 20%, transparent),
    0 10px 30px -18px color-mix(in srgb, var(--orb-lo) 70%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, .2);
}
/* Nagrane: tarcza swieci, ale przycisk jest juz nieczynny — zeby nagrac to zdanie od
   nowa, trzeba najpierw skasowac poprzednie krzyzykiem. Nic sie wiec nie nadpisuje
   przez przypadek. */
.mic.done {
  box-shadow:
    0 18px 46px -20px color-mix(in srgb, var(--orb-lo) 80%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, .34);
  cursor: default;
}
.mic.done:active { transform: none; }
.mic:disabled { opacity: 1; }
/* Trwa wysylka albo model juz pracuje z tym nagraniem - przycisk celowo nie reaguje,
   wiec musi tak wygladac. */
.mic.busy,
.mic.zamrozona {
  filter: saturate(.25) brightness(.55);
  box-shadow: none;
}
/* Wzorzec odkryty przed odpowiedzia - nagrywanie zamkniete, zostaje uwaga i „Dalej". */
.mic.locked {
  background: var(--bg-2);
  color: var(--muted);
  border: 1px dashed var(--line);
  box-shadow: none;
}
.mic.locked:active { transform: none; }

/* Krzyzyk siedzi DOKLADNIE na krawedzi tarczy, niezaleznie od jej srednicy:
   14,65% to odleglosc punktu 45° od rogu kwadratu opisanego na kole (0,5 - 0,3536),
   a `translate(50%, -50%)` przesuwa krzyzyk o polowe jego wlasnego rozmiaru, wiec
   jego srodek lezy na okregu. Dziala tak samo dla tarczy 232 px i dla orba 62 px.
   Przy DUZEJ tarczy sesji krzyzyk jest od 2026-09-09 wyjety poza kolo — nizej. */
.nagr { position: relative; display: inline-grid; }
.kasuj {
  position: absolute;
  top: 14.65%;
  right: 14.65%;
  transform: translate(50%, -50%);
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 2px solid var(--bg);     /* obwodka tlem odcina krzyzyk od tarczy */
  border-radius: 50%;
  /* Krzyzyk bierze barwe TARCZY, przy ktorej stoi. Do 2026-09-10 byl czerwony (`--rec`)
     i przy zapalonej tarczy czytal sie jak ostrzezenie — a przerwanie wlasnego nagrania
     i skasowanie proby nie sa niczym alarmujacym. Widac go zreszta wylacznie wtedy, gdy
     tarcza SWIECI (`.rec` i `.done` to jedyne stany, w ktorych stoi), wiec wariant na
     wygaszonej tarczy nie mialby gdzie sie pokazac — stad jedna regula, nie dwie.
     Krzyzyk na akcencie jest ciemny, nigdy bialy: `--orb-ink` daje 5,84:1. */
  background: var(--accent);
  color: var(--orb-ink);
  cursor: pointer;
  box-shadow: 0 4px 14px -4px rgba(0, 0, 0, .7);
}
.kasuj:active { transform: translate(50%, -50%) scale(.92); }
/* Krzyzyk przy tarczy jest grubszy od `.ico` (1,7): stoi na swiecacym tle, na malym
   polu, i przy bazowej grubosci gubil sie na akcencie. Ksztalt bierze z `icons.js`
   jak kazda ikona — wlasny ma tu tylko ciezar kreski. */
.kasuj-ico { fill: none; stroke: currentColor; stroke-width: 2.8; stroke-linecap: round; }
.mic--opcja + .kasuj { width: 28px; height: 28px; }

/* Tarcza sesji: krzyzyk stoi CALY poza kolem i jest wiekszy, bo od 2026-09-09 znaczy
   takze „przerwij nagrywanie" — a to trzeba trafic w biegu, jednym kciukiem, nie
   celujac w cos, co lezy na krawedzi swiecacej tarczy.
   Odjecie 20 px przesuwa srodek wzdluz promienia o 20·√2 ≈ 28 px, czyli o 8 px dalej,
   niz wynosi jego wlasny promien — miedzy krzyzykiem a tarcza zostaje przeswit. */
.mic:not(.mic--opcja) + .kasuj {
  width: 44px;
  height: 44px;
  top: calc(14.65% - 20px);
  right: calc(14.65% - 20px);
}
.mic:not(.mic--opcja) + .kasuj svg { width: 18px; height: 18px; }

/* Fala w srodku przycisku: jedyny dowod, ze aplikacja naprawde slyszy. Slupki ida
   za pasmami glosu, wiec cisza i mowa wygladaja inaczej — samo „Slucham" tego nie mowi.
   Rysowane w `currentColor`, czyli atramentem tarczy, tak jak reszta ikon w aplikacji.
   Zostaje takze przy `prefers-reduced-motion`: to nie ozdoba, tylko informacja zwrotna. */
.fala {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  height: var(--fala-h);
}
.fala i {
  display: block;
  width: 5px;
  height: 100%;
  border-radius: 3px;
  background: currentColor;
  opacity: .92;
  transform: scaleY(var(--h, .12));
  /* Bez wygladzania slupki drgaja klatka po klatce; 90 ms wystarczy, zeby ruch byl
     plynny, a nadal nadazal za sylabami. */
  transition: transform .09s linear;
}
.mic--opcja .fala { gap: 3px; }
.mic--opcja .fala i { width: 3px; }

/* Pierscien nadawania — jedyny ruch w interfejsie, i tylko w trakcie nagrywania. */
.mic.rec::after {
  content: "";
  position: absolute;
  inset: -10px;
  border-radius: 50%;
  border: 2px solid var(--rec);
  animation: ping 1.5s ease-out infinite;
}
@keyframes ping {
  0%   { transform: scale(1);    opacity: .85; }
  100% { transform: scale(1.13); opacity: 0; }
}

.orb {
  width: 62px;
  height: 62px;
  background: var(--bg-2);
  color: var(--muted);
  border: 0;
  font-size: 17px;
  font-weight: 500;
  letter-spacing: .04em;
  transition: background .14s ease, color .14s ease, border-color .14s ease;
}
.orb:active { transform: scale(.96); }
/* Jedyny orb, ktory zostal, to „?" — wiec `on` znaczy juz tylko „wzorzec odkryty".
   Reguly stanow nagrywania odeszly razem z orbem uwagi po polsku (2026-09-09). */
.orb.on {
  background: var(--text);
  color: var(--bg);
}

.tail { min-height: 56px; display: flex; align-items: flex-end; }

/* ---------------------------------------------------------------- przyciski szerokie */

/* Przycisk glowny nosi akcent — to jedyna akcja, ktora ekran proponuje.
   Tekst na akcencie jest ciemny (--orb-ink), nigdy bialy: patrz ../DESIGN.md. */
.wide {
  width: 100%;
  padding: 16px;
  border: 0;
  border-radius: var(--r-m);
  background: var(--accent);
  color: var(--orb-ink);
  font: 600 16px/1 var(--sans);
  transition: filter .14s ease, transform .14s ease;
}
.wide:active { transform: scale(.99); filter: brightness(.92); }
/* „Dalej" nosi akcent, jak kazda akcja glowna (do 2026-09-09 byl wyciszony).
   Zasada „w sesji swieci wylacznie mikrofon" przegrala z praktyka: tarcza po nagraniu
   i tak jest zapalona, wiec ciemny przycisk pod nia nie byl drugim swiatlem mniej,
   tylko niewidocznym wyjsciem ze zdania.
   „Wznow" na ekranie pauzy zostaje cichy — pauza nie jest akcja, ktora ekran proponuje. */
.paused .wide {
  background: var(--bg-2);
  color: var(--text);
}
/* `.wide` na ODSYLACZU - „Zaloguj przez Google" musi byc `<a>`, bo to pelna nawigacja,
   a nie `fetch`. Przycisk ma juz srodek i tlo; odsylaczowi trzeba dolozyc to, czego
   `<button>` nie potrzebuje: bycie blokiem, srodkowanie i zdjecie podkreslenia. */
a.wide {
  display: block;
  box-sizing: border-box;
  text-align: center;
  text-decoration: none;
}
/* Wariant drugorzedny: powierzchnia zamiast obrysu, tak jak reszta kart. */
.wide.ghost {
  background: var(--bg-2);
  border: 0;
  color: var(--text);
}

/* ---------------------------------------------------------------- analiza */

.analyze { margin: 4px 0; }
.analyze-state {
  font-size: 14.5px;
  line-height: 1.45;
  color: var(--muted);
  margin-top: 10px;
  min-height: 1.4em;
}
.analyze-state.work { color: var(--accent); }
.analyze-state.err { color: var(--rec); }

.wide[disabled] { opacity: .45; }

/* ---------------------------------------------------------------- profile */

.profiles {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-top: 8px;
}
.profile {
  width: 100%;
  padding: 22px 20px;
  border: 0;
  border-radius: var(--r-l);
  background: var(--bg-2);
  color: var(--text);
  font: 400 22px/1.2 var(--serif);
  text-align: left;
  transition: background .14s ease, transform .14s ease;
}
.profile:active { background: var(--bg-3); transform: scale(.99); }
/* Kafel wyboru jezyka pokazuje barwe TEGO jezyka — to samo swiatlo, ktore zapali sie
   potem pod tarcza. Klasy lang-* podmieniaja --accent, wiec wystarczy sie do niej odwolac. */
#lang-list .profile {
  box-shadow: inset 4px 0 0 var(--accent);
  padding-left: 22px;
}
.profile span {
  display: block;
  margin-top: 4px;
  font: 400 13px/1.3 var(--sans);
  color: var(--muted);
}

/* ---------------------------------------------------------------- moje sesje */

.sesje {
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
}

/* Separator dnia. Data zeszla z KAZDEGO wiersza do jednego podpisu na grupe — w wierszu
   zostala godzina. Kreska w `--line`, czyli tokenie separatora; podpis jest meta,
   wiec grotesk 12 px w `--muted`. Po prawej stronie kreski stoi licznik sesji tego dnia. */
.sesje-dzien {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 4px 0;
  font: 500 12px/1 var(--sans);
  color: var(--muted);
}
.sesje-dzien::after { content: ''; flex: 1; height: 1px; background: var(--line); }
/* Licznik stoi w DOM-ie przed kreska (pseudoelement idzie zawsze na koniec tresci),
   a ma sie rysowac za nia — stad `order`, jedyny sposob bez zamiany kreski na element. */
.sesje-dzien-ile { order: 1; flex: none; }
/* Nad pierwszym separatorem nie ma czego oddzielac. */
.sesje-dzien:first-child { margin-top: 0; }

/* „Wiecej" domyka spis, gdy serwer ma jeszcze starsze sesje. Wyciszony i wezszy od
   przyciskow nad spisem: to nie jest akcja, ktora ekran proponuje, tylko wyjscie w glab
   historii. Stoi WEWNATRZ listy, wiec przewija sie razem z nia i po doczytaniu zostaje
   tam, gdzie uczen go zostawil. Odstep od ostatniego wiersza daje `gap` listy. */
.sesje-wiecej {
  flex: none;
  padding: 12px;
  margin: 2px 0 4px;
  font: 500 14px/1 var(--sans);
}
.sesje-wiecej[disabled] { opacity: .55; }

/* Kalendarz miesiaca na samym dole spisu: w ktore dni byly sesje i ile ich bylo.
   Spis mowi, CO uczen cwiczyl; kalendarz - KIEDY, czyli jedyne miejsce, w ktorym widac
   regularnosc. Stoi wewnatrz listy, wiec przewija sie razem z nia i nie zabiera miejsca
   sesjom na pierwszym ekranie.

   Powierzchnia jak kazda karta (`--bg-2`), bez obrysu. Dzien z sesja dostaje kolko
   w akcencie z ciemna liczba (`--orb-ink`) - akcent znaczy tu „tego dnia cwiczyles",
   a liczba w srodku jest drugim nosnikiem, wiec barwa nie niesie stanu sama. */
.kalendarz {
  flex: none;
  margin-top: 6px;
}
.kalendarz-miesiac {
  margin: 0 4px 8px;
  font: 500 12px/1 var(--sans);
  color: var(--muted);
}
.kalendarz-siatka {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  /* Wiersze rozsuniete bardziej niz kolumny: kolko wisi POD swoim numerem, wiec przy
     rownym odstepie stalo blizej numeru z nastepnego tygodnia niz swojego. */
  gap: 8px 4px;
  padding: 12px 8px;
  background: var(--bg-2);
  border-radius: var(--r-m);
}
.kalendarz-nazwa {
  padding-bottom: 4px;
  font: 500 11px/1 var(--sans);
  color: var(--muted);
  text-align: center;
}
.kalendarz-pole {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  /* Miejsce na kolko zostaje takze w dniu bez sesji - inaczej wiersze tygodni mialyby
     rozne wysokosci i siatka przestalaby byc siatka. */
  min-height: 37px;
}
.kalendarz-numer {
  font: 400 11px/1 var(--sans);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
/* Dzisiaj: barwa i grubosc, bo to stan, a nie akcja - kolka tu nie ma po co dokladac. */
.kalendarz-pole--dzis .kalendarz-numer { color: var(--accent); font-weight: 600; }
.kalendarz-kolko {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--accent);
  color: var(--orb-ink);
  font: 600 12px/1 var(--sans);
  font-variant-numeric: tabular-nums;
}

/* Jedna sesja = jeden wiersz, ktory czyta sie jednym spojrzeniem: kiedy i za ile.
   Zdania, transkrypcje i komentarze siedza w raporcie — spis ma byc spisem.

   Od 2026-09-09 wiersz jest KLIKALNY, a spis jest ekranem domyslnym aplikacji. Stad
   podzial: tlo i zaokraglenie nosi opakowanie, a caly obszar tekstu to jeden przycisk,
   zeby cel dotykowy obejmowal wiersz, a nie sama date. Trzy kropki stoja OBOK niego,
   bo przycisk w przycisku jest niepoprawny i lapalby to samo klikniecie. */
.sesja {
  display: flex;
  align-items: stretch;
  background: var(--bg-2);
  border-radius: var(--r-m);
}
.sesja-wejscie {
  flex: 1;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 4px 13px 12px;
  border: 0;
  border-radius: var(--r-m) 0 0 var(--r-m);
  background: none;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.sesja-wejscie:active { background: var(--bg-3); }
/* Sesja bez nagran nie ma czego pokazac, wiec nie udaje, ze prowadzi dalej. */
.sesja-wejscie[disabled] { cursor: default; opacity: .55; }
/* Pole ikony rodzaju: stala szerokosc dla obu rodzajow, zeby tytuly wierszy staly
   w jednej kolumnie. Bez tla — rodzaj mowi ksztalt ikony i napis przy numerze. */
.sesja-ikona {
  flex: none;
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  color: var(--muted);
}
/* Ikonka rodzaju sesji: kartka z liniami albo dymki rozmowy, 30 px = 80% pola.
   Selektor jest DWUCZLONOWY nie dla ozdoby: bazowy `.ico` (17 px, `translateY(3px)`)
   stoi w tym pliku nizej i przy jednej klasie wygrywalby kaskada — ikona rodzaju
   siedziala przez to na 17 px i byla zsunieta o 3 px, cokolwiek deklarowalismy tutaj. */
.sesja-ikona .ico-rodzaj {
  flex: none;
  width: 30px;
  height: 30px;
  transform: none;
}
.sesja-tresc {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 3px;
}
/* Pierwsza linia wiersza: NAZWA sesji — godzina zeszla na poczatek linii meta,
   a numer sesji w dniu zniknal na rzecz licznika w podpisie dnia. */
.sesja-data {
  display: flex;
  align-items: baseline;
  gap: 8px;
  max-width: 100%;
  font: 600 17px/1.25 var(--sans);
}
/* NAZWA sesji („Rezerwacja pokoju w hotelu"), a przy sesjach sprzed nazw — dawne
   „zdania"/„rozmowa". Odkad nie ma nad nia numeru, to ona niesie wiersz: pelny kolor
   tekstu i 16 px zamiast wyciszonych 13. Nazwa bywa dluzsza niz jedno slowo, wiec
   na waskim ekranie urywa sie wielokropkiem zamiast rozpychac wiersz; `min-width: 0`
   jest tu warunkiem dzialania `ellipsis` wewnatrz flexa, a nie ozdoba. */
.sesja-rodzaj {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font: 600 16px/1.25 var(--sans);
  color: inherit;
}
.sesja-meta {
  font-size: 13px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

/* Prawa strona wiersza: jedna wartosc, ktora mowi, co z sesja jest. */
.sesja-czeka {
  flex: none;
  display: flex;
  align-items: center;
  padding: 13px 0;
}
/* Wynik siedzi w kolku — tym samym ksztalcie i tej samej wielkosci, ktora sesja w toku
   pokazuje postep, wiec prawa kolumna spisu ma jeden ksztalt zamiast dwoch. Liczba
   zeszla z szeryfowych 24 px do groteski 13,5: w kolku „100%" po prostu nie miescilo
   sie w wiekszym stopniu, a wynik jest tu stanem wiersza, a nie naglowkiem do czytania.

   Kolko jest PELNE (od 2026-09-16), nie obrysowane: sam obrys gubil sie przy 42 px
   obok ikony rodzaju i mocnej nazwy sesji, a ocena jest w tym wierszu druga rzecza
   po nazwie. Barwa idzie wiec na powierzchnie, a liczba na niej jest ciemna
   (`--orb-ink`) — tak samo jak kolko dnia w kalendarzu i jak kazdy napis na kolorze
   w tej aplikacji (patrz ../DESIGN.md: bialego tekstu na barwie nie uzywamy). */
.sesja-ocena {
  flex: none;
  align-self: center;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  margin-left: 4px;
  border-radius: 50%;
  background: var(--muted);
  color: var(--orb-ink);
  font: 600 13.5px/1 var(--sans);
  font-variant-numeric: tabular-nums;
}
.sesja-ocena.good { background: var(--good); }
.sesja-ocena.half { background: var(--half); }
.sesja-ocena.bad  { background: var(--rec); }

/* Sesja bez analizy nie ma oceny i nie ma udawac, ze ma. Napis jest cichy, ale mowi
   wprost, na co czeka. */
.sesja-czeka {
  max-width: 7.5em;
  font-size: 12px;
  line-height: 1.25;
  text-align: right;
  color: var(--muted);
}
.sesja-czeka-tresc { display: inline-flex; align-items: center; gap: 6px; }
/* „analiza trwa" z kolowrotkiem zostaje w jednej linii: zlamany napis odrywal sie od
   ikonki i wygladal jak dwa niepowiazane elementy. */
.sesja-czeka--idzie { max-width: none; white-space: nowrap; }

/* Sesja w toku nie ma wyniku i nie bedzie go miala, dopoki sie nie skonczy — wiec
   w miejscu wyniku stoi niepelne kolko. Do 2026-09-12 stalo tam slowo „dokończ": mowilo
   tylko tyle, ze mozna wrocic, a nie mowilo, czy zostalo jedno zdanie, czy osiem.
   Drugim nosnikiem jest opis wiersza („3 z 10 zdań · w toku"), trzecim pasek akcentu. */
/* Geometria kolka (srednica, promien, grubosc kreski) siedzi w `Progress.js`, bo tam
   promien musi zgadzac sie z obwodem liczonym do `stroke-dasharray`. Arkusz odpowiada
   za barwe i ksztalt konca kreski. */
.sesja-postep {
  flex: none;
  align-self: center;
  margin-left: 4px;
  color: var(--accent);
}
.postep { display: block; }
.postep-tor { fill: none; stroke: var(--line); }
.postep-luk {
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  /* Luk ma ruszac od gory, a `stroke-dasharray` zaczyna od prawej strony okregu. */
  transform: rotate(-90deg);
  transform-origin: 50% 50%;
}
/* Sesja w toku: pasek akcentu przy krawedzi. To jedyny wiersz, ktory czeka na ucznia,
   reszta spisu to historia. Ten sam zapis, co przy kaflu wyboru jezyka —
   `box-shadow: inset`, bo `border` na zaokraglonym rogu rysuje sie na zewnatrz luku. */
.sesja--wtoku { box-shadow: inset 4px 0 0 var(--accent); }
.sesja--wtoku .sesja-wejscie { padding-left: 10px; }

/* Trzy kropki. Zwykly <details>, wiec rozwija sie bez JavaScriptu; domykanie klikiem
   obok dokłada app.js, tak samo jak belka.js robi to dla szuflady. */
.sesja-menu { position: relative; flex: none; }
.sesja-menu > summary {
  display: grid;
  place-items: center;
  width: 44px;
  height: 100%;
  min-height: 44px;
  color: var(--muted);
  cursor: pointer;
  list-style: none;
  border-radius: 0 var(--r-m) var(--r-m) 0;
}
.sesja-menu > summary::-webkit-details-marker { display: none; }
.sesja-menu[open] > summary, .sesja-menu > summary:active {
  background: var(--bg-3);
  color: var(--text);
}
/* Menu lezy NAD karta, wiec bierze powierzchnie o stopien wyzsza (patrz ../DESIGN.md). */
.sesja-menu > nav {
  position: absolute;
  right: 6px;
  top: calc(100% - 4px);
  z-index: 3;
  min-width: 10.5em;
  padding: 4px;
  background: var(--bg-3);
  border-radius: var(--r-s);
  box-shadow: 0 14px 34px -12px rgba(0, 0, 0, .8);
}
/* Pozycja menu: ikona i napis w jednej linii, jak w szufladzie belki. Ikona jest
   DRUGIM nosnikiem znaczenia (patrz ../DESIGN.md) — kosz mowi „to kasuje" jeszcze zanim
   ktos przeczyta czerwony napis. */
.sesja-poz {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 11px 12px;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--text);
  font: 500 14.5px/1 var(--sans);
  text-align: left;
  cursor: pointer;
}
/* `.ico` podnosi sie o 3 px do linii pisma akapitu; tutaj stoi w rzedzie i srodkuje
   sie samo. Bez `flex: none` kurczy sie, gdy napis nie miesci sie w szufladce. */
.sesja-poz .ico { transform: none; flex: none; }
.sesja-poz:active { background: var(--bg-2); }
.sesja-poz--kasuj { color: var(--rec); }
/* Pozycja, ktorej jeszcze nie ma. Zostaje w menu, bo mowi, co tu bedzie - ale nie udaje
   klikalnej: wyciszona i bez reakcji na dotkniecie. */
.sesja-poz[disabled] { color: var(--muted); cursor: default; }
.sesja-poz[disabled]:active { background: none; }

/* ---------------------------------------------------------------- raport */

.report {
  flex: 1;
  overflow-y: auto;
  font-size: 15.5px;
  line-height: 1.55;
  max-width: 64ch;
  padding-right: 2px;
}
.report h2 { font: 500 16px/1.3 var(--sans); margin: 22px 0 8px; }
/* Globalne p ma margines zero, wiec bloki raportu skleilyby sie w jedna sciane tekstu. */
.report p { margin: 0 0 13px; }
.report p:last-child { margin-bottom: 0; }
.report strong { color: var(--text); }
.report ul { margin: 6px 0; padding-left: 18px; }
.report li { margin: 3px 0; }

/* Sekcje raportu. Naglowki uklada agent i za kazdym razem sa inne („Co poszlo dobrze",
   „for kontra since", „Wymowa"), wiec styl dotyczy KAZDEJ sekcji, a nie zadnej
   konkretnej — nic tu nie jest wpisane na sztywno. */
.raport-tytul {
  font: 400 20px/1.3 var(--serif);
  color: var(--text);
  margin: 0 0 14px;
}
/* Podsumowanie stoi przed pierwszym naglowkiem i zwykle niesie najwazniejsze zdania
   raportu. Bez ramki, za to wieksze i podparte kreska w barwie jezyka: ma sie czytac
   jako wstep, a nie jako kolejna sekcja z listy. */
.raport-lead {
  border-left: 3px solid var(--accent);
  padding-left: 14px;
  margin: 0 0 20px;
  font-size: 16.5px;
}
/* Warstwa, nie ramka: sekcja stoi na --bg-2 i tego wystarcza, odkad skok jasnosci
   jest widoczny. Obrys byl proteza na czasy, gdy #101010 nie odcinalo sie od #000. */
.raport-sekcja {
  background: var(--bg-2);
  border-radius: var(--r-m);
  padding: 16px;
  margin: 18px 0;
}
/* Naglowek ma byc MOCNIEJSZY od tekstu sekcji, nie subtelniejszy — to on niesie podzial.
   Kropka w barwie jezyka odcina go dodatkowo, bo sama ramka na telefonie ledwo widac. */
.raport-sekcja > h2 {
  display: flex;
  align-items: center;
  gap: 9px;
  /* Wlasnosci dlugie, nie skrot `font`: skrot z `var()` w srodku jest trudniejszy do
     sprawdzenia i cala deklaracja przepada, gdy cokolwiek w nim nie zagra. Naglowek
     sekcji jest tu najwazniejszy, wiec ma byc odporny. */
  font-family: var(--sans);
  font-size: 16.5px;
  font-weight: 600;
  line-height: 1.3;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text);
  margin: 0 0 11px;
}
.raport-sekcja > h2::before {
  content: "";
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}
.raport-sekcja h3 { margin-top: 14px; }
.raport-sekcja p:last-child { margin-bottom: 0; }
.report strong { font-weight: 600; }
code, .report code {
  background: var(--bg-3);
  padding: 1px 5px;
  border-radius: 6px;
  font-size: .88em;
}

/* ---------------------------------------------------------------- wynik sesji */

/* Jedna liczba, ktora widac zanim sie cokolwiek przeczyta. */
.score {
  margin: 0 0 18px;
  padding: 16px 18px;
  border-radius: var(--r-m);
  background: var(--bg-2);
  border-left: 3px solid var(--line);
}
.score.good { border-left-color: var(--good); }
.score.half { border-left-color: var(--half); }
.score.bad  { border-left-color: var(--rec); }
.score-value {
  font: 400 clamp(34px, 9vw, 46px)/1 var(--serif);
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
}
.score.good .score-value { color: var(--good); }
.score.half .score-value { color: var(--half); }
.score.bad  .score-value { color: var(--rec); }
.score-bar {
  height: 6px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, .1);
  overflow: hidden;
  margin: 12px 0 8px;
}
.score-bar i {
  display: block;
  height: 100%;
  border-radius: var(--r-pill);
  background: currentColor;
}
.score.good .score-bar i { background: var(--good); }
.score.half .score-bar i { background: var(--half); }
.score.bad  .score-bar i { background: var(--rec); }
.score-label { font-size: 13px; color: var(--muted); }

.card-pct {
  float: right;
  font: 500 13px/1.4 var(--sans);
  font-variant-numeric: tabular-nums;
  color: var(--text);
  margin-left: 10px;
}
.card.good .card-pct { color: var(--good); }
.card.half .card-pct { color: var(--half); }
.card.bad  .card-pct { color: var(--rec); }

/* ---------------------------------------------------------------- karta zdania */

/* Trzy warstwy informacji maja byc rozroznialne bez czytania: pasek z lewej mowi,
   jak poszlo; moja wersja jest zwykla; poprawna swieci kolorem; komentarz jest cichy. */
.card {
  background: var(--bg-2);
  border-radius: var(--r-m);
  border-left: 3px solid var(--line);
  padding: 13px 15px;
  margin: 12px 0;
}
.card.good { border-left-color: var(--good); }
.card.half { border-left-color: var(--half); }
.card.bad  { border-left-color: var(--rec); }

/* Polecenie po lewej, ocena i czas namyslu razem w rogu - inaczej rozpychalyby zdanie. */
.card-pl {
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 14.5px;
  color: var(--muted);
  margin-bottom: 9px;
}
.card-rog {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 8px;
  white-space: nowrap;
}
.card-czas { font-size: 12px; font-variant-numeric: tabular-nums; }
.card-none { color: var(--muted); font-size: 15px; }
.card-note { font-size: 13px; color: var(--muted); margin-top: 8px; }
.card-comment {
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--muted);
  margin-top: 9px;
  padding-top: 9px;
  border-top: 1px solid var(--line);
}
/* Do 2026-09-13 komentarz byl ostatnim `p` karty i dolny margines z `.report p`
   zerowal mu sie sam przez `:last-child`. Teraz stoi pod nim rozwiniecie „wymowa",
   wiec trzeba to powiedziec wprost - i z dwoma klasami, bo `.report p` ma wyzsza
   szczegolowosc niz sama `.card-comment`. */
.card .card-comment { margin-bottom: 0; }

/* Wymowa - ostatnia warstwa karty, zwinieta. Zwykly <details>, jak menu wiersza spisu
   i szuflada belki: rozwija sie bez JavaScriptu. Trojkacik zostaje domyslny, bo napis
   i on to juz dwa nosniki stanu i nie ma po co dokladac trzeciego z `icons.js`.

   Cel dotykowy `summary` wychodzi ~37 px zamiast 44 - z tego samego powodu, co przy
   `.line-play` (32 px): to element WEWNATRZ karty, nie sterowanie sesja. Rekompensuje
   to szerokosc na cala karte. */
.card-speech { margin-top: 9px; }
.card-speech > summary {
  padding: 9px 0;
  font: 400 13px/1 var(--sans);
  color: var(--muted);
  cursor: pointer;
}
.card-speech[open] > summary { color: var(--text); }
/* Tresc lezy NAD karta `--bg-2`, wiec bierze powierzchnie o stopien wyzsza
   (patrz ../DESIGN.md) - tak samo jak menu wiersza spisu.
   JEDNA powierzchnia na cale rozwiniecie, a nie osobna pod kazdym akapitem: to jest
   jedna odpowiedz na jedno pytanie „jak to zabrzmialo". */
.speech-body {
  background: var(--bg-3);
  border-radius: var(--r-s);
  padding: 10px 12px;
}
/* Odstepy w srodku sa NASZE: `.report p/ul/li` niesie wlasne marginesy dla czesci
   omowieniowej raportu i tutaj skladalyby sie z ponizszymi. */
.card-speech p,
.card-speech ul,
.card-speech li { margin: 0; }
/* Dwa czlony, bo powyzsze zerowanie (klasa + element) bije sama `.speech-body`. */
.card-speech .speech-body > * + * { margin-top: 8px; }
/* Etykieta nalezy do listy pod soba, wiec trzyma sie jej blizej niz reszty. */
.card-speech .speech-body > .speech-meta + ul { margin-top: 4px; }
.speech-lead { font: 400 14px/1.45 var(--sans); color: var(--text); }
/* Na `--bg-3` `--muted` ma 4,68:1 - to margines, nie zapas. Nizej nie schodzimy. */
.speech-meta { font: 400 12.5px/1.45 var(--sans); color: var(--muted); }
.card-speech ul { padding: 0; list-style: none; }
.card-speech li {
  font: 400 12.5px/1.45 var(--sans);
  color: var(--muted);
}
.card-speech li + li { margin-top: 6px; }
/* `segment` to slowo w jezyku docelowym, czyli material jezykowy - a ten w tej
   aplikacji zawsze jest szeryfem, tak samo jak `.line-text` i `.sentence`. */
.card-speech li b { font: 400 14px/1 var(--serif); color: var(--text); }

.line {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: start;      /* ikona i przycisk rownaja sie do pierwszej linii tekstu */
  gap: 4px 10px;
  margin: 7px 0;
}
.ico {
  width: 17px;
  height: 17px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
  stroke-linecap: round;
  stroke-linejoin: round;
  transform: translateY(3px);
}
.ico-mine { color: var(--muted); }
.ico-good { color: var(--good); }
/* Wzorzec zdania jest informacja dodatkowa, nie werdyktem — stad wyciszony,
   zeby nie konkurowal z zielona wersja poprawna. */
.ico-wzorzec { color: var(--muted); }
.line--wzorzec .line-text { color: var(--muted); font-size: 15px; }
.line-text {
  font: 400 17px/1.35 var(--serif);
  word-break: break-word;
}
.line--good .line-text { color: var(--good); }
.line-play {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border: 0;
  background: var(--bg-2);
  color: var(--muted);
  border-radius: 50%;
  padding: 0;
}
.line-play .ico { transform: none; width: 15px; height: 15px; }
.line-play:active { background: var(--bg-3); }

/* ---------------------------------------------------------------- ekran analizy */

/* Koniec sesji nie ma zwykle nic do klikniecia: analiza rusza sama. Ekran dzieli sie
   wiec dokladnie na pol (od 2026-09-12): u gory przewijaja sie zdania wlasnie
   przerobionej sesji, u dolu stoi panel przebiegu. Rowne polowy, bo obie strony maja
   co pokazac - do tego dnia stan mieszkal w jednej linijce nad dolna krawedzia i przy
   kilkuminutowym przebiegu wygladal na zawieszony.

   Wiersze `1fr 1fr` nie kurcza sie ponizej swojej tresci (`1fr` to `minmax(auto, 1fr)`),
   wiec panel z logiem bledu rosnie i strona sie przewija, zamiast obcinac tresc. */
#s-done { display: grid; grid-template-rows: 1fr auto; }
/* Na pol dopiero wtedy, gdy dolna polowa ma co pokazac. Gdy przebieg nie idzie, zostaje
   w niej sam przycisk - i zdania moga zajac cala wysokosc, tak jak przed ta zmiana. */
#s-done.z-panelem { grid-template-rows: 1fr 1fr; }

.karuzela {
  min-height: 0;
  display: grid;
  place-items: center;
  padding: 8px 4px;
}

/* Wszystkie zdania leza na sobie w jednej komorce siatki: podmiana nie przesuwa wtedy
   niczego dookola, a wysokosc ekranu nie skacze miedzy krotkim a dlugim zdaniem. */
.karuzela-zdanie {
  grid-area: 1 / 1;
  margin: 0;
  text-align: center;
  max-width: 32ch;
  opacity: 0;
  visibility: hidden;
  transition: opacity .6s ease;
}
.karuzela-zdanie.jest { opacity: 1; visibility: visible; }

/* Material jezykowy skladamy szeryfem — to zdania do przeczytania, nie chrom. */
.karuzela-pl {
  margin: 0;
  font-family: var(--serif);
  font-size: 21px;
  line-height: 1.35;
}
.karuzela-ref {
  margin: 10px 0 0;
  font-family: var(--serif);
  font-size: 18px;
  line-height: 1.35;
  color: var(--muted);
}

/* Dolna polowa: jedno miejsce, ktore mowi, ze cos sie dzieje. Kolejnosc w srodku jest
   kolejnoscia pytan ucznia: co trwa -> na czym stoi -> jak dlugo -> czy musze tu siedziec. */
.praca {
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  text-align: center;
}
/* Panel lezy na TLE STRONY - do 2026-09-16 mial powierzchnie karty (`--bg-2`) i pol
   ekranu ciemniejszego prostokata dzielilo czekanie na dwa niepowiazane obrazki.
   Kolowrotek i cztery linijki tekstu nie sa karta z trescia, tylko jednym stanem
   ekranu, wiec siedza na tym samym tle, co zdania nad nimi. Klasa zostaje, bo nadal
   rozstrzyga jedno: tresc stoi POSRODKU dolnej polowy, a sam przycisk - nisko. */
.praca--srodek {
  padding: 16px;
  justify-content: center;
}
.praca-tytul { font: 500 17px/1.3 var(--sans); }
/* Naglowek czekania jest wersalikami i nie zmienia sie przez caly przebieg, wiec czyta
   sie go jak etykiete, a nie jak zdanie - swiatlo miedzy literami jak w `.live-etykieta`. */
.praca-tytul--etykieta { letter-spacing: .06em; }
.praca-krok { font: 400 14px/1.4 var(--sans); color: var(--muted); }
/* Licznik mowi, ile to juz trwa, i nic ponadto: przewidywanie „zwykle ok. N min"
   liczylo srednia z historii, w ktorej siedza przebiegi starego silnika, wiec podawalo
   czas kilka razy wiekszy od prawdy. Cyfry tabelaryczne, zeby sekundy nie skakaly. */
.praca-czas { font: 400 16px/1.3 var(--sans); font-variant-numeric: tabular-nums; }
/* Sentencja pod licznikiem. Wchodzi przenikaniem, bo zmienia sie co piec sekund sama
   z siebie - podmieniona w jednej klatce wygladalaby jak usterka, a nie jak odpowiedz
   ekranu na to, ze uczen wciaz czeka. Kazda ma w JS-ie wlasny `key`, wiec powstaje nowy
   wezel i animacja odpala sie od nowa. */
.praca-pociecha {
  font: 400 13px/1.4 var(--sans);
  color: var(--muted);
  animation: pociecha-wejscie .45s ease both;
}
@keyframes pociecha-wejscie { from { opacity: 0 } to { opacity: 1 } }
.praca .wide { width: 100%; margin-top: 6px; }

@media (prefers-reduced-motion: reduce) {
  /* Podmiana zdania zostaje — niesie informacje. Znika samo przenikanie. */
  .karuzela-zdanie { transition: none; }
  .praca-pociecha { animation: none; }
}

/* Mala tarcza: wniosek o nowy jezyk, scenka rozmowy i zyczenie do nowych zdan. Ta sama
   co w sesji, tylko mniejsza — reszta wyglada tak samo, bo znaczy to samo. */
.mic--opcja { --fala-h: 22px; width: 104px; border-width: 1.5px; }
.mic--opcja .mic-podpis { font-size: 13px; max-width: 84%; }

/* ------------------------------------------------------- dodaj nowy jezyk */

/* Ekran ma jedna rzecz do zrobienia: nagrac zdanie o tym, czego chce sie uczyc.
   Tarcza stoi na srodku, przycisk glowny u dolu. Zadnego nowego komponentu — wszystko
   poza kartą przykladow to `.mic--opcja`, `.kasuj`, `.status` i `.wide`. */
#s-nowyjezyk { gap: 14px; }
.nowy-wstep { color: var(--muted); font-size: 15px; line-height: 1.45; margin: 0; }

/* Przyklady to material jezykowy — to, co uczen ma powiedziec — a nie chrom
   interfejsu, wiec ida szeryfem, tak samo jak zdanie na ekranie sesji. */
.nowy-przyklady {
  background: var(--bg-2);
  border-radius: var(--r-m);
  padding: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.nowy-przyklady p {
  margin: 0;
  font: 300 16px/1.4 var(--serif);
  color: var(--muted);
}
#s-nowyjezyk .nagr { margin: 6px auto 0; }
#s-nowyjezyk .status, #s-dialog-start .status { min-height: 18px; text-align: center; }
.nowy-znane { margin: 0 auto; text-align: center; font-size: 13px; }
#s-nowyjezyk .wide { margin-top: auto; }
/* Ekran wejscia w rozmowe dzieli uklad z „Dodaj nowy jezyk": ten sam wstep, ta sama
   karta przykladow, ta sama mala tarcza. Rozni sie tym, co nad nimi — wyborem drogi. */
#s-dialog-start, #s-zdania-start { gap: 14px; }

/* ------------------------------- nowe zdania i nowa rozmowa: wybor drogi

   Oba ekrany zaczynaja sie JEDNA decyzja: model wymysla sam czy uczen mowi, czego
   chce. Kafle sa **tym samym ksztaltem, co kafel wyboru jezyka** (`.profile`): `--bg-2`,
   pasek akcentu z lewej, nazwa szeryfem i wyjasnienie meta pod nia. Dwa ekrany zadaja
   pytanie z zamknietego zbioru, wiec maja je zadawac tak samo — do 2026-09-16 pierwsza
   droga byla kaflem w pelnym akcencie, a druga wyciszona, czyli ten sam gest wygladal
   tu inaczej niz przy wyborze jezyka.

   Rowne kafle znaczy, ze ekran niczego nie poleca — obie drogi sa do wziecia i
   rozstrzyga o nich tekst, nie barwa. Wybor niesie potem nieobecnosc drugiego kafla
   i zdjety opis pierwszego. Oba gasna, gdy zadnej drogi nie da sie wziac: na ekranie
   zdan przy odmowie serwera („Najpierw dokoncz otwarta sesje…"), na ekranie rozmowy
   dopoki serwer nie odda numeru rozmowy. */
/* Tytul ekranu startowego. Jedyne dwa miejsca w aplikacji, gdzie ekran ma wlasny
   naglowek - dlaczego, mowi komentarz przy `OWN_TITLE` w `state/navigation.js`.
   Glif rodzaju idzie `--muted`, tak samo jak ikonka rodzaju w wierszu spisu: mowi
   „co to jest", a nie „tu jest akcja". */
.ekran-tytul {
  display: flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  font: 600 19px/1.2 var(--sans);
  color: var(--text);
}
.ekran-tytul .ico { width: 21px; height: 21px; transform: none; color: var(--muted); }

.wybor {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* Wymiary, powierzchnia i pasek akcentu jak w `.profile` — patrz sekcja „profile".
   Rozni je tylko glif rodzaju w nazwie i opis dwuwierszowy zamiast jednego podpisu. */
.wybor-kafel {
  --glif: 20px;
  --glif-odstep: 10px;
  width: 100%;
  padding: 22px 20px 22px 22px;
  border: 0;
  border-radius: var(--r-l);
  background: var(--bg-2);
  box-shadow: inset 4px 0 0 var(--accent);
  color: var(--text);
  text-align: left;
  font: 400 22px/1.2 var(--serif);
  transition: background .14s ease, transform .14s ease, opacity .14s ease;
}
.wybor-kafel:active { background: var(--bg-3); transform: scale(.99); }
/* Nazwa drogi i glif rodzaju stoja w jednym rzedzie: napis mowi, CO ta droga robi,
   a glif - CZEGO. Bez glifu oba ekrany startowe maja dokladnie te same dwa napisy.
   Glif ma wlasna kolumne (`--glif` + `--glif-odstep`), a opis zaczyna sie pod nazwa,
   nie pod glifem: inaczej pierwsza linijka kafla wisi w prawo wzgledem reszty. */
.wybor-nazwa { display: flex; align-items: center; gap: var(--glif-odstep); }
.wybor-nazwa .ico { width: var(--glif); height: var(--glif); transform: none; }
.wybor-opis {
  display: block;
  margin-top: 4px;
  padding-left: calc(var(--glif) + var(--glif-odstep));
  font: 400 13px/1.3 var(--sans);
  color: var(--muted);
}
.wybor-kafel[disabled] { opacity: .45; }
/* Wybrany nie jest wygaszony — jest jedyny. Opis znika, bo zrobil swoje: mial pomoc
   wybrac, a nie stac nad tarcza i zabierac jej miejsce na telefonie. */
.wybor-kafel--wybrany[disabled] { opacity: 1; }
.wybor-kafel--wybrany .wybor-opis { display: none; }
/* Po wyborze drogi „po swojemu" tarcza bierze cale wolne miejsce miedzy przykladami
   a przyciskiem u dolu: oba ekrany maja teraz jeden przycisk zamiast dwoch, wiec tarcza
   zostawala pod przykladami, a pod nia stala dziura na dwie piesci. */
#s-zdania-start .nagr, #s-dialog-start .nagr { margin: auto auto; }

#s-dialog-start .wide, #s-zdania-start .wide { margin-top: 0; }
#s-dialog-start #btn-dialog-zacznij,
#s-zdania-start #btn-zdania-uloz,
#s-pierwsza #btn-pierwsza-jezyk { margin-top: auto; }
/* Model pracuje: przyciskow nie ma, wiec komunikat zostaje na ekranie sam — i staje
   na srodku wolnego miejsca (`margin: auto 0` na ostatnim dziecku flexa), zamiast
   przyklejac sie pod statusem i zostawiac pod soba pustke po przyciskach. */
.analyze--czekam {
  margin: auto 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}
.analyze--czekam .analyze-state { margin: 0; font-size: 15.5px; text-align: center; }

/* ---------------------------------------------------------------- dostepnosc */

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

/* Ta sekcja stoi PRZED wspolnym blokiem `prefers-reduced-motion`, a nie na koncu pliku,
   i to nie jest dowolnosc: tamten blok gasi ruch regulami o tej samej wadze, wiec wygrywa
   wylacznie tym, ze jest pozniej. Kazda animacja zapisana pod nim zostawalaby wlaczona
   takze tam, gdzie uczen prosil o spokoj - i nie widac tego ani w kodzie, ani w probach.
*/
/* ---------------------------------------------------------- kolowrotek ze znaku */

/* Czekanie rysowane ZNAKIEM, a nie obwodka: dymek z `logo.svg` rysuje sie sam - najpierw
   obrys, potem trzy slupki fali od dolu do gory - i sciera sie tak, jak powstal.
   Ksztalty siedza w `app/components/Loader.js`, tu jest barwa, rozmiar i ruch.

   Kreci sie tylko wtedy, gdy naprawde cos trwa (kolejka albo przebieg analizy). Ruch
   niesie tu informacje — sam tekst z licznikiem wygladal na zamrozony ekran, a analiza
   potrafi zajac kilkanascie minut.

   `pathLength="100"` w ksztalcie normalizuje dlugosc obrysu, wiec kazda liczba
   w `stroke-dasharray` i `stroke-dashoffset` to PROCENT jego obwodu - i nie trzeba
   mierzyc sciezki ani poprawiac tych liczb, gdy zmieni sie logo. Scieranie to
   przesuniecie schodzace do -100 przy `dasharray: 100` (kreska i tyle samo przerwy):
   ujemne zabiera kreske tak, jak dodatnie ja przynosilo. */
.loader {
  display: inline-block;
  flex: none;
  width: 17px;
  height: 17px;
  vertical-align: -4px;
  margin-right: 6px;
  /* Grubosc obrysu w JEDNOSTKACH KSZTALTU, nie w pikselach: pole ma 288 jednostek,
     a znak jest w nim zmniejszony do 0,8 - wiec na ekranie wychodzi z tego
     `wartosc x 0,8 x bok / 288`. Mala ikonka potrzebuje grubszej kreski niz duza,
     inaczej schodzi do wloska; dlatego to zmienna, a nie jedna liczba w ksztalcie. */
  --kreska: 34;
}
.sesja-czeka .loader { margin-right: 0; width: 16px; height: 16px; }
/* Kolowrotek jako jedyna tresc ekranu, a nie znaczek przy zdaniu: stoi sam, wiec rosnie
   do skali tarczy obok i traci odstep w linii. Przy tej wielkosci kreska moze zejsc
   do proporcji z logo. */
.loader--duzy {
  width: 52px;
  height: 52px;
  margin-right: 0;
  vertical-align: 0;
  --kreska: 20;
}

/* Obrys dymka w akcencie, slupki biale - tak jak w logo, gdzie fala jest biala na
   pomaranczy. Tu pomaranczy nie ma (dymek jest sam obrysem), wiec biel czyta sie
   z tla i mowi „to jest ta fala", zamiast zlewac sie z kreska dymka. */
.loader-obrys,
.loader-kreska {
  fill: none;
  stroke-linejoin: round;
  stroke-linecap: round;
  stroke-dasharray: 100;
}
.loader-obrys {
  stroke: var(--accent);
  stroke-width: var(--kreska);
  animation: rysuj-obrys 3s ease-in-out infinite;
}
/* Grubosc kreski slupka NIE jest tu: niesie ja atrybut ksztaltu, bo rowna sie szerokosci
   slupka w logo i jest jego geometria, a nie decyzja o wygladzie. */
.loader-kreska {
  stroke: var(--text);
  animation: rysuj-kreske 3s ease-in-out infinite;
}
/* Slupki ida PO dymku i jeden po drugim - stad opoznienia; ta sama klatkowka na
   wszystkich trzech, bo roznic ma je kolejnosc, a nie tempo. */
.loader-kreska--1 { animation-delay: .12s; }
.loader-kreska--2 { animation-delay: .24s; }
.loader-kreska--3 { animation-delay: .36s; }
@keyframes rysuj-obrys {
  0% { stroke-dashoffset: 100; }
  34%, 68% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -100; }
}
@keyframes rysuj-kreske {
  0%, 30% { stroke-dashoffset: 100; }
  48%, 70% { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -100; }
}
@media (prefers-reduced-motion: reduce) {
  .mic.rec::after { animation: none; opacity: .8; }
  /* Ikona zostaje tam, gdzie zjechala — gasnie sam puls. */
  .mic.rec .mic-ikona .ico { animation: none; }
  /* Kolowrotek ze znaku: zostaje SAM ZNAK, dorysowany do konca. Bez tego po zatrzymaniu
     ruchu zostawal dymek narysowany w polowie - czyli kreska, ktora nic nie znaczy.
     Informacja „to nadal idzie" jest tez w liczniku i w napisie obok. */
  .loader-obrys, .loader-kreska { animation: none; stroke-dashoffset: 0; }
  * { transition-duration: .01ms !important; }
}

/* Tryb jasny podmienia SAME TOKENY. Wczesniej powtarzal zielen #157F22 w pieciu
   regulach — kazdy nowy element w tej barwie trzeba bylo pamietac, zeby dopisac tu
   szosta. Teraz nie trzeba pamietac o niczym. */

/* --------------------------------------------------------------- strona startowa */
/* Ekran logowania jest zarazem STRONA STARTOWA serwisu (od 2026-09-13): `gadaj.pl`
   to adres publiczny, a stalo pod nim samo pole hasla - kto trafial tu pierwszy raz,
   nie mial z czego wyczytac, czym to jest.

   Do tego dnia tresc byla wysrodkowana w pionie (`justify-content: center`), bo ekran
   mial jedna rzecz do zrobienia. Teraz tresci jest wiecej niz widok, a wysrodkowany
   pojemnik flex, ktory sie przepelni, uciekalby GORA poza obszar przewijania - czyli
   logo i haslo bylyby nie do doscrollowania. Strona lezy wiec przy gornej krawedzi
   i zwyczajnie sie przewija.

   Jedno pole hasla, bez listy osob: publiczny adres nie zdradza, kto tu cwiczy. */
#s-login {
  justify-content: flex-start;
  align-items: center;
  gap: 28px;
}

/* Naglowek: znak, zdanie ucznia i odpowiedz na nie. */
.lead {
  display: grid;
  justify-items: center;
  gap: 14px;
  text-align: center;
  margin-top: 4px;
}

/* Logo zamiast pytania „Kto ćwiczy?" (do 2026-09-11). Ekran logowania to jedyne
   miejsce, w ktorym serwis przedstawia sie z nazwy, wiec naglowkiem strony jest tu
   znak; tresc naglowka niesie `alt` obrazka.

   Szerokosc ma trzy ograniczenia i kazde odpowiada na inne pytanie: `52vw` - zeby na
   waskim telefonie zostal margines, `210px` - zeby na monitorze logo nie uroslo na pol
   ekranu, `22vh` - zeby na NISKIM widoku (telefon poziomo, niskie okno przegladarki)
   znak zszedl z drogi. Wartosci zmalaly 2026-09-13 razem z dojsciem hasla i atutow:
   przy dawnych `min(62vw, 260px, 30vh)` sam znak zabieral polowe pierwszego ekranu
   i zdanie, po ktore ktos tu przyszedl, zaczynalo sie pod krawedzia. */
.logo { margin: 0; line-height: 0; }
.logo img { width: min(52vw, 210px, 22vh); height: auto; }

/* Haslo przewodnie. Szeryf, bo to zdanie MOWIONE - dokladnie to, co uczen mowi
   o sobie - a nie napis interfejsu; ta sama zasada co przy zdaniu w sesji
   i transkrypcji pod nim. */
.lead-cytat {
  margin: 0;
  max-width: 17ch;
  font: 400 clamp(22px, 6.6vw, 28px)/1.35 var(--serif);
  text-wrap: balance;
}

/* Odpowiedz na haslo: glos aplikacji, wiec grotesk i wyciszenie. */
.lead-odp {
  margin: 0;
  max-width: 28ch;
  font-size: 15px;
  line-height: 1.45;
  color: var(--muted);
}

/* Cztery atuty, siatka 2 x 2. Zbior zamkniety i krotki, wiec kafle - tak jak wybor
   jezyka, a nie lista. Wyciszone: akcent tego ekranu nosi „Wejdź", a atut nie jest
   stanem ani akcja. Roznice miedzy kaflami niesie napis I ksztalt ikony. */
.atuty {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  width: 100%;
  max-width: 340px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.atut {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
  padding: 14px;
  background: var(--bg-2);
  border-radius: var(--r-m);
  font-size: 14px;
  line-height: 1.3;
}
/* Wlasna klasa zamiast `.ico`: tamta wymusza 17 px i `translateY(3px)`, czyli rozmiar
   ikony w linii tekstu. Tutaj ikona stoi NAD napisem i ma swoja skale. */
.atut-ico {
  width: 24px;
  height: 24px;
  color: var(--muted);
  flex: none;
}
.login {
  display: grid;
  gap: 12px;
  width: 100%;
  max-width: 340px;
  margin: 0 auto;
  padding: 20px;
  background: var(--bg-2);
  border-radius: var(--r-l);
}

/* „Zaloguj przez Google" stoi POD karta i jest osobnym blokiem, wiec bez sufitu
   rozlewalby sie na cala szerokosc ekranu - szerzej niz karta nad nim i niz pas
   zrzutow pod nim. Jedna miara dla calej kolumny. */
#s-login > .wide { max-width: 340px; }

/* Dwa pola tego samego ekranu: login i haslo wygladaja identycznie. */
.login-pole {
  width: 100%;
  height: 56px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--bg-3);
  color: inherit;
  font: inherit;
  font-size: 17px;          /* ponizej 16 px iOS przybliza pole przy dotknieciu */
  text-align: center;
}

/* Kropki hasla rozstrzelone, zeby dalo sie policzyc znaki. Login zostaje zwykly. */
.login-pass { letter-spacing: 0.08em; }

.login-pole::placeholder {
  color: var(--muted);
  letter-spacing: normal;
}

/* Obrys pojawia sie wylacznie na polu aktywnym — jedyny przypadek, w ktorym ramka
   niesie informacje, a nie rysuje krawedz warstwy. */
.login-pole:focus {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}

/* Regulamin i polityka pod formularzem. Wyciszone i male: sa obowiazkowe do pokazania,
   ale nie sa tym, po co ktos tu przyszedl. Bez akcentu — ten nosi „Wejdź". */
.login-dokumenty {
  display: flex;
  gap: 20px;
  margin: 0;
  font-size: 14px;
}

.login-dokumenty a {
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px solid var(--line);
  padding-bottom: 2px;
}

/* Pas zrzutow ekranu pod logowaniem - przewijany palcem w bok, jak karta aplikacji
   w Google Play. Ramki sa na razie PUSTE; podpis nad pasem mowi o tym wprost, zeby
   cztery ciemne prostokaty nie czytaly sie jak obrazki, ktore sie nie wczytaly. */
.ekrany { width: 100%; max-width: 340px; }
.ekrany-podpis {
  margin: 0 0 10px;
  font-size: 13px;
  color: var(--muted);
}

/* Pas siega POZA margines ekranu (`-20px` = boczny padding `.screen`), zeby ostatnia
   widoczna ramka byla ucieta krawedzia telefonu, a nie marginesem - to ona mowi, ze
   jest co przewijac. Paska przewijania nie pokazujemy: na telefonie go nie ma,
   a na komputerze rysowalby kreske pod ramkami. */
.ekrany-pas {
  display: flex;
  gap: 12px;
  margin: 0 -20px;
  padding: 0 20px;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.ekrany-pas::-webkit-scrollbar { display: none; }

/* Proporcja ramki to ekran telefonu (9:19,5), bo to zrzuty z telefonu tu stana.
   Miare zadaje WYSOKOSC, a szerokosc wychodzi z proporcji: pas ma zajmowac tyle,
   ile mu wolno na ekranie telefonu, a nie tyle, ile wyjdzie z szerokosci ramki.
   Przy mierze od szerokosci (62% pasa) ramki mialy 430 px wysokosci i pod formularzem
   rosla sciana pustej powierzchni. */
.ekran {
  flex: none;
  height: min(38vh, 300px);
  aspect-ratio: 9 / 19.5;
  background: var(--bg-2);
  border-radius: var(--r-m);
  scroll-snap-align: center;
}


/* ---------------------------------------------------------------- rzad nad spisem */

/* Dwie akcje nad spisem: „Nowe zdania" i „Nowy dialog". Oba wyciszone, mimo ze obie cos
   zaczynaja — akcentem spisu jest sesja w toku, a pomaranczowy przycisk nad nia znosilby
   ja do zera. Tlo maja wiec to samo i roznice niesie napis oraz ikona: kartka z liniami
   kontra dwa dymki. */
.sesje-akcje {
  display: flex;
  gap: 12px;
  margin-bottom: 12px;
}
/* Ikona STOI NAD napisem, a nie obok niego (do 2026-09-16 bylo odwrotnie). Powodem sa
   kropki menu jezyka, ktore doszly na koniec rzedu: przycisk zwezil sie o polowe ich
   szerokosci i „Nowe zdania" przestalo miescic sie w jednej linii, wiec i tak lamalo sie
   na dwie - tyle ze przypadkiem i brzydko. Ulozone pionowo kafle potrzebuja na napis
   tylko jego wlasnej szerokosci i wychodza takiej samej wysokosci jak zlamany wiersz. */
.wide--para {
  flex: 1;
  min-width: 0;
  padding: 11px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: var(--bg-2);
  color: var(--text);
  font-size: 15px;
}
/* Ikona w kaflu nie ma podnosic sie do linii pisma, jak w akapicie - stoi w swoim
   wierszu i srodkuje sie sama. */
.wide--para .ico { transform: none; }

/* Trzecia rzecz w rzedzie: kropki z tym, co dotyczy CALEGO jezyka, a nie jednej sesji.
   Ten sam `<details>` i ta sama lista pozycji (`.sesja-poz`), co przy wierszu spisu -
   rozni je tylko to, z ktorej strony rozwija sie szufladka.

   Wysokosc bierze sie z rzedu (`height: 100%` w rozciagnietym elemencie flex), a nie
   z wlasnego minimum: kropki wyzsze od sasiadow podnosilyby caly rzad, a razem z nim
   spis i kalendarz pod spodem. Szerokosc 44 px to najmniejszy sensowny cel dotykowy -
   ta sama, co przy kropkach wiersza. */
.sesje-menu { position: relative; flex: none; }
.sesje-menu > summary {
  display: grid;
  place-items: center;
  width: 44px;
  height: 100%;
  background: var(--bg-2);
  color: var(--muted);
  cursor: pointer;
  list-style: none;
  border-radius: var(--r-m);
}
.sesje-menu > summary::-webkit-details-marker { display: none; }
.sesje-menu[open] > summary, .sesje-menu > summary:active {
  background: var(--bg-3);
  color: var(--text);
}
/* Menu lezy NAD rzedem, wiec bierze powierzchnie o stopien wyzsza (patrz ../DESIGN.md).
   Prawa krawedz szufladki rowna sie z prawa krawedzia ekranu, bo kropki stoja na koncu
   rzedu i lista rozwinieta w lewo nie ma jak wyjsc poza widok. */
.sesje-menu > nav {
  position: absolute;
  right: 0;
  top: calc(100% + 6px);
  z-index: 3;
  min-width: 11.5em;
  padding: 4px;
  background: var(--bg-3);
  border-radius: var(--r-s);
  box-shadow: 0 14px 34px -12px rgba(0, 0, 0, .8);
}

/* Linijka pod rzedem: dlaczego „Nowe zdania" jest nieczynne albo co teraz liczy model.
   `.analyze-state` daje jej wyglad, tutaj zostaje sam odstep. */
#zdania-state { margin: -4px 0 12px; }

/* ---------------------------------------------------------------- rozmowa (dialog) */

/* Scenka po polsku: to instrukcja, nie material jezykowy — grotesk i wyciszenie.
   Lezy WEWNATRZ `.dymki`, wiec `margin-bottom` odpada: odstepy trzyma `gap` pudelka.
   Kreskowany obrys zamiast wypelnienia odroznia ja od dymka rozmowcy, ktory ma
   te sama powierzchnie `--bg-2`. */
.dialog-scena {
  flex: none;
  padding: 12px 14px;
  margin: 0 0 2px;
  border: 1px dashed var(--line);
  border-radius: var(--r-m);
  font-size: 14px;
  line-height: 1.45;
  color: var(--muted);
}

/* Zyczenie ucznia: to, co nagral po polsku, ZANIM powstala scenka. Stoi nad nia, bo
   scenka jest jego skutkiem, i jest mniejsze od niej — scenka to tresc ekranu, a to
   tylko przypomnienie, o co uczen prosil. Bez obrysu, zeby dwie ramki jedna nad druga
   nie robily z gory ekranu plotu. */
.dialog-zyczenie {
  flex: none;
  margin: 0;
  padding: 0 14px;
  font: 400 13px/1.45 var(--sans);
  color: var(--muted);
}
.dialog-zyczenie span { opacity: .7; }

.dymki {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 10px;
  overflow-y: auto;
  padding-bottom: 4px;
}

/* Dymek: rozmowca po lewej na karcie, uczen po prawej na powierzchni o stopien wyzszej.
   Strona i powierzchnia niosa mowce razem — sam kolor bylby jednym nosnikiem za malo. */
.dymek {
  position: relative;
  max-width: 86%;
  padding: 10px 13px;
  border-radius: var(--r-m);
}
.dymek--rozmowca {
  align-self: flex-start;
  background: var(--bg-2);
  border-bottom-left-radius: 6px;
}
.dymek--ja {
  align-self: flex-end;
  background: var(--bg-3);
  border-bottom-right-radius: 6px;
}
/* Material jezykowy szeryfem, tak jak zdanie w sesji i wzorzec w raporcie. */
.dymek-tekst {
  font: 400 17px/1.4 var(--serif);
  word-break: break-word;
}
.dymek-play {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 28px;
  height: 28px;
  opacity: .55;
}
.dymek--ja .dymek-play { right: auto; left: 6px; }
.dymek-play:active { opacity: 1; }
.dymek-tekst { padding-right: 26px; }
.dymek--ja .dymek-tekst { padding-right: 0; padding-left: 26px; }

/* Czekanie na transkrypcje wlasnej wypowiedzi: groteskiem i wyciszone, bo to glos
   aplikacji, a nie material jezykowy — szeryf zostaje dla tego, co uczen powiedzial. */
.dymek-czeka {
  display: flex;
  align-items: center;
  font: 400 13.5px/1.45 var(--sans);
  color: var(--muted);
}

/* Uwaga do wypowiedzi: oddzielona kreska, groteskiem — to glos aplikacji, nie rozmowy. */
.dymek-uwaga {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px solid var(--line);
  font: 400 13.5px/1.45 var(--sans);
  color: var(--muted);
}
.dymek-pct {
  display: inline-block;
  margin-top: 6px;
  font: 500 12.5px/1 var(--sans);
  font-variant-numeric: tabular-nums;
}
.dymek-pct.good { color: var(--good); }
.dymek-pct.half { color: var(--half); }
.dymek-pct.bad  { color: var(--rec); }

/* Konsola rozmowy: tarcza mniejsza niz w sesji, bo nad nia stoi cala rozmowa
   i to ona jest trescia ekranu. */
/* Ekran rozmowy jest jedynym o STALEJ wysokosci: przewija sie sama rozmowa, a konsola
   z tarcza zostaje przy dolnej krawedzi. Przy `min-height` jak reszta ekranow lista
   dymkow rosla w dol i po kilku wypowiedziach mikrofon uciekal pod krawedz. */
.screen--dialog {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100dvh;
  overflow: hidden;
}
.z-belka .screen--dialog { height: calc(100dvh - var(--belka-pelna)); }
/* Tarcza siedzi w prawym dolnym rogu, „zakończ rozmowę" w lewym: kciuk trzymajacego
   telefon lezy po prawej, a wyjscie ma byc daleko od tego, w co sie celuje w biegu.
   `row-reverse` zamiast zamiany miejscami w DOM — tarcza jest glowna akcja ekranu
   i ma zostac pierwsza dla klawiatury i czytnika. */
.dialog-konsola {
  display: flex;
  flex-direction: row-reverse;
  justify-content: space-between;
  align-items: flex-end;
  gap: 12px;
  padding-top: 10px;
}
.mic--rozmowa { width: min(38vw, 150px); }
.mic--rozmowa .mic-podpis { font-size: 15px; }
.mic--rozmowa + .kasuj { width: 34px; height: 34px; }

/* ---------------------------------------------------------------- ustawienia konta */

/* Dwa bloki i nic miedzy nimi: zmiana imienia u gory, usuniecie konta dosuniete do
   dolu ekranu. Kreski ani obrysu tu nie ma - warstwy robi jasnosc, a odleglosc mowi
   „to jest cos innego" wystarczajaco (patrz ../DESIGN.md). */
.ustawienia {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.ustawienia-etykieta {
  font: 500 14px/1.3 var(--sans);
  color: var(--muted);
}
/* Pole imienia. Osobne od `.login-pole` mimo podobienstwa: tamto jest pigulka na
   wysrodkowany login i haslo, a imie czyta sie tu jak zwykla tresc - do lewej i na
   promieniu reszty kart. Obrys na polu aktywnym jest ten sam, bo to jedyny przypadek
   w aplikacji, w ktorym ramka niesie informacje. */
.ustawienia-pole {
  width: 100%;
  height: 56px;
  padding: 0 18px;
  border: 0;
  border-radius: var(--r-m);
  background: var(--bg-3);
  color: inherit;
  font: inherit;
  font-size: 17px;          /* ponizej 16 px iOS przybliza pole przy dotknieciu */
}
.ustawienia-pole:focus {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--accent);
}
.ustawienia-opis {
  font: 400 13px/1.45 var(--sans);
  color: var(--muted);
}
.ustawienia .wide { margin-top: 8px; }

/* Usuniecie konta stoi przy dolnej krawedzi - to ostatnia rzecz na tym ekranie
   i jedyna nieodwracalna. */
.ustawienia-koniec {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Czerwien jest tu drugim nosnikiem obok kosza i slowa, a nie jedynym - ten sam
   uklad, co przy „Usun jezyk" w menu spisu. Powierzchnia zostaje wyciszona
   (`.wide.ghost`): akcent nalezy do akcji, ktora ekran PROPONUJE, a tej nie proponuje. */
/* `.wide.ghost` ustawia kolor tekstu, wiec sama nazwa wariantu przegralaby kaskade -
   stad obie klasy w selektorze. */
.wide.ustawienia-kasuj {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--rec);
}
.ustawienia-kasuj .ico { transform: none; }
