/* ═══════════════════════════════════════════════════════════
   GMB Manager – style główne
   ═══════════════════════════════════════════════════════════ */

/* ── Widoczność wg roli (sterowane klasą role-* na <html>) ──
   Działa też dla elementów renderowanych dynamicznie (wiersze, akcje).

   KLUCZOWE: klasa siedzi na <html> (document.documentElement), a nie na <body>,
   bo <html> istnieje już w <head> — inline-skrypt w <head> czyta zcache'owaną
   rolę z localStorage i ustawia ją PRZED pierwszym malowaniem strony. Dzięki
   temu zakładki admin-only nie „znikają" na ułamek sekundy przy każdej nawigacji
   (wcześniej klasa była ustawiana dopiero po async /auth/me → migotanie/FOUC).
   /auth/me w app.js tylko UZGADNIA i odświeża cache.

   Dopóki rola nie jest znana (brak klasy role-*), treść zależna od roli jest
   UKRYTA — to chroni też przed mignięciem zakładek admina u klienta.

   Po ustaleniu roli ukrywamy tylko elementy NIEpasujące; pasujące wracają do
   swojego naturalnego display (nie wymuszamy wartości → nie psujemy flex/grid). */
html:not(.role-admin):not(.role-client) .admin-only,
html:not(.role-admin):not(.role-client) .client-only { display: none !important; }

html.role-client .admin-only { display: none !important; }
html.role-admin  .client-only { display: none !important; }

/* USUNIĘTE 2026-08-10 wraz ze stroną /hours.html: reguła `html:not(.can-hours)
   .hours-nav-link` i cała klasa 'can-hours'. Zakładka „Godziny otwarcia" zniknęła
   z nawigacji (godziny edytuje się w Edycji profilu, masowo w Ustawieniach), więc
   nie ma już elementu gatowanego FLAGĄ per-konto — zostaje wyłącznie mechanizm
   .admin-only/.client-only + perm-* niżej. */

/* Zakładki nawigacji odblokowane niestandardową rolą (services/permissions.js) —
   te same <li class="admin-only"> co reszta, więc domyślnie ukryte regułą wyżej
   dla nie-admina; klasa perm-<key> na <html> (ustawiana z /auth/me tym samym
   wzorcem co can-hours) je z powrotem odsłania. Wyższa specyficzność (3 klasy)
   niż `.role-client .admin-only` (2 klasy) → wygrywa mimo obu !important. */
html.perm-edit_profile             .nav-perm-edit_profile,
html.perm-manage_media             .nav-perm-manage_media,
html.perm-manage_posts             .nav-perm-manage_posts,
html.perm-manage_menu              .nav-perm-manage_menu,
html.perm-manage_rank_tracker      .nav-perm-manage_rank_tracker,
html.perm-view_dashboard           .nav-perm-view_dashboard,
html.perm-view_analytics           .nav-perm-view_analytics,
html.perm-view_location_analytics  .nav-perm-view_location_analytics,
html.perm-view_forecast            .nav-perm-view_forecast,
html.perm-view_flagged             .nav-perm-view_flagged,
html.perm-reviews_analysis         .nav-perm-reviews_analysis,
html.perm-view_recommendations     .nav-perm-view_recommendations,
html.perm-manage_qr                .nav-perm-manage_qr {
  display: list-item !important;
}

/* Przyciski (nie zakładki nawigacji) odblokowane uprawnieniem 'manage_sync' —
   „Synchronizuj wizytówki" (Dashboard, zbiorczy), sync pojedynczej wizytówki
   (Dashboard) i „Wykryj usunięte" (Opinie). Wszystkie trzy mają też admin-only,
   więc ta reguła realnie odsłania je z powrotem TYLKO dla nie-admina, który
   dostał manage_sync przez niestandardową rolę. „Pobierz moje wizytówki" (client
   self-sync) NIE dostaje tej klasy — jest gated osobno w JS (dashboard.js), żeby
   uniknąć remisu specyficzności z regułą `html.role-admin .client-only` wyżej. */
html.perm-manage_sync .manage-sync-gate { display: inline-flex !important; }

/* [v1.73] Pod-zakładki i przyciski gatowane uprawnieniem, które do tej pory były
   chowane DOPIERO w JS po async /auth/me (reviews.js, dashboard.js) — czyli po
   pierwszym malowaniu. Efekt: sekundowe mignięcie pod-zakładek/funkcji, do których
   konto nie ma dostępu, przy KAŻDYM wejściu na stronę. To ta sama klasa błędu co
   [v1.05] (role) i [v1.33] (can-hours), tylko na elementach, których tamte naprawy
   nie obejmowały — bo gating per-uprawnienie powstał później ([v1.45]/[v1.58]).

   ŚWIADOMIE tylko reguły UKRYWAJĄCE, nigdy odsłaniające: `#syncBtnClient` ma też
   klasę `client-only`, a admin ma z automatu WSZYSTKIE klucze uprawnień — reguła
   odsłaniająca licytowałaby się wtedy z `html.role-admin .client-only` i mogłaby
   ujawnić przycisk adminowi (dokładnie pułapka opisana w [v1.58]). Dwa niezależne
   warunki ukrycia komponują się bezpiecznie: element jest widoczny tylko wtedy,
   gdy ŻADEN z nich nie zachodzi (fail-closed).

   JS w reviews.js/dashboard.js ZOSTAJE nietknięty i nadal ustawia inline
   `style.display` — to nie jest duplikat do posprzątania: (1) uzgadnia stan, gdy
   cache uprawnień w localStorage jest nieaktualny, (2) dolny pasek mobilny z
   [v1.57] (`mIsShown`) czyta WYŁĄCZNIE inline style elementu, więc gating czysto
   klasowy sprawiłby, że zabroniona pod-zakładka trafiłaby do paska mobilnego. */
html:not(.perm-reviews_session) #subtab-session,
html:not(.perm-reviews_deleted) #subtab-deleted,
html:not(.perm-manage_sync)     #syncBtnClient { display: none !important; }

/* [v2.19] Oznaczenia wkładu AI (filtr „Udział AI" w Opiniach) — ta sama recepta
   fail-closed co wyżej: ukryte DOMYŚLNIE, odsłaniane wyłącznie brakiem trafienia
   w `:not(.perm-view_ai_markers)`. Badge na karcie opinii NIE potrzebuje reguły
   CSS — po prostu nie powstaje (backend nie przysyła `ai_outcome`, a
   aiOutcomeBadge dodatkowo sprawdza uprawnienie przed zbudowaniem HTML). */
html:not(.perm-view_ai_markers) .ai-markers-gate { display: none !important; }

/* Pod-zakładki Ustawień — ten sam wzorzec co wyżej. Pasek pod-zakładek jest od
   przebudowy 2026-08-07 widoczny w HTML od pierwszej klatki (koniec czekania na
   /auth/me i „artefaktów" u ról bez uprawnień), a poszczególne przyciski chowają
   te reguły wg klas perm-* z cache. „Moje konto" (#sst-account) CELOWO nie ma
   reguły — to gwarantowany baseline dla każdego zalogowanego, bez klucza uprawnień
   (jak sama strona /settings.html). settings.js dodatkowo ustawia inline
   style.display z cache PRZED mBuildSubbar (pasek mobilny czyta tylko inline). */
html:not(.perm-settings_api)       #sst-api,
html:not(.perm-settings_sync)      #sst-sync,
html:not(.perm-settings_latency)   #sst-latency,
html:not(.perm-settings_templates) #sst-tpl,
html:not(.perm-settings_themes)    #sst-themes,
html:not(.perm-manage_work_groups) #sst-wgroups,
html:not(.perm-edit_hours)         #sst-hours,
html:not(.perm-settings_uispec)    #sst-uispec { display: none !important; }

/* ── Ikony SVG (icons.js / inline w HTML) — zastąpiły emoji w całym UI ──────
   Stroke 24×24, kolor z currentColor (dziedziczy motyw i kolor przycisku).
   vertical-align dopasowuje ikonę do linii tekstu obok (etykiety przycisków,
   pozycje nawigacji). `.ic-fill` — wariant wypełniony (kropki statusu). */
.ic { display: inline-block; vertical-align: -0.19em; flex-shrink: 0; }
.ic-fill { fill: currentColor; stroke: none; }
.nav-icon .ic { vertical-align: -0.24em; }
/* Skalowanie ikon w stanach, które dotąd robił font-size na glifie emoji —
   SVG ma sztywne atrybuty width/height, więc CSS musi je nadpisać w tych
   samych miejscach (zwinięty panel, tablet, telefon — patrz reguły
   `.nav-icon { font-size: 18px }` niżej w pliku). */
html.sb-collapsed .nav-icon .ic { width: 18px; height: 18px; }
@media (max-width: 1180px) and (min-width: 901px) {
  .nav-icon .ic { width: 18px; height: 18px; }
}
@media (max-width: 900px) {
  .nav-link .nav-icon .ic { width: 18px; height: 18px; }
}
/* Logo na stronie logowania/zaproszenia — dawny emoji miał font-size 42px */
.login-logo .ic { width: 38px; height: 38px; }

/* ── Baner podglądu „co widzi użytkownik" (impersonacja) ─────────────────
   Tworzony dynamicznie w app.js (renderImpersonationBanner) — nie ma go w HTML.
   body.has-impersonation-banner odsuwa całą treść (padding-top), żeby fixed
   baner niczego nie zasłaniał, niezależnie od wewnętrznego layoutu strony. */
#impersonationBanner {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 10px 16px;
  background: linear-gradient(90deg, #d97706, #b45309);
  color: #fff;
  font-size: 13px;
  font-weight: 600;
  box-shadow: 0 2px 10px rgba(0,0,0,.15);
}
#impersonationBanner strong { font-weight: 800; }
#exitImpersonationBtn {
  background: rgba(255,255,255,.2);
  border: 1px solid rgba(255,255,255,.5);
  color: #fff;
  border-radius: 6px;
  padding: 4px 12px;
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
}
#exitImpersonationBtn:hover { background: rgba(255,255,255,.32); }
body.has-impersonation-banner { padding-top: 42px; }

:root {
  --primary:      #3b6ef0;          /* Google-blue accent (≈ oklch(54% .19 264)) */
  --primary-dark: #2f5ad6;
  --primary-glow: rgba(66,133,244,.28);

  /* Sidebar = jasne szkło (frosted glass) */
  --sidebar-bg:    rgba(255,255,255,.58);
  --sidebar-text:  #5b6275;         /* nieaktywny link */
  --sidebar-hover: rgba(255,255,255,.55);
  --sidebar-active:#3b6ef0;

  --bg:           #eef1f8;          /* fallback gdy brak gradientu */
  --surface:      rgba(255,255,255,.68);   /* szklane powierzchnie */
  --surface-solid:#ffffff;
  --border:       rgba(255,255,255,.85);   /* jasna krawędź szkła */
  --border-soft:  rgba(0,0,0,.08);         /* delikatna krawędź na jasnym tle */
  --text:         #1a1f2e;
  --muted:        #6b7180;
  /* Wartości ZAPASOWE — realnie obowiązują te z `locardly-brand.css`, który
     ładuje się PÓŹNIEJ i definiuje oba tokeny osobno dla każdej z czterech
     kombinacji paleta×motyw (tam też pełne uzasadnienie i zmierzone kontrasty).
     Tu wyłącznie na wypadek, gdyby klasa `loca-brand` zniknęła z `<html>`. */
  --muted-strong: #484e5e;
  --pe-header-bg: linear-gradient(135deg, #2f3757 0%, #1e2540 100%);
  --success:      #2f9e54;
  --warning:      #ECC94B;
  --danger:       #FC8181;
  --danger-dark:  #e53e3e;

  --radius:       12px;             /* kontrolki (przyciski, inputy) */
  --radius-card:  20px;             /* karty / panele */
  --shadow:       0 2px 14px rgba(0,0,0,.055), inset 0 1px 0 rgba(255,255,255,.9);
  --shadow-lg:    0 12px 40px rgba(0,0,0,.14);
  --blur:         blur(24px) saturate(160%);
  --sidebar-w:    240px;

  /* Spójny system kolorów gwiazdek (cała aplikacja) */
  --color-5star: #1B8A3E;  /* mocny zielony */
  --color-4star: #5CB85C;  /* średni zielony */
  --color-3star: #F0AD00;  /* żółty/złoty */
  --color-2star: #E8711A;  /* pomarańczowy */
  --color-1star: #D9230F;  /* mocny czerwony */
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', system-ui, sans-serif;
  background:
    linear-gradient(145deg,
      oklch(97.5% 0.008 220),
      oklch(97% 0.012 258) 50%,
      oklch(97.5% 0.007 185));
  background-color: var(--bg);
  background-attachment: fixed;
  color: var(--text);
  font-size: 14px;
  line-height: 1.5;
  min-height: 100vh;
}

/* ── Animowane tło: subtelne, powoli pływające „bloby" (CSS-only) ──
   Dwa stałe pseudo-elementy za całą treścią (z-index:-1). Każdy nosi
   po dwa radialne gradienty i dryfuje w przeciwną stronę → organiczny ruch
   bez zmian w HTML. Wyłączane przy prefers-reduced-motion. */
body::before,
body::after {
  content: "";
  position: fixed;
  z-index: -1;
  pointer-events: none;
  inset: -15%;
  background-repeat: no-repeat;
}
body::before {
  background-image:
    radial-gradient(circle at 18% 12%, oklch(88% 0.06 228) 0%, transparent 42%),
    radial-gradient(circle at 82% 70%, oklch(88% 0.05 288) 0%, transparent 40%);
  opacity: .5;
  animation: blobFloat 26s ease-in-out infinite;
}
body::after {
  background-image:
    radial-gradient(circle at 60% 92%, oklch(91% 0.045 154) 0%, transparent 44%),
    radial-gradient(circle at 8% 78%, oklch(89% 0.05 200) 0%, transparent 38%);
  opacity: .38;
  animation: blobFloat 34s ease-in-out infinite reverse;
}

@keyframes blobFloat {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33%      { transform: translate(2.2%, -1.6%) scale(1.04); }
  66%      { transform: translate(-1.6%, 1.1%) scale(0.97); }
}

@media (prefers-reduced-motion: reduce) {
  body::before, body::after { animation: none; }
}

/* ── Layout ─────────────────────────────────────────────────── */

.app-container {
  display: flex;
  min-height: 100vh;
}

/* ── Sidebar ────────────────────────────────────────────────── */

.sidebar {
  width: var(--sidebar-w);
  background: var(--sidebar-bg);
  backdrop-filter: blur(48px) saturate(165%);
  -webkit-backdrop-filter: blur(48px) saturate(165%);
  border-right: 1px solid rgba(255,255,255,.76);
  box-shadow: inset 1px 0 0 rgba(255,255,255,.55), 4px 0 32px rgba(0,0,0,.05);
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0; left: 0; bottom: 0;
  z-index: 100;
  overflow-y: auto;
}

.sidebar-header {
  padding: 24px 20px 16px;
  border-bottom: 1px solid rgba(0,0,0,.055);
}

.app-title {
  font-size: 18px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -.3px;
}

.app-subtitle {
  font-size: 11px;
  color: var(--muted);
  margin-top: 2px;
}

.nav-section-label {
  padding: 20px 20px 6px;
  font-size: 10px;
  font-weight: 600;
  color: rgba(107,113,128,.7);
  text-transform: uppercase;
  letter-spacing: .8px;
}

.nav-links {
  list-style: none;
  padding: 8px 12px;
  flex: 1;
}

.nav-links li {
  margin-bottom: 2px;
  position: relative;
}

.nav-link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  color: var(--sidebar-text);
  text-decoration: none;
  border-radius: 13px;
  font-size: 14px;
  font-weight: 500;
  transition: background .2s, color .2s, box-shadow .2s;
}

.nav-link:hover  { background: var(--sidebar-hover); color: var(--text); }
/* Aktywny link = biała szklana pigułka z miękkim cieniem (jak we wzorze) */
.nav-link.active {
  background: rgba(255,255,255,.9);
  color: var(--text);
  font-weight: 600;
  box-shadow: 0 2px 12px rgba(0,0,0,.07), inset 0 1px 0 rgba(255,255,255,.9);
}
.nav-link .nav-icon    { font-size: 16px; width: 20px; text-align: center; }

.sidebar-footer {
  padding: 16px 20px;
  border-top: 1px solid rgba(0,0,0,.055);
}

.app-version {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid rgba(0,0,0,.06);
  font-size: 11px;
  color: var(--muted);
  letter-spacing: .3px;
  text-align: center;
}

.user-info {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
  padding: 9px 11px;
  border-radius: 13px;
  background: rgba(255,255,255,.48);
  border: 1px solid rgba(255,255,255,.68);
}

.user-avatar {
  width: 36px;
  height: 36px;
  min-width: 36px;   /* zapobiega collapsowi przed załadowaniem */
  border-radius: 50%;
  object-fit: cover;
  background: rgba(0,0,0,.06);
  /* Płynne pojawienie się po załadowaniu */
  opacity: 0;
  transition: opacity 0.2s ease;
}
.user-avatar.loaded {
  opacity: 1;
}

.user-name  { font-size: 13px; color: var(--text); font-weight: 600; }
.user-role  { font-size: 11px; color: var(--muted); }

.logout-btn {
  display: block;
  width: 100%;
  padding: 8px;
  background: rgba(255,255,255,.55);
  color: var(--muted);
  text-decoration: none;
  border: 1px solid rgba(0,0,0,.07);
  border-radius: 11px;
  text-align: center;
  font-size: 13px;
  transition: background .15s, color .15s;
}
.logout-btn:hover { background:var(--surface-solid,#fff); color: var(--text); }

/* ── Główna zawartość ───────────────────────────────────────── */

.main-content {
  margin-left: var(--sidebar-w);
  flex: 1;
  /* KRYTYCZNE — nie usuwać. `.main-content` jest flex-itemem `.app-container`,
     a domyślne `min-width:auto` NIE POZWALA flex-itemowi zwęzić się poniżej
     intrinsic width jego treści. Efekt (zmierzony na 375 px: kolumna rozpychała
     się do 716 px): cała treść robiła się szersza od ekranu, dokument dostawał
     poziomy scroll i obszar roboczy dało się „przesuwać" palcem/myszą — łącznie
     46 elementów wystających poza viewport, wszystkie kaskadujące z TEGO jednego
     miejsca. `min-width:0` przywraca deterministyczną szerokość = 100% − sidebar. */
  min-width: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.page-header {
  padding: 28px 32px 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
}

.page-title {
  font-size: 22px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -.45px;
}

/* Nagłówek strony — JEDEN wzorzec dla 20 zakładek ([alfa 0.351]):
     .page-header > .page-heading (h1 + opcjonalny .page-subtitle) + .page-actions.
   Do tej wersji podtytuł miał cztery formy (inline div, .page-intro, .rk2-headnote,
   niezdefiniowana .page-subtitle), a akcje bez wrappera trafiały w ŚRODEK
   nagłówka (space-between z trzema dziećmi — Automatyzacja). */
.page-heading  { min-width: 0; }
.page-subtitle { margin: 4px 0 0; font-size: 13px; color: var(--muted-strong); max-width: 760px; }
.page-actions  { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.page-body {
  padding: 24px 32px 40px;
  flex: 1;
}

/* ── Karty ──────────────────────────────────────────────────── */

.card {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow);
  padding: 22px;
  border: 1px solid var(--border);
}

.card-title {
  font-size: 15px;
  font-weight: 700;
  margin-bottom: 16px;
  color: var(--text);
  letter-spacing: -.2px;
}

.chart-fill-card { padding: 14px 14px 10px; }

.line-chart-wrap {
  position: relative;
  height: 320px;
}

/* ── Statystyki (stats cards) ───────────────────────────────── */

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: 16px;
  margin-bottom: 24px;
}

.stat-card {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border-radius: var(--radius-card);
  padding: 20px;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

/* Kanoniczna typografia KPI ([alfa 0.351]) — wartość 28/700 tabular, etykieta
   11/600 uppercase. Te same liczby noszą .kpi-value (Analityka), .la-big-num
   (Analityka lokalu), .rk-kpi (Rekomendacje), .forecast-value (Prognoza) i
   .mn-stat (Menu) — zmieniasz tu, zmień tam. */
.stat-label  { font-size: 11px; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: .5px; }
.stat-value  { font-size: 28px; font-weight: 700; margin: 8px 0 2px; color: var(--text); letter-spacing: -.6px; font-variant-numeric: tabular-nums; }
.stat-sub    { font-size: 12px; color: var(--muted); }

.stat-card.stat-primary .stat-value { color: var(--primary); }
.stat-card.stat-success .stat-value { color: var(--success); }
.stat-card.stat-warning .stat-value { color: #d97706; }
.stat-card.stat-danger  .stat-value { color: var(--danger-dark); }

/* ── Przyciski ──────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 9px 18px;
  border-radius: var(--radius);
  border: none;
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  transition: background .15s, transform .12s, box-shadow .15s, opacity .15s;
  white-space: nowrap;
}

.btn:active { transform: scale(.97); opacity: .9; }

.btn-primary  { background: var(--primary); color: #fff; box-shadow: 0 3px 14px var(--primary-glow), inset 0 1px 0 rgba(255,255,255,.2); }
.btn-primary:hover  { background: var(--primary-dark); }
.btn-success  { background: var(--success); color: #fff; box-shadow: 0 3px 14px rgba(47,158,84,.25); }
.btn-success:hover  { background: #28894a; }
.btn-danger   { background: var(--danger-dark); color: #fff; box-shadow: 0 3px 14px rgba(229,62,62,.25); }
.btn-danger:hover   { background: #c53030; }
.btn-warning  { background: #d97706; color: #fff; }
.btn-warning:hover  { background: #b45309; }
/* Wtórny przycisk = jasne szkło */
.btn-secondary {
  background: rgba(255,255,255,.7);
  color: var(--text);
  border: 1px solid var(--border-soft);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.btn-secondary:hover { background:var(--surface-solid,#fff); }
.btn-outline  { background: transparent; color: var(--primary); border: 1.5px solid var(--primary); }
.btn-outline:hover  { background: var(--primary); color: #fff; }

.btn-sm { padding: 6px 12px; font-size: 12px; border-radius: 10px; }
.btn-lg { padding: 12px 24px; font-size: 15px; }

.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; }

/* ── Tabele ─────────────────────────────────────────────────── */

.table-wrapper { overflow-x: auto; border-radius: var(--radius); }

table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}

thead th {
  text-align: left;
  padding: 10px 14px;
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--muted);
  background: rgba(255,255,255,.45);
  border-bottom: 1px solid var(--border-soft);
}

tbody td {
  padding: 12px 14px;
  border-bottom: 1px solid rgba(0,0,0,.05);
  vertical-align: middle;
}

tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: rgba(255,255,255,.4); }

/* ── Formularz ──────────────────────────────────────────────── */

.form-group { margin-bottom: 16px; }
.form-label { display: block; font-size: 13px; font-weight: 500; margin-bottom: 6px; color: var(--text); }

.form-control {
  width: 100%;
  padding: 10px 13px;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  font-size: 14px;
  color: var(--text);
  background: rgba(255,255,255,.65);
  transition: border-color .15s, box-shadow .15s;
  outline: none;
}

.form-control:focus {
  border-color: rgba(66,133,244,.45);
  box-shadow: 0 0 0 3px rgba(66,133,244,.1);
}

textarea.form-control { min-height: 100px; resize: vertical; }

/* ── Badge ──────────────────────────────────────────────────── */

.badge {
  display: inline-block;
  padding: 3px 8px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .4px;
}

.badge-success  { background: #f0fff4; color: #276749; }
.badge-danger   { background:rgba(239,68,68,.12); color:var(--err-fg,#c53030); }
.badge-warning  { background:rgba(245,158,11,.14); color:var(--warn-fg,#92400e); }
.badge-info     { background: #ebf8ff; color: #2b6cb0; }
.badge-neutral  { background:var(--surface-sunken,#f7fafc); color:var(--text,#4a5568); }

/* ── Gwiazdki ───────────────────────────────────────────────── */

.stars {
  color: #f6c90e;
  font-size: 14px;
  letter-spacing: 1px;
}
.stars .empty { color: #e2e8f0; }

/* ── Toast notifications ────────────────────────────────────── */

#toast-container {
  position: fixed;
  bottom: 24px; right: 24px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.toast {
  padding: 12px 18px;
  border-radius: 8px;
  color: #fff;
  font-size: 14px;
  font-weight: 500;
  box-shadow: 0 4px 16px rgba(0,0,0,.2);
  transform: translateX(120%);
  transition: transform .3s ease;
  max-width: 340px;
  display: flex;
  align-items: flex-start;
  gap: 12px;
}
.toast .toast-msg { flex: 1; line-height: 1.4; }
.toast .toast-close {
  flex-shrink: 0;
  font-size: 13px;
  line-height: 1.4;
  opacity: .7;
  transition: opacity .15s;
}
.toast:hover .toast-close { opacity: 1; }

.toast.show         { transform: translateX(0); }
.toast.toast-success { background: var(--success); }
.toast.toast-error   { background: var(--danger-dark); }
.toast.toast-info    { background: var(--primary); }
.toast.toast-warning { background: #d97706; }

/* Toast podsumowania synchronizacji */
.toast-sync {
  padding: 13px 40px 13px 16px;
  border-radius: 10px;
  color: #fff;
  font-size: 14px;
  box-shadow: 0 6px 24px rgba(0,0,0,.22);
  transform: translateX(120%);
  transition: transform .35s cubic-bezier(.16,1,.3,1);
  max-width: 300px;
  min-width: 220px;
  position: relative;
}
.toast-sync.show { transform: translateX(0); }
.toast-sync-title {
  font-weight: 600;
  font-size: 13.5px;
  line-height: 1.3;
  margin-bottom: 4px;
}
.toast-sync-sub {
  font-size: 12px;
  opacity: .88;
  line-height: 1.3;
}
.toast-sync-close {
  position: absolute;
  top: 8px; right: 10px;
  background: none;
  border: none;
  color: #fff;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  opacity: .7;
  padding: 2px 4px;
  border-radius: 4px;
  transition: opacity .15s, background .15s;
}
.toast-sync-close:hover {
  opacity: 1;
  background: rgba(255,255,255,.18);
}

/* ── Modal ──────────────────────────────────────────────────── */

.modal-overlay {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.4);
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s;
}

.modal-overlay.open {
  opacity: 1;
  pointer-events: all;
}

.modal {
  background: rgba(255,255,255,.86);
  backdrop-filter: blur(40px) saturate(180%);
  -webkit-backdrop-filter: blur(40px) saturate(180%);
  border: 1px solid rgba(255,255,255,.9);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow-lg);
  width: 100%;
  max-width: 540px;
  max-height: 85vh;
  overflow-y: auto;
  transform: translateY(-20px);
  transition: transform .2s;
}

.modal-overlay { background: rgba(20,24,40,.35); backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); }
.modal-overlay.open .modal { transform: translateY(0); }

.modal-header {
  padding: 20px 24px 16px;
  border-bottom: 1px solid var(--border-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.modal-title { font-size: 16px; font-weight: 700; letter-spacing: -.2px; }
.modal-close { background: none; border: none; cursor: pointer; font-size: 20px; color: var(--muted); line-height: 1; padding: 0 4px; }
.modal-confirm { max-width: 440px; }
.modal-confirm .confirm-msg { margin: 0; font-size: 14px; line-height: 1.55; color: var(--text); white-space: pre-line; }
.modal-close:hover { color: var(--text); }
.modal-body   { padding: 20px 24px; }
.modal-footer { padding: 16px 24px; border-top: 1px solid var(--border-soft); display: flex; gap: 8px; justify-content: flex-end; }

/* ── Strona logowania ────────────────────────────────────────── */

.login-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.login-card {
  background: rgba(255,255,255,.72);
  backdrop-filter: blur(40px) saturate(180%);
  -webkit-backdrop-filter: blur(40px) saturate(180%);
  border: 1px solid rgba(255,255,255,.9);
  border-radius: var(--radius-card);
  padding: 48px 40px;
  width: 100%;
  max-width: 400px;
  box-shadow: var(--shadow-lg);
  text-align: center;
}

.login-logo    { font-size: 42px; margin-bottom: 12px; }
.login-title   { font-size: 24px; font-weight: 700; color: var(--text); margin-bottom: 6px; }
.login-subtitle { font-size: 14px; color: var(--muted); margin-bottom: 32px; }

.btn-google {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  width: 100%;
  padding: 13px 24px;
  background:var(--surface-solid,#fff);
  border: 2px solid var(--border);
  border-radius: 10px;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  text-decoration: none;
  transition: border-color .15s, box-shadow .15s;
}

.btn-google:hover {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(74,108,247,.12);
}

.google-icon {
  width: 20px; height: 20px;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 48 48'%3E%3Cpath fill='%234285F4' d='M24 9.5c3.54 0 6.71 1.22 9.21 3.6l6.85-6.85C35.9 2.38 30.47 0 24 0 14.62 0 6.51 5.38 2.56 13.22l7.98 6.19C12.43 13.72 17.74 9.5 24 9.5z'/%3E%3Cpath fill='%2334A853' d='M46.98 24.55c0-1.57-.15-3.09-.38-4.55H24v9.02h12.94c-.58 2.96-2.26 5.48-4.78 7.18l7.73 6c4.51-4.18 7.09-10.36 7.09-17.65z'/%3E%3Cpath fill='%23FBBC05' d='M10.53 28.59c-.48-1.45-.76-2.99-.76-4.59s.27-3.14.76-4.59l-7.98-6.19C.92 16.46 0 20.12 0 24c0 3.88.92 7.54 2.56 10.78l7.97-6.19z'/%3E%3Cpath fill='%23EA4335' d='M24 48c6.48 0 11.93-2.13 15.89-5.81l-7.73-6c-2.15 1.45-4.92 2.3-8.16 2.3-6.26 0-11.57-4.22-13.47-9.91l-7.98 6.19C6.51 42.62 14.62 48 24 48z'/%3E%3C/svg%3E") no-repeat center/contain;
}

.login-error {
  background:rgba(239,68,68,.12);
  color:var(--err-fg,#c53030);
  border: 1px solid #fed7d7;
  border-radius: 8px;
  padding: 10px 14px;
  font-size: 13px;
  margin-top: 16px;
}

.login-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 20px 0;
  color: var(--muted);
  font-size: 12px;
}
.login-divider::before, .login-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--border-soft);
}

.login-form { text-align: left; }
.login-form .form-group { margin-bottom: 14px; }

/* ── Loader ─────────────────────────────────────────────────── */

.spinner {
  width: 20px; height: 20px;
  border: 2px solid rgba(255,255,255,.3);
  border-top-color: #fff;
  border-radius: 50%;
  animation: spin .7s linear infinite;
  display: inline-block;
}

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

.page-loader {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 200px;
  color: var(--muted);
}

.page-loader .spinner {
  border-color: rgba(74,108,247,.3);
  border-top-color: var(--primary);
  width: 32px; height: 32px;
}

/* ── Elementy specyficzne ────────────────────────────────────── */

.review-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 16px;
  margin-bottom: 12px;
  transition: box-shadow .15s;
}
.review-card:hover { box-shadow: 0 4px 16px rgba(0,0,0,.08); }
.review-card.negative { border-left: 3px solid var(--danger-dark); }
.review-card.with_content { border-left: 3px solid var(--primary); }
.review-card.empty { border-left: 3px solid var(--success); }

.review-header { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.reviewer-avatar { width: 36px; height: 36px; border-radius: 50%; background: var(--bg); object-fit: cover; }
.reviewer-name { font-weight: 600; font-size: 13px; }
.review-date   { font-size: 11px; color: var(--muted); }
.review-comment { font-size: 13px; color: var(--text); line-height: 1.6; margin: 8px 0; }
.review-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

.ai-response-box {
  background: #f0f4ff;
  border: 1px solid #c3d0ff;
  border-radius: 8px;
  padding: 12px;
  margin: 10px 0;
  font-size: 13px;
  line-height: 1.6;
}

/* Box wysłanej odpowiedzi na karcie opinii. Wartości 1:1 z inline-style,
   który stał wcześniej w reviews.js — przeniesione do CSS, bo inline bije
   każdą regułę arkusza i motyw ciemny [v1.60] nie mógł go przykryć. */
.sent-reply-box {
  background: #f0fff4;
  border: 1px solid #c6f6d5;
  border-radius: 8px;
  padding: 10px;
  margin-top: 8px;
  font-size: 12px;
}
.sent-reply-label { font-weight: 600; color: #276749; }

.ai-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--primary);
  text-transform: uppercase;
  letter-spacing: .5px;
  margin-bottom: 4px;
}

/* ── Lokalizacje grid ───────────────────────────────────────── */

.locations-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 16px;
}

.location-card {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 20px;
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: box-shadow .15s, transform .15s;
}

.location-card:hover {
  box-shadow: 0 10px 30px rgba(0,0,0,.1);
  transform: translateY(-2px);
}

.location-name { font-size: 15px; font-weight: 600; margin-bottom: 4px; }
.location-alias { font-size: 12px; color: var(--primary); margin-bottom: 8px; }
.location-address { font-size: 12px; color: var(--muted); margin-bottom: 12px; }

/* stare klasy – zachowane dla kompatybilności */
.location-stats { display: flex; gap: 16px; }
.loc-stat { text-align: center; }
.loc-stat-value { font-size: 18px; font-weight: 700; color: var(--text); }
.loc-stat-label { font-size: 11px; color: var(--muted); }

/* Nowy układ karty: dwa wiersze (Google Maps + Okres) */
.loc-stats-block { margin-top: 10px; }

.loc-ever-row {
  display: flex; align-items: baseline; gap: 5px;
  flex-wrap: wrap;
}
.loc-ever-rating {
  font-size: 19px; font-weight: 800; color: var(--text); letter-spacing: -.01em;
}
.loc-ever-dot { font-size: 16px; color: #cbd5e0; font-weight: 400; }
.loc-ever-count { font-size: 15px; font-weight: 600; color: var(--text); }
.loc-ever-lbl {
  font-size: 10px; color: var(--muted); font-weight: 500;
  text-transform: uppercase; letter-spacing: .04em; margin-top: 2px;
}

.loc-period-divider {
  border-top: 1px solid var(--border);
  margin: 8px 0 6px;
}
.loc-period-row {
  display: flex; align-items: center; justify-content: space-between; gap: 8px; flex-wrap: wrap;
}
.loc-period-data { font-size: 12px; color: var(--muted); font-weight: 500; }
.loc-period-lbl  { font-size: 10px; color:var(--muted,#a0aec0); white-space: nowrap; }

/* ── Harmonogram ─────────────────────────────────────────────── */

.run-log {
  /* Konsola uruchomień — tło jest CELOWO ciemne w OBU motywach (styl
     terminala), więc tekst NIE może korzystać z `--muted`: w motywie
     jasnym to ciemny atrament, który zniknąłby na czarnym tle. */
  background: #1a202c;
  color: #cbd5e0;
  border-radius: 8px;
  padding: 16px;
  font-family: 'Menlo', 'Monaco', 'Consolas', monospace;
  font-size: 12px;
  max-height: 400px;
  overflow-y: auto;
  line-height: 1.6;
}

.run-log .log-error { color: #fc8181; }
.run-log .log-time  { color: #68d391; }

/* ── Filtry ──────────────────────────────────────────────────── */

.filters {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 20px;
}

.filter-select {
  padding: 8px 12px;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  font-size: 13px;
  color: var(--text);
  background: rgba(255,255,255,.7);
  outline: none;
}

.filter-select:focus {
  border-color: rgba(66,133,244,.45);
  box-shadow: 0 0 0 3px rgba(66,133,244,.1);
}

/* ── Multi-ocena: kwadraciki przełączane (1–5★) ──────────────── */
.rating-filter { display: inline-flex; gap: 4px; align-items: center; }
.rating-sq {
  min-width: 40px;
  padding: 8px 6px;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255,255,255,.7);
  color: var(--text);
  font-size: 12px;
  font-weight: 700;
  cursor: pointer;
  transition: background .12s ease, border-color .12s ease, color .12s ease, box-shadow .12s ease;
}
.rating-sq:hover { border-color: rgba(66,133,244,.45); }
.rating-sq.active { color: #fff; border-color: transparent; box-shadow: 0 2px 6px rgba(0,0,0,.14); }
/* kolory aktywnego kwadracika wg oceny (spójne z rozkładem ocen) */
.rating-sq.active[data-rating="5"] { background: #1B8A3E; }
.rating-sq.active[data-rating="4"] { background: #5CB85C; }
.rating-sq.active[data-rating="3"] { background: #F0AD00; }
.rating-sq.active[data-rating="2"] { background: #E8711A; }
.rating-sq.active[data-rating="1"] { background: #D9230F; }

/* ── Podgląd opinii w modalu odpowiedzi ──────────────────────── */
/* Układ celowo ZWARTY: autor, gwiazdki, sentyment i data w JEDNYM wierszu, treść
   opinii z własnym scrollem. Każdy zaoszczędzony tu piksel to piksel, o który
   stopka (Anuluj / Wyślij odpowiedź) jest bliżej paska szablonów. */
.reply-preview {
  background: var(--surface-sunken,#f8fafc);
  border-radius: 8px;
  padding: 9px 11px;
  margin-bottom: 8px;
  font-size: 13px;
}
.reply-preview-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 5px; }
.reply-preview-head strong { color: var(--text); font-size: 13px; }
.reply-preview-stars { font-size: 13px; }
.reply-preview-meta { font-size: 11px; color:var(--muted,#718096); margin-left: auto; }
.reply-sentiment-chip {
  font-size: 11px;
  font-weight: 700;
  padding: 2px 7px;
  border-radius: 999px;
  border: 1px solid;
  white-space: nowrap;
}
.reply-preview-comment {
  font-size: 13px;
  color: var(--text);
  line-height: 1.5;
  white-space: pre-wrap;
  max-height: 92px;
  overflow-y: auto;
}
.reply-preview-empty { color:var(--muted,#a0aec0); font-style: italic; }

/* ── Paginacja ───────────────────────────────────────────────── */

.pagination {
  display: flex;
  gap: 4px;
  align-items: center;
  justify-content: center;
  margin-top: 20px;
}

.pagination button {
  padding: 6px 12px;
  border: 1px solid var(--border);
  background: var(--surface);
  border-radius: 6px;
  cursor: pointer;
  font-size: 13px;
  color: var(--text);
  transition: background .15s;
}

.pagination button:hover      { background: var(--bg); }
.pagination button.active     { background: var(--primary); color: #fff; border-color: var(--primary); }
.pagination button:disabled   { opacity: .4; cursor: not-allowed; }

/* ── Empty state ─────────────────────────────────────────────── */

.empty-state {
  text-align: center;
  padding: 60px 20px;
  color: var(--muted);
}

.empty-state-icon { font-size: 48px; margin-bottom: 12px; }
.empty-state h3   { font-size: 16px; margin-bottom: 6px; color: var(--text); }

/* ── Analityka ───────────────────────────────────────────────── */


.sortable { cursor: pointer; user-select: none; }
.sortable:hover { color: var(--primary); }
.sort-ic { display: inline-block; margin-left: 4px; opacity: .5; }
.sortable:hover .sort-ic { opacity: 1; }

.top-tile { transition: box-shadow .15s; }
.top-tile:hover { box-shadow: 0 6px 20px rgba(0,0,0,.1); }

/* ── Import danych ───────────────────────────────────────────── */

.drop-zone {
  border: 2px dashed var(--border);
  border-radius: var(--radius);
  padding: 40px 20px;
  text-align: center;
  cursor: pointer;
  transition: border-color .2s, background .2s;
  color: var(--muted);
}

.drop-zone:hover, .drop-zone.drag-over {
  border-color: var(--primary);
  background: rgba(74,108,247,.04);
  color: var(--primary);
}

.star-input {
  display: flex;
  gap: 6px;
  margin-top: 4px;
}

.star-btn {
  font-size: 28px;
  color: #e2e8f0;
  cursor: pointer;
  transition: color .1s, transform .1s;
  line-height: 1;
}

.star-btn:hover, .star-btn.hover   { color: #f6c90e; transform: scale(1.15); }
.star-btn.active                   { color: #f6c90e; }

.import-summary {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
}

.import-sum-item {
  padding: 10px 16px;
  border-radius: 8px;
  font-size: 14px;
}

.sum-ok   { background: #f0fff4; color: #276749; }
.sum-skip { background:rgba(245,158,11,.14); color:var(--warn-fg,#92400e); }
.sum-err  { background:rgba(239,68,68,.12); color:var(--err-fg,#c53030); }

/* ── Badge: imported source ──────────────────────────────────── */

.source-badge {
  font-size: 10px;
  padding: 2px 6px;
  border-radius: 10px;
  background: #ebf8ff;
  color: #2b6cb0;
  font-weight: 600;
  vertical-align: middle;
  margin-left: 4px;
}

/* Znacznik opinii zawierającej zdjęcie/film (reviewMediaItems). Wyróżniony
   bursztynem, by łatwo wyłapać potencjalnie niepożądane zdjęcie. */
.media-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 12px;
  background:rgba(245,158,11,.14);
  color: #b45309;
  border: 1px solid #fcd34d;
  white-space: nowrap;
}

/* Znacznik opinii edytowanej przez klienta po opublikowaniu (sync wykrywa różnicę
   rating/comment vs to, co mamy zapisane — patrz previous_rating/previous_comment). */
.edited-badge {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 12px;
  background: #eef2ff;
  color: #4338ca;
  border: 1px solid #c7d2fe;
  white-space: nowrap;
}

/* Kategoria wkładu AI w wysłaną odpowiedź ([v2.06]) — trzy warianty koloru, żeby
   różnicę było widać na pierwszy rzut oka bez czytania tooltipa. `escalated` dostaje
   najbardziej ostrzegawczy kolor (bursztyn, jak media-badge) celowo: to kategoria,
   na której użytkownikowi zależało najbardziej — ma rzucać się w oczy. */
.ai-outcome-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 12px;
  white-space: nowrap;
}
.ai-outcome-badge.ai-outcome-full     { background: rgba(22,163,74,.12);  color: #15803d; border: 1px solid rgba(22,163,74,.35); }
.ai-outcome-badge.ai-outcome-assisted { background: #eef2ff;              color: #4338ca; border: 1px solid #c7d2fe; }
.ai-outcome-badge.ai-outcome-escalated{ background: rgba(217,119,6,.14);  color: #92400e; border: 1px solid #fcd34d; }

/* Znacznik heurystycznej kategoryzacji pochodzenia autora (patrz classifyReviewerOrigin
   w services/google-business.js) — czysto informacyjny, do zbierania danych. */
.origin-badge {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  font-weight: 700;
  padding: 2px 8px;
  border-radius: 12px;
  white-space: nowrap;
}
.origin-badge.origin-pl      { background: rgba(74,108,247,.12);  color: #3949ab; border: 1px solid rgba(74,108,247,.35); }
.origin-badge.origin-foreign { background: rgba(232,113,26,.14);  color: #b45309; border: 1px solid rgba(232,113,26,.35); }
html.theme-dark .origin-badge.origin-pl      { background: rgba(74,108,247,.18);  color: #a5b4fc; }
html.theme-dark .origin-badge.origin-foreign { background: rgba(232,113,26,.18);  color: #fdba74; }

/* Czerwona flaga opinii — ustawiana tylko podczas aktywnej sesji pracy (Workflow).
   Domyślnie wyszarzona/przezroczysta; .flagged = pełny czerwony akcent; .disabled =
   brak aktywnej sesji, przycisk widoczny tylko jako informacja (kursor default). */
.flag-btn {
  border: none;
  background: transparent;
  font-size: 15px;
  line-height: 1;
  padding: 2px 4px;
  cursor: pointer;
  filter: grayscale(1);
  opacity: 0.35;
  transition: opacity .15s, filter .15s, transform .1s;
}
.flag-btn:hover { opacity: 0.85; transform: scale(1.08); }
/* [v2.33] Stan „oflagowana" jest teraz WYRAŹNY (czerwona pigułka z etykietą),
   a nie samą przyciemnioną ikoną — to znacznik „wróć do tego", więc ma być
   widoczny z odległości ekranu, nie po najechaniu myszą. Klasa .disabled
   zniknęła razem z wymogiem aktywnej sesji (flagować można zawsze). */
.flag-btn.flagged {
  filter: none;
  opacity: 1;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .01em;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c;
  border: 1px solid #fca5a5;
}
.flag-btn.flagged:hover { transform: none; background: #fecaca; }

/* Rejestr opinii usuniętych z Google */
.badge-deleted {
  background: #fdf2f2;
  color: #b91c1c;
  border: 1px solid #f3c4c4;
}
.deleted-card { opacity: .92; border-left: 3px solid #e3a3a3; }
.deleted-card .review-meta { font-size: 12px; margin-top: 8px; }

/* ═══════════════════════════════════════════════════════════════════
   RESPONSYWNOŚĆ + CHOWANY PANEL BOCZNY
   Dwa niezależne stany, oba na <html> (nadawane synchronicznie w <head>,
   żeby nie migotało — wzorzec z [v1.05]):
     .sb-collapsed — desktop: pasek zwinięty do samych ikon (stan zapamiętany)
     .sb-open      — mobile: szuflada wysunięta nad treść (stan chwilowy)
   Wydajność: szuflada jedzie na `transform` (kompozycja GPU, zero layoutu),
   zwijanie na desktopie zmienia szerokość jednego kontenera przez krótkie .2s.
   Przy `prefers-reduced-motion` obie animacje znikają.
   ═══════════════════════════════════════════════════════════════════ */

/* Pasek i treść MUSZĄ jechać dokładnie tą samą krzywą i przez ten sam czas.
   Wcześniej było `width .2s ease` vs `transform .24s cubic-bezier(...)`, więc
   krawędź panelu i krawędź treści rozjeżdżały się w trakcie ruchu (treść
   „doganiała" panel) — to główny powód, dla którego zwijanie wyglądało
   niechlujnie. Jedna zmienna = jedna prawda o czasie animacji. */
:root { --sb-ease: cubic-bezier(.32,.72,0,1); --sb-dur: .26s; }

.sidebar      { transition: width var(--sb-dur) var(--sb-ease), transform var(--sb-dur) var(--sb-ease); }
.main-content { transition: margin-left var(--sb-dur) var(--sb-ease); }

/* Rezerwacja miejsca na pionowy pasek przewijania. Bez tego pojawienie się lub
   zniknięcie scrollbara (typowe, gdy zwinięcie panelu zmienia wysokość treści)
   przesuwa CAŁY układ o ~15 px w bok — dokładnie ten „skok", który wygląda jak
   niestabilny obszar roboczy. */
html { scrollbar-gutter: stable; }

/* W trakcie animacji panelu treść nie może wygenerować poziomego paska
   przewijania z chwilowego, przejściowego przepełnienia — inaczej pasek mruga
   i strona podskakuje w pionie. `clip` (nie `hidden`) nie tworzy scrollportu,
   więc nie psuje `position: sticky` w środku. */
html.sb-animating .main-content { overflow-x: clip; }
html.sb-animating .main-content,
html.sb-animating .sidebar      { will-change: margin-left, width; }

/* ── Przycisk zwijania (desktop) ─────────────────────────────── */
.sb-toggle {
  position: absolute; top: 18px; right: 12px;
  width: 28px; height: 28px; padding: 0;
  display: flex; align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 8px;
  background: rgba(255,255,255,.72); color: var(--muted);
  cursor: pointer; font-size: 14px; line-height: 1;
  transition: background .15s, color .15s;
}
.sb-toggle:hover { background:var(--surface-solid,#fff); color: var(--primary); }
/* Glif «/» z CSS, nie z JS: przycisk istnieje statycznie w HTML i musi być
   poprawny już przy pierwszym malowaniu, a klasa `sb-collapsed` jest nadawana
   inline-skryptem w <head> ([v1.83]). */
.sb-toggle::before { content: "\00AB"; }
html.sb-collapsed .sb-toggle::before { content: "\00BB"; }
.sidebar-header { position: relative; }

/* Elementy powłoki mobilnej istnieją w DOM na każdej szerokości (buduje je JS
   raz), ale POZA breakpointem mobilnym muszą być niewidoczne — bez tej reguły
   na desktopie wyrenderowałyby się jako zwykłe bloki z treścią. */
.m-appbar, .m-tabbar, .m-filters-toggle { display: none; }

/* ── Hamburger (mobile) ─────────────────────────────────────── */
.sb-burger {
  display: none;
  position: fixed; top: 12px; left: 12px; z-index: 130;
  width: 42px; height: 42px; padding: 0;
  align-items: center; justify-content: center;
  border: 1px solid var(--border); border-radius: 12px;
  background: rgba(255,255,255,.9);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: 0 2px 10px rgba(16,24,40,.12);
  color: var(--text); font-size: 18px; line-height: 1; cursor: pointer;
}
.sb-backdrop {
  display: none; position: fixed; inset: 0; z-index: 99;
  background: rgba(15,23,42,.44);
  opacity: 0; transition: opacity .24s ease;
}

/* ── Stan zwinięty (desktop) ────────────────────────────────── */
html.sb-collapsed { --sidebar-w: 76px; }
/* Etykiety pozycji nawigacji to gołe węzły tekstowe (bez własnego elementu),
   więc chowamy je zerową wielkością czcionki i przywracamy ją samej ikonie —
   to jedyny sposób bez przepisywania markupu 16 stron. */
html.sb-collapsed .nav-link  { font-size: 0; gap: 0; justify-content: center; padding: 11px 0; }
html.sb-collapsed .nav-icon  { font-size: 18px; }
html.sb-collapsed .app-subtitle,
html.sb-collapsed .user-info > div,
html.sb-collapsed .app-version { display: none; }
html.sb-collapsed .app-title { font-size: 0; text-align: center; }
html.sb-collapsed .app-title::before { content: "GMB"; font-size: 12px; font-weight: 800; letter-spacing: .04em; }
html.sb-collapsed .sidebar-header { padding-left: 12px; padding-right: 12px; text-align: center; }
html.sb-collapsed .sb-toggle { position: static; margin: 10px auto 0; }
html.sb-collapsed .user-info { justify-content: center; }
html.sb-collapsed .logout-btn { font-size: 0; padding: 10px 0; justify-content: center; }
html.sb-collapsed .logout-btn::before { content: "⏻"; font-size: 15px; }
html.sb-collapsed .sidebar-footer { padding-left: 10px; padding-right: 10px; }

/* ── Tablet: zwiń automatycznie, oszczędź szerokość ─────────── */
@media (max-width: 1180px) and (min-width: 901px) {
  :root { --sidebar-w: 76px; }
  .nav-link  { font-size: 0; gap: 0; justify-content: center; padding: 11px 0; }
  .nav-icon  { font-size: 18px; }
  .app-subtitle, .user-info > div, .app-version { display: none; }
  .app-title { font-size: 0; text-align: center; }
  .app-title::before { content: "GMB"; font-size: 12px; font-weight: 800; letter-spacing: .04em; }
  .sb-toggle { display: none; }  /* na tablecie zwinięcie jest wymuszone układem */
  .logout-btn { font-size: 0; padding: 10px 0; justify-content: center; }
  .logout-btn::before { content: "⏻"; font-size: 15px; }
}


/* ── Pasek postępu synchronizacji ────────────────────────────── */
.sync-progress {
  background:var(--surface-solid,#fff);
  border: 1px solid #e2e8f0;
  border-radius: 10px;
  padding: 14px 18px;
  margin-top: 12px;
  animation: fadeIn .2s ease;
}
.sync-progress-track {
  height: 8px;
  background:var(--surface-sunken,#edf2f7);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 8px;
}
.sync-progress-fill {
  height: 100%;
  background: linear-gradient(90deg, #4A6CF7, #7B63F7);
  border-radius: 4px;
  transition: width .6s ease;
  min-width: 3%;
}
.sync-progress-text {
  font-size: 12px;
  color:var(--muted,#718096);
  display: flex;
  justify-content: space-between;
}
.sync-progress-text .pct { font-weight: 600; color: #4A6CF7; }
@keyframes fadeIn { from { opacity:0; transform:translateY(-4px) } to { opacity:1; transform:none } }

/* ── Powiadomienie tło (auto-sync) ───────────────────────────── */
.bg-notif {
  position: fixed;
  bottom: 24px;
  right: 24px;
  background: rgba(255,255,255,.8);
  backdrop-filter: blur(20px) saturate(170%);
  -webkit-backdrop-filter: blur(20px) saturate(170%);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 11px 16px;
  box-shadow: 0 6px 24px rgba(0,0,0,.10);
  font-size: 13px;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 10px;
  z-index: 2000;
  transform: translateY(80px);
  opacity: 0;
  transition: transform .3s ease, opacity .3s ease;
  pointer-events: none;
}
.bg-notif.show { transform: translateY(0); opacity: 1; }
.bg-notif .bn-icon { font-size: 15px; }
.bg-notif .bn-text { flex: 1; }

/* ── Mały przycisk ikony na kartach wizytówek ─────────────────── */
.btn-icon-sm {
  background: none;
  border: 1px solid #e2e8f0;
  border-radius: 6px;
  color:var(--muted,#a0aec0);
  cursor: pointer;
  font-size: 13px;
  padding: 3px 7px;
  line-height: 1;
  transition: background .15s, color .15s, border-color .15s;
  flex-shrink: 0;
}
.btn-icon-sm:hover:not(:disabled) {
  background: #f0f5ff;
  color: #4A6CF7;
  border-color: #4A6CF7;
}
.btn-icon-sm:disabled { opacity: .45; cursor: not-allowed; }

/* ── Dezaktywuj wizytówkę (czerwony hover na ikonie) ─────────── */
.btn-deactivate:hover:not(:disabled) {
  background:rgba(239,68,68,.12) !important;
  color:var(--err-fg,#c53030) !important;
  border-color: #fc8181 !important;
}

/* ── Badge lokalizacji w opiniach ────────────────────────────── */
.loc-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  border-radius: 10px;
  font-size: 10px;
  font-weight: 600;
  background:rgba(59,110,240,.14);
  color: #2b6cb0;
  border: 1px solid #bee3f8;
  vertical-align: middle;
}

/* ── Link do wizytówki na Mapach (tylko przy opinii oflagowanej) ─ */
.maps-link-btn {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--accent-text, var(--primary));
  text-decoration: none;
  vertical-align: middle;
}
.maps-link-btn:hover { text-decoration: underline; }

/* ── Info paginacji w opiniach ───────────────────────────────── */
.pagination-info {
  font-size: 12px;
  color:var(--muted,#718096);
  margin: 4px 0 8px;
  text-align: center;
}

/* ── Panel postępu synchronizacji ────────────────────────────── */
.sync-panel {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 16px 18px 14px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
  animation: fadeSlideDown .25s ease;
}
@keyframes fadeSlideDown {
  from { opacity: 0; transform: translateY(-8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.sync-panel-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}
.sync-panel-title {
  font-weight: 600;
  font-size: 14px;
  margin-right: 10px;
}
.sync-panel-count {
  font-size: 12px;
  color: var(--muted);
}
.sync-panel-bar-wrap {
  height: 6px;
  background: rgba(0,0,0,.07);
  border-radius: 4px;
  overflow: hidden;
  margin-bottom: 12px;
}
.sync-panel-bar {
  height: 100%;
  background: linear-gradient(90deg, var(--primary), #7c96fa);
  border-radius: 4px;
  transition: width .4s ease;
}

/* Grid listy wizytówek w panelu */
.sync-panel-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 5px;
  max-height: 260px;
  overflow-y: auto;
}
.sq-item {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 4px 6px;
  border-radius: 6px;
  font-size: 12px;
  background:var(--surface-sunken,#f8fafc);
  border: 1px solid #e8edf4;
}
.sq-icon {
  font-size: 13px;
  width: 18px;
  text-align: center;
  flex-shrink: 0;
  font-style: normal;
}
.sq-done    { color: #38a169; }
.sq-running { color: var(--primary); }
.sq-error   { color: #e53e3e; }
.sq-pending { color:var(--muted,#a0aec0); }
.sq-name {
  flex: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  color: var(--text);
}
.sq-extra {
  font-size: 10px;
  color: var(--muted);
  flex-shrink: 0;
  max-width: 90px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sq-error-txt {
  color:var(--err-fg,#c53030);
}

/* ── Pasek wyboru zakresu dat (Dashboard) ────────────────────── */
.date-range-bar {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  padding: 10px 14px;
  margin-bottom: 16px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  box-shadow: var(--shadow);
}
.drb-custom {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.drb-lbl {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}
.drb-date-input {
  padding: 5px 9px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12px;
  background: var(--surface);
  color: var(--text);
  outline: none;
  cursor: pointer;
}
.drb-date-input:focus { border-color: var(--primary); }

/* ── Kolejność wizytówek w raporcie (drag & drop) ────────────── */
.ro-list {
  display: flex;
  flex-direction: column;
  gap: 5px;
  max-height: 520px;
  overflow-y: auto;
}
.ro-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  background:var(--surface-sunken,#f8fafc);
  border: 1px solid var(--border);
  border-radius: 8px;
  cursor: default;
  transition: background .15s, box-shadow .15s;
  user-select: none;
}
.ro-item.ro-drag-over {
  background:rgba(59,110,240,.14);
  border-color: var(--primary);
  box-shadow: 0 0 0 2px rgba(74,108,247,.2);
}
.ro-handle {
  color:var(--muted,#a0aec0);
  cursor: grab;
  font-size: 16px;
  flex-shrink: 0;
  padding: 0 2px;
}
.ro-handle:active { cursor: grabbing; }
.ro-idx {
  font-size: 11px;
  color: var(--muted);
  width: 22px;
  flex-shrink: 0;
  text-align: right;
}
.ro-name {
  flex: 1;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.ro-input {
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: 6px;
  font-size: 12px;
  width: 180px;
  flex-shrink: 0;
  background: var(--surface);
  color: var(--text);
  outline: none;
}
.ro-input:focus { border-color: var(--primary); }

/* ── Zakładki stron (Raporty) — ten sam język co `.subtabs` [alfa 0.335] ──
   Jedna definicja dla obu klas: segmentowa taca + pigułka (patrz `.subtabs`
   niżej, sekcja „Pod-zakładki"). `.page-tab-active` to historyczna nazwa
   stanu aktywnego w Raportach — zostaje, żeby nie ruszać `showReportTab`. */
.page-tabs { margin-bottom: 20px; }

/* ── Tabela historii raportów ────────────────────────────────── */
.hist-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.hist-table th {
  text-align: left;
  padding: 8px 12px;
  color: var(--muted);
  font-weight: 600;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .04em;
  border-bottom: 2px solid var(--border);
}
.hist-table td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.hist-table tr:last-child td { border-bottom: none; }
.hist-table tr:hover td { background:var(--surface-sunken,#f8fafc); }

/* ── Dropdown szablonów odpowiedzi w modalu opinii ────────────── */
.reply-tpl-bar {
  display: flex;
  gap: 8px;
  margin-bottom: 14px;
  flex-wrap: wrap;
}
.tpl-drop-wrap {
  position: relative;
}
.tpl-btn {
  white-space: nowrap;
}
.tpl-drop-list {
  display: none;
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 240px;
  background:var(--surface-solid,#fff);
  border: 1px solid #e2e8f0;
  border-radius: 8px;
  box-shadow: 0 6px 24px rgba(0,0,0,.13);
  z-index: 1100;
  max-height: 260px;
  overflow-y: auto;
}
.tpl-drop-list.open {
  display: block;
}
.tpl-drop-item {
  padding: 10px 14px;
  font-size: 13px;
  cursor: pointer;
  color:var(--text,#2d3748);
  border-bottom: 1px solid #f7fafc;
  transition: background .1s;
}
.tpl-drop-item:last-child { border-bottom: none; }
.tpl-drop-item:hover {
  background: #eef2ff;
  color: #4A6CF7;
}
.tpl-drop-empty {
  padding: 10px 14px;
  font-size: 12px;
  color:var(--muted,#a0aec0);
  font-style: italic;
}

/* ── Sekcje szablonów grzecznościowych w Ustawieniach ─────────── */
.tpl-section {
  border: 1px solid #e2e8f0;
  border-radius: 10px;
  margin-bottom: 10px;
  overflow: hidden;
}
.tpl-section-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 11px 16px;
  background:var(--surface-sunken,#f8fafc);
  cursor: pointer;
  font-weight: 600;
  font-size: 14px;
  user-select: none;
  transition: background .15s;
}
.tpl-section-header:hover {
  background: #eef2ff;
}
.tpl-section-toggle {
  color:var(--muted,#718096);
  font-size: 12px;
}
.tpl-section-body {
  padding: 0;
}
.tpl-section-body > .t-coll-inner { padding: 14px 16px 16px; }

/* ── KPI tiles (analytics, location-analytics) ───────────────── */
.kpi-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
  margin-bottom: 20px;
}
@media (max-width: 1300px) { .kpi-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width:  768px) { .kpi-grid { grid-template-columns: repeat(2, 1fr); } }

/* Ten sam kafelek co .stat-card (szkło, promień karty) — do [alfa 0.350] miał
   kolorową górną krawędź, mniejszy promień i podskok na hover, czyli osobny
   język z ery GMB Managera. */
.kpi-tile {
  background: var(--surface);
  backdrop-filter: var(--blur);
  -webkit-backdrop-filter: var(--blur);
  border: 1px solid var(--border);
  border-radius: var(--radius-card);
  box-shadow: var(--shadow);
  padding: 20px;
}

.kpi-icon {
  width: 42px; height: 42px;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 21px;
  margin-bottom: 14px;
}

.kpi-value {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -.6px;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1;
  margin-bottom: 5px;
}

.kpi-label {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .5px;
  color: var(--muted);
  margin-bottom: 8px;
}

.kpi-delta {
  font-size: 12px;
  font-weight: 600;
  display: flex;
  align-items: center;
  gap: 3px;
  flex-wrap: wrap;
}
.kpi-delta.up   { color: var(--success); }
.kpi-delta.down { color: var(--danger-dark); }
.kpi-delta.flat { color: var(--muted); font-weight: 400; }

/* ── GBP Performance notice ──────────────────────────────────── */
.perf-notice {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 16px;
  background:rgba(245,158,11,.14);
  border: 1px solid #fde68a;
  border-radius: 8px;
  font-size: 13px;
  color:var(--warn-fg,#92400e);
  margin-bottom: 16px;
  line-height: 1.5;
}

/* Wariant informacyjny (nie błąd) — np. dane jeszcze niedostępne z powodu
   opóźnienia raportowania Google, a nie awarii/braku uprawnień. */
.perf-notice.info {
  background: #eff6ff;
  border-color: #bfdbfe;
  color: #1e40af;
}

/* ── GBP Performance — pasek miesięcy ─────────────────────── */
.perf-month-strip {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding: 4px 2px 8px;
  scrollbar-width: thin;
  scrollbar-color: rgba(0,0,0,.15) transparent;
  -webkit-overflow-scrolling: touch;
}
.perf-month-strip::-webkit-scrollbar { height: 4px; }
.perf-month-strip::-webkit-scrollbar-thumb { background: rgba(0,0,0,.15); border-radius: 2px; }

.perf-month-chip {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 6px 10px;
  border-radius: 10px;
  border: 1px solid var(--border-soft);
  background: var(--surface);
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  cursor: pointer;
  line-height: 1.2;
  transition: background .12s, color .12s, border-color .12s, box-shadow .12s;
  white-space: nowrap;
}
.perf-month-chip:hover:not(.active) {
  background: rgba(59,110,240,.08);
  border-color: rgba(59,110,240,.3);
  color: var(--primary);
}
.perf-month-chip.active {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  box-shadow: 0 2px 8px rgba(59,110,240,.35);
}
.perf-chip-year {
  font-size: 10px;
  font-weight: 400;
  opacity: .75;
  margin-top: 1px;
}
.perf-month-chip.active .perf-chip-year { opacity: .85; }

/* Horyzont paska miesięcy (3/6/12/24) — czysto kosmetyczne ograniczenie WIDOKU
   paska (renderPerfMonthStrip tnie już pobraną listę miesięcy do ostatnich N,
   bez nowego zapytania). Ta sama recepta wizualna co .basemap-toggle/.basemap-btn
   (pigułka na Pozycjach lokalnych), ale świadomie WŁASNE klasy — nie współdzielimy
   ich z inną, niepowiązaną funkcją. Cały wiersz jest chowany w JS, gdy dostępnych
   miesięcy jest za mało, by wybór horyzontu miał jakikolwiek sens (patrz
   location-analytics.js). */
.perf-horizon-row {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  margin-bottom: 6px;
}
.perf-horizon-lbl { font-size: 11px; color: var(--muted); }
.perf-horizon-toggle {
  display: inline-flex; gap: 2px; padding: 2px;
  background: rgba(0,0,0,.05); border-radius: 8px;
}
.perf-horizon-btn {
  border: none; background: transparent; cursor: pointer;
  font-size: 11px; font-weight: 600; color: var(--muted);
  padding: 4px 10px; border-radius: 6px; transition: background .15s, color .15s;
}
.perf-horizon-btn:hover  { color: var(--text); }
.perf-horizon-btn.active { background:var(--surface-solid,#fff); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.12); }

.perf-cache-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px solid var(--border-soft);
}
.perf-cache-note {
  font-size: 11px;
  color: var(--muted);
  line-height: 1.4;
}
.perf-cache-refresh {
  flex-shrink: 0;
  padding: 4px 10px;
  border-radius: 8px;
  border: 1px solid var(--border-soft);
  background: transparent;
  color: var(--muted);
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  transition: background .12s, color .12s, border-color .12s;
}
.perf-cache-refresh:hover:not(:disabled) {
  background: rgba(59,110,240,.08);
  border-color: rgba(59,110,240,.3);
  color: var(--primary);
}
.perf-cache-refresh:disabled { opacity: .5; cursor: default; }

/* ── YoY delta na KPI tile ──────────────────────────────────── */
.kpi-delta-yoy {
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
  margin-top: 4px;
  min-height: 15px;
}
.kpi-delta-yoy.yoy-up   { color: #7c3aed; }
.kpi-delta-yoy.yoy-down { color: #9f1239; }

/* ── Prognoza na cały miesiąc ──────────────────────────────── */
.perf-prediction {
  background: rgba(59,110,240,.05);
  border: 1px solid rgba(59,110,240,.18);
  border-radius: 12px;
  padding: 12px 16px;
  margin-bottom: 16px;
}
.perf-pred-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  font-size: 12px;
  font-weight: 600;
  color: var(--primary);
  margin-bottom: 8px;
}
.perf-pred-progress-label {
  font-size: 11px;
  font-weight: 500;
  color: var(--muted);
}
.perf-pred-bar-wrap {
  height: 6px;
  background: rgba(59,110,240,.15);
  border-radius: 3px;
  overflow: hidden;
  margin-bottom: 10px;
}
.perf-pred-bar {
  height: 100%;
  background: var(--primary);
  border-radius: 3px;
  transition: width .4s ease;
}
.perf-pred-values {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
@media (max-width: 768px) { .perf-pred-values { grid-template-columns: repeat(2, 1fr); } }

/* ── Frazy wyszukiwania (Business Profile Performance API) ─────── */
.kw-list { display: flex; flex-direction: column; gap: 6px; }
.kw-row { display: grid; grid-template-columns: minmax(0,1fr) 100px 44px; align-items: center; gap: 10px; }
.kw-term { font-size: 12.5px; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kw-bar-track { height: 6px; background: rgba(74,108,247,.12); border-radius: 3px; overflow: hidden; }
.kw-bar-fill { height: 100%; background: var(--primary,#4A6CF7); border-radius: 3px; }
.kw-count { font-size: 11px; font-weight: 700; color: var(--muted); text-align: right; }
.perf-pred-val {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  font-size: 11px;
  color: var(--muted);
}
.perf-pred-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.perf-pred-metric { font-size: 10px; text-align: center; }
.perf-pred-num {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
}


/* ══════════════════════════════════════════════════════════
   EDYCJA PROFILU — pełny system stylów
   ══════════════════════════════════════════════════════════ */

/* ── Nagłówek wizytówki ─────────────────────────────────── */
/* NIE wracaj tu do `var(--sidebar-bg)`. Gradient był tak napisany, gdy sidebar
   był CIEMNY (#1E2235); restyle [v1.60] zrobił z niego jasne szkło, więc biały
   tekst nagłówka wylądował na tle rgba(255,255,255,.58) = 1.03:1 (niewidoczny),
   a w paletach zielonych `--sidebar-bg` jest GRADIENTEM, przez co przeglądarka
   odrzucała całą deklarację i nagłówek nie miał tła w ogóle. Tło jest teraz
   własnym tokenem palety — patrz `--pe-header-bg` w locardly-brand.css. */
.pe-header {
  background: var(--pe-header-bg);
  border-radius: var(--radius);
  padding: 24px 28px;
  display: flex;
  align-items: center;
  gap: 20px;
  margin-bottom: 20px;
  box-shadow: var(--shadow);
}
.pe-logo-circle {
  width: 72px; height: 72px;
  border-radius: 50%;
  background: rgba(255,255,255,.12);
  border: 2px solid rgba(255,255,255,.2);
  overflow: hidden;
  flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
}
.pe-logo-circle img {
  width: 100%; height: 100%; object-fit: cover;
}
.pe-logo-initials {
  font-size: 22px; font-weight: 700; color: rgba(255,255,255,.82);
  letter-spacing: -1px;
}
.pe-header-body { flex: 1; min-width: 0; }
.pe-header-name {
  font-size: 20px; font-weight: 700; color: #fff;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  margin-bottom: 2px;
}
/* Hierarchia krycia na ciemnym nagłówku (nie spłaszczaj jej — każdy poziom
   niesie inną wagę informacji): nazwa 100% → metadane .82 → kategoria .72. */
.pe-header-category {
  font-size: 12px; font-weight: 600; color: rgba(255,255,255,.72);
  text-transform: uppercase; letter-spacing: .6px; margin-bottom: 10px;
}
.pe-header-meta {
  display: flex; flex-wrap: wrap; gap: 14px;
}
.pe-meta-item {
  display: flex; align-items: center; gap: 5px;
  font-size: 13px; color: rgba(255,255,255,.82);
}
.pe-meta-item svg { opacity: .8; flex-shrink: 0; }
.pe-meta-link { color: rgba(255,255,255,.82); text-decoration: none; }
.pe-meta-link:hover { color: #fff; text-decoration: underline; }
.pe-header-badges { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
.pe-cat-badge {
  background: rgba(255,255,255,.14);
  border: 1px solid rgba(255,255,255,.24);
  border-radius: 20px;
  padding: 3px 11px;
  font-size: 12px; color: rgba(255,255,255,.88);
}
.pe-cat-badge.primary {
  background: rgba(74,108,247,.35);
  border-color: rgba(74,108,247,.6);
  color: #fff;
}

/* ── Karta z zakładkami ─────────────────────────────────── */
.pe-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}
.pe-tablist {
  display: flex;
  border-bottom: 2px solid var(--border);
  background: var(--bg);
  padding: 0 4px;
  gap: 0;
}
.pe-tab-btn {
  padding: 13px 18px;
  font-size: 14px; font-weight: 500;
  color: var(--muted-strong);
  background: none; border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -2px;
  cursor: pointer;
  transition: color .15s, border-color .15s;
  white-space: nowrap;
}
.pe-tab-btn:hover { color: var(--text); }
.pe-tab-btn.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
  font-weight: 600;
}
.pe-pane { display: none; padding: 24px 28px; }
.pe-pane.active { display: block; }

/* ── Pasek akcji (zapis) ────────────────────────────────── */
.pe-actions {
  display: flex; align-items: center; gap: 14px;
  padding: 16px 28px;
  border-top: 1px solid var(--border);
  background: var(--bg);
}
#saveMsg {
  font-size: 13px;
  display: none;
}

/* ── Formularz informacji podstawowych ─────────────────── */
.pe-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.pe-desc-wrap { position: relative; }
.pe-char-count {
  position: absolute; bottom: 9px; right: 10px;
  font-size: 12px; color: var(--muted-strong);
  background: var(--surface); padding: 1px 4px;
  pointer-events: none;
}
.pe-kw-section { margin-top: 8px; }
.pe-kw-bar {
  display: flex; align-items: center; gap: 8px; margin-bottom: 8px;
}
.pe-kw-bar label { font-size: 13px; font-weight: 500; color: var(--muted-strong); white-space: nowrap; }
.pe-kw-bar input { flex: 1; }
.pe-kw-toggle {
  font-size: 13px; padding: 5px 11px;
  background: none; border: 1px solid var(--border);
  border-radius: 6px; cursor: pointer; color: var(--muted-strong);
  transition: all .15s; white-space: nowrap;
}
.pe-kw-toggle:hover { border-color: var(--primary); color: var(--primary); }
.pe-kw-preview {
  display: none;
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 12px 14px;
  font-size: 14px; line-height: 1.6; color: var(--text);
  min-height: 80px; max-height: 200px; overflow-y: auto;
  white-space: pre-wrap;
}
.pe-kw-preview.visible { display: block; }
.pe-kw-mark {
  background: #fef3c7;
  color:var(--warn-fg,#92400e);
  border-radius: 3px;
  padding: 0 2px;
  font-weight: 600;
}
.pe-readonly-field {
  background: var(--bg);
  color: var(--muted-strong);
  cursor: default;
}

/* .pe-bulk-label zostaje — uzywa go Ustawienia -> Godziny otwarcia (settings.html). */
.pe-bulk-label { font-size: 12px; font-weight: 700; color: var(--muted-strong); text-transform: uppercase; letter-spacing: .4px; }

/* hours.html — sama tabela dni, bez kolumny zbiorczego zaznaczania z profile-editor
   (stąd osobna klasa wiersza z inną liczbą kolumn grida; podklasy .pe-day-name/
   .pe-closed-label/.pe-times/.pe-sep są współdzielone i działają bez zmian). */
.ho-hours-row {
  display: grid;
  grid-template-columns: 140px 110px 1fr;
  align-items: center;
  gap: 12px;
  padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.ho-hours-row:last-child { border-bottom: none; }

.pe-import-bar {
  display: flex; align-items: center; gap: 8px;
  margin-top: 14px; padding-top: 14px;
  border-top: 1px dashed var(--border);
}
.pe-import-bar .btn-sm { font-size: 13px; }

/* ── Godziny specjalne ──────────────────────────────────── */
.pe-more-type {
  border: 1px solid var(--border);
  border-radius: 8px;
  margin-bottom: 12px;
  overflow: hidden;
}
.pe-more-type-header {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  background: var(--bg);
  cursor: pointer;
  user-select: none;
  transition: background .15s;
}
.pe-more-type-header:hover { background:var(--surface-sunken,#edf2f7); }
.pe-more-toggle { accent-color: var(--primary); width: 15px; height: 15px; cursor: pointer; }
.pe-more-type-name { font-size: 14px; font-weight: 600; color: var(--text); }
.pe-more-type-sub { font-size: 13px; color: var(--muted-strong); margin-left: auto; }
.pe-more-type-body {
  padding: 14px;
  border-top: 1px solid var(--border);
  display: none;
}
.pe-more-type-body.open { display: block; }

/* ── Kategorie ──────────────────────────────────────────── */
.pe-cat-section { margin-bottom: 20px; }
.pe-cat-section-title {
  font-size: 12px; font-weight: 700; color: var(--muted-strong);
  text-transform: uppercase; letter-spacing: .5px; margin-bottom: 10px;
}
.pe-primary-cat {
  display: flex; align-items: center; gap: 10px;
  padding: 12px 14px;
  background: rgba(74,108,247,.06);
  border: 1px solid rgba(74,108,247,.2);
  border-radius: 8px;
}
.pe-primary-cat-icon {
  width: 32px; height: 32px;
  background: rgba(74,108,247,.12);
  border-radius: 8px;
  display: flex; align-items: center; justify-content: center;
}
.pe-primary-cat-name { font-size: 14px; font-weight: 600; color: var(--text); }
.pe-primary-cat-id { font-size: 12px; color: var(--muted-strong); margin-top: 2px; }
.pe-additional-cats { display: flex; flex-wrap: wrap; gap: 8px; }
.pe-additional-cat {
  display: flex; align-items: center; gap: 6px;
  padding: 5px 12px;
  border: 1px solid var(--border);
  border-radius: 20px;
  font-size: 13px; color: var(--text);
  background: var(--surface);
}
.pe-cat-info-box {
  display: flex; gap: 10px;
  padding: 12px 14px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  border-radius: 8px;
  font-size: 14px; color: #1e40af; line-height: 1.55;
  margin-top: 16px;
}
.pe-empty-state {
  text-align: center; padding: 32px 20px;
  color: var(--muted-strong); font-size: 14px;
}
.pe-empty-state svg { margin-bottom: 10px; opacity: .4; }

/* ── Loader ─────────────────────────────────────────────── */
.pe-loader {
  display: none;
  text-align: center; padding: 56px 24px;
  color: var(--muted-strong); font-size: 14px;
}
.pe-spinner {
  width: 32px; height: 32px;
  border: 3px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: spin .7s linear infinite;
  margin: 0 auto 14px;
}

/* ═══════════════════════════════════════════════════════════
   Przejście między zakładkami — spokojne przenikanie treści
   ───────────────────────────────────────────────────────────
   PRZEJŚCIA MIĘDZYDOKUMENTOWE (View Transitions API) ZOSTAŁY
   ŚWIADOMIE USUNIĘTE. Powody, oba zgłoszone i potwierdzone:

   1. CZARNY ARTEFAKT. `.sidebar` miał `view-transition-name` ORAZ
      `backdrop-filter: blur(48px)`. Element z `backdrop-filter`
      przechwycony do snapshotu przejścia nie ma za sobą ŻADNEGO
      tła do rozmycia, więc przeglądarka renderuje go jako ciemny
      prostokąt. To samo dotyczy kart wewnątrz `.main-content`.
      Efekt widoczny tylko tam, gdzie szkło jest włączone (Mac/iOS) —
      na Windows/Androidzie blur i tak jest wygaszony ([v1.61]).

   2. ANIMACJA WYPRZEDZAŁA TREŚĆ. Snapshot pokazywał dopracowane
      wejście PUSTEJ powłoki nowej strony — dane lecą dopiero po
      `/api/...`, więc animacja kończyła się nad spinnerami.
      Ładna animacja czegoś, czego jeszcze nie ma, to obietnica bez
      pokrycia; lepiej spokojne przenikanie niż udawany pośpiech.

   3. Dodatkowo statyczny snapshot panelu bocznego PRZYKRYWAŁ prawdziwy
      panel, więc przejazd pigułki aktywnej zakładki był w tym oknie
      niewidoczny i „doskakiwał" na końcu.

   Ciągłość między stronami niesie teraz WYŁĄCZNIE pigułka aktywnej
   zakładki (`.nav-pill`, sterowana z `app.js`) — działa niezależnie
   od View Transitions i od przewinięcia panelu.
   NIE PRZYWRACAJ `@view-transition` bez zdjęcia `backdrop-filter`
   z elementów objętych `view-transition-name`.
   ═══════════════════════════════════════════════════════════ */

/* USUNIĘTE [v1.87]: `.main-content { animation: gmbContentIn }` — przenikanie
   treści OD ZERA przy KAŻDEJ zmianie zakładki.

   To był główny powód, dla którego nawigacja wyglądała jak przeładowanie całego
   interfejsu: przy każdym wejściu na stronę obszar roboczy startował od
   `opacity: 0`, więc paski filtrów, pod-zakładki i nagłówek dosłownie znikały na
   moment, po czym się wywoływały. Zmiana zakładki to NAJCZĘSTSZA akcja w tej
   aplikacji, a przy takiej częstotliwości ozdobny ruch przestaje być ozdobą i
   staje się opóźnieniem, które widać.

   Ciągłość między stronami niesie teraz WYŁĄCZNIE przejazd pigułki nawigacji
   ([v1.70]/[v1.85]) — jedyny element, który realnie łączy stan „przed" i „po".
   Panel boczny i treść pojawiają się od razu, w pierwszej klatce, bez fazy
   pośredniej. Nie przywracaj tu animacji wejścia: w aplikacji wielostronicowej
   „fade od zera" jest nieodróżnialny od przeładowania, bo nim JEST.  */

/* ═══════════════════════════════════════════════════════════
   Pozycje lokalne (rank tracker) — siatka / heatmapa / statystyki
   ═══════════════════════════════════════════════════════════ */

.rank-config .form-group { margin-bottom: 16px; }
.rank-config-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.rank-hint { font-size: 12px; color: var(--muted); margin-top: 6px; }

/* Radio jako pigułki */
.rank-radio-group { display: flex; gap: 8px; flex-wrap: wrap; }
.rank-radio { position: relative; cursor: pointer; }
.rank-radio input { position: absolute; opacity: 0; pointer-events: none; }
.rank-radio span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 52px;
  padding: 8px 14px;
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
  background: var(--surface);
  transition: all .15s ease;
}
.rank-radio input:checked + span {
  border-color: var(--primary);
  background: var(--primary);
  color: #fff;
}

/* Nagłówek panelu wyników */
.rank-results-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
}

/* Siatka */
.rank-grid-wrap {
  display: flex;
  justify-content: center;
  margin: 18px 0;
  overflow-x: auto;
}
.rank-grid {
  display: grid;
  gap: 6px;
}
.rank-cell {
  width: 52px;
  height: 52px;
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 15px;
  color: #fff;
  cursor: default;
  transition: transform .12s ease, box-shadow .12s ease;
}
.rank-cell:hover {
  transform: scale(1.12);
  box-shadow: 0 4px 14px rgba(0,0,0,.25);
  z-index: 2;
}
.rank-cell-center {
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--primary);
}
.rank-cell-center:hover {
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px var(--primary), 0 4px 14px rgba(0,0,0,.25);
}
/* Nie znaleziono — przygaszony tekst */
.rank-cell[data-pos=""] { color: #e5e7eb; }

/* Legenda */
.rank-legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
  font-size: 12px;
  color: var(--text);
  margin: 8px 0 20px;
}
.rank-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.rank-legend-dot {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  display: inline-block;
}

/* Pasek statystyk pod mapą */
.rank-stats {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  align-items: stretch;
  padding: 10px 16px 0;
}
.rank-stat {
  flex: 1 1 90px;
  max-width: 150px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 8px 10px;
  text-align: center;
  line-height: 1.2;
}
.rank-stat .rs-value { font-size: 20px; font-weight: 800; color: var(--text); }
.rank-stat .rs-label { font-size: 11px; color: var(--muted); margin-top: 3px; }
.rank-stat.rs-accent .rs-value { color: var(--primary); }
.rank-stat.rs-good   .rs-value { color: var(--success); }
.rank-stat.rs-bad    .rs-value { color: #ef4444; }
.rank-stats-note {
  flex: 1 1 100%;
  text-align: center;
  font-size: 12px;
  color: #b45309;
  background:rgba(245,158,11,.14);
  border: 1px solid #fde68a;
  border-radius: var(--radius);
  padding: 8px 10px;
}

/* Kafelki statystyk */
.rank-stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 12px;
  margin-top: 8px;
}
.rank-stat-tile {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 12px;
  text-align: center;
  background: var(--surface);
}
.rank-stat-tile .stat-value {
  font-size: 24px;
  font-weight: 800;
  color: var(--primary);
}
.rank-stat-tile .stat-label {
  font-size: 12px;
  color: var(--muted);
  margin-top: 4px;
}

/* Pasek postępu */
.rank-progress-bar {
  height: 4px;
  background: var(--border);
  border-radius: 4px;
  overflow: hidden;
  margin: 8px 0 6px;
}
.rank-progress-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 4px;
  transition: width .4s ease;
}

@media (max-width: 600px) {
  .rank-config-row { grid-template-columns: 1fr; }
}

/* ═══════════════════════════════════════════════════════════
   Pozycje lokalne v2 — układ 3-kolumnowy + mapa Leaflet
   ═══════════════════════════════════════════════════════════ */

.rank-main { padding: 0 !important; height: 100vh; overflow: hidden; }
.rank-layout {
  display: flex;
  height: calc(100vh - 0px);
  overflow: hidden;
}
.rank-left, .rank-right {
  overflow-y: auto;
  padding: 16px;
  background: var(--surface);
  flex-shrink: 0;
}
.rank-left  { width: 260px; border-right: 1px solid var(--border); }
.rank-right { width: 220px; border-left: 1px solid var(--border); }
.rank-map-col { flex: 1; display: flex; flex-direction: column; min-width: 0; }

.rank-section { margin-bottom: 22px; }
.rank-section-title {
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--muted);
  margin: 0 0 10px;
}
.rank-divider { height: 1px; background: var(--border); margin: 18px 0; }
.rank-empty { color: var(--muted); font-size: 13px; padding: 6px 0; list-style: none; }

/* Widok mapy musi PRZEDŁUŻAĆ łańcuch flexboxa kolumny — bez tego `#map { flex:1 }`
   nie ma się do czego odnieść, mapa zostaje na min-height, a pod nią zostaje pas
   pustego tła (dokładnie ten artefakt). `min-height:0` jest konieczne, bo domyślne
   `min-height:auto` elementu flex blokuje kurczenie się poniżej treści. */
#viewMap {
  flex: 1; min-height: 0;
  display: flex; flex-direction: column;
}
#viewHistory {
  flex: 1; min-height: 0;
  overflow-y: auto;
  padding: 18px;
}
#map { flex: 1; min-height: 320px; width: 100%; z-index: 1; }
#mapLegend { padding: 10px 16px; border-top: 1px solid var(--border); background: var(--surface); margin: 0; flex-shrink: 0; }
#rankStats { flex-shrink: 0; }

/* Przełącznik trybu */
.mode-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; }
.mode-btn {
  padding: 8px 16px;
  border: none;
  background: var(--surface);
  color: var(--text);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.mode-btn + .mode-btn { border-left: 1px solid var(--border); }
.mode-btn.active { background: var(--primary); color: #fff; }

/* Lista haseł */
.rank-keywords { list-style: none; margin: 0; padding: 0; }
.keyword-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px 12px;
  border-radius: 8px;
  cursor: pointer;
  margin-bottom: 4px;
  transition: background .12s ease;
}
.keyword-item:hover { background: var(--bg); }
.keyword-item.active { background: rgba(74, 108, 247, .12); }
.keyword-item.active .keyword-text { color: var(--primary); font-weight: 600; }
.keyword-text { flex: 1; font-size: 14px; }
.keyword-del {
  color: var(--muted);
  font-size: 12px;
  padding: 2px 6px;
  border-radius: 4px;
  opacity: 0;
  transition: opacity .12s ease, color .12s ease;
}
.keyword-item:hover .keyword-del, .competitor-item:hover .keyword-del { opacity: 1; }
.keyword-del:hover { color: var(--danger-dark); background: var(--bg); }

/* Lista konkurentów */
.rank-competitors { display: flex; flex-direction: column; gap: 2px; }
.competitor-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px;
  border-radius: 8px;
}
.competitor-item:hover { background: var(--bg); }
.competitor-dot { width: 12px; height: 12px; border-radius: 50%; flex-shrink: 0; }
.competitor-name { flex: 1; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.comp-check { width: 15px; height: 15px; cursor: pointer; flex-shrink: 0; }

/* Wybór koloru */
.color-picker { display: flex; gap: 10px; }
.color-swatch {
  width: 26px; height: 26px;
  border-radius: 50%;
  cursor: pointer;
  border: 3px solid transparent;
  transition: transform .12s ease, border-color .12s ease;
}
.color-swatch:hover { transform: scale(1.12); }
.color-swatch.selected { border-color: var(--text); }

/* Status wyszukiwania */
.search-status { margin-top: 14px; font-size: 12px; color: var(--muted); line-height: 1.5; }
.search-status a { color: var(--primary); text-decoration: none; }
.search-status a:hover { text-decoration: underline; }

/* Spinner */
.rank-spinner {
  display: inline-block;
  width: 12px; height: 12px;
  border: 2px solid var(--border);
  border-top-color: var(--primary);
  border-radius: 50%;
  animation: rankspin .7s linear infinite;
  vertical-align: middle;
  margin-right: 4px;
}
@keyframes rankspin { to { transform: rotate(360deg); } }

/* ── Pinezki i znaczniki na mapie (Leaflet divIcon) ───────────────────────────
   Pinezka: kropla z białym pierścieniem i miękkim cieniem — czytelna zarówno na
   jasnym (Positron), jak i ciemnym (Dark Matter) podkładzie CARTO. */
.rank-pin {
  width: 22px; height: 22px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  background: var(--pin, #f59e0b);
  border: 2.5px solid #fff;
  box-shadow: 0 3px 10px rgba(0,0,0,.32), 0 1px 2px rgba(0,0,0,.2);
}
.rank-pin-own { width: 26px; height: 26px; border-width: 3px; }

/* „Geogrid": okrągły żeton z numerem pozycji w punkcie pomiaru. Zastąpił
   prostokąty siatki — patrz komentarz w renderGrid (rank-tracker.js). */
.rank-dot-icon { background: none; border: none; }
.rank-dot {
  width: var(--dot-size, 38px); height: var(--dot-size, 38px);
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: var(--dot, #94a3b8);
  border: 2.5px solid rgba(255,255,255,.95);
  box-shadow: 0 3px 10px rgba(15,23,42,.28), 0 1px 3px rgba(15,23,42,.18);
  color: #fff;
  font-weight: 800;
  font-size: calc(var(--dot-size, 38px) * .40);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
  text-shadow: 0 1px 2px rgba(0,0,0,.28);
  transition: transform .14s ease, box-shadow .14s ease;
  cursor: default;
}
.rank-dot:hover { transform: scale(1.14); box-shadow: 0 6px 18px rgba(15,23,42,.34); z-index: 500; }
/* Punkt bez wyniku — wyciszony, żeby nie konkurował z realnymi pozycjami */
.rank-dot-none { opacity: .55; border-color: rgba(255,255,255,.75); font-weight: 600; }
/* Środek siatki = adres wizytówki: złoty pierścień zamiast osobnego prostokąta */
.rank-dot-center {
  box-shadow: 0 0 0 3.5px #f59e0b, 0 4px 14px rgba(15,23,42,.34);
}
/* Ciemny podkład: pierścienie znaczników przyciemnione, żeby nie „świeciły" */
.rank-map-dark .rank-dot { border-color: rgba(255,255,255,.42); }
.rank-map-dark .rank-pin { border-color: rgba(255,255,255,.7); }

/* Dyskretny pasek atrybucji (wymagany licencyjnie przez OSM/CARTO) */
#map .leaflet-control-attribution {
  background: rgba(255,255,255,.72);
  backdrop-filter: blur(6px);
  font-size: 10px; color: #64748b;
  border-radius: 6px 0 0 0; padding: 2px 6px;
}
.rank-map-dark .leaflet-control-attribution { background: rgba(15,23,42,.6); color: #cbd5e1; }
.rank-map-dark .leaflet-control-attribution a { color:var(--muted,#94a3b8); }

/* Kontrolki zoomu w stylu aplikacji (szkło) */
#map .leaflet-control-zoom a {
  background: rgba(255,255,255,.86);
  backdrop-filter: blur(8px);
  border: none; color: #334155;
  width: 32px; height: 32px; line-height: 32px;
  font-weight: 600;
}
#map .leaflet-control-zoom { border: none; border-radius: 10px; overflow: hidden; box-shadow: var(--shadow); }
#map .leaflet-control-zoom a:hover { background:var(--surface-solid,#fff); color: var(--primary); }

/* ── Górny pasek Pozycji lokalnych ───────────────────────────────────────────
   Jeden spójny nagłówek kolumny mapy: wiersz 1 = przełącznik widoku (zawsze),
   wiersz 2 = narzędzia mapy (chowane w widoku historii). Zastąpił .rank-map-bar,
   który był osobnym paskiem POD zakładkami — stąd wrażenie, że przyciski wiszą
   w powietrzu tuż pod krawędzią. */
.rank-topbar {
  flex-shrink: 0;
  display: flex; flex-direction: column; gap: 12px;
  padding: 14px 18px 12px;
  background: var(--surface);
  border-bottom: 1px solid var(--border);
}
.rank-topbar-tools { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.rank-kw { margin-left: auto; }

/* Segmentowany przełącznik widoku — czytelny kontrast wobec tła paska:
   nieaktywna zakładka ma własne, jaśniejsze tło i obramowanie, aktywna jest pełna. */
.rank-viewtabs {
  display: inline-flex; gap: 4px; padding: 4px;
  background: rgba(15,23,42,.055);
  border: 1px solid var(--border);
  border-radius: 12px;
  align-self: flex-start;
}
.rank-viewtab {
  display: inline-flex; align-items: center; gap: 7px;
  border: 1px solid transparent; background: transparent;
  border-radius: 9px; padding: 8px 16px;
  font-size: 13px; font-weight: 650; color: var(--muted);
  cursor: pointer; white-space: nowrap;
  transition: background .18s ease, color .18s ease, box-shadow .18s ease;
}
.rank-viewtab:hover { background: rgba(255,255,255,.75); color: var(--text); }
.rank-viewtab.active {
  background: var(--primary); color: #fff;
  box-shadow: 0 2px 8px rgba(59,110,240,.32);
}
.rank-viewtab.active:hover { background: var(--primary); color: #fff; }

.basemap-toggle {
  display: inline-flex; gap: 2px; padding: 2px;
  background: rgba(0,0,0,.05); border-radius: 8px;
}
.basemap-btn {
  border: none; background: transparent; cursor: pointer;
  font-size: 11px; font-weight: 600; color: var(--muted);
  padding: 4px 10px; border-radius: 6px; transition: background .15s, color .15s;
}
.basemap-btn:hover  { color: var(--text); }
.basemap-btn.active { background:var(--surface-solid,#fff); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.12); }

/* ── Historia pozycji ───────────────────────────────────────────────────────── */
.rank-history-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
.rank-history-chart { height: 340px; position: relative; }
.rank-history-table { margin-top: 16px; overflow-x: auto; }
.rank-htable { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.rank-htable th {
  text-align: left; padding: 8px 10px;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  color: var(--muted); border-bottom: 1px solid var(--border); white-space: nowrap;
}
.rank-htable td { padding: 8px 10px; border-bottom: 1px solid rgba(0,0,0,.05); font-variant-numeric: tabular-nums; white-space: nowrap; }
.rank-htable tbody tr:hover { background: rgba(59,110,240,.04); }

@media (max-width: 1100px) {
  .rank-left  { width: 220px; }
  .rank-right { width: 200px; }
}

/* ── Modal odpowiedzi — większy rozmiar ──────────────────────── */

.modal.modal-reply {
  max-width: 720px;
  /* Header/stopka PRZYPIĘTE, scrolluje się WYŁĄCZNIE treść między nimi — inaczej
     przy dłuższej opinii/wielu szablonach przyciski Anuluj/Wyślij odpowiedź
     wędrowały poza ekran razem z resztą (cały .modal był jednym kontenerem
     przewijania, patrz bazowa reguła .modal{overflow-y:auto}). */
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.modal.modal-reply .modal-header,
.modal.modal-reply .modal-footer {
  flex-shrink: 0;
}

.modal.modal-reply .modal-body {
  flex: 1;
  overflow-y: auto;
  min-height: 0;
}

.modal.modal-reply textarea.form-control {
  min-height: 104px;
  font-size: 14px;
  line-height: 1.55;
}

/* Kompresja pionu panelu odpowiedzi — cel: „Anuluj" i „Wyślij odpowiedź" ZAWSZE
   widoczne i tuż pod paskiem szablonów, bez przewijania w typowym przypadku.
   Wszystkie reguły mają specyficzność 2 klas + element, więc wygrywają z blokami
   mobilnym/motywu niezależnie od kolejności w pliku (patrz ostrzeżenia w dzienniku
   błędów o kolejności sekcji na końcu tego arkusza). */
.modal.modal-reply .modal-header { padding: 13px 20px 11px; }
.modal.modal-reply .modal-body   { padding: 13px 20px; }
.modal.modal-reply .modal-footer { padding: 11px 20px; }
.modal.modal-reply .quick-suggestions {
  padding: 7px 10px;
  margin-bottom: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.modal.modal-reply .quick-suggestions-label { margin-bottom: 0; flex-shrink: 0; }
.modal.modal-reply .reply-tpl-bar  { margin-bottom: 8px; }
.modal.modal-reply .form-group     { margin-bottom: 0; }
.modal.modal-reply .form-group .form-label { margin-bottom: 4px; }

/* ── Panel analityki opinii ──────────────────────────────────── */

.reviews-analytics {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  margin-bottom: 20px;
  overflow: hidden;
  box-shadow: var(--shadow);
}

.reviews-analytics-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 20px;
  cursor: pointer;
  user-select: none;
  border-bottom: 1px solid transparent;
  transition: background .15s, border-color .15s;
}

.reviews-analytics-header:hover {
  background:var(--surface-sunken,#f8fafc);
}

.reviews-analytics-header.open {
  border-bottom-color: var(--border);
}

.reviews-analytics-title {
  font-size: 14px;
  font-weight: 600;
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 8px;
}

.analytics-toggle-icon {
  font-size: 11px;
  color: var(--muted);
  transition: transform .2s;
}

.analytics-toggle-icon.rotated {
  transform: rotate(180deg);
}

.reviews-analytics-body {
  /* Panel jest ANIMATOREM wysokości (`.t-coll`), a nie pudełkiem: własny
     padding rysowałby się także przy zerowej wysokości i zostawiał martwy
     pas pod zwiniętą sekcją. Całe pudełko siedzi w `.t-coll-inner`.
     `display:none` ZOSTAJE jako stan sprzed montażu warstwy — gdyby
     `motion.js` się nie załadował, panel zachowuje się dokładnie jak dawniej. */
  padding: 0;
  display: none;
}
.reviews-analytics-body > .t-coll-inner { padding: 20px; }

.reviews-analytics-body.open {
  display: block;
}

.analytics-kpi-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 14px;
  margin-bottom: 20px;
}

.analytics-kpi {
  background:var(--surface-sunken,#f8fafc);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 14px 16px;
  text-align: center;
}

.analytics-kpi-value {
  font-size: 26px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.1;
  margin-bottom: 4px;
}

.analytics-kpi-label {
  font-size: 11px;
  color: var(--muted);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: .4px;
}

.analytics-kpi.kpi-success .analytics-kpi-value { color: var(--success); }
.analytics-kpi.kpi-primary .analytics-kpi-value { color: var(--primary); }
.analytics-kpi.kpi-warning .analytics-kpi-value { color: #d97706; }
.analytics-kpi.kpi-danger  .analytics-kpi-value { color: var(--danger-dark); }

.analytics-rating-section {
  border-top: 1px solid var(--border);
  padding-top: 16px;
}

.analytics-rating-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: .5px;
  margin-bottom: 12px;
}

.rating-bar-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 7px;
  font-size: 12px;
}

.rating-bar-label {
  width: 24px;
  text-align: right;
  font-weight: 600;
  color: var(--text);
  flex-shrink: 0;
}

.rating-bar-track {
  flex: 1;
  background:var(--surface-sunken,#edf2f7);
  border-radius: 4px;
  height: 10px;
  overflow: hidden;
}

.rating-bar-fill {
  height: 100%;
  border-radius: 4px;
  transition: width .4s ease;
}

.rating-bar-count {
  width: 40px;
  text-align: right;
  color: var(--muted);
  flex-shrink: 0;
}

/* ── Szybkie sugestie szablonów ──────────────────────────────── */

.quick-suggestions {
  background: #f0f4ff;
  border: 1px solid #c3d0ff;
  border-radius: 8px;
  padding: 12px 14px;
  margin-bottom: 14px;
}

.quick-suggestions-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--primary);
  text-transform: uppercase;
  letter-spacing: .5px;
  margin-bottom: 8px;
}

.quick-suggestions-btns {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.quick-suggestion-btn {
  background:var(--surface-solid,#fff);
  border: 1px solid #c3d0ff;
  border-radius: 6px;
  padding: 5px 10px;
  font-size: 12px;
  color: var(--primary);
  cursor: pointer;
  transition: background .15s, border-color .15s;
  text-align: left;
  max-width: 260px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.quick-suggestion-btn:hover {
  background: var(--primary);
  color: #fff;
  border-color: var(--primary);
}

/* ── Filtr dat ───────────────────────────────────────────────── */

.filter-date-group {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: nowrap;
}

.filter-date-sep {
  font-size: 12px;
  color: var(--muted);
  white-space: nowrap;
}

input[type="date"].filter-select {
  min-width: 130px;
}

/* ── Pod-zakładki — SEGMENTOWA TACA z pigułką [alfa 0.335] ─────────────────
   Jeden wzorzec dla całego projektu: Opinie, Ustawienia, Zdjęcia, Menu
   (`.subtabs`) i Raporty (`.page-tabs`). Do 0.334 była to kreska pod tekstem
   (`border-bottom` 2px + podkreślenie aktywnej), dwie RÓŻNE definicje dla
   `.subtabs` i `.page-tabs` plus nadpisania brandu i motywu ciemnego w trzech
   miejscach arkusza — teraz jest jedna, na tokenach.

   Kształt: taca `inline-flex` z miękkim tłem i 1px obwódką, kafelki bez tła,
   aktywny = biała karta z cieniem w kolorze `--accent-text` (NIE `--primary`,
   który jako tekst daje 4.32:1 — patrz sekcja „Akcent JAKO TEKST" niżej).
   Ruch robi warstwa `data-t-tabs="pill" data-t-tabs-ink="keep"` (motion.js):
   pigułka `.t-tabs-pill` przejmuje wygląd aktywnego kafelka i jeździ POD
   kafelkami, a statyczne tło aktywnego gaśnie (reguła w motion.css, 3c).
   Kafelki MUSZĄ więc mieć przezroczyste tło — kryjące zasłoniłoby pigułkę
   w locie ([alfa 0.311], ograniczenie strukturalne trybu pill).

   Wyjątek: `.au-help-tabs` (spis treści w modalach pomocy) zostaje przy
   kresce dokumentowej — patrz reguła niżej. */
.subtabs, .page-tabs, .drb-presets, .ed-views, .range-tabs, .au-presets {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  max-width: 100%;
  padding: 4px;
  margin-bottom: 18px;
  border-radius: 12px;
  background: rgba(22,32,58,.055);
  border: 1px solid rgba(22,32,58,.06);
  overflow-x: auto;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.subtabs::-webkit-scrollbar,
.page-tabs::-webkit-scrollbar,
.drb-presets::-webkit-scrollbar,
.ed-views::-webkit-scrollbar,
.range-tabs::-webkit-scrollbar,
.au-presets::-webkit-scrollbar { display: none; }
.subtab, .page-tab, .drb-preset, .ed-view, .range-btn, .au-preset {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  border: none;
  border-radius: 9px;
  background: transparent;
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--muted-strong, #484e5e);
  white-space: nowrap;
  cursor: pointer;
  transition: color .15s, background .15s;
}
.subtab svg.ic, .page-tab svg.ic { flex-shrink: 0; opacity: .85; }
.subtab:hover,
.page-tab:hover,
.drb-preset:hover,
.ed-view:hover,
.range-btn:hover,
.au-preset:hover { color: var(--text); background: rgba(255,255,255,.45); }
.subtab.active, .page-tab.page-tab-active, .drb-preset.drb-active, .ed-view.active, .range-btn.active, .au-preset.au-preset-on {
  color: var(--accent-text, #2f5ad6);
  background: var(--surface-solid, #fff);
  box-shadow: 0 1px 2px rgba(0,0,0,.06), 0 6px 14px -8px rgba(0,0,0,.22);
}
.subtab.active svg.ic, .page-tab.page-tab-active svg.ic { opacity: 1; }
/* Paski stojące w karcie/filtrach (zakres dat, widoki Edycji, presety) nie są
   paskiem strony — zdejmujemy dolny odstęp tacy. */
.drb-presets, .ed-views, .range-tabs, .au-presets { margin-bottom: 0; }
.au-presets { margin-top: 8px; }
/* Licznik w kafelku (Menu): na tacy nie ma tła marki — zostaje cichy chip,
   który w aktywnym kafelku przejmuje akcent. */
.subtab .badge-count { background: rgba(22,32,58,.10); color: var(--muted-strong, #484e5e); margin-left: 2px; }
.subtab.active .badge-count { background: var(--primary, #3b6ef0); color: #fff; }

/* Modale pomocy (`.au-help-tabs`): spis treści dokumentu, nie przełącznik
   widoków — zostaje kreska dokumentowa z [v2.35], bez tacy. */
.subtabs.au-help-tabs {
  display: flex;
  gap: 4px;
  padding: 0 24px;
  margin: 0;
  border: 0;
  border-bottom: 1px solid var(--border-soft, #e2e8f0);
  border-radius: 0;
  background: none;
}
.au-help-tabs .subtab {
  border-radius: 0;
  padding: 10px 14px;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}
.au-help-tabs .subtab:hover { background: none; }
.au-help-tabs .subtab.active { background: none; box-shadow: none; border-bottom-color: var(--primary, #3b6ef0); }

/* (Baner sentymentu usunięty — sentyment jest teraz chipem w nagłówku podglądu
   opinii, `.reply-sentiment-chip`; osobny baner zabierał pion w modalu.) */

/* ── Motywy: chipsy na kartach opinii ────────────────────────── */
.review-themes {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin-top: 10px;
}
.theme-tag {
  display: inline-flex;
  align-items: center;
  padding: 2px 9px;
  border-radius: 20px;
  font-size: 11px;
  font-weight: 600;
  color: #fff;
  white-space: nowrap;
}
.theme-add-btn {
  background:var(--surface-sunken,#f7fafc);
  border: 1px dashed #cbd5e0;
  color: #4A6CF7;
  border-radius: 20px;
  padding: 2px 10px;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
}
.theme-add-btn:hover { background: #eef2ff; border-color: #4A6CF7; }

/* [2026-08-13] Znacznik trwałej blokady AI (`ai_locked`) — zajmuje miejsce
   przycisku „Generuj AI" na kartach opinii, dla których nawet bezpieczny szkic
   zastępczy dwukrotnie zawiódł. Kolor ostrzegawczy, nie błąd — „Własna
   odpowiedź" obok nadal w pełni działa, to tylko informacja o AI. */
.ai-locked-note {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: var(--radius, 8px);
  background: rgba(176, 122, 30, .12);
  color: #8a5a12;
  font-size: 12px;
  font-weight: 600;
  cursor: help;
}
html.theme-dark .ai-locked-note {
  background: rgba(176, 122, 30, .2);
  color: #e0b866;
}

/* Kółko z × na tagu motywu — ukryte, wysuwa się płynnie na hover karty/tagu.
   Szybkie usunięcie motywu bez otwierania modalu (patrz removeReviewTheme). */
.theme-tag { gap: 4px; }
.theme-tag-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 14px;
  height: 14px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: rgba(255,255,255,.28);
  color: #fff;
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  opacity: 0;
  max-width: 0;
  margin-left: -4px;
  overflow: hidden;
  transition: opacity .14s ease, max-width .14s ease, margin-left .14s ease;
}
.theme-tag:hover .theme-tag-x {
  opacity: 1;
  max-width: 14px;
  margin-left: 0;
}
.theme-tag-x:hover { background: rgba(255,255,255,.5); }

/* ── Modal motywów: pole z chipsami + datalist ───────────────── */
.theme-chip-input {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  border: 1px solid #cbd5e0;
  border-radius: 8px;
  padding: 8px 10px;
  min-height: 44px;
  cursor: text;
}
.theme-chip-input:focus-within { border-color: #4A6CF7; }
.theme-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: #eef2ff;
  color: #3a4cd6;
  border-radius: 20px;
  padding: 3px 10px;
  font-size: 12px;
  font-weight: 600;
}
.theme-chip .chip-x { cursor: pointer; font-weight: 700; opacity: .7; }
.theme-chip .chip-x:hover { opacity: 1; }
.theme-input {
  border: none;
  outline: none;
  flex: 1;
  min-width: 140px;
  font-size: 13px;
  padding: 4px 0;
}
.theme-quick {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 12px;
}
.theme-quick-label { width: 100%; font-size: 12px; color:var(--muted,#718096); margin-bottom: 2px; }
.theme-quick-btn {
  background:var(--surface-sunken,#f7fafc);
  border: 1px solid #e2e8f0;
  border-radius: 20px;
  padding: 3px 11px;
  font-size: 12px;
  cursor: pointer;
  color:var(--text,#4a5568);
}
.theme-quick-btn:hover { background: #eef2ff; border-color: #4A6CF7; }

/* ── Analiza motywów: paski częstości ────────────────────────── */
.theme-ana-row {
  margin-bottom: 14px;
}
.theme-ana-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 5px;
}
.theme-ana-name { font-weight: 600; font-size: 14px; display: flex; align-items: center; gap: 7px; }
.theme-ana-dot { width: 11px; height: 11px; border-radius: 50%; display: inline-block; }
.theme-ana-meta { font-size: 12px; color:var(--muted,#718096); }
.theme-ana-bar {
  display: flex;
  height: 18px;
  border-radius: 5px;
  overflow: hidden;
  background:var(--surface-sunken,#edf2f7);
}
.theme-ana-seg { height: 100%; }
.theme-ana-legend {
  display: flex;
  gap: 16px;
  flex-wrap: wrap;
  font-size: 12px;
  color:var(--text,#4a5568);
  margin-bottom: 16px;
}
.theme-ana-legend span { display: inline-flex; align-items: center; gap: 6px; }
.theme-ana-legend i { width: 11px; height: 11px; border-radius: 2px; display: inline-block; }

/* ═══════════════════════════════════════════════════════════
   Liquid-glass: globalny szlif (scrollbar, mikrointerakcje)
   Dodane przy migracji stylu na wzór „Business Profile Manager".
   ═══════════════════════════════════════════════════════════ */

/* Cienki pasek przewijania jak we wzorze */
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(0,0,0,.13); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,.22); }

/* Delikatny „press" na przyciskach (jak w makiecie) */
button { transition: opacity .15s, transform .15s, background .15s, box-shadow .15s; }

/* Spójny focus-ring dla pól wzorowany na makiecie */
input:focus, textarea:focus, select:focus {
  border-color: rgba(66,133,244,.45);
  box-shadow: 0 0 0 3px rgba(66,133,244,.1);
}

/* Karty częstości motywów na jasnym tle */
.theme-ana-bar { background: rgba(0,0,0,.07); }

/* ─── Ustawienia: listy motywów domyślnych ──────────────────── */
.themes-cols { display:flex; gap:16px; flex-wrap:wrap; }
.themes-col { flex:1; min-width:240px; display:flex; flex-direction:column; }
.themes-col-head { font-weight:700; font-size:14px; padding:8px 12px; border-radius:10px 10px 0 0; }
.themes-col-pos { background:rgba(72,187,120,.14); color:#2f855a; }
.themes-col-neg { background:rgba(229,62,62,.12); color:var(--err-fg,#c53030); }
.themes-col-hint { font-weight:500; font-size:12px; opacity:.75; }
.themes-list { border:1px solid var(--border-soft,#e2e8f0); border-top:none; border-radius:0 0 10px 10px;
  padding:8px; display:flex; flex-direction:column; gap:6px; min-height:60px; }
.themes-empty { font-size:12px; color:var(--muted,#a0aec0); padding:10px; text-align:center; }
.theme-row { display:flex; align-items:center; justify-content:space-between; gap:8px;
  background:rgba(0,0,0,.03); border-radius:8px; padding:6px 10px; font-size:13px; }
.theme-row-name { font-weight:600; display:flex; align-items:center; gap:6px; }
.theme-row-count { background:rgba(0,0,0,.08); border-radius:20px; padding:0 7px; font-size:11px; font-weight:600; }
.theme-row-actions { display:flex; gap:6px; flex-shrink:0; }
.theme-row-btn { border:1px solid var(--border-soft,#e2e8f0); background:var(--surface-solid,#fff); border-radius:6px;
  font-size:11px; padding:2px 7px; cursor:pointer; color:#4A6CF7; white-space:nowrap; }
.theme-row-btn:hover { background:#eef2ff; }
.theme-row-del { color:#e53e3e; font-size:14px; line-height:1; padding:2px 8px; }
.theme-row-del:hover { background:rgba(239,68,68,.12); }
.themes-add { display:flex; gap:8px; margin-top:10px; }
.themes-add .form-control { flex:1; }
.themes-incidental { display:flex; flex-direction:column; gap:6px; }
.theme-row-inc { background:rgba(0,0,0,.025); }
.theme-inc-sent { font-size:10px; font-weight:700; border-radius:6px; padding:1px 6px; }
.theme-inc-positive { background:rgba(72,187,120,.16); color:#2f855a; }
.theme-inc-negative { background:rgba(229,62,62,.14); color:var(--err-fg,#c53030); }

/* ─── Modal motywów opinii: dwie listy wyboru ───────────────── */
.theme-modal-hint { font-size:13px; color:#555; background:var(--surface-sunken,#f8fafc); border-radius:8px; padding:9px 12px; margin-bottom:14px; }
.theme-pick-cols { display:flex; gap:14px; flex-wrap:wrap; }
.theme-pick-col { flex:1; min-width:200px; border:1.5px solid var(--border-soft,#e2e8f0); border-radius:12px;
  padding:10px; transition:border-color .15s, box-shadow .15s; opacity:.82; }
.theme-pick-col.theme-col-active { opacity:1; border-color:#4A6CF7; box-shadow:0 0 0 3px rgba(74,108,247,.10); }
.theme-pick-head { font-weight:700; font-size:13px; margin-bottom:8px; }
.theme-col-pos { color:#2f855a; }
.theme-col-neg { color:var(--err-fg,#c53030); }
.theme-pick-list { display:flex; flex-wrap:wrap; gap:6px; }
.theme-pick-empty { font-size:12px; color:var(--muted,#a0aec0); }
.theme-pick-item { border:1px solid var(--border-soft,#e2e8f0); background:var(--surface-solid,#fff); border-radius:20px;
  padding:5px 12px; font-size:13px; cursor:pointer; transition:all .12s; }
.theme-pick-item:hover { border-color:#4A6CF7; }
.theme-pick-item.selected { background:#4A6CF7; border-color:#4A6CF7; color:#fff; font-weight:600; }
.theme-incidental-box { margin-top:16px; }
.theme-incidental-hint { font-size:11px; color:var(--muted,#a0aec0); margin-top:5px; }

/* ─── Modal odpowiedzi: badge formy grzecznościowej (auto Pani/Pan) ─ */
.salu-badge { display:inline-block; font-size:11px; font-weight:700; border-radius:20px; padding:1px 9px; margin-left:8px; vertical-align:middle; }
.salu-nick { font-size:12px; color:var(--muted,#718096); margin-left:8px; font-weight:600; }
.salu-pani    { background:rgba(213,63,140,.14); color:#b83280; }
.salu-pan     { background:rgba(49,130,206,.14); color:#2b6cb0; }
.salu-panipan { background:rgba(0,0,0,.07); color:var(--text,#4a5568); }
.qs-salu { font-size:12px; }
.tpl-btn.detected { border-color:#4A6CF7 !important; box-shadow:0 0 0 2px rgba(74,108,247,.18); font-weight:700; }

/* ─── Drag & drop motywów w Ustawieniach ────────────────────── */
.theme-row { cursor:default; }
.theme-row[draggable="true"] { cursor:grab; }
.theme-row-grip { color:var(--muted,#a0aec0); font-size:14px; line-height:1; cursor:grab; user-select:none; margin-right:2px; }
.theme-row.dragging { opacity:.45; cursor:grabbing; }
.themes-list.drop-target, .themes-incidental.drop-target {
  outline:2px dashed #4A6CF7; outline-offset:2px; background:rgba(74,108,247,.05); border-radius:10px;
}
.themes-incidental { min-height:48px; }

/* ─── Liquid glass — szybkie motywy w panelu Opinii ─────────────
   Cały wygląd „liquid glass" sterują poniższe zmienne. Aby zmienić styl,
   edytuj tylko ten blok :root (tło, rozmycie, obwódka, cień, kolor tekstu). */
:root {
  --lg-bg:        rgba(255,255,255,.45);
  --lg-bg-hover:  rgba(255,255,255,.72);
  --lg-border:    rgba(255,255,255,.65);
  --lg-blur:      blur(10px) saturate(160%);
  --lg-shadow:    0 2px 10px rgba(31,38,135,.12), inset 0 1px 0 rgba(255,255,255,.55);
  --lg-text:      #2d3748;
  --lg-radius:    20px;
}
.quick-themes { display:inline-flex; gap:6px; flex-wrap:wrap; vertical-align:middle; }
.lg-chip {
  display:inline-flex; align-items:center; gap:5px;
  font-size:12px; font-weight:600; color:var(--lg-text);
  padding:4px 11px; border-radius:var(--lg-radius);
  background:var(--lg-bg);
  border:1px solid var(--lg-border);
  -webkit-backdrop-filter:var(--lg-blur); backdrop-filter:var(--lg-blur);
  box-shadow:var(--lg-shadow);
  cursor:pointer; transition:background .15s, transform .12s, box-shadow .15s;
}
.lg-chip:hover { background:var(--lg-bg-hover); transform:translateY(-1px);
  box-shadow:0 4px 16px rgba(31,38,135,.18), inset 0 1px 0 rgba(255,255,255,.65); }
.lg-chip:active { transform:translateY(0); }
.lg-chip-plus { font-weight:800; color:var(--accent-text,#4A6CF7); font-size:13px; line-height:1; }

/* ─── Sesje pracy (Workflow) ─────────────────────────────────────────────── */
.session-bar {
  display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  padding:12px 16px; margin-bottom:14px;
  background:var(--surface, rgba(255,255,255,.68));
  backdrop-filter:blur(var(--blur,24px)) saturate(150%);
  border:1px solid var(--border-soft, rgba(255,255,255,.5));
  border-radius:var(--radius-card,16px);
  box-shadow:var(--shadow, 0 4px 18px rgba(31,38,135,.10));
}
.session-bar.active { border-color:rgba(39,103,73,.35); }
.session-bar.paused { border-color:rgba(191,135,0,.4); }
.session-bar .session-info { font-size:13px; color:var(--text,#2d3748); flex:1; min-width:180px; }
.session-bar .btn { margin-left:auto; }
.session-dot {
  width:10px; height:10px; border-radius:50%; background:#cbd5e0; flex:none;
}
.session-dot.active {
  background:#38a169; box-shadow:0 0 0 0 rgba(56,161,105,.5);
  animation:sessPulse 2s infinite;
}
.session-dot.paused { background:#d69e2e; }
@keyframes sessPulse {
  0%   { box-shadow:0 0 0 0 rgba(56,161,105,.5); }
  70%  { box-shadow:0 0 0 8px rgba(56,161,105,0); }
  100% { box-shadow:0 0 0 0 rgba(56,161,105,0); }
}
@media (prefers-reduced-motion: reduce) { .session-dot.active { animation:none; } }

.session-changes {
  padding:12px 16px; margin-bottom:14px; border-radius:var(--radius-card,16px);
  background:rgba(66,133,244,.08); border:1px solid rgba(66,133,244,.22);
}
.session-changes.none { background:rgba(160,174,192,.10); border-color:rgba(160,174,192,.25);
  color:var(--muted,#718096); font-size:13px; }
.session-changes .sc-title { font-weight:700; font-size:13px; color:var(--text,#2d3748); margin-bottom:8px; }
.session-changes .sc-list { display:flex; flex-wrap:wrap; gap:8px; }
.sc-item {
  display:inline-flex; align-items:center; gap:6px;
  background:rgba(255,255,255,.7); border:1px solid var(--border-soft,rgba(255,255,255,.5));
  border-radius:999px; padding:4px 12px; font-size:13px; color:var(--text,#2d3748);
}
.sc-item .sc-delta { font-weight:700; font-size:12px; }
.sc-item.up   .sc-delta { color:#276749; }
.sc-item.down .sc-delta { color:var(--err-fg,#c53030); }

/* ── Spójne emoji cross-platform — patrz sekcja „Platformy nie-Apple" na
   końcu pliku ([v1.47]: Twemoji zastąpione self-hostowanym fontem
   Noto Color Emoji + tryb odchudzonej grafiki dla Windows/Linux). ──────── */

/* ── Wydajność renderowania (bez zmiany wyglądu) ────────────────────────── */
/* Kompozytor izoluje każdą kartę osobno — bez przeliczania reszty strony
   przy zmianie jednej karty. Zero wpływu na wygląd, realny zysk zwłaszcza
   przy wielu kartach naraz (dashboard, lista wizytówek) na słabszym GPU. */
.card, .stat-card, .location-card {
  contain: layout paint style;
}

/* Przeglądarka pomija layout/paint dla treści poza widocznym obszarem —
   przydatne przy długich listach opinii/wizytówek. Zero wpływu na wygląd
   widocznej zawartości. */
.locations-grid, #locationsGrid, #reviewsList {
  content-visibility: auto;
  contain-intrinsic-size: 0 200px;
}

/* Wcześniejsze wydzielenie warstwy GPU TYLKO dla kluczowych, ciężkich
   elementów blur (sidebar, modal) — celowo NIE na każdej karcie, bo
   nadużyty will-change zwiększa zużycie pamięci GPU i może pogorszyć,
   nie poprawić, wydajność. */
.sidebar, .modal {
  will-change: backdrop-filter;
}

/* Drzewo uprawnień w kreatorze ról (Użytkownicy → Role) — zakładka→pod-zakładka. */
.role-perm-page { margin-bottom: 2px; }
.role-perm-page-row {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 4px; border-radius: 6px; cursor: pointer; font-size: 13px; font-weight: 600;
}
.role-perm-page-row:hover { background: rgba(66, 133, 244, .08); }
.role-perm-page-row.role-perm-leaf { font-weight: 400; cursor: default; }
.role-perm-page-label { flex: 1; }
.role-perm-page-chevron { font-size: 11px; color:var(--muted,#a0aec0); width: 12px; text-align: center; }
.role-perm-page-children {
  /* Odstęp i obramowanie w środku — na animatorze zostawiałyby 8 px
     martwego pasa i kreskę pod każdym zwiniętym wierszem. */
  margin: 0; padding: 0; border: 0;
}
.role-perm-page-children > .t-coll-inner {
  margin: 2px 0 6px 26px; padding-left: 10px; border-left: 2px solid rgba(66, 133, 244, .15);
}
.role-perm-child-row {
  display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 4px 0; cursor: pointer;
}

/* ═══════════════════════════════════════════════════════════════════════
   KOMPONENT WYBORU (ui-select.js) — jeden wzorzec dla całej aplikacji.

   Źródło stylu: modal „Nowa rola" (drzewo uprawnień `.role-perm-*` wyżej).
   Stamtąd: promień wiersza 6px, hover rgba(66,133,244,.08), 13px,
   waga 600 na pozycji aktywnej, chevron w kolorze #a0aec0.
   Panel dziedziczy szkło z `.modal` (blur 40px / saturate 180%).

   Natywny <select> zostaje w DOM (ukryty poniżej) — komponent to wyłącznie
   warstwa prezentacji. Patrz komentarz w public/js/ui-select.js.
   ═══════════════════════════════════════════════════════════════════════ */

.ui-sel { position: relative; display: inline-block; vertical-align: middle; }

/* Odpowiednik `width:100%` z `.form-control` — pola w formularzach/modalach
   mają zajmować całą szerokość kontenera, tak jak przed zmianą. */
.ui-sel-block { display: block; width: 100%; }

/* Natywny select: niewidoczny, ale wciąż źródło prawdy o stanie. */
select.ui-sel-native {
  position: absolute; opacity: 0; pointer-events: none;
  width: 100%; height: 100%; left: 0; top: 0; margin: 0; border: 0; padding: 0;
}

.ui-sel-trigger {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 10px 13px;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255,255,255,.65);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.ui-sel-compact .ui-sel-trigger { padding: 8px 12px; font-size: 13px; }

.ui-sel-trigger:hover:not(:disabled) {
  background: rgba(255,255,255,.85);
  border-color: rgba(66,133,244,.28);
}
.ui-sel-trigger:focus-visible,
.ui-sel-open .ui-sel-trigger {
  border-color: rgba(66,133,244,.45);
  box-shadow: 0 0 0 3px rgba(66,133,244,.1);
}

.ui-sel-label {
  flex: 1; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ui-sel-trigger.ui-sel-placeholder .ui-sel-label { color: var(--muted); }

.ui-sel-chevron {
  flex: none;
  font-size: 11px;
  color:var(--muted,#a0aec0);
  transition: transform .18s ease;
}
.ui-sel-open .ui-sel-chevron { transform: rotate(180deg); color: rgba(66,133,244,.75); }

.ui-sel-disabled { opacity: .55; }
.ui-sel-disabled .ui-sel-trigger { cursor: not-allowed; }

/* ── Panel opcji (montowany do <body>, pozycjonowany z JS) ────────────── */
.ui-sel-popup {
  position: fixed;
  z-index: 3000;                       /* nad modalami (.modal-overlay) */
  display: flex; flex-direction: column;
  padding: 6px;
  background: rgba(255,255,255,.86);
  backdrop-filter: blur(40px) saturate(180%);
  -webkit-backdrop-filter: blur(40px) saturate(180%);
  border: 1px solid rgba(255,255,255,.9);
  border-radius: 14px;
  box-shadow: var(--shadow-lg);
  overflow: hidden;
  opacity: 0;
  transform: translateY(-6px) scale(.985);
  transition: opacity .16s ease, transform .16s ease;
}
.ui-sel-popup-up { transform: translateY(6px) scale(.985); }
.ui-sel-popup.ui-sel-popup-in { opacity: 1; transform: translateY(0) scale(1); }

.ui-sel-list { overflow-y: auto; }

/* Wiersz opcji — 1:1 z `.role-perm-page-row` / `.role-perm-child-row`. */
.ui-sel-row {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 9px;
  border-radius: 6px;
  font-size: 13px;
  color: var(--text);
  cursor: pointer;
  transition: background .12s;
}
.ui-sel-row-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ui-sel-row-active { background: rgba(66,133,244,.08); }
.ui-sel-row-on { font-weight: 600; color: #2b5fd0; }
.ui-sel-row-on.ui-sel-row-active { background: rgba(66,133,244,.14); }
.ui-sel-row-off { opacity: .45; cursor: not-allowed; }

.ui-sel-check { flex: none; font-size: 12px; color: #2b5fd0; opacity: 0; }
.ui-sel-row-on .ui-sel-check { opacity: 1; }

.ui-sel-group {
  padding: 8px 9px 4px;
  font-size: 11px; font-weight: 700; letter-spacing: .3px;
  text-transform: uppercase;
  color: var(--muted);
}
.ui-sel-empty { padding: 14px 9px; font-size: 13px; color: var(--muted); text-align: center; }

.ui-sel-search { padding: 2px 2px 6px; }
.ui-sel-search input {
  width: 100%;
  padding: 7px 10px;
  border: 1.5px solid var(--border-soft);
  border-radius: 8px;
  background: rgba(255,255,255,.7);
  font-family: inherit; font-size: 13px; color: var(--text);
  outline: none;
}
.ui-sel-search input:focus {
  border-color: rgba(66,133,244,.45);
  box-shadow: 0 0 0 3px rgba(66,133,244,.1);
}

/* ── Pola daty i godziny ──────────────────────────────────────────────────
   Godziny (type=time) zostają natywnym zegarem systemowym — [v1.49],
   niezmienione. Daty (type=date) od [v1.50] mają WŁASNY kalendarz
   (ui-datepicker.js, blok niżej) — poniższa reguła na `input[type="date"]`
   jest teraz wyłącznie FALLBACKIEM: stylowana powłoka natywnego pola na
   wypadek gdyby JS się nie wykonał (`.ui-date-native` normalnie ukrywa ten
   element, patrz ui-datepicker.js). Obejmuje też pola BEZ klasy (godziny
   otwarcia w hours.js/profile-editor.js), które dotąd renderowały się w
   domyślnym stylu przeglądarki.                                        */
input[type="date"],
input[type="time"] {
  padding: 10px 13px;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255,255,255,.65);
  font-family: inherit;
  font-size: 14px;
  color: var(--text);
  outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
input[type="date"].filter-select,
input[type="time"].filter-select,
input[type="date"].drb-date-input,
.pe-hours-row input[type="time"],
.ho-hours-row input[type="time"] {
  padding: 8px 12px;
  font-size: 13px;
}
input[type="date"]:hover,
input[type="time"]:hover { background: rgba(255,255,255,.85); border-color: rgba(66,133,244,.28); }
input[type="date"]:focus,
input[type="time"]:focus {
  border-color: rgba(66,133,244,.45);
  box-shadow: 0 0 0 3px rgba(66,133,244,.1);
}
input[type="date"]:disabled,
input[type="time"]:disabled { opacity: .55; cursor: not-allowed; }

/* Ikona kalendarza/zegara w tonacji chevronu komponentu wyboru. */
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="time"]::-webkit-calendar-picker-indicator {
  opacity: .45;
  cursor: pointer;
  border-radius: 4px;
  padding: 2px;
  transition: opacity .15s, background .15s;
}
input[type="date"]:hover::-webkit-calendar-picker-indicator,
input[type="time"]:hover::-webkit-calendar-picker-indicator { opacity: .8; }
input[type="date"]::-webkit-calendar-picker-indicator:hover,
input[type="time"]::-webkit-calendar-picker-indicator:hover { background: rgba(66,133,244,.12); }

/* ═══════════════════════════════════════════════════════════════════════
   KALENDARZ DAT (ui-datepicker.js) — zastępuje natywny popup przeglądarki.

   Trigger dzieli tokeny 1:1 z `.ui-sel-trigger` (ten sam wzorzec stylu,
   modal „Nowa rola"); panel kalendarza dzieli materiał z `.ui-sel-popup`
   (to samo szkło co `.modal`). Natywny <input type="date"> zostaje w DOM,
   ukryty — patrz komentarz w ui-datepicker.js.
   ═══════════════════════════════════════════════════════════════════════ */

.ui-date { position: relative; display: inline-block; vertical-align: middle; }
.ui-date-block { display: block; width: 100%; }

input.ui-date-native {
  position: absolute; opacity: 0; pointer-events: none;
  width: 100%; height: 100%; left: 0; top: 0; margin: 0; border: 0; padding: 0;
}

.ui-date-trigger {
  display: flex; align-items: center; gap: 8px;
  width: 100%;
  padding: 10px 13px;
  border: 1.5px solid var(--border-soft);
  border-radius: var(--radius);
  background: rgba(255,255,255,.65);
  color: var(--text);
  font-family: inherit;
  font-size: 14px;
  line-height: 1.35;
  text-align: left;
  cursor: pointer;
  outline: none;
  transition: border-color .15s, box-shadow .15s, background .15s;
}
.ui-date-compact .ui-date-trigger { padding: 8px 12px; font-size: 13px; gap: 6px; }

.ui-date-trigger:hover:not(:disabled) { background: rgba(255,255,255,.85); border-color: rgba(66,133,244,.28); }
.ui-date-trigger:focus-visible,
.ui-date-open .ui-date-trigger { border-color: rgba(66,133,244,.45); box-shadow: 0 0 0 3px rgba(66,133,244,.1); }

.ui-date-icon { flex: none; display: flex; color:var(--muted,#a0aec0); transition: color .15s; }
.ui-date-open .ui-date-icon { color: rgba(66,133,244,.75); }

.ui-date-label { flex: 1; min-width: 0; white-space: nowrap; font-variant-numeric: tabular-nums; }
.ui-date-trigger.ui-date-placeholder .ui-date-label { color: var(--muted); }

.ui-date-disabled { opacity: .55; }
.ui-date-disabled .ui-date-trigger { cursor: not-allowed; }

/* ── Panel (montowany do <body>, jak .ui-sel-popup) ────────────────────── */
.ui-date-popup {
  position: fixed;
  z-index: 3000;
  width: 272px;
  padding: 10px;
  background: rgba(255,255,255,.86);
  backdrop-filter: blur(40px) saturate(180%);
  -webkit-backdrop-filter: blur(40px) saturate(180%);
  border: 1px solid rgba(255,255,255,.9);
  border-radius: 16px;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(-6px) scale(.985);
  transition: opacity .16s ease, transform .16s ease;
}
.ui-date-popup-up { transform: translateY(6px) scale(.985); }
.ui-date-popup.ui-date-popup-in { opacity: 1; transform: translateY(0) scale(1); }

.ui-date-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 8px;
}
.ui-date-nav {
  flex: none;
  width: 26px; height: 26px;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 8px;
  background: transparent;
  color: var(--muted);
  font-size: 15px;
  cursor: pointer;
  transition: background .12s, color .12s;
}
.ui-date-nav:hover { background: rgba(66,133,244,.1); color: #2b5fd0; }

.ui-date-title {
  flex: 1;
  display: flex; align-items: center; justify-content: center; gap: 4px;
  border: none; background: transparent;
  padding: 4px 8px;
  border-radius: 8px;
  font-family: inherit; font-size: 13px; font-weight: 700; letter-spacing: -.1px;
  color: var(--text);
  text-transform: capitalize;
  cursor: pointer;
  transition: background .12s;
}
.ui-date-title:hover { background: rgba(66,133,244,.08); }
.ui-date-title-static { cursor: default; }
.ui-date-title-static:hover { background: transparent; }
.ui-date-title-chevron { font-size: 10px; color:var(--muted,#a0aec0); }

.ui-date-weekrow {
  display: grid; grid-template-columns: repeat(7, 1fr);
  margin-bottom: 2px;
}
.ui-date-weekrow span {
  text-align: center;
  font-size: 11px; font-weight: 700;
  color: var(--muted);
  padding: 4px 0;
}

.ui-date-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }

.ui-date-cell {
  aspect-ratio: 1;
  display: flex; align-items: center; justify-content: center;
  border: none; border-radius: 8px;
  background: transparent;
  font-family: inherit; font-size: 13px;
  color: var(--text);
  cursor: pointer;
  transition: background .12s, color .12s;
}
.ui-date-cell:hover:not(:disabled) { background: rgba(66,133,244,.1); }
.ui-date-cell-out { color: #c3c9d5; }
.ui-date-cell-today { font-weight: 700; box-shadow: inset 0 0 0 1.5px rgba(66,133,244,.4); }
.ui-date-cell-sel { background: #2b5fd0; color: #fff; font-weight: 600; }
.ui-date-cell-sel:hover { background: #2b5fd0; }
.ui-date-cell-off { color: #d7dbe3; cursor: not-allowed; }

.ui-date-month-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; padding-top: 2px; }
.ui-date-month-cell {
  padding: 10px 4px;
  border: none; border-radius: 10px;
  background: transparent;
  font-family: inherit; font-size: 13px; text-transform: capitalize;
  color: var(--text);
  cursor: pointer;
  transition: background .12s, color .12s;
}
.ui-date-month-cell:hover { background: rgba(66,133,244,.1); }
.ui-date-month-cell.ui-date-cell-sel { background: #2b5fd0; color: #fff; font-weight: 600; }
.ui-date-month-cell.ui-date-cell-today:not(.ui-date-cell-sel) { box-shadow: inset 0 0 0 1.5px rgba(66,133,244,.4); }

.ui-date-foot {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 8px; padding-top: 8px;
  border-top: 1px solid var(--border-soft);
}
.ui-date-link {
  border: none; background: transparent;
  padding: 4px 6px;
  border-radius: 6px;
  font-family: inherit; font-size: 12.5px; font-weight: 600;
  color: #2b5fd0;
  cursor: pointer;
  transition: background .12s;
}
.ui-date-link:hover { background: rgba(66,133,244,.1); }

html.plt-noapple .ui-date-popup { backdrop-filter: none; -webkit-backdrop-filter: none; background: rgba(255,255,255,.97); }

/* ═══ Platformy nie-Apple (Windows/Linux) — emoji + odchudzona grafika ═══
   Klasa html.plt-noapple jest nadawana SYNCHRONICZNIE w inline-skrypcie
   <head> każdej strony (wzorzec anty-FOUC z [v1.05]/[v1.33] — detekcja
   platformy jest synchroniczna, zero sieci). Na Mac/iOS klasa nigdy nie
   występuje → poniższy blok jest tam martwy, wygląd 100% bez zmian.

   1) EMOJI ([v1.47], zastępuje Twemoji z [v1.38]): self-hostowany font
      Noto Color Emoji (licencja OFL, pliki w /fonts/noto-emoji/, 10
      segmentów woff2 ładowanych na żądanie wg unicode-range). Font jest
      wpięty w stack TYLKO pod html.plt-noapple, więc Mac/iOS zawsze używa
      natywnego Apple Color Emoji. Uwaga prawna: wygląd 1:1 Apple jest
      nieosiągalny legalnie (czcionka Apple nie jest licencjonowana do
      osadzania) — Noto to najbliższy legalny odpowiednik z głębią kolorów.

   2) WYDAJNOŚĆ: Windows kompozytuje backdrop-filter znacznie drożej niż
      macOS. Neutralizujemy najdroższe efekty: zamrożenie animacji tła
      (bloby wymuszały przeliczanie blura CO KLATKĘ pod każdą szklaną
      powierzchnią) i wyłączenie blura na kartach/chipach przez nadpisanie
      tokenów --blur/--lg-blur (+ bardziej kryjące --surface jako
      rekompensata). Sidebar i modale ZACHOWUJĄ blur (sygnaturowy wygląd,
      po zamrożeniu tła ich koszt jest akceptowalny). */

html.plt-noapple body,
html.plt-noapple button,
html.plt-noapple input,
html.plt-noapple select,
html.plt-noapple textarea {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI',
    system-ui, 'Noto Color Emoji', sans-serif;
}

html.plt-noapple {
  --blur: none;                       /* karty/panele: bez backdrop-filter */
  --lg-blur: none;                    /* chipy liquid-glass: bez blura     */
  --surface: rgba(255,255,255,.92);   /* rekompensata krycia bez blura     */
}
html.plt-noapple body::before,
html.plt-noapple body::after { animation: none; } /* statyczne bloby tła   */
/* Panel wyboru: bez backdrop-filter (ta sama zasada co karty/chipy w [v1.47]);
   krycie podbite, żeby lista pozostała czytelna nad treścią strony. */
html.plt-noapple .ui-sel-popup {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: rgba(255,255,255,.97);
}

html.plt-noapple .btn-secondary {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: rgba(255,255,255,.92);
}

/* @font-face Noto Color Emoji — wygenerowane z Google Fonts (css2 v39),
   URL-e przepisane na self-host. NIE edytuj unicode-range ręcznie. */
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.0.woff2) format('woff2');
  unicode-range: U+1f1e6-1f1ff;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.1.woff2) format('woff2');
  unicode-range: U+200d, U+2620, U+26a7, U+fe0f, U+1f308, U+1f38c, U+1f3c1, U+1f3f3-1f3f4, U+1f6a9, U+e0062-e0063, U+e0065, U+e0067, U+e006c, U+e006e, U+e0073-e0074, U+e0077, U+e007f;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.2.woff2) format('woff2');
  unicode-range: U+23, U+2a, U+30-39, U+a9, U+ae, U+200d, U+203c, U+2049, U+20e3, U+2122, U+2139, U+2194-2199, U+21a9-21aa, U+23cf, U+23e9-23ef, U+23f8-23fa, U+24c2, U+25aa-25ab, U+25b6, U+25c0, U+25fb-25fe, U+2611, U+2622-2623, U+2626, U+262a, U+262e-262f, U+2638, U+2640, U+2642, U+2648-2653, U+2660, U+2663, U+2665-2666, U+2668, U+267b, U+267e-267f, U+2695, U+269b-269c, U+26a0, U+26a7, U+26aa-26ab, U+26ce, U+26d4, U+2705, U+2714, U+2716, U+271d, U+2721, U+2733-2734, U+2747, U+274c, U+274e, U+2753-2755, U+2757, U+2764, U+2795-2797, U+27a1, U+27b0, U+27bf, U+2934-2935, U+2b05-2b07, U+2b1b-2b1c, U+2b55, U+3030, U+303d, U+3297, U+3299, U+fe0f, U+1f170-1f171, U+1f17e-1f17f, U+1f18e, U+1f191-1f19a, U+1f201-1f202, U+1f21a, U+1f22f, U+1f232-1f23a, U+1f250-1f251, U+1f310, U+1f3a6, U+1f3b5-1f3b6, U+1f3bc, U+1f3e7, U+1f441, U+1f499-1f49c, U+1f49f-1f4a0, U+1f4ac-1f4ad, U+1f4b1-1f4b2, U+1f4b9, U+1f4db, U+1f4f2-1f4f6, U+1f500-1f507, U+1f515, U+1f518-1f524, U+1f52f-1f53d, U+1f549, U+1f54e, U+1f5a4, U+1f5e8, U+1f5ef, U+1f6ab, U+1f6ad-1f6b1, U+1f6b3, U+1f6b7-1f6bc, U+1f6be, U+1f6c2-1f6c5, U+1f6d0-1f6d1, U+1f6d7, U+1f6dc, U+1f7e0-1f7eb, U+1f7f0, U+1f90d-1f90e, U+1f9d1-1f9d2, U+1f9e1, U+1fa75-1fa77, U+1faaf;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.3.woff2) format('woff2');
  unicode-range: U+200d, U+231a-231b, U+2328, U+23f0-23f3, U+2602, U+260e, U+2692, U+2694, U+2696-2697, U+2699, U+26b0-26b1, U+26cf, U+26d1, U+26d3, U+2702, U+2709, U+270f, U+2712, U+fe0f, U+1f302, U+1f321, U+1f392-1f393, U+1f3a9, U+1f3bd, U+1f3ee, U+1f3f7, U+1f3fa, U+1f451-1f462, U+1f484, U+1f489-1f48a, U+1f48c-1f48e, U+1f4a1, U+1f4a3, U+1f4a5, U+1f4b0, U+1f4b3-1f4b8, U+1f4bb-1f4da, U+1f4dc-1f4f1, U+1f4ff, U+1f508-1f514, U+1f516-1f517, U+1f526-1f529, U+1f52c-1f52e, U+1f550-1f567, U+1f56f-1f570, U+1f576, U+1f587, U+1f58a-1f58d, U+1f5a5, U+1f5a8, U+1f5b1-1f5b2, U+1f5c2-1f5c4, U+1f5d1-1f5d3, U+1f5dc-1f5de, U+1f5e1, U+1f5f3, U+1f6aa, U+1f6ac, U+1f6bd, U+1f6bf, U+1f6c1, U+1f6cb, U+1f6cd-1f6cf, U+1f6d2, U+1f6e0-1f6e1, U+1f6f0, U+1f97b-1f97f, U+1f9af, U+1f9ba, U+1f9e2-1f9e6, U+1f9ea-1f9ec, U+1f9ee-1f9f4, U+1f9f7-1f9ff, U+1fa71-1fa74, U+1fa79-1fa7b, U+1fa86, U+1fa8e-1fa8f, U+1fa91-1fa93, U+1fa96, U+1fa99-1faa0, U+1faa2-1faa7, U+1faaa-1faae;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.4.woff2) format('woff2');
  unicode-range: U+265f, U+26bd-26be, U+26f3, U+26f8, U+fe0f, U+1f004, U+1f0cf, U+1f380-1f384, U+1f386-1f38b, U+1f38d-1f391, U+1f396-1f397, U+1f399-1f39b, U+1f39e-1f39f, U+1f3a3-1f3a5, U+1f3a7-1f3a9, U+1f3ab-1f3b4, U+1f3b7-1f3bb, U+1f3bd-1f3c0, U+1f3c5-1f3c6, U+1f3c8-1f3c9, U+1f3cf-1f3d3, U+1f3f8-1f3f9, U+1f47e, U+1f4e2, U+1f4f7-1f4fd, U+1f52b, U+1f579, U+1f58c-1f58d, U+1f5bc, U+1f6f7, U+1f6f9, U+1f6fc, U+1f93f, U+1f941, U+1f945, U+1f947-1f94f, U+1f9e7-1f9e9, U+1f9f5-1f9f6, U+1fa70-1fa71, U+1fa80-1fa81, U+1fa83-1fa85, U+1fa87-1fa8a, U+1fa94-1fa95, U+1fa97-1fa98, U+1faa1, U+1faa9, U+1fadf;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.5.woff2) format('woff2');
  unicode-range: U+2693, U+26e9-26ea, U+26f1-26f2, U+26f4-26f5, U+26fa, U+26fd, U+2708, U+fe0f, U+1f301, U+1f303, U+1f306-1f307, U+1f309, U+1f310, U+1f3a0-1f3a2, U+1f3aa, U+1f3cd-1f3ce, U+1f3d5, U+1f3d7-1f3db, U+1f3df-1f3e6, U+1f3e8-1f3ed, U+1f3ef-1f3f0, U+1f488, U+1f492, U+1f4ba, U+1f54b-1f54d, U+1f5fa-1f5ff, U+1f680-1f6a2, U+1f6a4-1f6a8, U+1f6b2, U+1f6d1, U+1f6d5-1f6d6, U+1f6dd-1f6df, U+1f6e2-1f6e5, U+1f6e9, U+1f6eb-1f6ec, U+1f6f3-1f6f6, U+1f6f8, U+1f6fa-1f6fb, U+1f9bc-1f9bd, U+1f9ed, U+1f9f3, U+1fa7c;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.6.woff2) format('woff2');
  unicode-range: U+200d, U+2615, U+fe0f, U+1f32d-1f330, U+1f336, U+1f33d, U+1f344-1f37f, U+1f382, U+1f52a, U+1f7e9, U+1f7eb, U+1f942-1f944, U+1f950-1f96f, U+1f99e, U+1f9aa, U+1f9c0-1f9cb, U+1fad0-1fadc;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.7.woff2) format('woff2');
  unicode-range: U+200d, U+2600-2601, U+2603-2604, U+2614, U+2618, U+26a1, U+26c4-26c5, U+26c8, U+26f0, U+2728, U+2744, U+2b1b, U+2b50, U+fe0f, U+1f300, U+1f304-1f305, U+1f308, U+1f30a-1f30f, U+1f311-1f321, U+1f324-1f32c, U+1f331-1f335, U+1f337-1f33c, U+1f33e-1f344, U+1f3d4, U+1f3d6, U+1f3dc-1f3de, U+1f3f5, U+1f400-1f43f, U+1f490, U+1f4a7, U+1f4ae, U+1f525, U+1f54a, U+1f573, U+1f577-1f578, U+1f648-1f64a, U+1f6d8, U+1f940, U+1f980-1f9ae, U+1f9ba, U+1fa90, U+1faa8, U+1fab0-1fabf, U+1facd-1facf, U+1fae7;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.8.woff2) format('woff2');
  unicode-range: U+200d, U+2640, U+2642, U+2695-2696, U+26f7, U+26f9, U+2708, U+2764, U+27a1, U+fe0f, U+1f33e, U+1f373, U+1f37c, U+1f384-1f385, U+1f393, U+1f3a4, U+1f3a8, U+1f3c2-1f3c4, U+1f3c7, U+1f3ca-1f3cc, U+1f3eb, U+1f3ed, U+1f3fb-1f3ff, U+1f430, U+1f466-1f469, U+1f46b-1f478, U+1f47c, U+1f481-1f483, U+1f486-1f487, U+1f48b, U+1f48f, U+1f491, U+1f4bb-1f4bc, U+1f527, U+1f52c, U+1f574-1f575, U+1f57a, U+1f645-1f647, U+1f64b, U+1f64d-1f64e, U+1f680, U+1f692, U+1f6a3, U+1f6b4-1f6b6, U+1f6c0, U+1f6cc, U+1f91d, U+1f926, U+1f930-1f931, U+1f934-1f93a, U+1f93c-1f93e, U+1f977, U+1f9af-1f9b3, U+1f9b8-1f9b9, U+1f9bc-1f9bd, U+1f9cc-1f9cf, U+1f9d1-1f9df, U+1fa70, U+1fa82, U+1fac3-1fac5, U+1fac8, U+1faef;
}
@font-face {
  font-family: 'Noto Color Emoji';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(/fonts/noto-emoji/noto-emoji.9.woff2) format('woff2');
  unicode-range: U+200d, U+2194-2195, U+2603, U+261d, U+2620, U+2639-263a, U+2665, U+26a1, U+26c4, U+270a-270d, U+2728, U+2763-2764, U+2b50, U+fe0f, U+1f31a-1f31f, U+1f32b, U+1f389-1f38a, U+1f3fb-1f3ff, U+1f440-1f450, U+1f463-1f465, U+1f479-1f47b, U+1f47d-1f480, U+1f485, U+1f48b-1f48c, U+1f493-1f49f, U+1f4a2, U+1f4a4-1f4a6, U+1f4a8-1f4ab, U+1f4af, U+1f525, U+1f573, U+1f590, U+1f595-1f596, U+1f5a4, U+1f5e3, U+1f600-1f644, U+1f648-1f64a, U+1f64c, U+1f64f, U+1f90c-1f925, U+1f927-1f92f, U+1f932-1f933, U+1f970-1f976, U+1f978-1f97a, U+1f9a0, U+1f9b4-1f9b7, U+1f9bb, U+1f9be-1f9bf, U+1f9d0, U+1f9e0-1f9e1, U+1fa75-1fa79, U+1fac0-1fac2, U+1fac6, U+1fae0-1fae6, U+1fae8-1faea, U+1faef-1faf8;
}

/* ═══════════════════════════════════════════════════════════════════
   🚩 Opinie oflagowane (flagged.html)
   ═══════════════════════════════════════════════════════════════════ */
.fl-toolbar { display: flex; align-items: flex-end; gap: 12px; flex-wrap: wrap; }
.fl-toolbar-field { display: flex; flex-direction: column; gap: 4px; }
.fl-toolbar-field .form-label { margin: 0; font-size: 11px; }
.fl-count { margin-left: auto; font-size: 12px; color: var(--muted); font-weight: 600; }
.fl-hint { margin-top: 12px; font-size: 11.5px; color: var(--muted); line-height: 1.55; }

.fl-empty { padding: 40px 20px; text-align: center; color: var(--muted); font-size: 13.5px; line-height: 1.6; }
.fl-muted { color: var(--muted); }

.fl-card { margin-bottom: 14px; border-left: 3px solid #e6a23c; }
.fl-card-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; flex-wrap: wrap; }
.fl-stars { font-size: 15px; }
.fl-author { font-size: 13.5px; font-weight: 600; color: var(--text); margin-left: 6px; }
.fl-location { font-size: 12px; color: var(--muted); margin-top: 3px; }
.fl-maps-link {
  font-size: 11.5px; font-weight: 600; margin-left: 4px;
  color: var(--accent-text, var(--primary)); text-decoration: none;
}
.fl-maps-link:hover { text-decoration: underline; }
.fl-chips { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.fl-chip { font-size: 10.5px; font-weight: 700; padding: 3px 8px; border-radius: 999px; white-space: nowrap; }
.fl-chip-flag { background: rgba(230,162,60,.14); color: #a86a12; border: 1px solid rgba(230,162,60,.3); }
.fl-chip-ok   { background: rgba(72,187,120,.12); color: #1B8A3E; border: 1px solid rgba(72,187,120,.28); }
.fl-chip-wait { background: rgba(113,128,150,.12); color:var(--text,#4a5568); border: 1px solid rgba(113,128,150,.25); }

.fl-review-text { margin: 12px 0; font-size: 13.5px; line-height: 1.6; color: var(--text); white-space: pre-wrap; }

/* Metadane: data opinii / w systemie / oflagowania (z dokładną godziną) */
.fl-meta {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 10px; padding: 12px; margin-top: 4px;
  background: rgba(0,0,0,.025); border-radius: 10px;
}
.fl-meta > div { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.fl-meta-k { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.fl-meta-v { font-size: 12.5px; color: var(--text); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }

.fl-thread-bar { margin-top: 12px; }
.fl-thread { margin-top: 12px; border-top: 1px dashed var(--border); padding-top: 12px; }
.fl-comments { display: flex; flex-direction: column; gap: 10px; margin-bottom: 12px; }
.fl-comment { background: rgba(59,110,240,.05); border: 1px solid rgba(59,110,240,.14); border-radius: 10px; padding: 10px 12px; }
.fl-comment-head { display: flex; justify-content: space-between; gap: 10px; font-size: 11.5px; margin-bottom: 5px; flex-wrap: wrap; }
.fl-comment-body { font-size: 13px; line-height: 1.55; color: var(--text); white-space: pre-wrap; }
.fl-comment-form { display: flex; flex-direction: column; gap: 8px; }
.fl-comment-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* Opinia usunięta z Google — zostaje w rejestrze oflagowanych, wyraźnie oznaczona */
.fl-chip-del { background: var(--crit-soft, rgba(192,57,43,.10)); color: #C0392B; border: 1px solid rgba(192,57,43,.32); }
.fl-card-deleted { border-left-color: #C0392B; }
.fl-deleted-note {
  margin: 10px 0 4px; padding: 9px 12px;
  background: rgba(192,57,43,.07); border: 1px solid rgba(192,57,43,.2);
  border-radius: 9px; font-size: 12.5px; color: #9c2f22; line-height: 1.5;
}

/* ── Grupa robocza (Ustawienia → 🗂️ Grupa robocza) ─────────────────────────── */
.wg-grid { display: flex; flex-direction: column; gap: 10px; }
.wg-item {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 13px 15px; border: 1px solid var(--border); border-radius: 10px;
  background: var(--panel, #fff); flex-wrap: wrap;
}
.wg-item-main { min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.wg-item-name { font-weight: 650; font-size: 14px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.wg-item-desc { font-size: 12.5px; color: var(--muted); }
.wg-item-count { font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.wg-item-actions { display: flex; gap: 6px; flex-shrink: 0; }
.wg-badge {
  font-size: 10px; font-weight: 700; letter-spacing: .02em;
  padding: 2px 7px; border-radius: 999px;
  background: rgba(113,128,150,.13); color:var(--text,#4a5568);
}
.wg-badge-own    { background: rgba(59,110,240,.12); color: #2c56c9; }
.wg-badge-global { background: rgba(72,187,120,.14); color: #1B7F45; }

.wg-locations {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 6px;
  max-height: 280px; overflow-y: auto;
  padding: 10px; border: 1px solid var(--border); border-radius: 10px;
}
.wg-loc {
  display: flex; align-items: center; gap: 8px;
  font-size: 13px; padding: 5px 7px; border-radius: 7px; cursor: pointer;
  transition: background .12s;
}
.wg-loc:hover { background: rgba(59,110,240,.06); }
.wg-loc input { flex-shrink: 0; cursor: pointer; }
.wg-loc span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }


/* ═══════════════════════════════════════════════════════════════════
   UWAGA KOLEJNOŚCI: sekcja mobilna MUSI zostać na SAMYM KOŃCU arkusza.
   Media query NIE podnosi specyficzności, więc przy równej specyficzności
   decyduje kolejność w pliku. Gdy blok stał wyżej, bazowe reguły zdefiniowane
   niżej (np. `.drb-presets { flex-wrap: wrap }`) po cichu wygrywały z jego
   mobilnymi odpowiednikami — objaw: presety dat zawijały się do dwóch rzędów
   mimo jawnego `flex-wrap: nowrap`. Nie przenoś tego bloku wyżej i nie
   "naprawiaj" tego przez !important.
   ═══════════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════
   POWŁOKA MOBILNA (≤900px)
   ───────────────────────────────────────────────────────────────────
   Trzy elementy budowane w JS (app.js → initMobileShell), żeby nie
   duplikować markupu w 16 plikach HTML:
     .m-appbar  — przypięty górny pasek (hamburger + tytuł + akcje)
     .m-tabbar  — dolna nawigacja z najważniejszymi zakładkami
     .sidebar   — pełna nawigacja jako szuflada (gest przeciągnięcia)

   PROGRESSIVE ENHANCEMENT: reguły zależne od tych elementów są kluczowane
   klasami `m-has-appbar` / `m-has-tabbar` nadawanymi przez JS DOPIERO po ich
   utworzeniu. Gdy JS nie wykona się z jakiegokolwiek powodu, strona zostaje
   w pełni używalna w starym układzie (tytuł strony się nie chowa, treść nie
   ma sierocego odstępu na nieistniejący pasek) — świadomie, to jedyna
   siatka bezpieczeństwa dla powłoki tworzonej po stronie klienta.

   WYDAJNOŚĆ NA ANDROIDZIE: `backdrop-filter` to najdroższa operacja
   kompozycji na mobilnych GPU (ten sam wniosek co [v1.47] dla Windowsa) —
   na telefonie promień jest mocno obcięty, a na platformach nie-Apple
   wyłączony całkowicie i zastąpiony wyższym kryciem tła. Wszystkie animacje
   powłoki jadą WYŁĄCZNIE na `transform`/`opacity` (kompozycja GPU, zero
   layoutu), więc pozostają płynne także na słabszym sprzęcie.
   ═══════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {

  /* ── Tokeny mobilne ─────────────────────────────────────────── */
  :root {
    --blur:     blur(10px) saturate(150%);   /* z 24px — Android kompozytuje to wielokrotnie drożej */
    --lg-blur:  blur(10px);
    --surface:  rgba(255,255,255,.86);       /* rekompensata krycia za obcięty blur */
    --radius-card: 18px;
    --m-appbar-h: 56px;
    --m-tabbar-h: 60px;
    --m-gutter: 16px;
    --m-safe-b: env(safe-area-inset-bottom, 0px);
  }
  /* Android/Windows: blur znika całkowicie, tło robi się nieprzezroczyste. */
  html.plt-noapple {
    --blur: none;
    --lg-blur: none;
    --surface: rgba(255,255,255,.95);
  }
  html.plt-noapple .sidebar,
  html.plt-noapple .modal,
  html.plt-noapple .m-appbar,
  html.plt-noapple .m-tabbar { backdrop-filter: none; -webkit-backdrop-filter: none; }
  /* Animowane bloby tła wymuszają przeliczanie kompozycji CO KLATKĘ pod każdą
     szklaną powierzchnią — na telefonie zamrożone (koszt #1, lekcja z [v1.47]). */
  body::before, body::after { animation: none !important; }

  /* ── Układ bazowy ───────────────────────────────────────────── */
  .app-container { min-height: 100dvh; }
  .main-content  { margin-left: 0; min-height: 100dvh; }
  html { scrollbar-gutter: auto; }          /* na telefonie scrollbar jest nakładkowy */

  /* ── Górny pasek aplikacji ──────────────────────────────────── */
  .m-appbar {
    position: sticky; top: 0; z-index: 90;
    display: flex; align-items: center; gap: 6px;
    height: var(--m-appbar-h);
    padding: 0 8px 0 6px;
    background: rgba(255,255,255,.82);
    backdrop-filter: blur(18px) saturate(170%);
    -webkit-backdrop-filter: blur(18px) saturate(170%);
    border-bottom: 1px solid rgba(15,23,42,.07);
    transition: transform .28s var(--sb-ease), box-shadow .2s ease;
  }
  /* Cień pojawia się dopiero po odjechaniu treści spod paska — dopóki strona
     jest na górze, pasek ma zlewać się z tłem (wzorzec natywny). */
  .m-appbar.m-scrolled { box-shadow: 0 4px 18px rgba(15,23,42,.09); }
  /* Chowanie przy przewijaniu w dół oddaje ~56 px wysokości treści.
     `transform` — bez reflow, tanio nawet na słabym GPU. */
  .m-appbar.m-hidden { transform: translateY(-100%); }

  .m-appbar-title {
    flex: 1; min-width: 0;
    font-size: 17px; font-weight: 700; letter-spacing: -.35px; color: var(--text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  }
  .m-appbar-actions { display: flex; align-items: center; gap: 4px; flex-shrink: 0; }

  /* Tytuł żyje teraz w pasku — w treści byłby zdublowany. */
  html.m-has-appbar .page-title { display: none; }
  html.m-has-appbar .page-header {
    padding: 12px var(--m-gutter) 0;
    gap: 8px;
    align-items: center;
  }
  /* Pusty nagłówek (strona bez akcji) nie może zostawiać pionowej dziury. */
  html.m-has-appbar .page-header:empty,
  html.m-has-appbar .page-header.m-ph-titleonly { display: none; padding: 0; }

  /* ── Hamburger ──────────────────────────────────────────────── */
  .sb-burger {
    display: flex;
    position: static;                 /* w pasku, nie „pływa" nad treścią */
    top: auto; left: auto;
    width: 40px; height: 40px;
    border: none; background: transparent; box-shadow: none;
    backdrop-filter: none; -webkit-backdrop-filter: none;
    border-radius: 12px;
    font-size: 19px; color: var(--text);
    -webkit-tap-highlight-color: transparent;
    transition: background .15s ease, transform .12s ease;
  }
  .sb-burger:active { background: rgba(15,23,42,.08); transform: scale(.92); }
  .sb-toggle { display: none; }

  /* ── Szuflada nawigacji ─────────────────────────────────────── */
  .sidebar {
    width: min(300px, 84vw);
    transform: translateX(-102%);
    box-shadow: none;
    border-right: none;
    background: rgba(255,255,255,.9);
    backdrop-filter: blur(22px) saturate(170%);
    -webkit-backdrop-filter: blur(22px) saturate(170%);
    overscroll-behavior: contain;     /* przewijanie menu nie „przecieka" na stronę pod spodem */
    padding-bottom: var(--m-safe-b);
  }
  html.sb-open .sidebar {
    transform: translateX(0);
    box-shadow: 0 0 60px rgba(15,23,42,.3);
  }
  /* Podczas przeciągania palcem pozycją steruje JS (--sb-drag) — tranzycja
     musi zniknąć, inaczej panel wlecze się za palcem zamiast go śledzić. */
  html.sb-dragging .sidebar { transition: none; transform: translateX(var(--sb-drag, 0px)); }
  html.sb-dragging .sb-backdrop { transition: none; }

  .sb-backdrop {
    display: block;                   /* zawsze w drzewie — inaczej nie da się animować krycia */
    pointer-events: none;
    opacity: 0;
    background: rgba(15,23,42,.5);
    -webkit-tap-highlight-color: transparent;
  }
  html.sb-open .sb-backdrop { pointer-events: auto; opacity: 1; }

  /* Blokada przewijania tła przy otwartej szufladzie (pozycję przywraca JS). */
  body.m-scroll-locked {
    position: fixed; width: 100%; overflow: hidden;
  }

  /* Wejście pozycji menu kaskadą — sam `transform`/`opacity`. */
  html.sb-open .nav-links li {
    animation: mNavIn .34s var(--sb-ease) backwards;
  }
  html.sb-open .nav-links li:nth-child(1) { animation-delay: .02s }
  html.sb-open .nav-links li:nth-child(2) { animation-delay: .04s }
  html.sb-open .nav-links li:nth-child(3) { animation-delay: .06s }
  html.sb-open .nav-links li:nth-child(4) { animation-delay: .08s }
  html.sb-open .nav-links li:nth-child(5) { animation-delay: .10s }
  html.sb-open .nav-links li:nth-child(6) { animation-delay: .12s }
  html.sb-open .nav-links li:nth-child(7) { animation-delay: .14s }
  html.sb-open .nav-links li:nth-child(n+8) { animation-delay: .16s }
  @keyframes mNavIn {
    from { opacity: 0; transform: translateX(-14px); }
    to   { opacity: 1; transform: none; }
  }

  /* Zwinięcie z desktopu nie może „przeciekać" na telefon — szuflada zawsze pełna */
  html.sb-collapsed { --sidebar-w: 240px; }
  html.sb-collapsed .nav-link { font-size: 15px; gap: 12px; justify-content: flex-start; padding: 12px 14px; }
  html.sb-collapsed .app-title { font-size: 17px; text-align: left; }
  html.sb-collapsed .app-title::before { content: none; }
  html.sb-collapsed .app-subtitle,
  html.sb-collapsed .user-info > div { display: block; }
  html.sb-collapsed .logout-btn { font-size: 14px; padding: 12px 14px; }
  html.sb-collapsed .logout-btn::before { content: none; }
  html.sb-collapsed .sidebar-header { text-align: left; padding-left: 20px; padding-right: 20px; }

  /* Cel dotykowy ≥44 px (wytyczne Apple HIG / Material) */
  .nav-link  { padding: 12px 14px; font-size: 15px; border-radius: 14px; min-height: 44px; }
  .nav-link .nav-icon { font-size: 18px; width: 24px; }
  .nav-link:active { background: rgba(59,110,240,.12); }
  .sidebar-header { padding: 20px 20px 14px; }
  .logout-btn { padding: 12px; font-size: 14px; min-height: 44px; }

  /* ── Dolny pasek POD-ZAKŁADEK bieżącej strony ────────────────
     Pasek źródłowy w treści jest na telefonie chowany (JS nadaje mu klasę
     `m-subbar-src`) — inaczej te same przyciski byłyby na ekranie dwa razy.
     `!important`, bo Ustawienia sterują nim inline'owym `style.display`. */
  .subtabs.m-subbar-src, .pe-tablist.m-subbar-src, .rank-viewtabs.m-subbar-src {
    display: none !important;
  }

  .m-tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 95;
    display: flex; align-items: stretch;
    height: calc(var(--m-tabbar-h) + var(--m-safe-b));
    padding-bottom: var(--m-safe-b);
    background: rgba(255,255,255,.88);
    backdrop-filter: blur(20px) saturate(180%);
    -webkit-backdrop-filter: blur(20px) saturate(180%);
    border-top: 1px solid rgba(15,23,42,.08);
    box-shadow: 0 -2px 18px rgba(15,23,42,.06);
  }
  /* Więcej niż 4 pod-zakładki (Ustawienia mają 7) nie mieszczą się na 375 px —
     pasek przewija się wtedy w poziomie. `touch-action: pan-x` jest tu
     KLUCZOWE: bez niego ukośne przeciągnięcie palcem przewijało jednocześnie
     stronę w pionie i przyciski „skakały” góra-dół. Pasek jest `fixed`, więc
     przy pan-x ruch pionowy nie rusza nim wcale. */
  .m-tabbar.m-tabbar-scroll {
    justify-content: flex-start;
    overflow-x: auto; overflow-y: hidden;
    touch-action: pan-x;
    overscroll-behavior: contain;
    scroll-snap-type: x proximity;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
  }
  .m-tabbar.m-tabbar-scroll::-webkit-scrollbar { display: none; }
  .m-tabbar.m-tabbar-scroll .m-tab {
    flex: 0 0 auto; min-width: 92px;
    scroll-snap-align: center;
  }

  .m-tab {
    flex: 1 1 0; min-width: 0;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 3px; padding: 6px 2px;
    background: none; border: none; cursor: pointer;
    color: var(--muted); text-decoration: none;
    -webkit-tap-highlight-color: transparent;
    transition: color .18s ease;
  }
  .m-tab-icon {
    font-size: 19px; line-height: 1;
    transition: transform .26s var(--sb-ease);
  }
  .m-tab-label {
    font-size: 10px; font-weight: 600; letter-spacing: .1px;
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  .m-tab:active .m-tab-icon { transform: scale(.86); }
  .m-tab.active { color: var(--primary); }
  .m-tab.active .m-tab-icon { transform: translateY(-1px) scale(1.08); }
  /* Wskaźnik aktywnej zakładki — pigułka nad ikoną. */
  .m-tab.active::before {
    content: ""; position: absolute; top: 0;
    width: 26px; height: 3px; border-radius: 0 0 3px 3px;
    background: var(--primary);
    animation: mTabIn .3s var(--sb-ease);
  }
  .m-tab { position: relative; }
  @keyframes mTabIn { from { transform: scaleX(0); opacity: 0 } to { transform: none; opacity: 1 } }

  /* Treść musi kończyć się nad paskiem, inaczej ostatnia karta jest pod nim. */
  html.m-has-tabbar .page-body { padding-bottom: calc(var(--m-tabbar-h) + var(--m-safe-b) + 20px); }
  html.m-has-tabbar #toast-container { bottom: calc(var(--m-tabbar-h) + var(--m-safe-b) + 12px); }

  /* ── Treść: siatki, karty, typografia ───────────────────────── */
  .page-body { padding: 14px var(--m-gutter) 28px; }

  .stats-grid, .kpi-grid {
    grid-template-columns: repeat(2, 1fr) !important;
    gap: 10px !important; margin-bottom: 16px;
  }
  .locations-grid { grid-template-columns: 1fr !important; gap: 12px; }

  /* Siatki zdefiniowane INLINE w HTML (`style="grid-template-columns:2fr 1fr"`
     i podobne — 7 miejsc w dashboard/schedule/reports/analytics). Inline style
     przebija każdą zwykłą regułę arkusza, więc bez `!important` zostawałyby
     dwukolumnowe na 375 px i rozpychały układ (zmierzone: kolumny 334+334 px
     w kontenerze 349 px). Reguła jest CELOWO generyczna — obejmie też siatki
     dodane inline w przyszłości, bez potrzeby pamiętania o tym miejscu.
     `.stats-grid`/`.kpi-grid` mają wyżej własny, dwukolumnowy wariant. */
  [style*="grid-template-columns"]:not(.stats-grid):not(.kpi-grid) {
    grid-template-columns: 1fr !important;
  }

  /* Nieparzysta liczba kafelków (Dashboard ma 5 statystyk i 5 progów ocen)
     zostawiała w dwukolumnowej siatce pustą połowę wiersza. Ostatni samotny
     kafelek rozciąga się na pełną szerokość — wygląda jak decyzja, nie jak błąd. */
  .stats-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }

  .card      { padding: 16px; border-radius: var(--radius-card); }
  .stat-card { padding: 14px; border-radius: var(--radius-card); }
  .stat-label { font-size: 10px; letter-spacing: .4px; }
  .stat-value { font-size: 24px; margin: 6px 0 2px; letter-spacing: -.6px; }
  .stat-sub   { font-size: 11px; }
  .card-title { font-size: 14px; margin-bottom: 12px; }

  /* Wejście kart przy wczytaniu strony — subtelne, wyłącznie transform/opacity. */
  .stats-grid > *, .locations-grid > * { animation: mCardIn .38s var(--sb-ease) backwards; }
  .stats-grid > :nth-child(2), .locations-grid > :nth-child(2) { animation-delay: .04s }
  .stats-grid > :nth-child(3), .locations-grid > :nth-child(3) { animation-delay: .08s }
  .stats-grid > :nth-child(4), .locations-grid > :nth-child(4) { animation-delay: .12s }
  .stats-grid > :nth-child(n+5), .locations-grid > :nth-child(n+5) { animation-delay: .16s }
  @keyframes mCardIn { from { opacity: 0; transform: translateY(10px) } to { opacity: 1; transform: none } }

  /* ── Kontrolki ──────────────────────────────────────────────── */
  .btn { min-height: 44px; padding: 11px 18px; font-size: 14px; border-radius: 14px; }
  .btn-sm { min-height: 36px; padding: 8px 13px; font-size: 12.5px; }
  .btn:active { transform: scale(.96); }

  /* 16px to próg, poniżej którego iOS Safari SAM przybliża stronę przy wejściu
     w pole — i już z niej nie odzoomowuje. Dotyczy każdego pola tekstowego. */
  .form-control, input, select, textarea,
  .ui-sel-trigger, .ui-date-trigger, .drb-date-input {
    font-size: 16px !important;
    /* Kontrolki formularza NIE dziedziczą kroju z `body` (nadpisuje je arkusz
       przeglądarki) — `textarea` renderowała się domyślnym monospace, co w
       oknie odpowiedzi na opinię wyglądało jak pole terminala. */
    font-family: inherit;
  }
  .form-control { padding: 12px 14px; border-radius: 14px; min-height: 46px; }
  .form-label { font-size: 13px; margin-bottom: 7px; }

  /* ── Paski filtrów / zakładek: przewijanie poziome ze snapem ── */
  .subtabs, .drb-presets, .ed-views, .range-tabs, .au-presets, .page-header, .fl-toolbar {
    overflow-x: auto; flex-wrap: nowrap;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
  }
  .subtabs::-webkit-scrollbar, .drb-presets::-webkit-scrollbar,
  .page-header::-webkit-scrollbar, .fl-toolbar::-webkit-scrollbar { display: none; }
  .subtab, .drb-preset, .ed-view, .range-btn, .au-preset, .page-header > *, .fl-toolbar > * { flex-shrink: 0; white-space: nowrap; }
  .subtabs { scroll-snap-type: x proximity; gap: 2px; }
  .subtab  { scroll-snap-align: start; padding: 11px 14px; font-size: 13.5px; }

  .date-range-bar { padding: 8px 10px; gap: 8px; flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  .date-range-bar::-webkit-scrollbar { display: none; }

  /* ── Filtry zwijane (Opinie: 8 kontrolek = cały ekran przed 1. opinią) ──
     Panel jest UKRYWANY WIZUALNIE, ale elementy zostają dokładnie tam, gdzie
     były w DOM — `reviews.js` odpytuje je po `id` i każde przeniesienie
     (wrapper, `display:none` na rodzicu) zerwałoby te odwołania. Stąd
     max-height + visibility zamiast restrukturyzacji markupu. */
  .m-filters-toggle {
    display: flex; align-items: center; gap: 8px;
    width: 100%; min-height: 44px; margin-bottom: 12px;
    padding: 11px 14px;
    border: 1px solid var(--border-soft); border-radius: 14px;
    background: rgba(255,255,255,.72);
    color: var(--text); font-size: 14px; font-weight: 600;
    cursor: pointer; -webkit-tap-highlight-color: transparent;
  }
  .m-filters-toggle .m-ft-count {
    margin-left: auto; min-width: 21px; height: 21px; padding: 0 6px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 999px; background: var(--primary); color: #fff;
    font-size: 11px; font-weight: 700;
  }
  .m-filters-toggle .m-ft-count[hidden] { display: none; }
  .m-filters-toggle .m-ft-chev { transition: transform .26s var(--sb-ease); font-size: 11px; color: var(--muted); }
  .m-filters-toggle[aria-expanded="true"] .m-ft-chev { transform: rotate(180deg); }

  .filters.m-collapsible {
    max-height: 0; opacity: 0; visibility: hidden;
    margin-bottom: 0; overflow: hidden;
    transition: max-height .3s var(--sb-ease), opacity .2s ease,
                margin-bottom .3s var(--sb-ease), visibility 0s .3s;
  }
  .filters.m-collapsible.m-open {
    max-height: 640px; opacity: 1; visibility: visible;
    margin-bottom: 16px;
    transition: max-height .34s var(--sb-ease), opacity .24s ease,
                margin-bottom .34s var(--sb-ease), visibility 0s;
  }
  /* W rozwiniętym panelu kontrolki mają wypełniać szerokość, nie kleić się
     w nieregularne rzędy — na telefonie dwie kolumny czytają się najlepiej. */
  .filters.m-collapsible { flex-wrap: wrap; gap: 10px; }
  .filters.m-collapsible > * { flex: 1 1 calc(50% - 5px); min-width: 0; }
  .filters.m-collapsible > .rating-filter,
  .filters.m-collapsible > button { flex: 1 1 100%; }

  /* ── Tabele: własny kontener przewijania zamiast rozpychania strony ── */
  .table-wrapper { overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
  .table-wrapper table { min-width: max-content; }
  /* Karta zawierająca gołą tabelę (bez `.table-wrapper`) — a takich w projekcie
     jest sporo — dostaje przewijanie sama, zamiast rozciągać cały układ.
     `:has()` jest wspierane przez wszystkie docelowe przeglądarki mobilne;
     tam gdzie nie jest, po prostu nic się nie dzieje (bezpieczny degrade). */
  .card:has(> table) { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .card:has(> table) > table { min-width: max-content; }
  thead th { padding: 9px 12px; font-size: 10.5px; }
  tbody td { padding: 11px 12px; font-size: 13px; }

  /* ── Modale jako dolne arkusze (bottom sheet) ───────────────── */
  .modal-overlay { align-items: flex-end; padding: 0; }
  .modal {
    max-width: 100% !important; width: 100%;
    border-radius: 22px 22px 0 0;
    max-height: 92dvh;
    padding-bottom: var(--m-safe-b);
    transform: translateY(100%);
    transition: transform .34s var(--sb-ease);
    border-bottom: none;
    overscroll-behavior: contain;
  }
  .modal-overlay.open .modal { transform: translateY(0); }
  /* Uchwyt przeciągania — czytelny sygnał „to jest arkusz, da się zamknąć". */
  .modal-header { position: relative; padding: 24px 20px 14px; }
  .modal-header::before {
    content: ""; position: absolute; top: 8px; left: 50%;
    width: 38px; height: 4px; margin-left: -19px;
    border-radius: 999px; background: rgba(15,23,42,.18);
  }
  .modal-body   { padding: 18px 20px; }
  /* Nagłówek i stopka przypięte do krawędzi przewijanego arkusza. Bez tego
     przy dłuższej treści (okno odpowiedzi na opinię) przycisk „Wyślij" i „×"
     wyjeżdżały poza ekran i trzeba było ich szukać przewijaniem — na telefonie
     to najczęstszy powód porzucenia akcji. */
  .modal-header {
    position: sticky; top: 0; z-index: 2;
    background: rgba(255,255,255,.94);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  }
  .modal-footer {
    position: sticky; bottom: 0; z-index: 2;
    padding: 14px 20px calc(14px + var(--m-safe-b)); gap: 10px;
    background: rgba(255,255,255,.94);
    backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  }
  html.plt-noapple .modal-header,
  html.plt-noapple .modal-footer { background:var(--surface-solid,#fff); backdrop-filter: none; -webkit-backdrop-filter: none; }
  .modal-footer .btn { flex: 1; justify-content: center; }
  .modal-close { width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; }

  /* ── Toasty: od dołu, nie zza prawej krawędzi ───────────────── */
  #toast-container { left: 12px; right: 12px; bottom: 16px; align-items: stretch; }
  .toast {
    max-width: none; border-radius: 14px; padding: 13px 16px;
    transform: translateY(140%);
    transition: transform .32s var(--sb-ease), opacity .2s ease;
    box-shadow: 0 8px 28px rgba(15,23,42,.24);
  }
  .toast.show { transform: translateY(0); }

  /* ── Pozycje lokalne (brak .page-header — pasek i tak jest przypięty) ── */
  .rank-main   { height: auto; overflow: visible; }
  .rank-layout { flex-direction: column; height: auto; overflow: visible; }
  .rank-left, .rank-right {
    width: 100% !important; border: none;
    border-bottom: 1px solid var(--border); max-height: none;
  }
  .rank-map-col { min-height: 66vh; }
  #map { min-height: 54vh; }
  .rank-topbar { padding: 12px 14px; }
  .rank-viewtabs { width: 100%; }
  .rank-viewtab { flex: 1; justify-content: center; min-height: 42px; }
  /* `!important` konieczne: bazowa reguła `.rank-main { padding: 0 !important }`
     inaczej wygrywa i dolny pasek zasłania koniec widoku historii pozycji. */
  html.m-has-tabbar .rank-main { padding-bottom: calc(var(--m-tabbar-h) + var(--m-safe-b)) !important; }

  /* ── Logowanie / zaproszenie (brak powłoki, ale ten sam standard) ── */
  .login-card { padding: 32px 22px; border-radius: 22px; margin: 16px; }
  .login-title { font-size: 21px; }
}

/* ── Bardzo wąskie ekrany ─────────────────────────────────────── */
@media (max-width: 560px) {
  :root { --m-gutter: 13px; }
  .page-header { align-items: center; }
  .fl-toolbar-field { min-width: 190px; }
  .fl-count { margin-left: 0; }
  .fl-meta { grid-template-columns: 1fr; }
  .wg-item { flex-direction: column; align-items: flex-start; }
  .rank-history-chart { height: 260px; }
  .stat-value { font-size: 22px; }
  .m-tab-label { font-size: 9.5px; }
}

/* ── Bardzo niskie ekrany w poziomie: dolny pasek zjada zbyt dużo ──
   Skoro trzyma teraz POD-ZAKŁADKI, samo jego ukrycie odcięłoby dostęp do nich
   — dlatego równocześnie przywracamy pasek źródłowy w treści strony. */
@media (max-width: 900px) and (max-height: 460px) {
  .m-tabbar { display: none; }
  html.m-has-tabbar .page-body { padding-bottom: 24px; }
  .subtabs.m-subbar-src, .pe-tablist.m-subbar-src { display: flex !important; }
  .rank-viewtabs.m-subbar-src { display: inline-flex !important; }
}

@media (prefers-reduced-motion: reduce) {
  .sidebar, .main-content, .sb-backdrop, .m-appbar, .modal, .toast { transition: none !important; }
  .m-appbar.m-hidden { transform: none !important; }
  html.sb-open .nav-links li,
  .stats-grid > *, .locations-grid > *,
  .m-tab.active::before { animation: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOTYW 2.0 — JASNY (domyślny) + CIEMNY (html.theme-dark)          [v1.60]
   ═══════════════════════════════════════════════════════════════════════════
   Język designu przeniesiony z gałęzi „GMB Manager 2.0" (blok v2.01
   `html.theme-light`): ta sama geometria co wariant ciemny, akcent #3768ea,
   SOLIDNA niebieska pigułka aktywnej nawigacji, półprzezroczyste badge
   z obwódką, miękkie cienie w tonacji granatowej zamiast czystej czerni.

   ARCHITEKTURA (ważne przy każdej przyszłej zmianie):
   • JASNY jest DOMYŚLNY — definiowany tu, na `:root`, bez żadnej klasy.
   • CIEMNY jest opcjonalny — cały blok niżej ma prefiks `html.theme-dark`
     (specyficzność 0,2,1), więc wygrywa z jasnym BEZ `!important` i
     niezależnie od pozycji. Przełącznik siedzi w stopce panelu bocznego,
     wybór trzymany w `localStorage('gmbTheme')` i nakładany SYNCHRONICZNIE
     w inline-skrypcie `<head>` każdej strony — wzorzec anty-FOUC z
     [v1.05]/[v1.33]. Bez tego przy każdej nawigacji mignąłby jasny motyw.
   • Oba bloki stoją na KOŃCU pliku, za sekcją mobilną [v1.56] i za
     `plt-noapple` [v1.47], bo tamte hardkodują tła, a media query nie
     podnosi specyficzności. NIE przenoś ich wyżej.

   Wartości pochodzą z 2.0 z trzema korektami kontrastu (policzonymi, nie
   „na oko") — patrz komentarze przy `--muted` i `--sidebar-text`.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  color-scheme: light;
  accent-color: #3768ea;

  /* 2.0 miało #3b6ef0. Jako TŁO przycisku z białym tekstem dawało 4.49:1
     (o 0.01 poniżej AA), a jako TEKST na jasnej powierzchni 4.32:1 — też
     poniżej. #3768ea załatwia oba naraz: 4.85:1 pod białym tekstem i
     4.67:1 jako tekst. Różnica barwy niewidoczna gołym okiem (ΔE ≈ 2).  */
  --primary:      #3768ea;
  --primary-dark: #2f5ad6;
  --primary-glow: rgba(55,104,234,.30);

  /* Sidebar = jasne szkło */
  --sidebar-bg:    rgba(255,255,255,.60);
  /* 2.0 miało .55 → 3.67:1 ❌. .66 daje 5.5:1 i nadal czyta się lekko. */
  --sidebar-text:  rgba(22,32,58,.66);
  --sidebar-hover: rgba(22,32,58,.05);
  --sidebar-active:#3768ea;

  --bg:            #eef2fb;
  --surface:       rgba(255,255,255,.66);
  --surface-solid: #ffffff;
  --border:        rgba(255,255,255,.85);
  --border-soft:   rgba(22,32,58,.09);
  --text:          #16203a;
  /* 2.0 miało .48 → 3.01:1 ❌ dla tekstu <18px. To najczęstszy kolor
     drugorzędny w aplikacji (meta opinii, etykiety, opisy pól), więc musi
     przechodzić AA. .66 = 5.26:1 na białej karcie (.62 dawało 4.43:1 —
     wystarczało nad półprzezroczystą powierzchnią, ale NIE nad solidnie
     białą, a takich kart jest w aplikacji sporo).                       */
  --muted:         rgba(22,32,58,.66);
  --success:       #15803d;
  --warning:       #b45309;
  --danger:        #dc2626;
  --danger-dark:   #dc2626;

  --radius:        12px;
  --radius-card:   22px;
  --shadow:        0 4px 24px rgba(31,41,74,.08), inset 0 1px 0 rgba(255,255,255,.85);
  --shadow-lg:     0 16px 48px rgba(31,41,74,.16);
  --blur:          blur(32px) saturate(150%);

  /* Tokeny wprowadzone w [v1.60] przy tokenizacji hardkodów w JS/HTML.
     Wartości jasne = dawne literalne kolory, żeby nic nie zmieniło się
     przypadkiem; ciemne odpowiedniki są w bloku html.theme-dark.        */
  --surface-raised: #ffffff;              /* popupy, dropdowny            */
  --surface-sunken: #f8fafc;              /* wiersze list, „wgłębienia"   */
  --overlay:        rgba(20,24,40,.30);   /* tło modali                   */
  --row-error:      #fff5f5;              /* wiersz tabeli ze statusem błędu */
  --info-fg:        #1e40af;
  --warn-fg:        #92400e;
  --err-fg:         #b91c1c;
  /* Akcent jako TEKST musi być ciemniejszy niż akcent jako TŁO: #3768ea
     na SOLIDNIE białej karcie daje tylko 4.32:1. #2f5ad6 = 5.6:1.
     W motywie ciemnym ta sama zmienna idzie w drugą stronę (jaśniej).   */
  --accent-text:    #2f5ad6;

  /* Gwiazdki — progi z [v1.03] BEZ ZMIAN, tylko paleta. */
  --color-5star: #166534;
  --color-4star: #16a34a;
  --color-3star: #d97706;
  --color-2star: #ea580c;
  --color-1star: #c62828;

  /* Liquid glass ([v1.10]) */
  --lg-bg:       rgba(255,255,255,.55);
  --lg-bg-hover: rgba(255,255,255,.85);
  --lg-border:   rgba(22,32,58,.10);
  --lg-shadow:   0 2px 10px rgba(31,41,74,.10), inset 0 1px 0 rgba(255,255,255,.7);
  --lg-text:     rgba(22,32,58,.75);
}

/* ── Tło ────────────────────────────────────────────────────────────────────
   Chłodne, rozmyte poświaty zamiast pastelowych oklch z 1.0. Bloby
   (`body::before/::after`) zostają na `transform` i są nadal zamrażane
   pod `plt-noapple`, na telefonie i przy `prefers-reduced-motion`.      */
body {
  background:
    radial-gradient(ellipse 65vw 55vh at 88% -8%, rgba(140,170,255,.40) 0%, rgba(170,195,255,.18) 35%, transparent 70%),
    radial-gradient(ellipse 55vw 55vh at -8% 108%, rgba(165,150,255,.28) 0%, transparent 65%),
    radial-gradient(ellipse 45vw 40vh at 55% 55%, rgba(120,190,235,.18) 0%, transparent 70%),
    #eef2fb;
  background-attachment: fixed;
  color: var(--text);
}
body::before {
  background-image:
    radial-gradient(circle at 18% 12%, rgba(150,180,255,.35) 0%, transparent 42%),
    radial-gradient(circle at 82% 70%, rgba(175,160,255,.28) 0%, transparent 40%);
  opacity: .55;
}
body::after {
  background-image:
    radial-gradient(circle at 60% 92%, rgba(120,190,235,.25) 0%, transparent 44%),
    radial-gradient(circle at 8% 78%, rgba(150,180,255,.22) 0%, transparent 38%);
  opacity: .4;
}
::selection { background: rgba(55,104,234,.25); color: #16203a; }

/* ── Sidebar — jasne szkło, aktywna pozycja to SOLIDNA niebieska pigułka.
   To najbardziej charakterystyczny element języka 2.0; 1.0 miało tu białą
   szklaną pigułkę, która gubiła się na jasnym tle.                       */
.sidebar {
  background: var(--sidebar-bg);
  border-right: 1px solid rgba(255,255,255,.8);
  box-shadow: inset 1px 0 0 rgba(255,255,255,.6), 4px 0 32px rgba(31,41,74,.06);
}
.sidebar-header,
.sidebar-footer,
.app-version      { border-color: rgba(22,32,58,.07); }
.nav-section-label{ color: rgba(22,32,58,.45); }
.nav-link:hover   { background: var(--sidebar-hover); color: var(--text); }
.nav-link.active  {
  background: var(--primary);
  color: #fff;
  box-shadow: 0 2px 12px rgba(55,104,234,.35);
}
.user-info        { background: rgba(255,255,255,.6); border: 1px solid rgba(22,32,58,.07); }
.user-avatar      { background: rgba(22,32,58,.06); }
.logout-btn       { background: rgba(255,255,255,.6); border: 1px solid rgba(22,32,58,.09); }
.logout-btn:hover { background: #fff; color: var(--text); }
.sb-toggle        { background: rgba(255,255,255,.72); border-color: rgba(22,32,58,.10); color: var(--muted); }
.sb-toggle:hover  { background: #fff; color: var(--primary); }
.sb-burger        { background: rgba(255,255,255,.92); border-color: rgba(22,32,58,.10); color: var(--text); }

/* ── Tabele ─────────────────────────────────────────────────────────────── */
thead th          { background: rgba(22,32,58,.035); border-bottom: 1px solid var(--border-soft); }
tbody td          { border-bottom: 1px solid rgba(22,32,58,.06); }
tbody tr:hover td { background: rgba(22,32,58,.03); }

/* ── Formularze ─────────────────────────────────────────────────────────── */
.form-control {
  background: rgba(255,255,255,.75);
  border: 1.5px solid rgba(22,32,58,.12);
  color: var(--text);
}
.form-control::placeholder { color: rgba(22,32,58,.42); }
.form-control:focus {
  border-color: rgba(55,104,234,.5);
  box-shadow: 0 0 0 3px rgba(55,104,234,.10);
}
.filter-select {
  background: rgba(255,255,255,.75);
  border-color: rgba(22,32,58,.12);
  color: rgba(22,32,58,.8);
}
select option { background: #fff; color: #16203a; }
.ui-sel-trigger, .ui-date-trigger, input[type="time"] {
  background: rgba(255,255,255,.75);
  border-color: rgba(22,32,58,.12);
  color: var(--text);
}
.ui-sel-popup, .ui-date-popup { background: rgba(255,255,255,.97); border: 1px solid rgba(22,32,58,.10); }

/* ── Przyciski ──────────────────────────────────────────────────────────── */
.btn-secondary {
  background: rgba(255,255,255,.8);
  color: rgba(22,32,58,.78);
  border: 1px solid rgba(22,32,58,.11);
}
.btn-secondary:hover { background: #fff; color: var(--text); }
.btn-icon-sm:hover:not(:disabled) { color: var(--primary); }
.btn-deactivate:hover:not(:disabled) { background: rgba(220,38,38,.10) !important; }
/* Biały tekst na #dc2626 = 4.84:1 (na #e53e3e było 3.9:1). */
.btn-danger       { background: #dc2626; box-shadow: 0 3px 14px rgba(220,38,38,.22); }
.btn-danger:hover { background: #b91c1c; }

/* ── Badge — półprzezroczyste z obwódką (sygnatura 2.0) ─────────────────── */
.badge-success { background: rgba(34,197,94,.13);  color: #166534; border: 1px solid rgba(34,197,94,.28); }
.badge-danger  { background: rgba(239,68,68,.12);  color: #b91c1c; border: 1px solid rgba(239,68,68,.25); }
.badge-warning { background: rgba(245,158,11,.14); color: #92400e; border: 1px solid rgba(245,158,11,.30); }
.badge-info    { background: rgba(59,130,246,.12); color: #1d4ed8; border: 1px solid rgba(59,130,246,.25); }
.badge-neutral { background: rgba(22,32,58,.06);   color: rgba(22,32,58,.7); border: 1px solid rgba(22,32,58,.09); }
.source-badge  { color: #1d4ed8; }
.edited-badge  { background: rgba(139,92,246,.12); color: #6d28d9; }
.loc-badge     { background: rgba(55,104,234,.12); color: #1d4ed8; }
.media-badge   { background: rgba(245,158,11,.14); color: #92400e; }
.stars .empty  { color: rgba(22,32,58,.15); }

/* ── Modale / logowanie / karty ─────────────────────────────────────────── */
.modal         { background: rgba(255,255,255,.94); border: 1px solid rgba(255,255,255,.9); }
.modal-overlay { background: var(--overlay); }
.login-card    { background: rgba(255,255,255,.75); border: 1px solid rgba(255,255,255,.9); }
.login-error   { background: rgba(239,68,68,.10); color: #b91c1c; border: 1px solid rgba(239,68,68,.25); }
.review-card:hover { box-shadow: 0 8px 28px rgba(31,41,74,.10); }
.reviewer-avatar   { background: rgba(22,32,58,.06); }
.ai-response-box   { background: rgba(55,104,234,.08); border-color: rgba(55,104,234,.22); }
.sent-reply-box    { background: rgba(34,197,94,.10); border-color: rgba(34,197,94,.28); }
.sent-reply-label  { color: #166534; }

/* ── Badge oceny (app.js `ratingBadge`) ─────────────────────────────────────
   Tekst w barwie oceny na tincie tej samej barwy jest z natury nisko-
   kontrastowy, więc tekst jest tu CIEMNIEJSZY od obwódki, nie identyczny. */
.rating-badge {
  display: inline-flex; align-items: center;
  padding: 3px 9px; border-radius: 20px;
  font-size: 11px; font-weight: 700; border: 1px solid;
}
.rb-1 { background: rgba(220,38,38,.10);  color: #b91c1c; border-color: rgba(220,38,38,.55); }
.rb-2 { background: rgba(234,88,12,.10);  color: #9a3412; border-color: rgba(234,88,12,.55); }
.rb-3 { background: rgba(217,119,6,.10);  color: #92400e; border-color: rgba(217,119,6,.55); }
.rb-4 { background: rgba(34,197,94,.12);  color: #15803d; border-color: rgba(34,197,94,.55); }
.rb-5 { background: rgba(21,128,61,.10);  color: #166534; border-color: rgba(21,128,61,.55); }
.rb-0 { background: rgba(22,32,58,.06);   color: var(--muted); border-color: rgba(22,32,58,.20); }

/* Placeholder „–" w kafelku ostrzegawczym: bazowy bursztyn (#fbbf24) jest
   dobrany pod ciemne tło i na białej karcie daje 2.33:1. */
.stat-card.stat-warning .stat-value { color: var(--warning); }
.theme-add-btn { color: var(--accent-text); }

/* (.subtabs/.subtab: nadpisania brandu usunięte w [alfa 0.335] — definicja
   bazowa jest już na tokenach `--muted-strong`/`--accent-text`/`--surface-solid`.) */
.perf-month-chip.active { background: var(--primary); color: #fff; border-color: var(--primary); }
.rank-viewtab.active    { background: var(--primary); color: #fff; }
.ui-sel-chevron, .ui-date-icon { color: var(--muted); }

/* ── Akcent JAKO TEKST ──────────────────────────────────────────────────────
   Baza używa `color: var(--primary)` w 21 miejscach. Ten kolor jest dobrany
   pod BIAŁY TEKST NA NIM (przycisk, pigułka nawigacji), więc użyty jako sam
   tekst wypada za jasno na białym (4.32:1) i za ciemno na czarnym (4.13:1).
   Reguła jest CELOWO nieprefiksowana — działa w obu motywach, bo rozjeżdża
   się tylko wartość `--accent-text`. Dodając nowy selektor z
   `color: var(--primary)`, dopisz go tutaj.                              */
.ai-label,
.analytics-kpi.kpi-primary .analytics-kpi-value,
.drop-zone:hover, .drop-zone.drag-over,
.keyword-item.active .keyword-text,
.location-alias,
.m-tab.active,
.page-tab.page-tab-active,
.pe-day-chip:has(input:checked),
.pe-tab-btn.active,
.perf-cache-refresh:hover:not(:disabled),
.perf-month-chip:hover:not(.active),
.perf-pred-header,
.quick-suggestion-btn,
.quick-suggestions-label,
.rank-stat-tile .stat-value,
.rank-stat.rs-accent .rs-value,
.search-status a,
.sortable:hover,
.sq-running,
.stat-card.stat-primary .stat-value { color: var(--accent-text); }
.btn-outline { color: var(--accent-text); border-color: var(--accent-text); }

/* ── Sync / powiadomienia / listy ───────────────────────────────────────── */
.sync-progress       { background: #fff; border: 1px solid var(--border-soft); }
.sync-progress-track { background: rgba(22,32,58,.07); }
.bg-notif            { background: rgba(255,255,255,.94); border: 1px solid rgba(22,32,58,.09); }
.tpl-drop-list       { background: rgba(255,255,255,.98); border: 1px solid rgba(22,32,58,.10); }
.tpl-drop-item:hover { color: var(--primary); background: rgba(55,104,234,.08); }
.theme-row           { background: var(--surface-sunken); }
.fl-card             { background: var(--surface); border-color: var(--border-soft); }
.ho-hours-row        { background: var(--surface-sunken); border-color: var(--border-soft); }
.wg-item             { background: var(--surface-sunken); border-color: var(--border-soft); }

/* ── Scrollbar ──────────────────────────────────────────────────────────── */
::-webkit-scrollbar-thumb       { background: rgba(22,32,58,.18); }
::-webkit-scrollbar-thumb:hover { background: rgba(22,32,58,.30); }
::-webkit-scrollbar-track       { background: transparent; }

/* ── Przełącznik motywu (wstrzykiwany z app.js do stopki sidebara) ──────── */
.theme-toggle-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  width: 100%;
  margin-bottom: 8px;
  padding: 8px;
  border-radius: 11px;
  border: 1px solid rgba(22,32,58,.10);
  background: rgba(255,255,255,.6);
  color: rgba(22,32,58,.7);
  font-size: 12.5px;
  cursor: pointer;
  transition: background .15s, color .15s;
}
.theme-toggle-btn:hover { background: #fff; color: var(--text); }
/* W stanie zwiniętym sidebara zostaje sama ikona (wzorzec z [v1.54]). */
html.sb-collapsed .theme-toggle-btn { font-size: 0; padding: 8px 0; }
html.sb-collapsed .theme-toggle-btn .tt-ico { font-size: 15px; }

/* Etykieta i ikona przycisku motywu przełączane WYŁĄCZNIE CSS-em, wg klasy
   `theme-dark` nakładanej synchronicznie w <head>. Dzięki temu przycisk jest
   poprawny już przy pierwszym malowaniu — bez czekania na app.js, które wykonuje
   się dopiero na końcu <body> (przyczyna „reloadu" stopki, [v1.82]).
   Napis mówi, co się STANIE po kliknięciu, nie jaki motyw jest teraz. */
.tt-ico-light, .tt-label-light { display: none; }
html.theme-dark .tt-ico-dark,  html.theme-dark .tt-label-dark  { display: none; }
html.theme-dark .tt-ico-light, html.theme-dark .tt-label-light { display: inline; }

/* ── Wydajność na telefonie ─────────────────────────────────────────────────
   `background-attachment: fixed` zmusza przeglądarkę do repaintu całego
   viewportu przy KAŻDEJ klatce scrolla (a iOS Safari bywa go i tak nie
   honoruje). Efekt głębi dają `body::before/::after`, które są
   `position: fixed` — więc wyłączenie jest darmowe wizualnie.           */
@media (max-width: 900px) {
  body { background-attachment: scroll; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   THEME 2.0 — DARK GLASS                                            [v1.60]
   ═══════════════════════════════════════════════════════════════════════════
   Migracja motywu z gałęzi „GMB Manager 2.0". Zasada jak tam: ZERO zmian w
   HTML/JS i zero zmian w istniejących selektorach — wyłącznie nadpisania
   wartości. Usunięcie tego bloku przywraca motyw jasny w całości.

   DLACZEGO CAŁY BLOK JEST NA SAMYM KOŃCU PLIKU (nie w środku):
   sekcja mobilna ([v1.56]) i blok `plt-noapple` ([v1.47]) leżą powyżej i
   hardkodują JASNE tła (`.m-appbar`, `.m-tabbar`, `.modal-header`,
   `--surface: rgba(255,255,255,.92)`). Media query NIE podnosi
   specyficzności, a `html.plt-noapple` (0,1,1) bije `:root` (0,1,0) —
   więc jedynym sposobem, żeby motyw wygrał BEZ `!important`, jest pozycja
   za nimi. To rozszerzenie ostrzeżenia z [v1.56], nie jego złamanie:
   sekcja mobilna nadal jest za sekcjami bazowymi.
   NIE przenoś tego bloku wyżej i NIE „naprawiaj" kolejności `!important`-em.

   PUŁAPKA, KTÓRĄ TU ZAMYKAMY: `plt-noapple` ustawiał `--surface` na BIAŁY
   (rekompensata za wyłączony blur na Windows/Androidzie). Na ciemnym tle
   dawało to białe karty z białym tekstem — kontrast 1.17:1, treść
   niewidoczna dla 100% użytkowników Windows i Androida. Sekcja 5 niżej
   przepisuje te tokeny na ciemne odpowiedniki o podbitym kryciu — sama
   zasada „bez blura → więcej krycia" zostaje, zmienia się kierunek.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1. TOKENY ──────────────────────────────────────────────────────────────
   Musi stać za blokiem `--lg-*` (linia ~3392), inaczej chipy liquid-glass
   zostają jasne. Wartości z 2.0 z trzema korektami kontrastu (WCAG AA,
   policzone na realnym `--surface` nad `--bg`) — patrz komentarze.        */

html.theme-dark {
  /* Mówi przeglądarce, że UI jest ciemne — natywne kontrolki (checkboxy,
     radio, paski przewijania, wybieraki daty/godziny, autofill) renderują
     się wtedy w ciemnym wariancie SAME. To jedyny poprawny sposób; ręczne
     stylowanie natywnych widżetów jest niepełne i różni się per silnik. */
  color-scheme: dark;
  accent-color: #3b6ef0;

  /* 2.0 miało #3b6ef0 → biały tekst na pigułce/przycisku dawał 4.49:1,
     czyli o 0.01 poniżej progu AA. #3768ea to 4.85:1 przy różnicy barwy
     niewidocznej gołym okiem (ΔE ≈ 2). Dotyczy najczęściej klikanych
     elementów: przycisku głównego i aktywnej pozycji nawigacji.        */
  --primary:      #3768ea;
  --primary-dark: #2f5ad6;
  --primary-glow: rgba(55,104,234,.45);

  /* Sidebar = ciemne szkło */
  --sidebar-bg:    rgba(255,255,255,.045);
  --sidebar-text:  rgba(255,255,255,.52);  /* 2.0 miało .45 → 4.52:1 (na styk) */
  --sidebar-hover: rgba(255,255,255,.06);
  --sidebar-active:#3b6ef0;

  --bg:            #050810;
  --surface:       rgba(255,255,255,.055);
  --surface-solid: #10162a;
  --border:        rgba(255,255,255,.10);
  --border-soft:   rgba(255,255,255,.08);
  --text:          rgba(255,255,255,.92);   /* 15.4:1 ✅ */
  --muted:         rgba(255,255,255,.55);   /* 2.0 miało .40 → 3.82:1 ❌ AA dla
                                               tekstu <18px; .55 daje 5.6:1 ✅.
                                               To najczęstszy kolor drugorzędny
                                               w apce (meta opinii, etykiety). */
  --success:       #34d399;
  --warning:       #fbbf24;
  --danger:        #f87171;
  --danger-dark:   #ef4444;

  --radius:        12px;
  --radius-card:   22px;
  --shadow:        0 4px 32px rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.08);
  --shadow-lg:     0 16px 48px rgba(0,0,0,.5);
  /* 2.0 miało blur(40px). Świadomie 30px: `--blur` konsumują KARTY, a na
     Dashboardzie potrafi ich być 25+ naraz — każdy piksel promienia to
     realny koszt kompozycji na iOS przy scrollu. Różnica wizualna na
     ciemnym tle jest znikoma (ciemne szkło i tak mało przepuszcza).      */
  --blur:          blur(30px) saturate(140%);

  /* NOWE tokeny — zamykają hardkody popupów/wierszy list, których 2.0 nie
     znało (ui-select [v1.49], ui-datepicker [v1.50], flagged [v1.53]).   */
  --surface-raised: #1a2138;               /* popupy, dropdowny, panele nad treścią */
  --surface-sunken: rgba(255,255,255,.04); /* wiersze list, „wgłębienia"           */
  --overlay:        rgba(3,5,12,.62);      /* tła modali                            */
  --row-error:      rgba(239,68,68,.12);   /* wiersz tabeli ze statusem błędu       */
  /* Tekst w boxach semantycznych (info/ostrzeżenie/błąd). Tła tych boxów są
     półprzezroczystymi tintami wpisanymi wprost w HTML — działają w obu
     motywach, ale ich TEKST musi się rozjaśnić na ciemnym.                */
  --info-fg:        #93c5fd;
  --warn-fg:        #fcd34d;
  --err-fg:         #fca5a5;
  /* Akcent JAKO TEKST na ciemnym tle musi być jaśniejszy niż akcent jako
     TŁO. --primary (#3768ea) jest dobrany pod biały tekst na przycisku
     (4.85:1); ten sam kolor użyty jako tekst na tle strony dałby 4.13:1.
     Stąd druga zmienna — nie jest to duplikat.                          */
  --accent-text:    #8fabff;   /* 8.16:1 na --surface */

  /* Gwiazdki — progi z [v1.03] BEZ ZMIAN, korekta wyłącznie jasności:
     2.0 dawało 5★ #15803d = 3.62:1 (poniżej AA). #16a34a = 6.1:1 ✅      */
  --color-5star: #16a34a;
  --color-4star: #22c55e;
  --color-3star: #eab308;
  --color-2star: #f97316;
  --color-1star: #ef4444;

  /* Liquid glass ([v1.10]) — wariant ciemny */
  --lg-bg:       rgba(255,255,255,.06);
  --lg-bg-hover: rgba(255,255,255,.12);
  --lg-border:   rgba(255,255,255,.10);
  --lg-shadow:   0 2px 10px rgba(0,0,0,.30), inset 0 1px 0 rgba(255,255,255,.08);
  --lg-text:     rgba(255,255,255,.78);
}

/* ── 2. TŁO ─────────────────────────────────────────────────────────────────
   Bloby (`body::before/::after`) zostają na `transform` — kompozycja GPU,
   zero layoutu — i są nadal zamrażane przy `prefers-reduced-motion`,
   pod `plt-noapple` i na telefonie (reguły wyżej w pliku działają dalej). */

html.theme-dark body {
  background:
    radial-gradient(ellipse 65vw 55vh at 88% -8%, #1d3a8a 0%, rgba(15,31,92,.55) 35%, transparent 70%),
    radial-gradient(ellipse 55vw 55vh at -8% 108%, #1e1b4b 0%, transparent 65%),
    radial-gradient(ellipse 45vw 40vh at 55% 55%, rgba(3,105,161,.35) 0%, transparent 70%),
    #050810;
  background-attachment: fixed;
  color: var(--text);
}
html.theme-dark body::before {
  background-image:
    radial-gradient(circle at 18% 12%, rgba(29,58,138,.50) 0%, transparent 42%),
    radial-gradient(circle at 82% 70%, rgba(30,27,75,.45) 0%, transparent 40%);
  opacity: .5;
}
html.theme-dark body::after {
  background-image:
    radial-gradient(circle at 60% 92%, rgba(3,105,161,.30) 0%, transparent 44%),
    radial-gradient(circle at 8% 78%, rgba(29,58,138,.28) 0%, transparent 38%);
  opacity: .4;
}
html.theme-dark ::selection { background: rgba(59,110,240,.45); color: #fff; }

/* ── 3. KOMPONENTY BAZOWE (przeniesione z 2.0) ────────────────────────────── */

/* Sidebar */
html.theme-dark .sidebar {
  background: var(--sidebar-bg);
  border-right: 1px solid rgba(255,255,255,.08);
  box-shadow: inset 1px 0 0 rgba(255,255,255,.05), 4px 0 32px rgba(0,0,0,.35);
}
html.theme-dark .sidebar-header { border-bottom: 1px solid rgba(255,255,255,.07); }
html.theme-dark .sidebar-footer { border-top: 1px solid rgba(255,255,255,.07); }
html.theme-dark .app-version { border-top: 1px solid rgba(255,255,255,.07); }
html.theme-dark .nav-section-label { color: rgba(255,255,255,.42); }   /* 2.0 .25 → 2.25:1 ❌ */
html.theme-dark .nav-link:hover { background: var(--sidebar-hover); color: rgba(255,255,255,.85); }
html.theme-dark .nav-link.active {
  background: var(--primary);
  color: #fff;
  box-shadow: 0 2px 12px rgba(59,110,240,.45);
}
html.theme-dark .user-info { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.07); }
html.theme-dark .user-avatar { background: rgba(255,255,255,.10); }
html.theme-dark .logout-btn { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.08); }
html.theme-dark .logout-btn:hover { background: rgba(255,255,255,.12); color: var(--text); }

/* Zwijanie panelu ([v1.54]) — 2.0 tego nie znało */
html.theme-dark .sb-toggle { background: rgba(255,255,255,.07); border-color: var(--border); color: var(--muted); }
html.theme-dark .sb-toggle:hover { background: rgba(255,255,255,.14); color: #8fabff; }
html.theme-dark .sb-burger { background: rgba(16,22,42,.88); border-color: var(--border); color: var(--text); }
html.theme-dark .sb-backdrop { background: rgba(0,0,0,.55); }

/* Tabele */
html.theme-dark thead th { background: rgba(255,255,255,.04); border-bottom: 1px solid var(--border-soft); }
html.theme-dark tbody td { border-bottom: 1px solid rgba(255,255,255,.06); }
html.theme-dark tbody tr:hover td { background: rgba(255,255,255,.045); }

/* Formularze */
html.theme-dark .form-control {
  background: rgba(255,255,255,.06);
  border: 1.5px solid rgba(255,255,255,.10);
  color: var(--text);
}
html.theme-dark .form-control::placeholder { color: rgba(255,255,255,.38); }  /* 2.0 .22 → 2.01:1 ❌ */
html.theme-dark .form-control:focus {
  border-color: rgba(59,110,240,.5);
  box-shadow: 0 0 0 3px rgba(59,110,240,.12);
}
html.theme-dark .filter-select {
  background: rgba(255,255,255,.06);
  border-color: rgba(255,255,255,.10);
  color: rgba(255,255,255,.78);
}
/* Natywna lista rozwijana — widoczna tylko gdy ui-select.js się nie wykona */
html.theme-dark select,
html.theme-dark select.form-control,
html.theme-dark select.filter-select { color: rgba(255,255,255,.80); }
html.theme-dark select option { background: var(--surface-solid); color: rgba(255,255,255,.88); }

/* Przyciski */
html.theme-dark .btn-secondary {
  background: rgba(255,255,255,.07);
  color: rgba(255,255,255,.78);
  border: 1px solid rgba(255,255,255,.10);
}
html.theme-dark .btn-secondary:hover { background: rgba(255,255,255,.13); color: #fff; }
html.theme-dark .btn-warning { background: rgba(245,158,11,.85); }
html.theme-dark .btn-icon-sm { border-color: var(--border); }
html.theme-dark .btn-icon-sm:hover:not(:disabled) { color: #8fabff; }
html.theme-dark .btn-deactivate:hover:not(:disabled) { background: rgba(239,68,68,.15) !important; }
/* Google — celowo jasny (rozpoznawalność marki) */
html.theme-dark .btn-google { background: #fff; color: #1a1f2e; border-color: rgba(255,255,255,.25); }

/* Badge */
html.theme-dark .badge-success { background: rgba(34,197,94,.15);  color: #6ee7b7; border: 1px solid rgba(34,197,94,.25); }
html.theme-dark .badge-danger { background: rgba(239,68,68,.15);  color: #fca5a5; border: 1px solid rgba(239,68,68,.25); }
html.theme-dark .badge-warning { background: rgba(245,158,11,.15); color: #fcd34d; border: 1px solid rgba(245,158,11,.25); }
html.theme-dark .badge-info { background: rgba(59,130,246,.15); color: #93c5fd; border: 1px solid rgba(59,130,246,.25); }
html.theme-dark .badge-neutral { background: rgba(255,255,255,.07); color: rgba(255,255,255,.62); border: 1px solid rgba(255,255,255,.09); }
html.theme-dark .source-badge { color: #93c5fd; }
html.theme-dark .edited-badge { background: rgba(139,92,246,.15); color: #c4b5fd; }
html.theme-dark .loc-badge { color: #93c5fd; }
html.theme-dark .media-badge { background: rgba(245,158,11,.15); color: #fcd34d; }
html.theme-dark .ai-outcome-badge.ai-outcome-full      { background: rgba(22,163,74,.15);  color: #86efac; border-color: rgba(22,163,74,.3); }
html.theme-dark .ai-outcome-badge.ai-outcome-assisted  { background: rgba(139,92,246,.15); color: #c4b5fd; border-color: rgba(139,92,246,.3); }
html.theme-dark .ai-outcome-badge.ai-outcome-escalated { background: rgba(245,158,11,.15); color: #fcd34d; border-color: rgba(245,158,11,.3); }
html.theme-dark .stars .empty { color: rgba(255,255,255,.15); }

/* Modale */
html.theme-dark .modal { background: rgba(16,22,42,.88); border: 1px solid rgba(255,255,255,.10); }
html.theme-dark .modal-overlay {
  background: var(--overlay);
  backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px);
}

/* Logowanie */
html.theme-dark .login-card { background: rgba(255,255,255,.055); border: 1px solid rgba(255,255,255,.10); }
html.theme-dark .login-error { background: rgba(239,68,68,.12); color: #fca5a5; border: 1px solid rgba(239,68,68,.25); }

/* Karty opinii / awatary / boxy odpowiedzi */
html.theme-dark .review-card:hover { box-shadow: 0 8px 28px rgba(0,0,0,.35); }
html.theme-dark .reviewer-avatar { background: rgba(255,255,255,.08); }
html.theme-dark .ai-response-box { background: rgba(59,110,240,.10); border-color: rgba(59,110,240,.28); color: rgba(255,255,255,.88); }
html.theme-dark .sent-reply-box { background: rgba(34,197,94,.10);  border-color: rgba(34,197,94,.28);  color: rgba(255,255,255,.85); }
html.theme-dark .sent-reply-label { color: #6ee7b7; }
html.theme-dark .reply-preview { background: var(--surface-sunken); }
html.theme-dark .reply-preview-comment { color: rgba(255,255,255,.85); }
html.theme-dark .reply-preview-meta { color: var(--muted); }
html.theme-dark .reply-preview-empty { color: rgba(255,255,255,.38); }

/* Synchronizacja / postęp / powiadomienia */
html.theme-dark .sync-progress { background: var(--surface-solid); border: 1px solid var(--border); }
html.theme-dark .sync-progress-track { background: rgba(255,255,255,.08); }
html.theme-dark .sync-progress-text { color: var(--muted); }
html.theme-dark .sync-progress-text .pct { color: #8fabff; }
html.theme-dark .sync-panel-bar-wrap { background: rgba(255,255,255,.08); }
html.theme-dark .bg-notif { background: rgba(16,22,42,.90); border: 1px solid rgba(255,255,255,.10); }
html.theme-dark .pagination-info { color: var(--muted); }


/* Pod-zakładki */
/* Pod-zakładki [alfa 0.335]: taca i aktywna karta w ciemnym motywie.
   Aktywny kafelek NIE bierze `--surface-solid` (#10162a) — na tacy .07 białego
   byłby CIEMNIEJSZY od otoczenia i „zapadał się" (zmierzone na zrzucie). Zamiast
   tego jaśniejsza półprzezroczysta warstwa .11 + 1px obwódka — czyta się jako
   wypukła karta. Pigułka warstwy ruchu ma to samo tło (motion.css 3c). */
html.theme-dark .subtabs,
html.theme-dark .page-tabs,
html.theme-dark .drb-presets,
html.theme-dark .ed-views,
html.theme-dark .range-tabs,
html.theme-dark .au-presets { background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.07); }
html.theme-dark .subtab:hover,
html.theme-dark .page-tab:hover,
html.theme-dark .drb-preset:hover,
html.theme-dark .ed-view:hover,
html.theme-dark .range-btn:hover,
html.theme-dark .au-preset:hover { background: rgba(255,255,255,.06); }
html.theme-dark .subtab.active,
html.theme-dark .page-tab.page-tab-active,
html.theme-dark .drb-preset.drb-active,
html.theme-dark .ed-view.active,
html.theme-dark .range-btn.active,
html.theme-dark .au-preset.au-preset-on {
  background: rgba(255,255,255,.11);
  box-shadow: 0 0 0 1px rgba(255,255,255,.12), 0 6px 14px -8px rgba(0,0,0,.7);
}
html.theme-dark .subtab .badge-count { background: rgba(255,255,255,.12); }
html.theme-dark .subtabs.au-help-tabs { background: none; border-color: rgba(255,255,255,.08); }
html.theme-dark .au-help-tabs .subtab.active { box-shadow: none; }

/* Szablony odpowiedzi */
html.theme-dark .tpl-drop-list { background: var(--surface-raised); border: 1px solid rgba(255,255,255,.12); }
html.theme-dark .tpl-drop-item { color: rgba(255,255,255,.78); border-bottom-color: rgba(255,255,255,.06); }
html.theme-dark .tpl-drop-item:hover { color: #8fabff; background: rgba(59,110,240,.12); }
html.theme-dark .tpl-section { border-color: var(--border); }
html.theme-dark .tpl-section-toggle { color: var(--muted); }

/* Info-boxy / notice */
html.theme-dark .perf-notice { background: rgba(245,158,11,.10); border-color: rgba(245,158,11,.28); }
html.theme-dark .perf-notice.info { background: rgba(59,130,246,.10); border-color: rgba(59,130,246,.28); }
html.theme-dark .perf-notice,
html.theme-dark .perf-notice.info { color: rgba(255,255,255,.80); }
html.theme-dark .pe-cat-info-box { color: #93b4ff; background: rgba(59,130,246,.10); }
html.theme-dark .rank-stats-note { background: rgba(245,158,11,.10); color: #fcd34d; }
html.theme-dark .quick-suggestion-btn { background: rgba(255,255,255,.06); color: rgba(255,255,255,.75); border-color: rgba(255,255,255,.10); }
html.theme-dark .pe-more-type-header:hover { background: rgba(255,255,255,.06); }

/* Import / podsumowania */
html.theme-dark .sum-ok { background: rgba(34,197,94,.13);  color: #6ee7b7; }
html.theme-dark .sum-skip { background: rgba(245,158,11,.13); color: #fcd34d; }
html.theme-dark .sum-err { background: rgba(239,68,68,.13);  color: #fca5a5; }

/* Rozkład ocen */
html.theme-dark .rating-bar-track { background: rgba(255,255,255,.08); }
html.theme-dark .rating-sq { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.09); color: rgba(255,255,255,.55); }
html.theme-dark .stat-card.stat-warning .stat-value { color: #fbbf24; }

/* Motywy opinii ([v1.09]/[v1.10]) */
html.theme-dark .theme-add-btn { background: rgba(255,255,255,.05); border-color: rgba(255,255,255,.18); color: #8fabff; }
html.theme-dark .theme-add-btn:hover { background: rgba(59,110,240,.15); border-color: rgba(59,110,240,.5); }
html.theme-dark .theme-chip { color: #a5b8ff; background: rgba(59,110,240,.14); }
html.theme-dark .theme-tag-x:hover { background: rgba(255,255,255,.25); }
html.theme-dark .theme-ana-legend,
html.theme-dark .theme-ana-meta { color: rgba(255,255,255,.60); }
html.theme-dark .theme-ana-bar { background: rgba(255,255,255,.08); }
html.theme-dark .theme-row { background: var(--surface-sunken); }
html.theme-dark .theme-row-count { background: rgba(255,255,255,.10); }
html.theme-dark .theme-row-inc { background: rgba(255,255,255,.025); }
html.theme-dark .theme-row-btn { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.12); color: #8fabff; }
html.theme-dark .theme-row-del:hover { background: rgba(239,68,68,.15); }
html.theme-dark .themes-list { border-color: var(--border-soft); }
html.theme-dark .theme-pick-col { border-color: var(--border-soft); }
html.theme-dark .theme-pick-item { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.10); color: rgba(255,255,255,.78); }
html.theme-dark .theme-pick-item.selected { background: var(--primary); border-color: var(--primary); color: #fff; }
html.theme-dark .theme-col-pos { color: #6ee7b7; }
html.theme-dark .theme-col-neg { color: #fca5a5; }
html.theme-dark .theme-quick-label { color: var(--muted); }
html.theme-dark .theme-quick-btn { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.12); color: rgba(255,255,255,.78); }
html.theme-dark .lg-chip-plus { color: #8fabff; }

/* Forma grzecznościowa ([v1.09]) */
html.theme-dark .salu-nick { color: var(--muted); }
html.theme-dark .salu-pan { background: rgba(59,130,246,.18); color: #93c5fd; }
html.theme-dark .salu-panipan { background: rgba(255,255,255,.09); color: rgba(255,255,255,.70); }

/* Sesje pracy ([v1.12]) */
html.theme-dark .session-bar .session-info { color: rgba(255,255,255,.80); }
html.theme-dark .session-changes .sc-title { color: rgba(255,255,255,.88); }
html.theme-dark .session-changes.none { color: var(--muted); }
html.theme-dark .sc-item { background: rgba(255,255,255,.06); color: rgba(255,255,255,.80); }
html.theme-dark .sc-item.up   .sc-delta { color: #6ee7b7; }
html.theme-dark .sc-item.down .sc-delta { color: #fca5a5; }
html.theme-dark .session-dot { background: rgba(255,255,255,.22); }

/* Scrollbar */
html.theme-dark ::-webkit-scrollbar-thumb { background: rgba(255,255,255,.14); }
html.theme-dark ::-webkit-scrollbar-thumb:hover { background: rgba(255,255,255,.25); }
html.theme-dark ::-webkit-scrollbar-track { background: transparent; }

/* ── 4. KOMPONENTY POWSTAŁE PO ODGAŁĘZIENIU 2.0 ────────────────────────────
   2.0 odgałęziło się przed [v1.49]. Poniższe rodziny nie mają w nim ŻADNEGO
   pokrycia — bez tej sekcji zostałyby jasnymi wyspami na ciemnym tle.     */

/* ui-select.js ([v1.49]) */
html.theme-dark .ui-sel-trigger { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.10); color: var(--text); }
html.theme-dark .ui-sel-trigger:hover:not(:disabled) { background: rgba(255,255,255,.12); border-color: rgba(59,110,240,.45); }
html.theme-dark .ui-sel-popup { background: rgba(24,31,53,.96); border: 1px solid rgba(255,255,255,.12); }
html.theme-dark .ui-sel-search input { background: rgba(255,255,255,.07); border-color: rgba(255,255,255,.12); color: var(--text); }
html.theme-dark .ui-sel-search { border-bottom-color: var(--border-soft); }
html.theme-dark .ui-sel-row { color: rgba(255,255,255,.82); }
html.theme-dark .ui-sel-row:hover { background: rgba(59,110,240,.16); }
html.theme-dark .ui-sel-row-active { background: rgba(59,110,240,.28); color: #fff; }
html.theme-dark .ui-sel-row-on { color: #8fabff; }
html.theme-dark .ui-sel-row-off { color: rgba(255,255,255,.30); }
html.theme-dark .ui-sel-group { color: var(--muted); }
html.theme-dark .ui-sel-empty { color: var(--muted); }
html.theme-dark .ui-sel-placeholder { color: rgba(255,255,255,.38); }
html.theme-dark .ui-sel-chevron { color: var(--muted); }

/* ui-datepicker.js ([v1.50]) + natywne pola godziny ([v1.49]) */
html.theme-dark .ui-date-trigger { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.10); color: var(--text); }
html.theme-dark .ui-date-trigger:hover:not(:disabled) { background: rgba(255,255,255,.12); border-color: rgba(59,110,240,.45); }
html.theme-dark .ui-date-popup { background: rgba(24,31,53,.96); border: 1px solid rgba(255,255,255,.12); }
html.theme-dark .ui-date-head { border-bottom-color: var(--border-soft); }
html.theme-dark .ui-date-weekrow { color: var(--muted); }
html.theme-dark .ui-date-title { color: var(--text); }
html.theme-dark .ui-date-nav { color: rgba(255,255,255,.72); }
html.theme-dark .ui-date-nav:hover:not(:disabled) { background: rgba(255,255,255,.10); color: #fff; }
html.theme-dark .ui-date-cell { color: rgba(255,255,255,.82); }
html.theme-dark .ui-date-cell:hover:not(:disabled) { background: rgba(59,110,240,.16); }
html.theme-dark .ui-date-cell-out { color: rgba(255,255,255,.28); }
html.theme-dark .ui-date-cell-today { border-color: rgba(59,110,240,.55); }
html.theme-dark .ui-date-cell-sel { background: var(--primary); color: #fff; }
html.theme-dark .ui-date-month-cell.ui-date-cell-sel { background: var(--primary); color: #fff; }
html.theme-dark .ui-date-foot { border-top-color: var(--border-soft); }
html.theme-dark .ui-date-link { color: #8fabff; }
html.theme-dark .ui-date-placeholder { color: rgba(255,255,255,.38); }
html.theme-dark .ui-date-icon { color: var(--muted); }
html.theme-dark input[type="time"] { background: rgba(255,255,255,.06); border-color: rgba(255,255,255,.10); color: var(--text); }
html.theme-dark input[type="time"]:hover { background: rgba(255,255,255,.12); border-color: rgba(59,110,240,.45); }
/* Ikona wybieraka nie wymaga tu `filter: invert()` — `color-scheme: dark`
   z sekcji 1 przełącza natywne widżety na ciemny wariant automatycznie.
   Dodanie inwersji odwróciłoby ją PONOWNIE, na jasną. */

/* Godziny otwarcia ([v1.31]) */
html.theme-dark .ho-hours-row { background: var(--surface-sunken); border-color: var(--border-soft); }

/* Opinie oflagowane ([v1.53]/[v1.54]) */
html.theme-dark .fl-card { background: var(--surface); border-color: var(--border); }
html.theme-dark .fl-meta { background: var(--surface-sunken); }
html.theme-dark .fl-chip-wait { background: rgba(255,255,255,.08); color: rgba(255,255,255,.65); border: 1px solid rgba(255,255,255,.12); }

/* Grupa robocza ([v1.54]) */
html.theme-dark .wg-item { background: var(--surface-sunken); border-color: var(--border-soft); }
html.theme-dark .wg-badge { background: rgba(255,255,255,.09); color: rgba(255,255,255,.70); }

/* Pozycje lokalne — przełączniki i tabela historii ([v1.53]) */
html.theme-dark .rank-viewtab:hover { background: rgba(255,255,255,.10); color: var(--text); }
html.theme-dark .rank-viewtabs { background: rgba(255,255,255,.055); border-color: var(--border); }
html.theme-dark .basemap-toggle { background: rgba(255,255,255,.07); }
html.theme-dark .basemap-btn { color: var(--muted); }
html.theme-dark .basemap-btn.active { background: rgba(255,255,255,.16); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.4); }
html.theme-dark .rank-htable td { border-bottom-color: rgba(255,255,255,.07); }
html.theme-dark .rank-stat { background: var(--surface-sunken); border-color: var(--border-soft); }
html.theme-dark .rank-stat-tile { background: var(--surface-sunken); border-color: var(--border-soft); }
html.theme-dark .rank-cell[data-pos=""] { color: rgba(255,255,255,.30); }
html.theme-dark .rank-progress-bar { background: rgba(255,255,255,.08); }
/* Kontrolki Leaflet ZOSTAJĄ jasne — leżą na kafelkach mapy (jasnych w
   podkładzie „Jasna"/„Klasyczna"), nie na powierzchni aplikacji.         */

/* Analityka lokalu — pasek miesięcy i horyzont ([v1.18]/[v1.58]) */
html.theme-dark .perf-month-strip { border-color: var(--border-soft); }
html.theme-dark .perf-month-chip { background: rgba(255,255,255,.06); border-color: var(--border); color: rgba(255,255,255,.72); }
html.theme-dark .perf-month-chip:hover { background: rgba(255,255,255,.12); }
html.theme-dark .perf-month-chip.active { background: var(--primary); color: #fff; border-color: var(--primary); }
html.theme-dark .perf-horizon-lbl { color: var(--muted); }
html.theme-dark .perf-horizon-toggle { background: rgba(255,255,255,.07); }
html.theme-dark .perf-horizon-btn { color: var(--muted); }
html.theme-dark .perf-horizon-btn.active { background: rgba(255,255,255,.16); color: var(--text); box-shadow: 0 1px 3px rgba(0,0,0,.4); }
html.theme-dark .perf-cache-bar { background: var(--surface-sunken); }
html.theme-dark .perf-cache-note { color: var(--muted); }
html.theme-dark .perf-cache-refresh { background: rgba(255,255,255,.07); border-color: var(--border); color: rgba(255,255,255,.78); }
html.theme-dark .perf-prediction { background: rgba(59,130,246,.08); border-color: rgba(59,130,246,.28); }
html.theme-dark .perf-pred-bar-wrap { background: rgba(255,255,255,.08); }
html.theme-dark .perf-pred-metric { color: var(--muted); }

/* Kreator ról ([v1.44]/[v1.45]) */
html.theme-dark .role-perm-page:hover,
html.theme-dark .role-perm-leaf:hover { background: rgba(255,255,255,.06); }

/* (grupa „akcent jako tekst" jest wspólna dla obu motywów — patrz blok jasny) */


/* Przyciski destrukcyjne: biały tekst na #ef4444 to 3.76:1 (❌ AA).
   #dc2626 daje 4.84:1, hover #b91c1c — 6.55:1.                           */
html.theme-dark .btn-danger { background: #dc2626; box-shadow: 0 3px 14px rgba(220,38,38,.28); }
html.theme-dark .btn-danger:hover { background: #b91c1c; }
/* Puste gwiazdki: dekoracja, nie treść — ale .15 było ledwie widoczne. */
html.theme-dark .stars .empty { color: rgba(255,255,255,.22); }

/* ── 5. plt-noapple — ODCHUDZONA GRAFIKA W WERSJI CIEMNEJ ──────────────────
   Nadpisuje blok z [v1.47] (linie ~3888) — ten sam selektor, ta sama
   specyficzność, wygrywa pozycją. BEZ tej sekcji Windows/Android dostaje
   BIAŁE karty (`--surface: rgba(255,255,255,.92)`) z białym tekstem.     */

html.plt-noapple.theme-dark {
  --blur: none;                        /* karty/panele: zero backdrop-filter */
  --lg-blur: none;                     /* chipy liquid-glass                 */
  --surface: rgba(255,255,255,.10);    /* rekompensata krycia — CIEMNA       */
  --lg-bg: rgba(255,255,255,.10);
  --surface-raised: #1c2440;           /* popupy muszą być w pełni kryjące   */
}
/* Powierzchnie, które muszą być nieprzezroczyste, gdy nie ma za nimi blura */
html.plt-noapple.theme-dark .ui-sel-popup,
html.plt-noapple.theme-dark .ui-date-popup,
html.plt-noapple.theme-dark .tpl-drop-list {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: #1c2440;
}
html.plt-noapple.theme-dark .btn-secondary {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: rgba(255,255,255,.12);
}
html.plt-noapple.theme-dark .modal-overlay {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: rgba(3,5,12,.78);        /* krycie zamiast blura */
}
/* Bloby tła zostają zamrożone regułą z [v1.47] wyżej — nie powtarzamy jej. */

/* ── 6. POWŁOKA MOBILNA ([v1.56]/[v1.57]) ──────────────────────────────────
   Sekcja mobilna zaczyna się w linii ~4110 i hardkoduje jasne tła. Ta
   media query ma tę samą specyficzność, ale stoi za nią → wygrywa.       */@media (max-width: 900px) {
  /* Windows/Android na telefonie — ten sam problem co w sekcji 5 */
  html.plt-noapple.theme-dark {
    --blur: none;
    --lg-blur: none;
    --surface: rgba(255,255,255,.12);
  }
  html.plt-noapple.theme-dark .sidebar,
  html.plt-noapple.theme-dark .modal,
  html.plt-noapple.theme-dark .m-appbar,
  html.plt-noapple.theme-dark .m-tabbar {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: #0c1220;
  }

  /* Powłoka — ciemne szkło */
  html.theme-dark .m-appbar { background: rgba(10,14,28,.82); border-bottom-color: rgba(255,255,255,.08); }
  html.theme-dark .m-tabbar { background: rgba(10,14,28,.88); border-top-color: rgba(255,255,255,.08); }
  html.theme-dark .sidebar { background: rgba(10,14,28,.94); }
  html.theme-dark .m-appbar-title { color: var(--text); }
  html.theme-dark .m-tab { color: rgba(255,255,255,.55); }
  html.theme-dark .m-tab.active { color: #8fabff; }
  html.theme-dark .m-tab-label { color: inherit; }
  html.theme-dark .m-filters-toggle { background: rgba(255,255,255,.08); border-color: var(--border); color: rgba(255,255,255,.80); }
  html.theme-dark .m-ft-count { background: var(--primary); color: #fff; }
  html.theme-dark .modal-header,
  html.theme-dark .modal-footer { background: rgba(16,22,42,.94); }

  /* WYDAJNOŚĆ: `background-attachment: fixed` na telefonie zmusza
     przeglądarkę do repaintu całego viewportu przy KAŻDEJ klatce scrolla
     (a na iOS Safari bywa i tak ignorowane). Efekt paralaksy i tak dają
     `body::before/::after`, które są `position: fixed` — więc wyłączenie
     tego jest darmowe wizualnie, a zdejmuje realny koszt przewijania.   */
  html.theme-dark body { background-attachment: scroll; }
}

/* Landscape ≤460px — dopełnienie reguły z [v1.57] (pasek źródłowy wraca) */@media (max-width: 900px) and (max-height: 460px) {
  html.theme-dark .subtabs,
  html.theme-dark .pe-tablist,
  html.theme-dark .rank-viewtabs { background: rgba(255,255,255,.05); }
}

/* Badge oceny — wariant ciemny (tekst jaśniejszy od obwódki) */
html.theme-dark .rb-1 { background: rgba(239,68,68,.16);  color: #fca5a5; border-color: rgba(239,68,68,.45); }
html.theme-dark .rb-2 { background: rgba(249,115,22,.16); color: #fdba74; border-color: rgba(249,115,22,.45); }
html.theme-dark .rb-3 { background: rgba(234,179,8,.16);  color: #fcd34d; border-color: rgba(234,179,8,.45); }
html.theme-dark .rb-4 { background: rgba(34,197,94,.16);  color: #86efac; border-color: rgba(34,197,94,.45); }
html.theme-dark .rb-5 { background: rgba(22,163,74,.16);  color: #6ee7b7; border-color: rgba(22,163,74,.45); }
html.theme-dark .rb-0 { background: rgba(255,255,255,.07); color: var(--muted); border-color: rgba(255,255,255,.18); }

/* Przełącznik motywu — wariant ciemny. Bez tego zostawał jasny (3.59:1),
   bo jego jedyna definicja siedzi w bloku jasnym. */
html.theme-dark .theme-toggle-btn {
  background: rgba(255,255,255,.07);
  border-color: rgba(255,255,255,.12);
  color: rgba(255,255,255,.75);
}
html.theme-dark .theme-toggle-btn:hover { background: rgba(255,255,255,.14); color: #fff; }

/* ══════════════════════════════════════════════════════════════════════════
   [v1.61] WYDAJNOŚĆ KOMPOZYCJI — MUSI ZOSTAĆ NA KOŃCU PLIKU
   ══════════════════════════════════════════════════════════════════════════
   Diagnoza (pomiar computed style na ścieżce `plt-noapple`, 1440x900, motyw
   JASNY — czyli realny Windows desktop): aktywne były JEDNOCZEŚNIE
   `.sidebar` blur(48px) na 240x900, `.modal` blur(40px) x liczba modali na
   stronie (users.html ma ich 7) oraz pełnoekranowy `.modal-overlay` blur(3px)
   1434x900 — wszystkie z `will-change: backdrop-filter`, czyli WYMUSZONYM
   promowaniem warstwy GPU nawet przy zamkniętym modalu.

   Dlaczego to boli WYŁĄCZNIE na Windowsie, mimo że [v1.47] „załatwił" blur:
   [v1.47] wygasił blur tylko tam, gdzie idzie on przez tokeny `--blur`/
   `--lg-blur` (karty, chipy). Sidebar i modale mają promienie WPISANE NA
   SZTYWNO, więc token ich nie dotyczy i zostały włączone „bo po zamrożeniu
   tła ich koszt jest akceptowalny". Motyw CIEMNY z [v1.60] gasi je jawnie,
   ale tylko w `@media (max-width:900px)` — na desktopie w motywie JASNYM
   (domyślnym) nie gasił ich nikt.

   Sidebar jest tu najdroższy nie rozmiarem, tylko tym, ŻE JEST PRZYPIĘTY:
   jego backdropem jest przewijana treść, więc każda klatka przewijania listy
   opinii wymusza ponowne policzenie rozmycia 48px na pełnej wysokości okna.
   Stąd „tragicznie" właśnie przy sesji odpowiedzi (dużo scrolla + modal).

   UWAGA POMIAROWA (kosztowała w tej sesji dwie fałszywe hipotezy): koszt
   `backdrop-filter` ponosi WĄTEK KOMPOZYTORA, a `requestAnimationFrame`
   mierzy WĄTEK GŁÓWNY — pomiar rAF pokazywał równe 16.7 ms (60 FPS) nawet
   przy 40 pełnoekranowych warstwach rozmycia i NIE JEST w stanie wykryć tej
   klasy problemu. Nie „potwierdzaj" tutaj niczego przez FPS z rAF.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. Zamknięty modal nie ma prawa nic kompozytować (WSZYSTKIE platformy) ──
   `.modal-overlay` NIGDY nie dostaje `display:none` — jest chowany samym
   `opacity:0` (patrz definicja ~linia 639). Samo `opacity:0` przeglądarka
   zwykle potrafi pominąć, ALE `will-change: backdrop-filter` jawnie każe jej
   utrzymać warstwę mimo to — czyli kasuje tę optymalizację. Na users.html
   dawało to 7 na stałe promowanych warstw 40px w tle. */
.modal-overlay:not(.open),
.modal-overlay:not(.open) .modal {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  will-change: auto !important;
}

/* `will-change` tylko wtedy, gdy rozmycie realnie żyje — nadpisuje regułę
   `.sidebar, .modal { will-change: backdrop-filter }` z [v1.38], która
   obejmowała KAŻDY modal na stronie bezterminowo. */
.modal { will-change: auto; }
.modal-overlay.open .modal { will-change: backdrop-filter; }

/* ── 2. Izolacja karty opinii (WSZYSTKIE platformy, zero zmian w wyglądzie) ──
   `.review-card` nie miało ŻADNEGO `contain` (w przeciwieństwie do `.card`),
   więc podmiana jednej karty przez `refreshReviewCard` (każde wysłanie
   odpowiedzi) unieważniała layout całej listy. Zweryfikowano, że karty nie
   zawierają potomków `position:absolute/fixed` (0 sztuk), więc `paint` nic
   nie przytnie, a `layout` nie uwięzi pozycjonowania. */
.review-card { contain: layout paint style; }

/* ── 2b. Karta poza widocznym obszarem przestaje kosztować ──────────────────
   `content-visibility: auto` pozwala przeglądarce POMINĄĆ layout i paint
   karty, dopóki nie jest blisko widoku. Reguła w sekcji „Wydajność
   renderowania" wyżej obejmuje KONTENERY (`#reviewsList`, `#locationsGrid`),
   a to co innego: tamta pomija całą listę, gdy niewidoczna jest ONA — czyli
   nic nie daje, gdy właśnie na tej liście stoimy. Dopiero ta działa per karta.

   Powód: pod-zakładka „Sesja" renderuje do 900 kart naraz (500 sesji + 200
   oflagowanych + 200 BOK), podczas gdy główna lista ma 20 (PAGE_SIZE).
   Zmierzone JUŻ PO naprawie tła w locardly-brand.css (czyli to jest zysk
   PONAD tamten, nie zamiast niego):

     500 kart → bez tej reguły  82,8 FPS, z nią 166,1 FPS
     900 kart → bez tej reguły  46,0 FPS, z nią 163,9 FPS

   Przy pełnym obciążeniu sama naprawa tła nie wystarcza — 46 FPS to już
   widoczne szarpanie, a maszyna użytkownika bywa wolniejsza od testowej.
   Zero zmian w wyglądzie i zero zmian w zachowaniu: lista zostaje kompletna,
   nic nie jest paginowane ani obcinane.

   `contain-intrinsic-size: auto 260px` — `auto` zapamiętuje REALNĄ wysokość
   karty po pierwszym wyrenderowaniu; 260px to wartość startowa dla kart,
   których jeszcze nigdy nie pokazano, i NIE jest zgadnięta: to zmierzona
   MEDIANA wysokości karty opinii (rozkład 192–294 px, średnia 258).

   ZNANY, ŚWIADOMY KOSZT: dopóki część kart nie została jeszcze ani razu
   wyrenderowana, wysokość dokumentu jest szacowana, więc przy PIERWSZYM
   przewinięciu długiej listy pasek przewijania delikatnie „pełznie"
   (zmierzone 24 406 → 22 954 px, ok. 6%). Po pierwszym przejściu wysokości
   są zapamiętane i pasek jest stabilny. To nieodłączna cecha tego mechanizmu
   przy kartach o zmiennej wysokości — zaakceptowana, bo alternatywą jest
   46 FPS. Przeglądarka bez wsparcia ignoruje obie właściwości (degradacja
   cicha i bezpieczna).

   NIE zamieniaj `auto 260px` na samo `260px` (zamrozi wysokość i rozjedzie
   pasek przewijania) i NIE przenoś tego na `.card` — tam kart są sztuki,
   nie setki, więc zysk jest żaden. */
.review-card {
  content-visibility: auto;
  contain-intrinsic-size: auto 260px;
}

/* ── 3. Windows/Linux: ZERO backdrop-filter, bez wyjątków ───────────────────
   Rekompensata krycia, bo bez rozmycia półprzezroczysta powierzchnia
   przestaje separować treść. Wygląd zmienia się nieznacznie (płaska
   powierzchnia zamiast szkła) — świadomy kompromis na rzecz płynności. */
html.plt-noapple .sidebar,
html.plt-noapple .modal,
html.plt-noapple .modal-overlay,
html.plt-noapple .login-card,
html.plt-noapple .bg-notif,
html.plt-noapple .sb-burger,
html.plt-noapple .session-bar,
html.plt-noapple .ui-date-popup,
html.plt-noapple .tpl-drop-list,
html.plt-noapple #map .leaflet-control-zoom a,
html.plt-noapple #map .leaflet-control-attribution {
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  will-change: auto !important;
}

/* Motyw JASNY — kryjące odpowiedniki dawnych powierzchni szklanych */
html.plt-noapple .sidebar    { background: #f4f7fd; }
html.plt-noapple .modal,
html.plt-noapple .login-card { background: #fcfdff; }
html.plt-noapple .modal-overlay { background: rgba(20,24,40,.45); }
html.plt-noapple .bg-notif,
html.plt-noapple .session-bar,
html.plt-noapple .sb-burger  { background:var(--surface-solid,#fff); }
/* Karty w pełni kryjące — półprzezroczyste (.92) zmuszały kompozytor do
   mieszania KAŻDEJ karty z przypiętym gradientem tła przy każdej klatce
   przewijania. Różnica wizualna na poziomie 8% krycia. */
html.plt-noapple { --surface: #ffffff; }

/* Motyw CIEMNY — te same reguły, ciemne wartości (BLOKER 1 z [v1.60]:
   bez tego Windows dostaje białe karty z białym tekstem). Wartości spójne
   z blokiem mobilnym wyżej (#0c1220 / #1c2440). */
html.plt-noapple.theme-dark .sidebar    { background: #0c1220; }
html.plt-noapple.theme-dark .modal,
html.plt-noapple.theme-dark .login-card { background: #141b33; }
html.plt-noapple.theme-dark .modal-overlay { background: rgba(3,5,12,.78); }
html.plt-noapple.theme-dark .bg-notif,
html.plt-noapple.theme-dark .session-bar,
html.plt-noapple.theme-dark .sb-burger  { background: #1c2440; }
html.plt-noapple.theme-dark { --surface: #161d33; }

/* ═══════════════════════════════════════════════════════════════════════
   WARSTWA RUCHU [alfa 0.173] — MUSI ZOSTAĆ NA KOŃCU PLIKU
   ─────────────────────────────────────────────────────────────────────
   Ta sekcja stoi ZA blokiem wydajnościowym [v1.61] celowo: część reguł
   nadpisuje wcześniejsze definicje o tej samej specyficzności
   (`.nav-link.active`), więc decyduje kolejność w pliku. Nie przenoś jej
   wyżej i nie „naprawiaj" tego `!important`-em.

   Wszystkie animacje jadą WYŁĄCZNIE na `transform`/`opacity` (kompozycja
   GPU, zero layoutu/paintu) — jedyny wyjątek (`filter: blur`) jest jawnie
   wyłączony na Windows/Androidzie i telefonach, patrz punkt 3.
   ═══════════════════════════════════════════════════════════════════════ */

:root {
  --ease-out-strong: cubic-bezier(.23, 1, .32, 1);
  --pane-dur: .19s;
}

/* ── 1. Pod-zakładki: wejście panelu ────────────────────────────────────
   Panele przełączane są przez `display` (reviews/settings/photos/rank) albo
   klasę `.active` (edycja profilu). W OBU przypadkach element przechodzi ze
   stanu nierenderowanego do renderowanego, co RESTARTUJE animację CSS — więc
   nie trzeba dotykać ani jednej linijki w pięciu plikach JS przełączających
   te zakładki. Wyjście jest natychmiastowe (stary panel po prostu znika):
   szybkie wyjście + miękkie wejście czyta się lepiej niż symetryczny fade
   i nie opóźnia reakcji na klik.                                        */
@keyframes paneIn {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
/* Wariant BEZ transform — dla panelu z mapą Leaflet: transform na kontenerze
   mapy w trakcie przeliczania rozmiaru potrafi dać przycięty kadr ([v1.54]). */
@keyframes paneInFlat {
  from { opacity: 0; }
  to   { opacity: 1; }
}

#tab-reviews, #tab-session, #tab-deleted,   /* Opinie */
.settings-pane,                              /* Ustawienia (7 pod-zakładek) */
.pe-pane,                                    /* Edycja profilu */
.users-pane,                                 /* Użytkownicy (role / API) */
#pane-add, #pane-branding {                  /* Zdjęcia */
  animation: paneIn var(--pane-dur) var(--ease-out-strong) both;
}
/* UWAGA: selektor to `.pe-pane`, a NIE `.pe-pane.active`. Animacja ma być
   przypisana do panelu ZAWSZE — także gdy jest ukryty. Wtedy jedyną zmienną
   przy przełączaniu zakładki jest `display`, czyli dokładnie ten sam,
   zweryfikowany mechanizm co w Opiniach i Ustawieniach (element wchodzi do
   renderu → animacja startuje od zera). Przy `.pe-pane.active` nazwa animacji
   pojawiałaby się dopiero razem z odsłonięciem — to działa, ale jest inną
   ścieżką w silniku i trudniej ją potwierdzić pomiarem. */
#viewMap, #viewHistory {                     /* Pozycje lokalne (mapa/historia) */
  animation: paneInFlat var(--pane-dur) ease-out both;
}

/* ── 2. Pigułka aktywnej zakładki w panelu bocznym ──────────────────────
   Dotąd stan aktywny był tłem NA SAMYM LINKU, więc przy zmianie strony
   znikał w jednym miejscu i pojawiał się w drugim — bez ruchu łączącego.
   Teraz jest to JEDEN trwały element (`.nav-pill`) wstrzykiwany przez
   `app.js` do listy nawigacji i pozycjonowany `transform: translateY()`.

   DLACZEGO NIE `view-transition-name` (pierwsze podejście, WYCOFANE):
   `.sidebar` jest kontenerem PRZEWIJANYM (przy 900 px wysokości okna treść
   panelu ma ~1083 px). Kliknięcie zakładki położonej niżej powoduje, że
   przeglądarka przewija panel, żeby pokazać klikany link — a wtedy pigułka
   zakładki źródłowej ląduje POD górną krawędzią panelu (zmierzone: y = −88 px)
   i jej snapshot jest przycięty do zera. Przejście międzydokumentowe nie ma
   wtedy czego morfować, więc animacja „gubiła się" w jedną stronę (w dół),
   a działała w drugą (w górę, gdzie panel wraca na początek). Pozycja liczona
   `translateY` względem LISTY, a nie względem okna, jest od przewinięcia
   niezależna — dlatego działa w każdym kierunku.                          */
.nav-links { position: relative; }
.nav-pill {
  position: absolute;
  left: 12px; right: 12px; top: 0;
  border-radius: 13px;
  background: var(--primary);
  box-shadow: 0 2px 12px rgba(55,104,234,.35);
  z-index: 0;
  pointer-events: none;
  /* Ruch WYŁĄCZNIE na transform — kompozycja GPU, zero layoutu.
     `height` zmienia się tylko przy zwijaniu panelu (inna wysokość pozycji).
     420 ms, nie 320: przejazd bywa długi (z pierwszej zakładki na ostatnią to
     ~740 px), a strona i tak czeka wtedy na dane z API. Krótsza animacja
     ścigała się z ładowaniem treści zamiast je spokojnie przykryć. */
  transition: transform .42s var(--sb-ease), height .26s var(--sb-ease);
}
/* Bez skoku przy pierwszym renderze: pigułka pojawia się na swoim miejscu,
   a jedzie dopiero wtedy, gdy realnie zmieniamy zakładkę. */
.nav-pill.no-anim { transition: none; }
html.theme-dark .nav-pill { box-shadow: 0 2px 12px rgba(59,110,240,.45); }
.nav-link { position: relative; z-index: 1; }

/* [alfa 0.288] Kolor napisu aktywnej zakładki DOGANIA pigułkę.
   `.nav-link.active` ma `color:#fff`, bo zakłada, że pigułka jest już pod nim.
   Gdy pigułka dopiero JEDZIE (a od tej wersji jedzie w żywym DOM-ie, na widoku),
   przez cały przejazd napis w celu był biały na jasnym panelu — praktycznie
   nieczytelny (kontrast ~1,1:1). Klasę `navpill-travel` nadaje inline-skrypt
   TYLKO wtedy, gdy realnie zaplanował przejazd, więc przy zwykłym wejściu na
   stronę (bez historii, po zmianie szerokości okna, przy `prefers-reduced-motion`)
   nic się nie zmienia. `--pill-dur` ustawia ten sam skrypt, z tego samego
   wyliczenia co czas przejazdu — kolor i ruch kończą się razem. */
@keyframes gmbNavInk {
  0%, 55% { color: var(--sidebar-text); }
  100%    { color: #fff; }
}
html.navpill-travel .nav-link.active {
  animation: gmbNavInk var(--pill-dur, .42s) var(--sb-ease) both;
}
@media (prefers-reduced-motion: reduce) {
  html.navpill-travel .nav-link.active { animation: none; }
}

/* Tło zdejmujemy z samego linku dopiero WTEDY, gdy pigułka faktycznie
   istnieje (`app.js` nadaje `has-navpill`). Gdyby JS się nie wykonał,
   aktywna zakładka wygląda dokładnie jak przed tą zmianą — bez tego
   warunku brak JS oznaczałby zakładkę bez żadnego oznaczenia.
   Reguła dla motywu ciemnego jest osobna, bo tamta ma wyższą specyficzność. */
html.has-navpill .nav-link.active                 { background: transparent; box-shadow: none; }
html.theme-dark.has-navpill .nav-link.active      { background: transparent; box-shadow: none; }

/* ── 3. Odświeżanie list bez wygaszania treści ──────────────────────────
   Zmiana filtra nie czyści już listy do spinnera (patrz `loadReviews`) —
   poprzedni wynik zostaje na ekranie przygaszony, aż przyjdą nowe dane.
   Drobna interakcja przestaje wyglądać jak przeładowanie strony.        */
.list-refreshing {
  opacity: .45;
  pointer-events: none;
  filter: blur(1.5px);
  transition: opacity .18s ease, filter .18s ease;
}
/* Windows/Android i telefony: `blur` nad długą listą to koszt kompozycji
   liczony CO KLATKĘ na całej powierzchni — dokładnie ta klasa problemu,
   którą usuwał [v1.61]. Samo przygaszenie niesie ten sam komunikat. */
html.plt-noapple .list-refreshing { filter: none; }
@media (max-width: 900px) { .list-refreshing { filter: none; } }

/* ── 4. Wejście kart siatki na desktopie ────────────────────────────────
   Mobile miał ten efekt od [v1.56] (`mCardIn`), desktop nie — ta sama
   aplikacja wyglądała „żywo" na telefonie i płasko na komputerze.
   Osobne keyframes, bo `mCardIn` jest zdefiniowane WEWNĄTRZ media query
   (max-width:900px), więc na desktopie w ogóle nie istnieje.            */
@media (min-width: 901px) {
  @keyframes gridCardIn {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
  }
  .stats-grid > *, .locations-grid > * {
    animation: gridCardIn .34s var(--ease-out-strong) backwards;
  }
  .stats-grid > :nth-child(2), .locations-grid > :nth-child(2) { animation-delay: .03s }
  .stats-grid > :nth-child(3), .locations-grid > :nth-child(3) { animation-delay: .06s }
  .stats-grid > :nth-child(4), .locations-grid > :nth-child(4) { animation-delay: .09s }
  .stats-grid > :nth-child(5), .locations-grid > :nth-child(5) { animation-delay: .12s }
  /* Powyżej 5. kafelka opóźnienie się NIE kumuluje — przy 25 wizytówkach
     narastający stagger oznaczałby ponad sekundę czekania na ostatnią kartę. */
  .stats-grid > :nth-child(n+6), .locations-grid > :nth-child(n+6) { animation-delay: .15s }
}

/* ── 5. Puste stany ─────────────────────────────────────────────────────
   Pojawiały się skokowo zaraz po spinnerze — to samo szarpnięcie, co przy
   pod-zakładkach, tylko w innym miejscu.                                */
.empty-state { animation: paneIn .22s var(--ease-out-strong) both; }

/* ── 6. Dostępność ──────────────────────────────────────────────────────
   Reduced motion = mniej ruchu, nie zero informacji: zostawiamy przenikanie
   (pomaga zrozumieć, że treść się zmieniła), zdejmujemy przesunięcia.    */
@media (prefers-reduced-motion: reduce) {
  #tab-reviews, #tab-session, #tab-deleted,
  .settings-pane, .pe-pane,
  #pane-add, #pane-branding,
  .empty-state {
    animation: paneInFlat .15s ease both;
  }
  .stats-grid > *, .locations-grid > * { animation: none !important; }
  .list-refreshing { filter: none; transition: none; }
  .nav-pill { transition: none !important; }
}


/* ══════════════════════════════════════════════════════════════════════════
   POWIADOMIENIA SYSTEMU — dzwonek w nagłówku panelu + centrum powiadomień
   Sekcja celowo na KOŃCU pliku (jak „warstwa ruchu" i blok wydajności) — część
   reguł ma wygrywać kolejnością z blokiem mobilnym i motywem ciemnym.
   Dzwonek wstrzykuje app.js → initNotifications(); panel jest dzieckiem <body>
   (position:fixed), więc nie przycina go scroll ani overflow panelu bocznego.
   ══════════════════════════════════════════════════════════════════════════ */

/* DZWONEK POWIADOMIEN: caly komponent (rozmiar, ksztalt, odznaka,
   pozycja, wariant zwiniety i ciemny) siedzi w `public/css/motion.css`,
   sekcja 7 — port rareui/components/notificationbell. Nie dubluj go tutaj:
   motion.css laduje sie POZNIEJ i cicho wygra przy rownej specyficznosci. */

.gmb-notif-panel {
  position: fixed; z-index: 2500;              /* nad treścią, pod modalami (3000) */
  display: none; overflow: hidden;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--surface-solid, #fff);
  box-shadow: 0 12px 34px rgba(20,30,60,.18);
}
.gmb-notif-panel.open { display: block; }
.gmb-notif-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 14px; border-bottom: 1px solid var(--border-soft);
  font-size: 13px; font-weight: 700;
}
.gmb-notif-readall {
  border: none; background: none; cursor: pointer;
  font-size: 11.5px; font-weight: 650; color: var(--accent-text, #2f5ad6);
}
.gmb-notif-readall:hover { text-decoration: underline; }
.gmb-notif-list { max-height: min(420px, 60vh); overflow-y: auto; }
.gmb-notif-empty { padding: 22px 14px; text-align: center; font-size: 12.5px; color: var(--muted); }

.gmb-notif {
  display: flex; gap: 11px; align-items: flex-start;
  padding: 11px 14px; border-bottom: 1px solid var(--border-soft);
  cursor: pointer; transition: background .12s;
}
.gmb-notif:last-child { border-bottom: none; }
.gmb-notif:hover { background: var(--surface-sunken, #f7f8fc); }
.gmb-notif.unread { background: rgba(55,104,234,.06); }
.gmb-notif.unread:hover { background: rgba(55,104,234,.10); }
.gmb-notif-ico { font-size: 16px; line-height: 1.3; flex-shrink: 0; }
.gmb-notif-body { flex: 1; min-width: 0; }
.gmb-notif-title { font-size: 12.8px; font-weight: 650; color: var(--text); }
.gmb-notif-sub { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.gmb-notif-when { font-size: 10.5px; color: var(--muted); white-space: nowrap; flex-shrink: 0; }
.gmb-notif.sev-error   .gmb-notif-title { color: #c62828; }
.gmb-notif.sev-warning .gmb-notif-title { color: #b45309; }

html.theme-dark .gmb-notif-panel { background: var(--surface-raised, #141b2c); border-color: rgba(255,255,255,.12); }
html.theme-dark .gmb-notif.unread { background: rgba(59,110,240,.14); }
html.theme-dark .gmb-notif:hover  { background: rgba(255,255,255,.05); }

/* ── Karta „Nadchodzące zmiany menu" na Dashboardzie (wariant C) ─────────── */
.upnext-list { display: flex; flex-direction: column; gap: 9px; }
.upnext-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 12px; border: 1px solid var(--border-soft); border-radius: 10px;
  background: var(--surface-sunken, #f8fafc);
}
.upnext-when { width: 118px; flex-shrink: 0; }
.upnext-when .d { font-weight: 700; font-size: 12.8px; }
.upnext-when .h { font-size: 11.5px; color: var(--muted); }
.upnext-main { flex: 1; min-width: 0; }
.upnext-main .f { font-weight: 650; font-size: 12.8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upnext-main .m { font-size: 11.5px; color: var(--muted); }
.upnext-cd { font-variant-numeric: tabular-nums; font-weight: 700; font-size: 12.5px; color: var(--warn-fg, #b45309); white-space: nowrap; }
.upnext-cd.far { color: var(--muted); font-weight: 600; }
.upnext-empty { padding: 16px; text-align: center; font-size: 12.5px; color: var(--muted); }

@media (max-width: 900px) {
  .gmb-notif-panel { max-width: calc(100vw - 16px); }
  .upnext-row { flex-wrap: wrap; }
  .upnext-when { width: auto; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PRZEJŚCIA MIĘDZYDOKUMENTOWE (View Transitions) — [v1.88]
   Sekcja celowo na SAMYM KOŃCU pliku, jak pozostałe warstwy nadpisujące.

   PO CO: aplikacja jest WIELOSTRONICOWA — każda zmiana zakładki to nowy
   dokument. Bez tego przeglądarka przytrzymuje obraz poprzedniej strony tylko
   do pewnego progu, a po jego przekroczeniu pokazuje PUSTĄ KLATKĘ (zgłoszone
   jako „interfejs się reloaduje, znika pasek"). Przejście międzydokumentowe
   usuwa to STRUKTURALNIE: przeglądarka trzyma snapshot starej strony aż nowy
   dokument jest gotowy do wyświetlenia, i dopiero wtedy przenika. Nie ma
   momentu, w którym nie ma czego pokazać.

   DLACZEGO TERAZ, SKORO [v1.70] TO WYCOFAŁO — trzy tamte powody są zaadresowane:

   1. CZARNY ARTEFAKT brał się z `view-transition-name` na `.sidebar`, który ma
      `backdrop-filter`. Element z rozmyciem tła wyodrębniony do WŁASNEGO
      snapshotu nie ma za sobą niczego do rozmycia i renderuje się jako ciemny
      prostokąt. Tutaj NIC z `backdrop-filter` nie dostaje nazwy — panel i karty
      zostają częścią snapshotu korzenia, gdzie mają prawdziwe tło pod spodem.
      NIE NADAWAJ `view-transition-name` PANELOWI ANI KARTOM.

   2. ANIMACJA WYPRZEDZAŁA TREŚĆ — stąd korzeń dostaje tylko 140 ms liniowo.
      To nie jest efekt do oglądania, tylko przytrzymanie obrazu na czas
      podmiany dokumentu. Do tego strony są teraz pobierane z wyprzedzeniem
      ([v1.87]), więc nowy dokument jest zwykle gotowy od razu.

   3. SNAPSHOT PANELU PRZYKRYWAŁ PRZEJAZD PIGUŁKI — dlatego pigułka dostaje
      WŁASNĄ nazwę i morfuje natywnie między pozycjami. Jest jednolitym
      kolorem bez rozmycia, więc punkt 1 jej nie dotyczy. Skrypt w HTML
      pomija wtedy własny przejazd (patrz `_vt` w inline-skrypcie), żeby
      pigułka nie jechała dwa razy.
   ═══════════════════════════════════════════════════════════════════════════ */

@view-transition { navigation: auto; }

/* ── Czasy przejścia jako TOKENY, nie liczby wpisane w regułę ────────────────
   [v2.01] Windows/Linux dostaje inne wartości niż Mac (patrz blok
   `html.plt-noapple` niżej). Sterowanie idzie przez zmienne, a NIE przez
   selektor `html.plt-noapple::view-transition-old(root)`, bo pseudo-elementy
   przejścia wiszą przy elemencie głównym i taki zapis jest kruchy między
   wersjami przeglądarki. Zmienne dziedziczą z `:root` do całego drzewa
   `::view-transition-*` — to droga udokumentowana w specyfikacji. */
:root {
  --vt-root-dur: .14s;   /* przenikanie korzenia (pełnoekranowe)  */
  --vt-pill-dur: .42s;   /* przejazd pigułki nawigacji            */
}

/* Korzeń: krótkie, liniowe przenikanie. Celem jest CIĄGŁOŚĆ OBRAZU, nie efekt —
   dłuższa animacja pokazywałaby pustą jeszcze powłokę nowej strony. */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: var(--vt-root-dur);
  animation-timing-function: linear;
}

/* USUNIĘTE [alfa 0.288]: `.nav-pill { view-transition-name: gmb-navpill }` wraz
   z regułami `::view-transition-*(gmb-navpill)`. Historia, żeby nikt tego nie
   „przywrócił" jako ulepszenia:

   [v1.88] oddało przejazd pigułki przeglądarce (nazwana grupa przejścia) —
   argument brzmiał „nie da się go wyprzedzić". Wada ujawniła się dopiero, gdy
   [alfa 0.287] odsunęło ekran ładowania od panelu i panel stał się WIDOCZNY
   w trakcie nawigacji. Nazwana grupa jest wynoszona PONAD cały snapshot
   korzenia, więc pigułka malowała się nad tekstem linku — a normalnie jest pod
   nim (`.nav-pill{z-index:0}` vs `.nav-link{z-index:1}`). Zmierzone w klatkach
   z realnej nawigacji Użytkownicy→Dashboard: przez całe 560 ms przejazdu
   aktywna zakładka była PUSTYM niebieskim prostokątem, bez ikony i napisu.

   Teraz przejazd wykonuje zwykła tranzycja CSS w ŻYWYM DOM-ie (mechanizm
   z [v1.85]: pozycja startowa z `sessionStorage`, czas z `_dur`), więc pigułka
   wraca pod tekst. Przenikanie korzenia (`--vt-root-dur`) ZOSTAJE — ono nadal
   łagodnie wymienia treść na ekran ładowania. */

/* ── Windows/Linux: te same czasy przejścia co Mac — ŚWIADOMIE ──────────────
   [v2.03] Historia w dwóch aktach, żeby nikt nie „przywrócił" aktu pierwszego:

   AKT 1 [v2.01]: tu stało `html.plt-noapple { --vt-root-dur: 0s;
   --vt-pill-dur: .22s; }` — hipoteza brzmiała „mieszanie dwóch
   pełnoekranowych tekstur jest za drogie dla zintegrowanej grafiki".
   Ta hipoteza NIGDY nie została potwierdzona pomiarem na realnym Windowsie.

   AKT 2 [v2.02]: prawdziwa, ZMIERZONA przyczyna zacinania okazała się
   sieciowa — Mac testuje na localhost, Windows na VPS, a VPS serwował
   261 KB surowego CSS z blokującą rewalidacją 208 ms przy każdej zakładce.
   Render nowej strony czekał na sieć, więc przejście rwało/abortowało
   (mechanizm z [v1.91]). [v2.01] leczyło OBJAW, gasząc animację — po czym
   użytkownik zgłosił, że twardy przeskok na Windowsie wygląda gorzej niż
   płynne przejście na Macu. Oczywiście, że wyglądał — animacji nie było.

   Po naprawie sieci ([v2.02]: stale-while-revalidate + gzip + HTTP/2)
   zasoby idą z cache, render nie czeka na round-trip i przejście ma z czego
   rysować klatki. Windows dostaje więc te same wartości co Mac (dziedziczy
   `--vt-root-dur: .14s` / `--vt-pill-dur: .42s` z `:root` — brak nadpisania
   jest tu celową decyzją, nie przeoczeniem).

   JEŚLI ktoś w przyszłości znów zgłosi rwące przejścia na Windows: najpierw
   pomiar na TEJ maszynie (DevTools → Performance, dropped frames w trakcie
   przejścia), nie zgadywanie warstwy. Dopiero potwierdzony pomiarem koszt
   kompozycji uzasadnia powrót do skróconych czasów — i wtedy skracaj
   (`.22s`), nie zeruj: `0s` na korzeniu czyta się jako brak animacji,
   a zero na pigułce to regresja [v1.85]. */

/* Tło strony przestaje być przypięte do okna. `background-attachment: fixed`
   zabrania przeglądarce przewijania warstwy tła — każda klatka przewijania
   wymaga przerysowania CAŁEGO widocznego obszaru z trzema gradientami
   radialnymi, a przy nawigacji ta sama powierzchnia rasteryzuje się ponownie
   na krytycznej ścieżce pierwszego renderu. Dokładnie tę zamianę zrobiło już
   [v1.60] dla telefonu, z tym samym uzasadnieniem — desktopowy Windows nigdy
   nie został nią objęty. Wrażenie głębi niesie `body::before/::after`, które
   są `position: fixed` i zostają nieruchome, więc różnicę widać dopiero po
   przewinięciu długiej listy (gradienty odjeżdżają z treścią). Na Macu bez
   zmian — cały ten blok jest tam martwy. */
html.plt-noapple body { background-attachment: scroll; }

@media (prefers-reduced-motion: reduce) {
  ::view-transition-group(*),
  ::view-transition-old(*),
  ::view-transition-new(*) { animation: none !important; }
}

/* ═══════════════════════════════════════════════════════════════
   EDYTOWANE OPINIE — dyskretny znacznik przy krawędzi (zmiana 2026-08-09)
   Gość zmienił opinię po opublikowaniu; wariant .edited-after-reply =
   edycja PO naszej wysłanej odpowiedzi (najcenniejszy sygnał — sprawdź,
   czy odpowiedź nadal pasuje do nowej treści). Sekcja celowo na KOŃCU
   pliku — wygrywa kolejnością z bazową kartą i blokami motywów.

   DLACZEGO NIE BEŻOWE TŁO CAŁEJ KARTY (poprzedni stan, [v1.92]):
   edycja to informacja o JEDNEJ opinii, nie zdarzenie rangi alarmu — a
   zamalowana karta czytała się jak ostrzeżenie i wyrywała opinię z rytmu
   listy. Wyróżnienie sprowadzone do paska przy lewej krawędzi: widać je
   przy przewijaniu, ale nie krzyczy. KOMPLET INFORMACJI ZOSTAJE — badge
   przy ocenie i ramka „Poprzednia wersja" pod treścią są nietknięte.
   Nie przywracaj tu tła karty; jeśli edycja ma być bardziej widoczna,
   wzmocnij pasek (szerokość/nasycenie), nie powierzchnię.
   ═══════════════════════════════════════════════════════════════ */
.review-card.edited-review {
  border-left: 3px solid rgba(197, 160, 89, .75);
}
.review-card.edited-after-reply {
  border-left: 3px solid rgba(197, 138, 48, .95);
}
html.theme-dark .review-card.edited-review {
  border-left-color: rgba(197, 160, 89, .6);
}
html.theme-dark .review-card.edited-after-reply {
  border-left-color: rgba(214, 158, 70, .85);
}
.edited-badge.edited-badge-alert {
  background: rgba(197, 138, 48, .18);
  color: #9a5b00;
  font-weight: 700;
}
html.theme-dark .edited-badge.edited-badge-alert {
  background: rgba(214, 158, 70, .22);
  color: #f0c684;
}
.edited-prev-box {
  margin-top: 8px;
  padding: 10px 12px;
  border-radius: 10px;
  background: rgba(197, 160, 89, .12);
  border: 1px dashed rgba(197, 160, 89, .5);
  font-size: 13px;
}
.edited-prev-head {
  display: flex; justify-content: space-between; align-items: center;
  gap: 8px; flex-wrap: wrap;
  font-weight: 600; color: #8a5a10; margin-bottom: 6px; font-size: 12px;
}
html.theme-dark .edited-prev-head { color: #f0c684; }
.edited-prev-rating { font-size: 13px; }
.edited-prev-label { font-size: 11px; color: var(--muted); margin-bottom: 2px; }
.edited-prev-comment { white-space: pre-wrap; color: var(--text); }
/* [alfa 0.336] Dwie wersje edytowanej opinii + czerwony „zakreślacz" różnic
   (jak wyróżnienie tekstu w Wordzie). .hl-del = słowa usunięte (przekreślone). */
.edited-ver { margin-top: 8px; padding: 8px 10px; border-radius: 8px; background: rgba(255,255,255,.45); }
html.theme-dark .edited-ver { background: rgba(255,255,255,.05); }
.edited-ver-new { border: 1px solid rgba(239,68,68,.35); }
.edited-ver-head { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-strong); margin-bottom: 4px; display: flex; justify-content: space-between; gap: 8px; flex-wrap: wrap; }
.edited-legend { font-weight: 500; text-transform: none; letter-spacing: 0; }
.hl-red { background: #ff5c5c; color: #fff; text-decoration: none; border-radius: 2px; padding: 0 2px; }
.hl-del { background: rgba(239,68,68,.12); color: #991b1b; text-decoration: line-through; border-radius: 2px; padding: 0 1px; }
html.theme-dark .hl-red { background: #dc2626; }
html.theme-dark .hl-del { color: #fca5a5; }
.edited-prev-box-dismissed { opacity: .72; border-style: dotted; }
.edited-badge.edited-badge-muted { opacity: .7; }
/* Usunięta i dodana ponownie przez tego samego autora */
.review-card.readded-review { border-left: 3px solid rgba(239,68,68,.85); }
.readded-badge { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 700; padding: 2px 8px; border-radius: 999px; background: rgba(239,68,68,.14); color: #991b1b; }
html.theme-dark .readded-badge { color: #fca5a5; background: rgba(239,68,68,.22); }
.readded-box { margin-top: 8px; padding: 10px 12px; border-radius: 10px; background: rgba(239,68,68,.07); border: 1px dashed rgba(239,68,68,.45); font-size: 13px; }
.readded-head { display: flex; justify-content: space-between; align-items: center; gap: 8px; flex-wrap: wrap; font-weight: 700; color: #991b1b; font-size: 12px; margin-bottom: 4px; }
html.theme-dark .readded-head { color: #fca5a5; }

/* ═══════════════════════════════════════════════════════════════════════════
   AUTOMATYZACJA ([v1.96])
   ---------------------------------------------------------------------------
   MUSI ZOSTAĆ NA KOŃCU PLIKU — tak jak sekcja mobilna i bloki motywów.
   Media query NIE podnosi specyficzności, więc o wyniku decyduje kolejność
   (lekcja z [v1.56]/[v1.60]/[v1.61]). Przeniesienie tego bloku wyżej cicho
   odda reguły blokowi mobilnemu.

   Zero nowych kolorów i krojów: strona korzysta wyłącznie z tokenów systemu
   (--surface, --border, --accent-text…), żeby wejść w istniejący język
   wizualny zamiast z nim konkurować.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ─── Pasek stanu ─────────────────────────────────────────────────────────── */
.au-status {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;                                  /* 1px + tło = hairline między celami */
  background: var(--border-soft, #e2e8f0);
  border: 1px solid var(--border-soft, #e2e8f0);
  border-radius: var(--radius-card, 20px);
  overflow: hidden;
  margin-bottom: 14px;
}
.au-status-cell {
  background: var(--surface, #fff);
  backdrop-filter: var(--blur, blur(30px));
  padding: 18px 20px;
  min-width: 0;                              /* pozwala treści się kurczyć */
}
.au-status-label {
  font-size: 11px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted, #718096); margin-bottom: 8px;
}
.au-status-value {
  display: flex; align-items: center; gap: 9px;
  font-size: 20px; font-weight: 650; color: var(--text, #1a202c);
  line-height: 1.2;
}
.au-status-sub {
  margin-top: 5px; font-size: 12px; color: var(--muted, #718096);
  overflow-wrap: anywhere;
}
/* Koszt większy niż reszta: to jedyna liczba na tej stronie, która realnie
   ubywa z konta — ma być czytelna bez szukania. */
.au-cost { font-size: 24px; font-variant-numeric: tabular-nums; }

.au-dot {
  width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0;
  background: var(--muted, #a0aec0);
}
.au-dot.on  { background: #16a34a; box-shadow: 0 0 0 3px rgba(22, 163, 74, .16); }
.au-dot.off { background: #a0aec0; }
.au-dot.warn{ background: #d97706; box-shadow: 0 0 0 3px rgba(217, 119, 6, .16); }

/* ─── Gwarancja pod paskiem ───────────────────────────────────────────────── */
.au-promise {
  display: flex; align-items: center; gap: 8px;
  margin: 0 0 24px; padding: 0 4px;
  font-size: 13px; color: var(--muted, #718096);
}
.au-promise .ic { flex-shrink: 0; color: #16a34a; }

/* ─── Jakość automatyzacji ([v2.06]) ─────────────────────────────────────────
   Trzy kategorie w jednym wierszu, jako linki do Opinii z pre-ustawionym
   filtrem — kliknięcie liczby ma być szybsze niż ręczne ustawianie filtra. */
#auQualityCard { margin-bottom: 16px; }
.au-quality-window { font-weight: 400; color: var(--muted, #718096); font-size: 12px; }
.au-quality-row {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 4px;
}
.au-quality-stat {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 12px 8px; border-radius: 12px; text-decoration: none;
  border: 1px solid var(--border-soft, #e2e8f0); transition: transform .12s ease;
}
.au-quality-stat:hover { transform: translateY(-1px); }
.au-quality-num  { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text, #1a202c); }
.au-quality-pct  { font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; }
.au-quality-label{ font-size: 11px; color: var(--muted, #718096); text-align: center; }
.au-quality-stat.ai-outcome-full      { background: rgba(22,163,74,.06);  border-color: rgba(22,163,74,.25); }
.au-quality-stat.ai-outcome-full      .au-quality-pct { color: #15803d; }
.au-quality-stat.ai-outcome-assisted  { background: rgba(139,92,246,.06); border-color: rgba(139,92,246,.25); }
.au-quality-stat.ai-outcome-assisted  .au-quality-pct { color: #6d28d9; }
.au-quality-stat.ai-outcome-escalated { background: rgba(217,119,6,.07);  border-color: rgba(217,119,6,.3); }
.au-quality-stat.ai-outcome-escalated .au-quality-pct { color: #92400e; }

/* ─── Siatka dwóch kart ───────────────────────────────────────────────────── */
.au-grid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 16px; align-items: start;
}

/* ─── Przełącznik jako cały wiersz (większy cel kliknięcia niż sam checkbox) ─ */
.au-switch {
  display: flex; align-items: flex-start; gap: 11px;
  padding: 12px; margin-bottom: 8px;
  border: 1px solid var(--border-soft, #e2e8f0); border-radius: 10px;
  cursor: pointer; transition: background .15s ease, border-color .15s ease;
}
.au-switch:hover { background: rgba(66, 133, 244, .05); border-color: var(--border, #cbd5e0); }
.au-switch input { width: 16px; height: 16px; margin-top: 2px; flex-shrink: 0; cursor: pointer; }
.au-switch-body { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.au-switch-name { font-size: 13px; font-weight: 600; color: var(--text, #1a202c); }
.au-switch-desc { font-size: 12px; color: var(--muted, #718096); line-height: 1.45; }

.au-field { margin-top: 16px; }
.au-hint  { margin-top: 6px; font-size: 12px; color: var(--muted, #718096); line-height: 1.45; }
.au-lead  { margin: 0 0 16px; font-size: 13px; color: var(--muted, #718096); line-height: 1.5; }
.au-wide  { width: 100%; margin-top: 18px; }

/* ─── Powitanie w odpowiedziach: pasek zbiorczy + lista wizytówek ────────── */
.au-sal-card { margin-top: 16px; }

/* Pasek zbiorczy dostaje własne, delikatnie zabarwione tło — bez niego dwa
   przyciski działające na WSZYSTKIE wizytówki naraz wyglądają jak kolejny
   wiersz listy, a robią coś nieporównanie szerszego. */
.au-sal-bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; flex-wrap: wrap;
  padding: 11px 14px; margin-bottom: 14px;
  border: 1px solid var(--border-soft, #e2e8f0); border-radius: 10px;
  background: rgba(59, 110, 240, .06);
}
.au-sal-count   { font-size: 13px; color: var(--muted-strong, #484e5e); min-width: 0; }
.au-sal-count b { color: var(--text, #1a202c); font-weight: 700; font-variant-numeric: tabular-nums; }
.au-sal-actions { display: flex; gap: 6px; flex-wrap: wrap; }

/* auto-fill, a nie stała liczba kolumn: lista rośnie razem z liczbą wizytówek,
   a na telefonie schodzi do jednej kolumny bez osobnej media query. */
.au-sal-list {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); gap: 6px;
}
.au-sal-row {
  display: flex; align-items: center; gap: 11px;
  padding: 8px 11px; min-width: 0;
  border: 1px solid var(--border-soft, #e2e8f0); border-radius: 9px;
  cursor: pointer; transition: background .15s ease, border-color .15s ease;
}
.au-sal-row:hover { background: rgba(66, 133, 244, .05); border-color: var(--border, #cbd5e0); }
/* min-width:0 jest WARUNKIEM, nie ozdobą: element flex ma domyślnie
   min-width:auto i nie da się go zwęzić, więc długa nazwa lokalu
   rozpychałaby kolumnę zamiast się uciąć (ta sama pułapka co w [v1.56]). */
.au-sal-name {
  font-size: 13px; color: var(--text, #1a202c); min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.au-sal-empty { font-size: 13px; color: var(--muted-strong, #484e5e); padding: 10px 2px; }

/* ─── Zakres dat ──────────────────────────────────────────────────────────── */
.au-dates   { display: flex; align-items: center; gap: 8px; }
.au-dates .form-control { flex: 1; min-width: 0; }
.au-dash    { color: var(--muted, #718096); flex-shrink: 0; }

/* Liczba opinii oczekujących w wybranym okresie + przycisk „wybierz cały
   zestaw" ([v2.05]) — wiersz pod presetami zakresu dat. */
.au-pending-line {
  margin-top: 10px; font-size: 12px; color: var(--muted, #718096);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.au-pending-line strong { color: var(--text, #1a202c); font-variant-numeric: tabular-nums; }

/* ─── Wynik przebiegu ─────────────────────────────────────────────────────── */
.au-result {
  margin-top: 16px; padding: 14px;
  border: 1px solid var(--border-soft, #e2e8f0); border-radius: 10px;
  background: var(--surface-sunken, #f8fafc);
  font-size: 13px; line-height: 1.6;
}
.au-result.err { border-color: rgba(220, 38, 38, .35); background: rgba(220, 38, 38, .06); }
.au-result-head { font-weight: 600; margin-bottom: 8px; color: var(--text, #1a202c); }
.au-result-row  { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; }
.au-result-row span:last-child { font-variant-numeric: tabular-nums; font-weight: 600; }
.au-result-note { margin-top: 10px; font-size: 12px; color: var(--muted, #718096); }

/* ─── Reset propozycji ────────────────────────────────────────────────────── */
/* Odsunięty i oddzielony linią od przycisku uruchomienia — to jedyna akcja na
   tej stronie, która kasuje pracę automatu, i nie ma prawa być kliknięta przez
   pomyłkę zamiast „Przygotuj propozycje". */
.au-reset {
  margin-top: 22px; padding-top: 16px;
  border-top: 1px solid var(--border-soft, #e2e8f0);
}

.au-footnote {
  margin-top: 20px; padding: 14px 16px;
  border: 1px solid rgba(217, 119, 6, .35); border-radius: 10px;
  background: rgba(217, 119, 6, .07);
  font-size: 13px; line-height: 1.55; color: var(--text, #1a202c);
}

/* ─── Telefon ─────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  /* Trzy cele obok siebie na 375 px dają ~100 px na komórkę — kwota by się
     łamała. W pionie każda dostaje pełną szerokość. */
  .au-status { grid-template-columns: 1fr; }
  .au-grid   { grid-template-columns: 1fr; }
  .au-cost   { font-size: 22px; }
}

/* ─── Samouczek Automatyzacji ([v1.96]) ───────────────────────────────────── */
/* Dopisane do sekcji AUTOMATYZACJA na końcu pliku — patrz ostrzeżenie wyżej. */


/* Szerszy niż domyślny modal: to dokument do czytania, a nie formularz.
   Wysokość ograniczona, żeby pasek zakładek został przyklejony u góry, a
   przewijała się wyłącznie treść. */
.modal.au-help { max-width: 760px; width: 100%; display: flex; flex-direction: column; max-height: 86vh; }
.au-help-tabs {
  padding: 0 24px; margin: 0; flex-shrink: 0;
  border-bottom: 1px solid var(--border-soft, #e2e8f0);
  overflow-x: auto; overscroll-behavior: contain; touch-action: pan-x;
}
.au-help-body { overflow-y: auto; flex: 1; min-height: 0; }

.au-help-lead { margin: 0 0 16px; font-size: 14px; line-height: 1.6; color: var(--text, #1a202c); }
.au-help-body h4 { margin: 22px 0 8px; font-size: 13px; font-weight: 700; color: var(--text, #1a202c); }
.au-help-body h4:first-child { margin-top: 0; }
.au-help-body p { margin: 0 0 12px; font-size: 13px; line-height: 1.65; color: var(--muted, #718096); }

.au-help-steps, .au-help-list { margin: 0 0 14px; padding-left: 22px; }
.au-help-steps li, .au-help-list li {
  font-size: 13px; line-height: 1.65; color: var(--muted, #718096); margin-bottom: 7px;
}
.au-help-steps li strong, .au-help-list li strong { color: var(--text, #1a202c); }
.au-help-steps { list-style: decimal; }
.au-help-list  { list-style: disc; }

/* Rzeczy, których pominięcie kosztuje — pieniądze albo publiczną wpadkę.
   Wyróżnione, ale bez krzyku: to nie jest błąd, tylko coś, co trzeba wiedzieć. */
.au-help-rule {
  margin: 0 0 16px; padding: 13px 15px;
  border-left: 3px solid var(--primary, #3768ea);
  border-radius: 0 8px 8px 0;
  background: rgba(66, 133, 244, .07);
  font-size: 13px; line-height: 1.6; color: var(--text, #1a202c);
}
.au-help-rule-warn {
  border-left-color: #d97706;
  background: rgba(217, 119, 6, .08);
}
.au-help-tip {
  margin: 18px 0 0; padding: 13px 15px; border-radius: 8px;
  background: var(--surface-sunken, #f8fafc);
  border: 1px solid var(--border-soft, #e2e8f0);
  font-size: 13px; line-height: 1.6; color: var(--muted, #718096);
}
.au-help-tip strong { color: var(--text, #1a202c); }

.au-help-faq { margin: 0; }
.au-help-faq dt {
  font-size: 13px; font-weight: 600; color: var(--text, #1a202c);
  margin-top: 14px; margin-bottom: 4px;
}
.au-help-faq dt:first-child { margin-top: 0; }
.au-help-faq dd {
  margin: 0; padding-left: 14px;
  border-left: 2px solid var(--border-soft, #e2e8f0);
  font-size: 13px; line-height: 1.6; color: var(--muted, #718096);
}

@media (max-width: 900px) {
  /* Na telefonie modale wjeżdżają od dołu (sekcja mobilna wyżej), więc
     ograniczenie wysokości oddajemy jej regułom — inaczej arkusz byłby
     przycięty w połowie ekranu. */
  .modal.au-help { max-height: none; }
  .au-help-tabs { padding: 0 20px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   EDYCJA PROPOZYCJI AI W MIEJSCU (klik w niebieskie pole na karcie opinii)
   Sekcja na KOŃCU pliku świadomie — nadpisuje `.ai-response-box` z bloku
   motywu ciemnego (linia ~4895), który wygrywa z regułą bazową kolejnością,
   nie specyficznością (ta sama lekcja co [v1.56]/[v1.60]/[v1.61]).
   ═══════════════════════════════════════════════════════════════════════════ */

.ai-response-box.ai-editable {
  cursor: text;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.ai-response-box.ai-editable:hover {
  border-color: var(--primary);
  box-shadow: 0 0 0 3px rgba(55, 104, 234, .10);
}

.ai-edit-area {
  width: 100%;
  box-sizing: border-box;
  margin-top: 4px;
  padding: 8px 10px;
  font: inherit;
  line-height: 1.6;
  color: var(--text, #1f2937);
  background: var(--surface, #fff);
  border: 1px solid var(--primary);
  border-radius: 6px;
  resize: vertical;
}
.ai-edit-area:focus { outline: none; box-shadow: 0 0 0 3px rgba(55, 104, 234, .12); }

.ai-edit-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 8px;
}
.ai-edit-count { font-size: 11px; color: var(--muted, #6b7280); margin-left: auto; }

/* Jakość automatyzacji ([v2.06]) w motywie ciemnym — reszta strony Automatyzacja
   celowo nie ma osobnych reguł dark (kolory statusu jak .au-dot działają
   identycznie w obu motywach), ale te trzy tła to szersze, jasne washe koloru
   na całej karcie, nie mały punkt — bez podbicia opacity ginęłyby na ciemnym tle. */
html.theme-dark .au-quality-stat.ai-outcome-full      { background: rgba(22,163,74,.14);  border-color: rgba(22,163,74,.3); }
html.theme-dark .au-quality-stat.ai-outcome-full      .au-quality-pct { color: #86efac; }
html.theme-dark .au-quality-stat.ai-outcome-assisted  { background: rgba(139,92,246,.16); border-color: rgba(139,92,246,.32); }
html.theme-dark .au-quality-stat.ai-outcome-assisted  .au-quality-pct { color: #c4b5fd; }
html.theme-dark .au-quality-stat.ai-outcome-escalated { background: rgba(245,158,11,.16); border-color: rgba(245,158,11,.32); }
html.theme-dark .au-quality-stat.ai-outcome-escalated .au-quality-pct { color: #fcd34d; }

/* Sekcja „.edit-needs-reply-box" USUNIĘTA 2026-08-09 razem ze skrzynką, którą
   stylowała (patrz komentarz w public/reviews.html). Dotarcie do tych opinii
   przejęła opcja filtra „Wymagają ponownej reakcji" z licznikiem — zwykły
   <option>, więc nie potrzebuje własnych stylów. */

/* ═══════════════════════════════════════════════════════════════════════════
   PASEK POSTĘPU PRZEBIEGU AI (2026-08-09)
   Przebieg trwa minutami (tempo narzuca limit zapytań), więc milczący przycisk
   był realnym problemem — użytkownik nie wiedział, czy coś się dzieje ani ile
   go to kosztuje. Wypełnienie animujemy szerokością, bo to jedyny sensowny
   sposób pokazania postępu determinowanego liczbą opinii; ruch jest wolny
   (jedna opinia co ~7 s), więc transition nie obciąża kompozytora.
   ═══════════════════════════════════════════════════════════════════════════ */
.au-progress { display: flex; flex-direction: column; gap: 8px; }
.au-progress-head,
.au-progress-foot {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  font-size: 13px;
}
.au-progress-foot { font-size: 12px; color: var(--muted); }
.au-progress-track {
  height: 6px; border-radius: 999px; overflow: hidden;
  background: rgba(127, 127, 127, .18);
}
.au-progress-fill {
  height: 100%; border-radius: 999px;
  background: var(--primary, #3768ea);
  transition: width .4s ease;
}
@media (prefers-reduced-motion: reduce) { .au-progress-fill { transition: none; } }

/* Dopisek „(edytowana)" przy dacie w nagłówku karty opinii — data jest wtedy
   datą ZMIANY, nie pierwszej publikacji (tak samo szereguje je Google Maps).
   Ma być czytelnym przypisem, nie drugim badge: bez tła, w kolorze wyciszonym. */
.rev-date-note { color: var(--muted); font-size: 11px; }

/* ═══════════════════════════════════════════════════════════════════
   EDYCJA PROFILU → GODZINY SPECJALNE: karta synchronizacji z godzinami
   otwarcia (2026-08-10). Świadomie na KOŃCU pliku — patrz ostrzeżenie przy
   sekcji mobilnej: reguły dopisane niżej wygrywają kolejnością, nie
   specyficznością, więc przeniesienie tego bloku wyżej może je wyłączyć.
   ═══════════════════════════════════════════════════════════════════ */
.pe-sync-card {
  border: 1px solid var(--border, #e2e8f0);
  border-radius: var(--radius-card, 20px);
  background: var(--surface-sunken, rgba(0,0,0,.02));
  padding: 16px 18px;
  margin-bottom: 20px;
}
.pe-sync-head { display: flex; align-items: center; gap: 10px; cursor: pointer; }
.pe-sync-head input[type="checkbox"] { width: 16px; height: 16px; flex-shrink: 0; }
.pe-sync-title { font-weight: 600; font-size: 14px; }
.pe-sync-desc  { font-size: 13px; color: var(--muted-strong); line-height: 1.55; margin: 8px 0 0 26px; }
.pe-sync-row   { display: flex; align-items: center; gap: 10px; margin: 12px 0 0 26px; }
.pe-sync-row input[type="time"] { max-width: 120px; }
/* Tabela sterowana automatem — czytelnie „tylko do odczytu", bez chowania danych. */
.pe-more-type.pe-synced .pe-hours-table { opacity: .6; pointer-events: none; }
.pe-more-type.pe-synced .pe-bulk-bar    { display: none; }
.pe-synced-note {
  font-size: 12.5px; color: var(--muted-strong); margin-top: 10px;
  display: flex; align-items: center; gap: 6px;
}

/* ─── WERSJE JĘZYKOWE OPINII ────────────────────────────────────────────────
   Google skleja oryginał i własne tłumaczenie w jedno pole, w kolejności
   zależnej od tego, kiedy opinia była synchronizowana. `review-text.js` stawia
   polską wersję na górze; te reguły odróżniają ją wizualnie od oryginału, żeby
   przy skanowaniu listy wzrokiem nie dało się ich pomylić (zgłoszenie
   użytkownika 2026-08-10: „dzięki temu jesteśmy w stanie efektywnie pracować").
   Sekcja celowo NA KOŃCU pliku — patrz ostrzeżenie o kolejności w [v1.56]. */
.rv-lang-tag {
  display: block;
  font-size: 10.5px; font-weight: 600; letter-spacing: .02em;
  text-transform: uppercase; color: var(--muted, #a0aec0);
  margin-bottom: 2px;
}
.rv-lang-main { display: block; }
/* Oryginał: przygaszony i odsunięty cienką linią — nadal w pełni czytelny
   (bywa jedynym miejscem, gdzie widać nazwę dania w oryginale), ale wyraźnie
   drugoplanowy wobec wersji polskiej. */
.rv-lang-orig {
  display: block; margin-top: 8px; padding-top: 6px;
  border-top: 1px dashed var(--border-soft, rgba(0,0,0,.08));
  color: var(--muted, #a0aec0); font-size: .93em;
}
.rv-lang-orig .rv-lang-tag { margin-bottom: 1px; }

/* ═══════════════════════════════════════════════════════════════════════════
   UŻYCIE UI (telemetria) — strona /telemetria.html
   Sekcja NA KOŃCU pliku (kolejność, nie specyficzność — patrz [v1.56]/[v1.60]).
   Nakładka heatmapy (?heatmap=1) ma style inline w telemetry.js — jest
   wstrzykiwana dynamicznie i ma być samowystarczalna na KAŻDEJ stronie.
   ═══════════════════════════════════════════════════════════════════════════ */

.tel-elem-row {
  display: grid;
  grid-template-columns: minmax(180px, 1.2fr) 2fr 52px;
  gap: 12px;
  align-items: center;
  padding: 7px 0;
  border-bottom: 1px solid var(--border-soft, rgba(0,0,0,.06));
}
.tel-elem-row:last-child { border-bottom: none; }
.tel-elem-name { font-size: 13px; min-width: 0; }
.tel-elem-name strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tel-elem-sel {
  display: block;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11px;
  color: var(--muted, #718096);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tel-elem-bar {
  height: 10px;
  border-radius: 5px;
  background: var(--surface-sunken, rgba(0,0,0,.05));
  overflow: hidden;
}
.tel-elem-bar span {
  display: block;
  height: 100%;
  border-radius: 5px;
  background: linear-gradient(90deg, #3768ea, #dc2626);
}
.tel-elem-count { font-size: 13px; font-weight: 600; text-align: right; }

.tel-path-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  padding: 6px 0;
  border-bottom: 1px solid var(--border-soft, rgba(0,0,0,.06));
}
.tel-path-row:last-child { border-bottom: none; }
.tel-path-arrow { color: var(--accent-text, #2f5ad6); font-weight: 700; }
.tel-path-count { margin-left: auto; font-weight: 600; color: var(--muted, #718096); }

/* Telefon: siatka rankingu elementów zwija się do dwóch wierszy */
@media (max-width: 900px) {
  .tel-elem-row { grid-template-columns: 1fr 60px; }
  .tel-elem-bar { grid-column: 1 / -1; }
}

/* Blok „Uzupełnij motywy" w karcie „Uruchom teraz" (Automatyzacja, [v2.31]).
   Oddzielony linią od przycisku propozycji, bo to OSOBNY przebieg na tym samym
   zakresie dat — bez separatora czytało się jak wariant przycisku wyżej. */
.au-themes-block {
  margin-top: 18px; padding-top: 16px;
  border-top: 1px solid var(--border-soft, rgba(127,127,127,.18));
  display: flex; flex-direction: column; gap: 10px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   [v2.33] SPRAWY W TOKU NA KARCIE OPINII — flaga, zgłoszenie do Google, BOK

   Trzy niezależne stany, które NIE mieszczą się w `response_status` (opinia
   może być jednocześnie odpowiedziana, oflagowana, zgłoszona i odesłana na
   BOK). Wszystkie trzy mają być widoczne z odległości ekranu, bo to znaczniki
   „wróć do tego", a nie ozdoby. Sekcja na końcu pliku — patrz ostrzeżenie
   o kolejności z [v1.56]/[v1.60]/[v1.61].
   ═══════════════════════════════════════════════════════════════════════════ */

/* Pasek przy lewej krawędzi karty. Osobne kolory: flaga = uwaga człowieka,
   zgłoszenie = sprawa u Google. Gdy zachodzą oba, wygrywa flaga (reguła niżej
   w pliku) — to ona oznacza „mam się tym zająć". */
.review-card.flagged-review  { border-left: 4px solid #dc2626; }
.review-card.reported-review { border-left: 4px solid #7c3aed; }
.review-card.reported-review.flagged-review { border-left-color: #dc2626; }

/* Odznaka „zgłoszona do Google". Bywa linkiem (gdy podano adres zgłoszenia) —
   oba warianty muszą wyglądać identycznie, stąd wspólny selektor i jawne
   zdjęcie podkreślenia z wariantu <a>. */
.reported-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700;
  padding: 3px 9px; border-radius: 999px;
  background: #ede9fe; color: #6d28d9; border: 1px solid #ddd6fe;
  text-decoration: none;
}
a.reported-badge:hover { background: #ddd6fe; text-decoration: none; }

/* Odznaka „odpowiedź kieruje na BOK" — bursztyn, bo to zobowiązanie z
   terminem (mail czeka na obsługę), nie neutralna informacja. */
.bok-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700;
  padding: 3px 9px; border-radius: 999px;
  background: #fef3c7; color: #92400e; border: 1px solid #fde68a;
}

/* [alfa 0.262] Odznaka „podejrzenie naruszenia regulaminu Google". Czerwień —
   jedyna wolna barwa w tym rzędzie (fiolet zajęty przez zgłoszenie, bursztyn
   przez BOK i edycję) i jednocześnie właściwa: to znacznik „coś tu przegina
   pałę". Jest <button>, bo klik otwiera modal zgłoszenia — stąd jawny reset
   domyślnych stylów przycisku, inaczej przeglądarka narzuciłaby własne tło,
   obramowanie i krój, rozjeżdżając rząd odznak.
   Kontrast policzony, nie dobrany na oko ([v2.34]): #b91c1c na #fee2e2 = 5,30:1
   (motyw jasny), #fca5a5 na tle karty po zmieszaniu z rgba(220,38,38,.18)
   = 7,97:1 (ciemny) — oba powyżej progu 4,5:1 dla tekstu 11 px. */
.policy-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700; font-family: inherit; line-height: 1.4;
  padding: 3px 9px; border-radius: 999px;
  background: #fee2e2; color: #b91c1c; border: 1px solid #fecaca;
  cursor: pointer;
}
.policy-badge:hover { background: #fecaca; }

/* Przycisk „Celowo pomiń" — świadomie stonowany, nie czerwony: to normalna
   decyzja robocza, nie operacja destrukcyjna. Odróżnia go sama etykieta
   i wymagane potwierdzenie. */
.btn.btn-skip-deliberate { border-style: dashed; }

.session-bok-hint {
  font-size: 12px; color: var(--muted, #6b7280);
  margin: -4px 0 10px;
}
.report-modal-hint {
  font-size: 12px; color: var(--muted, #6b7280);
  background: var(--surface-sunken, #f8fafc);
  border-radius: 8px; padding: 8px 10px; margin-bottom: 12px;
}

/* Motyw CIEMNY — wszystkie odznaki mają wpisane na sztywno jasne tła (paleta
   semantyczna, nie tokeny), więc bez tych nadpisań byłyby nieczytelne. */
html.theme-dark .flag-btn.flagged  { background: rgba(220,38,38,.18);  color: #fca5a5; border-color: rgba(220,38,38,.45); }
html.theme-dark .flag-btn.flagged:hover { background: rgba(220,38,38,.28); }
html.theme-dark .reported-badge    { background: rgba(124,58,237,.18); color: #c4b5fd; border-color: rgba(124,58,237,.45); }
html.theme-dark a.reported-badge:hover { background: rgba(124,58,237,.28); }
html.theme-dark .bok-badge         { background: rgba(217,119,6,.18);  color: #fcd34d; border-color: rgba(217,119,6,.45); }

/* Odznaka „odpowiedz czeka w kolejce na wyslanie do Google. Blekit — neutralny,
   informacyjny; swiadomie NIE bursztyn (zajety przez BOK i edycje, oba znacza
   „wymaga uwagi czlowieka”) i NIE czerwien (zajeta przez podejrzenie naruszenia
   regulaminu). Tu nic nie jest nie tak — tresc po prostu jeszcze leci. */
.queued-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11px; font-weight: 700;
  padding: 3px 9px; border-radius: 999px;
  background: #dbeafe; color: #1e40af; border: 1px solid #bfdbfe;
}
html.theme-dark .queued-badge      { background: rgba(59,130,246,.18); color: #93c5fd; border-color: rgba(59,130,246,.45); }
html.theme-dark .policy-badge      { background: rgba(220,38,38,.18);  color: #fca5a5; border-color: rgba(220,38,38,.45); }
html.theme-dark .policy-badge:hover { background: rgba(220,38,38,.28); }

/* == [2026-08-20] Poprawka wyslanej odpowiedzi + boks „Ostatnia odpowiedz" ==
   Sekcja NA KONCU pliku swiadomie: czesc regul wygrywa kolejnoscia, nie
   specyficznoscia (ta sama lekcja co przy sekcji mobilnej i motywach). */
.reply-edit-warn {
  margin: 8px 0 4px; padding: 8px 10px; border-radius: 8px; font-size: 12px;
  background: rgba(217,119,6,.10); border: 1px solid rgba(217,119,6,.35); color: #92400e;
}
html.theme-dark .reply-edit-warn { background: rgba(217,119,6,.18); border-color: rgba(217,119,6,.45); color: #fcd34d; }

.last-replied-box { margin-bottom: 14px; }
.last-replied-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-bottom: 6px; font-size: 12px; font-weight: 600; letter-spacing: .2px;
  color: var(--muted, #718096);
}




/* ═══════════════════════════════════════════════════════════════
   EDYCJA PROFILU → GODZINY  (prefiksy .ph- i .mh-)

   [alfa 0.302] Pasek doby, oś, legenda i warstwy-szyny USUNIĘTE.
   Poprzedni ekran robił z ustawienia godziny precyzyjne zadanie
   myszą (chwyt krawędzi, detenty co 15 min) i chował dokładne
   wartości pod chevronem — dla czynności, która jest wpisaniem
   dwóch liczb. Teraz wiersz dnia JEST formularzem: stan i obie
   godziny widać bez rozwijania czegokolwiek.

   Miejsce paska zajmuje SZYLD (.ph-sign): to samo pytanie („jak
   ten dzień leży"), ale zadane w języku gościa, nie analityka —
   kartka na drzwiach, którą Google i tak wyświetli. Zero interakcji,
   zero uczenia się gestu. Dni o identycznych godzinach są sklejane
   („pon.–pt."), a kropkowany łącznik między dniem a godziną to
   rejestr drukowanej karty godzin, nie ozdoba.

   KONTRAKT DOM (nie zmieniaj nazw — stoją na nim derivedSpecialPeriods,
   applyBulkHours, collectHoursFromTable, collectSpecialHours, collectMoreHours):
     #hoursTableMain > .pe-hours-row[data-day] > .pe-closed-cb/.pe-open/.pe-close
                                               > .pe-open2/.pe-close2 (przerwa)
     #holidayRows    > .pe-hol-row[data-date]  > .pe-hol-cb/.pe-hol-open/.pe-hol-close
     #moreHoursBox   > .mh-type[data-type-id]  > .mh-row[data-day] > .mh-on/.mh-open/.mh-close
   ═══════════════════════════════════════════════════════════════ */

.ph-card { margin-bottom: 16px; }
/* .card-title jest w bazie BLOKIEM — bez tego odznaka („N dni bez potwierdzenia")
   i chevron karty godzin dodatkowych nie trafialyby na prawa strone naglowka
   (margin-left:auto dziala tylko w kontenerze flex). */
.ph-card > .card-title { display: flex; align-items: center; gap: 8px; }
.ph-card > .card-title > svg { flex-shrink: 0; }
.ph-lede {
  font-size: 13px; color: var(--muted-strong);
  margin: -4px 0 14px; line-height: 1.55; max-width: 68ch;
}
.ph-note { font-size: 12px; font-weight: 500; color: var(--muted-strong); }
.ph-hint { font-size: 11.5px; color: var(--muted-strong); }
.ph-empty { font-size: 13px; color: var(--muted-strong); padding: 14px 0; margin: 0; }

/* Odznaka „N dni bez potwierdzenia" — to jest stan, za który Google karze
   ostrzeżeniem przy wizytówce, więc ma być widoczny w nagłówku karty,
   a nie dopiero po przejrzeniu pustych pól. */
.ph-badge {
  font-size: 11px; font-weight: 700; letter-spacing: .01em;
  color: #92400e; background: #fef3c7;
  padding: 3px 9px; border-radius: 999px; margin-left: auto;
}
.ph-badge.is-ok { color: #10632f; background: rgba(16,99,47,.10); }
html.theme-dark .ph-badge { color: #fcd34d; background: #4a3410; }
html.theme-dark .ph-badge.is-ok { color: #7ee2a8; background: rgba(126,226,168,.12); }

/* ── Rząd zbiorczy ───────────────────────────────────────────── */
/* Zastępuje dawne „zaznacz dni checkboxami → wpisz godziny → Zastosuj"
   schowane w rozwijanej szufladzie. Godziny wpisujesz raz, klikasz grupę dni. */
.ph-bulk {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding: 10px 12px; margin-bottom: 14px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
}
.ph-bulk-lbl { font-size: 12px; font-weight: 600; color: var(--muted-strong); }
.ph-apply {
  font-size: 12.5px; font-weight: 600; padding: 6px 11px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); color: var(--text); cursor: pointer;
  transition: border-color .15s, color .15s;
}
.ph-apply:hover { border-color: var(--primary); color: var(--primary); }
.ph-apply:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.ph-apply.is-quiet { color: var(--muted-strong); border-style: dashed; }
.ph-apply:disabled { opacity: .45; cursor: not-allowed; }
.ph-apply:disabled:hover { border-color: var(--border); color: var(--muted-strong); }

/* ── Pole godziny ────────────────────────────────────────────── */
/* Selektor typu + klasa (0,2,1), żeby wygrać z globalnym input[type="time"]
   niezależnie od kolejności w pliku. Cyfry monospace i tabelaryczne — kolumny
   godzin w siedmiu wierszach mają się zgadzać co do piksela. */
input[type="time"].ph-time {
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 13px; padding: 7px 9px; width: 104px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--surface); color: var(--text);
}
input[type="time"].ph-time:disabled { opacity: .5; cursor: not-allowed; }
.ph-dash, .ph-comma { color: var(--muted-strong); font-size: 13px; }

/* ── Tydzień i wyjątki: wspólny wiersz ───────────────────────── */
.ph-week, .ph-hol { border-top: 1px solid var(--border); }
.ph-week .ph-row, .ph-hol .ph-row {
  display: grid; align-items: center; gap: 12px;
  padding: 9px 0; border-bottom: 1px solid var(--border);
}
.ph-week .ph-row { grid-template-columns: 118px auto minmax(0, 1fr) auto; }
.ph-hol  .ph-row { grid-template-columns: 54px minmax(0, 1fr) auto auto 28px; }
.ph-week .ph-row:last-child, .ph-hol .ph-row:last-child { border-bottom: none; }

.ph-day { font-size: 13.5px; font-weight: 600; color: var(--text); }
.ph-row.ph-closed .ph-day { color: var(--muted-strong); font-weight: 500; }

/* ── Przełącznik otwarte / zamknięte ─────────────────────────── */
/* Segment zamiast checkboxa „Zamknięte" — koniec podwójnej negacji
   („odznacz, żeby było otwarte"). Stan trzyma UKRYTY checkbox .pe-closed-cb,
   to on jest jedynym źródłem prawdy dla zapisu; przyciski go tylko ustawiają. */
.ph-state {
  display: inline-flex; gap: 2px; padding: 2px;
  background: var(--bg); border: 1px solid var(--border); border-radius: 9px;
}
.ph-state-btn {
  font-size: 12px; font-weight: 600; white-space: nowrap;
  padding: 5px 11px; border: 0; border-radius: 7px;
  background: transparent; color: var(--muted-strong); cursor: pointer;
  transition: background .16s, color .16s;
}
.ph-state-btn:hover { color: var(--text); }
.ph-state-btn:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.ph-state-btn[data-open="1"][aria-pressed="true"] {
  background-color: var(--primary);
  background-image: linear-gradient(rgba(0,0,0,.14), rgba(0,0,0,.14));
  color: #fff;
}
.ph-state-btn[data-open="0"][aria-pressed="true"] { background: var(--text); color: var(--bg); }
.ph-state-btn:disabled { cursor: not-allowed; opacity: .55; }

/* ── Godziny w wierszu ───────────────────────────────────────── */
.ph-times { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.ph-row.ph-closed .ph-times { opacity: .45; }
.ph-brk { display: inline-flex; align-items: center; gap: 6px; }
.ph-brk-add {
  font-size: 12px; font-weight: 600; color: var(--muted-strong);
  background: transparent; border: 1px dashed var(--border);
  border-radius: 8px; padding: 5px 9px; cursor: pointer;
  transition: color .15s, border-color .15s;
}
.ph-brk-add:hover { color: var(--primary); border-color: var(--primary); }
.ph-brk-add:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; }
.ph-brk-x, .ph-clear {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0;
  border: 0; border-radius: 7px; background: transparent;
  color: var(--muted-strong); cursor: pointer; transition: background .15s, color .15s;
}
.ph-brk-x:hover, .ph-clear:hover { background: var(--bg); color: var(--text); }
.ph-brk-x:focus-visible, .ph-clear:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }

/* Okresy, których edytor nie pokazuje (Google dopuszcza więcej niż dwa na dzień) —
   są zapisywane bez zmian, ale wiersz musi o nich mówić, żeby liczby się zgadzały. */
.ph-extra {
  font-size: 11px; font-weight: 700; white-space: nowrap;
  color: #92400e; background: #fef3c7; padding: 2px 8px; border-radius: 999px;
}
html.theme-dark .ph-extra { background: #4a3410; color: #fcd34d; }

/* ── Szyld: co gość realnie zobaczy ──────────────────────────── */
.ph-split { display: grid; grid-template-columns: minmax(0, 1fr) 268px; gap: 22px; align-items: start; }
.ph-sign {
  position: sticky; top: 14px;
  padding: 15px 17px 17px;
  border: 1px solid var(--border); border-radius: 12px;
  background: var(--bg);
}
.ph-sign-head {
  font-size: 10.5px; font-weight: 700; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted-strong);
  margin-bottom: 11px; padding-bottom: 9px; border-bottom: 1px solid var(--border);
}
.ph-sign-body {
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; line-height: 1.95;
}
.ph-sign-row { display: flex; align-items: baseline; }
/* Kropkowany łącznik dzień → godzina: rejestr drukowanej karty godzin. */
.ph-sign-d {
  flex: 1; display: flex; align-items: baseline; gap: 8px;
  color: var(--muted-strong); white-space: nowrap; min-width: 0;
}
.ph-sign-d::after {
  content: ""; flex: 1; border-bottom: 1px dotted var(--border); transform: translateY(-3px);
}
.ph-sign-t { color: var(--text); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
.ph-sign-row.is-off .ph-sign-t { color: var(--muted-strong); font-weight: 500; }
.ph-sign-sep { height: 1px; background: var(--border); margin: 11px 0; }
.ph-sign-more { font-size: 11px; color: var(--muted-strong); margin-top: 7px; }

/* ── Wyjątki w kalendarzu ────────────────────────────────────── */
.ph-holdate {
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12.5px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums;
}
.ph-holname { display: flex; flex-direction: column; gap: 1px; min-width: 0; font-size: 13px; font-weight: 600; }
.ph-holname em { font-style: normal; font-size: 11.5px; font-weight: 500; color: var(--muted-strong); }
/* Dzień bez potwierdzenia — miękka bursztynowa poświata zamiast twardej ramki:
   ma zwracać uwagę na liście, nie krzyczeć przy każdym wierszu. */
.ph-hol .ph-row.ph-unset { background: linear-gradient(90deg, rgba(217,119,6,.09), transparent 45%); }
.ph-hol .ph-row.ph-unset .ph-holdate { color: #92400e; }
html.theme-dark .ph-hol .ph-row.ph-unset { background: linear-gradient(90deg, rgba(252,211,77,.10), transparent 45%); }
html.theme-dark .ph-hol .ph-row.ph-unset .ph-holdate { color: #fcd34d; }
.ph-hol .ph-row.ph-foreign .ph-holname { color: var(--muted-strong); }

/* ── Godziny dodatkowe (moreHours) ───────────────────────────── */
.ph-more > summary { cursor: pointer; list-style: none; user-select: none; }
.ph-more > summary::-webkit-details-marker { display: none; }
.ph-more > summary::after {
  content: ""; margin-left: auto; width: 7px; height: 7px;
  border-right: 2px solid var(--muted-strong); border-bottom: 2px solid var(--muted-strong);
  transform: rotate(-45deg); transition: transform .18s;
}
.ph-more[open] > summary::after { transform: rotate(45deg); }
.ph-more > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 6px; }
.ph-more-body { margin-top: 14px; }

.mh-type { padding: 15px 0; border-top: 1px solid var(--border); }
.mh-type:first-child { border-top: 0; padding-top: 2px; }
.mh-head { display: flex; align-items: center; gap: 10px; margin-bottom: 10px; }
.mh-name { font-size: 13.5px; font-weight: 700; color: var(--text); }
.mh-auto {
  font-size: 11px; font-weight: 700;
  color: #92400e; background: #fef3c7; padding: 2px 9px; border-radius: 999px;
}
html.theme-dark .mh-auto { background: #4a3410; color: #fcd34d; }
.mh-type.mh-locked { opacity: .78; }
.mh-bulk { margin-bottom: 10px; }
.mh-days { display: grid; grid-template-columns: repeat(auto-fill, minmax(238px, 1fr)); gap: 7px 20px; }
.mh-row { display: flex; align-items: center; gap: 7px; }
.mh-on-lbl { display: inline-flex; align-items: center; gap: 7px; cursor: pointer; min-width: 54px; }
.mh-on { accent-color: var(--primary); cursor: pointer; margin: 0; }
.mh-day { font-size: 12.5px; font-weight: 600; color: var(--muted-strong); }
.mh-type.mh-locked .mh-on-lbl { cursor: default; }

/* ── Szuflada narzędzi ───────────────────────────────────────── */
.ph-tools { margin-top: 16px; border-top: 1px solid var(--border); padding-top: 12px; }
.ph-tools > summary {
  display: flex; align-items: center; gap: 7px; cursor: pointer; list-style: none;
  font-size: 12.5px; font-weight: 600; color: var(--muted-strong);
}
.ph-tools > summary::-webkit-details-marker { display: none; }
.ph-tools > summary:hover { color: var(--text); }
.ph-tools > summary:focus-visible { outline: 2px solid var(--primary); outline-offset: 3px; border-radius: 6px; }
.ph-tools > summary svg { transition: transform .18s; }
.ph-tools[open] > summary svg { transform: rotate(90deg); }
.ph-tools-body { padding-top: 8px; }
/* Pasek importu to flex bez zawijania (definicja wyzej w pliku) — przy 375 px
   podpowiedz wychodzila poza karte. Zawijanie punktowo, w tej szufladzie. */
.ph-tools .pe-import-bar { flex-wrap: wrap; }
.ph-tools .ph-hint { min-width: 0; }

/* ── Atrybuty wizytówki ──────────────────────────────────────── */
/* Bez własnej palety i bez własnych kontrolek: wiersz atrybutu to ten sam
   segment co wiersz dnia w godzinach (.ph-state), tylko z trzecim stanem.
   Trzeci stan niesie informację, nie ozdobę — Google rozróżnia „lokal NIE ma
   toalety" od „nie wiadomo", a tylko pierwsze wyklucza wizytówkę z zapytania
   filtrowanego. Nowe są wyłącznie: szyld potwierdzeń, grupy i pasek filtra. */
.pa-toolbar { margin: 14px 0 2px; }
input.pa-search { max-width: 240px; font-size: 13px; padding: 6px 10px; }
/* Wciśnięty filtr — ta sama nakładka procentowa co segment godzin. Wpisany na
   sztywno ciemniejszy odcień nie przechodzi AA we wszystkich czterech
   paletach ([alfa 0.302]). */
.ph-apply.is-on {
  color: #fff; border-color: var(--primary); border-style: solid;
  background-color: var(--primary);
  background-image: linear-gradient(rgba(0,0,0,.14), rgba(0,0,0,.14));
}
.ph-apply.is-on:hover { color: #fff; }

/* Szyld: wyłącznie potwierdzenia, bo tylko one trafiają na publiczny profil. */
.pa-sign {
  border: 1px solid var(--border); background: var(--bg);
  border-radius: 12px; padding: 12px 14px; margin-bottom: 4px;
}
.pa-sign-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.pa-chip {
  font-size: 12px; font-weight: 600; color: var(--text);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 999px; padding: 4px 10px;
}
.pa-chip-more { color: var(--muted-strong); }

.pa-group { padding-top: 18px; }
/* Linki idą PRZED przełącznikami i mają odstęp od nich — to pola tekstowe,
   nie odpowiedzi Tak/Nie, i Google też trzyma je osobno (zakładka Kontakt). */
.pa-links { padding-top: 4px; padding-bottom: 6px; }
.pa-group-title {
  display: flex; align-items: center; gap: 10px;
  font-size: 12px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted-strong); padding-bottom: 7px; border-bottom: 1px solid var(--border);
}
.pa-group-n {
  margin-left: auto; font-size: 11.5px; font-weight: 600;
  letter-spacing: 0; text-transform: none; font-variant-numeric: tabular-nums;
}

.pa-row {
  display: grid; grid-template-columns: minmax(0, 1fr) auto;
  align-items: center; gap: 12px; padding: 8px 0;
  border-bottom: 1px solid var(--border);
}
.pa-group > .pa-row:last-child, .pa-multi > .pa-row:last-child { border-bottom: none; }
.pa-label { font-size: 13.5px; font-weight: 500; color: var(--text); min-width: 0; }
.pa-multi { padding-bottom: 2px; }
.pa-sub { font-size: 12.5px; font-weight: 700; color: var(--text); padding: 10px 0 2px; }
.pa-multi .pa-row { padding-left: 14px; }
input.pa-url { font-size: 13px; padding: 6px 10px; width: 340px; max-width: 100%; }
select.pa-enum { max-width: 240px; font-size: 13px; padding: 6px 10px; }

/* Trzeci stan segmentu. „Nie ustawiono" ma być czytelne, ale najciszsze
   z trzech — to stan wyjściowy, nie decyzja. */
.ph-state-btn.pa-unset[aria-pressed="true"] {
  background: var(--surface); color: var(--text);
  box-shadow: inset 0 0 0 1.5px var(--muted-strong), 0 1px 2px rgba(0, 0, 0, .07);
}

@media (max-width: 700px) {
  .pa-row { grid-template-columns: minmax(0, 1fr); }
  input.pa-url { width: 100%; }
  .pa-row .ph-state, .pa-row select, .pa-row input { justify-self: start; }
  input.pa-search { max-width: none; flex: 1; }
}
/* ── Pasek zapisu ────────────────────────────────────────────── */
/* Półprzezroczysta warstwa przyklejona do dołu, treść przewija się POD nią.
   Pojawia się dopiero, gdy realnie jest co zapisać, i mówi CO się zmieni —
   to jedyny moment przed publikacją na żywej wizytówce w Google. */
.hx-savebar {
  position: sticky; bottom: 0; z-index: 20;
  margin: 18px -4px 0; padding: 0 4px 4px;
}
.hx-savebar-in {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding: 12px 16px;
  background: var(--surface); backdrop-filter: blur(var(--blur, 18px));
  border: 1px solid var(--border); border-radius: 14px;
  box-shadow: var(--shadow-lg, 0 10px 30px rgba(0,0,0,.10));
}
.hx-savebar.is-in .hx-savebar-in { animation: hxSaveIn .22s ease both; }
@keyframes hxSaveIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.hx-save-what { display: flex; align-items: center; gap: 10px; min-width: 0; flex: 1; }
.hx-save-count {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 22px; height: 22px; padding: 0 6px;
  font-size: 12px; font-weight: 700; color: #fff; background: var(--primary);
  border-radius: 999px;
}
.hx-save-list {
  font-size: 12.5px; color: var(--muted-strong);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
.hx-save-list b { font-weight: 600; color: var(--text); }

/* ── Dostępność: ruch, przezroczystość, kontrast ─────────────── */
@media (prefers-reduced-motion: reduce) {
  .ph-apply, .ph-state-btn, .ph-brk-add, .ph-brk-x, .ph-clear,
  .ph-more > summary::after, .ph-tools > summary svg { transition: none !important; }
  .hx-savebar.is-in .hx-savebar-in { animation: none; }
}
@media (prefers-reduced-transparency: reduce) {
  .hx-savebar-in { background: var(--surface); backdrop-filter: none; }
}
@media (prefers-contrast: more) {
  .hx-savebar-in { background: var(--surface); backdrop-filter: none; border-color: var(--text); }
  .ph-state { border-color: var(--muted-strong); }
}

/* ── Telefon ─────────────────────────────────────────────────── */
@media (max-width: 1100px) {
  .ph-split { grid-template-columns: 1fr; }
  .ph-sign { position: static; }
}
@media (max-width: 900px) {
  .ph-week .ph-row { grid-template-columns: minmax(0, 1fr) auto; row-gap: 9px; }
  .ph-week .ph-times, .ph-extra { grid-column: 1 / -1; }
  .ph-hol .ph-row { grid-template-columns: 54px minmax(0, 1fr) 26px; row-gap: 9px; }
  .ph-hol .ph-clear { grid-row: 1; grid-column: 3; }
  .ph-hol .ph-state, .ph-hol .ph-times { grid-column: 1 / -1; }
  .hx-savebar { margin-left: 0; margin-right: 0; }
  .hx-savebar-in { padding: 10px 12px; }
  .hx-save-list { display: none; }
}

/* ══ Siatka cieplna — wspólny komponent dwóch ekranów Ustawień ═════════════
   Używana DWA razy, z dwóch różnych powodów, i to jest sedno:
     • Szablony → macierz POKRYCIA (nazwa × forma grzecznościowa). Pusta
       komórka nie jest kosmetyką: brak wariantu dla danej formy sprawia,
       że resolveNegativeTemplate schodzi na formę bezosobową albo na szablon
       awaryjny — gość dostaje wtedy mniej trafną odpowiedź, a dotąd nie było
       tego widać nigdzie w interfejsie.
     • Motywy → heatmapa UŻYCIA (motyw × miesiąc). Pusty wiersz to motyw,
       którego model nie użył ani razu w oknie — kandydat do usunięcia.
   Jeden komponent zamiast dwóch, bo oba pytania mają ten sam kształt:
   etykieta wiersza plus ciąg liczb, w którym liczy się intensywność.

   Skala jest SEKWENCYJNA i jednobarwna (przezroczystość --primary), bo dane
   są ilościowe. Barwy semantyczne (bursztyn) są zarezerwowane WYŁĄCZNIE dla
   luki w pokryciu — to nie jest „mało", tylko „brak", czyli inna kategoria. */

.hgrid-wrap { overflow-x: auto; border: 1px solid var(--border); border-radius: 12px; background: var(--surface); }
.hgrid { border-collapse: separate; border-spacing: 0; width: 100%; font-size: 13px; }
.hgrid th, .hgrid td { padding: 0; }

/* Nagłówek kolumn — etykiety miesięcy/form. */
.hgrid thead th {
  position: sticky; top: 0; z-index: 2;
  background: var(--surface-sunken, var(--surface));
  border-bottom: 1px solid var(--border);
  font-size: 10.5px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted-strong); white-space: nowrap; padding: 9px 8px; text-align: center;
}
.hgrid thead th.hgrid-rowhead { text-align: left; padding-left: 14px; }

/* Pierwsza kolumna przyklejona — przy 12 miesiącach tabela się przewija
   w poziomie, a bez nazwy motywu liczby nic nie znaczą. */
.hgrid-rowhead {
  position: sticky; left: 0; z-index: 1;
  background: var(--surface);
  border-right: 1px solid var(--border);
  text-align: left; padding: 7px 14px; white-space: nowrap;
  max-width: 260px; overflow: hidden; text-overflow: ellipsis;
}
.hgrid thead th.hgrid-rowhead { z-index: 3; background: var(--surface-sunken, var(--surface)); }
.hgrid tbody tr:hover .hgrid-rowhead { background: var(--surface-hover, var(--surface-sunken, var(--surface))); }

/* Podział na sekcje (sentyment / lista motywów) — nagłówek wewnątrz tabeli. */
.hgrid-group td {
  padding: 12px 14px 5px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted-strong);
  position: sticky; left: 0;
}

/* Komórka — poziom intensywności w data-lvl, żeby skala żyła w JEDNYM
   miejscu i nie dało się jej rozjechać między dwoma ekranami. */
.hgrid-c {
  text-align: center; font-variant-numeric: tabular-nums;
  font-size: 12px; color: var(--text);
  border-bottom: 1px solid var(--border-soft, var(--border));
  padding: 7px 8px; min-width: 44px;
}
.hgrid-c[data-lvl="0"] { color: var(--muted); }
.hgrid-c[data-lvl="1"] { background: rgba(59,110,240,.12); background: color-mix(in srgb, var(--primary) 12%, transparent); }
.hgrid-c[data-lvl="2"] { background: rgba(59,110,240,.22); background: color-mix(in srgb, var(--primary) 22%, transparent); }
.hgrid-c[data-lvl="3"] { background: rgba(59,110,240,.26); background: color-mix(in srgb, var(--primary) 26%, transparent); font-weight: 600; }
.hgrid-c[data-lvl="4"] { background: rgba(59,110,240,.36); background: color-mix(in srgb, var(--primary) 36%, transparent); font-weight: 700; }

/* Luka w pokryciu — kategoria, nie natężenie. Bursztyn projektu ([alfa 0.296]). */
.hgrid-c.is-gap {
  background: color-mix(in srgb, #92400e 14%, transparent);
  color: #92400e; font-weight: 700;
}
html.theme-dark .hgrid-c.is-gap { background: color-mix(in srgb, #E2AC55 16%, transparent); color: #E2AC55; }

/* Kolumna sumy — oddzielona kreską, bo to inna wielkość niż komórki miesięcy. */
.hgrid-c.hgrid-total {
  border-left: 1px solid var(--border); font-weight: 600; background: none;
  color: var(--text); min-width: 52px;
}
.hgrid tbody tr.is-dead .hgrid-rowhead { color: var(--muted); }
.hgrid-dead-tag {
  display: inline-block; margin-left: 7px; font-size: 9.5px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: #92400e;
  background: color-mix(in srgb, #92400e 12%, transparent);
  padding: 1px 5px; border-radius: 4px; vertical-align: 1px;
}
html.theme-dark .hgrid-dead-tag { color: #E2AC55; background: color-mix(in srgb, #E2AC55 14%, transparent); }

/* Klikalna komórka macierzy szablonów — prowadzi do edycji tej grupy. */
.hgrid-c.is-link { cursor: pointer; }
.hgrid-c.is-link:hover { outline: 2px solid var(--primary); outline-offset: -2px; }
.hgrid-c.is-link:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }

/* Legenda skali. */
.hgrid-legend {
  display: flex; align-items: center; flex-wrap: wrap; gap: 8px 14px;
  margin-top: 10px; font-size: 11.5px; color: var(--muted-strong);
}
.hgrid-scale { display: flex; align-items: center; gap: 4px; }
.hgrid-sw { width: 18px; height: 12px; border-radius: 3px; border: 1px solid var(--border); }
.hgrid-sw[data-lvl="0"] { background: var(--surface); }
.hgrid-sw[data-lvl="1"] { background: color-mix(in srgb, var(--primary) 12%, transparent); }
.hgrid-sw[data-lvl="2"] { background: color-mix(in srgb, var(--primary) 22%, transparent); }
.hgrid-sw[data-lvl="3"] { background: color-mix(in srgb, var(--primary) 26%, transparent); }
.hgrid-sw[data-lvl="4"] { background: color-mix(in srgb, var(--primary) 36%, transparent); }
.hgrid-sw.is-gap { background: color-mix(in srgb, #92400e 14%, transparent); border-color: #92400e; }

/* Pasek podsumowania nad siatką — liczby, które trzeba znać PRZED czytaniem
   siatki (ile pozycji, ile martwych, ile luk). */
.hgrid-summary { display: flex; flex-wrap: wrap; gap: 8px 22px; margin-bottom: 12px; }
.hgrid-stat { display: flex; flex-direction: column; gap: 1px; }
.hgrid-stat b { font-size: 19px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -.02em; }
.hgrid-stat span { font-size: 11.5px; color: var(--muted-strong); }
.hgrid-stat.is-warn b { color: #92400e; }
html.theme-dark .hgrid-stat.is-warn b { color: #E2AC55; }

@media (max-width: 700px) {
  .hgrid-rowhead { max-width: 150px; }
  .hgrid-c { min-width: 38px; padding: 6px 5px; font-size: 11.5px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   [alfa 0.318] Pozycje lokalne — hasła z odznaką pozycji + zwijane ustawienia
   ═══════════════════════════════════════════════════════════════════════════ */
/* Wiersz hasła ma teraz dwie linie (fraza+odznaka / meta) — nadpisujemy flex
   z definicji bazowej wyżej (ta sama specyficzność, ten plik czytany dalej). */
.keyword-item { display: block; }
.keyword-row  { display: flex; align-items: center; gap: 8px; }
.keyword-meta { font-size: 11.5px; color: var(--muted-strong); margin-top: 3px; }
/* Odznaka: kolor pozycji niesie KROPKA, liczba zostaje w tokenie tekstu
   (tekst nigdy w kolorze serii — czytelność w obu motywach). */
.kw-pos {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;
  font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums;
  color: var(--text); line-height: 1.5; white-space: nowrap;
  padding: 1px 9px; border-radius: 999px;
  background: color-mix(in srgb, var(--kb, #94a3b8) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--kb, #94a3b8) 45%, transparent);
}
.kw-pos::before { content: ''; width: 7px; height: 7px; border-radius: 50%; background: var(--kb, #94a3b8); flex: none; }
.kw-pos-none { color: var(--muted-strong); font-weight: 500; background: transparent; border: 1px dashed var(--border); }
.kw-pos-none::before { display: none; }
.kw-trend { font-size: 10px; line-height: 1; flex: none; }
.kw-trend.up   { color: #15803d; }
.kw-trend.down { color: #b91c1c; }
html.theme-dark .kw-trend.up   { color: #4ade80; }
html.theme-dark .kw-trend.down { color: #f87171; }
.rank-settings-acc > summary { cursor: pointer; list-style: none; }
.rank-settings-acc > summary::-webkit-details-marker { display: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   [alfa 0.318] Wspólny wstęp zakładek (Zmiany zewnętrzne / Frazy wyszukiwania)
   ═══════════════════════════════════════════════════════════════════════════ */
.page-intro { font-size: 13.5px; color: var(--muted-strong); max-width: 760px; margin-bottom: 16px; }

/* ═══════════════════════════════════════════════════════════════════════════
   [alfa 0.318] Zmiany zewnętrzne (/zmiany.html) — rejestr „było → jest"
   ═══════════════════════════════════════════════════════════════════════════ */
.chg-day {
  display: flex; align-items: center; gap: 10px;
  margin: 22px 0 10px; font-size: 12px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; color: var(--muted-strong);
}
.chg-day::after { content: ''; flex: 1; height: 1px; background: var(--border); }
.chg-entry { padding: 14px 16px; margin-bottom: 10px; }
.chg-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.chg-field {
  display: inline-flex; align-items: center; gap: 6px; flex: none;
  font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px;
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  /* NIE var(--primary): #3b6ef0 na własnym 12% tincie daje 4,32:1 (zmierzone
     w Chromium z kompozycją alfa) — poniżej progu AA 4,5 dla tekstu 12 px. */
  color: #2b50c6;
}
html.theme-dark .chg-field { color: #9db9ff; }
.chg-locname { font-weight: 600; font-size: 14px; }
.chg-time { margin-left: auto; font-size: 12px; color: var(--muted-strong); font-variant-numeric: tabular-nums; }
/* Wartość skalarna: było (przekreślone, czerwona rama) → jest (zielona rama).
   Kierunek niesie strzałka i etykieta kolumn, nie sam kolor. */
.chg-scalar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.chg-old, .chg-new {
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace; font-size: 13px;
  padding: 4px 10px; border-radius: 8px; border: 1px solid transparent;
  overflow-wrap: anywhere; min-width: 0;
}
.chg-old {
  background: color-mix(in srgb, #b91c1c 7%, transparent);
  border-color: color-mix(in srgb, #b91c1c 30%, transparent);
  color: var(--muted-strong);
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, #b91c1c 55%, transparent);
}
.chg-new {
  background: color-mix(in srgb, #15803d 8%, transparent);
  border-color: color-mix(in srgb, #15803d 32%, transparent);
  color: var(--text); font-weight: 500;
}
.chg-none { font-style: italic; text-decoration: none; }
.chg-arrow { color: var(--muted-strong); flex: none; }
/* Pola listowe (kategorie, godziny dodatkowe): różnica jako chipy ± */
.chg-chips { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.chg-chip-add, .chg-chip-del { font-size: 12.5px; padding: 3px 10px; border-radius: 999px; border: 1px solid; }
.chg-chip-add {
  background: color-mix(in srgb, #15803d 10%, transparent);
  border-color: color-mix(in srgb, #15803d 35%, transparent);
  color: #116233; font-weight: 600;
}
.chg-chip-del {
  background: color-mix(in srgb, #b91c1c 7%, transparent);
  border-color: color-mix(in srgb, #b91c1c 32%, transparent);
  color: #9b1c1c; text-decoration: line-through;
}
html.theme-dark .chg-chip-add { color: #4ade80; }
html.theme-dark .chg-chip-del { color: #f87171; }
.chg-chip-same { font-size: 12.5px; color: var(--muted-strong); }
/* Opis / godziny: dwie kolumny „Było / Jest" */
.chg-cols { display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); gap: 10px; align-items: start; }
.chg-col-label {
  font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--muted-strong); margin-bottom: 4px;
}
.chg-txt { white-space: pre-wrap; }
.chg-txt.clamp { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; cursor: pointer; }
.chg-hours { font-size: 12.5px; line-height: 1.7; white-space: pre-line; text-decoration: none; }
@media (max-width: 700px) {
  .chg-cols { grid-template-columns: 1fr; }
  .chg-cols .chg-arrow { display: none; }
  .chg-time { margin-left: 0; width: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   [alfa 0.318] Frazy wyszukiwania (/frazy.html) — tabela zbiorcza + iskierki
   ═══════════════════════════════════════════════════════════════════════════ */
.fz-wrap { overflow-x: auto; }
.fz-table { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.fz-table th {
  text-align: left; font-size: 11.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .05em; color: var(--muted-strong);
  padding: 8px 10px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
.fz-table td { padding: 9px 10px; border-bottom: 1px solid var(--border); vertical-align: middle; }
.fz-table th.num, .fz-table td.num { text-align: right; font-variant-numeric: tabular-nums; }
.fz-row { cursor: pointer; }
.fz-row:hover > td { background: color-mix(in srgb, var(--primary) 5%, transparent); }
.fz-kw { font-weight: 500; overflow-wrap: anywhere; }
.fz-approx { color: var(--muted-strong); }
/* Iskierka 6 miesięcy: jedna barwa (skala = wysokość), bieżący miesiąc pełnym
   kolorem marki, wcześniejsze przygaszone — tekst wartości w tooltipie. */
.fz-spark { display: inline-flex; align-items: flex-end; gap: 2px; height: 22px; }
.fz-spark i { display: block; width: 7px; min-height: 2px; border-radius: 2px 2px 0 0; background: color-mix(in srgb, var(--primary) 38%, var(--surface)); }
.fz-spark i:last-child { background: var(--primary); }
.fz-delta {
  display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600;
  padding: 2px 8px; border-radius: 999px; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.fz-delta.up   { color: #116233; background: color-mix(in srgb, #15803d 10%, transparent); }
.fz-delta.down { color: #9b1c1c; background: color-mix(in srgb, #b91c1c 8%, transparent); }
.fz-delta.flat { color: var(--muted-strong); background: color-mix(in srgb, #94a3b8 14%, transparent); }
html.theme-dark .fz-delta.up   { color: #4ade80; }
html.theme-dark .fz-delta.down { color: #f87171; }
.fz-chip { font-size: 11.5px; font-weight: 600; padding: 3px 9px; border-radius: 999px; white-space: nowrap; }
.fz-chip-on {
  color: #116233; background: color-mix(in srgb, #15803d 11%, transparent);
  border: 1px solid color-mix(in srgb, #15803d 30%, transparent);
}
html.theme-dark .fz-chip-on { color: #4ade80; }
.fz-chip-off { color: var(--muted-strong); background: transparent; border: 1px dashed var(--border); }
.fz-chev { display: inline-block; transition: transform .18s ease; color: var(--muted-strong); }
.fz-row.open .fz-chev { transform: rotate(90deg); }
.fz-detail > td { background: color-mix(in srgb, var(--primary) 4%, transparent); padding: 12px 16px 14px; }
.fz-loc-row { display: flex; align-items: center; gap: 10px; padding: 7px 0; border-bottom: 1px dashed var(--border); font-size: 13px; }
.fz-loc-row:last-child { border-bottom: none; }
.fz-loc-name { flex: 1; min-width: 0; overflow-wrap: anywhere; }
.fz-loc-val { font-variant-numeric: tabular-nums; font-weight: 600; }
.fz-more { font-size: 12.5px; color: var(--muted-strong); margin-top: 10px; }
.fz-filters-check { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text); cursor: pointer; user-select: none; }

/* ═══════════════════════════════════════════════════════════════════════════
   [alfa 0.319] Pozycje lokalne 2.0 — układ wg projektu Claude Design
   („Pozycje lokalne 2.0"): mapa + wynik + historia jako JEDEN przewijany
   widok, hasła jako chipy w pasku kontekstu, zero pod-zakładek.
   Stare klasy .rank-layout/.rank-left/.rank-map-col/.rank-viewtab*/.rank-stat*
   zostają w arkuszu jako martwe (świadomy dług — patrz dziennik).
   ═══════════════════════════════════════════════════════════════════════════ */

/* Pasek kontekstu: wizytówka + chipy haseł */
.rk2-bar { display: flex; align-items: center; gap: 14px; padding: 12px 16px; margin-bottom: 12px; }
.rk2-locbox { min-width: 250px; flex: none; }
.rk2-locbox .form-control { font-weight: 600; }
.rk2-sep { width: 1px; align-self: stretch; background: var(--border-soft); flex: none; }
.rk2-chips { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; flex: 1; }
.rk2-chip {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; user-select: none;
  background: var(--surface-solid); border: 1px solid var(--border-soft);
  border-radius: 999px; padding: 7px 13px; font-size: 13.5px; color: var(--text);
  transition: box-shadow .15s ease, border-color .15s ease;
}
.rk2-chip:hover { border-color: var(--primary); }
/* NIE var(--primary): biały tekst 13,5px na #3b6ef0 daje 4,49:1 — o włos pod
   progiem AA 4,5 (zmierzone w Chromium z kompozycją alfa). --primary-dark
   przechodzi z zapasem w obu motywach. */
.rk2-chip.active {
  background: var(--primary-dark); border-color: var(--primary-dark); color: #fff; font-weight: 600;
  box-shadow: 0 4px 14px rgba(59,110,240,.35);
}
.rk2-chip-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-family: 'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;
  font-size: 12px; font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Nakładka CIEMNA, nie biała: biała podnosiła jasność tła pod białą cyfrą
   i kontrast spadał do 3,1 (zmierzone). */
.rk2-badge-act { background: rgba(0,0,0,.2); border-radius: 999px; padding: 2px 9px; }
.rk2-chip-none { color: var(--muted-strong); font-weight: 500; }
.rk2-chip.active .rk2-chip-none { color: rgba(255,255,255,.85); }
.rk2-dot { width: 8px; height: 8px; border-radius: 50%; flex: none; display: inline-block; }
.rk2-chip-del { color: var(--muted); font-size: 14px; line-height: 1; padding: 0 2px; opacity: 0; transition: opacity .12s ease; }
.rk2-chip:hover .rk2-chip-del { opacity: 1; }
.rk2-chip.active .rk2-chip-del { color: rgba(255,255,255,.8); }
.rk2-chip-del:hover { color: var(--danger-dark); }
.rk2-chip.active .rk2-chip-del:hover { color: #fff; }
.rk2-chip-add { border-style: dashed; border-color: rgba(0,0,0,.18); color: var(--muted-strong); background: transparent; }
html.theme-dark .rk2-chip-add { border-color: rgba(255,255,255,.25); }
.rk2-addform { display: flex; align-items: center; gap: 8px; padding: 10px 14px; margin-bottom: 12px; }
/* `display: flex` NADPISUJE atrybut [hidden] (styl UA to zwykłe display:none) —
   bez tej reguły formularz byłby widoczny na stałe. Zmierzone testem. */
.rk2-addform[hidden] { display: none; }
.rk2-addform .form-control { max-width: 320px; }

/* Siatka: mapa + prawa szyna */
.rk2-grid { display: grid; grid-template-columns: minmax(0, 1fr) 332px; gap: 16px; align-items: stretch; }
.rk2-mapcard {
  position: relative; min-height: 566px; border-radius: var(--radius-card); overflow: hidden;
  border: 1px solid var(--border); box-shadow: var(--shadow); background: var(--surface);
}
.rk2-mapcard #map { position: absolute; inset: 0; height: 100%; min-height: 0; }
.rk2-ov { position: absolute; z-index: 1100; }
.rk2-ov-tl { top: 14px; left: 14px; }
.rk2-ov-tr { top: 14px; right: 14px; }
/* Kontrolki LEŻĄ NA MAPIE, nie na karcie — podkład bywa jasny niezależnie od
   motywu aplikacji (użytkownik wybiera go osobno), więc pigułki są ZAWSZE
   jasnym szkłem, jak kontrolki Leaflet i legenda. W motywie ciemnym tokeny
   dawały ciemny pasek na jasnych kafelkach — nieczytelne (zmierzone okiem
   na zrzucie, stąd stałe kolory zamiast var()). */
.rk2-ov .mode-toggle, .rk2-ov .basemap-toggle {
  background: rgba(255,255,255,.92); border: 1px solid rgba(255,255,255,.95);
  box-shadow: 0 2px 10px rgba(0,0,0,.16);
}
.rk2-ov .mode-btn, .rk2-ov .basemap-btn { color: #484e5e; background: transparent; }
.rk2-ov .mode-btn.active { color: #fff; background: #2f5ad6; }
.rk2-ov .basemap-btn.active { color: #1a1f2e; background: #fff; box-shadow: 0 1px 6px rgba(0,0,0,.14); }
.rk2-legend {
  position: absolute; z-index: 1100; bottom: 14px; left: 14px;
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap; max-width: calc(100% - 80px);
  background: rgba(255,255,255,.92); border-radius: 999px; padding: 7px 14px;
  box-shadow: 0 2px 10px rgba(0,0,0,.12); font-size: 11.5px; color: #1a1f2e;
}
/* Legenda leży NA mapie (jasny podkład), więc kolory są stałe, nie tokenowe —
   w podkładzie ciemnym pigułka zostaje jasna, jak kontrolki Leaflet. */
.rk2-legend .rank-legend-item { display: inline-flex; align-items: center; gap: 5px; }
.rk2-legend .rank-legend-dot { width: 10px; height: 10px; border-radius: 50%; display: inline-block; }

/* Prawa szyna */
.rk2-rail { display: flex; flex-direction: column; gap: 14px; min-width: 0; }
.rk2-result, .rk2-comp { padding: 18px; margin: 0; }
.rk2-cardhead { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 13px; }
.rk2-eyebrow { font-size: 11.5px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted-strong); }
.rk2-date { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 11.5px; color: var(--muted-strong); }
.rk2-hero { display: flex; align-items: flex-end; gap: 18px; margin-bottom: 14px; }
.rk2-big { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 38px; font-weight: 600; line-height: 1; letter-spacing: -.02em; }
.rk2-avgrow { display: flex; align-items: center; gap: 7px; padding-bottom: 6px; }
.rk2-mid { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 23px; font-weight: 600; line-height: 1; }
.rk2-sub { font-size: 12px; color: var(--muted-strong); margin-top: 5px; }
.rk2-trend { display: inline-flex; align-items: center; gap: 3px; border-radius: 999px; padding: 2px 8px; font-size: 11.5px; font-weight: 600; white-space: nowrap; }
.rk2-trend.up   { background: color-mix(in srgb, #15803d 10%, transparent); color: #116233; }
.rk2-trend.down { background: color-mix(in srgb, #b91c1c 9%, transparent);  color: #9b1c1c; }
html.theme-dark .rk2-trend.up   { color: #4ade80; }
html.theme-dark .rk2-trend.down { color: #f87171; }
.rk2-minis { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.rk2-mini { background: var(--surface-raised); border: 1px solid var(--border-soft); border-radius: var(--radius); padding: 9px 10px; }
.rk2-mini b { display: block; font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 17px; font-weight: 600; }
.rk2-mini span { font-size: 11px; color: var(--muted-strong); margin-top: 2px; display: block; }
.rk2-note { font-size: 12px; color: #92400e; background: color-mix(in srgb, #92400e 9%, transparent); border-radius: 10px; padding: 8px 10px; margin-top: 12px; }
html.theme-dark .rk2-note { color: #E2AC55; }
.rk2-resfoot { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--border-soft); }
.rk2-gridinfo { font-size: 12px; color: var(--muted-strong); }
.rk2-check { display: inline-flex; align-items: center; gap: 5px; font-size: 12.5px; font-weight: 600; color: var(--primary); text-decoration: none; }
.rk2-check:hover { color: var(--primary-dark); }
/* --primary na ciemnej karcie = 3,07:1 (zmierzone) — jaśniejszy odcień jak .chg-field. */
html.theme-dark .rk2-check { color: #9db9ff; }
html.theme-dark .rk2-check:hover { color: #c3d4ff; }
.rk2-ownrow { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius); background: rgba(245,158,11,.09); margin-bottom: 4px; }
.rk2-dot-own { width: 10px; height: 10px; border-radius: 50%; background: #f59e0b; box-shadow: 0 0 0 2px rgba(245,158,11,.25); flex: none; }
.rk2-ownname { font-size: 13px; font-weight: 600; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rk2-owntag { font-size: 11px; color: var(--muted-strong); flex: none; }
.rk2-ghostbtn {
  display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%;
  border: 1px dashed rgba(0,0,0,.18); background: transparent; border-radius: var(--radius);
  padding: 9px; margin-top: 10px; color: var(--muted-strong); font-size: 12.5px; font-weight: 500;
  cursor: pointer; font-family: inherit;
}
html.theme-dark .rk2-ghostbtn { border-color: rgba(255,255,255,.25); }
.rk2-ghostbtn:hover { border-color: var(--primary); color: var(--primary); }
.rk2-hint { font-size: 11.5px; color: var(--muted-strong); margin-top: 10px; line-height: 1.5; }
.rk2-settings { background: var(--surface-sunken); border: 1px solid var(--border-soft); border-radius: 14px; padding: 11px 15px; }
.rk2-setsummary { display: flex; align-items: center; justify-content: space-between; gap: 10px; cursor: pointer; list-style: none; }
.rk2-setsummary::-webkit-details-marker { display: none; }
.rk2-setsummary > span:first-child { font-size: 12.5px; font-weight: 600; color: var(--muted-strong); }
.rk2-setvals { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 11.5px; color: var(--muted-strong); }
.rk2-settings .form-label { margin-top: 10px; }

/* Historia — stała sekcja pod mapą */
.rk2-history { margin-top: 16px; padding: 20px; }
.rk2-histhead { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; margin-bottom: 14px; }
.rk2-histtitle { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; }
.rk2-histname { font-size: 15px; font-weight: 700; }
.rk2-histmeta { font-size: 12.5px; color: var(--muted-strong); }
.rk2-histbody { display: grid; grid-template-columns: minmax(0, 1fr) 356px; gap: 24px; align-items: start; }
.rk2-chart { position: relative; height: 300px; }
.rk2-axisnote { font-size: 11.5px; color: var(--muted-strong); margin-top: 8px; text-align: right; }
.rk2-histtable { min-width: 0; }

@media (max-width: 1180px) {
  .rk2-grid { grid-template-columns: minmax(0, 1fr); }
  .rk2-mapcard { min-height: 480px; }
  .rk2-histbody { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 900px) {
  .rk2-bar { flex-direction: column; align-items: stretch; gap: 10px; }
  .rk2-sep { display: none; }
  .rk2-locbox { min-width: 0; }
  .rk2-chips { overflow-x: auto; flex-wrap: nowrap; padding-bottom: 4px; -webkit-overflow-scrolling: touch; }
  .rk2-chip { flex: none; min-height: 44px; }
  .rk2-chip-del { opacity: 1; }
  .rk2-mapcard { min-height: 380px; }
  .rk2-legend { max-width: calc(100% - 24px); border-radius: 14px; }
  .rk2-hero { flex-wrap: wrap; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   ERGONOMIA MOBILNA — 2026-08-29
   Sekcja CELOWO NA KOŃCU PLIKU: reguły niżej mają tę samą specyficzność co ich
   odpowiedniki w bloku mobilnym z linii ~4225 i wygrywają KOLEJNOŚCIĄ
   (ostrzeżenie o kolejności — patrz [v1.56]).
   Każda pozycja pochodzi z POMIARU w realnym Chromium (Pixel 5, 393 px)
   na 21 stronach, nie z oceny na oko.
   ═════════════════════════════════════════════════════════════════════════ */
@media (max-width: 900px) {

  /* ── 1. Tor siatki nie może przekroczyć kontenera ─────────────────────────
     `1fr` to skrót od `minmax(auto, 1fr)`, a `auto` jako MINIMUM toru rozwiązuje
     się do min-content elementu i IGNORUJE szerokość kontenera. Wystarczy jedno
     dziecko, które nie chce się zwęzić (`.ui-sel-trigger` niesie etykietę
     z `white-space: nowrap`), żeby tor rozdął się ponad ekran i cała strona
     zaczęła przewijać się w poziomie.
     ZMIERZONE na Automatyzacji: tor 519,8 px w kontenerze 367 px = 140 px
     przepełnienia — stan zastany odnotowany jako nienaprawiony w [alfa 0.305]
     i [alfa 0.315]. `minmax(0, 1fr)` zdejmuje automatyczne minimum; etykieta
     przycina się wtedy wielokropkiem, który `.ui-sel-label` i tak deklaruje.
     To ta sama pułapka co `0fr` vs `minmax(0, 0fr)` w [alfa 0.314].
     Zmiana dotyczy WYŁĄCZNIE minimum toru — liczba kolumn zostaje ta sama. */
  .stats-grid, .kpi-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
  }
  /* Siatki zdefiniowane w ARKUSZU (nie inline) trzeba wymienić z nazwy — CSS nie
     ma selektora „element o display:grid". Dodając nową siatkę jednokolumnową
     na telefonie DOPISZ ją tutaj, inaczej odziedziczy tę samą pułapkę.
     `.menu-grid` mieszka w inline'owym <style> w `menu.html` (stąd `!important`
     — tamten blok stoi PO linku do tego arkusza): zmierzone 12 px przepełnienia
     przy 360 px. */
  .locations-grid,
  .au-grid,
  .menu-grid,
  [style*="grid-template-columns"]:not(.stats-grid):not(.kpi-grid) {
    grid-template-columns: minmax(0, 1fr) !important;
  }

  /* ── 2. Cele dotykowe ≥ 44 px ─────────────────────────────────────────────
     Projekt sam deklaruje ten standard przy `.nav-link` („wytyczne Apple HIG /
     Material"), ale stosował go tylko do nawigacji i `.btn`. Pomiar wykazał
     kontrolki 20–36 px rozsiane po wszystkich stronach.
     CO ŚWIADOMIE POMINIĘTO: checkboxy `.loc-cb`/`.loc-check`/`.au-switch input`
     mają 16 px, ale siedzą wewnątrz `<label>` obejmującego cały wiersz — realnym
     celem jest wiersz, nie kwadracik. Powiększanie ich byłoby kosmetyką udającą
     naprawę ergonomii.
     Hierarchia wizualna „mały vs zwykły przycisk" przenosi się na rozmiar
     czcionki i wcięcie poziome — wysokość przestaje ją nieść, bo wysokość jest
     tym, w co realnie trafia kciuk. */

  /* (a) Przyciski stojące we własnym wierszu — powiększamy NAPRAWDĘ. */
  .btn-sm,
  .page-tab,
  .seg-btn,
  .mode-btn,
  .drb-preset,
  .ed-view,
  .range-btn,
  .au-preset,
  .theme-toggle-btn,
  .ui-sel-trigger, .ui-date-trigger {
    min-height: 44px;
  }
  /* Wcięcie poziome zostaje małe — inaczej wąskie paski (presety zakresu dat,
     segmenty) zaczęłyby się zawijać i urosłyby o cały wiersz. */
  .drb-preset, .ed-view, .range-btn, .au-preset { padding-top: 0; padding-bottom: 0; }
  .page-tab, .seg-btn, .mode-btn { padding-top: 0; padding-bottom: 0; }

  /* (b) Małe ikony — powiększamy do kwadratu 44×44 i centrujemy zawartość.
     `.basemap-btn` celowo dostaje 40 px: to kontrolka NA MAPIE, a każdy piksel
     jej wysokości zabiera widok, w który użytkownik właśnie patrzy. */
  .btn-icon-sm,
  .flag-btn,
  .modal-close {
    min-width: 44px; min-height: 44px;
    display: inline-flex; align-items: center; justify-content: center;
    padding: 0;
  }
  /* Pigułka grupy w Menu — filtr klikany przy każdym imporcie. Wskaźnik
     z [alfa 0.311] liczy geometrię w runtime, więc podąża za nową wysokością. */
  .group-pill { min-height: 40px; display: inline-flex; align-items: center; }
  .theme-add-btn { min-height: 40px; display: inline-flex; align-items: center; }
  .basemap-btn   { min-height: 40px; }

  /* (c) Dzwonek powiadomień — 28 px, ale jest `position: absolute` w nagłówku
     szuflady i jego powiększenie rozjechałoby układ z [alfa 0.306] (odznaka
     liczy orbitę z `--nb-size`). Dlatego rozszerzamy WYŁĄCZNIE POLE TRAFIENIA
     pseudo-elementem — wygląd zostaje co do piksela.
     Sąsiedni `.sb-toggle` jest na telefonie `display: none`, więc powiększone
     pole nie ma z czym kolidować. */
  .gmb-bell { position: absolute; }
  .gmb-bell::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
    border-radius: 999px;
  }

  /* (d) Sterowanie mapą Leaflet — 32 px z biblioteki. */
  .leaflet-control-zoom-in, .leaflet-control-zoom-out {
    width: 40px !important; height: 40px !important; line-height: 40px !important;
  }

  /* (e) Wiersz wyboru wizytówki (Menu, Zdjęcia, Posty) — checkbox ma 16 px,
     ale klikalny jest CAŁY <label>. Wiersz mierzył 33 px, więc to on był
     realnym, za małym celem. Powiększamy wiersz, nie kwadracik. */
  #locPicker .loc-row, .loc-row { min-height: 44px; }

  /* ── 3. Raporty: pasek `.page-tabs` trafił do lustra w dolnym pasku ───────
     `.page-tabs` dołączono do `M_SUBTAB_SOURCES` w `app.js`. Bez reguły niżej
     te same dwa przyciski byłyby na ekranie DWA RAZY (pasek źródłowy + lustro)
     — dokładnie to, przed czym ostrzega komentarz przy regule z linii ~4383.
     `!important`, bo pasek bywa sterowany inline'owym `style.display`. */
  .page-tabs.m-subbar-src { display: none !important; }
}

/* Bardzo niskie ekrany w poziomie: dolny pasek jest ukryty, więc pasek źródłowy
   MUSI wrócić do treści — inaczej pod-zakładki Raportów znikłyby całkowicie.
   Dopełnienie reguły z linii ~4673 dla nowego źródła. */
@media (max-width: 900px) and (max-height: 460px) {
  .page-tabs.m-subbar-src { display: flex !important; }
}

/* ── Edycje opinii (.ed-*) — pod-zakładka „Edycje" w Opiniach [alfa 0.334/0.335].
   Tekst drugorzędny w --muted-strong (kontrast AA, [alfa 0.296]); rozmiary ≥ 12 px. */
.ed-stats { margin-bottom: 16px; }
.ed-charts { display: grid; grid-template-columns: 1.4fr 1.4fr 1fr; gap: 14px; margin-bottom: 16px; }
/* min-width:0 — element siatki ma domyślnie min-width:auto i canvas Chart.js rozpycha
   kolumnę poza kartę (zmierzone 50 px przepełnienia; ta sama pułapka co [v1.56]). */
.ed-chart-card { padding: 14px 16px; min-width: 0; }
.ed-chart-box canvas { max-width: 100%; }
.ed-chart-box { position: relative; height: 220px; }
.ed-chart-box-sm { height: 170px; }
.ed-byloc-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-strong); margin: 12px 0 6px; }
.ed-locrow { display: grid; grid-template-columns: minmax(0,1fr) 72px auto; gap: 8px; align-items: center; font-size: 12.5px; padding: 3px 0; }
.ed-locname { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ed-locbar { height: 6px; background: rgba(0,0,0,.06); border-radius: 3px; overflow: hidden; }
.ed-locbar i { display: block; height: 100%; background: var(--primary); border-radius: 3px; }
.ed-locnum { font-variant-numeric: tabular-nums; font-weight: 600; }
.ed-locnum em { font-style: normal; color: #b91c1c; font-weight: 500; }
.ed-filters { align-items: center; gap: 10px; margin-bottom: 10px; flex-wrap: wrap; }
.ed-count { margin-left: auto; font-size: 12.5px; color: var(--muted-strong); }
.ed-empty { padding: 28px; text-align: center; color: var(--muted-strong); background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius, 12px); }

.ed-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius, 12px); padding: 14px 16px; margin-bottom: 12px; content-visibility: auto; contain-intrinsic-size: auto 320px; }
.ed-card-neg { border-left: 4px solid #ef4444; }
.ed-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; flex-wrap: wrap; margin-bottom: 10px; }
.ed-head-l { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.ed-head-r { display: flex; gap: 6px; flex-wrap: wrap; }
.ed-loc { font-weight: 700; font-size: 14px; }
.ed-author { color: var(--muted-strong); font-size: 13px; }
.ed-rating { font-weight: 700; font-size: 13px; padding: 2px 8px; border-radius: 999px; font-variant-numeric: tabular-nums; }
.ed-rating s { opacity: .7; }
.ed-r-bad  { background: rgba(239,68,68,.14); color: #991b1b; }
.ed-r-mid  { background: rgba(234,179,8,.18); color: #854d0e; }
.ed-r-good { background: rgba(34,197,94,.16); color: #166534; }
.ed-badge { font-size: 12px; font-weight: 600; padding: 2px 8px; border-radius: 999px; white-space: nowrap; }
.ed-b-warn   { background: rgba(249,115,22,.14); color: #9a3412; }
.ed-b-danger { background: rgba(239,68,68,.14); color: #991b1b; }
.ed-b-ok     { background: rgba(34,197,94,.16); color: #166534; }
.ed-b-flag   { background: rgba(59,110,240,.12); color: #2b50c6; }

.ed-timeline { display: flex; align-items: stretch; gap: 0; overflow-x: auto; padding: 4px 0 8px; }
.ed-step { flex: 1 1 0; min-width: 150px; padding: 8px 10px; border-radius: 10px; background: rgba(0,0,0,.035); }
.ed-step-hot { background: rgba(59,110,240,.10); }
.ed-step-inc.ed-step-hot { background: rgba(239,68,68,.10); }
.ed-step-label { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-strong); }
.ed-step-main { font-family: 'IBM Plex Mono', ui-monospace, monospace; font-size: 13.5px; font-weight: 600; margin-top: 2px; font-variant-numeric: tabular-nums; }
.ed-step-sub { font-size: 12px; color: var(--muted-strong); margin-top: 2px; }
.ed-step-ev { font-size: 12px; margin-top: 4px; color: #991b1b; font-style: italic; }
.ed-step-arrow { flex: 0 0 18px; align-self: center; height: 2px; background: var(--border); position: relative; }
.ed-step-arrow::after { content: ''; position: absolute; right: -1px; top: -4px; border: 5px solid transparent; border-left-color: var(--border); }
.ed-second-inc { font-size: 12.5px; color: #9a3412; background: rgba(249,115,22,.10); border-radius: 8px; padding: 6px 10px; margin-bottom: 8px; }

.ed-diff-title { font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted-strong); margin: 6px 0 4px; display: flex; justify-content: space-between; }
.ed-legend { text-transform: none; letter-spacing: 0; font-weight: 500; }
.ed-diff { white-space: pre-wrap; word-break: break-word; font-size: 14px; line-height: 1.55; padding: 10px 12px; background: rgba(0,0,0,.03); border-radius: 10px; }
.ed-ins { background: rgba(34,197,94,.22); text-decoration: none; border-radius: 3px; padding: 0 1px; }
.ed-del { background: rgba(239,68,68,.16); color: #7f1d1d; border-radius: 3px; padding: 0 1px; }
.ed-reply { margin-top: 8px; font-size: 13px; }
.ed-reply summary { cursor: pointer; color: var(--muted-strong); font-weight: 600; }
.ed-reply-body { white-space: pre-wrap; padding: 8px 12px; margin-top: 6px; border-left: 3px solid var(--primary); background: rgba(59,110,240,.06); border-radius: 0 8px 8px 0; }
.ed-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.ed-muted { color: var(--muted-strong); }

html.theme-dark .ed-locbar, html.theme-dark .ed-step, html.theme-dark .ed-diff { background: rgba(255,255,255,.07); }
html.theme-dark .ed-step-hot { background: rgba(99,140,255,.18); }
html.theme-dark .ed-step-inc.ed-step-hot { background: rgba(239,68,68,.20); }
html.theme-dark .ed-r-bad, html.theme-dark .ed-b-danger { color: #fca5a5; }
html.theme-dark .ed-r-mid { color: #fcd34d; }
html.theme-dark .ed-r-good, html.theme-dark .ed-b-ok { color: #86efac; }
html.theme-dark .ed-b-warn, html.theme-dark .ed-second-inc { color: #fdba74; }
html.theme-dark .ed-b-flag { color: #9db9ff; }
html.theme-dark .ed-step-ev, html.theme-dark .ed-locnum em { color: #fca5a5; }
html.theme-dark .ed-del { color: #fecaca; }

@media (max-width: 1100px) { .ed-charts { grid-template-columns: 1fr 1fr; } .ed-charts .ed-chart-card:last-child { grid-column: 1 / -1; } }
@media (max-width: 900px)  { .ed-charts { grid-template-columns: 1fr; } .ed-count { margin-left: 0; } .ed-timeline { flex-direction: column; } .ed-step-arrow { display: none; } }

/* [alfa 0.343] Wiersz wyboru wizytówki w modalu Użytkownicy → Wizytówki — dawne
   onmouseover/onmouseout z users.js (CSP bez inline handlerów). */
.loc-pick-row:hover { background: #f8fafc; }
