

/* ==========================================================================
   css/pages/project.css
   страничные стили
   ========================================================================== */
/* ===========================================================================
   Страница /project/ — «Проект участка и точная смета». Владелец файла:
   tools/gen_project.py и js/modules/plot-planner.js.

   Оформление — только через токены css/tokens.css; общие компоненты (кнопки,
   поля, таблица, шаги мастера, значки) берутся из css/components.css и здесь
   не переопределяются. Единственные «физические» цвета — палитра дизайн-
   пресетов внизу файла: это цвета покрытия из data/designs.json, а не цвета
   темы, и в разметке им появляться нельзя (см. тот же приём для RAL в
   css/pages/catalog.css).

   Холст плана нарисован в САНТИМЕТРАХ: система координат SVG совпадает с
   единицами проекта, поэтому толщина линий задаётся non-scaling-stroke, а
   кегль подписей считает js по коэффициенту «сантиметров в пикселе».
   =========================================================================== */

.project {
  /* Пропорции карты из макета: 903 × 362 при ширине макета 1536. Задаём
     соотношением, а не высотой: колонка резиновая, а чертёж должен оставаться
     таким же широким, как на макете, на любой ширине окна. */
  --plot-ratio: 903 / 362;
  /* Панель инструментов, компас и линейка друг на друга не налезают начиная
     с 380 px: панель 250 (пять строк макета плюс ряд второстепенных иконок)
     + компас 68 + линейка 24 + поля. Колонка у нас чуть уже макетной, поэтому
     одной пропорции мало — держим ещё и минимум. */
  /* Минимальная высота карты. Поднята с 380: в панели инструментов стало на
     одну строку больше («Повторить» получило подпись), и её нижний край лёг
     на компас. Пропорция из макета (903/362) на широком экране всё равно даёт
     меньше этой высоты, поэтому здесь правится именно нижняя граница. */
  --plot-min-h: 412px;
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

/* Блоки, которые без JavaScript бессмысленны, прячет <noscript> в <head>;
   пояснения, наоборот, появляются только без него. */
.project__nojs { display: none; }

/* ============================== ШАПКА И ШАГИ ============================== */

/* В макете заголовок и шаги стоят одной строкой и выровнены по центру: под H1
   ничего нет, первый экран целиком отдан карте участка. */
.project__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4) var(--s-7);
  flex-wrap: wrap;
}
.project__head h1 { margin-bottom: 0; }

.project__steps { margin-top: 0; }
/* Кегль и кружок шага в макете крупнее общего компонента: шаги здесь — вторая
   по важности вещь на первом экране, а не служебная строка. */
.project__steps .steps-bar__item { font-size: 15px; }
.project__steps .steps-bar__n { width: 28px; height: 28px; font-size: 13px; }
.project__steps .steps-bar__item:not(.is-active) .steps-bar__n {
  background: var(--white); border: 1px solid var(--line-2);
}
/* min-height — цель нажатия: строка шага сама по себе 26 px, пальцем не попасть. */
.project__steps button {
  display: flex; align-items: center; gap: 8px; min-height: 44px;
  background: none; border: 0; padding: 0; margin: 0;
  font: inherit; color: inherit; cursor: pointer;
}
/* Соединительная линия между шагами: у последнего её нет. */
.project__steps .steps-bar__item:not(:last-child)::after {
  content: ''; width: 34px; height: 1px; background: var(--line-2); flex: none;
}

/* ================================= СЕТКА ================================= */

/* Двадцать четыре колонки, а не «слева/справа»: в макете первый ряд поделён
   903 : 540 (то есть 5 : 3, или 15 : 9 из 24), а второй — ровно пополам.
   Одной парой колонок такую сетку не выразить. */
.project__grid {
  display: grid;
  grid-template-columns: repeat(24, minmax(0, 1fr));
  gap: var(--s-5);
  /* Растяжка, а не start: в макете обе карточки ряда одной высоты — смета
     тянется под колонку дизайнов, а плитки итога прижаты к её низу. */
  align-items: stretch;
}
/* min-width: 0 обязателен: у grid-элемента минимальная ширина по умолчанию
   равна min-content, и широкая таблица сметы растягивала бы всю страницу
   вместо того, чтобы прокручиваться внутри .table-wrap. */
.project__grid > * { min-width: 0; }
.project__grid > .plot { grid-column: span 15; }
.project__grid > .project__side { grid-column: span 9; }
.project__grid > .project__design { grid-column: span 12; }
/* Смета не растягивается под колонку дизайнов: свёрнутая спецификация делает
   карточку вдвое короче соседней, и растяжка оставляла бы под плитками итога
   полкарточки пустоты. Плитки прижаты к низу самой сметы, как в макете. */
.project__grid > .project__estimate { grid-column: span 12; align-self: start; }
.project__side { display: flex; flex-direction: column; gap: var(--s-4); }

.project__block-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--s-4); flex-wrap: wrap; margin-bottom: var(--s-5);
}
.project__block-head--pad { padding: var(--s-6) var(--s-6) 0; margin-bottom: var(--s-4); }
.project__block-head .section__title { margin-bottom: 0; }

/* =============================== ХОЛСТ ПЛАНА =============================== */

.plot { overflow: hidden; display: flex; flex-direction: column; }
.plot__stage {
  position: relative;
  aspect-ratio: var(--plot-ratio);
  min-height: var(--plot-min-h);
  background: var(--bg-2);
  border-bottom: 1px solid var(--line);
}
/* Поле слева — место под плавающую панель инструментов: viewBox холста
   раскладывается по content-box, поэтому padding честно отодвигает чертёж, и
   подпись крайней стороны не уезжает под кнопки. Снизу поле шире: там компас
   и масштабная линейка. */
/* Компас с линейкой привязаны к чертежу, а не к карточке: на телефоне панель
   инструментов и «Слои» встают в поток под холстом, и абсолютный слой,
   отсчитанный от .plot__stage, ложился прямо на них. */
/* Карта заливает карточку целиком, как в макете, а панель инструментов и
   «Слои» плавают поверх неё. Поэтому холст НЕ обрезает то, что выходит за
   viewBox: земля, дорога и соседи нарочно нарисованы далеко за его краями и
   должны доходить до углов карточки. Обрезает их рамка карточки. */
.plot__canvas-box { position: relative; height: 100%; overflow: hidden; }
.plot__canvas {
  display: block; width: 100%; height: 100%;
  padding: 26px 80px 58px 152px;
  overflow: visible;
  touch-action: none;            /* иначе тач-перетаскивание вершины скроллит страницу */
}
.plot__canvas:focus-visible { outline: 2px solid var(--gold); outline-offset: -2px; }

/* --- земля вокруг участка ---
   В макете под контуром лежит съёмка участка: трава, дорога снизу, соседние
   дома по краям. Спутниковой подложки у нас нет, поэтому та же сцена нарисована
   вектором (js/modules/plot-planner.js → sceneShapes). Цвета — производные от
   токенов темы: физическому «зелёному газону» в палитре сайта места нет, а
   мешать оттенки прямо здесь честнее, чем заводить вторую палитру. */
.plot__stage {
  --map-grass: var(--sage-50);
  --map-grass-2: var(--bg-2);
  --map-hedge: var(--muted-2);
  --map-tree: var(--sage);
  --map-road: var(--line-2);
  --map-kerb: var(--white);
  --map-drive: var(--bg);
  --map-roof: var(--muted-2);
}
@supports (color: color-mix(in srgb, red 50%, blue)) {
  .plot__stage {
    --map-grass: color-mix(in srgb, var(--sage) 64%, var(--white));
    /* Соседний надел — та же трава, но глуше: «мой участок» обязан читаться
       светлее и зеленее всего, что вокруг. */
    --map-grass-2: color-mix(in srgb, var(--map-grass) 78%, var(--muted));
    --map-hedge: color-mix(in srgb, var(--sage) 80%, var(--white));
    --map-tree: color-mix(in srgb, var(--sage) 92%, var(--white));
    --map-road: color-mix(in srgb, var(--ink-2) 34%, var(--white));
    --map-kerb: color-mix(in srgb, var(--line) 55%, var(--white));
    --map-drive: color-mix(in srgb, var(--line-2) 55%, var(--white));
    --map-roof: color-mix(in srgb, var(--ink-2) 42%, var(--white));
  }
}
.plot__ground { fill: var(--map-grass); }
.plot__neighbour { fill: var(--map-grass-2); }
.plot__hedge { fill: none; stroke: var(--map-hedge); stroke-width: 1.5; stroke-dasharray: 6 5; }
.plot__tree { fill: var(--map-tree); opacity: .5; }
.plot__nb-house { fill: var(--map-roof); opacity: .75; }
.plot__nb-ridge { fill: none; stroke: var(--map-kerb); stroke-width: 1.2; opacity: .55; }
.plot__road { fill: var(--map-road); }
.plot__kerb { fill: var(--map-kerb); }
.plot__road-mark { fill: none; stroke: var(--map-kerb); stroke-width: 12; opacity: .8; }
.plot__drive { fill: var(--map-drive); }

/* --- слои чертежа --- */
/* Сетка поверх травы — светлая разметка, а не миллиметровка: тёмные линии
   превращали газон в тетрадный лист. */
.plot__grid { stroke: var(--white); stroke-width: 1; opacity: .22; fill: none; }
.plot__area { fill: var(--white); fill-opacity: .22; }
/* Контур участка белый, как в макете; тёмная подложка держит его читаемым и
   на дороге, и на подъезде к воротам. */
.plot__outline { fill: none; stroke: var(--white); stroke-width: 2.5; stroke-linejoin: round; }
.plot__outline-halo { fill: none; stroke: var(--navy); stroke-width: 5; stroke-linejoin: round; opacity: .3; }
.plot__side { stroke: transparent; cursor: pointer; }
.plot__side:hover { stroke: var(--gold); stroke-opacity: .28; }
.plot__side.is-selected { stroke: var(--gold); stroke-opacity: .45; }
.plot__rubber { stroke: var(--gold); stroke-width: 2; stroke-dasharray: 6 5; fill: none; }

/* Подписи длин в макете белые прямо по траве. Обводка тут не украшение:
   она и есть фон под глифом, иначе белым по светлой зелени не прочитать. */
.plot__dim {
  fill: var(--white); font-weight: 800; letter-spacing: -.01em;
  paint-order: stroke; stroke: var(--navy); stroke-width: 7; stroke-linejoin: round; stroke-opacity: .8;
}
.plot__mark-label {
  fill: var(--white); font-weight: 700;
  paint-order: stroke; stroke: var(--navy); stroke-width: 6; stroke-linejoin: round; stroke-opacity: .7;
}

.plot__gap { stroke: var(--orange); stroke-linecap: round; }
.plot__leaf { fill: none; stroke: var(--orange); stroke-width: 1.6; stroke-dasharray: 4 4; }
.plot__opening { cursor: grab; }
.plot__opening:focus-visible { outline: none; }
.plot__opening:focus-visible .plot__gap { stroke: var(--navy); }

.plot__node {
  fill: var(--white); stroke: var(--navy); stroke-width: 2.5; cursor: grab;
  vector-effect: non-scaling-stroke;
}
.plot__node:hover, .plot__node:focus-visible { fill: var(--gold); outline: none; }

/* Дом в макете — постройка на участке, а не пунктирная рамка: заливка кровли
   и тонкий контур. Перетаскивание и угол-ручка не меняются. */
.plot__house-body { fill: var(--map-roof); fill-opacity: .92; stroke: var(--white); stroke-width: 1.4; }
.plot__handle { fill: var(--navy); cursor: nwse-resize; }
.plot__entrance { fill: none; stroke: var(--sage); stroke-width: 2.5; }
.plot__arrow-head { fill: var(--sage); }

/* Курсор подсказывает выбранный инструмент: клик по холсту в режиме рисования
   ставит точку, а не выделяет. */
.plot[data-tool="draw"] .plot__canvas { cursor: crosshair; }
.plot[data-tool="gate"] .plot__canvas,
.plot[data-tool="wicket"] .plot__canvas,
.plot[data-tool="entrance"] .plot__canvas,
.plot[data-tool="house"] .plot__canvas { cursor: copy; }

/* --- панель инструментов поверх холста ---
   В макете это белая карточка 133 × 221 при ширине 1536 (то есть 125 × 207
   у нас): пять строк по 41 px, иконка слева, подпись в две строки, между
   строками тонкие разделители. */
.plot__tools {
  position: absolute; top: 14px; left: 15px;
  display: flex; flex-direction: column;
  background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-sm);
  padding: 3px 0; width: 126px;
}
.plot__tool {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 6px 10px; border: 0; border-radius: 0;
  background: transparent; color: var(--ink); cursor: pointer;
  font-size: var(--fs-xs); font-weight: 700; text-align: left; line-height: 1.2;
}
/* Разделители внутри панели, как в макете: линия не доходит до краёв. */
.plot__tool + .plot__tool { border-top: 1px solid var(--line); }
.plot__tool:hover { background: var(--bg-2); }
.plot__tool.is-active { background: var(--gold-100); color: var(--navy); }
.plot__tool small { display: block; font-weight: 700; font-size: var(--fs-xs); }
.plot__tool-ic { width: 19px; height: 19px; flex: none; color: var(--navy); }
.plot__tool--file { position: relative; }

/* Выключенная кнопка истории — это ответ на вопрос «а есть ли куда
   возвращаться». Гасим и снимаем отклик на наведение, чтобы она не выглядела
   нажимаемой: нажатие без эффекта читается как поломка. */
.plot__tool[disabled] { opacity: .38; cursor: default; }
.plot__tool[disabled]:hover { background: transparent; }
.plot__tool--file:focus-within { background: var(--bg-2); outline: 2px solid var(--gold); outline-offset: -2px; }

/* --- «Слои» --- */
.plot__layers { position: absolute; top: var(--s-4); right: var(--s-4); }
.plot__layers-btn {
  display: inline-flex; align-items: center; gap: 8px; cursor: pointer; list-style: none;
  padding: 10px 14px; min-height: 44px; background: var(--white); border: 1px solid var(--line);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-sm);
  font-size: var(--fs-sm); font-weight: 700;
}
.plot__layers-btn::-webkit-details-marker { display: none; }
.plot__layers-box {
  position: absolute; right: 0; top: calc(100% + 6px); width: 250px;
  display: flex; flex-direction: column; gap: 10px;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius-sm);
  box-shadow: var(--shadow); padding: var(--s-4); font-size: var(--fs-sm);
}
.plot__layers-acts { display: flex; gap: 6px; flex-wrap: wrap; }
.plot__layers-acts .btn { min-height: 44px; }        /* цель нажатия */
.plot__range { width: 100%; accent-color: var(--gold); }

/* --- компас и масштабная линейка ---
   В макете обе подписи стоят в левом нижнем углу карты: компас 80 px, под ним
   линейка 0 · 5 · 10 · 15 м. Живут в HTML-слое, а не в viewBox: внутри
   чертежа их прижимало бы к контуру участка. */
.plot__hud {
  position: absolute; left: 18px; bottom: 12px; z-index: 1;
  display: flex; flex-direction: column; gap: 8px; pointer-events: none;
}
.plot__compass { width: 68px; height: 68px; }
.plot__compass svg { width: 100%; height: 100%; }
.plot__compass-ring { fill: var(--white); fill-opacity: .72; stroke: var(--line-2); stroke-width: 1; }
.plot__compass-rose { fill: var(--white); stroke: var(--muted-2); stroke-width: .8; stroke-linejoin: round; }
.plot__compass-rose-2 { fill: var(--bg-2); stroke: var(--muted-2); stroke-width: .8; stroke-linejoin: round; }
.plot__compass-hub { fill: var(--ink-2); }
.plot__compass-letter { fill: var(--ink); font-size: 11px; font-weight: 800; }

.plot__scale { font-variant-numeric: tabular-nums; }
/* Линейка лежит на траве: подписи держим белой подсветкой, иначе мелкие
   цифры тонут в зелени. */
.plot__scale-ticks {
  display: flex; justify-content: space-between;
  font-size: 10px; font-weight: 700; color: var(--ink); line-height: 1;
  text-shadow: 0 0 3px var(--white), 0 0 2px var(--white);
}
/* Засечки рисуем фоном: четыре штриха по краям и на третях линейки. */
.plot__scale-line {
  height: 6px; margin-top: 3px;
  border-bottom: 1.5px solid var(--ink-2);
  background:
    linear-gradient(var(--ink-2), var(--ink-2)) 0 100% / 1.5px 6px no-repeat,
    linear-gradient(var(--ink-2), var(--ink-2)) 33.33% 100% / 1.5px 6px no-repeat,
    linear-gradient(var(--ink-2), var(--ink-2)) 66.66% 100% / 1.5px 6px no-repeat,
    linear-gradient(var(--ink-2), var(--ink-2)) 100% 100% / 1.5px 6px no-repeat;
}

/* --- подсказка и панели под холстом --- */
.plot__hint {
  display: flex; align-items: center;
  padding: var(--s-2) var(--s-5); color: var(--muted); font-size: var(--fs-xs);
  border-bottom: 1px solid var(--line); min-height: 38px;
}
.plot__panel { padding: 0 var(--s-5) var(--s-4); }
.plot .project__nojs + .plot__panel { padding-top: var(--s-4); }
.plot .project__nojs { margin: var(--s-5) var(--s-5) 0; }

/* Поля по вертикали — цель нажатия (сама строка 21 px). display у <summary>
   не трогаем: вместе с ним пропадает треугольник раскрытия. */
.plot__details summary {
  cursor: pointer; font-weight: 800; font-size: var(--fs-sm);
  padding: 12px 0;
}
/* Периметр и площадь — живая подпись прямо в свёрнутой строке: в макете под
   картой ничего нет, и без неё цифры контура пропадали бы из виду. */
.plot__details summary b { float: right; color: var(--muted); font-weight: 700; }
.plot__details[open] summary { margin-bottom: var(--s-2); }
.plot__sides {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: var(--s-2) var(--s-4);
}
/* --- подпись длины как управление ---
   Подпись обязана выглядеть нажимаемой ДО нажатия, иначе возможность останется
   незамеченной ровно так же, как остался незамеченным список сторон в свёрнутом
   блоке под картой. Плашка проявляется на наведении и на фокусе. */
.plot__dim-box { cursor: text; }
.plot__dim-hit { fill: transparent; stroke: none; }
.plot__dim-box:hover .plot__dim-hit,
.plot__dim-box:focus-visible .plot__dim-hit {
  fill: var(--white); fill-opacity: .92;
  stroke: var(--line-2); stroke-width: 1; vector-effect: non-scaling-stroke;
}
.plot__dim-box:focus-visible { outline: none; }
.plot__dim-box:focus-visible .plot__dim-hit { stroke: var(--gold); stroke-width: 2; }
.plot__dim-box:hover .plot__dim { fill: var(--navy); }
/* Поле держим в HTML-слое над холстом, а не в <foreignObject>: перерисовка SVG
   уничтожала бы его вместе с фокусом и наполовину набранным числом.
   Кегль ровно 16 px — на меньшем iOS зумит страницу при фокусе. */
.plot__dim-input {
  position: absolute; z-index: 2; width: 76px; padding: 4px 6px;
  transform: translate(-50%, -50%);
  font: 700 16px/1.1 inherit; text-align: center; color: var(--ink);
  background: var(--white); border: 2px solid var(--gold); border-radius: var(--radius-xs);
  box-shadow: var(--shadow-sm);
}
.plot__dim-input[hidden] { display: none; }

.plot__side-row { display: flex; align-items: center; gap: 8px; }
/* Строка «Сторон участка» задаёт форму, а не правит одну сторону: отделяем её
   от списка длин линией, иначе читается как ещё одна сторона. */
.plot__side-row--count { padding-bottom: var(--s-2); border-bottom: 1px solid var(--line); margin-bottom: var(--s-1); }
.plot__side-row--count .select { flex: none; width: 148px; }
.plot__side-name { flex: 1; font-size: var(--fs-sm); color: var(--ink-2); font-weight: 600; }
.plot__side-unit { color: var(--muted); font-size: var(--fs-sm); }
/* Строку «Периметр: … · площадь …» редактор дописывает в конец списка сторон,
   а нужна она сразу под планом: это единственное живое текстовое описание
   контура, и холст больше не role="img", чтобы его подменять. order выносит
   её наверх сетки, не трогая порядок в разметке. */
.plot__side-total {
  order: -1; grid-column: 1 / -1; margin-bottom: var(--s-2);
  font-size: var(--fs-sm); color: var(--ink-2);
}
.plot__side-total b { color: var(--ink); }
/* То же описание для страницы без JavaScript: там живой строки нет. */
.plot__summary { font-size: var(--fs-sm); color: var(--ink-2); margin-bottom: var(--s-4); }

/* Компактные поля — только отступами: кегль ниже 16 px заставляет iPhone
   увеличивать страницу при фокусе (см. --fs-field в css/tokens.css). */
.input--sm, .select--sm { padding: 6px 10px; }
.select--sm { padding-right: 30px; background-size: 14px; }
.plot__side-row .input--sm { width: 92px; flex: none; text-align: right; }

.plot__ops { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-4); }
.project__opening {
  display: grid; grid-template-columns: 1.2fr .8fr 1.3fr auto; gap: 6px; align-items: center;
}
.project__opening-del { padding: 7px 10px; min-height: 44px; }   /* цель нажатия */

.plot__static-title { font-weight: 800; font-size: var(--fs-sm); margin-bottom: 6px; }
.plot__static-list { list-style: none; display: flex; flex-wrap: wrap; gap: 6px var(--s-5); margin-bottom: var(--s-4); color: var(--ink-2); font-size: var(--fs-sm); }

/* ============================ ПАРАМЕТРЫ УЧАСТКА ============================ */

/* Карточка параметров из макета: четыре блока, между ними тонкие линии на всю
   ширину карточки. Поэтому разделители вешаем на сами блоки, а не на обёртку. */
.project__params { display: flex; flex-direction: column; gap: 0; padding: 16px; }
.project__params > * + * { border-top: 1px solid var(--line); padding-top: var(--s-4); margin-top: var(--s-4); }
.project__field .field__label { margin-bottom: 6px; }
/* Подписи полей в макете обычным предложением, а не капслоком: строка
   «Расстояние от производства» капслоком не влезает в колонку и ломается
   надвое. Правило живёт здесь, а не в компонентах: это оформление страницы. */
.project__params .field__label,
.project__params legend.field__label {
  text-transform: none; letter-spacing: 0; font-size: var(--fs-xs); font-weight: 600;
}

/* Подсказка к полю свёрнута в значок «i» — сам текст лежит рядом скрытым и
   привязан к полю через aria-describedby. */
.project__i { display: inline-flex; color: var(--muted-2); cursor: help; }
.project__i-ic { width: 15px; height: 15px; }

/* Карандаш в поле адреса: только подсказка, кликов не ловит. */
.project__input-ic { position: relative; }
.project__input-ic .input { padding-right: 44px; }
.project__input-ic-svg {
  position: absolute; right: 14px; top: 50%; transform: translateY(-50%);
  width: 18px; height: 18px; color: var(--muted-2); pointer-events: none;
}

/* Вертикальная линия между «расстоянием» и «грунтом» — как в макете. */
.project__two { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-5); }
.project__two > * + * { border-left: 1px solid var(--line); padding-left: var(--s-5); }
/* Отрицательный отступ гасит собственный padding поля: «37» встаёт ровно под
   левый край подписи, как в макете. */
.project__km { display: flex; align-items: baseline; gap: 5px; margin-left: -3px; }
/* «37 км» в макете — крупная надпись, а не поле. Поле оставляем настоящим
   (расстояние влияет на доставку в смете), но убираем у него рамку: она
   проявляется на наведении и фокусе, чтобы правку было где начать. */
.project__km-input {
  width: 2.35ch; padding: 2px 3px; border-color: transparent; background: transparent;
  font-size: 26px; font-weight: 800; letter-spacing: -.02em; color: var(--ink);
  text-align: left; -moz-appearance: textfield;
}
.project__km-input::-webkit-outer-spin-button,
.project__km-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.project__km-input:hover { border-color: var(--line-2); }
.project__km-unit { font-size: 22px; font-weight: 800; color: var(--ink); }

.project__fieldset { border: 0; }
/* Три варианта перепада в макете стоят одной строкой. Кегль мельче базового —
   иначе строка не помещается в колонку 480 px. */
.project__radios { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 6px; margin-top: var(--s-3); }
/* 11 px — не каприз: три подписи со скобками занимают 441 px при 13 px,
   а колонка параметров у нас 428 px. Мельче сделать нельзя (читаемость),
   шире колонку — тоже (пропорции первого ряда заданы макетом). */
.project__radio { font-size: 11px; letter-spacing: -.01em; font-weight: 600; align-items: center; gap: 5px; white-space: nowrap; }
.project__radio input { width: 14px; height: 14px; margin-top: 0; }

.project__toggle {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-4);
}
.project__toggle-label { font-size: var(--fs-sm); color: var(--ink-2); font-weight: 600; }
.project__switch { display: inline-flex; align-items: center; gap: 10px; cursor: pointer; font-size: var(--fs-sm); color: var(--muted); }
.project__switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.project__switch-track {
  position: relative; width: 46px; height: 26px; border-radius: var(--radius-pill);
  background: var(--line-2); transition: background var(--dur); flex: none;
}
.project__switch-track::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px;
  border-radius: 50%; background: var(--white); box-shadow: var(--shadow-xs);
  transition: transform var(--dur) var(--ease);
}
.project__switch input:checked + .project__switch-track { background: var(--sage); }
.project__switch input:checked + .project__switch-track::after { transform: translateX(20px); }
.project__switch input:focus-visible + .project__switch-track { outline: 2px solid var(--gold); outline-offset: 2px; }

/* ========================= ИНЖЕНЕРНЫЕ ПРЕДУПРЕЖДЕНИЯ ========================= */

/* Рамка — приглушённый оттенок предупреждения, а не свой жёлтый: сырых hex
   в странице быть не должно, поэтому подмешиваем белый через color-mix, а
   старым браузерам оставляем токен --gold. */
.project__warn { border-color: var(--gold); background: var(--warning-50); }
@supports (color: color-mix(in srgb, red 50%, blue)) {
  .project__warn { border-color: color-mix(in srgb, var(--warning) 34%, var(--white)); }
}
.project__warn { padding: var(--s-4) var(--s-5); }
.project__warn-title { display: flex; align-items: center; gap: 9px; font-weight: 800; font-size: var(--fs-sm); color: var(--ink); margin-bottom: var(--s-3); }
.project__warn-title .ic { width: 19px; height: 19px; flex: none; color: var(--warning); }
.project__warn-list { list-style: none; display: flex; flex-direction: column; gap: var(--s-3); }
.project__warn-item { display: flex; align-items: flex-start; gap: 9px; font-size: var(--fs-xs); color: var(--ink-2); }
/* В макете это простая зелёная галочка без плашки — плашка тянула на себя
   внимание сильнее самого текста предупреждения. */
.project__warn-mark { width: 15px; height: 15px; flex: none; color: var(--sage); margin-top: 2px; }
.project__warn-item.is-warn .project__warn-mark { color: var(--warning); }

/* ================================ ДИЗАЙНЫ ================================ */

.project__design { padding: var(--s-5); }
/* Заголовок и два поля стоят одной строкой: перенос отдавал полям целый ряд,
   которого в макете нет вовсе. */
/* Заголовок ужимается первым, поля — вторыми. Раньше строка полей стояла
   flex: none и получала ровно свою основу: на любой ширине окна ей доставалось
   335 px на два поля, то есть по 162, и «Металл под дерево» (149 px текста плюс
   стрелка и отступы) не помещался никогда. Заголовку в этой строке места нужно
   меньше, чем выбранному значению: прочитать «Выберите дизайн ограждения» можно
   и в две строки, а обрезанное значение поля прочитать нельзя. */
.project__design .project__block-head { margin-bottom: var(--s-4); align-items: center; flex-wrap: wrap; }
.project__design .section__title { min-width: 0; flex: 1 1 200px; }
.project__design .section__title { font-size: 16px; }
.project__design-fields { display: flex; gap: var(--s-3); flex-wrap: wrap; flex: 1 1 auto; justify-content: flex-end; }
/* Не фиксированные 132 px, а минимум с правом вырасти: в 132 px не помещались
   ни «Профнастил», ни «Суглинок» — подпись выбранного значения уезжала в
   многоточие, и человек не видел, что выбрал. Гибкая основа даёт полям занять
   свободное место в строке и ужаться только там, где его нет. */
/* Верхняя граница по самому длинному значению: «Металл под дерево» требует
   149 px текста плюс отступы и стрелка. На 220 оно резалось. */
.project__field-inline { flex: 1 1 170px; min-width: 132px; max-width: 260px; gap: 4px; }
/* Место делим по длине значений, а не поровну: «Металл под дерево» требует
   149 px текста, «2,5 м» — сорока. Пока поля были равны, тип ограждения резался,
   а высота держала половину ячейки пустой. */
.project__field-inline:has(#pj-height) { flex: 0 1 128px; min-width: 108px; }
.project__field-inline:has(#pj-system) { flex: 2 1 210px; max-width: 280px; }
.project__field-inline .field__label {
  margin-bottom: 0; text-transform: none; letter-spacing: 0; font-size: var(--fs-xs); font-weight: 600;
}

/* Ровно три карточки в ряд, как в макете: auto-fill при узкой колонке давал
   то две, то четыре, и превью каждый раз меняло пропорции. */
.project__presets {
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--s-3);
}
.preset {
  display: flex; flex-direction: column; overflow: hidden; cursor: pointer;
  background: var(--white); border: 1.5px solid var(--line); border-radius: var(--radius);
  transition: border-color var(--dur), box-shadow var(--dur), transform var(--dur);
}
.preset:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
/* Фокус ловит кнопка внутри карточки, а рамку по-прежнему рисуем вокруг всей
   карточки: клавиатурой видно, какой дизайн сейчас выбирают. */
.preset:focus-within { outline: 2px solid var(--gold); outline-offset: 2px; }
.preset__btn:focus-visible { outline: none; }
.preset.is-selected { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-100); }
/* Галочка выбранного дизайна — как в макете, кружком в углу превью. */
.preset.is-selected .preset__media::after {
  content: '✓'; position: absolute; top: 9px; left: 9px;
  width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center;
  background: var(--gold); color: var(--white); font-size: 14px; font-weight: 800;
}
/* Пропорции превью из макета: 229 × 262 при ширине 1536 — вертикальный кадр
   с воротами и секцией забора, а не полоска фасада. */
.preset__media { position: relative; aspect-ratio: 229 / 262; background: var(--bg-2); overflow: hidden; }
.preset__media .pv { display: block; width: 100%; height: 100%; }
/* Палитра покрытия полосой по низу превью выбранной карточки (как в макете). */
.preset__ral {
  position: absolute; left: 0; right: 0; bottom: 0; gap: 0;
  padding: 0;
}
/* Полоса делит ширину карточки поровну, и при двенадцати цветах на образец
   оставалось 17 px — меньше минимума 24×24 из WCAG 2.5.8, причём без зазоров
   между целями, так что исключение для разнесённых кнопок здесь не работает.
   Ставим минимум 24 и разрешаем перенос: полоса становится в два ряда там,
   где в один не помещается. */
.preset__ral { flex-wrap: wrap; }
.preset__ral .swatch {
  flex: 1 0 24px; min-width: 24px; width: auto; height: 30px;
  border-radius: 0; border-width: 0;
}
.preset__ral .swatch[aria-pressed="true"] { box-shadow: inset 0 0 0 2px var(--white), inset 0 0 0 4px var(--gold); }
.preset__body { display: flex; flex-direction: column; gap: 4px; padding: var(--s-3) var(--s-4) var(--s-4); flex: 1; }
.preset__title { font-size: 15px; display: flex; align-items: center; gap: 8px; }
.preset__price { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); }
.preset.is-selected .preset__price { color: var(--ink-2); }
/* Кнопка настоящая, поэтому pointer-events её больше не отключает; клик мимо
   кнопки по карточке ловит делегированный обработчик страницы. */
.preset__btn { margin-top: auto; padding-top: var(--s-2); min-height: 40px; font-size: var(--fs-sm); }
/* Невыбранные кнопки в макете тоже золотой обводкой, только на белом фоне. */
.preset__btn.btn--ghost { border-color: var(--gold); color: var(--navy); }
.preset__btn.btn--ghost:hover { background: var(--gold-100); border-color: var(--gold-600); }
.preset__btn.btn--outline { background: var(--gold-100); }

/* Цвета образцов RAL приходят из общей палитры сайта (--ral-*, объявлена
   в css/pages/catalog.css вместе с правилами .swatch[data-ral]): второй копии
   физических цветов покрытия в проекте быть не должно. */

/* ================================== СМЕТА ================================== */

.project__estimate { display: flex; flex-direction: column; }
.project__estimate .project__block-head { align-items: center; }
.project__estimate .section__title { font-size: 16px; }
.project__block-head--pad { padding: var(--s-5) var(--s-5) var(--s-4); margin-bottom: 0; border-bottom: 1px solid var(--line); }
/* --muted-2 — токен НЕАКТИВНОГО (3:1), для текста его не хватает: замер на
   боевом дал 3,64:1 при норме 4,5:1. Здесь настоящий текст — цена метра,
   строка сметы, счётчик позиций, — значит нужен --muted. */
.project__per-meter { font-size: var(--fs-xs); font-weight: 600; color: var(--muted); white-space: nowrap; }

/* Смета в макете плотная: строка 25 px, колонки разделены вертикальными
   линиями, числа выровнены по центру своей колонки. */
.project__table { font-size: var(--fs-xs); }
.project__table th { padding: 8px 8px; text-transform: none; letter-spacing: 0; font-weight: 600; background: var(--bg-2); }
.project__table td { padding: 5px 8px; vertical-align: middle; }
.project__table th:first-child, .project__table td:first-child { padding-left: var(--s-5); min-width: 190px; }
.project__table th:last-child, .project__table td:last-child { padding-right: var(--s-5); }
.project__table th:not(:first-child), .project__table td:not(:first-child) { width: 15%; border-left: 1px solid var(--line); }
.project__table th.num, .project__table td.num { text-align: center; }
.project__table td .badge { margin-left: 6px; }
.project__table tr.is-muted td { color: var(--muted); }
.project__demo { margin: var(--s-3) var(--s-5) 0; }

/* Подробная спецификация под раскрытием: в таблице наверху — товарные строки,
   а состав нужен тем, кто её проверяет. */
.project__breakdown { border-top: 1px solid var(--line); }
.project__breakdown summary {
  display: flex; align-items: center; gap: var(--s-2); cursor: pointer;
  padding: 12px var(--s-5); min-height: 44px;
  font-size: var(--fs-sm); font-weight: 700; color: var(--ink-2);
  list-style: none;
}
.project__breakdown summary::-webkit-details-marker { display: none; }
/* Свой треугольник: у summary с display:flex браузер прячет штатный маркер. */
.project__breakdown summary::before {
  content: ''; width: 0; height: 0; flex: none; margin-right: 2px;
  border: 5px solid transparent; border-left-color: currentColor;
  transition: transform var(--dur) var(--ease);
}
.project__breakdown[open] summary::before { transform: rotate(90deg) translateX(2px); }
.project__breakdown summary:hover { color: var(--navy); }
.project__breakdown-n { color: var(--muted); font-weight: 600; font-size: var(--fs-xs); }
.project__breakdown .table-wrap { border-top: 1px solid var(--line); }
/* Заголовок группы внутри спецификации: с суммой по группе справа. */
.project__group th { background: var(--bg-2); font-weight: 800; text-align: left; }
.project__group td { background: var(--bg-2); font-weight: 800; }

/* Подпись под таблицей: одна строка про доставку теми же словами, что и на
   остальных страницах. Живёт рядом со сметой, потому что объясняет её строку. */
.project__note-line {
  display: flex; gap: var(--s-3); margin: var(--s-3) var(--s-5) 0;
  font-size: var(--fs-sm); color: var(--muted);
}
.project__note-line .ic { width: 18px; height: 18px; flex: none; margin-top: 2px; color: var(--gold-600); }

/* Сроки этапами. Одно число «14–21 день» спорило с общим обещанием сайта:
   у замера, производства и монтажа разные сроки и разные причины расти. */
.project__terms { margin: var(--s-5) var(--s-5) 0; }
.project__terms-head {
  font-size: var(--fs-xs); font-weight: 800; letter-spacing: .05em;
  text-transform: uppercase; color: var(--muted); margin-bottom: var(--s-3);
}
.project__terms-list {
  list-style: none; display: grid; gap: var(--s-3); margin: 0;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 180px), 1fr));
}
.project__term {
  background: var(--bg-2); border-radius: var(--radius-sm); padding: var(--s-3) var(--s-4);
}
.project__term b { display: block; font-size: 18px; font-weight: 800; letter-spacing: -.02em; }
.project__term-name {
  display: block; font-size: var(--fs-xs); font-weight: 800; letter-spacing: .04em;
  text-transform: uppercase; color: var(--navy);
}
.project__term-note { display: block; margin-top: 2px; font-size: var(--fs-xs); color: var(--muted); }
.project__terms-total { margin-top: var(--s-3); font-size: var(--fs-sm); color: var(--ink-2); }
.project__terms-note {
  margin-top: var(--s-2); font-size: var(--fs-sm); color: var(--muted);
  padding-left: var(--s-3); border-left: 3px solid var(--gold);
}
.project__terms-note[hidden] { display: none; }

.project__tiles {
  display: grid; grid-template-columns: auto 1fr auto; gap: var(--s-3);
  padding: var(--s-4) var(--s-5) var(--s-5); align-items: stretch; margin-top: auto;
}
.project__tile {
  display: flex; align-items: center; gap: var(--s-3);
  background: var(--bg-2); border-radius: var(--radius-sm); padding: var(--s-3) var(--s-4);
}
.project__tile-ic { width: 24px; height: 24px; flex: none; color: var(--navy); }
.project__tile b { display: block; font-size: 18px; font-weight: 800; letter-spacing: -.02em; white-space: nowrap; }
.project__tile span { font-size: var(--fs-xs); color: var(--muted); }
/* Плитка итога в макете такая же светлая, как соседние: цену выделяет кегль,
   а не золотая рамка — золото на странице закреплено за выбором дизайна. */
.project__total {
  display: flex; flex-direction: column; justify-content: center; gap: 2px;
  padding: var(--s-3) var(--s-4); border: 1px solid var(--line); border-radius: var(--radius-sm);
  background: var(--white); min-width: 200px;
}
.project__total > span:first-child { font-size: var(--fs-xs); font-weight: 700; color: var(--muted); }
.project__total b { font-size: 30px; font-weight: 800; letter-spacing: -.03em; font-variant-numeric: tabular-nums; white-space: nowrap; }

/* =============================== КНОПКИ ВНИЗУ =============================== */

/* В макете это обычная полоса в конце проекта, а не липкая панель: карточка
   светлее полотна, кнопки слева, оговорка справа. Липкой полоса остаётся
   только на телефоне (см. медиазапрос ниже) — там до кнопок далеко скроллить. */
.project__actions {
  display: flex; align-items: center; gap: var(--s-3); flex-wrap: wrap;
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  padding: var(--s-2) var(--s-5); min-height: 62px;
}
.project__actions .btn { min-height: 44px; padding-left: var(--s-6); padding-right: var(--s-6); }
.project__disclaimer {
  display: flex; align-items: flex-start; gap: 10px; margin-left: auto;
  max-width: 480px; font-size: var(--fs-xs); color: var(--muted); line-height: 1.5;
}
.project__disclaimer .ic { width: 18px; height: 18px; flex: none; color: var(--muted-2); }
.project__actions .project__nojs { flex-basis: 100%; }

/* ============================== ПАЛИТРА ДИЗАЙНОВ ==============================
   Физические цвета покрытия из data/designs.json (поле preview): полотно,
   столб и подсветка. В разметке им появляться нельзя — превью рисует
   generator одними классами, а цвет подставляется здесь по data-preset. */

.preset__media {
  --pv-fill: #45494e;
  --pv-post: #33383d;
  --pv-accent: #5b6169;
}
.preset[data-preset="graphite"] .preset__media { --pv-fill: #45494e; --pv-post: #33383d; --pv-accent: #5b6169; }
.preset[data-preset="woodlook"] .preset__media { --pv-fill: #8a5a2f; --pv-post: #3a3330; --pv-accent: #a8703c; }
.preset[data-preset="lightstone"] .preset__media { --pv-fill: #d8cbb2; --pv-post: #b9b2a6; --pv-accent: #e6dcc7; }
.preset[data-preset="forest"] .preset__media { --pv-fill: #1d5a49; --pv-post: #33383d; --pv-accent: #2b7460; }
.preset[data-preset="monolith"] .preset__media { --pv-fill: #17181a; --pv-post: #9c6b52; --pv-accent: #2a2c30; }

/* Сцена вокруг забора (небо, дом, зелень, дорога) — не физические цвета
   изделия, поэтому только токены темы. Физический цвет здесь один: полотно и
   столбы выбранного дизайна. */
.pv__sky { fill: var(--bg-2); }
.pv__tree { fill: var(--sage-50); }
.pv__bld { fill: var(--bg); }
.pv__roof { fill: var(--line-2); }
.pv__win { fill: var(--line-2); }
.pv__road { fill: var(--line-2); }
.pv__kerb { fill: var(--line); }
.pv__leaf { fill: var(--pv-accent); opacity: .35; }
.pv__slat { fill: var(--pv-fill); }
.pv__seam { fill: var(--bg-2); opacity: .8; }
.pv__post { fill: var(--pv-post); }
.pv__cap { fill: var(--pv-accent); }

/* ================================= АДАПТИВ ================================= */

@media (max-width: 1180px) {
  .project__grid { grid-template-columns: minmax(0, 1fr); }
  /* Спаны обязательно снимаем: «span 15» в сетке с одной колонкой создаёт
     неявные колонки, и страница уезжает вбок горизонтальной прокруткой. */
  .project__grid > * { grid-column: 1 / -1; }
  .project__side { flex-direction: row; flex-wrap: wrap; }
  .project__params, .project__warn { flex: 1 1 320px; min-width: 0; }
  .project { --plot-ratio: 16 / 9; }
}

@media (max-width: 860px) {
  /* Панель инструментов здесь стоит в потоке, а не поверх карты, поэтому
     пропорцию задаёт сам холст: у .plot__stage aspect-ratio + статичная панель
     внутри давали переполнение и обрезанные кнопки. */
  .plot__stage { aspect-ratio: auto; min-height: 0; }
  .plot__canvas { height: 62vw; min-height: 280px; max-height: 420px; }
  /* Вертикальная линия между «расстоянием» и «грунтом» превращается
     в горизонтальную вместе с самой сеткой. */
  .project__two > * + * { border-left: 0; border-top: 1px solid var(--line); padding-left: 0; padding-top: var(--s-4); }
  .project__presets { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Заголовок и поля снова переносятся: в одну строку они здесь не влезают
     и налезали друг на друга. */
  .project__design .project__block-head { flex-wrap: wrap; }
  .project__design-fields { flex: 1 1 100%; }
  .project__field-inline { width: auto; flex: 1 1 130px; }
  .plot__tool + .plot__tool { border-top: 0; }
  .plot__hud { left: 10px; bottom: 6px; }
  .project__table th:first-child, .project__table td:first-child { padding-left: var(--s-4); }
  .project__table th:last-child, .project__table td:last-child { padding-right: var(--s-4); }
  .project__side { flex-direction: column; }
  /* В колонке flex-basis становится высотой: без сброса карточка
     предупреждений растягивалась на 320 px пустоты. */
  .project__params, .project__warn { flex: 0 1 auto; }
  .project__two { grid-template-columns: 1fr; }
  .project__tiles { grid-template-columns: 1fr; }
  /* На узком экране панель инструментов перестаёт быть плавающей: поверх
     маленького холста она закрывала бы половину участка. */
  .plot__tools {
    position: static; flex-direction: row; overflow-x: auto; max-width: none; width: auto;
    border: 0; border-bottom: 1px solid var(--line); border-radius: 0; box-shadow: none;
  }
  /* Поле снизу оставляем под масштабную линейку — компас здесь спрятан;
     сверху — под подпись длины верхней стороны, иначе её срезает край. */
  .plot__canvas { padding: 22px var(--s-3) 32px; }
  .plot__canvas-box { height: auto; }
  .plot__tool { flex-direction: column; gap: 4px; text-align: center; white-space: nowrap; }
  .plot__tools-row { flex: none; }
  /* «Слои» тоже уходят из плавающего слоя: панель инструментов здесь стоит в
     потоке и заканчивается у нижнего края .plot__stage, а абсолютная кнопка
     ложилась прямо на неё и закрывала «Загрузить план». */
  .plot__layers {
    position: relative; top: auto; right: auto; bottom: auto;
    display: inline-block; margin: var(--s-3) var(--s-4);
  }
  /* Панель открывается вниз и от левого края: у правого края она уходила бы
     за экран — кнопка теперь слева, а коробка шире её втрое. */
  .plot__layers-box { top: calc(100% + 6px); bottom: auto; left: 0; right: auto; max-width: calc(100vw - 2 * var(--gutter)); }
  .plot__compass { display: none; }
  /* Две колонки: тип и ширина в первой строке, сторона и «убрать» во второй. */
  .project__opening { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }

  /* Раньше здесь стояло .project__actions { position: static } — и «Добавить
     комплект в корзину» на телефоне показывалась только в самом низу страницы,
     после ~6500 px прокрутки. Полосу возвращаем, но липкой оставляем ОДНУ
     главную кнопку: панель целиком (три кнопки + дисклеймер) съела бы четверть
     экрана. display: contents поднимает кнопки на уровень .project, и тогда
     содержащий блок липкой кнопки — вся страница проекта, а не короткая
     панель: кнопка держится у нижнего края с первого экрана. */
  .project { flex-flow: row wrap; align-items: flex-start; column-gap: 0; }
  .project > *, .project__actions > * { flex: 1 1 100%; min-width: 0; }
  .project__actions { display: contents; }
  .project__actions > [data-act="cart"] {
    order: 90;                       /* в потоке — в самом низу страницы */
    position: sticky; bottom: var(--s-3); z-index: 4;
    box-shadow: var(--shadow);
  }
  .project__disclaimer { margin-left: 0; max-width: none; }
}

/* ================================== ПЕЧАТЬ ==================================
   «Скачать PDF» без серверного endpoint печатает страницу браузером, поэтому
   лист должен выглядеть сметой, а не интерфейсом. */

@media print {
  .project__steps, .plot__tools, .plot__layers, .plot__compass, .plot__hint,
  .plot__panel, .project__actions, .project__presets { display: none !important; }
  /* На бумаге карта окружения — только заливка краской: печатаем чертёж. */
  .plot__canvas [data-layer="scene"] { display: none; }
  .plot__outline { stroke: var(--navy); }
  .plot__outline-halo { display: none; }
  .plot__dim { fill: var(--ink); stroke: var(--white); stroke-opacity: 1; }
  .plot__mark-label { fill: var(--muted); stroke: var(--white); stroke-opacity: 1; }
  .plot__house-body { fill: var(--bg-2); stroke: var(--muted); }
  /* Спецификация в PDF нужна целиком: браузер печатает только раскрытые details. */
  .project__breakdown summary { display: none; }
  .project__breakdown > .table-wrap { display: block !important; }
  .project__grid { display: block; }
  .plot, .project__warn { border: 1px solid var(--line); box-shadow: none; break-inside: avoid; }
  .project__estimate { break-before: page; }
  .project__tiles { grid-template-columns: repeat(3, 1fr); }
}

@media (max-width: 480px) {
  /* Подпись стороны («Сторона 1 · 24 м») требует 129 px, а половина ряда на
     360 px даёт 100 — выбранную сторону нельзя было прочитать. Ставим поля в
     столбик: длинная подпись важнее компактности строки. */
  .project__opening { grid-template-columns: minmax(0, 1fr); }
  .project__opening-del { justify-self: end; }
}
