@import url('fonts.css');

/* ==========================================================================
   SHALE — основная таблица стилей
   Порядок: токены → сброс → типографика → раскладка → компоненты → движение
   ========================================================================== */

/* ------------------------------------------------------------ ТОКЕНЫ */
:root{
  /* цвет: тёплые нейтральные — крем, слоновая кость, камень */
  --paper:#F5F1E9;
  --paper-2:#EDE7DA;
  --paper-3:#E3DACA;
  --paper-4:#D8CDB7;
  --paper-line:#D4C9B4;

  --ink:#16140F;
  --ink-2:#211E18;
  --ink-soft:#1F1D18;
  --ink-line:#332F27;

  --on-light:#191713;
  --on-light-mute:#6B6355;
  --on-dark:#F5F1E9;
  --on-dark-mute:#A29885;

  --gold:#C9A24E;
  --gold-bright:#E8C67C;
  --gold-deep:#8A6A22;

  /* градиенты разделов: логическое деление без резких границ.
     Раунд 4 — вся шкала сдвинута в тёплую сторону: холодные серо-белые
     оттенки читались на фоне золота как грязь. */
  --grad-paper:linear-gradient(180deg,#FAF6EE 0%,#F2EADA 100%);
  --grad-light:linear-gradient(180deg,#FDFBF6 0%,#F6F0E2 100%);
  --grad-beige:linear-gradient(180deg,#F1E8D6 0%,#E5D9BF 100%);
  --grad-cream:linear-gradient(180deg,#F9F3E5 0%,#EFE1C6 100%);
  --grad-ink:linear-gradient(180deg,#26221A 0%,#14120D 100%);
  /* тёмно-золотой акцент: угольный фон, золотой текст */
  --grad-gold-ink:linear-gradient(165deg,#2A2419 0%,#1A160F 55%,#231C10 100%);

  /* типографика */
  --font-display:'Jost',system-ui,sans-serif;
  --font-text:'Manrope',system-ui,sans-serif;

  --fs-display:clamp(34px,5.2vw,88px);
  --fs-h3:clamp(21px,1.8vw,29px);
  --fs-lead:clamp(17px,1.3vw,22px);
  --fs-body:clamp(15px,1.02vw,17px);
  --fs-small:clamp(13px,.84vw,15px);
  --fs-label:clamp(10px,.7vw,12px);
  --fs-numeral:clamp(42px,6.4vw,112px);

  /* пространство */
  --pad-x:clamp(20px,5vw,96px);
  --gutter:clamp(14px,1.5vw,30px);
  --sec-y:clamp(76px,10vh,180px);
  --wrap:1680px;
  --header-h:clamp(62px,7vh,86px);

  /* движение */
  --ease-main:cubic-bezier(.4,.5,.1,1);
  --ease-menu:cubic-bezier(.77,0,.175,1);
  --ease-out:cubic-bezier(.2,.8,.2,1);
  --dur-micro:.35s;
  --dur-ui:.46s;
  --dur-reveal:.95s;
  --dur-image:1.3s;
  --dur-hero:1.8s;
}

/* ------------------------------------------------------------ СБРОС */
*,*::before,*::after{box-sizing:border-box}
html{
  -webkit-text-size-adjust:100%;
  /* clip вместо hidden: не создаёт лишний контейнер прокрутки и не ломает
     position:sticky и события скролла, в отличие от overflow-x:hidden */
  overflow-x:clip;
}
body{
  margin:0;
  background:var(--paper);
  color:var(--on-light);
  font-family:var(--font-text);
  font-size:var(--fs-body);
  line-height:1.7;
  overflow-x:clip;
  -webkit-font-smoothing:antialiased;
}
img,picture,video{display:block;max-width:100%;height:auto}
h1,h2,h3,h4,p,ul,ol,figure,blockquote{margin:0}
ul{padding:0;list-style:none}
a{color:inherit;text-decoration:none}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
/* СКРУГЛЕНИЯ РАУНД 6. Рамка фокуса рисовалась с радиусом 2px, то есть
   практически острым углом, — при переходе по сайту с клавиатуры это видно
   на каждом элементе. Теперь она повторяет скругление самого элемента, а
   там, где своего радиуса нет, берёт мягкое значение по умолчанию. */
:focus-visible{outline:2px solid var(--gold-deep);outline-offset:3px;border-radius:12px}
/* Ловушка для спам-ботов. Правил для неё не было вовсе, и она показывалась
   человеку: белое поле с серой рамкой и подписью «Не заполняйте» — на каждой
   странице с формой. Это не только чужеродный прямоугольник в вёрстке: если
   посетитель случайно введёт туда что-нибудь, обработчик сочтёт заявку
   спамом и молча её выбросит (api/lead.php). Прячем от человека, оставляя
   в разметке для роботов: они читают код и заполняют такие поля. */
.hp{position:absolute!important;left:-9999px;width:1px;height:1px;overflow:hidden}
:focus-visible.btn,:focus-visible.socials a,:focus-visible.tier__cta{border-radius:999px}

/* Ссылка «к содержимому» выезжает из левого верхнего угла при переходе с
   клавиатуры — скругляем ей свободный угол, чтобы и она не была прямой. */
.skip-link{position:absolute;left:-9999px;top:0;z-index:999;background:var(--ink);color:var(--paper);padding:12px 20px;font-weight:700;border-radius:0 0 14px 0}
.skip-link:focus{left:0}

.sr-only{
  position:absolute!important;width:1px;height:1px;
  padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0;
}

.wrap{max-width:var(--wrap);margin-inline:auto;padding-inline:var(--pad-x)}

/* ------------------------------------------------------------ ТИПОГРАФИКА */
.label{
  font-family:var(--font-text);font-size:var(--fs-label);font-weight:700;
  letter-spacing:.2em;text-transform:uppercase;color:var(--on-light-mute);
  margin-bottom:clamp(18px,2.6vw,38px);
}
.display{
  font-family:var(--font-display);font-weight:300;font-size:var(--fs-display);
  line-height:1.04;letter-spacing:-.018em;text-wrap:balance;
  margin-bottom:clamp(22px,2.8vw,44px);
}
h3{font-family:var(--font-display);font-weight:300;font-size:var(--fs-h3);line-height:1.18}
.lead{font-size:var(--fs-lead);line-height:1.55;max-width:34em}
.lead--narrow{max-width:30em;color:var(--on-light-mute)}
p+p{margin-top:1.1em}

.numeral{
  display:block;font-family:var(--font-display);font-weight:200;
  font-size:var(--fs-numeral);line-height:.9;letter-spacing:-.025em;
  font-variant-numeric:tabular-nums;
}
.numeral span{font-size:.4em;vertical-align:super;margin-left:.08em;color:var(--gold-deep)}
.numeral--sm{font-size:clamp(32px,3.2vw,56px)}

/* ------------------------------------------------------------ СЕКЦИИ
   Каждый раздел чуть темнее или светлее соседнего, переход внутри раздела —
   мягкий градиент. Границ-линеек нет: делят оттенки, а не рамки. */
.section{padding-block:var(--sec-y);position:relative}
.section--paper{background:var(--grad-paper);color:var(--on-light)}
.section--light{background:var(--grad-light);color:var(--on-light)}
.section--beige{background:var(--grad-beige);color:var(--on-light)}
.section--ink{background:var(--grad-ink);color:var(--on-dark)}
.section--ink .label,.section--ink .lead--narrow{color:var(--on-dark-mute)}
.section--ink .numeral span{color:var(--gold)}
.section__head{display:grid;gap:6px}
.section__head .link-arrow{justify-self:start;margin-top:10px}

/* Тонкая золотая черта над номером раздела — акцент вместо разделительной линии */
.label--rule{position:relative;padding-top:20px}
.label--rule::before{
  content:'';position:absolute;left:0;top:0;width:54px;height:2px;
  background:linear-gradient(90deg,var(--gold),transparent);
}

/* ------------------------------------------------------------ ШАПКА */
.header{
  position:fixed;inset:0 0 auto 0;z-index:80;
  height:var(--header-h);
  display:flex;align-items:center;gap:var(--gutter);
  padding-inline:var(--pad-x);
  color:var(--on-dark);
  transition:background var(--dur-ui) var(--ease-main),
             color var(--dur-ui) var(--ease-main),
             backdrop-filter var(--dur-ui) var(--ease-main),
             box-shadow var(--dur-ui) var(--ease-main);
}
/* Шапка не появляется скачком. Скрипт ведёт --hs от 0 до 1 по первым
   экранам прокрутки, и по этой одной величине одновременно набирают силу
   заливка, размытие и подпись под шапкой. Цвет текста переключается
   отдельным классом ближе к концу — на полпути он читался бы плохо
   на обоих фонах сразу. */
.header::before{
  content:'';position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(253,251,246,.97) 0%,rgba(245,238,224,.90) 100%);
  box-shadow:0 1px 0 rgba(25,23,19,.09),0 10px 34px -22px rgba(25,23,19,.5);
  opacity:var(--hs,0);
}
/* РАДИУС РАЗМЫТИЯ ПОСТОЯННЫЙ (раунд 6). Раньше здесь стояло
   blur(calc(var(--hs) * 20px)) — радиус менялся каждый кадр прокрутки, и
   браузер каждый кадр заново размывал всю полосу шапки. Это и читалось как
   «логотип подвисает». Теперь радиус фиксированный: по --hs набирает силу
   только прозрачность подложки, а это компоновка на видеокарте, почти
   бесплатная. Само размытие включается после 60px прокрутки — на первом
   экране, где летит логотип, его нет вовсе. */
body.has-scrolled .header::before{
  backdrop-filter:blur(16px) saturate(1.08);
  -webkit-backdrop-filter:blur(16px) saturate(1.08);
}
body.has-scrolled .header{color:var(--on-light)}
/* На внутренних страницах логотип — обычная картинка. Он такой же чернильный,
   как в шапке главной, и так же светлеет над тёмной верхней плашкой. */
.header__logo-img{filter:invert(1);transition:filter var(--dur-ui) var(--ease-main)}
body.has-scrolled .header__logo-img{filter:invert(0)}

/* Пустое посадочное место: держит размер и позицию, куда прилетает вордмарк.
   Вордмарк очень широкий и тонкий — при ширине 120 px его высота около 10 px,
   поэтому кликабельной делаем всю высоту шапки, а не картинку. */
.header__logo{flex:none;display:flex;align-items:center;gap:10px;min-height:44px;position:relative}
/* Внутренние страницы: знак стоит так же, как садится на главной, —
   в 2,1 раза крупнее посадочного места, центр на верхней кромке страницы
   (верхняя половина срезана), буквы заходят на видимую часть. */
.header__sign-img{
  position:absolute;z-index:1;display:block;
  width:calc(clamp(30px,2.8vw,44px) * 2.1);aspect-ratio:820/711;
  left:calc(clamp(30px,2.8vw,44px) * -0.55);
  top:50%;transform:translateY(calc(-50% - var(--header-h) / 2));
  opacity:.92;
  filter:saturate(1.3) brightness(1.16) drop-shadow(0 0 18px rgba(201,162,78,.25));
}
/* Знак из материала: пропорции у него другие, чем у плоского золотого,
   и подсветка ему не нужна — иначе мрамор и бетон выгорают добела. */
.header__sign-img--mat{aspect-ratio:288/220;filter:none;opacity:.8}
.header__logo-img{position:relative;z-index:2;margin-left:calc(clamp(30px,2.8vw,44px) + 10px)}
/* Раунд 4: надпись в шапке крупнее — пропорции те же, вырос только кегль. */
.header__logo-slot{display:block;width:clamp(146px,12.4vw,208px);aspect-ratio:1016/87}
.header__logo-img{width:clamp(146px,12.4vw,208px)}
/* Посадочное место знака. Знак крупнее шапки и обрезается её верхним краем —
   в шапке видно примерно половину треугольника. */
.header__sign-slot{display:block;width:clamp(30px,2.8vw,44px);aspect-ratio:820/711}

.header__nav{margin-left:auto}
.header__nav ul{display:flex;gap:clamp(16px,1.9vw,38px)}
.header__nav a{
  font-size:var(--fs-small);font-weight:500;letter-spacing:.03em;
  position:relative;padding-block:6px;display:block;
  transition:opacity var(--dur-micro) var(--ease-out);
}
.header__nav a::after{
  content:'';position:absolute;left:0;right:0;bottom:2px;height:1px;background:currentColor;opacity:.7;
  /* transform вместо right: полоска растёт без пересчёта раскладки. */
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-ui) var(--ease-main);
}
.header__nav a:hover::after{transform:scaleX(1)}
.fade-siblings.is-hovered li:not(.is-lit){opacity:.32}
.fade-siblings li{transition:opacity var(--dur-micro) var(--ease-out)}

.header__phone{
  font-size:var(--fs-small);font-weight:700;letter-spacing:.03em;white-space:nowrap;
  padding:10px 0;position:relative;
}
.header__phone::after{
  content:'';position:absolute;left:0;right:0;bottom:6px;height:1px;background:currentColor;opacity:.7;
  transform:scaleX(0);transform-origin:right;transition:transform var(--dur-ui) var(--ease-main);
}
.header__phone:hover::after{transform:scaleX(1);transform-origin:left}

.header__burger{display:none;width:44px;height:44px;position:relative}
.header__burger span{
  position:absolute;left:10px;right:10px;height:1px;background:currentColor;
  transition:transform var(--dur-ui) var(--ease-menu),opacity var(--dur-micro);
}
.header__burger span:first-child{top:19px}
.header__burger span:last-child{top:25px}
body.menu-is-open .header{color:var(--on-light)}
body.menu-is-open .header__burger span:first-child{transform:translateY(3px) rotate(45deg)}
body.menu-is-open .header__burger span:last-child{transform:translateY(-3px) rotate(-45deg)}

/* ------------------------------------------------------------ ВОРДМАРК
   Один элемент на всю главную: стоит внизу первого экрана и при прокрутке
   физически переезжает в шапку. Позицию каждый кадр считает скрипт — он
   помещает элемент между двумя посадочными местами.

   Живёт прямо в <body>, а не внутри первого экрана. Первый экран создаёт
   собственный слой наложения (isolation), и вордмарк внутри него не мог бы
   подняться выше шапки: любой z-index работал бы только внутри экрана. */
.brandmark{
  /* display обязателен: без него ссылка остаётся строчной,
     а к строчным элементам aspect-ratio не применяется и высота схлопывается */
  display:block;
  position:fixed;top:0;left:0;z-index:95;
  aspect-ratio:1016/87;
  transform-origin:0 0;will-change:transform;
}
/* Буквы стоят там же, где в исходном начертании: координаты взяты из нарезки,
   поэтому собранное слово в точности повторяет фирменный логотип. */
.brandmark .wm{
  position:absolute;top:0;height:100%;overflow:hidden;
  left:calc(var(--x) * 100% / 1016);
  width:calc(var(--w) * 100% / 1016);
}
.brandmark .wm img{
  width:100%;height:100%;object-fit:contain;
  transform:translateY(106%);
  transition:transform 1.25s var(--ease-main);
  transition-delay:calc(var(--i) * 95ms + 300ms);
  /* Буквы нарисованы почти чёрным. Над тёмным первым экраном они должны быть
     кремовыми, в кремовой шапке — чернильными. Инверсию ведёт скрипт: одно
     и то же тело просто меняет цвет по ходу перелёта. */
  filter:invert(var(--wm-inv,1));
}
body.has-landed .brandmark .wm img{transform:translateY(0)}
.hero__brand-slot{
  display:block;width:min(88vw,1180px);margin-inline:auto;
  aspect-ratio:1016/87;pointer-events:none;
}

/* ------------------------------------------------------------ МОБИЛЬНОЕ МЕНЮ */
.mobile-menu{
  position:fixed;inset:0;z-index:85;
  background:var(--grad-paper);color:var(--on-light);
  display:flex;flex-direction:column;justify-content:center;gap:36px;
  padding:calc(var(--header-h) + 24px) var(--pad-x) 40px;
  clip-path:inset(0 0 100% 0);
  transition:clip-path .8s var(--ease-menu);
}
body.menu-is-open .mobile-menu{clip-path:inset(0 0 0 0)}
.mobile-menu[hidden]{display:flex}
.mobile-menu__list li{overflow:hidden}
.mobile-menu__list a{
  display:block;font-family:var(--font-display);font-weight:300;
  font-size:clamp(28px,7.4vw,50px);line-height:1.28;
  transform:translateY(110%);
  transition:transform .7s var(--ease-main);
  transition-delay:calc(var(--mi,0) * 45ms);
}
body.menu-is-open .mobile-menu__list a{transform:translateY(0)}
.mobile-menu__foot{display:flex;flex-direction:column;gap:6px;color:var(--on-light-mute);font-size:var(--fs-lead)}

/* ------------------------------------------------------------ ПЕРВЫЙ ЭКРАН
   Фотография вечернего дома — тёмная, поэтому текст на ней светлый. */
.hero{
  position:relative;min-height:100svh;
  display:grid;grid-template-rows:1fr auto auto;
  /* Колонка задана явно и с нулевым минимумом. Без этого ширину первого
     экрана определял самый широкий потомок — подпись .hero__meta с колонками
     по max-content, — и на телефоне блок раздувался до 457 px при экране 375.
     Последняя буква вордмарка уходила за обрез. */
  grid-template-columns:minmax(0,1fr);
  align-items:end;
  padding-block:calc(var(--header-h) + 24px) clamp(18px,3vh,40px);
  isolation:isolate;
  background:var(--ink);
  color:var(--on-dark);
}
/* Обрезку держит отдельный слой, а не сам первый экран: запас фона под
   параллакс не должен превращаться в горизонтальную прокрутку. */
.hero__bg{position:absolute;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
.hero__media{
  position:absolute;inset:-6%;
  transform:translate3d(calc(var(--mx,0) * -16px),calc(var(--py,0px) + var(--my,0) * -16px),0);
}
.hero__media img{
  width:100%;height:100%;object-fit:cover;object-position:center 62%;
  opacity:0;transform:scale(1.14);
  transition:opacity 1.2s ease,transform 2.8s var(--ease-main);
}
body.has-landed .hero__media img{opacity:1}
body.has-loaded .hero__media img{transform:scale(1)}
/* Вуаль слегка притемняет верх и низ: сверху под шапку, снизу под вордмарк.
   Середина остаётся почти нетронутой — там сам дом. */
.hero__scrim{
  position:absolute;inset:0;
  background:
    linear-gradient(to bottom,
      rgba(10,9,7,.62) 0%,
      rgba(10,9,7,.18) 26%,
      rgba(10,9,7,.30) 58%,
      rgba(10,9,7,.78) 100%),
    linear-gradient(100deg,rgba(10,9,7,.45) 0%,rgba(10,9,7,0) 62%);
}
/* Фирменный треугольник: присутствует постоянно, золотой и заметный,
   но сквозь него видно фотографию. */
.hero__mark{
  position:absolute;right:5%;top:15%;
  width:min(32vw,380px);height:auto;
  /* Раунд 5: это только посадочная разметка. Сам знак рисует .brandsign —
     он стоит на этом месте и улетает в шапку. Так знак ровно один. */
  visibility:hidden;
}

.hero__inner{
  position:relative;z-index:2;grid-row:2;
  /* min-width:0 обязателен: в сетке минимум по умолчанию равен содержимому,
     и без него блок всё равно упёрся бы в самое длинное слово. */
  width:100%;min-width:0;max-width:var(--wrap);margin-inline:auto;
  padding-inline:var(--pad-x);
  padding-bottom:clamp(24px,4.5vh,64px);
  /* Пока вордмарк летит в шапку, текст первого экрана уходит вверх и гаснет —
     так буквам не с чем пересечься по дороге. */
  opacity:calc(1 - var(--hp,0));
  transform:translate3d(0,calc(var(--hp,0) * -46px),0);
}
/* Подпись над заголовком читается на любой фотографии: собственный светлый
   цвет, полупрозрачная подложка с размытием и тонкая тень под буквами.
   Приглушённый серый на снимке терялся полностью. */
.hero__meta{
  /* inline-grid: ширина стекла ровно по тексту. Прежний flex с fit-content
     считал ширину ДО переноса строк — стекло тянулось до фонового знака. */
  display:inline-grid;grid-template-columns:repeat(3,max-content);
  gap:7px clamp(12px,1.8vw,28px);
  font-size:var(--fs-label);letter-spacing:.2em;text-transform:uppercase;
  color:#F7F2E6;font-weight:700;
  width:fit-content;max-width:100%;
  padding:12px clamp(18px,2vw,30px);border-radius:26px;
  /* Настоящее стекло (правка владельца 26.08): собственного фона у плашки
     почти нет — только преломление кадра под ней. Читаемость держат
     размытие и тень букв, а не затемняющая подложка. Тонкий световой
     кант сверху даёт кромку стекла, снизу — мягкую тень на фото. */
  background:linear-gradient(180deg,rgba(255,255,255,.055),rgba(255,255,255,.012) 55%,rgba(255,255,255,.03));
  backdrop-filter:blur(18px) saturate(1.35) brightness(1.04);
  -webkit-backdrop-filter:blur(18px) saturate(1.35) brightness(1.04);
  border:1px solid rgba(255,255,255,.13);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28),
             inset 0 -1px 0 rgba(255,255,255,.07),
             0 14px 34px -26px rgba(8,7,5,.55);
  text-shadow:0 1px 10px rgba(8,7,5,.62),0 0 2px rgba(8,7,5,.35);
  opacity:0;transform:translateY(12px);
  transition:opacity .9s var(--ease-main) .5s,transform .9s var(--ease-main) .5s;
}
/* География — первой строкой на всю ширину, факты — второй. */
.hero__meta span:first-child{grid-column:1/-1}
@media (max-width:700px){.hero__meta{grid-template-columns:repeat(2,max-content)}}
body.has-loaded .hero__meta{opacity:1;transform:none}
.hero__meta span{position:relative;padding-left:15px}
/* Открытое мобильное меню лежит ниже логотипа (85 против 94/95) — на время
   меню летящие надпись и знак гаснут, иначе буква S ложится на телефоны.
   !important нужен: их прозрачность каждый кадр пишет скрипт в style. */
body.menu-is-open .brandmark,
body.menu-is-open .brandsign{opacity:0!important;visibility:hidden;transition:opacity .2s ease,visibility 0s .2s}
.hero__meta span::before{content:'';position:absolute;left:0;top:.6em;width:7px;height:1px;background:var(--gold)}

.hero__title{
  font-family:var(--font-display);font-weight:300;
  font-size:clamp(26px,3.4vw,54px);line-height:1.14;letter-spacing:-.015em;
  max-width:17em;margin-top:clamp(16px,2.4vw,32px);
  color:var(--on-dark);
  text-shadow:0 2px 30px rgba(10,9,7,.45);
}

.hero__brand{grid-row:3;position:relative;z-index:2;min-width:0}

.hero__scroll{
  position:absolute;right:var(--pad-x);bottom:clamp(24px,4.5vh,64px);z-index:3;
  display:grid;justify-items:center;gap:10px;
  font-size:var(--fs-label);letter-spacing:.2em;text-transform:uppercase;
  color:var(--on-dark-mute);
  opacity:0;transition:opacity .8s ease 1.2s,color var(--dur-micro);
}
body.has-displayed .hero__scroll{opacity:1}
.hero__scroll:hover{color:var(--gold-bright)}
.hero__scroll-line{width:1px;height:clamp(26px,5vh,52px);background:linear-gradient(var(--gold),transparent);
  animation:scrollPulse 2.4s var(--ease-main) infinite}
@keyframes scrollPulse{0%,100%{transform:scaleY(.35);transform-origin:top}50%{transform:scaleY(1);transform-origin:top}}
body.has-scrolled .hero__scroll{opacity:0;pointer-events:none}

/* ------------------------------------------------------------ ВЕРХ ВНУТРЕННЕЙ СТРАНИЦЫ */
.page-hero{
  position:relative;isolation:isolate;overflow:hidden;
  background:var(--ink);color:var(--on-dark);
  min-height:min(62vh,620px);display:flex;align-items:flex-end;
  padding-block:calc(var(--header-h) + clamp(40px,7vw,110px)) clamp(34px,5vw,80px);
}
.page-hero__media{position:absolute;inset:-6%;z-index:-2}
.page-hero__media img{width:100%;height:100%;object-fit:cover;transform:translate3d(0,var(--py,0px),0)}
.page-hero::after{
  content:'';position:absolute;inset:0;z-index:-1;
  background:linear-gradient(to bottom,rgba(10,9,7,.70) 0%,rgba(10,9,7,.34) 45%,rgba(10,9,7,.80) 100%);
}
.page-hero .label{color:var(--on-dark-mute)}
.page-hero h1{
  font-family:var(--font-display);font-weight:300;font-size:var(--fs-display);
  line-height:1.05;letter-spacing:-.018em;max-width:15em;text-wrap:balance;
}
.page-hero .lead{margin-top:clamp(16px,2vw,26px);color:var(--on-dark)}
.crumbs{display:flex;flex-wrap:wrap;gap:8px;font-size:var(--fs-label);letter-spacing:.14em;
  text-transform:uppercase;color:var(--on-dark-mute);margin-bottom:clamp(16px,2.2vw,30px)}
.crumbs a:hover{color:var(--gold-bright)}
.crumbs span::before{content:'—';margin-right:8px}

/* Проза внутренних страниц */
.prose{max-width:44em}
.prose h3{margin:clamp(26px,3vw,44px) 0 12px}
.prose p{color:var(--on-light-mute)}
.prose ul{display:grid;gap:9px;margin-top:14px}
.prose li{position:relative;padding-left:24px;font-size:var(--fs-small);line-height:1.55;color:var(--on-light-mute)}
.prose li::before{content:'';position:absolute;left:0;top:.62em;width:10px;height:1px;background:var(--gold)}
.prose--wide{max-width:none}

/* Двухколоночная сетка внутренних страниц */
.cols{display:grid;gap:clamp(28px,3.6vw,72px);grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);align-items:start}
.cols--even{grid-template-columns:repeat(2,minmax(0,1fr))}

/* Плитка услуг и этапов */
.tiles{display:grid;gap:var(--gutter);grid-template-columns:repeat(3,minmax(0,1fr));margin-top:clamp(30px,3.6vw,58px)}
.tile{border:1px solid var(--paper-line);border-radius:14px;padding:clamp(18px,2.2vw,30px);
  background:linear-gradient(180deg,rgba(255,253,249,.7),rgba(255,253,249,0));
  transition:border-color var(--dur-ui) var(--ease-main),transform var(--dur-ui) var(--ease-main)}
.tile:hover{border-color:var(--gold);transform:translateY(-4px)}
/* Раунд 5, этап 5: знак технологии из «её» материала — в правом верхнем углу. */
.tile{position:relative}
.tile__mat{
  position:absolute;right:clamp(14px,1.8vw,24px);top:clamp(12px,1.6vw,20px);
  width:clamp(44px,4.6vw,62px);height:auto;
  filter:drop-shadow(0 3px 8px rgba(11,11,13,.18));
  transition:transform var(--dur-ui) var(--ease-main);
}
.tile .tile__num{font-family:var(--font-display);font-size:var(--fs-small);color:var(--gold-deep);display:block;margin-bottom:12px}
.tile h3{margin-bottom:10px}
.tile p{font-size:var(--fs-small);color:var(--on-light-mute)}
.section--ink .tile{border-color:var(--ink-line);background:linear-gradient(180deg,rgba(255,253,249,.05),transparent)}
.section--ink .tile p{color:var(--on-dark-mute)}

/* Галерея объекта */
/* Плашка на визуализациях: это проект, а не сданный объект */
.viz-badge{
  position:absolute;top:14px;left:14px;z-index:2;
  padding:5px 12px;border-radius:999px;
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  background:rgba(11,11,13,.62);color:#F5F1E8;
  backdrop-filter:blur(4px);
}
.gallery figure{position:relative}
.gallery{display:grid;gap:var(--gutter);grid-template-columns:repeat(2,minmax(0,1fr));margin-top:clamp(30px,3.6vw,58px)}
.gallery figure:first-child{grid-column:1/-1}
.gallery picture{display:block;overflow:hidden;aspect-ratio:3/2;background:var(--paper-3)}
.gallery img{width:100%;height:100%;object-fit:cover;border-radius:12px;
  transform:translate3d(0,var(--py,0px),0) scale(var(--ps,1.03));
  transition:transform var(--dur-image) var(--ease-main)}
.gallery figure:hover img{--ps:1.08}
.gallery figcaption{padding-top:12px;font-size:var(--fs-small);color:var(--on-light-mute);line-height:1.5}

/* Таблица фактов объекта */
.facts{display:grid;gap:0;margin-top:clamp(24px,3vw,44px)}
.facts div{display:grid;grid-template-columns:minmax(0,14em) minmax(0,1fr);gap:clamp(12px,2vw,30px);
  border-top:1px solid var(--paper-line);padding:14px 0}
.facts dt{color:var(--on-light-mute);font-size:var(--fs-small)}
.facts dd{margin:0}

@media (max-width:1240px){
  .cols,.cols--even{grid-template-columns:minmax(0,1fr)}
  .tiles{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:640px){
  .tiles,.gallery{grid-template-columns:minmax(0,1fr)}
  .facts div{grid-template-columns:minmax(0,1fr);gap:4px}
}

/* ------------------------------------------------------------ БЕГУЩАЯ СТРОКА
   Идёт медленно, чтобы слова успевали читаться. Прокрутка колеса лишь слегка
   подталкивает её, а не разгоняет. */
.marquee{
  overflow:hidden;padding-block:clamp(18px,2.4vw,34px);
  background:linear-gradient(180deg,#F1EBDF,#E9E2D3);
  border-bottom:1px solid var(--paper-line);
  user-select:none;
}
.marquee__track{display:flex;width:max-content;will-change:transform}
.marquee__group{display:flex;flex:none;align-items:center}
.marquee__group span{
  font-family:var(--font-display);font-weight:300;
  font-size:clamp(20px,2.4vw,38px);line-height:1;letter-spacing:-.01em;
  color:var(--on-light);padding-inline:clamp(18px,2.2vw,40px);
  display:flex;align-items:center;gap:clamp(18px,2.2vw,40px);
  white-space:nowrap;
}
.marquee__group span::after{content:'';width:6px;height:6px;border-radius:50%;background:var(--gold-deep);opacity:.6;flex:none}

/* ------------------------------------------------------------ ПОЗИЦИОНИРОВАНИЕ */
.positioning{overflow:hidden}
.positioning__grid{
  display:grid;gap:clamp(36px,4.6vw,84px);
  grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);
  align-items:start;
}
.positioning__text p{color:var(--on-light-mute)}
.positioning__text .lead{color:var(--on-light);margin-bottom:1.2em}
.positioning__facts{display:grid;gap:clamp(20px,2.4vw,34px)}
/* Раунд 5, этап 2: списки-источники скрыты — их содержимое показывает
   облачко мыслей (слой .thought в body), раскрывающееся справа от курсора. */
.facts__tech{position:relative;cursor:default;outline:none}
.tech-pop{display:none}
.tech-pop li{font-size:14px;line-height:2;color:var(--on-light);white-space:nowrap}
.tech-pop__note{
  max-width:270px;white-space:normal!important;line-height:1.5!important;
  padding-bottom:8px;margin-bottom:6px;border-bottom:1px solid var(--paper-line);
  color:var(--on-light-mute)!important;font-size:13px!important;
}

/* Слово «более» при крупной цифре — мелко, капителью, золотом. */
.numeral__pre{
  font-style:normal;font-size:.22em;letter-spacing:.14em;text-transform:uppercase;
  margin-right:.6em;vertical-align:.62em;color:var(--gold-deep);font-weight:600;
}
@media (hover:none){.tech-pop{display:none}}
/* На телефоне мышиных сдвигов нет, а скролльный параллакс придавлен:
   иначе запаса в 6% не хватает и фон «убегает» за край. */
@media (hover:none){
  .hero__media{transform:translate3d(0,calc(var(--py,0px) * .3),0)}
}
/* Мини-знаки у курсора: сетка на весь экран, слой не ловит события
   и лежит ниже шапки (80), прогресс-бара (94) и курсора (200). */
/* Полоса цифр на внутренних страницах: три в строку, на узком экране
   складывается в столбик. На главной и в «О компании» тот же список
   стоит колонкой — там он в узкой части сетки. */
.positioning__facts--row{grid-template-columns:repeat(3,minmax(0,1fr));
  gap:clamp(20px,3vw,44px)}
@media (max-width:760px){.positioning__facts--row{grid-template-columns:minmax(0,1fr)}}
.facts-strip{padding-block:clamp(28px,3.4vw,52px)}
.positioning__facts li{
  border-top:1px solid var(--paper-line);padding-top:16px;position:relative;
}
.positioning__facts li::before{
  content:'';position:absolute;left:0;top:-1px;width:0;height:2px;background:var(--gold);
  transition:width 1.1s var(--ease-main);
}
.positioning__facts li.is-animated::before{width:38px}
.positioning__facts b{color:var(--on-light)}
.positioning__facts span:last-child{display:block;margin-top:6px;font-size:var(--fs-small);color:var(--on-light-mute)}
/* Крупный водяной знак — тот же треугольник, что и на первом экране */
.positioning__mark{
  /* Раунд 5: как в КП, но зеркально — знак в левом верхнем углу, крупнее. */
  /* Этап 2: знак опущен, чтобы верхушка треугольника была видна целиком,
     и поднят по плотности — раньше 7% терялись на бумаге. */
  position:absolute;left:-4%;top:4%;
  width:min(44vw,540px);height:auto;opacity:.11;pointer-events:none;
  transform:translate3d(0,var(--py,0px),0);
}

/* ------------------------------------------------------------ КАРТОЧКИ ПРОЕКТОВ
   Все карточки одного формата 3:2 и стоят по одной сетке — ни одна не
   выбивается ни размером, ни кадрированием. */
.projects__grid{
  display:grid;gap:var(--gutter) clamp(14px,1.5vw,30px);
  grid-template-columns:repeat(3,minmax(0,1fr));
  margin-top:clamp(30px,3.6vw,60px);
}
.card a{display:flex;flex-direction:column;height:100%}
.card__media{overflow:hidden;background:var(--paper-3);aspect-ratio:3/2;position:relative;border-radius:14px}
.card__media img{
  width:100%;height:100%;object-fit:cover;
  transform:translate3d(0,var(--py,0px),0) scale(var(--ps,1.04));
  transition:transform var(--dur-image) var(--ease-main);
}
.card:hover .card__media img{--ps:1.09}
.card__body{padding-top:16px;position:relative;flex:1;display:flex;flex-direction:column}
.card__body .label{margin-bottom:8px}
.card__body h3{margin-bottom:8px;transition:color var(--dur-micro)}
.card:hover .card__body h3{color:var(--gold-deep)}
.card__desc{font-size:var(--fs-small);color:var(--on-light-mute);margin-bottom:10px}
.card__specs{display:grid;gap:4px;margin-top:auto}
.card__specs div{
  display:flex;gap:10px;font-size:var(--fs-small);
  border-top:1px solid var(--paper-line);padding-top:6px;
}
.card__specs dt{flex:none;width:8.5em;color:var(--on-light-mute)}
.card__specs dd{margin:0;color:var(--on-light)}
.card__price{color:var(--gold-deep);font-weight:700}
.card__body::before{
  content:'';position:absolute;top:0;left:0;right:100%;height:1px;background:var(--gold-deep);
  transition:right var(--dur-ui) var(--ease-main);
}
.card:hover .card__body::before{right:0}

/* ------------------------------------------------------------ ТЕХНОЛОГИИ */
.tech__layout{
  display:grid;gap:clamp(28px,3.6vw,68px);
  grid-template-columns:minmax(0,1fr) minmax(0,1.15fr);
  align-items:start;margin-top:clamp(32px,4vw,66px);
}
.tech__list button{
  width:100%;display:flex;align-items:baseline;gap:clamp(12px,1.6vw,26px);
  padding:clamp(13px,1.5vw,21px) 0;
  border-top:1px solid var(--paper-line);text-align:left;
  transition:color var(--dur-micro) var(--ease-out),padding-left var(--dur-ui) var(--ease-main);
}
.tech__list li:last-child button{border-bottom:1px solid var(--paper-line)}
.tech__num{font-family:var(--font-display);font-size:var(--fs-small);color:var(--on-light-mute);flex:none}
.tech__name{font-family:var(--font-display);font-weight:300;font-size:clamp(19px,2.1vw,32px);line-height:1.1}
.tech__list button:hover,.tech__list button.is-active{color:var(--gold-deep);padding-left:clamp(8px,1vw,18px)}

/* Пока кадр открывается шторкой, из-под него видно не серую заглушку,
   а тёплый кремово-золотой градиент. */
.tech__stage{
  /* Кадр технологии был единственной картинкой с прямыми углами: у карточек
     проектов (.card__media) скругление 14px, а здесь его не было. */
  border-radius:14px;
  position:relative;aspect-ratio:3/2;overflow:hidden;
  background:linear-gradient(135deg,#F0E8D6 0%,#DFCDA0 55%,#C9A24E 100%);
}
.tech__stage figure{
  position:absolute;inset:0;
  clip-path:inset(0 0 0 100%);
  transition:clip-path .9s var(--ease-main);
}
.tech__stage figure.is-active{clip-path:inset(0 0 0 0)}
.tech__stage img{width:100%;height:100%;object-fit:cover;transform:scale(1.07);transition:transform 1.5s var(--ease-main)}
.tech__stage figure.is-active img{transform:scale(1)}
/* Новый кадр открывается сквозь золотую вуаль, которая тут же сходит на нет:
   переход читается как тёплая вспышка, а не как смена серых прямоугольников. */
.tech__stage figure::after{
  content:'';position:absolute;inset:0;pointer-events:none;opacity:0;
  background:linear-gradient(100deg,rgba(232,198,124,.92) 0%,rgba(201,162,78,.34) 60%,rgba(240,232,214,.2) 100%);
}
.tech__stage figure.is-active::after{animation:goldWash 1.05s var(--ease-main)}
@keyframes goldWash{0%{opacity:.92}60%{opacity:.42}100%{opacity:0}}
.tech__stage figcaption{
  position:absolute;left:0;right:0;bottom:0;
  padding:clamp(14px,1.8vw,26px);
  background:linear-gradient(transparent,rgba(20,19,16,.88));
  color:var(--on-dark);font-size:var(--fs-small);line-height:1.5;
}

/* ------------------------------------------------------------ ЧТО ВХОДИТ / НЕ ВХОДИТ */
.scope__grid{
  display:grid;gap:clamp(26px,3.2vw,60px);
  grid-template-columns:minmax(0,1.4fr) minmax(0,1fr);
  margin-top:clamp(32px,4vw,66px);
}
.scope__col{border-top:1px solid var(--ink-line);padding-top:clamp(18px,2.2vw,34px)}
.scope__col h3{display:flex;align-items:center;gap:12px;margin-bottom:clamp(16px,1.8vw,26px)}
.dot{width:8px;height:8px;border-radius:50%;flex:none}
.dot--in{background:var(--gold)}
.dot--out{background:transparent;box-shadow:inset 0 0 0 1px var(--on-dark-mute)}
.scope__col ul{display:grid;gap:9px}
.scope__col li{position:relative;padding-left:24px;font-size:var(--fs-small);line-height:1.55}
.scope__col--in li::before{content:'';position:absolute;left:0;top:.62em;width:10px;height:1px;background:var(--gold)}
.scope__col--out li{color:var(--on-dark-mute)}
.scope__col--out li::before{content:'';position:absolute;left:0;top:.62em;width:10px;height:1px;background:var(--on-dark-mute);opacity:.5}
.scope__note{margin-top:clamp(18px,2.2vw,30px);font-size:var(--fs-small);color:var(--on-dark-mute);max-width:28em}

/* ------------------------------------------------------------ ВНУТРИ */
.inside__grid{
  display:grid;gap:var(--gutter);
  grid-template-columns:repeat(3,minmax(0,1fr));
  margin-top:clamp(32px,4vw,66px);
}
.inside__grid picture{display:block;overflow:hidden;aspect-ratio:3/2;background:var(--paper-3)}
.inside__grid img{
  width:100%;height:100%;object-fit:cover;
  transform:translate3d(0,var(--py,0px),0) scale(var(--ps,1.05));
  transition:transform var(--dur-image) var(--ease-main);
}
.inside__grid figure:hover img{--ps:1.1}
.inside__grid figcaption{padding-top:12px;font-size:var(--fs-small);color:var(--on-light-mute);line-height:1.5}

/* ------------------------------------------------------------ ЦЕНЫ
   Комплектации обведены рамкой и раскрываются: внутри полный состав работ
   и кнопка заявки именно на эту комплектацию. */
.pricing__grid{
  display:grid;gap:var(--gutter);
  grid-template-columns:repeat(3,minmax(0,1fr));
  margin-top:clamp(32px,4vw,66px);
  align-items:start;
}
.tier{
  border:1px solid var(--paper-line);
  background:linear-gradient(180deg,rgba(255,253,249,.75),rgba(255,253,249,0));
  padding:clamp(20px,2.4vw,34px);
  transition:border-color var(--dur-ui) var(--ease-main),box-shadow var(--dur-ui) var(--ease-main);
}
.tier:hover,.tier.is-open{border-color:var(--gold);box-shadow:0 18px 40px -28px rgba(90,70,25,.55)}
.tier--main{border-color:var(--gold-deep)}
.tier h3{margin-bottom:clamp(12px,1.6vw,20px)}
.tier__price{font-family:var(--font-display);font-weight:200;font-size:clamp(30px,3.4vw,54px);line-height:1;letter-spacing:-.025em}
.tier__from{font-size:.34em;color:var(--on-light-mute);vertical-align:middle;margin-right:.35em;letter-spacing:0}
.tier__unit{font-size:.34em;color:var(--gold-deep);vertical-align:middle;margin-left:.2em}
.tier__desc{margin-top:clamp(12px,1.6vw,20px);font-size:var(--fs-small);color:var(--on-light-mute)}

.tier__toggle{
  margin-top:clamp(16px,2vw,26px);width:100%;
  display:flex;align-items:center;justify-content:space-between;gap:12px;
  min-height:44px;padding-top:14px;border-top:1px solid var(--paper-line);
  font-size:var(--fs-label);font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  transition:color var(--dur-micro);
}
.tier__toggle:hover{color:var(--gold-deep)}
.tier__toggle::after{
  content:'';width:11px;height:11px;flex:none;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:translateY(-3px) rotate(45deg);
  transition:transform var(--dur-ui) var(--ease-main);
}
.tier.is-open .tier__toggle::after{transform:translateY(1px) rotate(-135deg)}
/* Раскрытие идёт по сетке: содержимое не нужно измерять и подставлять в px,
   поэтому нет ни скачка высоты, ни рывка при первом клике. */
.tier__detail{display:grid;grid-template-rows:0fr;transition:grid-template-rows .6s var(--ease-main)}
.tier.is-open .tier__detail{grid-template-rows:1fr}
.tier__detail>div{overflow:hidden}
.tier__detail ul{display:grid;gap:8px;padding-top:16px}
.tier__detail li{position:relative;padding-left:22px;font-size:var(--fs-small);line-height:1.5;color:var(--on-light-mute)}
.tier__detail li::before{content:'';position:absolute;left:0;top:.62em;width:10px;height:1px;background:var(--gold)}
.tier__detail h4{
  margin:18px 0 8px;font-family:var(--font-text);font-size:var(--fs-label);font-weight:700;
  letter-spacing:.16em;text-transform:uppercase;color:var(--on-light-mute);
}
.tier__detail p{font-size:var(--fs-small);color:var(--on-light-mute)}
.tier .btn{margin-top:20px;width:100%}

/* ------------------------------------------------------------ КАЛЬКУЛЯТОР */
.calc{
  margin-top:clamp(52px,6.4vw,110px);
  border-top:1px solid var(--paper-line);
  padding-top:clamp(26px,3.2vw,48px);
}
.calc__layout{
  display:grid;gap:clamp(26px,3.4vw,64px);
  grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
  align-items:start;margin-top:clamp(24px,3vw,44px);
}
.calc>h3{margin-bottom:12px}
.calc__controls{display:grid;gap:clamp(18px,2.2vw,30px)}
.calc__legend{display:block;margin-bottom:10px}
/* Уровень отделки имеет смысл только для «под ключ»: в коробке и тёплом
   контуре отделки нет вовсе, и держать неработающий переключатель нечестно. */
.calc--finish-off .calc__row--finish{display:none}
.calc__row label{
  display:flex;justify-content:space-between;align-items:baseline;gap:12px;
  font-size:var(--fs-label);font-weight:700;letter-spacing:.16em;text-transform:uppercase;
  color:var(--on-light-mute);margin-bottom:10px;
}
.calc__row output{
  font-family:var(--font-display);font-size:clamp(16px,1.4vw,22px);font-weight:300;
  letter-spacing:0;text-transform:none;color:var(--on-light);
}
.calc__row input[type=range]{
  width:100%;height:44px;background:transparent;accent-color:var(--gold-deep);cursor:pointer;
}
.calc__seg{display:flex;flex-wrap:wrap;gap:8px}
.calc__seg button{
  min-height:44px;padding:0 clamp(12px,1.4vw,20px);border-radius:999px;
  border:1px solid var(--paper-line);background:rgba(255,253,249,.6);
  font-size:var(--fs-small);
  transition:border-color var(--dur-micro),background var(--dur-micro),color var(--dur-micro);
}
.calc__seg button:hover{border-color:var(--gold)}
.calc__seg button.is-on{border-color:var(--gold-deep);background:var(--gold-deep);color:var(--paper)}

.calc__view{display:grid;gap:clamp(16px,2vw,26px)}
.calc__sketch{
  aspect-ratio:4/3;
  background:linear-gradient(180deg,#FBF9F4,#F0EADD);
  border:1px solid var(--paper-line);
}
.calc__sketch svg{width:100%;height:100%;display:block}
.calc__out{display:grid;gap:6px}
.calc__sum{
  font-family:var(--font-display);font-weight:200;
  font-size:clamp(28px,3.4vw,52px);line-height:1.05;letter-spacing:-.02em;
  font-variant-numeric:tabular-nums;
}
.calc__sum small{font-size:.34em;color:var(--on-light-mute);letter-spacing:.1em;text-transform:uppercase;display:block;margin-bottom:6px}
.calc__rate{font-size:var(--fs-small);color:var(--on-light-mute)}
.calc__note{font-size:var(--fs-small);color:var(--on-light-mute);max-width:34em}
.calc .btn{margin-top:6px}

/* ------------------------------------------------------------ ФОРМА */
.contact__wrap{
  display:grid;gap:clamp(36px,4.6vw,90px);
  grid-template-columns:minmax(0,1.2fr) minmax(0,1fr);
  align-items:start;
}
.contact__text .lead{color:var(--on-light-mute)}
.contact__list{margin-top:clamp(22px,2.8vw,38px);display:grid;gap:9px}
.contact__list li{position:relative;padding-left:22px;font-size:var(--fs-small);color:var(--on-light-mute)}
.contact__list li::before{content:'';position:absolute;left:0;top:.62em;width:10px;height:1px;background:var(--gold-deep)}

.form{display:grid;gap:clamp(18px,2.4vw,32px)}
.field{position:relative}
.field input[type=text],.field input[type=tel],.field input[type=email],.field textarea{
  width:100%;padding:18px 0 12px;
  background:transparent;border:0;border-bottom:1px solid var(--paper-line);
  font:inherit;color:var(--on-light);
  transition:border-color var(--dur-ui) var(--ease-main);
}
.field textarea{resize:vertical;min-height:76px;line-height:1.55}
.field label{
  position:absolute;left:0;top:18px;color:var(--on-light-mute);pointer-events:none;
  transition:transform var(--dur-ui) var(--ease-main),font-size var(--dur-ui) var(--ease-main);
}
.field input:focus,.field textarea:focus{outline:none;border-bottom-color:var(--gold-deep)}
/* Всплывающая подпись — только у полей ввода. Галочку сюда пускать нельзя:
   у чекбокса нет плейсхолдера, поэтому :not(:placeholder-shown) для него
   истинно всегда, и согласие на обработку данных рисовалось капслоком
   вразрядку и со сдвигом вверх — как служебная метка поля. */
.field:not(.field--check) input:focus+label,
.field:not(.field--check) textarea:focus+label,
.field:not(.field--check) input:not(:placeholder-shown)+label,
.field:not(.field--check) textarea:not(:placeholder-shown)+label{transform:translateY(-20px);font-size:var(--fs-label);letter-spacing:.14em;text-transform:uppercase}
.field--check{display:flex;gap:12px;align-items:flex-start}
.field--check input{margin-top:4px;accent-color:var(--gold-deep);width:16px;height:16px;flex:none}
.field--check label{position:static;font-size:var(--fs-small);line-height:1.5;pointer-events:auto}
.field--check a{text-decoration:underline;text-underline-offset:3px}
.hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

/* Строка «о чём заявка»: заполняется, когда человек пришёл из комплектации
   или из калькулятора. Пустой её не показываем. */
.form__subject{
  display:none;font-size:var(--fs-small);
  border-left:2px solid var(--gold);padding:8px 0 8px 14px;color:var(--on-light-mute);
}
.form__subject[data-filled]{display:block}
.form__subject b{color:var(--on-light);font-weight:500}

.btn{
  position:relative;display:inline-flex;align-items:center;justify-content:center;
  min-height:52px;padding:0 clamp(26px,3.2vw,48px);
  border:0;border-radius:999px;overflow:hidden;
  /* «Выпуклая» кнопка без чёткой границы: свет по верхней кромке, тень
     к нижней — рельеф вместо рамки, та же логика, что у стеклянной плашки. */
  background:linear-gradient(180deg,#FFFDF8 0%,#F1EADC 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.9),
             inset 0 -2px 6px -2px rgba(88,70,42,.22),
             0 12px 26px -14px rgba(60,48,30,.5),
             0 1px 3px rgba(60,48,30,.18);
  font-size:var(--fs-small);font-weight:700;letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-light);justify-self:start;
  transition:color var(--dur-micro) var(--ease-out),
             transform var(--dur-ui) var(--ease-main),
             box-shadow var(--dur-ui) var(--ease-main);
}
.btn::before{
  content:'';position:absolute;inset:0;background:var(--gold-deep);
  transform:translateY(101%);transition:transform var(--dur-ui) var(--ease-main);
}
.btn span{position:relative;z-index:1}
.btn:hover{
  color:var(--paper);
  /* При наведении кнопка «вдавливается»: корпус чуть оседает,
     наружная тень уходит. */
  transform:translateY(1px);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.35),
             0 4px 10px -8px rgba(60,48,30,.4);
}
/* Вдавленность рисует сама золотая заливка: у неё тень внутрь по верхней
   кромке. На корпусе её рисовать нельзя — заливка легла бы поверх. */
.btn:hover::before{
  transform:translateY(0);
  box-shadow:inset 0 3px 9px -2px rgba(31,24,12,.55),
             inset 0 -1px 0 rgba(255,255,255,.14);
}

.form__status{font-size:var(--fs-small);min-height:1.4em}
.form__status[data-state=ok]{color:var(--gold-deep)}
.form__status[data-state=err]{color:#A33A24}

.link-arrow{
  display:inline-flex;align-items:center;gap:10px;
  font-size:var(--fs-small);font-weight:700;letter-spacing:.12em;text-transform:uppercase;
}
.link-arrow::after{content:'→';transition:transform var(--dur-ui) var(--ease-main)}
.link-arrow:hover::after{transform:translateX(7px)}

/* ------------------------------------------------------------ ПОДВАЛ
   Подвал — цоколь сайта, поэтому и выглядит как облицовка фундамента:
   тёплый коричневый камень под плотной вуалью. Фактура не спорит с текстом,
   но даёт странице основание. */
.footer{
  /* Верх подвала прозрачный и втягивается в тёмное на глубину кромки:
     секция сверху уходит под подвал без единой линии стыка. Ниже последней
     точки градиента цвет продолжается сам — подвал остаётся сплошным. */
  /* ПОДВАЛ БЕЗ ДЫМКИ (раунд 7). Фон сплошной. Раньше здесь стояло растворение
     сверху вниз, но под прозрачной частью лежит кремовый фон страницы,
     а не кладка: тёмное полупрозрачное поверх кремового давало серо-белую
     дымку в сто с лишним пикселей. Граница теперь — сам край плиток. */
  background:rgb(27,24,19);
  color:var(--on-dark);
  /* сверху отступаем на всю глубину кромки: заголовки колонок иначе
     попадают в вырез и обрезаются маской. */
  padding-block:calc(var(--edge-h) + clamp(30px,3vw,54px)) 26px;
  position:relative;overflow:hidden;isolation:isolate;
  /* Верхняя кромка — маска, построенная по швам планок самого фото кладки
     (build/footer-seamless-gen.py): выступ — целая плитка, ширина по
     вертикальным швам, верх по горизонтальному стыку. Маска и фон стоят
     одним масштабом от center top — ступени сидят точно на плитках. */
  --stone-w:1850px;                        /* видимая ширина кадра: больше = ближе */
  --edge-h:calc(var(--stone-w) * 0.074074);/* 130px кромки в том же масштабе */
  --frame-h:calc(var(--stone-w) * 0.364672);/* 640px кадра в том же масштабе */
  /* МАСКА ПЕРЕЕХАЛА НА КЛАДКУ (раунд 6). Раньше вырезы прорезали подвал
     насквозь и показывали кремовый фон страницы — белые прямоугольники с
     ровным низом, та самая «белая линия». Теперь подвал сплошной, а край
     плиток живёт на слое кладки: плитки выходят из темноты, а не из дырок.
     Наружной тени вверх здесь быть не должно: она обрывается ровно на
     границе подвала, а фон внутри в этой точке ещё прозрачен — на стыке
     получалась ступенька. Растворение верха подвала делает переход само. */
}
.footer::before{
  content:'';position:absolute;inset:0;z-index:-2;
  /* Кадр 2000px показывается в ширину --stone-w: камень отодвинут,
     а масштаб совпадает с маской кромки. */
  /* Кадр обрезан по крайним швам планок (footer-seamless-gen.py): стык
     повтора попадает на шов и читается как ещё один шов кладки. */
  background-image:image-set(url('../img/bg-stone-seamless-2000.avif?v=6470fd3c') type('image/avif'),
                             url('../img/bg-stone-seamless-2000.jpg?v=43a4b0d2') type('image/jpeg'));
  background-size:var(--stone-w) auto;
  background-position:center top;
  /* по вертикали не повторяем: низ кадра — произвольный срез, его стык
     был бы виден. Ниже кладки подвал уходит в собственный тёмный тон. */
  background-repeat:repeat-x;
  /* Кладка начинается от самого верха подвала: её неровный край и есть
     граница с секцией сверху. Полоса тени сверху убрана вместе с дымкой. */
  background-position:center top;
  /* Две маски разом: сверху — край по настоящим стыкам плиток (полоса
     высотой --edge-h), ниже — сплошная заливка, у которой растворяется
     нижний край. Слои складываются, поэтому сплошная начинается ровно там,
     где заканчивается полоса края. */
  /* Второй слой начинается на --edge-h ниже первого, иначе он залил бы
     полосу края и плиток не стало бы. Поэтому и точки растворения считаются
     от этого смещения: кадр кладки заканчивается на (--edge-h + --frame-h),
     значит маска обязана стать прозрачной за (--frame-h - --edge-h) от своего
     начала. Раньше эти две величины не совпадали, и низ кладки обрывался
     линией — особенно заметно на телефоне. */
  -webkit-mask-image:url('../img/footer-edge.png?v=00f49d94'),
                     linear-gradient(#000 calc(var(--frame-h) - var(--edge-h) - 150px),
                                     transparent calc(var(--frame-h) - var(--edge-h)));
  -webkit-mask-size:var(--stone-w) var(--edge-h),100% 100%;
  -webkit-mask-position:center top,left calc(var(--edge-h) - 6px);
  -webkit-mask-repeat:repeat-x,no-repeat;
  mask-image:url('../img/footer-edge.png?v=00f49d94'),
             linear-gradient(#000 calc(var(--frame-h) - var(--edge-h) - 150px),
                             transparent calc(var(--frame-h) - var(--edge-h)));
  mask-size:var(--stone-w) var(--edge-h),100% 100%;
  mask-position:center top,left calc(var(--edge-h) - 6px);
  mask-repeat:repeat-x,no-repeat;
  opacity:.95;   /* кладка читается в полную силу (раунд 7) */
}
.footer::after{
  content:'';position:absolute;inset:0;z-index:-1;
  /* Вуаль начинается ниже зоны растворения (раунд 6): она сплошная, и если
     положить её от самого верха, на стыке с кремовой секцией получается
     ступенька — ровно та «белая линия» с обратным знаком. */
  top:var(--edge-h);
  /* Раунд 7: цветных углов больше нет. Два радиальных затемнения по углам
     плюс общая вуаль 0,42 — это и были «лишние цвета»: камень под ними
     превращался в бурое пятно. Осталась одна ровная лёгкая вуаль, её
     задача только одна — держать контраст текста поверх кладки. */
  background:rgba(20,17,12,.34);
}
/* Телефон: кадр уже, иначе в экран попадают две-три плитки и кладка
   читается как абстрактные полосы. Пропорции кромки и кадра держатся
   на коэффициентах, поэтому меняем только --stone-w. */
@media (max-width:700px){.footer{--stone-w:1300px}}
/* Знак справа — фон, его не трогаем. Раунд 4: поднимается снизу вверх. */
.footer__mark{
  /* Этап 3: знак поднят — виден целиком, не тонет за нижним краем, —
     плотнее и с лёгким золотым свечением по контуру. */
  position:absolute;right:-4%;bottom:2%;
  width:min(46vw,620px);height:auto;opacity:0;pointer-events:none;
  filter:drop-shadow(0 0 30px rgba(232,198,124,.32));
  transform:translate3d(0,calc(var(--py,0px) + 90px),0);
  transition:opacity 1.4s var(--ease-main) .15s,transform 1.6s var(--ease-main) .15s;
}
.footer.is-animated .footer__mark{opacity:.16;transform:translate3d(0,var(--py,0px),0)}
.footer__inner{
  display:grid;gap:clamp(28px,3.6vw,68px);
  grid-template-columns:minmax(0,1.3fr) repeat(2,minmax(0,1fr));
  position:relative;z-index:1;
}
/* Золотой знак выезжает слева, следом по буквам поднимается SHALE —
   тот же приём, что и на первом экране. Раунд 4: знак вырос примерно
   до половины высоты надписи — заканчивается там же, где буква «A». */
.footer__sign{
  display:block;width:clamp(92px,8.4vw,148px);height:auto;margin-bottom:20px;
  filter:saturate(1.35) brightness(1.3) drop-shadow(0 0 30px rgba(201,162,78,.28));
  opacity:0;transform:translateX(-70px);
  transition:opacity 1.15s var(--ease-main),transform 1.25s var(--ease-main);
}
.footer__brand.is-animated .footer__sign{opacity:1;transform:none}

.footer__wordmark{display:block;width:clamp(150px,15vw,260px);aspect-ratio:1016/87;position:relative}
.footer__wordmark .wm{
  position:absolute;top:0;height:100%;overflow:hidden;
  left:calc(var(--x) * 100% / 1016);
  width:calc(var(--w) * 100% / 1016);
}
.footer__wordmark .wm img{
  width:100%;height:100%;object-fit:contain;filter:invert(1);
  transform:translateY(108%);
  transition:transform 1.15s var(--ease-main);
  transition-delay:calc(var(--i) * 90ms + 120ms);
}
.footer__brand.is-animated .footer__wordmark .wm img{transform:translateY(0)}

.footer__claim{
  font-family:var(--font-display);font-weight:300;
  font-size:clamp(20px,2vw,32px);line-height:1.2;max-width:12em;
  margin-top:26px;
}
.footer__guarantee{margin-top:14px;font-size:var(--fs-small);color:var(--on-dark-mute);max-width:26em}
.footer h2.label{margin-bottom:16px;color:var(--on-dark-mute)}
.footer__nav li+li{margin-top:9px}
.footer__nav a,.footer__contacts a{font-size:var(--fs-small);transition:color var(--dur-micro)}
.footer__nav a:hover,.footer__contacts a:hover{color:var(--gold-bright)}
.footer__contacts p{font-size:var(--fs-small)}
.footer__contacts p+p{margin-top:7px}
.footer__geo{color:var(--on-dark-mute);margin-top:14px!important}
.footer__legal p{font-size:var(--fs-small);color:var(--on-dark-mute)}
.footer__legal p+p{margin-top:7px}
.footer__requisites{
  flex-basis:100%;font-size:12px;color:inherit;opacity:.55;margin-bottom:6px;
}
.footer__bottom{
  display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:14px;
  margin-top:clamp(38px,4.6vw,74px);padding-top:22px;
  border-top:1px solid var(--ink-line);
  font-size:var(--fs-label);letter-spacing:.1em;color:var(--on-dark-mute);
  position:relative;z-index:1;
}
.footer__bottom ul{display:flex;flex-wrap:wrap;gap:22px}
.footer__bottom a:hover{color:var(--gold-bright)}

/* ------------------------------------------------------------ КУРСОР */
.mouse-cursor{
  position:fixed;top:0;left:0;z-index:200;
  width:10px;height:10px;margin:-5px 0 0 -5px;
  border-radius:50%;background:var(--gold-deep);
  pointer-events:none;opacity:0;
  transition:opacity .3s,width .4s var(--ease-main),height .4s var(--ease-main),margin .4s var(--ease-main),background .4s;
  display:grid;place-items:center;
}
body.mouse-has-moved .mouse-cursor{opacity:1}
.mouse-cursor__label{
  font-size:11px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  color:var(--paper);opacity:0;transition:opacity .3s;white-space:nowrap;
}
body.cursor-is-view .mouse-cursor{width:88px;height:88px;margin:-44px 0 0 -44px;background:var(--ink)}
body.cursor-is-view .mouse-cursor__label{opacity:1}
@media (hover:none),(pointer:coarse){.mouse-cursor{display:none}}

/* ------------------------------------------------------------ ПОЯВЛЕНИЕ ПРИ СКРОЛЛЕ */
.js [class*="do-anim"]{
  opacity:0;transform:translateY(26px);
  transition:opacity var(--dur-reveal) var(--ease-main),transform var(--dur-reveal) var(--ease-main);
}
.js [class*="do-anim"].is-animated{opacity:1;transform:none}

/* Изображения открываются шторкой, а не проявляются прозрачностью */
.js .do-anim-media picture,.js .do-anim-media .card__media{
  clip-path:inset(0 0 100% 0);
  transition:clip-path var(--dur-image) var(--ease-main);
}
.js .do-anim-media.is-animated picture,.js .do-anim-media.is-animated .card__media{clip-path:inset(0 0 0 0)}

/* ------------------------------------------------------------ ЗАГОЛОВКИ ПО СЛОВАМ
   Каждое слово — в своей маске. Нижний отступ с отрицательным полем нужен,
   чтобы маска не срезала выносные элементы букв: у, р, д, ц, щ. */
.js .word-lettering .word{
  display:inline-block;overflow:hidden;vertical-align:bottom;
  padding-bottom:.14em;margin-bottom:-.14em;
}
.js .word-lettering .word__i{
  display:inline-block;
  transform:translateY(108%);
  transition:transform calc(.85s + var(--wr,0) * 40ms) var(--ease-main);
  transition-delay:calc(var(--wi,0) * 42ms);
}
.js .word-lettering.is-shown .word__i{transform:translateY(0)}
.js .hero__title .word__i{transition-delay:calc(var(--wi,0) * 42ms + 420ms)}

/* ============================================================ РАУНД 4 */

/* ------------------------------------------------------------ ЛЕТЯЩИЙ ЗНАК
   Золотой треугольник едет в шапку вместе с надписью. В шапке он крупнее
   самой шапки, поэтому верхний край страницы срезает его примерно пополам —
   видна нижняя часть со «стропилами» и точкой. Ничего не перекрывает:
   элемент не ловит указатель. */
.brandsign{
  position:fixed;top:0;left:0;z-index:94;
  transform-origin:0 0;will-change:transform;
  pointer-events:none;
  filter:saturate(1.3) brightness(1.16) drop-shadow(0 0 26px rgba(201,162,78,.3));
  opacity:0; /* прозрачность ведёт скрипт: появление + посадка */
}

/* Объёмный золотой знак лежит ровно на летящем и подменяет его к концу
   перелёта. Своей подсветки ему не нужно: объём и блики нарисованы
   в самом файле, а saturate/brightness плоского знака его бы пересветили. */
.brandsign--gold{filter:drop-shadow(0 0 26px rgba(201,162,78,.3))}

/* ------------------------------------------------------------ ВИДЕО-ФОН
   Кадр из фильма о компании крутится без звука вместо статичной фотографии.
   poster держит первый кадр, пока файл качается; на узких экранах видео
   не грузится вовсе — там остаётся картинка. */
.media-bg{position:absolute;inset:0;overflow:hidden}
.media-bg video,.media-bg img{
  width:100%;height:100%;object-fit:cover;object-position:center 55%;
  display:block;
}
.media-bg video{opacity:0;transition:opacity 1.4s var(--ease-main)}
.media-bg video.is-playing{opacity:1}
.media-bg video.is-playing+.media-bg__still{opacity:0}
.media-bg__still{position:absolute;inset:0;transition:opacity 1.4s var(--ease-main)}

/* Кнопка «Смотреть фильм» — ненавязчивая, с золотым кольцом */
.play{
  display:inline-flex;align-items:center;gap:14px;
  font-size:var(--fs-small);font-weight:700;letter-spacing:.14em;text-transform:uppercase;
}
/* ЗНАЧОК РАСКРЫТИЯ ВИДЕО. Было простое кольцо с треугольником из рамок.
   Стало: тонкое кольцо, которое дочерчивается по кругу при наведении, знак
   внутри подаётся вперёд, вокруг всходит мягкое золотое свечение. Кольцо
   рисуется поворотом штриха в SVG — это единственный способ провести линию
   по дуге, обычной рамкой так нельзя. */
.play__ring{
  flex:none;position:relative;display:grid;place-items:center;
  width:64px;height:64px;border-radius:50%;
  transition:transform var(--dur-ui) var(--ease-main);
}
/* неподвижное основание кольца — чтобы дуга всегда шла по видимой окружности */
.play__ring::after{
  content:'';position:absolute;inset:0;border-radius:50%;
  border:1px solid currentColor;opacity:.34;
  transition:opacity var(--dur-ui) var(--ease-main),
             box-shadow var(--dur-ui) var(--ease-main);
}
.play__ring svg{position:absolute;inset:0;width:100%;height:100%;transform:rotate(-90deg)}
.play__ring circle{
  fill:none;stroke:currentColor;stroke-width:1;
  stroke-dasharray:201;                 /* длина окружности при r=32 */
  stroke-dashoffset:201;
  transition:stroke-dashoffset .85s var(--ease-main);
}
/* треугольник фирменного знака вместо безликой «стрелки плеера» */
.play__ring i{
  position:relative;display:block;width:0;height:0;margin-left:4px;
  border:9px solid transparent;border-left-color:currentColor;
  transition:transform var(--dur-ui) var(--ease-main);
}
.play:hover .play__ring,.play:focus-visible .play__ring{transform:scale(1.06)}
.play:hover .play__ring circle,.play:focus-visible .play__ring circle{stroke-dashoffset:0}
.play:hover .play__ring::after,.play:focus-visible .play__ring::after{
  opacity:.7;box-shadow:0 0 0 6px rgba(201,162,78,.10),0 0 26px rgba(232,198,124,.30);
}
.play:hover .play__ring i,.play:focus-visible .play__ring i{transform:translateX(3px)}

/* ---------------------------------------- КАРТОЧКИ ВИДЕО (два новых ролика)
   Ролик из Коломяг снят вертикально (1080×1920) — в широкую карточку он
   встал бы с чёрными полями по бокам, поэтому у него своя пропорция. */
.films{
  display:grid;gap:var(--gutter);margin-top:clamp(32px,4vw,64px);
  /* Ширины подобраны так, чтобы горизонтальная карточка (16:9) и
     вертикальная (3:4) вышли одной высоты: при 1.55:1 нижние края
     расходились на 230 px и под левой карточкой зияла пустота.
     Отношение 2.3:1 — решение уравнения w1*9/16 = w2*3/4. */
  grid-template-columns:minmax(0,2.3fr) minmax(0,1fr);align-items:start;
}
@media (max-width:900px){.films{grid-template-columns:1fr}}
.filmcard{
  position:relative;overflow:hidden;border-radius:16px;
  background:var(--ink);aspect-ratio:16/9;
  border:1px solid rgba(245,241,233,.10);
}
.filmcard--portrait{aspect-ratio:3/4}
.filmcard video,.filmcard img{
  position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;
}
.filmcard video{opacity:0;transition:opacity 1.2s var(--ease-main)}
.filmcard video.is-playing{opacity:1}
.filmcard::after{
  content:'';position:absolute;inset:0;pointer-events:none;
  background:linear-gradient(180deg,rgba(12,11,9,.10) 0%,rgba(12,11,9,.20) 45%,rgba(12,11,9,.82) 100%);
}
.filmcard__body{
  position:absolute;left:0;right:0;bottom:0;z-index:2;
  padding:clamp(18px,2.2vw,30px);color:var(--on-dark);
}
.filmcard__body h3{font-size:clamp(18px,1.7vw,24px);margin-bottom:6px}
.filmcard__body p{font-size:var(--fs-small);color:var(--on-dark-mute);margin-bottom:14px}
.filmcard .play{color:var(--on-dark)}

/* Полноэкранный проигрыватель со звуком */
.vmodal{
  position:fixed;inset:0;z-index:210;display:grid;place-items:center;
  background:rgba(9,8,6,.94);padding:clamp(16px,4vw,56px);
  opacity:0;visibility:hidden;
  transition:opacity var(--dur-ui) var(--ease-main),visibility var(--dur-ui);
}
.vmodal.is-open{opacity:1;visibility:visible}
/* Размер окна плеера — он же потолок качества: библиотека не берёт поток
   крупнее, чем помещается на экран. Прежние 1280 px означали, что 1080p
   не включался никогда, даже на большом мониторе (замерено).

   Важно: размер коробки задаётся раскладкой, а не самим видео. Свободные
   width/height пробовал — получается петля: поток стартует с 540p, коробка
   ужимается под него, потолок падает, и качество больше не растёт. */
.vmodal video{width:min(100%,1920px);height:auto;max-height:84vh;
  object-fit:contain;border-radius:12px;background:#000}
/* Вертикальная съёмка: ведём по высоте, иначе кадр тонет в чёрных полях. */
.vmodal--portrait video{width:auto;height:84vh;max-width:100%}
.vmodal__close{
  /* круглая кнопка закрытия: своей рамки у неё нет, но рамка фокуса была
     прямоугольной */
  border-radius:50%;
  position:absolute;top:clamp(12px,2vw,28px);right:clamp(12px,2vw,28px);
  width:48px;height:48px;color:var(--paper);
}
.vmodal__close::before,.vmodal__close::after{
  content:'';position:absolute;left:12px;right:12px;top:23px;height:1px;background:currentColor;
}
.vmodal__close::before{transform:rotate(45deg)}
.vmodal__close::after{transform:rotate(-45deg)}

/* ------------------------------------------------------------ ФАКТУРНЫЕ БЛОКИ
   Камень, бетон и дерево лежат отдельным слоем под градиентной вуалью:
   так фактура читается как поверхность, а не как фотография, и текст
   поверх неё остаётся контрастным. */
.section--tex{position:relative;isolation:isolate;background:none}
.section--tex::before{
  content:'';position:absolute;inset:0;z-index:-2;
  background-image:var(--tex);background-size:cover;background-position:center;
  opacity:var(--tex-o,.55);
}
.section--tex::after{content:'';position:absolute;inset:0;z-index:-1;background:var(--tex-veil)}

.section--stone{
  --tex:image-set(url('../img/bg-slate-2000.avif') type('image/avif'),url('../img/bg-slate-2000.jpg') type('image/jpeg'));
  --tex-o:.62;
  --tex-veil:linear-gradient(175deg,rgba(24,21,15,.90) 0%,rgba(18,16,11,.94) 55%,rgba(26,22,15,.90) 100%);
  color:var(--on-dark);
}
.section--concrete{
  --tex:image-set(url('../img/bg-concrete-2000.avif') type('image/avif'),url('../img/bg-concrete-2000.jpg') type('image/jpeg'));
  --tex-o:.30;
  --tex-veil:linear-gradient(180deg,rgba(250,246,238,.90) 0%,rgba(242,234,218,.93) 100%);
  color:var(--on-light);
}
.section--cream{
  --tex:image-set(url('../img/bg-plaster-2000.avif') type('image/avif'),url('../img/bg-plaster-2000.jpg') type('image/jpeg'));
  --tex-o:.42;
  --tex-veil:linear-gradient(180deg,rgba(251,245,232,.86) 0%,rgba(240,227,201,.90) 100%);
  color:var(--on-light);
}
.section--wood{
  --tex:image-set(url('../img/bg-wood-2000.avif') type('image/avif'),url('../img/bg-wood-2000.jpg') type('image/jpeg'));
  --tex-o:.70;
  --tex-veil:linear-gradient(180deg,rgba(22,19,13,.86) 0%,rgba(30,24,14,.90) 100%);
  color:var(--on-dark);
}
.section--tex.section--stone .label,.section--tex.section--wood .label,
.section--tex.section--stone .lead--narrow,.section--tex.section--wood .lead--narrow{color:var(--on-dark-mute)}

/* Тёмно-золотой акцент: угольная плашка и золотой текст */
.section--gold-ink{background:var(--grad-gold-ink);color:#EBDCB8}
.section--gold-ink .display,.section--gold-ink h3{color:var(--gold-bright)}
.section--gold-ink .label{color:var(--gold)}
.section--gold-ink .lead,.section--gold-ink .lead--narrow{color:#C6B58C}

/* Фирменный паттерн треугольников в углу — не на каждом блоке, а через один */
.section--sigil::before,.sigil{
  content:'';position:absolute;pointer-events:none;
  right:calc(var(--pad-x) * -.2);top:8%;
  width:min(38vw,440px);aspect-ratio:1;
  background:url('../img/pattern-triangles.png') no-repeat center/contain;
  opacity:.20;z-index:0;
}
.section--tex.section--sigil::before{opacity:.15}
.sigil--left{right:auto;left:calc(var(--pad-x) * -.3);top:auto;bottom:6%;transform:scaleX(-1)}
.section--sigil>.wrap{position:relative;z-index:1}

/* ------------------------------------------------------------ ЗНАК В ФОНЕ БЛОКА (раунд 7)
   Тот же приём, что в коммерческих предложениях: знак лежит в фоне блока
   и читается только если приглядеться. Угол чередуется через блок — иначе
   на длинной странице это выглядит штампом, а не фирменным элементом.
   Знак не ставится на первый экран, блоки с видео, галереи и подвал:
   там он спорит с содержимым или уже есть свой. */
.section--mark{position:relative;isolation:isolate}
.section--mark::after{
  content:'';position:absolute;pointer-events:none;z-index:0;
  right:-3%;bottom:-14%;
  width:min(46vw,520px);aspect-ratio:590/512;
  background:url('../img/mark-shale.png') no-repeat center/contain;
  opacity:.07;
}
/* На тёмном блоке тот же знак почти пропадает — даём ему больше плотности. */
.section--ink.section--mark::after,
.section--stone.section--mark::after,
.section--gold-ink.section--mark::after{opacity:.13}
/* Через блок знак переезжает в левый нижний угол и разворачивается. */
.section--mark--left::after{right:auto;left:-4%;transform:scaleX(-1)}
/* Содержимое всегда выше знака. */
.section--mark>.wrap{position:relative;z-index:1}
@media (max-width:700px){
  .section--mark::after{width:min(72vw,340px);bottom:-8%;opacity:.06}
  .section--ink.section--mark::after,
  .section--stone.section--mark::after,
  .section--gold-ink.section--mark::after{opacity:.11}
}


/* ------------------------------------------------------------ ЛИНИИ МЕЖДУ БЛОКАМИ
   Тонкая черта прочерчивается слева направо, крестики проявляются следом.
   Приём взят из справочника по движению: он размечает страницу и даёт
   глазу точку отдыха между разделами. */
.edge{position:relative;height:1px;margin-bottom:clamp(30px,4vw,64px);color:currentColor}
.edge__line{
  position:absolute;inset:0;height:1px;background:currentColor;opacity:.28;
  transform:scaleX(0);transform-origin:left;
  transition:transform 1.2s var(--ease-main);
}
.edge.is-animated .edge__line{transform:scaleX(1)}
.edge__x{
  position:absolute;top:0;width:13px;height:13px;margin:-6px 0 0 -6px;
  left:calc(var(--xp) * 1%);
  /* Пол-оборота с четвертью: вращение видно, а не только рост. */
  opacity:0;transform:rotate(-225deg) scale(.4);
  transition:opacity .55s ease,transform 1s var(--ease-main);
}
/* Каждая вторая линия рисуется от правого края экрана, и крестики
   проявляются в обратном порядке — движение отвечает краю, а не шаблону. */
.edge--from-right .edge__line{transform-origin:right}
.edge--from-right.is-animated .edge__x{
  transition-delay:calc(.30s + (3 - var(--xi,0)) * .13s);
}
.edge__x::before,.edge__x::after{content:'';position:absolute;background:currentColor;opacity:.55}
.edge__x::before{left:0;right:0;top:6px;height:1px}
.edge__x::after{top:0;bottom:0;left:6px;width:1px}
.edge.is-animated .edge__x{
  opacity:1;transform:rotate(0) scale(1);
  transition-delay:calc(.30s + var(--xi,0) * .13s);
}

/* Ссылка внутри абзаца: подчёркивание золотом, без синевы браузера */
.link-inline{
  color:inherit;text-decoration:underline;text-underline-offset:4px;
  text-decoration-color:var(--gold);text-decoration-thickness:1px;
  transition:color var(--dur-micro),text-decoration-color var(--dur-micro);
}
.link-inline:hover{color:var(--gold-deep);text-decoration-color:var(--gold-deep)}
.section--gold-ink .link-inline{text-decoration-color:var(--gold)}
.section--gold-ink .link-inline:hover{color:var(--gold-bright)}
.scope__link{display:inline-flex;margin-top:20px;color:var(--gold-bright)}

/* Блок фильма: текст поверх видео */
.film{overflow:hidden;isolation:isolate}
.film .media-bg{z-index:-2}
.film::after{
  content:'';position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,rgba(16,14,10,.80) 0%,rgba(16,14,10,.66) 45%,rgba(16,14,10,.86) 100%);
}
.film__inner{position:relative;z-index:1;max-width:var(--wrap)}
/* ТЕКСТ ВИДЕОБЛОКА ВСЕГДА СВЕТЛЫЙ (раунд 7).
   Под блоком всегда лежит видео, затемнённое плашкой .film::after, поэтому
   светлый текст верен независимо от того, какой модификатор секции стоит.
   Без этого правила достаточно поставить светлый модификатор — и заголовок
   пропадает: так и вышло с блоком «Квартира на Динамо». */
.film,.film h2,.film .display{color:var(--on-dark)}
.film .label,.film .lead,.film .filmlinks__label{color:var(--on-dark-mute)}
.film .play{color:var(--on-dark)}

.film .play{margin-top:clamp(24px,3vw,44px)}

/* ------------------------------------------------------------ СОЦСЕТИ И КАРТЫ */
.socials{display:flex;flex-wrap:wrap;gap:8px;margin-top:16px}
/* ЗНАЧКИ ВИДНЫ (раунд 7). Значок рисовался приглушённым цветом поверх
   фотографии кладки и почти сливался с ней. Теперь он светлый, обводка
   заметная, а под кружком своя тёмная подложка — значок стоит на ровном
   фоне, а не на случайном куске камня. */
.socials a{
  display:inline-flex;align-items:center;justify-content:center;
  min-width:44px;height:44px;padding-inline:13px;
  border:1px solid rgba(245,241,233,.42);border-radius:999px;
  background:rgba(18,15,11,.55);
  font-size:var(--fs-label);letter-spacing:.1em;text-transform:uppercase;font-weight:700;
  color:var(--on-dark);
  transition:color var(--dur-micro),border-color var(--dur-micro),
             background var(--dur-micro),transform var(--dur-micro);
}
.socials a:hover,.socials a:focus-visible{
  color:var(--ink);border-color:var(--gold-bright);background:var(--gold);
  transform:translateY(-2px);
}
.socials svg{width:20px;height:20px;display:block}
/* Знак-надпись соцсети: у MAX и 2ГИС логотип и есть надпись, поэтому здесь
   не иконка, а компактный знак в шрифте сайта — того же размера и веса, что
   и рисованные значки рядом. */
.socials__mark{
  display:block;font-size:12px;font-weight:700;letter-spacing:.06em;
  line-height:20px;height:20px;
}
.socials li[hidden]{display:none}
.footer__map{
  display:inline-flex;align-items:center;gap:8px;margin-top:12px;
  font-size:var(--fs-small);color:var(--gold);
}
.footer__map::after{content:'→';transition:transform var(--dur-micro) var(--ease-out)}
.footer__map:hover::after{transform:translateX(5px)}

/* ------------------------------------------------------------ КОМПЛЕКТАЦИИ
   Состав раскрывается по наведению — читать можно, ничего не нажимая.
   Нажатие ведёт к заявке. На тач-устройствах наведения нет, поэтому там
   работает кнопка-переключатель: она остаётся в разметке всегда. */
.tier{
  border:1px solid var(--paper-line);border-radius:14px;
  padding:clamp(22px,2.4vw,34px);
  background:linear-gradient(180deg,rgba(255,253,248,.55),rgba(255,253,248,0));
  transition:border-color var(--dur-ui) var(--ease-main),
             box-shadow var(--dur-ui) var(--ease-main),
             transform var(--dur-ui) var(--ease-main);
}
.tier:hover,.tier.is-open{
  border-color:var(--gold);
  box-shadow:0 20px 50px -34px rgba(25,23,19,.55);
  transform:translateY(-3px);
}
.tier--main{border-color:var(--gold-deep)}
@media (hover:hover) and (pointer:fine){
  .tier:hover .tier__detail{grid-template-rows:1fr}
  .tier__toggle{display:none}
}
.tier__cta{
  display:block;width:100%;margin-top:18px;padding:14px 18px;
  border:1px solid var(--ink);border-radius:999px;text-align:center;
  font-size:var(--fs-small);font-weight:700;letter-spacing:.1em;text-transform:uppercase;
  transition:background var(--dur-ui) var(--ease-main),color var(--dur-ui) var(--ease-main);
}
.tier__cta:hover{background:var(--ink);color:var(--paper)}

/* ------------------------------------------------------------ КАЛЬКУЛЯТОР 2.0 */
.calc__scene{
  position:relative;border:1px solid var(--paper-line);border-radius:14px;
  background:linear-gradient(180deg,#FCF9F2,#F3ECDD);
  overflow:hidden;
}
.calc__scene svg{display:block;width:100%;height:auto}
/* Контур ведётся «карандашом»: тот же фильтр смещения, что и в первой версии,
   но теперь поверх залитых граней. */
.sc-lines path{fill:none;stroke:#221F19;stroke-width:.9;stroke-linejoin:round;stroke-linecap:round;opacity:.62}
.sc-solid path{stroke:none}
.sc-weather .drop{stroke:rgba(216,228,240,.72);stroke-width:1.1;stroke-linecap:round;animation:calcRain .85s linear infinite;animation-delay:var(--d,0s)}
.sc-weather .flake{fill:rgba(246,250,255,.88);animation:calcSnow 4.6s linear infinite;animation-delay:var(--d,0s)}
@keyframes calcRain{
  from{transform:translate3d(0,0,0);opacity:0}
  12%{opacity:1}
  to{transform:translate3d(-46px,360px,0);opacity:0}
}
@keyframes calcSnow{
  from{transform:translate3d(0,0,0);opacity:0}
  10%{opacity:1}
  90%{opacity:.9}
  to{transform:translate3d(26px,352px,0);opacity:0}
}
.calc__hint{
  position:absolute;left:14px;bottom:12px;
  font-size:var(--fs-label);letter-spacing:.12em;text-transform:uppercase;
  color:var(--on-light-mute);opacity:.75;pointer-events:none;
}
.calc__dial{
  display:flex;align-items:center;gap:12px;margin-top:14px;
  font-size:var(--fs-small);color:var(--on-light-mute);
}
.calc__dial input{flex:1}
.calc__legend{margin-bottom:10px;display:block}
.calc__seg{display:flex;flex-wrap:wrap;gap:6px}
.calc__seg button{
  padding:10px 14px;border:1px solid var(--paper-line);border-radius:999px;
  font-size:var(--fs-small);line-height:1.2;min-height:44px;
  transition:background var(--dur-micro),border-color var(--dur-micro),color var(--dur-micro);
}
.calc__seg button:hover{border-color:var(--gold)}
.calc__seg button.is-on{background:var(--ink);border-color:var(--ink);color:var(--paper)}
.calc__dims{
  display:flex;flex-wrap:wrap;gap:6px 20px;margin-top:12px;
  font-size:var(--fs-small);color:var(--on-light-mute);
  font-variant-numeric:tabular-nums;
}
.calc__dims b{color:var(--on-light);font-weight:700}
.calc__tierline{
  margin-top:10px;font-size:var(--fs-small);color:var(--on-light-mute);
  padding-left:14px;border-left:2px solid var(--gold);
}

/* ------------------------------------------------------------ УСЛУГИ С ВЫБОРОМ
   Отмеченные услуги собираются в текст комментария к заявке. */
.picks{display:grid;gap:10px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.pick{
  display:flex;gap:12px;align-items:flex-start;
  padding:14px 16px;border:1px solid var(--paper-line);border-radius:12px;
  cursor:pointer;transition:border-color var(--dur-micro),background var(--dur-micro);
}
.pick:hover{border-color:var(--gold)}
.pick input{margin-top:3px;width:20px;height:20px;accent-color:var(--gold-deep);flex:none}
.pick.is-on{border-color:var(--gold);background:rgba(201,162,78,.09)}
.pick b{display:block;font-weight:700;font-size:var(--fs-small)}
.pick span{display:block;font-size:var(--fs-small);color:var(--on-light-mute)}

/* ------------------------------------------------------------ РАСКРЫВАЮЩИЕСЯ ПРИНЦИПЫ */
.rule-item{border-top:1px solid var(--paper-line);padding-block:clamp(18px,2vw,28px)}
.rule-item:last-child{border-bottom:1px solid var(--paper-line)}
.rule-item__head{
  display:flex;align-items:baseline;gap:clamp(14px,2vw,32px);width:100%;text-align:left;
}
.rule-item__num{
  font-family:var(--font-display);font-weight:200;font-size:clamp(20px,2vw,30px);
  color:var(--gold-deep);flex:none;font-variant-numeric:tabular-nums;
}
.rule-item__title{font-family:var(--font-display);font-weight:300;font-size:var(--fs-h3);line-height:1.2;flex:1}
.rule-item__sign{
  flex:none;width:22px;height:22px;position:relative;align-self:center;opacity:.5;
  transition:opacity var(--dur-micro),transform var(--dur-ui) var(--ease-main);
}
.rule-item__sign::before,.rule-item__sign::after{
  content:'';position:absolute;background:currentColor;
}
.rule-item__sign::before{left:0;right:0;top:10px;height:1px}
.rule-item__sign::after{top:0;bottom:0;left:10px;width:1px;transition:transform var(--dur-ui) var(--ease-main)}
.rule-item.is-open .rule-item__sign{opacity:1;transform:rotate(90deg)}
.rule-item.is-open .rule-item__sign::after{transform:scaleY(0)}
.rule-item__body{display:grid;grid-template-rows:0fr;transition:grid-template-rows .6s var(--ease-main)}
.rule-item.is-open .rule-item__body{grid-template-rows:1fr}
.rule-item__body>div{overflow:hidden}
.rule-item__body p{max-width:52em;margin-top:16px}
.rule-item__body .btn{margin-top:20px}

/* ------------------------------------------------------------ БЛОК О ЛОГОТИПЕ
   Каменный фон, золотой знак, золотая надпись. */
.sigil-block{position:relative;isolation:isolate;overflow:hidden;padding-block:clamp(74px,9vw,150px)}
.sigil-block::before{
  content:'';position:absolute;inset:0;z-index:-2;
  background:image-set(url('../img/bg-stone-grey-2000.avif') type('image/avif'),
                       url('../img/bg-stone-grey-2000.jpg') type('image/jpeg'))
             center/cover;
  filter:grayscale(.55);
}
.sigil-block::after{
  content:'';position:absolute;inset:0;z-index:-1;
  background:linear-gradient(165deg,rgba(22,20,15,.88) 0%,rgba(16,14,10,.93) 60%,rgba(28,23,15,.88) 100%);
}
.sigil-block__mark{
  display:block;width:clamp(130px,17vw,260px);height:auto;margin:0 auto clamp(22px,2.6vw,40px);
  filter:saturate(1.4) brightness(1.35) drop-shadow(0 0 42px rgba(201,162,78,.36));
}
.sigil-block__name{
  display:block;width:clamp(200px,26vw,420px);aspect-ratio:1016/87;
  margin:0 auto clamp(28px,3.4vw,54px);position:relative;
}
.sigil-block__name .wm{
  position:absolute;top:0;height:100%;overflow:hidden;
  left:calc(var(--x) * 100% / 1016);width:calc(var(--w) * 100% / 1016);
}
/* Буквы нарисованы чернильными: инверсия делает их светлыми, а золотой
   оттенок задаёт sepia+поворот тона поверх. */
.sigil-block__name .wm img{
  width:100%;height:100%;object-fit:contain;
  filter:invert(1) sepia(1) saturate(3.2) hue-rotate(-14deg) brightness(1.05);
  transform:translateY(110%);
  transition:transform 1.2s var(--ease-main);
  transition-delay:calc(var(--i) * 95ms + 200ms);
}
.sigil-block.is-animated .sigil-block__name .wm img{transform:translateY(0)}
.sigil-block__text{max-width:44em;margin-inline:auto;text-align:center;color:#CFC0A0}
.sigil-block__text p+p{margin-top:1.2em}
.sigil-block__text b{color:var(--gold-bright);font-weight:400}

/* Список раскрывающихся строк: услуги и принципы */
.rules{margin-top:clamp(20px,2.6vw,38px)}
.section--tex .rule-item,.section--tex .rule-item:last-child{border-color:rgba(25,23,19,.14)}
.section--stone .rule-item,.section--wood .rule-item{border-color:rgba(245,241,233,.16)}

/* ------------------------------------------------------------ АДАПТИВ */
@media (max-width:1240px){
  .header__nav,.header__phone{display:none}
  .header__burger{display:block;margin-left:auto}
  .header__logo-slot,.header__logo-img{width:clamp(134px,30vw,190px)}
  .header__sign-slot{width:clamp(26px,5.4vw,38px)}
  .header__sign-img{width:calc(clamp(26px,5.4vw,38px) * 2.1);left:calc(clamp(26px,5.4vw,38px) * -0.55)}
  .header__logo-img{margin-left:calc(clamp(26px,5.4vw,38px) + 10px)}
  .positioning__grid,.tech__layout,.scope__grid,.contact__wrap,.calc__layout{grid-template-columns:minmax(0,1fr)}
  .projects__grid{grid-template-columns:repeat(2,minmax(0,1fr))}
  .footer__inner{grid-template-columns:repeat(2,minmax(0,1fr))}
  .hero__mark{width:min(50vw,320px)}
}
@media (max-width:900px){
  .inside__grid,.pricing__grid{grid-template-columns:minmax(0,1fr)}
  .positioning__facts{grid-template-columns:repeat(2,minmax(0,1fr))}
}
@media (max-width:640px){
  .projects__grid{grid-template-columns:minmax(0,1fr)}
  .footer__inner{grid-template-columns:minmax(0,1fr)}
  .positioning__facts{grid-template-columns:minmax(0,1fr)}
  .hero__brand-slot{width:94vw}
  /* Одна колонка: три подписи капслоком с разрядкой .2em в 375 px не встают
     ни в три колонки, ни в две — они и раздували первый экран. */
  .hero__meta{gap:6px 16px;grid-template-columns:minmax(0,1fr)}
  .hero__scroll{display:none}
  .footer__bottom{flex-direction:column;align-items:flex-start}
  .picks{grid-template-columns:minmax(0,1fr)}
  .sigil--left,.section--sigil::before{width:min(70vw,300px);opacity:.15}
}

/* Зоны нажатия: палец требует минимум 44 px. Правило действует только там,
   где нет точного указателя, чтобы не раздувать десктопную вёрстку. */
@media (hover:none),(pointer:coarse){
  .footer__bottom li{display:flex}
  .mobile-menu__list a{min-height:52px;display:flex;align-items:center}
  .mobile-menu__foot a,.footer__nav a,.footer__contacts a,
  .footer__bottom a,.link-arrow{min-height:44px;display:inline-flex;align-items:center}
  .footer__nav li+li{margin-top:2px}
  .footer__contacts p+p{margin-top:0}
  .field--check label{padding-block:6px}
  .field--check input{width:22px;height:22px;margin-top:1px}
  .tech__list button{padding-block:16px}
}

@media print{
  .header,.mobile-menu,.hero__scroll,.mouse-cursor,.form,.marquee,.brandmark{display:none}
  body{background:#fff;color:#000}
}

/* ------------------------------------------------------------ РАУНД 5: до/после
   Ползунок сравнения: снизу «после», сверху обрезаемое «до». */
.ba{position:relative;overflow:hidden;border-radius:14px;aspect-ratio:900/506}
.ba picture,.ba img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
.ba__before{z-index:2;clip-path:inset(0 calc(100% - var(--ba,50%)) 0 0)}
.ba__handle{
  position:absolute;top:0;bottom:0;left:var(--ba,50%);width:2px;z-index:3;
  background:#F5F1E8;box-shadow:0 0 14px rgba(11,11,13,.4);transform:translateX(-1px);
}
.ba__handle::after{
  content:'◂ ▸';position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  background:#F5F1E8;color:#0B0B0D;font-size:11px;letter-spacing:2px;
  padding:7px 10px;border-radius:999px;white-space:nowrap;
  box-shadow:0 6px 22px rgba(11,11,13,.3);
}
.ba__tag{
  position:absolute;top:12px;z-index:3;padding:4px 12px;border-radius:999px;
  font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  background:rgba(11,11,13,.6);color:#F5F1E8;backdrop-filter:blur(4px);
}
.ba__tag--l{left:12px}
.ba__tag--r{right:12px}
.ba__range{
  position:absolute;inset:0;z-index:4;width:100%;height:100%;
  opacity:0;cursor:ew-resize;margin:0;-webkit-appearance:none;touch-action:none;
}
/* Переход на объект: появляется при наведении на кадр технологии */
.tech__go{
  display:inline-block;margin-left:10px;color:var(--gold);text-decoration:none;
  opacity:0;transform:translateX(-6px);
  transition:opacity .35s var(--ease-main),transform .35s var(--ease-main);
}
.tech__stage figure:hover .tech__go,.tech__go:focus-visible{opacity:1;transform:none}
@media (hover:none){.tech__go{opacity:1;transform:none}}

/* ------------------------------------------------------------ ОБЛАЧКО МЫСЛЕЙ
   Раунд 5, этап 2. Слой живёт в body поверх всего — его не режет overflow
   секций, поэтому облако может раскрываться справа от курсора. Появление:
   две «мысленные» точки всплывают по очереди, следом разворачивается облако. */
.thought{
  position:fixed;left:0;top:0;z-index:80;pointer-events:none;opacity:0;
  transition:opacity .2s ease,transform .18s cubic-bezier(.22,.61,.36,1);
}
.thought.is-on{opacity:1}
.thought__dot{
  position:absolute;border-radius:50%;
  background:rgba(255,255,255,.55);
  -webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px);
  border:1px solid rgba(255,255,255,.6);
  box-shadow:0 4px 14px rgba(11,11,13,.12);
  transform:scale(0);transition:transform .3s var(--ease-main);
}
.thought__dot--1{width:9px;height:9px;left:16px;top:-7px}
.thought__dot--2{width:15px;height:15px;left:32px;top:-18px}
.thought.is-on .thought__dot{transform:scale(1)}
.thought.is-on .thought__dot--2{transition-delay:.07s}
.thought__cloud{
  position:absolute;left:56px;top:-10px;transform:translateY(-50%) scale(.82);
  transform-origin:left center;
  min-width:236px;margin:0;padding:18px 24px;list-style:none;
  background:rgba(255,255,255,.42);
  -webkit-backdrop-filter:blur(16px) saturate(1.15);backdrop-filter:blur(16px) saturate(1.15);
  border:1px solid rgba(255,255,255,.55);
  border-radius:30px 34px 32px 30px / 32px 30px 34px 30px;
  box-shadow:0 18px 60px rgba(11,11,13,.14);
  opacity:0;transition:opacity .3s var(--ease-main),transform .3s var(--ease-main);
}
.thought.is-on .thought__cloud{opacity:1;transform:translateY(-50%) scale(1);transition-delay:.14s}
.thought__cloud li{font-size:14px;line-height:2;color:var(--on-light);white-space:nowrap}
/* У правого края экрана облако зеркалится и уходит влево от курсора. */
.thought--flip .thought__dot--1{left:-25px}
.thought--flip .thought__dot--2{left:-47px}
.thought--flip .thought__cloud{left:auto;right:56px;transform-origin:right center}

/* Компактный разделитель внутри блока «Кто мы»: та же линия с крестиками. */
.edge--mini{margin-bottom:clamp(16px,2vw,26px)}

/* ------------------------------------------------------------ 3D-КАЛЬКУЛЯТОР
   Раунд 5: объёмный эскиз на WebGL. Канвас встаёт на место SVG; рядом с
   каждым ползунком — точное числовое поле (ввод руками), оно же показывает
   текущее значение вместо прежней подписи. */
.calc__gl{display:block;width:100%;height:auto;border-radius:inherit}
.calc__num{
  position:absolute;right:0;top:-4px;width:84px;padding:5px 10px;
  border:1px solid var(--paper-line);border-radius:999px;
  background:rgba(255,253,249,.7);font-size:var(--fs-small);text-align:center;
  transition:border-color var(--dur-micro);
}
.calc__num:focus{outline:none;border-color:var(--gold-deep)}
.calc__row{position:relative}
.calc__row:has(.calc__num) output{display:none}

/* ------------------------------------------------ КАЛЬКУЛЯТОР: ВИД (26.08)
   Запрос владельца — «улучши визуальную часть». Ползунки, поля, сцена и итог
   приведены к одному языку: золото на действии, бумага в покое. Заполнение
   трека считает JS (переменная --p), поэтому видно, где стоит значение. */
.calc__row{position:relative}
.calc__row input[type=range]{
  -webkit-appearance:none;appearance:none;--p:50%;
  width:100%;height:36px;background:transparent;cursor:pointer;
}
.calc__row input[type=range]::-webkit-slider-runnable-track{
  height:6px;border-radius:999px;
  background:linear-gradient(90deg,var(--gold-deep) 0 var(--p),rgba(34,31,25,.12) var(--p) 100%);
}
.calc__row input[type=range]::-webkit-slider-thumb{
  -webkit-appearance:none;appearance:none;
  width:22px;height:22px;margin-top:-8px;border-radius:50%;
  background:var(--paper);border:2px solid var(--gold-deep);
  box-shadow:0 2px 9px rgba(34,31,25,.22);
  transition:transform var(--dur-micro),box-shadow var(--dur-micro);
}
.calc__row input[type=range]:hover::-webkit-slider-thumb{transform:scale(1.08)}
.calc__row input[type=range]:active::-webkit-slider-thumb{
  transform:scale(1.16);box-shadow:0 3px 15px rgba(34,31,25,.32);
}
.calc__row input[type=range]::-moz-range-track{height:6px;border-radius:999px;background:rgba(34,31,25,.12)}
.calc__row input[type=range]::-moz-range-progress{height:6px;border-radius:999px;background:var(--gold-deep)}
.calc__row input[type=range]::-moz-range-thumb{
  width:20px;height:20px;border-radius:50%;border:2px solid var(--gold-deep);
  background:var(--paper);box-shadow:0 2px 9px rgba(34,31,25,.22);
}
.calc__row input[type=range]:focus-visible{outline:2px solid var(--gold);outline-offset:6px;border-radius:999px}

.calc__num{
  position:absolute;right:0;top:-6px;width:92px;padding:7px 12px;
  border:1px solid var(--paper-line);border-radius:10px;
  background:rgba(255,253,249,.9);color:var(--on-light);
  font-family:var(--font-display);font-size:clamp(15px,1.25vw,19px);font-weight:300;
  font-variant-numeric:tabular-nums;text-align:center;
  transition:border-color var(--dur-micro),box-shadow var(--dur-micro);
}
.calc__num:hover{border-color:var(--gold)}
.calc__num:focus{outline:none;border-color:var(--gold-deep);box-shadow:0 0 0 3px rgba(176,141,74,.16)}

/* сцена — карточка, а не врезка в странице */
.calc__scene{
  border-radius:16px;border:1px solid rgba(34,31,25,.10);
  background:linear-gradient(180deg,#E9EFF6,#F6F1E6);
  box-shadow:0 22px 46px -30px rgba(34,31,25,.62);
}
.calc__gl{border-radius:inherit}
.calc__hint{
  left:12px;bottom:11px;padding:7px 13px;border-radius:999px;opacity:1;
  background:rgba(255,253,249,.74);border:1px solid rgba(34,31,25,.08);
  -webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px);
  color:var(--on-light-mute);
}

/* переключатели: один вид на всех блоках калькулятора */
.calc__seg button.is-on{
  background:var(--gold-deep);border-color:var(--gold-deep);color:var(--paper);
  box-shadow:0 10px 20px -14px rgba(120,92,38,.9);
}

/* итог отделён от параметров: цена читается первой */
.calc__out{
  margin-top:4px;padding:clamp(16px,2vw,24px);
  border:1px solid var(--paper-line);border-radius:16px;
  background:linear-gradient(180deg,rgba(255,253,249,.94),rgba(246,240,228,.8));
}
.calc__out .calc__sum{border-top:2px solid var(--gold);padding-top:14px;margin-top:2px}
.calc__dims{gap:6px 22px}
.calc__dims b{color:var(--on-light)}

/* -------------------------------------- КАЛЬКУЛЯТОР ВРЕМЕННО СКРЫТ (26.08)
   Владелец снял блок до переделки сцены в фотореалистичном виде. Разметка
   и скрипты на месте — возвращается удалением этого правила и раскомментированием
   тега calc3d.js в build/pages.py и shale-site/index.html. */
.calc{display:none}

/* --------------------------------------- ПЕРВЫЙ ЭКРАН НА ТЕЛЕФОНЕ (26.08)
   Для телефона подключён отдельный вертикальный кадр. Точку кадрирования
   поднимаем к дому: центр вертикали у портретного снимка приходится
   на настил террасы. Запас под параллакс на телефоне не нужен — он там
   придавлен, а лишние 6% только съедают полезную часть кадра. */
@media (max-width:700px){
  .hero__media{inset:-2%}
  .hero__media img{object-position:center 38%}
}

/* ------------------------------------------- ССЫЛКИ НА ДРУГИЕ ВИДЕО (раунд 7)
   Под каждым видеоблоком — два других ролика. Раньше все видео жили в одном
   разделе, и если человек до него не долистал, он не видел ни одного. Теперь
   из любого блока можно открыть остальные. */
.filmlinks{
  display:flex;flex-wrap:wrap;align-items:center;gap:10px 18px;
  margin-top:clamp(22px,2.6vw,36px);
}
.filmlinks__label{
  font-size:var(--fs-label);letter-spacing:.14em;text-transform:uppercase;
  color:var(--on-dark-mute);margin-right:4px;
}
.filmlink{
  display:inline-flex;align-items:center;gap:9px;
  padding:9px 16px;border-radius:999px;
  border:1px solid rgba(245,241,233,.30);background:rgba(16,14,10,.42);
  color:var(--on-dark);font-size:var(--fs-small);text-align:left;
  transition:border-color var(--dur-micro),background var(--dur-micro),
             color var(--dur-micro),transform var(--dur-micro);
}
.filmlink:hover,.filmlink:focus-visible{
  border-color:var(--gold);background:rgba(201,162,78,.16);transform:translateY(-2px);
}
.filmlink__dot{
  width:9px;height:9px;border-radius:50%;flex:none;
  border:1px solid var(--gold);position:relative;
}
.filmlink__dot::after{
  content:'';position:absolute;left:2.6px;top:1.7px;
  border-left:3.4px solid var(--gold);
  border-top:2.3px solid transparent;border-bottom:2.3px solid transparent;
}
.filmlink__dur{color:var(--on-dark-mute);margin-left:2px}
@media (max-width:560px){
  .filmlinks{flex-direction:column;align-items:flex-start;gap:9px}
  .filmlink{width:100%}
}

/* ---------------------------------------------------------------- ЗНАЧКИ МАТЕРИАЛОВ (раунд 8)
   Значок материала стоит рядом с названием технологии: материал и технология
   на этом сайте связаны жёстко, один материал — одна технология.

   Отклик на наведение сделан заметным намеренно. Прежний вариант поднимал
   значок на 2 px и увеличивал на 5% — на картинке высотой 50 px этого
   не видно вообще, и выглядело так, будто наведение не работает. */
.tech__list button{position:relative}
.tech__mat{
  position:absolute;right:clamp(8px,1.2vw,16px);top:50%;
  width:clamp(30px,3vw,44px);height:auto;
  transform:translateY(-50%);
  opacity:.55;
  filter:drop-shadow(0 2px 6px rgba(11,11,13,.22));
  transition:opacity var(--dur-ui) var(--ease-main),
             transform var(--dur-ui) var(--ease-main),
             filter var(--dur-ui) var(--ease-main);
  pointer-events:none;
}
.tech__mat img{width:100%;height:auto;display:block}
.tech__list button:hover .tech__mat,
.tech__list button:focus-visible .tech__mat,
.tech__list button.is-active .tech__mat{
  opacity:1;
  transform:translateY(-50%) scale(1.16);
  filter:drop-shadow(0 6px 14px rgba(11,11,13,.34));
}
/* Тот же принцип для плиток технологий на странице «Дома». */
.tile:hover .tile__mat,.tile:focus-within .tile__mat{
  transform:translateY(-4px) scale(1.16);
  filter:drop-shadow(0 8px 18px rgba(11,11,13,.30));
}
@media (max-width:640px){
  /* На телефоне наведения нет — значок просто виден в полную силу. */
  .tech__mat{opacity:.9;width:30px}
}

/* Ссылка на объект под инженерным кадром. Инженерия без адреса — картинка
   из интернета; со ссылкой это доказательство, которое можно проверить. */
.figlink{
  display:inline-block;margin-top:5px;
  font-size:var(--fs-label);letter-spacing:.08em;text-transform:uppercase;
  color:var(--gold);text-decoration:none;
  border-bottom:1px solid color-mix(in srgb,var(--gold) 45%, transparent);
  transition:color var(--dur-ui) var(--ease-main),border-color var(--dur-ui) var(--ease-main);
}
.figlink::after{content:' →';letter-spacing:0}
.figlink:hover,.figlink:focus-visible{
  color:var(--on-dark);border-bottom-color:var(--on-dark);
}

/* ---------------------------------------------------------------- ВОПРОСЫ
   Список на <details>: раскрывается без скриптов и остаётся доступным
   с клавиатуры. Первый вопрос открыт — иначе блок выглядит как глухая
   стена заголовков, и его пролистывают не читая. */
.faq{margin-top:clamp(24px,3vw,44px);border-top:1px solid var(--rule)}
.faq__item{border-bottom:1px solid var(--rule)}
.faq__item summary{
  display:flex;align-items:flex-start;gap:16px;
  padding:clamp(16px,2vw,24px) 0;
  cursor:pointer;list-style:none;
  font-family:var(--font-display);font-weight:300;
  font-size:clamp(17px,1.5vw,23px);line-height:1.3;
  transition:color var(--dur-ui) var(--ease-main);
}
.faq__item summary::-webkit-details-marker{display:none}
.faq__item summary::after{
  content:'';flex:0 0 auto;margin-left:auto;
  width:13px;height:13px;margin-top:.42em;
  border-right:1px solid currentColor;border-bottom:1px solid currentColor;
  transform:rotate(45deg);
  transition:transform var(--dur-ui) var(--ease-main);
}
.faq__item[open] summary::after{transform:rotate(225deg)}
.faq__item summary:hover{color:var(--gold-deep)}
.faq__answer{padding:0 0 clamp(18px,2.2vw,26px);max-width:64ch}
.faq__answer p{color:var(--on-light-mute);font-size:var(--fs-small);line-height:1.62}
/* На тёмных полосах цвет ответа берётся от полосы, а не от светлой темы. */
.section--concrete .faq__answer p,.section--stone .faq__answer p,
.section--gold-ink .faq__answer p{color:var(--on-dark-mute)}
.section--concrete .faq,.section--stone .faq,.section--gold-ink .faq{
  border-color:color-mix(in srgb,var(--on-dark) 22%, transparent)}
.section--concrete .faq__item,.section--stone .faq__item,.section--gold-ink .faq__item{
  border-color:color-mix(in srgb,var(--on-dark) 22%, transparent)}

/* ---------------------------------------------------------------- ЗОНЫ НАЖАТИЯ ТЕКСТОВЫХ ССЫЛОК (раунд 8)
   Палец требует 44 px, но у текстовых ссылок высота равна высоте строки —
   20–22 px. Увеличивать сам текст нельзя: разъедется вёрстка и собьётся
   ритм абзацев. Поэтому область нажатия расширяется невидимым слоем поверх
   ссылки: внешне ничего не меняется, попадание становится честным.

   inset подобран так, чтобы соседние строки не перекрывали друг друга:
   по вертикали ссылка дотягивается до 44 px, по горизонтали добавляется
   небольшой запас по краям. */
@media (hover:none),(pointer:coarse){
  .link-arrow,.tech__go,.figlink,.header__phone,.footer a:not(.footer__logo){
    position:relative;
  }
  /* Слой вешается на ::before, а НЕ на ::after. У .link-arrow в ::after
     лежит сама стрелка «→», у .header__phone — линия подчёркивания,
     у .figlink — стрелка. Перехват ::after стёр бы их все. */
  .link-arrow::before,.tech__go::before,.figlink::before,
  .header__phone::before,.footer a:not(.footer__logo)::before{
    content:'';position:absolute;left:-8px;right:-8px;
    top:50%;height:44px;transform:translateY(-50%);
    pointer-events:auto;
  }
}

/* ==== НАЧАЛО: правка первого экрана 28.08 (build/hero-glass.py) ==== */
/* 1. Текст первого экрана выше над нижним краем. */
.hero__inner{padding-bottom:clamp(44px,7.5vh,112px)}

/* 2. Знак справа крупнее и ниже. Это посадочная разметка: размер и место
      летящего знака .brandsign скрипт берёт из её прямоугольника.
      Ширина задана по двум диапазонам, потому что в main.css уже есть
      правило для max-width:1240px, а этот блок стоит в файле позже и при
      равной специфичности перебил бы его на всех ширинах. */
.hero__mark{right:4.5%;top:19%}
@media (min-width:1241px){.hero__mark{width:min(37vw,452px)}}
@media (max-width:1240px){.hero__mark{width:min(56vw,376px)}}

/* 3. Стекло с переливами. Собственного фона у плашки почти нет — цвет ей
      дают преломление кадра под ней и радужные отсветы. Слои лежат под
      текстом (z-index:-1) внутри собственного контекста наложения, поэтому
      наружу не протекают. */
.hero__meta{
  position:relative;isolation:isolate;overflow:hidden;
  background:linear-gradient(180deg,rgba(255,255,255,.038),rgba(255,255,255,.008) 55%,rgba(255,255,255,.022));
}
.hero__meta::before{
  content:'';position:absolute;z-index:-1;inset:-70% -28%;
  /* Спектр идёт ПОПЕРЁК плашки и укладывается в её ширину целиком, поэтому
     видны сразу несколько цветов. Кольцо (conic) пробовал — в узкой плашке
     виден лишь один его сектор, выходил ровный тёплый оттенок. Растянутая
     на 400 % полоса тоже не годилась: в кадр попадала четверть радуги. */
  background:linear-gradient(100deg,
    transparent 2%,
    rgba(255,120,150,.34) 13%,
    rgba(255,205,110,.30) 23%,
    rgba(190,255,170,.26) 33%,
    rgba(120,215,255,.34) 43%,
    rgba(180,150,255,.32) 54%,
    rgba(255,130,170,.30) 65%,
    rgba(255,215,130,.24) 74%,
    transparent 86%);
  filter:blur(16px) saturate(1.6);
  animation:hero-meta-iris 17s ease-in-out infinite;
}
@keyframes hero-meta-iris{
  0%,100%{transform:translateX(-15%)}
  50%{transform:translateX(15%)}
}
/* Когда первый экран ушёл вверх, крутить размытый слой незачем. */
body.past-hero .hero__meta::before{animation-play-state:paused}
@media (prefers-reduced-motion:reduce){
  .hero__meta::before{animation:none}
}
/* ==== КОНЕЦ: правка первого экрана 28.08 ==== */

/* ==== НАЧАЛО: знак в фоне блока и сирота в сетке 28.08 (build/section-mark.py) ==== */
/* Знак во весь блок и без прозрачности. Размер задаётся по высоте блока,
   поэтому знак растёт вместе с ним, а не остаётся пятном в углу. */
.section--mark::after{
  inset:0;right:0;bottom:0;width:auto;height:auto;aspect-ratio:auto;
  /* Высота ровно 100 %: при 118 % знак вылезал за границы блока и залезал
     на соседний — у .section--mark нет overflow:hidden. */
  background:url('../img/mark-shale.png') no-repeat calc(100% + 6%) center/auto 100%;
  opacity:.28;
}
.section--ink.section--mark::after,
.section--stone.section--mark::after,
.section--gold-ink.section--mark::after{opacity:.34}
/* Через блок знак переезжает к левому краю и разворачивается. */
.section--mark--left::after{
  background-position:calc(0% - 5%) center;
  transform:none;
}
@media (max-width:700px){
  /* На телефоне колонка текста узкая, знак во всю высоту накрыл бы её
     целиком — оставляем его пониже и помельче, но по-прежнему плотным. */
  .section--mark::after{background-size:auto 74%;background-position:calc(100% + 14%) 82%;opacity:.24}
  .section--mark--left::after{background-position:calc(0% - 14%) 82%}
  .section--ink.section--mark::after,
  .section--stone.section--mark::after,
  .section--gold-ink.section--mark::after{opacity:.30}
}

/* Сирота в сетке плиток: последняя плитка на позиции 3n+1 стоит одна
   в ряду — ставим её в среднюю колонку. Только там, где колонок три. */
@media (min-width:1241px){
  .tiles>:last-child:nth-child(3n+1){grid-column:2}
}
/* ==== КОНЕЦ: знак в фоне блока и сирота в сетке 28.08 ==== */

/* ==== НАЧАЛО: блок заявки под штукатурку 28.08 (build/plaster-block.py) ==== */
.contact{
  position:relative;isolation:isolate;overflow:hidden;
  /* Тон подложки равен среднему тону фактуры: пока картинка не загрузилась,
     блок не мигает белым. */
  background:#F2ECE0;
  /* Отступ сверху — штатный отступ секции плюс глубина кромки: иначе
     подпись «Начать» попадает в вырез следа кельмы. Число здесь писать
     нельзя: у секций сайта отступ задан переменной --sec-y, и любой
     подобранный на глаз clamp разъедется с соседними блоками. */
  padding-top:calc(var(--sec-y) + 24px);
}
.contact::before{
  content:'';position:absolute;inset:0;z-index:-2;pointer-events:none;
  /* Первый слой — короткая тень под кромкой: без неё след кельмы теряется
     на кремовом фоне соседней секции. Второй — сама фактура. */
  background-image:linear-gradient(rgba(74,62,44,.11),rgba(74,62,44,0) 20px),
                   image-set(url("../img/plaster-cream-1600.avif") type("image/avif"),
                             url("../img/plaster-cream-1600.webp") type("image/webp"),
                             url("../img/plaster-cream-1600.jpg") type("image/jpeg"));
  background-size:100% 100%,clamp(420px,42vw,760px) auto;
  background-repeat:no-repeat,repeat;
  /* Верхний край — след кельмы. Маска повторяется по горизонтали, ниже
     полосы края идёт сплошная заливка. */
  -webkit-mask-image:url("../img/plaster-edge.png"),linear-gradient(#000,#000);
  -webkit-mask-size:1600px 30px,100% 100%;
  -webkit-mask-position:left top,left 30px;
  -webkit-mask-repeat:repeat-x,no-repeat;
  mask-image:url("../img/plaster-edge.png"),linear-gradient(#000,#000);
  mask-size:1600px 30px,100% 100%;
  mask-position:left top,left 30px;
  mask-repeat:repeat-x,no-repeat;
}
.contact__glit{
  position:absolute;inset:0;z-index:-1;pointer-events:none;
  /* Два слоя: сверху сама слюда, под ней тёплая световая лужа. Лужа и есть
     «как будто на него светят»: рядом с ней светлые ядра блёсток начинают
     читаться, а не тонуть в кремовом. */
  background-image:url("../img/plaster-sparkle.png"),
                   radial-gradient(circle at var(--gx) var(--gy),
                     rgba(255,246,222,.34),rgba(255,246,222,0) 58%);
  background-size:clamp(300px,26vw,460px) auto,100% 100%;
  background-repeat:repeat,no-repeat;
  /* Обычное наложение, не screen: блёстка читается перепадом «светлое ядро —
     тёмный ободок», а не яркостью. На почти белой штукатурке screen давал
     прибавку в двенадцать уровней, то есть ничего. */
  opacity:.95;
  /* Видна только окрестность точки света. Мышь ведёт её напрямую,
     прокрутка — сверху вниз по блоку. */
  --gx:50%;--gy:32%;
  -webkit-mask-image:radial-gradient(circle at var(--gx) var(--gy),
    rgba(0,0,0,1) 0,rgba(0,0,0,.9) 14%,rgba(0,0,0,.35) 42%,transparent 70%);
  mask-image:radial-gradient(circle at var(--gx) var(--gy),
    rgba(0,0,0,1) 0,rgba(0,0,0,.9) 14%,rgba(0,0,0,.35) 42%,transparent 70%);
}
@media (prefers-reduced-motion:reduce){
  .contact__glit{opacity:.55}
}
/* ==== КОНЕЦ: блок заявки под штукатурку 28.08 ==== */

/* ==== НАЧАЛО: правки по обходу на пяти экранах 28.08 (build/qa-fixes-2808.py) ==== */
/* 1. Фото первого экрана закрывает блок на любом экране.
      Проценту высоты нужен родитель с известной высотой; <picture> в сбросе
      идёт с height:auto, поэтому высоту задаём ему явно. */
.hero__media picture,
.page-hero__media picture{display:block;width:100%;height:100%}

/* 2. Пока меню открыто, шапка лежит НАД ним — иначе крестика не видно
      и не нажать: подложка меню (z-index 85) закрывала шапку (80). */
body.menu-is-open .header{z-index:90}

/* 4. Последняя карточка, оставшаяся одна в ряду из трёх, встаёт по центру. */
@media (min-width:1241px){
  .projects__grid>:last-child:nth-child(3n+1){grid-column:2}
}

/* 5. Кнопка меню читается и на светлой части фотографии. */
.header__burger span{filter:drop-shadow(0 1px 2px rgba(8,7,5,.55))}
body.menu-is-open .header__burger span{filter:none}

/* 6. На узком экране отсветы приглушены: размытие задано в пикселях и на
      плашке в 320 px разливает спектр в сплошной цвет. */
@media (max-width:700px){
  .hero__meta::before{opacity:.45;filter:blur(22px) saturate(1.25)}
}
/* ==== КОНЕЦ: правки по обходу на пяти экранах 28.08 ==== */

/* ==== НАЧАЛО: зоны нажатия по обходу 28.08 (build/tap-round8.py) ==== */
@media (hover:none),(pointer:coarse){
  /* Галочки согласия и рассылки. Слой ставим от подписи, а не от самого
     поля: у input нет ::before — это заменяемый элемент, псевдоэлементы
     к нему не применяются. Подпись привязана через for, значит нажатие
     в слой переключит именно её галочку. */
  .field--check{position:relative}
  .field--check label::before{
    content:'';position:absolute;left:-11px;top:-10px;width:44px;height:44px;
  }
  /* Вордмарк в шапке: ссылка на главную высотой в строку.
     ВНИМАНИЕ: position здесь трогать нельзя. У .brandmark стоит
     position:fixed — он и так контейнер для абсолютного ::before, отдельное
     позиционирование ему не нужно. Раньше здесь стояло
     .brandmark{position:relative}: на сенсорных экранах логотип переставал
     быть закреплённым, вставал в поток документа сразу после подвала, а
     скрипт продолжал двигать его по формуле для закреплённого элемента —
     на прокрутке надпись SHALE улетала вверх за пределы страницы. */
  .brandmark::before{
    content:'';position:absolute;left:-8px;right:-8px;
    top:50%;height:44px;transform:translateY(-50%);
  }
  /* Телефоны и ссылки в подвале мобильного меню — тем же приёмом. */
  .mobile-menu__foot a{position:relative}
  .mobile-menu__foot a::before{
    content:'';position:absolute;left:-8px;right:-8px;
    top:50%;height:44px;transform:translateY(-50%);
  }
  /* Хлебные крошки (.crumbs, не .crumb): высота строки, 17 точек.
     Слой на ::before — ::after там свободен, но правило дома одно.
     Ссылке «политику конфиденциальности» слой НЕ даём: она стоит
     внутри бегущего текста согласия, и слой высотой 44 px накрыл бы
     строку выше — нажатие по тексту согласия уводило бы на страницу
     политики вместо постановки галочки. Цель там и так большая:
     подпись целиком переключает галочку. */
  .crumbs a{position:relative}
  .crumbs a::before{
    content:'';position:absolute;left:-6px;right:-6px;
    top:50%;height:44px;transform:translateY(-50%);
  }
  /* Заголовок вопроса: высоты не хватало на десять точек. */
  .rule-item__head{min-height:44px}
}
/* ==== КОНЕЦ: зоны нажатия по обходу 28.08 ==== */

/* ==== НАЧАЛО: край подвала по плиткам 28.08 (build/footer-edge-round8.py) ==== */
/* Заливка подвала повторяет силуэт кладки. Без этого тёмное шло ровной
   прямой от верха блока, и над верхушками плиток оставалась чёрная
   полоса в глубину кромки. Маска — тот же файл и тот же масштаб, что
   у слоя плиток, поэтому силуэты совпадают точка в точку.
   Второй слой — сплошной, начинается ровно на глубине кромки: ниже
   подвал должен быть плотным, иначе сквозь него просвечивала бы
   страница. */
.footer{
  -webkit-mask-image:url('../img/footer-edge.png?v=00f49d94'),linear-gradient(#000,#000);
  -webkit-mask-size:var(--stone-w) var(--edge-h),100% 100%;
  -webkit-mask-position:center top,left var(--edge-h);
  -webkit-mask-repeat:repeat-x,no-repeat;
  mask-image:url('../img/footer-edge.png?v=00f49d94'),linear-gradient(#000,#000);
  mask-size:var(--stone-w) var(--edge-h),100% 100%;
  mask-position:center top,left var(--edge-h);
  mask-repeat:repeat-x,no-repeat;
}
/* ==== КОНЕЦ: край подвала по плиткам 28.08 ==== */

/* ==== НАЧАЛО: плитка подвала прямо в песок (build/footer-sand-round9.py) ==== */
/* Глубина кромки продублирована на :root, потому что нижнее поле надо
   задать секции, а не подвалу. Числа те же, что в правиле .footer выше:
   ширина кадра кладки 1850 px (на телефоне 1300) и коэффициент 0.074074 —
   это 130 px кромки в масштабе кадра. */
:root{--footer-edge-h:calc(1850px * 0.074074)}
@media (max-width:700px){:root{--footer-edge-h:calc(1300px * 0.074074)}}

/* Последний блок страницы продолжается под кромку подвала: его фон и есть
   то, из чего выходят плитки. Содержимое не сдвигается — поле растёт ровно
   на ту же величину, на которую подвал поднимается. */
main>:last-child{padding-bottom:calc(var(--sec-y) + var(--footer-edge-h))}

/* Подвал заходит на секцию сверху на глубину кромки. Верх подвала при этом
   остаётся на прежнем месте: секция ниже стала ровно на столько же. */
.footer{margin-top:calc(-1 * var(--footer-edge-h))}
/* ==== КОНЕЦ: плитка подвала прямо в песок ==== */

/* ==== НАЧАЛО: плавность перелёта логотипа (build/logo-motion-round9.py) ==== */
/* Переход для filter. Инверсию букв скрипт теперь пишет ступенями по 0,05
   вместо непрерывного значения — переход в 200 мс превращает ступени
   обратно в плавность, но перерисовок при этом в двадцать раз меньше.
   Задержка вступительного выезда букв записана прямо в первом слое, иначе
   отдельное свойство transition-delay растянуло бы её и на filter. */
.brandmark .wm img{
  transition:transform 1.25s var(--ease-main) calc(var(--i) * 95ms + 300ms),
             filter 200ms linear 0s;
}
/* Знак и его золотая подмена едут и гаснут каждый кадр — им нужен
   собственный слой, иначе браузер перерисовывает их вместе с фоном. */
.brandsign,.brandsign--gold{will-change:transform,opacity}
/* ==== КОНЕЦ: плавность перелёта логотипа ==== */

/* ==== НАЧАЛО: действие в шапке (build/header-action-round10.py) ==== */
/* Кнопка в шапке ниже ростом обычной: 52 px в 72-пиксельную шапку
   не помещаются вместе с отступами. */
.btn--sm{min-height:40px;padding:0 20px;font-size:var(--fs-label);letter-spacing:.1em}
.header__cta{margin-left:0;flex:none;text-decoration:none}
.header__phone{flex:none}

@media (max-width:1240px){
  /* Телефон остаётся, но значком: полный номер в шапку не влезает,
     а звонок — самое частое действие с телефона. */
  .header__nav{display:none}
  .header__cta{display:none}
  .header__phone{
    display:inline-flex;align-items:center;justify-content:center;
    width:44px;height:44px;margin-left:auto;
    font-size:0;line-height:0;letter-spacing:0;
  }
  /* ::after у этой ссылки занят подчёркиванием — берём ::before. */
  .header__phone::after{display:none}
  .header__phone::before{
    content:'';display:block;width:21px;height:21px;background:currentColor;
    -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.6 10.8a15.1 15.1 0 0 0 6.6 6.6l2.2-2.2c.28-.28.7-.37 1.05-.25 1.12.37 2.33.57 3.55.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1C10.6 21 3 13.4 3 4c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.22.2 2.43.57 3.55.11.35.03.77-.25 1.05l-2.22 2.2z'/%3E%3C/svg%3E") center/contain no-repeat;
            mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6.6 10.8a15.1 15.1 0 0 0 6.6 6.6l2.2-2.2c.28-.28.7-.37 1.05-.25 1.12.37 2.33.57 3.55.57.55 0 1 .45 1 1V20c0 .55-.45 1-1 1C10.6 21 3 13.4 3 4c0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.22.2 2.43.57 3.55.11.35.03.77-.25 1.05l-2.22 2.2z'/%3E%3C/svg%3E") center/contain no-repeat;
  }
  .header__burger{margin-left:6px}
}
/* ==== КОНЕЦ: действие в шапке ==== */

/* ==== НАЧАЛО: оформление, раунд 10 (build/design-round10.py) ==== */
/* 1. Кнопка становится фигурой, а не текстом на фоне.
      Было: заливка #FFFDF8→#F1EADC на фоне #F2ECE0 — контраст 1,02.
      Стало: корпус --ink #16140F, текст --paper #F5F1E9 — контраст 17:1.
      Рельеф оставляем, но перенастраиваем под тёмный корпус: светлая
      кромка сверху даёт выпуклость, на светлом корпусе она была не видна. */
.btn{
  background:linear-gradient(180deg,#26231C 0%,var(--ink) 100%);
  color:var(--paper);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.18),
             inset 0 -2px 6px -2px rgba(0,0,0,.5),
             0 12px 26px -14px rgba(60,48,30,.55),
             0 1px 3px rgba(60,48,30,.25);
}
/* При наведении золото по-прежнему выезжает снизу — фирменное движение
   сохранено, просто теперь идёт от тёмного к золотому. Цвет текста
   уже светлый, поэтому переключать его не нужно. */
.btn:hover{
  color:var(--paper);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.1),
             0 4px 10px -8px rgba(60,48,30,.45);
}

/* 3. Состояния «нажато» и «идёт отправка». Без них человек жмёт кнопку
      второй раз и создаёт вторую заявку. */
.btn:active{transform:translateY(2px)}
.btn[disabled],.btn:disabled{
  opacity:.5;cursor:progress;box-shadow:none;pointer-events:none;
}

/* 2. Переменная, на которую ссылались линии в блоке вопросов, не была
      объявлена нигде. Объявляем её здесь, а не правим две строки: если
      --rule встретится ещё где-то, оно тоже заработает. */
:root{--rule:var(--paper-line)}

/* 4. Карточка комплектации должна сама говорить, что раскрывается.
      Медиазапрос hover:hover прятал единственный видимый признак. */
@media (hover:hover) and (pointer:fine){
  .tier__toggle{display:flex}
}
/* Раскрытие с клавиатуры: до этого дойти до кнопки «Оставить заявку»
   внутри свёрнутого блока табом было нельзя вовсе. */
.tier:focus-within .tier__detail{grid-template-rows:1fr}
/* ==== КОНЕЦ: оформление, раунд 10 ==== */



/* ==== НАЧАЛО: читаемость надписей, раунд 11 (build/contrast-round11.py) ==== */
/* 1. Крошки и рубрика над заголовком лежат на фотографии в той полосе,
      где затемняющая плашка самая светлая. Замер: от 1,07 до 1,60 при
      норме 4,5. Светлый цвет чинит все 19 страниц и не трогает кадр. */
.page-hero .label{color:var(--on-dark)}
.crumbs{color:var(--on-dark)}
/* Одного цвета не хватило: замер по пикселям снимка показал, что после
   осветления текста крошки на /ceny/ дают 2,42, а рубрика 2,68 — фото
   под ними слишком светлое. Плотность затемнения в середине поднимаем
   с 34 % до 58 %: надписи садятся именно в эту полосу, потому что
   содержимое первого экрана выровнено по низу. Верх и низ не трогаем —
   там уже темно. */
.page-hero::after{
  background:linear-gradient(to bottom,rgba(10,9,7,.72) 0%,rgba(10,9,7,.58) 45%,rgba(10,9,7,.82) 100%);
}
/* Разделитель приглушаем отдельно — иначе цепочка станет шумной. */
.crumbs span::before{color:var(--on-dark-mute)}

/* 3. Переход от фотографии узла к странице объекта. Золото --gold
      на кремовом даёт 2,13 — бледнее серой подписи рядом. На тёмных
      секциях прежний оттенок остаётся: там он читается. */
.figlink{color:var(--gold-deep)}
.section--stone .figlink,.section--wood .figlink,.section--gold-ink .figlink{color:var(--gold)}

/* 4. Единственная подсказка, что страница листается. Было 2,7. */
.hero__scroll-text{color:var(--on-dark)}

/* 5. Серый текст на текстурных секциях давал 3,94. На чистой бумаге
      тот же цвет даёт 5,26 — значит, дело в паре с текстурой,
      а не в самом цвете. */
:root{--on-light-mute:#635B4D}

/* 6. Раскрытие по наведению сдвигало страницу на 691 px под курсором,
      причём человек об этом не просил: достаточно провести мышью,
      читая соседний блок. Оставляем нажатие и клавиатуру. */
@media (hover:hover) and (pointer:fine){
  .tier:hover .tier__detail{grid-template-rows:0fr}
  .tier.is-open .tier__detail,
  .tier:focus-within .tier__detail{grid-template-rows:1fr}
}

/* 7. Длина строки в раскрывающихся блоках: было 98 знаков на широком
      экране при комфортных 45–75. Приводим к той же мере, что у .prose. */
.rule-item__body p{max-width:44em}
/* ==== КОНЕЦ: читаемость надписей, раунд 11 ==== */

/* ==== НАЧАЛО: телефон, раунд 11 (build/mobile-round11.py) ==== */
/* 1. Меню должно прокручиваться, когда не помещается. В ландшафте
      539 px содержимого не влезали в окно 390 px: «Контакты» и оба
      телефона были недоступны вовсе, а выйти можно было только
      крестиком. Выравнивание по центру оставляем, пока место есть:
      при нехватке центрирование само превращается в прокрутку. */
.mobile-menu{
  overflow-y:auto;
  overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch;
  justify-content:flex-start;
}
.mobile-menu>*{margin-block:auto}

/* 2. Затемнение под подписью было ростом с саму подпись: чем длиннее
      текст, тем больше строк оказывалось в прозрачной части градиента.
      Фиксируем высоту — 240 px перекрывают четыре строки при любой
      длине фразы. */
.tech__stage figcaption{
  background-image:linear-gradient(to top,rgba(20,19,16,.92) 0%,rgba(20,19,16,.78) 45%,rgba(20,19,16,0) 100%);
  background-repeat:no-repeat;
  background-position:bottom;
  background-size:100% 240px;
}

/* 3. Поле мельче 16 px заставляет Safari на iOS увеличить страницу
      при фокусе и обратно не возвращает. Один пиксель на глаз
      незаметен, поведение меняется полностью. */
/* Селектор обязан повторять тот, что стоит выше по файлу
   (.field input[type=text] и т. д.): там font:inherit, и по весу
   он перебивает более короткое правило. Замер это и показал —
   textarea получил 16 px, а три поля ввода остались на 15. */
.field input[type=text],.field input[type=tel],.field input[type=email],
.field textarea{font-size:max(16px,var(--fs-body))}

/* 5. Окно плеера не должно отдавать прокрутку странице под собой,
      даже когда само доскроллено до края. */
.vmodal{overscroll-behavior:contain}

/* 4. Невидимый ползунок «до/после» лежит во всю площадь кадра.
      touch-action:none запрещал браузеру любые жесты внутри фотографии,
      включая прокрутку страницы. pan-y отдаёт вертикальный жест
      браузеру, горизонтальный остаётся ползунку. */
.ba__range{touch-action:pan-y}

/* 6. «от» — часть цены, а не служебная метка. Было 10,2 px
      приглушённым серым, физическая ширина 8 px рядом
      с тридцатипиксельной цифрой. */
.tier__from{font-size:max(11px,.34em);color:var(--on-light)}

@media (max-width:700px){
  /* 7. Главное действие экрана — во всю ширину колонки. */
  #lead-form .btn{width:100%}
}
/* ==== КОНЕЦ: телефон, раунд 11 ==== */

/* ==== НАЧАЛО: читаемость на телефоне (build/readability-round9.py) ==== */
/* 1. Нижняя граница мелкого шрифта — 11px вместо 10px. Верхняя та же,
      значит на компьютере ничего не меняется. Этим размером набраны
      рубрики, крошки и нижняя строка подвала с юридическими ссылками. */
:root{--fs-label:clamp(11px,.7vw,12px)}

/* Слово «более» перед крупной цифрой задано долей от неё и на телефоне
   падало до 9,2px. Доля остаётся, но ниже 11px не опускается. */
.numeral__pre{font-size:max(11px,.22em)}

/* «₽/м²» рядом с ценой пакета — та же болезнь: .34em от цены, которая
   на узком экране упирается в нижнюю границу 30px, даёт 10,2px. Это
   единица измерения при цене — если её не прочесть, цена читается
   неправильно на порядок. */
.tier__unit{font-size:max(11px,.34em)}

@media (hover:none),(pointer:coarse){
  /* 2. Ссылка, стоящая в абзаце или пункте списка одна, — это отдельная
        цель нажатия, а не слово внутри предложения. Высоту поднимаем на
        самой ссылке: абзац станет выше, соседние строки не сдвинутся.
        Ссылки вокруг картинок исключены — у них своя высота велика,
        а inline-flex сломал бы им раскладку. */
  main p>a:only-child:not(:has(img)):not(:has(picture)):not(:has(svg)),
  main li>a:only-child:not(:has(img)):not(:has(picture)):not(:has(svg)),
  /* Заголовок, целиком являющийся ссылкой, — тоже отдельная цель. */
  main h2>a:only-child,
  main h3>a:only-child,
  main h4>a:only-child,
  /* Телефон и почта — исключение из правила «только один в абзаце»:
     на странице контактов два телефона стоят в одном абзаце через <br>,
     поэтому :only-child их не ловит. А это самая важная цель нажатия
     на всём сайте: человек, дошедший до контактов, готов звонить. */
  main p>a[href^="tel:"],
  main p>a[href^="mailto:"]{
    display:inline-flex;align-items:center;min-height:44px;
  }
}
/* ==== КОНЕЦ: читаемость на телефоне ==== */

/* ==== НАЧАЛО: знак в углу блока (build/section-mark-subtle.py) ==== */
/* Знак стоит в углу блока и виден целиком. inset и height сбрасывают
   растяжку раунда 28.08 — без этого знак остался бы во весь блок,
   потому что то правило стоит выше по файлу и задаёт inset:0.

   max-height держит знак внутри блока: у .section--mark нет
   overflow:hidden, и на невысоком блоке он иначе залезет на соседний. */
.section--mark::after{
  content:'';
  inset:auto;
  right:-2%;bottom:0;left:auto;top:auto;
  width:min(42vw,500px);height:auto;max-height:82%;
  aspect-ratio:590/512;
  background:url('../img/mark-shale.png') no-repeat right bottom/contain;
  opacity:.12;
}
/* На тёмном фоне тот же знак читается слабее — даём чуть больше. */
.section--ink.section--mark::after,
.section--stone.section--mark::after,
.section--gold-ink.section--mark::after{opacity:.2}

/* Через блок знак переезжает в левый угол. transform:none — отмена
   зеркального отражения из старого правила: знак симметричный,
   и отражать его незачем. */
.section--mark--left::after{
  right:auto;left:-2%;
  background-position:left bottom;
  transform:none;
}

@media (min-width:1600px){
  /* На широком экране знак шириной 500 пикселей занимает пятую часть
     блока и читается не фактурой, а случайным пятном в углу. Растёт
     вместе с экраном и одновременно бледнеет: чем больше площадь
     пятна, тем ниже должна быть его плотность, иначе оно начинает
     спорить с текстом. */
  .section--mark::after{width:min(38vw,760px);max-height:88%;opacity:.085}
  .section--ink.section--mark::after,
  .section--stone.section--mark::after,
  .section--gold-ink.section--mark::after{opacity:.15}
}

@media (max-width:700px){
  /* На телефоне колонка текста узкая: знак мельче и бледнее,
     иначе он спорит с текстом, а не поддерживает его. */
  .section--mark::after{width:min(62vw,300px);max-height:56%;opacity:.09}
  .section--ink.section--mark::after,
  .section--stone.section--mark::after,
  .section--gold-ink.section--mark::after{opacity:.16}
}
/* ==== КОНЕЦ: знак в углу блока ==== */

/* ==== НАЧАЛО: бесшовные фоны (build/bg-seamless-round12.py) ==== */
/* Текстура ставится повтором, а не растяжкой. Размер плитки на экране
   ровно вдвое меньше файла: на экране с двойной плотностью пиксели
   ложатся один к одному, и фон не мылит ни на телефоне, ни на 4К.

   Переменные --tex-size и --tex-repeat заданы здесь со значениями
   по умолчанию «как было»: секции с не-бесшовными текстурами
   продолжают растягивать фон, иначе на них появились бы швы. */
.section--tex::before{
  background-size:var(--tex-size,cover);
  background-repeat:var(--tex-repeat,no-repeat);
}

.section--concrete{
  --tex:image-set(url('../img/bg-concrete-tile.avif') type('image/avif'),
                  url('../img/bg-concrete-tile.webp') type('image/webp'),
                  url('../img/bg-concrete-tile.jpg') type('image/jpeg'));
  --tex-size:700px;
  --tex-repeat:repeat;
}
.section--cream{
  --tex:image-set(url('../img/bg-plaster-tile.avif') type('image/avif'),
                  url('../img/bg-plaster-tile.webp') type('image/webp'),
                  url('../img/bg-plaster-tile.jpg') type('image/jpeg'));
  --tex-size:700px;
  --tex-repeat:repeat;
}

@media (max-width:700px){
  /* На телефоне плитка мельче: при размере в 700 пикселей на узком
     экране в кадр попадала бы половина плитки, и фактура читалась бы
     крупными пятнами вместо ровного фона. */
  .section--concrete,.section--cream{--tex-size:340px}
}
/* ==== КОНЕЦ: бесшовные фоны ==== */

/* ==== НАЧАЛО: шапка и кнопка наверх (build/header-round12.py) ==== */
/* ── Бургер ─────────────────────────────────────────────────────────
   Виден на всех экранах и стоит последним в шапке — правее кнопки
   «Обсудить проект».
   Три полоски: в закрытом виде лежат горизонтально, в открытом
   поворачиваются и встают вертикально рядом друг с другом. */
.header__burger{
  display:block;margin:0 0 0 4px;
  width:44px;height:44px;position:relative;
  background:none;border:0;cursor:pointer;color:inherit;flex:none;
}
.header__burger span{
  position:absolute;left:13px;width:18px;height:1.5px;border-radius:2px;
  background:currentColor;
  transition:transform .42s cubic-bezier(.66,0,.2,1),
             opacity .2s ease;
}
/* Закрытое положение: три горизонтали через шесть пикселей. */
.header__burger span:nth-child(1){top:16px}
.header__burger span:nth-child(2){top:21.5px}
.header__burger span:nth-child(3){top:27px}

/* Открытое: каждая полоска поворачивается на 90° вокруг центра кнопки
   и расходится в стороны. Поворот вокруг общего центра, а не своего:
   так три горизонтали превращаются ровно в три вертикали. */
body.menu-is-open .header__burger span{transform-origin:50% 50%}
body.menu-is-open .header__burger span:nth-child(1){
  transform:translateY(5.5px) rotate(90deg) translateX(0) translateY(-6px);
}
body.menu-is-open .header__burger span:nth-child(2){
  transform:rotate(90deg);
}
body.menu-is-open .header__burger span:nth-child(3){
  transform:translateY(-5.5px) rotate(90deg) translateX(0) translateY(6px);
}

@media (hover:hover){
  .header__burger:hover span:nth-child(1){transform:translateY(-1px)}
  .header__burger:hover span:nth-child(3){transform:translateY(1px)}
  body.menu-is-open .header__burger:hover span:nth-child(1){
    transform:translateY(5.5px) rotate(90deg) translateX(0) translateY(-6px);
  }
  body.menu-is-open .header__burger:hover span:nth-child(3){
    transform:translateY(-5.5px) rotate(90deg) translateX(0) translateY(6px);
  }
}
.header__burger:focus-visible{outline:2px solid var(--gold,#B8935A);outline-offset:2px;border-radius:6px}

/* На узком экране верхнее меню по-прежнему скрыто, и бургер остаётся
   единственной навигацией — но место у него то же, правый край шапки. */

/* ── Кнопка «наверх» ────────────────────────────────────────────────
   Появляется после двух экранов прокрутки. Круг, а не стрелка в углу:
   круглую цель проще поймать пальцем. */
.to-top{
  position:fixed;right:clamp(14px,2.2vw,28px);bottom:clamp(14px,2.2vw,28px);
  z-index:60;width:46px;height:46px;border-radius:50%;
  display:grid;place-items:center;cursor:pointer;
  background:rgba(31,42,54,.86);color:#F5F1E9;
  border:1px solid rgba(245,241,233,.18);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  opacity:0;transform:translateY(10px) scale(.9);pointer-events:none;
  transition:opacity .3s ease,transform .3s cubic-bezier(.66,0,.2,1);
}
.to-top svg{width:20px;height:20px;display:block}
.to-top.is-shown{opacity:1;transform:none;pointer-events:auto}
.to-top:hover{background:rgba(31,42,54,.96);border-color:var(--gold,#B8935A)}
.to-top:focus-visible{outline:2px solid var(--gold,#B8935A);outline-offset:3px}
/* Под открытым меню кнопка не нужна и мешает. */
body.menu-is-open .to-top{opacity:0;pointer-events:none}

@media (prefers-reduced-motion:reduce){
  .header__burger span,.to-top{transition:none}
}
/* ==== КОНЕЦ: шапка и кнопка наверх ==== */

/* ==== НАЧАЛО: просмотр фото на весь экран (build/lightbox-round12.py) ==== */
/* ── Кнопка поверх кадра ────────────────────────────────────────────
   Кнопка, а не обработчик на картинке: так кадр открывается и с
   клавиатуры, и озвучивается программой чтения с экрана. Растянута
   на всю картинку, но не на подпись — подпись читается, а не жмётся. */
figure:has(.fig-zoom){position:relative}
.gallery figure{position:relative}
.fig-zoom{
  position:absolute;left:0;top:0;right:0;bottom:auto;
  width:100%;padding:0;margin:0;border:0;background:none;
  cursor:zoom-in;color:#F5F1E9;
  /* Высота — по картинке, а не по всей фигуре. С bottom:0 кнопка
     накрывала подпись и ссылку «Смотреть объект» под ней: замер
     показывал под серединой ссылки элемент .fig-zoom, и ссылка
     не нажималась вовсе. Все кадры сайта 3:2 (pic() отдаёт
     1400x933), поэтому высота берётся соотношением сторон —
     это точнее любого подбора в пикселях. */
  aspect-ratio:3/2;
}
.gallery figure picture{display:block}
/* Страховка на случай, если у кадра окажется другое соотношение:
   подпись и ссылка под ней лежат выше кнопки по слоям. */
.gallery figure figcaption,
.gallery figure > a{position:relative;z-index:1}
.fig-zoom::before{
  content:"";position:absolute;right:12px;bottom:12px;
  width:38px;height:38px;border-radius:50%;
  background:rgba(31,42,54,.62) url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23F5F1E9' stroke-width='1.6' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='6.5'/%3E%3Cpath d='M20 20l-4.4-4.4M11 8.4v5.2M8.4 11h5.2'/%3E%3C/svg%3E") center/20px 20px no-repeat;
  backdrop-filter:blur(4px);-webkit-backdrop-filter:blur(4px);
  opacity:0;transform:scale(.86);
  transition:opacity .25s ease,transform .25s cubic-bezier(.66,0,.2,1);
}
@media (hover:hover){
  .gallery figure:hover .fig-zoom::before{opacity:1;transform:none}
}
/* На сенсорном экране наведения нет — значок виден всегда, иначе
   о самой возможности открыть кадр никто не узнает. */
@media (hover:none),(pointer:coarse){
  .fig-zoom::before{opacity:.9;transform:none}
}
.fig-zoom:focus-visible{outline:2px solid var(--gold,#B8935A);outline-offset:-4px}
.fig-zoom:focus-visible::before{opacity:1;transform:none}

/* ── Окно просмотра ─────────────────────────────────────────────────*/
.lbox{
  position:fixed;inset:0;z-index:200;
  display:grid;grid-template-rows:1fr auto;
  place-items:center;gap:0;
  background:rgba(18,24,31,.94);
  backdrop-filter:blur(10px);-webkit-backdrop-filter:blur(10px);
  opacity:0;visibility:hidden;
  transition:opacity .3s ease,visibility .3s;
  overscroll-behavior:contain;
  padding:clamp(12px,3vw,40px);
  touch-action:pan-y;
}
.lbox.is-open{opacity:1;visibility:visible}
.lbox__figure{
  margin:0;display:grid;grid-template-rows:1fr auto;gap:14px;
  max-width:100%;max-height:100%;justify-items:center;align-content:center;
}
.lbox__img{
  display:block;max-width:100%;max-height:78vh;
  width:auto;height:auto;object-fit:contain;
  border-radius:2px;background:rgba(245,241,233,.06);
  transition:opacity .22s ease;
}
.lbox.is-swapping .lbox__img{opacity:.25}
.lbox__cap{
  color:rgba(245,241,233,.9);font-size:clamp(13px,1.5vw,15px);
  line-height:1.5;text-align:center;max-width:64ch;margin:0;
}
.lbox__count{
  color:rgba(245,241,233,.55);font-size:12px;letter-spacing:.14em;
  margin:14px 0 0;font-variant-numeric:tabular-nums;
}

/* Кнопки. Круглые и крупные: на телефоне в них надо попадать пальцем. */
.lbox__close,.lbox__nav{
  position:absolute;z-index:2;width:48px;height:48px;border-radius:50%;
  border:1px solid rgba(245,241,233,.18);background:rgba(31,42,54,.7);
  cursor:pointer;color:#F5F1E9;
  transition:background .2s ease,border-color .2s ease,opacity .2s ease;
}
.lbox__close:hover,.lbox__nav:hover{
  background:rgba(31,42,54,.95);border-color:var(--gold,#B8935A);
}
.lbox__close:focus-visible,.lbox__nav:focus-visible{
  outline:2px solid var(--gold,#B8935A);outline-offset:3px;
}
.lbox__close{right:clamp(10px,2vw,26px);top:clamp(10px,2vw,26px)}
.lbox__close::before,.lbox__close::after{
  content:"";position:absolute;left:15px;top:23px;width:18px;height:1.5px;
  background:currentColor;border-radius:2px;
}
.lbox__close::before{transform:rotate(45deg)}
.lbox__close::after{transform:rotate(-45deg)}

.lbox__nav{top:50%;margin-top:-24px}
.lbox__nav--prev{left:clamp(10px,2vw,26px)}
.lbox__nav--next{right:clamp(10px,2vw,26px)}
.lbox__nav::before{
  content:"";position:absolute;left:18px;top:18px;
  width:11px;height:11px;border:1.5px solid currentColor;
  border-width:1.5px 1.5px 0 0;
}
.lbox__nav--prev::before{transform:rotate(-135deg);left:20px}
.lbox__nav--next::before{transform:rotate(45deg);left:16px}
/* Один кадр в галерее — листать нечего, кнопки прячутся. */
.lbox.is-single .lbox__nav{display:none}

@media (max-width:640px){
  .lbox__img{max-height:66vh}
  /* Стрелки уезжают вниз: по краям экрана в них не попасть большим
     пальцем, а поверх фотографии они закрывают то, ради чего окно
     и открыли. Свайп при этом работает по-прежнему. */
  .lbox__nav{top:auto;bottom:16px;margin-top:0;width:52px;height:52px}
  .lbox__nav--prev{left:calc(50% - 66px)}
  .lbox__nav--next{right:calc(50% - 66px)}
  .lbox__count{margin-bottom:74px}
}

@media (prefers-reduced-motion:reduce){
  .lbox,.lbox__img,.fig-zoom::before{transition:none}
}
/* ==== КОНЕЦ: просмотр фото на весь экран ==== */

/* ==== НАЧАЛО: кадры скрытых работ (build/uslugi-photos-round12.py) ==== */
/* Ссылка на объект под подписью кадра. Отдельной строкой, а не внутри
   подписи: подпись читается как подпись, ссылка нажимается как ссылка.
   В окне просмотра берётся только подпись — ссылки там нет. */
.gallery figure .figobj{
  display:inline-block;margin-top:6px;font-size:13px;letter-spacing:.02em;
}
/* ==== КОНЕЦ: кадры скрытых работ ==== */

/* ==== НАЧАЛО: наложения в блоке технологий (build/tech-overlap-round12.py) ==== */
/* Слой сравнения замкнут: z-index его половинок больше не спорит
   с подписью сцены. Без этого «до» (z-index:2) закрывала текст. */
.ba{isolation:isolate}

/* Значок материала стоит абсолютом у правого края и в потоке не
   участвует — место под него освобождает сама кнопка. Ширина:
   значок 30px, при наведении растёт до 1.16 (≈35px), правый край
   до 16px, плюс воздух. */
.tech__list button{padding-right:clamp(52px,5vw,64px)}
.tech__name{min-width:0}
/* ==== КОНЕЦ: наложения в блоке технологий ==== */

/* ==== НАЧАЛО: группы технологий (build/tech-groups-round12.py) ==== */
/* Переключатель групп. Две кнопки, а не выпадающий список: вариантов
   мало, и оба должны быть видны сразу — иначе про отделку квартир
   в этом разделе никто не узнает. */
.tech__groups{
  display:flex;gap:8px;flex-wrap:wrap;
  margin:clamp(18px,2.4vw,30px) 0 clamp(4px,1vw,12px);
}
.tech__group{
  padding:9px 18px;border-radius:999px;cursor:pointer;
  border:1px solid var(--paper-line);background:none;color:inherit;
  font-size:var(--fs-small);letter-spacing:.06em;
  transition:background var(--dur-ui) var(--ease-main),
             border-color var(--dur-ui) var(--ease-main),
             color var(--dur-ui) var(--ease-main);
}
.tech__group:hover{border-color:var(--gold)}
.tech__group.is-active{
  background:var(--ink,#1F2A36);border-color:var(--ink,#1F2A36);color:var(--on-dark,#F5F1E9);
}
.tech__group:focus-visible{outline:2px solid var(--gold);outline-offset:3px}
/* Пункт скрытой группы убирается из потока целиком: с display:none
   у соседей не остаётся ни границы, ни отступа. */
.tech__list li[hidden]{display:none}
/* ==== КОНЕЦ: группы технологий ==== */

/* ==== НАЧАЛО: цифры справа от текста (build/who-facts-round12.py) ==== */
/* Блок «Кто мы»: цифры остаются справа до планшета.
   Правило идёт после @media (max-width:1240px), которое схлопывает
   .cols в одну колонку, — иначе оно бы не применилось. */
@media (min-width:761px){
  .cols:has(.positioning__facts){
    grid-template-columns:minmax(0,1fr) minmax(200px,.42fr);
  }
}
/* Ниже 760 цифры встают под текст — так же, как перестраивается
   полоса цифр на главной. В узкой колонке число 150 с подписью
   «объектов» уже не помещается в строку. */
/* ==== КОНЕЦ: цифры справа от текста ==== */

/* ==== НАЧАЛО: кадр в честной смете (build/scope-photo-round12.py) ==== */
/* Раздел тёмный, поэтому у кадра нет светлой рамки — только скругление
   как у карточек проектов. Подпись под кадром, а не поверх него:
   поверх она легла бы на небо и не читалась. */
.scope__shot{
  margin:clamp(22px,3vw,38px) 0 0;position:relative;
}
.scope__shot picture{display:block;border-radius:14px;overflow:hidden}
.scope__shot img{width:100%;height:auto;display:block}
.scope__shot figcaption{
  margin-top:12px;font-size:var(--fs-small);line-height:1.5;
  color:var(--on-dark-mute,rgba(245,241,233,.72));
}
.scope__shot .link-arrow{margin-left:8px;white-space:nowrap}
/* ==== КОНЕЦ: кадр в честной смете ==== */

/* ==== НАЧАЛО: край подложки шапки (build/header-edge-round12.py) ==== */
.header::before{
  /* Конец градиента — ровно цвет страницы, иначе на стыке ступенька.
     Значение --paper брать нельзя: подложка полупрозрачная и лежит
     поверх содержимого, поэтому цвет задан с той же альфой, что был. */
  background-image:linear-gradient(rgba(253,251,246,.97) 0%,
                                   rgba(245,241,233,.9) 100%);
  /* Нижние восемь пикселей растворяются: обрезанное размытие
     видно даже при совпавшем цвете. */
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 8px),transparent 100%);
  mask-image:linear-gradient(to bottom,#000 calc(100% - 8px),transparent 100%);
}
/* ==== КОНЕЦ: край подложки шапки ==== */

/* ==== НАЧАЛО: группы ссылок в подвале (build/footer-groups-round12.py) ==== */
/* Группы идут одна под другой внутри своей колонки подвала.
   Отступ между группами больше межстрочного — иначе три коротких
   списка читаются как один длинный. */
.footer__group + .footer__group{margin-top:clamp(20px,2.2vw,28px)}
.footer__group .label{display:block;margin-bottom:10px}
/* ==== КОНЕЦ: группы ссылок в подвале ==== */

/* ==== НАЧАЛО: карта офиса (build/mission-map-round12.py) ==== */
.office-map{
  margin-top:clamp(22px,3vw,34px);
  border-radius:14px;overflow:hidden;
  border:1px solid var(--paper-line);
  background:rgba(0,0,0,.04);
}
.office-map iframe{
  display:block;width:100%;height:clamp(260px,32vw,380px);border:0;
}
.office-map__note{
  margin:10px 0 0;font-size:var(--fs-small);color:var(--on-light-mute);
}
/* ==== КОНЕЦ: карта офиса ==== */

/* ==== НАЧАЛО: логотипы партнёров (build/partner-logo-round12.py) ==== */
.partners-logos{
  display:flex;flex-wrap:wrap;gap:clamp(20px,3vw,40px);align-items:center;
  margin-top:clamp(22px,3vw,34px);
}
.partner-logo{
  display:flex;flex-direction:column;gap:10px;align-items:flex-start;
  /* Ширину задаём явно: во flex-строке figure ужимается по содержимому,
     и логотип выходил 81 пиксель вместо 220. */
  flex:0 0 auto;width:clamp(150px,20vw,220px);margin:0;
}
.partner-logo img{
  display:block;width:100%;height:auto;
  /* Чужой логотип не перекрашиваем и не подгоняем под палитру:
     это чужой знак, и менять его нельзя. Только размер. */
}
.partner-logo figcaption{
  font-size:var(--fs-small);line-height:1.5;color:var(--on-light-mute);
}
/* ==== КОНЕЦ: логотипы партнёров ==== */

/* ==== НАЧАЛО: кегль меток (build/label-size-round12.py) ==== */
/* Нижняя граница кегля меток — 12px вместо 11. Правило переопределяет
   переменную, а не отдельные селекторы: метка набирается в семи местах
   (.label, .footer__group .label, .crumbs, .tile__num и другие),
   и подпирать каждое по отдельности пришлось бы снова при каждой правке. */
:root{--fs-label:clamp(12px,.72vw,13px)}
/* ==== КОНЕЦ: кегль меток ==== */

/* ==== НАЧАЛО: кегль микро-надписей (build/microtext-round12.py) ==== */
/* Доля от родителя сохраняется, но не опускается ниже порога. */
.numeral__pre{font-size:max(.22em,12px)}
.tier__unit{font-size:max(.34em,12px)}
.pricing small,.tier small{font-size:max(.34em,12px)}
.viz-badge{font-size:12px}
.ba__tag{font-size:12px}
/* ==== КОНЕЦ: кегль микро-надписей ==== */

/* ==== НАЧАЛО: кромки блоков по фактуре (build/edges-round13.py) ==== */
:root{
  /* Глубина кромки: 45 px на большом экране, 26 на телефоне. Владелец
     выбрал «средне»: край читается, но не превращает страницу в пилу. */
  --edge-d:clamp(26px,3.2vw,45px);
  /* Ширина плитки маски на экране. Файл вдвое шире — на экране
     с двойной плотностью край не мылит. */
  --edge-tile:1400px;
}
@media (max-width:700px){:root{--edge-tile:760px}}

.section--paper,.section--light,.section--beige,.section--ink,
.section--gold-ink,.section--tex,.sigil-block,.contact{
  --edge-img:url('../img/edge-plaster.png');
  margin-top:calc(-1 * var(--edge-d));
  padding-top:calc(var(--sec-pad-top,var(--sec-y)) + var(--edge-d));
  -webkit-mask-image:var(--edge-img),linear-gradient(#000,#000);
  -webkit-mask-size:var(--edge-tile) var(--edge-d),200vw 12000px;
  -webkit-mask-position:left top,-50vw var(--edge-d);
  -webkit-mask-repeat:repeat-x,no-repeat;
  mask-image:var(--edge-img),linear-gradient(#000,#000);
  mask-size:var(--edge-tile) var(--edge-d),200vw 12000px;
  mask-position:left top,-50vw var(--edge-d);
  mask-repeat:repeat-x,no-repeat;
}

/* Бетон крошится мелко и рвано, сланец колется прямыми участками по
   слоям, штукатурка ложится широкими следами кельмы. Материал блока
   и определяет форму его края. */
.section--concrete{--edge-img:url('../img/edge-concrete.png')}
.section--stone,.section--wood,.section--ink,
.section--gold-ink,.sigil-block{--edge-img:url('../img/edge-stone.png')}

/* Блоки со своим верхним отступом. Значения повторяют те, что стоят
   выше по файлу: правило кромки их не заменяет, а прибавляет к ним. */
.facts-strip{--sec-pad-top:clamp(28px,3.4vw,52px)}
.contact{--sec-pad-top:calc(var(--sec-y) + 24px)}

/* Первый экран отдаёт кромке свою нижнюю полосу: без этого подпись под
   вордмарком и стрелка прокрутки уходят под приподнятый блок. */
.hero{padding-bottom:calc(clamp(18px,3vh,40px) + var(--edge-d))}
.page-hero{padding-bottom:calc(clamp(34px,5vw,80px) + var(--edge-d))}

@media (prefers-reduced-motion:no-preference){}
/* ==== КОНЕЦ: кромки блоков по фактуре ==== */

/* ==== НАЧАЛО: раскрытое меню (build/menu-round13.py) ==== */
/* --- 1. Закрытие: сначала уходят пункты, потом панель ------------- */
.mobile-menu{transition:clip-path .5s var(--ease-menu) .3s}
body.menu-is-open .mobile-menu{transition:clip-path .8s var(--ease-menu)}
.mobile-menu__list a{transition:transform .42s var(--ease-main);transition-delay:0s}
body.menu-is-open .mobile-menu__list a{
  transition:transform .7s var(--ease-main);
  transition-delay:calc(var(--mi,0) * 45ms);
}

/* --- 2. Логотип в шапке, пока меню открыто ------------------------ */
.header__menu-only{opacity:0;visibility:hidden;transition:opacity .3s ease .12s,visibility 0s .42s}
body.menu-is-open .header__menu-only{opacity:1;visibility:visible;transition:opacity .3s ease .12s,visibility 0s}
/* Надпись стоит на месте посадочного места: ширина знака плюс зазор
   шапки. Absolute нужен, чтобы она не добавила себя во flex-строку
   и не сдвинула вкладки с телефоном вправо. */
.header__logo-img.header__menu-only{
  position:absolute;left:calc(clamp(30px,2.8vw,44px) + 10px);
  top:50%;transform:translateY(-50%);margin-left:0;
}
@media (max-width:900px){
  .header__logo-img.header__menu-only{left:calc(clamp(26px,5.4vw,38px) + 10px)}
}

/* --- 3. Подчёркивание пунктов, как у вкладок шапки ---------------- */
.mobile-menu__list a{position:relative;width:-moz-fit-content;width:fit-content}
.mobile-menu__list a::after{
  content:'';position:absolute;left:0;right:0;bottom:.12em;height:1px;
  background:currentColor;opacity:.65;
  transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-ui) var(--ease-main);
}
@media (hover:hover){.mobile-menu__list a:hover::after{transform:scaleX(1)}}
.mobile-menu__list a:focus-visible::after{transform:scaleX(1)}

/* --- 4. Знак в фоне справа снизу ---------------------------------- */
.mobile-menu::after{
  content:'';position:absolute;pointer-events:none;z-index:-1;
  right:-4%;bottom:-8%;
  width:min(46vw,420px);aspect-ratio:820/711;
  background:url('../img/mark-shale.svg') no-repeat center/contain;
  opacity:.07;
}
@media (max-width:700px){
  .mobile-menu::after{width:min(66vw,320px);right:-10%;bottom:-4%;opacity:.08}
}

/* --- 5. Почта рядом с телефонами ---------------------------------- */
.mobile-menu__foot a{width:-moz-fit-content;width:fit-content}
/* ==== КОНЕЦ: раскрытое меню ==== */

/* ==== НАЧАЛО: блок «Кто мы» (build/who-round13.py) ==== */
/* Явные координаты вместо автопотока: иначе декоративная черта
   съедает первую ячейку правой колонки и цифры уезжают под текст. */
.positioning__grid{grid-template-rows:auto minmax(0,1fr)}
.positioning__grid > .positioning__text{grid-column:1;grid-row:1 / span 2}
.positioning__grid > .edge--mini{grid-column:2;grid-row:1;align-self:start}
.positioning__grid > .positioning__facts{grid-column:2;grid-row:2;align-self:start}

@media (max-width:1000px){
  /* Одна колонка: цифры возвращаются под текст — иначе на планшете
     на них остаётся 200 пикселей и число 150 переносится по цифрам. */
  .positioning__grid > .positioning__text,
  .positioning__grid > .edge--mini,
  .positioning__grid > .positioning__facts{grid-column:1;grid-row:auto}
}
/* ==== КОНЕЦ: блок «Кто мы» ==== */

/* ==== НАЧАЛО: модуль целиком как ссылка (build/clickable-round13.py) ==== */
[data-linkbox]{cursor:pointer}
/* Ссылка внутри модуля остаётся ссылкой: она подчёркнута и её видно.
   Просто теперь искать её не обязательно. */

/* Кнопка увеличения на модуле-ссылке: нажимается только значок в углу,
   остальная площадь снимка ведёт на объект.

   Обрезка делается clip-path, а не парой pointer-events:none на кнопке
   и pointer-events:auto на её псевдоэлементе. Вторая схема выглядит
   изящнее и не работает: замер elementFromPoint по центру значка
   возвращал саму фигуру, то есть значок событий не получал вовсе.
   clip-path обрезает и рисование, и попадание курсора — это проверено
   тем же замером. 62 пикселя — значок 38 плюс отступ 12 с запасом. */
figure[data-linkbox] .fig-zoom{
  clip-path:inset(calc(100% - 62px) 0 0 calc(100% - 62px));
}
/* Обводка фокуса переезжает на сам значок: у кнопки её обрезало бы. */
figure[data-linkbox] .fig-zoom:focus-visible{outline:none}
figure[data-linkbox] .fig-zoom:focus-visible::before{
  outline:2px solid var(--gold,#B8935A);outline-offset:2px;
}
@media (hover:hover){
  figure:hover .fig-zoom::before{opacity:1;transform:none}
}

/* Кружок «Увеличить» — тот же, что «Смотреть»: другой только текст. */
body.cursor-is-zoom .mouse-cursor,
body.cursor-is-open .mouse-cursor{
  width:88px;height:88px;margin:-44px 0 0 -44px;background:var(--ink);
}
body.cursor-is-zoom .mouse-cursor__label,
body.cursor-is-open .mouse-cursor__label{opacity:1}
/* ==== КОНЕЦ: модуль целиком как ссылка ==== */

/* ==== НАЧАЛО: кадр в честной смете справа (build/scope-round13.py) ==== */
.scope__intro{
  display:grid;gap:clamp(26px,3.4vw,56px);
  grid-template-columns:minmax(0,1.25fr) minmax(0,1fr);
  align-items:start;
  margin-top:clamp(18px,2.4vw,32px);
}
.scope__intro .lead--narrow{max-width:none}
.scope__intro .lead + .lead{margin-top:clamp(14px,1.6vw,22px)}
/* Кадр меньше: он иллюстрация к абзацу, а не самостоятельный блок. */
.scope__intro .scope__shot{margin-top:6px}

@media (max-width:900px){
  .scope__intro{grid-template-columns:minmax(0,1fr)}
  .scope__intro .scope__shot{margin-top:clamp(18px,3vw,28px)}
}
/* ==== КОНЕЦ: кадр в честной смете справа ==== */

/* ==== НАЧАЛО: запасной блок карты (build/map-round13.py) ==== */
.office-map{position:relative}
.office-map__fallback{
  position:absolute;inset:0;z-index:0;
  display:grid;place-content:center;justify-items:center;gap:16px;
  padding:clamp(20px,3vw,34px);text-align:center;
  background:var(--paper-2);
}
.office-map__addr{margin:0;font-size:var(--fs-lead);color:var(--on-light)}
.office-map iframe{position:relative;z-index:1;background:transparent}
/* Пока карта не отчиталась о загрузке, кадр прозрачен и виден запасной
   блок под ним. Класс ставит скрипт. */
.office-map:not(.is-ready) iframe{opacity:0}
.office-map.is-blocked iframe{display:none}
/* ==== КОНЕЦ: запасной блок карты ==== */

/* ==== НАЧАЛО: галька в подвале (build/pebbles-round13.py) ==== */
/* Два слоя, а не один. Камни гребня лежат на самом блоке, поле гальки —
   на его ::before со своей маской.

   Сначала было наоборот: поле на блоке, гребень на ::before выше него.
   Так не работает — маска на элементе обрезает и его псевдоэлементы,
   а гребень висит ВЫШЕ верхнего края блока, где у маски нет ни одной
   строки. Он пропадал целиком, и на стыке оставались только зубцы
   собственной маски поля: на снимке 1:1 это читалось как ровная линия
   с прямоугольными выступами. */
.footer__pebbles{
  position:absolute;left:0;right:0;bottom:0;z-index:-1;pointer-events:none;
  /* Ширина плитки гальки на экране. Файл вдвое шире — на экране
     с двойной плотностью камни не мылит. */
  --peb-w:900px;
  --peb-edge:calc(var(--peb-w) * 46 / 1800);
  --peb-crest:calc(var(--peb-w) * 330 / 1800);
  --peb-seam:calc(var(--peb-w) * 165 / 1800);
  /* Стык с кладкой: доля ширины кадра кладки, а не пиксели. Блок
     поднят ещё на вылет гребня — камни лежат выше стыка. */
  top:calc(var(--edge-h) + var(--stone-w) * 0.30 - var(--peb-seam));
  /* WebP с прозрачностью весит 62 КБ против 405 у PNG: PNG хранит
     фотографию камней без потерь. PNG остаётся запасным. */
  background-image:image-set(url('../img/pebble-crest.webp') type('image/webp'),
                             url('../img/pebble-crest.png') type('image/png'));
  background-repeat:repeat-x;
  background-position:center top;
  background-size:var(--peb-w) var(--peb-crest);
}
.footer__pebbles::before{
  content:'';position:absolute;left:0;right:0;bottom:0;
  top:var(--peb-seam);
  background-image:image-set(url('../img/bg-pebbles-1800.avif') type('image/avif'),
                             url('../img/bg-pebbles-1800.webp') type('image/webp'),
                             url('../img/bg-pebbles-1800.jpg') type('image/jpeg'));
  background-size:var(--peb-w) auto;
  background-position:center top;
  background-repeat:repeat;
  /* Верхний край поля обрезан по настоящим спинам камней кадра:
     маска и фактура кладутся одним масштабом и одной привязкой,
     поэтому вырез совпадает с камнями, а не режет их поперёк. */
  -webkit-mask-image:url('../img/edge-pebble.png'),linear-gradient(#000,#000);
  -webkit-mask-size:var(--peb-w) var(--peb-edge),200vw 12000px;
  -webkit-mask-position:center top,-50vw var(--peb-edge);
  -webkit-mask-repeat:repeat-x,no-repeat;
  mask-image:url('../img/edge-pebble.png'),linear-gradient(#000,#000);
  mask-size:var(--peb-w) var(--peb-edge),200vw 12000px;
  mask-position:center top,-50vw var(--peb-edge);
  mask-repeat:repeat-x,no-repeat;
}
@media (max-width:700px){
  /* Кадр кладки на телефоне уже (--stone-w 1300), и галька уменьшается
     вместе с ним: иначе в экран попадает три камня и поле читается
     как случайные пятна. */
  .footer__pebbles{--peb-w:560px}
}

/* Вуаль подвала начиналась ровной линией на глубине кромки: над кладкой
   этого не было видно, а по светлой гальке пошла горизонтальная полоса.
   Растворяем её первые шестьдесят пикселей. */
.footer::after{
  background:linear-gradient(rgba(20,17,12,0) 0,rgba(20,17,12,.34) 60px);
}

/* Линейка над нижней строкой подвала лежала прямо по гальке. Владелец:
   «никаких проставок, линий, других цветов там не должно быть — только
   галька». Отбивка держится отступом. */
.footer__bottom{border-top:0}
/* ==== КОНЕЦ: галька в подвале ==== */

/* ==== НАЧАЛО: мягкая кромка блока видео (build/film-edge-round14.py) ==== */
/* Блоки видео (.film — единственные носители section--stone) получают
   спокойную кромку вместо сланцевой лесенки. Остальные носители
   edge-stone.png (section--wood, section--ink, section--gold-ink,
   .sigil-block) остаются как были: там скол по слоям уместен. */
.section--stone{--edge-img:url('../img/edge-film.png')}
/* ==== КОНЕЦ: мягкая кромка блока видео ==== */

/* ==== НАЧАЛО: блог (build/blog-round14.py) ==== */
/* ---------------------------------------------------------- список статей */
.blog-chips{
  display:flex;flex-wrap:wrap;gap:10px 12px;
  margin-bottom:clamp(28px,3.4vw,56px);
}
.blog-chips a{
  display:inline-block;padding:8px 16px;border:1px solid var(--paper-line);
  border-radius:999px;font-size:var(--fs-small);color:var(--on-light-mute);
  text-decoration:none;transition:border-color var(--dur-micro) var(--ease-main),
    color var(--dur-micro) var(--ease-main);
}
.blog-chips a:hover{border-color:var(--gold);color:var(--on-light)}

.posts{
  display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));
  gap:clamp(28px,3vw,56px) clamp(20px,2.2vw,40px);
}
.posts--rel{grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.postcard{display:flex;flex-direction:column;gap:clamp(10px,1vw,16px)}
.postcard__shot{overflow:hidden;background:var(--paper-3)}
.postcard__shot img{
  display:block;width:100%;height:auto;aspect-ratio:3/2;object-fit:cover;
  transition:transform var(--dur-image) var(--ease-main);
}
.postcard:hover .postcard__shot img{transform:scale(1.045)}
.postcard__label{
  font-size:var(--fs-label);font-weight:700;letter-spacing:.2em;
  text-transform:uppercase;color:var(--on-light-mute);
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;
}
/* Разделитель между рубрикой и датой — точка, а не дефис: дефис между
   словами ловит check_text.py как ошибку набора. Точка нарисована
   псевдоэлементом самой даты, а не отдельным флекс-элементом: иначе при
   переносе она остаётся висеть в конце первой строки. */
.postcard__label time{
  display:inline-flex;align-items:center;gap:10px;white-space:nowrap;
}
.postcard__label time::before{
  content:"";width:3px;height:3px;border-radius:50%;background:var(--gold);
}

/* Восьмой пункт в шапке («Блог») сделал строку тесной, и «О компании»
   переносилось в две строки. Названия разделов не переносим. */
.header__nav a{white-space:nowrap}
.postcard__title{
  font-family:var(--font-display);font-weight:500;
  font-size:clamp(19px,1.45vw,25px);line-height:1.2;text-wrap:balance;
}
.postcard__title a{color:inherit;text-decoration:none}
.postcard__lead{
  font-size:var(--fs-small);line-height:1.55;color:var(--on-light-mute);
  max-width:46ch;
}

/* --------------------------------------------------------------- статья */
.post__grid{
  display:grid;grid-template-columns:minmax(0,1fr) clamp(200px,17vw,270px);
  gap:clamp(28px,4vw,86px);align-items:start;
}
.post__body{
  max-width:68ch;font-size:var(--fs-lead);line-height:1.66;color:var(--on-light);
}
.post__body p{margin:0 0 1.05em}
.post__body a{color:inherit;text-decoration:underline;text-underline-offset:3px;
  text-decoration-color:var(--gold)}
.post__body > :first-child{margin-top:0}
.post__h2{
  font-family:var(--font-display);font-weight:500;
  font-size:clamp(23px,2.15vw,38px);line-height:1.16;text-wrap:balance;
  margin:1.9em 0 .6em;scroll-margin-top:calc(var(--header-h) + 24px);
}
.post__h3{
  font-family:var(--font-display);font-weight:500;
  font-size:clamp(18px,1.35vw,23px);line-height:1.24;margin:1.6em 0 .5em;
}
.post__list,.post__steps{margin:0 0 1.2em;padding-left:1.3em}
.post__list{list-style:none;padding-left:0}
.post__list li{position:relative;padding-left:26px;margin-bottom:.5em}
.post__list li::before{
  content:"";position:absolute;left:4px;top:.62em;width:9px;height:1px;
  background:var(--gold);
}
.post__steps{counter-reset:st;list-style:none;padding-left:0}
.post__steps li{position:relative;padding-left:42px;margin-bottom:.72em}
.post__steps li::before{
  counter-increment:st;content:counter(st,decimal-leading-zero);
  position:absolute;left:0;top:.12em;font-family:var(--font-display);
  /* Тёмное золото, а не яркое: номер шага — это текст, и его читают.
     Яркое золото на бумаге даёт контраст 2.13 при норме 4.5, тёмное —
     4.48. Яркое остаётся на том, что не читают: черта у пункта списка,
     точка-разделитель, стрелка оглавления. */
  font-size:var(--fs-small);color:var(--gold-deep);letter-spacing:.06em;
}
.post__note{
  margin:1.7em 0;padding:clamp(16px,1.6vw,26px) clamp(18px,1.8vw,30px);
  background:var(--paper-2);border-left:2px solid var(--gold);
}
.post__note p{margin:0;font-size:var(--fs-body);line-height:1.6}
.post__hr{border:0;border-top:1px solid var(--paper-line);margin:2.4em 0}
.post__tablewrap{overflow-x:auto;margin:1.8em 0;-webkit-overflow-scrolling:touch}
.post__table{border-collapse:collapse;width:100%;min-width:460px;
  font-size:var(--fs-body)}
.post__table th,.post__table td{
  text-align:left;padding:12px 16px;border-bottom:1px solid var(--paper-line);
  vertical-align:top;
}
.post__table th{
  font-size:var(--fs-label);font-weight:700;letter-spacing:.14em;
  text-transform:uppercase;color:var(--on-light-mute);
}
.post__table td:not(:first-child){font-variant-numeric:tabular-nums}
.post__figure{margin:2em 0}
.post__figure picture,.post__figure img{display:block;width:100%;height:auto}
.post__figure figcaption{
  margin-top:10px;font-size:var(--fs-small);color:var(--on-light-mute);
  line-height:1.5;
}
.post__body code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em;
  background:var(--paper-2);padding:1px 5px;
}

.post__aside{position:sticky;top:calc(var(--header-h) + 28px)}
.post__meta{
  font-size:var(--fs-label);font-weight:700;letter-spacing:.16em;
  text-transform:uppercase;color:var(--on-light-mute);line-height:1.55;
  display:flex;flex-direction:column;gap:7px;
}
.post__meta time{color:var(--on-light)}
.post__toc{margin-top:clamp(20px,2vw,32px);border-top:1px solid var(--paper-line);
  padding-top:clamp(16px,1.6vw,26px)}
.post__toc > summary{
  margin-bottom:12px;cursor:pointer;list-style:none;
  display:flex;align-items:center;justify-content:space-between;gap:10px;
}
.post__toc > summary::-webkit-details-marker{display:none}
/* Стрелка-указатель поворачивается при открытии. Рисуем рамкой, а не
   символом: символ зависит от шрифта и на части устройств пустой. */
.post__toc > summary::after{
  content:"";width:7px;height:7px;flex:none;
  border-right:1.5px solid var(--gold);border-bottom:1.5px solid var(--gold);
  transform:rotate(45deg) translateY(-2px);
  transition:transform var(--dur-micro) var(--ease-main);
}
.post__toc[open] > summary::after{transform:rotate(-135deg) translateY(-2px)}
.post__toc ol{list-style:none;counter-reset:tc;padding:0;margin:0}
.post__toc li{counter-increment:tc;margin-bottom:9px;line-height:1.35}
.post__toc a{
  font-size:var(--fs-small);color:var(--on-light-mute);text-decoration:none;
  display:grid;grid-template-columns:22px minmax(0,1fr);
  transition:color var(--dur-micro) var(--ease-main);
}
/* Номер отдельной колонкой сетки: пробел в content схлопывается,
   и на телефоне выходило «1.Коротко». */
.post__toc a::before{content:counter(tc) ".";color:var(--gold-deep)}
.post__toc a:hover{color:var(--on-light)}
.post__rubric{margin-top:clamp(18px,2vw,30px);font-size:var(--fs-small)}
.post__rubric a{color:var(--on-light-mute);text-underline-offset:3px}

@media (max-width:1000px){
  .post__grid{grid-template-columns:minmax(0,1fr)}
  /* Оглавление наверх: на узком экране колонка встаёт под текстом,
     и содержание там уже никому не нужно. */
  .post__aside{position:static;order:-1;
    border-bottom:1px solid var(--paper-line);padding-bottom:clamp(16px,3vw,26px)}
  .post__body{max-width:none}
}
/* ==== КОНЕЦ: блог ==== */

/* ==== НАЧАЛО: меню раунда 16 ==== */
/* 1. Место под полосу прокрутки зарезервировано всегда.
      Пока меню закрыто, видно ровно то же, что и раньше: полоса стоит
      в этом месте. Когда меню ставит overflow:hidden, полоса исчезает,
      но место остаётся занятым — ширина окна не меняется, страница
      не пересчитывается, закреплённые элементы стоят на месте. */
html{scrollbar-gutter:stable}

/* 2. Блокировка прокрутки классом, а не строчным стилем: так её видно
      в отладчике и можно к ней привязать стили. Отступ — подстраховка
      для браузеров без scrollbar-gutter; там, где оно работает,
      --lock-pad равен нулю и отступ ничего не делает. */
html.is-locked{overflow:hidden;padding-right:var(--lock-pad,0px)}

/* 3. Панель меню — на своём слое. Без этого каждый кадр раскрытия
      перерисовывает всё, что лежит под ней во весь экран. */
.mobile-menu{will-change:clip-path;contain:layout style}

/* 4. Фирменный паттерн треугольников справа. Тот же файл, что в блоках
      страниц (.section--sigil). Лежит ниже текста по z-index, поэтому
      пункты меню читаются поверх него. */
.mobile-menu::after{
  content:'';position:absolute;pointer-events:none;z-index:-1;
  right:-2%;top:12%;
  width:min(44vw,480px);aspect-ratio:1;
  background:url('../img/pattern-triangles.png') no-repeat center/contain;
  opacity:0;transform:translateY(22px);
  transition:opacity .55s ease,transform .55s var(--ease-main);
}
/* Появляется, когда панель уже раскрылась: иначе паттерн виден
   сквозь ещё не доехавшую кромку. */
body.menu-is-open .mobile-menu::after{
  opacity:.24;transform:none;
  transition:opacity .9s ease .34s,transform .9s var(--ease-main) .34s;
}
@media (max-width:900px){
  .mobile-menu::after{right:-6%;top:auto;bottom:7%;width:min(58vw,340px)}
  body.menu-is-open .mobile-menu::after{opacity:.18}
}
@media (max-width:520px){
  .mobile-menu::after{right:-10%;bottom:4%;width:min(66vw,280px)}
}
@media (prefers-reduced-motion:reduce){
  .mobile-menu::after,body.menu-is-open .mobile-menu::after{transition:opacity .2s linear}
  .mobile-menu::after{transform:none}
}
/* ── Блог: порядок погружения и «подробнее» ─────────────────────────────── */
.post__course{margin-top:26px;padding-top:18px;border-top:1px solid var(--paper-line)}
.post__course ol{list-style:none;margin:10px 0 0;padding:0}
.post__course li{display:flex;gap:10px;align-items:baseline;
  padding:7px 0;font-size:14px;line-height:1.35}
.post__course li+li{border-top:1px solid var(--paper-line)}
.post__course-n{font-family:var(--font-display),serif;font-size:13px;
  letter-spacing:.06em;color:var(--gold-deep);min-width:22px}
.post__course a{color:inherit;text-decoration:none;border-bottom:1px solid transparent}
.post__course a:hover{border-bottom-color:var(--gold-deep)}
.post__course .is-here b{font-weight:600}

/* Расширенная версия. Закрыта по умолчанию: статья обязана читаться
   за один лист, а всё сверх того — по желанию читателя. */
.post__more{margin:30px 0 6px;border:1px solid var(--paper-line);
  background:var(--paper-2)}
.post__more>summary{cursor:pointer;list-style:none;padding:16px 20px;
  display:flex;align-items:center;gap:12px;font-weight:600;font-size:15px}
.post__more>summary::-webkit-details-marker{display:none}
.post__more>summary::after{content:"";margin-left:auto;width:9px;height:9px;
  border-right:1.5px solid var(--gold-deep);border-bottom:1.5px solid var(--gold-deep);
  transform:rotate(45deg);transition:transform .2s}
.post__more[open]>summary::after{transform:rotate(-135deg)}
.post__more-body{padding:0 20px 18px}
.post__more-body>*:first-child{margin-top:0}

/* ==== КОНЕЦ: меню раунда 16 ==== */
