/* base.css — Sygno
   Reset + custom properties (tokeny z brief/04-STYLEGUIDE.md) + bazowe komponenty.
   Wartości TODO są neutralne — podmień na tokeny z makiet sparingu (JEDEN kierunek). */

/* ---- Custom properties (mapują 1:1 na 04-STYLEGUIDE.md) ---- */
:root {
  /* Kolory — motyw marki „papier + atrament + bursztyn" (brief/04-STYLEGUIDE.md; 1:1 z landing.css).
     WSPÓLNE dla /auth, /app, /admin. landing.css nadpisuje te same wartości lokalnie dla index.html,
     więc landing wygląda identycznie — a panele przestają być generyczne niebiesko-białe. */
  --color-bg:            #F4F1E8;  /* jasny papier przetargowy (tła stron) */
  --color-surface:       #FFFCF4;  /* karta dokumentu */
  --color-surface-2:     #FBF8F0;  /* podniesione tło (paski, nagłówki tabel) */
  --color-text:          #1C1A15;  /* ciepła czerń (tekst / primary) */
  --color-text-muted:    #6E675B;  /* drugorzędny (AA na papierze) */
  --color-accent:        #F4B000;  /* bursztyn — CTA/akcent. Na przyciskach ZAWSZE z ciemnym tekstem;
                                       jako TEKST na jasnym tle NIE przechodzi AA → do linków patrz --color-link. */
  --color-accent-hover:  #D89A00;
  --color-accent-text:   #1C1A15;  /* ZAWSZE ciemny tekst na bursztynie (AA ~10:1; biały = zakaz) */
  --color-link:          #8A5A00;  /* link = ciemny ochra (AA ≥5:1 na papierze i bieli); hover = podkreślenie */
  --color-border:        #E4DFD3;  /* obrysy „marginesy dokumentu" */
  --color-success:       #2F6B40;  /* Zgodny / OK (AA jako tekst) */
  --color-warning:       #B45309;  /* ciemny bursztyn-brąz — używany jako TEKST/badge, musi być AA (nie #F4B000) */
  --color-error:         #C93A32;  /* Niezgodny · UWAGA · błąd */

  /* Bursztynowe akcenty pomocnicze (podkreślenia linków, highlight klauzul) — spójne z landing.css. */
  --amber-wash: rgba(244, 176, 0, .16);
  --amber-line: rgba(244, 176, 0, .45);

  /* Typografia */
  --font-head: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

  /* Geometria — skala promieni (jedno źródło; wszystkie komponenty biorą z tej skali).
     --radius = domyślny promień komponentu (karty/przyciski/inputy). Warianty sm/md/lg/pill
     dla podglądów, chipów i pigułek. Formalizacja: eliminuje undefined `var(--radius-md)`. */
  --radius-sm:   6px;
  --radius:      8px;   /* bazowy — nie zmieniać bez rewizji komponentów */
  --radius-md:   10px;
  --radius-lg:   14px;
  --radius-pill: 999px;
  --border-w: 1px;
  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .06);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, .08);

  /* Ruch — czas i krzywe (spójne z zasadą „animacje narracyjne, nie gadżety").
     Były używane z fallbackiem (var(--dur-base,.25s)); formalizujemy jako tokeny. */
  --dur-fast: .15s;
  --dur-base: .25s;
  --ease-out: cubic-bezier(.2, .7, .2, 1);

  /* Spacing scale */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 48px; --sp-8: 64px;

  --maxw: 1080px;

  /* Skala z-index (S27) — JEDNA prawda o warstwach; zero magicznych liczb w komponentach.
     Kolejność rośnie z „ważnością" nakładki. Paywall MUSI być NAD overlayem gatingu
     (canceled/past_due), inaczej user nie wybierze planu (bug Fachmata). */
  --z-sticky:  50;
  --z-fab:     900;
  --z-aha:     940;
  --z-overlay: 1000;
  --z-modal:   1050;
  --z-paywall: 1100;
  --z-banner:  1150;
  --z-toast:   1200;
  --z-maintenance: 1300;  /* plansza przerwy technicznej — NAD wszystkim (B10) */
}

/* ---- Reset ---- */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  font-family: var(--font-body);
  color: var(--color-text);
  background: var(--color-bg);
  line-height: 1.55;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4 { font-family: var(--font-head); line-height: 1.2; font-weight: 700; }
h1 { font-size: clamp(2rem, 5vw, 3rem); }
h2 { font-size: clamp(1.5rem, 4vw, 2.25rem); }
h3 { font-size: 1.25rem; }
a { color: var(--color-link); text-decoration: none; }
a:hover { text-decoration: underline; text-decoration-color: var(--amber-line); text-underline-offset: 2px; }
img { max-width: 100%; height: auto; display: block; }
ul { list-style: none; }

/* ---- Layout helpers ---- */
.container { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--sp-4); }
.section { padding: var(--sp-8) 0; }
/* Kotwice (#cennik itp.) nie chowają nagłówka pod sticky-headerem/banerem przy skoku.
   Domyślnie 0px (topnav NIE jest sticky → brak sztucznej luki). Apka, która USTAWI sticky
   nawigację landingu, definiuje --sticky-offset (= wysokość paska) na :root i kotwice
   automatycznie dostają oddech. Wzorzec: dobrywstep .lp-section[id] scroll-margin-top:96px. */
.section[id] { scroll-margin-top: var(--sticky-offset, 0px); }
.stack > * + * { margin-top: var(--sp-4); }
.center { text-align: center; }
.muted { color: var(--color-text-muted); }
.hidden { display: none !important; }

/* ---- Button ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  font-family: var(--font-body); font-size: 1rem; font-weight: 600;
  padding: var(--sp-3) var(--sp-5);
  border: var(--border-w) solid transparent; border-radius: var(--radius);
  cursor: pointer; text-decoration: none; transition: background .15s, border-color .15s, opacity .15s;
  background: var(--color-surface); color: var(--color-text);
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--color-accent); color: var(--color-accent-text); }
.btn-primary:hover { background: var(--color-accent-hover); }
.btn-ghost { background: transparent; border-color: var(--color-border); }
.btn-ghost:hover { background: var(--color-surface); }
.btn:disabled { opacity: .55; cursor: not-allowed; }
.btn-block { width: 100%; }

/* ---- Card ---- */
.card {
  background: var(--color-surface);
  border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius);
  padding: var(--sp-5);
  box-shadow: var(--shadow-sm);
}

/* ---- Input / form ---- */
.field { display: block; margin-bottom: var(--sp-4); }
.field label { display: block; font-size: .875rem; font-weight: 600; margin-bottom: var(--sp-2); }
.input {
  width: 100%; font-family: var(--font-body); font-size: 1rem;
  padding: var(--sp-3); color: var(--color-text); background: var(--color-bg);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius);
}
.input:focus { outline: 2px solid var(--color-accent); outline-offset: 1px; }

/* ---- Feedback message (auth/errors) ---- */
.msg { padding: var(--sp-3); border-radius: var(--radius); font-size: .9rem; }
.msg-error   { background: #fdecec; color: var(--color-error); }
.msg-success { background: #e8f6ee; color: var(--color-success); }

/* ---- Badge (lifecycle status) ---- */
.badge {
  display: inline-block; font-size: .75rem; font-weight: 600;
  padding: 2px var(--sp-2); border-radius: 999px; border: var(--border-w) solid var(--color-border);
}
/* Warianty statusu (np. dostarczalność maili w Wiadomościach): OK / oczekujący / błąd. */
.badge-ok     { border-color: var(--color-success); color: var(--color-success); }
.badge-warn   { border-color: var(--color-warning); color: var(--color-warning); }
.badge-danger { border-color: var(--color-error);   color: var(--color-error); }

/* ---- Top nav (app/admin) ---- */
.topnav {
  display: flex; align-items: center; justify-content: space-between;
  padding: var(--sp-3) var(--sp-4);
  border-bottom: var(--border-w) solid var(--color-border);
  background: var(--color-bg);
}
.topnav .brand { font-weight: 700; font-family: var(--font-head); }
.topnav nav { display: flex; gap: var(--sp-4); align-items: center; }

/* Stopka nawigacyjna: linki tekstowe muszą mieć cel dotykowy ≥44px (WCAG 2.5.8 wymaga ≥24px;
   44px = komfort). inline-flex, by separatory „·" zostały w tekście, a tap-area linku objęła
   cały jego wiersz bez rozpychania układu w poziomie. Klasa `foot-nav` na <footer>. */
.foot-nav a { display: inline-flex; align-items: center; min-height: 44px; }
/* Wąskie telefony (≤560px): nagłówek nie może rozpychać strony (poziomy scroll całej appki — lekcja S4a).
   Zawijamy pasek i skracamy e-mail usera z wielokropkiem zamiast wypychać „Wyloguj" poza ekran. */
@media (max-width: 560px) {
  .topnav { flex-wrap: wrap; row-gap: var(--sp-2); }
  .topnav nav { flex-wrap: wrap; gap: var(--sp-2) var(--sp-3); min-width: 0; justify-content: flex-end; }
  .topnav nav #user-name { max-width: 42vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* ---- Empty state ---- */
.empty {
  text-align: center; padding: var(--sp-8) var(--sp-4);
  border: var(--border-w) dashed var(--color-border); border-radius: var(--radius);
  color: var(--color-text-muted);
}

/* ---- Table (admin) ---- */
/* Afordancja przewijania poziomego (mobile): subtelny cień na krawędzi, gdy tabela ma więcej
   kolumn w poziomie niż widać (np. Historia wiadomości — kolumna Status po prawej). Cień znika po
   dosunięciu do końca dzięki background-attachment: local. Baza = --color-surface (białe karty,
   motyw light-only — bez wariantu dark). Wszystkie .table-wrap to białe .card panelu admina.
   Backport S-W1 Dobry Wstęp. */
.table-wrap {
  overflow-x: auto;
  background:
    linear-gradient(to right, var(--color-surface) 30%, transparent) 0 0 / 28px 100% no-repeat local,
    linear-gradient(to left, var(--color-surface) 30%, transparent) 100% 0 / 28px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, rgba(31, 25, 15, 0.10), transparent) 0 0 / 12px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, rgba(31, 25, 15, 0.10), transparent) 100% 0 / 12px 100% no-repeat scroll,
    var(--color-surface);
}
table { width: 100%; border-collapse: collapse; font-size: .9rem; }
th, td { text-align: left; padding: var(--sp-3); border-bottom: var(--border-w) solid var(--color-border); }
th { font-weight: 600; color: var(--color-text-muted); }

/* ---- Grid ---- */
.grid { display: grid; gap: var(--sp-4); }
@media (min-width: 720px) {
  .grid-2 { grid-template-columns: repeat(2, 1fr); }
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(4, 1fr); }
}

/* ---- Separator „albo" (OAuth ↔ formularz e-mail) ---- */
.or-sep { display: flex; align-items: center; gap: var(--sp-3); margin: 0 0 var(--sp-4); color: var(--color-text-muted); font-size: .8rem; }
.or-sep::before, .or-sep::after { content: ""; flex: 1; height: 1px; background: var(--color-border); }

/* ---- Baner trybu podglądu operatora (impersonation) — TRWAŁY, u góry, czerwony ---- */
.impersonation-banner {
  position: sticky; top: 0; z-index: var(--z-banner);
  background: var(--color-error); color: #fff;
  padding: var(--sp-2) var(--sp-4); text-align: center;
  font-size: .85rem; font-weight: 600;
}

/* ---- TRYB PRZERWY TECHNICZNEJ (maintenance mode, B10) — plansza + baner (maintenance.js) ----
   Plansza (mode 'app'): pełny ekran NAD wszystkim, user nie działa. Baner (mode 'admin'): sticky,
   panel operatora działa dalej. Landing (index.html) świadomie bez bramki. Wszystko na tokenach DS. */
.maintenance-locked { overflow: hidden; }
.maintenance-plane {
  position: fixed; inset: 0; z-index: var(--z-maintenance);
  display: flex; align-items: center; justify-content: center; padding: var(--sp-5);
  background: var(--color-bg);
}
.maintenance-box {
  max-width: 420px; width: 100%; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-4);
}
.maintenance-box .maintenance-brand { transform: scale(1.1); margin-bottom: var(--sp-2); }
.maintenance-ico { width: 44px; height: 44px; color: var(--color-accent); }
.maintenance-title { font-size: 1.5rem; }
.maintenance-sub { font-size: 1rem; margin: 0; }

.maintenance-banner {
  position: sticky; top: 0; z-index: var(--z-banner);
  display: flex; align-items: center; justify-content: center; gap: var(--sp-3); flex-wrap: wrap;
  background: var(--color-warning, #C08A16); color: #fff;
  padding: var(--sp-2) var(--sp-4); text-align: center;
  font-size: .85rem; font-weight: 600;
}
.maintenance-banner-link { color: #fff; text-decoration: underline; white-space: nowrap; }

/* ---- Zgoda (checkbox z linkami przy rejestracji) ---- */
.check-line { display: flex; gap: var(--sp-2); align-items: flex-start; font-size: .9rem; margin-bottom: var(--sp-4); }
.check-line input { margin-top: 3px; }

/* ---- Onboarding: wiersz kroku „Pierwsze kroki" (stack na wąskich telefonach) ----
   Forward-compatible (S27): gdy apka zbuduje POZIOMY wiersz kroku (.onb-step z przyciskiem .btn),
   poniżej 460px przycisk schodzi pod treść na całą szerokość zamiast się ściskać.
   Starter renderuje kroki jako listę .check-line (już pionowo) — reguła aktywuje się dopiero
   gdy apka doda .onb-step (jak Fachmat). Zero efektu dla obecnego #onboarding-card. */
@media (max-width: 460px) {
  .onb-step { flex-wrap: wrap; }
  .onb-step .btn { flex-basis: 100%; width: 100%; margin-top: var(--sp-2); }
}

/* ---- Checklist „Pierwsze kroki" — @dsChecklist (STANDARD FABRYKI) ----------
   Renderowana przez js/onboard.js (initChecklist). Pasek postępu x/N, 1. krok
   PRE-CHECKED (endowed progress), odhaczanie po evencie/akcji, celebracja
   papierowa (@dsCelebrate), znika po ukończeniu. Kroki = KONFIGURACJA per apka
   (ONBOARDING_STEPS). Klasa .ds-checklist na kontenerze karty. ------------- */
.ds-checklist { padding: var(--sp-5); }
/* Nagłówek oczekiwań (§1.3) — ZAWSZE nad checklistą, niezależny od survey: jedno zdanie wartości + czas. */
.ds-onb-welcome { font-size: .95rem; color: var(--color-text); margin: 0 0 var(--sp-4); line-height: 1.5; }
.ds-onb-welcome-time { color: var(--color-text-muted); font-weight: 600; white-space: nowrap; }
.ds-checklist-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.ds-checklist-head h3 { margin: 0; }
.ds-checklist-count {
  font-size: .8rem; font-weight: 700; color: var(--color-text-muted);
  background: var(--color-bg); border: var(--border-w) solid var(--color-border);
  border-radius: 999px; padding: 2px var(--sp-2);
}
.ds-checklist-sub { font-size: .9rem; margin: var(--sp-2) 0 var(--sp-3); }

/* Pasek postępu — @dsProgress. Track + fill (szerokość ustawia JS w %). */
.ds-progress { height: 8px; border-radius: 999px; background: var(--color-border); overflow: hidden; }
.ds-progress-fill {
  height: 100%; border-radius: 999px; background: var(--color-accent);
  transition: width .35s cubic-bezier(.4, 0, .2, 1); min-width: 6px;
}

.ds-checklist-list { list-style: none; margin: var(--sp-4) 0 0; padding: 0; }
.ds-checklist-item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-top: var(--border-w) solid var(--color-border);
  font-size: .95rem;
}
.ds-checklist-item:first-child { border-top: 0; }
.ds-check-ico {
  flex: none; width: 24px; height: 24px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  border: var(--border-w) solid var(--color-border); background: var(--color-bg);
  color: var(--color-accent-text); font-size: .8rem; font-weight: 700;
}
.ds-checklist-item.is-done .ds-check-ico { background: var(--color-success); border-color: transparent; }
.ds-check-label { flex: 1 1 auto; min-width: 0; }
.ds-checklist-item.is-done .ds-check-label { color: var(--color-text-muted); text-decoration: line-through; }
.ds-check-cta { flex: none; margin-left: auto; }
.ds-check-box { flex: none; margin-left: auto; width: 18px; height: 18px; }
/* Krok przyszły — wskaźnik nieaktywny (nie przycisk): „jeden oczywisty następny ruch" ma TYLKO pierwszy
   nieukończony krok (§1.4). Wyszarzony, bez interakcji. Tokeny DS (spójny z @dsChecklist), nie hardkod. */
.ds-check-cta-later {
  flex: none; margin-left: auto; display: inline-flex; align-items: center; justify-content: center;
  padding: var(--sp-2) var(--sp-3); border-radius: var(--radius);
  font-size: .85rem; font-weight: 600; color: var(--color-text-muted);
  background: var(--color-border); cursor: default; pointer-events: none; user-select: none;
}

/* Krok „awaiting" (§6 pkt 5) — user zrobił swoją część, wartość domknie ŚWIAT (event serwerowy). Stan
   „✓ Zrobione po Twojej stronie — czekamy na X" ma NIE wyglądać jak porażka: ikona = subtelny check (nie
   sukces-zielony, bo krok jeszcze trwa), status wyszarzony po prawej. Odhaczenie robi realny event. */
.ds-checklist-item.is-await .ds-check-ico { background: var(--color-surface); border-color: var(--color-border); color: var(--color-text-muted); }
.ds-checklist-item.is-await .ds-check-ico::after { content: "\2713"; } /* ✓ — Twoja część zrobiona */
.ds-check-await {
  flex: 1 1 auto; margin-left: auto; text-align: right;
  font-size: .85rem; color: var(--color-text-muted); font-style: italic; line-height: 1.35;
}

/* Celebracja papierowa — @dsCelebrate. Lekki stempel „Gotowe!" (NIE gadżet). */
.ds-celebrate { text-align: center; padding: var(--sp-6) var(--sp-4); }
.ds-celebrate-stamp {
  display: inline-block; font-family: var(--font-head); font-weight: 800;
  font-size: 1.35rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--color-success); border: 2.5px solid var(--color-success);
  border-radius: var(--radius); padding: var(--sp-2) var(--sp-4);
  transform: rotate(-4deg); opacity: .92;
  animation: ds-stamp-in .32s cubic-bezier(.34, 1.56, .64, 1) both;
}
.ds-celebrate-msg { margin: var(--sp-4) 0 0; color: var(--color-text-muted); font-size: .95rem; }
@keyframes ds-stamp-in { from { transform: rotate(-4deg) scale(1.35); opacity: 0; } to { transform: rotate(-4deg) scale(1); opacity: .92; } }
@media (prefers-reduced-motion: reduce) { .ds-celebrate-stamp { animation: none; } .ds-progress-fill { transition: none; } }

@media (max-width: 460px) {
  .ds-checklist-item { flex-wrap: wrap; }
  .ds-check-cta, .ds-check-cta-later, .ds-check-box { margin-left: calc(24px + var(--sp-3)); }
  .ds-check-await { margin-left: calc(24px + var(--sp-3)); text-align: left; flex-basis: 100%; }
}

/* ---- Empty-state uczący — @dsEmptyOnboard (helper emptyOnboard() w onboard.js) ----
   Rozszerza .empty: (a) nazwa WARTOŚCI, (b) ghost-row/preview (aria-hidden),
   (c) 1 CTA czasownik, (d) furtka (dane przykładowe/import). ZERO przeprosin. */
.ds-empty-onb { text-align: center; }
.ds-empty-onb-value { margin: 0; color: var(--color-text); }
.ds-empty-onb-hint { margin: var(--sp-2) auto 0; max-width: 46ch; }
.ds-empty-onb-cta { margin-top: var(--sp-5); display: flex; gap: var(--sp-3); justify-content: center; flex-wrap: wrap; }
/* Ghost-row: kształt sukcesu, wyszarzony (to atrapa, nie dane → aria-hidden w JS). */
.ds-ghost { max-width: 340px; margin: 0 auto var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.ds-ghost-row {
  height: 14px; border-radius: 6px;
  background: linear-gradient(90deg, var(--color-border) 0%, var(--color-surface) 50%, var(--color-border) 100%);
  opacity: .6;
}
.ds-ghost-row:nth-child(2) { width: 86%; }
.ds-ghost-row:nth-child(3) { width: 68%; }

/* ---- Welcome survey (JTBD) — @dsSurvey. Modal 1-3 pytania (initWelcomeSurvey). ---- */
.ds-survey { max-width: 460px; }
.ds-survey-q { margin-top: var(--sp-4); }
.ds-survey-qlabel { font-weight: 600; margin: 0 0 var(--sp-2); font-size: .95rem; }
.ds-survey-opts { display: flex; flex-direction: column; gap: var(--sp-2); }
.ds-survey-opt { justify-content: flex-start; text-align: left; }
.ds-survey-opt.is-selected { border-color: var(--color-accent); box-shadow: 0 0 0 2px var(--amber-wash); }
.ds-survey-actions { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); margin-top: var(--sp-5); }

/* ---- Lejek onboardingu (panel operatora, Aktywacja) — paski per krok + drop-off ---- */
.onb-funnel-row { padding: var(--sp-3) 0; border-top: var(--border-w) solid var(--color-border); }
.onb-funnel-row:first-child { border-top: 0; }
.onb-funnel-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); font-size: .9rem; margin-bottom: var(--sp-2); }
.onb-funnel-bar { height: 10px; border-radius: 999px; background: var(--color-border); overflow: hidden; }
.onb-funnel-fill { height: 100%; border-radius: 999px; background: var(--color-accent); }
.onb-funnel-row.is-bottleneck .onb-funnel-fill { background: var(--color-warning); }
.onb-funnel-row.is-bottleneck .onb-funnel-head { font-weight: 600; }

/* ---- Kontekstowy tooltip — @dsTooltip (showTip). 1 naraz, action-triggered (2-5 s). ---- */
.ds-tip {
  position: fixed; z-index: var(--z-banner); max-width: 260px;
  display: flex; align-items: flex-start; gap: var(--sp-2);
  background: var(--color-text); color: var(--color-bg);
  border-radius: var(--radius); padding: var(--sp-2) var(--sp-3);
  font-size: .85rem; line-height: 1.4; box-shadow: 0 6px 20px rgba(10, 12, 16, .22);
  animation: ds-tip-in .18s ease-out both;
}
.ds-tip-close { flex: none; background: transparent; border: 0; color: inherit; opacity: .7; cursor: pointer; font-size: 1.1rem; line-height: 1; padding: 0; }
.ds-tip-close:hover { opacity: 1; }
@keyframes ds-tip-in { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ds-tip { animation: none; } }

/* ---- Pas zaufania — @dsTrustBar (trustBar() w onboard.js) — §7 „pas zaufania" (lęk#1=scam) ----
   Stały, widoczny sygnał legitymacji na ekranie onboardingu: kto stoi za produktem / co z danymi (link
   trust page) / 1 dowód / 1 żywy kanał kontaktu. Papierowy motyw, tokeny DS. Zawija się na wąskich. */
.ds-trustbar {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2) var(--sp-4);
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); padding: var(--sp-3) var(--sp-4);
  font-size: .85rem; color: var(--color-text-muted);
}
.ds-trust-item { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.ds-trust-ico { flex: none; font-size: .95rem; line-height: 1; color: var(--color-accent); }
.ds-trust-text { color: var(--color-text); }
.ds-trust-link {
  display: inline-flex; align-items: center; min-height: 24px; /* touch-target ≥24px (WCAG 2.5.8) */
  color: var(--color-accent); font-weight: 600;
}
.ds-trust-link:hover { text-decoration: underline; }

/* ---- Pomiar jakościowy drop-offu — @dsFriction (askFriction() w onboard.js) — §7 ----
   Mikro-prompt „Co Cię zatrzymało?" (3-4 powody 1-tap + opcjonalne pole). Lekki, papierowy, pomijalny.
   Wariant pływający (.ds-friction-floating) = karta u dołu ekranu; wariant osadzony (opts.mount) = w karcie. */
.ds-friction {
  background: var(--color-bg); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); padding: var(--sp-4); box-shadow: var(--shadow-md);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.ds-friction-floating {
  position: fixed; right: var(--sp-4); bottom: var(--sp-4); z-index: var(--z-banner);
  width: min(360px, calc(100vw - 2 * var(--sp-4)));
  animation: ds-friction-in .18s ease-out both;
}
.ds-friction-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); }
.ds-friction-title { margin: 0; font-weight: 700; font-size: .95rem; color: var(--color-text); }
.ds-friction-close {
  flex: none; background: transparent; border: 0; color: var(--color-text-muted); cursor: pointer;
  font-size: 1.2rem; line-height: 1; padding: 0;
  min-width: 24px; min-height: 24px; display: inline-flex; align-items: center; justify-content: center;
}
.ds-friction-close:hover { color: var(--color-text); }
.ds-friction-opts { display: flex; flex-direction: column; gap: var(--sp-2); }
.ds-friction-opt { justify-content: flex-start; text-align: left; min-height: 24px; }
.ds-friction-note { resize: vertical; font-size: .9rem; }
@keyframes ds-friction-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ds-friction-floating { animation: none; } }

/* ---- A11y baseline onboardingu — WCAG 2.2 AA (§7 ONBOARDING-FABRYKA) ---------------------
   Prawnie wymagane w UE od 28.06.2025 (EAA/WCAG 2.2 AA). Widoczny, NIE-zasłonięty focus na
   WSZYSTKICH interaktywnych elementach onboardingu (checklist CTA, survey, empty-state CTA,
   tooltip) + touch-target ≥24×24 px (WCAG 2.5.8 Target Size). Tokeny DS, jasny motyw;
   prefers-reduced-motion respektowany wyżej (animacje @dsCelebrate/@dsTooltip). ----------- */
/* SR-only — status postępu (aria-live) ogłaszany czytnikowi bez zmiany layoutu (onboard.js renderChecklist). */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* Widoczny focus-visible — część elementów onboardingu (checkbox, tip-close) nie dziedziczy stylu .btn. */
.ds-check-cta:focus-visible,
.ds-check-box:focus-visible,
.ds-survey-opt:focus-visible,
.ds-survey-actions .btn:focus-visible,
.ds-empty-onb-cta .btn:focus-visible,
.ds-empty-onb-escape:focus-visible,
.ds-tip-close:focus-visible,
.ds-trust-link:focus-visible,
.ds-friction-opt:focus-visible,
.ds-friction-close:focus-visible {
  outline: 2px solid var(--color-accent); outline-offset: 2px; border-radius: var(--radius);
}
/* Touch-target ≥24×24 px (WCAG 2.5.8) na interaktywnych elementach onboardingu. */
.ds-check-cta, .ds-survey-opt, .ds-empty-onb-cta .btn, .ds-empty-onb-escape { min-height: 24px; }
.ds-check-box { min-width: 24px; min-height: 24px; }
.ds-tip-close { min-width: 24px; min-height: 24px; display: inline-flex; align-items: center; justify-content: center; }

/* ---- Przycisk destrukcyjny + strefa czerwona (usunięcie konta) ---- */
.btn-danger { background: var(--color-error); color: #fff; }
.btn-danger:hover { background: #a01f1f; }
.danger-zone { border-color: var(--color-error); }

/* ---- Overlay pełnoekranowy (subscription gating: past_due / canceled) ----
   UWAGA: to warstwa UX. Twardy gate = RLS/edge (patrz app.js requireActiveSub). */
.overlay {
  position: fixed; inset: 0; z-index: var(--z-overlay);
  display: flex; align-items: center; justify-content: center; padding: var(--sp-4);
  background: rgba(10, 12, 16, .72); backdrop-filter: blur(2px);
}
.overlay-box { max-width: 440px; text-align: center; background: var(--color-bg); }

/* ---- Pływający przycisk „Zgłoś uwagę" (feedback widget) ----
   Desktop (≥1024px): kompaktowa pigułka-ikona (52×52) bez etykiety — nie zasłania treści.
   Mobile: pełna pigułka z ikoną + etykietą (czytelny cel dotyku). */
.fab {
  position: fixed; right: var(--sp-4); bottom: var(--sp-4); z-index: var(--z-fab);
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5); border-radius: 999px; border: none;
  background: var(--color-accent); color: var(--color-accent-text);
  font-weight: 600; cursor: pointer; box-shadow: var(--shadow-md);
  transition: transform var(--dur-base, .25s) var(--ease-out, ease), opacity var(--dur-base, .25s) ease;
}
.fab:hover { background: var(--color-accent-hover); }
/* KLASA BŁĘDU „FAB zakrywa wartości/treść" (backport DW S4b/S4d/S4e — 3× kolizja FAB↔treść w jednej apce)
   → jedna GLOBALNA reguła zamiast łatania per-ekran: pływający FAB CHOWA SIĘ przy przewijaniu w dół
   (czytanie) i wraca przy przewijaniu w górę / u góry (js: toggle .fab-tucked wg kierunku scrolla —
   app.js initFabAutoHide). Dzięki temu FAB NIGDY nie „siedzi" nad treścią, którą user właśnie czyta —
   działa DOMYŚLNIE na KAŻDYM ekranie każdej apki. reduced-motion respektowane. */
.fab.fab-tucked { transform: translateY(160%); opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: reduce) { .fab { transition: opacity .01ms; } }
.fab .fab-ico { flex: none; }
@media (min-width: 1024px) {
  .fab { width: 52px; height: 52px; padding: 0; justify-content: center; }
  .fab .fab-label { display: none; }
}
/* Wąskie telefony (≤375px): pełna pigułka „Zgłoś uwagę" zachodziła na treść — zwijamy do samej ikony
   (koło 48×48), etykieta znika. Cel dotyku ≥44px zachowany. */
@media (max-width: 375px) {
  .fab { width: 48px; height: 48px; padding: 0; justify-content: center; }
  .fab .fab-label { display: none; }
}

/* ---- Toast (efemeryczny komunikat sukcesu/akcji) — @dsToast ----
   Prosty, papierowy, z aria-live (ogłaszany czytnikowi). Tworzony w JS (app.js showToast).
   Znika sam; NIE blokuje interakcji. Ruch respektuje reduced-motion. */
.toast-wrap {
  position: fixed; left: 50%; bottom: var(--sp-5); transform: translateX(-50%);
  z-index: var(--z-toast); display: flex; flex-direction: column; gap: var(--sp-2);
  width: min(420px, calc(100vw - 2 * var(--sp-4))); pointer-events: none;
}
.toast {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  background: var(--color-text); color: var(--color-surface);
  border-radius: var(--radius); padding: var(--sp-3) var(--sp-4);
  box-shadow: var(--shadow-md); font-size: .92rem; line-height: 1.4;
  animation: toast-in .2s ease-out both;
}
.toast::before {
  content: "✓"; flex: none; font-weight: 800; color: var(--color-accent); line-height: 1.4;
}
.toast.is-leaving { animation: toast-out .2s ease-in both; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes toast-out { from { opacity: 1; } to { opacity: 0; transform: translateY(8px); } }
@media (prefers-reduced-motion: reduce) { .toast, .toast.is-leaving { animation: none; } }

/* ---- Modal (feedback) ---- */
.modal-backdrop {
  position: fixed; inset: 0; z-index: var(--z-modal);
  display: flex; align-items: center; justify-content: center; padding: var(--sp-4);
  background: rgba(10, 12, 16, .55);
}
/* Paywall = modal wyboru planu OTWIERANY Z overlaya gatingu → MUSI być nad overlayem
   (canceled/past_due), inaczej plany są zasłonięte i user nie wznowi subskrypcji. */
.modal-backdrop.paywall { z-index: var(--z-paywall); }
.modal { width: 100%; max-width: 480px; background: var(--color-bg); }
.modal textarea.input { resize: vertical; }

/* ============================================================
   SHELL nawigacji w tabach — panel operatora (admin) + wejście operatora (app).
   Standard fabryki: kanoniczny topnav z zakładkami + hash-routing + menu mobilne.
   Reużywany przez admin.html (6 zakładek) i app.html (link „Panel operatora").
   Wszystko na tokenach; #fff = biel na grafitowym tle (jak reszta pliku, brak tokenu bieli).
   ============================================================ */

/* ---- Warianty przycisków używane w topnav ---- */
.btn-sm { padding: var(--sp-2) var(--sp-4); font-size: .85rem; }
.btn-neutral { background: var(--color-text); color: #fff; border-color: var(--color-text); }
.btn-neutral:hover { background: var(--color-text); opacity: .88; }

/* ---- Nagłówek widoku (tytuł zakładki) ---- */
.page-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); margin-bottom: var(--sp-4); flex-wrap: wrap; }

/* ---- Plakietka „PANEL OPERATORA" (odróżnienie panelu od aplikacji) ---- */
.plaq {
  display: inline-flex; align-items: center; gap: var(--sp-2); flex: none;
  background: var(--color-text); color: #fff; border-radius: var(--radius);
  padding: var(--sp-1) var(--sp-3);
  font-weight: 700; font-size: .7rem; letter-spacing: .08em; text-transform: uppercase;
}
.plaq-op::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: var(--color-accent); flex: none; }

/* ---- Zakładki topnav (hash-routing; aktywna = podkreślenie akcentu) ---- */
.navtabs { display: flex; gap: var(--sp-4); align-items: center; flex: 1; justify-content: center; }
.navtab {
  font-weight: 600; font-size: .9rem; color: var(--color-text-muted);
  padding: var(--sp-2) 0; border-bottom: 2px solid transparent; text-decoration: none;
  transition: color .2s, border-color .2s;
}
.navtab:hover { color: var(--color-text); text-decoration: none; }
.navtab-active { color: var(--color-text); border-bottom-color: var(--color-accent); }
/* Link „Panel operatora" w app (widoczny tylko dla operatora) — wyróżniony obrys-pigułka */
.navtab-op {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1.5px solid var(--color-text); border-radius: 999px;
  padding: 5px var(--sp-3); color: var(--color-text);
  transition: background .15s, color .15s;
}
.navtab-op:hover { background: var(--color-text); color: #fff; text-decoration: none; }
.navtab-op svg { flex: none; }

/* ---- CTA topnav (← Aplikacja) + przycisk MENU (mobile) ---- */
.nav-cta { flex: none; }
.nav-menu-mobile { display: none; flex: none; }

/* ---- Rozwijane menu (mobile ≤860px) — lista zakładek pod topnavem (vanilla) ---- */
.nav-menu-panel {
  display: flex; flex-direction: column; gap: 2px;
  background: var(--color-surface); border-bottom: var(--border-w) solid var(--color-border);
  box-shadow: var(--shadow-sm); padding: var(--sp-2);
}
.nav-menu-panel a {
  display: block; text-align: left; font-weight: 600; font-size: .95rem; color: var(--color-text);
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius); text-decoration: none;
}
.nav-menu-panel a:hover { background: var(--color-bg); text-decoration: none; }
.nav-menu-panel a.navtab-active { color: var(--color-accent); }
.nav-menu-panel .nav-menu-op, .nav-menu-panel .nav-cta-m { color: var(--color-accent); }
.nav-menu-head { display: block; font-size: .7rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--color-text-muted); padding: var(--sp-2) var(--sp-4) var(--sp-1); }

/* ---- Pasek konta operatora (Pulpit): kto zalogowany + Wyloguj ---- */
.admin-userbar { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-5); }

/* ---- Widok routera (pokazywanie/ukrywanie przez .hidden) ---- */
.view { animation: fade-in .18s ease-out; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ---- Fix overflow poziomy tabel na mobile ----
   Karty gridu (grid-3/grid-4) mają domyślnie min-width:auto → nie schodzą poniżej
   min-content i rozpychają viewport. Zerujemy min-width, a szerokie tabele scrollują
   REALNIE wewnątrz .table-wrap (overflow-x:auto) zamiast rozciągać stronę. */
.grid > * { min-width: 0; }
[data-view] .table-wrap { max-width: 100%; }

/* ---- Mobile ≤860px: topnav = brand + MENU; zakładki/CTA/plakietkę chowamy ----
   Breakpoint 860 (nie 720): desktopowy topnav (zakładki + CTA + plakietka) nie mieści się
   poniżej ~860px → w strefie 721–860px rozpychał viewport i dawał poziomy scroll (S27). */
@media (max-width: 860px) {
  .topnav .navtabs, .topnav .nav-cta, .topnav .plaq-op { display: none; }
  .nav-menu-mobile { display: inline-flex; }
}

/* ============================================================
   MODUŁ WIADOMOŚCI (panel operatora — tab „Wiadomości"): pod-zakładki, edytor szablonów,
   podgląd renderu w iframe. Wszystko na tokenach. */
.subtabs { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-5);
  border-bottom: var(--border-w) solid var(--color-border); }
.subtab {
  background: transparent; border: none; border-bottom: 2px solid transparent;
  padding: var(--sp-3) var(--sp-3); font-family: var(--font-body); font-size: .9rem; font-weight: 600;
  color: var(--color-text-muted); cursor: pointer; transition: color .15s, border-color .15s;
}
.subtab:hover { color: var(--color-text); }
.subtab-active { color: var(--color-text); border-bottom-color: var(--color-accent); }

/* Szablony: lista + edytor obok siebie (na wąskich = jedna kolumna). */
.msg-tpl-grid { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 900px) { .msg-tpl-grid { grid-template-columns: 260px 1fr; align-items: start; } }
.msg-tpl-editor { display: block; }
#tpl-list li { list-style: none; }
.tpl-item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  width: 100%; text-align: left; background: transparent; border: var(--border-w) solid transparent;
  border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); cursor: pointer;
  font-family: var(--font-body); font-size: .9rem; color: var(--color-text);
}
.tpl-item:hover { background: var(--color-bg); }
.tpl-item-active { background: var(--color-bg); border-color: var(--color-border); font-weight: 600; }
.tpl-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; background: var(--color-text-muted); }
.tpl-dot.on { background: var(--color-success); }
.tpl-dot.off { background: var(--color-warning); }

/* Podgląd renderu w izolowanym iframe (sandbox="" — brak skryptów, XSS-safe). */
.msg-preview-wrap { margin-top: var(--sp-4); }
.msg-preview {
  width: 100%; height: 420px; border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); background: #f4f5f7;
}

/* ============================================================
   MODUŁ POLECENIA — prompt aha (pasek), licznik, panel operatora. Wszystko na tokenach. */
.aha-ref {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-left: 3px solid var(--color-accent); border-radius: var(--radius);
  padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-5); box-shadow: var(--shadow-sm);
}
.aha-ref #aha-referral-text { flex: 1 1 220px; font-size: .95rem; color: var(--color-text); }
.aha-ref-close {
  background: transparent; border: none; color: var(--color-text-muted); cursor: pointer;
  font-size: 1.3rem; line-height: 1; padding: 0 var(--sp-1);
}
.aha-ref-close:hover { color: var(--color-text); }
.ref-stats { color: var(--color-text-muted); }
.ref-stats b { color: var(--color-text); }
.ref-stat-grid { display: grid; gap: var(--sp-3); grid-template-columns: repeat(2, 1fr); }
@media (min-width: 720px) { .ref-stat-grid { grid-template-columns: repeat(5, 1fr); } }
.ref-stat { background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); padding: var(--sp-3) var(--sp-4); }
.ref-stat .n { font-family: var(--font-head); font-size: 1.5rem; color: var(--color-text); }
.ref-stat .l { font-size: .8rem; color: var(--color-text-muted); }
.ref-chip { display: inline-block; padding: 2px var(--sp-2); border-radius: 999px;
  font-size: .78rem; font-weight: 600; border: var(--border-w) solid var(--color-border); }
.ref-chip.invited  { color: var(--color-text-muted); }
.ref-chip.paid     { color: var(--color-warning); border-color: var(--color-warning); }
.ref-chip.rewarded { color: var(--color-success); border-color: var(--color-success); }
.ref-chip.refunded, .ref-chip.rejected { color: var(--color-error); border-color: var(--color-error); }

/* ---- Kreator etapowy — @dsWizard (STANDARD FABRYKI) -------------------------
   Formularz RDZENIA (>5–6 pól) rozbij na kroki „jedna myśl / jedno pytanie na
   ekran" — nie ściana pól. Ta sama zasada „jedna myśl" co landing, dla WEJŚCIA
   danych. Składniki: pasek postępu (żetony + etykiety, klik w osiągnięty krok =
   skok wstecz) + kroki (.wiz-step, przełączane .hidden) + nawigacja (.wiz-nav:
   Wstecz/Dalej + submit na ostatnim) + walidacja PER KROK (.field-err pod polem)
   + autozapis szkicu przy „Dalej" (logika w js/app.js — upsert draft). Aktywny
   krok = akcent, ukończony = sukces (oliwka) z checkiem. Mobile: jedno pytanie
   na ekran, etykiety pasku chowane, nawigacja pełnej szerokości.
   GOTCHA: przełączaj przyciski nawigacji klasą .hidden (display:none !important),
   NIE atrybutem [hidden] — .btn{display:...} (specyficzność klasy) bije UA
   [hidden]{display:none}, więc [hidden] na .btn NIE ukrywa (oba CTA naraz). ---- */
.wizard-steps { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: nowrap; margin-bottom: var(--sp-5); }
.wizard-step {
  display: inline-flex; align-items: center; gap: var(--sp-2); flex: 0 1 auto; min-width: 0;
  background: transparent; border: 0; padding: 2px; margin: -2px; border-radius: var(--radius);
  font-family: var(--font-body); font-size: .875rem; font-weight: 600;
  color: var(--color-text-muted); cursor: default; text-align: left;
}
.wizard-step:not(:disabled) { cursor: pointer; }
.wizard-step .wiz-dot {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--color-surface); color: var(--color-text-muted);
  font-weight: 700; font-size: .875rem; line-height: 1; border: var(--border-w) solid var(--color-border);
}
.wizard-step .wiz-label { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wizard-step.is-active { color: var(--color-text); }
.wizard-step.is-active .wiz-dot { background: var(--color-accent); color: var(--color-accent-text); border-color: transparent; }
.wizard-step.is-done { color: var(--color-success); }
.wizard-step.is-done .wiz-dot { background: var(--color-success); color: #fff; border-color: transparent; }
.wizard-step:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.wizard-sep { flex: 1 1 auto; height: 2px; min-width: 10px; background: var(--color-border); border-radius: 2px; }

.wiz-q { font-family: var(--font-head); font-size: 1.5rem; line-height: 1.15; color: var(--color-text); margin: 0; }
.wiz-q-sub { color: var(--color-text-muted); font-size: 1rem; margin: 0 0 var(--sp-2); max-width: 48ch; }

.wiz-nav { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-2); }
.wiz-nav .wiz-spacer { flex: 1 1 auto; }
.wiz-draft-row { text-align: center; margin: var(--sp-1) 0 0; }

/* Błąd walidacji pod polem — @dsFieldError (inline, per pole). */
.field-err { display: block; font-size: .8125rem; color: var(--color-error); margin-top: var(--sp-2); font-weight: 600; }
.input.is-invalid, textarea.input.is-invalid, select.input.is-invalid {
  border-color: var(--color-error); box-shadow: 0 0 0 3px rgba(192, 38, 38, .15);
}

@media (max-width: 430px) {
  .wizard-steps { gap: var(--sp-1); }
  .wizard-step .wiz-label { display: none; }
  .wiz-nav .btn { flex: 1 1 auto; }
  .wiz-nav .wiz-spacer { display: none; }
}

/* ---- Spinner (obrotowy wskaźnik ładowania) — @dsSpinner ----
   Zależność komponentu generacji (js/generation.js) oraz dowolnej akcji „to potrwa chwilę".
   Ruch respektuje prefers-reduced-motion (zwalnia zamiast znikać — wskaźnik nadal żyje). */
.spinner {
  display: inline-block; width: 18px; height: 18px; flex: none; border-radius: 50%;
  border: 2px solid var(--color-border); border-top-color: var(--color-accent);
  animation: ds-spin .7s linear infinite;
}
@keyframes ds-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 1.6s; } }

/* ---- Generacja AI: nazwane etapy + skeleton artefaktu + panel porażki (js/generation.js) — @dsGeneration
   §4b standardu fabryki: „nagi spinner" → rosnąca checklista czynności w 1. osobie, skeleton w kształcie
   wyniku, panel „wina systemu" z retry + fallback. Wszystko na tokenach DS; ruch respektuje reduced-motion;
   jasny „papierowy" motyw (ZAKAZ ciemnych teł). APKA wypełnia etapy/estimate/skeleton w kroku onboarding. */
.gen-wrap { display: flex; flex-direction: column; gap: var(--sp-3); width: 100%; }
.gen-stages { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.gen-stage { display: flex; align-items: center; gap: var(--sp-3); font-family: var(--font-body); font-size: .9rem;
  color: var(--color-text-muted); transition: color .18s ease; }
.gen-stage.is-current { color: var(--color-text); font-weight: 600; }
.gen-stage.is-done { color: var(--color-text-muted); }
.gen-ico { flex: none; display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px;
  border-radius: 50%; background: var(--color-surface); color: var(--color-text-muted);
  font-size: .75rem; font-weight: 700; line-height: 1; }
.gen-stage.is-done .gen-ico { background: var(--color-success); color: #fff; }
.gen-stage .gen-ico .spinner { width: 13px; height: 13px; border-width: 2px; }
.gen-eta { font-size: .8rem; margin: 0; }

/* Skeleton w kształcie artefaktu — szare placeholdery z delikatnym shimmerem (APKA buduje węzły). */
.gen-skel { display: flex; flex-direction: column; gap: var(--sp-3); margin-top: var(--sp-2); opacity: .75; }
.gen-skel-row { display: flex; gap: var(--sp-3); align-items: flex-start; }
.gen-skel-num { flex: none; width: 26px; height: 26px; border-radius: 50%; }
.gen-skel-lines { flex: 1 1 auto; display: flex; flex-direction: column; gap: var(--sp-2); }
.gen-skel-bar { height: 10px; border-radius: 999px; }
.gen-skel-bar.w-40 { width: 40%; }
.gen-skel-bar.w-70 { width: 70%; }
.gen-skel-bar.w-90 { width: 90%; }
.gen-skel-num, .gen-skel-bar {
  background: linear-gradient(90deg, var(--color-border) 25%, var(--color-surface) 37%, var(--color-border) 63%);
  background-size: 400% 100%; animation: gen-shimmer 1.4s ease infinite;
}
@keyframes gen-shimmer { 0% { background-position: 100% 0; } 100% { background-position: 0 0; } }
@media (prefers-reduced-motion: reduce) { .gen-skel-num, .gen-skel-bar { animation: none; } }

/* Panel porażki generacji — wina po stronie SYSTEMU, retry + fallback (bez żargonu). */
.gen-fail { display: flex; flex-direction: column; gap: var(--sp-3); }
.gen-fail-msg { margin: 0; color: var(--color-text); font-size: 1rem; }
.gen-fail-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; }
.gen-fail-note { margin: 0; font-size: .9rem; }

/* ---- Value-before-signup: podgląd wartości + bramka rejestracji — @dsDemoGate (demoAhaGate() w onboard.js).
   §7 „value-before-signup + keepable artifact": apka pokazuje PRÓBKĘ wartości PRZED rejestracją (na landingu),
   z bramką „zarejestruj, by zapisać / pełny wynik". DOMYŚLNIE off (apka włącza przez previewFn). Jasny motyw,
   tokeny DS; ruch respektuje reduced-motion. ------------------------------------------------------------------ */
.ds-demo { display: flex; flex-direction: column; gap: var(--sp-4); width: 100%; }
.ds-demo-preview { display: flex; flex-direction: column; gap: var(--sp-3); }
.ds-demo-gate {
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius);
  background: var(--color-surface); padding: var(--sp-4);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--sp-3);
  animation: ds-demo-reveal .2s ease-out both;
}
.ds-demo-gate-msg { margin: 0; color: var(--color-text); font-size: .95rem; flex: 1 1 220px; }
.ds-demo-cta { flex: none; }
@keyframes ds-demo-reveal { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@media (prefers-reduced-motion: reduce) { .ds-demo-gate { animation: none; } }

/* ---- Agent domyka setup „za mnie": ekran akceptacji przygotowanej konfiguracji — @dsAgentSetup
   (agentSetup() w onboard.js). §7/§4b: gdy setup >2 pól, DOMYŚLNĄ ścieżką jest agent (edge AI) wypełniający
   konfigurację z inputu usera → user tylko sprawdza i AKCEPTUJE (aha = akceptacja). Faza czekania = runGeneration
   (@dsGeneration, ten sam UX). DOMYŚLNIE off. ------------------------------------------------------------------ */
.ds-agentsetup { display: flex; flex-direction: column; gap: var(--sp-4); width: 100%; }
.ds-agentsetup-intro { margin: 0; color: var(--color-text); font-size: .95rem; line-height: 1.5; }
.ds-agentsetup-fields { display: flex; flex-direction: column; gap: var(--sp-4); }
.ds-agentsetup-field { display: flex; flex-direction: column; gap: var(--sp-2); }
.ds-agentsetup-label { font-weight: 600; font-size: .9rem; color: var(--color-text); }
.ds-agentsetup-input { width: 100%; }
.ds-agentsetup-actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; align-items: center; }

/* A11y (§7 WCAG 2.2 AA): widoczny focus-visible + touch-target ≥24 px dla nowego UI (demo-gate / agent-setup).
   Przyciski dziedziczą .btn, ale dokładamy jawny floor (spójnie z resztą onboardingu, patrz .ds-check-cta). */
.ds-demo-cta:focus-visible,
.ds-agentsetup-accept:focus-visible,
.ds-agentsetup-input:focus-visible {
  outline: 2px solid var(--color-accent); outline-offset: 2px;
}
.ds-demo-cta, .ds-agentsetup-accept { min-height: 24px; }

/* ---- Druk (S31): przy Ctrl+P chowamy chrome aplikacji (nawigacja, akcje, warstwy nakładkowe),
   żeby na wydruku/PDF została wyłącznie treść. Uniwersalny podzbiór — TYLKO selektory, które
   starter faktycznie ma. Rozszerzaj per apka o własne elementy sticky/floating (paski sum,
   szybkie skoki, toasty), gdy je dodasz. */
@media print {
  .topnav,
  .nav-menu-panel,
  .nav-menu-mobile,
  .impersonation-banner,
  .fab,
  .aha-ref,
  .ds-tip,
  .ds-friction-floating,
  .toast-wrap,
  .overlay,
  .modal-backdrop {
    display: none !important;
  }
  /* Druk raportu (F4 „PDF" v1 = drukowalny widok): zostaw sam raport, schowaj chrome panelu. */
  .pulpit-head, #an-meta, #an-proc, #an-accept, #an-doks-card, .foot-nav, .report-actions { display: none !important; }
  #an-report { display: block !important; }
  .report-part, .verdict-card { break-inside: avoid; box-shadow: none !important; border: 1px solid #ccc !important; }
  .report-table { font-size: 10pt; }
  body { background: #fff !important; }

  /* ⑤ Druk profesjonalny: marginesy strony + numeracja „Strona X" (silniki wspierające margin-boxy). */
  @page { margin: 18mm 15mm 20mm; @bottom-right { content: "Strona " counter(page); font-size: 9pt; color: #555; } }

  /* Nagłówek dokumentu (print-only) zastępuje ekranowy .report-head — logo + tytuł + ID/inwestor/rola/stan prawny.
     ⛔ BEZ daty wygenerowania raportu (spec D4) — stan prawny to NIE data raportu. */
  .report-head { display: none !important; }
  .print-doc-header { display: flex !important; align-items: center; justify-content: space-between; gap: 12px;
    padding-bottom: 8pt; margin-bottom: 10pt; border-bottom: 1.5pt solid #333; break-after: avoid; }
  .print-doc-header .print-brand { font-family: var(--font-head, serif); font-weight: 800; font-size: 15pt; color: #111; }
  .print-doc-header .print-brand img { max-height: 34px; width: auto; }
  .print-doc-meta { text-align: right; }
  .print-doc-title { margin: 0; font-size: 11pt; font-weight: 700; color: #111; }
  .print-doc-sub { margin: 2pt 0 0; font-size: 8.5pt; color: #555; }

  /* Rozwinięte <details> „Podstawa prawna" na wydruku (JS ustawia open; CSS chowa summary, treść zostaje). */
  .podstawa-disclosure > summary { display: none !important; }
  .podstawa-disclosure, .podstawa-body { display: block !important; }
  .report-table td.podstawa-detail-cell { background: #f7f7f5 !important; border-top: 1px solid #ccc; }
  .przepis-tresc { font-size: 9pt; }

  /* Pozycje raportu i pieczątka werdyktu nie łamią się między stronami. */
  .report-table tbody tr, .flag-pill { break-inside: avoid; }
}

/* ============================================================
   FUNKCJA GŁÓWNA S4a — pulpit (lista analiz), kreator (upload), ekran analizy.
   Motyw jasny z tokenów; zero ciemnych teł. Wszystko textContent-safe (JS). */

/* Aktywna zakładka w topnav (przyciski .btn.navtab) — akcent, nie border-tab. */
.navtab.navtab-active { color: var(--color-accent); background: var(--color-bg); }

/* Stan „ładowanie" przycisku (kreator: autozapis szkicu). */
.btn-loading { opacity: .65; pointer-events: none; }

/* Komunikat neutralny (info). */
.msg-info { background: var(--color-bg); color: var(--color-text-muted); }

/* Warianty plakietki statusu (badge bazowe = linia 125). */
.badge-success { border-color: var(--color-success); color: var(--color-success); }
.badge-warning { border-color: var(--color-warning); color: var(--color-warning); }
.badge-error   { border-color: var(--color-error);   color: var(--color-error); }
.badge-accent  { border-color: var(--color-accent);  color: var(--color-accent); }
.badge-muted   { border-color: var(--color-border);  color: var(--color-text-muted); }

/* Nagłówek widoku: tytuł + akcja po prawej (zawija na wąskich). */
.pulpit-head { display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-5); }

/* Karta analizy na pulpicie (link). */
.an-card {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  flex-wrap: wrap; background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); padding: var(--sp-4); box-shadow: var(--shadow-sm);
  color: var(--color-text); transition: border-color .15s, box-shadow .15s;
}
.an-card:hover { border-color: var(--color-accent); box-shadow: var(--shadow-md, var(--shadow-sm)); }
.an-card-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.an-card-inwestor { font-weight: 600; }
.an-card-rola { font-size: .85rem; }
.an-card-side { display: flex; align-items: center; gap: var(--sp-3); }
.an-card-date { font-size: .85rem; }

/* Demo (furtka onboardingu) — pigułka „przykład” na karcie + baner na widoku analizy. */
.an-demo-pill {
  align-self: flex-start; margin-top: 2px; font-size: .7rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; padding: 1px 7px; border-radius: 999px;
  background: var(--color-surface-2); border: 1px solid var(--color-border); color: var(--color-text-muted);
}
.an-demo-banner {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4); border-radius: var(--radius);
  background: var(--color-surface-2); border: 1px dashed var(--color-border); color: var(--color-text-muted);
  font-size: .9rem;
}
.an-demo-banner span { flex: 1 1 auto; min-width: 0; }
.an-demo-banner .btn { flex: 0 0 auto; }
/* Furtka sceptyka pod checklistą — drugorzędna, wyciszona (nie konkuruje z „Wgraj umowę”). */
.pulpit-furtka {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) 0 0; font-size: .9rem;
}
.pulpit-furtka p { margin: 0; }

/* Wiersz uploadu (kreator, krok 2). */
.upload-row { background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); padding: var(--sp-4); }
.upload-row-head { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.upload-rodzaj { font-weight: 600; }
.upload-req { font-size: .8rem; }
.upload-file { font-size: .85rem; margin: var(--sp-2) 0; word-break: break-all; }
.upload-bar { height: 6px; border-radius: 999px; background: var(--color-bg);
  overflow: hidden; margin: var(--sp-2) 0; }
.upload-bar-fill { height: 100%; width: 0; background: var(--color-accent);
  border-radius: 999px; transition: width .3s ease; }
.upload-bar-fill.is-indeterminate { width: 40%; animation: upload-indet 1.1s ease-in-out infinite; }
@keyframes upload-indet { 0% { margin-left: -40%; } 100% { margin-left: 100%; } }
@media (prefers-reduced-motion: reduce) {
  .upload-bar-fill.is-indeterminate { animation: none; width: 100%; margin-left: 0; opacity: .5; }
}

/* Oś statusów pipeline (ekran analizy). */
.pipeline { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.pipeline-note { color: var(--color-text-muted); font-size: .9rem; margin-bottom: var(--sp-2); }
.pipeline-step { display: flex; align-items: center; gap: var(--sp-3); color: var(--color-text-muted); }
.pipeline-dot { display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 22px; height: 22px; border-radius: 50%; font-size: .75rem; font-weight: 700;
  border: var(--border-w) solid var(--color-border); background: var(--color-surface); color: transparent; }
.pipeline-step.is-done { color: var(--color-text); }
.pipeline-step.is-done .pipeline-dot { background: var(--color-success); border-color: transparent; color: #fff; }
.pipeline-step.is-active { color: var(--color-text); font-weight: 600; }
.pipeline-step.is-active .pipeline-dot { border-color: var(--color-accent); box-shadow: 0 0 0 3px rgba(37,99,235,.15); }
.pipeline-label { font-size: .95rem; }

/* Wiersz podsumowania / metadanych analizy. */
.sum-row { display: flex; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) 0; border-bottom: var(--border-w) solid var(--color-border); }
.sum-row:last-child { border-bottom: 0; }
.sum-l { color: var(--color-text-muted); font-size: .9rem; }
.sum-v { font-weight: 600; text-align: right; word-break: break-word; }

/* Wiersz dokumentu (ekran analizy). */
.dok-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: var(--sp-2) 0; border-bottom: var(--border-w) solid var(--color-border); }
.dok-row:last-child { border-bottom: 0; }
.dok-rodzaj { font-weight: 600; }

/* ============================================================
   FUNKCJA GŁÓWNA S4b — F2 akcept zanonimizowanej kopii + raport 3-częściowy + werdykt-pieczątka.
   Motyw jasny z tokenów; flagi = warstwa wizualna (kanon D2). Wszystko textContent-safe (JS). */

/* --- F2: akcept zanonimizowanej kopii --- */
.anon-doc { border: var(--border-w) solid var(--color-border); border-radius: var(--radius);
  padding: var(--sp-4); background: var(--color-surface-2); }
.anon-doc + .anon-doc { margin-top: var(--sp-3); }
.anon-doc-head { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3); }
.anon-preview { white-space: pre-wrap; word-break: break-word; max-height: 260px; overflow-y: auto;
  background: var(--color-bg); border: var(--border-w) solid var(--color-border); border-radius: var(--radius);
  padding: var(--sp-3); font-size: .85rem; line-height: 1.5; color: var(--color-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; margin: 0; }
.anon-correct { margin-top: var(--sp-3); }
.anon-correct > summary { cursor: pointer; font-size: .9rem; font-weight: 600; color: var(--color-link);
  padding: var(--sp-2) 0; }
.anon-correct > summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.anon-correct textarea { margin-top: var(--sp-2); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .85rem; }
.an-accept-actions { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }

/* --- Werdykt-pieczątka (motyw marki) --- */
.verdict-card { border: 2px solid var(--color-border); border-radius: var(--radius);
  padding: var(--sp-5) var(--sp-5) var(--sp-4); background: var(--color-surface);
  position: relative; overflow: hidden; }
.verdict-ok { border-color: var(--color-success); background: #f2f9f4; }
.verdict-negocjuj { border-color: var(--color-error); background: #fdf3f2; }
.verdict-stamp { display: inline-block; font-weight: 800; letter-spacing: .06em; text-transform: uppercase;
  font-size: clamp(1.1rem, 3vw, 1.5rem); padding: var(--sp-2) var(--sp-4); border: 3px double currentColor;
  border-radius: 6px; transform: rotate(-1.5deg); }
.verdict-ok .verdict-stamp { color: var(--color-success); }
.verdict-negocjuj .verdict-stamp { color: var(--color-error); }
.verdict-sub { margin: var(--sp-3) 0 0; font-weight: 600; }
.verdict-scope { margin: var(--sp-2) 0 0; font-size: .82rem; font-weight: 400; }
.verdict-ocr-warn { margin: var(--sp-2) 0 0; font-size: .85rem; font-weight: 600; color: var(--color-warning, #B45309); }
.verdict-reasons-h { margin: var(--sp-4) 0 var(--sp-2); font-weight: 700; font-size: .95rem; }
.verdict-reasons, .verdict-podstawy ul { margin: 0; padding-left: var(--sp-5); }
.verdict-reasons li, .verdict-podstawy li { margin-bottom: var(--sp-2); font-size: .92rem; }
.verdict-podstawy { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: var(--border-w) solid var(--color-border); }

/* --- Nagłówek raportu --- */
.report-head { margin-bottom: var(--sp-4); }
.report-title { font-size: 1.5rem; margin: 0 0 var(--sp-1); }
.report-nokg { margin: var(--sp-3) 0 0; padding: var(--sp-3); border-radius: var(--radius);
  background: #fef6e7; color: var(--color-warning); font-size: .9rem; border: var(--border-w) solid var(--color-warning); }

/* --- Sekcje / tabele raportu --- */
.report-part { margin-top: var(--sp-4); }
.report-part-title { margin: 0; font-size: 1.15rem; }
.report-part-sub { margin: 0; font-size: .88rem; }
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; border: var(--border-w) solid var(--color-border); border-radius: var(--radius); }
.report-table { width: 100%; border-collapse: collapse; font-size: .85rem; min-width: 640px; }
.report-table th, .report-table td { text-align: left; vertical-align: top; padding: var(--sp-3);
  border-bottom: var(--border-w) solid var(--color-border); }
.report-table thead th { background: var(--color-surface-2); font-weight: 700; font-size: .8rem;
  text-transform: uppercase; letter-spacing: .02em; color: var(--color-text-muted); white-space: nowrap; }
.report-table tbody tr:last-child td { border-bottom: 0; }
.report-table .cell-cyt { color: var(--color-text-muted); font-size: .82rem; max-width: 320px; }
.uwaga-decyzja { color: var(--color-error); font-weight: 800; letter-spacing: .03em; white-space: nowrap; }
.report-stan-prawny { margin: var(--sp-1) 0 0; font-size: .82rem; font-weight: 600; color: var(--color-text-muted); }

/* --- Blok „Podstawa prawna" pod pozycją (④) — natywny <details> (disclosure wg CLAUDE.md §f) --- */
.report-table td.podstawa-detail-cell { padding: 0; background: var(--color-surface-2); }
.podstawa-disclosure { border-top: var(--border-w) solid var(--color-border); }
.podstawa-disclosure > summary { list-style: none; cursor: pointer; padding: var(--sp-2) var(--sp-3);
  font-size: .8rem; font-weight: 700; color: var(--color-accent); display: flex; align-items: center; gap: var(--sp-2); }
.podstawa-disclosure > summary::-webkit-details-marker { display: none; }
.podstawa-disclosure > summary::before { content: "+"; flex: none; display: inline-flex; width: 1.15em; height: 1.15em;
  align-items: center; justify-content: center; border: 1px solid currentColor; border-radius: 4px; line-height: 1; }
.podstawa-disclosure[open] > summary::before { content: "\2013"; }
.podstawa-body { padding: 0 var(--sp-3) var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-3); }
.przepis-item { border-left: 3px solid var(--color-border); padding-left: var(--sp-3); }
.przepis-label { margin: 0; font-weight: 700; font-size: .82rem; }
.przepis-opis { margin: 2px 0 0; font-size: .78rem; color: var(--color-text-muted); }
.przepis-tresc { margin: var(--sp-2) 0 0; font-size: .82rem; line-height: 1.55; white-space: pre-line; }
.przepis-nota { margin: var(--sp-2) 0 0; font-size: .74rem; font-style: italic; color: var(--color-text-muted); }

/* Nagłówek dokumentu tylko dla druku — ukryty na ekranie (odsłaniany w @media print, ⑤). */
.print-doc-header { display: none; }

/* --- Widok kart raportu ≤640px (P2 review_ux E5 R2): tabela → karty dla WSZYSTKICH części (I/II/III),
   flaga „Wynik" na górze; próg = min-width tabeli (640px), więc poniżej niego zero poziomego scrolla --- */
@media (max-width: 640px) {
  .report-table { min-width: 0; }
  .report-table thead { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
  .report-table tbody, .report-table td { display: block; width: auto; }
  .report-table tbody tr { display: flex; flex-direction: column; border: var(--border-w) solid var(--color-border);
    border-radius: var(--radius); background: var(--color-surface); padding: var(--sp-2) var(--sp-3); margin: var(--sp-3); }
  .report-table tbody tr.podstawa-row { margin: calc(var(--sp-3) * -1 + 2px) var(--sp-3) var(--sp-3); border-top: 0;
    border-top-left-radius: 0; border-top-right-radius: 0; padding: 0; }
  .report-table td { display: flex; gap: var(--sp-3); justify-content: space-between; align-items: baseline;
    padding: var(--sp-2) 0; border-bottom: 1px dashed var(--color-border); }
  .report-table tbody tr td:last-child { border-bottom: 0; }
  .report-table td::before { content: attr(data-label); flex: 0 0 38%; font-weight: 700; font-size: .68rem;
    text-transform: uppercase; letter-spacing: .02em; color: var(--color-text-muted); }
  .report-table td.cell-cyt { max-width: none; }
  /* Flaga „Wynik" wyeksponowana na górze karty — zawsze widoczna, bez scrolla w prawo. */
  .report-table td[data-label="Wynik"] { order: -1; border-bottom: var(--border-w) solid var(--color-border);
    padding-bottom: var(--sp-2); margin-bottom: var(--sp-1); }
  /* Wiersz „Podstawa prawna" = pełna szerokość, bez etykiety i bez rozbicia na dwie kolumny. */
  .report-table td.podstawa-detail-cell { display: block; padding: 0; }
  .report-table td.podstawa-detail-cell::before { content: none; }
}

/* --- Flagi (warstwa wizualna, kanon D2) --- */
.flag-pill { display: inline-flex; align-items: center; gap: 4px; padding: 2px var(--sp-2);
  border-radius: 999px; font-size: .75rem; font-weight: 700; white-space: nowrap; border: var(--border-w) solid; }
.flag-pill::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: currentColor; }
.flag-ok   { color: var(--color-success); border-color: var(--color-success); background: #eef7f1; }
.flag-bad  { color: var(--color-error);   border-color: var(--color-error);   background: #fdecec; }
.flag-warn { color: var(--color-warning); border-color: var(--color-warning); background: #fdf4e6; }

/* --- Disclaimer + akcje raportu --- */
.report-disclaimer { margin-top: var(--sp-5); padding-top: var(--sp-4); border-top: var(--border-w) solid var(--color-border);
  font-size: .8rem; color: var(--color-text-muted); font-style: italic; line-height: 1.6; }
.report-actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-5); }
