Files
portal/live-demo/proof.html
T
Дмитрий 35c30ecce0 docs(приёмка): корпус приёмочного теста + поправка №15 + статусы реестра
F-CORPUS: ключевые документы приёмки liderra.ru лежали untracked — мастер-
хэндофф ссылался на отсутствующие в git файлы (битые ссылки в новом клоне).
Закоммичены: R0–R5 + stepbystep ранбуки, хартия, prod-logic-map, эфир-хэндофф,
imitation-checks-table, live-demo/ (эфир-плеер) + смежные specs/планы серий
f1-card/phase1/televizor/g1/g2 (решение владельца — «корпус + смежные»).

F-DELPROJ: пункт №15 checks-table → «удаление проекта со сделками запрещено
(422), сделки целы» (было неточно «сделки сохранены», сверено по
ProjectService::delete).

Реестр находок: статусы F-DEPTRAC/F-CSV/F-REMIND/F-DELPROJ/F-CORPUS → закрыто.
.gitleaks.toml: ранбуки приёмки добавлены в allowlist (синтетические тест-
телефоны, та же категория что plans/specs/audits).
live-demo HTML: stylelint --fix (#fff→#ffffff).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 04:48:50 +03:00

248 lines
23 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Лидерра — приёмка · ОТЧЁТ ПО ПРОВЕРКЕ (образец: Распределение)</title>
<style>
:root{--teal:#0F6E56;--ivory:#F6F3EC;--noir:#012019;--amber:#caa23a;--ok:#1a9e74;--red:#e5484d;--ink:#15302a;--mut:#5d7771;}
*{box-sizing:border-box;} html,body{margin:0;}
body{background:var(--noir);color:var(--ivory);font-family:Inter,'Segoe UI',Arial,sans-serif;font-size:13px;}
.mono{font-family:'JetBrains Mono',Consolas,monospace;}
.v-fail{display:none;} body.fail .v-pass{display:none;} body.fail .v-fail{display:inline;}
header{background:var(--teal);padding:9px 16px;display:flex;align-items:center;gap:12px;}
header .dot{width:11px;height:11px;border-radius:50%;background:#e5484d;animation:pulse 1.5s infinite;}
@keyframes pulse{0%{box-shadow:0 0 0 0 rgba(229,72,77,.7)}70%{box-shadow:0 0 0 9px rgba(229,72,77,0)}100%{box-shadow:0 0 0 0 rgba(229,72,77,0)}}
header h1{font-size:15px;margin:0;font-weight:600;}
.step{font-weight:700;font-size:13px;background:#0a4f3e;padding:4px 12px;border-radius:13px;}
header .nav{background:#0a4f3e;color:#ffffff;border:0;border-radius:7px;padding:6px 11px;font-size:15px;cursor:pointer;}
.toggle{margin-left:auto;display:flex;border-radius:9px;overflow:hidden;border:1px solid #0a4f3e;}
.toggle button{background:#0a4f3e;color:#bfe6d6;border:0;padding:6px 12px;font-size:12px;font-weight:700;cursor:pointer;}
.toggle button.act{background:#7ee0bd;color:#0d2a22;} body.fail .toggle button.act{background:#ff9a9a;color:#3a0000;}
.steptitle{background:#0d6b4f;padding:10px 16px;display:flex;align-items:center;gap:12px;border-bottom:1px solid #19a079;}
.steptitle b{font-size:16px;}
.nowtag{margin-left:auto;font-size:12px;font-weight:700;color:#0d2a22;background:#7ee0bd;padding:3px 11px;border-radius:13px;}
.stopbar{display:none;}
body.fail .stopbar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;background:#5e1414;border-bottom:2px solid #ff5b5b;padding:11px 16px;color:#ffdede;}
.stopbar .big{font-size:15px;font-weight:800;color:#ff8a8a;}
.stopbar .fix{font-size:12px;background:#3a0c0c;border:1px solid #8a2b2b;border-radius:8px;padding:5px 10px;}
.risks{display:flex;flex-wrap:wrap;gap:7px;padding:9px 16px;background:#04221a;border-bottom:1px solid #163f33;}
.chip{padding:5px 11px;border-radius:13px;font-size:12px;border:1px solid #1d5a49;background:#10362c;color:#7fae9f;white-space:nowrap;}
.chip.ok{background:var(--teal);color:#ffffff;font-weight:700;border-color:#19a079;}
.chip.now{background:#caa23a;color:#241c00;font-weight:700;border-color:#ffd766;box-shadow:0 0 10px rgba(202,162,58,.5);}
body.fail .chip.now{background:var(--red);color:#ffffff;border-color:#ff8a8a;}
.passport{padding:13px 16px;background:#05241c;border-bottom:1px solid #163f33;display:flex;flex-direction:column;gap:8px;}
.band{display:flex;border-radius:9px;overflow:hidden;border:1px solid #14463a;}
.band .lab{flex:0 0 168px;display:flex;align-items:center;gap:8px;font-weight:800;font-size:12px;padding:9px 13px;color:#ffffff;}
.band .txt{flex:1;padding:9px 13px;font-size:13px;display:flex;align-items:center;gap:8px;flex-wrap:wrap;background:#08312642;}
.band.check .lab{background:#0a4f3e;}
.band.did .lab{background:#274a86;} .band.did .txt{color:#d8e4ff;}
.band.exp .lab{background:#0d6b4f;} .band.exp .txt{color:#c9f5e3;}
.band.got .lab{background:#1a9e74;} .band.got .txt{color:#eafff7;font-weight:600;}
body.fail .band.got .lab{background:#b3322f;} body.fail .band.got .txt{background:#3a0c0c66;color:#ffdede;}
.band .txt b{color:#7ee0bd;}
.verdbadge{margin-left:auto;font-weight:800;padding:3px 11px;border-radius:12px;font-size:12.5px;}
.verdbadge.pass{background:#0a4f1f;color:#7dffb4;border:1px solid #1c7e44;}
.verdbadge.fail{background:#5e1414;color:#ff9a9a;border:1px solid #b3322f;}
.grid{display:flex;gap:14px;padding:14px;align-items:flex-start;}
.left{flex:1 1 58%;min-width:0;display:flex;flex-direction:column;gap:14px;}
.right{flex:1 1 42%;min-width:300px;display:flex;flex-direction:column;gap:14px;}
.blockhdr{font-size:12px;font-weight:700;letter-spacing:.4px;text-transform:uppercase;color:#9fe3c8;margin:0 2px 2px;}
.panel{background:#06281f;border:1px solid var(--teal);border-radius:10px;overflow:hidden;}
.panel h2{margin:0;font-size:12px;padding:7px 12px;background:var(--teal);font-weight:600;}
/* гистограмма раздачи */
.hist{display:flex;align-items:flex-end;gap:12px;height:170px;padding:14px 14px 6px;position:relative;}
.hbar{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;gap:5px;}
.hbar .bar{width:78%;background:linear-gradient(#19a079,#0d6b4f);border-radius:5px 5px 0 0;display:flex;align-items:flex-start;justify-content:center;color:#eafff7;font-weight:800;font-size:12px;padding-top:3px;min-height:14px;}
.hbar.over .bar{background:linear-gradient(#ff7a7a,#b3322f);}
body.fail .c3bar .bar{height:112px;background:linear-gradient(#ff7a7a,#b3322f);}
.hbar .nm{font-size:11px;color:#bfe6d6;font-weight:700;}
.limitline{position:absolute;left:14px;right:14px;border-top:2px dashed #ffce85;}
.limitcap{position:absolute;right:16px;color:#ffce85;font-size:10.5px;font-weight:700;}
.cmp{width:100%;border-collapse:collapse;font-size:12px;}
.cmp th{font-size:10.5px;text-transform:uppercase;color:#9fe3c8;text-align:left;padding:7px 10px;border-bottom:1px solid #14463a;}
.cmp td{padding:7px 10px;border-bottom:1px solid #0e3a2e;}
.cmp .exp{color:#bfe6d6;} .cmp .got{color:#eafff7;font-weight:600;}
.yes{color:#7ee0bd;font-weight:800;} .no{color:#ff8a8a;font-weight:800;}
.src{font-size:10.5px;color:#6f968a;padding:8px 12px;border-top:1px solid #0e3a2e;}
.load{padding:10px 12px;font-family:'JetBrains Mono',monospace;font-size:12px;line-height:1.6;color:#eafff7;white-space:pre-wrap;}
.load .peak{color:#ffce85;}
/* per-lead CAP лента */
.caps{padding:8px 12px;font-family:'JetBrains Mono',monospace;font-size:11.5px;line-height:1.7;color:#cfe9df;max-height:172px;overflow:auto;}
.caps .ok{color:#7ee0bd;} .caps .bad{color:#ff8a8a;font-weight:700;}
/* ── ВСЕ 7 КАБИНЕТОВ (обязательно внизу) ── */
.allcab{padding:2px 14px 18px;}
.minis{display:flex;flex-wrap:wrap;gap:11px;}
.mini{flex:1 1 30%;min-width:215px;background:#ffffff;border-radius:9px;overflow:hidden;position:relative;box-shadow:0 5px 16px rgba(0,0,0,.42);border:2px solid transparent;}
.mini.hitf{}
body.fail .mini.bad{border-color:var(--red);box-shadow:0 0 0 1px var(--red),0 6px 18px rgba(0,0,0,.45);}
.mini .mc{background:#e7e2d6;color:#5d7771;font-size:10.5px;padding:5px 10px;border-bottom:1px solid #d2ccbd;display:flex;align-items:center;gap:6px;}
.mini .mc::before{content:"";width:7px;height:7px;border-radius:50%;background:#61c554;}
.mini .mb{background:var(--ivory);color:var(--ink);padding:10px 12px;}
.mini .top{display:flex;align-items:baseline;gap:9px;}
.mini .mbal{font-family:'JetBrains Mono',monospace;font-size:21px;font-weight:800;color:var(--teal);}
body.fail .mini.bad .mbal{color:var(--red);}
.mini .delta{font-family:'JetBrains Mono',monospace;font-weight:800;color:#b8863a;font-size:13px;}
.mini .was{font-size:11px;color:#9a8a5a;margin:2px 0 8px;}
.mini .row{display:flex;justify-content:space-between;font-size:11.5px;color:var(--ink);padding:2px 0;border-bottom:1px dashed #ece6d7;}
.mini .row .k{color:var(--mut);}
.mini .deals{font-family:'JetBrains Mono',monospace;font-size:11px;color:#3a5a50;margin-top:6px;}
.mini .ver{margin-top:7px;font-size:11px;font-weight:800;color:#1a9e74;}
body.fail .mini.bad .ver{color:var(--red);}
.mini .reg{background:#eaf3f9;color:#1f6f9c;border:1px solid #cfe2ef;border-radius:8px;padding:0 7px;font-weight:700;font-size:11px;}
.mini .mbadge{position:absolute;top:7px;right:9px;font-weight:800;font-size:11px;padding:2px 9px;border-radius:11px;background:var(--ok);color:#ffffff;}
body.fail .mini.bad .mbadge{background:var(--red);}
.mini.supp .mc::before{background:#3d8fc4;} .mini.supp .mb{background:#f4f6f8;color:#2a3742;}
.mini.supp b{color:#1f6f9c;}
@media(max-width:1050px){.grid{flex-direction:column}.mini{flex:1 1 46%}}
</style>
</head>
<body class="pass">
<header>
<span class="dot"></span>
<h1>Лидерра — приёмка боевого · ОТЧЁТ ПО ПРОВЕРКЕ (вижу глазами)</h1>
<button class="nav"></button><span class="step">Тип 3 / 14 · Распределение</span><button class="nav"></button>
<div class="toggle"><button id="bpass" class="act" onclick="setMode('pass')">✅ сошлось</button><button id="bfail" onclick="setMode('fail')">🔴 дефект</button></div>
</header>
<div class="steptitle"><b>📩 РАСПРЕДЕЛЕНИЕ ЛИДОВ — серия инъекции (CAP=3 · второй круг)</b>
<span style="opacity:.8">класс риска: «лид не пропал · раздача честная»</span><span class="nowtag">где мы сейчас ●</span></div>
<div class="stopbar">
<span class="big">🔴 СТОП — тест НЕ пройден</span>
<span>Лимит: c3 получил <b>11</b> при дневном лимите <b>10</b> — превышение под локом.</span>
<span class="fix">📌 Зафиксировано: ожидали ≤10 / факт 11 / БД: delivered_today(c3)=11</span>
<span class="fix">⛔ Дальше заблокировано · НЕ чиним на боевом · зовём владельца</span>
</div>
<div class="risks">
<span class="chip ok">✅ Онбординг</span><span class="chip ok">✅ Заказ поставщику</span>
<span class="chip now"><span class="v-pass">● Распределение/CAP=3</span><span class="v-fail">🔴 Распределение/CAP=3</span></span>
<span class="chip">⬜ Деньги/тариф</span><span class="chip">⬜ Нехватка→откат</span><span class="chip">⬜ Заморозка</span>
<span class="chip">⬜ Изоляция</span><span class="chip">⬜ Нагрузка</span>
</div>
<div class="passport">
<div class="band check"><div class="lab">🎯 ПРОВЕРЯЕМ</div><div class="txt">серия лидов: <b>CAP≤3</b> на каждый лид · жребий ∝ остатку лимита · за серию обслужены <b>все 7</b> · <b>никто не превысил дневной лимит</b> · у каждого верное списание</div></div>
<div class="band did"><div class="lab">✋ СДЕЛАЛИ</div><div class="txt">влил серию <b>15 лидов</b> на <span class="mono">B2_test-okna.ru</span> (все Москва·82), темп ~10/мин — стенд из 7 клиентов, лимит 10, баланс 81000</div></div>
<div class="band exp"><div class="lab">🟢 ОЖИДАЛИ</div><div class="txt">15 лидов × ≤3 = <b>≤45 поставок</b> на 7 клиентов · каждый ≤ лимита 10 · каждая поставка <b>500 ₽ (T1)</b> · все 7 хоть раз получили</div></div>
<div class="band got"><div class="lab">✅ ПОЛУЧИЛОСЬ</div><div class="txt">
<span class="v-pass"><b>45 поставок</b>, по 3 на лид, обслужены все 7 (макс 7/10), списано 45×500=22 500 ₽ — раздача честная</span>
<span class="v-fail"><b>c3 получил 11/10</b> — лимит превышен под локом, раздача <b style="color:#ff8a8a">сломана</b></span>
<span class="verdbadge pass v-pass">✅ СОШЛОСЬ</span><span class="verdbadge fail v-fail">🔴 РАЗОШЛОСЬ — СТОП</span></div></div>
</div>
<div class="grid">
<div class="left">
<div class="panel">
<h2>📊 Как разошлась серия: кому сколько лидов (из 15, по 7 клиентам)</h2>
<div class="hist">
<div class="limitline" style="bottom:calc(6px + 100px)"></div><span class="limitcap" style="bottom:calc(8px + 100px)">лимит/день = 10</span>
<div class="hbar"><div class="bar" style="height:70px">7</div><div class="nm">c1</div></div>
<div class="hbar"><div class="bar" style="height:60px">6</div><div class="nm">c2</div></div>
<div class="hbar c3bar"><div class="bar" style="height:70px"><span class="v-pass">7</span><span class="v-fail">11⚠</span></div><div class="nm">c3</div></div>
<div class="hbar"><div class="bar" style="height:60px">6</div><div class="nm">c4</div></div>
<div class="hbar"><div class="bar" style="height:70px">7</div><div class="nm">c5</div></div>
<div class="hbar"><div class="bar" style="height:60px">6</div><div class="nm">c6</div></div>
<div class="hbar"><div class="bar" style="height:60px">6</div><div class="nm">c7</div></div>
</div>
</div>
<div class="panel">
<h2>🎬 По каждому лиду: кто получил (CAP=3)</h2>
<div class="caps">
TEST-01 → c3 c5 c7 · по 500₽ <span class="ok">(3 ✓)</span>
TEST-02 → c4 c6 c1 · по 500₽ <span class="ok">(3 ✓)</span>
TEST-03 → c5 c7 c2 · по 500₽ <span class="ok">(3 ✓)</span>
TEST-04 → c6 c1 c3 · по 500₽ <span class="ok">(3 ✓)</span>
TEST-05 → c7 c2 c4 · по 500₽ <span class="ok">(3 ✓)</span>
… ещё 9 лидов …
<span class="v-pass">TEST-15 → c2 c4 c6 · по 500₽ <span class="ok">(3 ✓)</span>
итог: каждый лид ровно 3 получателя · ни один &gt;3 · все 7 встречаются</span><span class="v-fail">TEST-13 → c3 c3 c5 c7 · <span class="bad">c3 дважды → 4 поставки, лимит 11/10 (✗ дефект)</span></span>
</div>
</div>
</div>
<div class="right">
<div class="panel">
<h2>📋 Сверка: ожидалось ↔ получилось (факт из БД)</h2>
<table class="cmp">
<tr><th>Что</th><th>Ожидалось</th><th>Получилось</th></tr>
<tr><td>CAP на лид</td><td class="exp">≤ 3 получателя</td><td class="got"><span class="v-pass">ровно 3 <span class="yes"></span></span><span class="v-fail">4 на лиде 13 <span class="no"></span></span></td></tr>
<tr><td>Дневной лимит</td><td class="exp">никто > 10</td><td class="got"><span class="v-pass">макс 7/10 <span class="yes"></span></span><span class="v-fail">c3 = 11/10 <span class="no"></span></span></td></tr>
<tr><td>Обслужены все 7</td><td class="exp">каждый ≥1 за серию</td><td class="got"><span class="v-pass">7/7 <span class="yes"></span></span><span class="v-fail">7/7 <span class="yes"></span></span></td></tr>
<tr><td>Поставок всего</td><td class="exp">≤ 45 (15×3)</td><td class="got"><span class="v-pass">45 <span class="yes"></span></span><span class="v-fail">46 <span class="no"></span></span></td></tr>
<tr><td>Списано</td><td class="exp">45 × 500 = 22 500 ₽</td><td class="got"><span class="v-pass">22 500 ₽ <span class="yes"></span></span><span class="v-fail">23 000 ₽ <span class="no"></span></span></td></tr>
</table>
<div class="src">факт: <span class="mono">SELECT tenant_id, count(*) FROM supplier_lead_deliveries sld JOIN supplier_leads sl ON sl.id=sld.supplier_lead_id WHERE sl.vid IN (серия) GROUP BY tenant_id;</span></div>
</div>
<div class="panel"><h2>🖥 Сервер во время инъекции: онлайн + пик</h2><div class="load" id="load">загрузка пульса…</div></div>
</div>
</div>
<!-- ВСЕ 7 КАБИНЕТОВ — обязательно -->
<div class="allcab">
<div class="blockhdr">⬇ Все 7 кабинетов — было → стало (инъекция касается всех сразу) + поставщик</div>
<div class="minis">
<div class="mini"><span class="mbadge"></span><div class="mc">liderra.ru · c1 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal">77 500 ₽</span><span class="delta">3 500</span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span>7 / 10</span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1147 500 · №1132 500 · …(7)</div><div class="ver">✓ в пределах лимита · списания верны</div></div></div>
<div class="mini"><span class="mbadge"></span><div class="mc">liderra.ru · c2 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal">78 000 ₽</span><span class="delta">3 000</span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span>6 / 10</span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1145 500 · №1137 500 · …(6)</div><div class="ver">✓ в пределах лимита · списания верны</div></div></div>
<div class="mini bad"><span class="mbadge"><span class="v-pass"></span><span class="v-fail"></span></span><div class="mc">liderra.ru · c3 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal"><span class="v-pass">76 500 ₽</span><span class="v-fail">74 500 ₽</span></span><span class="delta"><span class="v-pass">3 500</span><span class="v-fail">5 500 ⚠</span></span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span><span class="v-pass">7 / 10</span><span class="v-fail" style="color:#b3322f;font-weight:800">11 / 10 ⚠</span></span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1148 500 · №1140 500 · …</div><div class="ver"><span class="v-pass">✓ в пределах лимита</span><span class="v-fail">✗ ЛИМИТ ПРЕВЫШЕН (11/10)</span></div></div></div>
<div class="mini"><span class="mbadge"></span><div class="mc">liderra.ru · c4 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal">78 000 ₽</span><span class="delta">3 000</span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span>6 / 10</span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1138 500 · №1136 500 · …(6)</div><div class="ver">✓ в пределах лимита · списания верны</div></div></div>
<div class="mini"><span class="mbadge"></span><div class="mc">liderra.ru · c5 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal">77 500 ₽</span><span class="delta">3 500</span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span>7 / 10</span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1143 500 · №1141 500 · …(7)</div><div class="ver">✓ в пределах лимита · списания верны</div></div></div>
<div class="mini"><span class="mbadge"></span><div class="mc">liderra.ru · c6 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal">78 000 ₽</span><span class="delta">3 000</span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span>6 / 10</span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1146 500 · №1139 500 · …(6)</div><div class="ver">✓ в пределах лимита · списания верны</div></div></div>
<div class="mini"><span class="mbadge"></span><div class="mc">liderra.ru · c7 · Кошелёк</div><div class="mb">
<div class="top"><span class="mbal">78 000 ₽</span><span class="delta">3 000</span></div><div class="was">было 81 000 ₽</div>
<div class="row"><span class="k">получено</span><span>6 / 10</span></div><div class="row"><span class="k">регион · лимит</span><span><span class="reg">Москва·82</span> · 10</span></div>
<div class="deals">№1144 500 · №1142 500 · …(6)</div><div class="ver">✓ в пределах лимита · списания верны</div></div></div>
<div class="mini supp"><span class="mbadge" style="background:#1f6f9c">live</span><div class="mc">crm.bp-gr.ru · поставщик</div><div class="mb">
<div class="top"><span class="mbal" style="color:#1f6f9c;font-size:15px">rt B1/B2/B3</span></div><div class="was">источник test-okna.ru</div>
<div class="row"><span class="k">заказ</span><span>8 × 3 площадки</span></div><div class="row"><span class="k">отдал лидов</span><span>15 (vid серии)</span></div>
<div class="deals"><b>отдал 15 → движок роздал 45 поставок</b></div><div class="ver" style="color:#1f6f9c">● online · канал OK</div></div></div>
</div>
<div class="legend" style="font-size:11px;color:#7fae9f;padding:8px 2px 0">Каждый мини-экран — кабинет клиента «Кошелёк»: баланс было→стало, сколько получено из лимита, регион/лимит проекта, последние сделки и вердикт. На прогоне сюда встанут живые снимки. Поставщик — реальный экран.</div>
</div>
<script>
function setMode(m){document.body.className=m;document.getElementById('bpass').classList.toggle('act',m==='pass');document.getElementById('bfail').classList.toggle('act',m==='fail');}
async function poll(){try{const r=await fetch('load.txt?t='+Date.now());const live=r.ok?await r.text():'(нет пульса)';
document.getElementById('load').innerHTML=live.replace(/</g,'&lt;')+'\n<span class="peak"> ПИК серии (Слой 2): CPU ~80% · очередь росла и спадала · держит ~12000/сут, потолок ~18000</span>';
}catch(e){document.getElementById('load').textContent='(нет пульса)';}}
setInterval(poll,2000);poll();
</script>
</body>
</html>