Files
portal/web/v8/v8_dashboard.html
T
Дмитрий 887abf444e rebrand(v8.5→Лидерра): дизайн-handoff Платона v8 Forest + Лидпоток→Лидерра
Получен handoff-пакет liderra_v8_handoff/ от дизайнера Платона
(kpd9363@gmail.com) от 07.05.2026 — v8 Forest. Заказчик 08.05 решил
применить только в части дизайна, имени, логотипа. Функционал, состав
страниц и правила (CTO-11, click-wrap, SSO break-glass, 14 статусов
воронки) — без изменений (источник — ТЗ v8.5/schema v8.5).

Что сделано:

- Массовая замена Лидпоток→Лидерра (с учётом падежей: Лидерры/Лидерре)
  в 33 файлах (449 вхождений) — все .md/.sql/.json/.toml/.yml/.txt/.html,
  кроме исторических упоминаний внутри liderra_v8_handoff/
- Удалён docs/brandbook.md v1.1 — заменён на BRANDBOOK_v2.md из handoff
- Скопированы 13 концептов liderra_v8_handoff/concepts/v8_*.html в
  web/v8/. Удалены старые web/01-login.html, 02-dashboard.html,
  03-deals.html, index.html (палитра v1.1 deprecated)
- CLAUDE.md v1.0→v1.1: §0 (BRANDBOOK_v2 + DEVELOPER_HANDOFF в источниках),
  §2 (палитра Forest, Inter+JBM, Lucide), §5 п.6 (anti-pattern Inter
  снят — в Forest Inter наш основной шрифт), §6 (13 концептов в web/v8/)
- Реестр Открытые_вопросы_v8_3.md v1.12→v1.13: добавлена запись о
  ребрендинге + 4 точечных расхождений handoff vs ТЗ (статусы воронки,
  click-wrap чекбоксы, SSO fallback, axe violations)
- package.json/package-lock.json: name lidpotok→liderra

4 расхождения handoff vs ТЗ (НЕ применены, источник истины — ТЗ/schema):

1. 14 «обобщённых» статусов в BRANDBOOK_v2 §3.6 ≠ 14 slug'ов в
   schema.sql:2076 (совпадает 2 из 14: «Переговоры», «Оплачено»).
   Источник — schema/ТЗ §6.4 (реселлерская модель из аудита crm.bp-gr.ru,
   6 системных + 8 настраиваемых статусов).
2. 3-й click-wrap в v8_login.html («маркетинг-опционально») ≠ ТЗ §1.5/§4.1
   («согласие на ПДн», обязательное, OPEN-Ж-3).
3. SSO в v8_admin.html («локальный 2FA fallback») ≠ ТЗ OPEN-И-13
   (break-glass super_admin, локальный 2FA выключен).
4. Заявление «axe-core 4.10.2 — 0 violations» в README handoff — локально
   Pa11y 9.1.1 + axe нашёл 81 violation на 10/13 HTML (преимущественно
   color-contrast на декоративных separator'ах с --ink-disabled).
   Чисто: settings/errors/palette_options.

Что НЕ включено в коммит:
- лендинг/TZ_landing_v1_0.md — untracked, не моя работа в этой сессии
- .tmp/ — gitignored

Что осталось (для следующих сессий):
- Возможное переименование GitHub-репо CoralMinister/lidpotok → liderra
  (отдельное решение заказчика)
- Опционально: обратная связь Платону по 4 расхождениям handoff vs ТЗ

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 07:11:58 +03:00

1153 lines
48 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">
<title>v8 · Дашборд — Лидерра (Forest)</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
@media (prefers-reduced-motion: reduce) {
.has-motion { animation: none !important; transition: none !important; }
}
:root {
/* v8 Forest — warm ivory main + deep teal-noir sidebar */
--bg: #F6F3EC;
--surface: #FFFDFA;
--sunken: #F0EDE4;
--hairline: #D9D5CD;
--hairline-soft:#E8E3D6;
--ink: #081319;
--ink-2: #343C41;
--ink-3: #66635C;
--ink-disabled: #92907B;
--accent: #0F6E56;
--accent-tint: #E1EEEA;
--accent-deep: #084635;
/* Forest sidebar tokens — dark teal-noir */
--side-bg: #012019;
--side-text: #B1C2BD; /* nav-item text on side-bg */
--side-text-2: #7A8C87; /* nav-eyebrow / muted */
--side-active: #13382F; /* active fill */
--side-icon: #5C7A72; /* nav-icon idle */
--side-icon-act: #32C8A9; /* bright Teal — accent on dark */
--side-hover: #0A2A22;
--side-border: #1A3A30;
/* funnel 14 — same OKLCH palette as v7_deals */
--st-new-solid: #B94837;
--st-work-solid: #B35100;
--st-call-solid: #9A6700;
--st-nocall-solid: #7E7500;
--st-neg-solid: #538200;
--st-quote-solid: #008A4D;
--st-think-solid: #008C7E;
--st-wait-solid: #00889B;
--st-paid-solid: #007EB8;
--st-refund-solid: #406DC8;
--st-fail-solid: #6C60C4;
--st-dup-solid: #9052AE;
--st-spam-solid: #AA4788;
--st-arch-solid: #B7445F;
--r-xs: 4px;
--r-sm: 6px;
--r-md: 10px;
--r-lg: 14px;
--font-ui: 'Inter', system-ui, sans-serif;
--font-mono:'JetBrains Mono', ui-monospace, monospace;
}
body {
background: var(--bg);
color: var(--ink);
font-family: var(--font-ui);
font-feature-settings: 'cv11', 'ss01', 'ss03';
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-variation-settings: 'opsz' 14;
min-height: 100vh;
}
a { color: inherit; text-decoration: none; }
button { font-family: inherit; }
a:focus-visible, button:focus-visible, input:focus-visible,
[tabindex]:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
border-radius: var(--r-sm);
}
.skip-link {
position: absolute; top: -40px; left: 12px;
background: var(--ink); color: #fff;
padding: 9px 16px; z-index: 200;
text-decoration: none; font-weight: 600;
border-radius: var(--r-sm);
}
.skip-link:focus { top: 12px; }
/* ============================================================
APP — same shell as v7_deals.html
============================================================ */
.app {
display: grid;
grid-template-columns: 232px 1fr;
min-height: 100vh;
}
.side {
background: var(--side-bg);
border-right: 1px solid var(--side-border);
padding: 18px 12px 24px;
position: sticky; top: 0; height: 100vh;
overflow-y: auto;
color: var(--side-text);
}
.brand {
display: flex; align-items: center; gap: 10px;
padding: 6px 8px 18px;
font-weight: 600;
font-size: 14.5px;
letter-spacing: -0.01em;
font-variation-settings: 'opsz' 18;
color: #FFFFFF;
}
.brand-mark {
width: 22px; height: 22px;
border-radius: var(--r-xs);
background: #FFFFFF;
display: inline-flex; align-items: center; justify-content: center;
flex-shrink: 0;
overflow: hidden;
}
.brand-mark svg { width: 100%; height: 100%; display: block; }
.brand-dot { color: var(--side-icon-act); }
.nav { display: flex; flex-direction: column; gap: 1px; }
.nav-eyebrow {
font-size: 11px; font-weight: 500;
letter-spacing: 0.01em;
color: var(--side-text-2);
padding: 14px 10px 6px;
}
.nav-item {
display: flex; align-items: center; gap: 10px;
height: 32px; padding: 0 10px;
border-radius: var(--r-sm);
font-size: 13px;
color: var(--side-text);
transition: background 100ms ease, color 100ms ease;
}
.nav-item:hover { background: var(--side-hover); color: #FFFFFF; }
.nav-item.active { background: var(--side-active); color: #FFFFFF; font-weight: 500; }
.nav-item.active .nav-icon { color: var(--side-icon-act); }
.nav-item.active .nav-count { background: rgba(255,255,255,0.14); color: #fff; }
.nav-icon { width: 15px; height: 15px; flex-shrink: 0; color: var(--side-icon); stroke-width: 1.6; }
.nav-item:hover .nav-icon { color: #FFFFFF; }
.nav-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-count {
font-family: var(--font-mono);
font-size: 10.5px; font-weight: 500;
font-feature-settings: 'tnum';
background: rgba(255,255,255,0.10);
color: var(--side-text);
padding: 2px 6px;
border-radius: 4px;
}
.main { display: flex; flex-direction: column; min-width: 0; }
.topbar {
height: 48px;
border-bottom: 1px solid var(--hairline);
background: var(--surface);
padding: 0 24px;
display: flex; align-items: center; gap: 12px;
position: sticky; top: 0; z-index: 50;
}
.crumb { font-size: 12.5px; color: var(--ink-3); display: flex; align-items: center; gap: 8px; }
.crumb strong { color: var(--ink); font-weight: 500; }
.crumb svg { width: 11px; height: 11px; color: var(--ink-3); opacity: 0.5; }
.topbar-spacer { flex: 1; }
.searchbar {
display: inline-flex; align-items: center; gap: 8px;
height: 30px; padding: 0 10px 0 12px;
border: 1px solid var(--hairline);
border-radius: var(--r-sm);
background: var(--surface);
font-size: 12.5px; color: var(--ink-3);
cursor: pointer;
min-width: 280px;
}
.searchbar:hover { border-color: #BFC4C8; }
.searchbar svg { width: 13px; height: 13px; flex-shrink: 0; }
.searchbar kbd {
margin-left: auto;
font-family: var(--font-mono);
font-size: 10px;
color: var(--ink-3);
background: var(--sunken);
padding: 2px 5px;
border-radius: 3px;
border: 1px solid var(--hairline);
}
.icon-btn {
width: 30px; height: 30px;
border-radius: var(--r-sm);
border: 1px solid transparent;
background: transparent;
color: var(--ink-2);
display: inline-flex; align-items: center; justify-content: center;
cursor: pointer; position: relative;
}
.icon-btn:hover { background: var(--sunken); color: var(--ink); }
.icon-btn .pip {
position: absolute; top: 5px; right: 5px;
width: 6px; height: 6px;
border-radius: 50%;
background: var(--accent);
box-shadow: 0 0 0 2px var(--surface);
}
.user-chip {
display: inline-flex; align-items: center; gap: 8px;
height: 30px; padding: 0 10px 0 4px;
border-radius: 100px;
border: 1px solid var(--hairline);
background: var(--surface);
}
.user-chip .ava {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--ink); color: #fff;
display: inline-flex; align-items: center; justify-content: center;
font-size: 9.5px; font-weight: 600;
letter-spacing: 0.02em;
}
.user-chip .uname { font-size: 12px; color: var(--ink); font-weight: 500; }
/* ============================================================
DASHBOARD CONTENT
============================================================ */
.content { padding: 24px 28px 56px; flex: 1; }
.page-head {
display: flex; align-items: flex-end; justify-content: space-between;
margin-bottom: 22px; gap: 16px;
}
.page-greet {
font-size: 28px;
font-weight: 600;
font-variation-settings: 'opsz' 28;
letter-spacing: -0.02em;
line-height: 1.1;
margin: 0 0 6px;
}
.page-greet em { color: var(--accent); font-style: normal; }
.page-meta {
font-size: 12.5px; color: var(--ink-3);
display: flex; gap: 12px; align-items: center;
}
.page-meta .num { font-family: var(--font-mono); font-feature-settings: 'tnum'; color: var(--ink-2); font-weight: 500; }
.page-meta .accent-num { color: var(--accent); font-weight: 600; }
.page-meta .sep { color: var(--ink-disabled); }
.range-toggle {
display: inline-flex; gap: 1px;
border: 1px solid var(--hairline);
border-radius: var(--r-sm);
padding: 2px;
background: var(--surface);
}
.range-toggle button {
height: 26px; padding: 0 11px;
border: none; background: transparent;
font-family: inherit; font-size: 11.5px; font-weight: 500;
color: var(--ink-3);
cursor: pointer; border-radius: 4px;
letter-spacing: -0.005em;
}
.range-toggle button.active { background: var(--ink); color: #fff; }
/* ============================================================
KPI ROW — 4 monochrome tiles, 1 hero (balance + runway)
============================================================ */
.kpi-row {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1.45fr;
gap: 12px;
margin-bottom: 14px;
}
.kpi {
background: var(--surface);
border: 1px solid var(--hairline);
border-radius: var(--r-md);
padding: 16px 18px;
display: flex; flex-direction: column;
justify-content: space-between;
min-height: 132px;
position: relative;
}
.kpi-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.kpi-label {
font-size: 11.5px; color: var(--ink-3); font-weight: 500;
letter-spacing: 0.005em;
}
.kpi-info {
width: 18px; height: 18px;
border: none; background: none;
color: var(--ink-disabled); cursor: pointer;
border-radius: 50%;
display: inline-flex; align-items: center; justify-content: center;
}
.kpi-info:hover { background: var(--sunken); color: var(--ink-2); }
.kpi-info svg { width: 12px; height: 12px; stroke-width: 1.7; }
.kpi-value {
font-family: var(--font-mono);
font-feature-settings: 'tnum', 'ss01';
font-size: 32px;
font-weight: 500;
letter-spacing: -0.025em;
line-height: 1;
color: var(--ink);
}
.kpi-value .unit {
font-size: 14px;
color: var(--ink-3);
margin-left: 3px;
font-weight: 400;
letter-spacing: -0.005em;
}
.kpi-foot {
display: flex; align-items: center; gap: 6px;
font-family: var(--font-mono);
font-feature-settings: 'tnum';
font-size: 11px;
color: var(--ink-3);
letter-spacing: -0.005em;
}
.delta-up { color: var(--accent); font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
.delta-up svg { width: 9px; height: 9px; stroke-width: 2.5; }
.delta-down { color: var(--st-new-solid); font-weight: 600; display: inline-flex; align-items: center; gap: 3px; }
.delta-down svg { width: 9px; height: 9px; stroke-width: 2.5; }
.delta-neutral { color: var(--ink-2); font-weight: 500; }
/* hero balance — same surface, no dark island, accent ring + runway scale */
.balance {
background: var(--surface);
border: 1px solid var(--hairline);
border-radius: var(--r-md);
padding: 16px 18px 18px;
display: flex; flex-direction: column; gap: 10px;
min-height: 132px;
position: relative;
overflow: hidden;
}
.balance::before {
content: ''; position: absolute;
inset: -1px;
border-radius: var(--r-md);
border: 1px solid var(--accent);
pointer-events: none;
opacity: 0.55;
}
.balance-row1 {
display: flex; align-items: center; justify-content: space-between;
}
.balance-label { font-size: 11.5px; color: var(--ink-3); font-weight: 500; }
.balance-tag {
font-family: var(--font-mono);
font-size: 9.5px; font-weight: 600;
letter-spacing: 0.06em;
padding: 2px 6px;
border-radius: 3px;
background: var(--accent-tint);
color: var(--accent-deep);
}
.balance-amount {
display: flex; align-items: baseline; gap: 4px;
}
.balance-amount .num {
font-family: var(--font-mono);
font-feature-settings: 'tnum';
font-weight: 600;
font-size: 36px;
letter-spacing: -0.03em;
line-height: 1;
color: var(--ink);
}
.balance-amount .ru {
font-family: var(--font-mono);
font-size: 14px;
color: var(--ink-3);
font-weight: 400;
}
/* runway scale — hairline ticks visualising days of runway */
.runway {
display: flex; flex-direction: column; gap: 6px;
}
.runway-bar {
display: grid; grid-template-columns: repeat(7, 1fr);
gap: 3px;
height: 6px;
}
.runway-bar span {
background: var(--sunken);
border-radius: 1px;
position: relative;
}
.runway-bar span.fill { background: var(--accent); }
.runway-bar span.partial::after {
content: ''; position: absolute;
left: 0; top: 0; bottom: 0;
width: 35%;
background: var(--accent);
border-radius: 1px 0 0 1px;
}
.runway-foot {
display: flex; justify-content: space-between; align-items: center;
font-family: var(--font-mono);
font-feature-settings: 'tnum';
font-size: 10.5px;
color: var(--ink-3);
letter-spacing: -0.005em;
}
.runway-foot strong { color: var(--accent); font-weight: 600; }
/* ============================================================
CHART PANEL + FUNNEL
============================================================ */
.charts-row {
display: grid;
grid-template-columns: 1.6fr 1fr;
gap: 12px;
margin-bottom: 14px;
}
.panel {
background: var(--surface);
border: 1px solid var(--hairline);
border-radius: var(--r-md);
padding: 18px 20px;
}
.panel-head {
display: flex; align-items: flex-start; justify-content: space-between;
margin-bottom: 14px;
}
.panel-title {
font-size: 16px;
font-weight: 600;
font-variation-settings: 'opsz' 18;
letter-spacing: -0.012em;
margin: 0 0 2px;
}
.panel-sub { font-size: 11.5px; color: var(--ink-3); }
.panel-tabs { display: inline-flex; gap: 2px; padding: 2px; background: var(--sunken); border-radius: var(--r-sm); }
.panel-tabs button {
height: 24px; padding: 0 9px;
border: none; background: transparent;
font-family: inherit; font-size: 11px; font-weight: 500;
color: var(--ink-3);
cursor: pointer; border-radius: 4px;
letter-spacing: -0.005em;
}
.panel-tabs button.active { background: var(--surface); color: var(--ink); box-shadow: inset 0 0 0 1px var(--hairline); }
.chart-wrap { height: 220px; position: relative; }
.chart-wrap svg { display: block; width: 100%; height: 100%; }
.chart-axis-y, .chart-axis-x {
font-family: var(--font-mono);
font-feature-settings: 'tnum';
font-size: 10px;
fill: var(--ink-3);
letter-spacing: -0.01em;
}
.chart-axis-x.today { fill: var(--ink); font-weight: 600; }
/* legend dots */
.chart-legend {
display: flex; gap: 14px; margin-top: 10px;
font-size: 11.5px; color: var(--ink-2);
}
.chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend .ldot {
width: 8px; height: 8px;
border-radius: 50%;
position: relative;
}
.chart-legend .ldot::after {
content: ''; position: absolute; inset: -1px;
border-radius: 50%;
border: 1px solid rgba(10,19,25,0.10);
}
.chart-legend .ldot.received { background: var(--ink); }
.chart-legend .ldot.paid { background: var(--accent); }
.chart-legend .ldot.refused { background: var(--st-new-solid); }
/* ============================================================
FUNNEL — horizontal stacked bar, 14 statuses
============================================================ */
.funnel-bar {
display: flex;
height: 28px;
border-radius: 4px;
overflow: hidden;
border: 1px solid var(--hairline);
background: var(--sunken);
}
.funnel-seg {
position: relative;
cursor: default;
}
.funnel-seg + .funnel-seg { box-shadow: inset 1px 0 0 rgba(255,255,255,0.18); }
.funnel-list {
display: grid;
grid-template-columns: 1fr 1fr;
column-gap: 14px; row-gap: 6px;
margin-top: 14px;
font-size: 12px;
color: var(--ink-2);
}
.funnel-list-item {
display: flex; align-items: center; gap: 8px;
letter-spacing: -0.005em;
}
.funnel-list-item .dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; position: relative; }
.funnel-list-item .dot::after {
content: ''; position: absolute; inset: -1px;
border-radius: 50%;
border: 1px solid rgba(10,19,25,0.10);
}
.funnel-list-item .name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.funnel-list-item .qty {
font-family: var(--font-mono); font-feature-settings: 'tnum';
font-size: 11px; color: var(--ink-3); font-weight: 500;
}
/* ============================================================
ACTIVITY LIST — recent leads, compact
============================================================ */
.activity-row {
display: grid;
grid-template-columns: 1.5fr 1fr;
gap: 12px;
margin-bottom: 14px;
}
.list-row {
display: flex; align-items: center; gap: 10px;
padding: 10px 18px;
border-bottom: 1px solid var(--hairline-soft);
font-size: 12.5px;
}
.list-row:last-child { border-bottom: none; }
.list-row:hover { background: var(--sunken); cursor: pointer; }
.l-time {
font-family: var(--font-mono); font-feature-settings: 'tnum';
font-size: 10.5px; color: var(--ink-3);
width: 48px; flex-shrink: 0;
letter-spacing: -0.005em;
}
.l-deal { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
.l-ava {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--sunken);
color: var(--ink-2);
display: inline-flex; align-items: center; justify-content: center;
font-size: 8.5px; font-weight: 600;
position: relative;
flex-shrink: 0;
}
.l-ava::after {
content: ''; position: absolute; inset: 0;
border-radius: 50%;
border: 1px solid rgba(10,19,25,0.08);
}
.l-name { font-weight: 500; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.l-product { color: var(--ink-3); font-size: 11.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.l-chip {
display: inline-flex; align-items: center; gap: 6px;
font-size: 11.5px; font-weight: 500;
color: var(--ink);
white-space: nowrap;
flex-shrink: 0;
}
.l-chip .dot {
width: 7px; height: 7px; border-radius: 50%;
position: relative;
}
.l-chip .dot::after {
content: ''; position: absolute; inset: -1px;
border-radius: 50%;
border: 1px solid rgba(10,19,25,0.10);
}
.l-price {
font-family: var(--font-mono); font-feature-settings: 'tnum';
font-size: 11.5px; color: var(--ink); font-weight: 500;
letter-spacing: -0.005em;
min-width: 58px; text-align: right;
}
.list-foot {
padding: 10px 18px;
border-top: 1px solid var(--hairline);
text-align: center;
font-size: 12px;
color: var(--ink-3);
}
.list-foot a { color: var(--accent); font-weight: 500; }
.list-foot a:hover { text-decoration: underline; }
/* ============================================================
SYSTEM HEALTH PANEL
============================================================ */
.health-list { display: flex; flex-direction: column; gap: 1px; }
.health-row {
display: grid;
grid-template-columns: 1fr auto auto;
gap: 12px;
padding: 9px 0;
align-items: center;
border-bottom: 1px solid var(--hairline-soft);
font-size: 12.5px;
}
.health-row:last-child { border-bottom: none; }
.h-name { color: var(--ink); font-weight: 500; }
.h-name .h-sub { display: block; font-size: 11px; color: var(--ink-3); font-weight: 400; margin-top: 2px; }
.h-metric {
font-family: var(--font-mono); font-feature-settings: 'tnum';
font-size: 11px; color: var(--ink-2);
letter-spacing: -0.005em;
}
.h-status {
display: inline-flex; align-items: center; gap: 6px;
font-size: 11px; color: var(--ink-2);
font-weight: 500;
}
.h-status .dot {
width: 7px; height: 7px; border-radius: 50%;
position: relative;
background: var(--accent);
}
.h-status .dot::after {
content: ''; position: absolute; inset: -1px;
border-radius: 50%;
border: 1px solid rgba(10,19,25,0.10);
}
.h-status.warn .dot { background: var(--st-call-solid); }
.h-status.fail .dot { background: var(--st-new-solid); }
/* ============================================================
QUICK ACTIONS
============================================================ */
.qa-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
.qa-card {
background: var(--surface);
border: 1px solid var(--hairline);
border-radius: var(--r-md);
padding: 14px 16px;
display: flex; align-items: center; gap: 12px;
cursor: pointer;
transition: border-color 120ms ease, background 120ms ease;
}
.qa-card:hover { border-color: var(--ink-disabled); background: var(--surface); }
.qa-icon {
width: 30px; height: 30px;
border-radius: var(--r-sm);
background: var(--sunken);
color: var(--ink-2);
display: inline-flex; align-items: center; justify-content: center;
flex-shrink: 0;
}
.qa-icon svg { width: 14px; height: 14px; stroke-width: 1.7; }
.qa-text { display: flex; flex-direction: column; min-width: 0; }
.qa-title {
font-size: 12.5px; color: var(--ink); font-weight: 500;
letter-spacing: -0.005em;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.qa-sub {
font-family: var(--font-mono); font-feature-settings: 'tnum';
font-size: 10.5px; color: var(--ink-3);
letter-spacing: -0.005em;
}
/* ============================================================
RESPONSIVE
============================================================ */
@media (max-width: 1280px) {
.kpi-row { grid-template-columns: 1fr 1fr; }
.charts-row { grid-template-columns: 1fr; }
.activity-row { grid-template-columns: 1fr; }
.qa-row { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 1100px) {
.app { grid-template-columns: 56px 1fr; }
.side { padding: 14px 6px; }
.brand .brand-text,
.nav-eyebrow,
.nav-text,
.nav-item:not(.active) .nav-count { display: none; }
.nav-item { justify-content: center; padding: 0; }
.topbar { padding: 0 16px; }
.content { padding: 18px 18px 56px; }
.searchbar { min-width: 200px; }
}
@media (max-width: 768px) {
.app { grid-template-columns: 1fr; }
.side { display: none; }
.topbar .crumb span:first-child { display: none; }
.page-head { flex-direction: column; align-items: flex-start; gap: 12px; }
.page-greet { font-size: 24px; }
.kpi-row { grid-template-columns: 1fr; }
.qa-row { grid-template-columns: 1fr; }
.funnel-list { grid-template-columns: 1fr; }
.chart-wrap { height: 180px; }
}
</style>
</head>
<body>
<a href="#main" class="skip-link">К контенту</a>
<div class="app">
<!-- ===== SIDEBAR ===== -->
<aside class="side" aria-label="Главное меню">
<div class="brand">
<span class="brand-mark" aria-hidden="true">
<svg viewBox="0 0 48 48"><path d="M16 14 L16 34 L32 34" stroke="#012019" stroke-width="4.5" stroke-linecap="round" stroke-linejoin="round" fill="none"/><circle cx="32" cy="34" r="3.5" fill="#0F6E56"/></svg>
</span>
<span class="brand-text">Лидерра<span class="brand-dot">.</span></span>
</div>
<nav class="nav">
<div class="nav-eyebrow">Работа</div>
<a class="nav-item active" href="#" aria-current="page">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
<span class="nav-text">Дашборд</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 6h18M6 12h12M9 18h6"/></svg>
<span class="nav-text">Сделки</span>
<span class="nav-count">247</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="3" width="6" height="18"/><rect x="11" y="3" width="6" height="12"/><rect x="19" y="3" width="2" height="8"/></svg>
<span class="nav-text">Канбан</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M12 6v6l4 2"/><circle cx="12" cy="12" r="9"/></svg>
<span class="nav-text">Напоминания</span>
<span class="nav-count">12</span>
</a>
<div class="nav-eyebrow">Финансы</div>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><rect x="3" y="6" width="18" height="13" rx="1"/><path d="M3 10h18M7 15h3"/></svg>
<span class="nav-text">Биллинг</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M3 12h18M3 6h18M3 18h18"/></svg>
<span class="nav-text">Отчёты</span>
</a>
<div class="nav-eyebrow">Команда</div>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M22 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
<span class="nav-text">Менеджеры</span>
<span class="nav-count">4</span>
</a>
<a class="nav-item" href="#">
<svg class="nav-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
<span class="nav-text">Настройки</span>
</a>
</nav>
</aside>
<!-- ===== MAIN ===== -->
<div class="main">
<div class="topbar">
<div class="crumb">
<span>Рабочая область</span>
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M9 18l6-6-6-6"/></svg>
<strong>Дашборд</strong>
</div>
<div class="topbar-spacer"></div>
<button type="button" class="searchbar" aria-label="Поиск, ⌘K">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
<span>Поиск</span>
<kbd>⌘K</kbd>
</button>
<button type="button" class="icon-btn" aria-label="Уведомления, есть новые">
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.7" aria-hidden="true"><path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9M13.73 21a2 2 0 0 1-3.46 0"/></svg>
<span class="pip" aria-hidden="true"></span>
</button>
<button type="button" class="user-chip" aria-label="Профиль · Иван Петров">
<span class="ava" aria-hidden="true">ИП</span>
<span class="uname">Иван П.</span>
</button>
</div>
<main id="main" class="content">
<!-- page head -->
<header class="page-head">
<div>
<h1 class="page-greet">Доброе утро, <em>Иван</em></h1>
<div class="page-meta">
<span><span class="num accent-num">+3</span> новых лида с утра</span>
<span class="sep">·</span>
<span>сегодня <span class="num">11</span> · вчера <span class="num">38</span></span>
<span class="sep">·</span>
<span>средняя стоимость <span class="num">2 248&nbsp;</span></span>
</div>
</div>
<div class="range-toggle" role="group" aria-label="Период">
<button type="button" aria-pressed="false">Сегодня</button>
<button type="button" class="active" aria-pressed="true">7 дней</button>
<button type="button" aria-pressed="false">30 дней</button>
<button type="button" aria-pressed="false">Период…</button>
</div>
</header>
<!-- KPI strip + balance hero -->
<div class="kpi-row">
<article class="kpi" tabindex="0" aria-label="KPI: получено лидов">
<div class="kpi-head">
<span class="kpi-label">Получено лидов</span>
<button type="button" class="kpi-info" aria-label="Подробнее"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg></button>
</div>
<div>
<div class="kpi-value">247</div>
<div class="kpi-foot">
<span class="delta-up"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 14l5-5 5 5"/></svg>12.3%</span>
<span>vs предыдущие 7 дней</span>
</div>
</div>
</article>
<article class="kpi" tabindex="0" aria-label="KPI: конверсия в оплату">
<div class="kpi-head">
<span class="kpi-label">Конверсия в оплату</span>
<button type="button" class="kpi-info" aria-label="Подробнее"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg></button>
</div>
<div>
<div class="kpi-value">18.4<span class="unit">%</span></div>
<div class="kpi-foot">
<span class="delta-up"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path d="M7 14l5-5 5 5"/></svg>2.1pp</span>
<span>vs предыдущие 7 дней</span>
</div>
</div>
</article>
<article class="kpi" tabindex="0" aria-label="KPI: активные проекты">
<div class="kpi-head">
<span class="kpi-label">Активные проекты</span>
<button type="button" class="kpi-info" aria-label="Подробнее"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="9"/><path d="M12 8v4M12 16h.01"/></svg></button>
</div>
<div>
<div class="kpi-value">8<span class="unit">/ 10</span></div>
<div class="kpi-foot">
<span class="delta-neutral">2 свободно</span>
<span class="sep" style="color:var(--ink-disabled)">·</span>
<span>тариф «Команда»</span>
</div>
</div>
</article>
<!-- Hero balance + runway scale -->
<article class="balance" tabindex="0" aria-labelledby="bal-label">
<div class="balance-row1">
<span id="bal-label" class="balance-label">Баланс</span>
<span class="balance-tag">LIVE</span>
</div>
<div class="balance-amount">
<span class="num">14&nbsp;250</span><span class="ru"></span>
</div>
<div class="runway">
<div class="runway-bar" aria-label="Хватит на 4 дня из 7" role="img">
<span class="fill"></span>
<span class="fill"></span>
<span class="fill"></span>
<span class="fill"></span>
<span class="partial"></span>
<span></span>
<span></span>
</div>
<div class="runway-foot">
<span>≈ 285 лидов · хватит на <strong>4 дня</strong></span>
<span>пополнить →</span>
</div>
</div>
</article>
</div>
<!-- Activity chart + Funnel -->
<div class="charts-row">
<section class="panel" aria-labelledby="chart-title">
<div class="panel-head">
<div>
<h2 class="panel-title" id="chart-title">Активность по дням</h2>
<div class="panel-sub">принято · оплачено · отказ — последние 7 дней</div>
</div>
<div class="panel-tabs" role="tablist" aria-label="Метрика графика">
<button type="button" role="tab" aria-selected="true" class="active">Принято</button>
<button type="button" role="tab" aria-selected="false">Оплачено</button>
<button type="button" role="tab" aria-selected="false">Отказ</button>
</div>
</div>
<div class="chart-wrap">
<svg viewBox="0 0 800 220" preserveAspectRatio="none" aria-label="Активность по дням, последние 7 дней">
<line x1="36" y1="20" x2="790" y2="20" stroke="#E8EBED"/>
<line x1="36" y1="68" x2="790" y2="68" stroke="#E8EBED"/>
<line x1="36" y1="116" x2="790" y2="116" stroke="#E8EBED"/>
<line x1="36" y1="164" x2="790" y2="164" stroke="#E8EBED"/>
<text x="28" y="24" text-anchor="end" class="chart-axis-y">60</text>
<text x="28" y="72" text-anchor="end" class="chart-axis-y">45</text>
<text x="28" y="120" text-anchor="end" class="chart-axis-y">30</text>
<text x="28" y="168" text-anchor="end" class="chart-axis-y">15</text>
<text x="28" y="200" text-anchor="end" class="chart-axis-y">0</text>
<defs>
<linearGradient id="grad-area" x1="0" y1="0" x2="0" y2="1">
<stop offset="0%" stop-color="#0A1319" stop-opacity="0.10"/>
<stop offset="100%" stop-color="#0A1319" stop-opacity="0"/>
</linearGradient>
</defs>
<path d="M50,148 L170,108 L290,124 L410,72 L530,90 L650,52 L770,60 L770,200 L50,200 Z"
fill="url(#grad-area)"/>
<path d="M50,148 L170,108 L290,124 L410,72 L530,90 L650,52 L770,60"
fill="none" stroke="#0A1319" stroke-width="1.7" stroke-linejoin="round" stroke-linecap="round"/>
<circle cx="50" cy="148" r="2.6" fill="#FFFFFF" stroke="#0A1319" stroke-width="1.6"/>
<circle cx="170" cy="108" r="2.6" fill="#FFFFFF" stroke="#0A1319" stroke-width="1.6"/>
<circle cx="290" cy="124" r="2.6" fill="#FFFFFF" stroke="#0A1319" stroke-width="1.6"/>
<circle cx="410" cy="72" r="2.6" fill="#FFFFFF" stroke="#0A1319" stroke-width="1.6"/>
<circle cx="530" cy="90" r="2.6" fill="#FFFFFF" stroke="#0A1319" stroke-width="1.6"/>
<circle cx="650" cy="52" r="4.2" fill="#0F6E56" stroke="#FFFFFF" stroke-width="2"/>
<circle cx="770" cy="60" r="2.6" fill="#FFFFFF" stroke="#0A1319" stroke-width="1.6"/>
<text x="50" y="216" text-anchor="middle" class="chart-axis-x">пн</text>
<text x="170" y="216" text-anchor="middle" class="chart-axis-x">вт</text>
<text x="290" y="216" text-anchor="middle" class="chart-axis-x">ср</text>
<text x="410" y="216" text-anchor="middle" class="chart-axis-x">чт</text>
<text x="530" y="216" text-anchor="middle" class="chart-axis-x">пт</text>
<text x="650" y="216" text-anchor="middle" class="chart-axis-x today">сб</text>
<text x="770" y="216" text-anchor="middle" class="chart-axis-x">сегодня</text>
</svg>
</div>
<div class="chart-legend" aria-hidden="true">
<span><span class="ldot received"></span>принято</span>
<span><span class="ldot paid"></span>оплачено</span>
<span><span class="ldot refused"></span>отказ</span>
</div>
</section>
<section class="panel" aria-labelledby="funnel-title">
<div class="panel-head">
<div>
<h2 class="panel-title" id="funnel-title">Воронка</h2>
<div class="panel-sub">14 статусов · 247 лидов · сейчас</div>
</div>
</div>
<div class="funnel-bar" role="img" aria-label="Распределение 247 лидов по 14 статусам — детали ниже">
<div class="funnel-seg" style="flex: 18; background: var(--st-new-solid);" title="Новая · 18"></div>
<div class="funnel-seg" style="flex: 14; background: var(--st-work-solid);" title="В работе · 14"></div>
<div class="funnel-seg" style="flex: 22; background: var(--st-call-solid);" title="Дозвон · 22"></div>
<div class="funnel-seg" style="flex: 9; background: var(--st-nocall-solid);" title="Не дозвон. · 9"></div>
<div class="funnel-seg" style="flex: 16; background: var(--st-neg-solid);" title="Переговоры · 16"></div>
<div class="funnel-seg" style="flex: 11; background: var(--st-quote-solid);" title="КП · 11"></div>
<div class="funnel-seg" style="flex: 7; background: var(--st-think-solid);" title="Думает · 7"></div>
<div class="funnel-seg" style="flex: 4; background: var(--st-wait-solid);" title="Ждёт оплату · 4"></div>
<div class="funnel-seg" style="flex: 45; background: var(--st-paid-solid);" title="Оплачено · 45"></div>
<div class="funnel-seg" style="flex: 3; background: var(--st-refund-solid);" title="Возврат · 3"></div>
<div class="funnel-seg" style="flex: 38; background: var(--st-fail-solid);" title="Отказ · 38"></div>
<div class="funnel-seg" style="flex: 5; background: var(--st-dup-solid);" title="Дубликат · 5"></div>
<div class="funnel-seg" style="flex: 5; background: var(--st-spam-solid);" title="Спам · 5"></div>
<div class="funnel-seg" style="flex: 39; background: var(--st-arch-solid);" title="Архив · 39"></div>
</div>
<div class="funnel-list">
<span class="funnel-list-item"><span class="dot" style="background: var(--st-new-solid)"></span><span class="name">Новая</span><span class="qty">18</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-paid-solid)"></span><span class="name">Оплачено</span><span class="qty">45</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-work-solid)"></span><span class="name">В работе</span><span class="qty">14</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-arch-solid)"></span><span class="name">Архив</span><span class="qty">39</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-call-solid)"></span><span class="name">Дозвон</span><span class="qty">22</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-fail-solid)"></span><span class="name">Отказ</span><span class="qty">38</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-neg-solid)"></span><span class="name">Переговоры</span><span class="qty">16</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-quote-solid)"></span><span class="name">КП отправлено</span><span class="qty">11</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-nocall-solid)"></span><span class="name">Не дозвон.</span><span class="qty">9</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-wait-solid)"></span><span class="name">Ждёт оплату</span><span class="qty">4</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-think-solid)"></span><span class="name">Думает</span><span class="qty">7</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-spam-solid)"></span><span class="name">Спам</span><span class="qty">5</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-dup-solid)"></span><span class="name">Дубликат</span><span class="qty">5</span></span>
<span class="funnel-list-item"><span class="dot" style="background: var(--st-refund-solid)"></span><span class="name">Возврат</span><span class="qty">3</span></span>
</div>
</section>
</div>
<!-- Recent activity + system health -->
<div class="activity-row">
<section class="panel" style="padding:0" aria-labelledby="recent-title">
<div class="panel-head" style="padding:18px 20px 14px">
<div>
<h2 class="panel-title" id="recent-title">Последние сделки</h2>
<div class="panel-sub">обновляются автоматически</div>
</div>
</div>
<div class="list-row">
<span class="l-time">28м</span>
<span class="l-deal"><span class="l-ava" aria-hidden="true">АС</span><span class="l-name">Анна Соколова</span><span class="l-product">· Натяжные потолки</span></span>
<span class="l-chip"><span class="dot" style="background: var(--st-new-solid)"></span>Новая</span>
<span class="l-price">1&nbsp;850&nbsp;</span>
</div>
<div class="list-row">
<span class="l-time"></span>
<span class="l-deal"><span class="l-ava" aria-hidden="true">ИП</span><span class="l-name">Иван Петров</span><span class="l-product">· Окна Москва</span></span>
<span class="l-chip"><span class="dot" style="background: var(--st-neg-solid)"></span>Переговоры</span>
<span class="l-price">2&nbsp;200&nbsp;</span>
</div>
<div class="list-row">
<span class="l-time"></span>
<span class="l-deal"><span class="l-ava" aria-hidden="true">ДК</span><span class="l-name">Дмитрий Котов</span><span class="l-product">· Окна Москва</span></span>
<span class="l-chip"><span class="dot" style="background: var(--st-paid-solid)"></span>Оплачено</span>
<span class="l-price">2&nbsp;200&nbsp;</span>
</div>
<div class="list-row">
<span class="l-time"></span>
<span class="l-deal"><span class="l-ava" aria-hidden="true">МО</span><span class="l-name">Михаил Орлов</span><span class="l-product">· Натяжные потолки</span></span>
<span class="l-chip"><span class="dot" style="background: var(--st-wait-solid)"></span>Ждёт оплату</span>
<span class="l-price">1&nbsp;850&nbsp;</span>
</div>
<div class="list-row">
<span class="l-time"></span>
<span class="l-deal"><span class="l-ava" aria-hidden="true">ЕВ</span><span class="l-name">Елена Васильева</span><span class="l-product">· Кухни на заказ</span></span>
<span class="l-chip"><span class="dot" style="background: var(--st-call-solid)"></span>Дозвон</span>
<span class="l-price">3&nbsp;100&nbsp;</span>
</div>
<div class="list-row">
<span class="l-time"></span>
<span class="l-deal"><span class="l-ava" aria-hidden="true">СН</span><span class="l-name">Сергей Новиков</span><span class="l-product">· Окна Москва</span></span>
<span class="l-chip"><span class="dot" style="background: var(--st-fail-solid)"></span>Отказ</span>
<span class="l-price">2&nbsp;200&nbsp;</span>
</div>
<div class="list-foot">
<a href="#">Все сделки →</a>
</div>
</section>
<section class="panel" aria-labelledby="health-title">
<div class="panel-head">
<div>
<h2 class="panel-title" id="health-title">Состояние системы</h2>
<div class="panel-sub">за последние 24 часа</div>
</div>
</div>
<div class="health-list">
<div class="health-row">
<span class="h-name">Приём лидов <span class="h-sub">webhook → API</span></span>
<span class="h-metric">142&nbsp;ms · 99.97%</span>
<span class="h-status"><span class="dot" aria-hidden="true"></span>OK</span>
</div>
<div class="health-row">
<span class="h-name">Платёжный шлюз <span class="h-sub">YooKassa</span></span>
<span class="h-metric">208&nbsp;ms · 100%</span>
<span class="h-status"><span class="dot" aria-hidden="true"></span>OK</span>
</div>
<div class="health-row">
<span class="h-name">Telegram-бот <span class="h-sub">уведомления команды</span></span>
<span class="h-metric">89&nbsp;ms · 99.20%</span>
<span class="h-status warn"><span class="dot" aria-hidden="true"></span>деградация</span>
</div>
<div class="health-row">
<span class="h-name">Я.Директ интеграция <span class="h-sub">utm + лиды</span></span>
<span class="h-metric">синхр.&nbsp;3 мин назад</span>
<span class="h-status"><span class="dot" aria-hidden="true"></span>OK</span>
</div>
<div class="health-row">
<span class="h-name">SMS-шлюз <span class="h-sub">SMSC.RU</span></span>
<span class="h-metric">412&nbsp;ms · 96.40%</span>
<span class="h-status warn"><span class="dot" aria-hidden="true"></span>задержка</span>
</div>
</div>
</section>
</div>
<!-- Quick actions -->
<section aria-labelledby="qa-title">
<h2 class="panel-title" id="qa-title" style="margin-bottom:10px;font-size:13px;color:var(--ink-3);font-weight:500;letter-spacing:0.005em">Быстрые действия</h2>
<div class="qa-row">
<button type="button" class="qa-card">
<span class="qa-icon" aria-hidden="true">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
</span>
<span class="qa-text">
<span class="qa-title">Новая сделка</span>
<span class="qa-sub">⌘ + N</span>
</span>
</button>
<button type="button" class="qa-card">
<span class="qa-icon" aria-hidden="true">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><rect x="3" y="6" width="18" height="13" rx="1"/><path d="M3 10h18M7 15h3"/></svg>
</span>
<span class="qa-text">
<span class="qa-title">Пополнить баланс</span>
<span class="qa-sub">от 5 000 ₽</span>
</span>
</button>
<button type="button" class="qa-card">
<span class="qa-icon" aria-hidden="true">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7,10 12,15 17,10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
</span>
<span class="qa-text">
<span class="qa-title">Экспорт отчёта</span>
<span class="qa-sub">CSV · Excel</span>
</span>
</button>
<button type="button" class="qa-card">
<span class="qa-icon" aria-hidden="true">
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
</span>
<span class="qa-text">
<span class="qa-title">Настроить дашборд</span>
<span class="qa-sub">видимые виджеты</span>
</span>
</button>
</div>
</section>
</main>
</div>
</div>
</body>
</html>