gendesign/tradein-mvp/frontend/src/components/trade-in/trade-in.css
bot-backend d0e29ce914
All checks were successful
CI Trade-In / changes (pull_request) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Successful in 1m1s
feat(tradein/admin): audit + activity dashboards (Feature 2/3 UI)
Admin-only read dashboards over the merged user_events audit API (#2520):
- /admin/audit — accounts table (IP/device/login/search counts) with a
  click-to-expand drilldown per account (IPs, devices, recent searches,
  recent raw activity).
- /admin/analytics — "Активность" (user-behavior analytics, distinct from
  the market-analytics overlay label): summary KPI cards, a 7/30/90-day
  events/users line chart (recharts), top-searches/top-paths/by-account
  tables.

Both pages are admin-only via the existing Topbar NAV_ITEMS admin-scopePath
convention (mirrors /scrapers) so non-admin roles never see the nav entries;
a direct-URL 403 from the API is caught and rendered as NoAccessScreen
instead of crashing, matching the RouteGuard "user" variant.
2026-07-13 23:42:06 +03:00

2822 lines
77 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* #657 white-label: Manrope — OPEN geometric grotesk для брендового режима.
Подключается всегда, но применяется только при активном бренде
(см. --font-sans override ниже). */
@import url('https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap');
:root {
/* surface */
--bg: oklch(99% 0.002 240);
--surface: oklch(100% 0 0);
--surface-2: oklch(97.5% 0.004 240);
--surface-3: oklch(96% 0.006 240);
/* ink */
--fg: oklch(18% 0.012 250);
--fg-2: oklch(32% 0.014 250);
--muted: #5f6570; /* #834 a11y follow-up: oklch(50%)≈#6b7280 (3.96 на тонир. KPI-фонах) → ≥4.8:1 на #fee2e2/#dbeafe тинтах */
--muted-2: #676d73; /* #834 a11y: было oklch(62%)=#82878c (3.6:1) → AA ≥4.65:1 на белом/off-white */
/* lines */
--border: oklch(92% 0.005 250);
--border-2: oklch(88% 0.006 250);
--border-strong: oklch(80% 0.008 250);
/* accents */
--accent: oklch(54% 0.18 258);
--accent-ink: oklch(36% 0.16 258);
--accent-soft: oklch(96% 0.03 258);
--accent-2: oklch(64% 0.17 50); /* orange — warn / secondary */
--accent-2-soft: oklch(96% 0.05 70);
--success: #197038; /* #834 a11y: было oklch(56%)≈#218a45 (4.4:1) → AA ≥5.5:1 на белом/success-soft */
--success-soft: oklch(96% 0.04 150);
--danger: oklch(56% 0.20 25);
--danger-soft: oklch(96% 0.04 25);
/* viz palette (price bars / sources) */
--viz-1: oklch(56% 0.16 258);
--viz-2: oklch(60% 0.16 200);
--viz-3: oklch(64% 0.15 150);
--viz-4: oklch(70% 0.15 80);
--viz-5: oklch(66% 0.17 30);
/* type */
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
--font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
/* #657 white-label font (Manrope) — применяется через .brand-active ниже */
--font-brand: 'Manrope', var(--font-sans);
/* layout */
--radius: 10px;
--radius-sm: 6px;
--radius-lg: 14px;
--shadow-sm: 0 1px 2px rgba(16,24,40,.04);
--shadow-md: 0 4px 18px -6px rgba(16,24,40,.10), 0 1px 2px rgba(16,24,40,.04);
--container: 1320px;
}
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
margin: 0;
background: var(--bg);
color: var(--fg);
font: 15px/1.55 var(--font-sans);
font-feature-settings: 'cv11', 'ss03';
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.num, .mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
[data-tnum] { font-variant-numeric: tabular-nums; }
h1, h2, h3, h4 { margin: 0; font-weight: 600; letter-spacing: -0.012em; color: var(--fg); }
p { margin: 0; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
/* ============================================================
HEADER (white-label — wordmark slot)
============================================================ */
.topbar {
position: sticky;
top: 0;
z-index: 50;
background: color-mix(in oklch, var(--surface) 92%, transparent);
backdrop-filter: saturate(140%) blur(12px);
-webkit-backdrop-filter: saturate(140%) blur(12px);
border-bottom: 1px solid var(--border);
}
.topbar-inner {
max-width: var(--container);
margin: 0 auto;
padding: 12px 28px;
display: flex;
align-items: center;
gap: 28px;
}
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
font-weight: 700;
letter-spacing: 0.06em;
font-size: 13px;
color: var(--fg);
}
.brand-mark {
width: 28px; height: 28px;
background: var(--fg);
color: var(--surface);
border-radius: 6px;
display: grid; place-items: center;
font-family: var(--font-mono);
font-size: 13px;
font-weight: 600;
}
.brand-mark-svg { width: 22px; height: 22px; display: block; }
.brand-name { letter-spacing: 0.22em; }
.brand-sep { width: 1px; height: 18px; background: var(--border); margin: 0 2px; }
.brand-product {
font-weight: 500;
letter-spacing: 0.04em;
font-size: 13px;
color: var(--muted);
text-transform: uppercase;
}
/* #657 white-label: логотип клиента вместо «TI»-метки (см. Topbar.tsx).
object-fit:contain + max-width — защита от расплющивания, если у бренда SVG
без нормального viewBox/с preserveAspectRatio="none" (как был хотлинк
logo-pink.svg). Полноразмерный wordmark (viewBox 1498×194) рендерится ~200×26. */
.brand-logo {
height: 26px;
width: auto;
max-width: 200px;
object-fit: contain;
object-position: left center;
display: block;
}
/* Активный бренд: переопределяем шрифт всего trade-in scope на Manrope.
--accent / --accent-2 переопределяются в рантайме из page.tsx
(document.documentElement.style.setProperty). Без ?brand= класс не
вешается → стандартный Inter + OKLCH-палитра нетронуты. */
.brand-active { --font-sans: var(--font-brand); }
.top-nav {
display: flex;
gap: 22px;
margin-left: auto;
align-items: center;
}
.top-nav a {
color: var(--fg-2);
font-size: 13px;
font-weight: 500;
}
.top-nav a.is-active { color: var(--fg); }
.top-cta {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 7px 12px;
border: 1px solid var(--border-2);
border-radius: 8px;
font-size: 13px;
font-weight: 500;
color: var(--fg);
background: var(--surface);
}
.top-user {
width: 30px; height: 30px;
border-radius: 50%;
background: var(--surface-3);
border: 1px solid var(--border);
display: grid; place-items: center;
font-size: 12px;
font-weight: 600;
color: var(--fg-2);
}
/* ============================================================
PAGE HEAD
============================================================ */
.page {
max-width: var(--container);
margin: 0 auto;
padding: 28px 28px 96px;
}
.crumbs {
display: flex; align-items: center; gap: 8px;
color: var(--muted-2);
font-size: 12px;
letter-spacing: 0.04em;
margin-bottom: 14px;
}
.crumbs span { color: var(--muted); }
.crumbs em { font-style: normal; color: var(--fg-2); }
.page-title {
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 24px;
margin-bottom: 8px;
}
.page-title h1 {
font-size: 30px;
line-height: 1.1;
letter-spacing: -0.02em;
}
.page-meta {
display: inline-flex;
gap: 10px;
flex-wrap: wrap;
}
.pill {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px;
border-radius: 999px;
border: 1px solid var(--border-2);
background: var(--surface);
font-size: 12px;
color: var(--fg-2);
letter-spacing: 0.02em;
}
.pill .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--success); }
.pill .dot.danger { background: var(--danger); }
.pill .dot.warn { background: var(--accent-2); }
.pill .dot.muted { background: var(--muted-2); }
.pill .mono { font-size: 11px; }
.page-subtitle {
color: var(--muted);
font-size: 14px;
max-width: 720px;
}
/* ============================================================
MAIN GRID (sticky form / result column)
============================================================ */
.layout {
display: grid;
grid-template-columns: 360px 1fr;
gap: 40px;
margin-top: 28px;
align-items: start;
}
/* ---- form ---- */
.form-card {
position: sticky;
top: 84px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
max-height: calc(100vh - 104px);
/* overflow-y:auto (было hidden) — на коротких вьюпортах (13" MacBook @100%)
форма выше max-height; flex-shrink тела внутри max-height-контейнера не
срабатывает, и кнопка «Оценить» в .form-foot выдавливалась за границу и
обрезалась. Скролл на самой карточке делает кнопку всегда доступной. */
overflow-y: auto;
overflow-x: hidden;
display: flex;
flex-direction: column;
}
.form-head {
padding: 16px 18px;
border-bottom: 1px solid var(--border);
display: flex; align-items: center; gap: 12px;
}
.form-head h2 {
font-size: 14px;
letter-spacing: 0.02em;
}
.form-head .form-step {
margin-left: auto;
font-family: var(--font-mono);
font-size: 11px;
color: var(--muted);
letter-spacing: 0.08em;
}
.form-body {
padding: 14px 18px 6px;
/* overflow-y:visible — скроллом владеет .form-card целиком (см. выше); вложенный
auto-скролл тут не нужен (flex-shrink тела в max-height-контейнере не работал). */
overflow-y: visible;
flex: 1;
}
/* margin-bottom 12→9 — лёгкое уплотнение, чтобы форма помещалась на ноутбуках. */
.field { margin-bottom: 9px; }
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.field-row.triple { grid-template-columns: 1fr 1fr 1fr; }
label.field-label {
display: flex;
justify-content: space-between;
align-items: baseline;
font-size: 12px;
color: var(--fg-2);
font-weight: 500;
margin-bottom: 5px;
}
label.field-label .req { color: var(--accent-2); font-size: 11px; }
label.field-label .hint { color: var(--muted-2); font-size: 11px; font-weight: 400; }
.control {
width: 100%;
padding: 8px 10px;
border: 1px solid var(--border-2);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--fg);
font: 13px/1.4 var(--font-sans);
transition: border-color .12s, box-shadow .12s, background .12s;
}
.control:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px color-mix(in oklch, var(--accent) 18%, transparent);
}
.control[readonly] { background: var(--surface-2); color: var(--fg-2); }
.control-with-icon { position: relative; }
.control-with-icon .control { padding-left: 32px; }
.control-with-icon .icon {
position: absolute;
left: 9px; top: 50%;
transform: translateY(-50%);
width: 16px; height: 16px;
color: var(--muted-2);
pointer-events: none;
}
.control-with-suffix { position: relative; }
.control-with-suffix .suffix {
position: absolute;
right: 12px; top: 50%;
transform: translateY(-50%);
font-family: var(--font-mono);
font-size: 11px;
color: var(--muted);
pointer-events: none;
}
select.control {
appearance: none;
background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%);
background-position: calc(100% - 14px) center, calc(100% - 10px) center;
background-size: 4px 4px, 4px 4px;
background-repeat: no-repeat;
padding-right: 26px;
}
.autocomplete {
position: relative;
}
.ac-list {
position: absolute;
top: calc(100% + 4px);
left: 0; right: 0;
background: var(--surface);
border: 1px solid var(--border-2);
border-radius: var(--radius-sm);
box-shadow: var(--shadow-md);
z-index: 10;
max-height: 220px;
overflow-y: auto;
display: none;
}
.ac-list.is-open { display: block; }
.ac-item {
padding: 8px 10px;
font-size: 13px;
cursor: pointer;
display: flex; gap: 8px;
align-items: baseline;
border-bottom: 1px solid var(--border);
}
.ac-item:last-child { border-bottom: 0; }
.ac-item:hover, .ac-item.is-focus { background: var(--accent-soft); }
.ac-item .ac-main { color: var(--fg); }
.ac-item .ac-sub { color: var(--muted); font-size: 11px; margin-left: auto; font-family: var(--font-mono); }
.file-drop {
border: 1px dashed var(--border-strong);
border-radius: var(--radius-sm);
padding: 14px 12px;
text-align: center;
color: var(--muted);
font-size: 12px;
background: var(--surface-2);
}
.file-drop b { color: var(--fg-2); font-weight: 500; }
.form-foot {
padding: 10px 18px 12px;
border-top: 1px solid var(--border);
background: linear-gradient(to bottom, transparent, color-mix(in oklch, var(--surface-2) 60%, transparent) 40%);
/* flex-shrink:0 — футер с кнопкой «Оценить» не сжимается при скролле карточки. */
flex-shrink: 0;
}
.btn {
display: inline-flex; align-items: center; justify-content: center; gap: 8px;
padding: 10px 14px;
border-radius: 8px;
font: 500 13px/1 var(--font-sans);
cursor: pointer;
border: 1px solid transparent;
transition: background .12s, transform .04s, box-shadow .12s;
}
.btn:active { transform: translateY(1px); }
.btn-primary {
width: 100%;
background: var(--fg);
color: var(--surface);
padding: 12px 14px;
font-weight: 600;
}
.btn-primary:hover { background: oklch(28% 0.018 250); }
.btn-accent {
background: var(--accent);
color: var(--surface);
}
.btn-accent:hover { background: var(--accent-ink); }
.btn-ghost {
background: var(--surface);
color: var(--fg);
border-color: var(--border-2);
}
.btn-ghost:hover { background: var(--surface-2); }
.form-foot-meta {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 8px;
font-size: 11px;
color: var(--muted);
}
.form-foot-meta .mono { font-size: 11px; }
.form-foot-meta .ok { color: var(--success); }
/* ============================================================
RESULT COLUMN — shared
============================================================ */
.result-col { min-width: 0; display: flex; flex-direction: column; gap: 28px; }
.card {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
box-shadow: var(--shadow-sm);
overflow: hidden;
}
.card-head {
padding: 18px 22px 14px;
display: flex;
align-items: flex-end;
justify-content: space-between;
gap: 16px;
border-bottom: 1px solid var(--border);
}
.section-kicker {
font-family: var(--font-mono);
font-size: 11px;
letter-spacing: 0.16em;
color: var(--muted-2);
text-transform: uppercase;
margin-bottom: 4px;
}
.card-head h2 {
font-size: 19px;
letter-spacing: -0.012em;
}
.card-head .card-meta {
text-align: right;
color: var(--muted);
font-size: 12px;
line-height: 1.5;
}
.card-head .card-meta b { color: var(--fg); font-weight: 600; }
.card-body { padding: 22px; }
.card-foot { padding: 12px 22px; background: var(--surface-2); border-top: 1px solid var(--border); font-size: 12px; color: var(--muted); }
/* ============================================================
PROGRESS BLOCK
============================================================ */
.progress-card { background: var(--surface); }
.progress-summary {
display: flex;
gap: 22px;
align-items: baseline;
flex-wrap: wrap;
margin-bottom: 16px;
}
.progress-summary .lead {
font-size: 13px;
color: var(--muted);
}
.progress-summary .num-done {
font-family: var(--font-mono);
font-size: 22px;
font-weight: 500;
color: var(--fg);
}
.progress-summary .num-done .total { color: var(--muted-2); font-weight: 400; }
.progress-overall {
flex: 1;
min-width: 200px;
height: 4px;
background: var(--surface-3);
border-radius: 2px;
overflow: hidden;
position: relative;
}
.progress-overall .bar {
height: 100%;
width: 64%;
background: linear-gradient(90deg, var(--accent) 0%, var(--viz-3) 100%);
transition: width .3s ease;
}
.progress-eta {
font-family: var(--font-mono);
font-size: 11px;
letter-spacing: 0.06em;
color: var(--muted-2);
}
.progress-list {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 0 28px;
}
.progress-row {
display: grid;
grid-template-columns: 18px 110px 1fr auto;
align-items: center;
gap: 12px;
padding: 9px 0;
border-bottom: 1px solid var(--border);
font-size: 13px;
}
.progress-row:last-child, .progress-row:nth-last-child(2) { border-bottom: 0; }
.progress-row .status-icon {
width: 16px; height: 16px;
display: grid; place-items: center;
}
.status-icon.done { color: var(--success); }
.status-icon.loading { color: var(--accent); animation: spin 1.1s linear infinite; }
.status-icon.error { color: var(--danger); }
@keyframes spin { to { transform: rotate(360deg); } }
.progress-row .src-name {
color: var(--fg);
font-weight: 500;
letter-spacing: -0.005em;
}
.progress-row .src-bar {
height: 4px;
background: var(--surface-3);
border-radius: 2px;
overflow: hidden;
position: relative;
}
.progress-row .src-bar > i {
position: absolute;
inset: 0;
width: var(--p, 100%);
background: var(--accent);
transition: width .3s ease;
}
.progress-row.is-loading .src-bar > i { background: linear-gradient(90deg, var(--accent), transparent); }
.progress-row.is-error .src-bar > i { background: var(--danger-soft); }
.progress-row .src-value {
font-family: var(--font-mono);
font-size: 12px;
color: var(--muted);
letter-spacing: -0.01em;
white-space: nowrap;
}
.progress-row .src-value b { color: var(--fg); font-weight: 500; }
/* ============================================================
HERO (Section 1)
============================================================ */
.hero-card .card-body { padding: 0; }
.hero-top {
display: grid;
grid-template-columns: 320px 1fr;
gap: 0;
border-bottom: 1px solid var(--border);
}
.hero-photo {
aspect-ratio: 4/3;
position: relative;
background: linear-gradient(135deg, oklch(85% 0.02 250), oklch(78% 0.025 240));
overflow: hidden;
}
/* Реальное фото аналога должно перекрывать плейсхолдер-скелет (::before /
::after) — иначе абсолютные псевдоэлементы рисуются поверх <img>.
Если фото нет или оно не загрузилось — скелет остаётся виден. */
.hero-photo img {
position: relative;
z-index: 1;
}
.hero-photo .photo-meta {
position: absolute;
z-index: 2;
bottom: 10px; left: 12px;
display: inline-flex; gap: 6px;
padding: 4px 8px;
background: rgba(20, 22, 30, 0.7);
backdrop-filter: blur(8px);
border-radius: 4px;
color: rgba(255,255,255,.9);
font: 500 10px/1 var(--font-mono);
letter-spacing: 0.06em;
}
/* placeholder window/blocks pattern to suggest a building photo */
.hero-photo::before {
content: '';
position: absolute;
inset: 0;
background:
linear-gradient(180deg, transparent 55%, rgba(8,12,20,.55) 100%),
repeating-linear-gradient(
0deg,
oklch(82% 0.018 250) 0 14px,
oklch(76% 0.020 250) 14px 18px
),
repeating-linear-gradient(
90deg,
transparent 0 22px,
rgba(255,255,255,.10) 22px 24px,
transparent 24px 36px
);
background-blend-mode: normal, multiply, normal;
}
.hero-photo::after {
content: '';
position: absolute;
inset: 30% 18% 6% 18%;
background:
repeating-linear-gradient(90deg, oklch(80% 0.02 250) 0 24px, oklch(74% 0.02 250) 24px 28px),
repeating-linear-gradient(0deg, transparent 0 20px, rgba(255,255,255,.18) 20px 22px);
border-top: 1px solid rgba(255,255,255,.2);
border-left: 1px solid rgba(255,255,255,.2);
}
.hero-meta {
padding: 20px 22px;
display: flex;
flex-direction: column;
gap: 8px;
}
.hero-address {
font-size: 17px;
font-weight: 600;
letter-spacing: -0.012em;
margin-bottom: 4px;
}
.hero-cad {
font-family: var(--font-mono);
font-size: 11px;
color: var(--muted);
letter-spacing: 0.04em;
margin-bottom: 12px;
}
.meta-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 10px 20px;
margin-top: 4px;
}
.meta-grid .meta-row {
display: flex;
justify-content: space-between;
gap: 12px;
font-size: 13px;
padding-bottom: 8px;
border-bottom: 1px dashed var(--border-2);
}
.meta-grid .meta-row .k { color: var(--muted); }
.meta-grid .meta-row .v { color: var(--fg); font-weight: 500; }
.meta-grid .meta-row .v.mono { font-family: var(--font-mono); }
/* Два равнозначных ценовых ориентира: запрос vs ожидаемая продажа (#648 S5a).
Одинаковый размер value у обоих — ни один не доминирует. */
.hero-prices {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
padding: 20px 22px;
border-bottom: 1px solid var(--border);
}
.hero-prices.single { grid-template-columns: 1fr; }
.price-figure {
display: flex;
flex-direction: column;
gap: 4px;
padding: 16px 18px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.price-figure[data-kind="sold"] {
background: var(--accent-soft);
border-color: color-mix(in oklch, var(--accent) 22%, var(--border));
}
/* ДКП-сделки (Росреестр) — нейтральный «факт-рынок» оттенок, отличный от
asking, чтобы читались как ДВА разных источника. */
.price-figure[data-kind="dkp"] {
background: var(--surface-3);
border-color: var(--border-strong, var(--border));
}
/* ── Две равноправные hero-цены: «Выставить» + «Получить» ──
Равный визуальный вес: одинаковый размер value у обоих. */
.hero-duo {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 16px;
padding: 20px 22px;
border-bottom: 1px solid var(--border);
}
.hero-duo--single { grid-template-columns: 1fr; }
.hero-duo__cell {
display: flex;
flex-direction: column;
gap: 5px;
padding: 18px 20px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius);
}
.hero-duo__cell[data-role=sold] {
background: var(--accent-soft);
border-color: color-mix(in oklch, var(--accent) 22%, var(--border));
}
.hero-duo__label {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.02em;
color: var(--muted);
}
.hero-duo__cell[data-role=sold] .hero-duo__label { color: var(--accent-ink); }
.hero-duo__delta {
font-family: var(--font-mono);
font-size: 11px;
font-weight: 600;
padding: 1px 6px;
border-radius: var(--radius-sm);
background: color-mix(in oklch, var(--accent) 16%, transparent);
color: var(--accent-ink);
}
.hero-duo__value {
font-size: 28px;
font-weight: 700;
line-height: 1.1;
letter-spacing: -0.02em;
color: var(--fg);
}
.hero-duo__range {
font-size: 12px;
color: var(--muted);
letter-spacing: 0.01em;
}
.hero-duo__perm2 {
font-size: 11px;
color: var(--muted-2);
letter-spacing: 0.04em;
}
.hero-duo__note {
margin-top: 4px;
font-size: 11px;
color: var(--muted);
font-style: italic;
}
/* ── §1.1 «Одна цифра-герой»: expected_sold доминирует, median — вторичный
ориентир (не конкурирует за внимание). Применяется только когда есть
expected_sold (класс .hero-duo--sold-primary). ── */
.hero-duo--sold-primary {
grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
align-items: stretch;
}
/* Цифра-герой (expected_sold) — крупнее, чем вторичный median. */
.hero-duo--sold-primary .hero-duo__cell[data-role=sold] .hero-duo__value {
font-size: 34px;
}
/* Вторичный median-ориентир — приглушённый фон + меньший кегль числа. */
.hero-duo--sold-primary .hero-duo__cell[data-role=asking] {
background: var(--surface-1, var(--bg));
}
.hero-duo--sold-primary .hero-duo__cell[data-role=asking] .hero-duo__value {
font-size: 20px;
font-weight: 600;
color: var(--fg-2);
}
/* Честное пояснение к разбросу — «не погрешность оценки». */
.hero-duo__hint {
margin: 6px 0 0;
font-size: 11px;
line-height: 1.45;
color: var(--muted);
max-width: 44ch;
}
/* ── Компактный ряд бенчмарков под hero-duo ── */
.hero-benchmarks {
display: flex;
flex-wrap: wrap;
gap: 10px;
padding: 14px 22px;
border-bottom: 1px solid var(--border);
background: var(--surface-1, var(--bg));
}
.bench-chip {
display: flex;
flex-direction: column;
gap: 2px;
padding: 8px 12px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
min-width: 120px;
}
.bench-chip__src {
font-size: 10px;
font-weight: 600;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--muted-2);
}
.bench-chip__val {
font-size: 14px;
font-weight: 600;
letter-spacing: -0.01em;
color: var(--fg);
}
.bench-chip__sub {
font-size: 10px;
color: var(--muted);
}
/* ── empty-state headline (без данных) ── */
.headline-value-empty {
font-size: 22px;
font-weight: 600;
line-height: 1.27;
color: var(--fg);
}
.headline-note {
margin: 4px 0 0;
font-size: 12px;
line-height: 1.5;
color: var(--fg-2);
max-width: 60ch;
}
.headline-note b { font-weight: 700; }
.hero-prices-note {
margin: 0;
padding: 12px 22px 0;
font-size: 12px;
line-height: 1.5;
color: var(--muted);
}
.hero-prices-note b { color: var(--fg-2); font-weight: 600; }
.hero-bars {
padding: 18px 22px 20px;
border-bottom: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 22px;
}
.bar-block .bar-head {
display: flex; justify-content: space-between; align-items: baseline;
font-size: 12px;
color: var(--muted);
letter-spacing: 0.02em;
margin-bottom: 8px;
}
.bar-block .bar-head .bar-title { color: var(--fg-2); font-weight: 500; }
.bar-block .bar-head .bar-cv { font-family: var(--font-mono); font-size: 11px; color: var(--muted-2); }
.pricebar {
position: relative;
height: 56px;
border-bottom: 1px solid var(--border);
}
.pricebar .axis {
position: absolute;
left: 0; right: 0; top: 22px;
height: 6px;
background: var(--surface-3);
border-radius: 3px;
}
.pricebar .axis .range {
position: absolute;
top: 0; bottom: 0;
background: linear-gradient(90deg, var(--viz-1), var(--viz-2));
border-radius: 3px;
}
.pricebar .axis .median {
position: absolute;
top: -3px; bottom: -3px;
width: 2px;
background: var(--fg);
}
.pricebar .endpoint {
position: absolute;
top: 0;
transform: translateX(-50%);
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
}
.pricebar .endpoint .endpoint-val {
font: 600 13px/1 var(--font-mono);
color: var(--fg);
white-space: nowrap;
}
.pricebar .endpoint .endpoint-tick {
width: 1px;
height: 14px;
background: var(--border-strong);
margin-top: 4px;
}
.pricebar .median-label {
position: absolute;
bottom: 0;
transform: translateX(-50%);
font-family: var(--font-mono);
font-size: 11px;
color: var(--fg-2);
padding: 2px 6px;
background: var(--surface);
border: 1px solid var(--border-2);
border-radius: 4px;
white-space: nowrap;
}
.pricebar .exp {
position: absolute;
top: 36px;
font-family: var(--font-mono);
font-size: 10px;
color: var(--muted-2);
letter-spacing: 0.04em;
white-space: nowrap;
}
.pricebar .exp.left { left: 0; }
.pricebar .exp.right { right: 0; }
.hero-warnings {
padding: 18px 22px;
display: flex;
flex-direction: column;
gap: 10px;
}
.warn-row {
display: grid;
grid-template-columns: 22px 1fr;
gap: 10px;
align-items: flex-start;
font-size: 13px;
color: var(--fg-2);
line-height: 1.5;
}
.warn-row .ic {
width: 22px; height: 22px;
border-radius: 50%;
background: var(--accent-2-soft);
color: var(--accent-2);
display: grid; place-items: center;
flex-shrink: 0;
}
/* ============================================================
HERO TRUST + ACTIONS — свежесть, «как рассчитано», PDF, CTA
(web-преимущества над статичным PDF). Тема через brand --accent.
============================================================ */
.hero-trust {
padding: 14px 22px 0;
display: flex;
flex-direction: column;
gap: 12px;
}
/* ── Форма заявки на трейд-ин (issue #2377) — телефон + согласие ФЗ-152 ── */
.hero-lead {
border: 1px solid var(--border);
border-radius: 10px;
background: var(--surface-2);
padding: 14px 16px;
}
.hero-lead-form {
display: flex;
flex-direction: column;
gap: 10px;
}
.hero-lead-head {
display: flex;
align-items: center;
gap: 8px;
font-size: 13.5px;
font-weight: 600;
color: var(--fg);
}
.hero-lead-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.hero-lead-row .control {
flex: 1 1 200px;
min-width: 0;
}
.hero-lead-submit {
flex: 0 0 auto;
white-space: nowrap;
}
.hero-lead-consent {
display: flex;
align-items: flex-start;
gap: 8px;
font-size: 11.5px;
line-height: 1.4;
color: var(--fg-2);
cursor: pointer;
}
.hero-lead-consent input {
width: 14px;
height: 14px;
margin-top: 2px;
flex-shrink: 0;
cursor: pointer;
}
.hero-lead-error {
margin: 0;
font-size: 12px;
color: var(--danger);
}
.hero-lead-success {
display: flex;
align-items: center;
gap: 8px;
margin: 0;
font-size: 13.5px;
font-weight: 600;
color: var(--success, #16a34a);
}
.hero-trust-actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.hero-trust-cta {
flex: 1 1 240px;
font-weight: 600;
}
.hero-trust-pdf {
flex: 0 1 auto;
}
.hero-trust-freshness {
display: inline-flex;
align-items: center;
gap: 7px;
margin: 0;
font-size: 12.5px;
color: var(--fg-2);
}
.hero-trust-freshness .dot {
width: 7px; height: 7px;
border-radius: 50%;
background: var(--success, #16a34a);
box-shadow: 0 0 0 3px color-mix(in oklch, var(--success, #16a34a) 22%, transparent);
flex-shrink: 0;
}
.hero-trust-freshness b { color: var(--fg); font-weight: 600; }
.hero-trust-how {
border: 1px solid var(--border);
border-radius: 8px;
background: var(--surface-2);
overflow: hidden;
}
.hero-trust-how > summary {
display: flex;
align-items: center;
gap: 10px;
padding: 11px 14px;
cursor: pointer;
list-style: none;
font-size: 13px;
color: var(--fg);
user-select: none;
}
.hero-trust-how > summary::-webkit-details-marker { display: none; }
.hero-trust-how .how-title { font-weight: 600; }
.hero-trust-how .how-band {
padding: 2px 9px;
border-radius: 999px;
font-size: 11.5px;
font-weight: 500;
background: color-mix(in oklch, var(--accent) 12%, transparent);
color: var(--accent-ink);
}
.hero-trust-how .how-chevron {
margin-left: auto;
color: var(--muted);
transition: transform .15s ease;
}
.hero-trust-how[open] .how-chevron { transform: rotate(180deg); }
.hero-trust-how .how-body {
padding: 4px 14px 14px;
border-top: 1px solid var(--border);
display: flex;
flex-direction: column;
gap: 12px;
}
.hero-trust-how .how-facts {
list-style: none;
margin: 12px 0 0;
padding: 0;
display: flex;
flex-direction: column;
gap: 7px;
}
.hero-trust-how .how-facts li {
display: flex;
justify-content: space-between;
gap: 16px;
font-size: 13px;
}
.hero-trust-how .how-facts .k { color: var(--muted); }
.hero-trust-how .how-facts .v { color: var(--fg); font-weight: 500; text-align: right; }
.hero-trust-how .how-facts .v.mono { font-family: var(--font-mono); }
.hero-trust-how .how-explanation {
margin: 0;
font-size: 12.5px;
line-height: 1.5;
color: var(--fg-2);
padding: 10px 12px;
border-radius: 6px;
background: var(--surface);
border: 1px solid var(--border);
}
@media (max-width: 560px) {
.hero-trust-cta, .hero-trust-pdf { flex: 1 1 100%; }
}
/* ============================================================
FILTER + SOURCE chips
============================================================ */
.filters {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.chip {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 9px;
background: var(--surface-2);
border: 1px solid var(--border);
border-radius: 999px;
font-size: 12px;
color: var(--fg-2);
}
.chip .k { color: var(--muted); font-size: 11px; }
.chip .v { font-family: var(--font-mono); font-size: 12px; color: var(--fg); }
.sources {
display: flex;
gap: 6px;
flex-wrap: wrap;
}
.source-chip {
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 10px 4px 8px;
background: var(--surface);
border: 1px solid var(--border);
border-radius: 6px;
font-size: 12px;
color: var(--fg-2);
font-weight: 500;
letter-spacing: 0.01em;
}
.source-chip.is-error { color: var(--muted-2); }
.source-chip .src-dot {
width: 8px; height: 8px;
border-radius: 2px;
}
.source-chip .src-dot.cian { background: var(--viz-3); }
.source-chip .src-dot.avito { background: var(--viz-5); }
.source-chip .src-dot.dom { background: var(--viz-1); }
.source-chip .src-dot.yandex { background: var(--viz-4); }
.source-chip .src-dot.rosreestr { background: var(--fg); }
.source-chip .src-dot.etagi { background: var(--viz-2); }
.source-chip .src-dot.restate { background: var(--viz-2); }
.source-chip .src-dot.domrf { background: var(--accent-2); }
/* ============================================================
LISTINGS / DEALS Section (2 & 3) — count strip + filters + bar + table
============================================================ */
.count-strip {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 22px;
padding: 16px 22px;
border-bottom: 1px solid var(--border);
background: var(--surface-2);
}
.count-cell .label {
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
margin-bottom: 4px;
}
.count-cell .value {
font-family: var(--font-mono);
font-size: 20px;
font-weight: 500;
color: var(--fg);
letter-spacing: -0.02em;
}
.count-cell .value .unit {
font-size: 12px;
color: var(--muted);
margin-left: 4px;
font-weight: 400;
}
.count-cell .sub {
font-size: 11px;
color: var(--muted);
margin-top: 2px;
}
.filters-row {
display: flex;
gap: 12px;
padding: 14px 22px;
flex-wrap: wrap;
align-items: center;
border-bottom: 1px solid var(--border);
}
.filters-row .lbl {
font-size: 11px;
color: var(--muted);
letter-spacing: 0.08em;
text-transform: uppercase;
margin-right: 6px;
}
.pricebar-block {
padding: 18px 22px;
border-bottom: 1px solid var(--border);
}
table.dt {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
table.dt thead th {
text-align: left;
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
font-weight: 500;
padding: 12px 18px;
background: var(--surface-2);
border-bottom: 1px solid var(--border);
}
table.dt thead th.num,
table.dt tbody td.num { text-align: right; font-family: var(--font-mono); font-variant-numeric: tabular-nums; }
table.dt tbody td {
padding: 13px 18px;
border-bottom: 1px solid var(--border);
vertical-align: middle;
color: var(--fg);
}
table.dt tbody tr:last-child td { border-bottom: 0; }
table.dt tbody td .addr {
display: flex; flex-direction: column; gap: 2px;
}
table.dt tbody td .addr .a-main { color: var(--fg); font-weight: 500; }
table.dt tbody td .addr .a-sub { color: var(--muted); font-size: 11px; font-family: var(--font-mono); }
table.dt tbody td .src-mini {
display: inline-flex; align-items: center; gap: 4px;
padding: 2px 6px;
border: 1px solid var(--border);
border-radius: 4px;
font-size: 11px;
color: var(--muted);
}
table.dt tbody td .src-mini .src-dot { width: 6px; height: 6px; border-radius: 1.5px; }
table.dt .row-link {
display: inline-flex;
width: 22px; height: 22px;
align-items: center; justify-content: center;
color: var(--muted-2);
border-radius: 4px;
}
table.dt .row-link:hover { background: var(--surface-2); color: var(--accent); }
.table-foot {
padding: 12px 22px;
display: flex; justify-content: space-between; align-items: center;
font-size: 12px;
color: var(--muted);
background: var(--surface-2);
border-top: 1px solid var(--border);
}
.table-foot a { font-family: var(--font-mono); font-size: 12px; }
/* warning banner */
.warn-banner {
display: grid;
grid-template-columns: 22px 1fr;
gap: 12px;
align-items: flex-start;
padding: 14px 22px;
background: var(--accent-2-soft);
border-top: 1px solid color-mix(in oklch, var(--accent-2) 25%, var(--border));
font-size: 13px;
color: var(--fg-2);
line-height: 1.5;
}
.warn-banner .ic {
width: 22px; height: 22px;
border-radius: 50%;
background: color-mix(in oklch, var(--accent-2) 25%, var(--surface));
color: var(--accent-2);
display: grid; place-items: center;
flex-shrink: 0;
}
.warn-banner b { color: var(--fg); font-weight: 600; }
/* ============================================================
OFFER Section (4)
============================================================ */
/* ── Prominent «Ваша выгода» block ── */
.offer-benefit {
margin: 18px 22px 4px;
padding: 18px 22px;
border-radius: var(--radius-lg);
background: var(--success-soft);
border: 1px solid color-mix(in oklch, var(--success) 35%, var(--border));
}
.offer-benefit .ob-label {
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--success);
font-weight: 600;
}
.offer-benefit .ob-value {
font-size: 28px;
font-weight: 700;
letter-spacing: -0.01em;
color: var(--success);
margin: 4px 0 6px;
font-variant-numeric: tabular-nums;
}
.offer-benefit .ob-sub {
font-size: 12px;
color: var(--fg-2);
line-height: 1.5;
}
table.offer-tbl {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
table.offer-tbl thead th {
text-align: left;
font-size: 11px;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--muted);
font-weight: 500;
padding: 14px 18px;
background: var(--surface-2);
border-bottom: 1px solid var(--border);
}
table.offer-tbl thead th.col-trade,
table.offer-tbl thead th.col-self {
text-align: right;
}
table.offer-tbl tbody td {
padding: 14px 18px;
border-bottom: 1px solid var(--border);
vertical-align: top;
color: var(--fg);
}
table.offer-tbl tbody td.col-trade,
table.offer-tbl tbody td.col-self {
text-align: right;
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
}
table.offer-tbl tbody td.col-trade {
color: var(--success);
font-weight: 500;
letter-spacing: -0.01em;
}
table.offer-tbl tbody td.col-self {
color: var(--fg);
}
table.offer-tbl tbody td .item-name {
font-weight: 500;
color: var(--fg);
margin-bottom: 2px;
}
table.offer-tbl tbody td .item-sub {
font-size: 11px;
color: var(--muted);
}
table.offer-tbl tfoot td {
padding: 16px 18px;
background: var(--fg);
color: var(--surface);
font-weight: 600;
letter-spacing: 0.02em;
font-size: 14px;
}
table.offer-tbl tfoot td.col-trade,
table.offer-tbl tfoot td.col-self {
text-align: right;
font-family: var(--font-mono);
}
table.offer-tbl tfoot td.col-trade { color: oklch(78% 0.14 150); }
.advantages {
display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr));
gap: 14px;
padding: 22px;
border-top: 1px solid var(--border);
background: var(--surface-2);
}
.advantage {
background: var(--surface);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 16px;
display: flex;
flex-direction: column;
gap: 10px;
}
.advantage .adv-ic {
width: 32px; height: 32px;
border-radius: 8px;
background: var(--accent-soft);
color: var(--accent);
display: grid; place-items: center;
margin-bottom: 4px;
}
.advantage h3 {
font-size: 14px;
letter-spacing: -0.005em;
}
.advantage p {
font-size: 12px;
color: var(--muted);
line-height: 1.5;
}
.offer-cta {
padding: 22px;
display: flex;
gap: 12px;
justify-content: space-between;
align-items: center;
border-top: 1px solid var(--border);
background: var(--surface);
flex-wrap: wrap;
}
.offer-cta-text {
font-size: 13px;
color: var(--muted);
}
.offer-cta-text b { color: var(--fg); font-weight: 600; }
.offer-cta-buttons {
display: inline-flex; gap: 10px;
}
/* ============================================================
Footer
============================================================ */
.page-foot {
max-width: var(--container);
margin: 32px auto 0;
padding: 22px 28px 32px;
display: flex;
justify-content: space-between;
gap: 18px;
font-size: 12px;
color: var(--muted);
border-top: 1px solid var(--border);
flex-wrap: wrap;
}
.page-foot a { color: var(--muted); }
.page-foot a:hover { color: var(--fg); }
/* ============================================================
Responsive
============================================================ */
@media (max-width: 1100px) {
.layout { grid-template-columns: 1fr; }
.form-card { position: static; max-height: none; }
.hero-top { grid-template-columns: 1fr; }
.hero-duo { grid-template-columns: 1fr; }
.hero-duo--sold-primary { grid-template-columns: 1fr; }
.hero-prices { grid-template-columns: 1fr; }
.hero-photo { aspect-ratio: 16/9; }
.progress-list { grid-template-columns: 1fr; }
.advantages { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 720px) {
.page { padding: 16px 16px 64px; }
.topbar-inner { padding: 12px 16px; gap: 14px; flex-wrap: wrap; }
.top-nav { gap: 12px; }
.page-title { flex-direction: column; align-items: flex-start; }
.page-title h1 { font-size: 24px; }
.count-strip { grid-template-columns: 1fr; gap: 10px; padding: 14px 16px; }
.meta-grid { grid-template-columns: 1fr; }
table.dt thead { display: none; }
table.dt tbody td { padding: 8px 14px; display: block; border-bottom: 0; }
table.dt tbody tr { display: block; padding: 10px 0; border-bottom: 1px solid var(--border); }
table.offer-tbl, table.offer-tbl thead, table.offer-tbl tbody, table.offer-tbl tr, table.offer-tbl th, table.offer-tbl td { display: block; }
table.offer-tbl thead { display: none; }
table.offer-tbl tbody tr { padding: 10px 14px; border-bottom: 1px solid var(--border); }
table.offer-tbl tbody td { padding: 4px 0; text-align: left !important; }
.advantages { grid-template-columns: 1fr; }
.offer-cta { flex-direction: column; align-items: stretch; }
.offer-cta-buttons { justify-content: stretch; }
.offer-cta-buttons .btn { flex: 1; }
.card-head { flex-direction: column; align-items: flex-start; }
.card-head .card-meta { text-align: left; }
.offer-benefit .ob-value { font-size: 24px; }
}
/* ── Stage 4b: IMV benchmark + house info card ── */
.imv-benchmark {
margin: 16px 0;
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 12px;
background: #fafbfc;
}
.imv-benchmark--loading {
display: flex;
gap: 8px;
align-items: center;
color: #6b7280;
}
.imv-benchmark__head {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 12px;
}
.imv-benchmark__title {
font-weight: 600;
font-size: 14px;
}
.imv-benchmark__source {
font-size: 11px;
color: #6b7280;
text-decoration: none;
}
.imv-benchmark__source:hover {
text-decoration: underline;
}
.imv-benchmark__row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 16px;
}
.imv-benchmark__metric-label {
font-size: 12px;
color: #6b7280;
margin-bottom: 2px;
}
.imv-benchmark__metric-value {
font-size: 16px;
font-weight: 600;
color: #111827;
}
.imv-benchmark__compare {
margin-top: 12px;
padding-top: 12px;
border-top: 1px solid #e5e7eb;
font-size: 13px;
color: #374151;
}
/* Cian valuation card */
.cian-valuation {
margin: 16px 0;
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 12px;
background: #fff;
}
.cian-valuation__head {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 12px;
}
.cian-valuation__title {
font-size: 13px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #6b7280;
}
.cian-valuation__badge {
font-size: 12px;
font-weight: 600;
padding: 2px 7px;
border-radius: 6px;
}
.cian-valuation__badge--up {
background: #d1fae5;
color: #065f46;
}
.cian-valuation__badge--down {
background: #fee2e2;
color: #991b1b;
}
.cian-valuation__badge--neutral {
background: #f3f4f6;
color: #374151;
}
.cian-valuation__row {
display: flex;
gap: 24px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.cian-valuation__metric-label {
font-size: 12px;
color: #6b7280;
margin-bottom: 2px;
}
.cian-valuation__metric-value {
font-size: 15px;
font-weight: 500;
color: #111827;
}
.cian-valuation__metric-value--primary {
font-size: 20px;
font-weight: 700;
}
.cian-valuation__sparkline {
color: #2563eb;
}
.cian-valuation__sparkline-dates {
display: flex;
justify-content: space-between;
font-size: 11px;
color: #6b7280; /* #834 a11y: было #9ca3af (2.5:1) → AA 4.83:1 на белом */
width: 240px;
margin-top: 2px;
}
/* House info card */
.house-info-card {
margin: 16px 0;
padding: 16px;
border: 1px solid #e5e7eb;
border-radius: 12px;
background: #fff;
}
.house-info-card__head {
display: flex;
justify-content: space-between;
align-items: baseline;
margin-bottom: 12px;
}
.house-info-card__title {
font-size: 16px;
font-weight: 600;
margin: 0;
}
.house-info-card__addr {
font-size: 13px;
color: #6b7280;
margin: 0;
}
.house-info-card__rating {
display: flex;
gap: 8px;
align-items: baseline;
margin-bottom: 12px;
}
.house-info-card__rating strong {
font-size: 24px;
color: #b45309; /* #834 a11y: было #f59e0b (2.14:1) → AA large-text 5.0:1 на белом */
}
.house-info-card__rating-label {
font-size: 12px;
color: #6b7280;
}
.house-info-card__features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 8px 16px;
margin: 0;
}
.house-info-card__feature {
display: flex;
justify-content: space-between;
font-size: 13px;
padding: 4px 0;
border-bottom: 1px dotted #e5e7eb;
}
.house-info-card__feature dt {
color: #6b7280;
}
.house-info-card__feature dd {
margin: 0;
font-weight: 500;
color: #111827;
}
.house-info-card__more {
margin-top: 12px;
font-size: 12px;
color: #6b7280;
font-style: italic;
}
/* ── Stage 4c: scrapers admin pages ── */
.scraper-page {
max-width: 960px;
margin: 0 auto;
padding: 24px 20px 60px;
}
.scraper-h1 {
font-size: 22px;
font-weight: 600;
margin: 0 0 4px;
color: var(--fg-primary, #111111);
}
.scraper-subtitle {
font-size: 14px;
color: var(--fg-secondary, #5b6066);
margin: 0 0 24px;
}
.scraper-section {
margin-bottom: 24px;
padding: 20px;
background: var(--bg-card, #ffffff);
border: 1px solid var(--border-card, #e6e8ec);
border-radius: 12px;
}
.scraper-section h2 {
font-size: 16px;
font-weight: 600;
margin: 0 0 8px;
color: var(--fg-primary, #111111);
}
.scraper-hint {
font-size: 13px;
color: var(--fg-secondary, #5b6066);
margin: 0 0 16px;
}
.scraper-form {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 12px;
align-items: end;
}
.scraper-form label {
display: flex;
flex-direction: column;
font-size: 12px;
color: var(--fg-secondary, #5b6066);
gap: 4px;
}
.scraper-form label.full {
grid-column: 1 / -1;
}
.scraper-form label.checkbox {
flex-direction: row;
align-items: center;
gap: 6px;
font-size: 13px;
color: var(--fg-primary, #111111);
}
.scraper-form input,
.scraper-form select {
padding: 8px 10px;
border: 1px solid var(--border-strong, #d1d5db);
border-radius: 6px;
font-size: 14px;
background: #fff;
color: var(--fg-primary, #111111);
}
.scraper-form input:focus,
.scraper-form select:focus {
outline: 2px solid var(--accent, #1d4ed8);
outline-offset: -1px;
border-color: var(--accent, #1d4ed8);
}
.scraper-form button {
padding: 8px 16px;
background: var(--accent, #1d4ed8);
color: #fff;
border: none;
border-radius: 6px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
grid-column: 1 / -1;
justify-self: start;
}
.scraper-form button:hover:not(:disabled) {
background: var(--accent-hover, #1e40af);
}
.scraper-form button:disabled {
background: var(--border-strong, #d1d5db);
cursor: not-allowed;
}
.scraper-result {
margin-top: 16px;
padding: 12px;
background: var(--bg-card-alt, #fafbfc);
border: 1px solid var(--border-soft, #eef0f3);
border-radius: 8px;
font-size: 12px;
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
max-height: 320px;
overflow: auto;
}
.scraper-result--error {
background: var(--danger-soft, #fee2e2);
border-color: var(--danger, #b3261e);
color: var(--danger, #b3261e);
font-family: inherit;
}
.scraper-result pre {
margin: 0;
white-space: pre-wrap;
word-break: break-all;
}
/* ── Stage 4d: city sweep section ── */
.scraper-section--highlight {
border-color: var(--accent, #1d4ed8);
background: var(--accent-soft, #dbeafe);
}
.scraper-section--highlight h2 {
color: var(--accent, #1d4ed8);
}
.city-sweep-runs {
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid var(--border-card, #e6e8ec);
}
.city-sweep-runs h3 {
font-size: 14px;
font-weight: 600;
margin: 0 0 12px;
color: var(--fg-primary, #111111);
}
.runs-table {
width: 100%;
border-collapse: collapse;
font-size: 12px;
background: #ffffff;
border-radius: 6px;
overflow: hidden;
}
.runs-table thead {
background: var(--bg-card-alt, #fafbfc);
}
.runs-table th {
padding: 8px 10px;
text-align: left;
font-weight: 600;
font-size: 11px;
color: var(--fg-secondary, #5b6066);
text-transform: uppercase;
letter-spacing: 0.04em;
border-bottom: 1px solid var(--border-card, #e6e8ec);
}
.runs-table td {
padding: 8px 10px;
border-bottom: 1px solid var(--border-soft, #eef0f3);
font-variant-numeric: tabular-nums;
}
.runs-table .run-muted {
color: var(--fg-secondary, #5b6066);
font-size: 11px;
}
.run-badge {
padding: 3px 8px;
border-radius: 4px;
font-size: 11px;
font-weight: 500;
}
.run-badge--running {
background: var(--accent-soft, #dbeafe);
color: var(--accent, #1d4ed8);
}
.run-badge--done {
background: var(--success-soft, #dcfce7);
color: var(--success, #0a7a3a);
}
.run-badge--failed,
.run-badge--zombie {
background: var(--danger-soft, #fee2e2);
color: var(--danger, #b3261e);
}
.run-badge--cancelled {
background: var(--warn-soft, #fef3c7);
color: var(--warn, #9a6700);
}
.cancel-btn {
padding: 4px 10px;
background: var(--danger, #b3261e);
color: #ffffff;
border: none;
border-radius: 4px;
font-size: 11px;
cursor: pointer;
}
.cancel-btn:hover:not(:disabled) {
background: #8b1d18;
}
.cancel-btn:disabled {
background: var(--border-strong, #d1d5db);
cursor: not-allowed;
}
/* ── Stage 4e: scheduler section ── */
.scraper-section--schedule {
border-color: var(--success, #0a7a3a);
background: var(--success-soft, #dcfce7);
}
.scraper-section--schedule h2 {
color: var(--success, #0a7a3a);
}
.schedule-status {
margin-bottom: 16px;
padding: 12px;
background: #ffffff;
border-radius: 6px;
border: 1px solid var(--border-card, #e6e8ec);
}
.schedule-status__row {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
padding: 4px 0;
}
.schedule-status__label {
min-width: 140px;
color: var(--fg-secondary, #5b6066);
font-weight: 500;
}
/* ── Росреестр deeplink button ── */
.rosreestr-btn {
background: transparent;
border: 1px solid var(--border);
color: var(--muted);
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
cursor: pointer;
white-space: nowrap;
}
.rosreestr-btn:hover {
color: var(--fg);
border-color: var(--fg);
}
/* ── PR L — StreetDealsCard with paired listings (sales-vs-listings) ── */
/* Подсказка о покрытии (linkage_rate_pct) в card-head */
.linkage-hint {
margin-top: 6px;
font-size: 12px;
color: var(--muted);
line-height: 1.5;
}
.linkage-hint b {
color: var(--fg-2);
font-weight: 500;
}
/* Знак discount_pct — отрицательный = торг (success), положительный = редко (danger). */
.discount-neg { color: var(--success); }
.discount-pos { color: var(--danger); }
/* #835 a11y: визуально-скрытый текст для скринридеров (sr-only) — для пустых
th-заголовков (empty-table-header требует ТЕКСТ, не aria-label). */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
/* Ячейка listing-колонки */
.listing-cell {
min-width: 200px;
max-width: 280px;
}
.listing-empty {
color: var(--muted-2);
font-family: var(--font-mono);
font-size: 12px;
}
/* Container link / static — inline-flex с baseline alignment */
.listing-link {
display: inline-flex;
flex-wrap: wrap;
align-items: baseline;
gap: 6px;
max-width: 100%;
color: var(--fg);
text-decoration: none;
line-height: 1.4;
}
.listing-link:hover:not(.is-static) .listing-price { color: var(--accent); }
.listing-link.is-static { cursor: default; }
/* Source badge (AVITO / CIAN / YANDEX / DOMKLIK) — per ui-tokens accent-soft + accent text uppercase 11px */
.listing-source-badge {
display: inline-block;
padding: 1px 6px;
background: var(--accent-soft);
color: var(--accent-ink);
border-radius: 4px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
white-space: nowrap;
}
.listing-price {
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
font-size: 13px;
color: var(--fg);
font-weight: 500;
white-space: nowrap;
}
.listing-meta {
font-size: 11px;
color: var(--muted);
letter-spacing: 0.01em;
white-space: nowrap;
}
/* Mobile (≤720px) — listing column stacks; tables уже становятся block per existing rules */
@media (max-width: 720px) {
.listing-cell { min-width: 0; max-width: none; }
.listing-link { flex-direction: column; align-items: flex-start; gap: 2px; }
}
/* ── PR M (#564 Phase 3) — Tier badge for rosreestr deals ────────────────── */
.tier-badge {
display: inline-block;
margin-left: 6px;
padding: 1px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
vertical-align: middle;
}
.tier-t0 {
/* T0_per_house — точный кадастровый match (high confidence) */
background: var(--success-soft);
color: var(--success);
}
.tier-t1 {
/* T1_per_street — улица-уровень (open dataset default) */
background: var(--bg-card-alt);
color: #666970; /* #834 a11y: было var(--fg-tertiary)=#73767e (4.4:1) → AA 5.3:1 на #fafbfc */
}
/* ── Address precision badge (DaData qc_geo) ─────────────────────────────── */
.precision-badge {
display: inline-block;
margin-left: 6px;
padding: 1px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
vertical-align: middle;
}
.precision-house {
/* qc_geo=0 — дом определён точно (high confidence) */
background: var(--success-soft);
color: var(--success);
}
.precision-street {
/* qc_geo=1 — до улицы (neutral, как tier-t1) */
background: var(--bg-card-alt);
color: #666970; /* #834 a11y: было var(--fg-tertiary)=#73767e (4.4:1) → AA 5.3:1 на #fafbfc */
}
.precision-approx {
/* qc_geo≥2 — приблизительно. Amber-токены под «Адрес распознан неточно» disclaimer */
background: var(--accent-2-soft);
color: var(--accent-2);
}
/* ── #2002: бейдж премиального дома (рядом с адресом) ────────────────────────
Та же форма, что precision-badge; цвет — brand-accent (синий, prestige),
отличается от amber-warn и green-success. Только существующие токены. */
.premium-badge {
display: inline-block;
align-self: flex-start;
margin-bottom: 2px;
padding: 2px 8px;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
background: var(--accent-soft);
color: var(--accent-ink);
border: 1px solid color-mix(in oklch, var(--accent) 25%, var(--border));
}
/* ── #2002: баннер «рекомендуется ручная оценка» (amber, non-alarming) ───────
Под headline-числом. Те же amber-токены, что mock-address disclaimer выше. */
.manual-review {
margin: 16px 22px 0;
padding: 12px 16px;
border: 1px solid var(--accent-2);
background: var(--accent-2-soft);
border-radius: var(--radius);
color: var(--fg);
font-size: 13px;
line-height: 1.5;
}
.manual-review__head {
display: flex;
align-items: center;
gap: 8px;
font-weight: 600;
color: var(--accent-2);
}
.manual-review__icon {
display: grid;
place-items: center;
width: 18px;
height: 18px;
flex-shrink: 0;
}
.manual-review__title {
font-size: 14px;
}
.manual-review__lead {
margin: 6px 0 0;
color: var(--fg-2);
}
.manual-review__reasons {
margin: 8px 0 0;
padding-left: 18px;
display: flex;
flex-direction: column;
gap: 3px;
color: var(--fg-2);
}
.manual-review__reasons li {
line-height: 1.45;
}
/* ── «Что-если» интерактивный пересчёт (web-преимущество над PDF) ──
Компактная панель над HeroSummary: segmented ремонт + stepper/slider этаж +
numeric площадь + балкон. Делает тот же POST /estimate (debounced) и диффит
к baseline. Все цвета — через brand-токены (работает в .brand-active). */
.whatif-card {
border: 1px solid var(--accent);
box-shadow: 0 0 0 3px var(--accent-soft);
}
.whatif-head {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
padding: 16px 22px 10px;
}
.whatif-title {
font-size: 15px;
font-weight: 600;
margin: 2px 0 0;
color: var(--fg);
}
.whatif-auto {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 12px;
color: var(--muted);
cursor: pointer;
white-space: nowrap;
}
.whatif-auto input { width: 14px; height: 14px; cursor: pointer; }
.whatif-body {
padding: 4px 22px 14px;
display: flex;
flex-direction: column;
gap: 14px;
}
.whatif-field { display: flex; flex-direction: column; gap: 6px; }
.whatif-label {
font-size: 12px;
font-weight: 600;
color: var(--fg-2);
display: flex;
align-items: baseline;
gap: 6px;
}
.whatif-hint { font-size: 11px; font-weight: 400; color: var(--muted); }
.whatif-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
}
.whatif-segmented {
display: flex;
gap: 4px;
background: var(--surface-2);
padding: 4px;
border-radius: var(--radius);
border: 1px solid var(--border);
flex-wrap: wrap;
}
.whatif-seg {
flex: 1 1 auto;
min-width: 88px;
padding: 7px 8px;
font-size: 12px;
font-weight: 500;
border: 1px solid transparent;
border-radius: calc(var(--radius) - 4px);
background: transparent;
color: var(--fg-2);
cursor: pointer;
transition: background .12s, color .12s, border-color .12s;
}
.whatif-seg:hover { background: var(--surface); }
.whatif-seg.is-active {
background: var(--accent);
color: var(--surface);
border-color: var(--accent);
}
.whatif-stepper { display: flex; align-items: center; gap: 8px; }
.whatif-step-btn {
flex: 0 0 auto;
width: 30px;
height: 30px;
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 18px;
line-height: 1;
border: 1px solid var(--border);
border-radius: 8px;
background: var(--surface);
color: var(--accent);
cursor: pointer;
}
.whatif-step-btn:hover:not(:disabled) { background: var(--accent-soft); }
.whatif-step-btn:disabled { opacity: .4; cursor: not-allowed; }
.whatif-slider { flex: 1 1 auto; accent-color: var(--accent); cursor: pointer; }
.whatif-num { width: 84px; text-align: center; padding: 6px 8px; }
.whatif-balcony {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--fg);
cursor: pointer;
}
.whatif-balcony input { width: 14px; height: 14px; cursor: pointer; }
.whatif-foot {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
flex-wrap: wrap;
padding: 14px 22px;
border-top: 1px solid var(--border);
background: var(--surface-2);
border-radius: 0 0 var(--radius) var(--radius);
}
.whatif-result { display: flex; flex-direction: column; gap: 2px; min-height: 34px; justify-content: center; }
.whatif-delta { font-size: 18px; font-weight: 700; color: var(--muted); }
.whatif-delta.up { color: var(--success); }
.whatif-delta.down { color: var(--danger); }
.whatif-newprice { font-size: 12px; color: var(--muted); }
.whatif-baseline { font-size: 13px; color: var(--fg-2); }
.whatif-loading { display: inline-flex; align-items: center; gap: 7px; font-size: 13px; color: var(--muted); }
.whatif-actions { display: flex; align-items: center; gap: 8px; }
.whatif-recalc { padding: 8px 16px; }
.whatif-error {
margin: 0 22px 16px;
padding: 10px 12px;
background: var(--danger-soft);
border: 1px solid var(--danger);
border-radius: 6px;
color: var(--danger);
font-size: 12px;
}
@media (max-width: 560px) {
.whatif-row { grid-template-columns: 1fr; }
}
@keyframes ti-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
/* ============================================================
#692 — Mobile horizontal-overflow guard (≤390px)
Root causes: recharts ResponsiveContainer / Leaflet tiles /
wide comp-tables / top-nav, все push width когда flex/grid
ребёнок имеет дефолтный min-width:auto и не может ужаться.
Эти правила desktop-neutral: на ≥1100px ничего не меняют
(layout уже single-col и контент влезает), только страхуют
узкие вьюпорты от бокового скролла страницы.
============================================================ */
/* Последняя линия обороны: страница никогда не скроллится вбок.
clip (не hidden) — не создаёт scroll-container, не ломает sticky. */
html, body { overflow-x: clip; }
.page { max-width: 100%; overflow-x: clip; }
/* Каждая прямая карточка/секция результат-колонки должна уметь
ужиматься (flex-ребёнок по умолчанию min-width:auto). .result-col
уже min-width:0; добавляем то же его детям + клип переполнения. */
.result-col > * { min-width: 0; max-width: 100%; }
/* Recharts: контейнер графика всегда 100% ширины родителя и
не шире её — ResponsiveContainer мерит этот box. */
.recharts-responsive-container,
.recharts-wrapper { max-width: 100%; }
/* Leaflet-обёртка карты (MapCard) — не даём тайлам растянуть карточку. */
.card > [aria-label="Карта аналогов и сделок"] { max-width: 100%; }
/* Comp/analog-таблицы со «склейкой» listing-ячейки шире остального:
на узких вьюпортах горизонтальный скролл ВНУТРИ карточки, не страницы. */
.card > table.dt,
.card > table.offer-tbl { max-width: 100%; }
@media (max-width: 720px) {
/* Topbar: nav переносится и не выпирает за ширину бара. */
.top-nav { flex-wrap: wrap; min-width: 0; margin-left: auto; }
.topbar-inner { max-width: 100%; }
}
/* ============================================================
SALE SHARE — «доля квартир дома в продаже» (#2055 UI)
============================================================ */
.ss-banner {
max-width: var(--container);
margin: 16px auto 0;
padding: 12px 16px;
border-radius: var(--radius);
background: var(--accent-soft);
border: 1px solid var(--border);
color: var(--fg-2);
font-size: 13px;
line-height: 1.5;
}
.ss-banner.is-warn {
background: var(--accent-2-soft);
border-color: var(--accent-2);
}
.ss-banner b { color: var(--fg); }
/* Histogram strip */
.ss-hist {
display: flex;
align-items: flex-end;
gap: 6px;
height: 96px;
margin-bottom: 18px;
}
.ss-hist-col {
flex: 1 1 0;
display: flex;
flex-direction: column;
align-items: center;
gap: 4px;
min-width: 0;
height: 100%;
}
.ss-hist-count {
font-family: var(--font-mono);
font-size: 11px;
color: var(--muted);
}
.ss-hist-track {
flex: 1;
width: 100%;
display: flex;
align-items: flex-end;
justify-content: center;
}
.ss-hist-bar {
width: 100%;
max-width: 38px;
border-radius: 4px 4px 0 0;
transition: opacity 0.15s ease;
}
.ss-hist-label {
font-size: 10px;
color: var(--muted-2);
white-space: nowrap;
}
/* Window toggle (сейчас / за 45 дней) */
.ss-window-row {
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 18px;
flex-wrap: wrap;
}
.ss-window-label {
font-size: 13px;
color: var(--fg-2);
white-space: nowrap;
}
.ss-seg {
display: inline-flex;
gap: 4px;
background: var(--surface-2);
padding: 4px;
border-radius: var(--radius);
border: 1px solid var(--border);
}
.ss-seg-btn {
padding: 7px 14px;
font-size: 13px;
font-weight: 500;
border: 1px solid transparent;
border-radius: calc(var(--radius) - 4px);
background: transparent;
color: var(--fg-2);
cursor: pointer;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.ss-seg-btn:hover { background: var(--surface); }
.ss-seg-btn.is-active {
background: var(--accent);
color: var(--surface);
border-color: var(--accent);
}
.ss-seg-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 1px;
}
/* Slider */
.ss-slider-row {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
gap: 14px;
}
.ss-slider-label {
font-size: 13px;
color: var(--fg-2);
white-space: nowrap;
}
.ss-slider { width: 100%; accent-color: var(--accent); }
.ss-slider-out {
font-family: var(--font-mono);
font-size: 16px;
font-weight: 600;
color: var(--accent-ink);
min-width: 48px;
text-align: right;
}
/* Filters grid */
.ss-filters {
margin-top: 18px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 12px;
}
.ss-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.ss-field label { font-size: 12px; color: var(--muted); }
.ss-field input,
.ss-field select {
padding: 7px 10px;
border: 1px solid var(--border-strong);
border-radius: var(--radius-sm);
background: var(--surface);
color: var(--fg);
font: inherit;
font-size: 13px;
width: 100%;
}
.ss-field input:focus,
.ss-field select:focus {
outline: 2px solid var(--accent);
outline-offset: 1px;
border-color: var(--accent);
}
/* Map */
.ss-map-wrap { position: relative; width: 100%; }
.ss-map { height: 460px; width: 100%; background: var(--surface-2); }
.ss-map-empty {
display: grid;
place-items: center;
height: 460px;
padding: 24px;
text-align: center;
color: var(--muted);
font-size: 14px;
}
.ss-legend {
display: inline-flex;
align-items: center;
gap: 8px;
font-size: 11px;
color: var(--muted);
}
.ss-legend-bar {
width: 90px;
height: 8px;
border-radius: 4px;
background: linear-gradient(
90deg,
#16a34a 0%,
#ca8a04 40%,
#ea580c 65%,
#dc2626 85%,
#7f1d1d 100%
);
}
/* List table */
.ss-table-scroll { width: 100%; overflow-x: auto; }
.ss-table { width: 100%; }
.ss-th-btn {
background: none;
border: none;
padding: 0;
font: inherit;
font-weight: 600;
color: var(--fg-2);
cursor: pointer;
white-space: nowrap;
}
.ss-th-btn:hover { color: var(--accent); }
.ss-row { cursor: pointer; transition: background 0.12s ease; }
.ss-row:hover,
.ss-row.is-hovered { background: var(--surface-2); }
.ss-row.is-selected { background: var(--accent-soft); }
.ss-pct {
display: inline-block;
padding: 2px 8px;
border-radius: 999px;
font-family: var(--font-mono);
font-size: 12px;
font-weight: 600;
font-variant-numeric: tabular-nums;
}
.ss-badge {
display: inline-block;
padding: 1px 6px;
border-radius: 4px;
font-size: 11px;
line-height: 1.5;
}
.ss-badge--danger { background: var(--danger-soft); color: var(--danger); }
.ss-badge--warn { background: var(--accent-2-soft); color: var(--accent-2); }
.ss-row-btn {
padding: 5px 10px;
font-size: 12px;
white-space: nowrap;
}
/* Drawer */
.ss-drawer-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.4);
z-index: 1000;
display: flex;
justify-content: flex-end;
}
.ss-drawer {
background: var(--surface);
width: min(460px, 100%);
height: 100%;
display: flex;
flex-direction: column;
box-shadow: -8px 0 24px -8px rgba(16, 24, 40, 0.25);
}
.ss-drawer-head {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
padding: 16px 18px;
border-bottom: 1px solid var(--border);
}
.ss-drawer-close {
border: none;
background: none;
font-size: 24px;
line-height: 1;
cursor: pointer;
color: var(--muted);
padding: 0 4px;
}
.ss-drawer-close:hover { color: var(--fg); }
.ss-drawer-body { flex: 1; overflow-y: auto; padding: 12px 18px 24px; }
.ss-listing-list { list-style: none; margin: 0; padding: 0; }
.ss-listing {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 12px 0;
border-bottom: 1px solid var(--border);
}
.ss-listing-main { min-width: 0; }
.ss-listing-price {
font-weight: 600;
font-size: 15px;
color: var(--fg);
font-variant-numeric: tabular-nums;
}
.ss-listing-meta { font-size: 13px; color: var(--fg-2); margin-top: 2px; }
.ss-listing-sub { font-size: 12px; color: var(--muted); margin-top: 2px; }
.ss-listing-link {
flex-shrink: 0;
display: grid;
place-items: center;
width: 34px;
height: 34px;
border-radius: var(--radius-sm);
border: 1px solid var(--border-strong);
color: var(--accent);
}
.ss-listing-link:hover { background: var(--surface-2); text-decoration: none; }
@media (max-width: 720px) {
.ss-slider-row { grid-template-columns: 1fr auto; }
.ss-slider-label { grid-column: 1 / -1; }
.ss-hist { height: 76px; }
.ss-map, .ss-map-empty { height: 360px; }
}
/* ── Admin dashboards: audit (Feature 2) + activity (Feature 3), #2521 ── */
.admin-kpi-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 12px;
margin-bottom: 20px;
}
.admin-kpi-card {
background: var(--bg-card, #ffffff);
border: 1px solid var(--border-card, #e6e8ec);
border-radius: 10px;
padding: 14px 16px;
}
.admin-kpi-label {
font-size: 11px;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--fg-secondary, #5b6066);
}
.admin-kpi-value {
font-size: 26px;
font-weight: 600;
color: var(--fg-primary, #111111);
margin-top: 6px;
font-variant-numeric: tabular-nums;
}
.admin-days-filter {
display: flex;
gap: 8px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.admin-days-filter button {
padding: 4px 12px;
border-radius: 6px;
border: 1px solid var(--border-card, #e6e8ec);
font-size: 13px;
cursor: pointer;
background: var(--bg-card, #fff);
color: var(--fg-secondary, #5b6066);
}
.admin-days-filter button.is-active {
background: var(--accent, #1d4ed8);
border-color: var(--accent, #1d4ed8);
color: #fff;
}
.admin-row-toggle {
background: none;
border: none;
padding: 0;
font: inherit;
color: var(--accent, #1d4ed8);
cursor: pointer;
text-align: left;
}
.admin-row-toggle:hover {
text-decoration: underline;
}
.admin-drilldown {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 16px;
padding: 14px 6px;
}
.admin-drilldown h4 {
font-size: 12px;
font-weight: 600;
color: var(--fg-primary, #111111);
margin: 0 0 8px;
}
.admin-two-col {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
gap: 16px;
}