/* =============================================================
   Таск Визимо — общая дизайн-система страниц /task и /report.
   Отдаётся сервером по адресу /task.css (server.cjs читает этот
   файл с диска на каждый запрос — правки видны после F5, рестарт
   сервера не нужен).
   -------------------------------------------------------------
   Устройство: один каркас на обе страницы. Страница отличается
   только акцентом — атрибут data-tool на <html>:
       tasks  — задания (фиолетовый)
       report — отчёт (бирюзовый)
   Тема тёмная по умолчанию, светлая переключателем в шапке;
   выбор хранится в localStorage под ключом visymo-theme.
   Старый файл лежит в _ui_backup_20260724/task_ui.css.
   ============================================================= */

:root {
  color-scheme: dark;

  --bg: #0a0c12;
  --bg-grad:
     radial-gradient(1100px 620px at 10% -10%, #17203c 0%, rgba(23,32,60,0) 58%),
     radial-gradient(900px 560px at 96% 0%,   #1d1731 0%, rgba(29,23,49,0) 55%),
     linear-gradient(180deg, #0d1018, #0a0c12 55%);

  --panel:     #12151f;
  --panel-2:   #171b27;
  --raise:     rgba(255,255,255,.035);
  --raise-hi:  rgba(255,255,255,.06);

  --line:      #232838;
  --line-soft: #1a1e2b;

  --txt:     #e8ecf6;
  --txt-dim: #c3cadb;
  --muted:   #949db3;
  --muted-2: #6b7387;

  --accent:      #8b7bff;
  --accent-soft: rgba(139,123,255,.16);
  --accent-line: rgba(139,123,255,.38);
  --on-accent:   #0a0718;

  --ok:          #35d48a;
  --ok-soft:     rgba(53,212,138,.14);
  --warn:        #f5b544;
  --warn-soft:   rgba(245,181,68,.14);
  --danger:      #ff7a91;
  --danger-soft: rgba(255,122,145,.13);

  --radius:    16px;
  --shadow:    0 24px 60px -34px rgba(0,0,0,.9);
  --shadow-sm: 0 10px 26px -18px rgba(0,0,0,.8);

  --mono: ui-monospace, "JetBrains Mono", "SF Mono", Consolas, monospace;
  --sans: "Segoe UI Variable Display", "Segoe UI", Inter, system-ui, -apple-system, Roboto, Arial, sans-serif;
}

[data-tool="tasks"]  { --accent:#8b7bff; --accent-soft:rgba(139,123,255,.16); --accent-line:rgba(139,123,255,.38); --on-accent:#0a0718; }
[data-tool="report"] { --accent:#2fd0c4; --accent-soft:rgba(47,208,196,.15);  --accent-line:rgba(47,208,196,.36); --on-accent:#041614; }

[data-theme="light"] {
  color-scheme: light;
  --bg: #f2f5fa;
  --bg-grad:
     radial-gradient(1100px 620px at 10% -10%, #dfe9ff 0%, rgba(223,233,255,0) 55%),
     radial-gradient(900px 560px at 96% 0%,   #ffe7f0 0%, rgba(255,231,240,0) 52%),
     linear-gradient(180deg, #f8fafe, #f0f3f9 60%);
  --panel:     #ffffff;
  --panel-2:   #f8fafd;
  --raise:     #ffffff;
  --raise-hi:  #f4f7fc;
  --line:      #e2e7f0;
  --line-soft: #eaeef5;
  --txt:     #161c2b;
  --txt-dim: #333c52;
  --muted:   #5f6a80;
  --muted-2: #8d97ab;
  --shadow:    0 18px 44px -28px rgba(24,40,80,.45);
  --shadow-sm: 0 8px 20px -14px rgba(24,40,80,.4);
  --on-accent: #ffffff;
  --ok:#12a566; --ok-soft:rgba(18,165,102,.1);
  --warn:#b7791f; --warn-soft:rgba(183,121,31,.12);
  --danger:#d93f57; --danger-soft:rgba(217,63,87,.09);
}
[data-theme="light"][data-tool="tasks"]  { --accent:#6a4df0; --accent-soft:rgba(106,77,240,.1); --accent-line:rgba(106,77,240,.3); }
[data-theme="light"][data-tool="report"] { --accent:#0f9a8d; --accent-soft:rgba(15,154,141,.1); --accent-line:rgba(15,154,141,.3); }

* { box-sizing: border-box; }
html, body { margin:0; padding:0; }
body {
  background: var(--bg-grad) fixed, var(--bg);
  color: var(--txt);
  font-family: var(--sans);
  font-size: 14px; line-height: 1.45;
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; }
button:disabled { cursor: not-allowed; opacity: .45; }
h1,h2,h3,p { margin: 0; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }
.num-t { font-variant-numeric: tabular-nums; }
.spacer { flex: 1 1 auto; }

/* ------------------------------------------------------------- шапка */
.top {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  padding: 11px max(18px, 2.4vw);
  background: rgba(10,12,18,.78);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border-bottom: 1px solid var(--line-soft);
}
[data-theme="light"] .top { background: rgba(248,250,254,.82); }
.ident { display:flex; align-items:center; gap:11px; min-width:0; text-decoration:none; }
.mark {
  width:34px; height:34px; border-radius:10px; flex:none; display:grid; place-items:center;
  background: linear-gradient(150deg, var(--accent), color-mix(in srgb, var(--accent) 55%, #7b8cff));
  color: var(--on-accent); box-shadow: 0 8px 22px -10px var(--accent);
}
.mark svg { width:19px; height:19px; }
.ident h1 { font-size:15.5px; font-weight:660; white-space:nowrap; }
.ident p  { font-size:11.5px; color:var(--muted-2); white-space:nowrap; }

.seg { display:flex; gap:2px; padding:3px; border-radius:12px; background:var(--raise); border:1px solid var(--line-soft); }
.seg button {
  border:0; background:transparent; color:var(--muted); border-radius:9px;
  padding:7px 14px; font-size:12.5px; font-weight:600; white-space:nowrap;
  transition: background .15s, color .15s;
}
.seg button:hover { color: var(--txt); background: var(--raise-hi); }
.seg button[aria-selected="true"] { background: var(--accent-soft); color: var(--accent); box-shadow: inset 0 0 0 1px var(--accent-line); }
.seg a { text-decoration:none; }

.pill {
  display:inline-flex; align-items:center; gap:8px; white-space:nowrap;
  padding:6px 12px; border-radius:999px; font-size:12px; font-weight:600;
  background: var(--raise); border:1px solid var(--line-soft); color: var(--muted);
}
.pill b { color: var(--txt); font-weight:650; }
.dot { width:7px; height:7px; border-radius:50%; background: currentColor; flex:none; }

.icon-btn {
  width:34px; height:34px; border-radius:10px; display:grid; place-items:center; flex:none;
  background: var(--raise); border:1px solid var(--line-soft); color: var(--muted); transition:.16s;
}
.icon-btn:hover { color: var(--txt); background: var(--raise-hi); border-color: var(--line); }
.icon-btn svg { width:17px; height:17px; }

/* шаги: 1 строки → 2 ресёрч → 3 публикация */
.steps { display:flex; align-items:center; gap:6px; }
.step { display:flex; align-items:center; gap:9px; padding:6px 12px 6px 8px; border-radius:10px; font-size:12.5px; color: var(--muted-2); white-space:nowrap; }
.step b { width:20px; height:20px; border-radius:6px; display:grid; place-items:center; font-size:11px; font-weight:700;
          background: var(--raise); border:1px solid var(--line-soft); color: var(--muted-2); }
.step.done { color: var(--muted); }
.step.done b { background: var(--ok-soft); border-color: transparent; color: var(--ok); }
.step.now { color: var(--txt); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent-line); }
.step.now b { background: var(--accent); border-color: transparent; color: var(--on-accent); }
.step-line { width:16px; height:1px; background: var(--line); flex:none; }

/* ------------------------------------------------------------- каркас */
.wrap { max-width: 1420px; margin: 0 auto; padding: 20px max(18px,2.4vw) 110px; }
.cols { display:grid; grid-template-columns: minmax(0,1fr) 356px; gap: 18px; align-items:start; }
.side { display:grid; gap:14px; position: sticky; top: 74px; }
@media (max-width: 1180px) { .cols { grid-template-columns: minmax(0,1fr); } .side { position:static; } }

.card { background: var(--panel); border:1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow-sm); }
.card + .card { margin-top: 14px; }
/* gap 10, а не 12: в шапке сетки теперь и уровень, и фильтр, и поиск — на 12 она
   переносится второй строкой. */
.card-head { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding: 13px 17px; border-bottom:1px solid var(--line-soft); }
.card-head h2 { font-size:13.5px; font-weight:650; }
.card-head .sub { font-size:11.5px; color: var(--muted-2); }
.card-body { padding: 15px 17px; }
.card-body.tight { padding: 12px 14px; }
.eyebrow { font-size:10px; font-weight:730; letter-spacing:.1em; text-transform:uppercase; color:var(--muted-2); }
.hint { font-size:11.5px; color: var(--muted-2); line-height:1.5; }
/* Σ у бюджета и бида кампании: число собрано по её адгруппам, а не задано на
   ней самой. Приглушённый, чтобы не спорить с самой цифрой. */
.sum-mark { margin-right:3px; font-size:10.5px; font-weight:650; color: var(--muted-2); }
.sep { height:1px; background: var(--line-soft); margin: 13px 0; }

/* ------------------------------------------------------------- кнопки */
.btn {
  display:inline-flex; align-items:center; justify-content:center; gap:9px;
  height:38px; padding:0 16px; border-radius:11px; font-size:13px; font-weight:620;
  background: var(--raise); border:1px solid var(--line); color: var(--txt-dim);
  transition: transform .14s, background .14s, border-color .14s, box-shadow .14s;
}
.btn:hover:not(:disabled) { background: var(--raise-hi); transform: translateY(-1px); }
.btn svg { width:15px; height:15px; }
.btn-primary { background: var(--accent); border-color: transparent; color: var(--on-accent); box-shadow: 0 10px 26px -12px var(--accent); }
.btn-primary:hover:not(:disabled) { box-shadow: 0 14px 30px -12px var(--accent); }
.btn-ghost { background: transparent; border-color: transparent; color: var(--muted); }
.btn-ghost:hover:not(:disabled) { background: var(--raise); color: var(--txt); }
.btn-lg { height:44px; padding:0 20px; font-size:14px; border-radius:12px; }
.btn-sm { height:32px; padding:0 12px; font-size:12.5px; border-radius:9px; }
.btn-xs { height:28px; padding:0 10px; font-size:12px; border-radius:8px; }
.btn-block { width:100%; }
.btn-dash { border-style: dashed; color: var(--muted); background: transparent; }
.btn-dash:hover:not(:disabled) { color: var(--accent); border-color: var(--accent-line); background: var(--accent-soft); }

/* ------------------------------------------------------------- поля */
.inp {
  height:38px; width:100%; padding:0 12px; border-radius:10px;
  background: var(--panel-2); border:1px solid var(--line); color: var(--txt);
  outline:none; transition: border-color .14s, box-shadow .14s;
}
.inp::placeholder { color: var(--muted-2); }
.inp:hover { border-color: color-mix(in srgb, var(--accent) 30%, var(--line)); }
.inp:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.inp-sm { height:32px; font-size:13px; }
textarea.inp { height:auto; padding:11px 13px; resize:vertical; line-height:1.55; }
select.inp { appearance:none; padding-right:30px;
  background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: calc(100% - 15px) 16px, calc(100% - 10px) 16px; background-size: 5px 5px; background-repeat:no-repeat; }
input[type="date"].inp { padding-right:8px; }
[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator,
:root:not([data-theme="light"]) input[type="date"]::-webkit-calendar-picker-indicator { filter: invert(.7); }

.field { display:grid; gap:6px; min-width:0; }
/* Только первый span — подпись. Второй span это обёртка поля (.src), и если
   на неё попадут стили подписи, поле унаследует 10 px капсом. */
.field > span:first-child { font-size:10.5px; font-weight:700; letter-spacing:.07em; text-transform:uppercase; color: var(--muted-2); }
.field > span:first-child em { font-style:normal; text-transform:none; letter-spacing:0; font-weight:600; }
.two   { display:grid; grid-template-columns: 1fr 1fr; gap:12px; }
.three { display:grid; grid-template-columns: 1.5fr 1fr 1fr; gap:12px; }
@media (max-width:760px) { .two, .three { grid-template-columns: 1fr; } }

/* маркер источника значения: полоска слева, а не заливка поля */
.src { position:relative; display:block; font-size:14px; font-weight:400; letter-spacing:normal; text-transform:none; }
.src::before { content:""; position:absolute; left:0; top:7px; bottom:7px; width:2px; border-radius:2px; z-index:1; }
.src-ai::before  { background: var(--ok); }
.src-you::before { background: var(--accent); }
.src > .inp { padding-left:14px; }

.chips { display:flex; flex-wrap:wrap; gap:7px; }
.chip {
  display:inline-flex; align-items:center; gap:7px; height:30px; padding:0 11px;
  border-radius:9px; font-size:12.5px; font-weight:600; white-space:nowrap;
  background: var(--raise); border:1px solid var(--line-soft); color: var(--muted); transition:.14s;
}
.chip:hover { color: var(--txt); border-color: var(--line); }
.chip[aria-pressed="true"] { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }

.switch { display:inline-flex; align-items:center; gap:10px; cursor:pointer; font-size:12.5px; color: var(--muted); }
.switch input { position:absolute; opacity:0; pointer-events:none; }
.switch .track { width:38px; height:22px; border-radius:999px; background: var(--line); position:relative; transition:.18s; flex:none; }
.switch .track::after { content:""; position:absolute; top:3px; left:3px; width:16px; height:16px; border-radius:50%; background:#fff; transition:.18s; }
.switch input:checked + .track { background: var(--accent); }
.switch input:checked + .track::after { transform: translateX(16px); }

/* ------------------------------------------------------- карточка задания */
.task { border:1px solid var(--line); border-radius:14px; background: var(--panel); overflow:hidden; transition: border-color .15s; }
.task + .task { margin-top:10px; }
.task:hover { border-color: color-mix(in srgb, var(--accent) 26%, var(--line)); }
.task-h { display:flex; align-items:center; gap:10px; padding:10px 12px; background: var(--panel-2); border-bottom:1px solid var(--line-soft); }
.task-n { width:22px; height:22px; border-radius:7px; display:grid; place-items:center; flex:none;
          font-size:11px; font-weight:700; background: var(--raise); color: var(--muted-2); border:1px solid var(--line-soft); }
.task-title {
  flex:1; min-width:0; height:32px; padding:0 10px; border-radius:8px;
  background: transparent; border:1px solid transparent; color: var(--txt);
  font-size:13px; font-weight:620; outline:none;
}
.task-title::placeholder { color: var(--muted-2); font-weight:500; }
.task-title:hover { border-color: var(--line); }
.task-title:focus { background: var(--panel); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.task-b { padding:13px; display:grid; gap:12px; }
.row-x { width:30px; height:30px; border-radius:8px; border:1px solid transparent; background:transparent; color: var(--muted-2); font-size:16px; line-height:1; flex:none; }
.row-x:hover:not(:disabled) { color: var(--danger); background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 26%, transparent); }

/* свёрнутые параметры: значения видно чипами, редактирование по раскрытию */
.params-box { border:1px solid var(--line-soft); border-radius:12px; background: var(--panel-2); }
.params-box > summary { list-style:none; cursor:pointer; padding:9px 11px; display:flex; align-items:center; gap:9px; flex-wrap:wrap; }
.params-box > summary::-webkit-details-marker { display:none; }
.params-box > summary::before { content:"▸"; color: var(--muted-2); font-size:11px; flex:none; }
.params-box[open] > summary::before { content:"▾"; }
.params-box > summary:hover { background: var(--raise); border-radius:12px; }
.params-grid { display:grid; grid-template-columns: repeat(auto-fit, minmax(150px,1fr)); gap:11px; padding:4px 11px 12px; }
.params { display:flex; flex-wrap:wrap; gap:6px; align-items:center; min-width:0; }
.param {
  display:inline-flex; align-items:center; gap:6px; height:26px; padding:0 9px; border-radius:8px;
  font-size:11.5px; background: var(--raise); border:1px solid var(--line-soft); color: var(--muted); white-space:nowrap;
}
.param em { font-style:normal; color: var(--txt-dim); font-weight:600; font-variant-numeric: tabular-nums; }
.param.edited { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); }
.param.edited em { color: var(--accent); }
.param.ai { background: var(--ok-soft); border-color: color-mix(in srgb, var(--ok) 26%, transparent); color: var(--ok); }
.param.ai em { color: var(--ok); }

.legend { display:flex; gap:16px; flex-wrap:wrap; font-size:11.5px; color: var(--muted-2); }
.legend i { display:inline-block; width:8px; height:8px; border-radius:3px; margin-right:6px; vertical-align:1px; }

.drop {
  border:1.5px dashed var(--line); border-radius:13px; padding:15px; display:flex; align-items:center; gap:14px;
  background: var(--panel-2); transition:.15s; flex-wrap:wrap;
}
.drop.over { border-color: var(--accent); background: var(--accent-soft); }
.drop-ic { width:42px; height:42px; border-radius:11px; display:grid; place-items:center; flex:none;
           background: var(--raise); border:1px solid var(--line-soft); color: var(--muted); }
.drop-ic svg { width:20px; height:20px; }
.drop strong { display:block; font-size:13px; }
.drop .files { font-size:11.5px; color: var(--muted-2); word-break:break-word; }

/* ------------------------------------------------------------- проверки */
.checks { display:grid; gap:10px; }
.check { display:flex; align-items:flex-start; gap:10px; font-size:12.5px; color: var(--muted); }
.check .dot { margin-top:6px; }
.check.ok { color: var(--ok); }
.check.bad { color: var(--danger); }
.check.mute { color: var(--muted-2); }
.check span { color: var(--txt-dim); }
.kv { display:grid; gap:11px; margin:0; }
.kv > div { display:flex; justify-content:space-between; gap:14px; font-size:12.5px; }
.kv dt { color: var(--muted); }
.kv dd { margin:0; color: var(--txt-dim); font-weight:600; text-align:right; font-variant-numeric: tabular-nums; }

/* лента событий / что сделал ИИ */
.feed { display:grid; gap:2px; max-height:300px; overflow:auto; }
.feed-item { display:flex; gap:10px; padding:8px; border-radius:10px; }
.feed-item:hover { background: var(--raise); }
.feed-ic { width:20px; height:20px; border-radius:6px; flex:none; display:grid; place-items:center; font-size:11px; font-weight:800; margin-top:1px; }
.feed-ic.on { background: var(--ok-soft); color: var(--ok); }
.feed-ic.off { background: var(--danger-soft); color: var(--danger); }
.feed-ic.idle { background: var(--raise); color: var(--muted-2); }
.feed-main { min-width:0; flex:1; }
.feed-title { font-size:12.5px; color: var(--txt-dim); }
.feed-meta { font-size:11px; color: var(--muted-2); }

/* консоль хода работы */
.log {
  font-family: var(--mono); font-size:11.5px; line-height:1.65; white-space:pre-wrap; word-break:break-word;
  max-height:220px; overflow:auto; padding:11px 13px; border-radius:11px;
  background: var(--panel-2); border:1px solid var(--line-soft); color: var(--muted);
}
.log a { color: var(--accent); }

/* ------------------------------------------------------------- нижняя панель */
.dock {
  position: fixed; left:0; right:0; bottom:0; z-index:35;
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  padding: 11px max(18px,2.4vw);
  background: rgba(10,12,18,.84);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  border-top:1px solid var(--line-soft);
}
[data-theme="light"] .dock { background: rgba(248,250,254,.88); }
.dock .note { font-size:11.5px; color: var(--muted-2); }
.dock .note b { color: var(--txt-dim); font-weight:620; }

/* ------------------------------------------------------------- отчёт */
.total { display:flex; align-items:baseline; gap:14px; flex-wrap:wrap; }
.total .big { font-size:34px; font-weight:720; letter-spacing:-.03em; font-variant-numeric: tabular-nums; }
.total .cur { font-size:20px; color: var(--muted); }

.offer { border-radius:13px; border:1px solid var(--line-soft); background: var(--panel); overflow:hidden; }
.offer + .offer { margin-top:8px; }
.offer.sel { border-color: var(--accent-line); background: var(--accent-soft); }
.offer-h { display:flex; align-items:center; gap:12px; padding:11px 13px; flex-wrap:wrap; }
.offer-name {
  font-size:13.5px; font-weight:640; border:1px solid transparent; background:transparent;
  border-radius:8px; padding:5px 9px; min-width:140px; flex:1 1 auto; outline:none; color: var(--txt);
}
.offer-name:hover { border-color: var(--line); }
.offer-name:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); background: var(--panel-2); }
.offer-sum { font-size:15px; font-weight:700; font-variant-numeric: tabular-nums; white-space:nowrap; flex:none; }
.offer-share { font-size:11px; color: var(--muted-2); font-variant-numeric: tabular-nums; flex:none; }
.offer-meta { font-size:11px; color: var(--muted-2); white-space:nowrap; overflow:hidden; text-overflow:ellipsis; flex:0 1 auto; min-width:0; }
.offer-meta b { color: var(--txt-dim); font-weight:650; }
.cab-badge { display:inline-block; background: var(--raise); color: var(--muted); border:1px solid var(--line-soft);
             border-radius:6px; padding:1px 6px; font-size:10.5px; margin-left:4px; }
.bar { height:4px; background: var(--line-soft); }
.bar i { display:block; height:100%; background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 45%, transparent)); }
.offer-body { display:none; padding:4px 14px 12px 40px; border-top:1px solid var(--line-soft); background: var(--panel-2); }
.offer-body.open { display:block; }
.camp { display:flex; gap:12px; align-items:center; padding:6px 0; font-size:12px; border-bottom:1px dashed var(--line-soft); }
.camp:last-child { border-bottom:0; }
.camp .s { width:76px; text-align:right; font-variant-numeric: tabular-nums; font-weight:650; flex:none; }
.camp .n { flex:1; color: var(--muted); min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.camp .c { font-size:10.5px; color: var(--muted-2); flex:none; }
.cbx { width:16px; height:16px; accent-color: var(--accent); flex:none; }
.empty { text-align:center; color: var(--muted-2); padding:28px; font-size:13px; }

/* список кабинетов */
.cab-tools { display:flex; gap:9px; align-items:center; flex-wrap:wrap; margin-bottom:10px; }
.cab-list { max-height:280px; overflow:auto; border:1px solid var(--line-soft); border-radius:12px; background: var(--panel-2); padding:5px; }
.cab-item { display:flex; align-items:center; gap:10px; padding:6px 9px; border-radius:8px; cursor:pointer; font-size:12.5px; color: var(--txt-dim); }
.cab-item:hover { background: var(--raise); }

@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration:.01ms !important; transition-duration:.01ms !important; } }

/* =============================================================
   TikTok Ads Manager — дополнения к общей дизайн-системе.
   Всё выше — общий каркас Таск Визимо (см. шапку файла). Ниже
   только то, чего в нём нет: таблица-дерево сетки и её тумблеры.
   Акцент инструмента — синий (data-tool="ads"): своя вкладка на
   глаз не путается ни с заданиями, ни с отчётом.
   ============================================================= */

[data-tool="ads"] { --accent:#4f8cff; --accent-soft:rgba(79,140,255,.15); --accent-line:rgba(79,140,255,.36); --on-accent:#04101f; }
[data-theme="light"][data-tool="ads"] { --accent:#2f6ad9; --accent-soft:rgba(47,106,217,.1); --accent-line:rgba(47,106,217,.3); }

/* ------------------------------------------------------- плитки итогов */
.tiles { display:grid; grid-template-columns: repeat(auto-fit, minmax(118px,1fr)); gap:10px; }
.tile { background: var(--panel-2); border:1px solid var(--line-soft); border-radius:12px; padding:10px 13px; }
.tile span { display:block; font-size:10px; font-weight:730; letter-spacing:.09em; text-transform:uppercase; color: var(--muted-2); }
.tile b { font-size:19px; font-weight:700; letter-spacing:-.02em; font-variant-numeric: tabular-nums; }
.tile.accent b { color: var(--accent); }

/* ------------------------------------------------------- таблица сетки */
.grid-wrap { overflow:auto; max-height: calc(100vh - 372px); min-height: 46vh; border-top:1px solid var(--line-soft); }
table.grid { width:100%; border-collapse:collapse; font-size:12.5px; }
table.grid thead th {
  position:sticky; top:0; z-index:3; background: var(--panel-2); text-align:right;
  padding:9px 10px; border-bottom:1px solid var(--line); color: var(--muted-2);
  font-size:10px; font-weight:730; letter-spacing:.08em; text-transform:uppercase; white-space:nowrap;
}
table.grid thead th.l { text-align:left; }
table.grid thead th.sortable { cursor:pointer; user-select:none; }
table.grid thead th.sortable:hover { color: var(--txt); }
table.grid thead th[aria-sort] { color: var(--accent); }
table.grid thead th i { font-style:normal; margin-left:4px; opacity:.85; }
table.grid tbody td { text-align:right; padding:7px 10px; border-bottom:1px solid var(--line-soft); font-variant-numeric: tabular-nums; white-space:nowrap; color: var(--txt-dim); }
table.grid tbody td.l { text-align:left; white-space:normal; }
table.grid tbody tr:hover { background: var(--raise); }
table.grid tbody tr.sel { background: var(--accent-soft); box-shadow: inset 2px 0 0 var(--accent); }
/* Уровень читается фоном, а не только отступом: глазом видно, где кончается ветка. */
table.grid tbody tr.lvl-adgroup { background: color-mix(in srgb, var(--panel-2) 55%, transparent); }
table.grid tbody tr.lvl-ad { background: color-mix(in srgb, var(--panel-2) 85%, transparent); }
table.grid tbody tr.dim .nm { color: var(--muted); }

.namecell { display:flex; align-items:center; gap:9px; min-width:300px; }
.namecell .txt { min-width:0; }
.nm { font-size:12.5px; font-weight:560; color: var(--txt); word-break:break-word; }
.nsub { font-size:10.5px; color: var(--muted-2); font-variant-numeric: tabular-nums; }
.caret { width:18px; height:18px; flex:none; display:grid; place-items:center; border:0; background:transparent;
  color: var(--muted-2); border-radius:6px; font-size:10px; transition:.14s; }
.caret:hover { color: var(--txt); background: var(--raise-hi); }
.caret.none { visibility:hidden; }

/* Тумблер строки — тот же вид, что у .switch в общем наборе, но кнопкой. */
.tg { width:36px; height:20px; border-radius:999px; background: var(--line); border:0; padding:0; position:relative; flex:none; transition:.18s; }
.tg::after { content:""; position:absolute; top:3px; left:3px; width:14px; height:14px; border-radius:50%; background:#fff; transition:.18s; }
.tg.on { background: var(--ok); }
.tg.on::after { transform: translateX(16px); }
.tg:disabled { opacity:.4; }
.tg.busy { opacity:.5; cursor:progress; }

/* ------------------------------------------------------ просмотр креатива */
.creative-thumb { width:42px; height:56px; flex:none; position:relative; display:grid; place-items:center; overflow:hidden;
  padding:0; border:1px solid var(--line); border-radius:9px; color:var(--muted-2); background:var(--raise);
  box-shadow:0 1px 3px rgba(10,20,38,.08); isolation:isolate; transition:border-color .14s, box-shadow .14s, transform .14s; }
.creative-thumb::before { content:""; position:absolute; inset:0; z-index:0; opacity:.5;
  background:linear-gradient(110deg, transparent 20%, var(--raise-hi) 43%, transparent 66%);
  background-size:220% 100%; animation:thumb-load 1.35s linear infinite; }
.creative-thumb img { position:absolute; inset:0; z-index:1; width:100%; height:100%; object-fit:cover; opacity:0;
  transition:opacity .2s ease; }
.creative-thumb.has-cover img { opacity:1; }
.creative-thumb.has-cover::before, .creative-thumb.cover-unavailable::before { display:none; }
.creative-thumb-play { position:relative; z-index:2; display:grid; place-items:center; width:20px; height:20px;
  padding-left:1px; border:1px solid rgba(255,255,255,.72); border-radius:50%; color:#fff; background:rgba(9,17,31,.58);
  box-shadow:0 1px 5px rgba(0,0,0,.25); font-size:7px; backdrop-filter:blur(2px); transition:.14s; }
.creative-thumb:not(.has-cover) .creative-thumb-play { color:var(--muted-2); border-color:var(--line);
  background:var(--raise-hi); box-shadow:none; }
.creative-thumb:hover { border-color:var(--accent-line, var(--accent)); box-shadow:0 4px 12px rgba(10,20,38,.18); transform:translateY(-1px); }
.creative-thumb:hover .creative-thumb-play { color:#fff; background:color-mix(in srgb, var(--accent) 78%, transparent); }
@keyframes thumb-load { to { background-position:-220% 0; } }
.modal { position:fixed; inset:0; z-index:200; display:flex; align-items:center; justify-content:center;
  padding:24px; background: color-mix(in srgb, #05070c 62%, transparent); backdrop-filter: blur(3px); }
.modal-card { width:min(460px,100%); max-height:92vh; overflow:auto; background: var(--panel);
  border:1px solid var(--line); border-radius:16px; box-shadow:0 24px 80px rgba(0,0,0,.5); }
/* Ролики вертикальные (720×1280) — по высоте, иначе окно уезжает за экран. */
.creative-video { display:block; width:100%; max-height:64vh; border-radius:12px; background:#000; }

/* --------------------------------------------------- балансы кабинетов */
/* Своя обёртка, а не .grid-wrap: у той min-height 46vh — под таблицу на шесть
   строк это полэкрана пустоты. */
.bal-bc + .bal-bc { margin-top:16px; }
.bal-bc-head { display:flex; align-items:center; gap:10px; padding:0 3px 7px; font-size:12.5px; }
.bal-bc-head b { font-weight:650; font-variant-numeric: tabular-nums; }
.bal-wrap { border:1px solid var(--line-soft); border-radius:12px; overflow:auto; max-height:54vh; }
.bal-wrap table.grid thead th { background: var(--panel-2); }
.bal-wrap table.grid tbody tr:last-child td { border-bottom:0; }
.bal-wrap table.grid tbody tr.dim td, .bal-wrap table.grid tbody tr.dim .nm { color: var(--muted-2); }

.tag { display:inline-flex; align-items:center; gap:5px; padding:2px 8px; border-radius:7px; font-size:10.5px; font-weight:650; white-space:nowrap; }
.tag-on { background: var(--ok-soft); color: var(--ok); }
.tag-off { background: var(--danger-soft); color: var(--danger); }
.tag-warn { background: var(--warn-soft); color: var(--warn); }
.tag-sp { background: var(--accent-soft); color: var(--accent); padding:1px 6px; font-size:9.5px; }
/* Модерация — не ошибка и не «работает»: своё, нейтрально-синее состояние.
   Раньше объект на проверке TikTok показывался как «крутится». */
.tag-audit { background: var(--accent-soft); color: var(--accent); }
.tag-audit::before { content:''; width:5px; height:5px; border-radius:50%; background:currentColor; animation: pulse 1.6s ease-in-out infinite; }
@keyframes pulse { 0%,100% { opacity:.35 } 50% { opacity:1 } }

/* ------------------------------------------------------- сообщения */
.note { border-radius:12px; padding:10px 13px; font-size:12px; line-height:1.5; }
.note-warn { background: var(--warn-soft); color: var(--warn); border:1px solid color-mix(in srgb, var(--warn) 30%, transparent); }
.note-err { background: var(--danger-soft); color: var(--danger); border:1px solid color-mix(in srgb, var(--danger) 30%, transparent); }

#toast { position:fixed; right:20px; bottom:88px; z-index:60; display:grid; gap:8px; justify-items:end; }
.toast { background: var(--panel); border:1px solid var(--line); box-shadow: var(--shadow);
  border-radius:12px; padding:11px 14px; font-size:12.5px; max-width:400px; color: var(--txt-dim); }
.toast.ok { border-color: color-mix(in srgb, var(--ok) 40%, transparent); }
.toast.err { border-color: color-mix(in srgb, var(--danger) 45%, transparent); }

.spin { display:inline-block; width:12px; height:12px; border:2px solid var(--line); border-top-color: var(--accent);
  border-radius:50%; animation: spin .7s linear infinite; vertical-align:-1px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* Кнопка «Телефон» — только для узкого экрана: на десктопе она бессмысленна. */
#toMobile { display: none; }

/* ==========================================================================
   ТЕЛЕФОНЫ (≤ 760px)
   Панель открывается с телефона через домен, поэтому экран 390px — рабочий
   размер, а не крайний случай. Всё правится ТОЛЬКО внутри media-query:
   десктопная вёрстка не меняется ни на пиксель.
   `!important` здесь вынужденно: ширины полей заданы инлайном в index.html
   (style="width:210px" и т.п.), а инлайн бьёт обычные правила.
   ========================================================================== */
@media (max-width: 760px) {

  /* --- шапка: подзаголовок и лишние отступы съедают полэкрана --- */
  .top { gap: 9px; padding: 9px 12px; }
  .ident p { display: none; }
  .ident h1 { font-size: 15px; }
  .mark { width: 30px; height: 30px; }
  .top .pill { font-size: 11px; padding: 5px 9px; }

  .wrap { padding: 12px 12px calc(96px + env(safe-area-inset-bottom, 0px)); }

  /* --- панель запроса: одна колонка на всю ширину --- */
  .card-body { padding: 12px; }
  .card-head { padding: 11px 12px; gap: 9px; }
  #presets ~ .spacer, .card-head .spacer { display: none; }
  /* вертикальные разделители-«палочки» между блоками фильтра */
  .card-body > span[style*="width:1px"] { display: none !important; }

  .card-body[style*="flex"] { flex-direction: column; align-items: stretch !important; gap: 9px !important; }

  /* поля и кнопки — на всю ширину и крупнее под палец */
  .card-body .inp,
  .card-body .btn,
  .card-body select.inp { width: 100% !important; max-width: none !important; }
  .inp-sm, .btn-sm { height: 40px; font-size: 14px; }
  .card-body label.hint { display: grid !important; grid-template-columns: 22px 1fr; align-items: center; gap: 8px !important; }

  /* Кнопка «Показать» — главная, поэтому крупнее и последней в потоке. */
  #run { height: 46px; font-size: 15px; }

  /* --- ленты кнопок (периоды, фильтр сетки): один ряд + смахивание --- */
  .seg {
    width: 100%; overflow-x: auto; scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }
  .seg::-webkit-scrollbar { display: none; }
  .seg button { flex: 0 0 auto; padding: 9px 13px; }
  /* переключатель площадок в шапке шириной по содержимому, а не на весь экран */
  #platformSeg { width: auto; }

  /* --- плитки итогов: ровно две в ряд, иначе цифры рвутся --- */
  .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
  .tile { padding: 9px 11px; }
  .tile b { font-size: 17px; }

  /* --- сетка: горизонтальная прокрутка + «липкое» название --- */
  .grid-wrap { max-height: 68vh; min-height: 40vh; }
  table.grid { font-size: 12px; }
  table.grid thead th, table.grid tbody td { padding: 8px 8px; }
  .namecell { min-width: 190px; gap: 7px; }

  /* Колонка выделения не нужна: массовые операции — работа с компьютера,
     а на телефоне она только ловит случайные касания. */
  table.grid thead th:first-child,
  table.grid tbody td:first-child { display: none; }

  /* Название прилипает слева, чтобы при прокрутке метрик было видно, чья строка.
     Фон обязателен и должен повторять подсветку уровня — иначе под ячейкой
     просвечивают соседние колонки. */
  table.grid thead th:nth-child(2),
  table.grid tbody td:nth-child(2) {
    position: sticky; left: 0; z-index: 2;
    background: var(--panel);
    box-shadow: 1px 0 0 var(--line-soft);
  }
  table.grid thead th:nth-child(2) { z-index: 4; background: var(--panel-2); }
  table.grid tbody tr.lvl-adgroup td:nth-child(2) { background: color-mix(in srgb, var(--panel-2) 55%, var(--panel)); }
  table.grid tbody tr.lvl-ad td:nth-child(2)      { background: color-mix(in srgb, var(--panel-2) 85%, var(--panel)); }
  table.grid tbody tr.sel td:nth-child(2)         { background: color-mix(in srgb, var(--accent) 14%, var(--panel)); }

  /* --- поиск и список кабинетов --- */
  #search { width: 100% !important; max-width: none !important; }
  .cab-list { max-height: 220px; }
  .cab-tools .inp { max-width: none !important; }

  /* --- док массовых действий: кнопки в ряд, с отступом под жест «домой» --- */
  .dock {
    gap: 8px; padding: 10px 12px calc(10px + env(safe-area-inset-bottom, 0px));
    flex-wrap: nowrap;
  }
  .dock .note { flex: 0 0 auto; }
  .dock .btn { flex: 1 1 auto; height: 40px; padding: 0 10px; font-size: 13px; }

  /* Уйти на телефонную страницу (mobile.html) — она тут уместнее таблицы. */
  #toMobile { display: inline-flex; height: 34px; }
}

/* =============================================================
   ЭКРАН ОЖИДАНИЯ — «СФЕРА» В КАРТОЧКЕ СЕТКИ (макет 3b)
   -------------------------------------------------------------
   Второго экрана у панели нет: сфера накрывает ТОЛЬКО карточку
   сетки. Строка запроса, плитки итогов и шапка страницы стоят на
   месте всё время — по ним видно, что именно собирается, и период
   можно сменить прямо во время сбора. Шапка самой карточки поднята
   НАД вуалью и остаётся кликабельной: уровень выбирают до запроса.

   Три состояния, и переходы между ними — одно движение:
     .is-idle  дежурное: сфера стоит с первой секунды вместо пустой
               таблицы, кольца и луч вполсилы, в центре — сколько
               кабинетов в области;
     .is-live  сбор: из дежурного сфера не появляется заново, а
               РАЗГОРАЕТСЯ; поверх готовой таблицы — сначала
               засасывает её строки (`#tbody tr.rd-suck`);
     .is-out   уход: точки сходятся в центр, кольца расходятся,
               центр переезжает в плитку «Расход» (двойник
               `.radar-morph`, FLIP по реальным координатам).

   ПОЧЕМУ ВСЁ НА ПЕРЕХОДАХ, А НЕ НА @keyframes: анимация с
   `forwards` держит свойство за собой, и строка выхода до элемента
   уже не доходит, а снятие анимации роняет его в исходное
   состояние скачком. Анимациями остались только вечные петли
   (вращение луча, эхо, покачивание карточек) — они вынесены в
   отдельные узлы, чтобы не спорить с переходами родителя.
   Хореография и тайминги — объект `radar` в index.html.
   ============================================================= */

/* Карточка сетки — система координат сферы; её шапка живёт НАД вуалью. */
#gridCard { position: relative; }
#gridCard > .card-head { position: relative; z-index: 6; }
/* Подпись «Выбери период…» дублировала бы дежурную сферу. */
#gridCard:has(.radar:not([hidden])) .empty { visibility: hidden; }

.radar {
  position: absolute; inset: 0; z-index: 5;
  display: flex; flex-direction: column;
  border-radius: var(--radius); overflow: hidden;
  font-variant-numeric: tabular-nums;
  --rd-1: var(--accent);
  --rd-2: color-mix(in srgb, var(--accent) 62%, #8fb6ff);
  --rd-field: clamp(190px, min(36vh, 26vw), 380px);
  --rd-head: 52px;                      /* высоту шапки карточки ставит JS */
}
.radar[hidden] { display: none; }

/* Вуаль. Таблица под ней остаётся видимой размытым силуэтом — сфера читается
   как «панель думает над этим», а не как отдельная заставка.
   Задержка на входе не косметическая: пока вуаль наливается, ВИДНО, как сфера
   засасывает прежние строки; закройся она сразу — засасывание осталось бы за
   мутным стеклом. */
.radar-veil {
  position: absolute; inset: 0; opacity: 0;
  background:
    radial-gradient(120% 90% at 50% 46%,
      color-mix(in srgb, var(--panel) 86%, transparent) 0%,
      color-mix(in srgb, var(--bg) 90%, transparent) 55%,
      color-mix(in srgb, var(--bg) 97%, transparent) 100%);
  backdrop-filter: blur(14px) saturate(1.06);
  -webkit-backdrop-filter: blur(14px) saturate(1.06);
  transition: opacity .55s cubic-bezier(.2,.8,.2,1) .22s;
}
.radar.is-in  .radar-veil { opacity: 1; }
.radar.is-out .radar-veil { opacity: 0; transition-duration: .52s; transition-delay: .3s; }

/* ------------------------------------------------------------- рябь по зоне */
/* Круги расходятся от сферы по ВСЕЙ карточке и растворяются у краёв — как от
   камешка, брошенного в воду. Бока карточки до этого пустовали, и «локатор»
   читался статичной картинкой.
   Центр ряби НЕ равен центру карточки: сфера центруется по таблице (сверху
   отступ на её шапку), поэтому `--rd-cx/--rd-cy` и предельный радиус
   `--rd-rmax` меряет JS в fitHead(). Значения в var() — запасные, до первого
   замера; они намеренно скромные, иначе на первых кадрах через всю карточку
   проходила гигантская дуга. */
.radar-waves {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  width: 100%; height: 100%;
  opacity: 0; transition: opacity 1.2s ease;
  overflow: visible;
  /* Шапка сетки (уровень, фильтр, поиск) фона не имеет, и кольца проходили
     прямо сквозь неё. Обрезаем рябь по той же линии, по которой начинается
     таблица. */
  clip-path: inset(var(--rd-head, 52px) 0 0 0);
  /* Затухание к краям: волна не обрывается о край зоны, а тает. Проценты
     считаются от карточки, поэтому эллипс сам повторяет её пропорции —
     широкая карточка гасит волну по бокам позже, чем сверху и снизу. */
  -webkit-mask-image: radial-gradient(135% 135% at var(--rd-cx, 50%) var(--rd-cy, 50%),
    #000 12%, rgba(0,0,0,.92) 58%, rgba(0,0,0,.5) 88%, transparent 100%);
          mask-image: radial-gradient(135% 135% at var(--rd-cx, 50%) var(--rd-cy, 50%),
    #000 12%, rgba(0,0,0,.92) 58%, rgba(0,0,0,.5) 88%, transparent 100%);
}
.radar.is-in .radar-waves { opacity: 1; }
/* В сборе рябь приглушена: там своя жизнь — луч, точки, счёт. */
.radar.is-in.is-live .radar-waves { opacity: .6; }
.radar.is-out .radar-waves { opacity: 0; transition-duration: .3s; }
/* На тёмной теме синий по почти чёрному контрастнее втрое: та же рябь, что на
   светлой читается фоном, здесь начинала спорить со сферой. */
:root:not([data-theme="light"]) .radar.is-in .radar-waves { opacity: .62; }
:root:not([data-theme="light"]) .radar.is-in.is-live .radar-waves { opacity: .4; }

/* Кольцо — ЛИНИЯ, а не полоса градиента: у SVG-окружности толщина задаётся
   отдельно от радиуса, поэтому она остаётся волосяной и в 40px от центра, и в
   900px. Растянутый transform-ом div так не умеет — вместе с радиусом растёт и
   полоса, и на краю зоны карандашная линия превращалась в неоновый маркер.
   Плата за это — анимация `r` считается на процессоре, а не на видеокарте; на
   пяти тонких окружностях это ничто, но множить их числом не стоит. */
.radar-waves circle {
  fill: none;
  cx: var(--rd-cx, 50%); cy: var(--rd-cy, 50%);
  stroke: var(--accent); stroke-opacity: .17; stroke-width: 1.1px;
  animation: rdWaveGrow var(--rd-dur, 15s) linear infinite,
             rdWaveFade var(--rd-dur, 15s) linear infinite;
}
/* Волна каждые 3 с — запасные значения до первого замера: дальше и время
   хода, и шаг ставит JS, чтобы скорость кольца не зависела от ширины окна
   (около 58px/с; прежние 137 читались как расходящийся радар, а не рябь). */
.radar-waves circle:nth-child(2) { animation-delay: 3s; }
.radar-waves circle:nth-child(3) { animation-delay: 6s; }
.radar-waves circle:nth-child(4) { animation-delay: 9s; }
.radar-waves circle:nth-child(5) { animation-delay: 12s; }

.radar-stage {
  position: relative; z-index: 2; flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px;
  padding: var(--rd-head) max(14px, 1.6vw) 14px;
}

/* ------------------------------------------------------------- поле */
.radar-field {
  position: relative; flex: none; container-type: inline-size;
  width: var(--rd-field); height: var(--rd-field);
}

/* Кольца — ТОЖЕ волна, а не рамка вокруг сферы. Появляясь, каждое рождается
   под сферой (scale .06 — пятачок в 5px, его закрывает круг центра) и уходит к
   своему радиусу; дальнее трогается позже ближнего, поэтому читается один фронт,
   идущий от центра, а не три круга, надувшихся разом.
   Финиш там же, где кольца стояли раньше: 51 / 75 / 100% поля.

   ШАГ ДОЛЖЕН БЫТЬ НЕ КОРОЧЕ САМОГО ХОДА. Первый вариант считал шаг от
   расстояния между орбитами (0.62с при ходе 0.95с) — арифметически волна, а на
   экране три кольца, идущие внахлёст, то есть «всё разом». Теперь задержка
   равна длительности: кольцо доходит до места и ПЕРЕДАЁТ ход следующему. */
.radar-ring {
  position: absolute; left: 50%; top: 50%; border-radius: 50%;
  opacity: 0; transform: translate(-50%,-50%) scale(.06);
  transition: transform .85s cubic-bezier(.22,.72,.2,1), opacity .5s ease;
}
/* Рамка — на вложенном узле. Появление живёт на родителе (переход), вечный
   прилив — здесь (анимация): на одном элементе они делят transform, и анимация
   перехода не отдаёт — кольцо роняло бы себя в центр рывком. */
.radar-ring > i {
  position: absolute; inset: 0; border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  transition: border-color .6s ease;
  /* `backwards` — не мелочь: без него первые 1.24 с (пока ждёт своей очереди
     дальнее кольцо) действует базовая прозрачность 1, а с началом петли она
     ступенькой падает до .8 — на глаз мигание. */
  animation: rdTide 8s cubic-bezier(.4,0,.35,1) infinite backwards var(--rd-t, 0s);
}
.radar-ring.r1 { width: 51%;  height: 51%;  --rd-t: 0s;    }
.radar-ring.r2 { width: 75%;  height: 75%;  --rd-t: 1.15s; }
.radar-ring.r3 { width: 100%; height: 100%; --rd-t: 2.3s;  }
.radar-ring.r1 > i { border-color: color-mix(in srgb, var(--accent) 30%, transparent); }
.radar-ring.r3 > i { border-color: color-mix(in srgb, var(--accent) 16%, transparent); }
.radar.is-in .radar-ring    { opacity: 1; transform: translate(-50%,-50%) scale(1); }
.radar.is-in .radar-ring.r2 { transition-delay: .85s; }
.radar.is-in .radar-ring.r3 { transition-delay: 1.7s; }

/* Орбита точек стоит ровно на своём кольце (.265/.385/.495 поля против
   .255/.375/.5), поэтому прилив у неё тот же и с той же задержкой — точки едут
   вместе со своим кольцом. Обёртка нужна, чтобы петля не трогала сами точки:
   у них на scale/translate висят состояния («зажглась», «ответила лучу»), и
   анимация перебила бы их насовсем. */
.rd-orbit { position: absolute; inset: 0;
            animation: rdTideO 8s cubic-bezier(.4,0,.35,1) infinite backwards var(--rd-t, 0s); }
.rd-orbit.o0 { --rd-t: 0s;    }
.rd-orbit.o1 { --rd-t: 1.15s; }
.rd-orbit.o2 { --rd-t: 2.3s;  }

/* Луч. Крутится с первого кадра, а появляется отдельной прозрачностью —
   иначе виден рывок «включили вращение». Скорость одна на все состояния:
   сменить animation-duration на ходу — значит дёрнуть луч на новый угол. */
.radar-sweep {
  position: absolute; left: 50%; top: 50%; width: 100%; height: 100%;
  margin: -50% 0 0 -50%; border-radius: 50%; opacity: 0;
  background: conic-gradient(from 0deg,
    color-mix(in srgb, var(--accent) 30%, transparent),
    transparent 26%);
  animation: rdSweep 3.6s linear infinite;
  transition: opacity .9s ease;
}
.radar.is-in .radar-sweep { opacity: 1; }

/* Эхо живёт в своей обёртке: вечная петля внутри, прозрачность снаружи —
   иначе на выходе анимация не отдаёт свойство переходу. */
.radar-echoes { position: absolute; inset: 0; opacity: 0; transition: opacity .6s ease; }
.radar.is-in .radar-echoes { opacity: 1; }
.radar.is-out .radar-echoes { opacity: 0; transition-duration: .28s; }
.radar-echo {
  position: absolute; left: 50%; top: 50%; width: 51%; height: 51%;
  border-radius: 50%; border: 1.5px solid color-mix(in srgb, var(--accent) 34%, transparent);
  transform: translate(-50%,-50%); pointer-events: none;
  animation: rdEcho 2.6s ease-out infinite;
}
.radar-echo.e2 { animation-delay: 1.3s; border-color: color-mix(in srgb, var(--rd-2) 30%, transparent); }

/* ------------------------------------------------------------- точки кабинетов */
.rd-node {
  position: absolute; left: 50%; top: 50%; width: 8px; height: 8px; margin: -4px 0 0 -4px;
  border-radius: 50%; background: color-mix(in srgb, var(--accent) 26%, transparent);
  /* Точка ЖИВЁТ В ЦЕНТРЕ, а своё место на орбите получает вместе с `.is-in` —
     ровно так же, как кольцо получает свой радиус. Раньше смещение стояло тут,
     и созвездие просто проявлялось на готовых местах; теперь оно выезжает из-под
     сферы волной (задержка `--d` считается по радиусу, см. build()). */
  translate: 0px 0px; scale: .2; opacity: 0;
  transition: scale .55s cubic-bezier(.2,.8,.2,1), opacity .5s ease,
              background .55s ease, translate .85s cubic-bezier(.22,.72,.2,1),
              box-shadow .55s ease;
}
.rd-node.sm { width: 6px; height: 6px; margin: -3px 0 0 -3px; background: color-mix(in srgb, var(--accent) 18%, transparent); }
.radar.is-in .rd-node { translate: var(--x) var(--y); scale: 1; opacity: 1; transition-delay: var(--d, 0ms); }
/* Зажглась — отдельным правилом ПОВЕРХ появления, иначе .is-in вернул бы ей
   обычный размер и ответ кабинета стало бы не видно. */
.rd-node.on { background: var(--rd-1); box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 14%, transparent); }
.rd-node.sm.on { background: var(--rd-2); }
.radar.is-in .rd-node.on { scale: 1.3; transition-delay: 0ms; }
/* Отклик кольцом ровно там, где луч — точка «отвечает» под ним, а не сама по себе. */
.rd-node > i {
  position: absolute; inset: -1px; border-radius: 50%;
  border: 1.5px solid var(--rd-1); opacity: 0; pointer-events: none;
}
.rd-node.hit > i { animation: rdPing .85s cubic-bezier(.2,.7,.3,1) both; }
.rd-node.hit { animation: rdPop .6s cubic-bezier(.3,1.4,.4,1) both; }

/* ------------------------------------------------------------- центр */
.radar-core {
  position: absolute; left: 50%; top: 50%; width: 41%; height: 41%;
  opacity: 0; transform: translate(-50%,-50%) scale(.78);
  border-radius: 50%; background: var(--panel);
  box-shadow: 0 24px 50px -24px rgba(0,0,0,.55), 0 0 0 1px var(--line-soft);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px;
  /* Круг — жёсткая рамка: подпись длиннее его хорды переносилась и вылезала за
     нижний край. Отступ по бокам + запрет переноса держат её внутри.
     Отступ В ПИКСЕЛЯХ, а не в процентах: процентный padding считается от ширины
     КОНТЕЙНЕРА (поля 310px), а не самого круга (127px) — внутрь оставалось 59px
     из 127, и число резалось на ровном месте. */
  padding: 0 clamp(6px, 3cqw, 11px); text-align: center;
  --rd-sum: clamp(19px, 7.4cqw, 34px);
  transition: opacity .5s ease, transform .6s cubic-bezier(.2,.9,.25,1), box-shadow .6s ease;
}
.radar-core .cap, .radar-core .of, .radar-core .sum { white-space: nowrap; max-width: 100%; }
.radar.is-in .radar-core { opacity: 1; transform: translate(-50%,-50%) scale(1); transition-delay: .12s; }
.radar.is-out .radar-core { opacity: 0; transition: opacity .18s ease .08s; }
.radar-core .cap, .radar-core .of { transition: opacity .15s ease; }
/* Подписи в круге тянутся за его размером (cqw от поля): на узком экране сфера
   вдвое меньше, а текст оставался прежним — «кабинетов в области» переносилось
   и вылезало за нижний край. Теперь и текст короткий, и кегль пропорционален. */
.radar-core .cap {
  font-size: clamp(7.5px, 2.2cqw, 10px); font-weight: 730; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted-2);
}
.radar-core .sum {
  /* Кегль ужимается под длину: «49» и «$12 480.37» — это 2 и 10 знаков, одним
     размером в круг они не помещаются. Коэффициент ставит JS (`showSum`). */
  font-size: calc(var(--rd-sum) * var(--fit, 1)); font-weight: 800; letter-spacing: -.035em; line-height: 1;
  transition: font-size .2s ease, opacity .15s ease;
}
.radar-core .of { font-family: var(--mono); font-size: clamp(8.5px, 2.5cqw, 11px); font-weight: 600; color: var(--accent); }
.radar-core .bar {
  width: 62%; height: 5px; border-radius: 999px; background: var(--raise-hi);
  overflow: hidden; margin-top: 2px; transition: opacity .4s ease;
}
.radar-core .bar > i { display: block; height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--rd-1), var(--rd-2)); transition: width .55s cubic-bezier(.2,.8,.2,1); }

/* ------------------------------------------------------------- дежурное состояние */
/* Сфера ждёт, а не работает: луч и кольца вполсилы, точки притушены и мельче.
   Составными селекторами (.is-in.is-idle), чтобы не зависеть от порядка правил. */
.radar.is-in.is-idle .radar-sweep { opacity: .3; }
.radar.is-in.is-idle .radar-echoes { opacity: .45; }
.radar.is-in.is-idle .radar-ring > i { border-color: color-mix(in srgb, var(--accent) 13%, transparent); }
.radar.is-in.is-idle .rd-node { scale: .72; opacity: .55; }
.radar.is-in.is-idle .radar-core { box-shadow: 0 18px 40px -26px rgba(0,0,0,.5), 0 0 0 1px var(--line-soft); }
.radar.is-idle .radar-core .bar { opacity: 0; }
.radar.is-idle .radar-core .of { color: var(--muted-2); }

/* ------------------------------------------------------------- карточки ответивших */
.radar-cards { position: absolute; inset: 0; pointer-events: none; }
.rd-card {
  position: absolute; width: 168px;
  opacity: 0; transform: translateY(10px) scale(.96);
  transition: opacity .42s ease, transform .42s cubic-bezier(.2,.8,.2,1);
}
.rd-card.show { opacity: 1; transform: translateY(0) scale(1); }
/* Покачивание — внутри карточки: снаружи её transform занят появлением. */
.rd-card > div {
  padding: 9px 12px; border-radius: 15px;
  background: color-mix(in srgb, var(--panel) 88%, transparent);
  box-shadow: var(--shadow-sm), 0 0 0 1px var(--line-soft);
  display: flex; flex-direction: column; gap: 3px;
}
.rd-card.show > div { animation: rdFloat 5s ease-in-out infinite; }
.rd-card .who {
  font-family: var(--mono); font-size: 10px; font-weight: 600; color: var(--muted-2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rd-card .val { font-size: 15px; font-weight: 800; letter-spacing: -.02em; }
.rd-card.bad > div { background: color-mix(in srgb, var(--danger-soft) 70%, var(--panel)); }
.rd-card.bad .who, .rd-card.bad .val { color: var(--danger); }
.rd-card.s0 { left: -206px; top: 10%; }
.rd-card.s1 { left: -186px; top: 64%; }
.rd-card.s2 { right: -206px; top: 6%; }
.rd-card.s3 { right: -186px; top: 60%; }
.rd-card.s1 > div, .rd-card.s3 > div { animation-delay: 1.2s; }
.rd-card.s2 > div { animation-delay: .6s; }

/* ------------------------------------------------------------- нижняя строка */
/* Дежурная подпись и рабочая строка стоят в одном месте и меняются
   прозрачностью — строка не переезжает, когда сбор начинается. */
.radar-bottom { position: relative; width: min(940px, 96%); height: 44px; flex: none; }
.radar-hint, .radar-foot {
  position: absolute; left: 0; right: 0; top: 0;
  display: flex; align-items: center; gap: 10px; justify-content: center;
  height: 44px; padding: 0 16px; border-radius: 16px;
  background: color-mix(in srgb, var(--panel) 76%, transparent);
  box-shadow: 0 0 0 1px var(--line-soft);
  opacity: 0; transform: translateY(12px);
  transition: opacity .45s ease, transform .45s cubic-bezier(.2,.8,.2,1);
}
.radar-hint { font-size: 12.5px; color: var(--muted); }
.radar-foot { justify-content: flex-start; }
.radar.is-in.is-idle .radar-hint { opacity: 1; transform: none; transition-delay: .16s; }
.radar.is-in.is-live .radar-foot { opacity: 1; transform: none; transition-delay: .12s; }
.radar.is-out .radar-hint, .radar.is-out .radar-foot {
  opacity: 0; transform: translateY(8px); transition-duration: .34s; transition-delay: 0s;
}
.radar-foot .cap {
  font-size: 11px; font-weight: 730; letter-spacing: .12em; text-transform: uppercase; color: var(--muted-2);
}
.rd-step {
  padding: 6px 12px; border-radius: 999px; font-size: 11.5px; font-weight: 600; white-space: nowrap;
  background: var(--raise); color: var(--muted);
  transition: background .5s ease, color .5s ease;
}
.rd-step.on { background: var(--accent-soft); color: var(--accent); }
.rd-step.done { color: var(--txt-dim); }
.radar-foot .bar { width: 180px; height: 6px; border-radius: 999px; background: var(--raise-hi); overflow: hidden; flex: none; }
.radar-foot .bar > i { display: block; height: 100%; width: 0; border-radius: 999px;
  background: linear-gradient(90deg, var(--rd-1), var(--rd-2)); transition: width .55s cubic-bezier(.2,.8,.2,1); }
.radar-foot .pct { font-family: var(--mono); font-size: 11.5px; font-weight: 700; }
.radar-foot .esc { font-size: 11px; color: var(--muted-2); white-space: nowrap; }

/* ------------------------------------------------------------- засасывание строк */
/* Прежний список не подменяется, а улетает в центр сферы: ближние строки
   уходят первыми, дальние тянутся следом — поэтому видно направление, а не
   просто исчезновение. Смещение до центра считает JS (`suck`). */
#tbody tr.rd-suck {
  transform: translate(var(--sx, 0), var(--sy, 0)) scale(.24);
  opacity: 0;
  transition: transform .58s cubic-bezier(.5,0,.25,1) var(--d, 0ms),
              opacity .42s ease var(--d, 0ms);
  pointer-events: none;
}

/* ------------------------------------------------------------- итоги на время сбора */
/* Плитки наверху не исчезают и не обнуляются: это ещё цифры прошлого запроса,
   и сказать об этом надо приглушением, а не подменой на прочерки. */
#tiles.is-stale .tile b { opacity: .3; }
#tiles .tile b { transition: opacity .45s ease; }

/* ------------------------------------------------------------- выход */
/* Тайминги согласованы с `radar.finish()` в index.html — правя одно, править оба. */
/* Уход быстрый: у появления ход длинный (кольцо идёт из центра почти секунду),
   но на выходе ждать его нельзя — вуаль гаснет за полсекунды и срезала бы
   хвост. Поэтому и длительность, и задержки перебиваются здесь. */
.radar.is-out .radar-ring { opacity: 0; transform: translate(-50%,-50%) scale(1.5);
                            transition-duration: .42s; transition-delay: 0s; }
.radar.is-out .radar-ring.r2 { transition-delay: .03s; }
.radar.is-out .radar-ring.r3 { transition-delay: .06s; }
.radar.is-out .radar-sweep { opacity: 0; transition-duration: .34s; }
.radar.is-out .rd-node { translate: 0px 0px; scale: .15; opacity: 0;
                         transition-duration: .34s; transition-delay: 0ms; animation: none; }
/* Зажжённая точка крупнее прочих (правило .is-in .on), и без этой строки
   она бы уехала в центр, не сжавшись. */
.radar.is-out .rd-node.on { scale: .15; }
.radar.is-out .rd-card { opacity: 0; transform: translateY(-10px) scale(.94); }
.radar.is-out .rd-card > div { animation: none; }

/* Двойник центра, который переезжает в плитку «Расход». Живёт вне .radar,
   поэтому сфера может гаснуть, а он — продолжать путь. */
.radar-morph {
  position: fixed; z-index: 61; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: 5px;
  background: var(--panel); box-shadow: 0 24px 50px -24px rgba(0,0,0,.55), 0 0 0 1px var(--line-soft);
  overflow: hidden; pointer-events: none;
  transition: left .66s cubic-bezier(.2,.75,.2,1), top .66s cubic-bezier(.2,.75,.2,1),
              width .66s cubic-bezier(.2,.75,.2,1), height .66s cubic-bezier(.2,.75,.2,1),
              border-radius .66s cubic-bezier(.2,.75,.2,1), gap .66s ease, padding .66s ease,
              background .66s ease, box-shadow .66s ease, opacity .22s ease;
}
.radar-morph .cap {
  font-size: 10px; font-weight: 730; letter-spacing: .09em; text-transform: uppercase;
  color: var(--muted-2); white-space: nowrap;
}
.radar-morph .sum {
  font-weight: 800; letter-spacing: -.03em; line-height: 1; color: var(--accent); white-space: nowrap;
  transition: font-size .66s cubic-bezier(.2,.75,.2,1);
}
.radar-morph.to-tile {
  border-radius: 12px; gap: 1px; align-items: flex-start; padding: 10px 13px;
  background: var(--panel-2); box-shadow: 0 0 0 1px var(--line-soft);
}

/* Приземление сводки: плитки и первые строки не появляются разом, а
   всплывают друг за другом — та же волна, только наружу. */
.rd-land { animation: rdLand .46s cubic-bezier(.2,.8,.2,1) both; animation-delay: var(--d, 0ms); }

@keyframes rdLand { from { opacity: 0; transform: translateY(9px) } to { opacity: 1; transform: translateY(0) } }
@keyframes rdSweep { to { transform: rotate(360deg) } }
/* Рябь. Ход и затухание разведены по двум анимациям (см. .radar-waves circle):
   кольцо идёт равномерно, а гаснет по своей кривой. Предельный радиус — в
   переменной, он зависит от размеров карточки и ставится из JS. */
@keyframes rdWaveGrow {
  from { r: 30px }
  to   { r: var(--rd-rmax, 520px) }
}
/* Гаснет РОВНО ВСЮ ДОРОГУ — от рождения до края зоны, без плато. Короткая
   вспышка на старте нужна только чтобы кольцо не появлялось из ниоткуда
   ступенькой. */
@keyframes rdWaveFade {
  0%   { opacity: 0 }
  4%   { opacity: 1 }
  100% { opacity: 0 }
}
/* Прилив по кольцам: волна раз в 8 с проходит от центра наружу — кольцо
   отодвигается на 3.5% своего радиуса и на пике светлеет. Порядок задаёт
   `--rd-t` (см. .radar-ring), а не разные кривые: одна и та же анимация со
   сдвигом читается как ОДИН фронт. Размах намеренно мал — движение должно
   ощущаться, а не бросаться в глаза: у внешнего кольца это 5px хода.

   САМ ВСПЛЕСК КОРОЧЕ ШАГА — 1.2 с против 1.15 с задержки. В первом варианте он
   занимал полпериода, и при шаге 0.62 с все три кольца качались одновременно:
   формально волна, на глаз — «дышит всё сразу». Теперь кольцо успевает вернуться
   в покой, пока поднимается следующее, и дальше 4.5 с тишины до нового захода. */
@keyframes rdTide {
  0%       { transform: scale(1);     opacity: .8 }
  7%       { transform: scale(1.035); opacity: 1 }
  15%,100% { transform: scale(1);     opacity: .8 }
}
/* Тот же прилив для орбит — но БЕЗ прозрачности: обёртка умножает её на
   собственную прозрачность точек, и зажжённые кабинеты меркли бы в такт волне. */
@keyframes rdTideO {
  0%       { transform: scale(1) }
  7%       { transform: scale(1.035) }
  15%,100% { transform: scale(1) }
}
@keyframes rdEcho { from { transform: translate(-50%,-50%) scale(.55); opacity: .5 }
                    to   { transform: translate(-50%,-50%) scale(1.75); opacity: 0 } }
@keyframes rdFloat { 0%,100% { transform: translateY(0) } 50% { transform: translateY(-7px) } }
@keyframes rdPing { from { opacity: .6; transform: scale(1) } to { opacity: 0; transform: scale(4.4) } }
@keyframes rdPop  { 0% { scale: 1 } 45% { scale: 2.1 } 100% { scale: 1.3 } }

/* Узкие экраны: карточки ответивших не влезают по бокам от круга. */
@media (max-width: 1240px) { .rd-card { display: none } }
@media (max-width: 760px) {
  .radar-foot { gap: 8px; padding: 0 12px; }
  .radar-foot .cap, .radar-foot .esc, #rdStep1, #rdStep2 { display: none; }
  .radar-foot .bar { flex: 1 1 auto; width: auto; }
}

/* ============================ СТАВКИ И REPLACE ============================ */
/* Кнопка-значение в ячейке «Бид»: выглядит как текст, карандаш проявляется
   при наведении — таблица не превращается в поле кнопок. */
.bid-btn { background:none; border:0; color:inherit; font:inherit; cursor:pointer;
  padding:2px 6px; border-radius:6px; }
.bid-btn:hover { background:var(--line-soft); }
.bid-btn i { font-style:normal; font-size:11px; margin-left:4px; color:var(--muted);
  opacity:0; transition:opacity .12s ease; }
.bid-btn:hover i { opacity:1; }
.bid-edit { display:inline-flex; gap:4px; align-items:center; }
.bid-edit .inp { width:76px; }

/* Лог прогона в диалоге ставок: строка на адгруппу, ok/err цветом. */
.bid-log { display:grid; gap:6px; max-height:340px; overflow:auto; font-size:12.5px; }
.bid-log:empty { display:none; }
.bid-log .row { display:flex; gap:8px; align-items:baseline; flex-wrap:wrap;
  border-bottom:1px dashed var(--line-soft); padding-bottom:5px; }
.bid-log .row.ok { color:var(--ok); }
.bid-log .row.ok b { color:inherit; }
.bid-log .row.err { color:var(--danger); }
.bid-log .row .err { color:var(--danger); }

/* Full-table silk: wide translucent ribbons, with a quiet glass readout. */
.radar { --rd-1:#85baff; --rd-2:#c3abef; --rd-field:min(340px,76vw); font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif; }
.radar .radar-waves,.radar .radar-ring,.radar .radar-sweep,.radar .radar-echoes,.radar .radar-cards,#radarNodes { display:none; }
.silk-panorama {
 position:absolute; inset:var(--rd-head,52px) 0 0; z-index:1; overflow:hidden;
 pointer-events:none; opacity:0; transition:opacity .8s ease;
 background:radial-gradient(ellipse at 0% 65%,#8abfff25,transparent 60%),radial-gradient(ellipse at 100% 30%,#d4b2f525,transparent 60%);
}
.loading-scene-image {
 position:absolute; inset:var(--rd-head,52px) 0 0; z-index:1; overflow:hidden;
 pointer-events:none; opacity:0; transform:scale(1.015);
 /* В исходных иллюстрациях нарисованы свои верхняя панель и нижняя плашка.
    Их не показываем: кадрируем до художественного фона, а настоящий прогресс
    и единственная подпись остаются элементами интерфейса поверх него. */
 background-position:50% 54%; background-repeat:no-repeat; background-size:260% auto;
 -webkit-mask-image:linear-gradient(to bottom,#000 0 68%,rgba(0,0,0,.78) 81%,transparent 100%);
         mask-image:linear-gradient(to bottom,#000 0 68%,rgba(0,0,0,.78) 81%,transparent 100%);
 transition:opacity .8s ease,transform 6s ease-out;
}
.loading-scene-image::before,.loading-scene-image::after {
 content:''; position:absolute; pointer-events:none; opacity:0;
}
/* Мягкие цветовые пятна не просто лежат на кадре: они медленно сходятся и
   расходятся, поэтому статичная иллюстрация ощущается живой, но не отвлекает
   от счётчика и фактического прогресса. */
.loading-scene-image::before {
 inset:-20%;
 background:radial-gradient(ellipse at 22% 68%,#78b7ff38,transparent 38%),
            radial-gradient(ellipse at 78% 25%,#caa7f445,transparent 42%);
 filter:blur(10px); mix-blend-mode:screen;
}
/* Один спокойный блик проходит по стеклу раз в несколько секунд. */
.loading-scene-image::after {
 inset:-40% -70%;
 background:linear-gradient(108deg,transparent 43%,#ffffff00 47%,#ffffff70 50%,#ffffff00 53%,transparent 57%);
 transform:translateX(-42%); mix-blend-mode:soft-light;
}
.radar.has-scene-image .silk-panorama { display:none; }
.radar.has-scene-image.is-in .loading-scene-image {
 opacity:1; transform:scale(1); animation:sceneCamera 6.5s cubic-bezier(.45,.05,.55,.95) infinite alternate;
}
.radar.has-scene-image.is-in .loading-scene-image::before { animation:sceneGlow 5.2s ease-in-out infinite alternate; }
.radar.has-scene-image.is-in .loading-scene-image::after { animation:sceneSweep 4.8s ease-in-out infinite .65s; }
.radar.has-scene-image.is-out .loading-scene-image { opacity:0; transition-duration:.55s; }
.radar.is-in .silk-panorama { opacity:1; }
.radar.is-out .silk-panorama { opacity:0; transition-duration:.55s; }
.silk-panorama::before,.silk-panorama::after {
 content:''; position:absolute; inset:-30%;
 background:radial-gradient(ellipse at 25% 65%,#86dce632,transparent 45%),radial-gradient(ellipse at 75% 30%,#c8acf640,transparent 45%);
 animation:silkAtmosphere 14s ease-in-out infinite alternate;
}
.silk-panorama::after { animation-delay:-7s; background:radial-gradient(ellipse at 70% 70%,#ffcdde28,transparent 50%); }
.silk-panorama svg { position:absolute; width:140%; height:120%; left:-20%; top:-10%; overflow:visible; }
.silk-ribbon { transform-origin:center; animation:silkDrift 12s ease-in-out infinite alternate; }
.silk-ribbon.r2 { animation-name:silkCounter; animation-duration:16s; animation-delay:-6s; }
.silk-ribbon.r3 { animation-duration:19s; animation-delay:-9s; }
.silk-ribbon.r4 { animation-name:silkCounter; animation-duration:14s; animation-delay:-4s; }
.silk-edge { fill:none; stroke:url(#silkEdge); stroke-width:1.3; vector-effect:non-scaling-stroke; }
.silk-thread { fill:none; stroke:url(#silkEdge); stroke-width:.65; opacity:.5; vector-effect:non-scaling-stroke; }
.silk-travel { fill:none; stroke:url(#silkLight); stroke-width:2; stroke-dasharray:80 1750; stroke-linecap:round; animation:silkTravel 7s linear infinite; opacity:.65; }
.silk-ribbon.r2 .silk-travel { animation-delay:-3s; animation-duration:9s; }
.silk-ribbon.r3 .silk-travel { animation-delay:-5s; animation-duration:11s; }
.radar-stage { gap:20px; }
.radar .radar-field { width:var(--rd-field); height:190px; }
.radar .radar-core {
 inset:0; width:100%; height:100%; padding:24px; gap:12px; border-radius:30px;
 background:color-mix(in srgb,var(--panel) 62%,transparent);
 border:1px solid #ffffff30; backdrop-filter:blur(26px) saturate(1.2);
 box-shadow:inset 0 1px 0 #ffffff20,0 16px 55px #00000013;
 transform:translateY(15px) scale(.97); --rd-sum:42px;
}
.radar.is-in .radar-core { transform:translateY(0) scale(1); }
.radar.is-in.is-idle .radar-core { box-shadow:inset 0 1px 0 #ffffff20,0 16px 55px #00000013; }
.radar-core .cap { font-size:10px; font-weight:500; letter-spacing:.2em; color:var(--muted); }
.radar-core .sum { font-size:calc(42px * var(--fit,1)); font-weight:550; letter-spacing:-.05em; }
.radar-core .of { font-family:inherit; font-size:12px; color:var(--muted); font-weight:400; }
.radar .radar-core .bar { width:72%; height:3px; margin-top:5px; background:color-mix(in srgb,var(--muted) 16%,transparent); }
.radar .radar-core .bar > i { background:linear-gradient(90deg,#79b9ee,#b4a2e2,#dfb6d1); }
.radar .radar-bottom { width:min(400px,90%); height:36px; }
.radar .radar-foot,.radar .radar-hint {
 height:36px; border-radius:20px; padding:0 16px;
 background:color-mix(in srgb,var(--panel) 68%,transparent);
 backdrop-filter:blur(16px); box-shadow:0 0 0 1px var(--line-soft);
}
.radar-foot .cap,.radar-foot .bar,.radar-foot .esc,#rdStep1,#rdStep2 { display:none; }
.radar .rd-step { background:none; padding:0; color:var(--muted); font-size:11px; font-weight:400; }
.radar .radar-foot .pct { color:var(--muted); font-size:10px; }
.radar .radar-hint { font-size:11px; }
#tbody tr.rd-suck { transform:translateY(8px); opacity:0; }
:root[data-theme="light"] .radar .radar-core { background:#ffffff88; border-color:#ffffffd0; box-shadow:inset 0 1px 0 #fff,0 16px 50px #6580a315; }
:root[data-theme="light"] .silk-panorama { filter:saturate(1.12); }
:root:not([data-theme="light"]) .silk-panorama { filter:saturate(.85); }
@keyframes silkDrift { from { transform:translate(-35px,-18px) scaleY(.86) rotate(-2deg); } to { transform:translate(35px,26px) scaleY(1.12) rotate(2deg); } }
@keyframes silkCounter { from { transform:translate(28px,32px) scaleY(1.08) rotate(2deg); } to { transform:translate(-28px,-24px) scaleY(.85) rotate(-2deg); } }
@keyframes silkAtmosphere { from { transform:translate(-4%,-3%) scale(.95); } to { transform:translate(4%,3%) scale(1.08); } }
@keyframes silkTravel { to { stroke-dashoffset:-1830; } }
@keyframes sceneCamera {
 from { background-position:43% 58%; transform:scale(1); }
 to   { background-position:57% 45%; transform:scale(1.055); }
}
@keyframes sceneGlow {
 from { opacity:.36; transform:translate3d(-4%,-2%,0) scale(.94); }
 to   { opacity:.72; transform:translate3d(5%,3%,0) scale(1.08); }
}
@keyframes sceneSweep {
 0%,12% { opacity:0; transform:translateX(-42%); }
 40%     { opacity:.72; }
 58%     { opacity:.72; transform:translateX(42%); }
 72%,100%{ opacity:0; transform:translateX(42%); }
}
@media(max-height:640px) { .radar .radar-field { height:155px; } .radar .radar-core { gap:8px; padding:16px; } }
@media(prefers-reduced-motion:reduce) {
 .radar *, .radar *::before,.radar *::after,#tbody tr.rd-suck { animation:none !important; transition-duration:.01s !important; transition-delay:0s !important; }
}

/* Panorama compatibility for an older document with freshly loaded styles. */
.radar { isolation:isolate; }
.radar-veil { z-index:0; }
.radar > .silk-panorama { z-index:1; }
.radar > .radar-stage { z-index:2; }
.radar:not(:has(.silk-panorama)) .radar-veil::after {
 content:''; position:absolute; inset:var(--rd-head,52px) -10% 0;
 background-image:url("data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%201600%20520%22%20preserveAspectRatio%3D%22none%22%3E%3Cdefs%3E%0A%3ClinearGradient%20id%3D%22silkBlue%22%20x2%3D%220.8%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22%237ebce8%22%20stop-opacity%3D%22.06%22%2F%3E%3Cstop%20offset%3D%22.55%22%20stop-color%3D%22%2383bcec%22%20stop-opacity%3D%22.3%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23c3e7fa%22%20stop-opacity%3D%22.05%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22silkLilac%22%20x2%3D%22.8%22%20y2%3D%221%22%3E%3Cstop%20stop-color%3D%22%23c2b0e8%22%20stop-opacity%3D%22.08%22%2F%3E%3Cstop%20offset%3D%22.6%22%20stop-color%3D%22%23b09bdd%22%20stop-opacity%3D%22.27%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23e8d5f8%22%20stop-opacity%3D%22.04%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22silkMint%22%20x2%3D%221%22%20y2%3D%22.4%22%3E%3Cstop%20stop-color%3D%22%2378c9d6%22%20stop-opacity%3D%22.27%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%239edcdb%22%20stop-opacity%3D%22.06%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23a9cce8%22%20stop-opacity%3D%22.25%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22silkRose%22%20x2%3D%221%22%20y2%3D%22.8%22%3E%3Cstop%20stop-color%3D%22%23e7c7db%22%20stop-opacity%3D%22.03%22%2F%3E%3Cstop%20offset%3D%22.65%22%20stop-color%3D%22%23e6b8d2%22%20stop-opacity%3D%22.2%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23b9b7ea%22%20stop-opacity%3D%22.05%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22silkEdge%22%3E%3Cstop%20stop-color%3D%22%23a1cdec%22%20stop-opacity%3D%22.08%22%2F%3E%3Cstop%20offset%3D%22.4%22%20stop-color%3D%22%23d5ecff%22%20stop-opacity%3D%22.8%22%2F%3E%3Cstop%20offset%3D%22.7%22%20stop-color%3D%22%23cbbbea%22%20stop-opacity%3D%22.5%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23c5dfed%22%20stop-opacity%3D%22.1%22%2F%3E%3C%2FlinearGradient%3E%0A%3ClinearGradient%20id%3D%22silkLight%22%3E%3Cstop%20stop-color%3D%22%23a7dcfa%22%20stop-opacity%3D%220%22%2F%3E%3Cstop%20offset%3D%22.5%22%20stop-color%3D%22%23d7eafa%22%2F%3E%3Cstop%20offset%3D%221%22%20stop-color%3D%22%23bcacf0%22%20stop-opacity%3D%220%22%2F%3E%3C%2FlinearGradient%3E%0A%3C%2Fdefs%3E%3Cg%20class%3D%22silk-ribbon%20r1%22%3E%3Cpath%20d%3D%22M0%20340%20C300%20500%20450%2040%20800%20230%20S1250%20500%201600%20170%20L1600%20280%20C1250%20560%201150%20460%20800%20270%20S300%20520%200%20440%20Z%22%20fill%3D%22url(%23silkBlue)%22%2F%3E%3Cpath%20d%3D%22M0%20340%20C300%20500%20450%2040%20800%20230%20S1250%20500%201600%20170%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M0%20440%20C300%20520%20450%20100%20800%20270%20S1250%20560%201600%20280%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.25%22%2F%3E%3Cpath%20d%3D%22M0%20340%20C300%20500%20450%2040%20800%20230%20S1250%20500%201600%20170%22%20fill%3D%22none%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3Cg%20class%3D%22silk-ribbon%20r2%22%3E%3Cpath%20d%3D%22M0%20100%20C350%20-30%20480%20480%20850%20280%20S1280%2010%201600%20180%20L1600%20270%20C1280%2070%201220%20130%20850%20330%20S350%2020%200%20170%20Z%22%20fill%3D%22url(%23silkLilac)%22%2F%3E%3Cpath%20d%3D%22M0%20100%20C350%20-30%20480%20480%20850%20280%20S1280%2010%201600%20180%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M0%20170%20C350%2020%20480%20550%20850%20330%20S1280%2070%201600%20270%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.25%22%2F%3E%3Cpath%20d%3D%22M0%20100%20C350%20-30%20480%20480%20850%20280%20S1280%2010%201600%20180%22%20fill%3D%22none%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3Cg%20class%3D%22silk-ribbon%20r3%22%3E%3Cpath%20d%3D%22M0%20420%20C260%20120%20470%20160%20800%20350%20S1270%20240%201600%2060%20L1600%20140%20C1270%20310%201130%20590%20800%20400%20S260%20230%200%20470%20Z%22%20fill%3D%22url(%23silkMint)%22%2F%3E%3Cpath%20d%3D%22M0%20420%20C260%20120%20470%20160%20800%20350%20S1270%20240%201600%2060%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M0%20470%20C260%20230%20470%20220%20800%20400%20S1270%20310%201600%20140%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.25%22%2F%3E%3Cpath%20d%3D%22M0%20420%20C260%20120%20470%20160%20800%20350%20S1270%20240%201600%2060%22%20fill%3D%22none%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3Cg%20class%3D%22silk-ribbon%20r4%22%3E%3Cpath%20d%3D%22M0%2060%20C350%20260%20500%2060%20850%20170%20S1300%20510%201600%20370%20L1600%20460%20C1300%20570%201200%20330%20850%20220%20S350%20310%200%20130%20Z%22%20fill%3D%22url(%23silkRose)%22%2F%3E%3Cpath%20d%3D%22M0%2060%20C350%20260%20500%2060%20850%20170%20S1300%20510%201600%20370%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.5%22%2F%3E%3Cpath%20d%3D%22M0%20130%20C350%20310%20500%20120%20850%20220%20S1300%20570%201600%20460%22%20fill%3D%22none%22%20stroke%3D%22%23b5cde8%22%20stroke-opacity%3D%22.25%22%2F%3E%3Cpath%20d%3D%22M0%2060%20C350%20260%20500%2060%20850%20170%20S1300%20510%201600%20370%22%20fill%3D%22none%22%20stroke%3D%22none%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E");
 background-size:100% 100%; background-repeat:no-repeat;
 animation:panoramaFallback 12s ease-in-out infinite alternate; pointer-events:none;
}
@keyframes panoramaFallback { from { transform:translateX(-2%) scaleY(.94); } to { transform:translateX(2%) scaleY(1.06); } }
.radar.is-live #radarOf { opacity:1 !important; transition:none; }
@media(prefers-reduced-motion:reduce) { .radar:not(:has(.silk-panorama)) .radar-veil::after { animation:none; } }
