Files
portal/web/v8/v8_settings.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

405 lines
34 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; }
:root {
--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;
--side-bg:#012019; --side-text:#B1C2BD; --side-text-2:#7A8C87;
--side-active:#13382F; --side-icon:#5C7A72; --side-icon-act:#32C8A9;
--side-hover:#0A2A22; --side-border:#1A3A30;
--st-paid:#007EB8; --st-quote:#008A4D; --st-call:#9A6700; --st-new:#B94837;
--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'; -webkit-font-smoothing:antialiased; font-variation-settings:'opsz' 14; min-height:100vh; }
button { font-family:inherit; }
a { color:inherit; text-decoration:none; }
a:focus-visible, button:focus-visible, input:focus-visible, select: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; font-weight:600; border-radius:var(--r-sm); }
.skip-link:focus { top:12px; }
/* Shell */
.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:#FFF; }
.brand-mark { width:22px; height:22px; border-radius:var(--r-xs); background:#FFF; 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); }
.nav-item:hover { background:var(--side-hover); color:#FFF; }
.nav-item.active { background:var(--side-active); color:#FFF; font-weight:500; }
.nav-item.active .nav-icon { color:var(--side-icon-act); }
.nav-icon { width:15px; height:15px; flex-shrink:0; color:var(--side-icon); stroke-width:1.6; }
.nav-item:hover .nav-icon { color:#FFF; }
.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; }
.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; }
.user-chip .uname { font-size:12px; color:var(--ink); font-weight:500; }
/* Page */
.content { display:grid; grid-template-columns:200px 1fr; gap:28px; padding:24px 28px 80px; max-width:1500px; margin:0 auto; }
.page-h { grid-column:1 / -1; display:flex; align-items:flex-end; justify-content:space-between; margin-bottom:6px; gap:16px; }
.page-title { font-size:28px; font-weight:600; font-variation-settings:'opsz' 28; letter-spacing:-0.02em; line-height:1.1; margin:0 0 6px; }
.page-meta { font-size:12.5px; color:var(--ink-3); }
/* Settings tab rail (left) */
.tab-rail { display:flex; flex-direction:column; gap:1px; position:sticky; top:64px; align-self:start; }
.tab-rail .rail-eyebrow { font-size:10.5px; font-weight:500; letter-spacing:0.06em; text-transform:uppercase; color:var(--ink-3); padding:10px 12px 6px; font-family:var(--font-mono); }
.tab-rail button { display:flex; align-items:center; gap:9px; padding:8px 12px; border:none; background:transparent; font-family:inherit; font-size:13px; color:var(--ink-2); cursor:pointer; border-radius:var(--r-sm); text-align:left; letter-spacing:-0.005em; }
.tab-rail button:hover { background:var(--sunken); color:var(--ink); }
.tab-rail button.active { background:var(--ink); color:#fff; font-weight:500; }
.tab-rail button.active .ico { color:var(--side-icon-act); }
.tab-rail button .ico { width:14px; height:14px; color:var(--ink-3); flex-shrink:0; stroke-width:1.7; }
.tab-rail button:hover .ico { color:var(--ink); }
/* Settings tab content */
.tab-content { display:flex; flex-direction:column; gap:14px; min-width:0; }
.section { background:var(--surface); border:1px solid var(--hairline); border-radius:var(--r-md); padding:22px 24px; }
.section-h { display:flex; align-items:flex-start; justify-content:space-between; gap:16px; margin-bottom:16px; flex-wrap:wrap; }
.section-h h2 { font-size:16px; font-weight:600; font-variation-settings:'opsz' 18; letter-spacing:-0.012em; margin:0 0 4px; }
.section-h .desc { font-size:12.5px; color:var(--ink-3); line-height:1.5; max-width:520px; }
.section-h .h-action { white-space:nowrap; }
.field { display:flex; flex-direction:column; gap:6px; margin-bottom:14px; }
.field:last-child { margin-bottom:0; }
.field label { font-size:11.5px; font-weight:500; color:var(--ink-2); letter-spacing:-0.005em; }
.field .hint { font-size:11.5px; color:var(--ink-3); margin-top:2px; line-height:1.4; }
.input, .select {
height:36px; padding:0 12px;
border:1px solid var(--hairline); border-radius:var(--r-sm);
background:var(--surface); font-family:inherit; font-size:13px;
color:var(--ink); outline:none; letter-spacing:-0.005em;
}
.input.mono { font-family:var(--font-mono); font-feature-settings:'tnum'; letter-spacing:0; }
.input:focus, .select:focus { border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-tint); }
.field-row { display:grid; grid-template-columns:1fr 1fr; gap:12px; margin-bottom:14px; }
.field-row .field { margin-bottom: 0; }
.btn { display:inline-flex; align-items:center; gap:7px; height:34px; padding:0 14px; border-radius:var(--r-sm); border:1px solid var(--hairline); background:var(--surface); font-size:12.5px; font-weight:500; color:var(--ink); cursor:pointer; font-family:inherit; letter-spacing:-0.005em; }
.btn:hover { border-color:var(--ink-disabled); background:var(--sunken); }
.btn-primary { background:var(--accent); color:#fff; border-color:var(--accent); }
.btn-primary:hover { background:var(--accent-deep); border-color:var(--accent-deep); }
.btn-danger { color:var(--st-new); }
.btn-danger:hover { background:#FFE7E2; border-color:var(--st-new); color:#8E2516; }
.btn svg { width:13px; height:13px; stroke-width:1.7; }
/* Toggle switch */
.toggle { display:flex; align-items:center; justify-content:space-between; gap:14px; padding:11px 14px; background:var(--bg); border:1px solid var(--hairline-soft); border-radius:var(--r-sm); margin-bottom:6px; }
.toggle:last-child { margin-bottom: 0; }
.toggle .t-label { font-size:13px; color:var(--ink); font-weight:500; letter-spacing:-0.005em; }
.toggle .t-desc { font-size:11.5px; color:var(--ink-3); margin-top:2px; line-height:1.4; }
.toggle .switch { position:relative; width:36px; height:20px; flex-shrink:0; }
.toggle .switch input { opacity:0; width:0; height:0; position:absolute; }
.toggle .switch .slider { position:absolute; inset:0; background:var(--ink-disabled); border-radius:100px; transition:background 120ms ease; cursor:pointer; }
.toggle .switch .slider::before { content:''; position:absolute; left:2px; top:2px; width:16px; height:16px; background:#fff; border-radius:50%; transition:transform 120ms ease; }
.toggle .switch input:checked + .slider { background:var(--accent); }
.toggle .switch input:checked + .slider::before { transform:translateX(16px); }
.toggle .switch input:focus-visible + .slider { outline:2px solid var(--accent); outline-offset:2px; }
/* Avatar uploader */
.avatar-up { display:flex; align-items:center; gap:14px; }
.avatar-up .ava-big {
width:64px; height:64px; border-radius:50%;
background: var(--ink); color:#fff;
display:inline-flex; align-items:center; justify-content:center;
font-size:22px; font-weight:600; letter-spacing:0.02em;
flex-shrink:0; position:relative;
}
.avatar-up .ava-big::after { content:''; position:absolute; inset:0; border-radius:50%; border:1px solid rgba(10,19,25,0.14); }
/* API tokens table */
.token-table { width:100%; border-collapse:collapse; font-size:12.5px; }
.token-table thead th { text-align:left; font-size:10.5px; font-weight:600; color:var(--ink-2); padding:8px 0; border-bottom:1px solid var(--hairline-soft); letter-spacing:0.005em; }
.token-table thead th.num { text-align:right; }
.token-table tbody td { padding:10px 0; border-bottom:1px solid var(--hairline-soft); vertical-align:middle; }
.token-table tbody tr:last-child td { border-bottom:none; }
.token-table .t-name { font-weight:500; color:var(--ink); }
.token-table .t-name .scope { font-family:var(--font-mono); font-size:10px; color:var(--ink-3); display:block; margin-top:2px; letter-spacing:-0.005em; }
.token-table .t-token { font-family:var(--font-mono); font-feature-settings:'tnum'; font-size:11.5px; color:var(--ink-2); }
.token-table .t-when { font-family:var(--font-mono); font-feature-settings:'tnum'; font-size:11px; color:var(--ink-3); white-space:nowrap; }
.token-table .row-action { width:24px; height:24px; border:none; background:none; color:var(--ink-3); border-radius:4px; cursor:pointer; display:inline-flex; align-items:center; justify-content:center; }
.token-table .row-action:hover { background:rgba(10,19,25,0.06); color:var(--st-new); }
.token-table .row-action svg { width:13px; height:13px; }
.tab-page { display:none; }
.tab-page.active { display:contents; }
@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 60px; grid-template-columns:170px 1fr; gap:20px; }
}
@media (max-width:768px) {
.app { grid-template-columns:1fr; }
.side { display:none; }
.topbar .crumb span:first-child { display:none; }
.content { grid-template-columns:1fr; gap:16px; }
.tab-rail { position:static; flex-direction:row; flex-wrap:wrap; gap:4px; padding-bottom:8px; }
.tab-rail .rail-eyebrow { display:none; }
.tab-rail button { padding:7px 10px; }
.field-row { grid-template-columns:1fr; }
.page-h { flex-direction:column; align-items:flex-start; gap:10px; }
.section { padding:16px 16px; }
}
</style>
</head>
<body>
<a href="#main" class="skip-link">К контенту</a>
<div class="app">
<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" href="#"><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"/></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"/></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"><circle cx="9" cy="7" r="4"/></svg><span class="nav-text">Менеджеры</span><span class="nav-count">4</span></a>
<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"><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>
<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="user-chip" aria-label="Профиль · Иван Петров"><span class="ava" aria-hidden="true">ИП</span><span class="uname">Иван П.</span></button>
</div>
<main id="main" class="content">
<header class="page-h">
<div>
<h1 class="page-title">Настройки</h1>
<div class="page-meta">тенант <strong style="color:var(--ink-2);font-weight:500">Окна Москва ООО</strong> · 4 менеджера · тариф «Команда»</div>
</div>
</header>
<!-- Tab rail (left column) -->
<nav class="tab-rail" role="tablist" aria-label="Разделы настроек">
<span class="rail-eyebrow">Личное</span>
<button type="button" class="active" role="tab" data-tab="profile" aria-selected="true"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="7" r="4"/><path d="M2 21v-2a4 4 0 0 1 4-4h12a4 4 0 0 1 4 4v2"/></svg>Профиль</button>
<button type="button" role="tab" data-tab="security" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/></svg>Безопасность</button>
<span class="rail-eyebrow">Тенант</span>
<button type="button" role="tab" data-tab="projects" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M3 7v13h18V7M3 7l3-4h12l3 4M3 7h18M9 11h6"/></svg>Проекты</button>
<button type="button" role="tab" data-tab="team" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="9" cy="7" r="4"/><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"/><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>Команда</button>
<button type="button" role="tab" data-tab="api" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M21 2L13 10M16 2h5v5"/><path d="M21 13v5a2 2 0 0 1-2 2h-14a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5"/></svg>API и Webhook</button>
<button type="button" role="tab" data-tab="integrations" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="6" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M6 15V9a3 3 0 0 1 3-3h3M18 9v6a3 3 0 0 1-3 3h-3"/></svg>Интеграции</button>
<span class="rail-eyebrow">Тонкости</span>
<button type="button" role="tab" data-tab="hours" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>Тихие часы</button>
<button type="button" role="tab" data-tab="notifications" aria-selected="false"><svg class="ico" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>Уведомления</button>
</nav>
<!-- Tab content -->
<div class="tab-content">
<!-- ===== ПРОФИЛЬ ===== -->
<section id="tab-profile" class="tab-page active" aria-labelledby="profile-h">
<article class="section">
<div class="section-h">
<div>
<h2 id="profile-h">Профиль аккаунта</h2>
<div class="desc">Эта информация используется при заключении договоров и в подписи писем.</div>
</div>
</div>
<div class="avatar-up">
<span class="ava-big" aria-hidden="true">ИП</span>
<div style="display:flex;flex-direction:column;gap:6px">
<div style="display:flex;gap:6px"><button type="button" class="btn">Загрузить фото</button><button type="button" class="btn btn-danger">Удалить</button></div>
<div style="font-size:11.5px;color:var(--ink-3)">PNG/JPG до 2MB · квадратное · минимум 256×256</div>
</div>
</div>
<div style="height:18px"></div>
<div class="field-row">
<div class="field"><label for="p-fname">Имя</label><input class="input" id="p-fname" type="text" value="Иван"></div>
<div class="field"><label for="p-lname">Фамилия</label><input class="input" id="p-lname" type="text" value="Петров"></div>
</div>
<div class="field-row">
<div class="field"><label for="p-email">Email</label><input class="input" id="p-email" type="email" value="ivan.petrov@example.ru"></div>
<div class="field"><label for="p-phone">Телефон</label><input class="input mono" id="p-phone" type="tel" value="+7 (916) 482-91-22"></div>
</div>
<div class="field"><label for="p-role">Роль в компании</label><input class="input" id="p-role" type="text" value="Старший менеджер" placeholder="Опционально"></div>
<div style="display:flex;gap:8px;margin-top:8px"><button type="button" class="btn btn-primary">Сохранить</button><button type="button" class="btn">Отменить</button></div>
</article>
<article class="section">
<div class="section-h">
<div>
<h2>Реквизиты юр. лица</h2>
<div class="desc">Для счетов и УПД. Обновляется в админке оператором — самостоятельно не редактируется.</div>
</div>
</div>
<div class="field-row">
<div class="field"><label>Юр. лицо</label><div style="font-size:13px;color:var(--ink);font-weight:500;letter-spacing:-0.005em">ООО «Окна Москва»</div></div>
<div class="field"><label>ИНН / КПП</label><div style="font-family:var(--font-mono);font-feature-settings:'tnum';font-size:12.5px;color:var(--ink-2)">7724444444 / 772401001</div></div>
</div>
<div class="field-row">
<div class="field"><label>Юр. адрес</label><div style="font-size:12.5px;color:var(--ink-2);line-height:1.5">115093, Москва, ул. Большая Серпуховская, 32 стр. 1, оф. 405</div></div>
<div class="field"><label>Расчётный счёт</label><div style="font-family:var(--font-mono);font-size:12px;color:var(--ink-2)">40702810400000000123 · ПАО «Сбербанк»</div></div>
</div>
</article>
<article class="section">
<div class="section-h">
<div>
<h2 style="color:var(--st-new)">Удалить аккаунт</h2>
<div class="desc">Все ваши проекты, сделки, история и баланс будут <strong style="color:var(--ink-2);font-weight:500">безвозвратно удалены</strong> по 152-ФЗ. Восстановление невозможно.</div>
</div>
<button type="button" class="btn btn-danger">Удалить мой аккаунт</button>
</div>
</article>
</section>
<!-- ===== БЕЗОПАСНОСТЬ ===== -->
<section id="tab-security" class="tab-page" aria-labelledby="security-h">
<article class="section">
<div class="section-h">
<div>
<h2 id="security-h">Пароль</h2>
<div class="desc">Замена пароля каждые 90 дней не обязательна, но рекомендуется. Минимум 8 символов, оценка через zxcvbn.</div>
</div>
</div>
<div class="field"><label for="s-old">Текущий пароль</label><input class="input" id="s-old" type="password" placeholder="••••••••"></div>
<div class="field-row">
<div class="field"><label for="s-new">Новый пароль</label><input class="input" id="s-new" type="password" placeholder="Минимум 8 символов"></div>
<div class="field"><label for="s-conf">Повторите</label><input class="input" id="s-conf" type="password" placeholder=""></div>
</div>
<div style="display:flex;gap:8px;margin-top:8px"><button type="button" class="btn btn-primary">Сменить пароль</button></div>
</article>
<article class="section">
<div class="section-h">
<div>
<h2>Двухфакторная аутентификация</h2>
<div class="desc">2FA через приложение-аутентификатор (Google Authenticator, Authy, Яндекс.Ключ). Включена на всех тарифах.</div>
</div>
<button type="button" class="btn">Скачать резервные коды</button>
</div>
<div class="toggle">
<div>
<div class="t-label">Двухфакторная защита включена</div>
<div class="t-desc">Привязано к Yandex.Ключ · последний вход подтверждён 28 минут назад</div>
</div>
<label class="switch"><input type="checkbox" checked aria-label="2FA"><span class="slider" aria-hidden="true"></span></label>
</div>
</article>
<article class="section">
<div class="section-h">
<div>
<h2>Активные сессии</h2>
<div class="desc">Если видите подозрительный вход — закройте сессию и смените пароль.</div>
</div>
<button type="button" class="btn">Закрыть все, кроме текущей</button>
</div>
<table class="token-table" aria-label="Активные сессии">
<thead><tr><th>Устройство</th><th>IP / город</th><th class="num">Активна</th><th></th></tr></thead>
<tbody>
<tr><td class="t-name">macOS · Safari 17 <span class="scope">Текущая сессия</span></td><td class="t-token">93.184.216.34 · Москва</td><td class="t-when">сейчас</td><td></td></tr>
<tr><td class="t-name">iOS · Safari Mobile</td><td class="t-token">94.51.21.108 · Москва</td><td class="t-when">3 ч назад</td><td><button type="button" class="row-action" aria-label="Закрыть сессию"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M18 6 6 18M6 6l12 12"/></svg></button></td></tr>
<tr><td class="t-name">Windows · Chrome 121</td><td class="t-token">85.142.39.18 · Санкт-Петербург</td><td class="t-when">вчера</td><td><button type="button" class="row-action" aria-label="Закрыть сессию"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><path d="M18 6 6 18M6 6l12 12"/></svg></button></td></tr>
</tbody>
</table>
</article>
</section>
<!-- ===== API И WEBHOOK ===== -->
<section id="tab-api" class="tab-page" aria-labelledby="api-h">
<article class="section">
<div class="section-h">
<div>
<h2 id="api-h">API-токены</h2>
<div class="desc">Для outbound webhook и интеграций. Все токены хранятся как <code style="font-family:var(--font-mono);font-size:11.5px;background:var(--sunken);padding:1px 4px;border-radius:3px">type="password"</code> — открытое значение видно только при создании.</div>
</div>
<button type="button" class="btn btn-primary"><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>Новый токен</button>
</div>
<table class="token-table" aria-label="API-токены">
<thead><tr><th>Имя · scope</th><th>Маска</th><th class="num">Создан</th><th></th></tr></thead>
<tbody>
<tr><td class="t-name">Webhook prod <span class="scope">leads:read · deals:write</span></td><td class="t-token">lpk_••••••e91k</td><td class="t-when">12.04.2026</td><td><button type="button" class="row-action" aria-label="Удалить токен"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></td></tr>
<tr><td class="t-name">Я.Директ интеграция <span class="scope">leads:read</span></td><td class="t-token">lpk_••••••3xqz</td><td class="t-when">28.03.2026</td><td><button type="button" class="row-action" aria-label="Удалить токен"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></td></tr>
<tr><td class="t-name">Тестовый <span class="scope">leads:read · deals:read</span></td><td class="t-token">lpk_••••••9btv</td><td class="t-when">15.02.2026</td><td><button type="button" class="row-action" aria-label="Удалить токен"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></td></tr>
</tbody>
</table>
</article>
<article class="section">
<div class="section-h">
<div>
<h2>Webhook эндпоинты</h2>
<div class="desc">URL ваших систем, куда мы отправим лиды/события сделок. Подпись HMAC SHA-256 в заголовке X-Liderra-Sign.</div>
</div>
<button type="button" class="btn btn-primary"><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>Новый эндпоинт</button>
</div>
<table class="token-table" aria-label="Webhook эндпоинты">
<thead><tr><th>URL · события</th><th>Статус (24ч)</th><th class="num">Последний</th><th></th></tr></thead>
<tbody>
<tr><td class="t-name">https://crm.example.ru/webhook/leads <span class="scope">lead.created · lead.updated</span></td><td><span style="display:inline-flex;align-items:center;gap:6px;font-size:11px"><span style="width:7px;height:7px;border-radius:50%;background:var(--st-quote)"></span>OK · 99.97% / 412</span></td><td class="t-when">3 мин назад</td><td><button type="button" class="row-action" aria-label="Удалить"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></td></tr>
<tr><td class="t-name">https://bitrix.example.ru/api/lead-in <span class="scope">lead.created</span></td><td><span style="display:inline-flex;align-items:center;gap:6px;font-size:11px"><span style="width:7px;height:7px;border-radius:50%;background:var(--st-call)"></span>деградация · 96.4%</span></td><td class="t-when">12 мин назад</td><td><button type="button" class="row-action" aria-label="Удалить"><svg fill="none" stroke="currentColor" viewBox="0 0 24 24"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></button></td></tr>
</tbody>
</table>
</article>
</section>
<!-- остальные tab-page заглушки чтобы переключатель работал, но не выводим контент -->
<section id="tab-projects" class="tab-page"><article class="section"><h2>Проекты</h2><p style="color:var(--ink-3);font-size:13px;margin:0;line-height:1.5">Список проектов с фильтрами, архивированием, массовыми операциями. <em>Контент в следующих итерациях.</em></p></article></section>
<section id="tab-team" class="tab-page"><article class="section"><h2>Команда</h2><p style="color:var(--ink-3);font-size:13px;margin:0;line-height:1.5">Менеджеры тенанта, приглашение по email + magic-link 24ч для подрядчиков. <em>Контент в следующих итерациях.</em></p></article></section>
<section id="tab-integrations" class="tab-page"><article class="section"><h2>Интеграции</h2><p style="color:var(--ink-3);font-size:13px;margin:0;line-height:1.5">amoCRM (спринт 1415), Bitrix24 / RetailCRM в Post-MVP. <em>Контент в следующих итерациях.</em></p></article></section>
<section id="tab-hours" class="tab-page"><article class="section"><h2>Тихие часы</h2><p style="color:var(--ink-3);font-size:13px;margin:0;line-height:1.5">start_hour / end_hour 0..23, минимум 3 часа, общий timezone тенанта. <em>Контент в следующих итерациях.</em></p></article></section>
<section id="tab-notifications" class="tab-page"><article class="section"><h2>Уведомления</h2><p style="color:var(--ink-3);font-size:13px;margin:0;line-height:1.5">Push, email, Telegram-канал команды. <em>Контент в следующих итерациях.</em></p></article></section>
</div>
</main>
</div>
</div>
<script>
const tabs = Array.from(document.querySelectorAll('.tab-rail [role="tab"]'));
const pages = Array.from(document.querySelectorAll('.tab-page'));
function setTab(id) {
tabs.forEach(t => {
const isA = t.dataset.tab === id;
t.classList.toggle('active', isA);
t.setAttribute('aria-selected', isA ? 'true' : 'false');
});
pages.forEach(p => p.classList.toggle('active', p.id === 'tab-' + id));
}
tabs.forEach(t => t.addEventListener('click', () => setTab(t.dataset.tab)));
</script>
</body>
</html>