/* goxlsxgo — podgląd arkusza XLSX.
 *
 * Kolory idą przez zmienne, a nie wprost, bo arkusz niesie barwy bezwzględne, a
 * strona hosta ma motyw jasny i ciemny. Komórka BEZ zadanego tła i BEZ zadanego
 * koloru czcionki nie dostaje tu żadnej deklaracji — dziedziczy motyw strony i
 * dzięki temu pusty arkusz wygląda w ciemnym motywie jak reszta aplikacji.
 * Komórki z jawnymi kolorami z Excela zachowują je w obu motywach.
 */

.xg {
  --xg-grid: #d7dbe0;
  --xg-head-bg: #f3f5f7;
  --xg-head-fg: #57606a;
  --xg-head-on: #dce3ea;
  --xg-surface: #ffffff;
  --xg-fg: #1f2328;
  --xg-sel: rgba(37, 99, 235, 0.16);
  --xg-sel-edge: #2563eb;
  --xg-row-w: 3.5rem;
  /* Wysokość wiersza liter kolumn. W jednym miejscu, bo liczy się z niej także
   * wyjście awaryjne przesunięć zamrożonych wierszy (freezeCSS). */
  --xg-head-h: 22px;
  /* Linia podziału zamrożonych okienek — wyraźniejsza od zwykłej siatki, bo
   * ma powiedzieć „tu kończy się to, co stoi". Każdy arkusz kalkulacyjny ją
   * rysuje i bez niej wiersz 14 wygląda jak sąsiad wiersza 59. */
  --xg-split: #8a939c;
  /* Górna granica wysokości obszaru przewijania.
   *
   * Bez niej kontrolka wstawiona do kontenera o wysokości automatycznej
   * rozpycha się na całą wysokość arkusza: wiersze-atrapy wirtualnego
   * przewijania mają wtedy do czego rosnąć, więc element osiąga setki tysięcy
   * pikseli, przewija się okno zamiast siatki, a przyklejony nagłówek i pasek
   * zakładek wypadają poza kadr. height:100% tego nie ratuje — w rodzicu o
   * wysokości auto nie ma się do czego odnieść.
   *
   * Host, który sam nadaje kontrolce wysokość (np. kolumna flex o znanym
   * rozmiarze), wyłącza limit przez --xg-max-h: none. */
  --xg-max-h: 70vh;

  /* Plakietka „indeksuję…" — patrz .xg-busy-note. */
  --xg-busy-bg: #fdf1d6;
  --xg-busy-fg: #7c4a03;
  --xg-busy-edge: #d9ae66;

  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  /* Kontekst pozycjonowania dla plakietki .xg-busy-note. */
  position: relative;
  color: var(--xg-fg);
  font-size: 13px;
  line-height: 1.35;
}

@media (prefers-color-scheme: dark) {
  .xg:not([data-xg-light]) {
    --xg-grid: #3a4149;
    --xg-split: #6b747d;
    --xg-head-bg: #23282e;
    --xg-head-fg: #9aa4ae;
    --xg-head-on: #313841;
    --xg-surface: #1b1f24;
    --xg-fg: #e6edf3;
    --xg-sel: rgba(96, 165, 250, 0.2);
    --xg-busy-bg: #3b2a10;
    --xg-busy-fg: #f2c675;
    --xg-busy-edge: #7a5a22;
    --xg-sel-edge: #60a5fa;
  }
}

/* DaisyUI i inne motywy stemplujące korzeń atrybutem — wybór jawny wygrywa z
 * ustawieniem systemowym w obie strony. */
[data-theme="dark"] .xg {
  --xg-grid: #3a4149;
  --xg-split: #6b747d;
  --xg-head-bg: #23282e;
  --xg-head-fg: #9aa4ae;
  --xg-head-on: #313841;
  --xg-surface: #1b1f24;
  --xg-fg: #e6edf3;
  --xg-sel: rgba(96, 165, 250, 0.2);
  --xg-busy-bg: #3b2a10;
  --xg-busy-fg: #f2c675;
  --xg-busy-edge: #7a5a22;
  --xg-sel-edge: #60a5fa;
}

.xg-scroll {
  flex: 1 1 auto;
  min-height: 0;
  max-height: var(--xg-max-h);
  overflow: auto;
  background: var(--xg-surface);
  border: 1px solid var(--xg-grid);
  border-radius: 4px;
  outline: none;
  /* Bez tego przewijanie na styku z oknem modalnym przechodzi na tło. */
  overscroll-behavior: contain;
}

/* Główka dużego arkusza (Viewer.Progressive): plakietka, nie zasłona.
 *
 * Zasłona przekreślałaby cel — arkusz pokazujemy wcześnie właśnie po to, żeby
 * dało się CZYTAĆ nagłówki, zanim indeks się domknie. Blokowania nie robi więc
 * CSS: serwer po prostu nie wypisuje data-xg-select ani wirtualnego
 * przewijania, więc siatka nie reaguje sama z siebie. Zakładki to jedyne, co
 * trzeba wygasić ręcznie, bo są zwykłymi odnośnikami.
 */
.xg-busy-note {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  z-index: 5;
  max-width: 90%;
  padding: 9px 20px;
  border: 1px solid var(--xg-busy-edge);
  border-radius: 999px;
  /* Własne tokeny, nie kolory nagłówka: w barwach nagłówka plakietka była
   * szara na szarym i po prostu jej nie było widać. Bursztyn odcina się od
   * siatki i od obu motywów, a host może ją przemalować bez łatania
   * kontrolki. Bez animacji — w bazowym CSS kontrolki nie ma efektów. */
  background: var(--xg-busy-bg);
  color: var(--xg-busy-fg);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.14);
  font-size: 14px;
  font-weight: 600;
  text-align: center;
  pointer-events: none;
}

.xg-busy .xg-tab {
  pointer-events: none;
  opacity: 0.5;
}

.xg-table {
  /* separate, nie collapse: przyklejone komórki gubią przy collapse własne
   * krawędzie, bo obramowanie należy wtedy do tabeli, a nie do komórki. */
  border-collapse: separate;
  border-spacing: 0;
  table-layout: fixed;
  width: max-content;
  min-width: 100%;
}

.xg-table col,
.xg-table td,
.xg-table th {
  /* Szerokość z <col> ma być szerokością CAŁEJ komórki, razem z marginesami
   * i krawędzią — tak liczy ją Excel (widthToPx: znaki × 7 + 5) i tak trafia
   * do katalogu przesunięć zamrożonych kolumn. Bez tej deklaracji wynik
   * zależałby od hosta: strona z resetem à la Tailwind daje border-box, strona
   * bez niego content-box, czyli komórki szersze o marginesy i krawędź.
   * Przyklejona kolumna przeskakiwała wtedy o te kilkanaście pikseli
   * w momencie przypięcia. */
  box-sizing: border-box;
  /* Jednolita, znana wysokość jest warunkiem poprawności arytmetyki
   * przewijania: to, co się nie mieści, ma być przycięte, a nie rozepchnąć
   * wiersz ponad wysokość zapisaną w pliku. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 1px 5px;
  border-right: 1px solid var(--xg-grid);
  border-bottom: 1px solid var(--xg-grid);
  vertical-align: bottom;
}

/* Nagłówek kolumn: przyklejony do góry. */
.xg-table thead th {
  position: sticky;
  top: 0;
  z-index: 5;
  background: var(--xg-head-bg);
  color: var(--xg-head-fg);
  font-weight: 500;
  text-align: center;
  height: var(--xg-head-h);
}

/* Kolumna numerów wierszy: przyklejona do lewej. */
.xg-rn {
  position: sticky;
  left: 0;
  z-index: 2;
  width: var(--xg-row-w);
  background: var(--xg-head-bg);
  color: var(--xg-head-fg);
  font-weight: 400;
  text-align: right;
  user-select: none;
}

/* Narożnik siedzi w obu osiach naraz, więc musi być nad wszystkim. */
.xg-corner {
  position: sticky;
  left: 0;
  top: 0;
  z-index: 7;
  width: var(--xg-row-w);
  background: var(--xg-head-bg);
}

.xg-rncol { width: var(--xg-row-w); }
.xg-hidden { visibility: collapse; }

.xg-empty {
  padding: 1.5rem;
  opacity: 0.6;
}

/* Wiersz ukryty w arkuszu.
 *
 * Pokazujemy go, zamiast zwijać jak Excel — w arkuszu przekazanym do badania
 * ukryty wiersz bywa dokładnie tym, który ktoś schował, a czytelnik podglądu
 * nie ma jak go odkryć. Rozróżnienie robi sama kontrolka: przygaszona treść i
 * pochylony numer wiersza. Bez paska obok tabeli — brakuje odróżnienia, nie
 * informacji.
 *
 * Numeracja i tak ma dziury (Excel nie zapisuje wierszy pustych), więc sam
 * przeskok numeru niczego by nie powiedział. */
.xg-row-off .xg-td {
  opacity: 0.45;
}
.xg-row-off .xg-rn {
  font-style: italic;
  opacity: 0.7;
}

/* Wiersze-atrapy wirtualnego przewijania. Nie mają klasy .xg-td ani żadnej
 * treści — zaznaczanie i klikanie muszą je pomijać. */
.xg-vspacer td {
  padding: 0;
  border: 0;
}

/* --- zaznaczanie --- */

.xg-td.xg-on {
  background-image: linear-gradient(var(--xg-sel), var(--xg-sel));
}
.xg-ch.xg-on,
.xg-rn.xg-on {
  background: var(--xg-head-on);
  color: var(--xg-fg);
}
.xg-scroll.xg-dragging {
  user-select: none;
  cursor: cell;
}

.xg-status {
  /* Nie kurczyć: w kolumnie flex rozciąga się WYŁĄCZNIE obszar przewijania.
     Bez tego pasek stanu i zakładki są duszone, gdy siatka bierze całą
     dostępną wysokość — w oknie pełnoekranowym zakładki schodziły do 4 px. */
  flex: 0 0 auto;
  display: flex;
  gap: 1.25rem;
  padding: 0.25rem 0.5rem;
  font-size: 12px;
  color: var(--xg-head-fg);
  border-top: 1px solid var(--xg-grid);
}
.xg-status[hidden] { display: none; }

/* Pasek opisujący zaznaczenie, którego agregat jeszcze nie wrócił. Liczby
 * zostają na miejscu — układ ma się nie ruszać — ale przygaszone, bo dotyczą
 * poprzedniego wyboru. To stan danych, nie efekt: bez tego pasek przez kilka
 * sekund po prostu kłamie. Przy błędzie znacznik ZOSTAJE, bo wartości
 * naprawdę są nieaktualne. */
.xg-status.xg-stale { opacity: 0.45; }
.xg-stat:empty { display: none; }
.xg-stat b { font-weight: 600; color: var(--xg-fg); }

/* --- zablokowane okienka --- */

/* Blokadę włącza JEDNA klasa na korzeniu kontrolki (.xg-frozen), a nie inny
 * render. To dlatego przełącznik w pasku narzędzi nie potrzebuje ani żądania
 * do serwera, ani przerysowania: przy wyłączonej blokadzie te same komórki
 * jadą z treścią, dokładnie jak przedtem.
 *
 * Przesunięcia `left` per kolumna dokłada katalog wstrzykiwany w <style>
 * wewnątrz kontrolki (freezeCSS) — tu jest wyłącznie to, co wspólne. */
.xg-frozen .xg-fz {
  position: sticky;
  z-index: 2;
  /* Komórka bez własnego tła jest przezroczysta, więc przyklejona
   * przepuszczałaby pod sobą przewijaną treść. Kolor z pliku i tak wygra:
   * katalog stylów celuje selektorem #id .xg-sN, mocniejszym o identyfikator. */
  background: var(--xg-surface);
}

/* Zamrożony wiersz. Przyklejamy KOMÓRKI, nie <tr>: przyklejony wiersz tabeli
 * bywa w przeglądarkach ignorowany, przyklejona komórka działa wszędzie — tak
 * samo robi wiersz liter powyżej. Przesunięcie `top` per wiersz dokłada katalog
 * (freezeCSS), bo blok bywa niejednolitej wysokości. */
.xg-frozen .xg-fr > td,
.xg-frozen .xg-fr > th {
  position: sticky;
  z-index: 3;
  background: var(--xg-surface);
}

/* Przecięcia. Kolejność warstw jest tu jedyną, jaka trzyma się kupy przy
 * przewijaniu w obie strony naraz: im więcej osi coś trzyma, tym wyżej.
 *
 *   zwykła komórka 0 · zamrożona kolumna 2 · zamrożony wiersz 3
 *   przecięcie 4 · wiersz liter 5 · litera zamrożonej kolumny 6 · narożnik 7 */
.xg-frozen .xg-fr > .xg-fz,
.xg-frozen .xg-fr > .xg-rn {
  z-index: 4;
}
.xg-frozen .xg-fr > .xg-rn {
  background: var(--xg-head-bg);
}

/* Litera zamrożonej kolumny stoi w obu osiach naraz — jak narożnik, więc i
 * warstwa tuż pod narożnikiem. */
.xg-frozen .xg-ch.xg-fz {
  z-index: 6;
  background: var(--xg-head-bg);
}

/* --- pasek dolny: zakładki i narzędzia --- */

.xg-footbar {
  flex: 0 0 auto;
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  min-width: 0;
}

/* W pasku dolnym to zakładki oddają miejsce, a nie narzędzia: zakładek bywa
 * dwadzieścia i mają własne przewijanie, a przycisków jest kilka i muszą być
 * widoczne. */
.xg-footbar .xg-tabs {
  flex: 1 1 auto;
  min-width: 0;
}

.xg-tools {
  flex: 0 0 auto;
  display: flex;
  gap: 2px;
  padding-top: 4px;
  margin-left: auto;
}

/* Przyciski paska są SAMĄ IKONĄ. Pasek stoi w linii zakładek, a te bywają
 * długie i liczne — podpisy zjadałyby im miejsce. Nazwa nie ginie: idzie
 * w aria-label dla czytnika ekranu i w title jako podpowiedź. */
.xg-tool {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  padding: 3px 7px;
  font: inherit;
  font-size: 12px;
  line-height: 1.35;
  color: var(--xg-head-fg);
  background: var(--xg-head-bg);
  border: 1px solid var(--xg-grid);
  border-top: none;
  border-radius: 0 0 4px 4px;
  cursor: pointer;
}
.xg-tool:hover:not(:disabled) { background: var(--xg-head-on); }

/* Przycisk mówi o STANIE: wciśnięty znaczy „zamrożone". Stąd wyraźne
 * odróżnienie obu położeń — bez niego przełącznik niczego by nie komunikował. */
.xg-tool[aria-pressed="true"] {
  color: var(--xg-fg);
  background: var(--xg-head-on);
  border-color: var(--xg-sel-edge);
  font-weight: 600;
}
/* Nieaktywny przycisk traci WYPEŁNIENIE, nie tylko nasycenie.
 *
 * Wcześniej całą różnicą było `opacity: 0.45`, a to przy cienkiej ikonie 1 px
 * na jasnym pasku nie odróżnia niczego — nieaktywne „Kopiuj zaznaczenie"
 * wyglądało jak aktywne (uwaga Michała). Teraz aktywny jest wypełnionym
 * kafelkiem, nieaktywny samym obrysem: różnica jest w kształcie, a ta czyta się
 * kątem oka. Przezroczystości nie używamy z tego samego powodu, co w panelu
 * etapów — rozcieńcza wszystko naraz i nic nie rozstrzyga. */
.xg-tool:disabled {
  color: color-mix(in oklab, var(--xg-head-fg) 35%, transparent);
  background: transparent;
  border-color: color-mix(in oklab, var(--xg-grid) 45%, transparent);
  cursor: default;
}

/* --- pełny ekran --- */

/* Nakładka na całe okno, a NIE Fullscreen API przeglądarki: ten sam mechanizm,
 * co maksymalizacja siatki w gogridgo. Nie wymaga gestu, nie zabiera paska
 * przeglądarki i wygląda tak samo w oknie modalnym, co na stronie.
 *
 * `height: auto` kasuje `height: 100%` z korzenia — w pozycji stałej odnosi się
 * ono do bloku zawierającego, którym jest teraz kadr okna, więc razem z
 * `inset: 0` dawałoby zapętloną wysokość. */
.xg.xg-max {
  position: fixed;
  inset: 0;
  z-index: 90;
  margin: 0;
  height: auto;
  padding: 0.5rem;
  border-radius: 0;
  background: var(--xg-surface);
}

/* Limit wysokości przewijania musi zniknąć razem z tym, co nadał host.
 *
 * UWAGA DLA HOSTA: własną wysokość arkusza trzeba pisać z `:not(.xg-max)`,
 * bo selektor z identyfikatorem wygra z tą regułą i arkusz zostanie wysoki na
 * swoje 24 rem pośrodku pustego ekranu. Tak samo rozwiązuje to gogridgo. */
.xg.xg-max .xg-scroll {
  max-height: none;
  height: auto;
  resize: none;
}

/* Ikona mówi, co się stanie po kliknięciu: rozsunięte rogi, gdy jesteśmy
 * w kadrze, zsunięte — gdy na pełnym ekranie. Podmiana w CSS, nie w JS, bo
 * kontrolka rysuje własne SVG i nie ma biblioteki ikon do przeładowania. */
.xg-ico-min { display: none; }
.xg-max .xg-ico-max { display: none; }
.xg-max .xg-ico-min { display: inline-flex; }

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

.xg-tabs {
  flex: 0 0 auto;
  display: flex;
  gap: 2px;
  padding-top: 4px;
  overflow-x: auto;
  scrollbar-width: thin;
}

.xg-tab {
  flex: 0 0 auto;
  padding: 3px 12px;
  font-size: 12px;
  text-decoration: none;
  color: var(--xg-head-fg);
  background: var(--xg-head-bg);
  border: 1px solid var(--xg-grid);
  border-top: none;
  border-radius: 0 0 4px 4px;
  cursor: pointer;
}
.xg-tab:hover { background: var(--xg-head-on); }
.xg-tab-on {
  color: var(--xg-fg);
  background: var(--xg-surface);
  font-weight: 600;
}
/* Arkusz ukryty w Excelu pokazujemy, ale przygaszony — to informacja o pliku,
 * nie zaproszenie. */
.xg-tab-hidden { opacity: 0.55; font-style: italic; }
