/* ============================================================
   Ростометр — сайт и кабинет.

   Направление: инженерный отчёт, а не яркий SaaS-лендинг. Продукт продаёт
   доказуемость и управление риском, поэтому интерфейс сдержанный: холодные
   нейтральные, один акцент, числа моноширинные и выровнены по разряду.

   Принципы: иерархия весом и цветом, шкала отступов 4/8/12/16/24/32/48/64,
   у каждого интерактивного элемента есть hover / active / focus-visible.
   ============================================================ */

:root {
    /* Бумага бланка измерений: холодная, с зелёным подтоном. Не крем — крем
       читается как «уютный лендинг», а здесь протокол. Все текстовые пары
       посчитаны формулой контраста, самая слабая — подпись на шапке бланка,
       4.70. */
    --ground: #EDEFE8;
    --surface: #F4F6F0;
    --surface-2: #E4E7DE;
    --surface-3: #DADED1;
    --line: #C3CABA;
    --line-soft: #D7DCCD;

    --ink-1: #1B1F1A;   /* графит с зелёным уклоном, не чёрный */
    --ink-2: #3A4137;
    --ink-3: #5A6155;
    --ink-4: #5F6759;   /* 4.70 на шапке бланка, 5.07 на бумаге — AA везде */

    --accent: #2F5D50;  /* цвет штемпельной краски */
    --accent-hover: #24483E;
    --accent-soft: #DCE6DF;
    --accent-line: #9FB6AA;
    --on-accent: #F4F6F0;

    --up: #2F5D50;      /* рост — тот же штемпель: это не «успех», а факт */
    --up-soft: #DCE6DF;
    --down: #9E3A22;    /* киноварь только под отклонения */
    --down-soft: #F2DED6;
    --warn: #8A5A12;
    --warn-soft: #F0E4CC;

    /* Тени на бумаге почти не работают: лист лежит на листе, глубину дают
       границы. Оставлены минимальными для всплывающих слоёв. */
    --shadow-sm: 0 1px 0 rgba(27, 31, 26, .06);
    --shadow: 0 1px 2px rgba(27, 31, 26, .10);
    --shadow-lg: 0 6px 18px rgba(27, 31, 26, .16);

    /* У бланка нет скруглений. Единственное исключение — круглые метки. */
    --radius: 0;
    --radius-lg: 0;
    --pill: 999px;

    /* Три роли: узкий гротеск на бланковых заголовках, серифный текст — его
       читают, а не сканируют, машинописный на числах и приборных метках.
       Все системные: веб-шрифт сдвинул бы LCP, а замеры держим на 100. */
    --narrow: "Arial Narrow", "Helvetica Neue Condensed", "Liberation Sans Narrow",
              "Roboto Condensed", system-ui, sans-serif;
    /* Charter выбывает, хотя визуально он лучший из системных серифов: замер
       показал, что он рисует неразрывный пробел на 4.6 px шире обычного (22 %),
       и текст с расставленной типографикой выглядит как текст с двойными
       пробелами. Hoefler Text ещё хуже — 9 px. У Iowan Old Style, Georgia,
       Palatino и Times New Roman разница нулевая. */
    --sans: "Iowan Old Style", "New York", Georgia, Palatino,
            "Times New Roman", serif;
    --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

    /* Движение. Кривые взяты из библиотеки, а не подобраны на глаз: вход —
       ease-out (быстрый старт читается как отзывчивость), уход — ease-in
       (ускоряется к концу и не задерживает), наведение — слабый ease-out.
       Длительностей ровно три: до этого в файле жили девять разных значений
       (90, 110, 120, 140, 160, 180, 200, 220, 260 мс), каждое подобранное
       отдельно, — и рассинхрон между соседними элементами был неизбежен. */
    --ease-out-quart: cubic-bezier(.165, .84, .44, 1);
    --ease-out-quad: cubic-bezier(.25, .46, .45, .94);
    --ease-in-quad: cubic-bezier(.4, 0, 1, 1);

    --dur-micro: 120ms;   /* наведение, нажатие, смена цвета */
    --dur-ui: 200ms;      /* появление поверхности: меню, полоса, сообщение */
    --dur-exit: 160ms;    /* её уход — пятая часть от --dur-ui, не от --dur-micro */

    --fast: var(--dur-micro) var(--ease-out-quad);
    --exit: var(--dur-exit) var(--ease-in-quad);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--ground);
    color: var(--ink-2);
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
    color: var(--ink-1);
    margin: 0;
    font-family: var(--narrow);
    /* Обычное начертание, а не жирное, и это вынужденно: у Arial Narrow нет
       жирного узкого, при 700 браузер подставляет обычный Arial Bold — замер
       показал, что там неразрывный пробел на 11.9 px шире обычного, и заголовок
       выглядит набранным с двойными пробелами. При 400 разница нулевая.
       Для бланка это и правильнее: на печатных формах заголовки набирали узким
       без жира, а вес держали кеглем и капсом. */
    font-weight: 400;
}
/* Узкий шрифт вмещает больше знаков в строку, поэтому кегль крупнее прежнего:
   заголовок бланка обязан читаться как заголовок документа. Трекинг у капса
   положительный — без него узкие буквы склеиваются. */
h1 { font-size: clamp(34px, 5.4vw, 54px); line-height: 1.02; letter-spacing: .002em; }
h2 {
    font-size: clamp(23px, 3.2vw, 33px);
    line-height: 1.12;
    letter-spacing: .012em;
    text-transform: uppercase;
}
h3 { font-size: 18px; line-height: 1.3; letter-spacing: .004em; }
p { margin: 0; }

a { color: var(--accent); text-underline-offset: 2px; }
a:hover { color: var(--accent-hover); }

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}

code {
    font-family: var(--mono);
    font-size: .88em;
    background: var(--surface-2);
    border: 1px solid var(--line-soft);
    border-radius: 4px;
    padding: .1em .35em;
}

.wrap {
    width: 100%;
    max-width: 1320px;
    margin: 0 auto;
    padding: 0 clamp(14px, 2.5vw, 24px);
}

.narrow { max-width: 760px; }

/* ---------- Шапка ---------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 50;
    background: var(--surface);
    /* Двойная линия — признак печатной формы: толстая отделяет шапку бланка от
       тела, тонкая под ней задаёт ритм. Размытие убрано: поверх бумаги оно даёт
       грязный оттенок, а лист не бывает полупрозрачным. */
    border-bottom: 2px solid var(--ink-1);
    box-shadow: 0 3px 0 -1px var(--line);
}

.topbar-inner {
    display: flex;
    align-items: center;
    gap: 24px;
    height: 62px;
}

.brand {
    display: inline-flex;
    align-items: baseline;
    gap: 9px;
    font-family: var(--narrow);
    font-weight: 400;
    font-size: 17px;
    text-transform: uppercase;
    letter-spacing: .09em;
    white-space: nowrap;
    color: var(--ink-1);
    text-decoration: none;
}

/* Знак марки — рисунок, а не заливка квадрата: обводка берёт акцентный цвет
   и работает в обеих темах без второго правила. Выравнивание по базовой линии
   у .brand выставлено под текст, поэтому знак опускается на свой оптический
   центр отдельно. */
.brand-mark {
    color: var(--accent);
    align-self: center;
    margin-block-start: -.15em;
}

.brand-sub {
    font-size: 12px;
    font-weight: 500;
    color: var(--ink-4);
    letter-spacing: 0;
}

.nav {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-left: auto;
}

.nav a {
    white-space: nowrap;
    padding: 7px 12px;
    border-radius: var(--radius);
    color: var(--ink-2);
    text-decoration: none;
    font-size: 14.5px;
    transition: background var(--fast), color var(--fast);
}
.nav a:hover { background: var(--surface-3); color: var(--ink-1); }
.nav a.active { color: var(--ink-1); font-weight: 600; }

/* Кнопка внутри навигации: без этого `.nav a` (специфичность выше, чем у
   `.btn-primary`) перекрашивала текст в тёмный, и он пропадал на тёмном фоне
   кнопки — проверено скриншотом. */
.nav a.btn-primary,
.nav a.btn-primary:hover { color: var(--on-accent); }
.nav a.btn-primary:hover { background: var(--accent-hover); }
.nav a.btn-secondary:hover { background: var(--surface); }

/* ---------- Кнопки ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 20px;
    border: 1px solid transparent;
    border-radius: var(--radius);
    /* `font: inherit` сбрасывает системный шрифт кнопки — он обязан стоять
       ВЫШЕ остальных объявлений шрифта: это сокращённая запись, и она затирает
       и семейство, и вес. Первая версия задавала их сверху, и кнопки молча
       набирались серифным вместо узкого. */
    font: inherit;
    font-family: var(--narrow);
    font-size: 15px;
    font-weight: 400;
    text-transform: uppercase;
    letter-spacing: .06em;
    white-space: nowrap;
    line-height: 1.2;
    text-decoration: none;
    cursor: pointer;
    transition: background var(--fast), border-color var(--fast), color var(--fast),
                box-shadow var(--fast), transform var(--fast);
}

.btn-primary {
    background: var(--accent);
    color: var(--on-accent);
}
.btn-primary:hover { background: var(--accent-hover); color: var(--on-accent); }
.btn-primary:active { transform: translateY(0) scale(.985); }

.btn-secondary {
    background: var(--surface);
    border-color: var(--line);
    color: var(--ink-1);
}
.btn-secondary:hover { border-color: var(--ink-4); }

.btn-ghost { background: transparent; color: var(--ink-3); padding: 7px 12px; }
.btn-ghost:hover { background: var(--surface-3); color: var(--ink-1); }

.btn-danger { background: transparent; color: var(--down); border-color: transparent; padding: 7px 12px; }
.btn-danger:hover { background: var(--down-soft); }

.btn-lg { padding: 14px 24px; font-size: 16px; }
.btn-sm { padding: 6px 12px; font-size: 13px; }

/* ---------- Лендинг ---------- */

/* Первый экран начинался с 96 px пустоты: при окне 900 px это одиннадцатая
   часть высоты ни на что. Поджато так, чтобы заголовок, кнопки и показания
   отчёта попадали в один экран без прокрутки. */
.hero { padding: clamp(36px, 5vw, 60px) 0 clamp(28px, 4vw, 48px); }

/* На широком экране правая половина первого экрана пустовала, а доказательство
   (карточка показаний) лежало под сгибом — то есть человек читал утверждение и
   не видел, чем оно подтверждается. Две колонки ставят их рядом: слева оффер,
   справа формат отчёта. Заодно первый экран становится ниже — та же задача, ради
   которой ниже ужимался отступ .proof.
   Порог 1060px совпадает с переключением меню на мобильное: ниже него колонка
   одна и порядок остаётся прежним. */
@media (min-width: 1060px) {
    .hero > .wrap {
        display: grid;
        grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
        align-items: center;
        column-gap: clamp(32px, 4vw, 64px);
    }
    .hero .proof { margin-top: 0; }
    /* В половине ширины три показания в ряд не помещаются: столбец читается как
       список замеров и не даёт сетке рассыпаться на 2+1.
       Но столбец из трёх ячеек в полный рост давал карточку в 722 px, и она,
       а не текст, задавала высоту первого экрана: кнопки уходили на 626–675 при
       окне 577. Поэтому в hero карточка идёт в сжатом наборе — те же данные,
       меньше воздуха и кегль цифр на четверть ниже. Секция ниже по странице
       остаётся в полном размере: там места сколько угодно. */
    .hero .proof-body { grid-template-columns: minmax(0, 1fr); }
    .hero .proof-cell { padding: 12px 24px; }
    .hero .proof-head { padding: 12px 24px; }
    /* Шапка и реквизиты забирали 123 и 174 px из 672 — почти половину карточки,
       хотя несут подпись, а не показания. В одну строку каждая: подпись остаётся
       читаемой, а высоту задаёт то, ради чего карточку и смотрят. */
    .hero .proof-sub { font-size: 12px; }
    .hero .proof-specs {
        display: flex;
        flex-wrap: wrap;
        gap: 1px;
        padding: 0;
    }
    .hero .proof-specs > div {
        display: flex;
        align-items: baseline;
        gap: 8px;
        flex: 1 1 auto;
        padding: 8px 24px;
    }
    .hero .proof-label { margin-bottom: 4px; }
    .hero .proof-value { font-size: 27px; }
    .hero .proof-delta { margin-top: 4px; font-size: 13px; }
    .hero .proof-foot { padding: 11px 24px; font-size: 13px; }
}

.eyebrow {
    display: inline-block;
    font-family: var(--mono);
    font-size: 11.5px;
    letter-spacing: .13em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 18px;
}

.hero h1 { max-width: 26ch; }

.hero-lead {
    margin-top: 20px;
    max-width: 58ch;
    font-size: clamp(17px, 1.7vw, 19px);
    color: var(--ink-2);
}

.hero-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 32px; }

.hero-note {
    margin-top: 16px;
    font-size: 14px;
    color: var(--ink-4);
}

/* Демонстрация сравнения групп — то, чем продукт отличается */
.proof {
    /* 56 px до блока показаний не давали первому экрану уложиться в окно
       ноутбука: замер 931 px при 900 px. Группа «заголовок → кнопки → показания»
       читается как одно целое, поэтому отступ внутри неё меньше. */
    margin-top: clamp(24px, 3.5vw, 36px);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.proof-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px 16px;
    padding: 16px 24px;
    border-bottom: 1px solid var(--line-soft);
    background: var(--surface-2);
}

.proof-title { font-size: 14px; font-weight: 640; color: var(--ink-1); }
.proof-sub { font-size: 13px; color: var(--ink-4); }

.proof-body {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr));
    /* Разделители — просвет подложки в зазоре сетки: одна честная линия в 1px
       вместо границ на ячейках, которые при переносе давали двойные и
       обрывающиеся линии. Приём взят из разбора генерации Stitch. */
    gap: 1px;
    background: var(--line-soft);
}

.proof-cell { padding: 24px; background: var(--surface); }

.proof-label {
    font-size: 12.5px;
    color: var(--ink-4);
    text-transform: uppercase;
    letter-spacing: .06em;
    margin-bottom: 10px;
}

.proof-value {
    font-family: var(--mono);
    font-size: 36px;
    font-weight: 500;
    color: var(--ink-1);
    font-variant-numeric: tabular-nums;
    line-height: 1.05;
    /* Запятая в моноширинном занимает полную ширину знака, и «6,4» читается как
       «6 , 4». Отрицательный трекинг убирает зазор, выравнивание по разрядам
       при этом сохраняется. */
    letter-spacing: -.04em;
}

.proof-delta { margin-top: 8px; font-size: 14px; font-weight: 600; }
.proof-delta.up { color: var(--up); }
.proof-delta.flat { color: var(--ink-4); }

.proof-foot {
    padding: 14px 24px;
    border-top: 1px solid var(--line-soft);
    background: var(--accent-soft);
    font-size: 14px;
    color: #0A5751;
}

/* ---------- Секции ---------- */

.section { padding: clamp(40px, 6vw, 72px) 0; }
.section + .section { border-top: 1px solid var(--line); }

.section-head { max-width: 60ch; margin-bottom: clamp(24px, 3vw, 36px); }
.section-head p { margin-top: 12px; color: var(--ink-3); }

/* Имена этих двух классов означают МИНИМАЛЬНУЮ ширину колонки, а не их число:
   при контейнере 1070 px оба дают три колонки, потому что 320 × 3 в него влезает.
   Ловушка для правящего: переключение grid-3 → grid-2 ничего не меняет. */
.grid-3 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 20px; }
.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 320px), 1fr)); gap: 20px; }

/* Сетка ровно на две колонки — для чётного числа карточек, где третья колонка
   оставляла бы последнюю сиротой в своём ряду. 400 × 2 влезает и в 1070, и в 840
   при ширине окна 900; 400 × 3 не влезает, поэтому колонок всегда две, а на узком экране одна. */
.grid-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr)); gap: 20px; }

.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 24px;
}

.card h3, .card .card-title { margin-bottom: 10px; }
.card p { color: var(--ink-3); font-size: 15px; }

/* ---------- Иконки ---------- */

/* Обводка наследует цвет текста, поэтому отдельных правил под тёмную и светлую
   тему не нужно вовсе: иконка всегда того же тона, что строка рядом с ней. */
.ico {
    flex: 0 0 auto;
    /* Базовая линия текста проходит ниже середины строчной буквы, и иконка,
       выровненная по ней, зрительно «всплывает». Сдвиг вниз на 0.15em ставит
       её оптический центр на один уровень с текстом. */
    vertical-align: -.15em;
}

/* Иконка в заголовке карточки: она называет свойство, о котором карточка, —
   две линии для контрольной группы, разброс точек для медианы, щит для
   автостопа. Акцентный цвет отделяет её от текста, но не спорит с ним по весу. */
/* Заголовок карточки: селектор охватывает и h3, и поднятый до h2 вариант —
   уровень заголовка диктует СТРУКТУРА страницы (на /contacts карточки идут
   сразу после h1 и являются вторым уровнем), а не оформление. Привязка вида к
   тегу заставляла бы выбирать между правильной иерархией и внешним видом. */
.card h3, .card .card-title {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    font-size: 17px;
    font-weight: 620;
    line-height: 1.35;
}
.card h3 .ico, .card .card-title .ico { color: var(--accent); margin-top: .1em; }

/* В таблице зон иконка кодирует решение по строке: берём, придерживаем, идём
   медленно или отказываемся. Это единственное место, где строку нужно оценить
   взглядом, не читая, — отказ должен быть виден сразу. */
.cell-icon {
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.cell-icon .ico { color: var(--ink-4); }
.cell-icon.is-yes .ico { color: var(--accent); }
.cell-icon.is-no .ico { color: var(--ink-5, var(--ink-4)); opacity: .8; }

/* .card-mark удалён вместе с нумерацией карточек: номер обязан кодировать
   порядок, а «контрольная группа», «медиана», «автостоп» и «разгон» — четыре
   независимых свойства, читаемых в любой последовательности. Настоящие шаги на
   тех же страницах размечены .step-num и нумерацию сохранили. */

/* ---------- Таблицы ---------- */

.table-wrap {
    overflow-x: auto;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
}

table { width: 100%; min-width: 560px; border-collapse: collapse; font-size: 14.5px; }

th, td { padding: 12px 18px; text-align: left; border-bottom: 1px solid var(--line-soft); }

thead th {
    background: var(--surface-2);
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ink-4);
    border-bottom: 1px solid var(--line);
    white-space: nowrap;
}

tbody tr:last-child td { border-bottom: none; }
tbody tr:hover td { background: var(--surface-2); }

td.num, th.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; }
td.num { color: var(--ink-1); font-weight: 600; }
td.muted { color: var(--ink-4); }
td.phrase { color: var(--ink-1); }

.delta-up { color: var(--up); font-weight: 640; }
.delta-down { color: var(--down); font-weight: 640; }
.delta-flat { color: var(--ink-4); }

/* ---------- Метки ---------- */

.tag {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 9px;
    border-radius: var(--pill);
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
}
.tag-control { background: var(--surface-3); color: var(--ink-3); }
.tag-working { background: var(--accent-soft); color: var(--accent); }
.tag-paused { background: var(--warn-soft); color: var(--warn); }
.tag-active { background: var(--up-soft); color: var(--up); }

/* Отбор запросов. «Вне выдачи» — не ошибка клиента и не поломка, поэтому
   киноварь отклонения здесь не годится: это факт, о котором мы сообщаем.
   Приглушённый нейтральный, а не тревожный; «далеко» и «удержание» —
   предупреждающий, потому что там работа идёт, но медленно или впустую. */
.tag-reject { background: var(--surface-3); color: var(--ink-3); text-decoration: line-through; }
.tag-slow { background: var(--warn-soft); color: var(--warn); }
.tag-hold { background: var(--surface-3); color: var(--ink-2); }

/* ---------- Тарифы ---------- */

/* Четыре тарифа: auto-fit с minmax(250px) не влезал в контейнер ровно на 4 px
   (1120 − 64 отступа = 1056 против нужных 1060), и четвёртый тариф уходил на
   вторую строку один. Полагаться на такой зазор нельзя — задаём явно. */
/* Пять тарифов: жёсткие пять колонок не читаются даже на ноутбуке —
   карточка становится уже 200px и заголовок ломается. auto-fit держит
   минимальную ширину и сам решает, сколько колонок поместится. */
/* Цена за переход рядом с числом переходов: это та величина, по которой
   человек сравнивает нас с конкурентом, и она должна быть видна без счёта
   в уме. Отдельной строкой и тише — она поясняет, а не спорит с ценой. */
.plan-unit { display: block; font-size: 12.5px; color: var(--ink-3); margin-top: 2px; }

/* Бесплатный тариф — полосой над ценами: другое предложение, другой вес.
   Горизонтальная раскладка отличает его от карточек и не даёт спутать с ними. */
.free-plan {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 16px 24px;
    padding: 20px 24px;
    margin-bottom: 24px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface-2);
}
.free-plan .hint { max-width: 64ch; margin-top: 4px; }

.plans { display: grid; gap: 16px;
         grid-template-columns: repeat(auto-fit, minmax(min(100%, 216px), 1fr)); }

@media (max-width: 1000px) { .plans { grid-template-columns: repeat(2, 1fr); gap: 20px; } }
@media (max-width: 560px) { .plans { grid-template-columns: 1fr; } }

.plan {
    display: flex;
    flex-direction: column;
    gap: 16px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 26px;
}
.plan.featured { border-color: var(--accent); border-width: 2px; }

.plan-name { font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-4); margin-bottom: 6px; }
.plan-price { font-size: 30px; font-weight: 680; color: var(--ink-1); font-variant-numeric: tabular-nums; }
.plan-price span { font-size: 14px; font-weight: 500; color: var(--ink-4); }
.plan ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 9px; font-size: 14.5px; }
.plan li { padding-left: 20px; position: relative; }
.plan li::before {
    content: "";
    position: absolute;
    left: 1px; top: .5em;
    width: 9px; height: 5px;
    border-left: 2px solid var(--accent);
    border-bottom: 2px solid var(--accent);
    border-radius: 1px;
    transform: rotate(-45deg);
}
.plan .btn { margin-top: auto; }

/* ---------- Формы ---------- */

.form-card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: clamp(24px, 4vw, 36px);
}

.field { display: flex; flex-direction: column; gap: 7px; margin-bottom: 18px; }

label { font-size: 13.5px; font-weight: 600; color: var(--ink-1); }

.hint { font-size: 13px; color: var(--ink-4); }

input[type="text"], input[type="email"], input[type="password"], input[type="url"],
select, textarea {
    width: 100%;
    padding: 10px 12px;
    font: inherit;
    font-size: 15px;
    color: var(--ink-1);
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    transition: border-color var(--fast), box-shadow var(--fast);
}

input:hover, select:hover, textarea:hover { border-color: var(--ink-4); }

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

textarea { min-height: 110px; resize: vertical; font-family: inherit; }

.checkbox { display: flex; align-items: flex-start; gap: 9px; font-size: 14.5px; color: var(--ink-2); }
.checkbox input { margin-top: 3px; }

/* Замер на 375 px: сама галочка 13×13 при ярлыке в 35 px — по ней надо
   попадать пальцем, отмечая десятки подобранных запросов подряд. Размер
   задаётся явно, потому что 13 px — это дефолт браузера, а не решение
   вёрстки; ярлык доводится до нормы 44 px и служит зоной нажатия целиком. */
@media (max-width: 1060px) {
    .checkbox { min-height: 44px; align-items: center; }
    .checkbox input[type="checkbox"] {
        width: 20px;
        height: 20px;
        margin-top: 0;
        flex: 0 0 auto;
        accent-color: var(--accent);
    }
}

/* Подобранные запросы: две колонки на широком экране, одна на телефоне.
   Список длинный — до сорока фраз, — поэтому он ограничен по высоте и
   прокручивается внутри себя: иначе кнопка «Добавить» уезжает за экран,
   и клиент не понимает, что делать с отмеченным. */
.suggest-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr));
    gap: 2px 20px;
    max-height: 340px;
    overflow-y: auto;
    padding: 4px 2px;
}
.suggest-item {
    padding: 7px 9px;
    border-radius: 8px;
    /* Наведение и фокус разделены: мышь подсвечивает строку, клавиатура —
       обводит её, иначе при обходе табом непонятно, где находишься. */
    transition: background-color 140ms ease-out;
}
.suggest-item:hover { background: var(--surface-2); }
.suggest-item:focus-within { outline: 2px solid var(--accent); outline-offset: 1px; }
.suggest-item span { line-height: 1.45; }
/* Пометка источника: фразы из подсказок поиска взяты не с сайта, и клиент
   должен видеть разницу — по ним сайт может вообще не ранжироваться. */
.suggest-origin {
    display: block;
    font-style: normal;
    font-size: 12px;
    color: var(--ink-3);
}

.form-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 220px), 1fr)); gap: 16px; }

/* ---------- Сообщения ---------- */

.flashes { display: flex; flex-direction: column; gap: 10px; margin-bottom: 22px; }

.flash {
    padding: 12px 16px;
    border-radius: var(--radius);
    border: 1px solid var(--line);
    font-size: 14.5px;
}
.flash-success { background: var(--up-soft); border-color: #BCDCC9; color: #14532D; }
.flash-error { background: var(--down-soft); border-color: #EFC5C8; color: #7A1B22; }

/* ---------- Кабинет ---------- */

.app-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 26px;
}

.app-head p { color: var(--ink-3); margin-top: 6px; }

.plan-chip {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 8px 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--pill);
    font-size: 13.5px;
    color: var(--ink-3);
}
.plan-chip b { color: var(--ink-1); font-variant-numeric: tabular-nums; }

.project-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 300px), 1fr)); gap: 20px; }

.project-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding: 22px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    text-decoration: none;
    color: inherit;
    transition: border-color var(--fast), background var(--fast), transform var(--fast);
}
.project-card:hover { border-color: var(--accent-line); background: var(--surface-2); }

.project-title { font-size: 17px; font-weight: 650; color: var(--ink-1); }
.project-url { font-size: 13.5px; color: var(--ink-4); word-break: break-all; margin-top: 4px; }

.project-stats { display: flex; flex-wrap: wrap; gap: 18px; margin-top: auto; padding-top: 12px; border-top: 1px solid var(--line-soft); }
.stat-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--ink-4);
}
.stat-label .ico { opacity: .75; }
.stat-value { font-size: 19px; font-weight: 650; color: var(--ink-1); font-variant-numeric: tabular-nums; }

.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr)); gap: 16px; margin-bottom: 24px; }

.metric {
    padding: 18px 20px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
}
/* Подпись показателя набрана капителью с разрядкой, поэтому иконка ставится
   через flex с явным зазором: inline-поток при letter-spacing добавляет к
   зазору ещё и межбуквенный интервал, и разрыв получается разным у разных
   подписей. */
.metric-label {
    display: flex;
    /* Не center: подпись из двух слов переносится («НАЙДЕНО В ВЫДАЧЕ»), и при
       центрировании иконка уезжала в промежуток между строками. Выравнивание по
       верху ставит её на первую строку независимо от числа переносов. */
    align-items: flex-start;
    gap: 7px;
    font-size: 12.5px;
    color: var(--ink-4);
    text-transform: uppercase;
    letter-spacing: .05em;
}
.metric-label .ico { opacity: .75; margin-top: .12em; }
.metric-value { font-size: 27px; font-weight: 670; color: var(--ink-1); font-variant-numeric: tabular-nums; margin-top: 6px; line-height: 1.15; }
.metric-note { font-size: 13px; color: var(--ink-3); margin-top: 4px; }

.panel {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    overflow: hidden;
    margin-bottom: 24px;
}

.panel-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 22px;
    border-bottom: 1px solid var(--line-soft);
    background: var(--surface-2);
}
.panel-head h2 { font-size: 16px; }
.panel-body { padding: 22px; }

.empty {
    padding: 40px 24px;
    text-align: center;
    color: var(--ink-3);
}
.empty-title { font-size: 16px; font-weight: 640; color: var(--ink-1); margin-bottom: 8px; }
.empty p { max-width: 46ch; margin: 0 auto; font-size: 14.5px; }

.verdict {
    padding: 16px 20px;
    border-radius: var(--radius);
    font-size: 14.5px;
    border: 1px solid var(--line);
}
.verdict-good { background: var(--up-soft); border-color: #BCDCC9; color: #14532D; }
.verdict-neutral { background: var(--surface-2); color: var(--ink-3); }
.verdict-warn { background: var(--warn-soft); border-color: #EBD5AE; color: #7A4708; }

.inline-form { display: inline; }
.inline-form + .inline-form { margin-left: 8px; }

/* ---------- Подвал ---------- */

.footer {
    padding: 36px 0 56px;
    border-top: 1px solid var(--line);
    margin-top: 48px;
    color: var(--ink-4);
    font-size: 14px;
}
.footer-inner { display: flex; flex-wrap: wrap; gap: 16px 32px; align-items: center; }
.footer a { color: var(--ink-3); text-decoration: none; }
.footer a:hover { color: var(--ink-1); }
.footer .spacer { margin-left: auto; }

.legal {
    margin-top: 18px;
    font-size: 13px;
    color: var(--ink-4);
    max-width: 78ch;
    line-height: 1.55;
}

@media (max-width: 640px) {
    .topbar-inner { height: auto; padding: 12px 0; flex-wrap: wrap; gap: 12px; }
    .nav { width: 100%; margin-left: 0; flex-wrap: wrap; }
    .proof-cell { border-right: none; border-bottom: 1px solid var(--line-soft); }
}

/* Текстовая пометка в числовой колонке.
   Без этого «нет в выдаче» наследовало моношрифт и выравнивание вправо и
   рвалось на две строки с рваными пробелами — видно на скриншоте таблицы. */
.cell-note {
    display: inline-block;
    font-family: var(--sans);
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-4);
    white-space: nowrap;
}

td.when { white-space: nowrap; font-variant-numeric: tabular-nums; font-size: 13.5px; }

/* ---------- График динамики по группам ---------- */

.chart-box { min-height: 120px; }
.chart-scroll { overflow-x: auto; }

.chart-svg { display: block; min-width: 520px; width: 100%; height: auto; overflow: visible; }

.chart-grid { stroke: var(--line); stroke-width: 1; }
.chart-axis { fill: var(--ink-4); font-size: 10px; font-variant-numeric: tabular-nums; }

/* Рабочие — акцентом, контрольные — нейтральным серым: смысл графика в том,
   что группы ведут себя ПО-РАЗНОМУ, и различать их нужно с первого взгляда */
.chart-line-working { fill: none; stroke: var(--accent); stroke-width: 2.2; stroke-linejoin: round; stroke-linecap: round; }
.chart-line-control { fill: none; stroke: var(--ink-4); stroke-width: 1.6; stroke-dasharray: 5 4; }

.chart-dot-working { fill: var(--accent); stroke: var(--surface); stroke-width: 1.4; }
.chart-dot-control { fill: var(--ink-4); stroke: var(--surface); stroke-width: 1.4; }

.chart-miss-working { stroke: var(--accent); stroke-width: 1.6; opacity: .7; }
.chart-miss-control { stroke: var(--ink-4); stroke-width: 1.6; opacity: .6; }

.chart-empty { padding: 24px 4px; font-size: 14px; color: var(--ink-3); }

/* ---------- Отчёт для заказчика ---------- */

.report-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }

.report {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: clamp(24px, 4vw, 44px);
    display: flex;
    flex-direction: column;
    gap: 28px;
}

.report-head { display: flex; flex-direction: column; gap: 6px; }
.report-meta { color: var(--ink-3); font-size: 14.5px; }

.report-summary {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
    gap: 20px;
    padding: 22px 0;
    border-top: 1px solid var(--line-soft);
    border-bottom: 1px solid var(--line-soft);
}
.report-label { font-size: 12.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--ink-4); }
.report-value { font-size: 30px; font-weight: 670; color: var(--ink-1); font-variant-numeric: tabular-nums; line-height: 1.1; margin-top: 6px; }
.report-note { font-size: 13px; color: var(--ink-3); margin-top: 4px; }

.report-method { border-top: 1px solid var(--line-soft); padding-top: 22px; }
.report-method li { font-size: 14.5px; }

/* Печать: интерфейс убираем, отчёт остаётся страницей документа */
@media print {
    .topbar, .footer, .report-actions, .flashes { display: none !important; }
    body { background: #fff; font-size: 12pt; }
    .report { border: none; border-radius: 0; padding: 0; box-shadow: none; }
    .table-wrap { border: 1px solid #ccc; overflow: visible; }
    table { min-width: 0; font-size: 10.5pt; }
    thead th { background: #f2f2f2 !important; }
    a[href]::after { content: ""; }
    .verdict { border: 1px solid #ccc; }
    @page { margin: 14mm; }
}

/* ---------- Навигация: подменю услуг ---------- */

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    padding: 10px 16px;
    background: var(--surface);
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    z-index: 100;
}
.skip-link:focus { left: 12px; top: 12px; }

.nav-menu { position: relative; }

.nav-menu > summary {
    list-style: none;
    cursor: pointer;
    padding: 7px 12px;
    border-radius: var(--radius);
    font-size: 14.5px;
    color: var(--ink-2);
    transition: background var(--fast), color var(--fast);
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.nav-menu > summary::after {
    content: "";
    display: inline-block;
    width: 5px; height: 5px;
    margin-left: 7px;
    border-right: 1.5px solid currentColor;
    border-bottom: 1.5px solid currentColor;
    transform: translateY(-2px) rotate(45deg);
}
.nav-menu > summary:hover { background: var(--surface-3); color: var(--ink-1); }
.nav-menu[open] > summary { background: var(--surface-3); color: var(--ink-1); }

.nav-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    min-width: 260px;
    display: flex;
    flex-direction: column;
    padding: 6px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: 60;
}
.nav-dropdown a { padding: 9px 12px; border-radius: var(--radius); white-space: nowrap; }

/* ---------- Хлебные крошки и компактный герой ---------- */

.crumbs { font-size: 13.5px; color: var(--ink-4); margin-bottom: 14px; }
.crumbs a { color: var(--ink-4); text-decoration: none; }
.crumbs a:hover { color: var(--ink-1); }

.hero-compact { padding: clamp(28px, 4vw, 48px) 0 clamp(20px, 3vw, 32px); }
.hero-compact h1 { max-width: 24ch; font-size: clamp(26px, 3.6vw, 38px); }

/* ---------- Шаги онбординга ---------- */

ol.steps { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }

ol.steps > li {
    display: grid;
    grid-template-columns: 64px 1fr;
    gap: 20px;
    padding: 22px 0;
    border-top: 1px solid var(--line);
}
ol.steps > li:last-child { border-bottom: 1px solid var(--line); }

.step-num {
    font-family: var(--mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--accent);
    letter-spacing: .06em;
    padding-top: 3px;
}
ol.steps h3 { margin-bottom: 6px; }
ol.steps p { color: var(--ink-3); font-size: 15px; }

/* ---------- Вопросы и ответы ---------- */

.faq { display: flex; flex-direction: column; gap: 10px; }

.faq-item {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: 0 22px;
    transition: border-color var(--fast);
}
.faq-item:hover { border-color: var(--accent-line); }

.faq-item > summary {
    list-style: none;
    cursor: pointer;
    padding: 18px 0;
    font-size: 16px;
    font-weight: 620;
    color: var(--ink-1);
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary::after {
    content: "+";
    flex: none;
    font-family: var(--mono);
    font-size: 19px;
    font-weight: 500;
    color: var(--ink-4);
    line-height: 1;
}
.faq-item[open] > summary::after { content: "−"; }
.faq-item > p { padding: 0 0 20px; color: var(--ink-2); max-width: 74ch; }

/* ---------- Полоса призыва ---------- */

.cta-band {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    margin-top: 32px;
    padding: clamp(22px, 3vw, 32px);
    background: var(--accent-soft);
    border: 1px solid var(--accent-line);
    border-radius: var(--radius-lg);
}
.cta-title { font-size: 18px; font-weight: 650; color: #0A5751; margin-bottom: 4px; }
.cta-band .hint { max-width: 60ch; }

/* ---------- Юридический документ ---------- */

.legal-doc {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    padding: clamp(22px, 3.5vw, 40px);
    display: flex;
    flex-direction: column;
    gap: 26px;
}
.legal-doc h2 { font-size: 17px; }
.legal-doc section { display: flex; flex-direction: column; gap: 10px; }
.legal-doc p { max-width: 76ch; font-size: 15px; }

/* ---------- Подвал: сетка ---------- */

.footer-grid {
    display: grid;
    grid-template-columns: 1.4fr repeat(3, 1fr);
    gap: 28px;
    padding-bottom: 28px;
}
.footer-col { display: flex; flex-direction: column; gap: 9px; align-items: flex-start; }
.footer-title {
    font-size: 12.5px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-4);
    margin-bottom: 2px;
}
.footer-about { font-size: 14px; color: var(--ink-4); max-width: 40ch; margin-top: 4px; }
.footer-bottom {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: center;
    padding-top: 20px;
    border-top: 1px solid var(--line);
    margin-top: 8px;
}

@media (max-width: 1060px) {
    .footer-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 520px) {
    .footer-grid { grid-template-columns: 1fr; }
}

/* ---------- Уведомление о cookie ---------- */

.cookie-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    width: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 9px 20px;
    background: var(--surface);
    border: none;
    border-top: 1px solid var(--line);
    border-radius: 0;
    box-shadow: var(--shadow-lg);
    font-size: 14px;
    color: var(--ink-2);
    z-index: 80;
}
.cookie-bar[hidden] { display: none; }

/* Место под полосу резервируется, пока согласие не дано, — иначе она накрывает
   последние строки футера. Браузер без :has() просто не получит резерв: полоса
   останется полосой и середину страницы не тронет. */
body:has(.cookie-bar:not([hidden])) { padding-bottom: 92px; }
@media (min-width: 700px) {
    body:has(.cookie-bar:not([hidden])) { padding-bottom: 56px; }
}

/* На широком экране полоса во всю ширину накрывает нижнюю кромку КАЖДОГО экрана,
   а не только футер: замер на окне 1280×577 показал, что кнопка «Начать
   бесплатно» (524–574) уходит под полосу (550–599) на 24 пикселя. Резерв
   padding-bottom тут не помогает — fixed-элемент вне потока. Поэтому на десктопе
   это компактная карточка у правого края: содержимое страницы прижато влево,
   и пересекаться им больше негде. На узком экране колонка одна — там полоса
   остаётся полосой, но кнопки в ней не тонут: hero там выше сгиба. */
@media (min-width: 900px) {
    .cookie-bar {
        left: auto;
        right: 20px;
        bottom: 20px;
        max-width: 460px;
        border: 1px solid var(--line);
        border-radius: var(--radius);
        padding: 10px 12px 10px 16px;
        /* Одна строка вместо двух: в два ряда карточка занимала 89 px и накрывала
           поле выбора региона в форме проекта (замер: SELECT#region под полосой).
           Полностью убрать перекрытие у плавающего элемента нельзя — можно только
           сократить его площадь до строки с кнопкой. */
        flex-wrap: nowrap;
        gap: 12px;
    }
    .cookie-bar .btn { flex: 0 0 auto; }
}

/* ============================================================
   Тёмная тема

   Переопределяются ТОЛЬКО токены: компоненты выше уже написаны через них,
   поэтому вторая тема не требует второго набора правил. Значения подобраны
   расчётом контраста, а не на глаз — все текстовые пары ≥ 4.5:1.

   Фон не чистый чёрный: #0D1117 читается как поверхность, а #000 — как дыра.
   ============================================================ */

@media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
        /* Светокопия: бумажный бланк тёмным не бывает, поэтому тёмная тема — не
           инверсия бумаги, а плёнка. Структура та же, подложка холодная. */
        --ground: #15181A;
        --surface: #1C2022;
        --surface-2: #232829;
        --surface-3: #2B3132;
        --line: #3C4446;
        --line-soft: #2A3032;

        --ink-1: #E8EDE6;
        --ink-2: #BFC7BE;
        --ink-3: #9BA49A;
        --ink-4: #98A197;

        --accent: #7FC4B2;
        --accent-hover: #9BD4C4;
        --accent-soft: #1B2E29;
        --accent-line: #34524A;
        /* Акцент на плёнке светлый: тёмный текст на нём читается, светлый — нет */
        --on-accent: #15181A;

        --up: #7FC4B2;
        --up-soft: #1B2E29;
        --down: #E8907A;
        --down-soft: #33201A;
        --warn: #D9A85F;
        --warn-soft: #2E2617;

        /* Тени на тёмном почти не видны — роль глубины берут границы */
        --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
        --shadow: 0 1px 3px rgba(0, 0, 0, .5), 0 8px 20px rgba(0, 0, 0, .35);
        --shadow-lg: 0 8px 24px rgba(0, 0, 0, .55), 0 24px 48px rgba(0, 0, 0, .4);
    }

    :root:not([data-theme="light"]) .topbar { background: rgba(21, 28, 36, .92); }

    /* Светлые «мягкие» подложки в тёмной теме требуют своего цвета текста:
       #14532D на #12291D — это тёмное на тёмном */
    :root:not([data-theme="light"]) .flash-success { background: var(--up-soft); border-color: #24583A; color: #A9E3C0; }
    :root:not([data-theme="light"]) .flash-error { background: var(--down-soft); border-color: #5E2A2E; color: #F5B8BC; }
    :root:not([data-theme="light"]) .verdict-good { background: var(--up-soft); border-color: #24583A; color: #A9E3C0; }
    :root:not([data-theme="light"]) .verdict-warn { background: var(--warn-soft); border-color: #5A4620; color: #ECC77F; }
    :root:not([data-theme="light"]) .proof-foot { color: #9FE0E6; }
    :root:not([data-theme="light"]) .cta-title { color: #9FE0E6; }
    :root:not([data-theme="light"]) .tag-active { background: var(--up-soft); color: #8FD9AE; }
    :root:not([data-theme="light"]) .tag-paused { background: var(--warn-soft); color: #E7BF77; }
    :root:not([data-theme="light"]) .tag-working { background: var(--accent-soft); color: #8FDDE5; }

    /* Печать отчёта всегда на белом: тёмный фон вылил бы тонер и не читался */
    @media print {
        body { background: #fff; color: #111; }
    }
}

/* ============================================================
   Явный выбор темы

   До этого тема бралась только из системной настройки, и человек с тёмным
   оформлением macOS не мог посмотреть светлую версию — выбора не было вообще.
   Теперь на `<html>` ставится `data-theme`, и он побеждает системную настройку.

   Правила ниже — точная копия системного блока: тот же набор токенов и те же
   переопределения компонентов, только селекторы с атрибутом. Копия сделана
   скриптом из исходного блока, а не руками, и её синхронность проверяется
   тестом: разъехавшиеся палитры дали бы текст одной темы на фоне другой.
   ============================================================ */

:root[data-theme="dark"] {
    /* Светокопия: бумажный бланк тёмным не бывает, поэтому тёмная тема — не
       инверсия бумаги, а плёнка. Структура та же, подложка холодная. */
    --ground: #15181A;
    --surface: #1C2022;
    --surface-2: #232829;
    --surface-3: #2B3132;
    --line: #3C4446;
    --line-soft: #2A3032;

    --ink-1: #E8EDE6;
    --ink-2: #BFC7BE;
    --ink-3: #9BA49A;
    --ink-4: #98A197;

    --accent: #7FC4B2;
    --accent-hover: #9BD4C4;
    --accent-soft: #1B2E29;
    --accent-line: #34524A;
    /* Акцент на плёнке светлый: тёмный текст на нём читается, светлый — нет */
    --on-accent: #15181A;

    --up: #7FC4B2;
    --up-soft: #1B2E29;
    --down: #E8907A;
    --down-soft: #33201A;
    --warn: #D9A85F;
    --warn-soft: #2E2617;

    /* Тени на тёмном почти не видны — роль глубины берут границы */
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow: 0 1px 3px rgba(0, 0, 0, .5), 0 8px 20px rgba(0, 0, 0, .35);
    --shadow-lg: 0 8px 24px rgba(0, 0, 0, .55), 0 24px 48px rgba(0, 0, 0, .4);
}

:root[data-theme="dark"] .topbar { background: rgba(21, 28, 36, .92); }

/* Светлые «мягкие» подложки в тёмной теме требуют своего цвета текста:
   #14532D на #12291D — это тёмное на тёмном */
:root[data-theme="dark"] .flash-success { background: var(--up-soft); border-color: #24583A; color: #A9E3C0; }
:root[data-theme="dark"] .flash-error { background: var(--down-soft); border-color: #5E2A2E; color: #F5B8BC; }
:root[data-theme="dark"] .verdict-good { background: var(--up-soft); border-color: #24583A; color: #A9E3C0; }
:root[data-theme="dark"] .verdict-warn { background: var(--warn-soft); border-color: #5A4620; color: #ECC77F; }
:root[data-theme="dark"] .proof-foot { color: #9FE0E6; }
:root[data-theme="dark"] .cta-title { color: #9FE0E6; }
:root[data-theme="dark"] .tag-active { background: var(--up-soft); color: #8FD9AE; }
:root[data-theme="dark"] .tag-paused { background: var(--warn-soft); color: #E7BF77; }
:root[data-theme="dark"] .tag-working { background: var(--accent-soft); color: #8FDDE5; }



/* ============================================================
   Движение

   Тайминги: 140 мс — отклик элемента, 200-260 мс — появление блока.
   Анимируются только transform и opacity: width/height/top вызывают
   пересчёт раскладки и дёргают страницу.
   ============================================================ */

@keyframes rise {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: none; }
}

.hero-copy > *,
.hero > .wrap > .proof {
    animation: rise var(--dur-ui) var(--ease-out-quart) backwards;
}
/* Порядок входа: надзаголовок → заголовок → описание → кнопки.
   Шаг 40 мс: меньше не читается как последовательность, больше выглядит вялым.
   Селекторы смотрят внутрь .hero-copy: левая колонка обёрнута ради раскладки в
   две колонки, и адресация через прямых детей .wrap перестала попадать в цель. */
.hero-copy > .eyebrow { animation-delay: 0ms; }
.hero-copy > h1 { animation-delay: 40ms; }
.hero-copy > .hero-lead { animation-delay: 80ms; }
.hero-copy > .hero-actions { animation-delay: 120ms; }
.hero-copy > .hero-note { animation-delay: 160ms; }
.hero > .wrap > .proof { animation-delay: 200ms; }

/* Разрешение анимировать переход к ключевому слову auto — объявляется здесь, а
   не на :root: свойство наследуемое, и глобально оно заряжает этим поведением
   каждый будущий переход с размерами. */
.faq { interpolate-size: allow-keywords; }

.faq-item::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size var(--dur-ui) var(--ease-out-quart),
                content-visibility var(--dur-ui) allow-discrete;
}
.faq-item[open]::details-content { block-size: auto; }

/* Уважение к системной настройке: людям с чувствительностью к движению
   анимация не «украшение», а причина закрыть страницу. */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: .01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .01ms !important;
        scroll-behavior: auto !important;
    }
    .btn-primary:hover, .project-card:hover { transform: none; }
}

/* ============================================================
   Мобильные: размер зоны нажатия

   Замер показал 33 элемента меньше 44×44 px — по пальцу это промахи.
   На узких экранах поднимаем интерактивные элементы до нормы.
   ============================================================ */

@media (max-width: 1060px) {
    .nav a,
    .nav-menu > summary,
    .nav-dropdown a,
    .footer-col a,
    .faq-item > summary {
        min-height: 44px;
        display: flex;
        align-items: center;
    }

    .btn, .btn-sm { min-height: 44px; }
    .btn-sm { padding: 8px 14px; }

    /* Поля ввода и списки — тоже цель для пальца: замер дал 42 px у select,
       на два меньше нормы. Шрифт не ниже 16 px, иначе iOS зумит форму.

       Селектор перечисляет типы, а не сокращён до `input`. Медиазапрос не
       повышает специфичность, поэтому голое `input` (0-0-1) проигрывало
       базовому `input[type="text"]` (0-1-1) — и правило про 16 px не работало
       НИ НА ОДНОМ текстовом поле сайта: ни на входе, ни на регистрации, ни в
       форме проекта. Замер на 375 px давал 15 px при живом правиле в стилях. */
    input[type="text"], input[type="email"], input[type="password"], input[type="url"],
    select, textarea { min-height: 44px; font-size: max(16px, 1rem); }

    /* Самостоятельные цели касания доводятся до нормы 44 px. Замер на 375 px:
       логотип 16 px, переключатель темы 34 px, ссылка в крошках 18 px — при
       том, что кнопки и поля до нормы уже доведены. Зона расширяется, а не
       размер знака: логотип и переключатель не должны становиться крупнее,
       им нужна площадь под палец.

       Ссылки ВНУТРИ абзацев тут не участвуют намеренно: WCAG 2.2 выводит
       inline-цели в предложении из-под требования к размеру, а вертикальный
       padding у них разъехался бы по строкам текста. */
    .brand {
        min-height: 44px;
        align-items: center;
        padding-block: 6px;
    }
    .crumbs a {
        display: inline-block;
        padding-block: 12px;
        margin-block: -12px;
    }

    /* Строки таблиц: действия «В контрольные» и «Удалить» стояли вплотную */
    td .btn-sm { min-height: 40px; margin: 2px 0; }
}

/* Явное состояние нажатия: на тач-устройствах hover не существует, и без
   :active нажатие ничем не подтверждается */
.btn { -webkit-tap-highlight-color: transparent; }
.btn:active { transform: translateY(0) scale(.985); }

/* Безопасные отступы под вырез и домашнюю полосу iOS */
.cookie-bar { padding-bottom: max(9px, env(safe-area-inset-bottom)); }
.footer { padding-bottom: max(56px, calc(40px + env(safe-area-inset-bottom))); }

/* ---------- Мобильное меню ---------- */

.nav-mobile { display: none; margin-left: auto; }

.nav-mobile > summary {
    list-style: none;
    display: flex;
    align-items: center;
    gap: 9px;
    min-height: 44px;
    padding: 0 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink-1);
    font-size: 14.5px;
    font-weight: 600;
    cursor: pointer;
}
.nav-mobile > summary::-webkit-details-marker { display: none; }

.burger {
    position: relative;
    display: block;
    width: 16px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}
.burger::before, .burger::after {
    content: "";
    position: absolute;
    left: 0;
    width: 16px;
    height: 2px;
    background: currentColor;
    border-radius: 2px;
}
.burger::before { top: -5px; }
.burger::after { top: 5px; }

.nav-mobile[open] > summary .burger { background: transparent; }
.nav-mobile[open] > summary .burger::before { top: 0; transform: rotate(45deg); }
.nav-mobile[open] > summary .burger::after { top: 0; transform: rotate(-45deg); }

.nav-mobile-panel {
    position: absolute;
    left: clamp(16px, 4vw, 32px);
    right: clamp(16px, 4vw, 32px);
    top: calc(100% + 8px);
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    z-index: 70;
}
.nav-mobile-panel a,
.nav-mobile-panel .btn-ghost {
    display: flex;
    align-items: center;
    min-height: 44px;
    padding: 0 12px;
    border-radius: var(--radius);
    color: var(--ink-2);
    text-decoration: none;
    font-size: 15px;
}
.nav-mobile-panel a:hover, .nav-mobile-panel a:active { background: var(--surface-3); color: var(--ink-1); }
.nav-mobile-panel a.active { color: var(--ink-1); font-weight: 600; }
.nav-mobile-panel .btn-primary { margin-top: 8px; justify-content: center; }

.nav-mobile-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--line-soft);
}
.nav-mobile-title {
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ink-4);
    padding: 6px 12px 2px;
}

@media (max-width: 1060px) {
    .nav-desktop { display: none; }
    .nav-mobile { display: block; }
    .topbar-inner { height: 60px; flex-wrap: nowrap; position: relative; }
    .brand { font-size: 15px; }
}

/* Cookie-баннер на телефоне занимал треть экрана */
@media (max-width: 520px) {
    .cookie-bar { font-size: 13px; padding: 12px 14px; gap: 10px; bottom: 8px; }
}

/* ============================================================
   Кнопки внутри контейнеров ссылок

   Это ТРЕТИЙ случай одного дефекта: контейнер задаёт `цвет` для `a`, его
   специфичность (0,2,0) выше, чем у `.btn-primary` (0,1,0), и текст кнопки
   перекрашивается в цвет ссылки — на акцентном фоне он пропадает. Ловилось
   только скриншотом, дважды.

   Поэтому правило собрано в одном месте и перечисляет все такие контейнеры:
   добавляя новый список ссылок, дописывать сюда.
   ============================================================ */

.nav a.btn-primary,
.nav-mobile-panel a.btn-primary,
.footer-col a.btn-primary,
.plan a.btn-primary {
    color: var(--on-accent);
    background: var(--accent);
}
.nav a.btn-primary:hover,
.nav-mobile-panel a.btn-primary:hover,
.footer-col a.btn-primary:hover,
.plan a.btn-primary:hover {
    color: var(--on-accent);
    background: var(--accent-hover);
}

.nav a.btn-secondary,
.nav-mobile-panel a.btn-secondary,
.plan a.btn-secondary { color: var(--ink-1); }

/* ---------- Заглушка графика на время загрузки ---------- */

.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;
}

.chart-skeleton {
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: 16px 0 8px;
    min-height: 200px;
}

.chart-skeleton-line {
    width: var(--w, 90%);
    height: 8px;
    border-radius: var(--pill);
    background: linear-gradient(90deg, var(--surface-3) 25%, var(--line-soft) 50%, var(--surface-3) 75%);
    background-size: 240% 100%;
    animation: shimmer 1400ms linear infinite;
}

.chart-skeleton-axis {
    margin-top: auto;
    height: 1px;
    background: var(--line);
}

@keyframes shimmer {
    from { background-position: 120% 0; }
    to { background-position: -120% 0; }
}

@media (prefers-reduced-motion: reduce) {
    .chart-skeleton-line { animation: none; background: var(--surface-3); }
}

/* ============================================================
   Приборные метки

   Технические подписи в панелях данных: моноширинный капс с разрядкой. Приём
   из разбора генерации Stitch — он усиливает характер измерительного
   инструмента, ради которого и выбрано направление.

   Метка обязана нести смысл: число замеров, дату, регион. Декоративные
   «SYS.OP.01» и поддельные строки лога, которые предлагал генератор, здесь
   не используются — это имитация данных, а продукт продаёт обратное.
   ============================================================ */

.meta-label {
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ink-4);
}

.panel-head .meta-label,
.proof-head .meta-label { margin-left: auto; }

/* Крупное число — отдельная типографская роль: моно, узкая разрядка,
   табличные цифры, чтобы колонки сходились по разряду */
.figure {
    font-family: var(--mono);
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
    color: var(--ink-1);
}

.proof-value, .metric-value, .report-value, .stat-value, .plan-price {
    font-variant-numeric: tabular-nums;
    letter-spacing: -.02em;
}

/* Подпись на акцентной подложке: ink-4 даёт на ней 4.38 — ниже AA для мелкого
   текста, поэтому здесь берём на ступень темнее (замер: 4.64) */
.cta-band .hint,
.proof-foot .hint { color: var(--ink-3); }

/* Кнопка в процессе отправки: повторный клик не проходит, и это видно.
   Точка-индикатор вместо спиннера — она не требует непрерывной анимации,
   которую пришлось бы отключать в reduced-motion. */
.btn.is-busy {
    pointer-events: none;
    opacity: .75;
}
.btn.is-busy::after {
    content: "";
    width: 6px; height: 6px;
    border-radius: 50%;
    background: currentColor;
    animation: pulse 900ms ease-in-out infinite;
}

@keyframes pulse {
    0%, 100% { opacity: .35; }
    50% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .btn.is-busy::after { animation: none; opacity: .8; }
}

/* ---------- Ошибка у поля ---------- */

/* Nielsen #9: ошибка стоит рядом с полем, которое надо исправить. В общем блоке
   сверху её не видно — исправляя форму, человек смотрит на поле. Цвет не
   единственный носитель смысла: есть текст и рамка. */
.field-error {
    font-size: 13px;
    color: var(--down);
    font-weight: 500;
}

input[aria-invalid="true"],
textarea[aria-invalid="true"] {
    border-color: var(--down);
}
input[aria-invalid="true"]:focus,
textarea[aria-invalid="true"]:focus {
    border-color: var(--down);
    box-shadow: 0 0 0 3px var(--down-soft);
}

/* ============================================================
   Финальный полиш: состояния и микродетали

   Отключённое состояние нигде не было оформлено: кнопка «Создать проект» при
   исчерпанном тарифе выглядела рабочей, и клиент жал её впустую.
   ============================================================ */

.btn:disabled,
.btn[disabled],
input:disabled,
textarea:disabled,
select:disabled {
    opacity: .55;
    cursor: not-allowed;
    /* Не .5 и не .2: при 0.5 текст уходит ниже AA, при 0.2 элемент выглядит
       исчезнувшим, и человек не понимает, что действие вообще существует */
}

.btn:disabled:hover,
.btn[disabled]:hover {
    background: var(--accent);
    transform: none;
}
.btn-secondary:disabled:hover { background: var(--surface); border-color: var(--line); }

input:disabled, textarea:disabled { background: var(--surface-2); color: var(--ink-4); }

/* Выделение текста в цветах продукта: браузерный синий выбивается из палитры */
::selection {
    background: var(--accent-soft);
    color: var(--ink-1);
}

/* Курсоры соответствуют смыслу */
summary { cursor: pointer; }
th { cursor: default; }

/* Слово без пробелов (склеенный запрос, длинный домен) не должно раздвигать
   таблицу: проверено запросом «ремонтквартирподключдешево…» в 58 символов */
td.phrase, .project-url, .legal-doc p { overflow-wrap: anywhere; }

/* Плавный переход между темами при системном переключении не нужен: он даёт
   заметную вспышку на больших областях. Явно фиксируем отсутствие. */
body, .topbar, .card, .panel { transition-property: border-color, background-color; }

/* Чип тарифа не переносился и на 320 px растягивал страницу до 374 px —
   появлялся горизонтальный скролл всего документа. Найдено свипом
   по брейкпоинтам: элемент шире вьюпорта. */
.plan-chip { flex-wrap: wrap; max-width: 100%; }

@media (max-width: 420px) {
    .plan-chip {
        gap: 4px 10px;
        font-size: 13px;
        padding: 8px 12px;
        border-radius: var(--radius);
    }
    /* Шапка кабинета на узком экране: заголовок и чип в столбец */
    .app-head { flex-direction: column; align-items: stretch; }
}

/* На 320 px название в шапке ломалось на две строки и раздувало её.
   Уменьшаем кегль и прижимаем межстрочное — умещается в одну. */
@media (max-width: 380px) {
    .brand { font-size: 13.5px; line-height: 1.2; }
    .brand-mark { width: 8px; height: 8px; box-shadow: 0 0 0 2px var(--accent-soft); }
    .nav-mobile > summary { padding: 0 10px; font-size: 13.5px; }

    /* На 320 px шапка вылезала за экран на 12 px, и горизонтально ехала вся
       страница — не только тарифы, а весь сайт. Замер: название 198 px +
       кнопка темы 16 + «Меню» 86 + отступы = 332 при экране 320. Название
       сжаться не может (white-space: nowrap), поэтому убираем подпись у
       бургера: значок остаётся, тап-таргет — тоже, за счёт min-width. */
    .burger-label { display: none; }
    .nav-mobile > summary { min-width: 44px; justify-content: center; }
}

/* ---------- Системные классы вместо инлайнов -------------------------------
   67 статических style="…" в шаблонах жили вне системы токенов: отступы 10,
   22, 28 px в обход шкалы, три разных clamp() для одного и того же заголовка
   страницы. Правило «ноль one-off значений» до этого проверялось по CSS-файлу,
   где их и не было, — а расходились именно шаблоны. -------------------------- */

.page-title { font-size: clamp(24px, 3vw, 32px); line-height: 1.18; }
.page-title-lg { font-size: clamp(26px, 3.4vw, 36px); line-height: 1.15; }
.page-title-sm { font-size: clamp(23px, 2.8vw, 30px); line-height: 1.2; }
.form-title { font-size: 24px; line-height: 1.25; margin-bottom: 8px; }
.panel-title { font-size: 18px; margin-bottom: 12px; }
.panel-title-sm { font-size: 16px; margin-bottom: 12px; }

/* Вертикальный ритм — только шаги шкалы 8/16/24/32/40. */
.stack-8 { margin-top: 8px; }
.stack-16 { margin-top: 16px; }
.stack-24 { margin-top: 24px; }
.stack-32 { margin-top: 32px; }
.stack-t-12 { margin-top: 12px; }
.stack-b-8 { margin-bottom: 8px; }
.stack-b-16 { margin-bottom: 16px; }
.stack-b-24 { margin-bottom: 24px; }
.stack-b-32 { margin-bottom: 32px; }
.stack-flush { margin: 0; }
.stack-top-flush { margin-top: 0; }

.btn-block { width: 100%; }
.note-center { text-align: center; margin-top: 16px; }
.auth-card { max-width: 420px; margin: 24px auto 0; }
.measure-60 { max-width: 60ch; }
.num-cell { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.row-inline { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.table-flush { border: none; border-radius: 0; }
.text-danger { color: var(--down); }
.section-divided { border-top: 1px solid var(--line); margin-top: 40px; }
.page-pad { padding-top: 32px; padding-bottom: 48px; }

.error-card { max-width: 520px; margin: 48px auto; text-align: center; }
.error-code {
    font-family: var(--mono);
    font-size: 13px;
    letter-spacing: .12em;
    color: var(--ink-4);
}
.error-title { font-size: 26px; margin: 12px 0 16px; }

/* ---------- Списки-пояснения ------------------------------------------------
   .plain, .warn и .burger-label стояли в разметке трёх страниц, а в CSS их не
   было: браузер рисовал дефолтные чёрные маркеры со своим отступом — ровно то,
   что выдаёт «страницу без дизайна». Найдены сверкой классов разметки со
   стилями, а не глазами: на скриншоте такой список выглядит просто «списком». */

.plain {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    gap: 10px;
}
.plain > li {
    position: relative;
    padding-left: 18px;
    color: var(--ink-2);
    line-height: 1.55;
}
.plain > li::before {
    content: "";
    position: absolute;
    left: 0;
    top: .62em;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
}
.plain > li strong { color: var(--ink-1); }

/* Список ограничений: тот же ритм, но маркер предупреждающего цвета — читается
   как «внимание», а не как перечисление возможностей. */
.plain.warn > li::before {
    background: var(--down);
    border-radius: 1px;
}

.burger-label {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-2);
    letter-spacing: -0.005em;
}

/* ---------- Движение --------------------------------------------------------
   Подъём при наведении — только там, где есть настоящий курсор. На тач-экране
   :hover залипает после тапа, и карточка остаётся приподнятой до следующего
   касания в другом месте: выглядит как зависший интерфейс. ------------------- */

@media (hover: hover) and (pointer: fine) {
    .btn-primary:hover { transform: translateY(-1px); }
    .project-card:hover { transform: translateY(-1px); }
}

/* Сообщение о результате действия («Проект создан», «Работа возобновлена»)
   возникало мгновенно — а это единственное подтверждение, что нажатие
   сработало. Короткий вход делает его замеченным, не задерживая. */
.flash { animation: rise var(--dur-ui) var(--ease-out-quart); }

/* Панель мобильного меню открывалась подстановкой: она перекрывает пол-экрана,
   и без движения непонятно, откуда взялась. Растёт из кнопки, а не из центра. */
.nav-mobile-panel {
    transform-origin: top right;
    opacity: 0;
    transform: translateY(-6px) scale(.98);
    /* Перехода на уход здесь нет намеренно. Замер: при закрытии <details>
       браузер прячет содержимое сразу (content-visibility у ::details-content),
       и прозрачность застывает на том значении, где её застали, — 0.91 в
       прогоне. Любая transition на уход тут мёртвая. Мгновенное закрытие
       меню правилам не противоречит: уход и должен ощущаться мгновенным. */
    /* 🛡️ Закрытая панель занимает 639 px и держит pointer-events: auto —
       клики по ней не проходят только потому, что <details> скрывает
       содержимое через content-visibility. Если браузер этого не сделает,
       невидимая панель перехватит половину экрана. Страховка на один рубль. */
    pointer-events: none;
}
.nav-mobile[open] > .nav-mobile-panel {
    opacity: 1;
    transform: none;
    pointer-events: auto;
    transition: opacity var(--dur-ui) var(--ease-out-quart),
                transform var(--dur-ui) var(--ease-out-quart);
}
@starting-style {
    .nav-mobile[open] > .nav-mobile-panel {
        opacity: 0;
        transform: translateY(-6px) scale(.98);
    }
}

/* Полоса уведомления о cookie: вход снизу, уход туда же и быстрее. Уход
   выполняется через класс, а не через мгновенное скрытие, иначе полоса
   исчезает рывком в момент клика. */
.cookie-bar { animation: slide-up var(--dur-ui) var(--ease-out-quart); }
.cookie-bar.is-leaving {
    transition: transform var(--exit), opacity var(--exit);
    transform: translateY(100%);
    opacity: 0;
    pointer-events: none;
}

@keyframes slide-up {
    from { transform: translateY(100%); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .nav-mobile-panel { transform: none; }
    .cookie-bar.is-leaving { transform: none; }
}

/* ============================================================
   Переходы между страницами

   Сайт серверный: каждый переход — настоящая перезагрузка документа, и
   браузер показывает вспышку между старой и новой страницей. Ведущий приём
   этого прохода — нативные View Transitions: браузер сам делает кроссфейд, JS
   не участвует вообще. Выбран он, а не «проявление секций при прокрутке»,
   потому что заметное движение на каждом блоке спорит с направлением
   «измерительный инструмент»: прибор не должен привлекать внимание к себе.

   Шапка и подвал получают имя перехода и потому не перерисовываются, а
   остаются на месте — переход читается как смена содержимого, а не страницы.
   ============================================================ */

@view-transition { navigation: auto; }

.topbar { view-transition-name: topbar; }
.footer { view-transition-name: footer; }
.cookie-bar { view-transition-name: cookie-bar; }

::view-transition-old(root) { animation: vt-out var(--dur-exit) var(--ease-in-quad) both; }
::view-transition-new(root) { animation: vt-in var(--dur-ui) var(--ease-out-quart) both; }

@keyframes vt-out { to { opacity: 0; } }
@keyframes vt-in { from { opacity: 0; transform: translateY(6px); } }

/* Постоянные элементы не двигаются вовсе: их «переход» — отсутствие перехода. */
::view-transition-group(topbar),
::view-transition-group(footer),
::view-transition-group(cookie-bar) { animation-duration: 0ms; }

@media (prefers-reduced-motion: reduce) {
    ::view-transition-old(root),
    ::view-transition-new(root) { animation: none; }
}

/* Контейнерный запрос на карточке проекта пробовался и убран. Во-первых,
   контейнером оказалась сетка во всю ширину страницы — то есть запрос отвечал
   на ширину окна, ровно как обычный медиазапрос. Во-первых-и-главное, правило
   задавало grid-template-columns элементу с display: flex и не действовало
   вообще, хотя проверка через getComputedStyle показывала «две колонки»:
   вычисленное значение существует и у неприменимого свойства. Метрики карточки
   и без него переносятся по flex-wrap, так что решать было нечего. */

/* content-visibility здесь пробовалась и убрана: заявленные 600 px на секцию
   против реальных 343–714 раздували документ на 665 px, полоса прокрутки
   показывала длину, которой нет, и страница укорачивалась по мере прокрутки.
   Выигрыш при этом нулевой — на странице нет ни одной картинки, а оценка
   производительности и до приёма была 100. Приём без измеренной пользы, но с
   заметным дефектом, в продукт не идёт. */

/* Заголовки ломаются по смыслу, а не по остатку строки. */
h2, h3, .cta-title, .plan-name { text-wrap: balance; }
.hero-lead, .section-head > p { text-wrap: pretty; }

/* Приписка под кнопкой тарифа: снимает возражение там, где принимается решение.
   Кнопка прижата к низу карточки через margin-top: auto, поэтому приписка
   должна прижиматься к ней, а не висеть отдельным блоком. */
.plan-note {
    margin-top: 10px;
    margin-bottom: 0;
    line-height: 1.4;
    text-wrap: pretty;
}

/* Подпись под карточкой проекта: когда был последний замер или что сделать,
   чтобы он появился. Без неё человек видит цифры и не знает, свежие ли они. */
.project-foot {
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--line-soft);
    font-size: 13px;
    color: var(--ink-4);
}
.project-stats .delta-up,
.project-stats .delta-down,
.project-stats .delta-flat { font-size: 19px; font-weight: 650; }
.project-stats .delta-up + .delta-down { margin-left: 8px; }

/* ---------- График двух групп в первом экране -------------------------------
   Продукт объяснялся только словами: на публичных страницах не было ни одного
   графика, хотя две линии — рабочая и контрольная — показывают суть быстрее
   любого абзаца. Классы линий и точек переиспользуются из графика кабинета,
   чтобы одна и та же сущность выглядела одинаково в двух местах. */

.proof-specs {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 150px), 1fr));
    gap: 1px;
    margin: 0;
    padding: 0;
    background: var(--line-soft);
    border-bottom: 1px solid var(--line);
}
.proof-specs > div { background: var(--surface); padding: 10px 16px; }
.proof-specs dt {
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-4);
}
.proof-specs dd {
    margin: 3px 0 0;
    font-size: 14px;
    font-weight: 500;
    color: var(--ink-1);
    overflow-wrap: anywhere;
}

.proof-plot { border-top: 1px solid var(--line); padding: 14px 10px 0; }
.proof-svg { min-width: 430px; }
/* Полоса прокрутки графика не должна выглядеть как часть бланка. */
.proof-plot .chart-scroll { padding-bottom: 4px; }
.proof-fill { fill: var(--accent); opacity: .08; }
.proof-tip {
    fill: var(--accent);
    font-family: var(--mono);
    font-size: 12px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    /* Запятая в моноширинном занимает полную ширину знака, и «6,4» читается
       как «6 , 4». Отрицательный трекинг убирает зазор, выравнивание цифр по
       разрядам при этом сохраняется. */
    letter-spacing: -.05em;
}
.proof-tip.flat { fill: var(--ink-4); }

.proof-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    padding: 8px 6px 12px;
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-3);
}
.proof-legend i {
    display: inline-block;
    width: 20px;
    height: 0;
    border-top: 2px solid;
    margin-right: 7px;
    vertical-align: middle;
}
.proof-legend .key-work { border-color: var(--accent); }
.proof-legend .key-ctrl { border-color: var(--ink-4); border-top-style: dashed; }
.proof-days { margin-left: auto; color: var(--ink-4); }

/* Вывод читается за полсекунды, абзац — нет. Метка стоит перед пояснением, а
   не вместо него: пояснение нужно тем, кто дочитывает. */
.proof-verdict {
    display: inline-block;
    margin-right: 8px;
    padding: 2px 8px;
    border: 1px solid var(--accent-line);
    border-radius: var(--radius);
    background: var(--accent-soft);
    color: var(--accent);
    font-family: var(--mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
    white-space: nowrap;
}

/* Линии чертятся по мере прокрутки — как перо самописца. Нормировка
   pathLength="1" в разметке обязательна: без неё stroke-dasharray: 1 означает
   один пиксель и черчения не будет вовсе. Точки догоняют линию, а не бегут
   впереди неё — иначе значения проступают там, где кривой ещё нет. */
/* Привязка к прокрутке здесь НЕ работает и не может: график стоит в первом
   экране, он виден с самого начала, и «входить в вид» ему некуда — замер дал
   дочерченную линию на всех позициях прокрутки. Поэтому черчение одноразовое,
   при загрузке, следом за появлением самого блока.
   900 мс — сознательное исключение из правила «UI короче 300 мс»: это не отклик
   на действие, а раскрытие данных, и оно происходит один раз. */
@media (prefers-reduced-motion: no-preference) {
    /* Привязка к прокрутке: график стоит отдельной секцией и реально входит в
       поле зрения. Пока он был в первом экране, это не работало — элемент виден
       сразу, «входить в вид» ему некуда, и замер давал дочерченную линию на
       всех позициях прокрутки. */
    @supports (animation-timeline: view()) {
        .proof-draw {
            stroke-dasharray: 1;
            animation: proof-draw linear both;
            animation-timeline: view();
            animation-range: entry 10% cover 45%;
        }
        /* Точки и подписи догоняют линию, а не бегут впереди: иначе значения
           проступают там, где кривой ещё нет. */
        .proof-dot, .proof-tip, .proof-fill {
            animation: proof-soak linear both;
            animation-timeline: view();
            animation-range: cover 35% cover 55%;
        }
    }
    /* Там, где привязки к прокрутке нет, черчение идёт один раз при загрузке. */
    @supports not (animation-timeline: view()) {
        .proof-draw {
            stroke-dasharray: 1;
            animation: proof-draw 900ms cubic-bezier(.33, 0, .3, 1) 260ms both;
        }
        .proof-dot, .proof-tip, .proof-fill {
            animation: proof-soak 420ms ease-out 820ms both;
        }
    }
}
@keyframes proof-draw { from { stroke-dashoffset: 1 } to { stroke-dashoffset: 0 } }
@keyframes proof-soak { from { opacity: 0 } }

/* ---------- Переключатель оформления ---------------------------------------
   Тема бралась только из системной настройки: человек с тёмным оформлением
   macOS не мог посмотреть светлую версию вообще. Кнопка циклит три состояния —
   как в системе, светлое, тёмное; выбор запоминается. Иконка меняется вместе с
   состоянием, а подпись живёт в aria-label и title, потому что в шапке нет
   места на слово. */

.theme-switch {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--surface);
    color: var(--ink-3);
    cursor: pointer;
    transition: border-color var(--fast), color var(--fast), background var(--fast);
}
.theme-switch:hover { border-color: var(--accent-line); color: var(--accent); }
.theme-switch:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* Размер под палец объявляется ПОСЛЕ базового правила, а не в общем мобильном
   блоке выше: медиазапрос не повышает специфичность, и при равном весе
   побеждает то правило, что ниже по файлу. Замер это и показал — 34 px
   оставались на месте при живом правиле в мобильном блоке. */
@media (max-width: 1060px) {
    .theme-switch { width: 44px; height: 44px; }
}

/* Иконка рисуется границами, без файлов и без шрифта значков: половина круга
   для системного режима, светлый круг и серп — для явных. */
.theme-icon {
    width: 14px;
    height: 14px;
    border: 1.6px solid currentColor;
    border-radius: 50%;
    position: relative;
    overflow: hidden;
}
.theme-icon::after {
    content: "";
    position: absolute;
    inset: 0 50% 0 0;
    background: currentColor;
}
/* Светлое: полный круг с лучом-обводкой */
.theme-switch[data-mode="light"] .theme-icon::after { inset: 0 100% 0 0; }
.theme-switch[data-mode="light"] .theme-icon {
    box-shadow: 0 0 0 2px var(--surface), 0 0 0 3.4px currentColor;
    width: 10px;
    height: 10px;
}
/* Тёмное: серп — круг с вырезом */
.theme-switch[data-mode="dark"] .theme-icon::after {
    inset: -3px -5px -3px 3px;
    border-radius: 50%;
    background: var(--surface);
}

/* На широких экранах вторая кнопка не нужна: она уже стоит в навигации.
   Правило обязано идти ДО медиазапроса — при равной специфичности побеждает то,
   что записано позже, и обратный порядок скрывал кнопку на мобильном, где она
   как раз единственная. */
.topbar-inner > .theme-switch { display: none; }

@media (max-width: 1060px) {
    /* Кнопка переезжает из скрытой навигации в саму шапку, рядом с бургером:
       оформление меняют до того, как открывают меню, а не внутри него. */
    .nav-desktop .theme-switch { display: none; }
    .topbar-inner > .theme-switch { display: inline-flex; margin-left: auto; }
    .nav-mobile { margin-left: 8px; }
}

/* ---------- Полотно графика как лист бланка ---------------------------------
   Один компонент на три страницы: шапка с подписями, поле графика, легенда.
   Классы линий переиспользуются из графика кабинета — одна сущность выглядит
   одинаково всюду, где её показывают. */

.plot { border: 1px solid var(--ink-1); background: var(--surface); }
.plot-head {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 18px;
    align-items: baseline;
    padding: 9px 14px;
    border-bottom: 1px solid var(--ink-1);
    background: var(--surface-2);
    font-family: var(--mono);
    font-size: 11px;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink-3);
}
.plot-right { margin-left: auto; color: var(--ink-4); }
.plot .chart-scroll { padding: 14px 10px 6px; }

.plot-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 20px;
    padding: 9px 14px;
    border-top: 1px solid var(--line);
    font-family: var(--mono);
    font-size: 10.5px;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--ink-3);
}
.plot-legend i,
.proof-legend i {
    display: inline-block;
    width: 20px;
    height: 0;
    border-top: 2px solid;
    margin-right: 7px;
    vertical-align: middle;
}
.key-work { border-color: var(--accent); }
.key-ctrl { border-color: var(--ink-4); border-top-style: dashed; }
.key-drop { border-color: var(--down); }

/* Линии медианы и среднего: медиана — рабочая, среднее — то, чему верить нельзя,
   поэтому оно сигнальным цветом и пунктиром. */
.proof-median { stroke: var(--accent); stroke-width: 1.6; }
.proof-mean { stroke: var(--down); stroke-width: 1.6; stroke-dasharray: 4 4; }

/* Полоса дневной квоты: диапазон, а не линия. */
.proof-fill-band { fill: var(--accent); opacity: .14; }

/* Просадка и отметка остановки — единственное место сигнального цвета. */
.proof-line-drop { fill: none; stroke: var(--down); stroke-width: 2.2; stroke-linejoin: round; }
.proof-dot-drop { fill: var(--down); }
.proof-stop { stroke: var(--down); stroke-width: 1.4; stroke-dasharray: 3 3; }
.proof-tip.warn { fill: var(--down); }

/* ---------- Публичная проверка сайта ---------- */

/* Поле и кнопка в одну строку на десктопе и в столбик на телефоне. Кнопка не
   ужимается: на узком экране первым переносится поле, а не действие. */
.check-form { margin-top: 8px; }
.check-row {
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
    align-items: stretch;
}
.check-row input {
    flex: 1 1 260px;
    min-width: 0;
}
.check-row .btn { flex: 0 0 auto; }

/* Найденные запросы — плитками, а не списком: их два-три десятка, и колонка
   в один столбец растянула бы страницу на два экрана ради перечисления. */
.check-tags {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 20px 24px;
}

.check-next {
    padding: 20px 24px;
    border-top: 1px solid var(--line-soft);
    background: var(--surface-2);
}
.check-next p { color: var(--ink-3); font-size: 15px; max-width: 74ch; }
.check-next .hero-actions { margin-top: 18px; }

/* Заголовок панели с иконкой: без flex-зазора знак прилипает к первой букве. */
.panel-title { display: inline-flex; align-items: center; gap: 8px; }
.panel-title .ico { color: var(--accent); }

/* --- админка --------------------------------------------------------------- */

.table-scroll { overflow-x: auto; }

.admin-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
}
.admin-table th, .admin-table td {
    text-align: left;
    padding: 8px 12px;
    border-bottom: 1px solid var(--line-soft);
    vertical-align: middle;
    white-space: nowrap;
}
.admin-table th {
    color: var(--ink-3);
    font-weight: 600;
    font-size: 12.5px;
    text-transform: uppercase;
    letter-spacing: .04em;
}
.admin-table td code { font-size: 12.5px; }

.admin-table select {
    font: inherit;
    color: inherit;
    background: var(--surface-2);
    border: 1px solid var(--line-soft);
    border-radius: 8px;
    padding: 5px 8px;
}

.input {
    font: inherit;
    color: var(--ink-1);
    background: var(--surface-2);
    border: 1px solid var(--line-soft);
    border-radius: 8px;
    padding: 8px 10px;
    width: 100%;
}
.input-sm { width: 92px; }
.input:focus { outline: 2px solid var(--accent-soft); border-color: var(--accent); }

.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
    gap: 16px;
    margin-bottom: 20px;
}
.form-grid label {
    display: flex;
    flex-direction: column;
    gap: 6px;
    font-size: 13.5px;
    color: var(--ink-2);
}
.form-grid .pair { display: inline-flex; align-items: center; gap: 6px; }

.tag-ok { background: var(--up-soft); color: var(--up); }

.tag-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0 18px; }

.bot-log {
    background: var(--surface-2);
    border: 1px solid var(--line-soft);
    border-radius: 10px;
    padding: 14px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.55;
    color: var(--ink-2);
    white-space: pre-wrap;
    word-break: break-word;
    max-height: 420px;
    overflow-y: auto;
}
