/* Widgets (klocki) CSS -------------------------------------------------
   Style SAMYCH klocków dashboardu: ramka organisms.DashboardWidget
   (.dash-widget*), szkielet ładowania (.dash-skel*), kafel KPI (.kpi*,
   .dash-kpis, .spark*), organisms.MetricChart (.mchart*), BigChart/
   BigChartWith (.bigchart*), CampaignTable + campaign_table_controls
   (.ctable*), lista (.dashlist*), tabela prosta (.dashtable*), alert
   (.dashalert*), PieChart (.pie*) i gotowe klocki (.dash-ready*).
   Plik GLOBALNY (baselineStylesheets w layouts/base.templ) — klocki
   renderują się nie tylko na /dashboard i /channels, ale też np. w
   szufladzie zadania procesów (zadanie process-task-blocks), więc ich
   style nie mogą zależeć od tego, czy strona ładuje dashboard.css.
   Style SAMEJ STRONY dashboard/kanały (nagłówki, paski zakładek, siatka
   edycji .dash-custom-grid, pełnostronicowy loader) zostają w
   dashboard.css — tam gdzie klocek jest edytowany/aranżowany, nie tam
   gdzie jest renderowany. Żadna reguła tutaj nie celuje w gołe tagi,
   .card, .row ani inne ogólne klasy strony — tylko w prefiksy klocków
   (dash-widget, dash-skel, kpi, mchart, bigchart, ctable, dashlist,
   dashtable, dashalert, pie, spark, dash-ready, dash-goal-*). */

@media (max-width: 1100px) {
  .dash-kpis { grid-template-columns: repeat(2, 1fr); }
}
/* Wysokość w skokach 40 px (--h) — ciało przewija nadmiar. */
.dash-widget[data-h] { height: calc(var(--h) * 40px); display: flex; flex-direction: column; }
.dash-widget[data-h] .dash-widget-body { flex: 1; min-height: 0; overflow: auto; }
/* Uchwyt zmiany rozmiaru — tylko w trybie edycji. */
.dash-widget-resize {
  position: absolute; right: 2px; bottom: 2px; width: 14px; height: 14px;
  cursor: nwse-resize; display: none; z-index: 5; touch-action: none;
  background: linear-gradient(135deg, transparent 50%, var(--ink-3, #9a958c) 50%, var(--ink-3, #9a958c) 60%, transparent 60%, transparent 70%, var(--ink-3, #9a958c) 70%, var(--ink-3, #9a958c) 80%, transparent 80%);
  border-bottom-right-radius: 6px; opacity: .7;
}
.dash-widget.is-resizing { outline: 2px solid var(--accent-deep, #d9a800) !important; z-index: 4; }
.dash-widget.is-resizing .dash-widget-body { pointer-events: none; }
.dash-widget {
  background: var(--bg-elev);
  border: 1px solid var(--line);
  border-radius: 14px;
  box-shadow: var(--sh-1);
  display: flex; flex-direction: column;
  min-width: 0;
}
.dash-widget-head {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line);
}
.dash-widget-handle {
  color: var(--ink-4);
  cursor: grab;
  display: inline-grid; place-items: center;
  flex: none;
}
.dash-widget-handle:active { cursor: grabbing; }
.dash-widget-title {
  flex: 1; min-width: 0;
  font-size: 13px; font-weight: 600; color: var(--ink);
  letter-spacing: -.005em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dash-widget-actions { display: flex; align-items: center; gap: 2px; }
/* Stan celu na kafelku. Całe czerwone tło (2026-09-23) okazało się za
   krzykliwe — przy dwóch klockach poza celem dashboard wyglądał jak
   alarm (zgłoszone 2026-09-24). Zostaje sygnał, którego nie da się
   przeoczyć, ale bez zalewania karty: pasek przy lewej krawędzi, kropka
   przy tytule i czerwony komunikat w treści.
   `:has()` bo ciało klocka doładowuje się asynchronicznie (skeleton →
   dane), więc chrome kafelka w momencie renderu nie zna stanu celu. */
.dash-widget:has([data-goal-tone="bad"]) {
  border-color: color-mix(in srgb, var(--bad, #B4413A) 28%, var(--line));
  box-shadow: inset 3px 0 0 var(--bad, #B4413A), var(--sh-1);
}
.dash-widget:has([data-goal-tone="warn"]) {
  border-color: color-mix(in srgb, var(--warn, #B6741A) 28%, var(--line));
  box-shadow: inset 3px 0 0 var(--warn, #B6741A), var(--sh-1);
}
.dash-widget:has([data-goal-tone]) .dash-widget-title::before {
  content: ""; display: inline-block; width: 7px; height: 7px; margin: 0 7px 1px 0;
  border-radius: 50%; vertical-align: middle; background: var(--good, #2F7A4D);
}
.dash-widget:has([data-goal-tone="bad"]) .dash-widget-title::before { background: var(--bad, #B4413A); box-shadow: 0 0 0 3px color-mix(in srgb, var(--bad, #B4413A) 18%, transparent); }
.dash-widget:has([data-goal-tone="warn"]) .dash-widget-title::before { background: var(--warn, #B6741A); }
/* Link „W Kanałach" w pasku tytułu klocka — nawigacja, widoczna zawsze. */
.dash-widget-link {
  display: inline-flex; align-items: center; gap: 5px; flex: none;
  padding: 3px 8px; border-radius: 6px;
  font-size: 11.5px; font-weight: 600; color: var(--ink-3); text-decoration: none;
  transition: background .12s, color .12s;
}
.dash-widget-link:hover, .dash-widget-link:focus-visible { background: var(--bg-sunk); color: var(--ink); }
@container (max-width: 260px) { .dash-widget-link span { display: none; } }
.dash-widget-btn {
  display: inline-grid; place-items: center;
  width: 24px; height: 24px;
  border: 0; border-radius: 6px;
  background: transparent; color: var(--ink-4);
  cursor: pointer;
  transition: background .12s, color .12s;
}
.dash-widget-btn:hover { background: var(--bg); color: var(--ink); }
.dash-widget-btn:disabled { opacity: .35; cursor: default; }
.dash-widget-btn:disabled:hover { background: transparent; color: var(--ink-4); }
.dash-widget-del:hover { color: var(--bad); }
/* Ciało wypełnia kafelek rozciągnięty do wysokości rzędu — inaczej
   treść zostawałaby u góry, a pod nią wisiałaby biała dziura bez ramki. */
.dash-widget-body {
  padding: 12px;
  min-width: 0;
  flex: 1;
  display: flex;
  flex-direction: column;
  min-height: 0;
}
/* Konfigurowalna wysokość klocka. Wykres i tabela potrzebują miejsca,
   którego siatka sama nie da: przy czterech kolumnach klocek na 1/4
   szerokości jest niski niezależnie od tego, ile ma treści. Wysokość
   dotyczy CIAŁA, nie całego kafelka, żeby nagłówek nie zjadał budżetu. */
.dash-widget[data-height="s"] .dash-widget-body { min-height: 150px; }
.dash-widget[data-height="m"] .dash-widget-body { min-height: 240px; }
.dash-widget[data-height="l"] .dash-widget-body { min-height: 340px; }
.dash-widget[data-height="xl"] .dash-widget-body { min-height: 460px; }
/* Wykres rozciąga się na przyznaną wysokość, zamiast zostawiać pustkę
   pod spodem. Tabela nie: jej wysokość wynika z liczby wierszy, a
   rozciąganie wierszy zrobiłoby z niej formularz.
   `.mchart-svg` ma domyślnie sztywne 220px — w klocku o zadanej wysokości
   musi je oddać, inaczej ustawienie wysokości nie robiłoby nic poza
   dokładaniem pustego miejsca. */
.dash-widget-body > .mchart { flex: 1; }
.dash-widget-body > .mchart .mchart-plot { flex: 1; min-height: 140px; }
.dash-widget-body > .mchart .mchart-svg { height: 100%; }

/* Sortable.js drag states */
.dash-widget-ghost { opacity: .4; }
.dash-widget-drag { box-shadow: var(--sh-2, 0 8px 24px rgba(0,0,0,.12)); }

/* Skeleton shimmer --------------------------------------------------- */
.dash-skel { display: flex; flex-direction: column; gap: 10px; }
.dash-skel-bar {
  height: 14px; border-radius: 6px;
  background: linear-gradient(90deg, var(--line) 25%, var(--bg) 50%, var(--line) 75%);
  background-size: 200% 100%;
  animation: dash-skel-shimmer 1.4s ease infinite;
}
.dash-skel-bar.lg { height: 28px; }
.dash-skel-bar.half { width: 50%; }
@keyframes dash-skel-shimmer {
  0% { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
/* ── PieChart (widget Data-Studio style) ─────────────────────────── */
.pie {
  display: flex;
  align-items: center;
  gap: 18px;
  min-height: 0;
}
.pie-svg { flex: 0 0 auto; }
/* Legenda lamie sie na kolumny, gdy jest miejsce: przy kilkunastu pozycjach
   jedna kolumna rozciagala widget w pionie i zmuszala do scrollowania, zeby
   sprawdzic, ktory wycinek to ktory klient. auto-fill, wiec waskie widgety
   (dashboard) dostaja jedna kolumne jak dotad. */
.pie-legend {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 6px 20px;
  align-content: center;
  min-width: 0;
  flex: 1;
}
.pie-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
  min-width: 0;
  border-radius: 6px;
  padding: 1px 4px;
  margin: -1px -4px;
}
/* Podswietlenie wiersza: przy kilkudziesieciu klientach mapowanie
   wycinek -> nazwa jest calym zadaniem tego widgetu. */
.pie-row:hover { background: var(--bg-2); }
.pie-row:hover .pie-name { color: var(--ink-1); }
.pie-swatch {
  width: 10px; height: 10px;
  border-radius: 3px;
  flex: 0 0 10px;
  display: inline-block;
}
.pie-name {
  flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  color: var(--ink-2);
}
.pie-pct { color: var(--ink-4); font-variant-numeric: tabular-nums; }
.pie-empty {
  padding: 24px 12px;
  text-align: center;
  color: var(--ink-4);
  font-size: 12.5px;
  font-style: italic;
}
/* Legenda multi-serii BigChartWith */
.bigchart-legend {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--ink-3);
}
.bigchart-legend-item { display: inline-flex; align-items: center; gap: 6px; }
/* ── Widget listy (rows z rejestru źródeł) ───────────────────────── */
.dashlist { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.dashlist-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 7px 8px;
  border-radius: 8px;
  font-size: 12.5px;
  color: var(--ink-2);
  text-decoration: none;
  min-width: 0;
}
a.dashlist-row:hover { background: var(--bg-sunk); }
.dashlist-row[data-tone="danger"] .dashlist-main { color: var(--danger, #c0392b); }
.dashlist-row[data-tone="ok"] .dashlist-badge { color: #1f7a4a; }
.dashlist-main {
  flex: 1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font-weight: 500;
  color: var(--ink-1);
}
.dashlist-meta { color: var(--ink-4); white-space: nowrap; font-size: 11.5px; }
.dashlist-badge { white-space: nowrap; font-size: 11px; }
.dashlist-empty {
  padding: 18px 8px;
  color: var(--ink-4);
  font-size: 12.5px;
  font-style: italic;
  text-align: center;
}
/* ── Widget tabeli (kind=table, kolumny z deskryptora źródła) ─────── */
.dashtable {
  width: 100%;
  border-collapse: collapse;
  font-size: 12px;
  min-width: 0;
}
.dashtable th {
  text-align: left;
  font-weight: 600;
  font-size: 11px;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ink-4);
  padding: 4px 8px 6px 0;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}
.dashtable td {
  padding: 6px 8px 6px 0;
  border-bottom: 1px solid var(--line);
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 180px;
}
.dashtable tbody tr:last-child td { border-bottom: none; }
/* ── Widget alarmu (kind=alert) ──────────────────────────────────────
   Alarm odnosi się do CELU, nie do liczby wpisanej w formularz, więc ma
   trzy stopnie zamiast dwóch: przekroczenie budżetu o 2% i o 375% nie
   mogą wyglądać identycznie. Układ pionowy, bo pod wartością idzie
   zdanie („Cel przekroczony o 131%") i wobec czego („cel 200 zł"). */
.dashalert {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 6px 2px;
}
.dashalert-head { display: flex; align-items: center; gap: 10px; }
.dashalert-dot {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--ink-5, #b8b4ac);
  flex: none;
}
.dashalert-dot.tone-good { background: var(--good, #2F7A4D); }
.dashalert-dot.tone-warn { background: var(--warn, #B6741A); }
.dashalert-dot.tone-bad  { background: var(--bad, #B4413A); }
.dashalert-value {
  font-size: 24px;
  font-weight: 600;
  letter-spacing: -.02em;
  font-feature-settings: 'tnum';
}
.dashalert[data-goal-tone="bad"] .dashalert-value { color: var(--bad, #B4413A); }
.dashalert-msg { font-size: 12.5px; color: var(--ink-3); }
.dashalert-msg.tone-bad { color: var(--bad, #B4413A); font-weight: 600; }
.dashalert-msg.tone-warn { color: var(--warn, #B6741A); }
.dashalert-detail { font-size: 11.5px; color: var(--ink-4); }
/* Metric chart (kafelki + wykres jak w panelach reklamowych) --------- */
/* Geometria w SVG (rozciąganym w poziomie), a wszystko z tekstem albo
   stałą grubością — osie, crosshair, dymek — w HTML nad nim. */
.mchart { display: flex; flex-direction: column; gap: 10px; position: relative; }
/* Przełącznik agregacji w prawym górnym rogu; kafelki zostawiają mu
   miejsce, żeby ostatni nie wszedł pod niego. */
.mchart-ctrls { position: absolute; top: 0; right: 0; z-index: 6; display: flex; gap: 6px; }
.mchart-gran {
  font: inherit; font-size: 11.5px; color: var(--ink-2);
  background: var(--bg-elev, #fff); border: 1px solid var(--line-2, #e5e2dc);
  border-radius: 6px; padding: 3px 6px; cursor: pointer;
}
.mchart-gran:hover { border-color: var(--ink-4, #8a8578); }
.mchart-gran:focus-visible { outline: 2px solid var(--accent, #3b6); outline-offset: 1px; }
.mchart-ctrls + .mchart-tiles { padding-right: 112px; }
.mchart-ctrls:has(.mchart-kind):has(.mchart-gran:not(.mchart-kind)) + .mchart-tiles { padding-right: 236px; }
.mchart-tiles { display: flex; gap: 8px; flex-wrap: wrap; }
.mchart-tile {
  appearance: none; cursor: pointer; text-align: left;
  display: flex; flex-direction: column; gap: 2px;
  padding: 8px 12px; min-width: 104px;
  background: var(--bg-elev, #fff);
  border: 1px solid var(--line-2, #e5e2dc);
  border-bottom: 2px solid var(--line-2, #e5e2dc);
  border-radius: 8px; font: inherit;
}
.mchart-tile:hover { background: var(--bg-sunk, #f8f7f4); }
.mchart-tile[data-on="true"] { background: var(--bg-sunk, #f8f7f4); }
.mchart-tile[data-on="false"] { opacity: .62; }
.mchart-tile-label { font-size: 11px; color: var(--ink-4); }
.mchart-tile-value { font-size: 17px; font-weight: 600; font-feature-settings: 'tnum'; }
.mchart-tile-delta { font-size: 11px; font-weight: 600; }
.mchart-tile-delta.good { color: var(--good, #2F7A4D); }
.mchart-tile-delta.bad { color: var(--bad, #B4413A); }

.mchart-plot { position: relative; }
.mchart-svg {
  width: 100%; height: 220px; display: block;
  background: linear-gradient(180deg, transparent 60%, var(--bg-sunk) 100%);
  border-radius: 8px;
}
.mchart-ytick {
  position: absolute; left: 0; transform: translateY(-50%);
  font-family: var(--font-mono); font-size: 10px; color: var(--ink-4);
  background: var(--bg-elev, #fff); padding: 0 3px; border-radius: 3px;
  pointer-events: none; z-index: 2;
}
.mchart-hits { position: absolute; inset: 0; display: flex; z-index: 3; }
.mchart-hit { flex: 1 1 0; outline: none; }
.mchart-hit:hover, .mchart-hit:focus-visible { background: color-mix(in srgb, var(--ink) 6%, transparent); }
.mchart-cursor {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: var(--ink-3, #8a8578); opacity: .5;
  pointer-events: none; z-index: 4; transform: translateX(-0.5px);
}
.mchart-tip {
  position: absolute; top: 4px; transform: translateX(-50%);
  min-width: 170px; max-width: 340px;
  background: var(--bg-elev, #fff); border: 1px solid var(--line-2, #e5e2dc);
  border-radius: 8px; box-shadow: 0 6px 18px rgba(0,0,0,.12);
  padding: 8px 10px; z-index: 5; pointer-events: none;
  font-size: 11.5px; line-height: 1.5;
}
/* Tooltip jako tabela: wiersz = metryka (cel pod nią), kolumna = okres.
   Data stoi raz w nagłówku kolumny, kolor znacznika mówi, która metryka. */
.mchart-tip-tbl { border-collapse: collapse; width: 100%; }
.mchart-tip-tbl th { font-weight: 400; text-align: right; padding: 0 0 4px 12px; vertical-align: bottom; }
.mchart-tip-cap { display: block; color: var(--ink-3); font-size: 10px; white-space: nowrap; }
.mchart-tip-date { color: var(--ink-2); font-size: 10.5px; font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.mchart-tip-col-prev .mchart-tip-date { color: var(--ink-3); }
.mchart-tip-tbl td { padding: 2px 0; }
.mchart-tip-group + .mchart-tip-group tr:first-child td { border-top: 1px solid var(--line-2, #e5e2dc); padding-top: 4px; }
.mchart-tip-label { color: var(--ink-2); white-space: nowrap; text-align: left; }
.mchart-tip-label > .pie-swatch, .mchart-tip-goal-mark { display: inline-block; vertical-align: middle; margin-right: 6px; }
.mchart-tip-val { text-align: right; padding-left: 12px !important; font-family: var(--font-mono); font-weight: 600; white-space: nowrap; }
.mchart-tip-val-prev { color: var(--ink-3); font-weight: 500; }
.mchart-tip-goal .mchart-tip-label { color: var(--ink-3); padding-left: 2px; }
.mchart-tip-goal .mchart-tip-val { font-weight: 500; }
.mchart-tip-goal-mark { width: 10px; border-top: 2px dashed var(--bad, #B4413A); }
/* Okres porównawczy w legendzie: przygaszony znacznik, bo na wykresie to
   przygaszony kolor serii, nie osobny kolor. */
.mchart-legend-prev { background: var(--ink-3, #8a8578); opacity: .35; }

/* Oś X: podziałki na swoich pozycjach, nie rozstrzelone justify-between —
   etykieta ma stać nad swoim punktem. */
.mchart-xaxis { position: relative; height: 16px; }
.mchart-xtick {
  position: absolute; transform: translateX(-50%);
  font-family: var(--font-mono); font-size: 10.5px; color: var(--ink-4);
  white-space: nowrap;
}
/* Legenda wynika z zaznaczonych kafelków, więc musi znieść zawijanie:
   dwie serie + cel + okres porównawczy to cztery pozycje. */
.mchart-legend {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-top: 6px;
  font-size: 11.5px;
  color: var(--ink-4);
}
.mchart-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.mchart-legend:empty { display: none; }
/* Campaign table (kolumny konfigurowalne + ocena wobec celów) -------- */
.ctable { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
/* Przewijanie poziome zamiast ścinania kolumn. Sześć metryk nie mieści się
   w klocku o szerokości połowy siatki, a zwężanie liczb do nieczytelnych
   byłoby gorsze niż przewinięcie. */
.ctable-scroll { overflow-x: auto; overflow-y: hidden; min-width: 0; }
.ctable-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: 12.5px; }
.ctable-th {
  text-align: left; font-weight: 500; font-size: 11px;
  text-transform: uppercase; letter-spacing: .03em; color: var(--ink-4);
  padding: 0 8px 6px; cursor: pointer; white-space: nowrap;
  border-bottom: 1px solid var(--line-2, #e5e2dc);
}
.ctable-th:hover { color: var(--ink-2); }
/* Nagłówek kolumny z celem: etykieta metryki + wartość progu w drugiej
   linijce. Wcześniej kod celu doklejony do etykiety rozpychał kolumnę i
   spychał resztę tabeli poza widoczny obszar. */
.ctable-th-label { display: block; }
.ctable-th-sub {
  display: block; margin-top: 1px; font-size: 10px; font-weight: 400;
  text-transform: none; letter-spacing: 0; color: var(--ink-4);
}
/* Realizacja celów stoi zaraz po nazwie — to kolumna, po którą user tu
   przychodzi, więc nie może wymagać przewinięcia. */
.ctable-th--goals, .ctable-td--goals { text-align: right; white-space: nowrap; }
.ctable-th--num { text-align: right; }
.ctable-th--name { cursor: default; }
/* Strzałka kierunku siedzi przy ETYKIECIE, nie na całym nagłówku — na
   nagłówku dwuliniowym (etykieta + wartość celu) lądowała w trzeciej
   linijce i rozpychała wiersz nagłówków. */
.ctable-th[data-sorted="desc"] .ctable-th-label::after,
.ctable-th[data-sorted="desc"]:not(:has(.ctable-th-label))::after { content: " \2193"; }
.ctable-th[data-sorted="asc"] .ctable-th-label::after,
.ctable-th[data-sorted="asc"]:not(:has(.ctable-th-label))::after { content: " \2191"; }
.ctable-row:hover .ctable-td { background: var(--bg-sunk); }
.ctable-td {
  padding: 7px 8px; border-bottom: 1px solid var(--line-2, #e5e2dc);
  vertical-align: middle; background: var(--bg-elev);
}
.ctable-td--num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
/* Nazwa kampanii zostaje na ekranie przy przewijaniu metryk — inaczej
   liczby po prawej byłyby niczyje. */
.ctable-th--name, .ctable-td--name {
  position: sticky; left: 0; z-index: 1;
  /* --bg-elev, nie literał: kolumna przyklejona musi zniknąć w tle karty
     także w ciemnym motywie. Z fallbackiem #fff zostawała biała i nazwy
     kampanii robiły się nieczytelne. */
  background: var(--bg-elev);
  max-width: 230px; min-width: 150px;
}
.ctable-th--name { background: var(--bg-elev); }
.ctable-name {
  display: block; overflow: hidden; text-overflow: ellipsis;
  white-space: nowrap; font-weight: 500;
}
.ctable-status { font-size: 10.5px; color: var(--ink-4); }
/* Nazwa-link (sekcja „Kanały"): kolor tekstu, podkreślenie dopiero na
   hover — tabela z dziesiątkami niebieskich nazw byłaby nieczytelna. */
.ctable-link { color: inherit; text-decoration: none; }
.ctable-link:hover, .ctable-link:focus-visible { color: var(--accent); text-decoration: underline; }
/* Nagłówek sortowany na serwerze — link wygląda jak zwykły nagłówek. */
.ctable-sort { color: inherit; text-decoration: none; display: inline-flex; flex-direction: column; }
.ctable-th--num .ctable-sort { align-items: flex-end; }
/* Kropka przy wartości = ta metryka ma cel i tak wypada wobec niego.
   Kolor bez kropki byłby nieczytelny dla daltonistów, a sama kropka bez
   koloru nic nie mówi — dlatego oba naraz. */
.ctable-dot {
  display: inline-block; width: 6px; height: 6px; border-radius: 999px;
  margin-right: 5px; vertical-align: middle;
}
.ctable-dot.is-good { background: var(--good, #2F7A4D); }
.ctable-dot.is-warn { background: var(--warn, #B6741A); }
.ctable-dot.is-bad  { background: var(--bad, #B4413A); }
/* Kropka-link do karty KPI komórki (KPI per kampania) — nieco większe
   pole trafienia, ten sam wygląd. */
.ctable-dot--link { width: 8px; height: 8px; margin-right: 4px; }
.ctable-dot--link:hover, .ctable-dot--link:focus-visible { box-shadow: 0 0 0 3px var(--line-2, #e5e2dc); outline: none; }
/* „+ cel” — komórka bez celu; widoczne dopiero przy najechaniu na wiersz
   albo fokusie, żeby tabela bez celów nie była usiana plusami. */
.ctable-goal-add {
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; margin-right: 4px; padding: 0; vertical-align: middle;
  border: 1px dashed var(--line, #d6d2ca); border-radius: 999px; background: transparent;
  color: var(--ink-3, #8a8578); font: 600 11px/1 var(--font-mono, ui-monospace, monospace);
  cursor: pointer; opacity: 0; transition: opacity .12s;
}
.ctable-row:hover .ctable-goal-add, .ctable-goal-add:focus-visible { opacity: 1; }
.ctable-goal-add:hover { color: var(--info, #2563eb); border-color: var(--info, #2563eb); }
/* Dotyk nie ma najechania, a tap w wiersz otwiera jego stronę — „+ cel”
   widoczny stale, przygaszony. */
@media (hover: none) {
  .ctable-goal-add { opacity: .5; }
}
.ctable-td.is-bad { color: var(--bad, #B4413A); font-weight: 600; }
.ctable-goals {
  font-variant-numeric: tabular-nums; font-weight: 600;
  padding: 1px 7px; border-radius: 999px; font-size: 11.5px;
}
.ctable-goals.is-good { color: var(--good, #2F7A4D); background: var(--good-soft, #DCEFE0); }
.ctable-goals.is-warn { color: var(--warn, #B6741A); background: var(--warn-soft, #FBEACD); }
.ctable-goals.is-bad  { color: var(--bad, #B4413A);  background: var(--bad-soft, #F6D9D5); }
.ctable-muted { color: var(--ink-4); }
.ctable-hint { font-size: 11px; color: var(--ink-4); }
.ctable-empty { font-size: 12.5px; color: var(--ink-4); padding: 8px 0; }
/* „Ustaw cel" — cichy skrót na kaflu bez celu ------------------------
   Widoczny WYŁĄCZNIE w trybie edycji zakładki. Poza nim byłby zachętą do
   klikania w czymś, co user właśnie czyta; w trybie edycji jest tym,
   po co się tam wchodzi. */
.dash-goal-cta {
  display: none;
  align-items: center;
  gap: 5px;
  margin-top: 8px;
  padding: 3px 9px;
  align-self: flex-start;
  border: 1px dashed var(--line-2, #e5e2dc);
  border-radius: 999px;
  background: transparent;
  font-size: 11.5px;
  color: var(--ink-3);
  cursor: pointer;
  transition: border-color 0.12s ease, color 0.12s ease;
}
/* Alarm bez celu jest WPROST prośbą o ustawienie celu — chowanie w nim
   skrótu poza trybem edycji kazałoby userowi zgadywać, gdzie to zrobić. */
.dashalert .dash-goal-cta { display: inline-flex; }
.dash-goal-cta:hover {
  border-color: var(--accent-deep, #8a6d00);
  color: var(--accent-deep, #8a6d00);
}
/* Okres porównawczy w komórce tabeli kampanii ------------------------
   Druga linijka zamiast kolejnych kolumn: tabela już przewija się w
   poziomie, a podwojenie liczby kolumn zepchnęłoby wszystko poza ekran.
   Wartość „wtedy" jest przygaszona, bo prowadzi liczba „teraz". */
.ctable-prev {
  display: block;
  margin-top: 1px;
  font-size: 10.5px;
  line-height: 1.3;
  white-space: nowrap;
}
.ctable-prev-val { color: var(--ink-4); }
.ctable-prev-delta { margin-left: 5px; font-weight: 600; }
.ctable-prev-delta.is-good { color: var(--good, #2F7A4D); }
.ctable-prev-delta.is-bad { color: var(--bad, #B4413A); }
/* ---- CampaignTable w trybie ServerSort (.ctable--server) — styl listy
   Google Ads: wyraźny hover wiersza, klikalny cały wiersz, sortowanie ze
   strzałką-podpowiedzią, wiersz „Łącznie" na dole. -------------------- */
.ctable--server .ctable-th { padding: 0; vertical-align: bottom; }
.ctable--server .ctable-sort {
  display: flex; flex-direction: column; padding: 8px 8px 7px; border-radius: 6px 6px 0 0;
  transition: background .1s, color .1s;
}
.ctable--server .ctable-th--num .ctable-sort { align-items: flex-end; }
.ctable--server .ctable-th:hover .ctable-sort { background: var(--bg-sunk); color: var(--ink-2); }
.ctable--server .ctable-th[data-sorted="asc"], .ctable--server .ctable-th[data-sorted="desc"] { color: var(--ink); font-weight: 700; }
.ctable--server .ctable-th[data-sorted="asc"], .ctable--server .ctable-th[data-sorted="desc"] { box-shadow: inset 0 -2px 0 var(--accent); }
/* Strzałka: w aktywnej kolumnie pełna (akcent), w pozostałych widoczna
   dopiero na hover — widać, że da się sortować, bez szumu w spoczynku. */
.ctable--server .ctable-th .ctable-th-label::after {
  content: " \2193"; opacity: 0; color: var(--ink-4); transition: opacity .1s;
}
.ctable--server .ctable-th:hover .ctable-th-label::after { opacity: .7; }
.ctable--server .ctable-th[data-sorted="desc"] .ctable-th-label::after { content: " \2193"; opacity: 1; color: var(--accent-deep); }
.ctable--server .ctable-th[data-sorted="asc"] .ctable-th-label::after { content: " \2191"; opacity: 1; color: var(--accent-deep); }
.ctable--server .ctable-th--name { cursor: pointer; }
.ctable--server .ctable-td { padding: 9px 8px; transition: background .08s; }
.ctable-row--link { cursor: pointer; }
.ctable-row--link:hover .ctable-td { background: var(--accent-wash); }
.ctable-row--link:hover .ctable-link { color: var(--ink); text-decoration: underline; }
.ctable-row--total .ctable-td {
  background: var(--bg-sunk); font-weight: 700; border-top: 2px solid var(--line-2); border-bottom: 0;
}
.ctable-row--total:hover .ctable-td { background: var(--bg-sunk); }
.ctable-status { display: inline-flex; align-items: center; gap: 5px; }
.ctable-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; }
.ctable-status-dot.is-good { background: var(--good); }
.ctable-status-dot.is-muted { background: var(--ink-5); }
.ctable-status-dot.is-bad { background: var(--bad); }

/* Host tabeli podczas żądania HTMX (sort/strona/szukaj): pasek postępu
   u góry + przygaszona tabela. Stary widok zostaje na ekranie, więc nic
   nie skacze, a widać, że ładuje się nowy. hx-indicator ustawia host. */
.ctable-host { position: relative; }
.ctable-host::before {
  content: ""; position: absolute; left: 0; top: 0; height: 2px; width: 0;
  background: var(--accent-deep); opacity: 0; z-index: 3; border-radius: 2px;
}
.ctable-host.htmx-request::before { opacity: 1; animation: ctable-progress 1.6s cubic-bezier(.3,.7,.4,1) infinite; }
.ctable-host.htmx-request .ctable { opacity: .45; pointer-events: none; transition: opacity .15s .1s; }
@keyframes ctable-progress { 0% { left: 0; width: 0; } 50% { left: 15%; width: 55%; } 100% { left: 100%; width: 0; } }
@media (prefers-reduced-motion: reduce) { .ctable-host.htmx-request::before { animation: none; } }
.ctable-td--text { text-align: left; white-space: nowrap; color: var(--ink-2); }
/* ── Dashboard: interaktywne kafelki, mini wykresy, animacje (2026-09-24) ──
   Kafelek z liczbą był martwy: bez „co to jest", bez przebiegu w czasie,
   a dashboard skakał, gdy klocki dociągały dane. */

/* Etykieta kafelka + ikonka „i" z definicją metryki. */
.kpi-label { display: flex; align-items: center; gap: 5px; }
.kpi-info {
  display: inline-grid; place-items: center;
  width: 16px; height: 16px; padding: 0;
  border: 0; border-radius: 50%;
  background: transparent; color: var(--ink-5, var(--ink-4));
  cursor: help; opacity: .55;
  transition: opacity .15s, color .15s, background .15s;
}
.kpi:hover .kpi-info, .dash-widget:hover .kpi-info, .kpi-info:focus-visible { opacity: 1; }
.kpi-info:hover, .kpi-info:focus-visible { color: var(--ink); background: var(--bg-sunk); outline: none; }
.kpi { transition: box-shadow .2s, transform .2s, border-color .2s; }
.kpi:hover { box-shadow: var(--sh-2, 0 6px 18px rgba(0,0,0,.08)); border-color: var(--line-2, var(--line)); }
.kpi-series { margin-top: 6px; }
/* SparkSeries — linia z prawdziwych danych + pole pod nią + cień okresu
   porównawczego. Kolor bierze z tonu (dobrze/źle wg delty). */
.spark { position: relative; height: 34px; color: var(--ink-3); }
.spark.is-good { color: var(--good); }
.spark.is-bad { color: var(--bad); }
.spark-svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.spark-area { fill: currentColor; opacity: .1; }
.spark-prev { fill: none; stroke: var(--ink-4); stroke-width: 1.2; stroke-dasharray: 3 3; opacity: .55; }
.spark-line {
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 1; stroke-dashoffset: 0;
  animation: spark-draw .9s cubic-bezier(.3,.7,.2,1) both;
}
.spark-area { animation: spark-area-in .9s ease .25s both; }
@keyframes spark-area-in { from { opacity: 0; } to { opacity: .1; } }
@keyframes spark-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.spark-hits { position: absolute; inset: 0; display: flex; }
.spark-hit { flex: 1; position: relative; cursor: crosshair; }
.spark-hit::before {
  content: ""; position: absolute; left: 50%; top: 0; bottom: 0; width: 1px;
  background: currentColor; opacity: 0; transition: opacity .1s;
}
.spark-hit::after {
  content: ""; position: absolute; left: 50%; top: var(--spark-y, 50%);
  width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px; border-radius: 50%;
  background: var(--bg-elev); border: 2px solid currentColor;
  opacity: 0; transform: scale(.4); transition: opacity .1s, transform .15s;
}
.spark-hit:hover::before { opacity: .25; }
.spark-hit:hover::after { opacity: 1; transform: scale(1); }
/* Tabela w trybie porównania (jak w Google Ads): nagłówek metryki nad
   trzema podkolumnami — okres bieżący, porównawczy, zmiana. Grupy
   rozdziela pionowa linia, żeby przy sześciu metrykach (18 kolumn) oko
   nie gubiło, która liczba należy do której metryki. */
.ctable-th--group {
  text-align: center; cursor: default;
  padding: 0 10px 5px;
  border-bottom: 1px solid var(--line);
  border-left: 1px solid var(--line-2, #e5e2dc);
  color: var(--ink-3);
}
.ctable-th--group .ctable-sort { align-items: center; }
.ctable-subhead .ctable-th { padding-top: 5px; }
.ctable-th--period {
  font-size: 10px; font-weight: 500; text-transform: none; letter-spacing: 0;
  color: var(--ink-4); font-variant-numeric: tabular-nums;
}
.ctable-th--cur, .ctable-td--cur { border-left: 1px solid var(--line-2, #e5e2dc); padding-left: 12px; }
.ctable-th--cur { color: var(--ink-2); font-weight: 600; }
.ctable-td--cur { font-weight: 600; color: var(--ink); }
.ctable-td--prev { color: var(--ink-3); }
.ctable-td--chg { min-width: 70px; line-height: 1.2; }
.ctable-chg {
  display: inline-flex; align-items: center; gap: 2px;
  font-size: 11.5px; font-weight: 600; font-variant-numeric: tabular-nums;
}
.ctable-chg.is-good { color: var(--good); }
.ctable-chg.is-bad { color: var(--bad); }
.ctable-chg-arrow { font-size: 10px; }
.ctable-chg-abs { display: block; font-size: 10.5px; color: var(--ink-4); font-variant-numeric: tabular-nums; }
/* Kolumna bieżąca to ta, na którą user patrzy — subtelne tło wyróżnia
   ją w pionie bez dokładania kolejnych linii. */
.ctable-td--cur { background: color-mix(in srgb, var(--bg-sunk) 55%, var(--bg-elev)); }
.ctable-row:hover .ctable-td--cur { background: var(--bg-sunk); }
.ctable-row--total .ctable-td--cur, .ctable-row--total .ctable-td--prev, .ctable-row--total .ctable-td--chg { font-weight: 700; }
.ctable-row--total .ctable-td--cur { background: var(--bg-sunk); }
.ctable-row--link:hover .ctable-td--cur { background: var(--accent-wash); }
/* Sortowanie serwerowe (Kanały): nagłówki mają padding na linku, więc
   podkolumny bez linku muszą go dostać same. */
.ctable--server .ctable-th--period { padding: 6px 8px 7px; }
.ctable--server .ctable-th--group { padding: 0; }
.ctable--server .ctable-th--group .ctable-sort { align-items: center; padding: 8px 8px 5px; }
.ctable--server .ctable-th--group > .ctable-th-label { padding: 8px 8px 5px; }
/* Podkolumna z linkiem sortowania — padding niesie link (cały obszar klikalny). */
.ctable--server .ctable-th--period:has(> .ctable-sort) { padding: 0; }
/* Animacje wejścia. Każdy element wstawiony przez HTMX (dane zamiast
   szkieletu) odtwarza animację sam z siebie — CSS gra ją przy wstawieniu,
   bez JS. Przełączanie serii (x-show) też ją odtwarza, bo element wraca
   z display:none. */
@keyframes dash-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes dash-rise { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes dash-bar-grow { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes dash-line-draw { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
.dash-widget-body > :not(.dash-skel) { animation: dash-rise .35s cubic-bezier(.2,.8,.2,1) both; }
.dash-kpis > .kpi { animation: dash-rise .4s cubic-bezier(.2,.8,.2,1) both; }
.dash-kpis > .kpi:nth-child(2) { animation-delay: 40ms; }
.dash-kpis > .kpi:nth-child(3) { animation-delay: 80ms; }
.dash-kpis > .kpi:nth-child(4) { animation-delay: 120ms; }
.dash-kpis > .kpi:nth-child(5) { animation-delay: 160ms; }
.dash-kpis > .kpi:nth-child(6) { animation-delay: 200ms; }
.mchart-bar, .bigchart-svg rect {
  transform-box: fill-box; transform-origin: 50% 100%;
  animation: dash-bar-grow .55s cubic-bezier(.2,.8,.2,1) both;
  animation-delay: var(--mchart-delay, 0ms);
}
.mchart-line { stroke-dasharray: 1; animation: dash-line-draw .8s cubic-bezier(.3,.7,.2,1) both; }
.bigchart-svg polyline, .mchart-svg polyline:not(.mchart-line) { animation: dash-fade-in .6s ease .15s both; }
.mchart-area, .mchart-dots { animation: dash-fade-in .6s ease .15s both; }
.pie-svg { animation: dash-pie-in .6s cubic-bezier(.2,.8,.2,1) both; }
@keyframes dash-pie-in { from { opacity: 0; transform: rotate(-35deg) scale(.9); } to { opacity: 1; transform: none; } }
.ctable-row { animation: dash-fade-in .3s ease both; }
.dash-goal-bar-fill { animation: dash-goal-fill .8s cubic-bezier(.2,.8,.2,1) .15s both; transform-origin: left; }
@keyframes dash-goal-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* Ładowanie bez skakania. Klocek zna swój rozmiar (zadana wysokość albo
   zapamiętana z ostatniego renderu — dashboard.js), więc szkielet trzyma
   miejsce, a nad nim kręci się wskaźnik. Nowe dane podmieniają szkielet
   w tym samym miejscu, zamiast rozpychać siatkę. */
.dash-skel { position: relative; flex: 1; min-height: var(--dash-skel-h, 96px); }
.dash-skel::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 18px; height: 18px; margin: -9px 0 0 -9px;
  border: 2px solid var(--line-2, var(--line)); border-top-color: var(--ink-3);
  border-radius: 50%;
  animation: channels-spin .8s linear infinite;
  opacity: .8;
}
/* channels-spin zdefiniowany w dashboard.css (channels-refresh/dash-loader) —
   duplikat tutaj, bo widgets.css bywa jedynym ładowanym plikiem klocków
   (np. szuflada zadania procesów), a .dash-skel musi się kręcić także tam. */
@keyframes channels-spin { to { transform: rotate(360deg); } }
.dash-skel[data-kind="kpi"] { --dash-skel-h: 190px; }
.dash-skel[data-kind="chart"] { --dash-skel-h: 380px; }
.dash-skel[data-kind="table"] { --dash-skel-h: 240px; }
.dash-skel[data-kind="pie"] { --dash-skel-h: 180px; }
.dash-skel[data-kind="chart"]::before, .dash-skel[data-kind="table"]::before {
  content: ""; position: absolute; inset: 44px 0 0;
  border-radius: 8px;
  background: repeating-linear-gradient(180deg, transparent 0 27px, var(--line) 27px 28px);
  opacity: .5;
}
.dash-kpis .kpi .dash-skel { min-height: 104px; --dash-skel-h: 104px; }
.dash-kpis .kpi .dash-skel::after { display: none; }
/* Odświeżenie zakresu: stara treść zostaje pod półprzezroczystą warstwą,
   dopóki nie przyjdą nowe liczby (dashboard.js dokłada klasę). */
.dash-widget.is-refreshing .dash-widget-body { opacity: .45; transition: opacity .2s; pointer-events: none; }
@media (prefers-reduced-motion: reduce) {
  .spark-line, .spark-area, .mchart-bar, .bigchart-svg rect, .mchart-line,
  .bigchart-svg polyline, .mchart-svg polyline, .mchart-area, .mchart-dots, .pie-svg, .ctable-row,
  .dash-widget-body > *, .dash-kpis > .kpi, .dash-goal-bar-fill {
    animation: none !important;
  }
  .dash-skel::after { animation-duration: 2s; }
}
/* Chip z nazwą celu na kafelku: długa nazwa skraca się wielokropkiem,
   zamiast łamać „cel 200 zł" na dwie linie w wąskim klocku. */
.dash-goal-chip { min-width: 0; max-width: 62%; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; display: inline-flex; align-items: center; gap: 4px; }
.dash-goal-chip svg { flex: none; }
/* Nazwa w wierszu tabeli zakładki kanału jako link do Kanałów — kolor
   tekstu, podkreślenie dopiero na hover (jak .ctable-link). */
.dash-row-link { color: inherit; text-decoration: none; }
.dash-row-link:hover, .dash-row-link:focus-visible { color: var(--accent-deep, var(--ink)); text-decoration: underline; }
/* Stopka tabeli ze stronicowaniem: licznik „1–10 z 57" i pasek stron. */
.ctable-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 8px 4px 2px; font-size: 12px; color: var(--ink-4); }
.ctable-foot .data-table-pager { margin: 0; }
/* Sterowanie tabelą danych (organisms/campaign_table_controls.templ) —
   jeden wygląd dla tabel dashboardu i Kanałów: wyszukiwarka + filtry nad
   tabelą, licznik + wiersze na stronę + strony pod nią. */
.ctable { scroll-margin-top: 12px; }
.ctable-main { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.ctable-tools { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; }
.ctable-search.xsearch { height: 30px; min-width: 200px; max-width: 280px; flex: 0 1 280px; }
.ctable-filter { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; }
.ctable-filter-l { font-size: 11.5px; color: var(--ink-4); margin-right: 2px; }
.ctable-chip {
  display: inline-flex; align-items: center; height: 24px; padding: 0 9px; border-radius: 12px;
  border: 1px solid var(--line); background: var(--bg-elev); color: var(--ink-3);
  font: inherit; font-size: 11.5px; cursor: pointer; text-decoration: none; white-space: nowrap;
}
.ctable-chip:hover { color: var(--ink); background: var(--bg-sunk); }
.ctable-chip.is-on { color: var(--ink); background: var(--accent-wash); border-color: var(--accent-soft); font-weight: 500; }
.ctable-foot-meta { display: inline-flex; gap: 14px; font-variant-numeric: tabular-nums; }
.ctable-foot-r { display: inline-flex; align-items: center; gap: 10px; margin-left: auto; }
.ctable-foot .data-table-per-page-item { width: 100%; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.ctable-foot button.data-table-pager-step, .ctable-foot button.data-table-pager-page { font: inherit; cursor: pointer; }
.ctable-foot button.data-table-pager-ellipsis { border: 0; background: none; cursor: default; }
.ctable-row.is-out { display: none; }
@media print { .ctable-row.is-out { display: table-row; } .ctable-tools, .ctable-foot-r { display: none; } }
.ctable-name-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 7px; vertical-align: 1px; flex: none; }
.ctable-bar { display: inline-flex; align-items: center; gap: 8px; justify-content: flex-end; }
.ctable-bar-track { width: 64px; height: 6px; border-radius: 3px; background: var(--line); overflow: hidden; display: inline-block; }
.ctable-bar-fill { display: block; height: 100%; border-radius: 3px; background: var(--accent-deep); }
.ctable-bar-v { min-width: 34px; text-align: right; }
@media (max-width: 640px) { .ctable-search.xsearch { max-width: none; flex-basis: 100%; } }
/* Gotowe klocki (proxy: dashboard_ready.templ) — karta sekcji zakładki
   kanału w klocku. Klocek ma własną ramkę i tytuł, więc karta oddaje
   ramkę, odstępy i powtórzony tytuł; zostaje opis („co to pokazuje”). */
/* UWAGA: nadpisuje .card (base .card zostaje w dashboard.css, bo to
   ogólna karta strony, nie klocka). .dash-ready renderuje się poprawnie
   tylko tam, gdzie dashboard.css jest też załadowany — jeśli "gotowe
   klocki" mają trafić do miejsc bez dashboard.css (np. szuflada
   zadania), markup musi przestać zależeć od .card albo .card trzeba
   przenieść/zduplikować tutaj. */
.dash-ready > .card { border: 0; box-shadow: none; background: transparent; padding: 0; margin: 0 !important; }
.dash-ready > .card > .card-h .card-title { display: none; }
.dash-ready > .card > .card-h .card-sub { margin-top: 0; }
/* Wzrosty i spadki fraz obok siebie; w wąskim klocku jedna pod drugą. */
.dash-ready-split { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
.dash-ready-split > .card > .card-h .card-title { display: block; }
/* Drugi cel wiersza (CampaignTableRow.AuxHref, np. karta produktu):
   ikonka po prawej stronie komórki nazwy, wyraźna na hover wiersza. */
.ctable-td--name:has(.ctable-aux) { padding-right: 34px; }
/* td nazwy jest sticky, więc to on jest blokiem odniesienia dla absolute. */
.ctable-aux { position: absolute; right: 6px; top: 50%; transform: translateY(-50%); display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 6px; color: var(--ink-4); opacity: .55; }
.ctable-row:hover .ctable-aux, .ctable-aux:focus-visible { opacity: 1; }
.ctable-aux:hover { color: var(--accent-deep); background: var(--accent-wash); }

/* ── Klocki z bloków zadań procesów (zestaw liczb, status, ranking) ─────
   Rysowane przez proxy_sembot (pages/widget_kinds.templ) z tego samego
   SourceResult co reszta klocków — na dashboardzie, w raporcie, czacie
   i w szufladzie zadania. */

/* Zestaw liczb — kafle KPI w siatce, która sama łamie się do szerokości. */
.wvals { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.wvals-item {
  position: relative; min-width: 0;
  padding: 10px 12px 10px 14px;
  border: 1px solid var(--line-2); border-radius: var(--r-md, 10px);
  background: var(--bg-elev);
}
.wvals-item[data-tone]:not([data-tone=""])::before {
  content: ""; position: absolute; left: 0; top: 10px; bottom: 10px;
  width: 3px; border-radius: 0 3px 3px 0; background: var(--ink-4);
}
.wvals-item[data-tone="good"]::before { background: var(--good); }
.wvals-item[data-tone="warn"]::before { background: var(--warn); }
.wvals-item[data-tone="bad"]::before { background: var(--bad); }
.wvals-item .dash-kpi-value { font-size: 22px !important; overflow-wrap: anywhere; }
.wvals-note { font-size: 11.5px; color: var(--ink-3); line-height: 1.35; overflow-wrap: anywhere; }

/* Status — werdykt procesu (warunek spełniony / w normie / błąd). */
.wstatus {
  display: flex; flex-direction: column; gap: 4px;
  padding: 10px 14px;
  border: 1px solid var(--line-2); border-left: 3px solid var(--ink-4);
  border-radius: var(--r-md, 10px); background: var(--bg-elev);
  font-size: 12.5px;
}
.wstatus[data-tone="warn"] { border-left-color: var(--warn); }
.wstatus[data-tone="bad"] { border-left-color: var(--bad); }
.wstatus[data-tone="good"] { border-left-color: var(--good); }
.wstatus-head { display: flex; align-items: center; gap: 8px; }
.wstatus-dot { width: 7px; height: 7px; border-radius: 50%; flex: none; background: var(--ink-4); }
.wstatus[data-tone="warn"] .wstatus-dot { background: var(--warn); }
.wstatus[data-tone="bad"] .wstatus-dot { background: var(--bad); }
.wstatus[data-tone="good"] .wstatus-dot { background: var(--good); }
.wstatus-title { font-size: 13.5px; font-weight: 600; color: var(--ink); line-height: 1.35; }
.wstatus-detail { color: var(--ink-2); overflow-wrap: anywhere; }
.wstatus-meta { display: flex; flex-wrap: wrap; gap: 4px 14px; color: var(--ink-4); font-size: 11.5px; }
.wstatus-meta [title] { cursor: help; text-decoration: underline dotted; text-underline-offset: 3px; }

/* Ranking — poziome paski z etykietą i wartością ze znakiem. */
.wrank { display: flex; flex-direction: column; gap: 7px; }
.wrank-row { display: grid; grid-template-columns: minmax(90px, 40%) 1fr auto; gap: 10px; align-items: center; font-size: 12px; }
.wrank-label { color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.wrank-track { height: 8px; border-radius: 999px; background: var(--bg-sunk); overflow: hidden; }
.wrank-bar { display: block; height: 100%; border-radius: 999px; background: var(--ink-3); }
.wrank-row[data-tone="good"] .wrank-bar { background: var(--good); }
.wrank-row[data-tone="bad"] .wrank-bar { background: var(--bad); }
.wrank-value { font-variant-numeric: tabular-nums; font-family: var(--font-mono, monospace); font-size: 11.5px; color: var(--ink-2); text-align: right; min-width: 56px; }
.wrank-row[data-tone="good"] .wrank-value { color: var(--good); }
.wrank-row[data-tone="bad"] .wrank-value { color: var(--bad); }
@media (max-width: 560px) {
  .wrank-row { grid-template-columns: 1fr auto; }
  .wrank-track { grid-column: 1 / -1; order: 3; }
}

/* ── Blok z opisu zadania procesu (proxy pages/task_blocks.templ) ──────
   Klocek w treści opisu: bez siatki dashboardu, więc bez uchwytu
   przeciągania; podpis „stan z dnia / na żywo” pod danymi. */
.tblock { min-width: 0; }
.tblock .dash-widget { width: 100%; }
.tblock .dash-widget-handle,
.tblock .dash-widget-actions { display: none; }
.tblock-body { min-width: 0; overflow-x: auto; }
.tblock-note { margin: 8px 0 0; font-size: 12px; color: var(--ink-3); line-height: 1.45; }
.tblock-foot {
  display: flex; align-items: center; flex-wrap: wrap; gap: 6px 8px;
  margin-top: 8px; padding-top: 8px; border-top: 1px dashed var(--line-2);
  font-size: 11.5px; color: var(--ink-4);
}
.tblock-foot-gap { flex: 1; }
.tblock-foot.is-live { color: var(--ink-2); }
.tblock-live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--good); box-shadow: 0 0 0 3px var(--good-soft, transparent); flex: none; }
.tblock-missing {
  padding: 10px 12px; border: 1px dashed var(--line-2); border-radius: var(--r-md, 10px);
  color: var(--ink-3); font-size: 12px; background: var(--bg-sunk);
}

/* Kafelek AI bloku bez ramki (werdykt, zestaw liczb): w rogu bloku,
   widoczny po najechaniu — jako osobna linia nad blokiem wyglądał jak
   zgubiony napis. Klasa .dash-widget-head jest tylko po to, żeby pytania
   z wierszy znalazły element kontekstu (marketer-panel.js). */
.tblock { position: relative; }
.tblock-ask.dash-widget-head { position: absolute; top: 6px; right: 6px; z-index: 1; margin: 0; padding: 0; border: 0; background: none; min-height: 0; opacity: 0; transition: opacity .12s; }
.tblock:hover > .tblock-ask, .tblock-ask:focus-within { opacity: 1; }
.task-desc-view.is-editing .tblock-ask { display: none; }
