:root{
  --fs-10: 0.625rem;
  --fs-11: 0.6875rem;
  --fs-12: 0.75rem;
  --fs-13: 0.8125rem;
  --fs-14: 0.875rem;
  --fs-15: 0.9375rem;
  --fs-16: 1rem;
  --fs-18: 1.125rem;
  --fs-20: 1.25rem;
  --fs-22: 1.375rem;
  --fs-24: 1.5rem;
  --fs-26: 1.625rem;
  --fs-30: 1.875rem;
  --fs-34: 2.125rem;
  --fs-42: 2.625rem;
  --fs-48: 3rem;
  --fs-56: 3.5rem;
}
/* Дизайн-система wedsochi.ru.
   Токены сняты с polotnoagency.ru замером вычисленных стилей (ДИЗАЙН-СИСТЕМА.md).
   Премиальность ниши держится на двух приёмах: заголовки НЕ жирные (400 —
   минимальный вес, который есть у Lora) и разрядка 2px. Тот же кегль в 700
   сразу читается дёшево.
   Шрифты — свои, /assets/fonts.css, собирается scripts/fetch_fonts.py. */
:root{
  /* Цвета ТОЛЬКО из замера polotnoagency.ru (design/tokens-raw.json), ничего
     подобранного на глаз и ничего из палитр по умолчанию:
       #111111 — заголовки          #626262 — основной текст (самый частый, 23 узла)
       #7c8383 — приглушённые       #bd9f4b — золото, единственный акцент
       #b2946d — тауп, вторичный    #23282d — графит, фон тёмной секции
     Контраст #626262 на белом = 5.7:1, выше нормы WCAG AA (4.5:1), поэтому
     родной цвет референса берём как есть — подменять его не пришлось. */
  --bg:#fff; --ink:#111; --dark:#23282d; --text:#5c5c5c; --muted:#676c6d;
  --gold:#c2a479; --gold-ink:#8d7550; --taupe:#b2946d; --line:#e6e6e6; /* muted поднят до AA */
  --side:345px;
  /* Скругления в духе Apple (владелец 04.09.2026): крупный мягкий радиус вместо
     прежних 3 px. Три ступени, чтобы вложенные элементы не спорили друг с другом:
     мелкие контролы 10, карточки 18, крупные полотна 26. */
  --radius:18px; --radius-sm:10px; --radius-lg:26px;
  --ease:cubic-bezier(.16,1,.3,1);
  /* Стек повторяет референс дословно, вместе с порядком подстановки:
     у них 'Lato, Arial, Tahoma, sans-serif' и 'Lora, Arial, Tahoma, sans-serif'.
     У Lato НЕТ кириллицы (Google отдаёт только latin/latin-ext), поэтому
     русский текст рисует Arial — ровно как на самом polotnoagency.ru.
     Ни system-ui, ни Georgia: это подстановки по умолчанию, из-за которых
     на разных машинах страница набирается разными шрифтами. */
  /* ДВА шрифта (владелец 04.09.2026): Cormorant Garamond (заголовки, суммы)
     и Manrope (текст и интерфейс). Прежняя пара Lora/Lato снята — Manrope
     держит кириллицу во всех весах, чего у Lato не было.
     Prata убрана — на polotnoagency.ru она встречалась всего в двух узлах,
     а тянула отдельное семейство. Цифры-факты и суммы теперь рисует Lora:
     у неё тот же дидон-контраст, ради которого Prata и стояла. */
  --serif:'Cormorant Garamond',Georgia,'Times New Roman',serif;
  --sans:'Montserrat',-apple-system,'Segoe UI',Arial,sans-serif;
  --num:'Cormorant Garamond',Georgia,serif;
}
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--bg);color:var(--text);
  font:400 var(--fs-16)/1.75 var(--sans);-webkit-font-smoothing:antialiased}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
/* Вес 400, а не 300: у Lora начертания 300 не существует — запрос
   Lora:wght@300 Google отклоняет. Раньше в CSS стояла цифра, которой шрифт
   не знает, и браузер всё равно рисовал 400. «Светлость» заголовков даёт
   не вес, а крупный кегль и разрядка 2px. */
h1,h2,h3{font-family:var(--serif);font-weight:400;color:var(--ink);
  letter-spacing:2px;line-height:1.2;margin:0}
h1{font-size:clamp(34px,5vw,67px)}
h2{font-size:clamp(28px,3.4vw,42px)}
h3{font-size:clamp(20px,2vw,26px);letter-spacing:1px}
.eyebrow{font:600 var(--fs-12)/1 var(--serif);text-transform:uppercase;letter-spacing:2px;
  color:var(--gold-ink);margin-bottom:18px}

/* ── Каркас: фиксированный сайдбар + контентная колонка ───────────────── */
.layout{display:flex;min-height:100vh}
.side{width:var(--side);flex:0 0 var(--side);border-right:0;
  padding:34px 30px;position:fixed;inset:0 auto 0 0;overflow-y:auto;background:#fff;z-index:40}
.main{margin-left:var(--side);width:calc(100% - var(--side));min-width:0}
.logo{display:block;border:0;padding:6px 0 2px;text-align:center;
  font:400 var(--fs-18)/1 var(--num);letter-spacing:4px;color:var(--ink)}
.logo small{display:block;font:400 var(--fs-10)/1.6 var(--sans);letter-spacing:3px;
  color:var(--muted);margin-top:8px}
.nav{margin:34px 0}
.nav a{display:block;padding:9px 0;font:600 var(--fs-12)/1 var(--serif);text-transform:uppercase;
  letter-spacing:2px;color:var(--ink);transition:color .3s,padding-left .3s var(--ease)}
.nav a:hover{color:var(--gold);padding-left:8px}
.facts{border-top:0;padding-top:26px}
.fact{margin-bottom:20px}
.fact b{display:block;font:400 36px/1 var(--num);color:var(--ink);letter-spacing:.5px}
.fact span{font-size: var(--fs-13);color:var(--muted);line-height:1.45;display:block;margin-top:4px}
.side-phone{display:block;font:400 var(--fs-16)/1 var(--num);letter-spacing:1px;color:var(--ink);
  text-align:center;margin:24px 0 12px}
.btn{display:block;width:100%;border:0;cursor:pointer;background:var(--ink);color:#fff;
  padding:15px 20px;font:400 var(--fs-13)/1 var(--sans);letter-spacing:2px;text-transform:uppercase;
  text-align:center;border-radius:999px;transition:background .35s}
.btn:hover{background:var(--gold)}
/* Юридические страницы — в палитре сайта. Общая кнопка красится в --ink (#111),
   чисто чёрного на сайте больше нигде нет, и на тёплом фоне она читается чужой.
   🔴 Правило стоит ИМЕННО В ЭТОМ листе, потому что юр. страницы грузят только
   fonts-v2.css + style.css: написанное в v2/article.css до них не доходит вовсе
   (грабля проекта — так уже теряли правки). */
body.legal-page .btn{background:#3d2b1f}
body.legal-page .btn:hover{background:var(--gold)}
.btn-ghost{background:#f4f4f2;color:var(--ink)}
.btn-ghost:hover{background:var(--ink);color:#fff}

/* ── Баннер реализованных свадеб ───────────────────────────────────────
   Слайдер с кроссфейдом (просьба владельца вместо бегущей ленты): один кадр
   плавно гаснет, следующий плавно проявляется. Градиентную маску по краям
   убрали — она была нужна ленте, чтобы прятать въезд/выезд кадров; у слайдера
   въезда нет, маска только грязнила края.
   Все кадры лежат стопкой абсолютно, поэтому высота контейнера задана заранее
   и CLS не возникает (проверено PageSpeed: CLS 0). Анимируем только opacity —
   работа видеокарты, а не перерисовка. */
.hero{padding:0 0 10px}
.slider{position:relative;width:100%;height:clamp(300px,44vw,560px);overflow:hidden;
  background:#f2f0ec}
.slide{position:absolute;inset:0;opacity:0;transition:opacity 1.4s var(--ease)}
.slide.on{opacity:1}
.slide img{width:100%;height:100%;object-fit:cover;filter:saturate(.96)}
/* Точки-переключатели снизу: ненавязчивая навигация, как у обычного слайдера */
.slider-dots{position:absolute;left:0;right:0;bottom:16px;display:flex;gap:8px;
  justify-content:center;z-index:2}
.slider-dots b{width:7px;height:7px;border-radius:50%;background:rgba(255,255,255,.5);
  cursor:pointer;transition:background .3s,transform .3s}
.slider-dots b.on{background:#fff;transform:scale(1.25)}
.hero-title{padding:64px clamp(24px,5vw,80px) 10px;max-width:1000px}
.hero-title p{font-size: var(--fs-18);max-width:620px;margin-top:22px}

/* ── Секции ────────────────────────────────────────────────────────────── */
section{padding:clamp(48px,6vw,86px) clamp(24px,5vw,80px)}
.section-head{max-width:760px;margin-bottom:44px}
.section-head p{margin-top:16px}
.grid{display:grid;gap:22px}
.g-2{grid-template-columns:repeat(auto-fit,minmax(320px,1fr))}
.g-3{grid-template-columns:repeat(auto-fit,minmax(310px,1fr))}
.g-4{grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
/* Карточки без рамок (решение владельца): группировку держат воздух и тень,
   а не линии. Рамка на каждой карточке дробит светлую страницу на клетки и
   спорит с крупной типографикой — это ровно то, чего в референсе нет. */
.card{border:0;border-radius:var(--radius);padding:26px 26px 30px;background:#fff;
  transition:transform .5s var(--ease),box-shadow .5s}
.card:hover{transform:translateY(-4px);box-shadow:0 14px 40px rgba(17,17,17,.08)}
.card h3{margin-bottom:10px}
.card .price{font:400 var(--fs-24)/1 var(--num);color:var(--ink);letter-spacing:.5px;margin-top:16px;display:block}
.card .price em{font:400 var(--fs-12)/1 var(--sans);color:var(--muted);font-style:normal;letter-spacing:1px}
.tag{display:inline-block;font:600 var(--fs-10)/1 var(--serif);text-transform:uppercase;letter-spacing:2px;
  color:var(--gold-ink);padding:0;border:0}
.dark{background:var(--dark);color:rgba(255,255,255,.72)}
.dark h2,.dark h3,.dark .fact b{color:#fff}
.dark .eyebrow{color:var(--gold)}
.dark .fact span{color:rgba(255,255,255,.66)}

/* ── Конструктор сметы ─────────────────────────────────────────────────── */
.calc{display:grid;grid-template-columns:1fr 340px;gap:34px;align-items:start}
.calc-row{border:0;padding:16px 0;display:grid;
  grid-template-columns:1fr auto;gap:18px;align-items:center}
.calc-row:first-child{border-top:0}
.calc-row .ch4{margin:0 0 4px;font:400 var(--fs-18)/1.3 var(--serif);color:var(--ink);letter-spacing:.5px}
.calc-row small{color:var(--muted);font-size: var(--fs-13)}
.levels{display:flex;gap:6px;flex-wrap:wrap}
.lvl{border:0;background:#f4f4f2;cursor:pointer;padding:10px 14px;
  font:400 var(--fs-12)/1 var(--sans);letter-spacing:1px;color:var(--text);border-radius:var(--radius);
  transition:background .3s,color .3s}
.lvl:hover{background:#eceae6;color:var(--ink)}
.lvl[aria-pressed="true"]{background:var(--ink);color:#fff}
.total{position:sticky;top:34px;border:0;border-radius:var(--radius);padding:28px;background:#faf9f7}
.total .sum{font:400 clamp(30px,3.2vw,42px)/1.1 var(--num);color:var(--ink);letter-spacing:1px;margin:6px 0 4px}
.total ul{list-style:none;margin:18px 0;padding:0;font-size: var(--fs-14)}
.total li{display:flex;justify-content:space-between;gap:12px;padding:8px 0;border:0}
.total li span:last-child{white-space:nowrap;color:var(--ink)}
.note{font-size: var(--fs-13);color:var(--muted);line-height:1.6;margin-top:14px}

/* ── Площадки ──────────────────────────────────────────────────────────── */
.venue{border:0;border-radius:var(--radius);padding:24px 24px 28px;cursor:pointer;
  transition:transform .5s var(--ease),box-shadow .5s;background:#fff}
.venue:hover{transform:translateY(-4px);box-shadow:0 14px 40px rgba(17,17,17,.08)}
.venue .type{font:600 var(--fs-10)/1 var(--serif);text-transform:uppercase;letter-spacing:2px;color:var(--gold-ink)}
.venue h3{margin:12px 0 8px;font-size: var(--fs-20)}
.venue .cap{font-size: var(--fs-13);color:var(--muted)}
.venue.star{background:#faf8f4}
.venue.star:hover{box-shadow:0 14px 40px rgba(17,17,17,.08)}

/* ── Модалка ───────────────────────────────────────────────────────────── */
.modal{position:fixed;inset:0;z-index:90;display:none;place-items:center;padding:24px}
.modal[open]{display:grid}
.modal-bg{position:absolute;inset:0;background:rgba(20,22,24,.55);backdrop-filter:blur(3px);
  animation:fade .35s ease}
.modal-box{position:relative;background:#fff;max-width:720px;width:100%;max-height:86vh;
  overflow:auto;padding:38px;border-radius:var(--radius);animation:pop .45s var(--ease)}
.modal-close{position:absolute;top:14px;right:16px;border:0;background:none;cursor:pointer;
  font-size: var(--fs-26);line-height:1;color:var(--muted)}
@keyframes fade{from{opacity:0}}
@keyframes pop{from{opacity:0;transform:translateY(18px) scale(.985)}}

/* ── Форма ─────────────────────────────────────────────────────────────── */
.form{display:grid;gap:14px;max-width:430px}
/* Поля без рамок: подложка вместо линии. Совсем без визуального контейнера
   поле неотличимо от текста — это уже не «чисто», а непонятно, куда писать.
   Фокус помечаем не обводкой, а сменой фона плюс золотой полосой слева. */
.form input{border:0;background:#f4f4f2;padding:15px 16px;font:400 var(--fs-16) var(--sans);
  color:var(--ink);border-radius:var(--radius);transition:background .3s,box-shadow .3s}
.form input:focus{outline:none;background:#efeeea;box-shadow:inset 3px 0 0 var(--gold)}
/* Honeypot. Прячем позиционированием, а не display:none и не hidden: часть ботов
   умеет отсеивать скрытые правила и такое поле пропускает, а уехавшее за экран —
   заполняет как обычное. Скринридеру поле закрыто через aria-hidden в разметке. */
.form .hp{position:absolute;left:-9999px;width:1px;height:1px;opacity:0;pointer-events:none}
.note.err{color:var(--taupe)}
.note.err a{color:var(--taupe);border-bottom:1px solid currentColor}

/* ── Появление ────────────────────────────────────────────────────────────
   Формула снята ИЗ КОДА hollywoodexhibit2026.com, а не придумана:
     initial {opacity:0, filter:"blur(6px)"} -> animate {opacity:1, blur(0px)}
     duration .8, ease easeInOut.quart, staggerChildren .05-.12
   Ключевое отличие от привычного «выехало снизу»: там НЕТ сдвига. Работает
   именно расфокус — изображение будто наводится на резкость. Сдвиг на 24px
   рядом с фотографией читается как дёрганье, расфокус — как проявление плёнки.
   easeInOut.quart в CSS = cubic-bezier(.76,0,.24,1). */
:root{--quart:cubic-bezier(.76,0,.24,1)}
.rv{opacity:0;filter:blur(6px);will-change:opacity,filter;
  transition:opacity .8s var(--quart),filter .8s var(--quart)}
.rv.in{opacity:1;filter:blur(0)}
/* Каскад соседей: у них staggerChildren .05, задержку раздаёт JS по индексу */
.w{display:inline-block;opacity:0;filter:blur(6px);
  transition:opacity .8s var(--quart),filter .8s var(--quart)}
.w.in{opacity:1;filter:blur(0)}

/* Фотографии наводятся на резкость по мере загрузки. `will-change` снимаем
   после анимации (в JS): оставленный навсегда, он держит слой в памяти
   видеокарты на каждой картинке страницы. */
.fade-img{opacity:0;filter:blur(8px);transform:scale(1.02);
  transition:opacity .9s var(--quart),filter .9s var(--quart),transform .9s var(--quart)}
.fade-img.ready{opacity:1;filter:blur(0);transform:none}

.foot{border-top:0;padding:52px clamp(24px,5vw,80px);font-size: var(--fs-14);color:var(--muted)}

/* Липкая полоса действий — только на телефоне, где сайдбар уезжает наверх */
.sticky{position:fixed;left:0;right:0;bottom:0;z-index:50;display:none;gap:1px;
  background:#e9e7e3;box-shadow:0 -10px 30px rgba(17,17,17,.06)}
.sticky a,.sticky button{flex:1;background:#fff;border:0;padding:15px;font:400 var(--fs-13)/1 var(--sans);
  letter-spacing:1px;color:var(--ink);cursor:pointer;text-align:center}
.sticky .acc{background:var(--ink);color:#fff}

@media (max-width:1080px){.calc{grid-template-columns:1fr}.total{position:static}}
/* ── Телефон ───────────────────────────────────────────────────────────────
   Сайдбар на узком экране раскладывается сверху, и здесь легко потерять
   продажу: 29.08.2026 на 390px весь первый экран занимали логотип, меню из
   восьми пунктов, четыре счётчика и кнопка — а баннер с заголовком «Свадебное
   агентство в Сочи» начинался только за сгибом. Человек, пришедший из поиска,
   первым делом видел оглавление, а не предложение.
   Поэтому на телефоне из шапки остаётся только логотип со ссылкой на главную
   и меню одной прокручиваемой строкой. Цифры доверия убраны — они целиком
   повторяются в секции «о нас», а кнопка не нужна: внизу висит липкая полоса
   «Позвонить / Рассчитать смету», которая доступна с любого места страницы. */
@media (max-width:860px){
  .layout{display:block}
  .side{position:static;width:auto;height:auto;border:0;
    display:block;padding:16px 20px 0}
  .main{margin-left:0;width:100%}
  .logo{padding:12px 8px;font-size: var(--fs-16);letter-spacing:3px}
  .logo small{font-size:8px;margin-top:5px}
  /* Меню — одной строкой с горизонтальной прокруткой: восемь пунктов в столбик
     стоили бы ещё пол-экрана. mask справа подсказывает, что строка едет дальше. */
  .nav{display:flex;flex-wrap:nowrap;overflow-x:auto;gap:20px;margin:14px -20px 0;
    padding:0 20px 12px;scrollbar-width:none;
    mask-image:linear-gradient(90deg,#000 88%,transparent)}
  .nav::-webkit-scrollbar{display:none}
  .nav a{padding:0;white-space:nowrap;font-size: var(--fs-11)}
  .side .facts,.side>.btn,.side-phone{display:none}
  .sticky{display:flex}
  body{padding-bottom:52px}
  .hero-title{padding-top:34px}
  .prose{padding-top:28px}
  /* Врезка-CTA в статье на узком экране складывается в столбик, иначе кнопка
     сжимается до нечитаемой ширины. */
  .cta-inline{flex-direction:column;align-items:flex-start;gap:16px;padding:22px}
  .cta-inline .btn{width:100%}
}
/* Уважение к системной настройке: движение отключается полностью, а не
   «уменьшается» — иначе для чувствительных к укачиванию людей толку нет. */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;
    transition-duration:.001ms!important}
  .rv,.w{opacity:1;transform:none}
}

/* ── Поле «гостей» и ориентировочные категории ─────────────────────────── */
.guests{display:flex;align-items:center;gap:14px;flex-wrap:wrap;padding:0 0 22px}
.guests label{font:400 var(--fs-18)/1.3 var(--serif);color:var(--ink);letter-spacing:.5px}
.guests input{width:96px;border:0;background:#f4f4f2;border-radius:var(--radius);
  padding:11px 12px;font:400 var(--fs-16)/1 var(--num);color:var(--ink);text-align:center}
.guests input:focus{outline:none;box-shadow:inset 3px 0 0 var(--gold)}
.guests small{color:var(--muted);font-size: var(--fs-13)}
/* Знак «≈» честно помечает строки, где цена — ориентир по рынку, а не прайс
   конкретного подрядчика. Без пометки клиент считает её обещанием. */
.approx{color:var(--gold);font-family:var(--sans);font-size: var(--fs-15);cursor:help}

/* Работы подрядчика внутри карточки категории: горизонтальная лента,
   чтобы 6 кадров не растягивали модалку на три экрана */
.works{display:flex;gap:6px;overflow-x:auto;padding:2px 0 10px;scroll-snap-type:x mandatory}
.works img{height:150px;width:auto;border-radius:var(--radius);flex:0 0 auto;
  scroll-snap-align:start;transition:transform .6s var(--ease)}
.works img:hover{opacity:.94}

/* ══ Прелоадер ═══════════════════════════════════════════════════════════
   Идея снята с hollywoodexhibit2026.com: тёмный экран, серифный логотип по
   центру, тонкое кольцо внизу. Адаптация: вместо чистого чёрного берём наш
   графит (#23282d) — чистый чёрный убивает глубину и выдаёт шаблон.
   Экран уходит по window.load, но не дольше 2.2 с: если тормозит сеть или
   шрифт, посетитель не должен смотреть в заглушку. Пустой экран без причины
   стоит дороже, чем показанная недогруженная страница. */
#preloader{position:fixed;inset:0;z-index:120;background:var(--dark);
  display:grid;place-items:center;transition:opacity .7s var(--ease),visibility .7s}
#preloader.done{opacity:0;visibility:hidden}
.pre-inner{text-align:center;padding:24px}
.pre-logo{font:400 clamp(26px,4vw,44px)/1 var(--num);letter-spacing:clamp(6px,1.4vw,14px);
  color:#fff;opacity:0;transform:translateY(10px);
  animation:preIn .9s var(--ease) .15s forwards}
.pre-sub{margin-top:16px;font:400 var(--fs-12)/1.6 var(--sans);letter-spacing:3px;
  text-transform:uppercase;color:rgba(255,255,255,.5);opacity:0;
  animation:preIn .9s var(--ease) .38s forwards}
/* Кольцо крутится бесконечно, но живёт максимум 2.2 с — это индикатор
   ожидания, а не украшение страницы. */
.pre-ring{width:26px;height:26px;margin:30px auto 0;border-radius:50%;
  border:1px solid rgba(255,255,255,.18);border-top-color:var(--gold);
  animation:preSpin .9s linear infinite}
@keyframes preIn{to{opacity:1;transform:none}}
@keyframes preSpin{to{transform:rotate(360deg)}}

/* ══ Плёночное зерно ═════════════════════════════════════════════════════
   Снято ИЗ КОДА hollywoodexhibit2026.com (.noise + @keyframes grain), а не
   срисовано с картинки: слой 200%x200% со смещением -50%, чтобы дёрганье
   не открывало края, и `step-end` вместо плавной интерполяции — зерно должно
   ПРЫГАТЬ по кадрам, как плёнка, а не ползти.
   Отличие от оригинала: у них шум подтягивается PNG-кой с чужого CDN. Свой
   шум рисуем feTurbulence прямо в data-URI: ноль сетевых запросов и ничего
   чужого. Слой всегда fixed + pointer-events:none — на скроллящемся
   контейнере зерно уронило бы FPS постоянной перерисовкой. */
:root{
  --grain: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='.82' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)' opacity='.55'/%3E%3C/svg%3E");
}
.noise{position:absolute;top:-50%;left:-50%;width:200%;height:200%;
  background-image:var(--grain);pointer-events:none;
  animation:grain .15s step-end infinite}
@keyframes grain{
  0%{transform:translate(4%,-3%)}   10%{transform:translate(-3%,5%)}
  20%{transform:translate(6%,-1%)}  30%{transform:translate(-5%,-4%)}
  40%{transform:translate(2%,6%)}   50%{transform:translate(-6%,2%)}
  60%{transform:translate(5%,-5%)}  70%{transform:translate(-1%,3%)}
  80%{transform:translate(3%,-6%)}  90%{transform:translate(-4%,4%)}
  to{transform:translate(1%,-2%)}
}
/* Зерно поверх всей страницы: даёт «плёночную» фактуру белым плоскостям.
   Держим слабым (.045) — на светлой теме сильное зерно выглядит грязью. */
/* Статичное зерно: даёт фактуру, но не перерисовывается. will-change/анимации
   нет намеренно — это фон, который просто лежит. */
.grain-layer{position:fixed;inset:0;z-index:110;pointer-events:none;opacity:.05}
.grain-layer .noise{position:absolute;inset:0;width:100%;height:100%;
  background-image:var(--grain);animation:none}
#preloader .noise{opacity:.5}

/* ══ Курсор-кружок ═══════════════════════════════════════════════════════
   Снят из кода референса (.magic): 40x40, fixed, mix-blend-mode:difference,
   overflow:hidden, зерно внутри. difference и есть весь фокус — кружок
   инвертируется под собой, поэтому одинаково виден на белом и на графите,
   без единой строчки логики про «тёмная ли секция».
   Просьба владельца; включается ТОЛЬКО при точном указателе — на тач-экране
   курсора нет, и подменять его нечем, а при reduced-motion лишний
   догоняющий объект вреден. */
.cursor-dot{position:fixed;top:0;left:0;pointer-events:none;border-radius:50%;
  mix-blend-mode:difference;opacity:0;z-index:130;background:#fff;
  width:11px;height:11px;margin:-5.5px 0 0 -5.5px;
  transition:opacity .4s,width .35s var(--ease),height .35s var(--ease),margin .35s var(--ease)}
.cursor{display:none}
body.cursor-on .cursor-dot{opacity:1}
/* Над кликабельным точка подрастает: единственная оставшаяся подсказка
   «сюда можно нажать», поэтому разница в размере должна читаться сразу */
body.cursor-active .cursor-dot{width:26px;height:26px;margin:-13px 0 0 -13px}
@media (hover:hover) and (pointer:fine){
  body.cursor-on,body.cursor-on a,body.cursor-on button,
  body.cursor-on .card,body.cursor-on .venue,body.cursor-on .lvl,
  body.cursor-on input,body.cursor-on .modal-close{cursor:none}
}
@media (hover:none),(pointer:coarse){.cursor-dot{display:none}}
@media (prefers-reduced-motion:reduce){
  .cursor-dot,.grain-layer{display:none}
  #preloader{display:none}
  .noise{animation:none}
}

/* ── Страницы журнала ───────────────────────────────────────────────────────
   Ширина текста ограничена 68 символами (ch), а не пикселями: при смене кегля
   строка сама остаётся читаемой. Длиннее ~75 знаков глаз теряет начало
   следующей строки — на длинных статьях это заметная потеря дочитываний. */
.prose{max-width:72ch;padding:clamp(34px,4.5vw,64px) clamp(24px,5vw,80px) 20px}
.prose h1{font-size:clamp(30px,3.8vw,50px);margin-bottom:26px}
.prose h2{font-size:clamp(21px,2.2vw,29px);letter-spacing:1px;margin:44px 0 14px}
.prose p{margin:0 0 18px;font-size: var(--fs-16);line-height:1.8}
.prose p+p{margin-top:0}
.crumbs{font:600 var(--fs-11)/1 var(--serif);text-transform:uppercase;letter-spacing:2px;
  color:var(--muted);margin-bottom:22px}
.crumbs a{color:var(--gold)}
.crumbs a:hover{color:var(--ink)}
.nav a.on{color:var(--gold)}

/* Врезка с призывом внутри статьи: читатель статьи про бюджет должен уметь
   перейти к смете, не возвращаясь в меню. Ставится один раз, после текста —
   перебивать чтение блоками CTA в середине не даём. */
.cta-inline{display:flex;gap:26px;align-items:center;justify-content:space-between;
  flex-wrap:wrap;border:0;box-shadow:none;
  border-radius:var(--radius);padding:26px 28px;margin:44px 0 10px;background:#faf9f7}
.cta-inline h3{font-size: var(--fs-20);margin-bottom:8px}
.cta-inline p{font-size: var(--fs-14);margin:0;max-width:44ch}
.cta-inline .btn{width:auto;padding:14px 26px;white-space:nowrap}

.related{margin-top:52px;border-top:0;padding-top:34px}
.related h3{font-size: var(--fs-18);margin-bottom:18px}
.rel-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(210px,1fr));gap:12px}
.rel-card{display:block;border:0;background:#faf9f7;border-radius:var(--radius);
  padding:16px 18px;font-size: var(--fs-14);line-height:1.5;color:var(--ink);
  transition:background .4s,transform .5s var(--ease)}
.rel-card:hover{background:#f2f0ec;transform:translateY(-3px)}
.article-page .foot{margin-top:0}
.article-page .foot a{color:var(--ink)}

/* <picture> — обёртка только для выбора формата, в раскладке её быть не должно:
   display:contents убирает сам элемент из потока, и все правила, написанные
   для img (.marquee-row img, .works img), продолжают работать как раньше.
   Без этого picture стал бы инлайновым блоком и сломал flex-ленту баннера. */
picture{display:contents}

/* Иллюстрация в статье выходит за колонку текста на 40px с каждой стороны:
   текст остаётся узким и читаемым, а картинка получает воздух и не выглядит
   вставленной в абзац. На узких экранах вылет убираем — там его негде взять. */
.art-photo{margin:34px -40px;border-radius:var(--radius);overflow:hidden}
.art-photo img{width:100%;height:auto;display:block}
@media (max-width:900px){.art-photo{margin:26px 0}}


/* ── Переносы ────────────────────────────────────────────────────────────
   Три разные задачи, три разных инструмента:
   1. Заголовки — `text-wrap:balance`: браузер сам выравнивает длину строк,
      чтобы в последней не оставалось одно слово («сирота»).
   2. Абзацы — `text-wrap:pretty`: то же, но дешевле и без ограничения на
      число строк; балансировать длинный текст незачем.
   3. Цены и вместимость — `white-space:nowrap` там, где разрыв бессмысленен
      в принципе. Неразрывные пробелы внутри чисел ставит nbsp() в app.js:
      CSS не умеет «не рвать вот здесь», он умеет только «не рвать нигде».
   Плюс `hyphens:auto` для длинных составных слов вроде «Горно-туристический»
   в узкой карточке — иначе строка вылезает за край. */
h1,h2,h3,.calc-row h4,.venue h3,.card h3{text-wrap:balance}
p,.section-head p,.hero-title p,.note,.venue .cap,.card p{text-wrap:pretty}
/* `hyphens:auto` ПРОВЕРЕН И ОТКЛЮЧЁН: на карточках площадок он резал имена
   собственные по слогам — «Мацестин-ская ротонда», «Отель «Име-ретинский»»,
   «при-стань». Для названий это выглядит поломкой вёрстки, а не переносом.
   Вместо переносов даём карточкам больше ширины (минимум колонки ниже). */
body{hyphens:manual;-webkit-hyphens:manual}
.card .price,.total li span:last-child,.sum,.fact b{white-space:nowrap}
/* Длинные адреса и названия площадок рвём по слогам, но не в клочья */
.venue .cap,.venue h3{overflow-wrap:break-word}

/* ─── Новый статейник (scripts/build_blog.py) ───────────────────────────────
   Обводок нет по решению владельца: разделяем не рамкой, а подложкой, воздухом
   и золотой полосой слева (та же логика, что у карточек и полей формы). */
.prose .lead{font-size: var(--fs-20);line-height:1.7;color:var(--ink);margin-bottom:26px}
.prose .facts{width:100%;border-collapse:collapse;margin:0 0 30px;font-size: var(--fs-15)}
.prose .facts th{text-align:left;font-weight:400;color:var(--muted);
  padding:11px 16px 11px 0;vertical-align:top;width:38%}
.prose .facts td{padding:11px 0;color:var(--ink);vertical-align:top}
.prose .facts tr+tr th,.prose .facts tr+tr td{box-shadow:0 -1px 0 #f0efec}
.prose .facts thead th{color:var(--ink);padding-right:16px}
.summary{background:#faf9f7;border-radius:var(--radius);padding:22px 26px;margin:0 0 32px}
.summary h2{font-size: var(--fs-15)!important;letter-spacing:2px;text-transform:uppercase;
  color:var(--muted);margin:0 0 12px!important}
.summary ul{margin:0;padding-left:20px}
.summary li{font-size: var(--fs-16);line-height:1.65;margin-bottom:8px}
.opinion{background:#faf9f7;border-radius:var(--radius);padding:26px 30px;margin:40px 0}
.opinion h2{font-size: var(--fs-15)!important;letter-spacing:2px;text-transform:uppercase;
  color:var(--gold-ink);margin:0 0 14px!important}
.opinion p{font-size: var(--fs-16);line-height:1.75;margin-bottom:12px}
.opinion p:last-child{margin-bottom:0}
.faq-item{padding:16px 0;box-shadow:0 -1px 0 #f0efec}
.faq-item summary{cursor:pointer;font-size: var(--fs-16);color:var(--ink);list-style:none}
.faq-item summary::-webkit-details-marker{display:none}
.faq-item summary::after{content:'+';float:right;color:var(--gold);font-size: var(--fs-20);line-height:1}
.faq-item[open] summary::after{content:'−'}
.faq-item p{margin:12px 0 0;font-size: var(--fs-16)}
.art-photo figcaption{font-size: var(--fs-13);color:var(--muted);padding:10px 2px 0}
@media (max-width:600px){
  .prose .facts th{width:auto;display:block;padding-bottom:2px}
  .prose .facts td{display:block;padding-top:0;padding-bottom:14px}
}

/* Карточка журнала с превью. Картинка «вылезает» за padding карточки (отрицательные
   поля) — иначе внутри белой рамки получается рамка в рамке. Соотношение 3:2
   фиксировано, чтобы карточки не прыгали при догрузке (CLS = 0). */
.card-pic{padding-top:0;overflow:hidden}
.card-img{display:block;margin:0 -26px 18px;line-height:0}
.card-img img{width:100%;height:auto;aspect-ratio:3/2;object-fit:cover;border-radius:var(--radius) var(--radius) 0 0}

/* ---- ЛИД-МАГНИТЫ ----------------------------------------------------------
   Две формы в середине страницы. Приём взят с realty5 и проверен там: заявка
   рядом с крупным человеческим лицом собирает заметно больше, чем форма в
   подвале, — до подвала доходит меньшинство. Фото занимает ровно половину и
   не обрезается по лицам: object-position смещён вверх, потому что в свадебной
   съёмке пара почти всегда в верхней трети кадра. */
.lead-band{padding-left:clamp(16px,3vw,40px);padding-right:clamp(16px,3vw,40px)}
.lead-card{display:grid;grid-template-columns:1.05fr .95fr;background:#fff;
  border-radius:var(--radius);overflow:hidden;box-shadow:0 24px 70px rgba(17,17,17,.09)}
.lead-text{padding:clamp(34px,4vw,62px)}
.lead-text h2{margin:10px 0 16px}
.lead-text p{max-width:520px}
.lead-form{max-width:none;margin-top:26px}
.lead-row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.lead-form .btn{width:auto;justify-self:start;padding:15px 34px}
.lead-pic{position:relative;min-height:420px;background:#f4f4f2}
.lead-pic img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 30%}

/* Магнит-полоса: фото во всю ширину, текст поверх. Затемнение — градиентом,
   а не сплошной плёнкой: правая часть кадра остаётся видимой, и фотография
   работает, а не превращается в серый фон. */
.magnet{position:relative;overflow:hidden;color:#fff;padding-top:clamp(64px,8vw,112px);
  padding-bottom:clamp(64px,8vw,112px)}
/* 🔴 Позиционируем САМ <img>, а не <picture>: в этой системе у picture стоит
   display:contents (чтобы обёртка не ломала сетки), и на такой элемент
   position/inset не действуют вовсе — фон молча остаётся в потоке и секция
   разъезжается. Ловилось глазами на скриншоте, в консоли ошибок нет. */
.magnet-bg{position:absolute;inset:0;z-index:0}
.magnet-bg img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;
  object-position:50% 35%}
.magnet::after{content:"";position:absolute;inset:0;z-index:1;
  background:linear-gradient(100deg,rgba(20,22,24,.9) 0%,rgba(20,22,24,.72) 45%,rgba(20,22,24,.15) 100%)}
.magnet-in{position:relative;z-index:2;max-width:620px}
.magnet-in h2{color:#fff;margin:10px 0 16px}
.magnet-in p{color:rgba(255,255,255,.82)}
.magnet-form{max-width:520px;margin-top:26px}
.magnet-form input{background:rgba(255,255,255,.12);color:#fff}
.magnet-form input::placeholder{color:rgba(255,255,255,.6)}
.magnet-form input:focus{background:rgba(255,255,255,.2)}
.magnet-form .btn{width:auto;padding:15px 30px;background:var(--gold);color:#fff}
.magnet-form .btn:hover{background:#fff;color:var(--ink)}
@media(max-width:900px){
  .lead-card{grid-template-columns:1fr}
  .lead-pic{min-height:320px;order:-1}   /* на телефоне сначала фото, потом форма */
  .lead-row{grid-template-columns:1fr}
  .magnet::after{background:linear-gradient(180deg,rgba(20,22,24,.72),rgba(20,22,24,.92))}
}

/* ═══ Читалка статьи: прогресс, оглавление-штрихи, плавность ══════════════
   Ширина колонки поднята с 72ch до 84ch (в 12-колоночной сетке это +2
   колонки, требование владельца 04.09.2026): при кегле 17/1.8 строка в 72ch
   на десктопе оставляла справа пустую треть экрана. Больше 88ch не берём —
   глаз теряет начало следующей строки. */
.prose{max-width:84ch}
.prose p{font-size: var(--fs-18);line-height:1.82}

.read-bar{position:fixed;top:0;left:0;right:0;height:3px;z-index:60;pointer-events:none}
.read-bar i{display:block;height:100%;width:0;background:var(--gold,#b6975c);
  transition:width .15s ease-out}

.toc{position:fixed;left:max(14px,calc(var(--side) + 18px));top:50%;
  transform:translateY(-50%);z-index:40;transition:opacity .3s}
.toc.is-past{opacity:0;pointer-events:none}
.toc__ticks{display:flex;flex-direction:column;align-items:flex-start;gap:8px;
  padding:8px 10px 8px 0;transition:opacity .25s}
.toc.is-open .toc__ticks{opacity:0}
.toc__tick{display:block;height:2px;width:16px;border-radius:2px;
  background:rgba(26,25,23,.28);transition:background .25s,width .25s}
.toc__tick.on{background:var(--gold,#b6975c);width:26px}
.toc__panel{position:absolute;left:0;top:50%;transform:translateY(-50%) translateX(-6px);
  width:286px;max-height:64vh;overflow-y:auto;background:#fff;border-radius:16px;
  padding:10px 8px;box-shadow:0 20px 60px rgba(26,25,23,.14);
  opacity:0;pointer-events:none;transition:opacity .22s ease,transform .22s ease}
.toc.is-open .toc__panel{opacity:1;pointer-events:auto;transform:translateY(-50%) translateX(0)}
.toc__cap{font:600 var(--fs-10)/1 var(--sans,inherit);letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);padding:8px 12px 10px}
.toc__panel ul{list-style:none;margin:0;padding:0}
.toc__panel button{display:block;width:100%;text-align:left;border:0;background:none;
  cursor:pointer;font:400 var(--fs-14)/1.35 inherit;color:var(--ink);padding:9px 12px;
  border-radius:10px;transition:background .18s,color .18s}
.toc__panel button:hover{background:#f6f4f0}
.toc__panel button.on{background:#f2efe8;font-weight:600}
.toc-fab{display:none}

.reveal{opacity:0;transform:translateY(14px);
  transition:opacity .55s cubic-bezier(.22,.61,.36,1),transform .55s cubic-bezier(.22,.61,.36,1)}
.reveal.in{opacity:1;transform:none}

.faq-item summary{cursor:pointer;list-style:none}
.faq-item summary::-webkit-details-marker{display:none}
.faq-wrap{overflow:hidden;height:0;transition:height .26s cubic-bezier(.22,.61,.36,1)}

@media (max-width:1280px){.toc{display:none}}
@media (max-width:860px){
  .prose{max-width:none}
  .toc-fab{display:block;position:fixed;right:14px;bottom:18px;z-index:50;border:0;
    padding:12px 18px;border-radius:999px;background:var(--ink,#1a1917);color:#fff;
    font:600 var(--fs-13)/1 inherit;letter-spacing:.04em;cursor:pointer;
    box-shadow:0 10px 30px rgba(0,0,0,.22);transition:opacity .3s}
  .toc-fab.is-past{opacity:0;pointer-events:none}
  .toc{display:block;position:fixed;inset:0;left:0;top:0;transform:none;
    background:rgba(0,0,0,.45);opacity:0;pointer-events:none}
  .toc.is-open{opacity:1;pointer-events:auto}
  .toc.is-past{display:none}
  .toc__ticks{display:none}
  .toc__panel{position:absolute;left:0;right:0;bottom:0;top:auto;width:auto;
    transform:none;max-height:74vh;border-radius:20px 20px 0 0;padding:14px 10px 26px;
    opacity:1;pointer-events:auto}
  .toc.is-open .toc__panel{transform:none}
  .toc__panel button{font-size: var(--fs-15);padding:13px 14px}
}
@media (prefers-reduced-motion:reduce){
  .reveal{opacity:1;transform:none;transition:none}
  .faq-wrap{transition:none}
}

/* ═══ Врезка внутри статьи (услуга / площадка) ═══════════════════════════
   Отбивается от текста фоном и золотой линией слева, но остаётся тише
   заголовков: врезка ярче H2 перебивает чтение и читается как баннер. */
.prose .inline-offer{margin:36px 0;padding:26px 28px;background:#faf8f4;
  border:0;border-radius:var(--radius,14px)}
.prose .inline-offer--venue{background:#f7f5f1}
.inline-offer__cap{font:600 var(--fs-10)/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;
  color:var(--gold-ink);margin-bottom:10px}
.prose .inline-offer h3{font-size: var(--fs-20);margin:0 0 8px;letter-spacing:.3px}
.prose .inline-offer p{font-size: var(--fs-15);line-height:1.65;margin:0 0 10px;color:var(--muted)}
.inline-offer__meta{display:block;font-size: var(--fs-13);color:var(--muted);margin-bottom:14px}
.btn--sm{display:inline-block;border-radius:999px;padding:12px 24px;font-size: var(--fs-12);letter-spacing:.12em}
@media (max-width:600px){.prose .inline-offer{padding:20px 18px;margin:28px 0}}

/* ═══ Эксперт-автор ══════════════════════════════════════════════════════
   Подпись под мнением и карточка автора в конце. Именованный специалист —
   это требование E-E-A-T и то, на что опираются ИИ-ассистенты, выбирая
   источник; безличная «редакция» опытом не считается. */
.opinion__sign{margin-top:16px;padding-top:14px;border-top:1px solid #ece9e2;
  font-size: var(--fs-13);color:var(--muted)}
.opinion__sign strong{color:var(--ink);font-weight:600}
.prose .expert{background:#fff;border:1px solid #ece9e2;border-radius:var(--radius);
  padding:24px 28px;margin:34px 0}
.expert__cap{font:600 var(--fs-10)/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;
  color:var(--gold-ink);margin-bottom:12px}
.prose .expert p{font-size: var(--fs-16);line-height:1.75;font-style:italic;color:var(--ink)}
.prose .expert p:last-child{margin-bottom:0}
.author-box{display:flex;gap:22px;align-items:flex-start;margin:52px 0 8px;
  padding:26px 28px;background:#faf9f7;border-radius:var(--radius)}
.author-box__ava{flex:0 0 62px;width:62px;height:62px;border-radius:50%;
  background:var(--ink);color:#fff;display:flex;align-items:center;justify-content:center;
  font:600 var(--fs-18)/1 var(--serif);letter-spacing:1px}
.author-box__cap{font:600 var(--fs-10)/1 var(--sans);letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);margin-bottom:8px}
.author-box h3{font-size: var(--fs-20);margin:0 0 4px}
.author-box__role{font-size: var(--fs-13);color:var(--gold-ink);margin:0 0 10px!important}
.author-box p{font-size: var(--fs-15);line-height:1.7;color:var(--muted);margin:0 0 12px}
.author-box__link{font-size: var(--fs-13);letter-spacing:.06em;border-bottom:1px solid var(--gold)}
@media (max-width:600px){.author-box{flex-direction:column;gap:14px;padding:22px 18px}}

/* ═══ Каталог статей в левой колонке ═════════════════════════════════════
   Заменил общее меню на странице статьи: пришедшему из поиска нужны соседние
   материалы, а не разделы сайта. Строка компактная (превью 64 px), чтобы в
   колонку 345 px помещалось два десятка статей без прокрутки-бесконечности. */
.cat{margin:26px 0 22px}
.cat__cap{font:600 var(--fs-10)/1 var(--sans);letter-spacing:.2em;text-transform:uppercase;
  color:var(--muted);margin-bottom:14px}
.cat-item{display:flex;gap:11px;align-items:flex-start;padding:8px 8px 8px 6px;
  margin:0 -6px;border:0;border-radius:8px;transition:background .18s}
.cat-item:hover{background:#f7f5f1}
.cat-item.on{background:#f2efe8}
.cat-item picture,.cat-item__ph{flex:0 0 64px;width:64px;height:42px;border-radius:4px;
  overflow:hidden;background:#eeece7;display:block}
.cat-item img{width:64px;height:42px;object-fit:cover}
.cat-item__t{font:400 var(--fs-12)/1.35 var(--sans);color:var(--ink);
  display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden}
.cat-item.on .cat-item__t{font-weight:600}
.pop{display:flex;gap:3px;margin-top:6px}
.pop i{width:12px;height:2px;border-radius:2px;background:#e0ddd6}
.pop i.on{background:var(--gold)}
.cat__all{display:block;margin-top:14px;font:600 var(--fs-10)/1 var(--sans);letter-spacing:.16em;
  text-transform:uppercase;color:var(--gold-ink);border:0}
@media (max-width:860px){
  /* На узком экране сайдбар встаёт НАД текстом, и каталог из двух десятков
     строк отодвигал саму статью на полтора экрана вниз — человек, пришедший
     из поиска, видел список вместо ответа. Поэтому на мобильном в шапке
     остаётся только контакт, а соседние материалы человек получает в конце
     статьи («Читайте также») и по ссылке на журнал. */
  .side .cat{display:none}
  .cat-item{padding:10px 6px}
}


/* ═══ Bento: факты и таблицы плитками ════════════════════════════════════
   Владелец 04.09.2026: «где есть таблицы информации — нужен бенто-стиль».
   Таблица «Параметр | Значение» в статье превращается в сетку плиток: цифра
   крупная, подпись мелкая — так факт читается за один взгляд, а не построчно.
   Смысловые таблицы (сравнения, расписание) остаются таблицами: там важны
   отношения между колонками, и плитки их ломают. */
.prose .facts.bento{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;
  border:0;margin-bottom:34px}
.prose .facts.bento tbody{display:contents}
.prose .facts.bento tr{display:flex;flex-direction:column-reverse;gap:6px;
  background:#faf8f4;border-radius:var(--radius);padding:20px 20px 18px}
.prose .facts.bento tr+tr th,.prose .facts.bento tr+tr td{box-shadow:none}
.prose .facts.bento th{font:400 var(--fs-12)/1.35 var(--sans);color:var(--muted);
  padding:0;width:auto;letter-spacing:.02em}
.prose .facts.bento td{font:600 var(--fs-20)/1.2 var(--sans);letter-spacing:-.01em;
  font-variant-numeric:tabular-nums;color:var(--ink);padding:0}
@media (max-width:860px){.prose .facts.bento{grid-template-columns:repeat(2,1fr)}}
@media (max-width:480px){.prose .facts.bento{grid-template-columns:1fr}}
.related__more{margin-top:18px;font-size: var(--fs-13);letter-spacing:.02em}
.related__more a{border-bottom:1px solid rgba(141,117,80,.4)}


/* ═══ Журнальный формат страницы: мета-рельс справа ════════════════════════
   Порт формата статьи с realty5.ru (владелец, 04.09.2026): колонка текста
   744 px, слева штрихи-оглавление, справа — карточка «о материале».

   ЗАЧЕМ РЕЛЬС. Длинный текст не отвечает на вопросы «сколько читать», «когда
   обновляли» и «кто это написал» — они решают, читать ли вообще. На realty5
   этот блок поднял дочитывания и снял часть звонков «а вы вообще кто».
   Рубрика, время чтения и дата стоят выше кнопок намеренно: сначала ответ
   на вопрос читателя, потом предложение.

   ЧЕГО НЕ ДЕЛАТЬ. Не показывать рельс на узком экране колонкой поверх текста:
   до 1200 px он уходит вниз статьи, а до 900 px исчезает совсем — там уже есть
   блок автора и CTA, и повтор превращается в стену кнопок. */
@media (min-width: 1200px) {
  .main { display: grid; grid-template-columns: minmax(0, 1fr) 300px;
          column-gap: clamp(20px, 3vw, 48px); align-items: start; }
  .main > .foot { grid-column: 1 / -1; }
  .rail { position: sticky; top: 28px; padding: clamp(34px,4.5vw,64px) 24px 0 0; }
}
.rail { min-width: 0; }
.rail__box {
  background: #faf8f4; border: 1px solid #efece5; border-radius: 18px;
  padding: 20px 18px 22px;
}
.rail__row { display: flex; flex-direction: column; gap: 3px; margin-bottom: 14px; }
.rail__cap {
  font: 600 var(--fs-10)/1 var(--ui); letter-spacing: .18em; text-transform: uppercase;
  color: var(--dim);
}
.rail__row b { font: 400 var(--fs-15)/1.35 var(--ui); color: var(--ink); }
.rail__btn { display: block; width: 100%; text-align: center; margin-top: 6px; }
.btn--ghost {
  background: transparent; color: var(--ink); border: 1px solid #e2ddd2;
}
.btn--ghost:hover { background: #f2efe8; }
.rail__author {
  display: flex; gap: 11px; align-items: center;
  margin: 18px 0 10px; padding-top: 16px; border-top: 1px solid #efece5;
}
.rail__author img { width: 52px; height: 52px; border-radius: 50%; object-fit: cover; }
.rail__author b { display: block; font: 400 var(--fs-15)/1.3 var(--serif, var(--ui)); color: var(--ink); }
.rail__author span { display: block; font-size: var(--fs-12); line-height: 1.4; color: var(--dim); }
.rail__note { font-size: var(--fs-13); line-height: 1.55; color: var(--dim); margin: 0 0 12px; }
.rail__phone {
  display: block; text-align: center; margin-top: 12px;
  font: 400 var(--fs-15)/1 var(--num, var(--ui)); letter-spacing: .5px; color: var(--ink);
}
@media (max-width: 1199px) {
  .rail { padding: 0 clamp(24px,5vw,80px) 30px; max-width: 72ch; }
}
@media (max-width: 900px) { .rail { display: none; } }

/* Нумерованный список журнального формата: цифра мелкая и акцентная,
   висит на поле, текст выровнен в одну линию — как в realty5. */
.prose ol { list-style: none; counter-reset: r5; padding-left: 0; }
.prose ol > li {
  counter-increment: r5; position: relative;
  padding-left: 34px; margin-bottom: 12px; line-height: 1.75;
}
.prose ol > li::before {
  content: counter(r5); position: absolute; left: 6px; top: 2px;
  font: 600 var(--fs-11)/1 var(--ui); color: var(--brass, #b6975c);
}


/* Три колонки статьи влезают только на очень широком экране: каталог слева
   345 px + текст + рельс 300 px. На 1440 px колонка текста сжималась до 608 px
   (у realty5 — 744), и строка становилась короткой и рваной. Поэтому до 1600 px
   левый каталог статей убираем: он вторичен — перелинковка дублируется блоком
   «Читайте также» внизу и футером, а ширина строки важнее. */
@media (max-width: 1599px) {
  .article-page .side { display: none; }
  .article-page .main { margin-left: 0; width: 100%; }
}
@media (min-width: 1200px) {
  .article-page .prose { max-width: 744px; }
}

/* ── Журнал: разделы по кластерам ──────────────────────────────────────────
   ЗАЧЕМ. 123 карточки плоским списком — стена, в которой не найти нужное.
   Разделы с якорями дают навигацию читателю и структуру поисковику; чипсы
   сверху показывают, сколько материалов в каждой теме, и работают как
   оглавление страницы. */
.cl-nav { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 28px; }
.cl-nav .chip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 7px 14px; border: 1px solid #e7e2d8; border-radius: 999px;
  font: 400 var(--fs-13)/1 var(--ui); color: var(--muted); text-decoration: none;
  background: #fff; transition: border-color .2s, color .2s;
}
.cl-nav .chip:hover { border-color: var(--gold, #c9a227); color: var(--ink); }
.cl-nav .chip b { font-weight: 500; color: var(--ink); }
.cl { margin: 0 0 44px; scroll-margin-top: 90px; }
.cl-title {
  font: 400 clamp(20px, 2.4vw, 26px)/1.2 var(--serif, Georgia, serif);
  color: var(--ink); margin: 0 0 16px;
}

/* ── Навигация по документам на юридических страницах ──────────────────────────
   🔴 Поймано проверкой 05.09.2026. Класс `article-page` носят три разных типа
   страниц, и правило `.article-page .side{display:none}` из общего листа прячет
   сайдбар у всех. Пока существовал старый макет статьи, его перебивало правило
   показа; вместе с макетом оно ушло — и на юрстраницах молча пропала навигация
   по шести документам (ссылки остались в разметке, но невидимыми).
   Здесь она возвращается адресно: только для .legal-page. */
/* 🔴 НА МОБИЛЬНОМ ЮРСТРАНИЦА БЫЛА ТУПИКОМ. Правило показа сайдбара сделано
   только для ≥1100 px, а `.article-page .side{display:none}` действует всегда —
   значит на телефоне у документа не оставалось НИ навигации по остальным пяти
   документам, НИ ссылки на главную: 14 ссылок в DOM, из них 9 невидимых.
   Возвращаем список документов ПОД текстом (сверху он мешал бы читать сам
   документ) и оформляем как обычный блок, без sticky. Телефон и кнопку прячем:
   на юрстранице человек читает, а не заказывает. */
@media (max-width: 1099px) {
  body.legal-page .layout { display: flex; flex-direction: column; }
  body.legal-page .side { display: block !important; order: 2;
    margin: 2.5rem 0 0; padding-top: 1.6rem; border-top: 1px solid var(--line); }
  body.legal-page .main { order: 1; }
  body.legal-page .side .logo { display: block; margin-bottom: 1.4rem; }
  /* На узком экране места хватает, и подпись вставала В СТРОКУ с логотипом,
     читаясь как одно слово «WEDSOCHIСВАДЕБНОЕ». Явный блок и отступ. */
  body.legal-page .side .logo small { display: block; margin-top: 5px; }
  body.legal-page .side .btn, body.legal-page .side .side-phone { display: none; }
  body.legal-page .side .cat { display: block; }
}

@media (min-width: 1100px) {
  body.legal-page .layout {
    display: grid;
    grid-template-columns: minmax(13rem, 17rem) minmax(0, 46rem) 1fr;
    column-gap: 2.5rem; padding-left: 2rem;
  }
  /* Обе строки обязательны: .side идёт в разметке первым, и без явной строки
     .main уезжает во вторую — та же грабля, что ловили на старом макете. */
  body.legal-page .side { display: block !important;
    grid-column: 1; grid-row: 1; position: sticky;
    inset: auto; top: 5.5rem; align-self: start;
    max-height: calc(100vh - 7rem); overflow-y: auto; overflow-x: hidden;
    padding: 0; background: none; border: 0; width: 100%; flex: initial; z-index: auto;
  }
  body.legal-page .main { grid-column: 2; grid-row: 1; display: block; }
  body.legal-page .rail { display: none; }
}

/* ── Cookie-баннер и согласие в формах: нужны НА ВСЕХ страницах ──────────────
   Раньше эти правила лежали в v2/article.css, который подключён только к новым
   статьям: на главной, юридических страницах и в историях баннер появлялся бы
   без оформления. Метрика работает везде — значит и уведомление везде. */
/* Баннер о cookie (05.09.2026): сайт ставит Метрику и пишет в localStorage,
   поэтому посетителя надо уведомить. Своя реализация вместо стороннего сервиса —
   чужой загрузчик сам по себе тянет cookie, о которых мы не сможем отчитаться. */
#cookie-note {
  position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 60;
  max-width: 720px; margin: 0 auto; display: flex; gap: 14px; align-items: center;
  background: var(--white, #fffdfa); border: 1px solid var(--cream-dark, #ece6dc);
  border-radius: var(--radius-lg); padding: 14px 18px;
  box-shadow: 0 12px 40px rgba(60,40,20,.14);
  font-family: var(--font-sans); font-size: var(--fs-13); line-height: 1.5;
}
#cookie-note p { margin: 0; color: var(--text-primary, #2f2620); }
#cookie-note a { color: var(--brown-mid, #6b4c2d); text-decoration: underline; }
#cookie-ok {
  flex: 0 0 auto; border: 0; cursor: pointer;
  background: var(--brown-deep, #3d2b1f); color: var(--warm-white, #fdfbf8);
  border-radius: var(--radius-btn); padding: 10px 20px;
  font-family: var(--font-sans); font-size: var(--fs-12);
  letter-spacing: .12em; text-transform: uppercase;
}
@media (max-width: 620px) { #cookie-note { flex-direction: column; align-items: stretch; } }

/* Чекбокс согласия в формах */
.form-consent {
  display: flex; gap: 10px; align-items: flex-start;
  font-family: var(--font-sans); font-size: var(--fs-12); line-height: 1.45;
  color: var(--text-muted, #6f6257); margin: 4px 0 12px; cursor: pointer;
}
.form-consent input { margin-top: 2px; flex: 0 0 auto; accent-color: var(--brown-deep, #3d2b1f); }
.form-consent a { color: var(--brown-mid, #6b4c2d); text-decoration: underline; }

/* ── Унаследованные статьи без сайдбара ────────────────────────────────────────
   🔴 Поймано замером 05.09.2026. Раньше колонку текста держал слева сайдбар с
   каталогом; после его удаления текст остался прижат к левому краю, а справа
   зияло 721 px пустоты — при внешне исправной вёрстке. Центрируем колонку
   адресно: у нового макета (.article-v2) своя сетка, у юридических страниц
   (.legal-page) сайдбар остался, их правило не касается. */
@media (min-width: 1100px) {
  /* У .main из общего листа стоит сетка «текст + рельс 300 px». Рельса на этих
     страницах нет, но колонка под него резервируется — и текст, центрируясь внутри
     первой колонки, всё равно оказывался левее середины экрана (замер: 189 слева
     против 532 справа). Возвращаем блочный поток, тогда центрирует margin: auto. */
  body.article-page:not(.article-v2):not(.legal-page) .main { display: block; }
  body.article-page:not(.article-v2):not(.legal-page) .rail { display: none; }
  body.article-page:not(.article-v2):not(.legal-page) .prose {
    margin-left: auto; margin-right: auto;
  }
}

/* Юридические ссылки в футере журнала и унаследованных страниц: отдельной строкой,
   мельче копирайта — это служебная навигация, а не часть контактов. */
.foot__docs { display: block; margin-top: 10px; font-size: var(--fs-12);
              line-height: 1.9; color: var(--muted); }
.foot__docs a { color: var(--muted); border-bottom: 1px solid rgba(141,117,80,.28); }
.foot__docs a:hover { color: var(--ink); }
