/*
  Визуальный язык обоих приложений — общая оболочка (@build/ui).

  Здесь только то, что не знает ни про розетки, ни про венцы: тема и её
  переменные, раскладка окна, вкладки, кнопки, панели, поля, замечания,
  холст, лист, строка состояния, вход, облако, вводные, «Почему?».
  Доменное — знаки электроточек, редактор групп, знаки бруса — живёт в
  таблице стилей своего приложения и подключается ПОСЛЕ этой.

  --accent / --accent-2 — акцент оболочки. В apps/web они называются
  --pe-green / --pe-yellow (цвета взяты из маркировки жил: PE — жёлто-
  зелёный) и объявлены там алиасами: имя из электрики в общем пакете было бы
  той самой утечкой домена, которую пакет и должен исключать.
*/
:root {
  --paper: #f1f3ee;
  --panel: #fbfcfa;
  --sunk: #e7eae3;
  --ink: #161a16;
  --ink-2: #474e46;
  --ink-3: #757c73;
  --line: #d3d8cd;
  --line-2: #b9c0b2;

  --accent: #3e8e41;
  --accent-2: #c8ae12;
  --danger: #b33a2b;
  --warn: #b57a16;

  /*
    Второй акцент линейки — для страницы выбора вида проекта (`suite.ts`),
    единственного места, где оболочке нужно различить «Электрику» и «Дом из
    бруса» цветом, а не только текстом. Значение то же, что у `--timber` в
    apps/timber/styles.css: там оно для знаков бруса на чертеже, здесь — для
    идентичности вида проекта; совпадение цвета не случайно, но переменные
    разные по смыслу, и дублирование дешевле, чем протаскивать доменный цвет
    в общий пакет через импорт.
  */
  --kind-timber: #b07d3a;

  --wall: #23281f;
  --room: #e4e8dd;
  --glass: #7fb3c9;

  --mono: ui-monospace, "Cascadia Mono", Consolas, "SF Mono", monospace;
  /*
    Arial Narrow есть в Windows, но не в Linux и не всегда в macOS — там
    список без «Liberation Sans Narrow» тихо падал до обычного system-ui, и
    единственный узкий акцент интерфейса (имя проекта, суммы, заголовки
    листов) переставал быть узким без всякого предупреждения. Liberation
    Sans Narrow — метрический аналог Arial Narrow, идёт по умолчанию в
    большинстве дистрибутивов (пакет liberation-fonts).
  */
  --display: "Arial Narrow", "Liberation Sans Narrow", "Helvetica Neue", system-ui, sans-serif;

  /* Скругление: маленькое — на кнопках, полях, чипах; крупное — на карточках. */
  --radius: 5px;
  --radius-lg: 8px;

  /*
    Текст на закрашенной кнопке (`.btn.primary`). Один и тот же цвет в обеих
    темах: оба варианта `--accent` — среднего тона (не тёмный и не яркий), и
    тёмный текст даёт нужный контраст 4.5:1 что на светлом-зелёном, что на
    тёмном-зелёном фоне; светлый текст на светлой теме этот порог не проходит.
  */
  --on-accent: #12160f;

  /* И тема, и переключатель темы — только через prefers-color-scheme, своего
     переключателя в интерфейсе нет, поэтому значение здесь одно и не по
     медиа-запросу: браузер сам решает по ОС, каким рисовать то, что не
     стилизовано руками (нативный <select>, чекбоксы, полосы прокрутки). */
  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper: #0f120f;
    --panel: #161a16;
    --sunk: #1c211b;
    --ink: #e6eae3;
    --ink-2: #a7afa5;
    --ink-3: #7a8278;
    --line: #2a302a;
    --line-2: #3b433a;
    --accent: #5fb363;
    --accent-2: #dfc53f;
    --danger: #e07162;
    --warn: #dda44b;
    --kind-timber: #d7a35c;
    --wall: #c9d0c4;
    --room: #1e241d;
    --glass: #5c8fa8;
  }
}

* { box-sizing: border-box; }

html, body { height: 100%; margin: 0; }

body {
  background: var(--paper);
  color: var(--ink);
  font: 14px/1.45 system-ui, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

.app {
  height: 100%;
  display: grid;
  grid-template-columns: 232px minmax(0, 1fr) 272px;
  grid-template-rows: auto minmax(0, 1fr) auto;
  grid-template-areas:
    "bar bar bar"
    "left canvas right"
    "status status status";
}

.app[data-mode="estimate"] {
  grid-template-areas:
    "bar bar bar"
    "sheet sheet sheet"
    "status status status";
}
.view3d { grid-area: canvas; display: none; }
.app[data-mode="view3d"] .view3d { display: block; }
.app[data-mode="view3d"] #canvas-wrap { display: none; }
#view3d { display: block; width: 100%; height: 100%; cursor: grab; }
#view3d:active { cursor: grabbing; }

/* Раздел «Проекты» занимает экран так же, как смета: список во всю ширину.
   «Вводные» и «Люди» — тоже: там сплошной текст с полями и таблица, холст и
   панели ни при чём. */
.app[data-mode="projects"],
.app[data-mode="admin"],
.app[data-mode="intake"] {
  grid-template-areas:
    "bar bar bar"
    "sheet sheet sheet"
    "status status status";
}

.app[data-mode="estimate"] .left,
.app[data-mode="estimate"] .right,
.app[data-mode="estimate"] .canvas-wrap,
.app[data-mode="projects"] .left,
.app[data-mode="projects"] .right,
.app[data-mode="projects"] .canvas-wrap,
.app[data-mode="intake"] .left,
.app[data-mode="intake"] .right,
.app[data-mode="intake"] .canvas-wrap,
.app[data-mode="admin"] .left,
.app[data-mode="admin"] .right,
.app[data-mode="admin"] .canvas-wrap { display: none; }

.app:not([data-mode="estimate"]) #sheet { display: none; }
.app:not([data-mode="projects"]) #cloud { display: none; }
.app:not([data-mode="admin"]) #admin { display: none; }
.app:not([data-mode="intake"]) #intake { display: none; }

/* ── Вводные по объекту ──────────────────────────────────────────────── */

/* Три блока в ряд на широком экране, в столбик на узком. Поле и пояснение
   к нему стоят подряд: пояснение — часть вопроса, а не сноска. */
.intake-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 8px 28px;
  align-items: start;
  max-width: 1100px;
}
.intake-block { min-width: 0; }
.intake-field { padding-top: 10px; }
.intake-field > span { flex: 1 1 auto; }
.intake-field input, .intake-field select { flex: 0 1 auto; max-width: 58%; }
.intake-block .help.aside { margin-top: 2px; }
.intake-block .notice { margin-top: 8px; }
.notice.quiet { border-color: var(--line); color: var(--ink-3); }

/* ── Проекты на сервере ──────────────────────────────────────────────── */

.cloud-form { max-width: 340px; display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; }
.cloud-form .btn { margin-top: 8px; }
.cloud-who { float: right; display: flex; align-items: center; gap: 10px; font-size: var(--text-sm); color: var(--ink-3); font-family: var(--mono); }
/* Логин — данные, моноширинный уместен; кнопка внутри — действие, а не
   значение, и должна звучать как остальные кнопки экрана. */
.cloud-who .btn { font-family: system-ui, "Segoe UI", Roboto, sans-serif; }
.cloud-current { max-width: 420px; margin-bottom: 8px; }
.cloud-current .btn { margin-top: 8px; }
.cloud-actions { display: flex; gap: 6px; justify-content: flex-end; }
table.est tr.current td { background: var(--sunk); }

/* Заблокированный виден в списке, но приглушён: он не удалён, он не входит. */
table.est tr.blocked td { color: var(--ink-3); }
table.est tr.blocked td.name { text-decoration: line-through; }

.sync-ok { color: var(--accent); }
.sync-wait { color: var(--warn); }
.sync-no { color: var(--ink-3); }

/* ── Экран входа ─────────────────────────────────────────────────────── */

/* position: fixed выносит его из грид-раскладки .app — перекрывает всё,
   независимо от того, какая вкладка была открыта. */
.auth-gate {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--paper);
}
.auth-gate[hidden] { display: none; }

.auth-card { width: 100%; max-width: 320px; padding: 24px; }

.auth-logo { display: block; width: 100%; max-width: 260px; height: auto; margin: 0 0 28px; }

.field-check {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 2px 0 6px;
  font-size: var(--text-sm);
  color: var(--ink-2);
}
.field-check input { accent-color: var(--accent); }

.pw-wrap { display: flex; align-items: center; gap: 4px; }
.pw-toggle {
  flex: none;
  border: none;
  background: none;
  color: var(--ink-3);
  font-size: 14px;
  line-height: 1;
  padding: 4px;
  cursor: pointer;
}
.pw-toggle:hover { color: var(--ink); }
.pw-toggle:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ── Верхняя панель ─────────────────────────────────────────────────── */

.bar {
  grid-area: bar;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 8px 12px;
  background: var(--sunk);
  border-bottom: 1px solid var(--line);
}

.project-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 15px;
  background: transparent;
  border: 1px solid transparent;
  color: var(--ink);
  padding: 3px 6px;
  min-width: 180px;
}
.project-name:hover { border-color: var(--line-2); }
.project-name:focus { outline: none; border-color: var(--accent); background: var(--panel); }

.tabs { display: flex; gap: 2px; margin-left: auto; }

.tab {
  font: inherit;
  font-size: 13px;
  padding: 5px 14px;
  border: 1px solid transparent;
  border-radius: var(--radius) var(--radius) 0 0;
  background: transparent;
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color .12s ease, color .12s ease;
}
.tab:hover { color: var(--ink); background: var(--panel); }
.tab[aria-selected="true"] {
  background: var(--panel);
  border-color: var(--line-2);
  color: var(--ink);
  font-weight: 600;
}
.tab:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.bar-actions { display: flex; gap: 4px; }

/*
 * Шапка не вылезает за экран ни при какой ширине.
 *
 * `.bar` — flex без переноса, а вкладки и кнопки по тексту не сжимаются:
 * стоит им перестать помещаться, лишнее просто уезжает за кромку окна —
 * без скролла и без намёка, что оно вообще есть. Раньше это лечилось только
 * ниже 900px, но набор вкладок с тех пор вырос, и та же беда пришла на
 * обычный ноутбук: при 1280px «Очистить» уже за краем.
 *
 * Поэтому ленты сжимаются как КОНТЕЙНЕРЫ (`min-width: 0`) и прокручиваются,
 * а их содержимое остаётся читаемого размера (`flex-shrink: 0` на детях).
 * Пока всё помещается, полоса прокрутки не появляется и вид прежний.
 */
.tabs, .bar-actions {
  flex: 0 1 auto;
  min-width: 0;
  overflow-x: auto;
  scrollbar-width: thin;
  -webkit-overflow-scrolling: touch;
}
.tab, .bar-actions > * { flex-shrink: 0; }

/*
 * На планшете (768px) и уже шапка не помещается с запасом, поэтому к общему
 * правилу (см. `.tabs, .bar-actions` выше) добавляется сжатие имени проекта:
 * иначе оно съедает ширину, которой не хватает вкладкам. Перенос в две
 * строки не годится — он съедает высоту холста, которой и так мало.
 */
@media (max-width: 900px) {
  .bar { gap: 8px; }
  .project-name { min-width: 90px; flex: 0 1 140px; }
  /* Вкладкам отдаётся весь остаток: на планшете это главный способ
     переключаться, и лента должна быть длиннее ленты кнопок. */
  .tabs { flex-grow: 1; }
}

.btn {
  font: inherit;
  font-size: 13px;
  padding: 5px 11px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--ink);
  cursor: pointer;
  transition: background-color .12s ease, border-color .12s ease, color .12s ease;
}
.btn:hover { background: var(--sunk); }
.btn:disabled { opacity: 0.4; cursor: default; }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
/* Одна закрашенная кнопка на экран — не обведённая тем же цветом, что и
   обычная, а видимо главная: на панели с десятком кнопок это сразу заметно. */
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 600; }
.btn.primary:hover { filter: brightness(1.08); }

/* ── Панели ─────────────────────────────────────────────────────────── */

.left, .right {
  background: var(--panel);
  overflow-y: auto;
  padding: 12px;
}
.left { grid-area: left; border-right: 1px solid var(--line); }
.right { grid-area: right; border-left: 1px solid var(--line); padding: 0; }

/* Полоса прокрутки в цвет темы — везде, где панель выше окна. Firefox читает
   первую пару свойств, остальные — псевдоэлементы для Chrome/Safari/Edge. */
.left, .right, .sheet, .album {
  scrollbar-width: thin;
  scrollbar-color: var(--line-2) var(--panel);
}
.left::-webkit-scrollbar, .right::-webkit-scrollbar, .sheet::-webkit-scrollbar, .album::-webkit-scrollbar {
  width: 8px;
}
.left::-webkit-scrollbar-track, .right::-webkit-scrollbar-track, .sheet::-webkit-scrollbar-track, .album::-webkit-scrollbar-track {
  background: var(--panel);
}
.left::-webkit-scrollbar-thumb, .right::-webkit-scrollbar-thumb, .sheet::-webkit-scrollbar-thumb, .album::-webkit-scrollbar-thumb {
  background: var(--line-2);
  border-radius: 4px;
}
.left::-webkit-scrollbar-thumb:hover, .right::-webkit-scrollbar-thumb:hover, .sheet::-webkit-scrollbar-thumb:hover, .album::-webkit-scrollbar-thumb:hover {
  background: var(--ink-3);
}

/*
 * Шторки на узких экранах.
 *
 * Колонки `.left`/`.right` в `.app` заданы фиксированной шириной (232px и
 * 272px) — на ширине планшета (768px) холсту, ради которого всё
 * затевалось (рисование стен, трассировка), остаётся дай бог 260px. Ниже
 * 900px обе колонки схлопываются до 0, а сами панели становятся
 * накладными шторками поверх холста, вызываемыми кнопками-раскрывателями.
 */
.drawer-toggle { display: none; }
.drawer-backdrop { display: none; }

@media (max-width: 900px) {
  .app { grid-template-columns: 0 minmax(0, 1fr) 0; }

  .drawer-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    top: 54px;
    z-index: 80;
    width: 36px;
    height: 36px;
    border: 1px solid var(--line-2);
    border-radius: 50%;
    background: var(--panel);
    color: var(--ink);
    font-size: 16px;
    cursor: pointer;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.2);
  }
  .drawer-toggle-left { left: 8px; }
  .drawer-toggle-right { right: 8px; }
  .app[data-mode="estimate"] .drawer-toggle,
  .app[data-mode="projects"] .drawer-toggle,
  .app[data-mode="admin"] .drawer-toggle,
  .app[data-mode="intake"] .drawer-toggle { display: none; }

  .left, .right {
    position: fixed;
    top: 0;
    bottom: 0;
    z-index: 70;
    width: min(280px, 82vw);
    box-shadow: 0 0 24px rgba(0, 0, 0, 0.3);
    transition: left 0.2s ease, right 0.2s ease;
  }
  .left { left: calc(-1 * min(280px, 82vw)); }
  .right { right: calc(-1 * min(280px, 82vw)); }
  .left.open { left: 0; }
  .right.open { right: 0; }

  .drawer-backdrop.open {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 60;
    background: rgba(0, 0, 0, 0.35);
  }
}

/*
 * ТИПОГРАФИКА.
 *
 * Шкала тесная (шаг около 1.12) — интерфейс плотный, крупные ступени в нём
 * не помещаются. Иерархия держится на ТРЁХ признаках сразу: размер,
 * насыщенность и цвет. На одном она разваливается, что и произошло: метка
 * раздела была самым мелким (10 px) и самым бледным текстом на экране, то
 * есть проигрывала тексту, который должна возглавлять.
 *
 * Тело текста — не бледнее `--ink-2`: на `--ink-3` контраст падает до
 * границы 4.5:1 по WCAG 2.1, а на мелком кегле этого мало.
 */
:root {
  --text-xs: 11px;
  --text-sm: 12.5px;
  --text-md: 13.5px;
  --text-lg: 16px;
  --leading-tight: 1.3;
  --leading-normal: 1.55;
}

.panel-label {
  font-family: var(--mono);
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-2);
  /* Воздух сверху — главный признак начала раздела: он делает заголовок
     заголовком вернее, чем любое выделение. */
  margin: 24px 0 10px;
}

/* Первому разделу отбивка сверху не нужна — он и так первый. */
#left > .panel-label:first-child,
#right section > .panel-label:first-child { margin-top: 0; }

/** Пояснительный текст: то, что человек читает, а не сканирует. */
.help {
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--ink-2);
}
.help + .help { margin-top: 10px; }
.help b, .help strong { color: var(--ink); font-weight: 600; }
.help kbd, .help code {
  font-family: var(--mono);
  font-size: 0.92em;
  color: var(--ink);
}

/** Подсказка второго плана: сноска под блоком, а не самостоятельный текст. */
.help.aside {
  font-size: var(--text-xs);
  line-height: var(--leading-tight);
  color: var(--ink-3);
  margin-top: 8px;
}
/* Отбивку разделов задаёт общее правило `.panel-label` — прежний сброс
   здесь съедал её в правой панели, и заголовок прилипал к тексту над ним. */
.right section { padding: 12px; border-bottom: 1px solid var(--line); }

.tool-list { display: flex; flex-direction: column; gap: 1px; margin-bottom: 18px; }

/* Переключатель из двух-трёх коротких значений — в строку, как радиокнопки. */
.tool-list.tight { flex-direction: row; gap: 4px; margin-bottom: 0; }
.tool-list.tight .tool { padding: 4px 10px; }

.tool {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 6px 8px;
  font-size: 13.5px;
  color: var(--ink-2);
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: none;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
  transition: background-color .12s ease, color .12s ease;
}
.tool:hover { background: var(--sunk); color: var(--ink); }
.tool[aria-pressed="true"] {
  background: var(--sunk);
  border-color: var(--line-2);
  color: var(--ink);
  font-weight: 600;
}
.tool .key { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--ink-3); }

/* Подпись поля приглушена, значение — самое контрастное: глаз идёт по
   значениям, а подписи читает только при необходимости. */
.field { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 4px 0; font-size: var(--text-md); }
.field > span { color: var(--ink-3); }
.field > b { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.field > input[type="checkbox"] { flex: none; accent-color: var(--accent); }
.field input, .field select {
  font: inherit;
  font-family: var(--mono);
  font-size: 12.5px;
  width: 118px;
  padding: 3px 6px;
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  color: var(--ink);
  transition: border-color .12s ease;
}
.field input:focus, .field select:focus { outline: none; border-color: var(--accent); }

.selected-kind { font-family: var(--display); font-weight: 700; font-size: 17px; margin-bottom: 8px; }

/* ── Проблемы ───────────────────────────────────────────────────────── */

.issue {
  display: grid;
  grid-template-columns: 14px 1fr;
  gap: 8px;
  padding: 7px 8px;
  margin: 0 -8px;
  border-bottom: 1px solid var(--line);
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color .1s ease;
}
.issue:hover { background: var(--sunk); }
.issue:last-child { border-bottom: 0; }
.issue .mark { font-family: var(--mono); font-weight: 700; }
.issue.error .mark { color: var(--danger); }
.issue.warning .mark { color: var(--warn); }
.issue.info .mark { color: var(--ink-3); }
.issue b { color: var(--ink); font-weight: 600; }

/* Счётчик одинаковых замечаний: «×4» вместо четырёх одинаковых абзацев. */
.issue-count {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  color: var(--ink);
  margin-left: 6px;
  white-space: nowrap;
}

.count-badge {
  font-family: var(--mono);
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 3px;
  color: #fff;
  margin-left: 6px;
}
.count-badge.error { background: var(--danger); }
.count-badge.warning { background: var(--warn); }

/* ── Холст ──────────────────────────────────────────────────────────── */

.canvas-wrap { grid-area: canvas; position: relative; background: var(--sunk); overflow: hidden; }
#plan { display: block; width: 100%; height: 100%; cursor: crosshair; }

.hint {
  position: absolute;
  left: 12px;
  bottom: 12px;
  font-family: var(--mono);
  font-size: 11.5px;
  color: var(--ink-2);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 5px 9px;
  pointer-events: none;
  max-width: 60%;
}

/*
 * Камера и в 2D, и в 3D перецентровывается автоматически (смена вкладки,
 * загрузка проекта) — но не по требованию: увести вид панорамированием или
 * зумом и потеряться легко, а вернуться самому раньше можно было только
 * переключением вкладки туда-обратно. Кнопка дублирует именно то, что уже
 * вызывается автоматически (`editor.fit()` / `view3d.fit()`).
 */
.fit-view {
  position: absolute;
  right: 12px;
  bottom: 12px;
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  line-height: 1;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: 50%;
  cursor: pointer;
  transition: background-color .12s ease, box-shadow .12s ease;
}
.fit-view:hover { background: var(--sunk); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15); }
.fit-view:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

.dim-input {
  position: absolute;
  font-family: var(--mono);
  font-size: 13px;
  width: 92px;
  padding: 3px 6px;
  background: var(--panel);
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  color: var(--ink);
}
.dim-input:focus { outline: none; }

/* ── Смета ──────────────────────────────────────────────────────────── */

.sheet { grid-area: sheet; overflow-y: auto; padding: 18px 24px; background: var(--panel); }
.sheet h2 { font-family: var(--display); font-size: 20px; margin: 22px 0 10px; }
.sheet h2:first-child { margin-top: 0; }

table.est { width: 100%; border-collapse: collapse; font-size: 13px; }
table.est th {
  text-align: left;
  font-weight: 400;
  font-size: 10px;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-bottom: 1px solid var(--line-2);
  padding: 0 8px 5px 0;
}
table.est td { padding: 5px 8px 5px 0; border-bottom: 1px solid var(--line); color: var(--ink-2); transition: background-color .1s ease; }
table.est td.num { text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--ink); white-space: nowrap; }
table.est td.name { color: var(--ink); }
table.est tr.missing td { color: var(--danger); }
table.est .src { font-size: 11px; color: var(--ink-3); }
/* Строки по 20–40 в спецификации и ведомостях — подсветка под курсором
   превращает распечатку в рабочий список. */
table.est tbody tr:hover td { background: var(--sunk); }

table.est th.sortable { cursor: pointer; user-select: none; }
table.est th.sortable:hover { color: var(--ink); }
table.est th.sortable.active { color: var(--accent); }

.sheet-search { max-width: 320px; margin: 4px 0 18px; }
.sheet-search input { width: 100%; }

.totals { margin-top: 16px; display: flex; gap: 26px; align-items: baseline; flex-wrap: wrap; font-family: var(--mono); font-variant-numeric: tabular-nums; }
.totals .total { font-size: 20px; font-weight: 700; color: var(--ink); }

.notice {
  border-left: 3px solid var(--warn);
  padding: 8px 0 8px 12px;
  margin: 14px 0;
  color: var(--ink-2);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}
.notice b { color: var(--ink); font-weight: 600; }
.notice.green { border-color: var(--accent); }

/* ── Строка состояния ───────────────────────────────────────────────── */

.status {
  grid-area: status;
  border-top: 1px solid var(--line);
  background: var(--sunk);
  padding: 8px 14px;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 5px 18px;
  font-family: var(--mono);
  font-size: 12.5px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.status .sum { margin-left: auto; color: var(--ink); font-weight: 700; font-size: 15px; }
.status .sum span {
  font-family: system-ui, sans-serif;
  font-size: 10px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-3);
  font-weight: 400;
  margin-right: 8px;
}

/* ── Расчёт «Почему?» ───────────────────────────────────────────────── */

.why { border: 1px solid var(--line-2); border-radius: var(--radius); background: var(--panel); margin-top: 10px; overflow: hidden; }
.why-head { padding: 9px 11px; border-bottom: 1px solid var(--line); background: var(--sunk); }
.why-head .val { font-family: var(--display); font-weight: 700; font-size: 19px; }
.why-head .because { color: var(--ink-2); font-size: 12.5px; display: block; }
table.calc { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: 11.5px; font-variant-numeric: tabular-nums; }
table.calc td { padding: 5px 10px; border-bottom: 1px solid var(--line); vertical-align: top; }
table.calc tr:last-child td { border-bottom: 0; }
table.calc .lbl { color: var(--ink-2); }
table.calc .num { text-align: right; white-space: nowrap; color: var(--ink); }
table.calc .note { color: var(--ink-3); font-size: 10.5px; }
table.calc tr.decisive td { background: var(--sunk); }
table.calc tr.decisive .lbl { color: var(--ink); font-weight: 700; }

/*
 * Кнопка, ждущая подтверждения вторым нажатием.
 *
 * Взвод сам снимается через 4с (см. ARM_TIMEOUT в confirm.ts) без видимого
 * отсчёта — если отвлечься, второе нажатие приходится уже мимо, и это
 * выглядит как «ничего не произошло». Полоска снизу тает синхронно с
 * таймером; кнопка — новый узел DOM при каждом взводе (перерисовка целиком),
 * так что анимация начинается заново сама, без отдельного JS.
 */
.btn.armed {
  position: relative;
  overflow: hidden;
  border-color: var(--danger);
  color: var(--danger);
  font-weight: 600;
}
.btn.armed:hover { background: var(--danger); color: var(--panel); }
.btn.armed::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  height: 2px;
  width: 100%;
  background: var(--danger);
  animation: armed-countdown 4s linear forwards;
}
@keyframes armed-countdown {
  from { width: 100%; }
  to { width: 0%; }
}

.kind-dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  margin-right: 8px;
  flex: none;
}

/* ── Этажи ───────────────────────────────────────────────────────────────── */

.level-select {
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  padding: 4px 6px;
  font: inherit;
  font-size: 12.5px;
  max-width: 150px;
  transition: border-color .12s ease;
}
.level-select:focus { outline: none; border-color: var(--accent); }

/* ── Выдуманные цены не должны выглядеть настоящими ──────────────────────── */

.sum.demo { color: var(--warn); }
.sum.demo > span { color: var(--warn); opacity: 0.85; }
.totals .total.demo { color: var(--warn); }
.sheet-toggle[disabled] { opacity: 0.4; cursor: not-allowed; }

.hint-block {
  font-size: var(--text-xs);
  line-height: var(--leading-tight);
  color: var(--ink-3);
  margin-top: 14px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

@media (prefers-reduced-motion: reduce) { * { transition: none !important; animation: none !important; } }
/* ── Создание проекта ─────────────────────────────────────────────────────── */

/*
  Карточки видов проекта. Крупные и в столбик: выбор делается один раз и
  определяет, чем человек будет заниматься дальше, — это не переключатель в
  панели, а развилка. Пояснение под названием обязательно: «Дом из бруса»
  и «Дом из бруса и электрика» различимы только по нему.
*/
.kind-cards {
  display: flex;
  flex-direction: column;
  gap: 8px;
  max-width: 640px;
  margin: 14px 0 18px;
}

.kind-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  width: 100%;
  padding: 14px 16px;
  text-align: left;
  background: var(--panel);
  border: 1px solid var(--line-2);
  border-radius: var(--radius-lg);
  color: var(--ink);
  font: inherit;
  cursor: pointer;
  transition: border-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.kind-card:hover { border-color: var(--accent); background: var(--sunk); box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12); transform: translateY(-2px); }
.kind-card:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.kind-card[disabled] { opacity: 0.45; cursor: not-allowed; }
.kind-card[disabled]:hover { border-color: var(--line-2); background: var(--panel); box-shadow: none; transform: none; }

.kind-card-title { display: flex; align-items: center; font-family: var(--display); font-weight: 700; font-size: 18px; }
.kind-card-note { color: var(--ink-2); font-size: var(--text-md); line-height: 1.45; }
.kind-card-meta {
  font-family: var(--mono);
  font-size: 11px;
  color: var(--ink-3);
  margin-top: 2px;
}

/* Название приложения вместо логотипа: у продукта линейки логотипа может и
   не быть, а пустая картинка выглядит как несработавшая загрузка. */
.auth-name {
  font-family: var(--display);
  font-weight: 700;
  font-size: 26px;
  margin: 0 0 28px;
}
