feat(preview): static HTML mockups на /preview/* (basic auth) #268

Merged
lekss361 merged 1 commit from feat/preview-mockups-static into main 2026-05-17 08:19:25 +00:00
6 changed files with 2360 additions and 0 deletions

View file

@ -18,6 +18,16 @@ gendsgn.ru {
reverse_proxy backend:8000
}
# Static HTML mockups для review (audit alternatives).
# Basic auth: user=preview / pwd выдан вне репо. Bcrypt hash в Caddyfile (publishing OK).
handle_path /preview/* {
root * /srv/preview
basicauth {
preview $2a$14$6yBnKYGKaiPK4de1qoa7DuKhQ7h8UJmEIvCToM5M1IvBprpkop.Fy
}
file_server browse
}
handle {
reverse_proxy frontend:3000
}

View file

@ -185,6 +185,7 @@ services:
- "443:443"
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./preview:/srv/preview:ro
- caddy_data:/data
- caddy_config:/config
# backend: service_healthy — backend имеет /health endpoint, готов до Caddy.

588
preview/analytics.html Normal file
View file

@ -0,0 +1,588 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>/analytics — Свердл рынок · gendsgn</title>
<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:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
--bg-app:#F6F7F9; --bg-card:#FFFFFF; --bg-card-alt:#FAFBFC; --bg-headline:#0F172A;
--border-soft:#EEF0F3; --border-card:#E6E8EC; --border-strong:#D1D5DB;
--fg-primary:#111111; --fg-secondary:#5B6066; --fg-tertiary:#73767E;
--fg-on-dark:#E2E8F0; --fg-on-dark-muted:#94A3B8;
--accent:#1D4ED8; --accent-hover:#1E40AF; --accent-soft:#DBEAFE; --accent-2:#F2994A;
--success:#0A7A3A; --success-soft:#DCFCE7;
--warn:#9A6700; --warn-soft:#FEF3C7;
--danger:#B3261E; --danger-soft:#FEE2E2;
--viz-1:#1D4ED8; --viz-2:#0EA5E9; --viz-3:#14B8A6; --viz-4:#F59E0B; --viz-5:#8B5CF6;
--prediction-band: rgba(14,165,233,0.18);
--font-body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
}
* { box-sizing:border-box; margin:0; padding:0; }
html { background:var(--bg-app); }
body { font-family:var(--font-body); font-size:14px; line-height:1.5; color:var(--fg-primary); font-variant-numeric:tabular-nums; font-feature-settings:"tnum"; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; }
a { color:inherit; text-decoration:none; }
button { font:inherit; cursor:pointer; }
.mono { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.wrap { max-width:1440px; margin:0 auto; padding:0 24px; }
/* ============ DEV NAV ============ */
.dev-nav { position:sticky; top:0; z-index:100; display:flex; align-items:center; gap:18px; height:38px; padding:0 18px; background:#0b0f1a; color:rgba(255,255,255,0.92); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11.5px; letter-spacing:0.04em; border-bottom:1px solid rgba(255,255,255,0.08); }
.dev-nav .dev-label { display:inline-flex; align-items:center; gap:8px; color:#fbbf24; font-weight:600; letter-spacing:0.18em; text-transform:uppercase; white-space:nowrap; }
.dev-nav .dev-label::before { content:''; width:6px; height:6px; border-radius:50%; background:#fbbf24; box-shadow:0 0 0 3px rgba(251,191,36,0.22); }
.dev-nav .dev-tabs { display:inline-flex; gap:2px; align-items:center; }
.dev-nav .dev-sep { width:1px; height:16px; background:rgba(255,255,255,0.16); margin:0 6px; }
.dev-nav .dev-tabs a { padding:5px 11px; border-radius:5px; color:rgba(255,255,255,0.62); transition:background .12s,color .12s; }
.dev-nav .dev-tabs a:hover { color:#fff; background:rgba(255,255,255,0.08); }
.dev-nav .dev-tabs a[aria-current="page"] { color:#0b0f1a; background:#fbbf24; font-weight:600; }
.dev-nav .dev-hint { margin-left:auto; color:rgba(255,255,255,0.36); white-space:nowrap; }
@media print { .dev-nav { display:none !important; } }
.topbar { background:var(--bg-card); border-bottom:1px solid var(--border-card); }
.topbar-inner { display:flex; align-items:center; justify-content:space-between; height:56px; }
.brand { display:inline-flex; align-items:center; gap:8px; font-weight:700; font-size:15px; color:var(--fg-primary); letter-spacing:-0.01em; }
.brand-mark { width:22px; height:22px; border-radius:6px; background:var(--accent); display:grid; place-items:center; color:#fff; font-size:11px; font-weight:700; }
.brand-mark::before { content:'gd'; }
.topbar-user { display:flex; align-items:center; gap:12px; font-size:13px; color:var(--fg-secondary); }
.topbar-user .who { display:flex; align-items:center; gap:8px; padding:6px 12px; border-radius:6px; background:var(--bg-card-alt); border:1px solid var(--border-card); }
.topbar-user .avatar { width:22px; height:22px; border-radius:50%; background:var(--accent-soft); color:var(--accent); display:grid; place-items:center; font-weight:600; font-size:10px; }
.crumbs { display:flex; gap:8px; align-items:center; padding-top:16px; font-size:12.5px; color:var(--fg-secondary); }
.crumbs a { color:var(--fg-secondary); }
.crumbs a:hover { color:var(--accent); text-decoration:underline; text-underline-offset:3px; }
.crumbs .sep { color:var(--fg-tertiary); }
.crumbs .last { color:var(--fg-primary); }
.page-head { padding:8px 0 16px; display:flex; justify-content:space-between; align-items:flex-end; gap:24px; }
.page-head h1 { font-size:22px; line-height:1.25; font-weight:600; letter-spacing:-0.01em; }
.page-head .sub { font-size:13px; color:var(--fg-secondary); margin-top:4px; }
.page-head .right { display:flex; gap:8px; align-items:center; }
.a-tabs { display:flex; gap:2px; border-bottom:1px solid var(--border-card); margin-bottom:16px; overflow-x:auto; }
.a-tabs a { padding:10px 14px; font-size:13px; font-weight:500; color:var(--fg-secondary); border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; }
.a-tabs a:hover { color:var(--fg-primary); }
.a-tabs a[aria-current="page"] { color:var(--accent); border-bottom-color:var(--accent); font-weight:600; }
.headline-bar { background:var(--bg-headline); color:var(--fg-on-dark); border-radius:12px; padding:16px 20px; display:flex; align-items:center; gap:16px; margin-bottom:16px; }
.headline-bar .tag { font-size:10.5px; letter-spacing:0.08em; text-transform:uppercase; font-weight:600; color:var(--accent-2); white-space:nowrap; }
.headline-bar .verdict { font-size:15px; font-weight:500; line-height:1.4; color:var(--fg-on-dark); }
.headline-bar .verdict b { color:#fff; font-weight:600; }
.headline-bar .caveat { margin-left:auto; font-size:11.5px; color:var(--fg-on-dark-muted); white-space:nowrap; }
.kpi-row { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:24px; }
.kpi { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:16px 18px; }
.kpi .label { font-size:11px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; }
.kpi .value { font-size:28px; line-height:1.15; font-weight:600; color:var(--fg-primary); letter-spacing:-0.015em; margin-top:8px; }
.kpi .value small { font-size:14px; color:var(--fg-secondary); font-weight:500; margin-left:4px; }
.kpi .hint { font-size:12.5px; color:var(--fg-secondary); margin-top:6px; }
.kpi .delta { display:inline-flex; align-items:center; gap:4px; font-size:12px; font-weight:600; margin-top:8px; padding:2px 8px; border-radius:4px; font-variant-numeric:tabular-nums; }
.kpi .delta.pos { color:var(--success); background:var(--success-soft); }
.kpi .delta.neg { color:var(--danger); background:var(--danger-soft); }
.section { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:20px; margin-bottom:24px; }
.section-head { display:flex; align-items:flex-end; justify-content:space-between; gap:16px; margin-bottom:16px; }
.section-head h2 { font-size:18px; line-height:1.25; font-weight:600; letter-spacing:-0.01em; }
.section-head .sub { font-size:12.5px; color:var(--fg-secondary); margin-top:4px; }
.section-head .right { display:flex; gap:8px; align-items:center; }
.btn { display:inline-flex; align-items:center; gap:6px; height:36px; padding:0 16px; border-radius:8px; font-weight:500; font-size:13.5px; border:1px solid transparent; transition:all .12s; }
.btn-primary { background:var(--accent); color:#fff; border-color:var(--accent); }
.btn-primary:hover { background:var(--accent-hover); border-color:var(--accent-hover); }
.btn-secondary { background:var(--accent-2); color:#fff; border-color:var(--accent-2); }
.btn-secondary:hover { filter:brightness(0.94); }
.btn-tertiary { background:transparent; color:var(--fg-primary); border-color:var(--border-card); }
.btn-tertiary:hover { border-color:var(--fg-primary); }
.btn-compact { height:32px; padding:0 12px; font-size:12.5px; border-radius:6px; }
.chip { display:inline-flex; align-items:center; gap:6px; height:28px; padding:0 12px; border-radius:14px; font-size:12px; font-weight:500; color:var(--fg-secondary); background:transparent; border:1px solid var(--border-card); transition:all .12s; cursor:pointer; }
.chip:hover { color:var(--fg-primary); border-color:var(--fg-secondary); }
.chip[aria-pressed="true"] { color:var(--accent); background:var(--accent-soft); border-color:var(--accent-soft); }
.badge { display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:600; padding:2px 8px; border-radius:4px; }
.badge.live { color:var(--success); background:var(--success-soft); }
.badge.live::before { content:''; width:6px; height:6px; border-radius:50%; background:var(--success); box-shadow:0 0 0 3px rgba(10,122,58,0.18); }
.map-wrap { position:relative; height:480px; border-radius:8px; overflow:hidden; border:1px solid var(--border-soft); background:#EEF2F7; }
.map-wrap svg { width:100%; height:100%; display:block; }
.map-legend { position:absolute; bottom:12px; left:12px; background:rgba(255,255,255,0.96); backdrop-filter:blur(8px); border:1px solid var(--border-card); border-radius:8px; padding:10px 12px; font-size:11.5px; display:flex; flex-direction:column; gap:6px; }
.map-legend h4 { font-size:10px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; }
.map-legend .row { display:flex; align-items:center; gap:8px; }
.map-legend .row .pip { width:10px; height:10px; border-radius:50%; border:1.5px solid #fff; box-shadow:0 0 0 1px rgba(0,0,0,0.06); }
.map-controls { position:absolute; top:12px; right:12px; display:flex; flex-direction:column; gap:4px; }
.map-controls button { width:32px; height:32px; border-radius:6px; background:rgba(255,255,255,0.96); border:1px solid var(--border-card); font-size:14px; color:var(--fg-primary); display:grid; place-items:center; }
.map-tooltip { position:absolute; top:14%; left:36%; background:#fff; border:1px solid var(--border-card); border-radius:8px; padding:10px 12px; font-size:11.5px; box-shadow:0 8px 24px -8px rgba(0,0,0,0.18); min-width:200px; }
.map-tooltip .name { font-weight:600; color:var(--fg-primary); font-size:12.5px; margin-bottom:2px; }
.map-tooltip .meta { color:var(--fg-secondary); font-size:11px; line-height:1.45; }
.map-tooltip .stat { display:flex; justify-content:space-between; padding-top:6px; margin-top:6px; border-top:1px solid var(--border-soft); }
.pulse-wrap { display:grid; grid-template-columns:1fr 240px; gap:24px; align-items:start; }
.pulse-chart { position:relative; height:280px; border-left:1px solid var(--border-soft); border-bottom:1px solid var(--border-soft); }
.pulse-chart svg { width:100%; height:100%; display:block; }
.pulse-legend { display:flex; flex-direction:column; gap:10px; padding-top:8px; }
.pulse-legend .leg-row { display:flex; align-items:center; gap:8px; font-size:12.5px; }
.pulse-legend .leg-row .sw { width:14px; height:8px; border-radius:2px; }
.pulse-legend .leg-row .name { color:var(--fg-primary); font-weight:500; }
.pulse-legend .leg-row .meta { margin-left:auto; color:var(--fg-secondary); font-size:11.5px; }
.pulse-axis { position:absolute; font-size:10px; color:var(--fg-tertiary); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.qg-table { display:grid; grid-template-columns:160px 1fr 70px; gap:12px; }
.qg-row { display:contents; }
.qg-cell { padding:8px 0; border-top:1px solid var(--border-soft); display:flex; align-items:center; }
.qg-row:first-child .qg-cell { border-top:0; }
.qg-name { color:var(--fg-primary); font-weight:500; font-size:13px; }
.qg-bars { display:flex; flex-direction:column; gap:4px; padding:6px 0; flex:1; }
.qg-bar { height:14px; border-radius:4px; position:relative; min-width:1%; transition:all .15s; }
.qg-bar .v { position:absolute; right:8px; top:50%; transform:translateY(-50%); font-size:10.5px; font-weight:600; color:#fff; font-variant-numeric:tabular-nums; }
.qg-bar.supply { background:var(--fg-tertiary); }
.qg-bar.demand { background:var(--accent); }
.qg-delta { font-size:12px; font-weight:600; padding:3px 8px; border-radius:4px; text-align:center; font-variant-numeric:tabular-nums; }
.qg-delta.pos { color:var(--success); background:var(--success-soft); }
.qg-delta.neg { color:var(--danger); background:var(--danger-soft); }
.qg-delta.flat { color:var(--fg-secondary); background:var(--bg-card-alt); }
.two-col { display:grid; grid-template-columns:1fr 1fr; gap:24px; margin-bottom:24px; }
.pipeline { display:flex; flex-direction:column; gap:10px; padding-top:8px; }
.pipe-row { display:grid; grid-template-columns:60px 1fr 80px; gap:12px; align-items:center; }
.pipe-row .year { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:12px; color:var(--fg-secondary); }
.pipe-row .stack { height:18px; border-radius:4px; overflow:hidden; display:flex; background:var(--bg-card-alt); }
.pipe-row .stack .seg { height:100%; }
.pipe-row .total { font-size:12.5px; font-weight:600; color:var(--fg-primary); text-align:right; font-variant-numeric:tabular-nums; }
.ann-table { width:100%; border-collapse:collapse; }
.ann-table th { font-size:10px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; text-align:left; padding:8px 8px 8px 0; border-bottom:1px solid var(--border-card); }
.ann-table th:last-child, .ann-table td:last-child { text-align:right; padding-right:0; }
.ann-table td { font-size:13px; padding:10px 8px 10px 0; border-bottom:1px solid var(--border-soft); color:var(--fg-primary); }
.ann-table tr:last-child td { border-bottom:0; }
.ann-table .num { font-variant-numeric:tabular-nums; font-weight:500; }
.ann-table a { color:var(--accent); }
.ann-table a:hover { text-decoration:underline; text-underline-offset:2px; }
.treemap { display:grid; grid-template-columns:repeat(12,1fr); grid-auto-rows:54px; gap:4px; }
.tile { background:var(--accent); color:#fff; padding:10px 12px; border-radius:6px; display:flex; flex-direction:column; justify-content:space-between; cursor:pointer; transition:transform .1s; overflow:hidden; }
.tile:hover { transform:translateY(-1px); }
.tile .t-name { font-size:13px; font-weight:600; line-height:1.2; }
.tile .t-meta { font-size:11px; opacity:0.85; font-variant-numeric:tabular-nums; }
.tile.lvl-5 { background:#1E3A8A; }
.tile.lvl-4 { background:#1D4ED8; }
.tile.lvl-3 { background:#3B82F6; }
.tile.lvl-2 { background:#60A5FA; }
.tile.lvl-1 { background:#93C5FD; color:#1E3A8A; }
.tile.lvl-1 .t-meta { opacity:0.75; }
details.acc { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; margin-bottom:12px; }
details.acc summary { padding:14px 20px; font-size:14px; font-weight:600; color:var(--fg-primary); cursor:pointer; list-style:none; display:flex; justify-content:space-between; align-items:center; }
details.acc summary::-webkit-details-marker { display:none; }
details.acc summary::after { content:'+'; color:var(--fg-secondary); font-size:18px; font-weight:400; }
details.acc[open] summary::after { content:''; }
details.acc .acc-body { padding:0 20px 20px; font-size:13px; color:var(--fg-secondary); line-height:1.55; }
.caveat-bar { background:var(--warn-soft); border:1px solid var(--warn); border-radius:8px; padding:12px 16px; display:flex; gap:12px; align-items:flex-start; font-size:13px; color:var(--fg-primary); margin-bottom:24px; }
.caveat-bar .icon { width:18px; height:18px; flex-shrink:0; color:var(--warn); display:grid; place-items:center; font-weight:700; border:1.5px solid var(--warn); border-radius:50%; font-size:12px; }
.caveat-bar b { color:var(--warn); }
@media (max-width:1200px) {
.kpi-row { grid-template-columns:repeat(2,1fr); }
.two-col { grid-template-columns:1fr; }
.pulse-wrap { grid-template-columns:1fr; }
.treemap { grid-template-columns:repeat(6,1fr); }
}
</style>
</head>
<body>
<aside class="dev-nav" aria-label="Dev navigation">
<span class="dev-label">DEV · ТОЛЬКО ДЛЯ РАЗРАБОТКИ</span>
<nav class="dev-tabs" aria-label="WIP страницы">
<a href="landing.html">лендинг</a>
<a href="analytics.html" aria-current="page">/analytics</a>
<a href="site-finder.html">/recommend</a>
<a href="monitoring.html">/developers</a>
<span class="dev-sep"></span>
<a href="audit.html">audit&nbsp;(live)</a>
<a href="gendsgn-audit.html">audit&nbsp;(отчёт)</a>
</nav>
<span class="dev-hint">временная панель · скроется в print</span>
</aside>
<header class="topbar">
<div class="wrap topbar-inner">
<div style="display:flex;align-items:center;gap:24px;">
<a href="landing.html" class="brand"><span class="brand-mark"></span><span>gendsgn</span></a>
<span class="badge live">live · обновлено 4 ч назад</span>
</div>
<div class="topbar-user">
<span style="font-size:12px;color:var(--fg-tertiary);">Свердловская обл. · 2025-Q1</span>
<div class="who"><div class="avatar">AD</div>Алексей · PRINZIP (demo)</div>
</div>
</div>
</header>
<main class="wrap">
<nav class="crumbs" aria-label="Breadcrumb">
<a href="landing.html">gendsgn</a>
<span class="sep">/</span>
<span class="last">analytics — Свердл рынок</span>
</nav>
<div class="page-head">
<div>
<h1>Свердл рынок — обзор спроса и предложения</h1>
<div class="sub">6 832 411 ДДУ Росреестра · 1 482 объекта ДОМ.РФ в активной фазе · обновление еженедельно</div>
</div>
<div class="right">
<button class="btn btn-tertiary btn-compact">Снимок PDF</button>
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<nav class="a-tabs" aria-label="Разделы аналитики">
<a href="analytics.html" aria-current="page">Свердл рынок</a>
<a href="site-finder.html">Рекомендатор</a>
<a href="monitoring.html">Девелоперы</a>
<a href="#">PRINZIP · профиль</a>
<a href="#">Объекты</a>
</nav>
<div class="headline-bar" role="status">
<span class="tag">вердикт квартала</span>
<p class="verdict">Дефицит средне-большого жилья <b>80+ м²</b>: <b>37%</b> сделок Росреестра, но <b>11%</b> портфеля ДОМ.РФ. Окно сужается к <b>Q3 2026</b>.</p>
<span class="caveat">источник: ДОМ.РФ · Росреестр · март 2026</span>
</div>
<div class="kpi-row">
<div class="kpi">
<div class="label">Объём строительства</div>
<div class="value">5,82<small>млн м²</small></div>
<div class="hint">в активной фазе по области</div>
<span class="delta pos">↑ 4,1% YoY</span>
</div>
<div class="kpi">
<div class="label">Sold % (медиана)</div>
<div class="value">61,4 %</div>
<div class="hint">объекты в продаже &gt; 6 мес</div>
<span class="delta neg">↓ 3,2 пп QoQ</span>
</div>
<div class="kpi">
<div class="label">Средняя цена</div>
<div class="value">186<small>тыс ₽/м²</small></div>
<div class="hint">первичка, март 2026</div>
<span class="delta pos">↑ 1,8% MoM</span>
</div>
<div class="kpi">
<div class="label">Активных новостроек</div>
<div class="value">347</div>
<div class="hint">в открытой продаже Я.Недв</div>
<span class="delta pos">+12 за месяц</span>
</div>
</div>
<section class="section">
<div class="section-head">
<div>
<h2>Карта рынка — новостройки Свердловской области</h2>
<div class="sub">347 объектов в активной продаже · цвет точки — sold % за 6 месяцев · клик → drill-in</div>
</div>
<div class="right">
<button class="chip" aria-pressed="true">все классы</button>
<button class="chip">комфорт</button>
<button class="chip">бизнес</button>
<button class="chip">премиум</button>
<button class="btn btn-secondary btn-compact">Export GeoJSON ⤓</button>
</div>
</div>
<div class="map-wrap">
<svg viewBox="0 0 1200 480" preserveAspectRatio="xMidYMid slice" role="img" aria-label="Карта новостроек Екатеринбурга и окрестностей">
<defs>
<pattern id="grid" width="40" height="40" patternUnits="userSpaceOnUse">
<path d="M 40 0 L 0 0 0 40" fill="none" stroke="#DDE3EB" stroke-width="0.5"/>
</pattern>
</defs>
<rect width="1200" height="480" fill="url(#grid)"/>
<path d="M 100 80 Q 280 180 380 220 T 700 280 Q 880 320 1100 380" stroke="#0EA5E9" stroke-width="3.5" fill="none" opacity="0.45" stroke-linecap="round"/>
<path d="M 0 240 L 1200 240" stroke="#C5CCD6" stroke-width="2" opacity="0.6"/>
<path d="M 600 0 L 600 480" stroke="#C5CCD6" stroke-width="2" opacity="0.6"/>
<path d="M 180 0 Q 380 240 580 480" stroke="#C5CCD6" stroke-width="1.5" opacity="0.5"/>
<path d="M 850 0 Q 700 240 850 480" stroke="#C5CCD6" stroke-width="1.5" opacity="0.5"/>
<text x="280" y="110" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">Академический</text>
<text x="540" y="160" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">ВИЗ</text>
<text x="730" y="200" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">Центр</text>
<text x="920" y="270" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">Пионерский</text>
<text x="380" y="330" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">Юго-Запад</text>
<text x="680" y="380" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">Уралмаш</text>
<text x="980" y="420" font-family="Inter,sans-serif" font-size="11" fill="#5B6066" font-weight="500">Эльмаш</text>
<g id="markers">
<circle cx="220" cy="140" r="6" fill="#B3261E" stroke="#fff" stroke-width="2"/>
<circle cx="250" cy="160" r="6" fill="#B3261E" stroke="#fff" stroke-width="2"/>
<circle cx="310" cy="155" r="5" fill="#B3261E" stroke="#fff" stroke-width="2"/>
<circle cx="940" cy="290" r="5" fill="#B3261E" stroke="#fff" stroke-width="2"/>
<circle cx="290" cy="130" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="340" cy="170" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="520" cy="180" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="570" cy="200" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="650" cy="170" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="720" cy="220" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="790" cy="190" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="900" cy="260" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="380" cy="360" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="420" cy="340" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="700" cy="400" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<circle cx="240" cy="180" r="6" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="610" cy="140" r="5" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="670" cy="190" r="6" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="800" cy="230" r="5" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="450" cy="280" r="6" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="500" cy="320" r="5" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="970" cy="380" r="6" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="1020" cy="410" r="5" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<circle cx="320" cy="220" r="7" fill="#0A7A3A" stroke="#fff" stroke-width="2"/>
<circle cx="560" cy="240" r="6" fill="#0A7A3A" stroke="#fff" stroke-width="2"/>
<circle cx="640" cy="280" r="7" fill="#0A7A3A" stroke="#fff" stroke-width="2"/>
<circle cx="730" cy="320" r="6" fill="#0A7A3A" stroke="#fff" stroke-width="2"/>
<circle cx="850" cy="350" r="7" fill="#0A7A3A" stroke="#fff" stroke-width="2"/>
</g>
</svg>
<div class="map-controls">
<button aria-label="Zoom in">+</button>
<button aria-label="Zoom out"></button>
<button aria-label="Сбросить вид"></button>
</div>
<div class="map-legend">
<h4>Sold % за 6 мес</h4>
<div class="row"><span class="pip" style="background:#B3261E"></span>&lt; 40 % · риск затоваривания</div>
<div class="row"><span class="pip" style="background:#F59E0B"></span>4065 % · средний темп</div>
<div class="row"><span class="pip" style="background:#14B8A6"></span>6580 % · хороший темп</div>
<div class="row"><span class="pip" style="background:#0A7A3A"></span>80+ % · близко к закрытию</div>
</div>
<div class="map-tooltip" role="tooltip">
<div class="name">ЖК «Каменные палатки» · PRINZIP</div>
<div class="meta">Академический · комфорт · 1 824 кв</div>
<div class="stat"><span>Sold %</span><b style="color:var(--success);">78 %</b></div>
<div class="stat"><span>Срок продаж</span><b>22 мес</b></div>
<div class="stat"><span>Ср. цена</span><b>173 тыс ₽/м²</b></div>
</div>
</div>
<div style="margin-top:12px;font-size:12px;color:var(--fg-tertiary);">Карта стилизована для превью. В продукте — Leaflet с базой 2GIS, клик → /analytics/objects/[id]</div>
</section>
<section class="section">
<div class="section-head">
<div>
<h2>Динамика рынка — 14 месяцев</h2>
<div class="sub">Объём ДДУ (Росреестр) и две линии: sold % портфеля и средняя цена м²</div>
</div>
<div class="right">
<button class="chip" aria-pressed="true">14 мес</button>
<button class="chip">12 мес</button>
<button class="chip">6 мес</button>
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<div class="pulse-wrap">
<div class="pulse-chart">
<svg viewBox="0 0 800 280" preserveAspectRatio="none">
<g stroke="#EEF0F3" stroke-width="1">
<line x1="0" y1="56" x2="800" y2="56"/>
<line x1="0" y1="112" x2="800" y2="112"/>
<line x1="0" y1="168" x2="800" y2="168"/>
<line x1="0" y1="224" x2="800" y2="224"/>
</g>
<g fill="#DBEAFE">
<rect x="20" y="180" width="36" height="100"/>
<rect x="76" y="190" width="36" height="90"/>
<rect x="132" y="170" width="36" height="110"/>
<rect x="188" y="160" width="36" height="120"/>
<rect x="244" y="150" width="36" height="130"/>
<rect x="300" y="140" width="36" height="140"/>
<rect x="356" y="155" width="36" height="125"/>
<rect x="412" y="130" width="36" height="150"/>
<rect x="468" y="120" width="36" height="160"/>
<rect x="524" y="135" width="36" height="145"/>
<rect x="580" y="115" width="36" height="165"/>
<rect x="636" y="105" width="36" height="175"/>
<rect x="692" y="125" width="36" height="155"/>
<rect x="748" y="110" width="36" height="170"/>
</g>
<polyline fill="none" stroke="#1D4ED8" stroke-width="2.5" points="38,90 94,82 150,98 206,76 262,68 318,72 374,84 430,60 486,52 542,66 598,48 654,42 710,58 766,46"/>
<g fill="#1D4ED8">
<circle cx="38" cy="90" r="3"/><circle cx="94" cy="82" r="3"/><circle cx="150" cy="98" r="3"/><circle cx="206" cy="76" r="3"/>
<circle cx="262" cy="68" r="3"/><circle cx="318" cy="72" r="3"/><circle cx="374" cy="84" r="3"/><circle cx="430" cy="60" r="3"/>
<circle cx="486" cy="52" r="3"/><circle cx="542" cy="66" r="3"/><circle cx="598" cy="48" r="3"/><circle cx="654" cy="42" r="3"/>
<circle cx="710" cy="58" r="3"/><circle cx="766" cy="46" r="3"/>
</g>
<polyline fill="none" stroke="#F59E0B" stroke-width="2" points="38,140 94,138 150,134 206,128 262,126 318,120 374,116 430,112 486,108 542,102 598,98 654,92 710,88 766,84"/>
<g font-family="ui-monospace,Menlo" font-size="9" fill="#73767E">
<text x="34" y="276">фев</text><text x="90" y="276">мар</text><text x="146" y="276">апр</text><text x="202" y="276">май</text>
<text x="258" y="276">июн</text><text x="316" y="276">июл</text><text x="372" y="276">авг</text><text x="428" y="276">сен</text>
<text x="484" y="276">окт</text><text x="540" y="276">ноя</text><text x="596" y="276">дек</text><text x="654" y="276">янв</text>
<text x="710" y="276">фев</text><text x="764" y="276">мар</text>
</g>
</svg>
</div>
<aside class="pulse-legend">
<div class="leg-row"><span class="sw" style="background:#DBEAFE"></span><span class="name">Объём ДДУ</span><span class="meta">62 415</span></div>
<div class="leg-row"><span class="sw" style="background:#1D4ED8"></span><span class="name">Sold %</span><span class="meta">61,4 % · ↓ 3,2 пп</span></div>
<div class="leg-row"><span class="sw" style="background:#F59E0B"></span><span class="name">Цена ₽/м²</span><span class="meta">186 тыс · ↑ 12 %</span></div>
<div style="margin-top:16px;padding-top:16px;border-top:1px solid var(--border-soft);font-size:11.5px;color:var(--fg-secondary);line-height:1.5;">
Левая ось — sold % (синяя), правая ось — цена ₽/м² (оранжевая). Бары — объём ДДУ помесячно. Hover на точку — раскладка по классу жилья.
</div>
</aside>
</div>
</section>
<section class="section">
<div class="section-head">
<div>
<h2>Парадокс портфеля по комнатности</h2>
<div class="sub">Доля сегмента в портфеле ДОМ.РФ против доли в сделках Росреестра за 14 мес</div>
</div>
<div class="right">
<button class="chip" aria-pressed="true">вся область</button>
<button class="chip">Екатеринбург</button>
<button class="chip">область без ЕКБ</button>
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<div class="qg-table" role="table">
<div class="qg-row">
<div class="qg-cell qg-name">Сегмент</div>
<div class="qg-cell"><span style="font-size:10.5px;letter-spacing:0.04em;text-transform:uppercase;color:var(--fg-secondary);font-weight:500;">портфель ДОМ.РФ vs сделки Росреестра</span></div>
<div class="qg-cell" style="justify-content:flex-end;"><span style="font-size:10.5px;letter-spacing:0.04em;text-transform:uppercase;color:var(--fg-secondary);font-weight:500;">Δ пп</span></div>
</div>
<div class="qg-row">
<div class="qg-cell qg-name">Студии до 30 м²</div>
<div class="qg-cell qg-bars"><div class="qg-bar supply" style="width:78%"><span class="v">24%</span></div><div class="qg-bar demand" style="width:30%"><span class="v">9%</span></div></div>
<div class="qg-cell" style="justify-content:flex-end;"><span class="qg-delta neg">15</span></div>
</div>
<div class="qg-row">
<div class="qg-cell qg-name">1-комн. 3045 м²</div>
<div class="qg-cell qg-bars"><div class="qg-bar supply" style="width:88%"><span class="v">31%</span></div><div class="qg-bar demand" style="width:72%"><span class="v">24%</span></div></div>
<div class="qg-cell" style="justify-content:flex-end;"><span class="qg-delta neg">7</span></div>
</div>
<div class="qg-row">
<div class="qg-cell qg-name">2-комн. 4565 м²</div>
<div class="qg-cell qg-bars"><div class="qg-bar supply" style="width:62%"><span class="v">22%</span></div><div class="qg-bar demand" style="width:66%"><span class="v">23%</span></div></div>
<div class="qg-cell" style="justify-content:flex-end;"><span class="qg-delta flat">+1</span></div>
</div>
<div class="qg-row">
<div class="qg-cell qg-name">3-комн. 6585 м²</div>
<div class="qg-cell qg-bars"><div class="qg-bar supply" style="width:38%"><span class="v">13%</span></div><div class="qg-bar demand" style="width:72%"><span class="v">24%</span></div></div>
<div class="qg-cell" style="justify-content:flex-end;"><span class="qg-delta pos">+11</span></div>
</div>
<div class="qg-row">
<div class="qg-cell qg-name">4+ комн. / 85+ м²</div>
<div class="qg-cell qg-bars"><div class="qg-bar supply" style="width:32%"><span class="v">11%</span></div><div class="qg-bar demand" style="width:58%"><span class="v">20%</span></div></div>
<div class="qg-cell" style="justify-content:flex-end;"><span class="qg-delta pos">+9</span></div>
</div>
</div>
</section>
<div class="two-col">
<section class="section" style="margin-bottom:0;">
<div class="section-head">
<div>
<h2>Pipeline по году ввода</h2>
<div class="sub">Объём (тыс. м²) в разрезе классов</div>
</div>
<div class="right">
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<div class="pipeline">
<div class="pipe-row"><span class="year">2024</span><div class="stack"><div class="seg" style="width:42%;background:#93C5FD"></div><div class="seg" style="width:34%;background:#3B82F6"></div><div class="seg" style="width:18%;background:#1D4ED8"></div><div class="seg" style="width:6%;background:#1E3A8A"></div></div><span class="total">1 240</span></div>
<div class="pipe-row"><span class="year">2025</span><div class="stack"><div class="seg" style="width:48%;background:#93C5FD"></div><div class="seg" style="width:30%;background:#3B82F6"></div><div class="seg" style="width:16%;background:#1D4ED8"></div><div class="seg" style="width:6%;background:#1E3A8A"></div></div><span class="total">1 820</span></div>
<div class="pipe-row"><span class="year">2026</span><div class="stack"><div class="seg" style="width:52%;background:#93C5FD"></div><div class="seg" style="width:28%;background:#3B82F6"></div><div class="seg" style="width:14%;background:#1D4ED8"></div><div class="seg" style="width:6%;background:#1E3A8A"></div></div><span class="total">2 110</span></div>
<div class="pipe-row"><span class="year">2027</span><div class="stack"><div class="seg" style="width:56%;background:#93C5FD"></div><div class="seg" style="width:26%;background:#3B82F6"></div><div class="seg" style="width:12%;background:#1D4ED8"></div><div class="seg" style="width:6%;background:#1E3A8A"></div></div><span class="total">2 580</span></div>
<div class="pipe-row"><span class="year">2028</span><div class="stack"><div class="seg" style="width:60%;background:#93C5FD"></div><div class="seg" style="width:24%;background:#3B82F6"></div><div class="seg" style="width:11%;background:#1D4ED8"></div><div class="seg" style="width:5%;background:#1E3A8A"></div></div><span class="total">1 970</span></div>
</div>
<div style="margin-top:16px;display:flex;gap:16px;font-size:11.5px;color:var(--fg-secondary);flex-wrap:wrap;">
<span style="display:inline-flex;align-items:center;gap:6px;"><span style="width:10px;height:10px;background:#93C5FD;border-radius:2px;"></span>комфорт</span>
<span style="display:inline-flex;align-items:center;gap:6px;"><span style="width:10px;height:10px;background:#3B82F6;border-radius:2px;"></span>бизнес</span>
<span style="display:inline-flex;align-items:center;gap:6px;"><span style="width:10px;height:10px;background:#1D4ED8;border-radius:2px;"></span>премиум</span>
<span style="display:inline-flex;align-items:center;gap:6px;"><span style="width:10px;height:10px;background:#1E3A8A;border-radius:2px;"></span>элит</span>
</div>
</section>
<section class="section" style="margin-bottom:0;">
<div class="section-head">
<div>
<h2>Активные новостройки</h2>
<div class="sub">Топ-7 по объёму · Я.Недвижимость · обновлено 4 ч назад</div>
</div>
<div class="right">
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<table class="ann-table">
<thead>
<tr><th>ЖК</th><th>Девелопер</th><th>Sold %</th><th>Ср. цена</th></tr>
</thead>
<tbody>
<tr><td><a href="#">Каменные палатки</a></td><td>PRINZIP</td><td class="num">78 %</td><td class="num">173 ₽</td></tr>
<tr><td><a href="#">Северная корона</a></td><td>Брусника</td><td class="num">71 %</td><td class="num">198 ₽</td></tr>
<tr><td><a href="#">Чкалов</a></td><td>Атомстройком.</td><td class="num">64 %</td><td class="num">156 ₽</td></tr>
<tr><td><a href="#">Малевич</a></td><td>Форум-групп</td><td class="num">58 %</td><td class="num">182 ₽</td></tr>
<tr><td><a href="#">Уют</a></td><td>Атлас Девел.</td><td class="num">52 %</td><td class="num">141 ₽</td></tr>
<tr><td><a href="#">Гольф-парк</a></td><td>КОРТРОС</td><td class="num">41 %</td><td class="num">224 ₽</td></tr>
<tr><td><a href="#">Эталон City</a></td><td>Эталон</td><td class="num">38 %</td><td class="num">167 ₽</td></tr>
</tbody>
</table>
</section>
</div>
<section class="section">
<div class="section-head">
<div>
<h2>Концентрация ЖК по районам</h2>
<div class="sub">Площадь плитки — объём строительства · цвет — sold % · клик → топ девелоперов района</div>
</div>
<div class="right">
<button class="chip" aria-pressed="true">по объёму</button>
<button class="chip">по числу ЖК</button>
<button class="chip">по выручке</button>
</div>
</div>
<div class="treemap">
<a href="monitoring.html" class="tile lvl-4" style="grid-column:span 4;grid-row:span 2;"><span class="t-name">Академический</span><span class="t-meta">42 ЖК · 824 тыс м² · sold 71 %</span></a>
<a href="monitoring.html" class="tile lvl-3" style="grid-column:span 3;grid-row:span 2;"><span class="t-name">Центр</span><span class="t-meta">28 ЖК · 612 тыс м² · sold 64 %</span></a>
<a href="monitoring.html" class="tile lvl-5" style="grid-column:span 3;grid-row:span 2;"><span class="t-name">ВИЗ</span><span class="t-meta">31 ЖК · 588 тыс м² · sold 48 %</span></a>
<a href="monitoring.html" class="tile lvl-2" style="grid-column:span 2;grid-row:span 2;"><span class="t-name">Пионерский</span><span class="t-meta">19 ЖК · 411 тыс м²</span></a>
<a href="monitoring.html" class="tile lvl-4" style="grid-column:span 3;"><span class="t-name">Юго-Запад</span><span class="t-meta">14 · 386 тыс м²</span></a>
<a href="monitoring.html" class="tile lvl-2" style="grid-column:span 3;"><span class="t-name">Уралмаш</span><span class="t-meta">11 · 254 тыс м²</span></a>
<a href="monitoring.html" class="tile lvl-3" style="grid-column:span 2;"><span class="t-name">Эльмаш</span><span class="t-meta">8 · 198</span></a>
<a href="monitoring.html" class="tile lvl-1" style="grid-column:span 2;"><span class="t-name">Сортировка</span><span class="t-meta">6 · 142</span></a>
<a href="monitoring.html" class="tile lvl-3" style="grid-column:span 2;"><span class="t-name">Уктус</span><span class="t-meta">7 · 168</span></a>
<a href="monitoring.html" class="tile lvl-1" style="grid-column:span 2;"><span class="t-name">Химмаш</span><span class="t-meta">4 · 96</span></a>
<a href="monitoring.html" class="tile lvl-2" style="grid-column:span 3;"><span class="t-name">Широкая речка</span><span class="t-meta">5 · 124 тыс м²</span></a>
<a href="monitoring.html" class="tile lvl-1" style="grid-column:span 3;"><span class="t-name">Верхняя Пышма</span><span class="t-meta">12 · 218 тыс м²</span></a>
</div>
</section>
<div class="caveat-bar">
<span class="icon">!</span>
<div>
<b>Caveat по данным.</b> Sold % считается по объектам в продаже более 6 месяцев; новые ЖК со стартом &lt; 6 мес не входят в медиану, но видны на карте. Росреестр может задерживать ДДУ до 14 дней — берём 7-дневный backfill при еженедельном пересчёте.
</div>
</div>
<details class="acc">
<summary>Развёрнутый разрез по 17 районам области</summary>
<div class="acc-body">Sold %, средний срок, цена м², объём в работе — по каждому из 17 районов с фильтром по классу. Открывается отдельной таблицей в /analytics/districts.</div>
</details>
<details class="acc">
<summary>Методология подсчёта sold %</summary>
<div class="acc-body">Sold % = (общее число проданных лотов по объекту) / (общее число лотов в продаже). Источник: ДДУ Росреестра матчатся с лотами портфеля ДОМ.РФ по cadastral_id + comm_name fuzzy match (порог 0.85, pg_trgm).</div>
</details>
<details class="acc">
<summary>Сравнение с январём 2025 (год к году)</summary>
<div class="acc-body">Sold % медиана: 64,6 % → 61,4 % (3,2 пп). Объём строительства: 5,59 → 5,82 млн м² (+4,1 %). Средняя цена: 166 → 186 тыс ₽/м² (+12 %). Разрыв спрос-предложение в 3к/4+ сегменте увеличился: с +14 пп до +20 пп суммарно.</div>
</details>
</main>
</body>
</html>

646
preview/landing.html Normal file
View file

@ -0,0 +1,646 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>gendsgn — аналитика спроса для девелоперов</title>
<meta name="description" content="Что строят на рынке и что на самом деле продаётся. Региональная аналитика спроса на основе 6,83 млн ДДУ Росреестра, портфеля ДОМ.РФ и Яндекс.Недвижимости." />
<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:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
/* Surface */
--bg-app: #F6F7F9;
--bg-card: #FFFFFF;
--bg-card-alt: #FAFBFC;
--bg-headline: #0F172A;
/* Borders */
--border-soft: #EEF0F3;
--border-card: #E6E8EC;
--border-strong: #D1D5DB;
/* Text */
--fg-primary: #111111;
--fg-secondary: #5B6066;
--fg-tertiary: #73767E;
--fg-on-dark: #E2E8F0;
--fg-on-dark-muted: #94A3B8;
/* Brand / CTA */
--accent: #1D4ED8;
--accent-hover: #1E40AF;
--accent-soft: #DBEAFE;
--accent-2: #F2994A;
/* Semantic */
--success: #0A7A3A;
--success-soft: #DCFCE7;
--warn: #9A6700;
--warn-soft: #FEF3C7;
--danger: #B3261E;
--danger-soft: #FEE2E2;
/* Data-viz */
--viz-1: #1D4ED8;
--viz-2: #0EA5E9;
--viz-3: #14B8A6;
--viz-4: #F59E0B;
--viz-5: #8B5CF6;
--font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
html { background: var(--bg-app); scroll-behavior: smooth; }
body {
font-family: var(--font-body);
font-size: 14px;
line-height: 1.5;
color: var(--fg-primary);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-variant-numeric: tabular-nums;
font-feature-settings: "tnum";
}
a { color: inherit; text-decoration: none; }
button { font: inherit; cursor: pointer; }
.wrap { max-width: 1280px; margin: 0 auto; padding: 0 24px; }
/* ============ DEV NAV (временный, hide on print) ============ */
.dev-nav {
position: sticky; top: 0; z-index: 100;
display: flex; align-items: center; gap: 18px;
height: 38px; padding: 0 18px;
background: #0b0f1a; color: rgba(255,255,255,0.92);
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 11.5px; letter-spacing: 0.04em;
border-bottom: 1px solid rgba(255,255,255,0.08);
}
.dev-nav .dev-label {
display: inline-flex; align-items: center; gap: 8px;
color: #fbbf24; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase; white-space: nowrap;
}
.dev-nav .dev-label::before { content:''; width:6px; height:6px; border-radius:50%; background:#fbbf24; box-shadow:0 0 0 3px rgba(251,191,36,0.22); }
.dev-nav .dev-tabs { display: inline-flex; gap: 2px; align-items: center; }
.dev-nav .dev-sep { width: 1px; height: 16px; background: rgba(255,255,255,0.16); margin: 0 6px; }
.dev-nav .dev-tabs a {
padding: 5px 11px; border-radius: 5px;
color: rgba(255,255,255,0.62); text-decoration: none;
transition: background .12s, color .12s;
}
.dev-nav .dev-tabs a:hover { color: #fff; background: rgba(255,255,255,0.08); }
.dev-nav .dev-tabs a[aria-current="page"] { color: #0b0f1a; background: #fbbf24; font-weight: 600; }
.dev-nav .dev-hint { margin-left: auto; color: rgba(255,255,255,0.36); white-space: nowrap; }
@media print { .dev-nav { display: none !important; } }
@media (max-width: 720px) { .dev-nav .dev-hint { display: none; } .dev-nav { gap: 12px; padding: 0 12px; } }
/* ============ TOP NAV ============ */
header.nav {
position: sticky; top: 38px; z-index: 30;
background: rgba(255,255,255,0.92);
backdrop-filter: saturate(140%) blur(8px);
-webkit-backdrop-filter: saturate(140%) blur(8px);
border-bottom: 1px solid var(--border-card);
}
.nav-inner { display: flex; align-items: center; justify-content: space-between; height: 56px; }
.brand { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; font-size: 15px; color: var(--fg-primary); letter-spacing: -0.01em; }
.brand-mark { width: 22px; height: 22px; border-radius: 6px; background: var(--accent); display: grid; place-items: center; color: #fff; font-size: 11px; font-weight: 700; letter-spacing: 0; }
.brand-mark::before { content: 'gd'; }
.nav-links { display: flex; gap: 24px; }
.nav-links a { font-size: 13.5px; color: var(--fg-secondary); font-weight: 500; }
.nav-links a:hover { color: var(--fg-primary); }
.nav-cta { display: flex; align-items: center; gap: 12px; }
/* ============ BUTTONS ============ */
.btn { display: inline-flex; align-items: center; gap: 8px; height: 36px; padding: 0 16px; border-radius: 8px; font-weight: 500; font-size: 13.5px; border: 1px solid transparent; transition: background .12s, border-color .12s, color .12s; }
.btn-primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.btn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn-secondary { background: var(--accent-2); color: #fff; border-color: var(--accent-2); }
.btn-secondary:hover { filter: brightness(0.94); }
.btn-tertiary { background: transparent; color: var(--fg-primary); border-color: var(--border-card); }
.btn-tertiary:hover { border-color: var(--fg-primary); }
.btn-link { background: transparent; color: var(--accent); padding: 0; height: auto; }
.btn-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.btn-lg { height: 44px; padding: 0 20px; font-size: 14px; }
/* ============ HERO ============ */
.hero { padding: 56px 0 24px; }
.hero-grid { display: grid; grid-template-columns: 1.25fr 1fr; gap: 48px; align-items: start; }
.hero h1 { font-size: 44px; line-height: 1.1; letter-spacing: -0.02em; font-weight: 600; color: var(--fg-primary); max-width: 620px; text-wrap: balance; }
.hero .deck { font-size: 16px; line-height: 1.55; color: var(--fg-secondary); margin-top: 16px; max-width: 580px; }
.hero .cta { margin-top: 24px; display: flex; gap: 12px; align-items: center; }
.hero .cta .note { color: var(--fg-tertiary); font-size: 12.5px; margin-left: 4px; }
/* hero stat panel — right side */
.hero-stats { background: var(--bg-card); border: 1px solid var(--border-card); border-radius: 12px; padding: 20px; }
.hero-stats h3 { font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--fg-secondary); font-weight: 500; margin-bottom: 12px; }
.hero-stat { display: flex; align-items: baseline; justify-content: space-between; padding: 12px 0; border-top: 1px solid var(--border-soft); }
.hero-stat:first-of-type { border-top: 0; padding-top: 0; }
.hero-stat:last-child { padding-bottom: 0; }
.hero-stat .label { font-size: 12.5px; color: var(--fg-secondary); }
.hero-stat .value { font-size: 18px; font-weight: 600; color: var(--fg-primary); letter-spacing: -0.01em; }
/* ============ HEADLINE BAR ============ */
.headline-bar {
background: var(--bg-headline); color: var(--fg-on-dark);
border-radius: 12px; padding: 16px 20px;
display: flex; align-items: center; gap: 16px;
margin-top: 24px;
}
.headline-bar .tag { font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; color: var(--accent-2); white-space: nowrap; }
.headline-bar .verdict { font-size: 15px; font-weight: 500; line-height: 1.4; color: var(--fg-on-dark); }
.headline-bar .verdict b { color: #fff; font-weight: 600; }
.headline-bar .caveat { margin-left: auto; font-size: 11.5px; color: var(--fg-on-dark-muted); white-space: nowrap; }
/* ============ SECTIONS ============ */
.section { background: var(--bg-card); border: 1px solid var(--border-card); border-radius: 12px; padding: 20px; margin-top: 24px; }
.section-head { display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.section-head .titles h2 { font-size: 18px; line-height: 1.25; font-weight: 600; letter-spacing: -0.01em; color: var(--fg-primary); }
.section-head .titles .sub { font-size: 12.5px; color: var(--fg-secondary); margin-top: 4px; }
.section-head .right { display: flex; gap: 8px; align-items: center; }
.btn-compact { height: 32px; padding: 0 12px; font-size: 12.5px; border-radius: 6px; }
/* ============ KPI ROW ============ */
.kpi-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-top: 24px; }
.kpi { background: var(--bg-card); border: 1px solid var(--border-card); border-radius: 12px; padding: 16px 18px; }
.kpi .label { font-size: 11px; letter-spacing: 0.04em; text-transform: uppercase; color: var(--fg-secondary); font-weight: 500; }
.kpi .value { font-size: 28px; line-height: 1.15; font-weight: 600; color: var(--fg-primary); letter-spacing: -0.015em; margin-top: 8px; }
.kpi .hint { font-size: 12.5px; color: var(--fg-secondary); margin-top: 6px; }
.kpi .delta { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; font-weight: 600; margin-top: 8px; padding: 2px 8px; border-radius: 4px; }
.kpi .delta.pos { color: var(--success); background: var(--success-soft); }
.kpi .delta.neg { color: var(--danger); background: var(--danger-soft); }
/* ============ PARADOX SECTION ============ */
.paradox { margin-top: 32px; }
.paradox-chart { display: grid; grid-template-columns: 220px 1fr; gap: 24px; align-items: stretch; }
.paradox-legend { padding-right: 16px; border-right: 1px solid var(--border-soft); }
.paradox-legend h3 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--fg-secondary); font-weight: 500; margin-bottom: 12px; }
.legend-row { display: flex; align-items: center; gap: 8px; padding: 8px 0; font-size: 13px; }
.legend-row .sw { width: 12px; height: 12px; border-radius: 3px; }
.legend-row .label { color: var(--fg-primary); font-weight: 500; }
.legend-row .meta { color: var(--fg-secondary); margin-left: auto; font-size: 12px; }
.paradox-rows { display: flex; flex-direction: column; gap: 8px; }
.paradox-row { display: grid; grid-template-columns: 140px 1fr 80px; align-items: center; gap: 16px; padding: 8px 0; }
.paradox-row .seg { font-size: 13px; font-weight: 500; color: var(--fg-primary); }
.paradox-row .bars { display: flex; flex-direction: column; gap: 4px; }
.bar { height: 14px; border-radius: 4px; position: relative; }
.bar .v { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); font-size: 10.5px; font-weight: 600; color: #fff; font-variant-numeric: tabular-nums; }
.bar.supply { background: var(--fg-tertiary); }
.bar.demand { background: var(--accent); }
.paradox-row .delta-chip { font-size: 12px; font-weight: 600; padding: 3px 8px; border-radius: 4px; text-align: center; font-variant-numeric: tabular-nums; }
.delta-chip.pos { color: var(--success); background: var(--success-soft); }
.delta-chip.neg { color: var(--danger); background: var(--danger-soft); }
/* ============ MODULES ============ */
.modules { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 24px; }
.module { background: var(--bg-card); border: 1px solid var(--border-card); border-radius: 12px; padding: 20px; display: flex; flex-direction: column; }
.module-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 12px; }
.module-head h3 { font-size: 16px; font-weight: 600; color: var(--fg-primary); }
.module-head .badge { font-size: 10.5px; letter-spacing: 0.04em; text-transform: uppercase; font-weight: 600; padding: 2px 8px; border-radius: 4px; color: var(--accent); background: var(--accent-soft); }
.module p { font-size: 13.5px; color: var(--fg-secondary); line-height: 1.5; margin-bottom: 16px; }
.module .preview { background: var(--bg-card-alt); border: 1px solid var(--border-soft); border-radius: 8px; padding: 12px; margin-bottom: 12px; }
.module .cta-row { display: flex; gap: 12px; align-items: center; margin-top: auto; }
/* mini preview shapes per module */
.preview-table { display: flex; flex-direction: column; gap: 6px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; }
.preview-table .row { display: grid; grid-template-columns: 1fr 56px 32px; gap: 8px; align-items: center; padding: 4px 0; border-top: 1px solid var(--border-soft); }
.preview-table .row:first-child { border-top: 0; color: var(--fg-secondary); font-size: 9.5px; letter-spacing: 0.06em; text-transform: uppercase; }
.preview-table .row .num { text-align: right; color: var(--fg-primary); font-weight: 600; }
.preview-table .row .num.pos { color: var(--success); }
.preview-table .row .num.neg { color: var(--danger); }
.preview-table .row .pill { font-size: 9.5px; padding: 2px 6px; border-radius: 4px; text-align: center; font-weight: 600; }
.preview-table .row .pill.hot { color: var(--danger); background: var(--danger-soft); }
.preview-table .row .pill.warm { color: var(--warn); background: var(--warn-soft); }
.preview-table .row .pill.cool { color: var(--success); background: var(--success-soft); }
.preview-map { position: relative; height: 132px; background: linear-gradient(180deg, #fafbfc 0%, #f4f6f9 100%); border-radius: 6px; overflow: hidden; }
.preview-map svg { width: 100%; height: 100%; display: block; }
.preview-feed { display: flex; flex-direction: column; gap: 8px; font-size: 11.5px; }
.preview-feed .row { display: grid; grid-template-columns: 14px 1fr 60px; gap: 8px; align-items: center; }
.preview-feed .row .dot { width: 8px; height: 8px; border-radius: 50%; }
.preview-feed .row .dot.b { background: var(--accent); }
.preview-feed .row .dot.s { background: var(--success); }
.preview-feed .row .dot.w { background: var(--warn); }
.preview-feed .row .dot.d { background: var(--danger); }
.preview-feed .row .who { color: var(--fg-primary); font-weight: 500; }
.preview-feed .row .meta { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 10px; color: var(--fg-tertiary); text-align: right; }
/* ============ PRICING ============ */
.pricing { display: grid; grid-template-columns: 1.2fr 1fr; gap: 24px; align-items: stretch; }
.price-card { background: var(--bg-card); border: 1px solid var(--accent); border-radius: 12px; padding: 24px; position: relative; }
.price-card.alt { border-color: var(--border-card); }
.price-card .tag { display: inline-block; font-size: 10.5px; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: #fff; background: var(--accent); padding: 3px 10px; border-radius: 4px; margin-bottom: 12px; }
.price-card.alt .tag { background: var(--bg-card-alt); color: var(--fg-secondary); border: 1px solid var(--border-card); }
.price-card h3 { font-size: 20px; font-weight: 600; color: var(--fg-primary); margin-bottom: 4px; letter-spacing: -0.01em; }
.price-card .sub { font-size: 13px; color: var(--fg-secondary); }
.price-card .num { display: flex; align-items: baseline; gap: 6px; margin: 16px 0; }
.price-card .num b { font-size: 32px; font-weight: 600; letter-spacing: -0.02em; color: var(--fg-primary); }
.price-card .num span { color: var(--fg-secondary); font-size: 14px; }
.price-card ul { list-style: none; padding: 0; margin: 16px 0 24px; }
.price-card li { font-size: 13px; color: var(--fg-primary); padding: 8px 0; border-top: 1px solid var(--border-soft); display: flex; align-items: center; gap: 8px; }
.price-card li:first-child { border-top: 0; }
.price-card li::before { content: ''; width: 14px; height: 14px; border-radius: 4px; background: var(--accent-soft); flex-shrink: 0; }
.price-card.alt li::before { background: var(--bg-card-alt); border: 1px solid var(--border-card); }
.price-card .meta { font-size: 12px; color: var(--fg-secondary); padding-top: 16px; border-top: 1px solid var(--border-soft); }
/* ============ FAQ ============ */
.faq { display: grid; grid-template-columns: 240px 1fr; gap: 32px; }
.faq h2 { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.faq .sub { font-size: 13px; color: var(--fg-secondary); margin-top: 8px; }
.faq-list { display: flex; flex-direction: column; }
.faq-item { border-top: 1px solid var(--border-card); padding: 16px 0; cursor: pointer; }
.faq-item:first-child { border-top: 0; padding-top: 0; }
.faq-item summary { font-size: 15px; font-weight: 500; color: var(--fg-primary); list-style: none; display: flex; justify-content: space-between; align-items: center; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: '+'; color: var(--fg-secondary); font-size: 20px; font-weight: 400; transition: transform .12s; }
.faq-item[open] summary::after { content: ''; }
.faq-item .a { font-size: 14px; color: var(--fg-secondary); margin-top: 12px; line-height: 1.55; max-width: 720px; }
/* ============ FOOTER ============ */
footer.site { border-top: 1px solid var(--border-card); padding: 32px 0 48px; margin-top: 48px; background: var(--bg-app); }
footer .row { display: flex; justify-content: space-between; align-items: flex-start; gap: 24px; }
footer .col h4 { font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--fg-secondary); margin-bottom: 8px; font-weight: 500; }
footer .col a { display: block; font-size: 13px; color: var(--fg-primary); padding: 4px 0; }
footer .col a:hover { color: var(--accent); }
footer .legal { margin-top: 24px; padding-top: 16px; border-top: 1px solid var(--border-soft); font-size: 12px; color: var(--fg-secondary); display: flex; justify-content: space-between; }
/* ============ SECTION-TITLES ABOVE ============ */
.section-title { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; margin: 48px 0 16px; padding-top: 16px; border-top: 1px solid var(--border-card); }
.section-title h2 { font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.section-title .sub { font-size: 13px; color: var(--fg-secondary); }
/* ============ utility ============ */
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; }
@media (max-width: 1080px) {
.hero-grid { grid-template-columns: 1fr; gap: 24px; }
.kpi-row { grid-template-columns: repeat(2, 1fr); }
.modules { grid-template-columns: 1fr; }
.pricing { grid-template-columns: 1fr; }
.faq { grid-template-columns: 1fr; }
.paradox-chart { grid-template-columns: 1fr; }
.paradox-legend { padding-right: 0; padding-bottom: 12px; border-right: 0; border-bottom: 1px solid var(--border-soft); }
}
</style>
</head>
<body>
<aside class="dev-nav" aria-label="Dev navigation">
<span class="dev-label">DEV · ТОЛЬКО ДЛЯ РАЗРАБОТКИ</span>
<nav class="dev-tabs" aria-label="WIP страницы">
<a href="landing.html" aria-current="page">лендинг</a>
<a href="analytics.html">/analytics</a>
<a href="site-finder.html">/recommend</a>
<a href="monitoring.html">/developers</a>
<span class="dev-sep"></span>
<a href="audit.html">audit&nbsp;(live)</a>
<a href="gendsgn-audit.html">audit&nbsp;(отчёт)</a>
</nav>
<span class="dev-hint">временная панель · скроется в print</span>
</aside>
<header class="nav">
<div class="wrap nav-inner">
<a href="#" class="brand"><span class="brand-mark"></span><span>gendsgn</span></a>
<nav class="nav-links" aria-label="Основная навигация">
<a href="#product">Продукт</a>
<a href="#paradox">Аналитика спроса</a>
<a href="#pricing">Пилот</a>
<a href="#faq">FAQ</a>
</nav>
<div class="nav-cta">
<a href="analytics.html" class="btn btn-tertiary">Demo аналитики →</a>
<a href="#pricing" class="btn btn-primary">Запросить пилот</a>
</div>
</div>
</header>
<main class="wrap">
<!-- ============ HERO ============ -->
<section class="hero">
<div class="hero-grid">
<div>
<h1>Цифры рынка перед тем, как заливать фундамент.</h1>
<p class="deck">Что строят на рынке и что на самом деле продаётся — по 6,83 млн ДДУ Росреестра, портфелю ДОМ.РФ и активным новостройкам Яндекс.Недвижимости. Свердловская область, обновление еженедельно.</p>
<div class="cta">
<a href="#pricing" class="btn btn-primary btn-lg">Запросить пилот</a>
<a href="analytics.html" class="btn btn-link">Открыть demo аналитики →</a>
</div>
<p class="cta" style="margin-top:16px;color:var(--fg-tertiary);font-size:12.5px;">3 из 3 пилотных мест открыто · старт пилота — 2 недели · фикс-цена 30 000 ₽/мес</p>
</div>
<aside class="hero-stats" aria-label="Покрытие данных">
<h3>Покрытие данных</h3>
<div class="hero-stat"><span class="label">ДДУ в индексе (Росреестр)</span><span class="value">6 832 411</span></div>
<div class="hero-stat"><span class="label">Объекты ДОМ.РФ в Свердловской</span><span class="value">1 482</span></div>
<div class="hero-stat"><span class="label">Девелоперы в leaderboard</span><span class="value">87</span></div>
<div class="hero-stat"><span class="label">Глубина истории</span><span class="value">14 мес</span></div>
<div class="hero-stat"><span class="label">Обновление</span><span class="value">7 дней</span></div>
</aside>
</div>
</section>
<!-- ============ HEADLINE BAR ============ -->
<div class="headline-bar" role="status">
<span class="tag">Вердикт квартала</span>
<p class="verdict">Дефицит средне-большого жилья 80+ м²: <b>37%</b> сделок Росреестра, но <b>11%</b> портфеля ДОМ.РФ. Окно сужается к <b>Q3 2026</b>.</p>
<span class="caveat">данные: ДОМ.РФ · Росреестр · март 2026</span>
</div>
<!-- ============ KPI ROW ============ -->
<div class="kpi-row">
<div class="kpi">
<div class="label">Объём строительства</div>
<div class="value">5,8 млн м²</div>
<div class="hint">Свердловская обл., активная фаза</div>
<span class="delta pos">↑ 4,1% YoY</span>
</div>
<div class="kpi">
<div class="label">Sold % (медиана)</div>
<div class="value">61,4 %</div>
<div class="hint">по объектам в продаже &gt; 6 мес</div>
<span class="delta neg">↓ 3,2 пп QoQ</span>
</div>
<div class="kpi">
<div class="label">Средняя цена</div>
<div class="value">186 тыс ₽</div>
<div class="hint">за м², первичка, март 2026</div>
<span class="delta pos">↑ 1,8% MoM</span>
</div>
<div class="kpi">
<div class="label">Активных новостроек</div>
<div class="value">347</div>
<div class="hint">в Яндекс.Недв · в открытой продаже</div>
<span class="delta pos">+12 за месяц</span>
</div>
</div>
<!-- ============ PARADOX SECTION ============ -->
<div class="section-title" id="paradox">
<div>
<h2>Парадокс портфеля: что строят vs что продаётся</h2>
<div class="sub">Доля каждого сегмента в активном портфеле ДОМ.РФ против доли в сделках Росреестра за 14 месяцев</div>
</div>
<a href="analytics.html" class="btn btn-link">Открыть в /analytics →</a>
</div>
<section class="section paradox">
<div class="paradox-chart">
<aside class="paradox-legend">
<h3>Условные обозначения</h3>
<div class="legend-row"><span class="sw" style="background:var(--fg-tertiary)"></span><span class="label">Портфель ДОМ.РФ</span><span class="meta">что строят</span></div>
<div class="legend-row"><span class="sw" style="background:var(--accent)"></span><span class="label">Сделки Росреестра</span><span class="meta">что покупают</span></div>
<div style="font-size:11.5px;color:var(--fg-secondary);margin-top:16px;line-height:1.5;">
Δ пп — разница между долей в сделках и долей в портфеле. Положительная — дефицит предложения, отрицательная — затоваривание.
</div>
</aside>
<div class="paradox-rows" role="table">
<div class="paradox-row">
<div class="seg">Студии до 30 м²</div>
<div class="bars">
<div class="bar supply" style="width:24%"><span class="v">24%</span></div>
<div class="bar demand" style="width:9%"><span class="v">9%</span></div>
</div>
<div class="delta-chip neg">15 пп</div>
</div>
<div class="paradox-row">
<div class="seg">1-комн. 3045 м²</div>
<div class="bars">
<div class="bar supply" style="width:31%"><span class="v">31%</span></div>
<div class="bar demand" style="width:24%"><span class="v">24%</span></div>
</div>
<div class="delta-chip neg">7 пп</div>
</div>
<div class="paradox-row">
<div class="seg">2-комн. 4565 м²</div>
<div class="bars">
<div class="bar supply" style="width:22%"><span class="v">22%</span></div>
<div class="bar demand" style="width:23%"><span class="v">23%</span></div>
</div>
<div class="delta-chip pos">+1 пп</div>
</div>
<div class="paradox-row">
<div class="seg">3-комн. 6585 м²</div>
<div class="bars">
<div class="bar supply" style="width:13%"><span class="v">13%</span></div>
<div class="bar demand" style="width:24%"><span class="v">24%</span></div>
</div>
<div class="delta-chip pos">+11 пп</div>
</div>
<div class="paradox-row">
<div class="seg">4+ комн. / 85+ м²</div>
<div class="bars">
<div class="bar supply" style="width:11%"><span class="v">11%</span></div>
<div class="bar demand" style="width:20%"><span class="v">20%</span></div>
</div>
<div class="delta-chip pos">+9 пп</div>
</div>
</div>
</div>
<div style="margin-top:16px;padding-top:16px;border-top:1px solid var(--border-soft);font-size:12.5px;color:var(--fg-secondary);">
Иллюстративные данные пилотной выборки. В продуктовой версии — разрез по 17 районам области, классу жилья и году ввода. Источник: ДОМ.РФ (портфель в активной фазе строительства), Росреестр (сделки ДДУ за 14 мес).
</div>
</section>
<!-- ============ MODULES ============ -->
<div class="section-title" id="product">
<div>
<h2>Три рабочих модуля</h2>
<div class="sub">Не «features», а конкретные вопросы, на которые финдиректор девелопера ищет ответ</div>
</div>
</div>
<div class="modules">
<article class="module">
<div class="module-head">
<h3>Аналитика спроса</h3>
<span class="badge">/analytics</span>
</div>
<p>«В каких районах и сегментах сделки опережают предложение?» Разбивка sold % по комнатности, классу, году ввода. Бенчмарк против топ-15 девелоперов области.</p>
<div class="preview">
<div class="preview-table" aria-hidden="true">
<div class="row"><span>район / сегмент</span><span class="num">Δ пп</span><span class="pill">статус</span></div>
<div class="row"><span>Академический · 3к</span><span class="num pos">+14</span><span class="pill hot">дефицит</span></div>
<div class="row"><span>ВИЗ · студии</span><span class="num neg">12</span><span class="pill cool">избыток</span></div>
<div class="row"><span>Уралмаш · 2к</span><span class="num pos">+3</span><span class="pill warm">баланс</span></div>
</div>
</div>
<div class="cta-row">
<a href="analytics.html" class="btn btn-tertiary btn-compact">Открыть demo</a>
<a href="#pricing" class="btn btn-link">в пилот →</a>
</div>
</article>
<article class="module">
<div class="module-head">
<h3>Рекомендатор площадки</h3>
<span class="badge">/recommend</span>
</div>
<p>«Какую квартирографию закладывать на участке в Академическом, чтобы выйти за 22 месяца?» Mix по комнатности, прогноз срока 80 % продаж, расчёт выручки.</p>
<div class="preview">
<div class="preview-map" aria-hidden="true">
<svg viewBox="0 0 320 132" preserveAspectRatio="xMidYMid slice">
<defs>
<linearGradient id="lg1" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#cfd6e0"/><stop offset="1" stop-color="#dde3eb"/></linearGradient>
</defs>
<rect width="320" height="132" fill="url(#lg1)"/>
<path d="M0,80 Q80,60 160,90 T320,70" stroke="#0EA5E9" stroke-width="2" fill="none" stroke-dasharray="0"/>
<path d="M0,40 Q120,30 200,50 T320,40" stroke="#1D4ED8" stroke-width="2.5" fill="none"/>
<circle cx="60" cy="50" r="4" fill="#0A7A3A"/>
<circle cx="120" cy="48" r="4" fill="#0A7A3A"/>
<circle cx="180" cy="60" r="4" fill="#F2994A"/>
<circle cx="220" cy="62" r="4" fill="#F2994A"/>
<circle cx="260" cy="58" r="4" fill="#B3261E"/>
<text x="6" y="14" font-family="ui-monospace,Menlo" font-size="8" fill="#5B6066">srok %</text>
</svg>
</div>
</div>
<div class="cta-row">
<a href="site-finder.html" class="btn btn-tertiary btn-compact">Открыть demo</a>
<a href="#pricing" class="btn btn-link">в пилот →</a>
</div>
</article>
<article class="module">
<div class="module-head">
<h3>Топ-15 девелоперов</h3>
<span class="badge">/developers</span>
</div>
<p>«Кто продаёт быстрее в моём районе и за счёт чего?» Velocity-карта по площади и Δ sold %, фильтр по классу. Drill-down до объекта.</p>
<div class="preview">
<div class="preview-feed" aria-hidden="true">
<div class="row"><span class="dot s"></span><span class="who">PRINZIP</span><span class="meta">sold 74 %</span></div>
<div class="row"><span class="dot b"></span><span class="who">Брусника</span><span class="meta">sold 68 %</span></div>
<div class="row"><span class="dot w"></span><span class="who">Атомстройком.</span><span class="meta">sold 52 %</span></div>
<div class="row"><span class="dot d"></span><span class="who">КОРТРОС</span><span class="meta">sold 41 %</span></div>
</div>
</div>
<div class="cta-row">
<a href="monitoring.html" class="btn btn-tertiary btn-compact">Открыть demo</a>
<a href="#pricing" class="btn btn-link">в пилот →</a>
</div>
</article>
</div>
<!-- ============ PRICING ============ -->
<div class="section-title" id="pricing">
<div>
<h2>Пилот — 30 000 ₽ в месяц</h2>
<div class="sub">Один тариф, без апсейлов. 3 из 3 пилотных мест открыто, ввод данных за 2 недели.</div>
</div>
</div>
<div class="pricing">
<div class="price-card">
<span class="tag">Пилот · 6 месяцев</span>
<h3>gendsgn для одного девелопера</h3>
<p class="sub">Полный доступ к трём модулям. Свердловская область как первый регион, остальные — по запросу.</p>
<div class="num"><b>30 000 ₽</b><span>/ мес · фикс</span></div>
<ul>
<li>Аналитика спроса по 17 районам области</li>
<li>Рекомендатор площадки с прогнозом срока продаж</li>
<li>Бенчмарк против топ-15 девелоперов</li>
<li>Еженедельный апдейт данных Росреестра</li>
<li>Экспорт в Excel и CSV для финмодели</li>
<li>Запрос новых разрезов от пилотного клиента — приоритет</li>
</ul>
<a href="#" class="btn btn-primary btn-lg" style="width:100%;justify-content:center;">Запросить пилот</a>
<div class="meta" style="margin-top:16px;">Контакт менеджера — Алексей Демидов · al@gendsgn.ru</div>
</div>
<div class="price-card alt">
<span class="tag">После пилота</span>
<h3>Региональная лицензия</h3>
<p class="sub">Когда пилот закроется и продукт перейдёт к платным клиентам.</p>
<div class="num"><b>от 120 000 ₽</b><span>/ мес · region-pack</span></div>
<ul>
<li>Подключение дополнительных регионов</li>
<li>API для отдела финансового планирования</li>
<li>Бенчмарк против выбранных конкурентов</li>
<li>Кастомные разрезы и custom alerting</li>
</ul>
<a href="#" class="btn btn-tertiary btn-lg" style="width:100%;justify-content:center;">Запросить расчёт</a>
<div class="meta" style="margin-top:16px;">Расчёт индивидуально, после квалификации пилота</div>
</div>
</div>
<div style="margin-top:24px;padding:16px;background:var(--warn-soft);border:1px solid var(--warn);border-radius:8px;font-size:13px;color:var(--fg-primary);">
<b style="color:var(--warn);">Честный дисклеймер:</b> мы pre-revenue. Сайт показывает реальный продукт в работе на ваших данных. До первой ARR-метрики команда живёт за счёт основателей, и пилотных клиентов мы выбираем сами, а не наоборот.
</div>
<!-- ============ FAQ ============ -->
<div class="section-title" id="faq">
<div>
<h2>Частые возражения</h2>
<div class="sub">Что обычно спрашивают финдиректора прежде, чем согласиться на пилот</div>
</div>
</div>
<div class="faq">
<div>
<p style="font-size:13px;color:var(--fg-secondary);">Если ваше возражение не разобрано — напишите на <a href="mailto:al@gendsgn.ru" style="color:var(--accent)">al@gendsgn.ru</a>, ответим за 1 рабочий день.</p>
</div>
<div class="faq-list">
<details class="faq-item">
<summary>Чем вы отличаетесь от собственной BI-команды?</summary>
<div class="a">Мы не делаем дашборд под отдел — мы продаём готовый рыночный разрез по 6,83 млн ДДУ и портфелю ДОМ.РФ, который ваша BI собирала бы сама 46 месяцев. Внутренняя команда нужна, чтобы интерпретировать наши цифры в контексте конкретного проекта.</div>
</details>
<details class="faq-item">
<summary>Откуда у вас данные Росреестра и ДОМ.РФ?</summary>
<div class="a">ДОМ.РФ — открытый портфель новостроек. Росреестр — публичные ДДУ через выписки ЕГРН и партнёрские интеграции (без серых источников). Яндекс.Недвижимость — публичный листинг активных объектов в продаже.</div>
</details>
<details class="faq-item">
<summary>Что входит в «обновление 7 дней»?</summary>
<div class="a">Раз в неделю — пересчёт sold %, добавление новых ДДУ, обновление цен по активным объектам. Раз в месяц — пересмотр квартирографии и портфеля ДОМ.РФ. Любое окно &lt; 7 дней — кешируем предыдущий снимок и помечаем «stale».</div>
</details>
<details class="faq-item">
<summary>Почему только Свердловская область?</summary>
<div class="a">Мы pre-revenue и заточили пайплайн под один регион, чтобы доказать ROI за 6 месяцев пилота. Добавление второго региона — около 6 недель работы на наш бэк. Если в пилот зайдёт девелопер другой области — мы её добавим в очередь.</div>
</details>
<details class="faq-item">
<summary>Можно ли использовать данные в внутреннем финмоделировании?</summary>
<div class="a">Да. Все ключевые разрезы экспортируются в Excel и CSV (sold %, цены, mix). Лицензия пилота позволяет использовать выгрузки во внутреннем финмодуле без отдельного согласования.</div>
</details>
<details class="faq-item">
<summary>Что будет после 6 месяцев пилота?</summary>
<div class="a">Совместный отчёт по конкретным cases (где наши рекомендации совпали со сделкой, где разошлись), и переход на регулярную лицензию либо корректное расставание. Никаких автоматических продлений с отдельным счётом.</div>
</details>
</div>
</div>
</main>
<footer class="site">
<div class="wrap">
<div class="row">
<div class="col" style="max-width:280px;">
<div class="brand" style="margin-bottom:12px;"><span class="brand-mark"></span><span>gendsgn</span></div>
<p style="font-size:13px;color:var(--fg-secondary);line-height:1.55;">Рыночная аналитика для застройщиков. Свердловская область, далее — по запросу пилотных клиентов.</p>
</div>
<div class="col">
<h4>Продукт</h4>
<a href="analytics.html">Аналитика спроса</a>
<a href="site-finder.html">Рекомендатор площадки</a>
<a href="monitoring.html">Топ-15 девелоперов</a>
</div>
<div class="col">
<h4>Команда</h4>
<a href="#">О нас</a>
<a href="#">Методология</a>
<a href="#">Источники данных</a>
</div>
<div class="col">
<h4>Контакты</h4>
<a href="mailto:al@gendsgn.ru">al@gendsgn.ru</a>
<a href="https://t.me/gendsgn">Telegram</a>
<a href="#">+7 343 000 00 00</a>
</div>
</div>
<div class="legal">
<span>© 2026 gendsgn · Екатеринбург, Свердловская область</span>
<span>Данные: ДОМ.РФ, Росреестр, Яндекс.Недвижимость · обновление еженедельно</span>
</div>
</div>
</footer>
</body>
</html>

518
preview/monitoring.html Normal file
View file

@ -0,0 +1,518 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>/analytics/developers — Топ-15 девелоперов · gendsgn</title>
<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:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
--bg-app:#F6F7F9; --bg-card:#FFFFFF; --bg-card-alt:#FAFBFC; --bg-headline:#0F172A;
--border-soft:#EEF0F3; --border-card:#E6E8EC; --border-strong:#D1D5DB;
--fg-primary:#111111; --fg-secondary:#5B6066; --fg-tertiary:#73767E;
--fg-on-dark:#E2E8F0; --fg-on-dark-muted:#94A3B8;
--accent:#1D4ED8; --accent-hover:#1E40AF; --accent-soft:#DBEAFE; --accent-2:#F2994A;
--success:#0A7A3A; --success-soft:#DCFCE7;
--warn:#9A6700; --warn-soft:#FEF3C7;
--danger:#B3261E; --danger-soft:#FEE2E2;
--viz-1:#1D4ED8; --viz-2:#0EA5E9; --viz-3:#14B8A6; --viz-4:#F59E0B; --viz-5:#8B5CF6;
--font-body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
}
* { box-sizing:border-box; margin:0; padding:0; }
html { background:var(--bg-app); }
body { font-family:var(--font-body); font-size:14px; line-height:1.5; color:var(--fg-primary); font-variant-numeric:tabular-nums; font-feature-settings:"tnum"; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; }
a { color:inherit; text-decoration:none; }
button { font:inherit; cursor:pointer; }
.mono { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.wrap { max-width:1440px; margin:0 auto; padding:0 24px; }
.dev-nav { position:sticky; top:0; z-index:100; display:flex; align-items:center; gap:18px; height:38px; padding:0 18px; background:#0b0f1a; color:rgba(255,255,255,0.92); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11.5px; letter-spacing:0.04em; border-bottom:1px solid rgba(255,255,255,0.08); }
.dev-nav .dev-label { display:inline-flex; align-items:center; gap:8px; color:#fbbf24; font-weight:600; letter-spacing:0.18em; text-transform:uppercase; white-space:nowrap; }
.dev-nav .dev-label::before { content:''; width:6px; height:6px; border-radius:50%; background:#fbbf24; box-shadow:0 0 0 3px rgba(251,191,36,0.22); }
.dev-nav .dev-tabs { display:inline-flex; gap:2px; align-items:center; }
.dev-nav .dev-sep { width:1px; height:16px; background:rgba(255,255,255,0.16); margin:0 6px; }
.dev-nav .dev-tabs a { padding:5px 11px; border-radius:5px; color:rgba(255,255,255,0.62); transition:background .12s,color .12s; }
.dev-nav .dev-tabs a:hover { color:#fff; background:rgba(255,255,255,0.08); }
.dev-nav .dev-tabs a[aria-current="page"] { color:#0b0f1a; background:#fbbf24; font-weight:600; }
.dev-nav .dev-hint { margin-left:auto; color:rgba(255,255,255,0.36); white-space:nowrap; }
@media print { .dev-nav { display:none !important; } }
.topbar { background:var(--bg-card); border-bottom:1px solid var(--border-card); }
.topbar-inner { display:flex; align-items:center; justify-content:space-between; height:56px; }
.brand { display:inline-flex; align-items:center; gap:8px; font-weight:700; font-size:15px; color:var(--fg-primary); letter-spacing:-0.01em; }
.brand-mark { width:22px; height:22px; border-radius:6px; background:var(--accent); display:grid; place-items:center; color:#fff; font-size:11px; font-weight:700; }
.brand-mark::before { content:'gd'; }
.topbar-user { display:flex; align-items:center; gap:12px; font-size:13px; color:var(--fg-secondary); }
.topbar-user .who { display:flex; align-items:center; gap:8px; padding:6px 12px; border-radius:6px; background:var(--bg-card-alt); border:1px solid var(--border-card); }
.topbar-user .avatar { width:22px; height:22px; border-radius:50%; background:var(--accent-soft); color:var(--accent); display:grid; place-items:center; font-weight:600; font-size:10px; }
.crumbs { display:flex; gap:8px; align-items:center; padding-top:16px; font-size:12.5px; color:var(--fg-secondary); }
.crumbs a { color:var(--fg-secondary); }
.crumbs a:hover { color:var(--accent); text-decoration:underline; text-underline-offset:3px; }
.crumbs .sep { color:var(--fg-tertiary); }
.crumbs .last { color:var(--fg-primary); }
.page-head { padding:8px 0 16px; display:flex; justify-content:space-between; align-items:flex-end; gap:24px; }
.page-head h1 { font-size:22px; line-height:1.25; font-weight:600; letter-spacing:-0.01em; }
.page-head .sub { font-size:13px; color:var(--fg-secondary); margin-top:4px; }
.page-head .right { display:flex; gap:8px; align-items:center; }
.a-tabs { display:flex; gap:2px; border-bottom:1px solid var(--border-card); margin-bottom:16px; overflow-x:auto; }
.a-tabs a { padding:10px 14px; font-size:13px; font-weight:500; color:var(--fg-secondary); border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; }
.a-tabs a:hover { color:var(--fg-primary); }
.a-tabs a[aria-current="page"] { color:var(--accent); border-bottom-color:var(--accent); font-weight:600; }
.kpi-row { display:grid; grid-template-columns:repeat(4,1fr); gap:12px; margin-bottom:24px; }
.kpi { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:16px 18px; }
.kpi .label { font-size:11px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; }
.kpi .value { font-size:28px; line-height:1.15; font-weight:600; color:var(--fg-primary); letter-spacing:-0.015em; margin-top:8px; }
.kpi .value small { font-size:14px; color:var(--fg-secondary); font-weight:500; margin-left:4px; }
.kpi .hint { font-size:12.5px; color:var(--fg-secondary); margin-top:6px; }
.kpi .delta { display:inline-flex; align-items:center; gap:4px; font-size:12px; font-weight:600; margin-top:8px; padding:2px 8px; border-radius:4px; font-variant-numeric:tabular-nums; }
.kpi .delta.pos { color:var(--success); background:var(--success-soft); }
.kpi .delta.neg { color:var(--danger); background:var(--danger-soft); }
.kpi.who-kpi .value { font-size:20px; line-height:1.2; }
.kpi.who-kpi .badge-row { display:flex; gap:4px; margin-top:8px; }
.section { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:20px; margin-bottom:24px; }
.section-head { display:flex; align-items:flex-end; justify-content:space-between; gap:16px; margin-bottom:16px; }
.section-head h2 { font-size:18px; line-height:1.25; font-weight:600; letter-spacing:-0.01em; }
.section-head .sub { font-size:12.5px; color:var(--fg-secondary); margin-top:4px; }
.section-head .right { display:flex; gap:8px; align-items:center; }
.btn { display:inline-flex; align-items:center; gap:6px; height:36px; padding:0 16px; border-radius:8px; font-weight:500; font-size:13.5px; border:1px solid transparent; transition:all .12s; }
.btn-primary { background:var(--accent); color:#fff; border-color:var(--accent); }
.btn-primary:hover { background:var(--accent-hover); border-color:var(--accent-hover); }
.btn-secondary { background:var(--accent-2); color:#fff; border-color:var(--accent-2); }
.btn-secondary:hover { filter:brightness(0.94); }
.btn-tertiary { background:transparent; color:var(--fg-primary); border-color:var(--border-card); }
.btn-tertiary:hover { border-color:var(--fg-primary); }
.btn-compact { height:32px; padding:0 12px; font-size:12.5px; border-radius:6px; }
.chip { display:inline-flex; align-items:center; gap:6px; height:28px; padding:0 12px; border-radius:14px; font-size:12px; font-weight:500; color:var(--fg-secondary); background:transparent; border:1px solid var(--border-card); transition:all .12s; cursor:pointer; }
.chip:hover { color:var(--fg-primary); border-color:var(--fg-secondary); }
.chip[aria-pressed="true"] { color:var(--accent); background:var(--accent-soft); border-color:var(--accent-soft); }
.badge { display:inline-flex; align-items:center; gap:4px; font-size:11px; font-weight:600; padding:2px 8px; border-radius:4px; }
.badge.success { color:var(--success); background:var(--success-soft); }
.badge.warn { color:var(--warn); background:var(--warn-soft); }
.badge.danger { color:var(--danger); background:var(--danger-soft); }
/* ============ SEARCH ============ */
.search { position:relative; }
.search input { height:32px; padding:0 12px 0 32px; border:1px solid var(--border-strong); border-radius:6px; background:var(--bg-card); font:inherit; font-size:13px; color:var(--fg-primary); width:240px; }
.search input:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.search::before { content:''; position:absolute; left:10px; top:50%; transform:translateY(-50%); width:14px; height:14px; border:1.5px solid var(--fg-tertiary); border-radius:50%; box-shadow:5px 5px 0 -3px var(--fg-tertiary); pointer-events:none; }
/* ============ LEADERBOARD TABLE ============ */
.lb-wrap { overflow-x:auto; }
.lb { width:100%; border-collapse:collapse; min-width:920px; }
.lb th { font-size:10px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; text-align:left; padding:10px 8px; border-bottom:1px solid var(--border-card); background:var(--bg-card-alt); white-space:nowrap; }
.lb th:not(:nth-child(-n+2)) { text-align:right; }
.lb td { font-size:13px; padding:12px 8px; border-bottom:1px solid var(--border-soft); color:var(--fg-primary); }
.lb td:not(:nth-child(-n+2)) { text-align:right; font-variant-numeric:tabular-nums; }
.lb tr:last-child td { border-bottom:0; }
.lb tr:hover { background:var(--bg-card-alt); cursor:pointer; }
.lb tr.selected { background:var(--accent-soft); }
.lb tr.selected td { color:var(--fg-primary); }
.lb tr.selected td:first-child { color:var(--accent); font-weight:600; }
.lb .rank { color:var(--fg-tertiary); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11px; width:32px; }
.lb .name { color:var(--fg-primary); font-weight:500; }
.lb .name .sub { font-size:11px; color:var(--fg-secondary); font-weight:400; margin-top:2px; }
.lb .pill { display:inline-flex; align-items:center; padding:2px 8px; border-radius:4px; font-size:11px; font-weight:600; font-variant-numeric:tabular-nums; }
.lb .pill.pos { color:var(--success); background:var(--success-soft); }
.lb .pill.neg { color:var(--danger); background:var(--danger-soft); }
.lb .pill.flat { color:var(--fg-secondary); background:var(--bg-card-alt); }
.lb-foot { padding-top:12px; display:flex; justify-content:space-between; align-items:center; font-size:12.5px; color:var(--fg-secondary); }
/* ============ VELOCITY SCATTER ============ */
.scatter-wrap { position:relative; height:380px; padding:16px 0 32px 48px; }
.scatter-wrap svg { width:100%; height:100%; display:block; }
.axis-x-label { position:absolute; bottom:4px; left:50%; transform:translateX(-50%); font-size:11px; color:var(--fg-secondary); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.axis-y-label { position:absolute; top:50%; left:-8px; transform:translateY(-50%) rotate(-90deg); transform-origin:center; font-size:11px; color:var(--fg-secondary); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; white-space:nowrap; }
/* ============ COMPARE CHART ============ */
.compare-wrap { position:relative; height:280px; padding:8px 0 24px 48px; }
.compare-wrap svg { width:100%; height:100%; display:block; }
.legend-row { display:flex; gap:24px; padding-top:8px; }
.legend-row .leg { display:inline-flex; align-items:center; gap:8px; font-size:12.5px; color:var(--fg-primary); }
.legend-row .leg .sw { width:14px; height:8px; border-radius:2px; }
.legend-row .leg .meta { color:var(--fg-secondary); margin-left:4px; }
@media (max-width:1100px) {
.kpi-row { grid-template-columns:repeat(2,1fr); }
}
</style>
</head>
<body>
<aside class="dev-nav" aria-label="Dev navigation">
<span class="dev-label">DEV · ТОЛЬКО ДЛЯ РАЗРАБОТКИ</span>
<nav class="dev-tabs" aria-label="WIP страницы">
<a href="landing.html">лендинг</a>
<a href="analytics.html">/analytics</a>
<a href="site-finder.html">/recommend</a>
<a href="monitoring.html" aria-current="page">/developers</a>
<span class="dev-sep"></span>
<a href="audit.html">audit&nbsp;(live)</a>
<a href="gendsgn-audit.html">audit&nbsp;(отчёт)</a>
</nav>
<span class="dev-hint">временная панель · скроется в print</span>
</aside>
<header class="topbar">
<div class="wrap topbar-inner">
<div style="display:flex;align-items:center;gap:24px;">
<a href="landing.html" class="brand"><span class="brand-mark"></span><span>gendsgn</span></a>
</div>
<div class="topbar-user">
<span style="font-size:12px;color:var(--fg-tertiary);">Свердловская обл. · 2025-Q1</span>
<div class="who"><div class="avatar">AD</div>Алексей · PRINZIP (demo)</div>
</div>
</div>
</header>
<main class="wrap">
<nav class="crumbs" aria-label="Breadcrumb">
<a href="landing.html">gendsgn</a>
<span class="sep">/</span>
<a href="analytics.html">analytics</a>
<span class="sep">/</span>
<span class="last">developers — топ-15 девелоперов</span>
</nav>
<div class="page-head">
<div>
<h1>Топ-15 девелоперов Свердловской области</h1>
<div class="sub">Выбран: <b>PRINZIP</b> · кликните на строку leaderboard, чтобы сравнить с другим девелопером</div>
</div>
<div class="right">
<button class="btn btn-tertiary btn-compact">Снимок PDF</button>
</div>
</div>
<nav class="a-tabs" aria-label="Разделы аналитики">
<a href="analytics.html">Свердл рынок</a>
<a href="site-finder.html">Рекомендатор</a>
<a href="monitoring.html" aria-current="page">Девелоперы</a>
<a href="#">PRINZIP · профиль</a>
<a href="#">Объекты</a>
</nav>
<!-- 4 KPI for selected dev -->
<div class="kpi-row">
<div class="kpi who-kpi">
<div class="label">Девелопер</div>
<div class="value">PRINZIP</div>
<div class="hint">Екатеринбург · с 2007 г.</div>
<div class="badge-row">
<span class="badge success">комфорт</span>
<span class="badge warn">бизнес</span>
</div>
</div>
<div class="kpi">
<div class="label">Объём в Свердл</div>
<div class="value">412<small>тыс м²</small></div>
<div class="hint">14 ЖК в активной фазе</div>
<span class="delta pos">↑ +28 тыс vs Q4 2025</span>
</div>
<div class="kpi">
<div class="label">Sold % (медиана)</div>
<div class="value">74<small>%</small></div>
<div class="hint">по 14 ЖК в продаже</div>
<span class="delta pos">+13 пп vs рынок (61 %)</span>
</div>
<div class="kpi">
<div class="label">Средний метраж</div>
<div class="value">58<small>м²</small></div>
<div class="hint">взвешенно по лотности</div>
<span class="delta neg">9 м² vs рынок (67 м²)</span>
</div>
</div>
<!-- LEADERBOARD -->
<section class="section">
<div class="section-head">
<div>
<h2>Leaderboard — топ-15 по объёму</h2>
<div class="sub">Sticky первая колонка при scroll · клик по строке → drawer с профилем девелопера</div>
</div>
<div class="right">
<div class="search"><input type="text" placeholder="Поиск девелопера…" /></div>
<button class="chip" aria-pressed="true">все классы</button>
<button class="chip">комфорт</button>
<button class="chip">бизнес</button>
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<div class="lb-wrap">
<table class="lb">
<thead>
<tr>
<th>#</th>
<th>Девелопер</th>
<th>Объём, тыс м²</th>
<th>ЖК</th>
<th>Sold %</th>
<th>Δ 14 мес</th>
<th>Ср. цена ₽/м²</th>
<th>Ср. метраж</th>
<th>Топ-район</th>
</tr>
</thead>
<tbody>
<tr class="selected"><td class="rank">01</td><td class="name">PRINZIP<div class="sub">14 ЖК · комфорт+бизнес</div></td><td>412</td><td>14</td><td>74 %</td><td><span class="pill pos">+8,2 пп</span></td><td>173</td><td>58</td><td>Академический</td></tr>
<tr><td class="rank">02</td><td class="name">Брусника<div class="sub">11 ЖК · комфорт+бизнес</div></td><td>368</td><td>11</td><td>71 %</td><td><span class="pill pos">+5,1 пп</span></td><td>198</td><td>61</td><td>Центр</td></tr>
<tr><td class="rank">03</td><td class="name">Атомстройкомплекс<div class="sub">9 ЖК · комфорт</div></td><td>342</td><td>9</td><td>64 %</td><td><span class="pill pos">+2,8 пп</span></td><td>156</td><td>54</td><td>ВИЗ</td></tr>
<tr><td class="rank">04</td><td class="name">Форум-групп<div class="sub">8 ЖК · комфорт+бизнес</div></td><td>298</td><td>8</td><td>62 %</td><td><span class="pill flat">+0,4 пп</span></td><td>182</td><td>63</td><td>Юго-Запад</td></tr>
<tr><td class="rank">05</td><td class="name">КОРТРОС<div class="sub">6 ЖК · бизнес+премиум</div></td><td>284</td><td>6</td><td>54 %</td><td><span class="pill neg">3,2 пп</span></td><td>224</td><td>72</td><td>Пионерский</td></tr>
<tr><td class="rank">06</td><td class="name">Атлас Девелопмент<div class="sub">7 ЖК · комфорт</div></td><td>241</td><td>7</td><td>52 %</td><td><span class="pill neg">4,8 пп</span></td><td>141</td><td>52</td><td>Уралмаш</td></tr>
<tr><td class="rank">07</td><td class="name">Эталон<div class="sub">5 ЖК · бизнес</div></td><td>198</td><td>5</td><td>48 %</td><td><span class="pill neg">6,1 пп</span></td><td>167</td><td>59</td><td>Центр</td></tr>
<tr><td class="rank">08</td><td class="name">Унистрой<div class="sub">5 ЖК · комфорт</div></td><td>182</td><td>5</td><td>67 %</td><td><span class="pill pos">+3,4 пп</span></td><td>148</td><td>55</td><td>Уктус</td></tr>
<tr><td class="rank">09</td><td class="name">Атмосфера<div class="sub">4 ЖК · комфорт</div></td><td>156</td><td>4</td><td>69 %</td><td><span class="pill pos">+4,1 пп</span></td><td>152</td><td>57</td><td>Пионерский</td></tr>
<tr><td class="rank">10</td><td class="name">Эфес<div class="sub">4 ЖК · бизнес+премиум</div></td><td>142</td><td>4</td><td>58 %</td><td><span class="pill flat">+0,8 пп</span></td><td>211</td><td>76</td><td>Центр</td></tr>
<tr><td class="rank">11</td><td class="name">Семь<div class="sub">3 ЖК · комфорт</div></td><td>128</td><td>3</td><td>72 %</td><td><span class="pill pos">+6,7 пп</span></td><td>167</td><td>56</td><td>ВИЗ</td></tr>
<tr><td class="rank">12</td><td class="name">Гринстрой<div class="sub">3 ЖК · комфорт</div></td><td>116</td><td>3</td><td>49 %</td><td><span class="pill neg">5,4 пп</span></td><td>134</td><td>51</td><td>Сортировка</td></tr>
<tr><td class="rank">13</td><td class="name">Лидер<div class="sub">3 ЖК · комфорт</div></td><td>104</td><td>3</td><td>61 %</td><td><span class="pill pos">+1,2 пп</span></td><td>158</td><td>54</td><td>Уралмаш</td></tr>
<tr><td class="rank">14</td><td class="name">Гранд<div class="sub">3 ЖК · бизнес</div></td><td>96</td><td>3</td><td>44 %</td><td><span class="pill neg">8,1 пп</span></td><td>189</td><td>68</td><td>Юго-Запад</td></tr>
<tr><td class="rank">15</td><td class="name">УГМК-Девел.<div class="sub">2 ЖК · бизнес+премиум</div></td><td>84</td><td>2</td><td>56 %</td><td><span class="pill flat">+0,2 пп</span></td><td>231</td><td>74</td><td>Верх. Пышма</td></tr>
</tbody>
</table>
</div>
<div class="lb-foot">
<span>Показано 15 из 87 девелоперов в выборке. Порог — &gt; 20 тыс м² в активной фазе.</span>
<a href="#" style="color:var(--accent);font-weight:500;">Показать все 87 →</a>
</div>
</section>
<!-- VELOCITY SCATTER -->
<section class="section">
<div class="section-head">
<div>
<h2>Velocity-карта — объём против Δ sold %</h2>
<div class="sub">Кто продаёт быстрее в своём масштабе · ось X — тыс. м² в активной фазе · ось Y — Δ sold % за 14 мес</div>
</div>
<div class="right">
<button class="chip" aria-pressed="true">все классы</button>
<button class="chip">комфорт</button>
<button class="chip">бизнес+премиум</button>
<button class="btn btn-secondary btn-compact">Export PNG ⤓</button>
</div>
</div>
<div class="scatter-wrap">
<svg viewBox="0 0 1000 380" preserveAspectRatio="xMidYMid meet">
<!-- grid -->
<g stroke="#EEF0F3" stroke-width="1">
<line x1="0" y1="60" x2="1000" y2="60"/>
<line x1="0" y1="120" x2="1000" y2="120"/>
<line x1="0" y1="190" x2="1000" y2="190"/>
<line x1="0" y1="260" x2="1000" y2="260"/>
<line x1="0" y1="320" x2="1000" y2="320"/>
<line x1="200" y1="0" x2="200" y2="380" stroke-dasharray="2,4"/>
<line x1="400" y1="0" x2="400" y2="380" stroke-dasharray="2,4"/>
<line x1="600" y1="0" x2="600" y2="380" stroke-dasharray="2,4"/>
<line x1="800" y1="0" x2="800" y2="380" stroke-dasharray="2,4"/>
</g>
<!-- zero line -->
<line x1="0" y1="190" x2="1000" y2="190" stroke="#5B6066" stroke-width="1.5"/>
<text x="6" y="184" font-family="ui-monospace,Menlo" font-size="10" fill="#5B6066">0 пп — рынок</text>
<!-- quadrant labels -->
<text x="990" y="36" text-anchor="end" font-family="ui-monospace,Menlo" font-size="10" fill="#0A7A3A" font-weight="600">быстрее рынка</text>
<text x="990" y="360" text-anchor="end" font-family="ui-monospace,Menlo" font-size="10" fill="#B3261E" font-weight="600">медленнее рынка</text>
<!-- y axis labels -->
<g font-family="ui-monospace,Menlo" font-size="10" fill="#73767E">
<text x="-4" y="64" text-anchor="end">+10</text>
<text x="-4" y="124" text-anchor="end">+5</text>
<text x="-4" y="194" text-anchor="end">0</text>
<text x="-4" y="264" text-anchor="end">5</text>
<text x="-4" y="324" text-anchor="end">10</text>
</g>
<!-- x axis labels -->
<g font-family="ui-monospace,Menlo" font-size="10" fill="#73767E">
<text x="0" y="376">0</text>
<text x="200" y="376" text-anchor="middle">100</text>
<text x="400" y="376" text-anchor="middle">200</text>
<text x="600" y="376" text-anchor="middle">300</text>
<text x="800" y="376" text-anchor="middle">400</text>
<text x="998" y="376" text-anchor="end">500</text>
</g>
<!-- dots -->
<g>
<!-- PRINZIP (focused) -->
<circle cx="824" cy="92" r="14" fill="#1D4ED8" opacity="0.18"/>
<circle cx="824" cy="92" r="8" fill="#1D4ED8" stroke="#fff" stroke-width="2"/>
<text x="838" y="96" font-family="Inter" font-size="12" font-weight="600" fill="#1D4ED8">PRINZIP · +8,2</text>
<circle cx="736" cy="129" r="7" fill="#0EA5E9" stroke="#fff" stroke-width="2"/>
<text x="748" y="133" font-family="Inter" font-size="11" fill="#5B6066">Брусника · +5,1</text>
<circle cx="684" cy="151" r="7" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<text x="696" y="155" font-family="Inter" font-size="11" fill="#5B6066">Атомстройком. · +2,8</text>
<circle cx="596" cy="185" r="6" fill="#94A3B8" stroke="#fff" stroke-width="2"/>
<text x="608" y="189" font-family="Inter" font-size="11" fill="#73767E">Форум-групп</text>
<circle cx="568" cy="234" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<text x="580" y="238" font-family="Inter" font-size="11" fill="#5B6066">КОРТРОС · 3,2</text>
<circle cx="482" cy="258" r="6" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<text x="494" y="262" font-family="Inter" font-size="11" fill="#5B6066">Атлас Девел.</text>
<circle cx="396" cy="278" r="6" fill="#B3261E" stroke="#fff" stroke-width="2"/>
<text x="408" y="282" font-family="Inter" font-size="11" fill="#5B6066">Эталон · 6,1</text>
<circle cx="364" cy="142" r="6" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<text x="376" y="146" font-family="Inter" font-size="11" fill="#5B6066">Унистрой</text>
<circle cx="312" cy="138" r="5" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<text x="324" y="142" font-family="Inter" font-size="11" fill="#5B6066">Атмосфера</text>
<circle cx="284" cy="186" r="5" fill="#94A3B8" stroke="#fff" stroke-width="2"/>
<text x="296" y="190" font-family="Inter" font-size="11" fill="#5B6066">Эфес</text>
<circle cx="256" cy="108" r="5" fill="#14B8A6" stroke="#fff" stroke-width="2"/>
<text x="266" y="112" font-family="Inter" font-size="11" fill="#5B6066">Семь · +6,7</text>
<circle cx="232" cy="266" r="5" fill="#F59E0B" stroke="#fff" stroke-width="2"/>
<text x="244" y="270" font-family="Inter" font-size="11" fill="#5B6066">Гринстрой</text>
<circle cx="208" cy="178" r="4" fill="#94A3B8" stroke="#fff" stroke-width="2"/>
<text x="218" y="182" font-family="Inter" font-size="10.5" fill="#73767E">Лидер</text>
<circle cx="192" cy="298" r="4" fill="#B3261E" stroke="#fff" stroke-width="2"/>
<text x="202" y="302" font-family="Inter" font-size="10.5" fill="#73767E">Гранд</text>
<circle cx="168" cy="188" r="4" fill="#94A3B8" stroke="#fff" stroke-width="2"/>
<text x="178" y="192" font-family="Inter" font-size="10.5" fill="#73767E">УГМК-Девел.</text>
</g>
</svg>
<div class="axis-y-label">Δ sold % за 14 мес</div>
<div class="axis-x-label">Объём, тыс. м² в активной фазе</div>
</div>
<div style="display:flex;gap:24px;padding-top:12px;font-size:12px;color:var(--fg-secondary);flex-wrap:wrap;">
<span><b style="color:var(--fg-primary);">Размер точки</b> — число ЖК в портфеле</span>
<span><b style="color:var(--fg-primary);">Цвет</b> — статус velocity (зелёный — растёт, красный — падает)</span>
<span style="margin-left:auto;color:var(--fg-tertiary);">38 / 40 ЖК в выборке · 2 объекта &lt; 6 мес в продаже исключены</span>
</div>
</section>
<!-- COMPARE LINE -->
<section class="section">
<div class="section-head">
<div>
<h2>Сравнение sold % — PRINZIP vs топ-2</h2>
<div class="sub">Кумулятивный sold % помесячно по всему портфелю; PRINZIP жирнее, Брусника и Атомстройком. для контекста</div>
</div>
<div class="right">
<button class="chip" aria-pressed="true">vs топ-2</button>
<button class="chip">vs Брусника</button>
<button class="chip">vs Атомстройком.</button>
<button class="btn btn-secondary btn-compact">Export CSV ⤓</button>
</div>
</div>
<div class="compare-wrap">
<svg viewBox="0 0 1000 280" preserveAspectRatio="xMidYMid meet">
<g stroke="#EEF0F3" stroke-width="1">
<line x1="0" y1="56" x2="1000" y2="56"/>
<line x1="0" y1="112" x2="1000" y2="112"/>
<line x1="0" y1="168" x2="1000" y2="168"/>
<line x1="0" y1="224" x2="1000" y2="224"/>
</g>
<!-- PRINZIP -->
<polyline fill="none" stroke="#1D4ED8" stroke-width="3" points="0,210 70,196 140,180 210,164 280,150 350,134 420,118 490,104 560,92 630,80 700,72 770,66 840,60 910,56 980,52"/>
<g fill="#1D4ED8">
<circle cx="0" cy="210" r="3.5"/><circle cx="140" cy="180" r="3.5"/><circle cx="280" cy="150" r="3.5"/><circle cx="420" cy="118" r="3.5"/>
<circle cx="560" cy="92" r="3.5"/><circle cx="700" cy="72" r="3.5"/><circle cx="840" cy="60" r="3.5"/><circle cx="980" cy="52" r="3.5"/>
</g>
<!-- Брусника -->
<polyline fill="none" stroke="#0EA5E9" stroke-width="2" points="0,218 70,210 140,198 210,184 280,168 350,154 420,138 490,128 560,116 630,108 700,100 770,94 840,88 910,82 980,78"/>
<!-- Атомстройком. -->
<polyline fill="none" stroke="#14B8A6" stroke-width="2" points="0,226 70,220 140,212 210,202 280,192 350,180 420,170 490,160 560,150 630,140 700,132 770,124 840,118 910,112 980,108"/>
<!-- y axis labels -->
<g font-family="ui-monospace,Menlo" font-size="10" fill="#73767E">
<text x="-4" y="60" text-anchor="end">100 %</text>
<text x="-4" y="116" text-anchor="end">75 %</text>
<text x="-4" y="172" text-anchor="end">50 %</text>
<text x="-4" y="228" text-anchor="end">25 %</text>
</g>
<!-- x labels -->
<g font-family="ui-monospace,Menlo" font-size="9" fill="#73767E">
<text x="0" y="276">фев 25</text>
<text x="140" y="276" text-anchor="middle">апр</text>
<text x="280" y="276" text-anchor="middle">июн</text>
<text x="420" y="276" text-anchor="middle">авг</text>
<text x="560" y="276" text-anchor="middle">окт</text>
<text x="700" y="276" text-anchor="middle">дек</text>
<text x="840" y="276" text-anchor="middle">фев 26</text>
<text x="996" y="276" text-anchor="end">мар 26</text>
</g>
</svg>
</div>
<div class="legend-row">
<span class="leg"><span class="sw" style="background:#1D4ED8;height:10px;"></span>PRINZIP <span class="meta">74 % · +8,2 пп</span></span>
<span class="leg"><span class="sw" style="background:#0EA5E9"></span>Брусника <span class="meta">71 % · +5,1 пп</span></span>
<span class="leg"><span class="sw" style="background:#14B8A6"></span>Атомстройком. <span class="meta">64 % · +2,8 пп</span></span>
</div>
</section>
<!-- DRAWER (right-side) placeholder mock -->
<section class="section">
<div class="section-head">
<div>
<h2>Карточка выбранного девелопера — PRINZIP</h2>
<div class="sub">Открывается drawer'ом справа при клике на строку leaderboard (не navigate)</div>
</div>
<div class="right">
<a href="#" class="btn btn-tertiary btn-compact">Открыть профиль →</a>
</div>
</div>
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:16px;">
<div>
<h3 style="font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:var(--fg-secondary);margin-bottom:8px;">Концентрация по районам</h3>
<div style="display:flex;flex-direction:column;gap:6px;">
<div style="display:grid;grid-template-columns:120px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>Академический</span><div style="height:6px;background:var(--accent);border-radius:3px;width:62%;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">62 %</span></div>
<div style="display:grid;grid-template-columns:120px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>Центр</span><div style="height:6px;background:var(--accent);border-radius:3px;width:18%;opacity:0.7;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">18 %</span></div>
<div style="display:grid;grid-template-columns:120px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>Юго-Запад</span><div style="height:6px;background:var(--accent);border-radius:3px;width:11%;opacity:0.55;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">11 %</span></div>
<div style="display:grid;grid-template-columns:120px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>Пионерский</span><div style="height:6px;background:var(--accent);border-radius:3px;width:6%;opacity:0.4;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">6 %</span></div>
<div style="display:grid;grid-template-columns:120px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>ВИЗ</span><div style="height:6px;background:var(--accent);border-radius:3px;width:3%;opacity:0.4;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">3 %</span></div>
</div>
</div>
<div>
<h3 style="font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:var(--fg-secondary);margin-bottom:8px;">Распределение по комнатности</h3>
<div style="display:flex;flex-direction:column;gap:6px;">
<div style="display:grid;grid-template-columns:80px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>Студии</span><div style="height:6px;background:#93C5FD;border-radius:3px;width:18%;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">18 %</span></div>
<div style="display:grid;grid-template-columns:80px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>1-к</span><div style="height:6px;background:#60A5FA;border-radius:3px;width:34%;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">34 %</span></div>
<div style="display:grid;grid-template-columns:80px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>2-к</span><div style="height:6px;background:#3B82F6;border-radius:3px;width:28%;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">28 %</span></div>
<div style="display:grid;grid-template-columns:80px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>3-к</span><div style="height:6px;background:#1D4ED8;border-radius:3px;width:14%;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">14 %</span></div>
<div style="display:grid;grid-template-columns:80px 1fr 40px;gap:8px;align-items:center;font-size:12.5px;"><span>4+</span><div style="height:6px;background:#1E3A8A;border-radius:3px;width:6%;"></div><span style="text-align:right;font-variant-numeric:tabular-nums;">6 %</span></div>
</div>
<div style="margin-top:12px;padding:8px 12px;background:var(--warn-soft);border-radius:6px;font-size:11.5px;color:var(--fg-primary);">
<b style="color:var(--warn);">Gap vs рынок:</b> доля 3к/4+ — 20 % vs 44 % рыночного спроса. Недозагрузка в большом сегменте.
</div>
</div>
<div>
<h3 style="font-size:11px;letter-spacing:0.04em;text-transform:uppercase;color:var(--fg-secondary);margin-bottom:8px;">Топ-5 ЖК · drill-in</h3>
<table class="lb" style="min-width:0;">
<thead><tr><th>ЖК</th><th>Sold %</th></tr></thead>
<tbody>
<tr><td class="name"><a href="#" style="color:var(--accent);">Каменные палатки</a></td><td><span class="pill pos">78 %</span></td></tr>
<tr><td class="name"><a href="#" style="color:var(--accent);">Хрустальный</a></td><td><span class="pill pos">81 %</span></td></tr>
<tr><td class="name"><a href="#" style="color:var(--accent);">Прогресс</a></td><td><span class="pill pos">72 %</span></td></tr>
<tr><td class="name"><a href="#" style="color:var(--accent);">Светлая роща</a></td><td><span class="pill pos">69 %</span></td></tr>
<tr><td class="name"><a href="#" style="color:var(--accent);">Парк-холл</a></td><td><span class="pill flat">52 %</span></td></tr>
</tbody>
</table>
</div>
</div>
</section>
</main>
</body>
</html>

597
preview/site-finder.html Normal file
View file

@ -0,0 +1,597 @@
<!doctype html>
<html lang="ru">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>/analytics/recommend — Рекомендатор площадки · gendsgn</title>
<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:wght@400;500;600;700&display=swap" rel="stylesheet" />
<style>
:root {
--bg-app:#F6F7F9; --bg-card:#FFFFFF; --bg-card-alt:#FAFBFC; --bg-headline:#0F172A;
--border-soft:#EEF0F3; --border-card:#E6E8EC; --border-strong:#D1D5DB;
--fg-primary:#111111; --fg-secondary:#5B6066; --fg-tertiary:#73767E;
--fg-on-dark:#E2E8F0; --fg-on-dark-muted:#94A3B8;
--accent:#1D4ED8; --accent-hover:#1E40AF; --accent-soft:#DBEAFE; --accent-2:#F2994A;
--success:#0A7A3A; --success-soft:#DCFCE7;
--warn:#9A6700; --warn-soft:#FEF3C7;
--danger:#B3261E; --danger-soft:#FEE2E2;
--viz-1:#1D4ED8; --viz-2:#0EA5E9; --viz-3:#14B8A6; --viz-4:#F59E0B; --viz-5:#8B5CF6;
--prediction-band: rgba(14,165,233,0.18);
--font-body:'Inter',-apple-system,BlinkMacSystemFont,'Segoe UI',system-ui,sans-serif;
}
* { box-sizing:border-box; margin:0; padding:0; }
html { background:var(--bg-app); }
body { font-family:var(--font-body); font-size:14px; line-height:1.5; color:var(--fg-primary); font-variant-numeric:tabular-nums; font-feature-settings:"tnum"; -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale; }
a { color:inherit; text-decoration:none; }
button { font:inherit; cursor:pointer; }
.mono { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; }
.wrap { max-width:1440px; margin:0 auto; padding:0 24px; }
.dev-nav { position:sticky; top:0; z-index:100; display:flex; align-items:center; gap:18px; height:38px; padding:0 18px; background:#0b0f1a; color:rgba(255,255,255,0.92); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11.5px; letter-spacing:0.04em; border-bottom:1px solid rgba(255,255,255,0.08); }
.dev-nav .dev-label { display:inline-flex; align-items:center; gap:8px; color:#fbbf24; font-weight:600; letter-spacing:0.18em; text-transform:uppercase; white-space:nowrap; }
.dev-nav .dev-label::before { content:''; width:6px; height:6px; border-radius:50%; background:#fbbf24; box-shadow:0 0 0 3px rgba(251,191,36,0.22); }
.dev-nav .dev-tabs { display:inline-flex; gap:2px; align-items:center; }
.dev-nav .dev-sep { width:1px; height:16px; background:rgba(255,255,255,0.16); margin:0 6px; }
.dev-nav .dev-tabs a { padding:5px 11px; border-radius:5px; color:rgba(255,255,255,0.62); transition:background .12s,color .12s; }
.dev-nav .dev-tabs a:hover { color:#fff; background:rgba(255,255,255,0.08); }
.dev-nav .dev-tabs a[aria-current="page"] { color:#0b0f1a; background:#fbbf24; font-weight:600; }
.dev-nav .dev-hint { margin-left:auto; color:rgba(255,255,255,0.36); white-space:nowrap; }
@media print { .dev-nav { display:none !important; } }
.topbar { background:var(--bg-card); border-bottom:1px solid var(--border-card); }
.topbar-inner { display:flex; align-items:center; justify-content:space-between; height:56px; }
.brand { display:inline-flex; align-items:center; gap:8px; font-weight:700; font-size:15px; color:var(--fg-primary); letter-spacing:-0.01em; }
.brand-mark { width:22px; height:22px; border-radius:6px; background:var(--accent); display:grid; place-items:center; color:#fff; font-size:11px; font-weight:700; }
.brand-mark::before { content:'gd'; }
.topbar-user { display:flex; align-items:center; gap:12px; font-size:13px; color:var(--fg-secondary); }
.topbar-user .who { display:flex; align-items:center; gap:8px; padding:6px 12px; border-radius:6px; background:var(--bg-card-alt); border:1px solid var(--border-card); }
.topbar-user .avatar { width:22px; height:22px; border-radius:50%; background:var(--accent-soft); color:var(--accent); display:grid; place-items:center; font-weight:600; font-size:10px; }
.crumbs { display:flex; gap:8px; align-items:center; padding-top:16px; font-size:12.5px; color:var(--fg-secondary); }
.crumbs a { color:var(--fg-secondary); }
.crumbs a:hover { color:var(--accent); text-decoration:underline; text-underline-offset:3px; }
.crumbs .sep { color:var(--fg-tertiary); }
.crumbs .last { color:var(--fg-primary); }
.page-head { padding:8px 0 16px; display:flex; justify-content:space-between; align-items:flex-end; gap:24px; }
.page-head h1 { font-size:22px; line-height:1.25; font-weight:600; letter-spacing:-0.01em; }
.page-head .sub { font-size:13px; color:var(--fg-secondary); margin-top:4px; }
.page-head .right { display:flex; gap:8px; align-items:center; }
.a-tabs { display:flex; gap:2px; border-bottom:1px solid var(--border-card); margin-bottom:16px; overflow-x:auto; }
.a-tabs a { padding:10px 14px; font-size:13px; font-weight:500; color:var(--fg-secondary); border-bottom:2px solid transparent; margin-bottom:-1px; white-space:nowrap; }
.a-tabs a:hover { color:var(--fg-primary); }
.a-tabs a[aria-current="page"] { color:var(--accent); border-bottom-color:var(--accent); font-weight:600; }
/* ============ LAYOUT — form left, result right ============ */
.rec-grid { display:grid; grid-template-columns:340px 1fr; gap:24px; align-items:start; }
.form-card { position:sticky; top:88px; background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:20px; }
.form-card h2 { font-size:16px; font-weight:600; margin-bottom:4px; }
.form-card .sub { font-size:12.5px; color:var(--fg-secondary); margin-bottom:16px; }
.field { margin-bottom:16px; }
.field label { display:block; font-size:11px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; margin-bottom:6px; }
.field input, .field select { width:100%; height:36px; padding:0 12px; border:1px solid var(--border-strong); border-radius:6px; background:var(--bg-card); font:inherit; color:var(--fg-primary); font-variant-numeric:tabular-nums; }
.field input:focus, .field select:focus { outline:none; border-color:var(--accent); box-shadow:0 0 0 3px var(--accent-soft); }
.field .row2 { display:grid; grid-template-columns:1fr 1fr; gap:8px; }
.field .with-suffix { position:relative; }
.field .with-suffix .suf { position:absolute; right:12px; top:50%; transform:translateY(-50%); font-size:12px; color:var(--fg-tertiary); pointer-events:none; }
.chip-group { display:flex; flex-wrap:wrap; gap:4px; }
.chip-group .chip { display:inline-flex; align-items:center; height:28px; padding:0 12px; border-radius:14px; font-size:12px; font-weight:500; color:var(--fg-secondary); background:transparent; border:1px solid var(--border-card); cursor:pointer; transition:all .12s; }
.chip-group .chip[aria-pressed="true"] { color:var(--accent); background:var(--accent-soft); border-color:var(--accent-soft); }
.form-cta { margin-top:16px; padding-top:16px; border-top:1px solid var(--border-soft); }
.form-cta .btn-primary { width:100%; justify-content:center; }
.form-meta { margin-top:12px; font-size:11.5px; color:var(--fg-tertiary); line-height:1.5; }
/* ============ RESULT ============ */
.headline-bar { background:var(--bg-headline); color:var(--fg-on-dark); border-radius:12px; padding:16px 20px; display:flex; align-items:center; gap:16px; margin-bottom:16px; }
.headline-bar .tag { font-size:10.5px; letter-spacing:0.08em; text-transform:uppercase; font-weight:600; color:var(--accent-2); white-space:nowrap; }
.headline-bar .verdict { font-size:15px; font-weight:500; line-height:1.4; color:var(--fg-on-dark); }
.headline-bar .verdict b { color:#fff; font-weight:600; }
.headline-bar .caveat { margin-left:auto; font-size:11.5px; color:var(--fg-on-dark-muted); white-space:nowrap; }
.kpi-row-3 { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin-bottom:24px; }
.kpi { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:16px 18px; }
.kpi .label { font-size:11px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; }
.kpi .value { font-size:28px; line-height:1.15; font-weight:600; color:var(--fg-primary); letter-spacing:-0.015em; margin-top:8px; }
.kpi .value small { font-size:14px; color:var(--fg-secondary); font-weight:500; margin-left:4px; }
.kpi .hint { font-size:12.5px; color:var(--fg-secondary); margin-top:6px; }
.kpi .delta { display:inline-flex; align-items:center; gap:4px; font-size:12px; font-weight:600; margin-top:8px; padding:2px 8px; border-radius:4px; font-variant-numeric:tabular-nums; }
.kpi .delta.pos { color:var(--success); background:var(--success-soft); }
.kpi .delta.neg { color:var(--danger); background:var(--danger-soft); }
.section { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; padding:20px; margin-bottom:24px; }
.section-head { display:flex; align-items:flex-end; justify-content:space-between; gap:16px; margin-bottom:16px; }
.section-head h2 { font-size:18px; line-height:1.25; font-weight:600; letter-spacing:-0.01em; }
.section-head .sub { font-size:12.5px; color:var(--fg-secondary); margin-top:4px; }
.section-head .right { display:flex; gap:8px; align-items:center; }
.btn { display:inline-flex; align-items:center; gap:6px; height:36px; padding:0 16px; border-radius:8px; font-weight:500; font-size:13.5px; border:1px solid transparent; transition:all .12s; }
.btn-primary { background:var(--accent); color:#fff; border-color:var(--accent); height:44px; padding:0 20px; font-size:14px; }
.btn-primary:hover { background:var(--accent-hover); border-color:var(--accent-hover); }
.btn-secondary { background:var(--accent-2); color:#fff; border-color:var(--accent-2); }
.btn-secondary:hover { filter:brightness(0.94); }
.btn-tertiary { background:transparent; color:var(--fg-primary); border-color:var(--border-card); }
.btn-tertiary:hover { border-color:var(--fg-primary); }
.btn-compact { height:32px; padding:0 12px; font-size:12.5px; border-radius:6px; }
/* ============ VELOCITY PANEL (slider + live KPI) ============ */
.velocity { display:grid; grid-template-columns:1fr 280px; gap:24px; align-items:start; }
.velocity-slider { padding-top:16px; }
.velocity-slider .lbl-row { display:flex; justify-content:space-between; align-items:baseline; margin-bottom:12px; }
.velocity-slider .lbl-row .name { font-size:13px; font-weight:500; color:var(--fg-primary); }
.velocity-slider .lbl-row .val { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:13px; font-weight:600; color:var(--accent); font-variant-numeric:tabular-nums; }
.slider-track { position:relative; height:8px; background:var(--bg-card-alt); border-radius:4px; }
.slider-track .fill { position:absolute; top:0; left:0; height:100%; background:var(--accent); border-radius:4px; width:62%; }
.slider-track .handle { position:absolute; top:50%; left:62%; transform:translate(-50%,-50%); width:20px; height:20px; background:#fff; border:2px solid var(--accent); border-radius:50%; cursor:grab; box-shadow:0 1px 4px rgba(0,0,0,0.1); }
.slider-ticks { display:flex; justify-content:space-between; margin-top:8px; font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:10px; color:var(--fg-tertiary); }
.velocity-side { background:var(--bg-card-alt); border:1px solid var(--border-soft); border-radius:8px; padding:16px; }
.velocity-side h3 { font-size:11px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; margin-bottom:12px; }
.velocity-side .row { display:flex; justify-content:space-between; align-items:baseline; padding:8px 0; border-top:1px solid var(--border-soft); }
.velocity-side .row:first-of-type { border-top:0; padding-top:0; }
.velocity-side .row .lbl { font-size:12.5px; color:var(--fg-secondary); }
.velocity-side .row .val { font-size:14px; font-weight:600; color:var(--fg-primary); font-variant-numeric:tabular-nums; }
.velocity-side .row .val.pos { color:var(--success); }
.velocity-side .row .val.neg { color:var(--danger); }
/* ============ MIX SLIDERS ============ */
.mix-list { display:flex; flex-direction:column; gap:12px; }
.mix-row { display:grid; grid-template-columns:130px 1fr 60px 80px; gap:12px; align-items:center; }
.mix-row .name { font-size:13px; color:var(--fg-primary); font-weight:500; }
.mix-row .bar-wrap { height:8px; background:var(--bg-card-alt); border-radius:4px; position:relative; }
.mix-row .bar-wrap .fill { height:100%; border-radius:4px; background:var(--accent); }
.mix-row .pct { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:13px; font-weight:600; color:var(--fg-primary); text-align:right; font-variant-numeric:tabular-nums; }
.mix-row .pop { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:11.5px; color:var(--fg-secondary); text-align:right; font-variant-numeric:tabular-nums; }
.mix-foot { margin-top:16px; padding-top:12px; border-top:1px solid var(--border-soft); display:flex; justify-content:space-between; font-size:12.5px; color:var(--fg-secondary); }
.mix-foot b { color:var(--fg-primary); font-weight:600; }
/* ============ DISTRICT KPI GRID (5 cards) ============ */
.dist-grid { display:grid; grid-template-columns:repeat(5,1fr); gap:8px; }
.dist-cell { background:var(--bg-card-alt); border:1px solid var(--border-soft); border-radius:8px; padding:12px 14px; }
.dist-cell .lbl { font-size:10.5px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; }
.dist-cell .val { font-size:20px; font-weight:600; color:var(--fg-primary); letter-spacing:-0.01em; margin-top:4px; font-variant-numeric:tabular-nums; }
.dist-cell .meta { font-size:11.5px; color:var(--fg-tertiary); margin-top:4px; }
.dist-cell.warn .val { color:var(--warn); }
.dist-cell.ok .val { color:var(--success); }
/* ============ LIQUIDITY CHART ============ */
.liq-chart { position:relative; height:240px; border-left:1px solid var(--border-soft); border-bottom:1px solid var(--border-soft); }
.liq-chart svg { width:100%; height:100%; display:block; }
/* ============ BUCKETS CHART + TABLE ============ */
.buckets-row { display:grid; grid-template-columns:1fr 1fr; gap:24px; }
.bucket-chart { padding:8px 0; }
.bucket-chart svg { width:100%; height:200px; display:block; }
.buckets-table { width:100%; border-collapse:collapse; }
.buckets-table th { font-size:10px; letter-spacing:0.04em; text-transform:uppercase; color:var(--fg-secondary); font-weight:500; text-align:left; padding:8px 8px 8px 0; border-bottom:1px solid var(--border-card); }
.buckets-table th:not(:first-child), .buckets-table td:not(:first-child) { text-align:right; }
.buckets-table td { font-size:13px; padding:10px 8px 10px 0; border-bottom:1px solid var(--border-soft); color:var(--fg-primary); font-variant-numeric:tabular-nums; }
.buckets-table tr:last-child td { border-bottom:0; }
.buckets-table tr.total td { font-weight:600; background:var(--bg-card-alt); border-top:2px solid var(--border-card); }
/* ============ COMPARABLES ============ */
.comparables { display:flex; flex-direction:column; gap:8px; }
.comp-row { display:grid; grid-template-columns:1fr 100px 80px 70px 80px; gap:12px; align-items:center; padding:10px 0; border-top:1px solid var(--border-soft); }
.comp-row:first-child { border-top:0; }
.comp-row .name a { color:var(--accent); font-weight:500; font-size:13px; }
.comp-row .name a:hover { text-decoration:underline; }
.comp-row .name .meta { font-size:11.5px; color:var(--fg-secondary); margin-top:2px; }
.comp-row .num { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:13px; font-weight:500; text-align:right; font-variant-numeric:tabular-nums; }
/* ============ ACCORDIONS ============ */
details.acc { background:var(--bg-card); border:1px solid var(--border-card); border-radius:12px; margin-bottom:12px; }
details.acc summary { padding:14px 20px; font-size:14px; font-weight:600; color:var(--fg-primary); cursor:pointer; list-style:none; display:flex; justify-content:space-between; align-items:center; }
details.acc summary::-webkit-details-marker { display:none; }
details.acc summary::after { content:'+'; color:var(--fg-secondary); font-size:18px; }
details.acc[open] summary::after { content:''; }
details.acc .acc-body { padding:0 20px 20px; font-size:13px; color:var(--fg-primary); line-height:1.55; }
/* ============ CAVEAT ============ */
.caveat-bar { background:var(--warn-soft); border:1px solid var(--warn); border-radius:8px; padding:12px 16px; display:flex; gap:12px; align-items:flex-start; font-size:13px; color:var(--fg-primary); margin-bottom:24px; }
.caveat-bar .icon { width:18px; height:18px; flex-shrink:0; color:var(--warn); display:grid; place-items:center; font-weight:700; border:1.5px solid var(--warn); border-radius:50%; font-size:12px; }
.caveat-bar b { color:var(--warn); }
@media (max-width:1200px) {
.rec-grid { grid-template-columns:1fr; }
.form-card { position:relative; top:auto; }
.kpi-row-3 { grid-template-columns:1fr; }
.velocity { grid-template-columns:1fr; }
.dist-grid { grid-template-columns:repeat(2,1fr); }
.buckets-row { grid-template-columns:1fr; }
}
</style>
</head>
<body>
<aside class="dev-nav" aria-label="Dev navigation">
<span class="dev-label">DEV · ТОЛЬКО ДЛЯ РАЗРАБОТКИ</span>
<nav class="dev-tabs" aria-label="WIP страницы">
<a href="landing.html">лендинг</a>
<a href="analytics.html">/analytics</a>
<a href="site-finder.html" aria-current="page">/recommend</a>
<a href="monitoring.html">/developers</a>
<span class="dev-sep"></span>
<a href="audit.html">audit&nbsp;(live)</a>
<a href="gendsgn-audit.html">audit&nbsp;(отчёт)</a>
</nav>
<span class="dev-hint">временная панель · скроется в print</span>
</aside>
<header class="topbar">
<div class="wrap topbar-inner">
<div style="display:flex;align-items:center;gap:24px;">
<a href="landing.html" class="brand"><span class="brand-mark"></span><span>gendsgn</span></a>
</div>
<div class="topbar-user">
<span style="font-size:12px;color:var(--fg-tertiary);">Свердловская обл. · 2025-Q1</span>
<div class="who"><div class="avatar">AD</div>Алексей · PRINZIP (demo)</div>
</div>
</div>
</header>
<main class="wrap">
<nav class="crumbs" aria-label="Breadcrumb">
<a href="landing.html">gendsgn</a>
<span class="sep">/</span>
<a href="analytics.html">analytics</a>
<span class="sep">/</span>
<span class="last">recommend — рекомендатор площадки</span>
</nav>
<div class="page-head">
<div>
<h1>Рекомендатор площадки</h1>
<div class="sub">Mix квартир по комнатности, прогноз срока 80 % продаж, расчёт выручки на основе sold % сегмента и района</div>
</div>
</div>
<nav class="a-tabs" aria-label="Разделы аналитики">
<a href="analytics.html">Свердл рынок</a>
<a href="site-finder.html" aria-current="page">Рекомендатор</a>
<a href="monitoring.html">Девелоперы</a>
<a href="#">PRINZIP · профиль</a>
<a href="#">Объекты</a>
</nav>
<div class="rec-grid">
<!-- LEFT: form -->
<aside class="form-card" aria-label="Параметры площадки">
<h2>Параметры площадки</h2>
<div class="sub">Заполните, рекомендатор пересчитает за &lt; 1 сек</div>
<div class="field">
<label for="f-district">Район</label>
<select id="f-district">
<option>Академический</option>
<option>Центр</option>
<option>ВИЗ</option>
<option>Пионерский</option>
<option>Юго-Запад</option>
<option>Уралмаш</option>
<option>Уктус</option>
</select>
</div>
<div class="field">
<label>Класс жилья</label>
<div class="chip-group" role="group">
<button class="chip" aria-pressed="false">эконом</button>
<button class="chip" aria-pressed="true">комфорт</button>
<button class="chip" aria-pressed="false">бизнес</button>
<button class="chip" aria-pressed="false">премиум</button>
</div>
</div>
<div class="field">
<label for="f-area">Площадь застройки</label>
<div class="with-suffix">
<input id="f-area" type="text" value="12 000" />
<span class="suf">м²</span>
</div>
</div>
<div class="field">
<label>Окно ввода</label>
<div class="row2">
<div class="with-suffix"><input type="text" value="Q3 2026" /></div>
<div class="with-suffix"><input type="text" value="Q1 2028" /></div>
</div>
</div>
<div class="field">
<label for="f-target">Целевой срок 80 % продаж</label>
<div class="with-suffix">
<input id="f-target" type="text" value="24" />
<span class="suf">мес</span>
</div>
</div>
<div class="field">
<label for="f-price">Price factor</label>
<div class="with-suffix">
<input id="f-price" type="text" value="1,00" />
<span class="suf">× медианы района</span>
</div>
</div>
<div class="form-cta">
<button class="btn btn-primary">Рассчитать</button>
<div class="form-meta">Расчёт по 6 832 411 ДДУ Росреестра и портфелю ДОМ.РФ. Доверительный интервал ±p25/p75.</div>
</div>
</aside>
<!-- RIGHT: result -->
<div>
<div class="headline-bar" role="status">
<span class="tag">рекомендация</span>
<p class="verdict"><b>Академический</b> · комфорт · <b>12 000 м²</b>: mix <b>32/26/22/15/5</b> · срок 80 % продаж <b>22 мес</b> · выручка <b>2,4 млрд ₽</b></p>
<span class="caveat">пересчитано: 12 сек назад</span>
</div>
<!-- 3 KPI -->
<div class="kpi-row-3">
<div class="kpi">
<div class="label">Выручка</div>
<div class="value">2,4<small>млрд ₽</small></div>
<div class="hint">по медианной цене района ×1,00</div>
<span class="delta pos">↑ +180 млн vs дефолтный mix</span>
</div>
<div class="kpi">
<div class="label">Срок 80 % продаж</div>
<div class="value">22<small>мес</small></div>
<div class="hint">target 24 мес — внутри окна</div>
<span class="delta pos">опережает target на 2 мес</span>
</div>
<div class="kpi">
<div class="label">Liquidity score</div>
<div class="value">7,8<small>/ 10</small></div>
<div class="hint">взвешенно по sold % сегментов</div>
<span class="delta pos">в топ-30 % площадок района</span>
</div>
</div>
<!-- Velocity Panel -->
<section class="section">
<div class="section-head">
<div>
<h2>Velocity Panel — влияние цены</h2>
<div class="sub">Сдвиньте price factor, чтобы увидеть, как меняется срок 80 % продаж и выручка</div>
</div>
</div>
<div class="velocity">
<div class="velocity-slider">
<div class="lbl-row"><span class="name">Price factor (× медианы района)</span><span class="val">1,00</span></div>
<div class="slider-track"><div class="fill"></div><div class="handle"></div></div>
<div class="slider-ticks"><span>0,75</span><span>0,85</span><span>0,95</span><span>1,00</span><span>1,10</span><span>1,20</span><span>1,30</span></div>
<div style="margin-top:16px;font-size:12.5px;color:var(--fg-secondary);line-height:1.55;">
При factor <b style="color:var(--fg-primary);">0,90</b> срок падает до <b style="color:var(--success);">18 мес</b>, выручка снижается до <b>2,16 млрд ₽</b> (240 млн). При <b style="color:var(--fg-primary);">1,15</b> срок растёт до <b style="color:var(--danger);">31 мес</b> — выходим из окна. Сладкое пятно — 0,951,05.
</div>
</div>
<aside class="velocity-side">
<h3>На текущем factor 1,00</h3>
<div class="row"><span class="lbl">Срок 80 %</span><span class="val">22 мес</span></div>
<div class="row"><span class="lbl">Выручка</span><span class="val">2,4 млрд</span></div>
<div class="row"><span class="lbl">Маржа vs target</span><span class="val pos">+ 2 мес</span></div>
<div class="row"><span class="lbl">Liquidity</span><span class="val pos">7,8 / 10</span></div>
<div class="row"><span class="lbl">Δ sold % мес</span><span class="val">3,8 пп</span></div>
</aside>
</div>
</section>
<!-- CAVEAT -->
<div class="caveat-bar">
<span class="icon">!</span>
<div>
<b>Caveat по прогнозу.</b> Срок продаж предсказывается по выборке из 38 ЖК комфорт-класса в Академическом за последние 14 мес. Доверительный интервал p25/p75: 1926 мес. Прогноз чувствителен к курсу ипотеки — при ставке &gt; 18 % сместите окно на +6 мес.
</div>
</div>
<!-- ACCORDIONS -->
<details class="acc" open>
<summary>5 KPI района — Академический · комфорт</summary>
<div class="acc-body">
<div class="dist-grid">
<div class="dist-cell"><div class="lbl">Конкуренты</div><div class="val">11</div><div class="meta">ЖК в открытой продаже</div></div>
<div class="dist-cell"><div class="lbl">Velocity покрытие</div><div class="val">94 %</div><div class="meta">38 / 40 объектов в выборке</div></div>
<div class="dist-cell ok"><div class="lbl">Sold % медиана</div><div class="val">71 %</div><div class="meta">по комфорт-классу района</div></div>
<div class="dist-cell ok"><div class="lbl">Тренд 6 мес</div><div class="val">+4,2 пп</div><div class="meta">sold % растёт</div></div>
<div class="dist-cell"><div class="lbl">Class × District</div><div class="val">A</div><div class="meta">приоритет mix-инвестиций</div></div>
</div>
</div>
</details>
<details class="acc" open>
<summary>Mix квартир — рекомендованное распределение</summary>
<div class="acc-body">
<div class="mix-list">
<div class="mix-row">
<span class="name">Студии до 30 м²</span>
<div class="bar-wrap"><div class="fill" style="width:5%"></div></div>
<span class="pct">5 %</span>
<span class="pop">≈ 38 кв</span>
</div>
<div class="mix-row">
<span class="name">1-комн. 3045 м²</span>
<div class="bar-wrap"><div class="fill" style="width:15%"></div></div>
<span class="pct">15 %</span>
<span class="pop">≈ 115 кв</span>
</div>
<div class="mix-row">
<span class="name">2-комн. 4565 м²</span>
<div class="bar-wrap"><div class="fill" style="width:22%"></div></div>
<span class="pct">22 %</span>
<span class="pop">≈ 168 кв</span>
</div>
<div class="mix-row">
<span class="name">3-комн. 6585 м²</span>
<div class="bar-wrap"><div class="fill" style="width:26%"></div></div>
<span class="pct">26 %</span>
<span class="pop">≈ 198 кв</span>
</div>
<div class="mix-row">
<span class="name">4+ комн. / 85+ м²</span>
<div class="bar-wrap"><div class="fill" style="width:32%"></div></div>
<span class="pct">32 %</span>
<span class="pop">≈ 244 кв</span>
</div>
</div>
<div class="mix-foot">
<span>Итого <b>763 кв</b> · <b>59 800 м²</b> жилой площади</span>
<span>Sold % взвешенный по mix: <b style="color:var(--success);">74,1 %</b></span>
</div>
</div>
</details>
<details class="acc">
<summary>Liquidity по месяцам — 36 мес прогноз</summary>
<div class="acc-body">
<div class="liq-chart">
<svg viewBox="0 0 800 240" preserveAspectRatio="none">
<g stroke="#EEF0F3" stroke-width="1">
<line x1="0" y1="48" x2="800" y2="48"/>
<line x1="0" y1="96" x2="800" y2="96"/>
<line x1="0" y1="144" x2="800" y2="144"/>
<line x1="0" y1="192" x2="800" y2="192"/>
</g>
<!-- prediction band -->
<path d="M 0,200 L 50,180 L 100,150 L 150,120 L 200,98 L 250,82 L 300,70 L 350,62 L 400,52 L 450,46 L 500,42 L 550,38 L 600,36 L 650,34 L 700,32 L 750,30 L 800,28 L 800,80 L 750,82 L 700,84 L 650,88 L 600,90 L 550,94 L 500,98 L 450,102 L 400,108 L 350,118 L 300,128 L 250,140 L 200,156 L 150,178 L 100,206 L 50,224 L 0,240 Z" fill="rgba(14,165,233,0.18)"/>
<!-- main line -->
<polyline fill="none" stroke="#1D4ED8" stroke-width="2.5" points="0,220 50,200 100,178 150,156 200,134 250,116 300,98 350,84 400,72 450,62 500,54 550,48 600,42 650,38 700,34 750,32 800,30"/>
<!-- 80% target line -->
<line x1="0" y1="48" x2="800" y2="48" stroke="#0A7A3A" stroke-width="1.5" stroke-dasharray="6,4"/>
<text x="6" y="42" font-family="ui-monospace,Menlo" font-size="10" fill="#0A7A3A">target 80 %</text>
<!-- 22 mo marker -->
<line x1="490" y1="0" x2="490" y2="240" stroke="#F2994A" stroke-width="1.5" stroke-dasharray="4,3"/>
<text x="496" y="14" font-family="ui-monospace,Menlo" font-size="10" fill="#F2994A">22 мес — выход на target</text>
<!-- month axis -->
<g font-family="ui-monospace,Menlo" font-size="9" fill="#73767E">
<text x="0" y="236">0</text><text x="130" y="236">6</text><text x="262" y="236">12</text><text x="394" y="236">18</text><text x="526" y="236">24</text><text x="658" y="236">30</text><text x="780" y="236">36</text>
</g>
</svg>
</div>
<div style="margin-top:12px;font-size:12px;color:var(--fg-secondary);">Прогноз кумулятивного sold % по месяцам с учётом mix. Полоса — доверительный интервал p25/p75 на основе выборки 38 ЖК комфорт-класса района.</div>
</div>
</details>
<details class="acc">
<summary>Buckets — графика + таблица + Export Excel</summary>
<div class="acc-body">
<div class="buckets-row">
<div class="bucket-chart">
<svg viewBox="0 0 400 200" preserveAspectRatio="none">
<g stroke="#EEF0F3" stroke-width="1">
<line x1="0" y1="40" x2="400" y2="40"/>
<line x1="0" y1="80" x2="400" y2="80"/>
<line x1="0" y1="120" x2="400" y2="120"/>
<line x1="0" y1="160" x2="400" y2="160"/>
</g>
<g>
<rect x="20" y="160" width="50" height="30" fill="#93C5FD"/>
<text x="45" y="155" font-family="Inter" font-size="11" fill="#5B6066" text-anchor="middle">5 %</text>
<rect x="90" y="130" width="50" height="60" fill="#60A5FA"/>
<text x="115" y="125" font-family="Inter" font-size="11" fill="#5B6066" text-anchor="middle">15 %</text>
<rect x="160" y="102" width="50" height="88" fill="#3B82F6"/>
<text x="185" y="97" font-family="Inter" font-size="11" fill="#5B6066" text-anchor="middle">22 %</text>
<rect x="230" y="86" width="50" height="104" fill="#1D4ED8"/>
<text x="255" y="81" font-family="Inter" font-size="11" fill="#5B6066" text-anchor="middle">26 %</text>
<rect x="300" y="62" width="50" height="128" fill="#1E3A8A"/>
<text x="325" y="57" font-family="Inter" font-size="11" fill="#5B6066" text-anchor="middle">32 %</text>
</g>
<g font-family="ui-monospace,Menlo" font-size="9" fill="#73767E">
<text x="45" y="200" text-anchor="middle">студ</text>
<text x="115" y="200" text-anchor="middle"></text>
<text x="185" y="200" text-anchor="middle"></text>
<text x="255" y="200" text-anchor="middle"></text>
<text x="325" y="200" text-anchor="middle">4+</text>
</g>
</svg>
</div>
<table class="buckets-table">
<thead>
<tr><th>Сегмент</th><th>Кв</th><th>м²</th><th>Выручка</th></tr>
</thead>
<tbody>
<tr><td>студии</td><td>38</td><td>1 140</td><td>180 М</td></tr>
<tr><td>1-к</td><td>115</td><td>4 600</td><td>740 М</td></tr>
<tr><td>2-к</td><td>168</td><td>9 240</td><td>1,49 Б</td></tr>
<tr><td>3-к</td><td>198</td><td>14 850</td><td>2,39 Б</td></tr>
<tr><td>4+</td><td>244</td><td>29 970</td><td>4,82 Б</td></tr>
<tr class="total"><td>Итого</td><td>763</td><td>59 800</td><td>9,62 Б</td></tr>
</tbody>
</table>
</div>
<div style="margin-top:16px;display:flex;justify-content:space-between;align-items:center;padding-top:12px;border-top:1px solid var(--border-soft);">
<span style="font-size:12.5px;color:var(--fg-secondary);">Цифры в подсказке headline-bar — это выручка по сценарию price factor 1,00. Полная выгрузка — Export Excel.</span>
<button class="btn btn-secondary btn-compact">Export Excel ⤓</button>
</div>
</div>
</details>
<details class="acc">
<summary>Comparables — топ-5 похожих ЖК в районе</summary>
<div class="acc-body">
<div class="comparables">
<div class="comp-row">
<div class="name"><a href="#">Каменные палатки</a><div class="meta">PRINZIP · комфорт · 1 824 кв</div></div>
<div class="num">78 %</div>
<div class="num">22 мес</div>
<div class="num">173 ₽</div>
<div class="num">1,4 Б</div>
</div>
<div class="comp-row">
<div class="name"><a href="#">Северная корона</a><div class="meta">Брусника · комфорт · 1 408 кв</div></div>
<div class="num">71 %</div>
<div class="num">24 мес</div>
<div class="num">198 ₽</div>
<div class="num">1,8 Б</div>
</div>
<div class="comp-row">
<div class="name"><a href="#">Светлый</a><div class="meta">Атомстройком. · комфорт · 962 кв</div></div>
<div class="num">68 %</div>
<div class="num">26 мес</div>
<div class="num">156 ₽</div>
<div class="num">0,9 Б</div>
</div>
<div class="comp-row">
<div class="name"><a href="#">Радуга-Парк</a><div class="meta">Форум-групп · комфорт · 720 кв</div></div>
<div class="num">62 %</div>
<div class="num">28 мес</div>
<div class="num">162 ₽</div>
<div class="num">0,7 Б</div>
</div>
<div class="comp-row">
<div class="name"><a href="#">Уют</a><div class="meta">Атлас Девел. · комфорт · 612 кв</div></div>
<div class="num">52 %</div>
<div class="num">31 мес</div>
<div class="num">141 ₽</div>
<div class="num">0,5 Б</div>
</div>
</div>
<div style="margin-top:12px;font-size:11.5px;color:var(--fg-secondary);">Колонки: sold %, срок 80 %, ср. цена ₽/м², оценочная выручка. Клик по названию → /analytics/objects/[id].</div>
</div>
</details>
<details class="acc">
<summary>Caveats — что важно учесть</summary>
<div class="acc-body">
<ul style="list-style:none;padding:0;margin:0;display:flex;flex-direction:column;gap:8px;">
<li>• Выборка для прогноза — только ЖК с лотностью &gt; 200 кв; малоквартирные клубные дома (&lt; 100 кв) дают другой режим спроса.</li>
<li>• Расчёт не учитывает паркинг и кладовые — добавьте 47 % к выручке при наличии паркинга 1:1.</li>
<li>• Прогноз 36 мес — экстраполяция; при горизонте &gt; 24 мес доверительный интервал расширяется до p10/p90.</li>
<li>• Mix чувствителен к политике ипотеки: при ставке &gt; 18 % спрос смещается в студии и 1-к — пересмотрите mix.</li>
</ul>
</div>
</details>
</div>
</div>
</main>
</body>
</html>