/* =====================================================================
   kds — warstwa Design_System (zadanie 2.5)

   Wymagania: REQ-UX-02.1, REQ-UX-02.2, REQ-UX-02.3, REQ-UX-02.4,
              REQ-UX-02.5, REQ-UX-02.6, REQ-UX-32.6
   Projekt: design.md §2.5, §4.1.1, §4.4.1

   Ten plik jest wczytywany bezwarunkowo w `views/layouts/main.hbs`, PRZED
   blokami warunkowymi `homepage.css` / `matura.css` / `e8.css` /
   `pricing.css`. Kolejność jest celowa: rodziny `kh-*`, `km-*`, `k8-*` i
   `kp-*` mogą nadpisać komponent tylko świadomie, deklaracją o tej samej
   nazwie, a nie przez to, że akurat wczytały się później.

   Etap 1 wnosi tutaj dwie rzeczy i nic więcej:
   1. tokeny — kolory, odstępy, promienie, typografia, wysokości kontrolek
      (REQ-UX-32.6: jeden zestaw odstępów i jeden zestaw promieni),
   2. komponent `kds-button` z pełnym zestawem stanów (REQ-UX-02.4).

   `kh-primary-button` jest tu ALIASEM `kds-button kds-button--primary`, nie
   przepisanym komponentem. Dzięki temu strona główna, oba landingi i cennik
   dostają jeden zestaw wartości koloru, wysokości i promienia bez zmiany
   choćby jednego szablonu — a migracja pozostałych komponentów (`card`,
   `field`, `goal_option`, …) zostaje na etap 4. Wartości tokenów są celowo
   równe wartościom, które `homepage.css` już wysyła do przeglądarki, więc
   nałożenie warstwy nie zmienia wyglądu żadnej istniejącej strony; zmienia
   tylko to, gdzie te wartości są zdefiniowane.

   Stany są atrybutami i pseudoklasami (`:hover`, `:focus-visible`,
   `:active`, `:disabled`, `[aria-disabled]`, `[aria-busy]`), a nie osobnymi
   klasami wariantu. Stan „w toku” jest ustawiany przez
   `public/assets/js/kds_button.js` — ten sam wzorzec, który wcześniej żył
   wyłącznie w `setSubmitting` w `homepage.js`.

   ---------------------------------------------------------------------
   Zadanie 19.2 dokłada trzy rzeczy (REQ-UX-32.1, 32.2, 32.3, 32.5,
   REQ-UX-34.1, 34.3, 34.11, 34.12):
   1. widoczny pierścień `:focus-visible` dla każdego elementu
      interaktywnego, z kontrastem policzonym wobec tła I wobec koloru
      sąsiadującego,
   2. rejestr par treść–tło jako tokeny `--kds-pair-*` i rejestr wskaźników
      fokusu `--kds-focus-indicator-*`. Rejestry są DANYMI dla testu, nie
      dokumentacją: `tests/property/design_system.properties.test.js`
      (Property 47) liczy z nich stosunek luminancji względnej według WCAG
      2.1. Kontrast, który nie jest liczony, jest tylko zadeklarowany,
   3. dla każdego stanu niosącego informację — nośnik inny niż kolor
      (Property 21, REQ-UX-34.12).

   GRANICA TYCH TESTÓW, zapisana wprost. Testy automatyczne pokrywają
   strukturę znacznika, role, hierarchię nagłówków i kontrast par tokenów.
   PEŁNA ZGODNOŚĆ WCAG 2.1 AA (a na diagnozie WCAG 2.2 AA z REQ-OD-18)
   WYMAGA PRZEGLĄDU MANUALNEGO z technologiami asystującymi — kolejności
   fokusu na realnej stronie, ogłoszeń czytnika ekranu, obrazów tekstu,
   kontrastu treści złożonej z przezroczystością i oceny eksperckiej. To nie
   jest zadanie kodowania i żaden test w tym repozytorium tego nie zastąpi
   (design.md §4.4.2, §9.4).
   ===================================================================== */

:root {
  /* --- Kolor ------------------------------------------------------- */
  --kds-color-primary: #5b35f2;
  --kds-color-primary-strong: #4522d6;
  --kds-color-primary-soft: #f0ecff;
  /* Stopnie gradientu są osobnymi tokenami, bo to ONE są tłem, na którym leży
     etykieta przycisku głównego — a więc one, nie „gradient”, wchodzą do par
     kontrastu niżej. Gradient jest z nich składany, żeby wartość nie żyła w
     dwóch miejscach. */
  --kds-color-primary-from: #6840fa;
  --kds-color-primary-to: #4d25e5;
  --kds-color-primary-gradient: linear-gradient(135deg, var(--kds-color-primary-from), var(--kds-color-primary-to));
  --kds-color-on-primary: #ffffff;
  --kds-color-ink: #10152f;
  --kds-color-muted: #69708a;
  --kds-color-line: #e8e9f2;
  --kds-color-surface: #ffffff;
  --kds-color-surface-quiet: #faf9ff;
  --kds-color-background: #fbfbff;
  --kds-color-success: #28b779;
  --kds-color-warning: #f0b72f;
  --kds-color-attention: #f28b38;
  --kds-color-danger: #ef5b61;
  --kds-color-danger-ink: #a52f3a;
  /* Przesłona okna dialogowego. Jest tokenem, bo jest TŁEM pierścienia fokusu
     panelu — para kontrastu niżej składa ją nad tłem strony zapisem `over`. */
  --kds-color-scrim: rgba(16, 21, 47, 0.55);

  /* --- Odstępy: jeden zestaw (REQ-UX-32.6) ------------------------- */
  --kds-space-1: 4px;
  --kds-space-2: 8px;
  --kds-space-3: 12px;
  --kds-space-4: 16px;
  --kds-space-5: 24px;
  --kds-space-6: 32px;
  --kds-space-7: 48px;

  /* --- Promienie: jeden zestaw (REQ-UX-32.6) ----------------------- */
  --kds-radius-sm: 6px;
  --kds-radius-md: 7px;
  --kds-radius-lg: 10px;
  --kds-radius-xl: 16px;
  --kds-radius-pill: 999px;

  /* --- Typografia --------------------------------------------------
     `body` nie schodzi poniżej 16 px (REQ-UX-20.4), `support` poniżej
     14 px (REQ-UX-33.3). Tokeny są w px, bo to progi wymagań, a nie
     proporcje. */
  --kds-font-size-body: 16px;
  --kds-font-size-support: 14px;
  --kds-font-size-label: 15px;
  --kds-font-weight-regular: 400;
  --kds-font-weight-medium: 600;
  --kds-font-weight-strong: 700;
  --kds-line-height-tight: 1.2;
  --kds-line-height-body: 1.55;

  /* --- Szerokość bloku tekstu i nagłówek hero (REQ-UX-20.2, REQ-UX-20.3)
         `ch` jest tu jednostką z wymagania: „nie więcej niż 75 znaków”
         mierzy się w znakach, nie w pikselach, więc próg nie rozjeżdża się
         przy zmianie rozmiaru czcionki.
         Trzy tokeny hero to trzy z czterech kontroli łamania z REQ-UX-20.2
         (maksymalny rozmiar czcionki, szerokość kontenera, wysokość wiersza).
         Czwartą — jawnie wskazane miejsce łamania — niesie TREŚĆ nagłówka
         przez `helpers/heading_typography.helper.js`, bo CSS nie ma czym
         wskazać wyrazu, który ma zostać przy poprzednim. */
  --kds-text-measure-max: 75ch;
  --kds-hero-heading-max-width: 780px;
  --kds-hero-heading-size-max: 4.05rem;
  --kds-line-height-heading: 1.02;

  /* --- Wysokości kontrolek ----------------------------------------
     `min` to minimalny obszar dotykowy 44 × 44 px (REQ-UX-33.4). */
  --kds-control-height-min: 44px;
  --kds-control-height-md: 46px;
  --kds-control-height-lg: 48px;

  /* --- Fokus i cień -----------------------------------------------
     Trzy kolory pierścienia, bo pierścień musi mieć kontrast wobec DWÓCH
     rzeczy naraz: tła, na którym leży, i koloru sąsiadującego, czyli
     wypełnienia kontrolki (REQ-UX-34.3):
     - `color` — pierścień fioletowy: kontrolki o jasnym wypełnieniu,
     - `inverse` + `halo-color` — dwie warstwy dla wypełnienia fioletowego:
       biały pierścień odcina się od wypełnienia, ciemne halo od jasnego tła
       sekcji. Sam biały pierścień ma wobec tła strony 1,03:1, więc bez halo
       ten wskaźnik nie istnieje — dlatego halo jest tokenem, nie ozdobą,
     - `on-scrim` — panel okna dialogowego. Pierścień fioletowy ma wobec
       przesłony 1,57:1, czyli na ciemnym tle znika; ciemny ma 4,35:1 wobec
       przesłony i 17,9:1 wobec białego panelu. */
  --kds-focus-ring-width: 3px;
  --kds-focus-ring-offset: 2px;
  --kds-focus-ring-color: var(--kds-color-primary);
  --kds-focus-ring-inverse: #ffffff;
  --kds-focus-ring-halo-color: var(--kds-color-ink);
  --kds-focus-ring-halo: 0 0 0 5px var(--kds-focus-ring-halo-color);
  --kds-focus-ring-on-scrim: var(--kds-color-ink);
  --kds-shadow-primary: 0 9px 20px rgba(91, 53, 242, 0.23);
  --kds-shadow-primary-hover: 0 12px 24px rgba(91, 53, 242, 0.3);

  /* --- Rejestr par treść–tło (REQ-UX-34.11) ------------------------
     Kontrast jest LICZONY, nie deklarowany: `tests/property/design_system
     .properties.test.js` (Property 47) parsuje tokeny `--kds-pair-*`,
     rozwiązuje `var()`, liczy luminancję względną według WCAG 2.1 i porównuje
     stosunek z progiem roli. Zmiana któregokolwiek koloru wyżej zmienia wynik
     tego rachunku — o to chodzi, bo tylko wtedy próg pilnuje wartości, a nie
     komentarza.

     Zapis pary: `<kolor treści> <kolor tła> <rola>`.
     Role i progi (WCAG 2.1 AA, 1.4.3 i 1.4.11):
     - `text`       — tekst mniejszy niż 18,66 px pogrubiony / 24 px: 4,5:1,
     - `large-text` — tekst duży: 3:1,
     - `ui`         — granica i wskaźnik kontrolki, treść nietekstowa: 3:1.

     Rejestr obejmuje pary, które warstwa NAPRAWDĘ maluje. Pilnuje tego
     `tests/unit/design_system_guard.test.js`: kolor użyty w `color:` albo w
     tle komponentu w tym pliku musi występować w rejestrze po właściwej
     stronie pary. Dzięki temu rejestr nie może zostać z tyłu za CSS-em. */
  --kds-pair-ink-on-surface: var(--kds-color-ink) var(--kds-color-surface) text;
  --kds-pair-ink-on-background: var(--kds-color-ink) var(--kds-color-background) text;
  --kds-pair-ink-on-surface-quiet: var(--kds-color-ink) var(--kds-color-surface-quiet) text;
  --kds-pair-muted-on-surface: var(--kds-color-muted) var(--kds-color-surface) text;
  --kds-pair-muted-on-background: var(--kds-color-muted) var(--kds-color-background) text;
  --kds-pair-muted-on-surface-quiet: var(--kds-color-muted) var(--kds-color-surface-quiet) text;
  --kds-pair-on-primary-on-primary-from: var(--kds-color-on-primary) var(--kds-color-primary-from) text;
  --kds-pair-on-primary-on-primary-to: var(--kds-color-on-primary) var(--kds-color-primary-to) text;
  --kds-pair-primary-strong-on-surface: var(--kds-color-primary-strong) var(--kds-color-surface) text;
  --kds-pair-primary-strong-on-surface-quiet: var(--kds-color-primary-strong) var(--kds-color-surface-quiet) text;
  --kds-pair-primary-strong-on-primary-soft: var(--kds-color-primary-strong) var(--kds-color-primary-soft) text;
  --kds-pair-primary-on-surface: var(--kds-color-primary) var(--kds-color-surface) text;
  --kds-pair-primary-on-background: var(--kds-color-primary) var(--kds-color-background) text;
  --kds-pair-primary-on-surface-quiet: var(--kds-color-primary) var(--kds-color-surface-quiet) text;
  --kds-pair-danger-ink-on-surface: var(--kds-color-danger-ink) var(--kds-color-surface) text;
  /* Stan wybrany opcji celu: obramowanie i kółko znaku zaznaczenia to treść
     nietekstowa na białym tle, biała „✓” w kółku jest tekstem na fiolecie. */
  --kds-pair-selected-mark-on-surface: var(--kds-color-primary) var(--kds-color-surface) ui;
  --kds-pair-selected-mark-glyph: var(--kds-color-on-primary) var(--kds-color-primary) text;
  /* Granica przycisku drugorzędnego (`border: 1px solid currentColor`) i
     wskaźnik stanu „w toku” (`border` w `::after`, czyli też currentColor). */
  --kds-pair-secondary-border-on-surface: var(--kds-color-primary-strong) var(--kds-color-surface) ui;
  --kds-pair-busy-indicator-on-primary: var(--kds-color-on-primary) var(--kds-color-primary-from) ui;

  /* --- Rejestr wskaźników fokusu (REQ-UX-34.3) ---------------------
     Wskaźnik fokusu ma DWÓCH sąsiadów i wymaganie dotyczy obu: tła, na którym
     leży, i koloru, do którego przylega. Rejestr wypisuje jedno i drugie, więc
     test sprawdza dwie strony, a nie tę wygodniejszą.

     Wskaźnik może mieć więcej niż jedną warstwę (`layers`): pierścień i halo.
     Wtedy wystarczy, że dla danego sąsiada próg 3:1 spełnia JEDNA z warstw —
     tak działa wskaźnik dwuwarstwowy: biały pierścień widać na fiolecie,
     ciemne halo na jasnym tle. Warstwy muszą też odcinać się od siebie, bo
     inaczej „dwie warstwy” są jedną grubszą.

     `A over B` znaczy: A złożone nad B (przesłona nad tłem strony). Alfa jest
     policzona, a nie wpisana drugim tokenem, żeby nie powstała druga prawda o
     kolorze przesłony. */
  --kds-focus-indicator-primary-action-layers: var(--kds-focus-ring-inverse) var(--kds-focus-ring-halo-color);
  --kds-focus-indicator-primary-action-background: var(--kds-color-background) var(--kds-color-surface) var(--kds-color-surface-quiet);
  --kds-focus-indicator-primary-action-adjacent: var(--kds-color-primary-from) var(--kds-color-primary-to);
  --kds-focus-indicator-quiet-action-layers: var(--kds-focus-ring-color);
  --kds-focus-indicator-quiet-action-background: var(--kds-color-background) var(--kds-color-surface) var(--kds-color-surface-quiet);
  --kds-focus-indicator-quiet-action-adjacent: var(--kds-color-surface) var(--kds-color-primary-soft) var(--kds-color-line);
  --kds-focus-indicator-dialog-panel-layers: var(--kds-focus-ring-on-scrim);
  --kds-focus-indicator-dialog-panel-background: var(--kds-color-scrim) over var(--kds-color-background);
  --kds-focus-indicator-dialog-panel-adjacent: var(--kds-color-surface);

  /* --- Ruch -------------------------------------------------------- */
  --kds-transition: 160ms ease;

  /* --- Szerokość, poniżej której główne CTA jest pełnej szerokości
         (REQ-UX-02.6). Token dokumentacyjny: media query nie przyjmuje
         zmiennych CSS, więc wartość poniżej jest wpisana literalnie i
         musi zostać z nim zgodna. */
  --kds-breakpoint-cta-full-width: 375px;
}

/* =====================================================================
   Widoczny wskaźnik fokusu na KAŻDYM elemencie interaktywnym
   (REQ-UX-34.3, zadanie 19.2)

   To podłoga, nie wygląd docelowy. Wymaganie mówi „na każdym elemencie
   interaktywnym”, a lista takich elementów rośnie z każdym szablonem — więc
   reguła musi wychodzić od typu elementu, a nie od nazwy klasy, której nikt
   nie zdąży dopisać.

   `:where()` ma specyficzność ZERO. To jest tu istotne: każda reguła
   komponentu (`.kds-button--primary:focus-visible`) i każda reguła arkusza
   powierzchni nadpisuje ją bez `!important`. Reguła zastępuje domyślny
   pierścień przeglądarki wartościami z tokenów, więc kontrast pierścienia jest
   policzony (rejestr `--kds-focus-indicator-quiet-action-*`), a nie zależny od
   tego, jaki kolor akcentu ma system operacyjny ucznia.

   Czego tu NIE MA: `outline: none`. W tej warstwie nie ma ani jednej
   deklaracji gaszącej pierścień — element bez widocznego fokusu jest dla
   ucznia klawiatury elementem nieistniejącym.
   ===================================================================== */

:where(a[href], area[href], button, input, select, textarea, summary, [tabindex], [contenteditable="true"]):focus-visible {
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-color);
  outline-offset: var(--kds-focus-ring-offset);
}

/* =====================================================================
   kds-button (REQ-UX-02.1 … 02.6, REQ-UX-32.3)

   Stany: domyślny, hover, focus, aktywny, nieaktywny, w toku.
   ===================================================================== */

.kds-button,
.kh-primary-button {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--kds-space-2);
  min-height: var(--kds-control-height-lg);
  min-width: var(--kds-control-height-min);
  padding: 11px 18px;
  border: 0;
  border-radius: var(--kds-radius-md);
  font-size: var(--kds-font-size-label);
  font-weight: var(--kds-font-weight-strong);
  line-height: var(--kds-line-height-tight);
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--kds-transition), box-shadow var(--kds-transition),
    background-color var(--kds-transition), color var(--kds-transition);
}

/* Wariant główny: jeden zestaw wartości tła, koloru tekstu, wysokości i
   promienia na wszystkich powierzchniach z REQ-UX-01.2 (REQ-UX-02.1). */
.kds-button--primary,
.kh-primary-button {
  color: var(--kds-color-on-primary);
  background: var(--kds-color-primary-gradient);
  box-shadow: var(--kds-shadow-primary);
}

/* Wariant drugorzędny: różnica jest w WYPEŁNIENIU tła i obramowaniu, a nie
   w odcieniu tego samego koloru (REQ-UX-02.3). */
.kds-button--secondary {
  color: var(--kds-color-primary-strong);
  background: var(--kds-color-surface);
  border: 1px solid currentColor;
  box-shadow: none;
  font-weight: var(--kds-font-weight-medium);
}

/* Główne CTA sekcji: największa waga wizualna (REQ-UX-02.2). Klasa jest
   też znacznikiem dla testu „jedna waga wizualna na sekcję”
   (REQ-UX-02.7, Property 48), dlatego niesie wartości, a nie tylko nazwę. */
.kds-button--cta {
  min-height: var(--kds-control-height-lg);
  padding: var(--kds-space-3) var(--kds-space-5);
  font-size: var(--kds-font-size-body);
}

/* --- hover ------------------------------------------------------- */
.kds-button--primary:hover,
.kh-primary-button:hover {
  color: var(--kds-color-on-primary);
  transform: translateY(-1px);
  box-shadow: var(--kds-shadow-primary-hover);
}

.kds-button--secondary:hover {
  color: var(--kds-color-primary-strong);
  background: var(--kds-color-surface-quiet);
}

/* --- focus -------------------------------------------------------
   Biały pierścień plus ciemne halo: widoczny zarówno na fioletowym
   wypełnieniu, jak i na jasnym tle sekcji (REQ-UX-34.3). */
.kds-button--primary:focus-visible,
.kh-primary-button:focus-visible {
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-inverse);
  outline-offset: var(--kds-focus-ring-offset);
  box-shadow: var(--kds-focus-ring-halo);
}

.kds-button--secondary:focus-visible {
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-color);
  outline-offset: var(--kds-focus-ring-offset);
  box-shadow: none;
}

/* --- aktywny ------------------------------------------------------ */
.kds-button--primary:active,
.kh-primary-button:active {
  transform: translateY(1px);
  box-shadow: var(--kds-shadow-primary);
}

.kds-button--secondary:active {
  transform: translateY(1px);
  background: var(--kds-color-primary-soft);
}

/* --- nieaktywny ---------------------------------------------------
   Dwa zapisy stanu, bo mają różne zastosowania: `disabled` dla akcji,
   której nie da się wykonać, `aria-disabled` dla akcji, która ma zostać
   w kolejności fokusu razem ze swoją przyczyną. Wygląd jest ten sam.

   Stan nie jest przekazywany kolorem (REQ-UX-34.12): kursor, brak cienia,
   brak podniesienia i atrybut dostępności. Kolor jest czwartym sygnałem, nie
   jedynym.

   ZAPISANE WPROST, bo dotyczy kontrastu (REQ-UX-34.11). `opacity` przygasza
   RAZEM etykietę i wypełnienie, więc etykieta stanu nieaktywnego składa się na
   ok. 2,5–3,1:1 wobec swojego tła — poniżej 4,5:1 wymaganych od tekstu.
   WCAG 2.1 wyłącza nieaktywne kontrolki z 1.4.3 i 1.4.11, więc para NIE jest
   w rejestrze `--kds-pair-*`: wpisanie jej z zaniżonym progiem byłoby
   deklaracją zgodności, a rejestr istnieje po to, żeby kontrast był liczony.
   Przywrócenie pełnego kontrastu etykiety wymaga zastąpienia przygaszenia
   osobnym tokenem wypełnienia i etykiety — a to zmienia wygląd wysłanego już
   `.kh-primary-button:disabled` na Stronie_Głównej, więc należy do migracji
   komponentów (zadanie 20.1), nie do wniesienia tokenów. Do tego czasu jest to
   punkt dla przeglądu manualnego. */
.kds-button:disabled,
.kds-button[aria-disabled="true"],
.kh-primary-button:disabled,
.kh-primary-button[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.72;
  transform: none;
  box-shadow: none;
}

/* --- w toku (REQ-UX-02.5) ----------------------------------------
   Stan jest komunikowany w obrębie przycisku: kursor, wskaźnik obok
   etykiety oraz podmieniona etykieta ustawiana przez
   `public/assets/js/kds_button.js`. `aria-busy` niesie to samo dla
   czytnika ekranu, więc informacja nie jest przekazywana wyłącznie
   wyglądem (REQ-UX-34.12). */
.kds-button[aria-busy="true"],
.kh-primary-button[aria-busy="true"] {
  cursor: progress;
  opacity: 0.72;
  transform: none;
}

.kds-button[aria-busy="true"]::after,
.kh-primary-button[aria-busy="true"]::after {
  width: 0.85em;
  height: 0.85em;
  flex: 0 0 auto;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--kds-radius-pill);
  content: "";
  animation: kds-button-spin 700ms linear infinite;
}

@keyframes kds-button-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Etykieta jest osobnym elementem, żeby skrypt podmieniał tekst, a nie
   całą treść przycisku razem z ikoną i wskaźnikiem. */
.kds-button__label {
  min-width: 0;
  overflow-wrap: anywhere;
}

/* --- pełna szerokość na wąskim ekranie (REQ-UX-02.6) -------------
   Reguła należy do warstwy Design_System, a NIE do CSS pojedynczej
   strony: inaczej każda nowa powierzchnia musiałaby ją odkryć na nowo.
   Progiem jest 375 px włącznie, zgodnie z `--kds-breakpoint-cta-full-width`. */
@media (max-width: 375px) {
  .kds-button,
  .kh-primary-button {
    width: 100%;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kds-button,
  .kh-primary-button {
    transition: none !important;
  }

  .kds-button:hover,
  .kds-button:active,
  .kh-primary-button:hover,
  .kh-primary-button:active {
    transform: none;
  }

  .kds-button[aria-busy="true"]::after,
  .kh-primary-button[aria-busy="true"]::after {
    animation: none;
  }
}

/* =====================================================================
   Okno potwierdzenia — `views/partials/kds/dialog.hbs` (zadanie 4.2)

   Wymagania: REQ-UX-07.2, REQ-UX-07.3, REQ-UX-07.7, REQ-UX-32.4,
              REQ-UX-33.4, REQ-UX-34.3, REQ-UX-34.10
   Projekt: design.md §2.5, §4.1.4, §4.4.2

   Komponent mieszka w warstwie Design_System, nie w arkuszu diagnozy:
   to samo okno obsłuży potwierdzenie powrotu do poprzedniego pytania
   (§4.2.6), a dwa zestawy wartości dla jednego okna to dokładnie ten
   lokalny wariant, którego zabrania REQ-UX-32.4.

   `[hidden]` MUSI stać przy regule bazowej: `display: flex` wygrywa z
   domyślnym `display: none` atrybutu `hidden`, więc bez tej deklaracji
   okno „ukryte” byłoby widoczne — i to na ścieżce bez JavaScriptu, gdzie
   nikt by tego nie nadpisał.
   ===================================================================== */

.kds-dialog {
  position: fixed;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--kds-space-4);
  inset: 0;
}

.kds-dialog[hidden] {
  display: none;
}

.kds-dialog__backdrop {
  position: absolute;
  background: var(--kds-color-scrim);
  inset: 0;
}

.kds-dialog__panel {
  position: relative;
  width: 100%;
  max-width: 30rem;
  padding: var(--kds-space-5);
  border-radius: var(--kds-radius-lg);
  background: var(--kds-color-surface);
  box-shadow: 0 18px 44px rgba(16, 21, 47, 0.28);
}

/* Pierścień panelu jest CIEMNY, nie fioletowy: leży na przesłonie, a fiolet ma
   wobec niej 1,57:1, czyli na ciemnym tle nie istnieje (REQ-UX-34.3).
   Rejestr `--kds-focus-indicator-dialog-panel-*` w `:root` jest wprost o tej
   parze i to on jest liczony w teście. */
.kds-dialog__panel:focus-visible {
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-on-scrim);
  outline-offset: var(--kds-focus-ring-offset);
}

.kds-dialog__title {
  margin: 0 0 var(--kds-space-3);
  color: var(--kds-color-ink);
  font-size: var(--kds-font-size-body);
  font-weight: var(--kds-font-weight-strong);
  line-height: var(--kds-line-height-tight);
}

.kds-dialog__message {
  margin: 0 0 var(--kds-space-2);
  color: var(--kds-color-ink);
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}

/* Wyliczenie tego, co przepadnie: ta sama waga co komunikat, inny ton, bo
   to fakt o próbie ucznia, a nie zdanie o produkcie. */
.kds-dialog__detail {
  margin: 0 0 var(--kds-space-5);
  color: var(--kds-color-muted);
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}

/* Dwie akcje w jednym rzędzie, na wąskim ekranie jedna pod drugą. Kolejność
   DOM-u jest kolejnością prezentacji (REQ-UX-33.5), więc akcja bezpieczna
   zostaje pierwsza także po zawinięciu. */
.kds-dialog__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--kds-space-3);
}

.kds-dialog__actions .kds-dialog__action {
  margin: 0;
}

/* Akcja niszcząca jest odróżniona kolorem ORAZ treścią etykiety, więc
   informacja nie jest przekazywana wyłącznie kolorem (REQ-UX-34.12). */
.kds-dialog [data-kds-dialog-action="confirm"] {
  color: var(--kds-color-danger-ink);
}

@media (max-width: 375px) {
  .kds-dialog__actions {
    flex-direction: column;
  }

  .kds-dialog__actions .kds-dialog__action {
    width: 100%;
  }
}

/* =====================================================================
   Typografia treści: szerokość bloku i nagłówek hero
   (REQ-UX-20.2, REQ-UX-20.3, REQ-UX-20.4, REQ-UX-20.5)

   `.kds-prose` jest klasą dla NOWYCH bloków tekstu ciągłego: 75 znaków
   miary i tekst podstawowy nie mniejszy niż 16 px na każdej szerokości
   ekranu. Istniejące klasy powierzchni są dopisane do selektora miary
   jako ALIASY — tak samo jak `.kh-primary-button` jest aliasem
   `.kds-button--primary`. Tam, gdzie arkusz powierzchni wczytany później
   podaje własną szerokość (`.kh-hero h1`, `.kh-section-lead`,
   `.km-seo-copy`), wygrywa jego deklaracja; wartość mieszka jednak tutaj,
   więc etap 4 usuwa powtórzenia bez szukania ich po arkuszach.
   ===================================================================== */
.kds-prose,
.kh-hero-copy,
.kh-section-lead,
.kh-product-definition,
.km-seo-copy {
  max-width: var(--kds-text-measure-max);
  margin-inline: auto;
}
.kds-prose {
  font-size: var(--kds-font-size-body);
  line-height: var(--kds-line-height-body);
}
/* Nagłówek hero: trzy kontrole łamania w jednym miejscu. `min()` pilnuje
   maksymalnego rozmiaru czcionki niezależnie od tego, jak szeroki jest
   ekran, a `overflow-wrap` chroni przed przycięciem długiego wyrazu na
   320 px (REQ-UX-20.5). `text-wrap: balance` jest ulepszeniem: gdzie nie
   działa, nagłówek nadal nie zostawia wiszącego wyrazu, bo o tym decyduje
   spacja niełamiąca w treści. */
.kds-hero-heading,
.kh-hero h1 {
  max-width: var(--kds-hero-heading-max-width);
  margin-inline: auto;
  font-size: min(var(--kds-hero-heading-size-max), clamp(2.15rem, 4.8vw, 4.05rem));
  line-height: var(--kds-line-height-heading);
  text-wrap: balance;
  overflow-wrap: break-word;
}

/* =====================================================================
   Wyjaśnienie rozwijane — `views/partials/kds/hint.hbs` (zadanie 9.4)

   Wymagania: REQ-UX-17.7, REQ-UX-17.8, REQ-UX-33.3, REQ-UX-33.4,
              REQ-UX-34.3
   Projekt: design.md §2.5, §4.2.5

   Komponent mieszka w warstwie Design_System, bo to samo wyjaśnienie
   pojawia się w obu strefach. Dwa zestawy wartości dla jednego
   wyjaśnienia to lokalny wariant, którego zabrania REQ-UX-32.4.

   Przycisk jest tekstowy, ale zachowuje minimalny obszar dotykowy
   (REQ-UX-33.4) i widoczny pierścień fokusu (REQ-UX-34.3): to jedyna
   droga do treści, gdy skrypt ją zwinie.

   `[hidden]` na treści działa domyślnie (`display: none`), więc nie ma tu
   deklaracji, która musiałaby to naprawiać — w przeciwieństwie do
   `kds-dialog`, gdzie `display: flex` wygrywało z atrybutem.
   ===================================================================== */

.kds-hint {
  display: flex;
  flex-direction: column;
  gap: var(--kds-space-2);
  align-items: flex-start;
}

.kds-hint__toggle {
  display: inline-flex;
  gap: var(--kds-space-1);
  align-items: center;
  min-height: var(--kds-control-height-min);
  padding: 0;
  border: 0;
  background: none;
  color: var(--kds-color-primary);
  font-size: var(--kds-font-size-support);
  font-weight: var(--kds-font-weight-medium);
  line-height: var(--kds-line-height-body);
  text-align: left;
  cursor: pointer;
}

.kds-hint__toggle:hover .kds-hint__label {
  color: var(--kds-color-primary-strong);
}

.kds-hint__toggle:focus-visible {
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-color);
  outline-offset: var(--kds-focus-ring-offset);
}

/* Stan jest widoczny w treści etykiety i w obecności tekstu, a nie tylko
   w obrocie ikony — informacja nie może zależeć wyłącznie od grafiki
   (REQ-UX-34.12). */
.kds-hint__label {
  text-decoration: underline;
}

.kds-hint__content {
  max-width: var(--kds-text-measure-max);
  margin: 0;
  color: var(--kds-color-muted);
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}

/* =====================================================================
   Etap 4 — dokończenie migracji komponentów (zadanie 20.1)

   Wymagania: REQ-UX-32.1, REQ-UX-32.2, REQ-UX-32.3, REQ-UX-32.4, REQ-UX-32.6
   Projekt: design.md §2.5, §4.4.1 (tabela komponentów i stanów)

   Etap 1 przeniósł tu tokeny i przycisk; 4.2 dołożył okno, 9.4 wyjaśnienie,
   9.6 opcję celu. Ten blok domyka katalog z §4.4.1: `card`, `field`,
   `status_badge`, `alert`, `progress`, `skeleton`, `error_state`, każdy ze
   stanami z tabeli. Od teraz rodziny `km-*` i `k8-*` nie mają WŁASNYCH wartości
   koloru, wysokości i promienia — ich tokeny (`--km-radius`, `--k8-radius`, …)
   są aliasami `--kds-*`, więc wartość żyje tylko tutaj (REQ-UX-32.6, §2.5
   „krok trzeci: km-* i k8-* tracą własne wartości”).

   ZASADA KOLORU. Każdy kolor, który ta warstwa MALUJE (`color`,
   `background`), musi występować w rejestrze `--kds-pair-*` po właściwej
   stronie pary — pilnuje tego `tests/unit/design_system_guard.test.js`, a
   Property 47 liczy jego kontrast. Dlatego stany statusu (`status_badge`,
   `alert`) stoją na MIĘKKIM wypełnieniu z ciemnym tekstem `--kds-color-ink`
   (kontrast > 15:1). Ikona i kropka statusu są `currentColor` na tym samym
   miękkim tle, więc schodzą do ciemnego odcienia `*-ink` (≥ 4,6:1), a nie do
   nasyconego koloru, który miałby wobec swojego tła ~2,3:1. Obramowanie
   (`border-color`) zostaje nasycone — strażnik nie skanuje granic, a granica
   nie jest jedynym nośnikiem stanu. Żaden stan nie jest przekazywany wyłącznie
   kolorem: obok koloru zawsze jest ikona I słowo (REQ-UX-32.5, REQ-UX-34.12) —
   nośnik nietekstowy niesie szablon partiala.
   ===================================================================== */

:root {
  /* --- Miękkie wypełnienia statusu ---------------------------------
     Tło etykiet i alertów. Wartości są jasne, żeby ciemny tekst i ciemny
     odcień statusu (`*-ink`) miały na nich kontrast tekstu (≥ 4,5:1); Property
     47 liczy to z par niżej. */
  --kds-color-success-soft: #e6f7ef;
  --kds-color-warning-soft: #fdf3d9;
  --kds-color-attention-soft: #fdeede;
  --kds-color-danger-soft: #fdecec;
  --kds-color-info: #3f4bb0;
  --kds-color-info-soft: #eef0fb;
  /* Ciemniejsze warianty tekstu statusu: nasycony kolor `--kds-color-success`
     (#28b779) ma na białym 1,9:1, więc jako TEKST na powierzchni nie przechodzi
     progu 4,5:1. Te warianty są zaciemnione do poziomu tekstu. */
  --kds-color-success-ink: #1c7d54;
  --kds-color-warning-ink: #8a6410;
  --kds-color-attention-ink: #9a521c;

  /* --- Pary treść–tło dla stanów statusu (REQ-UX-34.11) ------------
     Rejestr obejmuje pary, które warstwa NAPRAWDĘ maluje w `color`/`background`
     (granice `border-color` nie są malowaniem treści i strażnik ich nie
     skanuje, więc nie ma dla nich par — nie chcemy liczyć progu 3:1 dla
     spoczynkowej, dekoracyjnej linii).

     Dwie rodzaje par:
     - ciemny tekst na miękkim wypełnieniu (rola `text`): treść alertu i badge,
     - ciemny odcień statusu (`*-ink`) jako TEKST/ikona na miękkim wypełnieniu
       (rola `text`) — bo kropka i ikona statusu są `currentColor`, a nasycony
       `--kds-color-success` (#28b779) ma wobec swojego miękkiego tła 2,3:1,
       czyli poniżej progu; ciemny `*-ink` daje ≥ 4,6:1. Do tego kolorowy tekst
       statusu na białej powierzchni (badge bez wypełnienia). */
  --kds-pair-ink-on-success-soft: var(--kds-color-ink) var(--kds-color-success-soft) text;
  --kds-pair-ink-on-warning-soft: var(--kds-color-ink) var(--kds-color-warning-soft) text;
  --kds-pair-ink-on-attention-soft: var(--kds-color-ink) var(--kds-color-attention-soft) text;
  --kds-pair-ink-on-danger-soft: var(--kds-color-ink) var(--kds-color-danger-soft) text;
  --kds-pair-ink-on-info-soft: var(--kds-color-ink) var(--kds-color-info-soft) text;
  --kds-pair-success-ink-on-soft: var(--kds-color-success-ink) var(--kds-color-success-soft) text;
  --kds-pair-warning-ink-on-soft: var(--kds-color-warning-ink) var(--kds-color-warning-soft) text;
  --kds-pair-attention-ink-on-soft: var(--kds-color-attention-ink) var(--kds-color-attention-soft) text;
  --kds-pair-danger-ink-on-soft: var(--kds-color-danger-ink) var(--kds-color-danger-soft) text;
  --kds-pair-info-on-soft: var(--kds-color-info) var(--kds-color-info-soft) text;
  --kds-pair-success-ink-on-surface: var(--kds-color-success-ink) var(--kds-color-surface) text;
  --kds-pair-warning-ink-on-surface: var(--kds-color-warning-ink) var(--kds-color-surface) text;
  --kds-pair-attention-ink-on-surface: var(--kds-color-attention-ink) var(--kds-color-surface) text;
  --kds-pair-info-on-surface: var(--kds-color-info) var(--kds-color-surface) text;
  /* Wypełnienie wskaźnika postępu na jego bieżni: oba tła są malowane, więc oba
     kolory MUSZĄ być w rejestrze. Fioletowe wypełnienie wobec jasnej bieżni to
     wskaźnik nietekstowy (rola `ui`, 5,6:1). */
  --kds-pair-progress-fill-on-track: var(--kds-color-primary) var(--kds-color-primary-soft) ui;

  /* --- Disabled-button: DECYZJA odroczona z 19.2 -------------------
     Zadanie 19.2 świadomie zostawiło parę „etykieta przycisku nieaktywnego /
     jego wypełnienie” POZA rejestrem `--kds-pair-*` i przekazało decyzję do
     20.1. Rozstrzygam ją tak: para ZOSTAJE poza rejestrem, i to jest decyzja
     zgodna z normą, nie luka.

     Powód rzeczowy: WCAG 2.1 wyłącza elementy nieaktywne z 1.4.3 (tekst) i
     1.4.11 (kontrast nietekstowy) — „inactive user interface components” nie
     podlegają progom. Wpisanie tej pary do rejestru zmusiłoby test do liczenia
     progu 4,5:1 dla kontrastu, którego norma NIE wymaga. Miałbym dwa wyjścia,
     oba złe: albo para nie przeszłaby progu i test zaczdeveloperowałby fałszywą
     porażkę na w pełni zgodnym stanie, albo musiałbym OBNIŻYĆ próg roli — a to
     osłabiłoby próg dla WSZYSTKICH par tekstu, bo `CONTRAST_THRESHOLDS.text`
     jest wspólny. Rejestr istnieje po to, żeby kontrast był LICZONY tam, gdzie
     norma go wymaga; dokładanie do niego pary wyłączonej z normy zamieniłoby go
     w miejsce deklaracji zgodności.

     Powód wizualny: stan nieaktywny nadal jest przygaszany `opacity: 0.72`
     (reguła `.kds-button:disabled` wyżej), więc etykieta i wypełnienie gasną
     RAZEM — nie ma osobnego koloru etykiety, który dałoby się zmierzyć jedną
     parą. Rozdzielenie ich na token wypełnienia i token etykiety zmieniłoby
     wygląd wysłanego już `.kh-primary-button:disabled`, a to jest zmiana
     wizualna dla przeglądu, nie warunek zgodności.

     Nie ma więc tokenu `--kds-pair-*-disabled` i nie ma go celowo. To pozostaje
     punktem dla przeglądu manualnego (design.md §4.4.2, §9.4), tak jak zapisano
     w 19.2 — z tą różnicą, że teraz jest to decyzja domknięta, nie odroczona. */

}

/* =====================================================================
   kds-card — karta (REQ-UX-32.3)
   Stany: domyślny, hover, wybrany.

   „Wybrany” nie jest tylko kolorem (REQ-UX-32.5): oprócz obramowania
   dostaje pierścień `box-shadow` i atrybut `aria-pressed`/`aria-current`,
   który niesie szablon. Karta klikalna jest `<button>`/`<a>`, nie `div`-em
   z `onclick` — o tym decyduje szablon partiala.
   ===================================================================== */

.kds-card {
  box-sizing: border-box;
  display: block;
  padding: var(--kds-space-5);
  color: var(--kds-color-ink);
  background: var(--kds-color-surface);
  border: 1px solid var(--kds-color-line);
  border-radius: var(--kds-radius-lg);
  transition: border-color var(--kds-transition), box-shadow var(--kds-transition),
    transform var(--kds-transition);
}

/* Karta interaktywna: wariant, który reaguje na wskazanie i wybór. Karta
   czysto prezentacyjna nie dostaje tych stanów. */
.kds-card--interactive {
  cursor: pointer;
}

.kds-card--interactive:hover {
  border-color: var(--kds-color-primary);
  box-shadow: 0 10px 26px rgba(16, 21, 47, 0.08);
  transform: translateY(-1px);
}

.kds-card--interactive:focus-visible {
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-color);
  outline-offset: var(--kds-focus-ring-offset);
}

/* Stan wybrany: obramowanie fioletowe PLUS pierścień, więc różnicę widać bez
   rozpoznawania barwy. Wyzwalany atrybutem, nie osobną klasą wariantu. */
.kds-card[aria-pressed="true"],
.kds-card[aria-current="true"],
.kds-card--selected {
  border-color: var(--kds-color-primary);
  box-shadow: 0 0 0 2px var(--kds-color-primary);
}

@media (prefers-reduced-motion: reduce) {
  .kds-card,
  .kds-card--interactive:hover {
    transition: none;
    transform: none;
  }
}

/* =====================================================================
   kds-field — pole formularza (REQ-UX-32.3, REQ-UX-34.6)
   Stany: domyślny, focus, błąd, powodzenie, nieaktywny.

   Etykieta jest ZAWSZE związana z kontrolką (`for`/`id`) w szablonie
   (REQ-UX-34.6). Stan błędu i powodzenia niesie obramowanie (kolor) ORAZ
   komunikat tekstowy z ikoną (kształt + słowo), nigdy sam kolor
   (REQ-UX-34.12) — komunikat składa partial.
   ===================================================================== */

.kds-field {
  display: flex;
  flex-direction: column;
  gap: var(--kds-space-2);
}

.kds-field__label {
  color: var(--kds-color-ink);
  font-size: var(--kds-font-size-label);
  font-weight: var(--kds-font-weight-medium);
  line-height: var(--kds-line-height-tight);
}

.kds-field__control {
  box-sizing: border-box;
  width: 100%;
  min-height: var(--kds-control-height-md);
  padding: var(--kds-space-3) var(--kds-space-4);
  color: var(--kds-color-ink);
  background: var(--kds-color-surface);
  border: 1px solid var(--kds-color-line);
  border-radius: var(--kds-radius-md);
  font-size: var(--kds-font-size-body);
  line-height: var(--kds-line-height-body);
  transition: border-color var(--kds-transition), box-shadow var(--kds-transition);
}

.kds-field__control::placeholder {
  color: var(--kds-color-muted);
}

.kds-field__control:focus-visible {
  border-color: var(--kds-color-primary);
  outline: var(--kds-focus-ring-width) solid var(--kds-focus-ring-color);
  outline-offset: var(--kds-focus-ring-offset);
}

/* Stan błędu / powodzenia: obramowanie w kolorze statusu. Atrybut, nie klasa
   wariantu, żeby stan był jeden — natywny `aria-invalid` niesie go dla
   czytnika ekranu, więc informacja nie jest wyłącznie kolorem. */
.kds-field__control[aria-invalid="true"],
.kds-field--error .kds-field__control {
  border-color: var(--kds-color-danger);
}

.kds-field--success .kds-field__control {
  border-color: var(--kds-color-success);
}

.kds-field__control:disabled,
.kds-field__control[aria-disabled="true"] {
  cursor: not-allowed;
  opacity: 0.72;
}

/* Komunikat pod polem. Ton błędu ma ciemniejszy odcień tekstu, bo to TEKST na
   białym (próg 4,5:1), nie granica. */
.kds-field__message {
  display: flex;
  gap: var(--kds-space-1);
  align-items: center;
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}

.kds-field--error .kds-field__message {
  color: var(--kds-color-danger-ink);
}

.kds-field--success .kds-field__message {
  color: var(--kds-color-success-ink);
}

.kds-field__hint {
  color: var(--kds-color-muted);
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}

/* =====================================================================
   kds-status-badge — etykieta statusu (REQ-UX-32.3)
   Tony: neutralny, sukces, ostrzeżenie, błąd, brak danych.

   Ton nigdy nie jest jedynym nośnikiem: obok koloru jest ikona (kształt) i
   etykieta (słowo), które składa partial (REQ-UX-34.12). Wypełnienie jest
   MIĘKKIE, a tekst ciemny — kontrast liczy Property 47 z par wyżej.

   To NIE jest fork `views/partials/shared/status_badge.hbs`: tamten badge
   opiera się na klasach motywu Bootstrap i obsługuje ekrany aplikacji
   (`app-shell`); ten jest komponentem Design_System dla powierzchni objętych
   tym specem, z tokenami `--kds-*`. Rozstrzygnięcie, którego użyć, należy do
   powierzchni, nie do tego pliku.
   ===================================================================== */

.kds-status-badge {
  display: inline-flex;
  gap: var(--kds-space-1);
  align-items: center;
  min-height: var(--kds-space-6);
  padding: var(--kds-space-1) var(--kds-space-3);
  color: var(--kds-color-ink);
  background: var(--kds-color-surface-quiet);
  border-radius: var(--kds-radius-pill);
  font-size: var(--kds-font-size-support);
  font-weight: var(--kds-font-weight-medium);
  line-height: var(--kds-line-height-tight);
}

/* Kropka statusu: nośnik nietekstowy obok koloru tła. */
.kds-status-badge__dot {
  width: 0.5em;
  height: 0.5em;
  flex: 0 0 auto;
  border-radius: var(--kds-radius-pill);
  background: currentColor;
}

/* Tekst I kropka są w CIEMNYM odcieniu statusu (`*-ink`), nie w nasyconym:
   nasycony `--kds-color-success` ma wobec swojego miękkiego tła 2,3:1, a
   `*-ink` ≥ 4,6:1. Kropka jest `currentColor`, więc dziedziczy ten sam
   kontrast. Miękkie tło niesie ton, ciemny tekst niesie kontrast. */
.kds-status-badge--success {
  color: var(--kds-color-success-ink);
  background: var(--kds-color-success-soft);
}

.kds-status-badge--warning {
  color: var(--kds-color-warning-ink);
  background: var(--kds-color-warning-soft);
}

.kds-status-badge--danger {
  color: var(--kds-color-danger-ink);
  background: var(--kds-color-danger-soft);
}

/* „Brak danych” jest tonem `attention`: kolor plus etykieta słowna, nigdy
   sam pusty stan bez wyjaśnienia (REQ-UX-34.12). */
.kds-status-badge--empty {
  color: var(--kds-color-attention-ink);
  background: var(--kds-color-attention-soft);
}

/* =====================================================================
   kds-alert — komunikat (REQ-UX-32.3, REQ-UX-34.8)
   Tony: informacja, ostrzeżenie, błąd, sukces.

   Alert niosący błąd albo powodzenie akcji dostaje `role="alert"`; alert
   informacyjny `role="status"` — o roli decyduje szablon, bo to on wie, czy
   komunikat jest reakcją na akcję (REQ-UX-34.8). Ton to kolor obramowania i
   miękkie wypełnienie; ikona i treść niosą znaczenie obok koloru.
   ===================================================================== */

.kds-alert {
  display: flex;
  gap: var(--kds-space-3);
  align-items: flex-start;
  padding: var(--kds-space-4);
  color: var(--kds-color-ink);
  background: var(--kds-color-info-soft);
  border: 1px solid var(--kds-color-info);
  border-radius: var(--kds-radius-md);
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}

/* Ikona alertu leży na miękkim wypełnieniu, więc — jak kropka badge — jest w
   odcieniu, który przechodzi próg wobec tego tła: `--kds-color-info` ma na
   `info-soft` 6,5:1, a tony sukcesu/ostrzeżenia/błędu schodzą do `*-ink`. */
.kds-alert__icon {
  flex: 0 0 auto;
  color: var(--kds-color-info);
  font-size: 1.15em;
  line-height: 1;
}

.kds-alert__body {
  min-width: 0;
}

.kds-alert__title {
  margin: 0 0 var(--kds-space-1);
  color: var(--kds-color-ink);
  font-size: var(--kds-font-size-label);
  font-weight: var(--kds-font-weight-strong);
  line-height: var(--kds-line-height-tight);
}

.kds-alert__message {
  margin: 0;
  color: var(--kds-color-ink);
}

.kds-alert--success {
  background: var(--kds-color-success-soft);
  border-color: var(--kds-color-success);
}

.kds-alert--success .kds-alert__icon {
  color: var(--kds-color-success-ink);
}

.kds-alert--warning {
  background: var(--kds-color-warning-soft);
  border-color: var(--kds-color-warning);
}

.kds-alert--warning .kds-alert__icon {
  color: var(--kds-color-warning-ink);
}

.kds-alert--danger {
  background: var(--kds-color-danger-soft);
  border-color: var(--kds-color-danger);
}

.kds-alert--danger .kds-alert__icon {
  color: var(--kds-color-danger-ink);
}

/* =====================================================================
   kds-progress — wskaźnik postępu (REQ-UX-32.3, REQ-UX-34.11)
   Stany: określony (`aria-valuenow`), nieokreślony.

   Rola i wartości (`role="progressbar"`, `aria-valuenow/min/max`) idą na
   znacznik w partialu. Wypełnienie jest wobec bieżni wskaźnikiem `ui`
   (para `--kds-pair-progress-fill-on-track`), więc pasek pozostaje widoczny
   także dla kogoś, kto nie rozróżnia odcienia.
   ===================================================================== */

.kds-progress {
  display: block;
  width: 100%;
  height: var(--kds-space-2);
  overflow: hidden;
  background: var(--kds-color-primary-soft);
  border-radius: var(--kds-radius-pill);
}

.kds-progress__fill {
  height: 100%;
  background: var(--kds-color-primary);
  border-radius: inherit;
  transition: width var(--kds-transition);
}

/* Stan nieokreślony: wypełnienie wędruje, bo wartości nie znamy. Znaczenie
   niesie `aria-valuenow` pominięte w szablonie, nie sam ruch. */
.kds-progress--indeterminate .kds-progress__fill {
  width: 40%;
  animation: kds-progress-slide 1.1s ease-in-out infinite;
}

@keyframes kds-progress-slide {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .kds-progress__fill {
    transition: none;
  }

  .kds-progress--indeterminate .kds-progress__fill {
    width: 100%;
    animation: none;
  }
}

/* =====================================================================
   kds-skeleton — stan ładowania (REQ-UX-32.3)

   Szkielet jest OZDOBĄ: znaczenie „trwa ładowanie” niesie `aria-busy` na
   kontenerze i tekst dla czytnika w partialu, nie kształt. Nie przenosi
   więc treści i nie jest parą kontrastu — para jasnego podłoża szkieletu z
   jaśniejszym tłem sekcji ma ~1,15:1 i żaden próg roli by jej nie objął.

   Dlatego szkielet MALUJE tylko jeden kolor tła — `--kds-color-surface-quiet`,
   który jest zadeklarowanym tłem w rejestrze (`--kds-pair-*-on-surface-quiet`)
   — a migotanie robi animacją `opacity` na warstwie `::after`, nie drugim
   kolorem w gradiencie. Strażnik `design_system_guard` skanuje `color` i
   `background`; `opacity` do nich nie należy, więc nie ma tu koloru bez pary. */

.kds-skeleton {
  position: relative;
  display: block;
  min-height: var(--kds-space-4);
  overflow: hidden;
  background: var(--kds-color-surface-quiet);
  border-radius: var(--kds-radius-sm);
}

.kds-skeleton::after {
  position: absolute;
  inset: 0;
  background: var(--kds-color-primary-soft);
  content: "";
  animation: kds-skeleton-shimmer 1.4s ease-in-out infinite;
}

.kds-skeleton--text {
  height: var(--kds-font-size-body);
}

.kds-skeleton--title {
  height: var(--kds-space-5);
}

.kds-skeleton--block {
  min-height: var(--kds-space-7);
}

@keyframes kds-skeleton-shimmer {
  0%,
  100% {
    opacity: 0.35;
  }
  50% {
    opacity: 0.85;
  }
}

@media (prefers-reduced-motion: reduce) {
  .kds-skeleton::after {
    animation: none;
    opacity: 0.5;
  }
}

/* =====================================================================
   kds-error-state — stan błędu z akcją ponowienia (REQ-UX-32.3)

   Błąd, którego uczeń może spróbować naprawić: komunikat plus akcja
   ponowienia. Akcja jest `kds-button` (partial składa ją przez `kds/button`),
   nie własnym przyciskiem, więc dziedziczy jej stany i kontrast.
   ===================================================================== */

.kds-error-state {
  display: flex;
  flex-direction: column;
  gap: var(--kds-space-3);
  align-items: center;
  padding: var(--kds-space-6);
  color: var(--kds-color-ink);
  background: var(--kds-color-surface);
  border: 1px solid var(--kds-color-line);
  border-radius: var(--kds-radius-lg);
  text-align: center;
}

/* Ikona błędu leży na białej powierzchni; `--kds-color-danger-ink` (para
   `--kds-pair-danger-ink-on-surface`, już w rejestrze) daje jej 5,99:1, więc
   ikona jest widoczna także bez rozpoznawania barwy. Znaczenie i tak niesie
   tytuł i komunikat obok niej. */
.kds-error-state__icon {
  color: var(--kds-color-danger-ink);
  font-size: 1.75em;
  line-height: 1;
}

.kds-error-state__title {
  margin: 0;
  color: var(--kds-color-ink);
  font-size: var(--kds-font-size-body);
  font-weight: var(--kds-font-weight-strong);
  line-height: var(--kds-line-height-tight);
}

.kds-error-state__message {
  max-width: var(--kds-text-measure-max);
  margin: 0;
  color: var(--kds-color-muted);
  font-size: var(--kds-font-size-support);
  line-height: var(--kds-line-height-body);
}
