/* ═══════════════════════════════════════════════════════════════════════════
   Panel VPN & Proxy — design system (dark)
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Wyraźna hierarchia tonalna: tło ciemne, powierzchnie wyraźnie jaśniejsze */
  --bg: #0c0f15;
  --bg-soft: #070a0e;
  --surface: #191d27;
  --surface-2: #232834;
  --surface-3: #2d3340;
  --border: rgba(255, 255, 255, .09);
  --border-strong: rgba(255, 255, 255, .16);
  --text: #f2f5fb;
  --text-dim: #bcc5d4;
  --text-faint: #828d9f;

  /* ── Miękkie cienie (soft UI), ale z zachowaniem separacji ── */
  --neu-raised:    0 1px 0 rgba(255,255,255,.05) inset, 0 3px 6px rgba(0,0,0,.35), 0 12px 26px rgba(0,0,0,.4);
  --neu-raised-lg: 0 1px 0 rgba(255,255,255,.06) inset, 0 12px 40px rgba(0,0,0,.55);
  --neu-raised-sm: 0 1px 0 rgba(255,255,255,.05) inset, 0 2px 5px rgba(0,0,0,.35);
  --neu-hover:     0 1px 0 rgba(255,255,255,.07) inset, 0 6px 12px rgba(0,0,0,.4), 0 16px 34px rgba(0,0,0,.46);
  --neu-pressed:    inset 0 2px 6px rgba(0,0,0,.55);
  --neu-pressed-sm: inset 0 1px 4px rgba(0,0,0,.5);
  /* Akcent spójny ze stroną główną: emerald */
  --accent: #10b981;
  --accent-strong: #059669;
  --accent-soft: rgba(16, 185, 129, .12);
  --green: #34d399;
  --green-soft: rgba(52, 211, 153, .12);
  --red: #f87171;
  --red-soft: rgba(248, 113, 113, .12);
  --amber: #fbbf24;
  --amber-soft: rgba(251, 191, 36, .12);
  --purple: #a78bfa;
  --purple-soft: rgba(167, 139, 250, .12);
  --sky: #38bdf8;
  --sky-soft: rgba(56, 189, 248, .12);
  /* Krawędź barwnej plakietki — ton mocniejszy niż wypełnienie, słabszy niż tekst */
  --green-edge: rgba(52, 211, 153, .35);
  --amber-edge: rgba(251, 191, 36, .32);
  --red-edge:   rgba(248, 113, 113, .32);
  --sky-edge:   rgba(56, 189, 248, .32);
  --radius: 16px;
  --radius-sm: 10px;
  --sidebar-w: 268px;
  --topbar-h: 60px;
  --font: 'Inter', system-ui, -apple-system, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, monospace;
}

* { box-sizing: border-box; margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; }
body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.55;
  min-height: 100vh;
  position: relative;
  overflow-x: hidden;
}

/* ═════ Bardzo delikatne tło morficzne — nie odciąga uwagi od treści ═════ */
body::before, body::after {
  content: '';
  position: fixed;
  pointer-events: none;
  z-index: 0;
  filter: blur(150px);
  opacity: .18;
  will-change: transform, border-radius;
}
body::before {
  width: 46rem; height: 46rem;
  top: -20rem; right: -16rem;
  background: radial-gradient(circle, rgba(16,185,129,.22), transparent 66%);
  border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%;
  animation: panel-morph 30s ease-in-out infinite, panel-blobdrift 38s ease-in-out infinite;
}
body::after {
  width: 38rem; height: 38rem;
  bottom: -18rem; left: -16rem;
  background: radial-gradient(circle, rgba(56,189,248,.12), transparent 66%);
  border-radius: 58% 42% 37% 63% / 44% 41% 59% 56%;
  animation: panel-morph 34s ease-in-out infinite reverse, panel-blobdrift2 42s ease-in-out infinite;
}
@keyframes panel-morph {
  0%,100% { border-radius: 42% 58% 63% 37% / 41% 44% 56% 59%; }
  34%     { border-radius: 66% 34% 42% 58% / 57% 62% 38% 43%; }
  67%     { border-radius: 36% 64% 57% 43% / 46% 37% 63% 54%; }
}
@keyframes panel-blobdrift  { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(40px,-30px) rotate(18deg); } }
@keyframes panel-blobdrift2 { 0%,100% { transform: translate(0,0) rotate(0); } 50% { transform: translate(-30px,25px) rotate(-14deg); } }
@keyframes panel-floaty     { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
@keyframes panel-sheen      { 0% { transform: translateX(-150%) skewX(-16deg); } 55%,100% { transform: translateX(280%) skewX(-16deg); } }
@keyframes panel-glowpulse  { 0%,100% { opacity: .5; } 50% { opacity: .95; } }
@media (prefers-reduced-motion: reduce) {
  body::before, body::after { animation: none; }
}
.mono { font-family: var(--mono); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: none; }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 3px; }
[v-cloak] { display: none; }

/* ── Layout ──────────────────────────────────────────────────────────────── */
.layout { display: flex; min-height: 100vh; }

.sidebar {
  width: var(--sidebar-w);
  background: #0a0d12;
  border-right: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  position: fixed;
  top: 0; bottom: 0; left: 0;
  z-index: 50;
  transition: transform .25s ease;
}
.sidebar-logo {
  display: flex; align-items: center; gap: 10px;
  padding: 16px 18px; height: var(--topbar-h);
  border-bottom: 1px solid var(--border);
}
.sidebar-logo .logo-icon {
  background: linear-gradient(145deg, #12c78a, #0d9668);
  width: 34px; height: 34px; border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; color: #04120c; flex-shrink: 0;
  box-shadow: var(--neu-raised-sm), inset 1px 1px 1px rgba(255,255,255,.3), 0 0 16px -4px rgba(16,185,129,.5);
}
.sidebar-logo .logo-name { font-weight: 700; font-size: 15px; letter-spacing: .01em; }
.sidebar-logo .logo-sub { font-size: 11px; color: var(--text-faint); margin-top: -2px; }

/* Nawigacja boczna: komplet reguł w jednym miejscu — patrz "SIDEBAR" niżej.
   Wcześniej te same selektory były definiowane tu i jeszcze dwa razy dalej
   w pliku, więc o wyglądzie decydowało to, co przypadkiem stało niżej. */

.sidebar-user {
  border-top: 1px solid var(--border);
  padding: 12px;
  display: flex; align-items: center; gap: 10px;
}
.sidebar-user .avatar {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  box-shadow: var(--neu-raised-sm);
  display: flex; align-items: center; justify-content: center;
  font-weight: 700; font-size: 13px; flex-shrink: 0;
}
.sidebar-user .u-name { font-size: 13.5px; font-weight: 600; line-height: 1.2; }
.sidebar-user .u-role { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .06em; }
.sidebar-user .u-actions { margin-left: auto; display: flex; gap: 4px; }

.main {
  flex: 1;
  margin-left: var(--sidebar-w);
  display: flex; flex-direction: column;
  min-width: 0;
}

.topbar {
  height: var(--topbar-h);
  border-bottom: 1px solid var(--border);
  background: rgba(10, 13, 18, .92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  display: flex; align-items: center; gap: 12px;
  padding: 0 22px;
  position: sticky; top: 0; z-index: 40;
}
.topbar .page-title { font-size: 16.5px; font-weight: 700; }
.topbar .page-desc { font-size: 12.5px; color: var(--text-faint); }
.topbar-right { margin-left: auto; display: flex; align-items: center; gap: 8px; }
.last-refresh { font-size: 12.5px; color: var(--text-faint); display: flex; align-items: center; gap: 5px; }

.content { padding: 22px; max-width: 1240px; width: 100%; margin: 0 auto; }

.hamburger { display: none; }
.sidebar-backdrop { display: none; }

@media (max-width: 900px) {
  .sidebar { transform: translateX(-100%); }
  .sidebar.open { transform: translateX(0); box-shadow: 0 0 60px rgba(0,0,0,.6); }
  .main { margin-left: 0; }
  .hamburger { display: inline-flex; }
  .sidebar-backdrop.show {
    display: block; position: fixed; inset: 0;
    background: rgba(0,0,0,.5); z-index: 45;
  }
  .content { padding: 14px; }
  .topbar { padding: 0 14px; }
}

/* ── Cards — wyniesione, wyraźnie oddzielone od tła ─────────────────────── */
.card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--neu-raised);
  transition: box-shadow .25s ease, border-color .25s ease;
}
.card:hover { border-color: var(--border-strong); }
.card-header {
  padding: 14px 18px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.card-header .grow { flex: 1; }
.card-title { font-size: 15px; font-weight: 700; }
.card-sub { font-size: 12.5px; color: var(--text-faint); margin-top: 1px; }
.card-body { padding: 18px; }
.card-body.tight { padding: 0; }

.grid { display: grid; gap: 14px; }
.grid-2 { grid-template-columns: repeat(2, 1fr); }
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-4 { grid-template-columns: repeat(4, 1fr); }
.grid-6 { grid-template-columns: repeat(6, 1fr); }
/* Siatka kart dopasowująca liczbę kolumn do zawartości. Sztywne grid-2 przy
   jednej karcie zostawiało pół ekranu pustki i wyrywało stronę z rytmu panelu;
   auto-fit zwija puste tory, więc pojedyncza karta rozciąga się na całą szerokość. */
.grid-cards { grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
@media (max-width: 1100px) {
  .grid-6 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid-2, .grid-3 { grid-template-columns: 1fr; }
  .grid-6, .grid-4 { grid-template-columns: repeat(2, 1fr); }
}

/* KPI — matowe kafle, mocna liczba na środku */
.kpi { padding: 16px 18px; }

/* ── Buttons — wyraźne, z krawędzią; miękkie wciśnięcie na klik ──────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  border-radius: var(--radius-sm);
  font-weight: 600; font-size: 13.5px; font-family: var(--font);
  padding: 8px 14px;
  cursor: pointer; border: 1px solid var(--border-strong);
  transition: box-shadow .15s, color .15s, background .15s, border-color .15s, transform .1s;
  white-space: nowrap;
  color: var(--text);
  background: var(--surface-2);
  box-shadow: var(--neu-raised-sm);
  text-decoration: none;
}
.btn:hover { color: #fff; background: var(--surface-3); border-color: rgba(255,255,255,.24); }
.btn:active { box-shadow: var(--neu-pressed-sm); transform: translateY(1px); }
.btn:disabled { opacity: .5; cursor: not-allowed; }

.btn.primary {
  background: linear-gradient(180deg, #16c78d, #0e9c6c);
  color: #04120c; border-color: rgba(16,185,129,.5);
  box-shadow: var(--neu-raised-sm), inset 0 1px 0 rgba(255,255,255,.25);
}
.btn.primary:hover { color: #04120c; background: linear-gradient(180deg, #22d69a, #12b57e); border-color: rgba(52,211,153,.6); }
.btn.primary:active { box-shadow: var(--neu-pressed-sm); }

.btn.danger { background: rgba(248,113,113,.16); border-color: rgba(248,113,113,.4); color: #fecaca; }
.btn.danger:hover { background: rgba(248,113,113,.26); border-color: rgba(248,113,113,.6); color: #fee2e2; }
.btn.success { background: rgba(52,211,153,.16); border-color: rgba(52,211,153,.4); color: #a7f3d0; }
.btn.success:hover { background: rgba(52,211,153,.26); border-color: rgba(52,211,153,.6); color: #d1fae5; }

.btn.ghost { background: transparent; border-color: transparent; color: var(--text-dim); box-shadow: none; }
.btn.ghost:hover { background: var(--surface-2); border-color: var(--border); color: var(--text); }

.btn.sm { padding: 6px 12px; font-size: 12.5px; gap: 5px; line-height: 1.3; }
.btn.icon { padding: 8px 11px; }
.btn.icon.sm { padding: 6px 9px; }

/* ── Badges / status ─────────────────────────────────────────────────────── */
.badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 700;
  padding: 3px 10px; border-radius: 99px;
  border: 1px solid transparent;
  white-space: nowrap;
}
.badge.green { background: var(--green-soft); color: var(--green); border-color: rgba(52,211,153,.25); }
.badge.red { background: var(--red-soft); color: var(--red); border-color: rgba(248,113,113,.25); }
.badge.amber { background: var(--amber-soft); color: var(--amber); border-color: rgba(251,191,36,.25); }
.badge.blue { background: var(--accent-soft); color: #6ee7b7; border-color: rgba(16,185,129,.25); }
.badge.purple { background: var(--purple-soft); color: var(--purple); border-color: rgba(167,139,250,.25); }
.badge.gray { background: var(--surface-2); color: var(--text-dim); border-color: var(--border-strong); }
.badge.sky { background: var(--sky-soft); color: var(--sky); border-color: rgba(56,189,248,.25); }

.dot { width: 8px; height: 8px; border-radius: 50%; display: inline-block; flex-shrink: 0; }
.dot.green { background: #22c55e; animation: pulse-dot 2s ease-in-out infinite; }
.dot.red { background: #ef4444; }
.dot.gray { background: #475569; }
@keyframes pulse-dot {
  0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,.4); }
  50% { box-shadow: 0 0 0 5px rgba(34,197,94,0); }
}

/* ── Tables ──────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; }
table.tbl { width: 100%; border-collapse: collapse; font-size: 14px; }
.tbl th {
  text-align: left; font-size: 11px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em;
  color: var(--text-faint);
  padding: 11px 14px;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
}
.tbl th.sortable { cursor: pointer; user-select: none; }
.tbl th.sortable:hover { color: var(--text-dim); }
.tbl td {
  padding: 12px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.tbl tbody tr:last-child td { border-bottom: none; }
.tbl tbody tr.clickable { cursor: pointer; }
.tbl tbody tr.clickable:hover td { background: rgba(30, 41, 59, .35); }
.tbl .actions { text-align: right; white-space: nowrap; }
.tbl .actions .btn { margin-left: 4px; }

/* ── Forms ───────────────────────────────────────────────────────────────── */
.field { margin-bottom: 14px; }
.field label {
  display: block; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim); margin-bottom: 6px;
}
.field .hint { font-size: 12px; color: var(--text-faint); margin-top: 5px; }
.input, .select, textarea.input {
  width: 100%;
  background: var(--bg-soft);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-size: 14px; font-family: var(--font);
  padding: 10px 13px;
  outline: none;
  box-shadow: var(--neu-pressed-sm);
  transition: box-shadow .15s, border-color .15s;
}
.input:focus, .select:focus, textarea.input:focus {
  border-color: var(--accent);
  box-shadow: var(--neu-pressed-sm), 0 0 0 3px rgba(16,185,129,.2);
}
.input::placeholder { color: var(--text-faint); }
.select { appearance: none; cursor: pointer; }
.input-group { position: relative; }
.input-group .prefix, .input-group .suffix {
  position: absolute; top: 0; bottom: 0;
  display: flex; align-items: center;
  color: var(--text-faint); font-size: 12px;
}
.input-group .prefix { left: 11px; }
.input-group .suffix { right: 11px; }
.input-group .prefix ~ .input { padding-left: 32px; }
.input.mono, .select.mono { font-family: var(--mono); font-size: 13px; }

.checkbox-row {
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 11px 13px;
  cursor: pointer; transition: border-color .15s, background .15s;
}
.checkbox-row:hover { border-color: var(--border-strong); background: var(--surface-3); }
.checkbox-row.checked {
  background: rgba(16,185,129,.12);
  border-color: var(--accent);
}
.checkbox-row input { margin-top: 3px; accent-color: var(--accent); }
.checkbox-row .cb-title { font-size: 13.5px; font-weight: 600; }
.checkbox-row .cb-desc { font-size: 12px; color: var(--text-faint); }

/* ── Compact selection items for modals ────────────────────────────────────── */
.compact-select-grid {
  display: flex !important;
  flex-direction: column !important;
  gap: 6px !important;
  height: 200px !important;
  max-height: 200px !important;
  overflow-y: auto !important;
  padding-right: 4px !important;
  box-sizing: border-box !important;
}
.compact-select-grid.single-col {
  display: flex !important;
  flex-direction: column !important;
}
.compact-select-card {
  display: flex !important;
  flex-direction: row !important;
  align-items: center !important;
  justify-content: flex-start !important;
  gap: 10px !important;
  background: var(--surface-2) !important;
  border: 1px solid var(--border) !important;
  border-radius: 6px !important;
  padding: 8px 12px !important;
  cursor: pointer !important;
  transition: all 0.15s ease !important;
  user-select: none !important;
  height: 40px !important;
  min-height: 40px !important;
  max-height: 40px !important;
  box-sizing: border-box !important;
  width: 100% !important;
}
.compact-select-card.mb-3 {
  margin-bottom: 14px !important;
}
.compact-select-card:hover {
  border-color: var(--border-strong) !important;
  background: var(--surface-3) !important;
}
.compact-select-card.checked {
  background: rgba(16, 185, 129, 0.12) !important;
  border-color: var(--accent) !important;
}
.compact-select-card input,
.compact-select-card input[type="checkbox"] {
  display: inline-block !important;
  margin: 0 !important;
  padding: 0 !important;
  accent-color: var(--accent) !important;
  flex-shrink: 0 !important;
  width: 16px !important;
  height: 16px !important;
  min-width: 16px !important;
  min-height: 16px !important;
  cursor: pointer !important;
  position: static !important;
  float: none !important;
}
.compact-select-card .csc-label {
  font-size: 12px !important;
  font-weight: 600 !important;
  white-space: nowrap !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  display: flex !important;
  flex-direction: row !important;
  align-items: center !important;
  gap: 6px !important;
  color: var(--text) !important;
  flex: 1 !important;
  min-width: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
  line-height: 1 !important;
  text-transform: none !important;
}
.compact-select-card .csc-port {
  font-size: 11px !important;
  font-family: var(--mono) !important;
  color: var(--text-faint) !important;
  margin-left: auto !important;
  flex-shrink: 0 !important;
  white-space: nowrap !important;
  line-height: 1 !important;
}
.btn.xs {
  padding: 4px 10px;
  font-size: 11.5px;
  height: 26px;
  gap: 4px;
  line-height: 1;
  border-radius: 5px;
}

/* ── Modals ──────────────────────────────────────────────────────────────── */
.modal-backdrop {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(2, 6, 14, .68);
  backdrop-filter: blur(8px) saturate(120%);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
  display: flex; align-items: flex-start; justify-content: center;
  padding: 5vh 16px 16px;
  overflow-y: auto;
  animation: fade-in .15s ease-out;
}
.modal {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius);
  width: 100%; max-width: 540px;
  box-shadow: 0 24px 64px rgba(0,0,0,.6);
  animation: modal-in .2s cubic-bezier(.2,.7,.2,1);
}
.modal.lg { max-width: 760px; }
.modal.xl { max-width: 940px; }
.modal-head {
  padding: 15px 20px;
  border-bottom: 1px solid var(--border);
  display: flex; align-items: center; gap: 12px;
}
.modal-head .m-title { font-size: 15.5px; font-weight: 700; flex: 1; min-width: 0; }
.modal-head .m-sub { font-size: 12px; color: var(--text-faint); margin-top: 1px; }
.modal-body { padding: 20px; }
.modal-foot {
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  display: flex; justify-content: flex-end; gap: 8px;
}
.modal-close {
  background: none; border: none; color: var(--text-faint);
  cursor: pointer; font-size: 15px; padding: 4px 6px; border-radius: 6px;
}
.modal-close:hover { color: var(--text); background: var(--surface-2); }
@keyframes modal-in { from { opacity: 0; transform: translateY(-12px) scale(.98); } to { opacity: 1; transform: none; } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ── Toasts ──────────────────────────────────────────────────────────────── */
.toasts {
  position: fixed; top: 16px; right: 16px; z-index: 300;
  display: flex; flex-direction: column; gap: 8px;
  pointer-events: none; max-width: 340px;
}
.toast {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  border-radius: 12px;
  padding: 12px 15px;
  font-size: 13.5px; font-weight: 500;
  display: flex; align-items: flex-start; gap: 9px;
  box-shadow: 0 14px 34px rgba(0,0,0,.5);
  animation: toast-in .2s cubic-bezier(.2,.7,.2,1);
  pointer-events: auto;
}
.toast i { margin-top: 2px; }
.toast.success i { color: var(--green); }
.toast.error i { color: var(--red); }
.toast.info i { color: var(--sky); }
.toast.warning i { color: var(--amber); }
@keyframes toast-in { from { opacity: 0; transform: translateX(60%); } to { opacity: 1; transform: none; } }

/* ── Progress bars / meters ──────────────────────────────────────────────── */
.meter { height: 8px; background: var(--bg-soft); border-radius: 99px; overflow: hidden; box-shadow: var(--neu-pressed-sm); }
.meter > div { height: 100%; border-radius: 99px; transition: width .6s ease; }
.meter .fill-blue { background: var(--accent); }
.meter .fill-purple { background: var(--purple); }
.meter .fill-amber { background: var(--amber); }
.meter .fill-green { background: var(--green); }
.meter .fill-red { background: var(--red); }

/* ── Pipeline steps (creation/diagnostics) ───────────────────────────────── */
.pipeline { display: flex; flex-direction: column; gap: 0; }
.pipe-step { display: flex; gap: 12px; }
.pipe-step .p-rail { display: flex; flex-direction: column; align-items: center; }
.pipe-step .p-dot {
  width: 26px; height: 26px; border-radius: 50%;
  border: 2px solid var(--border-strong);
  background: var(--surface);
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; color: var(--text-faint);
  flex-shrink: 0;
}
.pipe-step .p-line { width: 2px; flex: 1; background: var(--border); min-height: 14px; }
.pipe-step:last-child .p-line { display: none; }
.pipe-step .p-body { padding-bottom: 16px; min-width: 0; flex: 1; }
.pipe-step .p-title { font-size: 13.5px; font-weight: 600; padding-top: 3px; }
.pipe-step .p-detail { font-size: 12.5px; color: var(--text-faint); margin-top: 2px; word-break: break-word; }
.pipe-step.running .p-dot { border-color: var(--accent); color: #60a5fa; animation: step-pulse 1.4s ease-in-out infinite; }
.pipe-step.done .p-dot { border-color: #22c55e; background: rgba(34,197,94,.12); color: #4ade80; }
.pipe-step.error .p-dot { border-color: #ef4444; background: rgba(239,68,68,.12); color: var(--red); }
.pipe-step.error .p-detail { color: var(--red); }
@keyframes step-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(59,130,246,.45); }
  50% { box-shadow: 0 0 0 7px rgba(59,130,246,0); }
}

.deploy-pipeline-view {
  padding: 4px 0;
}
.deploy-status-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 14px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  margin-bottom: 16px;
  gap: 12px;
  flex-wrap: wrap;
}
.deploy-stack-badge {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 14px;
}
.deploy-stack-badge i {
  font-size: 16px;
  color: var(--accent);
}
.deploy-meta {
  font-size: 12.5px;
  color: var(--text-dim);
}

/* ── Misc ────────────────────────────────────────────────────────────────── */
.spin { animation: spin .8s linear infinite; display: inline-block; }
@keyframes spin { to { transform: rotate(360deg); } }

.empty {
  text-align: center; padding: 44px 20px; color: var(--text-faint);
}
.empty i { font-size: 34px; display: block; margin-bottom: 12px; opacity: .5; }
.empty .e-title { color: var(--text-dim); font-weight: 600; font-size: 15px; }
.empty .e-desc { font-size: 13px; margin-top: 4px; }

.code-block {
  background: #06090e;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: 12.5px;
  padding: 11px 13px;
  overflow-x: auto;
  color: #86efac;
  position: relative;
  word-break: break-all;
  white-space: pre-wrap;
}
.copy-row {
  display: flex; align-items: stretch; gap: 6px;
}
.copy-row .code-block { flex: 1; }

.log-view {
  background: #06090e;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  font-family: var(--mono);
  font-size: 12px;
  padding: 13px;
  max-height: 380px;
  overflow-y: auto;
  line-height: 1.65;
  white-space: pre-wrap;
  word-break: break-all;
}
.log-err { color: var(--red); } .log-warn { color: var(--amber); }
.log-ok { color: var(--green); } .log-info { color: var(--text-dim); }
.log-ts { color: var(--text-faint); }

.alert-banner {
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-size: 12.5px; font-weight: 500;
  display: flex; align-items: center; gap: 10px;
  border: 1px solid;
}
.alert-banner.critical { background: var(--red-soft); border-color: rgba(248,113,113,.3); color: #fca5a5; }
.alert-banner.warn { background: var(--amber-soft); border-color: rgba(251,191,36,.3); color: #fcd34d; }
.alert-banner.info { background: var(--sky-soft); border-color: rgba(56,189,248,.3); color: #7dd3fc; }

.tabs {
  display: flex; gap: 6px; border-bottom: 1px solid var(--border);
  padding: 0 8px; overflow-x: auto;
  margin: 22px 0 16px 0;
}
.tab {
  padding: 11px 16px; font-size: 13.5px; font-weight: 600;
  color: var(--text-dim); cursor: pointer;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px; white-space: nowrap;
  background: none; border-top: none; border-left: none; border-right: none;
  font-family: var(--font);
  transition: all 0.15s ease;
}
.tab:hover { color: var(--text); background: rgba(255,255,255,0.03); border-radius: 6px 6px 0 0; }
.tab.active { color: #6ee7b7; border-bottom-color: var(--accent); }

.detail-list { display: flex; flex-direction: column; gap: 0; }
.detail-list .row {
  display: flex; justify-content: space-between; gap: 14px;
  padding: 9px 0; font-size: 13.5px;
  border-bottom: 1px solid var(--border);
}
.detail-list .row:last-child { border-bottom: none; }
.detail-list .row .k { color: var(--text-faint); flex-shrink: 0; }
.detail-list .row .v { text-align: right; word-break: break-word; }

.page-head { display: flex; align-items: center; gap: 12px; margin-bottom: 18px; flex-wrap: wrap; }
.page-head .grow { flex: 1; min-width: 0; }
.page-head h1 { font-size: 22px; font-weight: 800; letter-spacing: -.015em; }
.page-head .desc { font-size: 13.5px; color: var(--text-faint); margin-top: 3px; }

.section-gap { display: flex; flex-direction: column; gap: 16px; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--bg-soft); border: 1px solid var(--border-strong);
  border-radius: 8px; padding: 5px 11px;
  font-size: 12.5px; font-family: var(--mono);
}
.chip .chip-copy { cursor: pointer; color: var(--text-faint); }
.chip .chip-copy:hover { color: var(--text); }

.text-dim { color: var(--text-dim); }
.text-faint { color: var(--text-faint); }
.text-green { color: var(--green); }
.text-red { color: var(--red); }
.text-amber { color: var(--amber); }
.text-blue { color: #6ee7b7; }
.text-xs { font-size: 12px; }
.text-sm { font-size: 13.5px; }
.fw-6 { font-weight: 600; }
.fw-7 { font-weight: 700; }
.mt-1 { margin-top: 6px; } .mt-2 { margin-top: 12px; } .mt-3 { margin-top: 18px; }
.mb-1 { margin-bottom: 6px; } .mb-2 { margin-bottom: 12px; } .mb-3 { margin-bottom: 18px; }
.flex { display: flex; }
.flex-col { display: flex; flex-direction: column; }
.flex-row { display: flex; flex-direction: row; }
.items-center { align-items: center; }
.items-start { align-items: flex-start; }
.items-end { align-items: flex-end; }
.justify-between { justify-content: space-between; }
.justify-center { justify-content: center; }
.justify-end { justify-content: flex-end; }
.gap-1 { gap: 6px; } .gap-2 { gap: 10px; } .gap-3 { gap: 16px; } .gap-4 { gap: 24px; }
.flex-wrap { flex-wrap: wrap; }
.flex-nowrap { flex-wrap: nowrap; }
.grow { flex: 1 1 0%; min-width: 0; }
.shrink-0 { flex-shrink: 0; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nowrap { white-space: nowrap; }
.w-full { width: 100%; }
.tnum { font-variant-numeric: tabular-nums; }

/* pasek postępu / zużycia (meter) */
.meter { height: 8px; border-radius: 5px; background: var(--surface-2); overflow: hidden; }
.meter > span { display: block; height: 100%; border-radius: 5px; background: var(--accent); transition: width .4s ease; }
.meter.green > span  { background: var(--green); }
.meter.amber > span  { background: var(--amber); }
.meter.red > span    { background: var(--red); }
.meter.sky > span    { background: var(--sky); }
.meter.purple > span { background: var(--purple); }
.meter.gray > span   { background: var(--border-strong); }

/* login page */
.login-wrap {
  min-height: 100vh; display: flex; align-items: center; justify-content: center;
  padding: 20px;
  position: relative;
}
.login-card {
  position: relative;
  width: 100%; max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: 18px;
  padding: 40px 36px;
  box-shadow: 0 30px 70px rgba(0,0,0,.6);
  z-index: 1;
}

/* ══════════ Strażnik AI ══════════ */

/* Pływający przycisk (robot) w prawym dolnym rogu */
.ai-fab {
  position: fixed; right: 22px; bottom: 22px; z-index: 60;
  width: 62px; height: 62px; border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: radial-gradient(circle at 50% 35%, #1b2130, #0e121b);
  box-shadow: 0 10px 30px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.06);
  cursor: pointer; display: grid; place-items: center;
  transition: transform .25s cubic-bezier(.2,.8,.2,1), box-shadow .25s, border-color .25s;
}
.ai-fab:hover { transform: translateY(-3px) scale(1.05); border-color: var(--accent); }
.ai-fab .ai-robot-svg { width: 40px; height: 40px; }
.ai-fab.ai-idle     { box-shadow: 0 10px 30px rgba(0,0,0,.5), 0 0 18px rgba(52,211,153,.25); }
.ai-fab.ai-scanning { box-shadow: 0 10px 30px rgba(0,0,0,.5), 0 0 22px rgba(56,189,248,.45); border-color: var(--sky); }
.ai-fab.ai-alert    { box-shadow: 0 10px 30px rgba(0,0,0,.5), 0 0 26px rgba(248,113,113,.55); border-color: var(--red);
                      animation: ai-fab-shake 2.2s ease-in-out infinite; }
@keyframes ai-fab-shake {
  0%,88%,100% { transform: translateY(0) rotate(0); }
  90% { transform: translateY(-1px) rotate(-6deg); } 94% { transform: rotate(6deg); } 97% { transform: rotate(-3deg); }
}
.ai-fab-badge {
  position: absolute; top: -3px; right: -3px; min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: 10px; background: var(--red); color: #fff; font-size: 11px; font-weight: 800;
  display: grid; place-items: center; border: 2px solid var(--bg); font-variant-numeric: tabular-nums;
}

/* Robot SVG — części i stany */
.ai-robot-svg { display: block; }
.ai-robot-svg .r-head  { fill: #232b3a; stroke: rgba(255,255,255,.14); stroke-width: 1.2; }
.ai-robot-svg .r-visor { fill: #0b0f17; stroke: rgba(255,255,255,.06); stroke-width: 1; }
.ai-robot-svg .r-body  { fill: #1a2130; stroke: rgba(255,255,255,.1); stroke-width: 1; }
.ai-robot-svg .r-mouth { stroke: rgba(255,255,255,.18); stroke-width: 1.4; stroke-linecap: round; }
.ai-robot-svg .r-antenna { stroke: rgba(255,255,255,.3); stroke-width: 1.6; stroke-linecap: round; }
.ai-robot-svg .r-eye { fill: var(--green); transform-origin: center; animation: ai-blink 4.5s infinite; }
.ai-robot-svg .r-antenna-dot { fill: var(--green); animation: ai-pulse 2.4s infinite; }
.ai-robot-svg .r-scan { fill: var(--sky); opacity: 0; }
.ai-robot-svg .r-bang { opacity: 0; transform: scale(.4); transform-origin: 50px 14px; }
.ai-robot-svg .r-bang-bg { fill: var(--red); }
.ai-robot-svg .r-bang-l, .ai-robot-svg .r-bang-d { stroke: #fff; fill: #fff; stroke-width: 2.4; stroke-linecap: round; }
@keyframes ai-blink { 0%,92%,100% { transform: scaleY(1); } 96% { transform: scaleY(.1); } }
@keyframes ai-pulse { 0%,100% { opacity: .45; } 50% { opacity: 1; } }

/* stan: skanowanie → oczy/antena cyjan + sweep linii skanu */
.ai-scanning .r-eye, .ai-scanning .r-antenna-dot { fill: var(--sky); }
.ai-scanning .r-scan { opacity: .9; animation: ai-scan-sweep 1.3s linear infinite; }
@keyframes ai-scan-sweep { 0% { transform: translateY(0); opacity: 0; } 20% { opacity: .95; } 100% { transform: translateY(13px); opacity: 0; } }

/* stan: alert → czerwone oczy + wykrzyknik */
.ai-alert .r-eye, .ai-alert .r-antenna-dot { fill: var(--red); }
.ai-alert .r-bang { opacity: 1; transform: scale(1); animation: ai-bang-pop 1.6s ease-in-out infinite; }
@keyframes ai-bang-pop { 0%,100% { transform: scale(1); } 50% { transform: scale(1.14); } }

/* idle → delikatne kołysanie całego robota */
.ai-idle .ai-robot-svg, .ai-fab.ai-idle .ai-robot-svg { animation: ai-bob 3.6s ease-in-out infinite; }
@keyframes ai-bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-2px); } }

/* Drawer */
.ai-drawer-backdrop { position: fixed; inset: 0; z-index: 65; background: rgba(0,0,0,.5); display: flex; justify-content: flex-end; }
.ai-drawer {
  width: 420px; max-width: 92vw; height: 100%; overflow-y: auto;
  background: var(--surface); border-left: 1px solid var(--border-strong);
  box-shadow: -20px 0 60px rgba(0,0,0,.5); display: flex; flex-direction: column;
}
.ai-drawer-head { display: flex; align-items: center; gap: 10px; padding: 16px 18px; border-bottom: 1px solid var(--border); position: sticky; top: 0; background: var(--surface); z-index: 1; }
.ai-drawer-logo { width: 38px; height: 38px; display: grid; place-items: center; }
.ai-drawer-logo .ai-robot-svg { width: 34px; height: 34px; }
.ai-drawer-title { font-weight: 700; }
.ai-drawer-sub { font-size: 12px; color: var(--text-faint); }
.ai-drawer-body { padding: 16px 18px; }
.ai-drawer-enter-active, .ai-drawer-leave-active { transition: opacity .2s; }
.ai-drawer-enter-active .ai-drawer, .ai-drawer-leave-active .ai-drawer { transition: transform .28s cubic-bezier(.2,.8,.2,1); }
.ai-drawer-enter-from, .ai-drawer-leave-to { opacity: 0; }
.ai-drawer-enter-from .ai-drawer, .ai-drawer-leave-to .ai-drawer { transform: translateX(100%); }

/* Panel — nagłówek statusu */
.ai-page-logo { width: 40px; height: 40px; display: grid; place-items: center; }
.ai-page-logo .ai-robot-svg { width: 38px; height: 38px; }
.ai-status-badge { width: 40px; height: 40px; border-radius: 10px; display: grid; place-items: center; font-size: 18px; background: rgba(0,0,0,.25); }
.sev-critical .ai-status-badge { color: var(--red); }
.sev-warn .ai-status-badge { color: var(--amber); }
.sev-info .ai-status-badge { color: var(--sky); }
.sev-ok .ai-status-badge { color: var(--green); }
.ai-status-title { font-weight: 700; font-size: 15px; }
.ai-status-sub { font-size: 12.5px; color: var(--text-dim); margin-top: 2px; }
.ai-count { text-align: center; padding: 10px; border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border); }
.ai-count b { display: block; font-size: 22px; font-weight: 800; font-variant-numeric: tabular-nums; }
.ai-count span { font-size: 11px; color: var(--text-faint); text-transform: uppercase; letter-spacing: .05em; }
.ai-count.red b { color: var(--red); } .ai-count.amber b { color: var(--amber); } .ai-count.sky b { color: var(--sky); }

/* ocena AI */
.ai-summary { border: 1px solid rgba(56,189,248,.25); background: var(--sky-soft); border-radius: 12px; padding: 12px 14px; margin-bottom: 14px; }
.ai-summary-head { font-size: 12px; font-weight: 700; color: var(--sky); text-transform: uppercase; letter-spacing: .05em; margin-bottom: 6px; }
.ai-summary-text { font-size: 13.5px; line-height: 1.55; color: var(--text); white-space: pre-line; }
.ai-meta { margin-top: 14px; font-size: 12px; color: var(--text-faint); }

/* Zakładki w drawerze */
.ai-tabs { display: flex; gap: 4px; padding: 8px 12px 0; border-bottom: 1px solid var(--border); position: sticky; top: 71px; background: var(--surface); z-index: 1; }
.ai-tab { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px; padding: 9px 8px;
  background: none; border: none; border-bottom: 2px solid transparent; color: var(--text-dim);
  font-size: 13px; font-weight: 600; cursor: pointer; }
.ai-tab:hover { color: var(--text); }
.ai-tab.active { color: var(--accent); border-bottom-color: var(--accent); }
.ai-tab-badge { min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px; background: var(--red); color: #fff; font-size: 10px; font-weight: 800; display: grid; place-items: center; }
.ai-drawer-body.no-pad { padding: 0; display: flex; flex-direction: column; flex: 1; min-height: 0; }

/* Czat asystenta */
.ai-chat { display: flex; flex-direction: column; height: 100%; min-height: 0; }
.ai-chat-page .ai-chat { height: 460px; }
.ai-chat-log { flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 12px; min-height: 0; }
.ai-chat-empty { margin: auto; text-align: center; color: var(--text-faint); padding: 20px; }
.ai-chat-empty > i { font-size: 30px; opacity: .5; margin-bottom: 10px; display: block; }
.ai-chat-empty > p { font-size: 13px; margin-bottom: 14px; }
.ai-chat-suggests { display: flex; flex-direction: column; gap: 7px; }
.ai-suggest { padding: 9px 12px; border-radius: 10px; border: 1px solid var(--border-strong); background: var(--surface-2);
  color: var(--text-dim); font-size: 12.5px; text-align: left; cursor: pointer; transition: all .15s; }
.ai-suggest:hover { border-color: var(--accent); color: var(--text); }
.ai-msg { display: flex; gap: 9px; align-items: flex-start; }
.ai-msg.user { flex-direction: row-reverse; }
.ai-msg-av { width: 28px; height: 28px; flex-shrink: 0; border-radius: 8px; display: grid; place-items: center; font-size: 12px; }
.ai-msg.assistant .ai-msg-av { background: var(--sky-soft); color: var(--sky); }
.ai-msg.user .ai-msg-av { background: var(--accent-soft); color: var(--accent); }
.ai-msg-bubble { max-width: 82%; padding: 9px 12px; border-radius: 12px; font-size: 13.5px; line-height: 1.5; white-space: pre-wrap; word-break: break-word; }
.ai-msg.assistant .ai-msg-bubble { background: var(--surface-2); border: 1px solid var(--border); border-top-left-radius: 3px; }
.ai-msg.user .ai-msg-bubble { background: var(--accent-soft); border: 1px solid rgba(16,185,129,.25); color: var(--text); border-top-right-radius: 3px; }
.ai-typing { display: inline-flex; gap: 4px; align-items: center; }
.ai-typing span { width: 6px; height: 6px; border-radius: 50%; background: var(--text-faint); animation: ai-type 1.2s infinite; }
.ai-typing span:nth-child(2) { animation-delay: .2s; } .ai-typing span:nth-child(3) { animation-delay: .4s; }
@keyframes ai-type { 0%,60%,100% { opacity: .3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }
.ai-chat-input { display: flex; gap: 8px; padding: 10px 12px; border-top: 1px solid var(--border); background: var(--surface); align-items: flex-end; }
.ai-chat-input textarea { flex: 1; resize: none; max-height: 120px; background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: 10px; padding: 9px 12px; color: var(--text); font: inherit; font-size: 13.5px; }
.ai-chat-input textarea:focus { outline: none; border-color: var(--accent); }

@media (max-width: 600px) { .ai-fab { right: 14px; bottom: 14px; } }

/* ── Automatyzacje: paleta klocków ────────────────────────────────────────── */
.puzzle-chip {
  display: flex; align-items: center; gap: 9px; text-align: left; width: 100%;
  padding: 8px 10px; border-radius: 9px; cursor: pointer; margin-bottom: 5px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text); transition: border-color .12s, background .12s;
}
.puzzle-chip:hover { border-color: var(--accent); background: var(--surface-3); }
.puzzle-chip:disabled { opacity: .4; cursor: not-allowed; }
.puzzle-chip i { font-size: 14px; width: 16px; flex: none; text-align: center; }
.puzzle-chip .pz-title { font-size: 12.5px; font-weight: 600; line-height: 1.25; }

/* ── Automatyzacje: scenariusz jako szyna kroków ──────────────────────────── */
.steps-rail { display: flex; flex-direction: column; }
.step-row { display: flex; gap: 12px; }
.step-row .step-rail { display: flex; flex-direction: column; align-items: center; }
.step-row .step-dot {
  width: 26px; height: 26px; border-radius: 50%; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 11.5px; font-weight: 700;
  background: var(--surface); border: 2px solid var(--border-strong); color: var(--text-dim);
}
.step-row .step-line { width: 2px; flex: 1; min-height: 10px; background: var(--border); }
.step-row:last-child .step-line { display: none; }

.step-card {
  flex: 1; min-width: 0; margin-bottom: 10px; padding: 10px 12px;
  border-radius: 10px; background: var(--surface-2); border: 1px solid var(--border);
}
.step-head { display: flex; align-items: center; gap: 8px; }
.step-head > i { font-size: 13px; width: 16px; text-align: center; flex: none; }
.step-name { font-size: 13.5px; font-weight: 600; flex: 1; min-width: 0;
             overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.step-tools { display: flex; gap: 2px; flex: none; }
.step-desc {
  font-size: 11.5px; color: var(--text-faint); margin-top: 2px; margin-left: 24px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.step-params { display: flex; flex-wrap: wrap; gap: 8px; margin: 9px 0 0 24px; }
.step-field { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1 1 170px; }
.step-field > span { font-size: 11px; color: var(--text-faint); font-weight: 500; }
.step-field.narrow { flex: 0 0 118px; }
.step-field .input, .step-field .select { padding: 7px 9px; font-size: 13px; }
.step-warn { font-size: 11.5px; color: var(--amber); margin: 7px 0 0 24px; }

/* Krok warunkowy to spinacz logiczny, nie akcja — jest lżejszy wizualnie */
.step-row.is-logic .step-card { background: transparent; border-style: dashed; }
.step-row.is-logic .step-dot { border-style: dashed; }
.step-row.is-invalid .step-card { border-color: rgba(251,191,36,.45); }
.step-row.is-invalid .step-dot { border-color: var(--amber); color: var(--amber); }

.puzzle-empty {
  border: 1px dashed var(--border-strong); border-radius: 12px;
  padding: 30px 18px; text-align: center; color: var(--text-faint); font-size: 13px;
}

/* ── Automatyzacje: przepisy, podsumowanie, zakładki, harmonogram ──────────── */
.tpl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: 10px; }
.tpl-card {
  text-align: left; padding: 14px; border-radius: 12px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text);
  transition: transform .12s, border-color .12s, background .12s;
}
.tpl-card:hover { transform: translateY(-2px); border-color: var(--accent); background: var(--surface-3); }
.tpl-card > i { font-size: 20px; }
.tpl-card .tpl-name { font-weight: 700; font-size: 14px; margin-top: 8px; }
.tpl-card .tpl-desc { font-size: 12px; color: var(--text-faint); margin-top: 3px; line-height: 1.45; }
.tpl-card.tpl-blank { border-style: dashed; }
.tpl-card.tpl-blank > i { color: var(--text-faint); }

.auto-summary {
  display: flex; gap: 10px; align-items: flex-start; padding: 11px 13px; margin-bottom: 12px;
  border-radius: 10px; background: var(--accent-soft); border: 1px solid rgba(16,185,129,.25);
  color: #6ee7b7;
}
.auto-summary.warn { background: var(--amber-soft); border-color: rgba(251,191,36,.3); color: #fcd34d; }
.auto-summary > i { font-size: 15px; margin-top: 2px; }

.auto-tabs { display: flex; gap: 6px; margin: 4px 0 12px; border-bottom: 1px solid var(--border); }
.auto-tab {
  display: flex; align-items: center; gap: 7px; padding: 8px 14px; cursor: pointer;
  background: none; border: none; border-bottom: 2px solid transparent;
  color: var(--text-dim); font-size: 13.5px; font-weight: 600;
}
.auto-tab:hover { color: var(--text); }
.auto-tab.active { color: var(--accent); border-bottom-color: var(--accent); }

.when-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px; }
.when-card {
  text-align: left; padding: 11px 12px; border-radius: 10px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border-strong); color: var(--text);
}
.when-card:hover { border-color: var(--accent); }
.when-card.active { border-color: var(--accent); background: var(--accent-soft); }
.when-card > i { font-size: 15px; color: var(--text-faint); }
.when-card.active > i { color: var(--accent); }
.when-card .when-name { font-weight: 600; font-size: 13px; margin-top: 6px; }
.when-card .when-desc { font-size: 11.5px; color: var(--text-faint); margin-top: 2px; line-height: 1.4; }

.select.is-missing, .input.is-missing { border-color: rgba(251,191,36,.55); }
@media (max-width: 720px) {
  .auto-row { flex-direction: column; align-items: stretch; }
}

/* ── Stylizacja Modala, Animacji i Kart Aplikacji Docker ────────────────────── */
@keyframes catPillGlow {
  0% { box-shadow: 0 2px 10px rgba(16, 185, 129, 0.4); }
  100% { box-shadow: 0 4px 20px rgba(16, 185, 129, 0.75), 0 0 12px rgba(52, 211, 153, 0.5); }
}

@keyframes cardPopIn {
  0% { opacity: 0; transform: translateY(14px) scale(0.96); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* ── Clean Step Badges & Form Grid ─────────────────────────────────────────── */
.f-label-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
}
.f-label-bold {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 0 !important;
}
.step-badge {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  background: rgba(16, 185, 129, 0.14);
  border: 1px solid rgba(16, 185, 129, 0.35);
  color: #10b981;
  font-size: 11px;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.f-grid-2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 12px;
  align-items: start;
}
.f-col {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.category-pills-wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 4px 0 10px;
  margin-bottom: 12px;
}

.cat-pill {
  padding: 6px 14px;
  border-radius: 20px;
  font-size: 12px;
  font-weight: 600;
  background: var(--surface-2);
  color: var(--text-dim);
  border: 1px solid var(--border);
  white-space: nowrap;
  cursor: pointer;
  transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.cat-pill:hover {
  background: var(--surface-3);
  color: var(--text);
  transform: translateY(-2px) scale(1.04);
  border-color: rgba(255, 255, 255, 0.2);
}

.cat-pill.active {
  background: linear-gradient(135deg, #10b981 0%, #059669 100%);
  color: #0c0f15;
  border-color: #34d399;
  font-weight: 700;
  transform: translateY(-1px) scale(1.03);
  animation: catPillGlow 2.5s ease-in-out infinite alternate;
}

.app-stack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 10px;
  max-height: 330px;
  overflow-y: auto;
  padding: 4px 4px 6px 2px;
}
.app-stack-grid::-webkit-scrollbar {
  width: 5px;
}
.app-stack-grid::-webkit-scrollbar-thumb {
  background: rgba(255, 255, 255, 0.15);
  border-radius: 4px;
}

.app-stack-card {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 13px 15px;
  border-radius: 14px;
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
  animation: cardPopIn 0.3s cubic-bezier(0.16, 1, 0.3, 1) ease-out;
}

.app-stack-card::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: radial-gradient(circle at 10% 10%, rgba(255, 255, 255, 0.08), transparent 60%);
  opacity: 0;
  transition: opacity 0.3s ease;
}

.app-stack-card:hover {
  border-color: rgba(16, 185, 129, 0.5);
  transform: translateY(-3px) scale(1.015);
  background: var(--surface-3);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4), 0 0 15px rgba(16, 185, 129, 0.15);
}

.app-stack-card:hover::before {
  opacity: 1;
}

.app-stack-card:hover .app-card-icon {
  transform: scale(1.1) rotate(4deg);
}

.app-stack-card.selected {
  border-color: var(--accent);
  background: linear-gradient(135deg, rgba(16, 185, 129, 0.14) 0%, rgba(16, 185, 129, 0.03) 100%);
  box-shadow: 0 0 20px rgba(16, 185, 129, 0.3), inset 0 0 12px rgba(16, 185, 129, 0.08);
}

.app-card-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.app-card-icon.icon-sky { background: rgba(56, 189, 248, 0.14); color: #38bdf8; border-color: rgba(56, 189, 248, 0.28); }
.app-card-icon.icon-emerald { background: rgba(16, 185, 129, 0.14); color: #10b981; border-color: rgba(16, 185, 129, 0.28); }
.app-card-icon.icon-amber { background: rgba(251, 191, 36, 0.14); color: #fbbf24; border-color: rgba(251, 191, 36, 0.28); }
.app-card-icon.icon-rose { background: rgba(244, 63, 94, 0.14); color: #f43f5e; border-color: rgba(244, 63, 94, 0.28); }
.app-card-icon.icon-blue { background: rgba(59, 130, 246, 0.14); color: #3b82f6; border-color: rgba(59, 130, 246, 0.28); }
.app-card-icon.icon-purple { background: rgba(167, 139, 250, 0.14); color: #a78bfa; border-color: rgba(167, 139, 250, 0.28); }
.app-card-icon.icon-indigo { background: rgba(99, 102, 241, 0.14); color: #6366f1; border-color: rgba(99, 102, 241, 0.28); }
.app-card-icon.icon-green { background: rgba(34, 197, 94, 0.14); color: #22c55e; border-color: rgba(34, 197, 94, 0.28); }
.app-card-icon.icon-slate { background: rgba(148, 163, 184, 0.14); color: #94a3b8; border-color: rgba(148, 163, 184, 0.28); }

/* ── Kafelki Wyboru Wariantu Instalacji (Nowa Maszyna / Modal) ─────────────── */
.install-mode-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px;
  margin-bottom: 14px;
}

.install-mode-card {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 14px;
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  cursor: pointer;
  position: relative;
  overflow: hidden;
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.install-mode-card:hover {
  border-color: rgba(255, 255, 255, 0.2);
  transform: translateY(-2px);
  background: var(--surface-3);
}

.install-mode-card.selected {
  border-color: var(--accent);
  background: linear-gradient(135deg, rgba(16, 185, 129, 0.12) 0%, rgba(16, 185, 129, 0.02) 100%);
  box-shadow: 0 0 18px rgba(16, 185, 129, 0.25);
}

.install-mode-card.selected.standard {
  border-color: var(--sky);
  background: linear-gradient(135deg, rgba(56, 189, 248, 0.12) 0%, rgba(56, 189, 248, 0.02) 100%);
  box-shadow: 0 0 18px rgba(56, 189, 248, 0.25);
}

.mode-card-icon {
  width: 46px;
  height: 46px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  flex-shrink: 0;
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.1);
  transition: transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.install-mode-card:hover .mode-card-icon {
  transform: scale(1.1) rotate(5deg);
}

.mode-card-icon.emerald {
  background: rgba(16, 185, 129, 0.14);
  color: #10b981;
  border-color: rgba(16, 185, 129, 0.3);
}

.mode-card-icon.sky {
  background: rgba(56, 189, 248, 0.14);
  color: #38bdf8;
  border-color: rgba(56, 189, 248, 0.3);
}

/* ── Custom Machine Picker Grid & Upgrade Banner ────────────────────────────── */
.machine-picker-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(235px, 1fr));
  gap: 10px;
  margin-top: 6px;
  margin-bottom: 14px;
}

.machine-picker-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px;
  border-radius: 14px;
  background: var(--surface-2);
  border: 1.5px solid var(--border);
  cursor: pointer;
  transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
  position: relative;
  user-select: none;
}

.machine-picker-card:hover {
  border-color: rgba(16, 185, 129, 0.4);
  background: var(--surface-3);
  transform: translateY(-2px);
}

.machine-picker-card.selected {
  border-color: var(--accent);
  background: linear-gradient(135deg, rgba(16, 185, 129, 0.12) 0%, rgba(16, 185, 129, 0.02) 100%);
  box-shadow: 0 0 16px rgba(16, 185, 129, 0.25), inset 0 0 8px rgba(16, 185, 129, 0.08);
}

.machine-picker-card .mp-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.machine-picker-card .mp-title {
  display: flex;
  align-items: center;
  gap: 7px;
  font-weight: 600;
  font-size: 13.5px;
  color: var(--text);
  min-width: 0;
}

.machine-picker-card .mp-ip {
  font-size: 11px;
  color: var(--text-faint);
  font-family: var(--font-mono);
}

/* ── Przełącznik platform (Linux, macOS, Windows) ── */
.os-pills {
  display: inline-flex;
  gap: 6px;
  background: rgba(15, 23, 42, 0.65);
  padding: 4px;
  border-radius: 10px;
  border: 1px solid var(--border, rgba(255, 255, 255, 0.1));
}
.os-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 6px 14px;
  border-radius: 7px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text-dim, #94a3b8);
  background: transparent;
  border: none;
  cursor: pointer;
  transition: all 0.2s cubic-bezier(0.2, 0, 0, 1);
}
.os-pill i {
  font-size: 14px;
}
.os-pill:hover {
  color: var(--text, #f8fafc);
  background: rgba(255, 255, 255, 0.06);
}
.os-pill.active {
  color: #fff;
  background: var(--primary, #0284c7);
  box-shadow: 0 2px 10px rgba(2, 132, 199, 0.35);
}

.upgrade-banner-card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 13px 16px;
  border-radius: 14px;
  background: linear-gradient(135deg, rgba(245, 158, 11, 0.14) 0%, rgba(245, 158, 11, 0.04) 100%);
  border: 1.5px solid rgba(245, 158, 11, 0.35);
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25), 0 0 15px rgba(245, 158, 11, 0.1);
  margin-bottom: 14px;
  animation: cardPopIn 0.3s cubic-bezier(0.16, 1, 0.3, 1) ease-out;
}

.upgrade-banner-card .ub-title {
  font-weight: 600;
  font-size: 13px;
  color: #fef08a;
  display: flex;
  align-items: center;
  gap: 6px;
}

.upgrade-banner-card .ub-desc {
  font-size: 12px;
  color: rgba(254, 240, 138, 0.85);
  margin-top: 3px;
  line-height: 1.35;
}

.btn-upgrade-gradient {
  background: linear-gradient(135deg, #f59e0b 0%, #d97706 100%);
  color: #0c0f15;
  font-weight: 700;
  border: none;
  padding: 8px 16px;
  border-radius: 9px;
  font-size: 12px;
  cursor: pointer;
  transition: all 0.22s cubic-bezier(0.34, 1.56, 0.64, 1);
  box-shadow: 0 3px 12px rgba(245, 158, 11, 0.35);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
}

.btn-upgrade-gradient:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 6px 20px rgba(245, 158, 11, 0.55);
  background: linear-gradient(135deg, #fbbf24 0%, #f59e0b 100%);
}




/* Pasek nieokreślonego postępu — instalacja stosu na węźle */
.meter span.indeterminate {
  display: block; height: 100%; width: 35%; border-radius: inherit;
  background: linear-gradient(90deg, transparent, var(--amber), transparent);
  animation: meter-slide 1.3s ease-in-out infinite;
}
@keyframes meter-slide {
  0%   { transform: translateX(-100%); }
  100% { transform: translateX(300%); }
}

/* Wybrany kafelek w kreatorach (aplikacja, rozmiar) */
.tpl-card.active-card { border-color: var(--accent); background: var(--accent-soft); }
.when-card.is-disabled { opacity: .45; cursor: not-allowed; }

/* Nagłówek grupy zasobów — rozdziela sprzęt klienta od serwera */
.group-head {
  display: flex; align-items: center; gap: 9px;
  padding: 10px 2px 8px; margin-top: 4px;
}
.group-head i { font-size: 14px; }
.group-head .gh-title { font-weight: 700; font-size: 14px; }
.group-head .gh-sub { font-size: 12px; color: var(--text-faint); }

/* ── Serwer lustrzany ─────────────────────────────────────────────────────── */
/* Tabela „etykieta → wartość" wewnątrz karty: bez nagłówka, ciasne wiersze */
.tbl.mini { width: 100%; }
.tbl.mini td { padding: 5px 0; border: none; font-size: 13px; vertical-align: baseline; }
.tbl.mini td:first-child { width: 46%; }
.tbl.mini td:last-child { text-align: right; }

/* Druga linia w karcie wyboru — liczba kontenerów, porty, wolumeny */
.compact-select-card .csc-meta {
  display: block;
  width: 100%;
  margin-top: 3px;
  padding-left: 26px;
  font-size: 11.5px;
  color: var(--text-faint);
  font-family: var(--mono);
}
.compact-select-card.is-disabled { opacity: .45; cursor: not-allowed; }
.compact-select-card .csc-label { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* Mniejsza plakietka do użycia wewnątrz wierszy wyboru */
.badge.sm { font-size: 10.5px; padding: 1px 7px; }

.mb-0 { margin-bottom: 0 !important; }

/* ── Drobne utilsy używane w szablonach ───────────────────────────────────── */
/* Kilka stron sięgało po nazwy w stylu Tailwinda, którego panel nie ładuje —
   klasy nic nie robiły i układ się rozjeżdżał. Definiujemy je wprost. */
.flex-1 { flex: 1 1 auto; min-width: 0; }
.flex-none { flex: 0 0 auto; }
.flex-between { display: flex; align-items: center; justify-content: space-between; }
.min-w-0 { min-width: 0; }
.text-center { text-align: center; }
.rounded { border-radius: var(--radius-sm); }
.grid-1 { grid-template-columns: 1fr; }
.gap-1\.5 { gap: 6px; }
.mt-0\.5 { margin-top: 2px; }
.ml-1 { margin-left: 6px; }
.mr-1 { margin-right: 6px; }
.p-2 { padding: 8px; }
.p-3 { padding: 12px; }
.p-4 { padding: 16px; }
.pt-3 { padding-top: 12px; }
.line-clamp-2 {
  display: -webkit-box; -webkit-line-clamp: 2; line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}
.text-sky { color: var(--sky); }
.text-emerald { color: var(--accent); }
.text-purple { color: var(--purple); }
/* Etykieta pola poza znacznikiem <label> — ten sam wygląd co .field label */
.field-label {
  display: block; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .06em;
  color: var(--text-dim); margin-bottom: 6px;
}
/* Ciaśniejszy wariant karty i tabeli — używany w modalach diagnostycznych */
.card.compact { padding: 0; }
.card.compact .card-body { padding: 12px 14px; }
.tbl.compact th, .tbl.compact td { padding: 6px 8px; }


/* ── Wiersze wyboru w oknie serwera lustrzanego ───────────────────────────── */
/* Własna struktura zamiast .csc-*, których reguły z !important przycinały
   nazwę do zera i chowały ją za wielokropkiem. */
.mir-pick {
  display: flex; align-items: flex-start; gap: 10px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 10px 12px; margin-bottom: 6px;
  cursor: pointer; transition: border-color .15s, background .15s;
}
.mir-pick:hover { border-color: var(--border-strong); background: var(--surface-3); }
.mir-pick.checked { background: rgba(16,185,129,.12); border-color: var(--accent); }
.mir-pick.is-disabled { opacity: .45; cursor: not-allowed; }
.mir-pick input { margin-top: 3px; accent-color: var(--accent); flex: 0 0 auto; }
.mir-pick .mir-body { flex: 1 1 auto; min-width: 0; }
.mir-pick .mir-name {
  display: flex; align-items: center; gap: 7px; flex-wrap: wrap;
  font-size: 13.5px; font-weight: 600;
}
.mir-pick .mir-meta {
  font-size: 11.5px; color: var(--text-faint);
  font-family: var(--mono); margin-top: 3px;
}
.mir-pick .mir-desc { font-size: 12px; color: var(--text-faint); margin-top: 3px; }
/* tytuł i opis w wierszu przełącznika muszą być osobnymi wierszami */
.checkbox-row .cb-title, .checkbox-row .cb-desc { display: block; }

/* ═══════════════════════════════════════════════════════════════════════════
   SYSTEM MONOCHROMATYCZNY
   Zasada: interfejs jest szary. Kolor niesie znaczenie — stan (zielony/
   bursztynowy/czerwony), informację (błękit) albo jedną akcję główną
   (akcent). Kolor użyty dekoracyjnie przestaje cokolwiek znaczyć.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* Skala neutralna — jedyne tło interfejsu */
  --n-0:  #0b0d11;   /* tło strony            */
  --n-1:  #12151b;   /* powierzchnia kart     */
  --n-2:  #181c24;   /* powierzchnia wyższa   */
  --n-3:  #20252f;   /* pola, wiersze hover   */
  --n-4:  #2b313d;   /* krawędzie mocne       */
  --n-line:   rgba(255,255,255,.07);
  --n-line-2: rgba(255,255,255,.13);
  --t-0: #ffffff;    /* tekst wyróżniony      */
  --t-1: #eef1f6;    /* tekst główny          */
  --t-2: #a8b1c0;    /* tekst drugorzędny     */
  --t-3: #6f7889;    /* tekst pomocniczy      */

  /* Szkło: powierzchnie budowane światłem, nie własnym kolorem. W ciemnym
     motywie to biel na małej kryciu; w jasnym musi być atrament, bo biel
     na bieli znika razem z całą kartą. */
  --glass-bg:        rgba(255,255,255,.04);
  --glass-bg-2:      rgba(255,255,255,.025);
  --glass-bg-hover:  rgba(255,255,255,.08);
  --glass-line:      rgba(255,255,255,.12);
  --glass-line-soft: rgba(255,255,255,.06);
  --glass-line-2:    rgba(255,255,255,.22);
  --glass-inset:     inset 0 1px 0 rgba(255,255,255,.08), 0 2px 6px rgba(0,0,0,.25);
  --glass-inset-2:   inset 0 1px 0 rgba(255,255,255,.05);
  --glass-inset-hi:  inset 0 1px 0 rgba(255,255,255,.15), 0 4px 10px rgba(0,0,0,.35);

  /* Rytm pionowy — jedna skala odstępów w całym panelu */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px;
  --s-4: 16px; --s-5: 24px; --s-6: 32px;

  --r-1: 8px;  --r-2: 12px; --r-3: 18px;

  /* Cienie ledwie obecne: separację robi krawędź, nie głębia */
  --sh-1: 0 1px 2px rgba(0,0,0,.4);
  --sh-2: 0 4px 16px rgba(0,0,0,.35);
}

/* ── Nagłówek widoku ─────────────────────────────────────────────────────── */
.view-head {
  display: flex; align-items: flex-start; gap: var(--s-4);
  padding-bottom: var(--s-4); margin-bottom: var(--s-5);
  border-bottom: 1px solid var(--n-line);
  flex-wrap: wrap;
}
.view-head .vh-main { flex: 1 1 320px; min-width: 0; }
.view-head h1 {
  font-size: 19px; font-weight: 650; letter-spacing: -.01em;
  color: var(--t-1); line-height: 1.3;
}
.view-head .vh-desc { font-size: 13px; color: var(--t-3); margin-top: var(--s-1); max-width: 68ch; }
.view-head .vh-actions { display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap; }

/* ── Sekcja: jednostka treści z tytułem ──────────────────────────────────── */
.sec { background: var(--n-1); border: 1px solid var(--n-line); border-radius: var(--r-2); }
.sec + .sec { margin-top: var(--s-4); }
/* Odstęp między blokami najwyższego poziomu strony. Sama reguła `.sec + .sec`
   łapała wyłącznie dwie sekcje stojące bezpośrednio obok siebie — a strony
   przeplatają .sec z .grid, .card i .metrics, więc sąsiadujące bloki stykały się
   bez przerwy (najbardziej widoczne w Analityce). Zakres ograniczony do dzieci
   korzenia widoku, żeby nie ruszać rytmu wnętrza kart. */
.content > div > :is(.sec, .grid, .card, .metrics)
  + :is(.sec, .grid, .card, .metrics) { margin-top: var(--s-4); }
.sec-head {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--n-line);
}
.sec-head .sec-title { font-size: 14px; font-weight: 600; color: var(--t-1); flex: 1 1 auto; min-width: 0; }
.sec-head .sec-sub { font-size: 12px; color: var(--t-3); font-weight: 400; margin-top: 1px; }
.sec-body { padding: var(--s-4); }
.sec-body.flush { padding: 0; }
.sec-foot {
  padding: var(--s-3) var(--s-4); border-top: 1px solid var(--n-line);
  display: flex; gap: var(--s-2); align-items: center; flex-wrap: wrap;
}

/* ── Miernik: liczba z podpisem, bez ozdób ───────────────────────────────── */
.metrics { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.metric { background: var(--n-1); border: 1px solid var(--n-line); border-radius: var(--r-2); padding: var(--s-4); }
.metric .m-label { font-size: 11.5px; color: var(--t-3); text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
.metric .m-value { font-size: 26px; font-weight: 680; color: var(--t-1); line-height: 1.15; margin-top: var(--s-2); font-variant-numeric: tabular-nums; }
.metric .m-foot { font-size: 12px; color: var(--t-3); margin-top: var(--s-1); }
/* Liczba nabiera koloru tylko wtedy, gdy coś znaczy */
.metric .m-value.is-good { color: var(--green); }
.metric .m-value.is-warn { color: var(--amber); }
.metric .m-value.is-bad  { color: var(--red); }

/* ── Lista etykieta → wartość ────────────────────────────────────────────── */
.facts { display: flex; flex-direction: column; }
.facts .fact { display: flex; align-items: baseline; gap: var(--s-3); padding: var(--s-2) 0; }
.facts .fact + .fact { border-top: 1px solid var(--n-line); }
.facts .f-key { font-size: 13px; color: var(--t-3); flex: 1 1 auto; min-width: 0; }
.facts .f-val { font-size: 13.5px; color: var(--t-1); font-weight: 550; text-align: right; font-variant-numeric: tabular-nums; }

/* ── Znacznik stanu: kropka + słowo, bez wypełnień w tle ─────────────────── */
.state { display: inline-flex; align-items: center; gap: 6px; font-size: 12.5px; color: var(--t-2); white-space: nowrap; }
.state::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: var(--t-3); flex: 0 0 auto; }
.state.ok::before   { background: var(--green); }
.state.warn::before { background: var(--amber); }
.state.bad::before  { background: var(--red); }
.state.info::before { background: var(--sky); }
.state.busy::before { background: var(--amber); animation: state-pulse 1.2s ease-in-out infinite; }
@keyframes state-pulse { 0%,100% { opacity: 1 } 50% { opacity: .3 } }

/* ── Pasek narzędzi nad tabelą ───────────────────────────────────────────── */
.toolbar { display: flex; align-items: center; gap: var(--s-2); padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--n-line); flex-wrap: wrap; }
.toolbar .tb-grow { flex: 1 1 auto; }

/* ── Tabela danych ───────────────────────────────────────────────────────── */
.dt { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.dt th {
  text-align: left; font-size: 11px; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--t-3);
  padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--n-line); white-space: nowrap;
}
.dt td { padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--n-line); color: var(--t-2); vertical-align: middle; }
.dt tbody tr:last-child td { border-bottom: none; }
.dt tbody tr:hover td { background: var(--n-2); }
.dt td.num, .dt th.num { text-align: right; font-variant-numeric: tabular-nums; }
.dt td.act { text-align: right; white-space: nowrap; }
.dt .primary-cell { color: var(--t-1); font-weight: 550; }

/* ── Komunikat: kolor tylko na lewej krawędzi ────────────────────────────── */
.note {
  display: flex; gap: var(--s-3); align-items: flex-start;
  background: var(--n-2); border: 1px solid var(--n-line);
  border-left: 3px solid var(--t-3);
  border-radius: var(--r-1); padding: var(--s-3) var(--s-4);
  font-size: 13px; color: var(--t-2); line-height: 1.5;
}
.note i { margin-top: 2px; color: var(--t-3); }
.note.ok   { border-left-color: var(--green); } .note.ok i   { color: var(--green); }
.note.warn { border-left-color: var(--amber); } .note.warn i { color: var(--amber); }
.note.bad  { border-left-color: var(--red); }   .note.bad i  { color: var(--red); }
.note.info { border-left-color: var(--sky); }   .note.info i { color: var(--sky); }
.note b { color: var(--t-1); font-weight: 600; }

/* ── Pusty widok ─────────────────────────────────────────────────────────── */
.blank { text-align: center; padding: var(--s-6) var(--s-4); }
.blank i { font-size: 26px; color: var(--n-4); }
.blank .b-title { font-size: 14.5px; font-weight: 600; color: var(--t-1); margin-top: var(--s-3); }
.blank .b-desc { font-size: 13px; color: var(--t-3); margin: var(--s-2) auto 0; max-width: 52ch; }
.blank .b-act { margin-top: var(--s-4); display: flex; gap: var(--s-2); justify-content: center; flex-wrap: wrap; }
/* Pusty stan w karcie zestawionej obok innych. Pełnowymiarowy zjadał ~200 px
   wysokości na komunikat "brak" — przy trzech takich kartach strona była samą pustką. */
.blank.compact { padding: var(--s-4) var(--s-3); }
.blank.compact i { font-size: 20px; }
.blank.compact .b-title { margin-top: var(--s-2); font-size: 13.5px; }
.blank.compact .b-desc { font-size: 12.5px; max-width: 40ch; }
.blank.compact .b-act { margin-top: var(--s-3); }

/* ── Etykieta pola i podpowiedź ──────────────────────────────────────────── */
.f-row { margin-bottom: var(--s-4); }
.f-row > label { display: block; font-size: 12.5px; font-weight: 600; color: var(--t-2); margin-bottom: 6px; }
.f-row .f-hint { font-size: 12px; color: var(--t-3); margin-top: 6px; line-height: 1.45; }

/* ═══════════════════════════════════════════════════════════════════════════
   UJEDNOLICENIE WARSTWY WSPÓLNEJ
   Reguły na końcu arkusza wygrywają — wyciszamy to, co krzyczało, nie
   przepisując całego pliku.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Powierzchnie: separację robi krawędź, nie cień */
body { background: var(--n-0); color: var(--t-1); }
.card {
  background: var(--n-1);
  border: 1px solid var(--n-line);
  border-radius: var(--r-2);
  box-shadow: none;
}
.card:hover { box-shadow: none; }
.card-header { border-bottom: 1px solid var(--n-line); }
.card-title { font-size: 14px; font-weight: 600; color: var(--t-1); }
.card-sub { font-size: 12px; color: var(--t-3); }

/* Przyciski — płaskie. Gradient i poświata robiły z każdego przycisku akcję główną. */
.btn {
  background: var(--n-2);
  border: 1px solid var(--n-line-2);
  color: var(--t-1);
  box-shadow: none;
  border-radius: var(--r-1);
  font-weight: 550;
}
.btn:hover { background: var(--n-3); border-color: var(--n-4); color: var(--t-1); }
.btn:active { box-shadow: none; transform: none; background: var(--n-3); }
.btn:disabled, .btn[disabled] { opacity: .4; cursor: not-allowed; }

/* Jedyny kolorowy przycisk w widoku: akcja główna */
.btn.primary {
  background: var(--accent); border-color: var(--accent);
  color: #04140d; box-shadow: none;
}
.btn.primary:hover { background: #13cc93; border-color: #13cc93; color: #04140d; }

/* Działania nieodwracalne — obrys, nie plama */
.btn.danger  { background: transparent; border-color: rgba(248,113,113,.45); color: #fca5a5; }
.btn.danger:hover  { background: rgba(248,113,113,.12); border-color: var(--red); color: #fecaca; }
.btn.success { background: transparent; border-color: rgba(52,211,153,.45); color: #6ee7b7; }
.btn.success:hover { background: rgba(52,211,153,.12); border-color: var(--green); color: #a7f3d0; }
.btn.ghost { background: transparent; border-color: transparent; color: var(--t-2); }
.btn.ghost:hover { background: var(--n-2); border-color: var(--n-line); color: var(--t-1); }

/* Plakietka domyślnie neutralna; kolor tylko dla stanu */
.badge {
  background: var(--n-3); border: 1px solid var(--n-line-2); color: var(--t-2);
  font-weight: 550; border-radius: 999px;
}

/* Pola formularzy — bez wciśnięcia, z czytelnym ogniskiem */
.input, .select, textarea.input {
  background: var(--n-0); border: 1px solid var(--n-line-2);
  box-shadow: none; border-radius: var(--r-1); color: var(--t-1);
}
.input:focus, .select:focus, textarea.input:focus {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); outline: none;
}
.input::placeholder { color: var(--t-3); }

/* Nawigacja i belka */
.sidebar, .topbar { background: var(--n-1); border-color: var(--n-line); }

/* Tabela zastana — ten sam rytm co nowa .dt */
.tbl th {
  background: transparent; color: var(--t-3);
  font-size: 11px; text-transform: uppercase; letter-spacing: .06em;
  border-bottom: 1px solid var(--n-line);
}
.tbl td { border-bottom: 1px solid var(--n-line); color: var(--t-2); }
.tbl tbody tr:hover td { background: var(--n-2); }

/* Tło morficzne strony — w monochromacie tylko przeszkadza */
body::before, body::after { display: none !important; }

/* kontener listy ustaleń Strażnika — nadal używany */
.ai-findings { display: flex; flex-direction: column; gap: 8px; }

/* ── Pozycjonowanie Google ─────────────────────────────────────────────────
   Lista appek jest zwykłą tabelą .dt (klikalny wiersz → podstrona appki),
   więc tutaj zostają tylko rzeczy, których panel jeszcze nie ma: wskaźnik
   postępu kropkami i pionowa lista kroków z wyjaśnieniami na podstronie. */

/* Cały wiersz prowadzi do podstrony — sama strzałka to za mały cel kliknięcia */
.gseo-row { cursor: pointer; }
.gseo-row.is-running { background: var(--sky-soft); }
/* Szewron to wyłącznie sygnał „tu się da wejść”, nie osobna akcja */
.gseo-go { color: var(--t-3); font-size: 11px; margin-left: var(--s-3); transition: transform .15s, color .15s; }
.gseo-row:hover .gseo-go { color: var(--t-1); transform: translateX(2px); }

/* Postęp pipeline'u: pięć kroków widocznych jednym rzutem oka */
.gseo-dots { display: inline-flex; align-items: center; gap: 4px; }
.gseo-dot {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--n-line); flex: 0 0 auto;
}
.gseo-dot.is-ok   { background: var(--green); }
.gseo-dot.is-warn { background: var(--amber); }
.gseo-dot.is-bad  { background: var(--red); }
.gseo-dots-label { font-size: 11.5px; color: var(--t-3); margin-left: 4px; font-variant-numeric: tabular-nums; }

.gseo-score-lg { font-size: 26px; font-weight: 680; }
.gseo-score-max { font-size: 12px; color: var(--t-3); font-weight: 400; }
.gseo-of { font-size: 15px; color: var(--t-3); font-weight: 500; }

/* Krok pipeline'u: ikona stanu + nazwa + zdanie wyjaśniające, co ten krok robi.
   Same plakietki z tooltipem nie mówiły, czego zabrakło ani po co ten krok jest. */
.gseo-step {
  display: flex; gap: var(--s-3); align-items: flex-start;
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--n-line);
}
.gseo-step:last-child { border-bottom: none; }
.gseo-step-icon { font-size: 15px; margin-top: 2px; flex: 0 0 auto; color: var(--t-3); }
.gseo-step-icon.is-ok   { color: var(--green); }
.gseo-step-icon.is-warn { color: var(--amber); }
.gseo-step-icon.is-bad  { color: var(--red); }
.gseo-step-title {
  font-size: 13.5px; font-weight: 600; color: var(--t-1);
  display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap;
}
.gseo-step-state { font-size: 12px; font-weight: 400; color: var(--t-3); }
.gseo-step-state.is-ok   { color: var(--green); }
.gseo-step-state.is-warn { color: var(--amber); }
.gseo-step-state.is-bad  { color: var(--red); }
.gseo-step-what { font-size: 12.5px; color: var(--t-3); margin-top: 3px; line-height: 1.5; }

.gseo-finding { display: flex; gap: var(--s-2); align-items: flex-start; font-size: 13.5px; line-height: 1.55; }

/* Zwijana sekcja konfiguracji — kursor musi zdradzać, że nagłówek jest klikalny */
.sec-head.is-clickable { cursor: pointer; }
.sec-head.is-clickable:hover .sec-title { color: var(--t-1); }

/* ═══════════════════════════════════════════════════════════════════════════
   TRIAŻ — pulpit odpowiada na pytanie „czy coś wymaga mojej uwagi?"
   Nie na „ile mam rzeczy". Liczniki nie mówią, co zrobić; lista spraw mówi.
   ═══════════════════════════════════════════════════════════════════════════ */
.verdict { display: flex; align-items: center; gap: var(--s-4); margin-bottom: var(--s-5); }
.verdict .v-mark {
  width: 44px; height: 44px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; font-size: 19px;
  background: var(--n-2); border: 1px solid var(--n-line-2); color: var(--t-3);
}
.verdict.is-ok   .v-mark { color: var(--green); border-color: rgba(52,211,153,.4); }
.verdict.is-warn .v-mark { color: var(--amber); border-color: rgba(251,191,36,.4); }
.verdict.is-bad  .v-mark { color: var(--red);   border-color: rgba(248,113,113,.4); }
.verdict .v-text { min-width: 0; }
.verdict .v-title { font-size: 20px; font-weight: 650; color: var(--t-1); line-height: 1.25; }
.verdict .v-sub { font-size: 13px; color: var(--t-3); margin-top: 2px; }

/* Sprawa do załatwienia: co się stało → co to znaczy → jedna akcja */
.issues { display: flex; flex-direction: column; }
.issue {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--n-line);
}
.issue:last-child { border-bottom: none; }
.issue:hover { background: var(--n-2); }
.issue .i-mark { flex: 0 0 auto; width: 18px; text-align: center; margin-top: 2px; color: var(--t-3); }
.issue.sev-bad  .i-mark { color: var(--red); }
.issue.sev-warn .i-mark { color: var(--amber); }
.issue.sev-info .i-mark { color: var(--sky); }
.issue .i-body { flex: 1 1 auto; min-width: 0; }
.issue .i-what { font-size: 13.5px; font-weight: 600; color: var(--t-1); }
.issue .i-why  { font-size: 12.5px; color: var(--t-3); margin-top: 2px; line-height: 1.45; }
.issue .i-act  { flex: 0 0 auto; display: flex; gap: var(--s-2); align-items: center; }

/* ═══════════════════════════════════════════════════════════════════════════
   TRYB JASNY
   Ta sama zasada co w ciemnym: interfejs jest szary, kolor niesie znaczenie.
   Zmieniamy WYŁĄCZNIE wartości zmiennych — żadna reguła układu nie jest
   powielana, więc oba motywy nie mogą się rozjechać.
   ═══════════════════════════════════════════════════════════════════════════ */
:root[data-theme="light"] {
  /* Skala neutralna odwrócona: papier zamiast atramentu */
  --n-0:  #f4f5f7;   /* tło strony          */
  --n-1:  #ffffff;   /* powierzchnia kart   */
  --n-2:  #f7f8fa;   /* powierzchnia wyższa */
  --n-3:  #eef0f4;   /* pola, wiersze hover */
  --n-4:  #d6dae1;   /* krawędzie mocne     */
  --n-line:   rgba(16,20,28,.10);
  --n-line-2: rgba(16,20,28,.16);
  --t-0: #05080d;    /* tekst wyróżniony    */
  --t-1: #10151d;    /* tekst główny        */
  --t-2: #48525f;    /* tekst drugorzędny   */
  --t-3: #6c7684;    /* tekst pomocniczy    */

  /* Szkło odwrócone: powierzchnia z atramentu o małej kryciu */
  --glass-bg:        rgba(16,20,28,.035);
  --glass-bg-2:      rgba(16,20,28,.022);
  --glass-bg-hover:  rgba(16,20,28,.07);
  --glass-line:      rgba(16,20,28,.12);
  --glass-line-soft: rgba(16,20,28,.07);
  --glass-line-2:    rgba(16,20,28,.20);
  --glass-inset:     0 1px 2px rgba(16,20,28,.06);
  --glass-inset-2:   none;
  --glass-inset-hi:  0 2px 6px rgba(16,20,28,.10);

  /* Zmienne zastane — stare reguły mają iść za motywem, a nie zostać w ciemności */
  --bg: #f4f5f7;
  --bg-soft: #eceef2;
  --surface: #ffffff;
  --surface-2: #f7f8fa;
  --surface-3: #eef0f4;
  --border: rgba(16,20,28,.10);
  --border-strong: rgba(16,20,28,.16);
  --text: #10151d;
  --text-dim: #48525f;
  --text-faint: #6c7684;

  /* Kolory znaczeniowe przyciemnione — na białym tle jasne odcienie znikają */
  --accent: #059669;
  --accent-strong: #047857;
  --accent-soft: rgba(5,150,105,.12);
  --green: #059669;      --green-soft:  rgba(5,150,105,.12);
  --red: #dc2626;        --red-soft:    rgba(220,38,38,.10);
  --amber: #b45309;      --amber-soft:  rgba(180,83,9,.12);
  --purple: #7c3aed;     --purple-soft: rgba(124,58,237,.10);
  --sky: #0284c7;        --sky-soft:    rgba(2,132,199,.10);
  --green-edge: rgba(5,150,105,.32);
  --amber-edge: rgba(180,83,9,.30);
  --red-edge:   rgba(220,38,38,.28);
  --sky-edge:   rgba(2,132,199,.28);

  /* Cienie ledwie obecne — na jasnym tle każdy mocniejszy wygląda jak brud */
  --sh-1: 0 1px 2px rgba(16,20,28,.06);
  --sh-2: 0 4px 14px rgba(16,20,28,.08);
  --neu-raised: none; --neu-raised-lg: none; --neu-raised-sm: none;
  --neu-hover: none;  --neu-pressed: none;  --neu-pressed-sm: none;
}

/* Miejsca, gdzie kolor był wpisany na sztywno pod ciemne tło */
:root[data-theme="light"] .btn:hover { color: var(--t-1); }
:root[data-theme="light"] .btn.primary { color: #fff; }
:root[data-theme="light"] .btn.primary:hover { background: var(--accent-strong); border-color: var(--accent-strong); color: #fff; }
:root[data-theme="light"] .btn.danger { color: var(--red); }
:root[data-theme="light"] .btn.danger:hover { color: var(--red); }
:root[data-theme="light"] .btn.success { color: var(--green); }
:root[data-theme="light"] .btn.success:hover { color: var(--green); }
:root[data-theme="light"] .note.ok, :root[data-theme="light"] .note.warn,
:root[data-theme="light"] .note.bad, :root[data-theme="light"] .note.info { color: var(--t-2); }
:root[data-theme="light"] .log-view, :root[data-theme="light"] .code-block,
:root[data-theme="light"] pre { background: var(--n-3); color: var(--t-1); }
:root[data-theme="light"] .sidebar, :root[data-theme="light"] .topbar { background: var(--n-1); }
:root[data-theme="light"] .card, :root[data-theme="light"] .sec { box-shadow: var(--sh-1); }
:root[data-theme="light"] .verdict .v-mark { background: var(--n-2); }

/* Przełącznik motywu w belce */
.theme-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 32px; height: 32px; border-radius: var(--r-1);
  background: transparent; border: 1px solid transparent;
  color: var(--t-2); cursor: pointer; transition: background .15s, color .15s, border-color .15s;
}
.theme-toggle:hover { background: var(--n-2); border-color: var(--n-line); color: var(--t-1); }

/* ═══════════════════════════════════════════════════════════════════════════
   SERWER LUSTRZANY — pipeline, wykresy, sygnalizacja stanu
   Kopiowanie dużego stosu trwa minutami. Widok bez ruchu wyglądał jak
   zawieszony, dlatego każdy trwający etap ma tu własną, wyraźną sygnalizację.
   ═══════════════════════════════════════════════════════════════════════════ */

.chart-wrap { position: relative; width: 100%; }

/* ── Znacznik „na żywo" ──────────────────────────────────────────────────── */
.mir-live {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; color: var(--t-2);
  padding: 4px 10px; border-radius: 999px;
  background: var(--green-soft); border: 1px solid var(--green-edge);
}
.mir-live-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--green);
  animation: mir-blink 1.4s ease-in-out infinite;
}
@keyframes mir-blink { 0%, 100% { opacity: 1; } 50% { opacity: .25; } }

/* Liczba wjeżdża po odświeżeniu — widać, że wskaźnik żyje, a nie zastygł */
.mir-pop { animation: mir-pop .45s cubic-bezier(.2,.9,.3,1.3); }
@keyframes mir-pop {
  from { opacity: 0; transform: translateY(6px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

/* ── Pipeline etapów kopiowania ──────────────────────────────────────────── */
.mir-pipe { display: flex; align-items: flex-start; gap: 0; }
.mir-stage { flex: 1 1 0; position: relative; text-align: center; min-width: 0; }
.mir-stage-dot {
  width: 30px; height: 30px; margin: 0 auto 6px;
  border-radius: 50%; display: grid; place-items: center;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  color: var(--t-3); font-size: 12px;
  transition: background .3s, border-color .3s, color .3s, box-shadow .3s;
}
.mir-stage-label {
  font-size: 11px; color: var(--t-3); line-height: 1.25;
  padding: 0 4px; overflow-wrap: anywhere;
}
.mir-stage.is-done .mir-stage-dot {
  background: var(--green-soft); border-color: var(--green-edge); color: var(--green);
}
.mir-stage.is-done .mir-stage-label { color: var(--t-2); }
.mir-stage.is-current .mir-stage-dot {
  background: var(--sky-soft); border-color: var(--sky); color: var(--sky);
  animation: mir-ring 1.5s ease-out infinite;
}
.mir-stage.is-current .mir-stage-label { color: var(--sky); font-weight: 600; }
.mir-stage.is-error .mir-stage-dot {
  background: var(--red-soft); border-color: var(--red); color: var(--red);
  animation: mir-shake .5s ease-in-out;
}
.mir-stage.is-error .mir-stage-label { color: var(--red); }
@keyframes mir-ring {
  0%   { box-shadow: 0 0 0 0 rgba(56,189,248,.45); }
  70%  { box-shadow: 0 0 0 9px rgba(56,189,248,0); }
  100% { box-shadow: 0 0 0 0 rgba(56,189,248,0); }
}
@keyframes mir-shake {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-3px); }
  75% { transform: translateX(3px); }
}

/* Łącznik między etapami; w trakcie pracy płynie w stronę celu */
.mir-stage-link {
  position: absolute; top: 14px;
  left: calc(50% + 20px); right: calc(-50% + 20px);
  height: 2px; background: var(--border-strong); border-radius: 2px; overflow: hidden;
}
.mir-stage.is-done .mir-stage-link { background: var(--green-edge); }
.mir-stage-flow { display: block; height: 100%; width: 100%; }
.mir-pipe.is-running .mir-stage.is-current .mir-stage-flow {
  background: linear-gradient(90deg, transparent, var(--sky), transparent);
  background-size: 60% 100%; background-repeat: no-repeat;
  animation: mir-flow 1.1s linear infinite;
}
@keyframes mir-flow {
  from { background-position: -60% 0; }
  to   { background-position: 160% 0; }
}

/* ── Karta lustra ────────────────────────────────────────────────────────── */
.mir-card { position: relative; overflow: hidden; }
.mir-card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: transparent; transition: background .3s;
}
.mir-card.is-syncing::before {
  background: linear-gradient(90deg, transparent, var(--sky), transparent);
  background-size: 40% 100%; background-repeat: no-repeat;
  animation: mir-flow 1.4s linear infinite;
}
.mir-card.is-live::before { background: var(--amber); animation: mir-blink 2s ease-in-out infinite; }
.mir-card.is-error::before { background: var(--red); }

/* ── Świeżość kopii ──────────────────────────────────────────────────────── */
.mir-rpo-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s-3); }
.mir-rpo-head .f-val.is-good { color: var(--green); }
.mir-rpo-head .f-val.is-warn { color: var(--amber); }
.mir-rpo-head .f-val.is-bad  { color: var(--red); }
.mir-rpo-bar {
  margin-top: 6px; height: 6px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border-strong); overflow: hidden;
}
.mir-rpo-fill {
  display: block; height: 100%; border-radius: 999px;
  transition: width .6s cubic-bezier(.3,.8,.4,1);
  background: var(--green);
}
.mir-rpo-fill.is-warn { background: var(--amber); }
.mir-rpo-fill.is-bad  { background: var(--red); }
.mir-rpo-foot {
  display: flex; justify-content: space-between; gap: var(--s-3);
  margin-top: 5px; font-size: 11.5px; color: var(--t-3);
}

/* ── Sparkline przebiegu kopiowania ──────────────────────────────────────── */
.mir-spark { margin-top: var(--s-3); height: 46px; }
.mir-spark svg { width: 100%; height: 100%; display: block; }
.mir-spark-line { stroke-dasharray: 1000; animation: mir-draw 1.2s ease-out forwards; }
@keyframes mir-draw { from { stroke-dashoffset: 1000; } to { stroke-dashoffset: 0; } }
.mir-dot-ok  { fill: var(--sky); }
.mir-dot-bad { fill: var(--red); }

/* ── Trend rozmiaru kopii ────────────────────────────────────────────────── */
/* ── Mini-wykresy metryk węzła w liście maszyn ───────────────────────────── */
.ld-spark { display: inline-flex; align-items: center; gap: 8px; }
.ld-spark svg { width: 72px; height: 24px; display: block; flex: none; }
/* Pojedyncza próbka: kropka zamiast wykresu — linia z jednego punktu nie istnieje. */
.ld-spark-dot { width: 6px; height: 6px; border-radius: 50%; flex: none; margin-left: 33px; }
.ld-spark.is-flat { min-width: 0; }
.ld-spark-val {
  font-size: 12.5px; font-weight: 600; color: var(--t-1);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.ld-spark-val.is-warn  { color: var(--amber); }
.ld-spark-val.is-bad   { color: var(--red); }
.ld-spark-val.is-empty { color: var(--t-3); font-weight: 400; }

/* Kolumny metryk trzymają stałą szerokość, żeby wykresy w sąsiednich wierszach
   startowały w tym samym miejscu — inaczej oko nie może ich porównać. */
.dt td.cel-metryka, .dt th.cel-metryka { width: 132px; }
.dt td.cel-metryka { padding-top: 6px; padding-bottom: 6px; }
.cel-system { white-space: nowrap; }
.cel-system .badge { margin-right: 4px; }
.cel-system .badge + .badge { margin-top: 4px; }

.mir-trend { font-size: 11px; margin-left: 6px; }
.mir-trend.up   { color: var(--amber); }
.mir-trend.down { color: var(--green); }

/* Ruch bywa przeszkodą — przy tym ustawieniu zostaje sam stan, bez animacji */
@media (prefers-reduced-motion: reduce) {
  .mir-live-dot, .mir-pop, .mir-stage.is-current .mir-stage-dot,
  .mir-stage.is-error .mir-stage-dot, .mir-pipe.is-running .mir-stage.is-current .mir-stage-flow,
  .mir-card.is-syncing::before, .mir-card.is-live::before, .mir-spark-line {
    animation: none;
  }
  .mir-spark-line { stroke-dasharray: none; }
}

/* ── Odzyskanie danych z kopii ────────────────────────────────────────────
   Kopiowanie idzie tylko w stronę maszyna → kopia. Gdy kopia obsługuje ruch,
   nowe dane istnieją wyłącznie na niej — ta sekcja jest jedyną drogą powrotną,
   więc musi się rzucać w oczy mocniej niż zwykła notka. */
.mir-back {
  border: 1px solid var(--amber-edge); border-radius: var(--r-2);
  background: var(--amber-soft); padding: var(--s-3);
}
.mir-back-head { display: flex; align-items: flex-start; gap: var(--s-3); }
.mir-back-head b { color: var(--t-1); font-size: 13.5px; }
/* Strzałka wraca w lewo — kierunek przenoszenia danych widać, zanim się czyta */
.mir-back-arrow {
  color: var(--amber); font-size: 15px; margin-top: 2px;
  animation: mir-back-slide 1.8s ease-in-out infinite;
}
@keyframes mir-back-slide {
  0%, 100% { transform: translateX(0); opacity: .9; }
  50%      { transform: translateX(-4px); opacity: 1; }
}
.mir-back.is-busy { border-color: var(--sky); }
.mir-back-progress {
  display: flex; align-items: center; gap: var(--s-2);
  margin-top: var(--s-2); font-size: 12.5px; color: var(--sky);
}
.mir-back-ready {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-3); flex-wrap: wrap;
  animation: mir-pop .4s cubic-bezier(.2,.9,.3,1.3);
}
.mir-back-act { display: flex; gap: var(--s-2); flex-wrap: wrap; }

@media (prefers-reduced-motion: reduce) {
  .mir-back-arrow, .mir-back-ready { animation: none; }
}

/* ── Zwarta karta lustra: komunikat w jednej linii, fakty jako kafelki ─────
   Trzy akapity prozy i pionowa lista klucz-wartość rozciągały kartę na dwa
   ekrany. Treść nie zniknęła — przeniosła się do popupu i tooltipów. */
.mir-msg {
  display: flex; align-items: center; gap: var(--s-2);
  padding: 8px 10px; border-radius: var(--r-1);
  font-size: 12.5px; line-height: 1.35;
  background: var(--surface-2); border: 1px solid var(--border-strong);
}
.mir-msg > i { flex: 0 0 auto; }
.mir-msg.is-warn { background: var(--amber-soft); border-color: var(--amber-edge); color: var(--amber); }
.mir-msg.is-bad  { background: var(--red-soft);   border-color: var(--red-edge); color: var(--red); }
.mir-msg.is-info { background: var(--sky-soft);   border-color: var(--sky-edge); color: var(--sky); }
.mir-msg .btn.ghost { color: inherit; opacity: .75; }
.mir-msg .btn.ghost:hover { opacity: 1; }

/* Sekcja powrotu danych zwinięta do jednego wiersza */
.mir-back { display: flex; align-items: center; gap: var(--s-3); }
.mir-back b { font-size: 13px; }
.mir-back-age {
  margin-left: 6px; font-size: 11px; color: var(--t-3);
  padding: 1px 7px; border-radius: 999px; background: var(--surface-2);
}

.mir-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.mir-chip {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12px; color: var(--t-2); white-space: nowrap;
  padding: 4px 9px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  transition: border-color .2s, color .2s, transform .2s;
}
.mir-chip:hover { border-color: var(--sky); color: var(--t-1); transform: translateY(-1px); }
.mir-chip > i { color: var(--t-3); font-size: 11px; }
.mir-chip.is-warn { border-color: var(--amber-edge); color: var(--amber); }
.mir-chip.is-warn > i { color: var(--amber); }
.mir-chip.is-bad { border-color: rgba(248,113,113,.35); color: var(--red); }
.mir-chip.is-bad > i { color: var(--red); }
.mir-chip-warn { color: var(--amber); }

@media (prefers-reduced-motion: reduce) { .mir-chip:hover { transform: none; } }

/* ── Kontenery pogrupowane w stosy (widok Serwer) ─────────────────────────
   Płaska lista kilkudziesięciu kontenerów nie odpowiadała na pytanie „co z czym
   działa". Stos zwija się do jednego wiersza z podsumowaniem; rozwinięte są
   domyślnie tylko te, w których coś nie działa. */
.stacks { display: flex; flex-direction: column; }
.stack + .stack { border-top: 1px solid var(--n-line); }
.stack-head {
  width: 100%; display: flex; align-items: center; gap: var(--s-2);
  padding: 10px var(--s-4); background: none; border: 0; cursor: pointer;
  color: var(--t-1); font: inherit; text-align: left;
  transition: background .15s;
}
.stack-head:hover { background: var(--surface-2); }
.stack-caret { color: var(--t-3); width: 10px; font-size: 11px; transition: transform .2s; }
.stack-icon { color: var(--sky); font-size: 13px; }
.stack.is-down .stack-icon { color: var(--amber); }
.stack-name { font-size: 13px; font-weight: 600; }
.stack-meta {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 12px; color: var(--t-3); white-space: nowrap; margin-left: var(--s-3);
}
.stack-meta > i { font-size: 10.5px; }
.stack-meta.is-bad { color: var(--amber); }
.stack-body { animation: stack-open .22s ease-out; }
@keyframes stack-open {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) { .stack-body { animation: none; } }

/* ── Karta Lustra i Nowy 2-Wierszowy Nagłówek (Odporny na długie nazwy) ── */
.mir-card {
  display: flex !important;
  flex-direction: column !important;
  height: 100% !important;
}

.mir-card-head {
  display: flex !important;
  flex-direction: column !important;
  gap: 8px !important;
  padding: 14px 16px 10px !important;
  border-bottom: 1px solid var(--glass-line-soft) !important;
}

.mir-head-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
}

.mir-title-box {
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  flex: 1 1 auto;
}

.mir-card-title {
  font-size: 15px;
  font-weight: 700;
  color: var(--t-0, #ffffff);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.2;
}

.mir-badges-box {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 0 0 auto;
}

.mir-head-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--t-3, #64748b);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  line-height: 1.3;
}

.mir-sub-link {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--t-2, #94a3b8);
  font-weight: 500;
  text-decoration: none;
}
.mir-sub-link:hover {
  color: var(--t-0, #ffffff);
}

.mir-sub-dot {
  color: var(--t-3, #475569);
}

.mir-sub-domain {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--sky, #38bdf8);
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.mir-sub-domain:hover {
  text-decoration: underline;
}

.mir-card .sec-body {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  padding: 12px 16px 14px;
}

/* ── Nowoczesny szklany licznik (Glassmorphic Countdown Timer) ────────── */
.mir-glass-timer {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px 3px 6px;
  height: 26px;
  border-radius: 9999px;
  background: var(--glass-bg);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-inset);
  color: var(--t-1, #f1f5f9);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
  user-select: none;
  cursor: default;
  transition: all 0.2s ease;
  flex: 0 0 auto;
}

.mir-glass-timer:hover {
  background: var(--glass-bg-hover);
  border-color: var(--glass-line-2);
  box-shadow: var(--glass-inset-hi);
}

.mgt-ring {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  flex: 0 0 16px;
}

.mgt-ring svg {
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.mgt-bg {
  stroke: var(--glass-line);
}

.mgt-fg {
  stroke: var(--sky, #38bdf8);
  filter: drop-shadow(0 0 2px rgba(56, 189, 248, 0.45));
  transition: stroke-dashoffset 0.8s linear, stroke 0.3s ease;
}

.mgt-content {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}

.mgt-prefix {
  font-size: 10px;
  font-weight: 500;
  color: var(--t-3);
  text-transform: lowercase;
}

.mgt-val {
  font-size: 11px;
  font-weight: 700;
  color: var(--t-0, #ffffff);
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}

/* Stan: zbliża się czas kopii (< 60s) */
.mir-glass-timer.is-soon {
  background: var(--amber-soft);
  border-color: var(--amber-edge);
  box-shadow: var(--glass-inset-2);
}
.mir-glass-timer.is-soon .mgt-fg {
  stroke: var(--amber, #f59e0b);
  filter: drop-shadow(0 0 3px rgba(245, 158, 11, 0.7));
}
.mir-glass-timer.is-soon .mgt-val {
  color: var(--amber, #f59e0b);
}
.mir-glass-timer.is-soon .mgt-prefix {
  color: var(--amber);
}

/* Stan: nadszedł czas (kopia w toku) */
.mir-glass-timer.is-due {
  background: var(--green-soft);
  border-color: var(--green-edge);
  box-shadow: var(--glass-inset-2);
}
.mir-glass-timer.is-due .mgt-fg {
  stroke: var(--green, #10b981);
  filter: drop-shadow(0 0 3px rgba(16, 185, 129, 0.7));
  animation: mir-blink 1.2s ease-in-out infinite;
}
.mir-glass-timer.is-due .mgt-val {
  color: var(--green, #10b981);
}

@media (prefers-reduced-motion: reduce) {
  .mgt-fg { transition: none; filter: none; }
  .mir-glass-timer.is-due .mgt-fg { animation: none; }
}

/* ── Nowoczesny Szklany Panel Kafelka Lustra (Glass Metrics Box) ───────── */
.mir-metric-box {
  background: var(--glass-bg-2);
  border: 1px solid var(--glass-line-soft);
  border-radius: 12px;
  padding: 12px 14px;
  box-shadow: var(--glass-inset-2);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.mir-metric-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 8px;
}

.mir-metric-title {
  font-size: 12px;
  font-weight: 600;
  color: var(--t-2, #94a3b8);
  display: flex;
  align-items: center;
}

.mir-metric-val {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.mir-facts-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px 14px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--glass-line-soft);
}

.mfg-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.mfg-item.clickable {
  cursor: pointer;
  border-radius: 6px;
  padding: 2px 4px;
  margin: -2px -4px;
  transition: background 0.15s;
}
.mfg-item.clickable:hover {
  background: var(--glass-bg-hover);
}

.mfg-lbl {
  font-size: 10px;
  font-weight: 500;
  color: var(--t-3, #64748b);
  display: flex;
  align-items: center;
  gap: 4px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

.mfg-val {
  font-size: 12px;
  font-weight: 600;
  color: var(--t-1, #e2e8f0);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.badge-mini-auto {
  display: inline-block;
  padding: 1px 4px;
  border-radius: 4px;
  font-size: 9px;
  font-weight: 700;
  background: rgba(56, 189, 248, 0.15);
  color: var(--sky, #38bdf8);
  border: 1px solid rgba(56, 189, 248, 0.3);
  margin-left: 4px;
}

.mir-extra-row {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed var(--glass-line-soft);
}

.mir-foot-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  border-top: 1px solid var(--border);
}

/* ── Jakość łącza węzła ───────────────────────────────────────────────────
   WireGuard nie podaje siły sygnału; słupki czytają wiek ostatniego
   handshake'u, bo to ta sama informacja podana szybciej niż datą. */
.sig { display: inline-flex; align-items: flex-end; gap: 2px; height: 12px; margin-left: 8px; vertical-align: middle; }
.sig i { width: 3px; border-radius: 1px; background: var(--border-strong); display: block; transition: background .3s; }
.sig i:nth-child(1) { height: 4px; }
.sig i:nth-child(2) { height: 6px; }
.sig i:nth-child(3) { height: 9px; }
.sig i:nth-child(4) { height: 12px; }
/* Kolor tylko tam, gdzie coś sygnalizuje. Zdrowe łącze jest neutralne —
   inaczej tabela świeci na zielono i oko nie ma się o co zaczepić. */
.sig.lvl-4 i.on, .sig.lvl-3 i.on { background: var(--t-2); }
.sig.lvl-2 i.on { background: var(--t-3); }
.sig.lvl-1 i.on { background: var(--amber); }
.sig.lvl-4 i:nth-child(4).on { animation: sig-live 2s ease-in-out infinite; }
@keyframes sig-live { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* Proporcja ruchu pobrane/wysłane pod liczbami transferu */
.tbar {
  display: block; height: 3px; margin-top: 4px; border-radius: 2px;
  background: var(--purple); overflow: hidden;
}
.tbar-rx { display: block; height: 100%; background: var(--sky); transition: width .5s ease; }

@media (prefers-reduced-motion: reduce) {
  .sig.lvl-4 i:nth-child(4).on { animation: none; }
  .tbar-rx { transition: none; }
}

/* ── Filtry listy jako pigułki ────────────────────────────────────────────
   Licznik przy każdym filtrze liczy się z pełnej listy, nie z przefiltrowanej,
   więc po kliknięciu widać, ile zostało po drugiej stronie. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px;
  font: inherit; font-size: 12px; color: var(--t-3); cursor: pointer;
  padding: 5px 10px; border-radius: 999px;
  background: transparent; border: 1px solid var(--border-strong);
  transition: color .15s, border-color .15s, background .15s;
}
.chip:hover { color: var(--t-1); border-color: var(--t-3); }
.chip.active { color: var(--t-1); border-color: var(--accent); background: var(--accent-soft); }
.chip > i { font-size: 11px; }
.chip-n {
  font-variant-numeric: tabular-nums; font-size: 11px;
  padding: 0 5px; border-radius: 999px; background: var(--surface-2); color: var(--t-3);
}
.chip.active .chip-n { background: rgba(255,255,255,.09); color: inherit; }

/* ── Karta aplikacji na serwerze enode ────────────────────────────────────
   Tabela miała siedem kolumn, w tym select i pięć ikon w jednej komórce —
   nie mieściła się czytelnie na żadnej szerokości. Karta pokazuje to samo
   plus zużycie względem przydziału, którego w tabeli w ogóle nie było widać. */
.capp {
  border: 1px solid var(--n-line); border-radius: var(--r-2);
  background: var(--n-1); overflow: hidden;
  transition: border-color .2s;
}
.capp:hover { border-color: var(--border-strong); }
.capp.is-off { opacity: .72; }
.capp-head {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4); border-bottom: 1px solid var(--n-line);
}
.capp-ikona { font-size: 18px; color: var(--t-3); }
.capp-name { font-size: 13.5px; font-weight: 600; }
.capp-sub { font-size: 11.5px; color: var(--t-3); }

.capp-mierniki {
  display: flex; align-items: center; gap: var(--s-4);
  padding: var(--s-4);
}
.capp-donut { position: relative; width: 56px; height: 56px; flex: 0 0 auto; text-align: center; }
.capp-donut svg { width: 44px; height: 44px; transform: rotate(-90deg); }
.capp-donut .d-bg { stroke: var(--border-strong); }
.capp-donut .d-fg { stroke: var(--t-2); transition: stroke-dashoffset .7s ease, stroke .3s; }
.capp-donut .d-fg.is-hot { stroke: var(--amber); }
.capp-donut-label {
  position: absolute; top: 0; left: 0; right: 0; height: 44px;
  display: grid; place-items: center;
  font-size: 11px; font-weight: 600; font-variant-numeric: tabular-nums; color: var(--t-1);
}
.capp-donut-cap { display: block; font-size: 10px; color: var(--t-3); letter-spacing: .04em; }
.capp-ram { flex: 1 1 auto; min-width: 0; }
.capp-ram-head {
  display: flex; justify-content: space-between; gap: var(--s-2);
  font-size: 12px; color: var(--t-2); margin-bottom: 5px;
}
.capp-ram .meter span { background: var(--t-2); }
.capp-ram .meter.is-hot span { background: var(--amber); }
.capp-ram-foot { margin-top: 5px; font-size: 11px; color: var(--t-3); display: flex; align-items: center; gap: 5px; }

.capp-adresy { padding: 0 var(--s-4) var(--s-3); display: flex; flex-direction: column; gap: 6px; }
.capp-adr {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: 12px; padding: 5px 8px; border-radius: var(--r-1);
  background: var(--surface-2); border: 1px solid var(--border-strong);
}
.capp-adr > i { color: var(--t-3); font-size: 11px; flex: 0 0 auto; }
.capp-adr .select.sm { height: 26px; font-size: 12px; padding: 0 8px; }
.capp-foot {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: var(--s-3) var(--s-4); border-top: 1px solid var(--n-line);
}

@media (prefers-reduced-motion: reduce) { .capp-donut .d-fg { transition: none; } }

/* ── Strona Agenta: macierz funkcji i oś wersji ───────────────────────────
   Agent jest jedynym kawałkiem systemu działającym na cudzym sprzęcie, więc
   musi być jasne, co potrafi i co dokłada każda wersja. */
.caps { display: grid; grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); gap: 8px; }
.cap {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: 10px 12px; border-radius: var(--r-1);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  transition: border-color .2s, transform .2s;
}
.cap:hover { border-color: var(--t-3); transform: translateY(-1px); }
.cap > i { color: var(--t-3); font-size: 14px; margin-top: 2px; width: 16px; text-align: center; }
.cap-name { font-size: 13px; font-weight: 600; color: var(--t-1); }
.cap-desc { font-size: 12px; color: var(--t-3); line-height: 1.4; margin-top: 2px; }
.cap-path {
  font-size: 10.5px; color: var(--t-3); background: var(--n-1);
  padding: 2px 6px; border-radius: 4px; border: 1px solid var(--border-strong);
  white-space: nowrap; flex: 0 0 auto;
}
.cap.is-undoc { border-color: var(--amber); }

.tl { display: flex; flex-direction: column; }
.tl-item { display: flex; gap: var(--s-3); }
.tl-rail { display: flex; flex-direction: column; align-items: center; flex: 0 0 auto; width: 16px; }
.tl-dot {
  width: 10px; height: 10px; border-radius: 50%; margin-top: 5px; flex: 0 0 auto;
  background: var(--surface-2); border: 2px solid var(--t-3);
}
.tl-dot.feat { border-color: var(--sky); }
.tl-line { flex: 1 1 auto; width: 2px; background: var(--n-line); margin: 4px 0; }
.tl-body { padding-bottom: var(--s-4); min-width: 0; }
.tl-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tl-ver { font-size: 14px; font-weight: 700; color: var(--t-1); }
.tl-title { font-size: 13px; color: var(--t-1); margin-top: 3px; }
.tl-notes { margin: 5px 0 0; padding-left: 18px; }
.tl-notes li { font-size: 12.5px; color: var(--t-3); line-height: 1.5; margin-bottom: 3px; }
.tl-item.is-current .tl-dot { background: var(--green); border-color: var(--green); }
.tl-item.is-current .tl-ver { color: var(--green); }

@media (prefers-reduced-motion: reduce) { .cap:hover { transform: none; } }

/* ── Przegląd sieci ───────────────────────────────────────────────────────
   Wyniki dopisują się po kolei, więc pasek postępu i wpadające kafelki
   pokazują, że coś się dzieje — zamiast zamrożonego ekranu na kilkanaście sekund. */
.sweep-bar { height: 4px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.sweep-fill { display: block; height: 100%; background: var(--accent); transition: width .3s ease; }
.sweep-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 6px; }
.sweep-item {
  display: flex; align-items: center; gap: var(--s-2);
  padding: 8px 10px; border-radius: var(--r-1);
  background: var(--surface-2); border: 1px solid var(--border-strong);
  animation: sweep-in .25s ease-out;
}
@keyframes sweep-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
.sweep-item > i { flex: 0 0 auto; font-size: 13px; color: var(--t-3); }
.sweep-item.is-ok > i  { color: var(--green); }
.sweep-item.is-bad     { border-color: rgba(248,113,113,.35); }
.sweep-item.is-bad > i { color: var(--red); }
.sweep-name { font-size: 12.5px; color: var(--t-1); }
.sweep-detail { font-size: 11.5px; color: var(--t-3); }
.sweep-kind {
  font-size: 10.5px; color: var(--t-3); text-transform: uppercase; letter-spacing: .04em;
  flex: 0 0 auto;
}
.sweep-podsum { font-size: 13px; color: var(--green); display: flex; align-items: center; gap: 7px; }
.sweep-podsum .is-bad { color: var(--amber); }

@media (prefers-reduced-motion: reduce) { .sweep-item { animation: none; } }

/* ── Mapa sieci (Nowoczesna topologia Cyber / Glassmorphism) ─────────────
   Brama VPN w środku, węzły na obwodzie, satelity usług i animowane strumienie WireGuard. */
.nm-root { width: 100%; }
.nm-title-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.nm-live-badge {
  display: inline-flex; align-items: center; gap: 6px;
  background: rgba(16, 185, 129, 0.12); border: 1px solid rgba(16, 185, 129, 0.35);
  color: #34d399; font-size: 10px; font-weight: 700; letter-spacing: 0.08em;
  padding: 3px 9px; border-radius: 999px; text-transform: uppercase;
}
.nm-live-dot {
  width: 6px; height: 6px; border-radius: 50%; background: #10b981;
  box-shadow: 0 0 8px #10b981; animation: nm-live-pulse 1.8s ease-in-out infinite;
}
@keyframes nm-live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.8); }
}

.nm-header-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.nm-toggles { display: flex; align-items: center; gap: 6px; }

/* Siatka metryk */
.nm-metrics-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: var(--s-3, 12px); margin-bottom: 20px;
}
.nm-metric {
  text-decoration: none; display: flex; flex-direction: column;
  padding: 12px 14px; border-radius: var(--radius-sm, 10px);
  background: var(--surface, #191d27); border: 1px solid var(--border, rgba(255,255,255,.09));
  box-shadow: var(--neu-raised-sm); transition: border-color .2s, transform .2s, box-shadow .2s;
}
.nm-metric:hover {
  border-color: var(--border-strong, rgba(255,255,255,.2));
  transform: translateY(-2px); box-shadow: var(--neu-hover);
}
.nm-metric .m-label { font-size: 11.5px; color: var(--text-faint, #828d9f); font-weight: 600; display: flex; align-items: center; gap: 6px; }
.nm-metric .m-value { font-size: 22px; font-weight: 700; color: var(--text, #f2f5fb); margin: 4px 0 2px; }
.nm-metric .m-value.is-warn { color: var(--amber, #fbbf24); }
.nm-metric .m-foot { font-size: 11px; color: var(--text-dim, #bcc5d4); display: flex; align-items: center; gap: 5px; margin-top: auto; }
.nm-metric-transfer .m-value { font-size: 18px; color: #38bdf8; }
.nm-go { font-size: 9px; margin-left: 3px; opacity: .7; transition: transform .15s; }
.nm-metric:hover .nm-go { transform: translateX(3px); }

/* Kontener sceny topologii */
.nm-topology-sec {
  background: radial-gradient(ellipse at 50% 50%, rgba(16, 185, 129, 0.05) 0%, rgba(6, 182, 212, 0.02) 40%, rgba(12, 0, 21, 0.95) 100%), var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius, 16px);
  overflow: hidden; box-shadow: 0 12px 36px rgba(0,0,0,.45);
}
.nm-stage-wrapper {
  position: relative; overflow: hidden; width: 100%;
  border-radius: var(--radius-sm);
}

/* Interaktywny Viewport z obsługą Zoom & Pan */
.nm-viewport {
  position: relative;
  width: 100%;
  height: 650px;
  min-height: 560px;
  overflow: hidden;
  cursor: grab;
  user-select: none;
}
.nm-viewport.is-dragging { cursor: grabbing; }

/* Płótno Canvas podlegające transformacjom */
.nm-canvas {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 0;
  height: 0;
  pointer-events: auto;
  transition: transform 0.05s ease-out;
}
.nm-viewport.is-dragging .nm-canvas { transition: none; }

/* Kontrolki HUD Zoom & Pan */
.nm-hud-controls {
  position: absolute;
  bottom: 16px;
  right: 16px;
  z-index: 10;
  display: flex;
  align-items: center;
  gap: 6px;
  background: rgba(18, 24, 38, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  padding: 4px 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
  pointer-events: auto;
}
.nm-hud-btn {
  width: 28px;
  height: 28px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.08);
  background: rgba(255, 255, 255, 0.05);
  color: var(--text, #f2f5fb);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  font-size: 11px;
  transition: all .15s ease;
}
.nm-hud-btn:hover {
  background: rgba(56, 189, 248, 0.2);
  border-color: rgba(56, 189, 248, 0.5);
  color: #38bdf8;
  box-shadow: 0 0 10px rgba(56, 189, 248, 0.4);
}

/* ── Tryb Pełnoekranowy (Fullscreen) dla Mapy Topologii ─────────────────── */
.nm-stage-wrapper.is-fullscreen {
  position: fixed !important;
  inset: 0 !important;
  width: 100vw !important;
  height: 100vh !important;
  z-index: 99999 !important;
  background: radial-gradient(circle at center, #0e1726 0%, #060a12 100%) !important;
  border-radius: 0 !important;
  margin: 0 !important;
  padding: 0 !important;
}
.nm-stage-wrapper.is-fullscreen .nm-viewport {
  width: 100vw !important;
  height: 100vh !important;
  min-height: 100vh !important;
  max-height: 100vh !important;
  border-radius: 0 !important;
}
.nm-stage-wrapper.is-fullscreen .nm-hud-controls {
  bottom: 24px !important;
  right: 24px !important;
  padding: 6px 14px !important;
}
.nm-fs-exit-hud {
  position: absolute;
  top: 20px;
  right: 20px;
  z-index: 100;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: rgba(15, 23, 42, 0.92);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid rgba(255, 255, 255, 0.18);
  border-radius: 999px;
  padding: 7px 16px;
  color: #f1f5f9;
  font-size: 12px;
  font-weight: 600;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.7);
  cursor: pointer;
  transition: all .2s ease;
}
.nm-fs-exit-hud:hover {
  background: rgba(239, 68, 68, 0.25);
  border-color: #ef4444;
  color: #fca5a5;
  box-shadow: 0 0 20px rgba(239, 68, 68, 0.45);
  transform: scale(1.03);
}
.nm-hud-zoom {
  font-family: var(--mono, monospace);
  font-size: 11.5px;
  font-weight: 700;
  color: #38bdf8;
  padding: 0 4px;
  min-width: 42px;
  text-align: center;
  cursor: pointer;
}
.nm-hud-zoom:hover { color: #67e8f9; text-decoration: underline; }
.nm-hud-hint {
  font-size: 10.5px;
  color: var(--text-faint, #828d9f);
  padding-left: 6px;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
  display: flex;
  align-items: center;
  gap: 4px;
}
@media (max-width: 640px) { .nm-hud-hint { display: none; } }

/* Warstwa SVG: Siatka, tunele, linie satelitów */
.nm-svg-layer {
  position: absolute;
  left: 0;
  top: 0;
  width: 2400px;
  height: 1800px;
  margin-left: -1200px;
  margin-top: -900px;
  overflow: visible;
  pointer-events: none;
  z-index: 2;
}

/* Siatka radarowa */
.nm-radar-ring {
  fill: none; stroke: rgba(56, 189, 248, 0.12); stroke-width: 1; stroke-dasharray: 4 8;
}
.nm-radar-ring.r-1 { stroke: rgba(16, 185, 129, 0.25); stroke-dasharray: 3 6; }
.nm-radar-ring.r-2 { stroke: rgba(56, 189, 248, 0.16); }
.nm-radar-ring.r-3 { stroke: rgba(167, 139, 250, 0.14); stroke-dasharray: 6 10; }
.nm-radar-ring.r-4 { stroke: rgba(255, 255, 255, 0.06); stroke-dasharray: 4 12; }
.nm-radar-axis { stroke: rgba(255, 255, 255, 0.06); stroke-width: 1; stroke-dasharray: 2 6; }
.nm-radar-axis-diag { stroke: rgba(255, 255, 255, 0.03); stroke-width: 1; stroke-dasharray: 2 8; }
.nm-radar-label {
  font-family: var(--mono, monospace); font-size: 8px; fill: rgba(255, 255, 255, 0.25);
  text-anchor: middle; letter-spacing: 0.12em; font-weight: 600;
}

/* Wiązka skanera radarowego */
.nm-radar-sweep-disc {
  fill: rgba(16, 185, 129, 0.03); stroke: rgba(16, 185, 129, 0.15);
  stroke-width: 1; stroke-dasharray: 12 280; transform-origin: 0 0;
  animation: nm-radar-spin 16s linear infinite;
}
@keyframes nm-radar-spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

/* Tunele WireGuard (Brama -> Węzły) */
.nm-tunnel-glow {
  stroke: rgba(16, 185, 129, 0.22); stroke-width: 7; stroke-linecap: round;
  filter: url(#nm-glow); transition: opacity .3s, stroke .3s, stroke-width .3s;
}
.nm-tunnel-glow.is-off { stroke: rgba(248, 113, 113, 0.15); stroke-width: 4; }
.nm-tunnel-glow.is-active { stroke: rgba(16, 185, 129, 0.55); stroke-width: 11; filter: url(#nm-glow-strong); }
.nm-tunnel-glow.is-dim { opacity: 0.06; }

.nm-tunnel-line {
  stroke: rgba(16, 185, 129, 0.75); stroke-width: 2; stroke-linecap: round;
  transition: opacity .3s, stroke .3s, stroke-width .3s;
}
.nm-tunnel-line.is-off { stroke: rgba(248, 113, 113, 0.5); stroke-width: 1.5; stroke-dasharray: 6 6; }
.nm-tunnel-line.is-warn { stroke: rgba(251, 191, 36, 0.75); stroke-width: 2; }
.nm-tunnel-line.is-active { stroke: #34d399; stroke-width: 3; filter: drop-shadow(0 0 6px #10b981); }
.nm-tunnel-line.is-dim { opacity: 0.12; }

/* Animowany przepływ pakietów */
.nm-tunnel-flow {
  stroke: #6ee7b7; stroke-width: 2.5; stroke-linecap: round;
  stroke-dasharray: 8 20; animation: nm-packet-stream 1.4s linear infinite;
  filter: drop-shadow(0 0 5px rgba(16, 185, 129, 0.85));
  transition: opacity .3s;
}
.nm-tunnel-flow.is-heavy {
  stroke: #38bdf8; stroke-dasharray: 10 16; animation-duration: 0.9s;
  filter: drop-shadow(0 0 7px rgba(56, 189, 248, 0.9));
}
.nm-tunnel-flow.is-active { stroke: #a7f3d0; stroke-width: 3.5; animation-duration: 0.8s; }
.nm-tunnel-flow.is-dim { opacity: 0.06; }

@keyframes nm-packet-stream {
  from { stroke-dashoffset: 28; }
  to { stroke-dashoffset: 0; }
}

/* Punkty kotwiczenia w tunelach */
.nm-node-anchor {
  fill: #10b981; stroke: #0c0f15; stroke-width: 2; filter: drop-shadow(0 0 4px #10b981);
  transition: all .3s;
}
.nm-node-anchor.is-off { fill: #f87171; filter: drop-shadow(0 0 4px #f87171); }
.nm-node-anchor.is-active { fill: #34d399; r: 7; filter: drop-shadow(0 0 8px #34d399); }
.nm-node-anchor.is-dim { opacity: 0.2; }
.nm-hub-anchor { fill: #10b981; stroke: #0c0f15; stroke-width: 2; filter: drop-shadow(0 0 6px #10b981); }

/* ── Laserowe Mosty Danych (Kopiowanie Luster & Migracje) ──────────────── */
.nm-sync-bridge { fill: none; }

/* 1. Kopiowanie / Synchronizacja: Szmaragdowa rurka transferu */
.nm-sync-bridge.is-syncing .nm-bridge-glow {
  stroke: rgba(16, 185, 129, 0.4); stroke-width: 14; stroke-linecap: round;
  filter: drop-shadow(0 0 12px #10b981);
}
.nm-sync-bridge.is-syncing .nm-bridge-track {
  stroke: rgba(52, 211, 153, 0.35); stroke-width: 7; stroke-linecap: round;
}
.nm-sync-bridge.is-syncing .nm-bridge-stream {
  stroke: #10b981; stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 40 25; animation: nm-laser-stream 0.9s linear infinite;
  filter: drop-shadow(0 0 6px #059669);
}
.nm-sync-bridge.is-syncing .nm-bridge-photons {
  stroke: #ffffff; stroke-width: 5.5; stroke-linecap: round;
  stroke-dasharray: 10 55; animation: nm-laser-stream 0.9s linear infinite;
  filter: drop-shadow(0 0 8px #ffffff);
}

/* 2. Przejęcie Awaryjne: Płomienna rurka z wlewającym się płynem */
.nm-sync-bridge.is-active .nm-bridge-glow {
  stroke: rgba(249, 115, 22, 0.4); stroke-width: 14; stroke-linecap: round;
  filter: drop-shadow(0 0 12px #f97316);
}
.nm-sync-bridge.is-active .nm-bridge-track {
  stroke: rgba(251, 146, 60, 0.35); stroke-width: 7; stroke-linecap: round;
}
.nm-sync-bridge.is-active .nm-bridge-stream {
  stroke: #f97316; stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 40 25; animation: nm-laser-stream 0.9s linear infinite;
  filter: drop-shadow(0 0 6px #ea580c);
}
.nm-sync-bridge.is-active .nm-bridge-photons {
  stroke: #fff7ed; stroke-width: 5.5; stroke-linecap: round;
  stroke-dasharray: 10 55; animation: nm-laser-stream 0.9s linear infinite;
  filter: drop-shadow(0 0 8px #ffedd5);
}

/* 3. Migracja Kontenerów: Fioletowo-błękitny strumień */
.nm-sync-bridge.is-migrating .nm-bridge-glow {
  stroke: rgba(192, 132, 252, 0.45); stroke-width: 12; stroke-linecap: round;
  filter: drop-shadow(0 0 12px #c084fc);
}
.nm-sync-bridge.is-migrating .nm-bridge-track {
  stroke: rgba(192, 132, 252, 0.85); stroke-width: 2.5; stroke-linecap: round;
}
.nm-sync-bridge.is-migrating .nm-bridge-stream {
  stroke: #60a5fa; stroke-width: 3.5; stroke-linecap: round;
  stroke-dasharray: 30 110; animation: nm-laser-stream 1.1s linear infinite;
  filter: drop-shadow(0 0 8px #38bdf8);
}
.nm-sync-bridge.is-migrating .nm-bridge-photons {
  stroke: #ffffff; stroke-width: 5; stroke-linecap: round;
  stroke-dasharray: 6 70; animation: nm-laser-stream 1.1s linear infinite;
}

@keyframes nm-laser-stream {
  from { stroke-dashoffset: 140; }
  to { stroke-dashoffset: 0; }
}
@keyframes nm-laser-stream-rev {
  from { stroke-dashoffset: 0; }
  to { stroke-dashoffset: 140; }
}

/* Połączenia satelitów (aplikacje, lustra) */
.nm-sat-link {
  fill: none; stroke: #38bdf8; stroke-width: 2; stroke-dasharray: 5 4; opacity: 0.65;
  transition: opacity .25s, stroke-width .25s, filter .25s;
}
.nm-sat-link.is-mirror { stroke: #c084fc; stroke-dasharray: 4 4; opacity: 0.75; }
.nm-sat-link.is-active { stroke-width: 3; opacity: 1; filter: drop-shadow(0 0 6px currentColor); }
.nm-sat-link.is-dim { opacity: 0.08; }

.nm-sat-anchor {
  fill: #38bdf8; stroke: #0c0f15; stroke-width: 1.5; transition: all .25s;
}
.nm-sat-anchor.is-mirror { fill: #c084fc; }
.nm-sat-anchor.is-active { r: 5; filter: drop-shadow(0 0 6px currentColor); }
.nm-sat-anchor.is-dim { opacity: 0.1; }

.nm-sat-dot {
  fill: #38bdf8; stroke: #0c0f15; stroke-width: 1.5; transition: all .25s;
}
.nm-sat-dot.is-mirror { fill: #c084fc; }
.nm-sat-dot.is-active { r: 4; filter: drop-shadow(0 0 6px currentColor); }
.nm-sat-dot.is-dim { opacity: 0.1; }

/* ── Centralna Brama VPN (Hub) ─────────────────────────────────────────── */
.nm-hub {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 130px; height: 130px; border-radius: 50%; z-index: 6;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: transform .25s cubic-bezier(0.2, 0, 0, 1);
}
.nm-hub:hover { transform: translate(-50%, -50%) scale(1.05); }

.nm-hub-ripple {
  position: absolute; inset: -10px; border-radius: 50%;
  border: 1px solid rgba(16, 185, 129, 0.45);
  animation: nm-hub-wave 3s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
  pointer-events: none;
}
.nm-hub-ripple.r-2 {
  inset: -24px; border-color: rgba(6, 182, 212, 0.25); animation-delay: 1.5s;
}
@keyframes nm-hub-wave {
  0%   { transform: scale(1);   opacity: 0.6; }
  50%  { transform: scale(1.3); opacity: 0.2; }
  100% { transform: scale(1.6);  opacity: 0; }
}

.nm-hub-core {
  position: relative; width: 100%; height: 100%; border-radius: 50%;
  background: rgba(15, 23, 42, 0.88);
  border: 2px solid rgba(16, 185, 129, 0.8);
  box-shadow: 0 0 24px rgba(16, 185, 129, 0.3), inset 0 0 16px rgba(16, 185, 129, 0.15);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  text-align: center; padding: 6px 8px;
  overflow: hidden;
  transition: all .3s;
}
.nm-hub-shield, .nm-hub-name, .nm-hub-ip, .nm-hub-stat {
  position: relative; z-index: 3;
}
.nm-hub-shield {
  font-size: 18px; color: #34d399; filter: drop-shadow(0 0 8px rgba(16, 185, 129, 0.6));
  margin-bottom: 2px; transition: all .3s;
}
.nm-hub-name { font-size: 13px; font-weight: 800; color: #f2f5fb; letter-spacing: 0.04em; line-height: 1.1; margin-top: 1px; }
.nm-hub-ip { font-size: 9.5px; color: #94a3b8; font-family: monospace; letter-spacing: -0.02em; line-height: 1.1; margin-top: 2px; }
.nm-hub-stat {
  margin-top: 3px;
  display: flex; align-items: center; justify-content: center;
}
.nm-hub-peers {
  font-size: 9px; font-weight: 700; color: #34d399;
  background: rgba(16, 185, 129, 0.16); padding: 1.5px 7px; border-radius: 999px;
  border: 1px solid rgba(16, 185, 129, 0.35); display: inline-flex; align-items: center; gap: 3.5px;
  white-space: nowrap;
}
.nm-hub-peers i { font-size: 8px; margin-right: 1px; }

.nm-hub-peers.is-failover {
  color: #ffedd5; background: rgba(249, 115, 22, 0.28); border-color: rgba(249, 115, 22, 0.6);
  box-shadow: 0 0 8px rgba(249, 115, 22, 0.4);
}
.nm-hub-peers.is-syncing {
  color: #6ee7b7; background: rgba(16, 185, 129, 0.28); border-color: rgba(16, 185, 129, 0.6);
  box-shadow: 0 0 8px rgba(16, 185, 129, 0.4);
}

/* ── Efekt wirującego płynu wewnątrz koła Huba ── */
.nm-hub-fluid-vortex {
  position: absolute; inset: -10%; border-radius: 50%;
  pointer-events: none; z-index: 1; opacity: 0;
  transition: opacity .4s ease;
}
.nm-hub-core.is-failover .nm-hub-fluid-vortex {
  opacity: 1;
}
.nm-hub-core.is-failover .nm-hub-fluid-vortex::before {
  content: ''; position: absolute; inset: -20%;
  background: conic-gradient(
    from 0deg,
    rgba(249, 115, 22, 0.1) 0deg,
    rgba(249, 115, 22, 0.75) 80deg,
    rgba(251, 191, 36, 0.9) 140deg,
    rgba(239, 68, 68, 0.75) 200deg,
    rgba(249, 115, 22, 0.2) 280deg,
    rgba(249, 115, 22, 0.1) 360deg
  );
  animation: nm-liquid-spin 3.5s linear infinite;
  filter: blur(12px);
}
.nm-hub-core.is-failover .nm-hub-fluid-vortex::after {
  content: ''; position: absolute; inset: 12px; border-radius: 50%;
  background: radial-gradient(
    circle at 50% 50%,
    rgba(254, 215, 170, 0.4) 0%,
    rgba(249, 115, 22, 0.25) 45%,
    rgba(15, 23, 42, 0.85) 75%
  );
  animation: nm-liquid-absorb 1.8s ease-in-out infinite alternate;
}

.nm-hub-core.is-syncing .nm-hub-fluid-vortex {
  opacity: 1;
}
.nm-hub-core.is-syncing .nm-hub-fluid-vortex::before {
  content: ''; position: absolute; inset: -20%;
  background: conic-gradient(
    from 0deg,
    rgba(16, 185, 129, 0.1) 0deg,
    rgba(16, 185, 129, 0.75) 90deg,
    rgba(52, 211, 153, 0.9) 150deg,
    rgba(6, 182, 212, 0.7) 230deg,
    rgba(16, 185, 129, 0.1) 360deg
  );
  animation: nm-liquid-spin 4s linear infinite;
  filter: blur(12px);
}

@keyframes nm-liquid-spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
@keyframes nm-liquid-absorb {
  0% { transform: scale(0.92); opacity: 0.75; }
  100% { transform: scale(1.05); opacity: 1; }
}

/* ── Hub: Przejęcie awaryjne (Failover) ── */
.nm-hub.is-failover .nm-hub-ripple.is-flame {
  border-color: rgba(249, 115, 22, 0.55);
  animation: nm-hub-wave-flame 2.2s cubic-bezier(0.2, 0.8, 0.2, 1) infinite;
}
.nm-hub.is-failover .nm-hub-ripple.is-flame.r-2 {
  border-color: rgba(239, 68, 68, 0.35);
  animation-delay: 1.1s;
}
@keyframes nm-hub-wave-flame {
  0%   { transform: scale(1);   opacity: 0.7; }
  50%  { transform: scale(1.35); opacity: 0.25; }
  100% { transform: scale(1.7);  opacity: 0; }
}

.nm-hub-core.is-failover {
  background: rgba(26, 18, 16, 0.88);
  border-color: #f97316;
  box-shadow: 0 0 32px rgba(249, 115, 22, 0.45), inset 0 0 16px rgba(239, 68, 68, 0.25);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  animation: nm-hub-flame-pulse 2.2s infinite ease-in-out;
}
.nm-hub-core.is-failover .nm-hub-shield {
  color: #fbbf24; filter: drop-shadow(0 0 8px #f97316);
}
@keyframes nm-hub-flame-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 24px rgba(249, 115, 22, 0.4); }
  50% { transform: scale(1.03); box-shadow: 0 0 36px rgba(249, 115, 22, 0.65), 0 0 12px #fbbf24; }
}

/* ── Hub: Aktywna synchronizacja ── */
.nm-hub-core.is-syncing {
  border-color: #34d399;
  box-shadow: 0 0 30px rgba(16, 185, 129, 0.5), inset 0 0 16px rgba(16, 185, 129, 0.25);
  animation: nm-hub-green-pulse 2s infinite ease-in-out;
}
@keyframes nm-hub-green-pulse {
  0%, 100% { transform: scale(1); box-shadow: 0 0 20px rgba(16, 185, 129, 0.4); }
  50% { transform: scale(1.03); box-shadow: 0 0 38px rgba(52, 211, 153, 0.75); }
}

/* ── Karty Węzłów (Maszyny w sieci WireGuard) ──────────────────────────── */
.nm-card {
  position: absolute; width: 218px; z-index: 10;
  background: rgba(16, 22, 34, 0.94);
  border: 1px solid rgba(255, 255, 255, 0.13);
  border-radius: 12px; padding: 10px 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.55), inset 0 1px 0 rgba(255,255,255,0.08);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  transition: border-color .2s, box-shadow .2s, opacity .2s;
}
.nm-card:hover, .nm-card.is-open, .nm-card.is-hovered {
  border-color: #38bdf8; z-index: 20;
  box-shadow: 0 14px 40px rgba(0,0,0,0.7), 0 0 20px rgba(56, 189, 248, 0.25), inset 0 1px 0 rgba(255,255,255,0.15);
}
.nm-card.is-off {
  border-style: dashed; border-color: rgba(248, 113, 113, 0.45); opacity: 0.8;
}
.nm-card.is-warn { border-color: rgba(251, 191, 36, 0.55); }
.nm-card.is-syncing {
  border-color: rgba(16, 185, 129, 0.75);
  box-shadow: 0 0 24px rgba(16, 185, 129, 0.35), inset 0 0 10px rgba(16, 185, 129, 0.15);
}
.nm-card.is-failover {
  border-color: rgba(249, 115, 22, 0.75);
  box-shadow: 0 0 28px rgba(249, 115, 22, 0.35), inset 0 0 10px rgba(249, 115, 22, 0.15);
}
.nm-card.is-dim { opacity: 0.18; pointer-events: none; }

.nm-sync-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 8.5px; font-weight: 800; letter-spacing: 0.05em;
  padding: 1px 6px; border-radius: 4px; flex-shrink: 0;
}
.nm-sync-badge.is-syncing {
  background: rgba(16, 185, 129, 0.25); color: #34d399; border: 1px solid #10b981;
  box-shadow: 0 0 8px rgba(16, 185, 129, 0.4);
}
.nm-sync-badge.is-failover {
  background: rgba(249, 115, 22, 0.25); color: #f97316; border: 1px solid #f97316;
  box-shadow: 0 0 8px rgba(249, 115, 22, 0.4);
}

.nm-card-head {
  display: flex; align-items: center; gap: 8px; width: 100%;
  background: none; border: 0; padding: 0; cursor: pointer; color: inherit; font: inherit; text-align: left;
}
.nm-card-device-icon {
  width: 28px; height: 28px; border-radius: 7px; background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1); display: flex; align-items: center;
  justify-content: center; font-size: 13px; color: #38bdf8; flex-shrink: 0;
  transition: all .2s;
}
.nm-status-beacon { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.nm-status-beacon.is-ok {
  background: #10b981; box-shadow: 0 0 8px #10b981; animation: nm-beacon-pulse 2s infinite;
}
.nm-status-beacon.is-bad { background: #f87171; box-shadow: 0 0 6px #f87171; }
@keyframes nm-beacon-pulse {
  0%, 100% { box-shadow: 0 0 6px #10b981; }
  50% { box-shadow: 0 0 14px #34d399, 0 0 4px #10b981; }
}

.nm-card-name { font-size: 13.5px; font-weight: 700; color: #ffffff; letter-spacing: -0.01em; }
.nm-caret { color: var(--t-3); font-size: 10px; width: 9px; transition: transform .2s; margin-left: 2px; }

.nm-card-meta {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 8px; padding-top: 7px; border-top: 1px solid rgba(255,255,255,0.08);
  font-size: 11px; color: #94a3b8;
}
.nm-card-ip { display: flex; align-items: center; gap: 4px; font-size: 11px; color: #f1f5f9; font-weight: 600; }
.nm-card-ip i { font-size: 9.5px; color: #38bdf8; }
.nm-card-traffic { display: flex; align-items: center; gap: 4px; font-size: 10.5px; color: #38bdf8; font-weight: 600; }
.nm-card-traffic i { font-size: 9px; }
.nm-card-ft { color: #a78bfa; font-size: 11px; }

.nm-sum { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 8px; cursor: pointer; }
.nm-pill {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10.5px; color: #e2e8f0; padding: 2px 8px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1);
  transition: background .15s, border-color .15s; font-weight: 500;
}
.nm-pill:hover { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.2); }
.nm-pill > i { font-size: 9.5px; color: var(--t-3); }
.nm-pill.is-empty { opacity: .4; }
.nm-pill-owner {
  margin-left: auto; background: rgba(167, 139, 250, 0.12);
  border-color: rgba(167, 139, 250, 0.3); color: #c084fc;
}

.nm-exp { display: grid; grid-template-rows: 0fr; transition: grid-template-rows .28s cubic-bezier(0.2, 0.8, 0.2, 1); }
.nm-exp.open { grid-template-rows: 1fr; }
.nm-exp-in { overflow: hidden; min-height: 0; }
.nm-grp { margin-top: 10px; }
.nm-grp-t {
  display: flex; align-items: center; gap: 6px; font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: #94a3b8; margin-bottom: 5px;
}
.nm-grp-t > i { font-size: 9px; }

.nm-app {
  display: flex; align-items: center; gap: 7px; font-size: 11.5px; color: #e2e8f0;
  text-decoration: none; padding: 5px 8px; border-radius: 6px; margin-bottom: 4px;
  background: rgba(255,255,255,0.03); border: 1px solid rgba(255,255,255,0.06);
  transition: all .15s;
}
.nm-app:hover {
  background: rgba(255,255,255,0.08); border-color: rgba(56,189,248,0.4);
  color: #38bdf8; transform: translateX(2px);
}
.nm-app > i:first-child { font-size: 10px; color: var(--t-3); flex: 0 0 auto; }
.nm-app.is-docker > i:first-child { color: var(--sky); }
.nm-app.is-bad { border-color: rgba(248,113,113,.4); }
.nm-app.is-bad > i:first-child { color: var(--red); }
.nm-app-port { font-size: 10px; color: var(--t-3); flex: 0 0 auto; }
.nm-app-shield { font-size: 9px; color: var(--sky); flex: 0 0 auto; }
.nm-mir.is-live > i:first-child { color: var(--amber); }
.nm-tun { cursor: default; }
.nm-apps-empty { font-size: 11px; color: var(--t-3); margin-top: 8px; }
.nm-open { width: 100%; justify-content: center; margin-top: 10px; font-size: 11.5px; }

/* ── Legenda ───────────────────────────────────────────────────────────── */
.nm-legend-inline { display: flex; gap: 14px; flex-wrap: wrap; font-size: 11.5px; color: var(--t-3); }
.nm-legend-inline > span { display: inline-flex; align-items: center; gap: 6px; }
.nm-key { width: 9px; height: 9px; border-radius: 50%; border: 2px solid var(--t-3); background: var(--surface-2); }
.nm-key-on { border-color: #10b981; background: #10b981; box-shadow: 0 0 6px rgba(16,185,129,.6); }
.nm-key-off { border-style: dashed; border-color: #f87171; }
.nm-key-dock { border-color: var(--sky); background: var(--sky); box-shadow: 0 0 6px rgba(56,189,248,.5); }
.nm-key-mir { border-color: var(--purple); background: var(--purple); box-shadow: 0 0 6px rgba(167,139,250,.5); }
.nm-key-stream {
  width: 14px; height: 3px; border-radius: 2px; background: #6ee7b7;
  box-shadow: 0 0 6px rgba(110,231,183,.8); border: 0;
}

@media (max-width: 820px) {
  .nm-stage { height: auto !important; min-height: 0; }
  .nm-svg-layer, .nm-hub { display: none; }
  .nm-card { position: static !important; transform: none !important; width: auto; margin-bottom: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .nm-hub-ripple { animation: none; }
  .nm-tunnel-flow { animation: none; }
  .nm-radar-sweep-disc { animation: none; }
  .nm-exp { transition: none; }
  .nm-metric:hover { transform: none; }
}

/* ── Mapa przełączenia luster (Wielostanowy most danych) ──────────────────
   Cała paleta mostu mieszka w zmiennych `--mf-*` ustawionych na .mf-list.
   Reguły niżej nie mają ani jednej wartości koloru wpisanej na sztywno, więc
   motyw jasny podmienia jeden blok wartości i układ nie może się rozjechać.
   W jasnym motywie gasną poświaty: na papierze łuna czyta się jak zabrudzenie,
   a nie jak sygnał — stan niosą tam krawędź, wypełnienie i nasycenie tekstu.
   ─────────────────────────────────────────────────────────────────────────── */
.mf-list {
  display: flex; flex-direction: column; gap: 8px;

  /* Powierzchnia wiersza i tekst */
  --mf-surface:       rgba(16, 22, 34, 0.85);
  --mf-surface-hover: rgba(16, 22, 34, 0.98);
  --mf-line:          rgba(255, 255, 255, 0.08);
  --mf-line-hover:    rgba(56, 189, 248, 0.30);
  --mf-shadow:        0 4px 20px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.05);
  --mf-shadow-hover:  0 8px 28px rgba(0, 0, 0, 0.6), 0 0 20px rgba(56, 189, 248, 0.15);
  --mf-text:          #f1f5f9;
  --mf-text-dim:      #94a3b8;

  /* Kafelek ikony węzła oraz pigułki (domena, pigułka transferu) */
  --mf-icon-bg:        rgba(255, 255, 255, 0.05);
  --mf-icon-line:      rgba(255, 255, 255, 0.12);
  --mf-chip-bg:        rgba(15, 23, 42, 0.70);
  --mf-chip-bg-strong: rgba(15, 23, 42, 0.85);
  --mf-chip-line:      rgba(255, 255, 255, 0.12);
  --mf-chip-text:      #e2e8f0;
  --mf-chip-shadow:    0 2px 8px rgba(0, 0, 0, 0.3);

  /* Tor transmisji i pakiety */
  --mf-track-bg:     rgba(255, 255, 255, 0.08);
  --mf-track-inset:  inset 0 1px 2px rgba(0, 0, 0, 0.5);
  --mf-conn-line-bg: linear-gradient(90deg, rgba(56, 189, 248, 0.2), rgba(96, 165, 250, 0.2));
  --mf-packet:       #ffffff;
  --mf-packet-sync:  #ecfdf5;
  --mf-packet-flame: #fff7ed;
  --mf-packet-glow:       0 0 8px #38bdf8, 0 0 4px #ffffff;
  --mf-packet-glow-sync:  0 0 12px #34d399, 0 0 6px #ffffff;
  --mf-packet-glow-flame: 0 0 10px #f97316, 0 0 6px #ef4444;
  --mf-progress-glow:     0 0 6px #34d399;

  /* Barwy stanu: pełna, rozjaśniona, tekstowa (na barwnym tle), wypełnienie */
  --mf-blue:        #38bdf8;
  --mf-blue-2:      #60a5fa;
  --mf-blue-text:   #7dd3fc;
  --mf-blue-fill:   rgba(56, 189, 248, 0.14);
  --mf-blue-fill-2: rgba(56, 189, 248, 0.10);
  --mf-blue-wash:   rgba(56, 189, 248, 0.04);
  --mf-blue-line:   rgba(56, 189, 248, 0.35);
  --mf-blue-line-2: rgba(56, 189, 248, 0.25);

  --mf-green:        #10b981;
  --mf-green-lit:    #34d399;
  --mf-green-text:   #6ee7b7;
  --mf-green-text-2: #a7f3d0;
  --mf-green-deep:   rgba(6, 78, 59, 0.85);
  --mf-green-fill:   rgba(16, 185, 129, 0.22);
  --mf-green-wash:   rgba(16, 185, 129, 0.10);
  --mf-green-line:   rgba(16, 185, 129, 0.50);

  --mf-amber:        #fbbf24;
  --mf-flame:        #f97316;
  --mf-flame-text:   #ffedd5;
  --mf-flame-text-2: #fed7aa;
  --mf-flame-deep:   rgba(124, 45, 18, 0.85);
  --mf-flame-fill:   rgba(249, 115, 22, 0.22);

  --mf-red:        #ef4444;
  --mf-red-lit:    #f87171;
  --mf-red-text:   #fca5a5;
  --mf-red-deep:   rgba(127, 29, 29, 0.60);
  --mf-red-fill:   rgba(239, 68, 68, 0.20);
  --mf-red-wash:   rgba(239, 68, 68, 0.08);
  --mf-red-line:   rgba(239, 68, 68, 0.60);

  /* Poświaty stanu — jedyne miejsce, gdzie „świeci" */
  --mf-glow-green-1: 0 0 10px rgba(16, 185, 129, 0.38);
  --mf-glow-green-2: 0 0 14px rgba(16, 185, 129, 0.55);
  --mf-glow-flame-1: 0 0 14px rgba(249, 115, 22, 0.50);
  --mf-glow-flame-2: 0 0 22px rgba(249, 115, 22, 0.45);
  --mf-glow-red-1:   0 0 10px rgba(248, 113, 113, 0.40);

  /* Wiersz w trakcie kopiowania / przejęcia / błędu */
  --mf-sync-bg:      rgba(6, 78, 59, 0.12);
  --mf-sync-line:    rgba(16, 185, 129, 0.65);
  --mf-sync-glow:    0 0 26px rgba(16, 185, 129, 0.25), inset 0 0 12px rgba(16, 185, 129, 0.1);
  --mf-sync-line-lo: rgba(16, 185, 129, 0.45);
  --mf-sync-line-hi: rgba(16, 185, 129, 0.85);
  --mf-sync-glow-lo: 0 0 18px rgba(16, 185, 129, 0.2);
  --mf-sync-glow-hi: 0 0 32px rgba(16, 185, 129, 0.45);

  --mf-flame-bg:      rgba(124, 45, 18, 0.12);
  --mf-flame-line:    rgba(249, 115, 22, 0.70);
  --mf-flame-glow:    0 0 32px rgba(239, 68, 68, 0.3), inset 0 0 14px rgba(249, 115, 22, 0.15);
  --mf-flame-line-lo: rgba(249, 115, 22, 0.55);
  --mf-flame-line-hi: rgba(239, 68, 68, 0.90);
  --mf-flame-glow-lo: 0 0 20px rgba(239, 68, 68, 0.25);
  --mf-flame-glow-hi: 0 0 36px rgba(249, 115, 22, 0.55);

  --mf-err-bg:   rgba(248, 113, 113, 0.08);
  --mf-err-line: rgba(248, 113, 113, 0.60);
  --mf-err-glow: 0 0 24px rgba(248, 113, 113, 0.25);

  /* Oddech etapu zrzutu / odtwarzania */
  --mf-breathe-lo: 0 0 10px rgba(16, 185, 129, 0.2);
  --mf-breathe-hi: 0 0 22px rgba(16, 185, 129, 0.6), inset 0 0 10px rgba(16, 185, 129, 0.25);
}

/* Motyw jasny: te same reguły, inne wartości. Barwy schodzą o dwa stopnie
   w dół skali (jasny błękit na bieli jest nieczytelny), a łuny gasną. */
:root[data-theme="light"] .mf-list {
  --mf-surface:       #f8fafc;
  --mf-surface-hover: #ffffff;
  --mf-line:          rgba(16, 20, 28, 0.12);
  --mf-line-hover:    rgba(2, 132, 199, 0.45);
  --mf-shadow:        0 1px 2px rgba(16, 20, 28, 0.06);
  --mf-shadow-hover:  0 2px 10px rgba(16, 20, 28, 0.10);
  --mf-text:          #10151d;
  --mf-text-dim:      #6c7684;

  --mf-icon-bg:        #eff1f5;
  --mf-icon-line:      rgba(16, 20, 28, 0.14);
  --mf-chip-bg:        #f4f6f9;
  --mf-chip-bg-strong: #eef2f7;
  --mf-chip-line:      rgba(16, 20, 28, 0.14);
  --mf-chip-text:      #38414e;
  --mf-chip-shadow:    0 1px 2px rgba(16, 20, 28, 0.05);

  --mf-track-bg:     rgba(16, 20, 28, 0.10);
  --mf-track-inset:  inset 0 1px 1px rgba(16, 20, 28, 0.08);
  --mf-conn-line-bg: linear-gradient(90deg, rgba(2, 132, 199, 0.18), rgba(37, 99, 235, 0.18));
  --mf-packet:       #0369a1;
  --mf-packet-sync:  #065f46;
  --mf-packet-flame: #9a3412;
  --mf-packet-glow:       none;
  --mf-packet-glow-sync:  none;
  --mf-packet-glow-flame: none;
  --mf-progress-glow:     none;

  --mf-blue:        #0284c7;
  --mf-blue-2:      #2563eb;
  --mf-blue-text:   #0369a1;
  --mf-blue-fill:   rgba(2, 132, 199, 0.10);
  --mf-blue-fill-2: rgba(2, 132, 199, 0.08);
  --mf-blue-wash:   rgba(2, 132, 199, 0.05);
  --mf-blue-line:   rgba(2, 132, 199, 0.32);
  --mf-blue-line-2: rgba(2, 132, 199, 0.24);

  --mf-green:        #059669;
  --mf-green-lit:    #047857;
  --mf-green-text:   #047857;
  --mf-green-text-2: #065f46;
  --mf-green-deep:   #ecfdf5;
  --mf-green-fill:   rgba(5, 150, 105, 0.12);
  --mf-green-wash:   rgba(5, 150, 105, 0.08);
  --mf-green-line:   rgba(5, 150, 105, 0.45);

  --mf-amber:        #d97706;
  --mf-flame:        #ea580c;
  --mf-flame-text:   #9a3412;
  --mf-flame-text-2: #9a3412;
  --mf-flame-deep:   #fff7ed;
  --mf-flame-fill:   rgba(234, 88, 12, 0.12);

  --mf-red:        #dc2626;
  --mf-red-lit:    #dc2626;
  --mf-red-text:   #b91c1c;
  --mf-red-deep:   #fef2f2;
  --mf-red-fill:   rgba(220, 38, 38, 0.10);
  --mf-red-wash:   rgba(220, 38, 38, 0.06);
  --mf-red-line:   rgba(220, 38, 38, 0.45);

  --mf-glow-green-1: none;
  --mf-glow-green-2: none;
  --mf-glow-flame-1: none;
  --mf-glow-flame-2: none;
  --mf-glow-red-1:   none;

  --mf-sync-bg:      rgba(5, 150, 105, 0.07);
  --mf-sync-line:    rgba(5, 150, 105, 0.55);
  --mf-sync-glow:    0 1px 2px rgba(16, 20, 28, 0.06);
  --mf-sync-line-lo: rgba(5, 150, 105, 0.35);
  --mf-sync-line-hi: rgba(5, 150, 105, 0.85);
  --mf-sync-glow-lo: 0 1px 2px rgba(16, 20, 28, 0.06);
  --mf-sync-glow-hi: 0 0 0 3px rgba(5, 150, 105, 0.12);

  --mf-flame-bg:      rgba(234, 88, 12, 0.07);
  --mf-flame-line:    rgba(234, 88, 12, 0.55);
  --mf-flame-glow:    0 1px 2px rgba(16, 20, 28, 0.06);
  --mf-flame-line-lo: rgba(234, 88, 12, 0.40);
  --mf-flame-line-hi: rgba(220, 38, 38, 0.85);
  --mf-flame-glow-lo: 0 1px 2px rgba(16, 20, 28, 0.06);
  --mf-flame-glow-hi: 0 0 0 3px rgba(234, 88, 12, 0.14);

  --mf-err-bg:   rgba(220, 38, 38, 0.06);
  --mf-err-line: rgba(220, 38, 38, 0.45);
  --mf-err-glow: 0 1px 2px rgba(16, 20, 28, 0.06);

  --mf-breathe-lo: 0 1px 2px rgba(16, 20, 28, 0.06);
  --mf-breathe-hi: 0 0 0 3px rgba(5, 150, 105, 0.14);
}

.mf-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 6px 14px; border-radius: 10px;
  background: var(--mf-surface);
  border: 1px solid var(--mf-line);
  box-shadow: var(--mf-shadow);
  transition: all .25s cubic-bezier(0.2, 0.8, 0.2, 1);
  position: relative; overflow: hidden;
}
.mf-row:hover {
  background: var(--mf-surface-hover);
  border-color: var(--mf-line-hover);
  box-shadow: var(--mf-shadow-hover);
}

/* ── Stan 1: BEZCZYNNA / STANDBY (Niebieski) ──────────────────────────── */
.mf-row.is-state-standby {
  border-color: var(--mf-blue-line-2);
}

/* ── Stan 2: KOPIOWANIE (Zielony) ────────────────────────────────────── */
.mf-row.is-state-syncing {
  border-color: var(--mf-sync-line);
  background: var(--mf-sync-bg);
  box-shadow: var(--mf-sync-glow);
  animation: mf-sync-green-pulse 2s infinite ease-in-out;
}
@keyframes mf-sync-green-pulse {
  0%, 100% { border-color: var(--mf-sync-line-lo); box-shadow: var(--mf-sync-glow-lo); }
  50% { border-color: var(--mf-sync-line-hi); box-shadow: var(--mf-sync-glow-hi); }
}

/* ── Stan 3: PRZEJĘCIE / PRZYWRACANIE (Czerwono-Pomarańczowy) ─────────── */
.mf-row.is-state-active {
  border-color: var(--mf-flame-line);
  background: var(--mf-flame-bg);
  box-shadow: var(--mf-flame-glow);
  animation: mf-flame-pulse 1.8s infinite ease-in-out;
}
@keyframes mf-flame-pulse {
  0%, 100% { border-color: var(--mf-flame-line-lo); box-shadow: var(--mf-flame-glow-lo); }
  50% { border-color: var(--mf-flame-line-hi); box-shadow: var(--mf-flame-glow-hi); }
}

/* ── Stan 4: BŁĄD (Czerwony) ─────────────────────────────────────────── */
.mf-row.is-state-error {
  border-color: var(--mf-err-line);
  background: var(--mf-err-bg);
  box-shadow: var(--mf-err-glow);
}

/* ── Węzły po lewej i prawej ─────────────────────────────────────────── */
.mf-node {
  display: inline-flex; align-items: center; gap: 8px; flex-shrink: 0;
  padding: 3px 8px; border-radius: 8px; border: 1px solid transparent;
  transition: all .2s;
}
.mf-node.is-serving {
  border-color: var(--mf-blue-line-2);
  background: var(--mf-blue-wash);
}
.mf-row.is-state-syncing .mf-node.is-serving {
  border-color: var(--mf-green-line);
  background: var(--mf-green-wash);
}
.mf-node.is-off {
  border: 1px dashed var(--mf-red-line);
  background: var(--mf-red-wash);
  opacity: 0.85;
}
.mf-node.is-replica.is-serving {
  border-color: var(--mf-flame);
  background: var(--mf-flame-fill);
  box-shadow: var(--mf-glow-flame-2);
}

.mf-node-icon {
  width: 26px; height: 26px; border-radius: 7px; background: var(--mf-icon-bg);
  border: 1px solid var(--mf-icon-line); display: flex; align-items: center;
  justify-content: center; font-size: 11.5px; color: var(--mf-blue); flex-shrink: 0;
  transition: all .2s;
}
.mf-node-icon.is-standby {
  color: var(--mf-blue); border-color: var(--mf-blue-line); background: var(--mf-blue-fill-2);
}
.mf-node-icon.is-syncing {
  color: var(--mf-green-lit); border-color: var(--mf-green); background: var(--mf-green-fill);
  box-shadow: var(--mf-glow-green-2);
}
.mf-node-icon.is-active {
  color: var(--mf-flame); border-color: var(--mf-red); background: var(--mf-red-fill);
  box-shadow: var(--mf-glow-flame-2);
}
.mf-node-icon.is-error {
  color: var(--mf-red-lit); border-color: var(--mf-red-line); background: var(--mf-red-fill);
}
.mf-node-icon.is-mirror { color: var(--mf-blue); }
.mf-row.is-state-syncing .mf-node-icon.is-mirror { color: var(--mf-green-lit); border-color: var(--mf-green); }
.mf-row.is-state-active .mf-node-icon.is-mirror { color: var(--mf-flame); border-color: var(--mf-flame); }

.mf-node-info { display: flex; flex-direction: column; }
.mf-node-info.text-right { text-align: right; }
.mf-node-name { font-size: 12.5px; font-weight: 700; color: var(--mf-text); line-height: 1.2; letter-spacing: -0.01em; }
.mf-node-sub { font-size: 9.5px; color: var(--mf-text-dim); line-height: 1.2; }

.mf-domain-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-family: var(--mono); padding: 2px 8px; border-radius: 999px;
  background: var(--mf-chip-bg); border: 1px solid var(--mf-chip-line);
  color: var(--mf-chip-text); white-space: nowrap; font-weight: 500;
  box-shadow: var(--mf-chip-shadow);
}
.mf-domain-badge.is-standby.is-active {
  background: var(--mf-chip-bg-strong); border-color: var(--mf-blue-line);
  color: var(--mf-blue-text); font-weight: 600;
}
.mf-domain-badge.is-syncing.is-active {
  background: var(--mf-green-deep); border-color: var(--mf-green);
  color: var(--mf-green-text); font-weight: 600; box-shadow: var(--mf-glow-green-1);
}
.mf-domain-badge.is-flame {
  background: var(--mf-flame-deep); border-color: var(--mf-flame);
  color: var(--mf-flame-text-2); box-shadow: var(--mf-glow-flame-1);
}

/* ── Tagi Stanu ───────────────────────────────────────────────────────── */
.mf-tag {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 9px; font-weight: 700; letter-spacing: 0.04em; padding: 2px 7px;
  border-radius: 5px; flex-shrink: 0; white-space: nowrap;
}
/* Niebieskie (Bezczynny) */
.mf-tag.is-blue-idle {
  background: var(--mf-blue-fill); color: var(--mf-blue); border: 1px solid var(--mf-blue-line);
}
.mf-tag.is-blue-standby {
  background: var(--mf-blue-fill-2); color: var(--mf-blue-text); border: 1px solid var(--mf-blue-line-2);
}

/* Zielone (Kopiowanie) */
.mf-tag.is-green-sync {
  background: var(--mf-green-fill); color: var(--mf-green-text); border: 1px solid var(--mf-green);
  box-shadow: var(--mf-glow-green-1);
}
.mf-tag.is-green-dest {
  background: var(--mf-green-fill); color: var(--mf-green-text-2); border: 1px solid var(--mf-green);
  box-shadow: var(--mf-glow-green-1);
}

/* Czerwono-Pomarańczowe (Przywracanie / Przejęcie) */
.mf-tag.is-flame-live {
  background: var(--mf-flame-fill); color: var(--mf-flame-text); border: 1px solid var(--mf-flame);
  box-shadow: var(--mf-glow-flame-1); font-weight: 800;
}
.mf-tag.is-flame-warn {
  background: var(--mf-red-fill); color: var(--mf-red-text); border: 1px solid var(--mf-red); font-weight: 700;
}

.mf-tag.is-error {
  background: var(--mf-red-fill); color: var(--mf-red-text); border: 1px solid var(--mf-red-lit);
  box-shadow: var(--mf-glow-red-1);
}

.mf-pulse-dot {
  width: 5.5px; height: 5.5px; border-radius: 50%;
}
.mf-pulse-dot.is-blue {
  background: var(--mf-blue); box-shadow: 0 0 6px var(--mf-blue); animation: mf-glow-blue 1.8s infinite ease-in-out;
}
.mf-pulse-dot.is-green {
  background: var(--mf-green); box-shadow: 0 0 8px var(--mf-green); animation: mf-glow-green 1.4s infinite ease-in-out;
}
.mf-pulse-dot.is-flame {
  background: var(--mf-flame); box-shadow: 0 0 8px var(--mf-red); animation: mf-glow-flame 1.4s infinite ease-in-out;
}

@keyframes mf-glow-blue {
  0%, 100% { transform: scale(1); box-shadow: 0 0 6px var(--mf-blue); }
  50% { transform: scale(1.3); box-shadow: 0 0 12px var(--mf-blue), 0 0 4px var(--mf-blue-2); }
}
@keyframes mf-glow-green {
  0%, 100% { transform: scale(1); box-shadow: 0 0 6px var(--mf-green); }
  50% { transform: scale(1.35); box-shadow: 0 0 14px var(--mf-green-lit), 0 0 5px var(--mf-green); }
}
@keyframes mf-glow-flame {
  0%, 100% { transform: scale(1); box-shadow: 0 0 6px var(--mf-flame); }
  50% { transform: scale(1.35); box-shadow: 0 0 16px var(--mf-red), 0 0 5px var(--mf-amber); }
}

/* ── Animowany Most Transmisyjny ──────────────────────────────────────── */
.mf-connector {
  flex: 1; min-width: 100px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px; position: relative; padding: 0 8px;
}
.mf-conn-track {
  position: relative; width: 100%; height: 4px; border-radius: 999px;
  background: var(--mf-track-bg); overflow: hidden;
  box-shadow: var(--mf-track-inset);
}
.mf-conn-line {
  position: absolute; inset: 0;
  background: var(--mf-conn-line-bg);
}

/* Wiązka strumienia lasera */
.mf-conn-beam {
  position: absolute; top: 0; bottom: 0; width: 40%;
}
/* Bezczynny: Spokojny błękit (3.2s) */
.mf-conn-track.is-standby .mf-conn-beam.is-forward {
  background: linear-gradient(90deg, transparent, var(--mf-blue), var(--mf-blue-2), transparent);
  animation: mf-beam-fwd 3.2s linear infinite;
}
/* Kopiowanie: Szybki, jaskrawy zielony laser (1.0s) */
.mf-conn-track.is-syncing .mf-conn-beam.is-forward {
  width: 55%;
  background: linear-gradient(90deg, transparent, var(--mf-green), var(--mf-green-lit), var(--mf-green-text), transparent);
  animation: mf-beam-fwd 1.0s linear infinite;
}
/* Przejęcie: Odwrócony płomienny czerwono-pomarańczowy laser (1.5s) */
.mf-conn-track.is-active .mf-conn-beam.is-reverse {
  width: 50%;
  background: linear-gradient(90deg, transparent, var(--mf-red), var(--mf-flame), var(--mf-amber), transparent);
  animation: mf-beam-rev 1.5s linear infinite;
}
.mf-conn-track.is-error .mf-conn-beam {
  width: 100%; background: var(--mf-red-line); animation: none;
}

@keyframes mf-beam-fwd {
  0% { transform: translateX(-150%); }
  100% { transform: translateX(350%); }
}
@keyframes mf-beam-rev {
  0% { transform: translateX(350%); }
  100% { transform: translateX(-150%); }
}

/* Pakiety danych */
.mf-conn-packet {
  position: absolute; top: 0; width: 8px; height: 4px; border-radius: 999px;
  background: var(--mf-packet); box-shadow: var(--mf-packet-glow);
}
.mf-conn-track.is-standby .mf-conn-packet.p1 { animation: mf-packet-fwd 3.2s linear infinite; }
.mf-conn-track.is-standby .mf-conn-packet.p2 { animation: mf-packet-fwd 3.2s linear infinite 1.0s; }
.mf-conn-track.is-standby .mf-conn-packet.p3 { animation: mf-packet-fwd 3.2s linear infinite 2.0s; }

/* Kopiowanie: zielone fotony */
.mf-conn-track.is-syncing .mf-conn-packet {
  width: 12px; background: var(--mf-packet-sync); box-shadow: var(--mf-packet-glow-sync);
}
.mf-conn-track.is-syncing .mf-conn-packet.p1 { animation: mf-packet-fwd 1.1s linear infinite; }
.mf-conn-track.is-syncing .mf-conn-packet.p2 { animation: mf-packet-fwd 1.1s linear infinite 0.35s; }
.mf-conn-track.is-syncing .mf-conn-packet.p3 { animation: mf-packet-fwd 1.1s linear infinite 0.7s; }

/* Przejęcie: czerwono-pomarańczowe fotony w lewo */
.mf-conn-track.is-active .mf-conn-packet {
  background: var(--mf-packet-flame); box-shadow: var(--mf-packet-glow-flame);
}
.mf-conn-track.is-active .mf-conn-packet.p1 { animation: mf-packet-rev 1.5s linear infinite; }
.mf-conn-track.is-active .mf-conn-packet.p2 { animation: mf-packet-rev 1.5s linear infinite 0.5s; }
.mf-conn-track.is-active .mf-conn-packet.p3 { animation: mf-packet-rev 1.5s linear infinite 1.0s; }

.mf-conn-track.is-error .mf-conn-packet { display: none; }

@keyframes mf-packet-fwd {
  0% { left: 0%; opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { left: 100%; opacity: 0; }
}
@keyframes mf-packet-rev {
  0% { left: 100%; opacity: 0; }
  15% { opacity: 1; }
  85% { opacity: 1; }
  100% { left: 0%; opacity: 0; }
}

.mf-conn-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 10px; font-weight: 600; color: var(--mf-text-dim); white-space: nowrap;
  background: var(--mf-chip-bg-strong); padding: 1.5px 9px; border-radius: 999px;
  border: 1px solid var(--mf-chip-line); box-shadow: var(--mf-chip-shadow);
}
.mf-conn-badge i { font-size: 9px; color: var(--mf-blue); }

.mf-conn-badge.is-standby {
  color: var(--mf-blue-text); border-color: var(--mf-blue-line);
}
.mf-conn-badge.is-syncing {
  color: var(--mf-green-text); border-color: var(--mf-green); background: var(--mf-green-deep);
  box-shadow: var(--mf-glow-green-1); font-weight: 700;
}
.mf-conn-badge.is-syncing i { color: var(--mf-green-lit); }

.mf-conn-badge.is-active {
  color: var(--mf-flame-text); border-color: var(--mf-flame); background: var(--mf-flame-deep);
  box-shadow: var(--mf-glow-flame-1); font-weight: 800;
}
.mf-conn-badge.is-active i { color: var(--mf-flame); }

.mf-conn-badge.is-error {
  color: var(--mf-red-text); border-color: var(--mf-red-line); background: var(--mf-red-deep);
}
.mf-conn-badge.is-error i { color: var(--mf-red-lit); }

/* Mini pasek postępu w pigułce transferu */
.mf-conn-progress-mini {
  width: 50px; height: 3px; border-radius: 999px;
  background: var(--mf-track-bg); overflow: hidden; margin-left: 6px;
  box-shadow: var(--mf-track-inset); flex-shrink: 0;
}
.mf-conn-progress-mini-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--mf-green), var(--mf-green-lit), var(--mf-green-text));
  box-shadow: var(--mf-progress-glow);
  transition: width 0.3s ease-out;
}

/* Animacje etapów Zrzutu (Dump) i Odtwarzania (Restore) */
.mf-node.is-dumping {
  animation: mf-dump-breathe 1.6s infinite ease-in-out;
}
@keyframes mf-dump-breathe {
  0%, 100% { box-shadow: var(--mf-breathe-lo); }
  50% { box-shadow: var(--mf-breathe-hi); }
}

.mf-node.is-restoring {
  animation: mf-restore-breathe 1.6s infinite ease-in-out;
}
@keyframes mf-restore-breathe {
  0%, 100% { box-shadow: var(--mf-breathe-lo); }
  50% { box-shadow: var(--mf-breathe-hi); }
}

@media (max-width: 820px) {
  .mf-row { flex-direction: column; align-items: stretch; gap: 8px; }
  .mf-node { justify-content: flex-start; }
  .mf-node-info.text-right { text-align: left; }
  .mf-connector { width: 100%; min-width: 0; padding: 4px 0; }
}
@media (prefers-reduced-motion: reduce) {
  .mf-conn-beam, .mf-conn-packet, .mf-pulse-dot, .mf-row, .mf-node { animation: none !important; }
}

/* ── Satelity mapy: aplikacje i lustra jako autonomiczne kapsuły ──────── */
.nm-sat {
  position: absolute; z-index: 12;
  display: inline-flex; align-items: center; gap: 7px; max-width: 215px;
  /* Stała wysokość i zakaz łamania. Bez tego wąski span z czasem ("23 min")
     zawijał się na drugą linię, pigułka rosła, a przy stałym skoku 44 px
     prześwity między sąsiadami robiły się nierówne. */
  height: 26px; white-space: nowrap; box-sizing: border-box;
  padding: 0 11px; border-radius: 999px; text-decoration: none;
  font-size: 11.5px; font-weight: 500; color: #f1f5f9;
  background: rgba(16, 22, 34, 0.95);
  border: 1px solid rgba(56, 189, 248, 0.35);
  box-shadow: 0 4px 16px rgba(0,0,0,0.5);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  transition: opacity .2s, border-color .15s, color .15s, box-shadow .2s, transform .2s;
  cursor: grab;
  user-select: none;
}
.nm-sat:active { cursor: grabbing; }
.nm-sat.is-source-dragged {
  opacity: 0.35;
  filter: grayscale(0.5);
  border-style: dashed;
}
.nm-sat.is-mirror {
  border-color: rgba(192, 132, 252, 0.45);
  border-style: dashed;
  cursor: pointer;
}
.nm-sat:hover, .nm-sat.is-hovered {
  border-color: #38bdf8; color: #ffffff; z-index: 25;
  box-shadow: 0 8px 24px rgba(0,0,0,0.65), 0 0 14px rgba(56, 189, 248, 0.4);
}
.nm-sat.is-mirror:hover, .nm-sat.is-mirror.is-hovered {
  border-color: #c084fc;
  box-shadow: 0 8px 24px rgba(0,0,0,0.65), 0 0 14px rgba(192, 132, 252, 0.4);
}
.nm-sat.is-live {
  border-color: #fbbf24; border-style: solid;
  box-shadow: 0 0 14px rgba(251, 191, 36, 0.35);
}
.nm-sat.is-syncing {
  border-color: #10b981 !important; border-style: solid !important;
  color: #34d399 !important;
  box-shadow: 0 0 18px rgba(16, 185, 129, 0.55) !important;
  animation: nm-sat-sync-pulse 1.8s infinite ease-in-out;
}
.nm-sat.is-syncing .nm-sat-icon-box { color: #34d399 !important; }
@keyframes nm-sat-sync-pulse {
  0%, 100% { box-shadow: 0 0 10px rgba(16, 185, 129, 0.3); }
  50% { box-shadow: 0 0 24px rgba(16, 185, 129, 0.7); }
}
.nm-sat-icon-box { font-size: 12px; color: #38bdf8; display: flex; align-items: center; justify-content: center; flex-shrink: 0; }
.nm-sat.is-mirror .nm-sat-icon-box { color: #c084fc; }
.nm-sat.is-bad { border-color: rgba(248,113,113,.6); }
.nm-sat.is-bad .nm-sat-icon-box { color: #f87171 !important; }
.nm-sat.is-dim { opacity: 0.12; pointer-events: none; }
.nm-sat-n { min-width: 0; font-weight: 600; color: #ffffff; }
.nm-sat-p { font-size: 10.5px; color: #94a3b8; font-family: var(--mono); }
.nm-sat-rpo { color: #c084fc; font-weight: 600; }
/* Czas i port nigdy się nie zwężają ani nie łamią — to one psuły wysokość */
.nm-sat-p { flex: 0 0 auto; white-space: nowrap; }
.nm-sat-n { min-width: 0; }          /* warunek działania truncate w flexie */
.nm-sat-icon-box, .nm-sat-shield { flex: 0 0 auto; }
.nm-sat-shield { font-size: 9.5px; color: #38bdf8; margin-left: 2px; }

/* ── Pływający Duszek Przeciągania (Pointer Drag Ghost) ────────────────── */
.nm-drag-ghost {
  position: fixed;
  pointer-events: none;
  z-index: 100000;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  filter: drop-shadow(0 14px 32px rgba(0, 0, 0, 0.85));
}
.nm-sat.is-dragging-ghost {
  position: static !important;
  border-color: #38bdf8 !important;
  background: rgba(16, 22, 34, 0.98) !important;
  box-shadow: 0 0 28px rgba(56, 189, 248, 0.65), 0 8px 24px rgba(0, 0, 0, 0.8) !important;
}
.nm-ghost-hint {
  font-size: 11px;
  font-weight: 700;
  color: #38bdf8;
  background: rgba(15, 23, 42, 0.94);
  border: 1px solid rgba(56, 189, 248, 0.4);
  padding: 3px 10px;
  border-radius: 999px;
  display: flex;
  align-items: center;
  gap: 6px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.6);
  white-space: nowrap;
  transition: all .2s;
}
.nm-ghost-hint.is-over-target {
  color: #34d399;
  border-color: #10b981;
  background: rgba(6, 78, 59, 0.92);
  box-shadow: 0 0 16px rgba(16, 185, 129, 0.6);
}

/* ── Strefa Zrzutu na Kartach Węzłów ──────────────────────────────────── */
.nm-root.is-app-dragging {
  cursor: grabbing !important;
  user-select: none;
}
.nm-card.is-eligible-target {
  border-color: rgba(16, 185, 129, 0.6) !important;
  border-style: dashed !important;
  box-shadow: 0 0 24px rgba(16, 185, 129, 0.28), inset 0 0 12px rgba(16, 185, 129, 0.15) !important;
  animation: nm-target-breathe 1.8s infinite ease-in-out;
}
@keyframes nm-target-breathe {
  0%, 100% { box-shadow: 0 0 18px rgba(16, 185, 129, 0.2); }
  50% { box-shadow: 0 0 32px rgba(16, 185, 129, 0.5); }
}

.nm-card.is-drop-target {
  border-color: #10b981 !important;
  border-style: solid !important;
  box-shadow: 0 0 42px rgba(16, 185, 129, 0.85), inset 0 0 18px rgba(16, 185, 129, 0.4) !important;
  z-index: 60 !important;
}
.nm-drop-overlay {
  position: absolute; inset: -2px; border-radius: 12px;
  background: rgba(16, 185, 129, 0.28);
  border: 2px dashed #10b981;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 6px; font-size: 11px; font-weight: 700; color: #34d399;
  z-index: 30; pointer-events: none;
  animation: nm-drop-pulse 1.2s infinite;
  backdrop-filter: blur(4px);
}
@keyframes nm-drop-pulse {
  0%, 100% { background: rgba(16, 185, 129, 0.2); }
  50% { background: rgba(16, 185, 129, 0.4); }
}

/* Szybki pasek akcji na karcie węzła */
.nm-card-quick-bar {
  display: flex; gap: 6px; margin-top: 8px; padding-top: 7px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.nm-card-quick-bar .btn {
  flex: 1; justify-content: center; font-size: 10.5px; padding: 2px 6px;
}

/* Wskazówka dodawania na centralnym hubie */
.nm-hub-add-hint {
  margin-top: 3px; font-size: 9px; font-weight: 600; color: #94a3b8; opacity: 0.7;
  transition: opacity .2s, color .2s;
}
.nm-hub:hover .nm-hub-add-hint { opacity: 1; color: #34d399; }

/* Skrzynka z kodem instalacyjnym */
.code-box {
  display: flex; align-items: center; justify-content: space-between;
  gap: 8px; background: rgba(0, 0, 0, 0.5); border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 8px; padding: 8px 12px; margin-top: 8px;
}
.code-box code { font-family: var(--mono); font-size: 11.5px; color: #38bdf8; word-break: break-all; }

@media (max-width: 820px) { .nm-sat { display: none; } }

/* ── Style: Wybór stosów, animacje replikacji i integracja z mapą ─────────── */
.rep-stack-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 10px;
  max-height: 280px;
  overflow-y: auto;
  padding: 4px;
  margin-top: 6px;
  border-radius: 8px;
}
.rep-stack-card {
  display: flex;
  flex-direction: column;
  padding: 10px 12px;
  background: rgba(16, 22, 34, 0.7);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 9px;
  cursor: pointer;
  transition: all .2s ease;
  position: relative;
  overflow: hidden;
}
.rep-stack-card:hover {
  background: rgba(30, 41, 59, 0.85);
  border-color: rgba(56, 189, 248, 0.4);
  transform: translateY(-2px);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4), 0 0 12px rgba(56, 189, 248, 0.15);
}
.rep-stack-card.is-selected {
  background: rgba(14, 116, 144, 0.18);
  border-color: var(--accent);
  box-shadow: 0 0 20px rgba(56, 189, 248, 0.35), inset 0 0 10px rgba(56, 189, 248, 0.15);
}
.rep-stack-card.is-selected::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; height: 2px;
  background: linear-gradient(90deg, #38bdf8, #10b981);
}
.rep-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  margin-bottom: 6px;
}
.rep-card-name {
  font-weight: 700;
  font-size: 13px;
  color: #f1f5f9;
  font-family: var(--mono);
}
.rep-card-services {
  font-size: 11px;
  color: #94a3b8;
  line-height: 1.3;
}
.rep-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  margin-top: 6px;
}
.rep-tag {
  font-size: 9.5px;
  font-weight: 600;
  padding: 1px 6px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.06);
  color: #cbd5e1;
  border: 1px solid rgba(255, 255, 255, 0.08);
}
.rep-tag.is-db {
  background: rgba(16, 185, 129, 0.15);
  color: #34d399;
  border-color: rgba(16, 185, 129, 0.3);
}

/* Animowany most replikacji (Dedyk s1 -> VPN -> Węzeł) */
.rep-transfer-bridge {
  padding: 16px;
  background: rgba(10, 15, 26, 0.95);
  border: 1px solid rgba(56, 189, 248, 0.3);
  border-radius: 12px;
  box-shadow: 0 0 30px rgba(56, 189, 248, 0.18), inset 0 0 16px rgba(0, 0, 0, 0.5);
  position: relative;
  overflow: hidden;
}
.rep-bridge-track {
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
  margin: 12px 0;
}
.rep-bridge-line {
  position: absolute;
  top: 50%;
  left: 40px;
  right: 40px;
  height: 2px;
  background: rgba(255, 255, 255, 0.12);
  transform: translateY(-50%);
  z-index: 1;
}
.rep-bridge-beam {
  position: absolute;
  top: 50%;
  left: 40px;
  right: 40px;
  height: 3px;
  background: linear-gradient(90deg, #38bdf8, #10b981, #38bdf8);
  transform: translateY(-50%);
  background-size: 200% 100%;
  animation: rep-beam-stream 1.5s linear infinite;
  z-index: 2;
  box-shadow: 0 0 12px #38bdf8;
}
@keyframes rep-beam-stream {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

.rep-bridge-node {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  z-index: 5;
  background: rgba(15, 23, 42, 0.95);
  padding: 8px 14px;
  border-radius: 10px;
  border: 1px solid rgba(255, 255, 255, 0.15);
  box-shadow: 0 4px 16px rgba(0,0,0,0.6);
}
.rep-bridge-node.is-source { border-color: rgba(56, 189, 248, 0.6); box-shadow: 0 0 16px rgba(56, 189, 248, 0.25); }
.rep-bridge-node.is-target { border-color: rgba(16, 185, 129, 0.6); box-shadow: 0 0 16px rgba(16, 185, 129, 0.25); }

/* Odznaka satelity repliki na mapie */
.nm-sat.is-replica {
  border-color: rgba(56, 189, 248, 0.5);
  background: rgba(14, 116, 144, 0.25);
  box-shadow: 0 0 14px rgba(56, 189, 248, 0.35);
}
.nm-sat.is-replica.is-syncing {
  border-color: #10b981;
  background: rgba(6, 78, 59, 0.4);
  box-shadow: 0 0 20px rgba(16, 185, 129, 0.55);
  animation: nm-target-breathe 1.5s infinite;
}
.nm-sat-link.is-replica {
  stroke: #38bdf8 !important;
  stroke-dasharray: 4 3;
  animation: nm-flow-dash 1.2s linear infinite;
}
.nm-badge-replica {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 7px;
  font-size: 10px;
  font-weight: 700;
  border-radius: 999px;
  background: rgba(14, 116, 144, 0.25);
  border: 1px solid rgba(56, 189, 248, 0.5);
  color: #38bdf8;
  margin-left: 4px;
}





/* ── Postęp klonowania stosu na węzeł ─────────────────────────────────────
   Wypełnienie steruje serwer. Wcześniej pasek napędzały setTimeout-y w
   przeglądarce i dobiegał końca, gdy paczka dopiero się pakowała. */
.nr-prog { height: 5px; border-radius: 999px; background: var(--surface-2);
           border: 1px solid var(--border-strong); overflow: hidden; }
.nr-prog-fill { display: block; height: 100%; background: var(--accent);
                transition: width .6s ease; }
@media (prefers-reduced-motion: reduce) { .nr-prog-fill { transition: none; } }

/* ═══════════════════════════════════════════════════════════════════════════
   NAWIGACJA BOCZNA — filtr, zwijane sekcje, liczniki, podpowiedzi
   Siedem grup i 22 pozycje to za dużo, żeby szukać wzrokiem. Menu daje więc
   trzy drogi do celu: wpisanie fragmentu nazwy, zwinięcie nieużywanych sekcji
   i liczniki pokazujące, gdzie faktycznie coś się dzieje.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════════════════════
   SIDEBAR — jedno miejsce na cały wygląd nawigacji
   ───────────────────────────────────────────────────────────────────────────
   Wcześniej te same selektory żyły w trzech blokach oddalonych o ~4000 linii
   i nadpisywały się nawzajem, więc o wyniku decydowała kolejność w pliku,
   a nie zamiar. Zasady, których się tu trzymamy:

     1. Jeden aktywny stan. Pozycja bieżąca ma tło, mocniejszy tekst i pionowy
        znacznik przy krawędzi — nic poza nią nie używa koloru akcentu.
     2. Plakietka = problem. Liczba w menu pojawia się wyłącznie tam, gdzie coś
        wymaga reakcji (patrz odznaka() w app.js). Neutralne liczniki „ile masz”
        zniknęły, bo konkurowały o uwagę z alertami.
     3. Ruch tylko na interakcji. Wjazd pozycji przy każdym przerysowaniu listy
        (filtrowanie, odświeżenie liczników) wyglądał jak usterka.
   ═══════════════════════════════════════════════════════════════════════════ */

.sidebar-nav { flex: 1; overflow-y: auto; padding: 12px 8px 8px; }

/* ── Szukajka ─────────────────────────────────────────────────────────────── */
.nav-search { position: relative; margin: 0 4px 10px; }
.nav-search > i {
  position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
  font-size: 11.5px; color: var(--text-faint); pointer-events: none; transition: color .15s;
}
.nav-search input {
  width: 100%; height: 34px; padding: 0 30px 0 31px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius-sm); color: var(--text); font-size: 13px;
  transition: border-color .15s, background .15s;
}
.nav-search input::placeholder { color: var(--text-faint); }
.nav-search input:focus { outline: none; border-color: var(--accent); background: var(--surface-2); }
.nav-search:focus-within > i, .nav-search.has-text > i { color: var(--accent); }
.nav-search-x {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  width: 22px; height: 22px; display: grid; place-items: center;
  background: none; border: 0; cursor: pointer; color: var(--text-faint);
  font-size: 11px; border-radius: 5px;
}
.nav-search-x:hover { color: var(--text); background: var(--surface-2); }

.nav-empty {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 26px 12px; color: var(--text-faint); font-size: 12.5px; text-align: center;
}
.nav-empty > i { font-size: 20px; opacity: .5; }

/* ── Grupa ────────────────────────────────────────────────────────────────── */
.nav-group + .nav-group { margin-top: 2px; padding-top: 10px; border-top: 1px solid var(--n-line); }
.nav-group { margin-bottom: 8px; }

.nav-group-label {
  width: 100%; background: none; border: 0; cursor: pointer; font: inherit;
  display: flex; align-items: center; gap: 8px;
  font-size: 10.5px; font-weight: 700; text-transform: uppercase;
  letter-spacing: .09em; color: var(--text-faint);
  padding: 5px 8px; margin-bottom: 3px; border-radius: var(--radius-sm);
  transition: color .15s, background .15s;
}
.nav-group-label:hover { color: var(--text-dim); background: var(--surface); }
.nav-group-icon { font-size: 10px; opacity: .7; width: 12px; text-align: center; }
.nav-caret { font-size: 9px; opacity: .45; transition: transform .28s cubic-bezier(.34,1.3,.64,1); }
.nav-group.is-collapsed .nav-caret { transform: rotate(-90deg); }

/* Sekcja ulubionych wyróżniona samą gwiazdką w kolorze — bez ramki i tła,
   żeby nie wyglądała na osobny widget. */
.nav-group.is-pinned .nav-group-icon { color: var(--amber); opacity: 1; }

/* Licznik grupy ma sens tylko przy zwiniętej sekcji — rozwinięta pokazuje
   przecież swoje pozycje. `display:none`, a nie `opacity:0`: niewidoczny
   element nadal zajmował miejsce i czytały go czytniki ekranu. */
.nav-group-n {
  font-size: 10px; font-weight: 700; min-width: 16px; text-align: center;
  padding: 1px 5px; border-radius: 999px;
  background: var(--surface-2); color: var(--text-faint);
}
.nav-group-n.is-warn { background: var(--amber-soft); color: var(--amber); }
.nav-group-n.is-bad  { background: var(--red-soft); color: var(--red); }
.nav-group:not(.is-collapsed) .nav-group-n { display: none; }

/* Zwijanie siatką 0fr → 1fr: płynna wysokość bez mierzenia w JS. */
.nav-items { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .3s cubic-bezier(.4,0,.2,1); }
.nav-group.is-collapsed .nav-items { grid-template-rows: 0fr; }
.nav-items-in { overflow: hidden; min-height: 0; }

/* ── Wiersz: link + gwiazdka ─────────────────────────────────────────────── */
.nav-row { position: relative; display: flex; align-items: center; }
/* Kaskada tylko w grupie z klasą .is-wjazd — patrz `pierwszeWejscie` w app.js. */
.nav-group.is-wjazd .nav-row {
  animation: nav-wjazd .38s cubic-bezier(.22,1,.36,1) backwards;
  animation-delay: calc(var(--i, 0) * 28ms);
}
@keyframes nav-wjazd {
  from { opacity: 0; transform: translateX(-10px); }
  to   { opacity: 1; transform: none; }
}
.nav-row + .nav-row { margin-top: 1px; }

.nav-link {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 11px;
  /* Wyższy wiersz: 28 pozycji czyta się gorzej ściśniętych niż przewijanych.
     36 px to wygodny cel kliknięcia i wyraźniejszy rytm pionowy. */
  padding: 9px 11px; border-radius: var(--radius-sm);
  color: var(--text-dim); font-size: 13.5px; font-weight: 500;
  cursor: pointer; position: relative;
  transition: background .18s cubic-bezier(.4,0,.2,1),
              color .18s cubic-bezier(.4,0,.2,1),
              padding-left .18s cubic-bezier(.4,0,.2,1);
}
.nav-ico {
  width: 17px; text-align: center; font-size: 13.5px; opacity: .75; flex: none;
  transition: color .18s, opacity .18s, transform .18s cubic-bezier(.4,0,.2,1);
}

/* Hover: tło + delikatne przesunięcie w prawo. Ruch mówi „to jest klikalne”
   wyraźniej niż sama zmiana tła, a 3 px nie rozjeżdża listy. */
.nav-row:hover .nav-link { color: var(--text); background: var(--surface); padding-left: 14px; }
.nav-row:hover .nav-ico { opacity: 1; transform: scale(1.08); }

/* Stan aktywny — jedyne miejsce z kolorem akcentu w całym menu. */
.nav-link.active {
  background: var(--accent-soft); color: var(--text); font-weight: 600; padding-left: 14px;
}
.nav-link.active .nav-ico { color: var(--accent); opacity: 1; }
/* Pasek przy krawędzi wjeżdża, zamiast pojawiać się skokowo. */
.nav-link::after {
  content: ""; position: absolute; left: 0; top: 50%;
  width: 3px; height: 0; border-radius: 0 3px 3px 0;
  background: var(--accent);
  transform: translateY(-50%);
  transition: height .26s cubic-bezier(.34,1.3,.64,1);
}
.nav-link.active::after { height: 64%; }

.nav-badge {
  flex: none; font-size: 10.5px; font-weight: 700; line-height: 1.6;
  min-width: 18px; text-align: center; padding: 0 6px; border-radius: 999px;
  background: var(--surface-2); color: var(--text-faint);
}
.nav-badge.is-warn { background: var(--amber-soft); color: var(--amber); }
.nav-badge.is-bad  { background: var(--red-soft); color: var(--red); }

/* ── Gwiazdka ulubionych ─────────────────────────────────────────────────── */
/* Domyślnie schowana, żeby 28 gwiazdek nie tworzyło drugiej kolumny szumu.
   Pokazuje się na hover/focus wiersza i zostaje widoczna, gdy jest zapalona. */
.nav-star {
  flex: none; width: 26px; height: 26px; margin-left: 2px;
  display: grid; place-items: center;
  background: none; border: 0; cursor: pointer; border-radius: 6px;
  color: var(--text-faint); font-size: 11px;
  opacity: 0; transition: opacity .14s, color .14s, background .14s, transform .14s;
}
.nav-row:hover .nav-star,
.nav-star:focus-visible,
.nav-star.on { opacity: 1; }
.nav-star:hover { background: var(--surface-2); color: var(--amber); transform: scale(1.18) rotate(8deg); }
.nav-star:active { transform: scale(.9); }
/* Zapalenie gwiazdki ma być widoczne — bez tego klik nie daje potwierdzenia. */
.nav-star.on { color: var(--amber); animation: nav-star-pop .32s cubic-bezier(.34,1.56,.64,1); }
@keyframes nav-star-pop {
  0%   { transform: scale(.6) rotate(-30deg); }
  60%  { transform: scale(1.25) rotate(6deg); }
  100% { transform: scale(1) rotate(0); }
}

@media (max-width: 1024px) { .nav-star { opacity: 1; } }

/* ── Podpowiedź ───────────────────────────────────────────────────────────
   position:fixed, bo .sidebar-nav przewija się w pionie, a przeglądarka
   wymusza wtedy przycinanie również w poziomie — dymek liczony względem
   wiersza byłby ucięty na krawędzi menu. Pozycję podaje JS z rect wiersza. */
.nav-tip {
  position: fixed; z-index: 80; width: 292px;
  pointer-events: none;
  /* Domyślnie schowany. Sterowanie klasą .show zamiast <transition> — patrz
     komentarz w app.js: klasa wejściowa Vue znika dopiero w rAF. */
  opacity: 0; visibility: hidden;
  transform: translateY(-50%) translateX(-8px);
  transition: opacity .16s ease, transform .2s cubic-bezier(.34,1.3,.64,1), visibility .2s;
  background: var(--n-1); border: 1px solid var(--border-strong);
  border-radius: var(--r-2); padding: 10px 12px;
  font-size: 12px; line-height: 1.5; color: var(--t-3);
  box-shadow: 0 12px 34px rgba(0,0,0,.45);
}
/* Nagłówek dymka: ikona pozycji w kafelku + nazwa. Ta sama ikona co w menu,
   więc dymek od razu wiąże się wzrokowo z wierszem, nad którym stoi. */
.nav-tip-head { display: flex; align-items: center; gap: 9px; margin-bottom: 7px; }
.nav-tip-ico {
  width: 26px; height: 26px; flex: none; display: grid; place-items: center;
  border-radius: 7px; background: var(--accent-soft); color: var(--accent); font-size: 12px;
}
.nav-tip b { color: var(--t-1); font-size: 13.5px; font-weight: 600; }
.nav-tip-desc { display: block; }
/* Lista konkretów: co użytkownik faktycznie na tej stronie zrobi. Oddzielona
   linią, bo to inny rodzaj informacji niż zdanie opisowe nad nią. */
.nav-tip-co {
  list-style: none; margin: 8px 0 0; padding: 8px 0 0;
  border-top: 1px solid var(--n-line);
  display: flex; flex-direction: column; gap: 5px;
}
/* ── Mini-wskaźnik w dymku ────────────────────────────────────────────────
   Pasek wypełnia się przy pokazaniu dymka — to jedyna animacja niosąca
   informację (długość = proporcja), a nie samą ozdobę. */
.nav-tip-stat {
  margin-top: 10px; padding: 9px 10px;
  background: var(--surface); border: 1px solid var(--n-line); border-radius: 8px;
}
.nts-top { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 11px; color: var(--t-3); }
.nts-top b { font-family: var(--mono, ui-monospace, monospace); font-size: 14px; font-weight: 600; color: var(--t-1); font-variant-numeric: tabular-nums; }
.nts-z { font-size: 11px; font-weight: 400; color: var(--t-3); }
.nts-tor { margin-top: 7px; height: 5px; border-radius: 3px; background: var(--n-line); overflow: hidden; }
.nts-fill {
  display: block; height: 100%; width: 0; border-radius: 3px;
  background: var(--accent);
  transition: width .6s cubic-bezier(.22,1,.36,1) .12s;
}
.nav-tip-stat.is-warn .nts-fill { background: var(--amber); }
.nav-tip-stat.is-bad  .nts-fill { background: var(--red); }
.nav-tip-stat.is-bad  .nts-top b { color: var(--red); }
/* Dopóki dymek jest schowany, pasek wraca do zera — dzięki temu przy każdym
   pokazaniu naprawdę się wypełnia, zamiast pojawiać się już pełny. */
.nav-tip:not(.show) .nts-fill { width: 0 !important; transition: none; }

/* Każdy punkt ma własną ikonę opisującą czynność — jednakowa strzałka przy
   każdym wierszu nie niosła żadnej informacji poza „to jest lista”. */
.nav-tip-co li { display: flex; gap: 8px; align-items: flex-start; color: var(--t-2); font-size: 11.5px; line-height: 1.5; }
.nav-tip-co li > i {
  width: 14px; flex: none; text-align: center; margin-top: 1px;
  color: var(--accent); font-size: 10.5px;
}
.nav-tip::before {
  content: ""; position: absolute; right: 100%; top: 50%; margin-top: -6px;
  border: 6px solid transparent; border-right-color: var(--border-strong);
}

/* Wejście z lekkim wysunięciem — dymek „wychodzi” zza krawędzi menu. */
.nav-tip.show { opacity: 1; visibility: visible; transform: translateY(-50%) translateX(0); }

@media (max-width: 1024px) { .nav-tip { display: none; } }

@media (prefers-reduced-motion: reduce) {
  .nav-items, .nav-caret, .nav-link, .nav-link::after, .nav-star, .nav-ico,
  .nav-tip, .nts-fill { transition: none; }
  .nav-group.is-wjazd .nav-row { animation: none; }
  .nav-star.on { animation: none; }
  .nav-row:hover .nav-link, .nav-link.active { padding-left: 11px; }
  .nav-row:hover .nav-ico { transform: none; }
}


/* ── Strumień zdarzeń na mapie ────────────────────────────────────────────
   Mapa odpytywała trzy endpointy co kilka sekund, więc krótkie stany (np.
   przejście lustra przez "syncing") ginęły między odpytaniami. Teraz zdarzenia
   przychodzą strumieniem SSE w chwili zapisu. */
.sse-stan {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 11.5px; color: var(--t-3);
  padding: 4px 10px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
}
.sse-stan.is-on { color: var(--green); border-color: rgba(52,211,153,.3); background: var(--green-soft); }
.sse-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--t-3); }
.sse-stan.is-on .sse-dot { background: var(--green); animation: sse-blink 1.6s ease-in-out infinite; }
@keyframes sse-blink { 0%, 100% { opacity: 1; } 50% { opacity: .2; } }

/* Węzeł, którego dotyczy świeże zdarzenie, mignie — widać GDZIE coś się stało */
.nm-card.is-flash { animation: nm-flash 2.4s ease-out; }
@keyframes nm-flash {
  0%   { box-shadow: 0 0 0 0 rgba(56,189,248,.55); border-color: var(--sky); }
  60%  { box-shadow: 0 0 0 14px rgba(56,189,248,0); border-color: var(--sky); }
  100% { box-shadow: 0 0 0 0 rgba(56,189,248,0); }
}

.ev-list { display: flex; flex-direction: column; max-height: 340px; overflow-y: auto; }
.ev {
  display: flex; align-items: center; gap: 10px;
  padding: 7px 4px; font-size: 12.5px; color: var(--t-2);
  border-bottom: 1px solid var(--n-line);
  animation: ev-in .3s cubic-bezier(.2,.9,.3,1.2);
}
.ev:last-child { border-bottom: 0; }
@keyframes ev-in {
  from { opacity: 0; transform: translateY(-8px); background: var(--accent-soft); }
  to   { opacity: 1; transform: none; background: transparent; }
}
.ev-czas { font-size: 11px; color: var(--t-3); flex: 0 0 auto; font-variant-numeric: tabular-nums; }
.ev-ikona { font-size: 11px; color: var(--green); flex: 0 0 auto; }
.ev.is-fail .ev-ikona { color: var(--red); }
.ev.is-stan .ev-ikona { color: var(--sky); }
.ev.is-fail { color: var(--t-1); }
.ev-tekst { min-width: 0; }
.ev-cel {
  font-size: 11px; color: var(--t-3); margin-left: 6px;
  padding: 1px 6px; border-radius: 4px; background: var(--surface-2);
}
.ev-wezel {
  font-size: 11px; color: var(--t-3); text-decoration: none; flex: 0 0 auto;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border-radius: 999px; border: 1px solid var(--border-strong);
  transition: color .15s, border-color .15s;
}
.ev-wezel:hover { color: var(--t-1); border-color: var(--sky); }
.ev-user { font-size: 10.5px; color: var(--t-3); flex: 0 0 auto; }

@media (prefers-reduced-motion: reduce) {
  .sse-stan.is-on .sse-dot, .nm-card.is-flash, .ev { animation: none; }
}

/* ── Repliki na węzłach (Node Replicas View) ────────────────────────── */
.nr-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: 100%;
}

.nr-card {
  background: rgba(15, 23, 42, 0.85);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 14px;
  padding: 18px 22px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.35);
  transition: all 0.25s ease;
  position: relative;
  overflow: hidden;
}

.nr-card:hover {
  border-color: rgba(56, 189, 248, 0.35);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 24px rgba(56, 189, 248, 0.12);
}

.nr-card.is-active {
  border-color: rgba(249, 115, 22, 0.4);
  background: linear-gradient(180deg, rgba(30, 20, 15, 0.9) 0%, rgba(15, 23, 42, 0.9) 100%);
}

.nr-card.is-standby {
  border-color: rgba(56, 189, 248, 0.25);
}

.nr-card.is-syncing {
  border-color: rgba(16, 185, 129, 0.5);
  box-shadow: 0 0 30px rgba(16, 185, 129, 0.2);
}

.nr-card-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 12px;
}

.nr-title-group {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.nr-icon-box {
  width: 36px;
  height: 36px;
  border-radius: 9px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 15px;
  background: rgba(56, 189, 248, 0.1);
  border: 1px solid rgba(56, 189, 248, 0.25);
  color: #38bdf8;
  flex-shrink: 0;
}

.nr-icon-box.is-active {
  background: rgba(249, 115, 22, 0.12);
  border-color: rgba(249, 115, 22, 0.35);
  color: #f97316;
}

.nr-stack-title {
  font-size: 16px;
  font-weight: 700;
  color: #f8fafc;
  letter-spacing: -0.01em;
}

.nr-meta-bar {
  display: flex;
  align-items: center;
  gap: 16px;
  font-size: 12px;
  color: #94a3b8;
  margin-bottom: 14px;
  padding-bottom: 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  flex-wrap: wrap;
}

.nr-meta-item {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.nr-meta-item i {
  color: var(--t-3);
  font-size: 11px;
}

.nr-meta-item b {
  color: #e2e8f0;
  font-weight: 600;
}

.nr-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Adres repliki na węźle — bez niego nie da się sprawdzić, czy kopia odpowiada */
.nr-dom {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; color: var(--sky); text-decoration: none;
  padding: 3px 10px; border-radius: 999px;
  background: var(--sky-soft); border: 1px solid rgba(56,189,248,.3);
  transition: border-color .15s, color .15s;
}
.nr-dom:hover { border-color: var(--sky); color: var(--t-1); }
.nr-dom > i { font-size: 10px; }

/* ── Most danych: klonowanie repliki z serwera na węzeł ───────────────────
   Kierunek odwrotny niż przy lustrach (serwer → maszyna klienta), więc kolor
   też inny — fiolet. Bez tego trwające klonowanie, nawet półgodzinne i
   wielogigabajtowe, nie zostawiało na mapie żadnego śladu. */
.nm-sync-bridge.is-replica .nm-bridge-glow {
  stroke: rgba(167, 139, 250, 0.38); stroke-width: 14; stroke-linecap: round;
  filter: drop-shadow(0 0 12px #a78bfa);
}
.nm-sync-bridge.is-replica .nm-bridge-track {
  stroke: rgba(167, 139, 250, 0.3); stroke-width: 7; stroke-linecap: round;
}
.nm-sync-bridge.is-replica .nm-bridge-stream {
  stroke: #a78bfa; stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 40 25; animation: nm-laser-stream 1.1s linear infinite;
  filter: drop-shadow(0 0 6px #7c3aed);
}
.nm-sync-bridge.is-replica .nm-bridge-photons {
  stroke: #ffffff; stroke-width: 5.5; stroke-linecap: round;
  stroke-dasharray: 10 55; animation: nm-laser-stream 1.1s linear infinite;
  filter: drop-shadow(0 0 8px #ffffff);
}

/* Linia węzeł → satelita nie miała żadnego stylu, więc renderowała się bez
   obrysu: satelity wisiały nad mapą bez widocznego połączenia. */
.nm-slink { stroke: rgba(148, 163, 184, .35); stroke-width: 1; }
.nm-slink.is-dim { opacity: .12; }

/* Karta w trakcie kopiowania oddycha, zamiast tylko świecić statycznie */
.nm-card.is-syncing { animation: nm-card-breath 2s ease-in-out infinite; }
@keyframes nm-card-breath {
  0%, 100% { box-shadow: 0 0 24px rgba(16,185,129,.35), inset 0 0 10px rgba(16,185,129,.15); }
  50%      { box-shadow: 0 0 34px rgba(16,185,129,.6),  inset 0 0 14px rgba(16,185,129,.25); }
}
.nm-sync-badge.is-syncing { animation: nm-blink-soft 1.4s ease-in-out infinite; }
@keyframes nm-blink-soft { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }

@media (prefers-reduced-motion: reduce) {
  .nm-sync-bridge.is-replica .nm-bridge-stream,
  .nm-sync-bridge.is-replica .nm-bridge-photons,
  .nm-card.is-syncing, .nm-sync-badge.is-syncing { animation: none; }
}

/* ── Konteneryzacja AI (Auto-Docker) ─────────────────────────────────────── */
/* Strona korzysta z komponentów panelu (.sec, .dt, .badge, .note); poniżej tylko
   to, czego one nie pokrywają. Kolory idą przez zmienne motywu — wcześniejsza
   wersja miała wpisane na sztywno jasne odcienie i w jasnym motywie znikał tekst. */

.cz-chip {
  cursor: pointer;
  padding: 2px 9px; border-radius: 5px;
  font-family: var(--mono); font-size: 11.5px;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-dim); transition: color .12s, border-color .12s, background .12s;
}
.cz-chip:hover { color: var(--text); border-color: var(--accent); background: rgba(16, 185, 129, .08); }

/* Podpowiedzi katalogów pod polem ręcznego wskazania ścieżki */
.cz-path-field { position: relative; }
.cz-path-suggest {
  position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 20;
  max-height: 240px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-2, 10px);
  box-shadow: var(--sh-1, 0 10px 30px rgba(0,0,0,.35));
  padding: 4px;
}
.cz-path-suggest-item {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 7px 10px; border-radius: 6px; border: none;
  background: transparent; color: var(--text);
  font-family: var(--mono); font-size: 12px; text-align: left;
  cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cz-path-suggest-item:hover { background: var(--surface-2); }
.cz-path-suggest-item > i { color: var(--text-faint); font-size: 11px; flex-shrink: 0; }

.cz-filterbar {
  display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
  padding: 10px 16px;
  background: var(--n-2, var(--surface-2));
  border-bottom: 1px solid var(--n-line, var(--border));
}

/* Ikona technologii — wspólna dla listy i kafelków */
.cz-ico {
  width: 32px; height: 32px; border-radius: 8px; flex-shrink: 0;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 15px;
  background: var(--surface-2); color: var(--text-dim);
  border: 1px solid var(--border);
}
.cz-ico-node    { background: rgba(34, 197, 94, .14);  color: #4ade80; border-color: rgba(34,197,94,.25); }
.cz-ico-python  { background: rgba(56, 189, 248, .14); color: #38bdf8; border-color: rgba(56,189,248,.25); }
.cz-ico-php     { background: rgba(168, 85, 247, .14); color: #c084fc; border-color: rgba(168,85,247,.25); }
.cz-ico-go      { background: rgba(6, 182, 212, .14);  color: #22d3ee; border-color: rgba(6,182,212,.25); }
.cz-ico-rust    { background: rgba(249, 115, 22, .14); color: #fb923c; border-color: rgba(249,115,22,.25); }
.cz-ico-java    { background: rgba(239, 68, 68, .14);  color: #f87171; border-color: rgba(239,68,68,.25); }
.cz-ico-static  { background: rgba(148, 163, 184, .14); color: #94a3b8; }
.cz-ico-compose { background: rgba(14, 165, 233, .14); color: #38bdf8; border-color: rgba(14,165,233,.25); }
/* Fallback techClass() — bez tej reguły stos o nieznanym typie dostawał samą klasę bazową. */
.cz-ico-generic { background: var(--surface-2); color: var(--text-dim); }

/* Kafelki wykrytych aplikacji */
.cz-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
  gap: 12px;
}
.cz-card {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-2, 12px); overflow: hidden; min-width: 0;
  transition: border-color .18s, box-shadow .18s;
}
.cz-card:hover { border-color: var(--border-strong); box-shadow: var(--sh-1, 0 6px 18px rgba(0,0,0,.28)); }
.cz-card-top { display: flex; align-items: center; gap: 10px; padding: 12px 14px; min-width: 0; }
.cz-card-path {
  display: flex; align-items: center; gap: 6px;
  padding: 7px 14px; font-size: 11.5px; color: var(--text-dim);
  background: var(--surface-2); border-top: 1px solid var(--border); min-width: 0;
}
.cz-card-path > i { flex-shrink: 0; color: var(--text-faint); font-size: 11px; }
.cz-tags { display: flex; flex-wrap: wrap; gap: 4px; padding: 9px 14px; border-top: 1px solid var(--border); }
.cz-tag {
  font-family: var(--mono); font-size: 10.5px; color: var(--text-dim);
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: 4px; padding: 2px 7px; white-space: nowrap;
}
.cz-card-foot {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: 9px 12px; border-top: 1px solid var(--border); margin-top: auto;
}

/* Studio: edytor + panel boczny */
.cz-studio {
  display: grid;
  grid-template-columns: minmax(0, 2fr) minmax(320px, 1fr);
  gap: 16px;
  align-items: start;
}
@media (max-width: 1100px) { .cz-studio { grid-template-columns: 1fr; } }

.cz-editor-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 12px;
  background: var(--n-2, var(--surface-2));
  border-bottom: 1px solid var(--n-line, var(--border));
  flex-wrap: wrap;
}
.cz-code {
  display: block; width: 100%; height: 520px;
  border: none; outline: none; resize: vertical;
  background: #06090e; color: #e2e8f0;
  padding: 14px;
  font-family: var(--mono); font-size: 12.5px; line-height: 1.55;
  tab-size: 2;
}
:root[data-theme="light"] .cz-code { background: var(--n-3); color: var(--t-1); }

/* Postęp akcji na wierszu stosu (start / stop / restart / usuwanie) */
.cz-postep {
  display: flex; align-items: center; gap: 7px;
  margin-top: 6px; padding: 5px 9px; border-radius: 6px;
  font-size: 12px; line-height: 1.35;
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text-dim);
}
.cz-postep > i { flex-shrink: 0; font-size: 11px; }
.cz-postep.is-running { border-color: rgba(56, 189, 248, .45); color: var(--text); }
.cz-postep.is-running > i { color: #38bdf8; }
.cz-postep.is-done { border-color: rgba(16, 185, 129, .45); color: var(--text); }
.cz-postep.is-done > i { color: var(--accent); }
.cz-postep.is-error { border-color: rgba(239, 68, 68, .5); color: var(--text); }
.cz-postep.is-error > i { color: #f87171; }

.cz-envrow { padding: 4px 0; border-bottom: 1px dashed var(--border); }
.cz-envrow:last-child { border-bottom: none; }

/* Stan „AI pracuje” / „skanowanie” */
.cz-thinking { padding: 34px 16px; text-align: center; color: var(--text-dim); }
.cz-thinking > i { font-size: 26px; color: var(--accent); }

/* Doradca migracji */
.cz-score {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 16px;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-2, 12px);
}
.cz-score-num { font-size: 30px; font-weight: 800; line-height: 1.1; font-variant-numeric: tabular-nums; }
.cz-score-icon { font-size: 30px; opacity: .85; }
.cz-step-row {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 9px 12px; margin-bottom: 6px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: 8px;
}
.cz-step-num {
  flex-shrink: 0; width: 21px; height: 21px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700;
  background: rgba(16, 185, 129, .16); border: 1px solid rgba(16, 185, 129, .4); color: var(--accent);
}

/* Pipeline budowania kontenera — pasek stanu, log na żywo */
.cz-run-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  padding: 10px 14px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-2, 12px);
}
.cz-log-head {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap;
  padding-bottom: 6px;
}
.cz-runlog { max-height: 320px; word-break: break-word; }
.cz-ai-context {
  max-width: 520px; margin: 0 auto; text-align: left;
  font-size: 12.5px; line-height: 1.9;
  background: var(--surface-2); border: 1px solid var(--border);
  border-radius: var(--r-1, 8px); padding: 10px 14px;
}

/* Lista stosów: stała siatka kolumn zamiast poziomego przewijania.
   Przy siedmiu kolumnach tabela wychodziła poza panel i nazwa stosu
   znikała pod paskiem przewijania — teraz szerokość dzieli się na stałe,
   a długie ścieżki i adresy skracają się wielokropkiem. */
.dt.cz-stacks { table-layout: fixed; width: 100%; }
.dt.cz-stacks td, .dt.cz-stacks th { overflow: hidden; }
.dt.cz-stacks td { vertical-align: top; padding-top: 12px; padding-bottom: 12px; }
.dt.cz-stacks tbody tr { transition: background .12s; }
.dt.cz-stacks tbody tr:hover { background: var(--surface-2); }
.dt.cz-stacks .cz-col-state { width: 130px; }
.dt.cz-stacks .cz-col-addr  { width: 210px; }
/* Akcje to teraz Start/Stop + logi + menu — 388 px zostało po wersji z pięcioma
   przyciskami i tylko zabierało miejsce kolumnie z nazwą i ścieżką. */
.dt.cz-stacks td.act, .dt.cz-stacks th.act { width: 230px; }
/* Ikony w tej tabeli są ciaśniejsze — inaczej ostatni przycisk łamał się do drugiej linii. */
.dt.cz-stacks td.act .btn.icon.sm { padding: 5px 7px; }
.dt.cz-stacks td.act .btn.sm { padding: 5px 10px; }
.dt.cz-stacks td > div { min-width: 0; }
.dt.cz-stacks .truncate { display: block; max-width: 100%; }
.dt.cz-stacks td.act .btn { flex: 0 0 auto; }

/* Generowanie konfiguracji: nagłówek + etapy zamiast samego kółka. */
.cz-gen-head {
  display: flex; align-items: center; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.cz-pipe { display: flex; flex-direction: column; padding: 12px 16px 4px; }
.cz-pipe-step { display: flex; align-items: flex-start; gap: 10px; padding: 7px 0; position: relative; }
/* Pionowa linia łącząca kropki — poza ostatnim krokiem. */
.cz-pipe-step:not(:last-child)::before {
  content: ""; position: absolute; left: 10px; top: 29px; bottom: -3px;
  width: 1px; background: var(--border);
}
.cz-pipe-dot {
  flex: none; width: 21px; height: 21px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 10px; z-index: 1;
  background: var(--surface-2); border: 1px solid var(--border); color: var(--text-faint);
}
.cz-pipe-body { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cz-pipe-title { font-size: 13px; color: var(--text-dim); line-height: 1.35; }
.cz-pipe-hint { font-size: 11.5px; color: var(--text-faint); line-height: 1.35; }

.cz-pipe-step.is-running .cz-pipe-dot { border-color: #38bdf8; color: #38bdf8; background: rgba(56,189,248,.12); }
.cz-pipe-step.is-running .cz-pipe-title { color: var(--text); font-weight: 600; }
.cz-pipe-step.is-done .cz-pipe-dot { border-color: rgba(16,185,129,.5); color: var(--accent); background: rgba(16,185,129,.12); }
.cz-pipe-step.is-done .cz-pipe-title { color: var(--text); }
.cz-pipe-step.is-error .cz-pipe-dot { border-color: rgba(239,68,68,.55); color: #f87171; background: rgba(239,68,68,.12); }
.cz-pipe-step.is-error .cz-pipe-title { color: var(--text); font-weight: 600; }
.cz-pipe-step.is-error .cz-pipe-hint { color: #f87171; }
.cz-pipe-step.is-skipped { opacity: .5; }

/* Plakietka z nazwą projektu w pasku zakładek — nie może rozpychać paska. */
.cz-tab-badge {
  max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Lista wykrytych aplikacji — te same proporcje i rytm co tabela stosów. */
.dt.cz-apps { table-layout: fixed; width: 100%; }
.dt.cz-apps td, .dt.cz-apps th { overflow: hidden; }
.dt.cz-apps td { vertical-align: top; padding-top: 12px; padding-bottom: 12px; }
.dt.cz-apps tbody tr { transition: background .12s; }
.dt.cz-apps tbody tr:hover { background: var(--surface-2); }
.dt.cz-apps .cz-col-tech { width: 210px; }
.dt.cz-apps .cz-col-port { width: 92px; }
.dt.cz-apps .cz-col-src  { width: 130px; }
.dt.cz-apps td.act, .dt.cz-apps th.act { width: 200px; }
.dt.cz-apps td.act .btn.icon.sm { padding: 5px 7px; }
.dt.cz-apps td > div { min-width: 0; }

/* Nagłówek Studia AI: ikona + nazwa + ścieżka, bez rozpychania paska akcji. */
.cz-studio-title { display: flex; align-items: flex-start; gap: 10px; min-width: 0; }

@media (max-width: 1200px) {
  .dt.cz-apps .cz-col-tech { width: 160px; }
  .dt.cz-apps .cz-col-src  { width: 110px; }
  .dt.cz-apps td.act, .dt.cz-apps th.act { width: 176px; }
}

/* Tabela stosów Containerizer */
.dt.cz-stacks {
  width: 100%;
}
.dt.cz-stacks td {
  vertical-align: middle !important;
  padding-top: 12px;
  padding-bottom: 12px;
}
.cz-stack-tr {
  transition: background 0.15s ease;
}
.cz-stack-tr:hover {
  background: var(--surface-2);
}
.cz-stack-main {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
/* Tabela stosów Containerizer — pełna integracja z design systemem panelu */
.dt.cz-stacks { width: 100%; }
.dt.cz-stacks td { vertical-align: middle !important; padding-top: 10px; padding-bottom: 10px; }
.cz-stack-tr { transition: background 0.12s; }
.cz-stack-tr:hover { background: var(--surface-2); }
.cz-stack-main { display: flex; align-items: center; gap: 10px; min-width: 0; }
.cz-app-icon {
  width: 32px; height: 32px; border-radius: var(--radius-sm);
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; flex-shrink: 0;
  background: var(--surface-2); color: var(--accent);
  border: 1px solid var(--border);
}

.cz-adres-badge {
  display: inline-flex; align-items: center; gap: 6px;
  font-size: 12.5px; font-weight: 500;
  color: var(--text); text-decoration: none;
}
.cz-adres-badge:hover { color: var(--accent); text-decoration: underline; }
.cz-port-pill {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; color: var(--text-faint);
  font-family: var(--mono, monospace);
  padding: 2px 6px; border-radius: 4px;
  background: var(--surface-2); border: 1px solid var(--border);
}

/* ═══════════════════════════════════════════════════════════════════════════
   TABELA STOSÓW CONTAINERIZERA — Czytelność, Proporcje i Odstępy
   ═══════════════════════════════════════════════════════════════════════════ */
.dt.cz-stacks {
  width: 100%;
  border-collapse: collapse;
}
.dt.cz-stacks th {
  padding: 12px 18px;
  font-size: 11.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--text-faint);
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.dt.cz-stacks td {
  padding: 16px 18px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}
.dt.cz-stacks tr.cz-stack-tr:hover td {
  background: var(--surface-hover, rgba(0, 0, 0, 0.015));
}
.dt.cz-stacks tr.cz-stack-tr.is-expanded td {
  border-bottom: 0 !important;
  background: var(--surface-1);
}

.cz-stack-main {
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: 0;
}
.cz-app-icon {
  width: 40px;
  height: 40px;
  border-radius: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 17px;
  color: var(--sky);
  flex-shrink: 0;
}
.cz-app-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  line-height: 1.3;
  margin-bottom: 5px;
}
.cz-badges-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

/* Pasek ścieżki w wierszu tabeli */
.cz-route-strip {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 7px;
  font-size: 12px;
  color: var(--text-dim);
}
.cz-route-node {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--text-dim);
}
.cz-route-node code {
  font-family: var(--mono, monospace);
  font-size: 11.5px;
  background: var(--surface-3);
  padding: 2px 7px;
  border-radius: 5px;
  border: 1px solid var(--border);
  color: var(--text);
  line-height: 1.4;
}
.cz-route-node.is-target code {
  background: var(--sky-soft);
  border-color: var(--sky-edge);
  color: var(--sky);
  font-weight: 600;
}
.cz-route-arrow {
  color: var(--sky);
  font-size: 11px;
  display: inline-flex;
  align-items: center;
}
.cz-route-arrow.is-active i {
  animation: cz-arrow-pulse 1.5s ease-in-out infinite;
}
@keyframes cz-arrow-pulse {
  0%, 100% { transform: translateX(0); opacity: 0.5; }
  50% { transform: translateX(3px); opacity: 1; }
}

.cz-live-dot {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--green); display: inline-block;
  box-shadow: 0 0 6px var(--green);
  animation: cz-dot-pulse 1.8s ease-in-out infinite;
  margin-right: 4px;
}
@keyframes cz-dot-pulse {
  0%, 100% { transform: scale(0.9); opacity: 0.6; box-shadow: 0 0 4px var(--green); }
  50% { transform: scale(1.25); opacity: 1; box-shadow: 0 0 10px var(--green); }
}

/* Kolumny tabeli */
.dt.cz-stacks .cz-col-state { width: 140px; }
.dt.cz-stacks .cz-col-addr { width: 180px; }
.dt.cz-stacks th.act, .dt.cz-stacks td.act {
  width: 260px;
  min-width: 250px;
  text-align: right;
  white-space: nowrap;
}
.dt.cz-stacks td.act .flex {
  white-space: nowrap;
  flex-wrap: nowrap;
}

/* Rozwinięty wiersz szczegółów stosu */
.cz-stacks tr.cz-details-tr td.cz-details-td {
  padding: 4px 20px 24px 20px !important;
  border-bottom: 2px solid var(--border);
  background: var(--surface-1);
}
.cz-details-wrap {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

/* 1. Schemat Topologii Przeniesienia i Właścicieli (Karty Źródło i Cel) */
.cz-flow-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius, 12px);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}
.cz-flow-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 8px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.cz-flow-header .fw-7 {
  font-size: 14px;
}
.cz-flow-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}
.cz-flow-pane {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius, 12px);
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.cz-flow-pane:hover {
  border-color: var(--border-strong);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
}
.cz-flow-pane-title {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 700;
  color: var(--text);
  padding-bottom: 10px;
  border-bottom: 1px solid var(--border);
}
.cz-flow-kv-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.cz-flow-kv-row {
  display: grid;
  grid-template-columns: 140px 1fr;
  gap: 12px;
  align-items: center;
  font-size: 12.5px;
}
.cz-flow-kv-label {
  color: var(--text-faint);
  font-size: 12px;
  font-weight: 500;
  white-space: nowrap;
}
.cz-flow-kv-val {
  color: var(--text);
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: 12.5px;
}
.cz-flow-kv-val code {
  font-family: var(--mono, monospace);
  font-size: 12px;
  background: var(--surface-3);
  padding: 3px 8px;
  border-radius: 5px;
  border: 1px solid var(--border);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
  flex: 1;
  line-height: 1.5;
}

/* 2. Pasek Szybkich Akcji i Narzędzi Maszyny */
.cz-quick-actions-bar {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px 18px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius, 12px);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.03);
}
.cz-quick-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.cz-quick-label {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-dim);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-right: 6px;
  white-space: nowrap;
}
.cz-quick-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 7px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text);
  font-size: 12px;
  font-weight: 550;
  text-decoration: none;
  cursor: pointer;
  transition: all 0.16s cubic-bezier(0.4, 0, 0.2, 1);
  position: relative;
  line-height: 1.3;
}
.cz-quick-btn:hover {
  background: var(--surface-3);
  border-color: var(--border-strong);
  color: var(--text);
  transform: translateY(-1.5px);
  box-shadow: 0 3px 8px rgba(0, 0, 0, 0.07);
}
.cz-quick-btn:active {
  transform: translateY(0);
}
.cz-quick-btn i {
  font-size: 11.5px;
  transition: transform 0.18s ease;
}
.cz-quick-btn:hover i {
  transform: scale(1.15);
}
.cz-quick-btn.is-ai {
  background: linear-gradient(135deg, rgba(56, 189, 248, 0.08) 0%, rgba(16, 185, 129, 0.08) 100%);
  border-color: rgba(56, 189, 248, 0.28);
  color: var(--sky);
}
.cz-quick-btn.is-ai:hover {
  background: linear-gradient(135deg, rgba(56, 189, 248, 0.16) 0%, rgba(16, 185, 129, 0.16) 100%);
  border-color: var(--sky);
  color: var(--sky);
  box-shadow: 0 0 10px rgba(56, 189, 248, 0.2);
}

/* 3. Telemetria na żywo */
.cz-telemetry-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px;
}
.cz-telemetry-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius, 12px);
  padding: 14px 16px;
  display: flex;
  align-items: flex-start;
  gap: 12px;
  transition: transform 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;
}
.cz-telemetry-card:hover {
  border-color: var(--border-strong);
  transform: translateY(-1px);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.05);
}
.cz-telemetry-icon {
  width: 36px; height: 36px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center;
  font-size: 14px; flex-shrink: 0;
  background: var(--surface-3); color: var(--accent);
  border: 1px solid var(--border);
}
.cz-telemetry-icon.is-sky { color: var(--sky); background: var(--sky-soft); border-color: var(--sky-edge); }
.cz-telemetry-icon.is-purple { color: var(--purple); background: var(--purple-soft); }
.cz-telemetry-icon.is-green { color: var(--green); background: var(--green-soft); border-color: var(--green-edge); }
.cz-telemetry-icon.is-amber { color: var(--amber); background: var(--amber-soft); border-color: var(--amber-edge); }
.cz-telemetry-body {
  display: flex; flex-direction: column; min-width: 0; gap: 3px; flex: 1;
}
.cz-telemetry-lbl {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--text-faint);
}
.cz-telemetry-val {
  font-size: 14px; font-weight: 700; color: var(--text);
  font-family: var(--mono, monospace);
  display: flex; align-items: baseline; gap: 5px; flex-wrap: wrap;
  line-height: 1.35;
}
.cz-telemetry-sub {
  font-size: 11.5px; font-weight: 400; color: var(--text-faint);
  font-family: var(--font, inherit);
}

/* Wizualne paski obciążenia / zużycia zasobów */
.cz-meter-bar {
  width: 100%; height: 4px;
  background: var(--surface-3);
  border-radius: 99px;
  margin-top: 4px;
  overflow: hidden;
}
.cz-meter-fill {
  height: 100%; border-radius: 99px;
  transition: width 0.6s cubic-bezier(0.4, 0, 0.2, 1);
  background: var(--sky);
}
.cz-meter-fill.is-green { background: var(--green); }
.cz-meter-fill.is-amber { background: var(--amber); }

/* Przeglądarka katalogów */
.cz-dir-list {
  display: flex;
  flex-direction: column;
}
.cz-dir-item {
  transition: background 0.15s ease;
}
.cz-dir-item:hover {
  background: var(--surface-3) !important;
}
.cz-dir-item:last-child {
  border-bottom: 0 !important;
}

@media (max-width: 900px) {
  .cz-flow-columns { grid-template-columns: 1fr; }
  .dt.cz-stacks .cz-col-state { width: 110px; }
  .dt.cz-stacks .cz-col-addr { width: 150px; }
  .dt.cz-stacks td.act, .dt.cz-stacks th.act { width: 220px; }
}

@media (max-width: 900px) {
  .cz-flow-grid { grid-template-columns: 1fr; }
  .cz-flow-connector { padding: 6px 0; }
  .dt.cz-stacks .cz-col-state { width: 110px; }
  .dt.cz-stacks .cz-col-addr { width: 150px; }
  .dt.cz-stacks td.act, .dt.cz-stacks th.act { width: 220px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   TOKENY BAZOWE v2 — typografia, rytm, kontrast
   Powód: w panelu było 26 rozmiarów czcionki (40% deklaracji poniżej 12px),
   30 różnych atomów odstępu, 5 wysokości kontrolek i 9 wag — z czego trzy
   (550/650/680) Inter w ogóle nie dostarcza, więc przeglądarka je syntetyzowała.
   Nazwy klas zostają bez zmian; zmieniamy wyłącznie wartości.
   ═══════════════════════════════════════════════════════════════════════════ */
:root {
  /* Typografia: 6 stopni zamiast 26 */
  --fs-1: 12px;   /* mikroetykieta: nagłówek tabeli, odznaka, podpowiedź */
  --fs-2: 13px;   /* tekst drugorzędny: komórki tabel, przyciski */
  --fs-3: 14px;   /* baza: treść, pola formularzy */
  --fs-4: 16px;   /* tytuł karty i sekcji */
  --fs-5: 20px;   /* nagłówek widoku */
  --fs-6: 28px;   /* liczba miernika */
  --fs-icon: 11px;          /* jedyny wyjątek poniżej 12px: glify ikon */

  /* Wagi wyłącznie te, które Inter faktycznie ma */
  --fw-normal: 400; --fw-medium: 500; --fw-semi: 600; --fw-bold: 700;

  /* Interlinia: 3 stopnie zamiast 14 */
  --lh-tight: 1.25; --lh-base: 1.45; --lh-read: 1.6;

  /* Rytm: dotychczasowa skala plus dwa krańce */
  --s-0: 2px; --s-1: 4px; --s-2: 8px; --s-3: 12px;
  --s-4: 16px; --s-5: 24px; --s-6: 32px; --s-7: 48px;

  /* Promienie: 3 stopnie i pigułka; stare nazwy zostają jako aliasy */
  --r-0: 6px; --r-1: 8px; --r-2: 12px; --r-pill: 999px;
  --r-3: var(--r-2);
  --radius: var(--r-2);
  --radius-sm: var(--r-1);

  /* Jedna prowadnica wysokości: przycisk i pole przestają się rozjeżdżać */
  --ctl-h: 34px; --ctl-h-sm: 28px; --ctl-h-xs: 24px;
  --badge-h: 20px; --row-h: 40px;

  /* Kontrast. --t-0 było UŻYWANE, ale nigdzie niezdefiniowane — trzy elementy
     brały biel z fallbacku i w jasnym motywie znikały na białym tle. */
  --t-0: #ffffff;
  --t-3: #8892a4;           /* było #6f7889 → 4,11:1; teraz 5,83:1 na --n-1 */
  --t-4: #6f7889;           /* stara wartość: wyłącznie elementy nietekstowe */
  --text-faint: #8892a4;    /* było #828d9f → 4,39:1 na --surface-2 */
}

:root[data-theme="light"] {
  --t-0: #0b0f16;           /* bez tego biały tekst na białej karcie */
  --t-3: #5d6673;           /* było #6c7684 → 4,03:1 na --n-3; teraz 5,09:1 */
  --t-4: #6c7684;
  --text-faint: #5d6673;

  /* Kolory znaczeniowe przyciemnione do progu 4,5:1 — na białym tle
     poprzednie wartości miały 3,3–4,4:1, czyli dokładnie te elementy,
     które mają sygnalizować stan, były najsłabiej czytelne. */
  --accent: #047857; --accent-strong: #036b4d; --accent-soft: rgba(4,120,87,.12);
  --green: #047857;  --green-soft: rgba(4,120,87,.12);
  --sky: #0369a1;    --sky-soft: rgba(3,105,161,.10);
  --red: #c81e1e;    --red-soft: rgba(200,30,30,.10);
  --amber: #a4500a;  --amber-soft: rgba(164,80,10,.12);
}

/* ═══════════════════════════════════════════════════════════════════════════
   WARSTWA KOREKCYJNA — czytelność
   Leży na końcu pliku, więc rozstrzyga kaskadą, bez ruszania 4500 linii wyżej.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Ognisko klawiatury. Panel miał pięć razy „outline: none” i ani jednej
   reguły :focus-visible — nawigacja Tabem była niewidoczna. */
:where(a, button, .btn, .nav-link, .tab, .chip, [tabindex]):focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-1);
}

/* Jedna reguła zamiast szesnastu punktowych bloków: 71 animacji chodziło
   w nieskończonej pętli, w tym pulsująca kropka przy każdym statusie. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Tabele: wspólna typografia i niższy wiersz — więcej danych bez ścieśnienia. */
.dt, table.tbl { font-size: var(--fs-2); line-height: var(--lh-base); }
.dt th, .tbl th {
  font-size: var(--fs-1); font-weight: var(--fw-semi);
  letter-spacing: .04em; color: var(--t-2);
  padding: var(--s-2) var(--s-4);
}
.dt td, .tbl td { padding: 10px var(--s-4); color: var(--t-2); }
.dt .primary-cell { color: var(--t-1); font-weight: var(--fw-semi); }
.dt.dense td, .tbl.dense td { padding: 6px var(--s-4); }

/* Karty i sekcje dostają wspólny rytm 12/16 — dotąd .card miał 14/18,
   czyli wartości spoza jakiejkolwiek skali. */
.card-header, .sec-head, .toolbar { padding: var(--s-3) var(--s-4); }
.card-body, .sec-body, .metric { padding: var(--s-4); }
.card-body.tight, .sec-body.flush { padding: 0; }

/* Tytuł 16px nad treścią 13px daje widoczną hierarchię; 14 nad 13 nie dawało. */
.card-title, .sec-head .sec-title {
  font-size: var(--fs-4); font-weight: var(--fw-semi);
  color: var(--t-1); line-height: var(--lh-tight);
}
.card-sub, .sec-head .sec-sub, .f-hint, .metric .m-label, .metric .m-foot,
.view-head .vh-desc, .blank .b-desc {
  font-size: var(--fs-1); color: var(--t-3); line-height: var(--lh-base);
}

/* Kontrolki na jednej prowadnicy: przycisk 34px, pole 34px. Dotąd 39 vs 44,
   więc każdy pasek narzędzi nad tabelą miał poszarpaną linię bazową. */
.btn {
  height: var(--ctl-h); padding: 0 var(--s-3);
  font-size: var(--fs-2); font-weight: var(--fw-semi);
  border-radius: var(--r-1); line-height: 1; box-shadow: none;
}
.btn.sm { height: var(--ctl-h-sm); padding: 0 10px; font-size: var(--fs-1); }
.btn.xs { height: var(--ctl-h-xs); padding: 0 var(--s-2); font-size: var(--fs-1); border-radius: var(--r-1); }
.btn.icon { width: var(--ctl-h); height: var(--ctl-h); padding: 0; }
.btn.icon.sm { width: var(--ctl-h-sm); height: var(--ctl-h-sm); }
.input, .select {
  height: var(--ctl-h); padding: 0 var(--s-3);
  font-size: var(--fs-3); border-radius: var(--r-1); box-shadow: none;
}
textarea.input {
  height: auto; min-height: 84px; padding: var(--s-2) var(--s-3);
  font-size: var(--fs-3); line-height: var(--lh-read);
}

/* Odznaki miały dwie sprzeczne definicje (waga 700 kontra 550). */
.badge {
  height: var(--badge-h); padding: 0 var(--s-2); font-size: var(--fs-1);
  font-weight: var(--fw-semi); border-radius: var(--r-pill); line-height: 1;
}
.badge.sm { height: 18px; padding: 0 7px; font-size: var(--fs-1); }

/* Znaczenie stanu przestaje wisieć na siedmiopikselowej kropce. */
.state { font-size: var(--fs-2); color: var(--t-2); }
.state.ok { color: var(--green); }
.state.warn { color: var(--amber); }
.state.bad { color: var(--red); }
.state.info { color: var(--sky); }

/* Jeden odstęp dla siatek tego samego poziomu — było 14 / 12 / 16px. */
.grid, .metrics, .section-gap { gap: var(--s-4); }

/* Neumorficzne cienie na wszystkim sprawiały, że nic się nie wyróżniało:
   skoro każdy element jest wyniesiony, wyniesienie przestaje coś znaczyć. */
:where(.card, .btn, .badge, .input, .select, .metric, .sec, .chip) { box-shadow: none; }

/* Kolory wpisane pod ciemne tło, przez co w jasnym motywie bladły. */
.btn:hover { color: var(--t-1); }
.tab.active, .nav-link.active { color: var(--accent); }

/* Menu „⋯” w wierszach tabel — rzadsze akcje z podpisami zamiast ściany ikon. */
.row-menu { position: relative; display: inline-flex; }
.row-menu-backdrop { position: fixed; inset: 0; z-index: 40; }
.row-menu-list {
  position: absolute; right: 0; top: calc(100% + 4px); z-index: 41;
  display: flex; flex-direction: column; min-width: 208px; padding: var(--s-1);
  background: var(--n-2, var(--surface-2));
  border: 1px solid var(--n-line, var(--border));
  border-radius: var(--r-1); box-shadow: 0 10px 28px rgba(0,0,0,.35);
  /* RowMenu nadpisuje pozycję na `fixed` (ucieczka z przycinającej tabeli);
     przy niskim oknie lista musi dać się przewinąć, a nie chować akcje. */
  overflow-y: auto;
}
.row-menu-item {
  display: flex; align-items: center; gap: var(--s-2);
  padding: var(--s-2) var(--s-3); border: 0; background: transparent;
  color: var(--t-2); font-size: var(--fs-2); font-family: var(--font);
  text-align: left; white-space: nowrap; cursor: pointer; border-radius: var(--r-0);
}
.row-menu-item:hover { background: var(--n-3, var(--surface-3)); color: var(--t-1); }
.row-menu-item:disabled { opacity: .45; cursor: not-allowed; }
.row-menu-item.is-danger { color: var(--red); }
.row-menu-item.is-danger:hover { background: var(--red-soft); }
.row-menu-item > i { width: 14px; text-align: center; color: var(--t-3); }
.row-menu-item.is-danger > i { color: var(--red); }
.row-menu-empty { padding: var(--s-2) var(--s-3); color: var(--t-3); font-size: var(--fs-1); }

/* Przełącznik w formularzach (Strażnik węzła, okno serwisowe).
   Klasa była używana w szablonie, ale nie miała żadnej reguły — checkbox
   renderował się bez wyrównania do etykiety. */
.switch {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-3); color: var(--t-1); cursor: pointer;
}
.switch > input { flex: none; width: 16px; height: 16px; accent-color: var(--accent); margin: 0; }
.switch > span { line-height: var(--lh-tight); }

/* ═══════════════════════════════════════════════════════════════════════════
   WIDOK MASZYNY — gęstość, zwijanie i hierarchia
   Strona urosła organicznie do sześciu sekcji i 26 wierszy faktów w jednej
   kolumnie. Poniżej brakujące warianty istniejących komponentów — bez nowych
   bytów, żeby nie budować drugiego systemu obok już działającego.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Fakt niosący listę zamiast jednej wartości (dyski, procesy, interfejsy).
   Zastępuje powtarzany pięciokrotnie blok stylów inline. */
.facts .fact.is-list { align-items: flex-start; }
.facts .fact.is-list > .f-val {
  display: flex; flex-direction: column; align-items: flex-end;
  gap: var(--s-1); font-weight: var(--fw-normal); line-height: var(--lh-base);
}

/* Fakty w dwóch kolumnach. Krótkie wartości nie potrzebują całej szerokości
   karty — kilkanaście wierszy w jednej kolumnie to tyle samo skoków wzroku. */
.facts.auto {
  display: grid; column-gap: var(--s-5);
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
}
.facts.auto > .fact { border-top: 0; }
.facts.cols { display: grid; grid-template-columns: 1fr; column-gap: var(--s-5); }
@media (min-width: 760px) {
  .facts.cols { grid-template-columns: 1fr 1fr; }
  .facts.cols > .fact:nth-child(2) { border-top: 0; }
}

/* Podsekcja wewnątrz .sec-body. Wcześniej zagnieżdżano pełne .sec z tłem
   podanym inline ze starej palety, przez co element nie reagował na motyw
   tak jak reszta karty. */
.subsec {
  background: var(--n-2); border: 1px solid var(--n-line);
  border-radius: var(--r-1); overflow: hidden;
}
.sec-body > .subsec { margin-top: var(--s-4); }
.subsec > .sec-head { padding: var(--s-2) var(--s-3); }
.subsec > .sec-body { padding: var(--s-3); }
.subsec > .sec-foot { padding: var(--s-2) var(--s-3); }
.subsec > .sec-head .sec-title { font-size: var(--fs-3); }

/* Sekcja zwijana. Nagłówek staje się przyciskiem; stan sekcji zostaje w nim
   widoczny, więc zwinięcie nigdy nie ukrywa sygnału — tylko szczegóły. */
button.sec-head {
  width: 100%; font: inherit; text-align: left; cursor: pointer;
  background: none; color: inherit;
  border: 0; border-bottom: 1px solid var(--n-line);
  transition: background .15s;
}
button.sec-head:hover { background: var(--n-2); }
.sec-caret { flex: none; width: 12px; font-size: var(--fs-icon); color: var(--t-3); }
.sec.is-closed > .sec-head { border-bottom: 0; }

/* Zwijanie sekcji, której nagłówek ma też własne przyciski akcji: klikalny jest
   sam tytuł, a nie cały pasek — inaczej „Odśwież” zwijałby sekcję przy okazji. */
.sec-head-toggle {
  display: flex; align-items: center; gap: var(--s-3);
  flex: 1 1 auto; min-width: 0;
  padding: 0; border: 0; background: none; cursor: pointer; text-align: left;
  font-family: var(--font); color: inherit;
}
.sec-head-toggle > .grow { display: flex; flex-direction: column; min-width: 0; }
.sec-head-toggle .sec-title,
.sec-head-toggle .sec-sub { display: block; }
.sec-head-toggle:hover .sec-title { color: var(--accent); }
.sec-head-toggle:hover .sec-caret { color: var(--accent); }

/* Rytm pionowy wewnątrz sekcji. Reguła ogólna obejmuje tylko dzieci korzenia
   widoku, więc bloki w .sec-body dostawały odstęp ręcznie — mt-1/mt-2/mt-3
   wymiennie, kilkanaście razy w jednym widoku. */
.sec-body > :is(.facts, .metrics, .note, .subsec, .issues, .table-wrap)
  + :is(.facts, .metrics, .note, .subsec, .issues, .table-wrap) { margin-top: var(--s-4); }

/* Propozycja autofixu SEO — wyraźnie oddzielona od ustaleń modelu, bo to
   jedyne miejsce, gdzie treść trafia na publiczną stronę po zatwierdzeniu. */
.gseo-fix {
  border: 1px solid var(--accent); border-radius: var(--r-2);
  background: var(--accent-soft); padding: var(--s-4);
}
.gseo-fix-row { padding-block: var(--s-2); border-top: 1px solid var(--n-line); }
.gseo-fix-row:first-of-type { border-top: none; }
.gseo-fix-old { text-decoration: line-through; opacity: .75; margin-top: 2px; }

/* ═══════════════════════════════════════════════════════════════════════════
   WIDOK MASZYNY — czytelność, wizualizacja, wyjaśnienia
   Zgłoszenie brzmiało „nie wiadomo, co się dzieje i gdzie co jest”. To nie był
   brak danych, tylko brak trzech rzeczy: modelu drogi, jaką pokonuje ruch;
   podziału strony na powody, dla których się na nią wchodzi; oraz wyjaśnień
   przy nazwach, które rozumie wyłącznie autor panelu.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Dymek z wyjaśnieniem ──────────────────────────────────────────────────
   Wisi na <body>, więc nie obcina go overflow karty ani tabeli. */
.tip-pop {
  position: fixed; z-index: 4000; max-width: 320px;
  padding: 10px 12px; border-radius: var(--r-1);
  background: var(--n-3); border: 1px solid var(--n-line-2);
  box-shadow: 0 12px 32px rgba(0,0,0,.45);
  font-family: var(--font); font-size: 12.5px; line-height: 1.5; color: var(--t-2);
  opacity: 0; visibility: hidden; transform: translateY(4px);
  transition: opacity .14s ease, transform .14s ease, visibility .14s;
  pointer-events: none;
}
.tip-pop.is-on { opacity: 1; visibility: visible; transform: none; }
.tip-pop b { display: block; color: var(--t-0); font-weight: var(--fw-semi); margin-bottom: 3px; font-size: 13px; }
.tip-pop::after {
  content: ""; position: absolute; bottom: -6px;
  left: var(--tip-arrow, 50%); margin-left: -5px;
  width: 10px; height: 10px; transform: rotate(45deg);
  background: var(--n-3); border: 1px solid var(--n-line-2);
  border-top: 0; border-left: 0;
}
.tip-pop.is-below::after { bottom: auto; top: -6px; border: 1px solid var(--n-line-2); border-bottom: 0; border-right: 0; }

/* Znaczek „?" — musi być WIDOCZNY, bo niewidoczna pomoc nie istnieje */
.hint-dot {
  display: inline-flex; align-items: center; justify-content: center;
  width: 15px; height: 15px; margin-left: 5px; padding: 0; vertical-align: -2px;
  border: 0; border-radius: 50%; cursor: help;
  background: transparent; color: var(--t-4); font-size: 11.5px; line-height: 1;
  transition: color .14s, transform .14s;
}
.hint-dot:hover, .hint-dot:focus-visible { color: var(--accent); transform: scale(1.15); outline: none; }

/* ── Przewodnik po stronie ─────────────────────────────────────────────── */
.mach-guide {
  background: var(--accent-soft); border: 1px solid var(--green-edge);
  border-radius: var(--r-2); padding: var(--s-4); margin-bottom: var(--s-4);
}
.mach-guide .mg-head {
  display: flex; align-items: center; gap: var(--s-2);
  font-size: var(--fs-3); color: var(--t-1);
}
.mach-guide .mg-head > i { color: var(--accent); }
.mach-guide .mg-close { margin-left: auto; }
.mach-guide .mg-steps {
  margin: var(--s-3) 0 0; padding-left: 20px;
  display: flex; flex-direction: column; gap: var(--s-2);
  font-size: 12.5px; color: var(--t-2); line-height: var(--lh-read);
}
.mach-guide .mg-steps b { color: var(--t-1); font-weight: var(--fw-semi); }
.mach-guide .mg-steps i { color: var(--t-3); }

/* ── Werdykt + ścieżka ruchu ───────────────────────────────────────────── */
.mach-hero {
  background: var(--n-1); border: 1px solid var(--n-line);
  border-radius: var(--r-2); overflow: hidden; margin-bottom: var(--s-4);
  border-left: 3px solid var(--n-4);
}
.mach-hero.is-ok   { border-left-color: var(--green); }
.mach-hero.is-warn { border-left-color: var(--amber); }
.mach-hero.is-bad  { border-left-color: var(--red); }

.mh-verdict { display: flex; align-items: center; gap: var(--s-4); padding: var(--s-4); }
.mh-mark {
  width: 46px; height: 46px; border-radius: 50%; flex: 0 0 auto;
  display: grid; place-items: center; font-size: 20px;
  background: var(--n-2); border: 1px solid var(--n-line-2); color: var(--t-3);
}
.mach-hero.is-ok   .mh-mark { color: var(--green); border-color: var(--green-edge); background: var(--green-soft); }
.mach-hero.is-warn .mh-mark { color: var(--amber); border-color: var(--amber-edge); background: var(--amber-soft); }
.mach-hero.is-bad  .mh-mark { color: var(--red);   border-color: var(--red-edge);   background: var(--red-soft); }
.mach-hero.is-bad  .mh-mark { animation: mh-alarm 2.2s ease-in-out infinite; }
@keyframes mh-alarm {
  0%, 100% { box-shadow: 0 0 0 0 rgba(248,113,113,.35); }
  50%      { box-shadow: 0 0 0 7px rgba(248,113,113,0); }
}
.mh-text { min-width: 0; flex: 1 1 auto; }
.mh-title { font-size: var(--fs-5); font-weight: 650; color: var(--t-1); line-height: var(--lh-tight); }
.mh-sub { font-size: var(--fs-2); color: var(--t-3); margin-top: 2px; }
.mh-refresh { flex: 0 0 auto; }

/* Ogniwa drogi: internet → enode → tunel → maszyna → aplikacje */
.flow {
  display: flex; align-items: stretch; gap: 0;
  padding: 0 var(--s-4) var(--s-3); flex-wrap: nowrap; overflow-x: auto;
}
.flow-node {
  flex: 1 1 0; min-width: 104px;
  display: flex; flex-direction: column; align-items: center; gap: 5px;
  padding: var(--s-3) var(--s-2); border-radius: var(--r-1);
  background: none; border: 1px solid transparent; cursor: pointer;
  font-family: var(--font); text-align: center;
  transition: background .16s, border-color .16s, transform .16s;
}
.flow-node:hover { background: var(--n-2); border-color: var(--n-line); transform: translateY(-2px); }
.fn-ico {
  width: 38px; height: 38px; border-radius: 50%; display: grid; place-items: center;
  font-size: 15px; background: var(--n-2); border: 1px solid var(--n-line-2); color: var(--t-3);
  transition: color .2s, border-color .2s, background .2s;
}
.flow-node.is-ok   .fn-ico { color: var(--green); border-color: var(--green-edge); background: var(--green-soft); }
.flow-node.is-warn .fn-ico { color: var(--amber); border-color: var(--amber-edge); background: var(--amber-soft); }
.flow-node.is-bad  .fn-ico { color: var(--red);   border-color: var(--red-edge);   background: var(--red-soft); }
.flow-node.is-wait .fn-ico { color: var(--sky);   border-color: var(--sky-edge);   background: var(--sky-soft); }
.flow-node.is-bad  .fn-ico { animation: fn-shake 3s ease-in-out infinite; }
@keyframes fn-shake { 0%,88%,100% { transform: none; } 92% { transform: translateX(-2px); } 96% { transform: translateX(2px); } }
.fn-label {
  font-size: 12px; font-weight: var(--fw-semi); color: var(--t-1);
  max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.fn-state { font-size: 11px; color: var(--t-3); line-height: 1.3; }
.flow-node.is-bad .fn-state { color: var(--red); }
.flow-node.is-warn .fn-state { color: var(--amber); }

/* Ogniwo między węzłami: kropka płynie w stronę maszyny, gdy droga jest drożna */
.flow-link {
  flex: 0 1 46px; min-width: 22px;
  padding-top: calc(var(--s-3) + 18px);   /* wysokość środka kółka ikony w węźle obok */
}
.fl-track {
  position: relative; display: block; width: 100%; height: 2px; border-radius: 2px;
  background: var(--n-4);
}
.fl-pip {
  position: absolute; top: -2px; left: 0; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent); opacity: 0;
}
.flow-link.is-live .fl-track { background: linear-gradient(90deg, var(--green-edge), var(--green)); }
.flow-link.is-live .fl-pip { opacity: 1; animation: fl-run 1.8s linear infinite; }
@keyframes fl-run { 0% { left: 0; opacity: 0; } 15% { opacity: 1; } 85% { opacity: 1; } 100% { left: 100%; opacity: 0; } }
.flow-link.is-cut .fl-track {
  background: repeating-linear-gradient(90deg, var(--red) 0 5px, transparent 5px 10px);
}
.flow-link.is-wait .fl-track {
  background: repeating-linear-gradient(90deg, var(--sky) 0 5px, transparent 5px 10px);
}
.flow-link.is-idle .fl-track {
  background: repeating-linear-gradient(90deg, var(--n-4) 0 5px, transparent 5px 10px);
}

.flow-legend {
  display: flex; gap: var(--s-2); align-items: flex-start;
  padding: var(--s-3) var(--s-4); border-top: 1px solid var(--n-line);
  background: var(--n-2); font-size: 12.5px; color: var(--t-3); line-height: var(--lh-base);
}
.flow-legend > i { margin-top: 2px; color: var(--t-4); }

@media (max-width: 720px) {
  .flow { flex-direction: column; }
  .flow-node { flex-direction: row; justify-content: flex-start; text-align: left; gap: var(--s-3); }
  .flow-node .fn-label, .flow-node .fn-state { max-width: none; }
  .flow-link { flex: 0 0 18px; padding: 0 0 0 27px; }   /* oś kółek w układzie pionowym */
  .fl-track { width: 2px; height: 100%; min-height: 16px; }
  .flow-link.is-live .fl-track { background: linear-gradient(180deg, var(--green-edge), var(--green)); }
  .fl-pip { display: none; }
}

/* ── Mierniki pierścieniowe ────────────────────────────────────────────── */
/* Siatka na flexie, nie na grid-template-columns. Powód jest konkretny: w siatce
   ostatni wiersz zostaje niedopełniony i pojedynczy kafelek wisi samotnie przy
   lewej krawędzi. Tu kafelki ostatniego wiersza rozciągają się na całą szerokość,
   więc dowolna ich liczba wygląda na zamierzoną. Górna granica pilnuje, żeby
   samotny kafelek nie rozlał się na cały ekran. */
.kpis { display: flex; flex-wrap: wrap; gap: var(--s-3); margin-bottom: var(--s-4); }
.kpis > .kpi { flex: 1 1 210px; max-width: 420px; }
.kpi {
  display: flex; align-items: center; gap: var(--s-3);
  background: var(--n-1); border: 1px solid var(--n-line);
  border-radius: var(--r-2); padding: var(--s-3) var(--s-4);
}
.kpi-ring { position: relative; width: 52px; height: 52px; flex: 0 0 auto; }
.kpi-ring svg { width: 100%; height: 100%; transform: rotate(-90deg); }
.kpi-ring circle { fill: none; stroke-width: 4; stroke-linecap: round; }
.kpi-ring .kr-bg { stroke: var(--n-3); }
.kpi-ring .kr-fg { stroke: var(--t-4); transition: stroke-dashoffset .8s cubic-bezier(.16,1,.3,1), stroke .3s; }
.kpi.is-ok   .kr-fg { stroke: var(--green); }
.kpi.is-warn .kr-fg { stroke: var(--amber); }
.kpi.is-bad  .kr-fg { stroke: var(--red); }
.kpi-ico {
  position: absolute; inset: 0; display: grid; place-items: center;
  font-size: 14px; color: var(--t-4);
}
.kpi.is-ok   .kpi-ico { color: var(--green); }
.kpi.is-warn .kpi-ico { color: var(--amber); }
.kpi.is-bad  .kpi-ico { color: var(--red); }
.kpi-body { min-width: 0; flex: 1 1 auto; }
.kpi-label {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  font-weight: var(--fw-semi); color: var(--t-3);
  display: flex; align-items: center;
}
.kpi-val { font-size: 21px; font-weight: 680; color: var(--t-1); line-height: 1.15; font-variant-numeric: tabular-nums; }
/* Wartość słowna („do wymiany", „nieznane") nie mieści się w stopniu pisma
   przewidzianym dla dwóch cyfr i procenta. */
.kpi-val.is-word { font-size: 17px; letter-spacing: -.01em; }
.kpi.is-warn .kpi-val { color: var(--amber); }
.kpi.is-bad  .kpi-val { color: var(--red); }
.kpi-foot { font-size: 11.5px; color: var(--t-3); margin-top: 1px; line-height: 1.35; }
.kpis > .kpi.is-empty { flex-basis: 100%; max-width: none; }
.kpi.is-empty .kpi-foot { max-width: 72ch; }

/* ── Szkielet kafelka ──────────────────────────────────────────────────────
   Ma dokładnie wymiary gotowego kafelka: to jedyny sposób, żeby wstawienie
   prawdziwych danych nie przesunęło ani jednego piksela niżej. */
.kpi.is-skeleton { pointer-events: none; animation: none; }
.sz-ring, .sz-line { display: block; border-radius: 999px; }
.sz-ring { width: 52px; height: 52px; border-radius: 50%; }
.sz-etykieta { width: 58%; height: 9px;  margin: 4px 0 5px; }   /* wiersz etykiety: 18 px */
.sz-wartosc  { width: 44%; height: 14px; margin: 0 0 10px; }    /* wiersz wartości: 24 px */
.sz-stopka   { width: 78%; height: 9px;  margin: 0 0 7px; }     /* wiersz stopki:   16 px */

/* Komunikat o ładowaniu wyłącznie dla czytników ekranu. Widoczny pasek „czekam"
   sam byłby skokiem układu — pojawiałby się i znikał dokładnie wtedy, gdy
   szkielety mają go nie dopuścić. Widzącym mówi to migotanie i kręcąca się
   strzałka odświeżania w nagłówku. */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ── Zakładki ──────────────────────────────────────────────────────────── */
.mtabs {
  display: flex; gap: var(--s-1); flex-wrap: wrap;
  border-bottom: 1px solid var(--n-line); margin-bottom: var(--s-2);
}
.mtab {
  position: relative; display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 10px var(--s-3); margin-bottom: -1px;
  background: none; border: 0; border-bottom: 2px solid transparent;
  font-family: var(--font); font-size: 13px; font-weight: var(--fw-medium);
  color: var(--t-3); cursor: pointer;
  transition: color .16s, border-color .16s;
}
.mtab:hover { color: var(--t-1); }
.mtab.is-on { color: var(--t-0); border-bottom-color: var(--accent); font-weight: var(--fw-semi); }
.mtab > i { font-size: var(--fs-icon); opacity: .9; }
.mtab .mt-count {
  min-width: 19px; height: 19px; padding: 0 5px; border-radius: 999px;
  display: inline-grid; place-items: center;
  background: var(--n-3); color: var(--t-2);
  font-size: 11px; font-variant-numeric: tabular-nums;
}
.mtab.is-on .mt-count { background: var(--accent-soft); color: var(--accent); }
.mtab .mt-alarm { width: 7px; height: 7px; border-radius: 50%; background: var(--t-4); }
.mtab .mt-alarm.is-bad  { background: var(--red);   animation: state-pulse 1.6s ease-in-out infinite; }
.mtab .mt-alarm.is-warn { background: var(--amber); }
.mtab .mt-alarm.is-info { background: var(--sky); }
@media (max-width: 620px) {
  .mtabs { flex-wrap: nowrap; overflow-x: auto; }
  .mtab { white-space: nowrap; }
}

.mtab-desc {
  display: flex; gap: var(--s-2); align-items: baseline;
  font-size: 12.5px; color: var(--t-3); line-height: var(--lh-base);
  padding: 0 2px var(--s-3);
}
.mtab-desc > i { font-size: 10px; color: var(--t-4); }
.mtab-panel { min-height: 220px; }

/* ── Kafelki „co ta maszyna robi” ──────────────────────────────────────── */
.rolki { display: grid; gap: var(--s-3); grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
.rolka {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: var(--s-3) var(--s-4); border-radius: var(--r-1);
  background: var(--n-2); border: 1px solid var(--n-line); cursor: pointer;
  font-family: var(--font); text-align: left;
  transition: border-color .16s, transform .16s, background .16s;
}
.rolka:hover { border-color: var(--n-4); background: var(--n-3); transform: translateY(-2px); }
.rolka-ico { font-size: 14px; color: var(--t-4); }
.rolka.is-ok   .rolka-ico { color: var(--green); }
.rolka.is-warn .rolka-ico { color: var(--amber); }
.rolka.is-info .rolka-ico { color: var(--sky); }
.rolka-num { font-size: 24px; font-weight: 680; color: var(--t-1); line-height: 1.1; font-variant-numeric: tabular-nums; }
.rolka-lab { font-size: 12.5px; font-weight: var(--fw-semi); color: var(--t-2); }
.rolka-sub { font-size: 11.5px; color: var(--t-3); }

/* ── Słupki obciążenia z zaznaczonym progiem ───────────────────────────── */
.bary { display: flex; flex-direction: column; gap: var(--s-3); }
.bar-row {
  display: grid; align-items: center; gap: 4px var(--s-3);
  grid-template-columns: minmax(120px, 190px) 1fr auto;
}
.bar-key { font-size: 12.5px; color: var(--t-2); display: flex; align-items: center; }
.bar-track {
  position: relative; height: 9px; border-radius: 999px;
  background: var(--n-3); overflow: hidden;
}
.bar-fill {
  display: block; height: 100%; border-radius: 999px; background: var(--t-4);
  transition: width .8s cubic-bezier(.16,1,.3,1), background .3s;
}
.bar-fill.is-ok   { background: var(--green); }
.bar-fill.is-warn { background: var(--amber); }
.bar-fill.is-bad  { background: var(--red); }
.bar-mark { position: absolute; top: -2px; bottom: -2px; width: 2px; background: var(--n-line-2); }
.bar-val { font-size: 13.5px; font-weight: 650; color: var(--t-1); font-variant-numeric: tabular-nums; }
.bar-val.is-warn { color: var(--amber); }
.bar-val.is-bad  { color: var(--red); }
.bar-foot { grid-column: 2 / -1; font-size: 11.5px; color: var(--t-3); }
@media (max-width: 620px) {
  .bar-row { grid-template-columns: 1fr auto; }
  .bar-key { grid-column: 1 / -1; }
  .bar-foot { grid-column: 1 / -1; }
}

/* ── Dziennik strażnika ────────────────────────────────────────────────── */
.dziennik { margin-top: var(--s-4); border-top: 1px solid var(--n-line); }
.dziennik .dz-head {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  font-weight: var(--fw-semi); color: var(--t-3); padding: var(--s-3) 0 var(--s-2);
}
.dz-row {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  padding: var(--s-2) 0; border-top: 1px solid var(--n-line); font-size: 12.5px;
}
.dz-stos { color: var(--t-1); }
.dz-czas { color: var(--t-3); font-size: 11.5px; margin-left: auto; }
.dz-detal { flex: 1 1 100%; color: var(--t-3); font-size: 12px; }

/* ── Wynik skanu portów ────────────────────────────────────────────────── */
.porty { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.port {
  display: inline-flex; align-items: center; gap: var(--s-2);
  padding: 6px 12px; border-radius: 999px; cursor: help;
  border: 1px solid var(--n-line-2); background: var(--n-2);
}
.port.is-open { border-color: var(--green-edge); background: var(--green-soft); }
.port.is-shut { opacity: .7; }
.port-num { font-size: 13px; font-weight: 650; color: var(--t-1); }
.port-st { font-size: 11.5px; color: var(--t-3); }
.port.is-open .port-st { color: var(--green); }

/* ── Diagnoza AI ───────────────────────────────────────────────────────── */
.diag-cta { display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; }
.diag-cta-desc { font-size: 12.5px; color: var(--t-3); max-width: 52ch; line-height: var(--lh-base); }
.diag-praca { margin-top: var(--s-3); }
.diag-praca .dp-krok { font-size: 12.5px; color: var(--t-3); }
.diag-praca .dp-bar {
  margin-top: 6px; height: 4px; border-radius: 999px; background: var(--n-3); overflow: hidden;
}
.diag-praca .dp-bar > span {
  display: block; height: 100%; width: 35%; border-radius: 999px; background: var(--accent);
  animation: dp-slide 1.4s ease-in-out infinite;
}
@keyframes dp-slide { 0% { transform: translateX(-110%); } 100% { transform: translateX(320%); } }

/* ── Sekcja alarmowa ───────────────────────────────────────────────────── */
.sec.sec-alert { border-color: var(--amber-edge); }
.sec.sec-alert > .sec-head .sec-title { display: flex; align-items: center; gap: var(--s-2); color: var(--t-0); }
.sec.sec-alert > .sec-head .sec-title > i { color: var(--amber); }


/* Kropka stanu w nagłówku pulsuje tylko wtedy, gdy stan jest żywy */
.state.live.ok::before { animation: state-breathe 2.4s ease-in-out infinite; }
.state.live.bad::before { animation: state-pulse 1.4s ease-in-out infinite; }
@keyframes state-breathe {
  0%, 100% { box-shadow: 0 0 0 0 rgba(52,211,153,.5); }
  50%      { box-shadow: 0 0 0 5px rgba(52,211,153,0); }
}

.mach-foot {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  margin-top: var(--s-5); padding-top: var(--s-3);
  border-top: 1px solid var(--n-line);
}

/* ── Przejścia ─────────────────────────────────────────────────────────── */
.tabswap-enter-active { transition: opacity .22s ease, transform .22s cubic-bezier(.16,1,.3,1); }
.tabswap-leave-active { transition: opacity .12s ease; }
.tabswap-enter-from { opacity: 0; transform: translateY(8px); }
.tabswap-leave-to { opacity: 0; }

.zwin-enter-active, .zwin-leave-active {
  transition: opacity .2s ease, transform .2s cubic-bezier(.16,1,.3,1);
  overflow: hidden;
}
.zwin-enter-from, .zwin-leave-to { opacity: 0; transform: translateY(-6px); }

/* Ruch bywa przeszkodą, nie ozdobą — kto o to poprosił w systemie, dostaje spokój */
@media (prefers-reduced-motion: reduce) {
  .fl-pip, .mh-mark, .flow-node .fn-ico, .state.live::before,
  .diag-praca .dp-bar > span, .mtab .mt-alarm { animation: none !important; }
  .kpi, .port, .sec.sec-alert .issue { animation: none !important; }
  /* Szkielet zostaje — bez ruchu, ale nadal trzyma wysokość */
  .sz-ring::after, .sz-line::after { animation: none !important; opacity: 0; }
  .kpi, .rolka, .flow-node, .port, .sec.sec-alert .issue, .mkarta, .akarta, .lrow, .hkarta,
  .kpi-ring .kr-fg, .kpi-ico, .bar-fill, .rolka-num.is-czeka,
  .pl-znacznik .pl-kropka, .tr-fill, .mkb-fill { animation: none !important; }
  .pl-znacznik, .tr-fill { transition: none !important; }
  .tabswap-enter-active, .tabswap-leave-active,
  .zwin-enter-active, .zwin-leave-active { transition: none !important; }
  .kpi-ring .kr-fg, .bar-fill { transition: none !important; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   RUCH — kaskada wejścia, rysowanie pierścieni, ładowanie
   Zasada: animacja ma nieść informację, nie ozdabiać. Kaskada prowadzi wzrok
   w kolejności czytania, pierścień rysuje się, żeby pokazać SKALĘ wartości,
   a szkielet trzyma wysokość, żeby nic nie skoczyło. Nic nie trwa dłużej niż
   sekundę i nic nie powtarza się w kółko poza tym, co naprawdę jest w toku.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Jedna kaskada dla wszystkich siatek: element podaje swój numer w --i */
.kpi, .rolka, .flow-node, .sec.sec-alert .issue, .port {
  animation: wejscie .42s cubic-bezier(.16,1,.3,1) both;
  animation-delay: calc(var(--i, 0) * 45ms);
}
@keyframes wejscie {
  from { opacity: 0; transform: translateY(9px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* Pierścień rysuje się od zera do swojej wartości. Klatka „from" wystarcza —
   klatką końcową jest własna wartość elementu, więc nie trzeba jej powtarzać
   w CSS i nie rozjedzie się z tą policzoną w JS. */
.kpi-ring .kr-fg {
  animation: pierscien .95s cubic-bezier(.16,1,.3,1) backwards;
  animation-delay: calc(var(--i, 0) * 45ms + 60ms);
}
@keyframes pierscien { from { stroke-dashoffset: 125.66; } }

/* Ikona w środku pierścienia dochodzi chwilę po nim */
.kpi-ico {
  animation: ikona .5s cubic-bezier(.16,1,.3,1) both;
  animation-delay: calc(var(--i, 0) * 45ms + 180ms);
}
@keyframes ikona { from { opacity: 0; transform: scale(.6); } to { opacity: 1; transform: none; } }

/* Szkielet nie wjeżdża kaskadą — ma stać nieruchomo i tylko migotać,
   inaczej ładowanie wygląda jak druga animacja treści. */
.kpi.is-skeleton { animation: none; }
.kpi.is-skeleton .kpi-ico { animation: none; }

/* Słupki obciążenia rosną od zera przy wejściu w zakładkę */
.bar-fill { animation: slupek .7s cubic-bezier(.16,1,.3,1) backwards; }
@keyframes slupek { from { width: 0; } }

/* ── Kafelek roli: to jest przycisk, więc musi to po sobie pokazać ───────── */
.rolka { position: relative; padding-right: var(--s-5); }
.rolka .rolka-ico {
  width: 30px; height: 30px; border-radius: 50%;
  display: grid; place-items: center; margin-bottom: var(--s-1);
  background: var(--n-3); border: 1px solid var(--n-line); color: var(--t-3);
  font-size: 13px; transition: transform .18s cubic-bezier(.16,1,.3,1), background .18s, color .18s;
}
.rolka.is-ok   .rolka-ico { color: var(--green); background: var(--green-soft); border-color: var(--green-edge); }
.rolka.is-warn .rolka-ico { color: var(--amber); background: var(--amber-soft); border-color: var(--amber-edge); }
.rolka.is-info .rolka-ico { color: var(--sky);   background: var(--sky-soft);   border-color: var(--sky-edge); }
.rolka:hover .rolka-ico { transform: scale(1.08) rotate(-4deg); }
.rolka-go {
  position: absolute; right: var(--s-3); top: 50%; margin-top: -6px;
  font-size: 11px; color: var(--t-4);
  opacity: 0; transform: translateX(-4px);
  transition: opacity .18s, transform .18s;
}
.rolka:hover .rolka-go, .rolka:focus-visible .rolka-go { opacity: 1; transform: none; }
.rolka:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Liczba, której jeszcze nie znamy: kreska w rytmie oddechu zamiast zera.
   Zero i „jeszcze nie wiem" to dwie różne odpowiedzi. */
.rolka-num.is-czeka {
  width: 34px; height: 26px; border-radius: var(--r-0);
  background: var(--n-3); animation: oddech 1.5s ease-in-out infinite;
}
.rolka.is-czeka .rolka-sub { color: var(--t-4); font-style: italic; }
@keyframes oddech { 0%,100% { opacity: .45; } 50% { opacity: .9; } }

/* ── Ładowanie: połysk przesuwający się po szkielecie ────────────────────── */
.sz-ring, .sz-line {
  background: var(--n-2);
  position: relative; overflow: hidden;
}
.sz-ring::after, .sz-line::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(100deg, transparent 20%, var(--n-4) 50%, transparent 80%);
  opacity: .5;
  transform: translateX(-100%);
  animation: polysk 1.5s cubic-bezier(.4,0,.2,1) infinite;
}
@keyframes polysk { to { transform: translateX(100%); } }
/* ═══════════════════════════════════════════════════════════════════════════
   POŁĄCZENIE Z SIECIĄ — cztery rzeczy pokazane, a nie wypisane
   Lista „klucz: wartość" wymaga, żeby czytający sam wiedział, czy 38 sekund to
   dużo, czy 8,3 GB do 329 MB to normalna proporcja i co właściwie znaczy
   „tylko do sieci VPN". Tutaj odpowiada na to rysunek.
   ═══════════════════════════════════════════════════════════════════════════ */
/* Dwie kolumny, nie auto-fit. Cztery bloki układają się wtedy w pełne 2×2;
   przy trzech na rząd czwarty zostawał sam na jedną trzecią szerokości, a obok
   niego świeciły dwie trzecie pustki. */
.polacz { display: grid; gap: var(--s-3); grid-template-columns: 1fr; }
@media (min-width: 900px) { .polacz { grid-template-columns: 1fr 1fr; } }
.pl-blok {
  display: flex; flex-direction: column;
  background: var(--n-2); border: 1px solid var(--n-line);
  border-radius: var(--r-1); padding: var(--s-3) var(--s-4);
}
/* Wyjaśnienie siada na dnie bloku. Bloki w rzędzie i tak wyrównują się do
   najwyższego — niech nadmiar miejsca wypadnie MIĘDZY treść a podpis,
   zamiast zbierać się pod spodem jako pusty pas. */
.pl-blok > .pl-opis { margin-top: auto; padding-top: var(--s-3); }
.pl-head { display: flex; align-items: baseline; gap: var(--s-3); margin-bottom: var(--s-3); }
.pl-tytul {
  flex: 1 1 auto; min-width: 0;
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  font-weight: var(--fw-semi); color: var(--t-3);
  display: flex; align-items: center;
}
.pl-stan { flex: 0 0 auto; font-size: 12px; color: var(--t-3); font-variant-numeric: tabular-nums; }
.pl-stan.is-ok   { color: var(--green); font-weight: var(--fw-semi); }
.pl-stan.is-warn { color: var(--amber); font-weight: var(--fw-semi); }
.pl-stan.is-bad  { color: var(--red);   font-weight: var(--fw-semi); }
.pl-stan.is-info { color: var(--sky); }
.pl-opis { font-size: 12px; color: var(--t-3); line-height: var(--lh-base); margin-top: var(--s-3); }

/* ── Skala świeżości handshake ───────────────────────────────────────────── */
.pl-skala {
  position: relative; display: flex; gap: 2px;
  height: 10px; border-radius: 999px; overflow: visible;
}
.pl-strefa { height: 100%; border-radius: 999px; }
.pl-strefa.is-ok   { flex: 60; background: var(--green-soft); box-shadow: inset 0 0 0 1px var(--green-edge); }
.pl-strefa.is-warn { flex: 25; background: var(--amber-soft); box-shadow: inset 0 0 0 1px var(--amber-edge); }
.pl-strefa.is-bad  { flex: 15; background: var(--red-soft);   box-shadow: inset 0 0 0 1px var(--red-edge); }
.pl-znacznik {
  position: absolute; top: 50%; width: 0; height: 0;
  transition: left .6s cubic-bezier(.16,1,.3,1);
}
.pl-kropka {
  position: absolute; left: -6px; top: -6px; width: 12px; height: 12px;
  border-radius: 50%; background: var(--t-1);
  border: 2px solid var(--n-2);
}
.pl-znacznik.is-ok   .pl-kropka { background: var(--green); }
.pl-znacznik.is-warn .pl-kropka { background: var(--amber); }
.pl-znacznik.is-bad  .pl-kropka { background: var(--red); }
.pl-znacznik.is-idle .pl-kropka { background: var(--t-4); }
/* Bicie serca tylko wtedy, gdy tunel naprawdę bije */
.pl-znacznik.is-ok .pl-kropka { animation: puls-bicie 2.4s ease-in-out infinite; }
@keyframes puls-bicie {
  0%, 100% { box-shadow: 0 0 0 0 rgba(52,211,153,.45); }
  55%      { box-shadow: 0 0 0 7px rgba(52,211,153,0); }
}
.pl-osie {
  display: flex; justify-content: space-between;
  margin-top: 6px; font-size: 10.5px; color: var(--t-4);
}

/* ── Bilans transferu ────────────────────────────────────────────────────── */
.tr-row {
  display: grid; align-items: center; gap: var(--s-2);
  grid-template-columns: 18px 74px 1fr auto;
}
.tr-row + .tr-row { margin-top: 7px; }
.tr-ico { font-size: 10px; text-align: center; }
.tr-ico.is-in  { color: var(--sky); }
.tr-ico.is-out { color: var(--purple); }
.tr-lab { font-size: 12px; color: var(--t-3); }
.tr-tor { height: 8px; border-radius: 999px; background: var(--n-3); overflow: hidden; }
.tr-fill {
  display: block; height: 100%; border-radius: 999px;
  animation: slupek .8s cubic-bezier(.16,1,.3,1) backwards;
  transition: width .6s cubic-bezier(.16,1,.3,1);
}
.tr-fill.is-in  { background: var(--sky); }
.tr-fill.is-out { background: var(--purple); }
.tr-val { font-size: 12.5px; font-weight: 650; color: var(--t-1); min-width: 62px; text-align: right; }

/* ── Trasa ruchu wychodzącego ────────────────────────────────────────────── */
/* Trasy i adresy rozpychają się na całą wysokość bloku. Bloki w rzędzie
   wyrównują się do najwyższego, więc nadmiar miejsca ma wejść MIĘDZY wiersze,
   a nie zostać pustym pasem pod ostatnim z nich. */
.trasy { display: flex; flex-direction: column; gap: var(--s-2); flex: 1 1 auto; }
.trasy > .trasa-row { flex: 1 1 auto; }
.trasa-row {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2) var(--s-3); border-radius: var(--r-0);
  background: var(--n-1); border: 1px solid var(--n-line);
  border-left: 3px solid var(--n-4);
}
.trasa-row.is-tunel  { border-left-color: var(--green); }
.trasa-row.is-wprost { border-left-color: var(--t-4); }
.tra-ico { flex: 0 0 auto; width: 18px; text-align: center; font-size: 12px; color: var(--t-3); }
.trasa-row.is-tunel .tra-ico { color: var(--green); }
.tra-tekst { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.tra-tekst b { font-size: 12.5px; font-weight: var(--fw-semi); color: var(--t-1); }
.tra-tekst > span { font-size: 11.5px; color: var(--t-3); line-height: 1.4; }
.tra-tag {
  flex: 0 0 auto; font-size: 10.5px; letter-spacing: .04em; text-transform: uppercase;
  color: var(--t-3); background: var(--n-3); border-radius: 999px; padding: 2px 8px;
}
.trasa-row.is-tunel .tra-tag { color: var(--green); background: var(--green-soft); }

/* ── Adresy do skopiowania ───────────────────────────────────────────────── */
.adresy { display: flex; flex-direction: column; gap: var(--s-2); flex: 1 1 auto; }
.adresy > .adres { flex: 1 1 auto; }
.adres {
  display: flex; align-items: center; gap: var(--s-3); width: 100%;
  padding: var(--s-2) var(--s-3); border-radius: var(--r-0);
  background: var(--n-1); border: 1px solid var(--n-line);
  font-family: var(--font); text-align: left; cursor: pointer;
  transition: border-color .16s, background .16s;
}
.adres:hover:not(:disabled):not(.is-pusty) { border-color: var(--accent); background: var(--accent-soft); }
.adres:disabled { cursor: default; opacity: .55; }
.adres.is-pusty { cursor: default; }
.ad-key {
  flex: 0 0 auto; width: 96px;
  font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--t-3);
}
.ad-val { flex: 1 1 auto; min-width: 0; font-size: 13.5px; color: var(--t-1); font-weight: 550; }
.adres.is-pusty .ad-val { font-size: 12px; color: var(--t-3); font-weight: 400; }
.adres > i { flex: 0 0 auto; font-size: 11px; color: var(--t-4); }
.adres:hover:not(:disabled) > i { color: var(--accent); }

/* Tempo transferu — trzeci wiersz bloku, zamiast pustego pasa pod paskami */
.tr-tempo {
  display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap;
  margin-top: var(--s-3); padding-top: var(--s-3);
  border-top: 1px solid var(--n-line);
}
.tr-tempo .tt-val { font-size: 15px; font-weight: 650; color: var(--t-1); }
.tr-tempo .tt-key { font-size: 12px; color: var(--t-3); flex: 1 1 auto; min-width: 0; }
.tr-tempo .tt-okres { font-size: 11px; color: var(--t-4); }

/* Wiersz „i N więcej" prowadzi do pełnej listy, więc wygląda jak przejście, nie jak dana */
.adres.is-wiecej { border-style: dashed; }
.adres.is-wiecej .ad-val { font-size: 12px; color: var(--t-3); font-weight: 400; }
.adres.is-wiecej:hover { border-style: solid; }
/* ═══════════════════════════════════════════════════════════════════════════
   LISTA MASZYN — karty zamiast dziewięciu kolumn
   Tabela z dziewięcioma kolumnami, dwoma wykresami wielkości znaczka i czterema
   rodzajami odznak wymagała czytania w poprzek. Karta mieści to samo pionowo,
   w kolejności, w jakiej się o to pyta: kto to jest → czy żyje → czy daje radę
   → co z niej wystawiono. Tabela zostaje dla porównywania wielu węzłów naraz.
   ═══════════════════════════════════════════════════════════════════════════ */
.mkarty { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.mkarty > .mkarta { flex: 1 1 320px; max-width: 560px; }
.mkarta {
  display: flex; flex-direction: column; gap: var(--s-3);
  background: var(--n-1); border: 1px solid var(--n-line);
  border-radius: var(--r-2); padding: var(--s-4);
  border-left: 3px solid var(--green);
  cursor: pointer;
  transition: border-color .16s, transform .16s cubic-bezier(.16,1,.3,1), box-shadow .16s;
}
.mkarta:hover { transform: translateY(-2px); border-color: var(--n-4); border-left-color: var(--green); }
.mkarta:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mkarta.is-bad  { border-left-color: var(--red); }
.mkarta.is-wait { border-left-color: var(--sky); }
.mkarta.is-idle { border-left-color: var(--n-4); opacity: .8; }
.mkarta.is-bad:hover  { border-left-color: var(--red); }
.mkarta.is-wait:hover { border-left-color: var(--sky); }

.mk-head { display: flex; align-items: center; gap: var(--s-2); }
.mk-head > .state { gap: 0; }
.mk-nazwa {
  flex: 1 1 auto; min-width: 0;
  font-size: 15px; font-weight: 650; color: var(--t-0);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mk-stan { flex: 0 0 auto; font-size: 11.5px; color: var(--t-3); }
.mk-stan.is-ok   { color: var(--green); }
.mk-stan.is-bad  { color: var(--red); }
.mk-stan.is-info { color: var(--sky); }
.mk-go { flex: 0 0 auto; font-size: 11px; color: var(--t-4); transition: transform .16s, color .16s; }
.mkarta:hover .mk-go { color: var(--accent); transform: translateX(2px); }
.mk-podpis { font-size: 12px; color: var(--t-3); min-height: 17px; margin-top: -6px; }

/* Puls — ten sam pasek, co na karcie pojedynczej maszyny */
.mk-puls { display: flex; align-items: center; gap: var(--s-3); }
.mk-puls > .pl-skala { flex: 1 1 auto; height: 8px; }
.mk-puls .pl-kropka { left: -5px; top: -5px; width: 10px; height: 10px; border-color: var(--n-1); }
.mk-puls-txt { flex: 0 0 auto; font-size: 11.5px; color: var(--t-3); font-variant-numeric: tabular-nums; }

/* Obciążenie: trzy paski zamiast dwóch mikrowykresów */
.mk-obc { display: flex; flex-direction: column; gap: 5px; min-height: 20px; }
.mk-bar { display: grid; grid-template-columns: 38px 1fr 44px; align-items: center; gap: var(--s-2); cursor: help; }
.mkb-key { font-size: 10.5px; letter-spacing: .04em; color: var(--t-4); }
.mkb-tor { height: 6px; border-radius: 999px; background: var(--n-3); overflow: hidden; }
.mkb-fill {
  display: block; height: 100%; border-radius: 999px; background: var(--t-4);
  animation: slupek .7s cubic-bezier(.16,1,.3,1) backwards;
  transition: width .6s cubic-bezier(.16,1,.3,1);
}
.mkb-fill.is-ok { background: var(--green); }
.mkb-fill.is-warn { background: var(--amber); }
.mkb-fill.is-bad { background: var(--red); }
.mkb-val { font-size: 11.5px; text-align: right; color: var(--t-2); font-variant-numeric: tabular-nums; }
.mkb-val.is-warn { color: var(--amber); }
.mkb-val.is-bad  { color: var(--red); }
.mk-brak { font-size: 11.5px; color: var(--t-4); display: flex; align-items: center; gap: var(--s-2); line-height: 1.4; }
/* Odczyt sprzed utraty łączności wygląda inaczej niż żywy pomiar */
.mk-obc.is-stary { opacity: .55; }

/* Znaczniki: liczby, które się skanuje, a nie czyta */
.mk-tagi { display: flex; flex-wrap: wrap; gap: 6px; margin-top: auto; }
.mk-tag {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 3px 8px; border-radius: 999px; cursor: help;
  background: var(--n-2); border: 1px solid var(--n-line);
  font-size: 11.5px; color: var(--t-2); font-variant-numeric: tabular-nums;
}
.mk-tag > i { font-size: 10px; color: var(--t-4); }
.mk-tag.is-ok   { color: var(--green); border-color: var(--green-edge); background: var(--green-soft); }
.mk-tag.is-ok > i { color: var(--green); }
.mk-tag.is-warn { color: var(--amber); border-color: var(--amber-edge); background: var(--amber-soft); }
.mk-tag.is-warn > i { color: var(--amber); }
.mk-tag.is-bad  { color: var(--red); border-color: var(--red-edge); background: var(--red-soft); }
.mk-tag.is-bad > i { color: var(--red); }

.mk-akcje {
  display: flex; align-items: center; gap: var(--s-1);
  padding-top: var(--s-3); border-top: 1px solid var(--n-line);
}
.mk-akcje > .btn.ghost.sm:last-child { margin-left: auto; }

/* Przełącznik karty/tabela — dwa stany, nie menu */
.widok-przel {
  display: inline-flex; flex: 0 0 auto;
  background: var(--n-2); border: 1px solid var(--n-line-2); border-radius: var(--r-1); padding: 2px;
}
.wp-opcja {
  display: grid; place-items: center; width: 30px; height: 26px;
  border: 0; border-radius: var(--r-0); background: none; cursor: pointer;
  color: var(--t-3); font-size: 12px;
  transition: background .14s, color .14s;
}
.wp-opcja:hover { color: var(--t-1); }
.wp-opcja.is-on { background: var(--n-4); color: var(--t-0); }

/* Kaskada wejścia jak wszędzie indziej */
.mkarta { animation: wejscie .42s cubic-bezier(.16,1,.3,1) both; animation-delay: calc(var(--i, 0) * 40ms); }
/* ═══════════════════════════════════════════════════════════════════════════
   LISTA APLIKACJI — karta zamiast wiersza czytanego w poprzek
   Najważniejszej informacji na tej stronie w ogóle nie było: adres wystawiony
   z maszyny, która jest offline, NIE DZIAŁA — a wiersz wyglądał identycznie
   jak sprawny. Karta stawia stan na pierwszym planie i rysuje drogę żądania,
   żeby było widać, w którym miejscu się urywa.
   ═══════════════════════════════════════════════════════════════════════════ */
.akarty { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.akarty > .akarta { flex: 1 1 340px; max-width: 580px; }
.akarta {
  position: relative; display: flex; flex-direction: column; gap: var(--s-3);
  background: var(--n-1); border: 1px solid var(--n-line);
  border-radius: var(--r-2); padding: var(--s-4);
  border-left: 3px solid var(--green);
  animation: wejscie .42s cubic-bezier(.16,1,.3,1) both;
  animation-delay: calc(var(--i, 0) * 40ms);
  transition: border-color .16s, transform .16s cubic-bezier(.16,1,.3,1);
}
.akarta:hover { transform: translateY(-2px); border-color: var(--n-4); }
.akarta.is-bad   { border-left-color: var(--red); }
.akarta.is-busy  { border-left-color: var(--amber); }
.akarta.is-idle  { border-left-color: var(--n-4); opacity: .8; }
.akarta.is-bad:hover  { border-left-color: var(--red); }
.akarta.is-busy:hover { border-left-color: var(--amber); }

.ak-head { display: flex; align-items: flex-start; gap: var(--s-3); }
.ak-ico {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: var(--r-0);
  display: grid; place-items: center; cursor: help;
  background: var(--n-3); border: 1px solid var(--n-line); color: var(--t-3); font-size: 13px;
}
.ak-ico.is-ai     { color: var(--purple); background: var(--purple-soft); border-color: rgba(167,139,250,.32); }
.ak-ico.is-docker { color: var(--sky);    background: var(--sky-soft);    border-color: var(--sky-edge); }
.ak-tytul { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.ak-adres {
  font-size: 14px; font-weight: 600; color: var(--t-0); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ak-adres:hover { color: var(--accent); text-decoration: underline; }
.ak-podpis {
  font-size: 11.5px; color: var(--t-3);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ak-stan {
  flex: 0 0 auto; display: inline-flex; align-items: center; gap: 5px; cursor: help;
  font-size: 11.5px; color: var(--t-3); white-space: nowrap;
}
.aks-kropka { width: 7px; height: 7px; border-radius: 50%; background: var(--t-4); flex: 0 0 auto; }
.ak-stan.ok   { color: var(--green); } .ak-stan.ok   .aks-kropka { background: var(--green); }
.ak-stan.bad  { color: var(--red); }   .ak-stan.bad  .aks-kropka { background: var(--red); }
.ak-stan.busy { color: var(--amber); } .ak-stan.busy .aks-kropka { background: var(--amber); animation: state-pulse 1.2s ease-in-out infinite; }

/* Droga żądania: internet → enode → maszyna → port */
.ak-tor {
  display: flex; align-items: center; gap: 5px; flex-wrap: wrap; cursor: help;
  padding: var(--s-2) var(--s-3); border-radius: var(--r-0);
  background: var(--n-2); border: 1px solid var(--n-line);
}
.akt-el {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; color: var(--t-2); text-decoration: none; white-space: nowrap;
}
.akt-el > i { font-size: 10px; color: var(--t-4); }
.akt-el.is-link { color: var(--t-1); }
.akt-el.is-link:hover { color: var(--accent); text-decoration: underline; }
.akt-el.is-port { color: var(--t-1); font-weight: 600; }
.akt-strzalka { flex: 1 1 12px; min-width: 12px; height: 2px; border-radius: 2px; background: var(--green); }
.akt-strzalka.bad  { background: repeating-linear-gradient(90deg, var(--red) 0 4px, transparent 4px 8px); }
.akt-strzalka.busy { background: repeating-linear-gradient(90deg, var(--amber) 0 4px, transparent 4px 8px); }
.akt-strzalka:not(.ok):not(.bad):not(.busy) { background: var(--n-4); }
.akt-extra {
  font-size: 10.5px; color: var(--t-3); cursor: help;
  background: var(--n-3); border-radius: 999px; padding: 1px 7px;
}

.ak-stopka {
  display: flex; align-items: center; gap: var(--s-2); margin-top: auto;
  padding-top: var(--s-3); border-top: 1px solid var(--n-line);
}
.ak-data { flex: 1 1 auto; font-size: 11.5px; color: var(--t-4); cursor: help; }
.ak-akcje { display: flex; align-items: center; gap: var(--s-1); }
.ak-zazn {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; color: var(--t-4); cursor: pointer;
  margin-top: -6px;
}
.ak-zazn:hover { color: var(--t-2); }
/* ═══════════════════════════════════════════════════════════════════════════
   LISTY PRZY DUŻEJ LICZBIE POZYCJI
   Karta jest świetna przy czterech maszynach i beznadziejna przy stu. Zamiast
   wybierać jedno, lista daje trzy gęstości, wypycha problemy na górę osobną
   grupą i renderuje porcjami — otwarcie strony kosztuje tyle samo przy
   czterech węzłach i przy dwustu.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Pasek narzędzi przykleja się do góry: przy stu pozycjach filtr i sortowanie
   muszą być pod ręką także w połowie przewiniętej listy. */
.lista-toolbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  padding: var(--s-3) var(--s-4);
  background: var(--n-1); border-bottom: 1px solid var(--n-line);
  border-radius: var(--r-2) var(--r-2) 0 0;
}
.lista-toolbar > .chips { flex: 1 1 auto; min-width: 0; }
.lt-prawa { display: flex; align-items: center; gap: var(--s-2); flex: 0 0 auto; }
.select.sm { height: var(--ctl-h-sm); font-size: 12.5px; padding: 0 var(--s-2); }
.chip.is-alert { border-color: var(--amber-edge); color: var(--amber); }
.chip.is-alert .chip-n { background: var(--amber-soft); color: var(--amber); }

/* Nagłówek grupy — mówi, ilu pozycji dotyczy i czy trzeba je czytać */
.grupa + .grupa { margin-top: var(--s-5); }
.grupa-head {
  display: flex; align-items: baseline; gap: var(--s-2); flex-wrap: wrap;
  padding-bottom: var(--s-2); margin-bottom: var(--s-3);
  border-bottom: 1px solid var(--n-line);
}
.grupa-head > i { color: var(--amber); font-size: 12px; }
.grupa-head.is-ok > i { color: var(--green); }
.gh-tytul { font-size: 13px; font-weight: var(--fw-semi); color: var(--t-1); }
.gh-licznik {
  font-size: 11.5px; font-variant-numeric: tabular-nums;
  background: var(--n-3); color: var(--t-2); border-radius: 999px; padding: 1px 8px;
}
.gh-opis { font-size: 11.5px; color: var(--t-3); flex: 1 1 auto; min-width: 0; }

/* ── Gęsty wiersz: jedna maszyna na linię ────────────────────────────────── */
.lrows { display: flex; flex-direction: column; }
.lrow {
  display: grid; align-items: center; gap: var(--s-3);
  grid-template-columns: 10px minmax(140px, 1.4fr) minmax(150px, 1.1fr) minmax(150px, 1fr) auto 12px;
  padding: 9px var(--s-3); border-radius: var(--r-1); cursor: pointer;
  border: 1px solid transparent; border-left: 3px solid var(--green);
  animation: wejscie .32s cubic-bezier(.16,1,.3,1) both;
  animation-delay: calc(var(--i, 0) * 18ms);
  transition: background .14s, border-color .14s;
}
.lrow + .lrow { margin-top: 3px; }
.lrow:hover { background: var(--n-2); border-color: var(--n-line); border-left-color: var(--green); }
.lrow:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.lrow.is-bad  { border-left-color: var(--red); }
.lrow.is-wait { border-left-color: var(--sky); }
.lrow.is-idle { border-left-color: var(--n-4); opacity: .75; }
.lrow.is-bad:hover  { border-left-color: var(--red); }
.lrow.is-wait:hover { border-left-color: var(--sky); }

.lr-dot { gap: 0; }
.lr-nazwa {
  min-width: 0; display: flex; flex-direction: column;
  font-size: 13.5px; font-weight: 600; color: var(--t-0);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lr-notka { font-size: 11px; font-weight: 400; color: var(--t-3); }
.lr-puls { display: flex; align-items: center; gap: var(--s-2); min-width: 0; cursor: help; }
.lr-puls > .pl-skala { flex: 1 1 auto; height: 6px; min-width: 54px; }
.lr-puls .pl-kropka { left: -4px; top: -4px; width: 8px; height: 8px; border-width: 1px; border-color: var(--n-1); }
.lr-puls-txt {
  flex: 0 0 auto; font-size: 11px; color: var(--t-3);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
.lr-obc { display: flex; gap: 6px; flex-wrap: wrap; min-width: 0; }
.lr-met {
  font-size: 11px; color: var(--t-2); cursor: help; white-space: nowrap;
  background: var(--n-2); border: 1px solid var(--n-line); border-radius: var(--r-0); padding: 1px 6px;
  font-variant-numeric: tabular-nums;
}
.lr-met.is-warn { color: var(--amber); border-color: var(--amber-edge); }
.lr-met.is-bad  { color: var(--red);   border-color: var(--red-edge); }
.lr-met.is-pusty { color: var(--t-4); }
.lr-tagi { display: flex; gap: 5px; flex-wrap: wrap; justify-content: flex-end; }
.lr-tagi .mk-tag { padding: 2px 7px; font-size: 11px; }
.lr-go { font-size: 10px; color: var(--t-4); transition: transform .14s, color .14s; }
.lrow:hover .lr-go { color: var(--accent); transform: translateX(2px); }

/* Na wąskim ekranie wiersz i tak musi się złamać — grid schodzi do dwóch pasm */
@media (max-width: 1100px) {
  .lrow { grid-template-columns: 10px minmax(120px, 1fr) minmax(120px, 1fr) auto 12px; }
  .lrow .lr-obc { display: none; }
}
@media (max-width: 760px) {
  .lrow { grid-template-columns: 10px 1fr 12px; row-gap: 6px; }
  .lrow .lr-puls, .lrow .lr-tagi { grid-column: 2 / 3; justify-content: flex-start; }
}

/* ── Doczytywanie porcjami ───────────────────────────────────────────────── */
.doladuj {
  display: flex; align-items: center; gap: var(--s-2); flex-wrap: wrap;
  padding-top: var(--s-4); margin-top: var(--s-2);
  border-top: 1px dashed var(--n-line-2);
}
.dl-reszta { font-size: 11.5px; color: var(--t-4); margin-left: auto; }

/* Ikona rodzaju aplikacji w gęstym wierszu — ten sam znak, mniejszy format */
.ak-ico.sm { width: 22px; height: 22px; font-size: 11px; border-radius: var(--r-0); }
/* Wiersz aplikacji ma inne pasma niż wiersz maszyny: adres, stan, maszyna+port, akcje */
.lrow > .ak-stan { justify-self: start; }
.lrow .lr-obc .lr-met { text-decoration: none; }
.lrow .lr-obc a.lr-met:hover { color: var(--accent); border-color: var(--accent); }
.lrow .lr-tagi .btn { padding: 0 6px; }

/* ── Karta konta hostingowego ─────────────────────────────────────────────
   Ten sam język, co karty maszyny i aplikacji: ikona rodzaju, nazwa, stan po
   prawej, cechy w środku, akcje w stopce. Poprzedni układ (nr-card) miał
   sześć przycisków z podpisami w nagłówku i ścianę plakietek pod spodem. */
.hkarty { display: flex; flex-wrap: wrap; gap: var(--s-3); }
.hkarty > .hkarta { flex: 1 1 340px; max-width: 580px; }
.hkarta {
  display: flex; flex-direction: column; gap: var(--s-3);
  background: var(--n-1); border: 1px solid var(--n-line);
  border-radius: var(--r-2); padding: var(--s-4);
  border-left: 3px solid var(--green);
  animation: wejscie .42s cubic-bezier(.16,1,.3,1) both;
  animation-delay: calc(var(--i, 0) * 40ms);
  transition: border-color .16s, transform .16s cubic-bezier(.16,1,.3,1);
}
.hkarta:hover { transform: translateY(-2px); border-color: var(--n-4); }
.hkarta.is-bad { border-left-color: var(--red); }
.hkarta.is-bad:hover { border-left-color: var(--red); }

.hk-head { display: flex; align-items: flex-start; gap: var(--s-3); }
.hk-ico {
  flex: 0 0 auto; width: 32px; height: 32px; border-radius: var(--r-0);
  display: grid; place-items: center; cursor: help; font-size: 13px;
  background: var(--green-soft); border: 1px solid var(--green-edge); color: var(--green);
}
.hk-ico.is-bad { background: var(--red-soft); border-color: var(--red-edge); color: var(--red); }
.hk-tytul { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.hk-domena {
  font-size: 14px; font-weight: 600; color: var(--t-0); text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hk-domena:hover { color: var(--accent); text-decoration: underline; }
.hk-podpis { font-size: 11.5px; color: var(--t-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.hk-cechy { display: flex; flex-wrap: wrap; gap: 6px; }
.hk-cecha {
  display: inline-flex; align-items: center; gap: 5px; cursor: help;
  padding: 3px 9px; border-radius: 999px; font-size: 11.5px;
  background: var(--n-2); border: 1px solid var(--n-line); color: var(--t-3);
}
.hk-cecha > i { font-size: 10px; }
.hk-cecha.is-ok { color: var(--green); border-color: var(--green-edge); background: var(--green-soft); }
.hk-cecha.is-off { color: var(--t-4); text-decoration: line-through; text-decoration-thickness: 1px; }

.hk-sciezka {
  display: flex; align-items: center; gap: var(--s-2); cursor: help;
  padding: var(--s-2) var(--s-3); border-radius: var(--r-0);
  background: var(--n-2); border: 1px solid var(--n-line);
  font-size: 11.5px; color: var(--t-2); min-width: 0;
}
.hk-sciezka > i { color: var(--t-4); font-size: 10px; flex: 0 0 auto; }
.hk-sciezka > span { min-width: 0; }

/* Pasek wyboru domeny w widoku poczty — jedna decyzja, którą trzeba podjąć
   przed czymkolwiek innym, więc stoi nad werdyktem, a nie w rzędzie z filtrami */
.dom-pasek {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  padding: var(--s-3) var(--s-4); margin-bottom: var(--s-4);
  background: var(--n-1); border: 1px solid var(--n-line); border-radius: var(--r-2);
}
.dp-etykieta {
  display: inline-flex; align-items: center; gap: var(--s-2);
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .05em;
  font-weight: var(--fw-semi); color: var(--t-3);
}
.dp-etykieta > i { color: var(--sky); font-size: 11px; }
.dom-pasek > .btn { margin-left: auto; }
.dom-pasek > .btn + .btn { margin-left: 0; }
