/* Wyniki na żywo — flyball.
   Mobile-first: kibice patrzą na telefonach stojąc przy ringu, często
   w słońcu, więc kontrast i rozmiar czcionki są celowo wysokie. */

:root {
  --bg: #f6f7f9;
  --surface: #ffffff;
  --surface-2: #eef1f5;
  --text: #16202a;
  --text-dim: #5b6b7a;
  --line: #d6dde5;
  --accent: #0d5b7a;
  --accent-soft: #e3f1f7;

  /* Tory: regulamin ZSF — lewy czerwony, prawy niebieski. */
  --lane-left: #c62828;
  --lane-right: #1565c0;

  --running: #0a7d34;
  --running-bg: #e4f6ea;
  --next-bg: #fff7e0;
  --next-line: #e0a800;

  --radius: 10px;
  --gutter: 16px;

  /* Wysokość nagłówka ringu. Na telefonie narzucamy ją sztywno, bo sticky
     thead musi znać ten odstęp w CSS — inaczej trzeba by go mierzyć w JS.
     46 px zostawia 25 px na 24-pikselowe przyciski zwijania i drukarki. */
  --ringhead-h: 46px;
}

/* Domyślnie jasny. Motyw systemowy honorujemy tylko wtedy, gdy strona nie ma
   jeszcze ustawionego motywu — po wyborze użytkownika decyduje data-theme. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme]) {
    --bg: #11161c;
    --surface: #1a2129;
    --surface-2: #232c36;
    --text: #e8edf2;
    --text-dim: #9aa8b6;
    --line: #313c48;
    --accent: #58b6d8;
    --accent-soft: #10303d;
    --lane-left: #ef5350;
    --lane-right: #64b5f6;
    --running: #4ade80;
    --running-bg: #10301d;
    --next-bg: #2e2716;
    --next-line: #c99a12;
  }
}
:root[data-theme="dark"] {
  --bg: #11161c; --surface: #1a2129; --surface-2: #232c36;
  --text: #e8edf2; --text-dim: #9aa8b6; --line: #313c48;
  --accent: #58b6d8; --accent-soft: #10303d;
  --lane-left: #ef5350; --lane-right: #64b5f6;
  --running: #4ade80; --running-bg: #10301d;
  --next-bg: #2e2716; --next-line: #c99a12;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.5 system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

.wrap {
  /* Bez sztywnego limitu w pikselach — rozpiska (i wyrównany z nią nagłówek)
     ma brać tyle szerokości, ile okno daje, bo dwa ringi obok siebie i długie
     nazwy drużyn potrzebują miejsca. Na dużym ekranie jest go jednak za dużo:
     przy monitorze 27" wiersz ciągnie się przez pół metra i oko gubi się
     w drodze od godziny do wyniku. Stąd 90% — po 5% luzu z każdej strony.
     Poniżej progu desktopu limit nie działa: tam liczy się każdy piksel,
     a rynienka z paddingu wystarczy. */
  margin: 0 auto;
  padding-left: var(--gutter);
  padding-right: var(--gutter);
}
@media (min-width: 900px) {
  .wrap { max-width: 90%; }
}

/* ---------------------------------------------------------------- nagłówek */

/* Nagłówek i zakładki przypięte do góry przy przewijaniu. */
.stickytop {
  position: sticky; top: 0; z-index: 30;
  background: var(--surface);
  box-shadow: 0 1px 0 var(--line), 0 6px 14px rgba(0, 0, 0, .06);
}
.topbar {
  background: var(--surface);
  color: var(--text);
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.topbar .wrap { display: flex; align-items: center; gap: 14px; }
.brand { margin: 0 auto 0 4px; }

/* Jedno logo organizacji po lewej, jedno sponsora po prawej — wszędzie te same.
   Białe tło kadru trzyma czytelność także w ciemnym motywie. */
.orglogo, .sponsorlogo {
  height: 56px; width: auto; border-radius: 8px; background: #fff;
  padding: 4px; flex: none; object-fit: contain;
}
.sponsorlink { flex: none; display: inline-flex; }
/* <picture> (telefon dostaje inny kadr sponsora) nie może rozspoić układu. */
.sponsorlink picture { display: inline-flex; }
.sponsorlogo { max-width: 220px; }
@media (max-width: 520px) {
  .orglogo { height: 44px; }
  .sponsorlogo { height: 38px; max-width: 130px; }

  /* Telefon: nazwa zawodów w OSI EKRANU, nie w środku resztki miejsca. Oba
     boczne gniazda dostają równą szerokość — zmierzone kadry to 42 px (logo
     organizacji, 111x119 przy wysokości 44 px) i 56 px (sponsor, 219x137 przy
     38 px), więc samo `margin: auto` stawiałoby nazwę 7 px za bardzo w lewo.
     Logotypy nie rosną: 64 px to gniazdo z zapasem, a object-position dosuwa
     każdy do swojej krawędzi, żeby rynienki po bokach były równe.

     Ten sam próg co podmiana kadru sponsora (<source media> w index.html)
     i wysokości logotypów wyżej — to NIE jest 560 px reszty telefonu.
     Powyżej 520 px sponsor to wciąż baner STRR o szerokości do 220 px;
     gniazdo 64 px i tak by go nie zmieściło (min-width: auto go broni),
     więc wyrównanie byłoby pozorne. */
  body:not(.admin) .topbar .wrap { gap: 8px; }
  body:not(.admin) .topbar .wrap > .orglogo,
  body:not(.admin) .topbar .wrap > .sponsorlink { flex: 0 0 64px; }
  body:not(.admin) .topbar .wrap > .orglogo { object-position: left center; }
  body:not(.admin) .topbar .wrap > .sponsorlink { justify-content: flex-end; }
  body:not(.admin) .brand { margin: 0; flex: 1 1 auto; min-width: 0; text-align: center; }
}
.topbar h1 { margin: 0; font-size: 1.1rem; font-weight: 700; letter-spacing: .01em; color: var(--text); }
.topbar .dates { margin: 2px 0 0; font-size: .78rem; color: var(--text-dim); }

/* Zmiana motywu i status "na żywo" na poziomie rozpiski (pasek zakładek). */
.navtools { margin-left: auto; display: flex; align-items: center; gap: 10px; }
.themebtn {
  border: 1px solid var(--line); background: var(--surface); color: var(--text);
  width: 30px; height: 30px; border-radius: 7px; cursor: pointer;
  font-size: 1rem; line-height: 1; padding: 0;
}
.themebtn:hover { background: var(--surface-2); }

.live { display: flex; align-items: center; gap: 7px; font-size: .78rem; white-space: nowrap; color: var(--text-dim); }
.live .dot {
  width: 9px; height: 9px; border-radius: 50%;
  background: #9ec9d8; flex: none;
}
.live.ok .dot { background: #6ee7a0; box-shadow: 0 0 0 0 rgba(110,231,160,.7); animation: pulse 2.4s infinite; }
.live.stale .dot { background: #f5c451; }
.live.error .dot { background: #ff8a80; }
/* Godzina ostatniego kontaktu obok kropki. Pusta = brak elementu, żeby nie
   zostawiała po sobie odstępu (.live ma gap). */
.live .since { font-size: .72rem; font-variant-numeric: tabular-nums; opacity: .85; }
.live .since:empty { display: none; }
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(110,231,160,.6); }
  70%  { box-shadow: 0 0 0 7px rgba(110,231,160,0); }
  100% { box-shadow: 0 0 0 0 rgba(110,231,160,0); }
}
@media (prefers-reduced-motion: reduce) { .live.ok .dot { animation: none; } }

/* ---------------------------------------------------------------- zakładki */

.tabs {
  display: flex; align-items: center; gap: 4px;
  padding-top: 8px; padding-bottom: 8px;
  overflow-x: auto; scrollbar-width: thin;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}
.tab {
  flex: none;
  padding: 7px 13px;
  border-radius: 999px;
  color: var(--text-dim);
  text-decoration: none;
  font-size: .87rem;
  font-weight: 550;
  white-space: nowrap;
}
.tab:hover { background: var(--surface-2); color: var(--text); }
.tab[aria-current="page"] { background: var(--accent); color: #fff; }
.tab-muted { margin-left: auto; }
.tab-sep { width: 1px; height: 20px; background: var(--line); flex: none; margin: 0 4px; }

.daytabs { display: flex; gap: 6px; align-items: center; }
.daytabs button {
  padding: 7px 16px; border-radius: 999px; cursor: pointer;
  border: 1px solid var(--line); background: var(--surface); color: var(--text-dim);
  font: inherit; font-size: .87rem; font-weight: 550;
}
.daytabs button:hover { background: var(--surface-2); color: var(--text); }
.daytabs button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Zakładki dywizji — pod dniem, każda w kolorze swojej dywizji. */
.division-tabs {
  display: flex; gap: 6px; flex-wrap: wrap;
  padding-top: 8px; padding-bottom: 8px;
}
.division-tabs[hidden] { display: none; }
.divtab {
  border: 1px solid var(--line); border-left: 4px solid var(--dc, var(--accent));
  border-radius: 8px; padding: 5px 11px;
  color: var(--text); text-decoration: none; font-size: .84rem; font-weight: 600;
  background: var(--surface); white-space: nowrap;
}
.divtab:hover { background: var(--surface-2); }
.divtab[aria-current="page"] { background: var(--dc, var(--accent)); color: var(--dtx, #fff); border-color: var(--dc, var(--accent)); }

/* „Rozpiska" — pierwsza w belce, powrót do pełnej rozpiski dnia. */
.divtab.sched-tab { border-left-color: var(--accent); font-weight: 700; margin-right: 4px; }
.divtab.sched-tab[aria-current="page"] { background: var(--accent); border-color: var(--accent); color: #fff; }

/* Telefon: belka dywizji w JEDNEJ linii, przewijana palcem — jak .tabs wyżej.
   Zawijanie wpychało tu drugą i trzecią linię, a cały ten blok siedzi
   w .stickytop, więc każda z nich na stałe zjadała ~38 px ekranu.
   Chipy się nie kurczą: .tab daje im flex: none, .divtab white-space: nowrap.
   Bez body:not(.admin) — panel w ogóle nie ma belki dywizji. */
@media (max-width: 560px) {
  .division-tabs {
    flex-wrap: nowrap;
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
  }
  .division-tabs::-webkit-scrollbar { display: none; }
}

/* ---------------------------------------------------------------- treść */

main { padding-top: 14px; padding-bottom: 40px; min-height: 55vh; }
main:focus { outline: none; }

.placeholder { color: var(--text-dim); padding: 28px 0; }

h2.section {
  font-size: .82rem; text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim); margin: 22px 0 8px;
}
/* Drukarka na nagłówku ringu — sama ikona, bez podpisu. Excel obok niej
   to ten sam przycisk z inną ikoną. */
.printbtn, .xlsbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; padding: 0; cursor: pointer;
  border: 1px solid var(--line); border-radius: 7px;
  background: var(--surface); color: var(--text-dim);
}
.printbtn:hover, .xlsbtn:hover { border-color: var(--accent); color: var(--accent); }
/* Ikona drukarki jako maska, nie obrazek: maluje ją tło w currentColor, więc
   zmienia kolor razem z tekstem przycisku (najechanie, motyw ciemny). */
.printbtn::before {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 9V3h12v6M6 18H4a1 1 0 0 1-1-1v-5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v5a1 1 0 0 1-1 1h-2M6 14h12v7H6z' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* Arkusz z siatką i „X" w rogu — czytelne jako Excel bez logo producenta. */
.xlsbtn::before {
  --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 3h16a1 1 0 0 1 1 1v16a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1zM3 9h18M3 15h18M12 9v12' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3Cpath d='M6.5 4.6l3 3M9.5 4.6l-3 3' fill='none' stroke='black' stroke-width='1.6' stroke-linecap='round'/%3E%3C/svg%3E");
}
.printbtn::before, .xlsbtn::before {
  content: '';
  width: 17px; height: 17px;
  background: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}
/* Na nagłówku ringu drukarka idzie na prawy skraj — tytuł i notka o zwinięciu
   mają zostać razem po lewej. */
.card > h3.ringhead .printbtn,
.card > h3.ringhead .xlsbtn { margin-left: auto; width: 24px; height: 24px; flex: none; }
/* Przy dwóch ikonach auto-margines ma tylko pierwsza — dwa podzieliłyby wolne
   miejsce i drukarka stanęłaby w połowie nagłówka. */
.card > h3.ringhead .xlsbtn + .printbtn { margin-left: 0; }

/* Kontener wydruku istnieje zawsze, ale na ekranie go nie widać. */
#printarea { display: none; }

.ringgrid { display: grid; gap: 18px; }
@media (min-width: 900px) { .ringgrid.two { grid-template-columns: 1fr 1fr; } }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
}
.card > h3 {
  margin: 0; padding: 10px 14px;
  background: var(--surface-2);
  font-size: .9rem; font-weight: 650;
  border-bottom: 1px solid var(--line);
}

/* ---------------------------------------------------------------- rozpiska */

/* Tabela ma teraz osobne kolumny (Lp, dywizja, format, nr), więc na telefonie
   pozwalamy jej przewijać się w poziomie zamiast ściskać nazwy drużyn. */
.sched-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.sched { width: 100%; border-collapse: collapse; font-size: .88rem; }
.sched col.c-lp    { width: 34px; }
.sched col.c-time  { width: 74px; }
.sched col.c-div   { width: 48px; }
.sched col.c-fmt   { width: 52px; }
.sched col.c-no    { width: 44px; }
.sched col.c-slot  { width: 34px; }
.sched col.c-score { width: 70px; }
@media (max-width: 380px) { .sched { font-size: .82rem; } }
.sched th {
  text-align: center; font-size: .7rem; text-transform: uppercase;
  letter-spacing: .04em; color: var(--text-dim); font-weight: 600;
  padding: 7px 8px; border-bottom: 1px solid var(--line); white-space: nowrap;
}
/* Na wąskim ekranie skracamy nagłówki do inicjałów, żeby nie łamały tabeli. */
@media (max-width: 560px) {
  /* Na telefonie tabela ma się MIEŚCIĆ w szerokości karty, bez poziomego
     przewijania. table-layout: fixed przycina kolumny do zadanych szerokości
     i nie pozwala tabeli urosnąć ponad 100% — resztę miejsca biorą nazwy
     drużyn, które i tak się zawijają. */
  .sched:not(.admin) { table-layout: fixed; }
  /* Panel ma dodatkowo „Akcje" — pole godziny i sześć przycisków minut, same
     w sobie szersze niż pół telefonu. Wciskanie TEJ tabeli w 100% szerokości
     ściskało kolumny drużyn do zera, a wiersz rozciągało na pół ekranu w pionie.
     Panelowi pozwalamy więc przewijać się w poziomie (sched-scroll już to umie);
     strona kibica zostaje przy sztywnym układzie, bo ma się mieścić bez gestów. */
  .sched.admin { width: auto; min-width: 100%; }
  .sched th, .sched td { padding: 6px 3px; }
  .sched col.c-lp    { width: 20px; }
  .sched col.c-time  { width: 40px; }
  .sched col.c-slot  { width: 24px; }
  /* Dywizja, formuła i numer w jednej kolumnie (patrz narrowSched w app.js).
     Trzy osobne zjadały ponad 80 px — zwolnione miejsce idzie na wynik, żeby
     czasy speed trialu zmieściły się obok siebie, i na nazwy drużyn. */
  .sched col.c-dfm   { width: 40px; }
  .sched col.c-score { width: 52px; }
  .sched.hastimes col.c-score { width: 94px; }
  .sched .dfm { line-height: 1.2; padding-top: 4px; padding-bottom: 4px; text-align: center; }
  /* Wszystko jedno pod drugim i wyśrodkowane w kolumnie. Plakietka dywizji
     dostaje ciaśniejszy krój — w pełnym rozmiarze była szersza niż kolumna
     i wystawała w prawo, przez co cała trójka wyglądała na przesuniętą. */
  .sched .dfm > * { display: block; text-align: center; }
  .sched .dfm .divpill {
    width: fit-content; margin: 0 auto 1px;
    padding: 1px 5px; font-size: .62rem;
  }
  .sched .dfm .fmt { font-size: .66rem; }
  .sched .dfm .mno { font-size: .7rem; }
  /* Skrót nagłówka dotyczy WYŁĄCZNIE rozpiski — ranking ma w tej kolumnie
     zupełnie co innego (drużyna), więc „G" kłamałoby. */
  .sched:not(.rank) thead th:nth-child(2) { font-size: 0; }
  .sched:not(.rank) thead th:nth-child(2)::after { content: "G"; font-size: .7rem; }
  .sched:not(.rank) thead th.h-dfm { font-size: 0; }
  .sched:not(.rank) thead th.h-dfm::after { content: "Mecz"; font-size: .7rem; }
  /* Ranking na telefonie: drugi czas schodzi pod główny, zamiast rozpychać
     kolumnę — inaczej „15,00 (15,10)" nie mieści się w jednej linii. */
  .sched.rank col.c-lp      { width: 26px; }
  .sched.rank col.c-rankdiv { width: 74px; }
  .sched.rank col.c-score   { width: 62px; }
  .sched.rank .divpill { padding: 1px 6px; font-size: .68rem; }
  .sched.rank .second { display: block; }
  .sched.rank .left { display: block; font-size: .72rem; }
  /* Na telefonie wynik dostaje węższą czcionkę i ciaśniejszy odstęp przy
     dwukropku — inaczej „17,20 : 16,96" nie zmieściłoby się w jednej linii
     nawet po scaleniu kolumn D/F/M. */
  .sched:not(.rank) .score { font-size: .68rem; }
  .sched .score .respair { column-gap: .1em; }
  .sched.rank .rteam, .sched.rank thead th:nth-child(2) { padding-left: 7px; }
  /* „Poz." nie mieści się w 26 px i wchodzi na nagłówek drużyny — na telefonie
     wystarczy „#", bo kolumna z numerami i tak mówi sama za siebie. */
  .sched.rank thead th:nth-child(1) { font-size: 0; }
  .sched.rank thead th:nth-child(1)::after { content: "#"; font-size: .7rem; }

  /* ---- przypięte nagłówki rozpiski (tylko strona kibica) ----
     Przewijając długi ring widać wtedy cały czas, czyja to rozpiska i co
     znaczy która kolumna. Dwa warunki trzeba było najpierw zdjąć:
     .card ma overflow: hidden (obcina sticky), a .sched-scroll overflow-x
     (tworzy własny scrollport, więc sticky przykleiłby się do niego zamiast
     do ekranu). Strona kibica ma tu table-layout: fixed i nic nie wystaje,
     więc ten scroller jest i tak bezczynny — panel zostaje ze swoim. */
  body:not(.admin) .ringgrid > .card,
  body:not(.admin) .ringgrid > .card > .sched-scroll { overflow: visible; }

  /* :not(.collapsed) — zwinięta karta to SAM nagłówek, bez tabeli pod spodem.
     Nie ma czego przypinać, a wymuszona wysokość obcięłaby dopisek „— zwinięty
     (N meczów)", gdyby przy długiej nazwie ringu zawinął się na drugą linię. */
  body:not(.admin) .ringgrid > .card:not(.collapsed) > h3.ringhead {
    position: sticky; top: var(--sticky-h, 0px); z-index: 12;
    height: var(--ringhead-h); box-sizing: border-box;
    /* Zdjęte overflow: hidden przestało docinać górne rogi karty. */
    border-radius: calc(var(--radius) - 1px) calc(var(--radius) - 1px) 0 0;
  }
  /* sticky siedzi na TH, nie na thead ani tr — to jedyny wariant, który przy
     border-collapse: collapse działa zgodnie we wszystkich silnikach. */
  body:not(.admin) .ringgrid > .card .sched thead th {
    position: sticky; top: calc(var(--sticky-h, 0px) + var(--ringhead-h)); z-index: 11;
    /* Tło musi być nieprzezroczyste, inaczej wiersze przejadą pod spodem. */
    background: var(--surface);
    /* Przy border-collapse krawędź należy do tabeli, nie do komórki, i przy
       przewijaniu zostałaby na miejscu. Cień jest częścią komórki. */
    border-bottom: none;
    box-shadow: inset 0 -1px 0 var(--line);
  }
  /* Zdjęte overflow: hidden przestało docinać także DOLNE rogi. Widać to tylko
     wtedy, gdy ostatni wiersz ma własne tło — mecz w toku albo pasek przerwy. */
  body:not(.admin) .ringgrid > .card .sched tbody tr:last-child td:first-child {
    border-bottom-left-radius: calc(var(--radius) - 1px);
  }
  body:not(.admin) .ringgrid > .card .sched tbody tr:last-child td:last-child {
    border-bottom-right-radius: calc(var(--radius) - 1px);
  }
}
.sched td { padding: 7px 8px; border-bottom: 1px solid var(--line); vertical-align: middle; text-align: center; }
.sched tr:last-child td { border-bottom: none; }

.sched .lp { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.sched .time { font-variant-numeric: tabular-nums; white-space: nowrap; font-weight: 600; }
/* Realny start pokazuje już tylko panel (.sched.admin) — na stronie kibica
   tej klasy nie ma, ale tabela jest wspólna, więc styl zostaje tutaj. */
.sched .actual { display: block; font-size: .66rem; font-weight: 400; color: var(--text-dim); }
.sched .actual.pending { font-style: italic; }
.sched .fmt { font-size: .78rem; color: var(--text-dim); white-space: nowrap; }
.sched .mno { font-variant-numeric: tabular-nums; color: var(--text-dim); }

/* Dywizja oznaczona kolorem — ta sama dywizja zawsze tym samym, żeby dało się
   ją wodzić wzrokiem przez rozpiskę (jak na obecnej stronie). */
.sched .divpill {
  display: inline-block; font-size: .72rem; font-weight: 700; color: var(--dtx, #fff);
  background: var(--dc, var(--accent)); padding: 2px 7px; border-radius: 5px;
  white-space: nowrap;
}
.sched tr > td:first-child { box-shadow: inset 3px 0 0 var(--dc, transparent); }

/* Nazwy drużyn zawijamy zamiast przycinać i wyśrodkowujemy. */
.sched .team { white-space: normal; overflow-wrap: anywhere; text-align: center; }
/* Tor własnego meczu, którego jeszcze nie znamy („Zwycięzca 1N") — przygaszony
   i kursywą, jak .tbd na drabince. Panel ładuje ten arkusz, więc jedna reguła. */
.sched .team.tbd { color: var(--text-dim); font-style: italic; }
/* Slot drabinki („W1") przykleja się do nazwy toru od strony tego toru. */
.sched .slot {
  color: var(--text-dim); font-size: .74rem; font-weight: 600;
  white-space: nowrap; font-variant-numeric: tabular-nums; padding-left: 2px; padding-right: 2px;
}
.sched .slot-left  { text-align: right; }
.sched .slot-right { text-align: left; }
.sched .score {
  font-variant-numeric: tabular-nums; font-weight: 700;
  text-align: center; white-space: nowrap;
}
.sched .score .pending { color: var(--text-dim); font-weight: 400; }
/* Wynik jako trzy kolumny: wartość — dwukropek — wartość. Siatka wypełnia całą
   komórkę, a komórki tej kolumny mają w tabeli jednakową szerokość, więc
   dwukropek stoi w każdym wierszu w tej samej pionowej linii. Skrajne kolumny
   po 1fr dzielą wolne miejsce równo, przez co „NT" i „17,19" kończą się w tym
   samym punkcie. */
.sched .score .respair {
  display: grid; grid-template-columns: 1fr auto 1fr;
  align-items: baseline; column-gap: .28em;
}
.sched .score .respair .rl { text-align: right; }
.sched .score .respair .rr { text-align: left; }

/* Mecz, który biegnie: tło + cały wiersz pogrubiony (zamiast plakietki). */
.sched tr.running { background: var(--running-bg); }
.sched tr.running td { font-weight: 700; }
.sched tr.running .time { color: var(--running); }

/* Wiersz, który się zmienił, na moment rozbłyskuje i gaśnie. */
@keyframes rowflash {
  0%   { background: var(--next-bg); }
  100% { background: transparent; }
}
.sched tr.changed td { animation: rowflash 2.2s ease-out; }
.sched tr.running.changed td { animation: none; }
@media (prefers-reduced-motion: reduce) { .sched tr.changed td { animation: none; } }

tr.blockrow td {
  background: var(--surface-2); color: var(--text-dim);
  font-size: .78rem; font-weight: 600; text-transform: uppercase; letter-spacing: .05em;
  text-align: center;
}
/* Przerwa ciągnąca się przez lukę (drugi ring gra) — jeden ciągły pasek:
   kasujemy linie między kolejnymi wierszami przerwy. */
.sched tr.blockrow:has(+ tr.blockrow) td { border-bottom: none; }
.sched tr.blockrow.cont td { height: auto; }
/* Puste wyrównanie (ring nie gra, ale nie z powodu przerwy) — bez treści. */
.sched tr.spacer td { background: transparent; }

.finished {
  margin: 18px 0; padding: 14px 16px;
  background: var(--accent-soft); border-radius: var(--radius);
  border: 1px solid var(--line);
}
.finished strong { display: block; margin-bottom: 2px; }

/* ---------------------------------------------------------------- dywizje */

/* ------------------------------------------------------- ranking czasowy */
.ranknote { margin: 0 0 10px; font-size: .8rem; color: var(--text-dim); line-height: 1.45; }
.sched.rank col.c-rankdiv { width: 116px; }
.sched.rank .place { color: var(--text-dim); font-variant-numeric: tabular-nums; }
.sched.rank .rteam { text-align: left; white-space: normal; overflow-wrap: anywhere; }
.sched.rank thead th:nth-child(2) { text-align: left; }
.sched.rank .rtime { font-variant-numeric: tabular-nums; font-weight: 700; white-space: nowrap; }
/* Ósemka mistrzowska odcięta od reszty — granica dywizji jest tu najważniejsza. */
.sched.rank tr.champ .rteam { font-weight: 600; }
.sched.rank tr.champ:last-of-type td { border-bottom: 2px solid var(--accent); }
.sched.rank .divpill {
  display: inline-block; border-radius: 999px; padding: 1px 9px;
  font-size: .72rem; font-weight: 600; background: var(--surface-2); color: var(--text-dim);
}
.sched.rank .divpill.mistrz { background: var(--accent); color: #fff; }
/* Drugi czas rozstrzygnął remis — pokazujemy go, ale ciszej niż czas główny. */
.sched.rank .second { font-weight: 400; color: var(--text-dim); cursor: help; }
.sched.rank .tie { color: var(--text-dim); font-weight: 700; cursor: help; }
/* Mecze do rozegrania — podpowiedź przy nazwie, nie część wyniku. */
.sched.rank .left { font-weight: 400; color: var(--text-dim); white-space: nowrap; }

/* Klasyfikacja końcowa: w kolumnie miejsca stoi też „II wicemistrz", więc jest
   szersza niż „#" rankingu; medalowe miejsca wyróżnione jak na dekoracji. */
.sched.rank.final col.c-place { width: 104px; }
.sched.rank.final col.c-fdiv  { width: 84px; }
.sched.rank.final col.c-ftime { width: 76px; }
.sched.rank.final col.c-pts   { width: 56px; }
.sched.rank.final .place.medal { color: var(--text); font-weight: 700; }
.sched.rank.final .rdiv { color: var(--text-dim); white-space: normal; }
.sched.rank.final .rpts { font-variant-numeric: tabular-nums; }
.sched.rank.final .rteam.tbd { color: var(--text-dim); font-style: italic; }
/* Na telefonie sześć kolumn musi zostawić nazwie drużyny choć trochę miejsca. */
@media (max-width: 560px) {
  .sched.rank.final col.c-place { width: 70px; }
  .sched.rank.final col.c-fdiv  { width: 48px; }
  .sched.rank.final col.c-ftime { width: 46px; }
  .sched.rank.final col.c-pts   { width: 30px; }
  .sched.rank.final .place, .sched.rank.final .rdiv { font-size: .72rem; white-space: normal; }
  .sched.rank.final .rtime { font-size: .72rem; }
}

/* 250 px zamiast 190: przy 190 karty były ciasne, a dłuższe nazwy drużyn
   zawijały się na dwie linie prawie zawsze. Szersze karty = mniej zawijania
   i czytelniejsze wiersze wyścigów. */
.teamgrid { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); }

/* Kolumna z dociśniętą stopką: karty w jednym rzędzie siatki są równej
   wysokości, więc stopki zrównują się nawet wtedy, gdy wyżej coś się różni. */
.teamcard {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; display: flex; flex-direction: column;
}
.teamcard footer { margin-top: auto; }
/*
 * Nagłówek trzyma wysokość dwóch linii nazwy niezależnie od tego, ile zajmuje
 * konkretna drużyna. Bez tego „Great Minds of Warsaw Bullets" zawijało się na
 * wąskiej karcie i spychało całą jej zawartość o linijkę w dół — sąsiednie
 * karty stały wtedy rozjechane co do wiersza.
 *
 * Wysokość liczymy z rozmiaru nazwy: 2 linie × interlinia 1,25 + padding.
 */
.teamcard header {
  padding: 8px 10px; background: var(--surface-2); border-bottom: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center; gap: 6px;
  /* 2 linie nazwy (0,84 rem × 1,25) + padding, z zapasem na zaokrąglenia
     metryk czcionki — bez zapasu karta dwuliniowa wychodziła o piksel wyższa. */
  min-height: 3.25rem;
  text-align: center;
}
.teamcard header .name { font-size: .84rem; font-weight: 600; line-height: 1.25; }

.rounds { padding: 6px 8px 8px; display: grid; gap: 6px; }
.round { border: 1px solid var(--line); border-radius: 7px; overflow: hidden; }
.round > .rh {
  display: flex; justify-content: space-between; align-items: center;
  padding: 3px 7px; font-size: .72rem; font-weight: 600; color: #fff;
}
.round.left  > .rh { background: var(--lane-left); }
.round.right > .rh { background: var(--lane-right); }
/* Czas na środku swojej kolumny, punkty przy prawej krawędzi, numer wyścigu
   przy lewej. Kolumna punktów ma stałą szerokość — przy `auto` dopasowywała
   się do treści, więc jedno- i dwuznakowe wyniki stały nierówno. */
.heat {
  display: grid; grid-template-columns: 1.4em 1fr 1.6em; gap: 6px;
  padding: 2px 7px; font-size: .78rem; font-variant-numeric: tabular-nums;
}
.heat .tm { text-align: center; }
.heat .pts { text-align: right; }
.heat + .heat { border-top: 1px solid var(--line); }
.heat .n { color: var(--text-dim); }
.heat .nt { color: var(--text-dim); }
.heat .pts { font-weight: 650; }
.heat .pts.w { color: var(--running); }
/* ST: bez kolumny W/P — czas dostaje całą pozostałą szerokość i dalej stoi
   na jej środku. */
.heat.timeonly { grid-template-columns: 1.4em 1fr; }

.teamcard footer {
  display: flex; flex-wrap: wrap; gap: 4px 10px; padding: 6px 10px;
  border-top: 1px solid var(--line); background: var(--surface-2);
  font-size: .76rem; color: var(--text-dim);
}
.teamcard footer b { color: var(--text); font-variant-numeric: tabular-nums; }
/* Miejsce w osobnej linii pod BT i punktami: to podsumowanie całej karty,
   a nie kolejna liczba w rzędzie. Stąd pełna szerokość, środek i większy stopień. */
.teamcard footer .placefoot {
  flex-basis: 100%; text-align: center; white-space: nowrap;
  font-size: .92rem; padding-top: 2px;
}
.teamcard footer .placefoot b { font-size: 1em; }
/* Podium czyta się z odległości. */
.teamcard footer .placefoot.podium { color: var(--text); }
.teamcard footer .placefoot.podium b { font-weight: 800; }
/* Wyliczone (w nawiasie) zapisujemy ciszej — to nasz rachunek, nie werdykt EJS. */
.teamcard footer .placefoot.derived b { color: var(--text-dim); cursor: help; }
.teamcard footer .placefoot.derived.podium b { color: var(--text); }

/* ---------------------------------------------------------------- drabinka */

.bracket-scroll { overflow-x: auto; padding-bottom: 10px; }
.bracket { display: block; min-width: 640px; }
/* Desktop: drabinka na całą szerokość strony — viewBox skaluje rysunek w całości.
   Poniżej 900px zostaje rozmiar naturalny z przewijaniem w poziomie; skalowanie
   w dół dałoby na telefonie nieczytelne litery. */
@media (min-width: 900px) { .bracket { width: 100%; height: auto; } }
.bracket .bx-line { stroke: var(--line); stroke-width: 1.5; fill: none; }
.bracket .bx-box { fill: var(--surface); stroke: var(--line); stroke-width: 1; }
.bracket .bx-box.done { stroke: var(--accent); }
.bracket .bx-team { font-size: 11.5px; fill: var(--text); }
.bracket .bx-team.win { font-weight: 700; }
.bracket .bx-team.tbd { fill: var(--text-dim); font-style: italic; }
.bracket .bx-score { font-size: 11.5px; font-weight: 700; fill: var(--text); font-variant-numeric: tabular-nums; }
.bracket .bx-label { font-size: 9.5px; fill: var(--text-dim); }
.bracket .bx-no { font-weight: 700; }
.bracket .bx-seed { font-size: 9px; fill: var(--text-dim); }

.standings { margin-top: 18px; }
.standings table { border-collapse: collapse; font-size: .88rem; }
.standings td { padding: 5px 12px 5px 0; border-bottom: 1px solid var(--line); }
.standings td.pl { font-weight: 700; color: var(--accent); text-align: right; font-variant-numeric: tabular-nums; }
/* Puste miejsca trzymają szerokość tabeli, zanim padnie pierwsze rozstrzygnięcie. */
.standings td:nth-child(2) { min-width: 200px; }
.standings tr.pending td.pl { color: var(--text-dim); font-weight: 400; }

.note {
  margin: 12px 0; padding: 10px 12px; border-radius: 8px;
  background: var(--next-bg); border: 1px solid var(--next-line);
  font-size: .82rem;
}

.foot { color: var(--text-dim); font-size: .76rem; padding-bottom: 28px; }
.foot p { margin: 0; }

/* ---------------------------------------------------------------- filtr rozpiski */
.filterbar {
  display: flex; gap: 10px 14px; align-items: center; flex-wrap: wrap;
  margin: 0 0 14px; padding: 9px 11px;
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius);
}
.filtergroup { display: inline-flex; gap: 5px; align-items: center; flex-wrap: wrap; }
.flabel { font-size: .8rem; color: var(--text-dim); }
.chip-toggle {
  border: 1px solid var(--line); background: var(--surface); color: var(--text-dim);
  border-radius: 999px; padding: 4px 12px; font: inherit; font-size: .82rem; cursor: pointer;
}
.chip-toggle:hover { border-color: var(--accent); }
.chip-toggle.on { background: var(--accent); border-color: var(--accent); color: #fff; }
.clearfilter {
  border: 1px solid var(--line); background: var(--surface); color: var(--text);
  border-radius: 8px; padding: 5px 12px; font: inherit; font-size: .82rem; cursor: pointer;
}
.clearfilter:hover { background: var(--surface-2); }

/* Telefon: pasek filtra w jednej linii. Przewija się WYŁĄCZNIE grupa chipów
   dywizji — lista drużyn i „Wyczyść" zostają na miejscu, bo rozwijany panel
   (.tpanel) jest position: absolute i każdy overflow na przodku by go obciął.
   Etykieta „Dywizja:" znika: zjadała ~55 px, a chipy mówią same za siebie. */
@media (max-width: 560px) {
  body:not(.admin) .filterbar { flex-wrap: nowrap; gap: 8px; padding: 8px; }
  body:not(.admin) .filtergroup {
    flex: 1 1 auto; min-width: 0;
    flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none;
  }
  body:not(.admin) .filtergroup::-webkit-scrollbar { display: none; }
  body:not(.admin) .filtergroup > * { flex: none; }
  body:not(.admin) .teamfilter,
  body:not(.admin) .clearfilter { flex: none; }
  /* Etykieta „Dywizja:" siedzi WEWNĄTRZ przewijanej grupy, więc jej ukrycie nie
     zwalnia szerokości paska — sprawia tylko, że pierwszy chip widać od razu,
     zamiast trzeba go przewijać. Nazwę grupy niesie wtedy aria-label z renderFilterBar. */
  body:not(.admin) .flabel { display: none; }
  /* Miejsca faktycznie przybywa tutaj: przy 320 px na chipy zostawały 73 px
     (półtora chipa), bo sam „Wyczyść filtr" zajmował 105 px. Zwijamy go do
     kwadratowego „✕" — tą samą techniką co nagłówki tabeli wyżej, więc pełny
     napis zostaje w drzewie dostępności jako nazwa przycisku. */
  body:not(.admin) .clearfilter {
    font-size: 0; padding: 0; width: 32px; height: 32px; flex: none;
    display: inline-flex; align-items: center; justify-content: center;
  }
  body:not(.admin) .clearfilter::after { content: "✕"; font-size: .95rem; line-height: 1; }
  /* Jedna linia zepchnęła „Drużyny" na środek paska, a panel listy kotwiczy się
     lewą krawędzią przycisku — przy 260 px szerokości wystawał poza ekran.
     Kotwicę przenosimy z przycisku na CAŁY pasek, więc lista rozkłada się na
     jego szerokość. Panel jest position: absolute, a .filterbar nie ma overflow,
     więc dalej swobodnie wychodzi poza pasek w dół. */
  body:not(.admin) .filterbar { position: relative; }
  body:not(.admin) .teamfilter { position: static; }
  body:not(.admin) .tpanel { left: 0; right: 0; width: auto; max-width: none; }
}

.teamfilter { position: relative; }
.teamfilter > summary {
  list-style: none; cursor: pointer; user-select: none;
  border: 1px solid var(--line); background: var(--surface); border-radius: 8px;
  padding: 5px 12px; font-size: .82rem;
}
.teamfilter > summary::-webkit-details-marker { display: none; }
.teamfilter[open] > summary { border-color: var(--accent); }
.tpanel {
  position: absolute; z-index: 40; margin-top: 4px; width: 260px; max-width: 82vw;
  background: var(--surface); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 8px 20px rgba(0,0,0,.18); padding: 8px;
}
.tsearch {
  width: 100%; box-sizing: border-box; padding: 6px 8px; margin-bottom: 6px;
  border: 1px solid var(--line); border-radius: 6px; background: var(--bg); color: var(--text); font: inherit; font-size: .84rem;
}
.tlist { max-height: 250px; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }
.titem { display: flex; align-items: center; gap: 6px; font-size: .84rem; padding: 3px 4px; border-radius: 5px; cursor: pointer; }
.titem:hover { background: var(--surface-2); }
.tpanel .note { font-size: .8rem; color: var(--text-dim); padding: 4px; }

/* ---------------------------------------------------------------- zwijanie ringów */
.card > h3.ringhead { display: flex; align-items: center; gap: 8px; }
.collapsebtn {
  border: 1px solid var(--line); background: var(--surface); color: var(--text);
  width: 24px; height: 24px; border-radius: 6px; cursor: pointer; font-size: .8rem; line-height: 1;
  display: inline-flex; align-items: center; justify-content: center; flex: none;
}
.collapsebtn:hover { border-color: var(--accent); }
.collapsed-note { font-size: .8rem; color: var(--text-dim); font-weight: 400; }

.tconfirm {
  width: 100%; margin-top: 8px; padding: 7px 10px; border: none; border-radius: 7px;
  background: var(--accent); color: #fff; font: inherit; font-size: .84rem; font-weight: 600; cursor: pointer;
}
.tconfirm:hover { filter: brightness(1.06); }
/* Drabinka MP: przegrani schodzą kreską przerywaną (repasaż, mecze o miejsca). */
.bracket .bx-line.loser { stroke-dasharray: 4 3; }

/* ---------------------------------------------------------------- wydruk */
/*
 * Drukujemy wyłącznie to, co zbudował printDivision(): jedną tabelę meczów.
 * Reszta strony — belki, filtry, drabinka — na kartce tylko przeszkadza,
 * a sędzia potrzebuje listy „kto, kiedy, na którym torze".
 */
@media print {
  body.printing > *:not(#printarea) { display: none !important; }
  body.printing #printarea { display: block !important; }

  body.printing #printarea h2 {
    font-size: 15pt; margin: 0 0 2pt; color: #000; text-transform: none; letter-spacing: 0;
  }
  body.printing #printarea .printmeta { font-size: 9pt; color: #444; margin: 0 0 10pt; }

  body.printing #printarea .sched { width: 100%; border-collapse: collapse; font-size: 10pt; }
  body.printing #printarea .sched th,
  body.printing #printarea .sched td {
    border: 1px solid #999; padding: 3pt 5pt; text-align: center; color: #000;
  }
  body.printing #printarea .sched th { background: #eee; font-size: 8.5pt; text-transform: uppercase; }
  body.printing #printarea .sched .team { text-align: left; }
  body.printing #printarea .sched .slot { color: #444; font-size: 8.5pt; }
  /* Przerwa w rozpisce ringu — pasek na całą szerokość, jak na ekranie. */
  body.printing #printarea .sched tr.blockrow td {
    background: #eee; font-weight: 600; text-align: left; font-size: 9pt;
  }
  body.printing #printarea .sched .fmt { font-size: 8.5pt; }
  /* Wiersze nie mogą się łamać w poprzek stron. */
  body.printing #printarea .sched tr { break-inside: avoid; page-break-inside: avoid; }
  body.printing #printarea .sched thead { display: table-header-group; }

  @page { margin: 12mm; }
}
