/*
 * assets/a.css — визуальный мир сайта: A · Sample Board.
 *
 * Материальный борд, который подрядчик привозит клиенту: выкраски, шпон,
 * латунь и камень на подложке с машинописными спецификационными подписями.
 * Тёплая нейтральная палитра, контрастный serif, разреженный uppercase-sans,
 * машинописные подписи, чередование светлых и тёмных секций, широкие поля,
 * тонкие линии вместо теней и рамок.
 *
 * Файл не задаёт поведение: поведение живёт в site.js и приходит сюда
 * только классами .is-stuck и .is-current.
 * Все раскладки — на логических свойствах: арабская локаль с dir="rtl"
 * не потребует ни одной правки.
 */

/* ------------------------------------------------------------------ *
 * 1. Материал
 * ------------------------------------------------------------------ */
:root {
  /* Палитра борда */
  --paper: #F4F0E8;
  --limestone: #E9E3D8;
  --board: #EFEAE0;         /* подложка чертежей: тем же тоном залит их SVG */
  --charcoal: #211F1C;
  --cedar: #A9663D;         /* линия, скол, выкраска — не текст */
  --cedar-ink: #8C4A25;     /* тот же кедр, доведённый до текстового контраста */
  --cedar-lit: #C98A5C;     /* кедр на угле */
  --brass: #C9A227;         /* только волосяная линия, меньше 5% площади */
  --brass-lit: #EFDCA4;     /* та же латунь на угле: блик по канту кнопки */
  --error: #A32B1E;         /* незаполненное поле формы: 6:1 на бумаге, не кедр — кедр значит фокус */

  --ink: #211F1C;
  --ink-muted: #5F584D;
  --sand: #EDE7DC;
  --sand-muted: #A79E90;

  /* Материалы выкрасок — те же, что нарисованы на борде в первом экране */
  --mat-wd01: #C08B57;
  --mat-st02: #D8D1C4;
  --mat-mt03: #C9A227;
  --mat-tz05: #DDD6C8;
  --mat-wd06: #B98A5A;
  --mat-tx07: #B8AF9F;
  --mat-pt10: #A9663D;

  /* Гарнитуры. Prata — контрастный дидон с кириллицей; Golos Text — служебный
     разреженный гротеск; PT Mono — машинописная подпись спецификации. */
  --font-display: "Prata", "PT Serif", Georgia, "Times New Roman", serif;
  --font-text: "Golos Text", "Helvetica Neue", Arial, "Segoe UI", sans-serif;
  --font-spec: "PT Mono", ui-monospace, "Courier New", monospace;

  /* Кегли — текучие, без единой фиксированной точки останова */
  --t-h1: clamp(2.375rem, 1.35rem + 4.6vw, 5.125rem);
  --t-h2: clamp(1.75rem, 1.24rem + 2.25vw, 3rem);
  --t-h3: clamp(1.125rem, 1.02rem + 0.5vw, 1.375rem);
  --t-lead: clamp(1.0625rem, 0.98rem + 0.4vw, 1.3125rem);
  --t-body: clamp(1rem, 0.95rem + 0.22vw, 1.125rem);
  --t-small: clamp(0.875rem, 0.85rem + 0.12vw, 0.9375rem);
  --t-spec: clamp(0.6875rem, 0.655rem + 0.14vw, 0.75rem);

  --gutter: clamp(1.25rem, 0.35rem + 3.6vw, 6rem);
  --shell: 82.5rem;
  --sec-pad: clamp(3.75rem, 2.2rem + 6.4vw, 8.5rem);
  --route-pad: clamp(1.5rem, 0.9rem + 2.4vw, 3rem);

  --head-h: clamp(3.75rem, 3.35rem + 1.6vw, 4.75rem);
  --af-anchor-offset: calc(var(--head-h) + 1.5rem);

  /* Кнопки в углу окна, WhatsApp над «Наверх»: сторона круга (высота кнопки
     шапки), отступ от углов окна и зазор между кругами. Под ними же подвал
     оставляет пустую полосу (раздел 16). */
  --up-size: 2.875rem;
  --up-gap: clamp(1rem, 0.8rem + 0.8vw, 1.5rem);
  --up-stack: 0.75rem;

  /* Ширина таблички с формой — на всех экранах, в «Контактах» и в попапе. */
  --form-w: 26rem;

  --draw: 460ms cubic-bezier(0.16, 1, 0.3, 1);

  /* Кант кнопки — таблетка: радиус заведомо больше половины её высоты. */
  --btn-r: 999px;
}

/* ------------------------------------------------------------------ *
 * 2. Грунт секции — «борд переворачивают»
 * ------------------------------------------------------------------ */
.a-sec--paper,
.a-sec--limestone,
.a-sec--dark,
.a-menu,
.a-head {
  background: var(--ground);
  color: var(--fg);
}

/* Кнопка WhatsApp в углу окна — тёмная пара кнопки «Наверх»: носит бумажный
   грунт, на котором сплошная кнопка угольная (раздел 6). */
.a-sec--paper,
.a-menu,
.a-head,
.a-wa {
  --ground: var(--paper);
  --fg: var(--ink);
  --fg-muted: var(--ink-muted);
  --accent: var(--cedar-ink);
  --line: var(--cedar);
  --rule: rgba(33, 31, 28, 0.16);
  --rule-strong: rgba(33, 31, 28, 0.34);
  --btn-bg: var(--ink);
  --btn-fg: var(--paper);
  --btn-ring: rgba(33, 31, 28, 0.16);
  --btn-gleam: var(--brass);
  --btn-glass: rgba(255, 255, 255, 0.5);
  --panel: #FBF9F4;
}

/* Попап с формой висит вне секций и носит грунт «Контактов»: форма в нём
   выглядит так же, как внизу страницы (раздел 15). */
.a-sec--limestone,
.a-dialog {
  --ground: var(--limestone);
  --fg: var(--ink);
  --fg-muted: var(--ink-muted);
  --accent: var(--cedar-ink);
  --line: var(--cedar);
  --rule: rgba(33, 31, 28, 0.17);
  --rule-strong: rgba(33, 31, 28, 0.36);
  --btn-bg: var(--ink);
  --btn-fg: var(--limestone);
  --btn-ring: rgba(33, 31, 28, 0.18);
  --btn-gleam: var(--brass);
  --btn-glass: rgba(255, 255, 255, 0.5);
  --panel: var(--paper);
}

/* Кнопка «Наверх» носит угольный грунт с собой: она висит над любой
   секцией, а выглядеть должна как кнопка шапки (раздел 6). */
.a-sec--dark,
.a-foot,
.a-up {
  --ground: var(--charcoal);
  --fg: var(--sand);
  --fg-muted: var(--sand-muted);
  --accent: var(--cedar-lit);
  --line: var(--cedar-lit);
  --rule: rgba(237, 231, 220, 0.18);
  --rule-strong: rgba(237, 231, 220, 0.38);
  --btn-bg: var(--sand);
  --btn-fg: var(--charcoal);
  --btn-ring: rgba(237, 231, 220, 0.15);
  --btn-gleam: var(--brass-lit);
  --btn-glass: rgba(33, 31, 28, 0.55);
  --panel: #2A2723;
  background: var(--ground);
  color: var(--fg);
}

/* ------------------------------------------------------------------ *
 * 3. Страница и типографика
 * ------------------------------------------------------------------ */
.a-page {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: 1.62;
  font-synthesis-weight: none;
  overflow-wrap: break-word;
  /* clip, а не hidden: hidden сделал бы body скролл-контейнером и убил sticky. */
  overflow-x: clip;
}

::selection {
  background: var(--cedar-ink);
  color: var(--paper);
}

/* Полоса прокрутки — часть материала, а не браузерная деталь по умолчанию. */
html { scrollbar-color: #B7AE9F var(--paper); }

:focus-visible {
  outline: 2px solid var(--accent, var(--cedar-ink));
  outline-offset: 3px;
}

.a-skip {
  position: absolute;
  inset-block-start: 0.75rem;
  inset-inline-start: 0.75rem;
  z-index: 60;
  background: var(--charcoal);
  color: var(--paper);
  padding-block: 0.75rem;
  padding-inline: 1.25rem;
  font: 500 var(--t-spec) / 1 var(--font-text);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-decoration: none;
}

.a-h1,
.a-h2,
.a-h3,
.a-step__title,
.a-svc__title,
.a-fan__hub,
.a-risk__label,
.a-form__label,
.a-dialog__title,
.a-menu__link,
.a-brand__name,
.a-foot__name {
  font-family: var(--font-display);
  font-weight: 400;
}

.a-h1 {
  font-size: var(--t-h1);
  line-height: 1.03;
  letter-spacing: -0.017em;
  text-wrap: balance;
  max-inline-size: 16ch;
}

.a-h2 {
  font-size: var(--t-h2);
  line-height: 1.13;
  letter-spacing: -0.011em;
  text-wrap: balance;
  max-inline-size: 20ch;
}

.a-h3 {
  font-size: var(--t-h3);
  line-height: 1.24;
  letter-spacing: -0.004em;
  text-wrap: balance;
}

.a-main .a-lead {
  font-size: var(--t-lead);
  line-height: 1.5;
  color: var(--fg-muted);
  max-inline-size: 46ch;
  text-wrap: pretty;
}

.a-main p { max-inline-size: 68ch; }

/* Машинописная подпись спецификации */
.a-spec {
  font-family: var(--font-spec);
  font-size: var(--t-spec);
  line-height: 1.4;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.a-link {
  color: inherit;
  text-decoration: underline;
  text-decoration-color: var(--rule-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.28em;
  transition: color var(--af-motion-fast) var(--af-ease),
              text-decoration-color var(--af-motion-fast) var(--af-ease);
}

.a-link:hover { color: var(--accent); text-decoration-color: var(--line); }

/* ------------------------------------------------------------------ *
 * 4. Раскладка
 * ------------------------------------------------------------------ */
.a-shell {
  inline-size: min(100%, var(--shell));
  margin-inline: auto;
}

.a-sec {
  padding: var(--sec-pad) var(--gutter);
  border-block-start: 1px solid transparent;
}

.a-intro { margin-block-end: clamp(2.5rem, 1.6rem + 3.4vw, 4.5rem); }
.a-intro .a-spec { margin-block-end: 1.25rem; }
.a-intro .a-h2 { max-inline-size: 30ch; }
.a-intro .a-h2 + .a-lead { margin-block-start: 1.5rem; }

/* ------------------------------------------------------------------ *
 * 5. Хедер
 * ------------------------------------------------------------------ */
/* Шапка стоит над сценой и не знает, что сейчас под ней: из «менять грунт
   по JS» и «один грунт везде» взято второе. Уголь согласуется с подвалом,
   который и так угольный, а светлый текст держится и на кадре, и на бумаге.
   До прилипания грунта нет — есть мягкая угольная вуаль сверху кадра: она
   же держит шапку читаемой без JS, когда .is-stuck не приходит вовсе. */
.a-head {
  position: sticky;
  padding-inline: var(--gutter);
  inset-block-start: 0;
  z-index: 40;
  --ground: var(--charcoal);
  --fg: var(--sand);
  --fg-muted: var(--sand-muted);
  --accent: var(--cedar-lit);
  --line: var(--cedar-lit);
  --rule: rgba(237, 231, 220, 0.18);
  --rule-strong: rgba(237, 231, 220, 0.38);
  --btn-bg: var(--sand);
  --btn-fg: var(--charcoal);
  --btn-ring: rgba(237, 231, 220, 0.15);
  --btn-gleam: var(--brass-lit);
  --btn-glass: rgba(33, 31, 28, 0.55);
  color: var(--fg);
  background-color: transparent;
  background-image: linear-gradient(to bottom, rgba(20, 18, 15, 0.5), rgba(20, 18, 15, 0));
  transition: background-color var(--af-motion-base) var(--af-ease),
              border-color var(--af-motion-base) var(--af-ease);
  border-block-end: 1px solid transparent;
}

.a-head.is-stuck {
  background-color: rgba(33, 31, 28, 0.82);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border-block-end-color: var(--rule);
}

.a-head__in {
  inline-size: min(100%, var(--shell));
  margin-inline: auto;
  min-block-size: var(--head-h);
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.5vw, 2.5rem);
}

.a-brand {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  gap: 0.625rem;
  text-decoration: none;
  color: inherit;
  margin-inline-end: auto;
}

/* Знак инлайновый: currentColor кладёт его тем же светом, что и имя рядом.
   Ширина — доля высоты по сетке знака 287×352, иначе пилоны сплющит. */
.a-brand__mark {
  flex: none;
  inline-size: 1.529rem;
  block-size: 1.875rem;
}

.a-brand__name {
  font-size: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  letter-spacing: 0.01em;
  white-space: nowrap;
}

.a-nav {
  display: none;
  gap: clamp(1.125rem, 1.8vw, 2.25rem);
}

.a-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  padding-block: 0.5rem;
  font-size: var(--t-spec);
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  color: var(--fg-muted);
  transition: color var(--af-motion-fast) var(--af-ease);
  white-space: nowrap;
}

.a-nav__link::after {
  content: "";
  position: absolute;
  inset-block-end: 0.15rem;
  inset-inline-start: 0;
  inline-size: 0;
  block-size: 1px;
  background: var(--cedar);
  transition: inline-size var(--draw);
}

.a-nav__link:hover,
.a-nav__link:focus-visible { color: var(--fg); }
.a-nav__link:hover::after,
.a-nav__link:focus-visible::after { inline-size: 100%; }

.a-nav__link.is-current { color: var(--fg); }
.a-nav__link.is-current::after { inline-size: 100%; }

.a-head__side {
  display: flex;
  flex: none;
  align-items: center;
  gap: clamp(0.75rem, 1.6vw, 1.5rem);
}

/* Переключатель языка — дорожка с ползунком: активная сторона не загорается
   квадратом, а принимает к себе поехавший ползунок. Ползунок стоит в потоке
   последним, поэтому его положение задаёт соседний селектор — без :has и без
   кодов языков в стилях: правило смотрит на порядок кнопок, а не на язык.
   Локалей сейчас две; третья — ещё одно правило положения здесь. */
.a-lang {
  position: relative;
  display: inline-flex;
  align-items: stretch;
  border: 1px solid var(--rule-strong);
  border-radius: 999px;
  background: var(--rule);
}

.a-lang__btn {
  position: relative;
  z-index: 1;
  flex: 1 1 50%;
  background: transparent;
  border: 0;
  border-radius: 999px;
  padding-block: 0.4rem;
  padding-inline: 0.75rem;
  min-block-size: 2.75rem;
  min-inline-size: 2.75rem;
  font-family: var(--font-spec);
  font-size: var(--t-spec);
  letter-spacing: 0.1em;
  color: var(--fg-muted);
  transition: color var(--af-motion-fast) var(--af-ease);
}

.a-lang__btn:hover { color: var(--fg); }

/* Без JS атрибута нет вовсе — активна первая кнопка: ползунок стоит под ней,
   и её подпись обязана читаться по грунту, а не по приглушённому тексту. */
.a-lang__btn[aria-pressed="true"],
.a-lang__btn:first-child:not([aria-pressed]) { color: var(--ground); }

.a-lang__thumb {
  position: absolute;
  z-index: 0;
  inset-block: 0.25rem;
  inset-inline-start: 0.25rem;
  inline-size: calc(50% - 0.5rem);
  border-radius: 999px;
  background: var(--fg);
  /* Та же спокойная доводка, что у остальных контролов; логическая
     координата сохраняет направление движения в RTL. */
  transition: inset-inline-start var(--af-motion-base) var(--af-ease);
}

.a-lang__btn:nth-child(2)[aria-pressed="true"] ~ .a-lang__thumb {
  inset-inline-start: calc(50% + 0.25rem);
}

/* Приоритет выше общей .a-btn ниже: на телефоне остаётся кнопка меню. */
.a-head__cta.a-btn { display: none; white-space: nowrap; }

/* ------------------------------------------------------------------ *
 * 6. Кнопки
 * ------------------------------------------------------------------ */
/* Кант с бегущим бликом — общая механика всех кнопок страницы, кроме
   переключателя языка: у него своя дорожка с ползунком, и таблетка ему
   не нужна.
   Слоёв три и все живут на одном элементе, потому что кнопка в разметке —
   один узел:
     фон элемента          — кант, ровная полоска шириной --btn-edge;
     ::before (z-index -2) — блик: размытый лоскут латуни в четверть кванта,
                             вращается вокруг центра, кант его подрезает;
     ::after  (z-index -1) — тело кнопки, вложено в кант на ту же полоску.
   Надпись остаётся содержимым и лежит выше обоих: z-index 0 на кнопке
   заводит контекст наложения, в котором отрицательные слои ложатся под
   текст, но над фоном-кантом. Ни строчки JS: и кант, и блик — CSS.
   Цвета берутся из грунта секции (--btn-ring / --btn-gleam / --btn-glass),
   поэтому одна и та же кнопка читается и на бумаге, и на кадре сцены. */
.a-btn,
.a-filter,
.a-burger {
  position: relative;
  z-index: 0;
  overflow: hidden;
  border: 0;
  border-radius: var(--btn-r);
  background: var(--btn-ring, rgba(33, 31, 28, 0.16));
  cursor: pointer;
  --btn-edge: 2px;
  /* Нажатие отзывается размером — по нему и идёт переход. */
  transition: transform 300ms var(--af-ease),
              color var(--af-motion-base) var(--af-ease);
}

.a-btn::before,
.a-filter::before,
.a-burger::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset-block-start: -50%;
  inset-inline-start: -50%;
  inline-size: 200%;
  block-size: 200%;
  background-image: linear-gradient(var(--btn-gleam, var(--brass)), var(--btn-gleam, var(--brass)));
  background-repeat: no-repeat;
  background-position: 100% 50%;
  background-size: 50% 30%;
  filter: blur(6px);
  animation: a-btn-gleam 4s linear infinite;
}

.a-btn::after,
.a-filter::after,
.a-burger::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: var(--btn-edge);
  border-radius: inherit;
  background: var(--btn-glass, rgba(255, 255, 255, 0.5));
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  transition: background var(--af-motion-base) var(--af-ease);
}

/* Блик обходит кант за четыре секунды. Свёрнутое движение (base.css гасит
   анимации при prefers-reduced-motion) оставляет лоскут стоять на месте —
   кант просто получает тёплый отлив с одной стороны. */
@keyframes a-btn-gleam {
  to { transform: rotate(1turn); }
}

/* Указателя нет — нет и наведения: на тач-экране таблетка не подрастает. */
@media (hover: hover) {
  .a-btn:hover,
  .a-filter:hover,
  .a-burger:hover { transform: scale(1.02); }
}

.a-btn:active,
.a-filter:active,
.a-burger:active { transform: scale(1); }

.a-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: 2.875rem;
  padding-block: 0.75rem;
  padding-inline: clamp(1.375rem, 1.05rem + 1.4vw, 2.25rem);
  font-family: var(--font-text);
  font-size: var(--t-spec);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
}

.a-btn--solid { color: var(--btn-fg); }
.a-btn--solid::after {
  background: var(--btn-bg);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Наведение уводит тело в акцент грунта: на бумаге это тёмный кедр под
   светлой надписью, на угле — светлый под тёмной. Обе пары уже сведены
   в --btn-fg, поэтому цвет надписи не меняется. */
.a-btn--solid:hover::after,
.a-btn--solid:focus-visible::after { background: var(--accent); }

.a-btn--line { color: var(--fg); }
.a-btn--line:hover { color: var(--accent); }

/* -- Кнопки в углу окна: WhatsApp и «Наверх» -------------------------- */
/* «Наверх» — та же сплошная кнопка, что «Связаться с нами» в шапке, только
   круглая и со стрелкой вместо надписи: песочное тело, латунный блик по канту,
   наведение уводит тело в кедр. Кант — полупрозрачный песок поверх угля:
   на угольной шапке он так и выглядит, а на бумаге без угольной подложки
   растворился бы вместе с краем кнопки.
   WhatsApp над ней — та же кнопка в бумажном грунте: угольное тело, светлый
   кант, наведение в тёмный кедр. На бумаге кант сливается с грунтом и кнопка
   читается тёмным кругом, на кадре сцены и в подвале её очерчивает кант.
   Ниже меню (39) и шапки (40): открытое меню обе кнопки накрывает. */
.a-up,
.a-wa {
  position: fixed;
  z-index: 30;
  inset-block-end: var(--up-gap);
  inset-inline-end: var(--up-gap);
  inline-size: var(--up-size);
  block-size: var(--up-size);
  min-block-size: 0;
  padding: 0;
  background: linear-gradient(var(--btn-ring), var(--btn-ring)) var(--ground);
}

.a-wa { inset-block-end: calc(var(--up-gap) + var(--up-size) + var(--up-stack)); }

/* Пока «Наверх» спрятана, WhatsApp стоит в самом углу, на её месте. translate,
   а не transform: transform у кнопок занят нажатием. Без :has() кнопка просто
   остаётся над пустым местом. */
.a-wa:has(~ .a-up[data-af-to-top-state="hidden"]) {
  translate: 0 calc(var(--up-size) + var(--up-stack));
}

.a-up svg,
.a-wa svg {
  inline-size: 1.125rem;
  block-size: 1.125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Знак WhatsApp — тот же, что в подвале, и того же веса. */
.a-wa svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  stroke-width: 1.5;
}

.a-wa .a-wa__glyph { fill: currentColor; stroke: none; }

/* У верха страницы кнопка не нужна: site.js ставит state="hidden", пока
   не прокручен первый экран. visibility, а не одна прозрачность, — чтобы
   невидимая кнопка не ловила ни фокус, ни нажатие. */
.a-up[data-af-to-top-state="hidden"] {
  opacity: 0;
  visibility: hidden;
}

.a-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-block-start: clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem);
}

/* ------------------------------------------------------------------ *
 * 7. Выкраска-чип — подпись к образцу
 * ------------------------------------------------------------------ */
.a-chip {
  display: block;
  flex: 0 0 auto;
  inline-size: 0.5rem;
  block-size: 1.375rem;
  background: var(--chip, var(--fg));
  transition: inline-size var(--draw);
}

.a-chip--wd01 { --chip: var(--mat-wd01); }
.a-chip--st02 { --chip: var(--mat-st02); }
.a-chip--mt03 { --chip: var(--mat-mt03); }
.a-chip--tz05 { --chip: var(--mat-tz05); }
.a-chip--wd06 { --chip: var(--mat-wd06); }
.a-chip--tx07 { --chip: var(--mat-tx07); }
.a-chip--pt10 { --chip: var(--mat-pt10); }
.a-chip--all { --chip: var(--fg-muted); }

/* ------------------------------------------------------------------ *
 * 8. Схема услуг: «круг, дуга и семь веток»
 *
 * Главный круг «Услуги», от него веером расходятся семь веток: кольцо
 * с выкраской материала и таблетка с названием. Нажатие раскрывает
 * ветку — таблетка заливается, как выбранный фильтр, а текст услуги
 * выпадает из неё списком.
 *
 * Ветка — нативный <details name="services">: браузер сам держит
 * открытой не больше одной, клавиатура и диктор работают без единой
 * строчки JS. Здесь — только раскладка и вид.
 *
 * Уже 75em схема — ствол: круг сверху, кольца нанизаны на одну линию,
 * текст раскрывается под таблеткой и раздвигает соседей. С 75em — веер,
 * и его геометрия считается от номера ветки (--i), а не от положения
 * на странице: раскрытая ветка выходит на первый план, её текст
 * разворачивается поверх соседей, а они блекнут — ни один ряд не
 * сдвигается. Заодно это держит сцену — высота «Услуг» от нажатия
 * не меняется, и кадр под ними не прыгает.
 * ------------------------------------------------------------------ */
.a-fan {
  --fan-n: 7;                 /* веток в схеме — столько же, сколько услуг */
  --fan-hub: clamp(8rem, 6.4rem + 5vw, 10.5rem);   /* диаметр круга */
  --fan-halo: 0.625rem;       /* ореол вокруг круга */
  --fan-node: 3.25rem;        /* диаметр кольца */
  --fan-pill: 3.5rem;         /* высота таблетки */
  --fan-dir: 1;               /* куда смотрит веер; в RTL — зеркально */
  --fan-start: 0%;            /* начальный край строки для transform-origin */
  position: relative;
}

[dir="rtl"] .a-fan { --fan-dir: -1; --fan-start: 100%; }

/* Круг: стеклянный диск поверх кадра и ореол светлее вокруг — как на эскизе. */
.a-fan__hub {
  display: grid;
  place-items: center;
  inline-size: var(--fan-hub);
  aspect-ratio: 1;
  margin: 0;
  padding: 1rem;
  border: 1px solid var(--rule);
  border-radius: 50%;
  box-shadow: 0 0 0 var(--fan-halo) color-mix(in srgb, var(--fg) 7%, transparent);
  background: var(--btn-glass);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  font-size: clamp(1.375rem, 1.05rem + 1.3vw, 2.25rem);
  line-height: 1.1;
  letter-spacing: -0.011em;
  text-align: center;
}

/* Дуга нужна только вееру. */
.a-fan__arc { display: none; }

/* Ствол идёт от центра круга: кольца нанизаны ровно под ним. Атрибут
   в селекторе — чтобы перебить сброс списка из base.css. */
.a-fan__list[role="list"] {
  margin-inline-start: calc(var(--fan-hub) / 2);
  max-inline-size: 44rem;
}

.a-svc {
  position: relative;
  padding-block: 0.4375rem;
}

.a-svc:first-child { padding-block-start: calc(var(--fan-halo) + 1rem); }

/* Ствол собирают сами ветки: у каждой свой отрезок во всю её высоту,
   и раскрытая ветка тянет его за собой. Последний доходит до кольца. */
.a-svc__spoke {
  position: absolute;
  inset-block: 0;
  inset-inline-start: -0.5px;
  inline-size: 1px;
  background-color: var(--rule-strong);
  transition: background-color var(--af-motion-base) var(--af-ease);
}

.a-svc:last-child > .a-svc__spoke {
  inset-block-end: auto;
  block-size: calc(0.4375rem + var(--fan-pill) / 2);
}

/* Таблетка — тот же стеклянный кант, что у кнопок, без бегущего блика:
   семь бликов разом спорили бы с кадром. Кольцо садится на её начало. */
.a-svc__pill {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.875rem;
  min-block-size: var(--fan-pill);
  padding-block: 0.5rem;
  padding-inline: 0 1.25rem;
  border: 1px solid var(--btn-ring);
  border-radius: var(--btn-r);
  background-color: var(--btn-glass);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  color: var(--fg);
  list-style: none;
  cursor: pointer;
  transition: background-color var(--af-motion-base) var(--af-ease),
              border-color var(--af-motion-base) var(--af-ease),
              color var(--af-motion-base) var(--af-ease),
              opacity var(--af-motion-base) var(--af-ease),
              scale var(--draw);
}

.a-svc__pill::-webkit-details-marker { display: none; }

.a-svc__node {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  inline-size: var(--fan-node);
  block-size: var(--fan-node);
  margin-inline-start: calc(var(--fan-node) / -2);
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--panel);
  transition: border-color var(--af-motion-base) var(--af-ease);
}

/* Выкраска материала в кольце — та же, что у строки услуг раньше.
   Подрастает при наведении и заполняет кольцо у раскрытой ветки. */
.a-svc__node::before {
  content: "";
  inline-size: 40%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--chip, var(--fg));
  transition: inline-size var(--draw);
}

.a-svc__title {
  flex: 1 1 auto;
  min-inline-size: 0;
  font-size: clamp(1.0625rem, 1rem + 0.25vw, 1.1875rem);
  line-height: 1.22;
  letter-spacing: -0.004em;
  text-wrap: balance;
}

/* Плюс из двух волосяных линий; у раскрытой ветки — крестик. */
.a-svc__mark {
  position: relative;
  flex: 0 0 auto;
  inline-size: 0.875rem;
  block-size: 0.875rem;
  margin-inline-start: auto;
  color: var(--fg-muted);
  transition: transform var(--draw),
              color var(--af-motion-base) var(--af-ease);
}

.a-svc__mark::before,
.a-svc__mark::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-start: calc(50% - 0.5px);
  block-size: 1px;
  background: currentColor;
}

.a-svc__mark::after { transform: rotate(90deg); }

@media (hover: hover) {
  .a-svc__pill:hover { border-color: var(--rule-strong); }
  .a-svc__pill:hover .a-svc__mark { color: var(--accent); }
  .a-svc__pill:hover .a-svc__node::before { inline-size: 56%; }
}

/* Раскрытая ветка: залитая таблетка, крестик, выкраска во всё кольцо,
   загоревшаяся линия. */
.a-svc__item[open] > .a-svc__pill {
  border-color: var(--btn-bg);
  background-color: var(--btn-bg);
  color: var(--btn-fg);
  text-shadow: none;
}

.a-svc__item[open] > .a-svc__pill .a-svc__mark {
  color: currentColor;
  transform: rotate(45deg);
}

.a-svc__item[open] .a-svc__node { border-color: var(--accent); }
.a-svc__item[open] .a-svc__node::before { inline-size: 72%; }
.a-svc:has(> .a-svc__item[open]) > .a-svc__spoke { background-color: var(--accent); }

/* Пока одна ветка раскрыта, остальные отступают, но остаются под рукой. */
.a-fan:has(.a-svc__item[open]) .a-svc__item:not([open]) > .a-svc__pill { opacity: 0.62; }
.a-fan:has(.a-svc__item[open]) .a-svc__item:not([open]) > .a-svc__pill:hover,
.a-fan:has(.a-svc__item[open]) .a-svc__item:not([open]) > .a-svc__pill:focus-visible { opacity: 1; }

/* В стволе раскрытая ветка становится карточкой: таблетка наверху, текст
   под ней на подложке того же радиуса. */
.a-svc__item {
  border-radius: calc(var(--fan-pill) / 2);
  transition: background-color var(--af-motion-base) var(--af-ease),
              box-shadow var(--af-motion-base) var(--af-ease);
}

.a-svc__item[open] {
  background-color: var(--panel);
  box-shadow: inset 0 0 0 1px var(--rule);
}

/* Высота раскрывается сеткой 0fr → 1fr на обёртке содержимого; закрытие
   доигрывает, пока content-visibility держится дискретным переходом.
   Где ::details-content нет, текст появляется сразу — и всё равно
   проявляется своей анимацией. Первая строка transition — для браузеров
   без allow-discrete: без неё они выбросили бы обе. */
.a-svc__item::details-content {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--draw);
  transition: grid-template-rows var(--draw),
              content-visibility var(--draw) allow-discrete;
}

.a-svc__item[open]::details-content { grid-template-rows: 1fr; }

.a-svc__body {
  min-block-size: 0;
  overflow: hidden;
  transition: opacity var(--af-motion-base) var(--af-ease);
}

.a-svc__item:not([open]) .a-svc__body { opacity: 0; }

/* Сверху текста — штрих выкраски этой ветки, каким у цифр идёт латунный. */
.a-main .a-svc__text {
  padding-block: 1rem 1.375rem;
  padding-inline: 1.375rem 1.5rem;
  max-inline-size: none;
  color: var(--fg);
  text-shadow: none;
  text-wrap: pretty;
}

.a-svc__text::before {
  content: "";
  display: block;
  inline-size: 2.5rem;
  block-size: 1px;
  margin-block-end: 0.875rem;
  background: var(--chip, var(--brass));
}

.a-svc__item[open] .a-svc__text { animation: a-svc-text var(--draw) 90ms backwards; }

@keyframes a-svc-text {
  from { opacity: 0; transform: translate3d(0, 0.5rem, 0); }
}

/* -- Веер ------------------------------------------------------------ */
/* Ряды идут ровным шагом, кольца стоят на окружности вокруг центра круга:
   смещение по строке — sqrt(reach² − dy²), где dy — номер ряда от среднего.
   Спицы — радиусы той же окружности, и видна от них только короткая
   --fan-spoke между дугой и кольцом: дуга выведена почти к кольцам, а круг
   вырос вместе с ней. Таблетки обрезаны по одной вертикали — по концу
   средней, самой короткой, — и вся схема стоит по центру блока. */
@media (min-width: 75em) {
  .a-fan {
    --fan-row: 5.5rem;          /* шаг ряда */
    --fan-pill: 4.25rem;        /* таблетка: название в две строки */
    --fan-node: 4.75rem;
    --fan-hub: 18rem;
    --fan-halo: 1rem;
    --fan-reach: 3.16;          /* радиус колец в шагах ряда: крайние спицы — около 72° */
    --fan-spoke: 2.75rem;       /* видимая спица — от дуги до кольца */
    --fan-label: 18.75rem;      /* ширина названия — одна на все ветки: «Ремонт коммерческих» в строку */
    --fan-arc: calc(var(--fan-reach) * var(--fan-row) - var(--fan-node) / 2 - var(--fan-spoke));
    /* Средняя таблетка: полкольца, название, плюс, два зазора, поле и кант
       с обеих сторон. По её концу обрезаны все остальные. */
    --fan-short: calc(var(--fan-node) / 2 + var(--fan-label) + 3 * 0.875rem + 1.25rem + 2px);
    --fan-cx: calc(var(--fan-hub) / 2 + var(--fan-halo));   /* центр круга */
    --fan-cy: calc(var(--fan-n) * var(--fan-row) / 2);
    inline-size: calc(var(--fan-cx) + var(--fan-reach) * var(--fan-row) + var(--fan-short));
    block-size: calc(var(--fan-n) * var(--fan-row));
    margin-inline: auto;
  }

  .a-fan__hub {
    position: absolute;
    inset-block-start: calc(var(--fan-cy) - var(--fan-hub) / 2);
    inset-inline-start: calc(var(--fan-cx) - var(--fan-hub) / 2);
    font-size: 3rem;
  }

  /* Полуокружность: коробка в радиус шириной, концевые углы скруглены
     на весь радиус. Углы логические — в RTL дуга смотрит сама. */
  .a-fan__arc {
    position: absolute;
    display: block;
    inset-block-start: calc(var(--fan-cy) - var(--fan-arc));
    inset-inline-start: var(--fan-cx);
    inline-size: var(--fan-arc);
    block-size: calc(2 * var(--fan-arc));
    border: 1px solid var(--rule-strong);
    border-inline-start: 0;
    border-start-end-radius: var(--fan-arc);
    border-end-end-radius: var(--fan-arc);
  }

  .a-fan__hub,
  .a-fan__arc,
  .a-svc__spoke { transition: opacity var(--draw), background-color var(--af-motion-base) var(--af-ease); }

  .a-fan__list[role="list"] {
    margin-inline-start: 0;
    max-inline-size: none;
  }

  /* Ряд не позиционирован: спица меряется от .a-fan. */
  .a-svc {
    --dy: calc(var(--i) - (var(--fan-n) - 1) / 2);
    --x: calc(sqrt(var(--fan-reach) * var(--fan-reach) - var(--dy) * var(--dy)) * var(--fan-row));
    position: static;
    display: flex;
    align-items: center;
    block-size: var(--fan-row);
    padding-block: 0;
  }

  .a-svc:nth-child(1) { --i: 0; }
  .a-svc:nth-child(2) { --i: 1; }
  .a-svc:nth-child(3) { --i: 2; }
  .a-svc:nth-child(4) { --i: 3; }
  .a-svc:nth-child(5) { --i: 4; }
  .a-svc:nth-child(6) { --i: 5; }
  .a-svc:nth-child(7) { --i: 6; }

  .a-svc:first-child { padding-block-start: 0; }

  /* Ветка начинается там, где кольцо садится на окружность, и кончается
     у общего края веера. Она же — опора своей карточки. */
  .a-svc__item {
    position: relative;
    flex: 1 1 auto;
    min-inline-size: 0;
    margin-inline-start: calc(var(--fan-cx) + var(--x));
    transform-origin: var(--fan-start) 50%;
    transition: scale var(--draw);
  }

  /* Раскрытая ветка выходит на первый план: встаёт над соседями и чуть
     подрастает от своего кольца — кольцо остаётся на конце спицы. */
  .a-svc__item[open] {
    z-index: 4;
    scale: 1.04;
    background-color: transparent;
    box-shadow: none;
  }

  /* Спица — луч из центра круга, видимый от дуги до кольца: начало
     закрыто полем, фон кладётся только на содержимое. */
  .a-svc__spoke,
  .a-svc:last-child > .a-svc__spoke {
    inset-block: var(--fan-cy) auto;
    inset-inline-start: var(--fan-cx);
    inline-size: calc(var(--fan-reach) * var(--fan-row) - var(--fan-node) / 2);
    block-size: 1px;
    margin-block-start: -0.5px;
    padding-inline-start: var(--fan-arc);
    background-clip: content-box;
    transform-origin: var(--fan-start) 50%;
    rotate: calc(var(--fan-dir) * asin(var(--dy) / var(--fan-reach)));
  }

  /* Узел на дуге, из которого выходит спица. */
  .a-svc__spoke::before {
    content: "";
    position: absolute;
    inset-block-start: calc(50% - 0.25rem);
    inset-inline-start: calc(var(--fan-arc) - 0.25rem);
    inline-size: 0.5rem;
    block-size: 0.5rem;
    border-radius: 50%;
    background-color: var(--fg-muted);
    transition: background-color var(--af-motion-base) var(--af-ease);
  }

  .a-svc:has(> .a-svc__item[open]) > .a-svc__spoke::before { background-color: var(--accent); }

  /* Таблетка лежит над своей карточкой: карточка — её продолжение вниз. */
  .a-svc__pill {
    z-index: 1;
    block-size: var(--fan-pill);
    min-block-size: 0;
    padding-block: 0;
    transform-origin: var(--fan-start) 50%;
  }

  /* Название не сжимается: на любой длине таблетки оно переносится одинаково. */
  .a-svc__title {
    flex: 0 0 var(--fan-label);
    font-size: 1.5rem;
    line-height: 1.15;
  }

  /* Пока одна ветка раскрыта, остальное отходит на фон: таблетки блекнут
     и чуть мельчают, круг, дуга и чужие спицы гаснут наполовину. Блекнет
     сама таблетка, а не ряд: прозрачный ряд отрезал бы стеклу кадр под ним. */
  .a-fan:has(.a-svc__item[open]) .a-svc__item:not([open]) > .a-svc__pill {
    opacity: 0.28;
    scale: 0.96;
  }

  .a-fan:has(.a-svc__item[open]) .a-fan__hub,
  .a-fan:has(.a-svc__item[open]) .a-fan__arc,
  .a-fan:has(.a-svc__item[open]) .a-svc:not(:has(> .a-svc__item[open])) > .a-svc__spoke { opacity: 0.45; }

  .a-fan:has(.a-svc__item[open]) .a-svc__item:not([open]) > .a-svc__pill:hover,
  .a-fan:has(.a-svc__item[open]) .a-svc__item:not([open]) > .a-svc__pill:focus-visible {
    opacity: 0.85;
    scale: 1;
  }

  /* Карточка — выпадающий список из таблетки: та же ширина и тот же
     радиус, таблетка шапкой сверху, текст разворачивается под ней поверх
     соседних веток. Высота растёт сеткой 0fr → 1fr на самой карточке:
     она вне потока, высота «Услуг» от раскрытия не меняется. У трёх
     нижних веток список разворачивается вверх — не выходит за низ веера. */
  .a-svc__body {
    --card-gap: 1.5rem;
    position: absolute;
    z-index: 0;
    inset-block: 0 auto;
    inset-inline: 0;
    display: grid;
    grid-template-rows: 0fr;
    padding-block: var(--fan-pill) 0;
    border: 1px solid var(--rule);
    border-radius: calc(var(--fan-pill) / 2);
    background: var(--panel);
    box-shadow: 0 1.75rem 3.5rem -1.25rem rgba(0, 0, 0, 0.6),
                0 0.5rem 1.25rem -0.5rem rgba(0, 0, 0, 0.35);
    transition: grid-template-rows var(--draw),
                padding-block var(--draw),
                opacity var(--af-motion-base) var(--af-ease);
  }

  .a-svc__item[open] .a-svc__body {
    grid-template-rows: 1fr;
    padding-block: var(--fan-pill) var(--card-gap);
    animation: a-svc-drop var(--draw);
  }

  .a-svc:nth-child(n + 5) .a-svc__body { inset-block: auto 0; padding-block: 0 var(--fan-pill); }

  .a-svc:nth-child(n + 5) .a-svc__item[open] .a-svc__body {
    padding-block: var(--card-gap) calc(var(--fan-pill) + 1.25rem);
    animation-name: a-svc-drop-up;
  }

  /* Вертикальные поля текста — внутри складываемой строки, иначе свёрнутая
     карточка была бы выше таблетки на эти поля. */
  .a-main .a-svc__text {
    min-block-size: 0;
    overflow: hidden;
    padding-block: 0;
    padding-inline: 1.75rem;
  }

  .a-svc__text::before { margin-block: 1.25rem 0.875rem; }
  .a-svc:nth-child(n + 5) .a-svc__text::before { margin-block-start: 0; }
}

/* Список выпадает из таблетки и разворачивается до своей высоты. */
@keyframes a-svc-drop {
  from { grid-template-rows: 0fr; padding-block: var(--fan-pill) 0; }
}

@keyframes a-svc-drop-up {
  from { grid-template-rows: 0fr; padding-block: 0 var(--fan-pill); }
}

/* ------------------------------------------------------------------ *
 * 9. Изображение
 * ------------------------------------------------------------------ */
.a-figure { margin: 0; }

.a-figure img {
  inline-size: 100%;
  block-size: auto;
  background: var(--panel);
}

/* ------------------------------------------------------------------ *
 * 10. Первый экран
 * ------------------------------------------------------------------ */
.a-hero { padding-block-start: clamp(2.25rem, 1.5rem + 3vw, 4rem); }

.a-hero__spec {
  /* Текст ключа уже прописной в обоих языках — второй раз его не поднимаем. */
  text-transform: none;
  letter-spacing: 0.05em;
  margin-block-end: clamp(1.5rem, 1.1rem + 1.6vw, 2.5rem);
  max-inline-size: none;
}

.a-hero .a-h1 { max-inline-size: 21ch; }

.a-hero__grid {
  display: grid;
  gap: clamp(2.25rem, 1.2rem + 4vw, 4.5rem);
  margin-block-start: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
  align-items: start;
}

/* ------------------------------------------------------------------ *
 * 11. Подход — линия с остановками; принципы — стеклянные карточки
 * ------------------------------------------------------------------ */
/* «Подход AxisForge» — линия с точками, как на референсе пользователя
   (docs/adr/0021): с 62em линия идёт по ширине блока, над каждой колонкой
   точка, под ней по центру название Prata и текст. Уже 62em — та же линия
   вертикальной осью вдоль начального края, текст — рядом с точкой.
   Линию собирают отрезки остановок (::after): каждый идёт от начала своей
   колонки до её конца, на оси — от своей точки до следующей, поэтому
   раздел 20 прорисовывает её по очереди, остановка за остановкой. */
.a-timeline[role="list"] {
  --tl-dot: 1rem;                                /* диаметр точки */
  --tl-y: calc(var(--t-h3) * 0.62);              /* центр первой строки названия */
  --tl-start: 0%;                                /* начальный край для transform-origin */
  display: grid;
  margin-block-start: clamp(2.5rem, 1.6rem + 3.4vw, 4.5rem);
}

[dir="rtl"] .a-timeline[role="list"] { --tl-start: 100%; }

.a-timeline__stop {
  position: relative;
  padding-inline-start: calc(var(--tl-dot) + 1.25rem);
  padding-block-end: clamp(1.75rem, 1.4rem + 1.4vw, 2.5rem);
}

.a-timeline__stop:last-child { padding-block-end: 0; }

/* Точка — на высоте первой строки названия. */
.a-timeline__stop::before {
  content: "";
  position: absolute;
  inset-block-start: calc(var(--tl-y) - var(--tl-dot) / 2);
  inset-inline-start: 0;
  inline-size: var(--tl-dot);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--fg-muted);
}

/* Отрезок оси — от своей точки до следующей: следующая стоит на той же
   высоте от верха своей остановки. У последней отрезка нет. */
.a-timeline__stop::after {
  content: "";
  position: absolute;
  inset-block: var(--tl-y) calc(var(--tl-y) * -1);
  inset-inline-start: calc(var(--tl-dot) / 2 - 0.75px);
  inline-size: 1.5px;
  background: var(--fg-muted);
  transform-origin: 50% 0;
}

.a-timeline__stop:last-child::after { content: none; }

.a-timeline__stop p {
  margin-block-start: 0.875rem;
  max-inline-size: 40ch;
  color: var(--fg-muted);
  font-size: var(--t-small);
  text-wrap: pretty;
}

/* -- Принципы: стеклянные карточки с номером ------------------------- */
/* Четыре принципа лежат на кадре сцены карточками из того же стекла, что
   таблетки и круг «Услуг» (--btn-glass, --btn-ring), радиусом раскрытой
   карточки услуги. Наверху заголовок и текст, внизу у конечного края —
   крупный контурный номер, который срезает нижняя кромка карточки.
   Номер не акцентный: акцентом идут только номера этапов «Процесса»,
   а этот — рисунок карточки, а не шаг маршрута. */
.a-tenets[role="list"] {
  counter-reset: tenet;
  display: grid;
  gap: clamp(0.875rem, 0.6rem + 1vw, 1.5rem);
}

.a-tenet {
  counter-increment: tenet;
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  overflow: hidden;
  /* Поле — как у текста раскрытой карточки услуги. Снизу его нет:
     там номер, и срезает его сама кромка. */
  padding: 1.75rem;
  padding-block-end: 0;
  border: 1px solid var(--btn-ring);
  border-radius: 1.75rem;
  background-color: var(--btn-glass);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.a-tenet p {
  color: var(--fg-muted);
  font-size: var(--t-small);
  text-wrap: pretty;
}

/* Метрики Prata при line-height 1: цифра занимает 0.82em от верха строки
   до базовой линии, под ней ещё 0.185em строки. Отрицательное поле
   −0.435em уводит под кромку четверть em цифры — видно около 70 % её
   высоты. Номер — последний в колонке и уходит вниз полем auto, поэтому
   в ряду карточек одной высоты номера стоят на одной линии. */
.a-tenet__no {
  align-self: flex-end;
  margin-block: auto -0.435em;
  padding-block-start: 0.5rem;
  font-family: var(--font-display);
  font-size: clamp(5.5rem, 3.6rem + 5vw, 8.5rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: lining-nums tabular-nums;
  /* Стекло сквозь цифру: почти прозрачная заливка и волосяной контур.
     Без text-stroke остаётся только заливка — бледный, но видный номер. */
  color: color-mix(in srgb, var(--fg) 8%, transparent);
  -webkit-text-stroke: 1px var(--rule-strong);
  text-shadow: none;
}

.a-tenet__no::before { content: counter(tenet, decimal-leading-zero); }

/* -- Цифры перед заголовком услуг ------------------------------------ */
/* Колонки без линеек: ни волосяных разделителей, ни штриха над числом —
   колонки разводит только промежуток сетки. Набор — как у карточек
   «Принципов»: число и к чему оно гарнитурой заголовков, подпись текстовой.
   Число без акцента: акцентом на странице идут только номера этапов,
   и цифры не должны читаться нумерацией. */
.a-stats[role="list"] {
  display: grid;
  gap: clamp(2rem, 1.5rem + 2vw, 3rem) clamp(2rem, 4.8vw, 4.5rem);
  margin-block-end: clamp(3rem, 2rem + 4vw, 5.5rem);
}

.a-stat__value {
  display: block;
  font-family: var(--font-display);
  font-size: clamp(2.875rem, 2.1rem + 3.2vw, 4.75rem);
  line-height: 1;
  letter-spacing: -0.02em;
  font-variant-numeric: lining-nums;
}

.a-stat__unit {
  display: block;
  margin-block-start: 0.625rem;
  font-family: var(--font-display);
  font-size: var(--t-h3);
  line-height: 1.24;
  text-wrap: balance;
}

.a-stat__caption {
  margin-block-start: 0.75rem;
  color: var(--fg-muted);
  font-size: var(--t-small);
}

/* -- Сноска к подписи ------------------------------------------------- */
/* Подпись-кнопка: наведение, фокус с клавиатуры и касание (на тач-экране
   его ловит :hover) открывают сноску мелким кеглем под подписью. Сноска
   лежит в разметке и без JS, а кнопка ссылается на неё aria-describedby —
   диктор прочтёт её сразу за подписью. */
.a-hint { position: relative; }

.a-hint__term {
  /* Кнопка не наследует набор сама: подпись набрана так же, как соседние. */
  padding-block: 0.875rem;
  padding-inline: 0;
  margin-block: -0.875rem;
  border: 0;
  background: none;
  text-align: inherit;
  line-height: inherit;
  text-shadow: inherit;
  cursor: help;
  text-decoration: underline dotted;
  text-decoration-color: var(--rule-strong);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.35em;
  transition: color var(--af-motion-fast) var(--af-ease),
              text-decoration-color var(--af-motion-fast) var(--af-ease);
}

/* Звёздочка — знак сноски. inline-block, чтобы под ней не шла точечная линия. */
.a-hint__term::after {
  content: "*";
  display: inline-block;
  margin-inline-start: 0.2em;
  color: var(--accent);
}

.a-hint__term:hover,
.a-hint__term:focus {
  color: var(--fg);
  text-decoration-color: var(--line);
}

/* Верхний отступ — мостик: указатель переходит с подписи на сноску,
   не роняя её. */
.a-hint__note {
  position: absolute;
  z-index: 2;
  inset-block-start: 100%;
  inset-inline-start: 0;
  inline-size: min(21rem, 100%);
  padding-block-start: 0.75rem;
  visibility: hidden;
  opacity: 0;
  transform: translate3d(0, -0.25rem, 0);
  transition: opacity var(--af-motion-fast) var(--af-ease),
              transform var(--af-motion-fast) var(--af-ease),
              visibility 0s linear var(--af-motion-fast);
}

.a-hint__term:hover + .a-hint__note,
.a-hint__term:focus + .a-hint__note,
.a-hint__note:hover {
  visibility: visible;
  opacity: 1;
  transform: none;
  transition-delay: 0s;
}

.a-hint__text {
  display: block;
  padding-block: 0.75rem;
  padding-inline: 1rem;
  background: var(--panel);
  border: 1px solid var(--rule);
  color: var(--fg);
  font-size: 0.75rem;
  line-height: 1.5;
  text-shadow: none;
  text-wrap: pretty;
}

.a-hint__text::before {
  content: "*\00a0";
  color: var(--accent);
}

/* ------------------------------------------------------------------ *
 * 12. Маршрут «Процесс» — змейка этапов, единственная акцентная нумерация
 *
 * Этап — нативный <details name="process">: название — <summary>, под ним
 * пояснение, открыто не больше одного. Номер рисует счётчик, в copy.js
 * номеров нет.
 *
 * Уже 62em маршрут — вертикальная ось от звезды к звезде: узлы нанизаны
 * на неё, пояснение раскрывается под названием и раздвигает соседей.
 * С 62em — змейка, как на эскизе (docs/adr/0019): линия — SVG в координатах
 * 1000 × 660, коробка маршрута держит ту же пропорцию, а узлы и звёзды
 * стоят в тех же координатах (--x, --y) — на любой ширине они на линии.
 * Пояснение выпадает карточкой поверх соседей, а они блекнут: этапы вне
 * потока, высота «Процесса» от нажатия не меняется, кадр сцены не прыгает.
 *
 * Узел горит, когда до него дошла прорисовка линии: --at — его доля пути,
 * --lit считает раздел 20 по --af-scrub. Без движения горит всё.
 * ------------------------------------------------------------------ */
.a-route {
  --node: 2.75rem;      /* диаметр узла */
  --star: 1.5rem;       /* звезда в начале и в конце пути */
  --node-gap: 0.75rem;  /* от узла до названия */
  position: relative;
}

/* Линия змейки нужна только змейке. */
.a-route__path { display: none; }

.a-route__steps[role="list"] {
  position: relative;
  counter-reset: step;
  padding-block: calc(var(--star) + 0.75rem);
}

/* Ось от звезды до звезды и её прорисованная часть поверх. */
.a-route__steps::before,
.a-route__steps::after {
  content: "";
  position: absolute;
  inset-block: calc(var(--star) / 2);
  inset-inline-start: calc(var(--node) / 2 - 0.75px);
  inline-size: 1.5px;
  background: var(--rule-strong);
}

.a-route__steps::after {
  background: var(--fg);
  transform-origin: 50% 0;
}

/* Восьмиконечная звезда — начало и конец пути, как на эскизе: два
   квадрата, второй повёрнут на 45°. Сторона квадрата — 1/√2 коробки,
   поэтому лучи обоих касаются её краёв. */
.a-route__star {
  position: absolute;
  z-index: 1;
  inset-block-start: 0;
  inset-inline-start: calc(var(--node) / 2 - var(--star) / 2);
  inline-size: var(--star);
  aspect-ratio: 1;
  transition: opacity var(--draw);
}

.a-route__star::before,
.a-route__star::after {
  content: "";
  position: absolute;
  inset: 14.645%;
  background: var(--fg);
}

.a-route__star::after { transform: rotate(45deg); }

.a-route__star--end { inset-block: auto 0; }

.a-step {
  counter-increment: step;
  padding-block: 0.75rem;
}

.a-step:nth-child(1) { --at: 0.14; }
.a-step:nth-child(2) { --at: 0.28; }
.a-step:nth-child(3) { --at: 0.42; }
.a-step:nth-child(4) { --at: 0.57; }
.a-step:nth-child(5) { --at: 0.71; }
.a-step:nth-child(6) { --at: 0.85; }

/* Название — строкой рядом с узлом: первая строка на высоте его центра. */
.a-step__head {
  position: relative;
  display: block;
  min-block-size: var(--node);
  padding-block-start: calc(var(--node) / 2 - 0.6em);
  padding-inline-start: calc(var(--node) + var(--node-gap));
  color: var(--fg);
  font-size: var(--t-h3);
  line-height: 1.2;
  text-wrap: balance;
  list-style: none;
  cursor: pointer;
}

.a-step__head::-webkit-details-marker { display: none; }

/* Узел: кольцо на тёмной подложке, номер — Prata. Загоревшийся залит
   акцентом, номер на нём угольный. Подложка глухая — линия под узлом
   не просвечивает. */
.a-step__no {
  position: absolute;
  z-index: 1;
  inset-block-start: 0;
  inset-inline-start: 0;
  isolation: isolate;
  display: grid;
  place-items: center;
  inline-size: var(--node);
  block-size: var(--node);
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--panel);
  font-family: var(--font-display);
  font-size: calc(var(--node) * 0.42);
  line-height: 1;
  font-variant-numeric: tabular-nums;
  text-shadow: none;
  filter: brightness(calc(0.3 + 0.7 * var(--dim, 1)));
  transition: filter var(--af-motion-base) var(--af-ease);
}

.a-step__no::before {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  border-radius: 50%;
  background: var(--accent);
  opacity: var(--lit, 1);
}

.a-step__no::after {
  content: counter(step);
  color: color-mix(in srgb, var(--charcoal) calc(var(--lit, 1) * 100%), var(--fg-muted));
}

.a-step__title {
  position: relative;
  padding-inline-end: calc(0.4em + 0.875rem);
  letter-spacing: -0.004em;
  opacity: var(--dim, 1);
  transition: color var(--af-motion-base) var(--af-ease),
              opacity var(--af-motion-base) var(--af-ease);
}

/* Плюс из двух волосяных линий, как у веток «Услуг»; у раскрытого этапа —
   крестик. Стоит в концевом поле названия: поле переносится вместе
   с последним словом, и плюс никогда не уходит на строку один. Это
   ::before, а не ::after: Chrome даёт разрыв строки перед вынесенным
   из потока элементом, и в конце названия он отрывал бы поле от слова. */
.a-step__title::before {
  content: "";
  position: absolute;
  inset-inline-end: 0;
  inset-block-end: 0.3em;
  inline-size: 0.875rem;
  block-size: 0.875rem;
  background: linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat,
              linear-gradient(currentColor, currentColor) center / 1px 100% no-repeat;
  color: var(--fg-muted);
  transition: transform var(--draw),
              color var(--af-motion-base) var(--af-ease);
}

@media (hover: hover) {
  .a-step__head:hover .a-step__title,
  .a-step__head:hover .a-step__title::before { color: var(--accent); }
}

.a-step__item[open] > .a-step__head .a-step__title::before {
  color: var(--accent);
  transform: rotate(45deg);
}

/* Пока один этап раскрыт, остальные отступают, но остаются под рукой:
   название блекнет, узел темнеет. Узел гасят яркостью, а не прозрачностью —
   иначе сквозь него проступила бы линия. */
.a-route:has(.a-step__item[open]) .a-step__item:not([open]) > .a-step__head { --dim: 0.62; }
.a-route:has(.a-step__item[open]) .a-step__item:not([open]) > .a-step__head:hover,
.a-route:has(.a-step__item[open]) .a-step__item:not([open]) > .a-step__head:focus-visible { --dim: 1; }

/* Высота раскрывается сеткой 0fr → 1fr, как у веток «Услуг» (раздел 8). */
.a-step__item::details-content {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--draw);
  transition: grid-template-rows var(--draw),
              content-visibility var(--draw) allow-discrete;
}

.a-step__item[open]::details-content { grid-template-rows: 1fr; }

.a-step__body {
  min-block-size: 0;
  overflow: hidden;
  transition: opacity var(--af-motion-base) var(--af-ease);
}

.a-step__item:not([open]) .a-step__body { opacity: 0; }

/* Сверху пояснения — латунный штрих, как над текстом карточки услуги. */
.a-main .a-step__result {
  margin: 0;
  padding-block: 0.875rem 0.5rem;
  padding-inline-start: calc(var(--node) + var(--node-gap));
  color: var(--fg-muted);
  font-size: var(--t-small);
  line-height: 1.55;
  text-wrap: pretty;
}

.a-step__result::before {
  content: "";
  display: block;
  inline-size: 2.5rem;
  block-size: 1px;
  margin-block-end: 0.75rem;
  background: var(--brass);
}

.a-step__item[open] .a-step__result { animation: a-step-text var(--draw) 90ms backwards; }

@keyframes a-step-text {
  from { opacity: 0; transform: translate3d(0, 0.5rem, 0); }
}

/* -- Змейка ---------------------------------------------------------- */
/* Четыре прогона и три полукруглых поворота: узлы 1, 3, 5 стоят на
   прогонах, название под узлом; узлы 2, 4, 6 — на вершинах поворотов,
   название рядом с узлом. Справа от змейки — поле для названий 2 и 6,
   поворот слева заключает название 4. Координаты узлов — те же числа,
   что в пути SVG; --at — доля пути до узла. */
@media (min-width: 62em) {
  .a-route {
    --node: 3rem;
    --star: 1.75rem;
    --node-gap: 0.875rem;
    --card-pad: 1.375rem;  /* на столько подложка карточки выходит за поле этапа */
    aspect-ratio: 1000 / 660;
    margin-inline-start: calc(var(--node) / 2);
  }

  .a-route__path {
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 0;
    display: block;
    inline-size: 100%;
    block-size: 100%;
    overflow: visible;
    fill: none;
    stroke-width: 1.5;
    transition: opacity var(--draw);
  }

  /* SVG не знает направления письма: в RTL змейку зеркалим руками. */
  [dir="rtl"] .a-route__path { transform: scaleX(-1); }

  .a-route__line { stroke: var(--rule-strong); }
  .a-route__ink { stroke: var(--fg); stroke-dasharray: 1; }

  /* Этапы меряются от коробки маршрута, ось им не нужна. */
  .a-route__steps[role="list"] { position: static; padding-block: 0; }
  .a-route__steps::before,
  .a-route__steps::after { content: none; }

  .a-route__star {
    inset-block-start: calc(40 / 660 * 100%);
    inset-inline-start: calc(120 / 1000 * 100%);
    margin-block-start: calc(var(--star) / -2);
    margin-inline-start: calc(var(--star) / -2);
  }

  .a-route__star--end {
    inset-block-start: calc(610 / 660 * 100%);
    inset-inline-start: calc(300 / 1000 * 100%);
  }

  /* Коробка этапа — поле названия и пояснения; узел вынесен из неё
     на линию. Она же — подложка раскрытой карточки (::before). */
  .a-step {
    --nx: calc(var(--x) / 1000 * 100%);
    --ny: calc(var(--y) / 660 * 100%);
    position: absolute;
    z-index: 1;
    padding-block: 0;
  }

  .a-step:nth-child(1) { --x: 380; --y: 40;  --at: 0.1060; }
  .a-step:nth-child(2) { --x: 700; --y: 135; --at: 0.2428; }
  .a-step:nth-child(3) { --x: 380; --y: 230; --at: 0.3796; }
  .a-step:nth-child(4) { --x: 0;   --y: 325; --at: 0.5384; }
  .a-step:nth-child(5) { --x: 380; --y: 420; --at: 0.6971; }
  .a-step:nth-child(6) { --x: 700; --y: 515; --at: 0.8339; }

  /* На прогоне: название под узлом, от его начального края до поворота. */
  .a-step:nth-child(odd) {
    inset-block-start: calc(var(--ny) + var(--node) / 2 + var(--node-gap));
    inset-inline-start: calc(var(--nx) - var(--node) / 2);
    inline-size: calc(290 / 1000 * 100%);
  }

  .a-step:nth-child(odd) .a-step__no {
    inset-block-start: calc(-1 * (var(--node) + var(--node-gap)));
    inset-inline-start: 0;
  }

  /* На вершине поворота: название рядом, первая строка — на высоте узла. */
  .a-step:nth-child(even) {
    inset-block-start: calc(var(--ny) - var(--node) / 2);
    inset-inline-start: calc(var(--nx) + var(--node) / 2 + var(--node-gap));
    inline-size: calc(30% - var(--node) / 2 - var(--node-gap) - var(--card-pad));
  }

  .a-step:nth-child(4) { inline-size: calc(38% - var(--node) - 2 * var(--node-gap)); }


  .a-step:nth-child(even) .a-step__no {
    inset-block-start: 0;
    inset-inline-start: calc(-1 * (var(--node) + var(--node-gap)));
  }

  /* Узел меряется от коробки этапа, а не от названия. */
  .a-step__head {
    position: static;
    min-block-size: 0;
    padding: 0;
  }

  .a-step:nth-child(even) .a-step__head { padding-block-start: calc(var(--node) / 2 - 0.6em); }

  /* Раскрытый этап — карточка поверх соседей: подложка выходит за поле
     названия и пояснения, узел остаётся на линии и прижимает её край. */
  .a-step::before {
    content: "";
    position: absolute;
    inset-block: -1.125rem;
    inset-inline: calc(-1 * var(--card-pad));
    z-index: -1;
    border: 1px solid var(--rule);
    border-radius: 1.25rem;
    background: var(--panel);
    box-shadow: 0 1.75rem 3.5rem -1.25rem rgba(0, 0, 0, 0.6),
                0 0.5rem 1.25rem -0.5rem rgba(0, 0, 0, 0.35);
    opacity: 0;
    transition: opacity var(--af-motion-base) var(--af-ease);
  }

  .a-step:has(> .a-step__item[open]) {
    z-index: 3;
    text-shadow: none;
  }

  .a-step:has(> .a-step__item[open])::before { opacity: 1; }

  .a-main .a-step__result {
    padding-block: 1rem 0;
    padding-inline-start: 0;
    color: var(--fg);
  }

  /* Пока один этап раскрыт, остальное отходит на фон: названия и узлы
     блекнут, линия и звёзды гаснут наполовину. */
  .a-route:has(.a-step__item[open]) .a-step__item:not([open]) > .a-step__head { --dim: 0.28; }

  .a-route:has(.a-step__item[open]) .a-route__path,
  .a-route:has(.a-step__item[open]) .a-route__star { opacity: 0.45; }

  .a-route:has(.a-step__item[open]) .a-step__item:not([open]) > .a-step__head:hover,
  .a-route:has(.a-step__item[open]) .a-step__item:not([open]) > .a-step__head:focus-visible { --dim: 0.85; }
}

/* ------------------------------------------------------------------ *
 * 13. Риски: пары кругов «что может пойти не так / как мы это держим»
 * ------------------------------------------------------------------ */
/* Риск — угольный круг, ответ на него — светлый круг того же диаметра,
   положенный поверх со сдвигом к концу строки и вниз. Вся геометрия
   в долях диаметра --risk-d, и кегль внутри круга тоже идёт от него:
   пара масштабируется целиком, как рисунок, и строки в кругах
   переносятся одинаково на любой ширине. Пол кегля держит телефон.
   Текст угольного круга стоит в той его части, которую не закрывает
   светлый: его поля посчитаны от сдвига (--risk-dx, --risk-dy) так,
   чтобы угол коробки текста отстоял от обеих окружностей не меньше
   чем на 0.04 диаметра. Меняете сдвиг — пересчитывайте поля.
   До 36em светлый круг ложится почти под угольный; с 36em — по
   диагонали, пары идут столбиком лесенкой; с 80em — четыре пары
   в два ряда со сдвигом второго ряда, как на эскизе. */
.a-risks[role="list"] {
  /* Диаметр считается от ширины списка, а не окна. */
  container-type: inline-size;
  display: flex;
  flex-direction: column;
  /* Свет падает сверху с конечной стороны: там блик и яркая кромка. */
  --risk-lit: 70%;
  --risk-rim: 225deg;
}

[dir="rtl"] .a-risks[role="list"] { --risk-lit: 30%; --risk-rim: 135deg; }

/* Уже 22.5em круг сдвинут меньше и кегль опускается до 13px: иначе
   самый длинный ответ (r1, по-русски) выходит за край светлого круга. */
.a-risk {
  --risk-d: min(22rem, 100cqi / (1 + var(--risk-dx)));
  --risk-dx: 0.04;
  --risk-dy: 0.8;
  --risk-floor: 0.8125rem;
  display: grid;
  inline-size: calc(var(--risk-d) * (1 + var(--risk-dx)));
}

@media (min-width: 22.5em) {
  .a-risk { --risk-dx: 0.1; --risk-floor: 0.875rem; }
}

.a-risk + .a-risk { margin-block-start: calc(var(--risk-d) * 0.08); }

.a-risk__disc {
  grid-area: 1 / 1;
  align-self: start;
  justify-self: start;
  display: flex;
  flex-direction: column;
  justify-content: center;
  inline-size: var(--risk-d);
  aspect-ratio: 1;
  border-radius: 50%;
  font-size: max(var(--risk-floor), var(--risk-d) * 0.045);
  line-height: 1.45;
}

.a-risk__disc--need {
  /* Песок, приглушённый к углю, а не --sand-muted: стекло пропускает
     бумагу, грунт светлее чистого угля, и приглушённому песку не хватило
     бы контраста. */
  --fg: var(--sand);
  --fg-muted: color-mix(in srgb, var(--sand) 72%, var(--charcoal));
  --risk-rim-hi: rgba(237, 231, 220, 0.75);
  --risk-rim-lo: rgba(237, 231, 220, 0.24);
  padding-block: calc(var(--risk-d) * 0.15) calc(var(--risk-d) * 0.25);
  padding-inline: calc(var(--risk-d) * 0.19);
  background:
    radial-gradient(90% 70% at var(--risk-lit) 0%, rgba(237, 231, 220, 0.2), rgba(237, 231, 220, 0) 60%),
    radial-gradient(70% 45% at calc(100% - var(--risk-lit)) 100%, rgba(237, 231, 220, 0.08), rgba(237, 231, 220, 0) 70%),
    color-mix(in srgb, var(--charcoal) 88%, transparent);
  box-shadow:
    inset 0 0 0.5rem rgba(237, 231, 220, 0.14),
    inset 0 0 2rem rgba(237, 231, 220, 0.06),
    0 1.5rem 3rem -1.25rem rgba(33, 31, 28, 0.42);
  color: var(--fg);
}

/* Светлый круг лежит на угольном: сквозь матовое стекло угольный круг
   проступает размытой тенью. Стекло плотное (0.84): над угольным, где
   стекло темнее всего, приглушённый текст держит 4.8:1. */
.a-risk__disc--control {
  --risk-rim-hi: rgba(255, 255, 255, 0.95);
  --risk-rim-lo: rgba(255, 255, 255, 0.6);
  margin-block-start: calc(var(--risk-d) * var(--risk-dy));
  margin-inline-start: calc(var(--risk-d) * var(--risk-dx));
  padding-block: calc(var(--risk-d) * 0.17);
  padding-inline: calc(var(--risk-d) * 0.15);
  background:
    radial-gradient(90% 70% at var(--risk-lit) 0%, rgba(255, 255, 255, 0.75), rgba(255, 255, 255, 0) 62%),
    color-mix(in srgb, var(--panel) 84%, transparent);
  box-shadow:
    inset 0 0 0.375rem rgba(255, 255, 255, 0.9),
    inset 0 0 1.75rem rgba(255, 255, 255, 0.55),
    inset 0 -0.75rem 1.5rem -1rem rgba(33, 31, 28, 0.14),
    0 0 0 1px rgba(33, 31, 28, 0.05),
    0 1.5rem 3rem -1.25rem rgba(33, 31, 28, 0.34),
    0 0.25rem 0.75rem -0.25rem rgba(33, 31, 28, 0.1);
  color: var(--fg);
}

/* -- Матовое жидкое стекло ------------------------------------------- */
/* Оба круга — стекло: фон за ними размыт (backdrop-filter), сверху со
   стороны света — блик, напротив внизу — слабый отсвет, вдоль края изнутри —
   узкая светлая полоса преломления и широкое свечение (inset-тени выше), по кромке — кольцо блика, яркое со стороны света
   и слабее с противоположной (::before), поверх — мелкое зерно матовой
   поверхности (::after). Оба слоя лежат под текстом: круг изолирован,
   слои стоят в нём на z-index −1.
   Без backdrop-filter стекло остаётся плотной тонировкой — текст читается. */
.a-risk__disc {
  position: relative;
  isolation: isolate;
  -webkit-backdrop-filter: blur(1.25rem) saturate(1.5);
  backdrop-filter: blur(1.25rem) saturate(1.5);
}

/* Кольцо — градиент в рамке 2px: маска вырезает всё, кроме полей. */
.a-risk__disc::before,
.a-risk__disc::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  pointer-events: none;
}

.a-risk__disc::before {
  padding: 2px;
  background: linear-gradient(var(--risk-rim), var(--risk-rim-hi), transparent 32%, transparent 68%, var(--risk-rim-lo));
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}

/* Зерно — шум feTurbulence без цвета. Скобки и решётка внутри SVG
   закодированы: tools/one-file.mjs принял бы url(#n) за путь к файлу. */
.a-risk__disc::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E");
  background-size: 10rem;
  mix-blend-mode: soft-light;
  opacity: 0.5;
}

/* Под парой — два мягких пятна материалов борда: стеклу на ровной бумаге
   нечего было бы размывать. Пятно чуть выходит из-под круга со стороны
   от соседа — по кромке стекла видно, что за ним цвет, а внутри он
   размыт. Пятна — на фоне пары (z-index −1 в изолированной паре). */
.a-risk {
  position: relative;
  isolation: isolate;
  --risk-tint-a: var(--mat-wd01);
  --risk-tint-b: var(--mat-mt03);
}

.a-risk:nth-child(2) { --risk-tint-a: var(--mat-pt10); --risk-tint-b: var(--mat-st02); }
.a-risk:nth-child(3) { --risk-tint-a: var(--mat-wd06); --risk-tint-b: var(--mat-pt10); }
.a-risk:nth-child(4) { --risk-tint-a: var(--mat-mt03); --risk-tint-b: var(--mat-wd01); }

/* Вне потока: пятна не раздвигают пару. */
.a-risk::before,
.a-risk::after {
  content: "";
  position: absolute;
  z-index: -1;
  inline-size: calc(var(--risk-d) * 0.9);
  aspect-ratio: 1;
  border-radius: 50%;
  pointer-events: none;
}

.a-risk::before {
  inset-block-start: calc(var(--risk-d) * -0.1);
  inset-inline-start: calc(var(--risk-d) * -0.1);
  background: radial-gradient(closest-side, color-mix(in srgb, var(--risk-tint-a) 60%, transparent), transparent);
}

.a-risk::after {
  inset-block-start: calc(var(--risk-d) * (var(--risk-dy) + 0.2));
  inset-inline-start: calc(var(--risk-d) * (var(--risk-dx) + 0.2));
  background: radial-gradient(closest-side, color-mix(in srgb, var(--risk-tint-b) 55%, transparent), transparent);
}

.a-risk__label {
  font-size: 1.3em;
  line-height: 1.15;
  letter-spacing: -0.004em;
  text-wrap: balance;
}

.a-risk__text {
  margin-block-start: 0.6em;
  color: var(--fg-muted);
  text-wrap: pretty;
}

/* Лесенка столбиком: столбик не шире двух ступеней, по центру блока. */
@media (min-width: 36em) {
  .a-risks[role="list"] {
    max-inline-size: 46.75rem;
    margin-inline: auto;
  }

  .a-risk { --risk-dx: 0.6; --risk-dy: 0.42; }

  .a-risk:nth-child(even) {
    margin-inline-start: min(var(--risk-d) * 0.52, 100% - var(--risk-d) * 1.6);
  }

  .a-risk__disc--need {
    padding-block: calc(var(--risk-d) * 0.2) calc(var(--risk-d) * 0.24);
    padding-inline: calc(var(--risk-d) * 0.15) calc(var(--risk-d) * 0.4);
  }
}

/* Два ряда, как на эскизе: все пары в одной ячейке сетки, каждая на своём
   месте в диаметрах. Второй ряд сдвинут на полдиаметра к концу строки,
   его угольные круги встают под светлые первого ряда. Ширина рисунка —
   3.76 диаметра, высота — 3.12. */
@media (min-width: 80em) {
  .a-risks[role="list"] {
    display: grid;
    justify-content: center;
    max-inline-size: none;
  }

  .a-risk { --risk-d: min(22rem, 100cqi / 3.76); grid-area: 1 / 1; }

  .a-risk:nth-child(1) { margin-block-start: 0; margin-inline-start: 0; }
  .a-risk:nth-child(2) { margin-block-start: calc(var(--risk-d) * 0.14); margin-inline-start: calc(var(--risk-d) * 1.64); }
  .a-risk:nth-child(3) { margin-block-start: calc(var(--risk-d) * 1.48); margin-inline-start: calc(var(--risk-d) * 0.52); }
  .a-risk:nth-child(4) { margin-block-start: calc(var(--risk-d) * 1.7); margin-inline-start: calc(var(--risk-d) * 2.16); }
}

/* ------------------------------------------------------------------ *
 * 14. Фильтры и карточки объектов
 * ------------------------------------------------------------------ */
.a-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 0.625rem;
  padding-block-end: 1.25rem;
  border-block-end: 1px solid var(--rule);
  margin-block-end: clamp(2rem, 1.4rem + 2.4vw, 3.5rem);
}

.a-filter {
  display: inline-flex;
  align-items: center;
  gap: 0.625rem;
  padding-block: 0.5rem;
  padding-inline: 1.125rem;
  min-block-size: 2.75rem;
  min-inline-size: 2.75rem;
  font-family: var(--font-text);
  font-size: var(--t-spec);
  font-weight: 500;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.a-filter .a-chip { block-size: 0.875rem; inline-size: 0.5rem; }

.a-filter:hover,
.a-filter:focus-visible { color: var(--fg); }

/* Выбранный фильтр — залитое тело вместо стеклянного: подчёркивания у
   таблетки нет, состояние держит сама заливка. */
.a-filter.is-current { color: var(--btn-fg); }
.a-filter.is-current::after {
  background: var(--btn-bg);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.a-folio {
  --a-folio-gap: clamp(2.5rem, 1.6rem + 3.4vw, 4.5rem);
  display: grid;
  gap: var(--a-folio-gap);
}

/* Объект, выбранный фильтром, — крупнее: в одну колонку фото выходит
   из полей к краям экрана, в две карточка встаёт по центру ряда в 1.25
   ширины колонки, до 780 px (раздел 18). Крупнее не делаем: кадры
   портфолио — 1600 px по длинной стороне (tools/folio-render.mjs), их
   хватает на 800 px при dpr 2. Размер меняется раскладкой, а не transform:
   фото рисуется из исходника в новом размере и не мылится. Рост — раздел 20. */
.a-card[data-af-project-state="solo"] .a-reel { margin-inline: calc(var(--gutter) * -1); }

.a-card {
  position: relative;
  padding-block-start: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  border-block-start: 1px solid var(--rule);
}

.a-card::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline-start: 0;
  inline-size: 0;
  block-size: 1px;
  background: var(--line);
  transition: inline-size var(--draw);
}

.a-card:hover::before { inline-size: 100%; }

/* Название объекта — подпись под фото, без машинописной метки над ним. */
.a-card__name { margin-block-start: 1.25rem; }

/* -- Карусель фотографий объекта ------------------------------------ */
/* Рамка 3:2 — ровно по горизонтальному кадру, и он заполняет её целиком.
   Вертикальный кадр встаёт по центру на подложку, как отпечаток на паспарту:
   фотографию заказчика не обрезаем ни с одной стороны. */
.a-reel {
  position: relative;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: var(--panel);
}

/* Без JS лента — обычная горизонтальная прокрутка со щелчком по кадру:
   все фотографии доступны пальцем, колесом и полосой прокрутки. */
.a-reel__track {
  display: flex;
  block-size: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
  scrollbar-color: var(--rule-strong) transparent;
}

.a-reel__slide {
  flex: 0 0 100%;
  block-size: 100%;
  scroll-snap-align: start;
}

.a-reel__slide img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  -webkit-user-select: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* С JS прокрутку заменяет сдвиг: site.js пишет --af-carousel — дробный номер
   кадра, видимого прямо сейчас, и ведёт его пружиной. Направление сдвига
   физическое, поэтому RTL зеркалится отдельным правилом. Вертикальная
   прокрутка страницы остаётся браузеру, горизонтальный жест — свайп. */
.a-reel[data-af-carousel-state="ready"] { touch-action: pan-y; }

.a-reel[data-af-carousel-state="ready"] .a-reel__track {
  overflow: visible;
  scroll-snap-type: none;
  transform: translate3d(calc(var(--af-carousel, 0) * -100%), 0, 0);
  will-change: transform;
}

[dir="rtl"] .a-reel[data-af-carousel-state="ready"] .a-reel__track {
  transform: translate3d(calc(var(--af-carousel, 0) * 100%), 0, 0);
}

/* Стрелки — круглые жетоны поверх фотографии. Кант с бегущим бликом
   (раздел 6) им не положен: это не кнопки страницы, а ручки самого кадра,
   и шесть вращающихся бликов над тремя фотографиями спорили бы с ними.
   Тень здесь — исключение из «линий вместо теней»: жетон должен
   отделяться и от белой стены виллы, и от тёмного санузла ресторана. */
.a-reel__btn {
  position: absolute;
  z-index: 1;
  inset-block-start: 50%;
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  margin-block-start: -1.375rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--sand);
  color: var(--charcoal);
  box-shadow: 0 0.375rem 1.25rem rgba(20, 18, 15, 0.3);
  opacity: 0.72;
  transition: transform var(--af-motion-base) var(--af-ease),
              opacity var(--af-motion-base) var(--af-ease);
}

.a-reel__btn--prev { inset-inline-start: clamp(0.625rem, 0.4rem + 1vw, 1rem); }
.a-reel__btn--next { inset-inline-end: clamp(0.625rem, 0.4rem + 1vw, 1rem); }

.a-reel__btn svg {
  inline-size: 1.375rem;
  block-size: 1.375rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* Шеврон смотрит туда, куда поедет лента: в RTL «вперёд» — влево. */
[dir="rtl"] .a-reel__btn svg { transform: scaleX(-1); }

.a-reel__btn:focus-visible { opacity: 1; }

@media (hover: hover) {
  .a-reel__btn:hover { opacity: 1; transform: scale(1.1); }
}

.a-reel__btn[aria-disabled="true"] {
  opacity: 0.32;
  transform: none;
  cursor: not-allowed;
}

/* Точки: идущий кадр вытягивается в черту. Подложка под ними держит
   их видимыми и на белой стене, и на тёмном кадре. Кнопки точек создаёт
   site.js, своих классов у них нет. Цель нажатия у точки 16×24 px — на
   телефоне в ряд встают 14 штук; полноразмерную цель 44 px дают стрелки
   и сам свайп, которые делают то же самое. */
.a-reel__dots {
  position: absolute;
  z-index: 1;
  inset-block-end: clamp(0.625rem, 0.4rem + 1vw, 1rem);
  inset-inline: 0;
  display: flex;
  inline-size: fit-content;
  max-inline-size: calc(100% - 1.5rem);
  margin-inline: auto;
  padding-inline: 0.375rem;
  border-radius: 999px;
  background: rgba(20, 18, 15, 0.38);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
}

.a-reel__dots > button {
  display: grid;
  place-items: center;
  flex: none;
  inline-size: 1rem;
  block-size: 1.5rem;
  padding: 0;
  border: 0;
  background: none;
  transition: inline-size var(--af-motion-base) var(--af-ease);
}

.a-reel__dots > button::before {
  content: "";
  inline-size: 0.5rem;
  block-size: 0.5rem;
  border-radius: 999px;
  background: rgba(237, 231, 220, 0.5);
  transition: inline-size var(--af-motion-base) var(--af-ease),
              background var(--af-motion-base) var(--af-ease);
}

.a-reel__dots > button[aria-current="true"] { inline-size: 2.5rem; }
.a-reel__dots > button[aria-current="true"]::before {
  inline-size: 2rem;
  background: var(--sand);
}

@media (hover: hover) {
  .a-reel__dots > button:hover::before { background: rgba(237, 231, 220, 0.85); }
  .a-reel__dots > button[aria-current="true"]:hover::before { background: var(--sand); }
}

.a-reel__dots > button:focus-visible { outline-offset: 0; }

/* ------------------------------------------------------------------ *
 * 15. Контакт
 * ------------------------------------------------------------------ */
.a-contact {
  display: grid;
  gap: clamp(2.5rem, 1.4rem + 4.4vw, 5.5rem);
  align-items: start;
}

.a-contact__text .a-lead { margin-block-start: 1.5rem; }

/* Контактная планка: та же табличка образца, только вместо выкраски — форма заявки.
   Узкая и вертикальная: поля табличка отдаёт строкам, а не отступам. */
.a-mount {
  --mount-block: clamp(1.5rem, 0.9rem + 2.4vw, 2.5rem);
  --mount-inline: clamp(1.25rem, 0.7rem + 2.4vw, 2.25rem);
  position: relative;
  max-inline-size: var(--form-w);
  background: var(--panel);
  border: 1px solid var(--rule);
  padding: var(--mount-block) var(--mount-inline);
}

.a-mount::before {
  content: "";
  position: absolute;
  inset-block-start: -1px;
  inset-inline-start: -1px;
  inline-size: clamp(4rem, 22%, 9rem);
  block-size: 1px;
  background: var(--brass);
}

/* Форма заявки — лист спецификации на табличке: подпись шрифтом заголовков и строка,
   которую заполняют, без рамок и теней. Кнопки — те же, что рядом в «Контактах»,
   поэтому они <button>: у <input> нет ::before и ::after, из которых собрана .a-btn. */
.a-form {
  display: grid;
  gap: clamp(1.25rem, 1rem + 1vw, 1.75rem);
}

.a-form__field {
  display: grid;
  gap: 0.25rem;
}

.a-form__label {
  font-size: var(--t-h3);
  line-height: 1.24;
  letter-spacing: -0.004em;
}

.a-form__req { color: var(--accent); }

/* Строка — граница поля, по ней его и находят: контраст к грунту не меньше 3:1,
   поэтому --fg-muted, а не волосяная --rule. */
.a-form__input {
  inline-size: 100%;
  min-block-size: 2.75rem;
  padding-block: 0.5rem;
  padding-inline: 0;
  border: 0;
  border-block-end: 1px solid var(--fg-muted);
  border-radius: 0;
  background: transparent;
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: 1.5;
  caret-color: var(--accent);
  -webkit-appearance: none;
  appearance: none;
  transition: border-color var(--af-motion-fast) var(--af-ease),
              box-shadow var(--af-motion-fast) var(--af-ease);
}

textarea.a-form__input {
  display: block;
  min-block-size: 7rem;
  resize: vertical;
}

/* Номер в RTL остаётся слева направо — как ссылка a[data-af-tel] ниже. */
.a-form__input[inputmode="tel"] { direction: ltr; }

@media (hover: hover) {
  .a-form__input:hover { border-block-end-color: var(--fg); }
}

/* Фокус — та же строка, вдвое толще и в акценте: рамка-outline вокруг строки
   читалась бы чужой коробкой. */
.a-form__input:focus {
  outline: 0;
  border-block-end-color: var(--accent);
  box-shadow: 0 1px 0 var(--accent);
}

.a-form__input[aria-invalid="true"] {
  border-block-end-color: var(--error);
  box-shadow: 0 1px 0 var(--error);
}

/* Автозаполнение браузера иначе красит поле своим голубым или жёлтым. */
.a-form__input:-webkit-autofill {
  -webkit-text-fill-color: var(--fg);
  box-shadow: inset 0 0 0 100vmax var(--panel);
}

.a-form__input:-webkit-autofill:focus {
  box-shadow: inset 0 0 0 100vmax var(--panel), 0 1px 0 var(--accent);
}

.a-form__error {
  font-size: var(--t-small);
  color: var(--error);
}

/* Согласие: подпись целиком — тач-цель галочки. */
.a-form__check {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 0.75rem;
  font-size: var(--t-small);
  line-height: 1.5;
  color: var(--fg-muted);
  cursor: pointer;
}

.a-form__check input {
  display: grid;
  place-content: center;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  margin-block-start: 0.0625rem;
  border: 1px solid var(--fg-muted);
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  transition: background-color var(--af-motion-fast) var(--af-ease),
              border-color var(--af-motion-fast) var(--af-ease);
}

/* Галка — рисунок, а не строка: в RTL не зеркалится, поэтому стороны физические. */
.a-form__check input::before {
  content: "";
  inline-size: 0.375rem;
  block-size: 0.6875rem;
  border: solid var(--panel);
  border-width: 0 2px 2px 0;
  transform: translateY(-1px) rotate(45deg);
  opacity: 0;
}

.a-form__check input:checked {
  background: var(--accent);
  border-color: var(--accent);
}

.a-form__check input:checked::before { opacity: 1; }

.a-form__check input[aria-invalid="true"] { border-color: var(--error); }

.a-form .a-actions { margin-block-start: 0; }

/* Заявка ушла, идёт переход в CRM: второй раз не отправить. */
.a-btn:disabled {
  opacity: 0.6;
  pointer-events: none;
}

/* -- Попап с формой -------------------------------------------------- */
/* Та же табличка и та же форма, что в «Контактах». Открывается по центру экрана
   в верхнем слое браузера, поэтому z-index ему не нужен. display у закрытого
   не задаём: иначе <dialog> было бы видно. Не влезла в экран — прокручивается
   только форма, заголовок с крестиком стоит на месте. Страница под попапом
   не прокручивается, а gutter не даёт ей сдвинуться, когда полоса прокрутки исчезла. */
html:has(.a-dialog[open]) {
  overflow: hidden;
  scrollbar-gutter: stable;
}

.a-dialog {
  inline-size: min(var(--form-w), 100% - 2rem);
  max-inline-size: none;
  max-block-size: none;
  margin: auto;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--fg);
  overflow: visible;
}

/* Цвет литералом: не все браузеры наследуют переменные в ::backdrop. */
.a-dialog::backdrop {
  background: rgba(33, 31, 28, 0.6);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
}

/* Первая строка — для браузеров без svh, вторая рабочая. */
.a-dialog__plate {
  display: flex;
  flex-direction: column;
  max-inline-size: none;
  max-block-size: calc(100vh - 2rem);
  max-block-size: calc(100svh - 2rem);
  padding: 0;
}

.a-dialog__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding-block: var(--mount-block) 1rem;
  padding-inline: var(--mount-inline);
  border-block-end: 1px solid var(--rule);
}

.a-dialog__title {
  font-size: clamp(1.5rem, 1.38rem + 0.5vw, 1.75rem);
  line-height: 1.13;
  letter-spacing: -0.011em;
  text-wrap: balance;
}

/* Тач-цель 44px; отрицательные поля ставят сам крестик вровень с полем таблички. */
.a-dialog__close {
  flex: none;
  display: grid;
  place-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  margin-block-start: -0.5rem;
  margin-inline-end: -0.75rem;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--fg-muted);
  transition: color var(--af-motion-fast) var(--af-ease);
}

.a-dialog__close:hover { color: var(--fg); }

.a-dialog__close svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
}

.a-dialog__body {
  flex: 1 1 auto;
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-block: 1.5rem var(--mount-block);
  padding-inline: var(--mount-inline);
}

a[data-af-placeholder] { text-decoration-style: dashed; }

/* Номер телефона — одно слово: не рвётся в узком подвале и в RTL
   не переставляет группы цифр. */
a[data-af-tel] { white-space: nowrap; direction: ltr; unicode-bidi: isolate; }

/* ------------------------------------------------------------------ *
 * 16. Подвал
 * ------------------------------------------------------------------ */
/* Подвал тонкий: бренд и контакты одним рядом, под чертой — права и политика.
   Обе пары стоят на одной сетке из двух колонок, политика — под контактами.
   Кнопки в углу окна (WhatsApp над «Наверх») внизу страницы не должны
   закрывать подвал. На телефоне его строки идут во всю ширину, и место
   кнопкам — полоса под подвалом (нижний отступ); с 48em им отдана дорожка
   у концевого края (раздел 18), и нижний отступ равен верхнему. */
.a-foot {
  --foot-pad: clamp(1.75rem, 1.4rem + 1.2vw, 2.5rem);
  padding-block: var(--foot-pad) calc(var(--up-size) * 2 + var(--up-stack) + var(--up-gap) * 2);
  padding-inline: var(--gutter);
}

.a-foot__top {
  display: grid;
  gap: 1.25rem 2.5rem;
  padding-block-end: clamp(1.25rem, 1rem + 1vw, 1.75rem);
  border-block-end: 1px solid var(--rule);
}

.a-foot__name {
  font-size: clamp(1.375rem, 1.2rem + 0.8vw, 1.75rem);
  line-height: 1.2;
}

.a-foot__blurb {
  margin-block-start: 0.5rem;
  color: var(--fg-muted);
}

.a-foot__col {
  display: grid;
  gap: 0.25rem;
  align-content: start;
  font-size: var(--t-small);
}

/* Телефон, почта и мессенджеры — одной строкой, в узкой колонке переносятся. */
.a-foot__reach {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1.5rem;
  color: var(--fg-muted);
}

.a-foot__reach .a-link {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
}

/* Мессенджеры — круглые иконки в тач-цель 44px, в рифму круглой кнопке
   «Наверх», но без тела и блика: в подвале они тише кнопок «Контактов».
   Пунктирный кант — то же, что пунктирное подчёркивание у текстовых
   ссылок: адрес ещё плейсхолдер. */
.a-foot__social {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
}

.a-foot__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  color: var(--fg);
  transition: color var(--af-motion-fast) var(--af-ease),
              border-color var(--af-motion-fast) var(--af-ease),
              transform 300ms var(--af-ease);
}

.a-foot__icon[data-af-placeholder] { border-style: dashed; }

.a-foot__icon:hover,
.a-foot__icon:focus-visible { color: var(--accent); border-color: var(--line); }

@media (hover: hover) {
  .a-foot__icon:hover { transform: translateY(-2px); }
}

.a-foot__icon svg {
  inline-size: 1.25rem;
  block-size: 1.25rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.a-foot__icon .a-foot__glyph { fill: currentColor; stroke: none; }

.a-foot__bar {
  display: grid;
  gap: 0.75rem 2.5rem;
  padding-block-start: 1rem;
}

.a-foot__rights,
.a-foot__privacy {
  font-family: var(--font-spec);
  font-size: var(--t-spec);
  line-height: 1.8;
  letter-spacing: 0.05em;
  color: var(--fg-muted);
}

.a-foot__rights span + span { margin-inline-start: 0.5ch; }

/* Тач-цель 44px полями, которые тут же сняты отрицательным отступом:
   строка под чертой остаётся высотой в одну строку текста. */
.a-foot__privacy .a-link {
  display: inline-block;
  padding-block: calc((2.75rem - 1.8em) / 2);
  margin-block: calc((1.8em - 2.75rem) / 2);
}

/* ------------------------------------------------------------------ *
 * 17. Мобильное меню
 * ------------------------------------------------------------------ */
.a-burger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.625rem;
  padding-block: 0.4rem;
  padding-inline: 1rem;
  min-block-size: 2.75rem;
  min-inline-size: 2.75rem;
  font-family: var(--font-spec);
  font-size: var(--t-spec);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--fg-muted);
}

.a-burger__bars {
  position: relative;
  inline-size: 1rem;
  block-size: 0.5rem;
  border-block: 1px solid currentColor;
}

.a-burger:hover { color: var(--fg); }

/* Открытое меню — залитое тело: кнопка держит состояние сама, без рамки. */
.a-burger[aria-expanded="true"] { color: var(--btn-fg); }
.a-burger[aria-expanded="true"]::after {
  background: var(--btn-bg);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

.a-menu {
  position: fixed;
  inset-block-start: var(--head-h);
  inset-block-end: 0;
  inset-inline: 0;
  z-index: 39;
  display: grid;
  grid-template-rows: 1fr auto;
  gap: 2rem;
  padding-block: clamp(1.5rem, 1.2rem + 1.4vw, 2.5rem) 2rem;
  padding-inline: var(--gutter);
  overflow-y: auto;
  overscroll-behavior-y: contain;
  border-block-start: 1px solid var(--rule);
}

.a-menu__nav {
  display: grid;
  align-content: start;
}

.a-menu__link {
  padding-block: 1rem;
  font-size: clamp(1.5rem, 1.2rem + 1.6vw, 2.125rem);
  line-height: 1.15;
  text-decoration: none;
  border-block-start: 1px solid var(--rule);
}

.a-menu__link:first-child { border-block-start: 0; }
.a-menu__link.is-current { color: var(--accent); }

.a-menu__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  padding-block-start: 1.5rem;
  border-block-start: 1px solid var(--rule);
}

.a-menu__foot .a-btn { flex: 1 1 12rem; }

/* ------------------------------------------------------------------ *
 * 18. Ширины
 * ------------------------------------------------------------------ */
@media (min-width: 34em) {
  /* Подвал: бренд рядом с контактами, права рядом с политикой — колонки
     одни и те же, политика стоит под контактами. */
  .a-foot__top,
  .a-foot__bar { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 48em) {
  .a-head__cta.a-btn { display: inline-flex; }
  .a-tenets[role="list"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .a-stats[role="list"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .a-folio { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .a-card[data-af-project-state="solo"] {
    grid-column: 1 / -1;
    justify-self: center;
    inline-size: calc((100% - var(--a-folio-gap)) / 2 * 1.25);
  }
  .a-card[data-af-project-state="solo"] .a-reel { margin-inline: 0; }
  /* Внизу страницы кнопки в углу встают в дорожку у концевого края подвала,
     а не в полосу под ним: текст кончается не ближе к краю окна, чем кнопки
     плюс зазор. Там, где ряд упёрся в --shell, край и так дальше — поле лишнее,
     но безвредное. Черта под рядом идёт во всю ширину: поле внутри неё. */
  .a-foot { padding-block-end: var(--foot-pad); }
  .a-foot__top,
  .a-foot__bar { padding-inline-end: max(0px, var(--up-size) + var(--up-gap) * 2 - var(--gutter)); }
}

@media (min-width: 62em) {
  .a-hero__grid { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  .a-hero .a-h1 { max-inline-size: 24ch; }

  /* Слева текст, справа узкая табличка с формой. На телефоне порядок разметки: текст, форма. */
  .a-contact { grid-template-columns: minmax(0, 1fr) minmax(0, var(--form-w)); }

  /* Подход — линия по ширине: колонки встык, их разводят поля, чтобы
     отрезки сомкнулись в одну линию. Как на референсе, линия начинается
     и кончается не у края блока, а чуть отступив от крайних колонок. */
  .a-timeline[role="list"] {
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
  }

  .a-timeline__stop {
    padding-block: calc(var(--tl-dot) + 1.75rem) 0;
    padding-inline: clamp(0.75rem, 1.6vw, 1.5rem);
    text-align: center;
  }

  .a-timeline__stop::before {
    inset-block-start: 0;
    inset-inline-start: calc(50% - var(--tl-dot) / 2);
  }

  .a-timeline__stop::after,
  .a-timeline__stop:last-child::after {
    content: "";
    inset-block: calc(var(--tl-dot) / 2 - 0.75px) auto;
    inset-inline: 0;
    inline-size: auto;
    block-size: 1.5px;
    transform-origin: var(--tl-start) 50%;
  }

  .a-timeline__stop:first-child::after { inset-inline-start: 12%; }
  .a-timeline__stop:last-child::after { inset-inline-end: 12%; }

  .a-timeline__stop p {
    max-inline-size: 26ch;
    margin-inline: auto;
    text-wrap: balance;
  }
}

@media (min-width: 75em) {
  .a-nav { display: flex; }
  .a-burger { display: none; }
  .a-menu { display: none; }
  .a-tenets[role="list"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* Узкий телефон: подпись кнопки меню уходит с глаз, но не из доступного
   имени — иначе хедер перестаёт помещаться в строку и появляется прокрутка. */
@media (max-width: 25.99em) {
  /* На узком телефоне язык выбирается в меню, где остаются обе кнопки. */
  .a-head__side .a-lang { display: none; }
  .a-burger { gap: 0; padding-inline: 0.6rem; }
  .a-burger__label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ------------------------------------------------------------------ *
 * 19. Сцена во весь экран
 *
 * Первые четыре секции лежат на ленте проходки по вилле: гостиная под
 * первым экраном, кухня под «Сервисами», спальня под «Проектами», ванная
 * под «Процессом». Доли ленты объявлены в разметке (data-af-scrub-segment),
 * прогресс считает motion.js — здесь только слой и его вид.
 *
 * Слой прилипший внутри обёртки, а не fixed: прилипание само кончается на
 * нижней кромке обёртки — не нужно ни JS-переключателя видимости, ни борьбы
 * с адресной строкой на телефоне.
 *
 * Ни одно правило раздела не ждёт флага движения: без JS, при
 * prefers-reduced-motion и до загрузки первого кадра на пине стоит постер
 * под той же вуалью, а весь текст четырёх секций читается светлым по нему.
 * ------------------------------------------------------------------ */

/* Шапка sticky и занимает место в потоке, поэтому обёртка поднимается на её
   высоту: кадр начинается под шапкой, а не под ней в потоке. Первый экран
   возвращает эту высоту отступом — заголовок не уходит под шапку. */
.a-stage {
  position: relative;
  isolation: isolate;
  margin-block-start: calc(-1 * var(--head-h));

  /* Вуаль: плотная сторона и открытая. Числа посчитаны от контраста
     светлого текста (--sand, яркость 0.787) на самых светлых кадрах:
     под текстом 0.12 подложки + 0.84 градиента ≈ 0.86, в открытых
     местах ≈ 0.17. */
  --a-veil-dense: rgba(20, 18, 15, 0.84);
  --a-veil-open: rgba(20, 18, 15, 0.06);

  /* Ход, на котором кадр уходит в бумагу: им же живёт нижний отступ
     последней секции — иначе её последняя строка попадёт в редеющую часть. */
  --a-hem-run: 32vh;
}

/* Отступ первого экрана объявлен числом, потому что его же читает вуаль:
   плотная часть обязана начинаться ровно на верхней кромке текста. */
.a-stage .a-hero {
  --a-veil-head: calc(var(--head-h) + clamp(2.25rem, 1.5rem + 3vw, 4rem));
  padding-block-start: var(--a-veil-head);
}

.a-stage__back {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Пин прилипает к верхней кромке окна. Высота — большой вьюпорт: телефон
   сворачивает адресную строку, окно вырастает до lvh, и пин его уже закрывает;
   на svh под ним открылась бы полоса бумаги. Размер холста при этом не меняется,
   поэтому кадр не перерисовывается посреди прокрутки. Первая строка block-size —
   для браузеров без lvh: на телефоне 100vh и есть большой вьюпорт. */
.a-stage__pin {
  position: sticky;
  inset-block-start: 0;
  block-size: 100vh;
  block-size: 100lvh;
  overflow: hidden;
  background-color: var(--charcoal);
  /* Постер — первый кадр ленты. Он и есть сцена, пока кадров нет: без JS,
     при выключенном движении и до загрузки первого кадра. */
  background-image: url("img/a/scene/poster.webp");
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}

.a-stage__frames {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

/* Вуаль, слой первый: ровная подложка на всём кадре. Слой второй —
   градиент на каждой секции, ниже. */
.a-stage__veil {
  position: absolute;
  inset: 0;
  display: block;
  background: rgba(20, 18, 15, 0.12);
}

/* Кромка: на последних полэкрана обёртки кадр уходит в бумажный грунт,
   на котором дальше стоит #problems — видео растворяется, а не
   обрывается линией. Направление физическое: блочная ось не
   переворачивается вместе с направлением письма. */
.a-stage__hem {
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  display: block;
  block-size: 50vh;
  background: linear-gradient(to bottom, rgba(244, 240, 232, 0), var(--paper));
}

/* Секции сцены: своего грунта у них больше нет, под ними кадр. Палитра — та
   же тёмная, что объявлена у .a-sec--dark: всё внутри ходит через токены и
   переезжает вместе с ней. Грунты #problems и ниже не тронуты. */
.a-stage .a-sec--paper,
.a-stage .a-sec--limestone,
.a-stage .a-sec--dark {
  position: relative;
  z-index: 1;
  background: transparent;
  --ground: transparent;
  --fg: var(--sand);
  --fg-muted: var(--sand-muted);
  --accent: var(--cedar-lit);
  --line: var(--cedar-lit);
  --rule: rgba(237, 231, 220, 0.2);
  --rule-strong: rgba(237, 231, 220, 0.42);
  --btn-bg: var(--sand);
  --btn-fg: var(--charcoal);
  --btn-ring: rgba(237, 231, 220, 0.18);
  --btn-gleam: var(--brass-lit);
  --btn-glass: rgba(33, 31, 28, 0.55);
  --panel: #2A2723;
  color: var(--fg);
  /* Ещё один запас контраста поверх вуали — на случай блика в кадре. */
  text-shadow: 0 1px 3px rgba(20, 18, 15, 0.5);
}

/* Вуаль, слой второй — по блоку у всех четырёх секций: плато плотности
   лежит ровно на коробке содержимого, а редеет вуаль только в отступах
   секции, то есть там, где играет переход между комнатами и куда не
   заходит ни одна строка.

   Градиента по строке здесь нет и быть не может: текстовой полосы у этих
   секций нет. Заголовок первого экрана набран по 24ch, карточки #projects
   идут во всю ширину сеткой .a-tenets — свободной стороны, которую можно
   открыть, ни у одной из четырёх не остаётся.

   Стопы: сверху — верхняя кромка текста (у первого экрана свой отступ,
   у остальных --sec-pad), снизу — нижняя (у последней секции длиннее на
   ход кромки). Между ними плотность не меняется вовсе. */
.a-stage .a-sec::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(to bottom,
    var(--a-veil-open) 0,
    var(--a-veil-dense) var(--a-veil-head, var(--sec-pad)),
    var(--a-veil-dense) calc(100% - var(--a-veil-tail, var(--sec-pad))),
    var(--a-veil-open) 100%);
}

/* Последняя секция сцены (#process) отдаёт кромке ход --a-hem-run: ниже её
   текста вуаль редеет ровно там, где кадр уходит в бумагу. Отступ и хвост
   вуали — одно и то же число. */
.a-stage > .a-sec:last-child {
  --a-veil-tail: calc(var(--sec-pad) + var(--a-hem-run));
  padding-block-end: calc(var(--sec-pad) + var(--a-hem-run));
}

/* Кнопка со сплошной заливкой — свой лист поверх кадра: тень текста на нём
   лишняя, а сама заливка контраст уже держит. */
.a-stage .a-btn--solid { text-shadow: none; }

/* ------------------------------------------------------------------ *
 * 20. Движение по прокрутке
 *
 * Конечное состояние объявлено по умолчанию — здесь и во всех разделах
 * выше. Стартовое включает только флаг data-af-motion на <html>, который
 * ставит motion.js. Нет JS, нет IntersectionObserver или стоит
 * prefers-reduced-motion — ни одно правило с флагом не применяется,
 * и страница читается целиком, без спрятанных строк.
 * ------------------------------------------------------------------ */

/* -- Сцена: первый кадр приходит на место постера -------------------- */
/* Пока кадров нет, холст прозрачен и на пине виден постер. Первый
   загруженный кадр ставит на сцену data-af-scrub-state="ready" — холст
   проявляется, а не подменяет постер рывком. */
[data-af-motion] .a-stage__frames {
  opacity: 0;
  transition: opacity 600ms var(--af-ease);
}

[data-af-motion] .a-stage[data-af-scrub-state="ready"] .a-stage__frames { opacity: 1; }

/* -- Появление секций ----------------------------------------------- */
[data-af-motion] [data-af-reveal] {
  transition: opacity 460ms var(--af-ease), transform 460ms var(--af-ease);
  /* Номер в группе ставит motion.js; шаг лесенки — дело этих стилей. */
  transition-delay: calc(var(--af-reveal-i, 0) * 70ms);
}

[data-af-motion] [data-af-reveal]:not(.is-inview) { opacity: 0; }
[data-af-motion] [data-af-reveal="rise"]:not(.is-inview) { transform: translate3d(0, 1rem, 0); }
[data-af-motion] [data-af-reveal="near"]:not(.is-inview) { transform: translate3d(-0.75rem, 0, 0); }
[data-af-motion] [data-af-reveal="far"]:not(.is-inview) { transform: translate3d(0.75rem, 0, 0); }

/* transform физический: встречное движение пар рисков зеркалим руками. */
[data-af-motion][dir="rtl"] [data-af-reveal="near"]:not(.is-inview) { transform: translate3d(0.75rem, 0, 0); }
[data-af-motion][dir="rtl"] [data-af-reveal="far"]:not(.is-inview) { transform: translate3d(-0.75rem, 0, 0); }

/* Подход (приём stop): линия прорисовывается остановка за остановкой —
   отрезок идёт ровно, без разгона, за то же время, что шаг лесенки, —
   точка вырастает, когда до неё дошла линия, текст поднимается следом.
   Сама остановка не гаснет: тогда гасла бы и линия. */
[data-af-motion] [data-af-reveal="stop"]:not(.is-inview) { opacity: 1; }

[data-af-motion] [data-af-reveal="stop"] > *,
[data-af-motion] [data-af-reveal="stop"]::before {
  transition: opacity 460ms var(--af-ease), transform 460ms var(--af-ease);
  transition-delay: calc(var(--af-reveal-i, 0) * 180ms);
}

[data-af-motion] [data-af-reveal="stop"]::after {
  transition: transform 180ms linear;
  transition-delay: calc(var(--af-reveal-i, 0) * 180ms);
}

[data-af-motion] [data-af-reveal="stop"]:not(.is-inview) > * { opacity: 0; transform: translate3d(0, 0.75rem, 0); }
[data-af-motion] [data-af-reveal="stop"]:not(.is-inview)::before { opacity: 0; transform: scale(0); }
[data-af-motion] [data-af-reveal="stop"]:not(.is-inview)::after { transform: scaleY(0); }

@media (min-width: 62em) {
  [data-af-motion] [data-af-reveal="stop"]:not(.is-inview)::after { transform: scaleX(0); }
}

/* Схема услуг приходит лесенкой веток — только прозрачностью (приём
   node): transform сделал бы ряд опорой для спицы, и она уехала бы
   с места. */

/* Маршрут прорисовывается по прогрессу своей прокрутки (--af-scrub), узел
   загорается, когда линия дошла до его доли пути (--at), звезда в конце —
   когда линия дошла до неё. Без движения линия стоит целиком, всё горит. */
[data-af-motion] .a-step { --lit: clamp(0, (var(--af-scrub, 1) - var(--at, 0)) * 40, 1); }
[data-af-motion] .a-route__ink { stroke-dashoffset: calc(1 - var(--af-scrub, 1)); }
[data-af-motion] .a-route__steps::after { transform: scaleY(var(--af-scrub, 1)); }
[data-af-motion] .a-route__star--end { opacity: clamp(0.45, (var(--af-scrub, 1) - 0.97) * 40, 1); }

/* -- Кнопка «Наверх» поднимается на место ----------------------------- */
/* Без движения она просто появляется и исчезает. Переходы .a-btn
   (нажатие размером, цвет) повторены: свойство transition одно на всех. */
[data-af-motion] .a-up {
  transition: transform 300ms var(--af-ease),
              color var(--af-motion-base) var(--af-ease),
              opacity var(--af-motion-base) var(--af-ease),
              visibility var(--af-motion-base) var(--af-ease);
}

[data-af-motion] .a-up[data-af-to-top-state="hidden"] { transform: translate3d(0, 0.75rem, 0); }

/* WhatsApp уступает ей угол и возвращается в него тем же ходом. */
[data-af-motion] .a-wa {
  transition: transform 300ms var(--af-ease),
              color var(--af-motion-base) var(--af-ease),
              translate var(--af-motion-base) var(--af-ease);
}

/* -- Попап с формой приходит на место ---------------------------------- */
/* Без движения он просто открыт. Длительность у ::backdrop литералом — по той же
   причине, что и цвет в разделе 15. */
[data-af-motion] .a-dialog[open] { animation: a-dialog-in 280ms var(--af-ease); }
[data-af-motion] .a-dialog[open]::backdrop { animation: a-dialog-fade 280ms ease-out; }

@keyframes a-dialog-in {
  from { opacity: 0; transform: translate3d(0, 0.75rem, 0); }
}

@keyframes a-dialog-fade {
  from { opacity: 0; }
}

/* -- Объект, выбранный фильтром, вырастает ----------------------------- */
/* Карточка проявляется в прежнем размере и растёт до своего (раздел 14).
   Ширина идёт раскладкой каждый кадр, поэтому фото всё время чёткое.
   Проявление прячет перескок из колонки в центр ряда. */
[data-af-motion] .a-card[data-af-project-state="solo"] {
  animation: a-solo-in 560ms var(--af-ease);
}

[data-af-motion] .a-card[data-af-project-state="solo"] .a-reel {
  animation: a-solo-bleed 560ms var(--af-ease);
}

@keyframes a-solo-in {
  from { opacity: 0; }
}

@keyframes a-solo-bleed {
  from { margin-inline: 0; }
}

@media (min-width: 48em) {
  [data-af-motion] .a-card[data-af-project-state="solo"] { animation-name: a-solo-grow; }
  [data-af-motion] .a-card[data-af-project-state="solo"] .a-reel { animation: none; }
}

@keyframes a-solo-grow {
  from { opacity: 0; inline-size: calc((100% - var(--a-folio-gap)) / 2); }
}
