/* base.css — Solamo · system designu (tokeny + komponenty)
   JEDNO ŹRÓDŁO PRAWDY tokenów w runtime (mapuje 1:1 na brief/04-STYLEGUIDE.md §Kolory/Typografia/Geometria).
   Kierunek: „elegancka papeteria kondolencyjna" — motyw JASNY (ZAKAZ ciemnych ciężkich teł), papier + kość
   słoniowa, zieleń cyprysowa = marka/tekst, złoto WYŁĄCZNIE dekoracyjne (kontrast tekstu <3:1 — patrz 04).
   Wszystkie pary tekst/tło ZMIERZONE WCAG AA (skrypt, nie „na oko"). Stylowanie ad hoc poza tokenami = ZAKAZ. */

/* Fonty: Google Fonts (CDN whitelistowany w vercel.json CSP: fonts.googleapis.com + fonts.gstatic.com),
   font-display:swap. Podzbiór latin-ext = polskie glify (ą ć ę ł ń ó ś ź ż) — Fraunces i Inter je mają. */
@import url('https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght@0,9..144,400..700;1,9..144,400..600&family=Inter:wght@400..700&display=swap');

/* ---- Custom properties (mapują 1:1 na 04-STYLEGUIDE.md) ---- */
:root {
  /* ===== KOLORY — motyw jasny; wartości ZMIERZONE (04-STYLEGUIDE §Kolory) ===== */
  /* Tła / powierzchnie */
  --color-bg:            #F4F0E8;   /* „ciepły papier" — tło stron */
  --color-surface:       #FFFCF6;   /* „kość słoniowa" — karty, panele */
  --color-bg-soft:       #EDE7DA;   /* subtelne wypełnienie: tor paska, chip, hover listy */

  /* Tekst na jasnym (AA/AAA zmierzone) */
  --color-text:          #22332C;   /* atrament — 11.71:1 na papierze (AAA) */
  --color-text-muted:    #635C4C;   /* ciepły taupe drugorzędny — 5.84:1 (AA) */
  --color-heading:       #29483D;   /* zieleń cyprysowa — nagłówki serif, 8.85:1 (AAA) */

  /* Akcent główny = marka / CTA */
  --color-accent:        #29483D;   /* zieleń cyprysowa */
  --color-accent-hover:  #20382E;
  --color-accent-active: #1A2F27;
  --color-accent-text:   #FFFCF6;   /* kość słoniowa na zieleni — 9.82:1 (AAA) */

  /* Akcent 2 = złoto — WYŁĄCZNIE DEKORACYJNE (obrysy, włoskowate linie, kropki etapów, ikony).
     NIE jako kolor TEKSTU na jasnym (2.44:1 = FAIL). „Złoty" tekst → --color-accent-2-text. */
  --color-accent-2:      #B59761;   /* „przygaszone złoto" — dekor/obrys/hairline/węzły etapów */
  --color-accent-2-text: #7A5E30;   /* brąz — złoto-tonowany TEKST (eyebrow, przedział ceny) 5.32:1 (AA) */

  /* Semantyka (fill + wariant tekstowy — 04-STYLEGUIDE §Kolory) */
  --color-success:       #2E6B4E;   /* zieleń „potwierdzone"; tekst 5.55:1, z białym 6.31:1 */
  --color-success-text:  #1E6B45;   /* tekst sukcesu na jasnym — 5.70:1 (AA) */
  --color-warning:       #8A5A18;   /* bursztyn/brąz „oczekuje / past_due"; tekst 5.20:1, z białym 5.90:1 */
  --color-warning-text:  #8A5A18;   /* = warning (przechodzi w OBU kierunkach) */
  --color-error:         #9E342C;   /* stonowany ceglany „błąd"; tekst 6.20:1, z białym 7.04:1 (AAA) */
  --color-error-text:    #9E342C;
  --color-error-active:  #872A23;   /* active/hover .btn-danger */
  --color-success-tint:  #E7F0E9;   /* tło bloku msg-success (tekst success-text 5.56:1) */
  --color-error-tint:    #F6E6E2;   /* tło bloku msg-error (tekst error 5.81:1) */

  /* Obrysy — cienkie, ciepłe (dekoracyjne; identyfikację komponentu niesie focus-ring 2px = 8.85:1) */
  --color-border:        #D8CFBB;
  --color-border-strong: #C7BCA3;   /* mocniejszy podział (gęsta tabela robocza panelu) */

  /* ===== TYPOGRAFIA ===== */
  --font-head: "Fraunces", "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, "Times New Roman", serif;
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* ===== GEOMETRIA ===== */
  --radius-sm:   6px;
  --radius:      8px;    /* workhorse: przyciski, inputy, badge, panele (kanon preview_brief) */
  --radius-lg:   16px;   /* duże kafle dotykowe (rodzina) + karty korzyści (landing) */
  --radius-pill: 999px;
  --border-w: 1px;

  /* Cienie ciepłe (cypress-tinted), „niemal niewidoczne" (research) */
  --shadow-sm: 0 1px 2px rgba(41, 72, 61, .06);
  --shadow-md: 0 6px 20px rgba(41, 72, 61, .08);
  --shadow-lg: 0 14px 40px rgba(41, 72, 61, .10);

  /* ===== RUCH — dyscyplina „premium, godna" (research): hover .15s, UI .2–.3s, load ~.55s ===== */
  --dur-fast: .15s;   /* hover / stany */
  --dur-base: .25s;   /* zmiana stanu UI */
  --dur-slow: .55s;   /* wejście treści / reveal */
  --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.6;
  font-size: 16px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  font-optical-sizing: auto;   /* Fraunces: opsz auto → duże nagłówki bardziej „display", drobny tekst czytelny */
}
/* Nagłówki: serif Fraunces, waga 500 (elegancja papeterii, NIE bold), lekki tracking ujemny, zieleń cyprysowa.
   Landing hero MOŻE nadpisać większym clampem (research: 34→56–60px) własną klasą — patrz 04-STYLEGUIDE. */
h1, h2, h3, h4 { font-family: var(--font-head); color: var(--color-heading); line-height: 1.14; font-weight: 500; letter-spacing: -0.015em; }
h1 { font-size: clamp(2rem, 5vw, 3rem); line-height: 1.1; }
h2 { font-size: clamp(1.5rem, 4vw, 2.25rem); }
h3 { font-size: 1.25rem; letter-spacing: -0.01em; }
h4 { font-size: 1.0625rem; letter-spacing: -0.005em; }
a { color: var(--color-accent); text-decoration: none; }
a:hover { text-decoration: underline; }
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; }
/* CTA główny = serif (ceremonialny — makiety: „Zapisz i przejdź dalej", „Otwórz ustalenia", „Rozpocznij ustalenia”
   są serif w zieleni). Przyciski UTYLITARNE (ghost/sm/neutral, nawigacja) zostają sans — patrz 04-STYLEGUIDE §Typografia. */
.btn-primary { background: var(--color-accent); color: var(--color-accent-text); font-family: var(--font-head); font-weight: 500; letter-spacing: .005em; }
.btn-primary:hover { background: var(--color-accent-hover); }
.btn-primary:active { background: var(--color-accent-active); }   /* sygnał wciśnięcia ceremonialnego CTA */
.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%; }

/* Focus-visible GLOBALNY — pierścień 2px zieleń na workhorse'ach interaktywnych (deklaracja 04-STYLEGUIDE:
   „na WSZYSTKICH elementach interaktywnych"). Onboarding/wizard/choice-tile mają własne, spójne reguły niżej. */
.btn:focus-visible,
a:focus-visible,
.navtab:focus-visible,
.subtab:focus-visible,
.fab:focus-visible,
.tpl-item:focus-visible,
.aha-ref-close:focus-visible,
.nav-menu-panel a:focus-visible {
  outline: 2px solid var(--color-accent); outline-offset: 2px;   /* outline dziedziczy natywny promień elementu — pigułki (.fab/.navtab-op) NIE spłaszczają się */
}

/* ---- 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: var(--color-error-tint); color: var(--color-error-text); }   /* tekst 5.81:1 (AA) */
.msg-success { background: var(--color-success-tint); color: var(--color-success-text); } /* tekst 5.56:1 (AA) */

/* ---- 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); }
/* Karta wyróżniona „Najczęściej wybierany" (cennik/landing: obrys złota) + badge WYPEŁNIONY (makieta landing). */
.card-featured { border-color: var(--color-accent-2); }
.badge-featured { background: var(--color-bg-soft); color: var(--color-accent-2-text); border-color: transparent; }

/* ---- 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: 500; font-family: var(--font-head); }   /* wordmark lekki (papeteria), nie bold */
.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, #8A5A18); 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: 700;
  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 rgba(41, 72, 61, .22); }
.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(24, 38, 31, .28);
  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;   /* outline dziedziczy natywny promień — jedna konwencja */
}
/* Dymek tooltipa ma CIEMNE tło (--color-text): pierścień zieleni byłby niewidoczny (~1.3:1) → kość słoniowa. */
.ds-tip-close:focus-visible { outline-color: var(--color-accent-text); }
/* 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: var(--color-error-active); }
.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(24, 38, 31, .72); backdrop-filter: blur(2px);   /* ciepły cypress-scrim (nie zimna czerń) */
}
.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; }
}

/* ---- 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(24, 38, 31, .55);   /* ciepły cypress-scrim */
}
/* 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); }
/* max-height + wewnętrzny scroll: wysoki modal (np. „Nowa pozycja" katalogu) na KRÓTKIM ekranie mobile
   (≤667px wys.) nie ucina nagłówka ani przycisków — karta przewija się w środku, centrowanie nie klipuje. */
.modal { width: 100%; max-width: 480px; max-height: calc(100dvh - 2 * var(--sp-4)); overflow-y: auto; 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; } }
@media (prefers-reduced-motion: reduce) { .view { animation: none; } }

/* ---- 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: var(--color-bg-soft);   /* ciepły papier-ish placeholder iframe */
}

/* ============================================================
   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-heading); }
.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: var(--color-accent-text); 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-heading); 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(158, 52, 44, .18);
}

@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: var(--color-accent-text); }
.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,
  .overlay,
  .modal-backdrop {
    display: none !important;
  }
}

/* ============================================================
   SOLAMO — KOMPONENTY NISZY („papeteria kondolencyjna"). Token-driven, per KONTEKST:
   • RODZINA  (mobile-first, duże kafle dotykowe ≥44px): .choice-tile, .timeline, .note-inline, .price-range
   • ZAKŁAD   (gęściej, roboczo):                        .eyebrow, .stat-num, .price-range, .note-inline
   • LANDING  (elegancja):                               .pill, .hairline, .eyebrow, .timeline
   Spis + zasady użycia = 04-STYLEGUIDE §Biblioteka. Stany hover/focus-visible/selected/disabled — patrz niżej.
   ============================================================ */

/* Eyebrow — mała, rozstrzelona etykieta w brązie (SPOKOJNE USTALENIA / RODZINA / DATA CEREMONII / eyebrow hero). */
.eyebrow {
  display: inline-block; font-family: var(--font-body);
  font-size: .72rem; font-weight: 600; letter-spacing: .14em; text-transform: uppercase;
  color: var(--color-accent-2-text);   /* brąz — 5.32:1 (AA); ZŁOTO #B59761 jako tekst = FAIL */
}

/* Włoskowata linia złota — @dsHairline (delikatny separator „papeterii"; wzorzec z placeholder index.html). */
.hairline { width: 3.25rem; height: 1px; border: 0; background: var(--color-accent-2); margin: var(--sp-4) 0; position: relative; }
.hairline.center { margin-left: auto; margin-right: auto; }
.hairline::before, .hairline::after {
  content: ""; position: absolute; top: 50%; width: 3px; height: 3px; border-radius: 50%;
  background: var(--color-accent-2); transform: translateY(-50%);
}
.hairline::before { left: -.6rem; }
.hairline::after  { right: -.6rem; }

/* SYGNATURA marki: pionowa „linia etapów jak program uroczystości" — @dsTimeline (podpis z preview_brief).
   Lewa szyna z włoskowatego złota + kropki-węzły. Stany: default (obrys złoto) / .is-active (zieleń) /
   .is-done (zieleń wypełniona). Wątkuje kroki konfiguratora rodziny i sekcję „Jak to działa" na landingu. */
.timeline { position: relative; padding-left: var(--sp-6); }
/* Szyna „paciorkowa" (włoskowate złote punkty) — mood „program uroczystości" (makiety panel/podsumowanie). */
.timeline::before {
  content: ""; position: absolute; left: 11px; top: 6px; bottom: 6px; width: 1px;
  background-image: linear-gradient(var(--color-accent-2) 45%, transparent 0);
  background-size: 1px 7px; background-repeat: repeat-y; opacity: .85;
}
.timeline-node { position: relative; padding: var(--sp-2) 0; }
.timeline-node::before {
  content: ""; position: absolute; left: calc(-1 * var(--sp-6) + 5px); top: .5em;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--color-bg); border: 1.5px solid var(--color-accent-2);
  box-shadow: 0 0 0 4px var(--color-bg);   /* przerywa szynę za węzłem */
}
.timeline-node.is-active::before { background: var(--color-accent); border-color: var(--color-accent); }
/* „done" = zieleń sukcesu — SPÓJNIE z wizardem/checklistą/generacją (jedna konwencja stanu ukończenia). */
.timeline-node.is-done::before   { background: var(--color-success); border-color: var(--color-success); }
/* Medalion węzła — gdy oś niesie IKONY (makieta panel: koperta/świeca/kwiat; podsumowanie: dokument/telefon/✓).
   Wstaw <span class="timeline-medallion">…ikona…</span> w węźle; .timeline.has-ico poszerza rynsztok, przesuwa
   szynę na środek medalionu i chowa małą kropkę → medalion siedzi NA szynie (jak makieta). Stany z is-active/is-done.
   Animowany wariant landingu (rysowanie szyny stroke-dashoffset) = inline SVG budowany w sesji landingu — patrz 04 §Ruch. */
.timeline.has-ico { padding-left: var(--sp-8); }
.timeline.has-ico::before { left: 24px; }                         /* szyna przez środek medalionu (40px w rynsztoku 64px=sp-8) */
.timeline.has-ico .timeline-node { min-height: 44px; }
.timeline.has-ico .timeline-node::before { display: none; }
.timeline-medallion {
  width: 40px; height: 40px; border-radius: 50%; flex: none;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-surface); border: 1px solid var(--color-accent-2); color: var(--color-heading);
  box-shadow: 0 0 0 4px var(--color-bg);   /* przerywa szynę za medalionem */
}
.timeline.has-ico .timeline-medallion {   /* osadzenie NA szynie: środek medalionu = 24px od lewej */
  position: absolute; left: calc(-1 * var(--sp-8) + 4px); top: 50%; transform: translateY(-50%);
}
.timeline-node.is-active .timeline-medallion { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-accent-text); }
.timeline-node.is-done .timeline-medallion   { background: var(--color-success); border-color: transparent; color: var(--color-accent-text); }

/* Kafel wyboru rodziny — @dsChoiceTile. Duży cel dotykowy (mobile-first), „Kto zapewnia ubranie?" /
   „Trumna otwarta/zamknięta" (makieta glowna). Stany: default / hover / focus-visible / selected / disabled.
   Selekcja przez [aria-pressed="true"] LUB .is-selected. min-height 128px ≫ WCAG 2.5.8 (≥44px). */
.choice-grid { display: grid; gap: var(--sp-4); grid-template-columns: 1fr; }
@media (min-width: 560px) { .choice-grid.cols-2 { grid-template-columns: 1fr 1fr; } }
.choice-tile {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-3); text-align: center;
  min-height: 128px; padding: var(--sp-5); width: 100%;
  background: var(--color-surface); color: var(--color-heading);   /* etykieta zieleń cyprysowa (makieta glowna) */
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-lg);
  font-family: var(--font-head); font-size: 1.05rem; font-weight: 500; line-height: 1.25; cursor: pointer;  /* serif — papeteria */
  transition: border-color var(--dur-base) var(--ease-out), box-shadow var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out);
}
.choice-tile:hover { border-color: var(--color-accent-2); }
.choice-tile:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.choice-tile[aria-pressed="true"], .choice-tile.is-selected {
  border-color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-accent);
}
.choice-tile:disabled, .choice-tile[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }
.choice-tile .choice-ico { width: 44px; height: 44px; color: var(--color-heading); flex: none; }
.choice-tile .choice-check {
  position: absolute; top: var(--sp-3); right: var(--sp-3);
  width: 26px; height: 26px; border-radius: 50%;
  display: none; align-items: center; justify-content: center;
  background: var(--color-accent); color: var(--color-accent-text); font-size: .85rem;
}
.choice-tile[aria-pressed="true"] .choice-check, .choice-tile.is-selected .choice-check { display: inline-flex; }

/* Pigułka zapowiedzi nad nagłówkiem (landing) — @dsPill. Pełne zaokrąglenie + włoskowaty obrys złota. */
.pill {
  display: inline-flex; align-items: center; gap: var(--sp-2);
  padding: 6px var(--sp-4); border-radius: var(--radius-pill);
  border: var(--border-w) solid var(--color-accent-2);
  background: var(--color-surface); color: var(--color-accent-2-text);
  font-size: .8rem; font-weight: 600; letter-spacing: .02em;
}

/* Licznik pulpitu zakładu — @dsStat. Duża liczba serif + podkreślenie złota (makieta panel: „Nowe zgłoszenia 3"). */
.stat-num { font-family: var(--font-head); font-weight: 500; font-size: 2.5rem; line-height: 1; color: var(--color-heading); }
.stat-underline { width: 2rem; height: 1px; background: var(--color-accent-2); margin-top: var(--sp-3); }

/* Pulpit zgłoszeń zakładu (S4b) — @dsCaseList. Kafle liczników + lista spraw (makieta panel.png).
   Layout WYŁĄCZNIE na tokenach. Mobile: kolumny stackują, etykiety kolumn (.col-label) się odsłaniają. */
.zg-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-4); }
@media (max-width: 620px) { .zg-stats { grid-template-columns: 1fr; } }
.zg-stat { text-align: center; }
.case-row {
  display: grid; grid-template-columns: 1.5fr 1fr 1.2fr 1.1fr auto; gap: var(--sp-4);
  align-items: center; padding: var(--sp-4); border-bottom: var(--border-w) solid var(--color-border);
}
.case-row:last-child { border-bottom: 0; }
.case-fam { font-family: var(--font-head); color: var(--color-heading); font-size: 1.15rem; }
.case-dec { color: var(--color-text-muted); font-size: .85rem; }
.col-label { display: none; }
@media (max-width: 820px) {
  .case-row { grid-template-columns: 1fr auto; row-gap: var(--sp-2); }
  .case-actions { grid-column: 1 / -1; }
  .col-label { display: block; font-size: .7rem; letter-spacing: .08em; text-transform: uppercase; color: var(--color-text-muted); margin-bottom: 2px; }
}

/* Orientacyjny PRZEDZIAŁ ceny — @dsPriceRange (NIGDY „jedna wiążąca kwota"; R1). Serif, spokojny. */
.price-range { font-family: var(--font-head); font-weight: 500; font-size: 1.6rem; letter-spacing: -0.01em; color: var(--color-heading); }
.price-range .cur { font-size: .8em; color: var(--color-accent-2-text); }   /* „zł" w brązie (de-emfaza; 5.32:1 AA) */
.price-range.price-range-lg { font-size: 2.4rem; }   /* wariant BOHATER — „Orientacyjna cena" na podsumowaniu */

/* Nota informacyjna „wybór wstępny / orientacyjny koszt" — @dsNote. Kluczowa dla tonu (każdy wybór wstępny,
   „Wybory potwierdzi pracownik zakładu"). (i) w brązie + tekst muted. */
.note-inline { display: inline-flex; align-items: flex-start; gap: var(--sp-2); font-size: .9rem; color: var(--color-text-muted); }
.note-inline .note-ico { flex: none; color: var(--color-accent-2-text); line-height: 1.3; }

/* Karta sprawy zakładu (S4c) — @dsSprawaCard. Nagłówek + żywy pasek + „Najpilniejsze" + sekcje robocze.
   Wyłącznie tokeny; mobile-first (kolumny stackują). Dane usera → textContent (template + data-hook). */
.sprawa-head-top { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-4); flex-wrap: wrap; }
.sprawa-zmarly { font-family: var(--font-head); font-weight: 500; font-size: 1.6rem; line-height: 1.1; color: var(--color-heading); margin: 2px 0 0; }
.sprawa-head-meta { text-align: right; display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2); }
.sprawa-termin { text-align: right; }
.sprawa-termin-data { font-family: var(--font-head); color: var(--color-heading); font-size: 1.05rem; }
.sprawa-head-actions { display: flex; gap: var(--sp-3); flex-wrap: wrap; }
@media (max-width: 620px) {
  .sprawa-head-meta, .sprawa-termin { text-align: left; align-items: flex-start; }
  .sprawa-head-meta .col-label { display: block; }
}

/* Żywy pasek postępu — reuse .ds-progress/.ds-progress-fill; nagłówek + procent + lista kamieni milowych. */
.sprawa-progress-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); }
.sprawa-progress-pct { font-family: var(--font-head); font-weight: 500; font-size: 1.25rem; color: var(--color-heading); }
.sprawa-steps { list-style: none; margin: var(--sp-2) 0 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2) var(--sp-4); }
@media (max-width: 560px) { .sprawa-steps { grid-template-columns: 1fr; } }
.sprawa-step { display: flex; align-items: center; gap: var(--sp-2); font-size: .9rem; color: var(--color-text-muted); }
.sprawa-step-mark {
  flex: none; width: 18px; height: 18px; border-radius: 50%; display: inline-flex; align-items: center; justify-content: center;
  border: 1.5px solid var(--color-border-strong); font-size: .7rem; color: var(--color-accent-text); background: transparent;
}
.sprawa-step.is-done { color: var(--color-text); }
.sprawa-step.is-done .sprawa-step-mark { background: var(--color-success); border-color: transparent; }
.sprawa-step.is-unknown { color: var(--color-warning); }
.sprawa-step.is-unknown .sprawa-step-mark { border-color: var(--color-warning); color: var(--color-warning); background: transparent; }

/* „Najpilniejsze teraz" — lista zadań; tag rozróżnia zadanie ZAKŁADU vs brak od RODZINY. */
.sprawa-urgent { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--sp-2); }
.sprawa-urgent-item {
  display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3);
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius);
  border-left: 3px solid var(--color-accent); background: var(--color-bg-soft); font-size: .95rem;
}
.sprawa-urgent-item.kind-rodzina { border-left-color: var(--color-warning); }
.sprawa-urgent-tag {
  flex: none; font-size: .68rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  padding: 2px var(--sp-2); border-radius: var(--radius-pill); color: var(--color-accent-text); background: var(--color-accent);
}
.sprawa-urgent-item.kind-rodzina .sprawa-urgent-tag { background: var(--color-warning); }
.sprawa-allclear { display: flex; align-items: center; gap: var(--sp-2); color: var(--color-success-text); font-size: .95rem; margin: 0; }

/* Dane zmarłego — lista definicji dwukolumnowa (etykieta / wartość). */
.sprawa-dl { display: grid; grid-template-columns: minmax(120px, auto) 1fr; gap: var(--sp-2) var(--sp-4); margin: 0; }
.sprawa-dl dt { color: var(--color-text-muted); font-size: .85rem; }
.sprawa-dl dd { margin: 0; color: var(--color-text); }

/* Rodzina i role — kafelki członków. */
.sprawa-people { display: flex; flex-direction: column; gap: var(--sp-2); }
.sprawa-person { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-top: var(--border-w) solid var(--color-border); }
.sprawa-person:first-child { border-top: 0; }
.sprawa-person-name { color: var(--color-text); }
.sprawa-rola { flex: none; }

/* Dokumenty — wiersz z ręcznym selektorem statusu (D3). */
.sprawa-dok { display: flex; flex-direction: column; }
.sprawa-dok-row { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); padding: var(--sp-3) 0; border-top: var(--border-w) solid var(--color-border); }
.sprawa-dok:first-child .sprawa-dok-row:first-child, .sprawa-dok-row:first-child { border-top: 0; }
.sprawa-dok-name { color: var(--color-text); }
.sprawa-dok-ctl { flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.sprawa-dok-status { width: auto; min-width: 150px; padding-top: 6px; padding-bottom: 6px; }
@media (max-width: 560px) {
  .sprawa-dok-row { flex-direction: column; align-items: stretch; gap: var(--sp-2); }
  .sprawa-dok-ctl { align-items: stretch; }
  .sprawa-dok-status { width: 100%; }
}

/* Wybory rodziny (podgląd). */
.sprawa-wybory { display: flex; flex-direction: column; }
.sprawa-wybor-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-top: var(--border-w) solid var(--color-border); flex-wrap: wrap; }
.sprawa-wybor-row:first-child { border-top: 0; }
.sprawa-wybor-val { color: var(--color-text); font-family: var(--font-head); }
.sprawa-wybor-flag { flex: none; }

/* Inline „dopisz" (historia/notatka) — pole + przycisk w jednym rzędzie. */
.sprawa-inline-add { display: flex; align-items: flex-end; gap: var(--sp-3); flex-wrap: wrap; }
.sprawa-inline-add .btn { flex: none; }

/* Log (historia kontaktów + notatki wewnętrzne). */
.sprawa-log { display: flex; flex-direction: column; }
.sprawa-log-row { padding: var(--sp-3) 0; border-top: var(--border-w) solid var(--color-border); }
.sprawa-log-row:first-child { border-top: 0; }
.sprawa-log-meta { font-size: .78rem; letter-spacing: .04em; text-transform: uppercase; color: var(--color-text-muted); margin-bottom: 2px; }
.sprawa-log-text { color: var(--color-text); font-size: .95rem; white-space: pre-wrap; }

/* Rozwijane „Dodaj dokument" — natywny <details>/<summary> stylizowany na link-akcję. */
.sprawa-add > summary { cursor: pointer; color: var(--color-accent); font-weight: 600; font-size: .9rem; list-style: none; display: inline-flex; align-items: center; gap: var(--sp-2); }
.sprawa-add > summary::-webkit-details-marker { display: none; }
.sprawa-add > summary::before { content: "+"; font-size: 1.1em; line-height: 1; }
.sprawa-add[open] > summary::before { content: "–"; }
.sprawa-add > summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; border-radius: var(--radius-sm); }

/* ===== KATALOG ZAKŁADU (S4d, F4/D4) — @dsKatalog. Karty kategorii + wiersze pozycji + miniatury zdjęć.
   Wyłącznie tokeny; mobile-first (stack). Dane usera → textContent (template + data-hook). ===== */
.kat-kat { gap: var(--sp-3); }
.kat-kat.kat-inactive { opacity: .72; }
.kat-kat-head { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.kat-typ { flex: none; }
.kat-kat-nazwa { font-family: var(--font-head); font-weight: 500; font-size: 1.2rem; color: var(--color-heading); }
.kat-hidden-badge { font-size: .68rem; vertical-align: middle; }
.kat-kat-actions { display: flex; gap: var(--sp-2); flex: none; }
.kat-del { color: var(--color-error); }

.kat-poz-list { display: flex; flex-direction: column; }
.kat-poz-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3) 0; border-top: var(--border-w) solid var(--color-border); }
.kat-poz-row:first-child { border-top: 0; }
.kat-poz-main { flex: 1 1 auto; min-width: 0; }
.kat-poz-nazwa { color: var(--color-text); font-weight: 600; }
.kat-poz-opis { white-space: normal; }
.kat-poz-niedost { margin-top: 4px; font-size: .68rem; }
.kat-poz-cena { flex: none; font-size: 1.2rem; text-align: right; }
.kat-poz-cena.kat-cena-indyw { font-size: .95rem; font-family: var(--font-body); color: var(--color-text-muted); font-weight: 400; }
.kat-poz-actions { flex: none; display: flex; gap: var(--sp-2); }

/* Miniatura zdjęcia pozycji (kwadrat, ivory tło, ciepły obrys — brak zdjęcia = „—"). */
.kat-thumb {
  flex: none; width: 52px; height: 52px; border-radius: var(--radius-sm); overflow: hidden;
  background: var(--color-bg-soft); border: var(--border-w) solid var(--color-border);
  display: inline-flex; align-items: center; justify-content: center;
}
.kat-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.kat-thumb-ph { color: var(--color-text-muted); font-size: 1rem; }
.kat-thumb-lg { width: 88px; height: 88px; }
.kat-foto-row { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }

@media (max-width: 560px) {
  .kat-poz-row { flex-wrap: wrap; }
  .kat-poz-cena { text-align: left; width: 100%; order: 3; }
  .kat-poz-actions { order: 4; }
}

/* ===== KOSZTORYS ZAKŁADU (S4g, F4/D9/D10) — @dsKosztorys. Pozycje zakład/zewnętrzne + sumy + zaliczka/saldo/zasiłek.
   Reuse .price-range (kwoty z groszy liczone SERWEROWO). Mobile-first (stack). Dane usera → textContent. ===== */
.koszt-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.koszt-przedzial { padding: var(--sp-3); border: var(--border-w) solid var(--color-border); border-radius: var(--radius); background: var(--color-bg-soft); }
.koszt-przedzial .col-label { display: block; margin-bottom: 2px; }
.koszt-grp-tyt { font-size: .78rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; color: var(--color-text-muted); margin: 0 0 var(--sp-1); }
.koszt-list { display: flex; flex-direction: column; }
.koszt-poz-row { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-2) 0; border-top: var(--border-w) solid var(--color-border); flex-wrap: wrap; }
.koszt-poz-row:first-child { border-top: 0; }
.koszt-poz-main { flex: 1 1 auto; min-width: 0; }
.koszt-poz-nazwa { color: var(--color-text); }
.koszt-poz-rabat { display: block; margin-top: 2px; }
.koszt-poz-kwota { flex: none; font-size: 1.1rem; }
.koszt-poz-actions { flex: none; display: flex; gap: var(--sp-1); }
.koszt-form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.koszt-kwoty { grid-template-columns: 1fr 1fr 1fr; margin-top: var(--sp-1); }
.koszt-sumy { display: flex; flex-direction: column; gap: 2px; }
.koszt-sum-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); padding: var(--sp-1) 0; color: var(--color-text-muted); }
.koszt-sum-row .koszt-sum-val { font-size: 1rem; color: var(--color-text); }
.koszt-sum-row.is-total { border-top: 2px solid var(--color-border-strong); margin-top: var(--sp-1); padding-top: var(--sp-2); color: var(--color-heading); }
.koszt-sum-row.is-total .koszt-sum-val { font-size: 1.35rem; }
.koszt-sum-row.is-zasilek .koszt-sum-val { color: var(--color-success-text); }
@media (max-width: 560px) {
  .koszt-kwoty { grid-template-columns: 1fr; }
  .koszt-poz-kwota { order: 2; }
  .koszt-poz-actions { order: 3; }
}

/* ===== AKCEPTACJA KOSZTORYSU (S4h, F4/D6/D9) — wyślij do rodziny + nota statusu + historia akceptacji (audyt). ===== */
.koszt-akcept { display: flex; flex-direction: column; gap: var(--sp-2); }
.koszt-akcept-note.is-ok { color: var(--color-success-text); }
.koszt-akcept-note.is-warn { color: var(--color-warning); }
.koszt-akcept-hist { display: flex; flex-direction: column; gap: var(--sp-1); }
.koszt-akcept-row { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; padding: var(--sp-1) 0; border-top: var(--border-w) solid var(--color-border); font-size: .85rem; }
.koszt-akcept-row:first-child { border-top: 0; }
.koszt-akcept-wersja { font-weight: 600; color: var(--color-heading); }
.koszt-akcept-kiedy { color: var(--color-text-muted); }
.koszt-akcept-tel, .koszt-akcept-hash { color: var(--color-text-muted); font-size: .78rem; }

/* ============================================================
   SOLAMO — LANDING (sprzedażowy, B2B do właściciela zakładu). Krok `landing`, spec brief/10-LANDING-KONCEPT.md.
   WYŁĄCZNIE tokeny + komponenty niszy (.pill .hairline .timeline .choice-tile .card-featured .badge-featured
   .eyebrow .price-range .note-inline). Klasy `.lp-*` = layout landingu. ZAKAZ gołych hexów / stylowania ad hoc.
   Rytm tonalny 3 uderzeń: hero (papier) · „Jak to działa" (kość) · finał (zieleń). Reszta = spokój papieru.
   ============================================================ */

/* ---- Skorupa strony marketingowej ---- */
.lp-main { display: block; }
/* Cele dotykowe nav landingu ≥44px (WCAG 2.5.8; spec §5.8). Scoped do topnavu landingu. */
.lp-topnav nav .btn { min-height: 44px; }
/* Wordmark „Solamo" = też cel dotykowy ≥44px (link do „/"; krytyk: był 26px). */
.lp-topnav .brand { display: inline-flex; align-items: center; min-height: 44px; }
/* Marginesy boczne treści ≥20px (spec §5.8) — landing nadpisuje bazowy .container (16px). */
.lp-main .container, .lp-footer .container { padding-left: var(--sp-5); padding-right: var(--sp-5); }
.lp-section { padding: var(--sp-8) 0; }
.lp-section-tight { padding: var(--sp-7) 0; }
/* TONALNE UDERZENIE #2 — pas kości: włoskowate obrysy demarkują zmianę tonu (papier↔kość jest subtelna;
   krytyk: 2. uderzenie mało czytelne). Token-only, spójne z paskiem reasekuracji. */
.lp-surface { background: var(--color-surface); border-top: var(--border-w) solid var(--color-border); border-bottom: var(--border-w) solid var(--color-border); }
.lp-eyebrow-c { display: block; margin-bottom: var(--sp-3); }
.lp-head { max-width: 40ch; }
.lp-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.lp-h2 { font-size: clamp(1.6rem, 3.4vw, 2.25rem); line-height: 1.12; }
.lp-lede { color: var(--color-text-muted); font-size: 1.05rem; margin-top: var(--sp-3); max-width: 46ch; }
.lp-lede.center { margin-left: auto; margin-right: auto; }

/* ---- HERO ---- */
.lp-hero { padding: var(--sp-6) 0 var(--sp-7); }
.lp-hero .container { display: grid; gap: var(--sp-6); align-items: center; }
.lp-hero-copy { max-width: 34rem; }
.lp-hero-h1 {
  font-family: var(--font-head); color: var(--color-heading); font-weight: 500;
  font-size: clamp(2.125rem, 5.4vw, 3.625rem);   /* 34 → 58px (research/spec) */
  letter-spacing: -0.015em; line-height: 1.08; margin-top: var(--sp-4);
}
.lp-hero-sub { font-size: clamp(1.05rem, 2.4vw, 1.25rem); color: var(--color-text); line-height: 1.5; margin-top: var(--sp-4); max-width: 34ch; }
.lp-hero-cta { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-5); }
.lp-hero-cta .btn { flex: 0 1 auto; }
.lp-microtrust { margin-top: var(--sp-3); font-size: .875rem; color: var(--color-text-muted); }

/* ---- POKAZ PRODUKTU: JEDEN KADR O STAŁEJ WYSOKOŚCI (fazy podmieniane W MIEJSCU) ---- */
.lp-stage {
  position: relative; height: 232px; margin: 0 auto; width: 100%; max-width: 420px;
  display: flex; align-items: center; justify-content: center;
}
.lp-phone {
  position: relative; height: 100%; aspect-ratio: 200 / 232; max-width: 92%;
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: 22px; box-shadow: var(--shadow-lg); padding: 12px 10px; overflow: hidden;
}
.lp-phone::before {   /* wcięcie ekranu (notch/pill) — dekor */
  content: ""; position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
  width: 30px; height: 4px; border-radius: 999px; background: var(--color-bg-soft); z-index: 2;
}
.lp-phone::after {   /* home-indicator — dopełnia „chrome" urządzenia (kadr = realny telefon, nie pusty box) */
  content: ""; position: absolute; bottom: 8px; left: 50%; transform: translateX(-50%);
  width: 60px; height: 4px; border-radius: 999px; background: var(--color-bg-soft);
}
/* Pasek statusu urządzenia (persystentny) — flankuje notch: godzina z lewej, sygnał/bateria z prawej. */
.lp-phone-head {
  position: absolute; top: 7px; left: 14px; right: 14px; height: 14px; z-index: 1;
  display: flex; align-items: center; justify-content: space-between;
  font-size: .5rem; color: var(--color-text-muted); font-variant-numeric: tabular-nums; letter-spacing: .02em;
}
.lp-phone-time { font-weight: 700; }
.lp-phone-status { display: inline-flex; align-items: flex-end; gap: 1.5px; }
.lp-phone-status i { display: block; width: 2px; border-radius: 1px; background: var(--color-border-strong); }
.lp-phone-status i:nth-child(1) { height: 4px; } .lp-phone-status i:nth-child(2) { height: 6px; } .lp-phone-status i:nth-child(3) { height: 8px; }
.lp-phone-status b { display: block; width: 10px; height: 6px; margin-left: 2px; border: 1px solid var(--color-border-strong); border-radius: 2px; position: relative; }
.lp-phone-status b::after { content: ""; position: absolute; inset: 1px; width: 60%; border-radius: 1px; background: var(--color-border-strong); }
.lp-screen { position: absolute; inset: 26px 12px 20px; }
.lp-phase {
  position: absolute; inset: 0; opacity: 0; transform: translateY(4px);
  /* FADE-THROUGH: faza WYCHODZĄCA gaśnie natychmiast; WCHODZĄCA startuje z opóźnieniem (po zgaszeniu) —
     eliminuje „okno z dwiema czytelnymi warstwami" (zakazany artefakt crossfade). */
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out);
  pointer-events: none; display: flex; flex-direction: column; justify-content: center; gap: var(--sp-2);
}
.lp-phase.is-active { opacity: 1; transform: none; transition-delay: var(--dur-base); }
/* Cena w kadrze pokazu — nie łamać przedziału ani „zł" (kompaktowy telefon). */
.lp-phase[data-phase="3"] .price-range { white-space: nowrap; font-size: clamp(.68rem, 3.4vw, 1.35rem); }
/* Faza 4 — karta panelu ZAKŁADU: wysuwa się zza telefonu (kulminacja). Warstwa nad całym kadrem. */
.lp-zaklad {
  position: absolute; right: 0; top: 50%; width: 74%; max-width: 300px;
  transform: translateY(-50%) translateX(18px); opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-slow) var(--ease-out);
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius); box-shadow: var(--shadow-lg); padding: var(--sp-4); pointer-events: none;
  display: flex; flex-direction: column; justify-content: center; gap: 6px;
}
.lp-zaklad.is-active { opacity: 1; transform: translateY(-50%) translateX(12px); }
/* Kulminacja (faza 4): telefon rodziny RECEDUJE (głębia), karta zgłoszenia „u Ciebie" wychodzi na wierzch —
   koniec „pustego telefonu za kartą" (krytyk). */
.lp-phone { transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out), filter var(--dur-slow) var(--ease-out); }
.lp-stage[data-phase="4"] .lp-phone { opacity: .45; transform: scale(.97); filter: blur(.6px); }

/* Miniatury UI wewnątrz kadru (żywy DOM z DS — NIE obrazek/wideo) */
.lp-sms { display: flex; flex-direction: column; align-items: flex-start; background: var(--color-bg-soft); border-radius: 12px 12px 12px 4px; padding: 10px 12px; font-size: .78rem; color: var(--color-text); }
.lp-sms .lp-sms-from { font-size: .62rem; letter-spacing: .1em; text-transform: uppercase; color: var(--color-text-muted); display: block; margin-bottom: 3px; }
.lp-sms .lp-sms-body { line-height: 1.35; }
.lp-sms-time { align-self: flex-start; margin-top: 6px; font-size: .58rem; letter-spacing: .04em; color: var(--color-text-muted); }
.lp-mini-btn { align-self: flex-start; margin-top: 8px; font-family: var(--font-head); font-size: .74rem; padding: 5px 14px; border-radius: var(--radius); background: var(--color-accent); color: var(--color-accent-text); }
.lp-mini-q { font-family: var(--font-head); color: var(--color-heading); font-size: .84rem; }
.lp-mini-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.lp-mini-tile {
  position: relative; min-height: 44px; border: var(--border-w) solid var(--color-border); border-radius: 10px;
  background: var(--color-surface); display: flex; align-items: center; justify-content: center;
  font-family: var(--font-head); font-size: .78rem; color: var(--color-heading);
}
.lp-mini-tile.is-selected { border-color: var(--color-accent); box-shadow: inset 0 0 0 1px var(--color-accent); }
.lp-mini-tile .lp-mini-check { position: absolute; top: 4px; right: 4px; width: 15px; height: 15px; border-radius: 50%; background: var(--color-accent); color: var(--color-accent-text); font-size: .6rem; display: none; align-items: center; justify-content: center; }
.lp-mini-tile.is-selected .lp-mini-check { display: inline-flex; }
.lp-mini-progress { height: 4px; border-radius: 999px; background: var(--color-bg-soft); overflow: hidden; }
.lp-mini-progress i { display: block; height: 100%; width: 60%; background: var(--color-accent-2); border-radius: 999px; }
.lp-mini-label { font-size: .64rem; letter-spacing: .1em; text-transform: uppercase; color: var(--color-accent-2-text); font-weight: 600; }
.lp-mini-note { font-size: .68rem; color: var(--color-text-muted); }
/* Wzbogacenie ekranu telefonu (nagłówek apki + treść dokująca do GÓRY) — kadr wypełnia się jak realny
   ekran, nie pływa w pustce (krytyk: fill 22–31% desktop). DOMYŚLNIE UKRYTE — pokazywane tylko na desktopie
   (≥900px), gdzie kadr jest duży i „pusty"; mobile bez zmian (fill ~70% już OK, brak ryzyka przycięcia). */
.lp-app-head, .lp-day-chip, .lp-mini-hint, .lp-mini-lines { display: none; }
.lp-app-head { align-items: center; justify-content: space-between; gap: var(--sp-2); padding-bottom: 7px; border-bottom: var(--border-w) solid var(--color-border); }
.lp-app-head--msg { justify-content: center; }
.lp-app-title { font-family: var(--font-head); font-size: .8rem; font-weight: 500; color: var(--color-heading); }
.lp-app-brand { font-family: var(--font-head); font-size: .72rem; font-weight: 500; color: var(--color-heading); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lp-app-step { flex: none; font-size: .58rem; letter-spacing: .04em; color: var(--color-text-muted); white-space: nowrap; }
.lp-day-chip { text-align: center; font-size: .58rem; letter-spacing: .04em; color: var(--color-text-muted); }
.lp-mini-hint { font-size: .62rem; color: var(--color-text-muted); }
.lp-mini-lines { display: none; flex-direction: column; gap: 5px; }
.lp-mini-lines li { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); font-size: .72rem; color: var(--color-text); }
.lp-mini-lines li i { flex: none; width: 15px; height: 15px; border-radius: 50%; background: var(--color-accent); color: var(--color-accent-text); font-size: .58rem; font-style: normal; display: inline-flex; align-items: center; justify-content: center; }
.lp-zaklad-eyebrow { font-size: .6rem; letter-spacing: .12em; text-transform: uppercase; color: var(--color-accent-2-text); font-weight: 600; }
.lp-zaklad-title { font-family: var(--font-head); color: var(--color-heading); font-size: .95rem; font-weight: 500; }
.lp-zaklad-row { display: flex; align-items: center; gap: 6px; font-size: .74rem; color: var(--color-text); }
.lp-count { font-family: var(--font-head); font-variant-numeric: tabular-nums; color: var(--color-heading); font-weight: 500; }

/* Kropki postępu pod kadrem */
.lp-dots { display: flex; gap: var(--sp-2); justify-content: center; margin-top: var(--sp-4); }
.lp-dot { position: relative; width: 7px; height: 7px; border-radius: 999px; border: 0; padding: 0; cursor: pointer; background: var(--color-border-strong); transition: width var(--dur-base) var(--ease-out), background var(--dur-base) var(--ease-out); }
/* Cel dotykowy 31px = spełnia WCAG 2.5.8 (≥24px, prawnie EAA) z zapasem, bez zmiany wyglądu.
   Pełne 44px (2.5.5 AAA) niewykonalne dla 4 sąsiednich kropek postępu bez nakładania hitboxów
   (dwuznaczność kliknięcia); to drugorzędna kontrolka skoku do fazy — autoplay koryguje. */
.lp-dot::after { content: ""; position: absolute; inset: -12px; }
.lp-dot.is-active { width: 20px; background: var(--color-accent); }
.lp-dot:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; }

@media (min-width: 900px) {
  .lp-hero { min-height: 100svh; display: flex; align-items: center; padding-top: clamp(var(--sp-7), 12vh, 148px); }
  .lp-hero .container { grid-template-columns: 1.05fr .95fr; gap: var(--sp-8); width: 100%; }
  /* Kadr niższy niż 440px (spec §1 sankcjonuje zmniejszanie, min 220) + treść DOKUJE do góry z nagłówkiem
     apki → ekran telefonu wypełnia się ≥50% zamiast pływać 22–31% w środku (krytyk). */
  .lp-stage { height: 316px; max-width: 460px; }
  .lp-zaklad { padding: var(--sp-5); }
  /* Dokowanie do góry + widoczne wzbogacenie ekranu (nagłówek apki, treść pomocnicza) */
  .lp-phase { justify-content: flex-start; gap: 10px; }
  .lp-app-head { display: flex; }
  .lp-day-chip, .lp-mini-hint { display: block; }
  .lp-mini-lines { display: flex; }
  /* Skala treści w kadrze podniesiona (duży desktopowy telefon udźwignie większy tekst = czytelniej + pełniej) */
  .lp-sms { font-size: .92rem; padding: 12px 14px; }
  .lp-sms .lp-sms-from { font-size: .66rem; }
  .lp-mini-btn { font-size: .82rem; padding: 7px 18px; margin-top: 10px; }
  .lp-mini-q { font-size: 1rem; }
  .lp-mini-tile { min-height: 54px; font-size: .9rem; }
  .lp-mini-label { font-size: .7rem; }
  .lp-mini-note { font-size: .8rem; }
  .lp-phase[data-phase="3"] .price-range { font-size: 1.7rem !important; }
}
/* Mobile: hero MUSI zmieścić się w 100dvh (spec §1 budżet) — kompaktujemy copy + kadr. */
@media (max-width: 899px) {
  .lp-hero { padding: var(--sp-4) 0 var(--sp-5); }
  .lp-hero .container { gap: var(--sp-5); }
}
@media (max-width: 480px) {
  .lp-topnav { padding-top: var(--sp-2); padding-bottom: var(--sp-2); }   /* kompaktowy topnav mobile (przyciski nadal ≥44px) — odzyskuje pion nad foldem */
  .lp-hero-h1 { font-size: 2.125rem; line-height: 1.05; margin-top: var(--sp-3); }   /* podłoga 34px (spec §1); nie schodzić niżej */
  .lp-hero-sub { font-size: .95rem; line-height: 1.4; margin-top: var(--sp-3); max-width: none; }
  .lp-hero-cta { flex-direction: column; align-items: stretch; margin-top: var(--sp-4); gap: var(--sp-2); }
  .lp-hero-cta .btn { width: 100%; font-size: .92rem; padding: var(--sp-3) var(--sp-4); }
  .lp-microtrust { margin-top: var(--sp-2); }
  .lp-hero .container { gap: var(--sp-4); }
  .lp-stage { height: 208px; }
  .lp-dots { margin-top: var(--sp-3); }
  /* Dymek SMS kompaktowy — mieści się w niskim kadrze telefonu bez przycięcia „ZAKŁAD…" na krawędzi
     (krytyk-pomiar: naturalny dymek ~170px > ekran ~150px). */
  .lp-sms { font-size: .72rem; padding: 8px 10px; }
  .lp-sms .lp-sms-from { font-size: .55rem; letter-spacing: .04em; margin-bottom: 2px; }
  .lp-mini-btn { font-size: .7rem; padding: 4px 12px; margin-top: 6px; }
  .lp-sms-time { margin-top: 4px; }
}
@media (max-height: 680px) and (max-width: 899px) {   /* bardzo niskie telefony (np. 360×640): topnav+CAŁE hero ≤ 100dvh (dots nad foldem) */
  .lp-stage { height: 128px; }
  .lp-hero { padding: var(--sp-2) 0 var(--sp-2); }
  .lp-hero .container { gap: var(--sp-2); }
  .lp-hero-sub { font-size: .9rem; }
  /* Najciaśniejszy kadr (ekran ~120px) — dymek jeszcze bardziej zwarty, by nie wychodził poza ekran. */
  .lp-sms { font-size: .66rem; padding: 7px 9px; }
  .lp-sms .lp-sms-from { font-size: .5rem; margin-bottom: 1px; }
  .lp-mini-btn { font-size: .64rem; padding: 3px 10px; margin-top: 5px; }
}

/* ---- Pasek reasekuracji ---- */
.lp-reassure-bar { border-top: var(--border-w) solid var(--color-border); border-bottom: var(--border-w) solid var(--color-border); background: var(--color-surface); }
.lp-reassure { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); justify-content: center; padding: var(--sp-4) 0; }
.lp-reassure li { display: inline-flex; align-items: center; gap: 8px; font-size: .92rem; color: var(--color-text); }
.lp-reassure svg { flex: none; color: var(--color-accent-2); }   /* ✓ w złocie (dekor) */

/* ---- DZIŚ → Z SOLAMO ---- */
.lp-transform { display: grid; gap: var(--sp-5); margin-top: var(--sp-6); }
/* align-items:start → karty przyjmują wysokość SWOJEJ treści; bez tego krótsza „Dziś" rozciąga się do
   wysokości „Z Solamo" i zostaje ~50px pustego dołu (krytyk). */
@media (min-width: 760px) { .lp-transform { grid-template-columns: 1fr 1fr; gap: var(--sp-6); align-items: start; } }
.lp-col-head { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.lp-col-head .eyebrow { margin: 0; }
.lp-list { display: flex; flex-direction: column; gap: var(--sp-3); }
.lp-list li { display: flex; gap: var(--sp-3); font-size: 1rem; color: var(--color-text); line-height: 1.45; }
.lp-list .lp-mark { flex: none; margin-top: 2px; }
.lp-list.is-today .lp-mark { color: var(--color-text-muted); }
.lp-list.is-solamo .lp-mark { color: var(--color-success); }
.lp-honest { margin-top: var(--sp-6); font-family: var(--font-head); font-style: italic; font-size: 1.15rem; line-height: 1.4; color: var(--color-heading); max-width: 52ch; }

/* ---- JAK TO DZIAŁA (oś-sygnatura: medaliony kroków = WĘZŁY; szyna rysowana przy scrollu) ----
   Redesign (krytyk): medaliony SĄ węzłami osi, a złota szyna = pionowe segmenty łączące środki
   sąsiednich medalionów (::before na kroku) — ZAWSZE wyrównane do treści (poprzedni sztywny SVG
   300/282px miał węzły dryfujące od kroków + zwisający ogon). „Rysowanie" = scaleY 0→1
   (transform-origin: top) = odpowiednik stroke-dashoffset, ale odporny na wysokość treści.
   Sprig (złota gałązka) wieńczy szczyt osi; oś kończy się na 3. medalionie (bez ogona). */
.lp-how { max-width: 560px; margin-top: var(--sp-6); }
.lp-steps { position: relative; display: flex; flex-direction: column; padding-top: 40px; }
.lp-sprig { position: absolute; top: 0; left: 20px; transform: translateX(-50%); color: var(--color-accent-2); }
.lp-step { position: relative; display: flex; gap: var(--sp-4); padding-bottom: var(--sp-5); }
.lp-step:last-child { padding-bottom: 0; }
/* Segment osi: od środka TEGO medalionu (y=20) do środka NASTĘPNego (−20px = 20px w następny krok);
   za medalionami (z-index) → linia „wychodzi" spod węzła. */
.lp-step:not(:last-child)::before {
  content: ""; position: absolute; left: 20px; margin-left: -0.75px; width: 1.5px;
  top: 20px; bottom: -20px; background: var(--color-accent-2);
  transform: scaleY(0); transform-origin: top; transition: transform 1.2s var(--ease-out);
}
.lp-how.is-drawn .lp-step:not(:last-child)::before { transform: scaleY(1); }
.lp-step-num {
  position: relative; z-index: 1; flex: none; width: 40px; height: 40px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--color-surface); border: var(--border-w) solid var(--color-accent-2);
  color: var(--color-heading); font-family: var(--font-head); font-weight: 500; font-size: 1.1rem;
}
.lp-surface .lp-step-num { background: var(--color-bg); }
.lp-step-body { padding-top: 7px; }   /* 1. linia h3 wyrównana do środka medalionu */
.lp-step-body h3 { font-size: 1.15rem; margin-bottom: 2px; }
.lp-step-body p { color: var(--color-text-muted); font-size: .98rem; }

/* ---- DOWÓD-DOKUMENT ---- */
.lp-proof { display: grid; gap: var(--sp-6); align-items: center; margin-top: var(--sp-6); }
@media (min-width: 820px) { .lp-proof { grid-template-columns: 1.1fr .9fr; } }
.lp-proof-frame {
  border: var(--border-w) solid var(--color-border); border-radius: var(--radius-lg);
  background: var(--color-surface); box-shadow: var(--shadow-lg); padding: var(--sp-3); overflow: hidden;
}
.lp-proof-frame img { width: 100%; height: auto; border-radius: var(--radius); display: block; }
.lp-proof-copy .note-inline { margin-top: var(--sp-4); }
.lp-proof-copy .btn { margin-top: var(--sp-4); }

/* ---- CO DOSTAJESZ (4 karty) ---- */
.lp-features { display: grid; gap: var(--sp-4); margin-top: var(--sp-6); grid-template-columns: 1fr; }
@media (min-width: 620px) { .lp-features { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1000px) { .lp-features { grid-template-columns: repeat(4, 1fr); } }
.lp-feature { display: flex; flex-direction: column; gap: var(--sp-2); transition: transform var(--dur-fast) var(--ease-out), box-shadow var(--dur-fast) var(--ease-out); }
.lp-feature:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.lp-feature .lp-feature-ico { width: 30px; height: 30px; color: var(--color-accent); }
.lp-feature h3 { font-size: 1.05rem; }
/* W rzędzie (≥620px): rezerwa 2 linii nagłówka → opisy startują na tej samej linii bazowej (wyrównanie kart). */
@media (min-width: 620px) { .lp-feature h3 { min-height: 3.2em; } }
.lp-feature p { color: var(--color-text-muted); font-size: .92rem; }

/* ---- BEZPIECZEŃSTWO (wyśrodkowana karta — spec §7 „zamknięte, bezpieczne pudełko") ---- */
.lp-security {
  max-width: 720px; margin: var(--sp-6) auto 0; text-align: center;
  background: var(--color-surface); border: var(--border-w) solid var(--color-border);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-sm); padding: var(--sp-7) var(--sp-6);
}
@media (max-width: 560px) { .lp-security { padding: var(--sp-6) var(--sp-4); } }
.lp-security .lp-shield { width: 40px; height: 40px; color: var(--color-accent); margin: 0 auto var(--sp-3); }
.lp-security-list { display: grid; gap: var(--sp-3); margin-top: var(--sp-5); text-align: left; }
@media (min-width: 620px) { .lp-security-list { grid-template-columns: 1fr 1fr; } }
.lp-security-list li { display: flex; gap: var(--sp-3); font-size: .95rem; color: var(--color-text); }
.lp-security-list .lp-mark { flex: none; color: var(--color-success); margin-top: 2px; }

/* ---- CENNIK ---- */
.lp-founding { text-align: center; max-width: 640px; margin: var(--sp-5) auto 0; padding: var(--sp-3) var(--sp-4); border: var(--border-w) solid var(--color-accent-2); border-radius: var(--radius-pill); background: var(--color-surface); font-size: .92rem; color: var(--color-text); }
.lp-toggle { display: inline-flex; gap: 2px; margin: var(--sp-5) auto 0; padding: 3px; border: var(--border-w) solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); }
.lp-toggle-wrap { display: flex; justify-content: center; }
.lp-toggle button { border: 0; cursor: pointer; font-family: var(--font-body); font-size: .88rem; font-weight: 600; min-height: 44px; padding: 0 18px; display: inline-flex; align-items: center; gap: 4px; border-radius: var(--radius-pill); background: transparent; color: var(--color-text-muted); }   /* cel dotykowy ≥44px */
.lp-toggle button[aria-pressed="true"] { background: var(--color-accent); color: var(--color-accent-text); }
.lp-toggle button:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.lp-toggle .lp-save { font-size: .78rem; color: var(--color-accent-2-text); }
.lp-plans { display: grid; gap: var(--sp-4); margin: var(--sp-5) auto 0; max-width: 720px; grid-template-columns: 1fr; }
@media (min-width: 680px) { .lp-plans { grid-template-columns: 1fr 1fr; align-items: start; } }
.lp-plan { display: flex; flex-direction: column; gap: var(--sp-3); }
/* Karta polecana (Standard) = czytelny anchor środka: elewacja + mocniejszy złoty obrys (godny ton, bez wypełnienia). */
.lp-plan.card-featured { border-width: 1.5px; box-shadow: var(--shadow-md); }
@media (min-width: 680px) { .lp-plan.card-featured { transform: translateY(-6px); } }
.lp-plan-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); flex-wrap: wrap; }
.lp-plan-name { font-family: var(--font-head); font-weight: 500; font-size: 1.25rem; color: var(--color-heading); }
.lp-plan-price { font-family: var(--font-head); font-weight: 500; font-size: 2rem; color: var(--color-heading); line-height: 1; letter-spacing: -0.01em; }
.lp-plan-price .lp-per { font-size: .85rem; font-family: var(--font-body); color: var(--color-text-muted); font-weight: 400; letter-spacing: 0; }
.lp-plan-price.is-empty { font-size: 1.05rem; color: var(--color-text-muted); }
.lp-plan-feats { display: flex; flex-direction: column; gap: var(--sp-2); }
.lp-plan-feats li { display: flex; gap: var(--sp-2); font-size: .92rem; color: var(--color-text); }
.lp-plan-feats .lp-mark { flex: none; color: var(--color-success); margin-top: 3px; }
.lp-pilot { text-align: center; margin: var(--sp-6) auto 0; max-width: 520px; }
.lp-pilot .btn { margin-bottom: var(--sp-2); }
.lp-anchor-note { text-align: center; color: var(--color-text-muted); font-size: .9rem; margin-top: var(--sp-4); }
.lp-enterprise { text-align: center; margin-top: var(--sp-3); font-size: .9rem; }

/* ---- FAQ ---- */
.lp-faq { max-width: 720px; margin: var(--sp-6) auto 0; display: flex; flex-direction: column; gap: 0; }
.lp-faq details { border-bottom: var(--border-w) solid var(--color-border); padding: var(--sp-2) 0; }
/* summary z pionowym paddingiem → cel dotykowy ≥44px (WCAG 2.5.8; spec §5.8) */
.lp-faq summary { cursor: pointer; list-style: none; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4); padding: 10px 0; font-family: var(--font-head); font-size: 1.08rem; color: var(--color-heading); font-weight: 500; }
.lp-faq summary::-webkit-details-marker { display: none; }
.lp-faq summary::after { content: "+"; flex: none; color: var(--color-accent-2-text); font-size: 1.3rem; line-height: 1; }
.lp-faq details[open] summary::after { content: "–"; }
.lp-faq summary:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 3px; border-radius: var(--radius-sm); }
.lp-faq details p { color: var(--color-text-muted); margin-top: var(--sp-3); font-size: .98rem; max-width: 60ch; }

/* ---- FINAŁ (zieleń cyprysowa — JEDYNY ciemny pas) ---- */
.lp-final { background: var(--color-accent); color: var(--color-accent-text); text-align: center; }
.lp-final h2 { color: var(--color-accent-text); font-size: clamp(1.5rem, 3.4vw, 2.25rem); max-width: 24ch; margin: 0 auto; }
.lp-final .lp-final-sub { color: var(--color-accent-text); opacity: .82; margin-top: var(--sp-3); font-size: .95rem; }
.lp-btn-ivory { background: var(--color-accent-text); color: var(--color-accent); font-family: var(--font-head); font-weight: 500; margin-top: var(--sp-5); }
.lp-btn-ivory:hover { background: var(--color-bg); }

/* ---- STOPKA ---- */
.lp-footer { border-top: var(--border-w) solid var(--color-border); padding: var(--sp-6) 0; }
.lp-footer .container { display: flex; flex-wrap: wrap; gap: var(--sp-3) var(--sp-5); align-items: center; justify-content: space-between; }
.lp-footer .lp-foot-brand { font-family: var(--font-head); color: var(--color-heading); font-weight: 500; }
.lp-footer nav { display: flex; flex-wrap: wrap; gap: var(--sp-2) var(--sp-4); }
.lp-footer nav a { color: var(--color-text-muted); font-size: .9rem; }

/* ---- STICKY CTA (mobile, po hero) ---- */
.lp-sticky-cta {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-sticky);
  padding: var(--sp-3) var(--sp-4); background: color-mix(in srgb, var(--color-bg) 92%, transparent);
  backdrop-filter: blur(6px); border-top: var(--border-w) solid var(--color-border);
  transform: translateY(110%); transition: transform var(--dur-base) var(--ease-out);
}
.lp-sticky-cta.is-on { transform: translateY(0); }
.lp-sticky-cta .btn { width: 100%; }
@media (min-width: 900px) { .lp-sticky-cta { display: none; } }

/* ---- Reveal on-scroll (fade-up 16px / .55s / ease-out, RAZ) ---- */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out); }
.reveal.is-visible { opacity: 1; transform: none; }

/* ---- prefers-reduced-motion: KOMPLET dla landingu ---- */
@media (prefers-reduced-motion: reduce) {
  .lp-phase { transition: none; }
  .lp-phase[data-phase="4"], .lp-zaklad { opacity: 1 !important; }
  .lp-zaklad { transform: translateY(-50%) translateX(12px) !important; }
  .lp-phase:not([data-phase="4"]):not(.lp-zaklad) { opacity: 0 !important; }
  .lp-dots { display: none; }
  .lp-step:not(:last-child)::before { transition: none; transform: scaleY(1); }   /* oś narysowana od razu */
  .lp-phone { transition: none; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .lp-feature { transition: none; }
  .lp-feature:hover { transform: none; }
  .lp-sticky-cta { transition: none; }
}
