/* umorya.com — каталог новостроек побережья.
   Палитра, ритм и вёрстка по work/umorya/design-plan.md.

   Порядок файла: переменные → основа и типографика → секции → компоненты → печать.
   Медиазапросы стоят рядом с правилом, которое поправляют, а не собраны в конце: искать
   поведение блока на телефоне удобнее там же, где описано его поведение на десктопе.

   Словарь классов — контракт для генераторов (build_index, build_pages, build_hubs,
   build_service):
     .hold / .hold--wide      колонка контента 1220 / полосная 1440
     .masthead                шапка; .masthead__panel — раскрытие на узком экране
     .slab / --band / --dark  секция; полынная заливка; тёмная полоса
     .kicker .lede .meta-line надзаголовок, лид, строка меты
     .shore-scale             signature «Отступ от воды»
     .reach-tool              мини-инструмент бюджета
     .rubricator              формат / класс / бюджет / готовность
     .coast-index .resort-index  указатель географии
     .residence-grid .residence-card  карточки объектов
     .residence-list          плотный текстовый указатель объектов
     .statement               полоса-утверждение
     .principles              пронумерованные пункты
     .qa                      FAQ на <details>
     .copy                    авторская проза из markdown
     .fact-row .fact          опорные цифры
     .marker-row .marker      пометки объекта
     .request                 форма заявки (выключена флагом сборки)
     .sitefoot                подвал-указатель
     .figure-note             подпись кадра
     .consent-bar             уведомление о хранилище браузера
     .um-map                  карта побережья (SVG, точки, попап-карточка, фильтры-ссылки)
     .karta-page               /karta/ — полная карта на всю ширину, список объектов сбоку
     .obj-map                 переключатель «Где на берегу» / «Что вокруг» на странице объекта
     .builder-page            хаб застройщика (дисклеймер под H1, сводка фактов, карта, объекты)
     .builders-root           корень раздела /zastroyshchik/ — плитка 19 брендов
*/

/* ── переменные ────────────────────────────────────────────────────────────── */

:root {
  --c-bg: #EFF1EA;
  --c-surface: #FFFFFF;
  --c-band: #E1E6DA;
  --c-edge: #CBD3C4;
  --c-ink: #12312B;
  --c-ink-2: #3C4E48;
  --c-muted: #5E6B65;
  --c-accent: #A8431C;
  --c-accent-soft: #DD9163;
  --c-dark: #12312B;
  --c-sand: #C9D2C1;

  /* карта: вода (фон обёртки) и суша (заливка контура). Держались литералами, пока их дублировал
     canvas 2D — `ctx.fillStyle` не читает custom properties без отдельного JS-моста. Канвас
     удалён (задача 14 плана 2026-08-20), рисует карту только CSS — цвета вернулись в палитру. */
  --c-map-sea: #DCEAF0;
  --c-map-land: #F2EDE1;

  /* ступени signature: тональный ряд доминанты, ближе к воде — плотнее */
  --c-tide-1: #12312B;
  --c-tide-2: #3C4E48;
  --c-tide-3: #7C8A83;
  --c-tide-4: #B7C1B6;

  --c-col: 1220px;
  --c-col-wide: 1440px;
  --c-step: clamp(56px, 8vw, 112px);
  --c-gutter: clamp(16px, 3.4vw, 34px);
  --c-round: 12px;
  --c-round-tight: 3px;
  --c-ease: cubic-bezier(.2, .7, .3, 1);

  --c-serif: 'Literata', Georgia, 'Times New Roman', serif;
  --c-sans: 'Commissioner', 'Segoe UI', 'Helvetica Neue', sans-serif;
}

/* ── основа и типографика ──────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-ink);
  font: 300 17px/1.62 var(--c-sans);
  font-variant-numeric: tabular-nums;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, h4 {
  font-family: var(--c-serif);
  font-weight: 300;
  line-height: 1.14;
  letter-spacing: -.012em;
  margin: 0 0 .5em;
  text-wrap: balance;
}

h1 { font-size: clamp(2.6rem, 6.4vw, 4.6rem); }
h2 { font-size: clamp(1.72rem, 3.4vw, 2.5rem); }
h3 { font-size: clamp(1.18rem, 2vw, 1.42rem); }
h4 { font-size: 1.06rem; font-family: var(--c-sans); font-weight: 600; letter-spacing: 0; }

p { margin: 0 0 1.05em; max-width: 74ch; }

a { color: var(--c-accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { text-decoration: none; }
a:focus-visible, summary:focus-visible, button:focus-visible, input:focus-visible,
select:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }

img { max-width: 100%; height: auto; display: block; }

.hold { width: 100%; max-width: var(--c-col); margin: 0 auto; padding: 0 var(--c-gutter); }
.hold--wide { max-width: var(--c-col-wide); }

.kicker {
  font-size: .82rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--c-muted);
  margin: 0 0 .9em;
}

.lede {
  font-size: clamp(1.06rem, 1.5vw, 1.24rem);
  color: var(--c-ink-2);
  max-width: 62ch;
}

.meta-line {
  display: flex;
  flex-wrap: wrap;
  gap: .5em 1.4em;
  margin: 1.6em 0 0;
  padding: .9em 0 0;
  border-top: 1px solid var(--c-edge);
  font-size: .94rem;
  color: var(--c-ink-2);
  list-style: none;
}
.meta-line b { font-weight: 600; }

.figure-note {
  margin: .55em 0 0;
  font-size: .84rem;
  color: var(--c-muted);
}

.season-note {
  margin: 1.4em 0 0;
  padding-left: 1em;
  border-left: 2px solid var(--c-accent);
  font-size: .95rem;
  color: var(--c-ink-2);
}

/* ── шапка ─────────────────────────────────────────────────────────────────── */

.masthead {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--c-bg);
  border-bottom: 1px solid var(--c-edge);
}
.masthead__row {
  display: flex;
  align-items: center;
  gap: clamp(12px, 2vw, 28px);
  min-height: 66px;
}
.masthead__mark { text-decoration: none; color: var(--c-ink); display: flex;
  flex-direction: column; gap: 2px; }
.masthead__mark b { font: 500 1.25rem/1 var(--c-serif); }
.masthead__mark span { font-size: .78rem; color: var(--c-muted); }
.masthead__counts {
  margin: 0;
  margin-left: auto;
  font-size: .84rem;
  color: var(--c-muted);
  max-width: 46ch;
}
.masthead__act {
  flex: none;
  background: var(--c-accent);
  color: #FFFFFF;
  text-decoration: none;
  border-radius: var(--c-round-tight);
  padding: .62em 1.15em;
  font-size: .92rem;
}
.masthead__act:hover { background: var(--c-ink); }
.masthead__nav { border-top: 1px solid var(--c-edge); }
.masthead__panel { display: block; }
.masthead__toggle { display: none; }
.masthead__toggle::-webkit-details-marker { display: none; }
.masthead__links {
  display: flex;
  flex-wrap: wrap;
  gap: .2em 1.4em;
  margin: 0;
  padding: .55em 0;
  list-style: none;
  font-size: .93rem;
}
.masthead__links a { color: var(--c-ink-2); text-decoration: none; }
.masthead__links a:hover { color: var(--c-accent); }

/* Липкая шапка перекрывала бы цель якоря — секция уезжала бы под неё. */
:target { scroll-margin-top: 130px; }

@media (max-width: 900px) {
  .masthead__counts { display: none; }
  .masthead__toggle { display: block; padding: .6em 0; cursor: pointer;
    font-size: .93rem; color: var(--c-ink-2); }
  .masthead__links { flex-direction: column; gap: .1em; padding-bottom: .8em; }
  :target { scroll-margin-top: 76px; }
}

/* ── секции ────────────────────────────────────────────────────────────────── */

/* Каждая секция несёт свой вертикальный отступ. Обнуление сверху оставлено ровно для того
   случая, ради которого его когда-то и писали: две подряд идущие секции без заливки, где
   двойной отступ читался бы провалом. У цветной секции (--band/--dark) отступ сверху есть
   всегда: без него фон начинается ровно на заголовке, и заголовок липнет к предыдущему
   блоку — замечание заказчика от 20.08.2026. */
.slab { padding: var(--c-step) 0; }
.slab:not(.slab--band):not(.slab--dark) + .slab:not(.slab--band):not(.slab--dark) {
  padding-top: 0;
}

.slab--band {
  background-color: var(--c-band);
  /* известняковый слой: горизонтальная штриховка почти на пределе видимости */
  background-image: repeating-linear-gradient(
    to bottom,
    rgba(18, 49, 43, .04) 0 1px,
    transparent 1px 4px
  );
  padding: var(--c-step) 0;
}

.slab--dark {
  background: var(--c-dark);
  color: var(--c-sand);
  padding: calc(var(--c-step) * .8) 0;
}
.slab--dark h2, .slab--dark h3 { color: #FFFFFF; }
.slab--dark a { color: var(--c-accent-soft); }

.slab__head { max-width: 74ch; margin-bottom: 2.2em; }
.slab__head p:last-child { margin-bottom: 0; }

.opening { padding: clamp(34px, 5vw, 68px) 0 0; }
.opening h1 { margin-bottom: .38em; }
.opening__frame { margin-top: clamp(28px, 4vw, 52px); }
.opening__frame img {
  width: 100%;
  height: clamp(180px, 26vw, 340px);
  object-fit: cover;
  border-radius: var(--c-round);
}

/* Первый экран в две колонки: слева текст и цифры, справа карточка формы (спека §3.2).
   Точка перелома — 900px, та же, что у шапки: ниже неё колонки складываются, форма встаёт
   под цифрами и остаётся в поле зрения без горизонтальной тесноты. */
.opening--split .hold {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(320px, .85fr);
  gap: clamp(26px, 4vw, 64px);
  align-items: start;
}
@media (max-width: 900px) {
  .opening--split .hold { grid-template-columns: 1fr; }
}
.opening__text p.lede { max-width: 46ch; }

.hero-form {
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  padding: clamp(18px, 2.4vw, 28px);
}
.hero-form__title { font-size: clamp(1.3rem, 2.2vw, 1.6rem); margin-bottom: .35em; }
.hero-form__note { font-size: .92rem; color: var(--c-ink-2); margin-bottom: 1.1em; }
.hero-form .request { border: 0; padding: 0; background: none; border-radius: 0; }

/* ── signature «Отступ от воды» ────────────────────────────────────────────── */

.shore-scale {
  margin: 0;
  border-top: 1px solid var(--c-edge);
}

.shore-scale__row {
  display: grid;
  grid-template-columns: 180px 1fr 148px;
  align-items: end;
  gap: 0 18px;
  min-height: 52px;
  padding: 12px 0;
  border-bottom: 1px solid var(--c-edge);
  animation: shore-rise 420ms var(--c-ease) both;
  animation-delay: calc(var(--i, 0) * 60ms);
}
.shore-scale__row--total {
  border-bottom: 2px solid var(--c-ink);
  min-height: 96px;
}

@keyframes shore-rise {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.shore-scale__label {
  font-size: .96rem;
  color: var(--c-ink);
  text-decoration: none;
  align-self: center;
}
.shore-scale__label:hover { color: var(--c-accent); }
.shore-scale__label i {
  display: block;
  font-style: normal;
  font-size: .8rem;
  color: var(--c-muted);
}

.shore-scale__track {
  position: relative;
  display: flex;
  align-items: flex-end;
  height: 46px;
}

.shore-scale__step {
  position: relative;
  display: block;
  flex: none;            /* ширина ступени — протяжённость полосы на оси, ужимать её нельзя */
  align-self: flex-end;
  min-height: 2px;
  border-radius: var(--c-round-tight) var(--c-round-tight) 0 0;
  text-decoration: none;
  transition: filter 180ms var(--c-ease);
}
.shore-scale__step:hover { filter: brightness(1.35); }
.shore-scale__step--near { background: var(--c-tide-1); }
.shore-scale__step--mid { background: var(--c-tide-2); }
.shore-scale__step--far { background: var(--c-tide-3); }
.shore-scale__step--out { background: var(--c-tide-4); }
.shore-scale__step--empty { background: transparent; }

.shore-scale__count {
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  text-align: center;
  font-size: .78rem;
  color: var(--c-ink-2);
  padding-bottom: 2px;
}

/* Медиана цены входа стоит ПОД ступенью сводной строки, а не внутри неё: на плотной заливке
   тонального ряда мелкий текст читается через раз, а перекрашивать его под четыре разных фона
   значило бы держать четыре пары контрастов вместо одной. Ступень служит только якорем
   позиционирования; место под строку медиан зарезервировано нижним отступом трека. */
.shore-scale__median {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  font-size: .8rem;
  color: var(--c-muted);
  text-align: center;
  padding-top: 4px;
  white-space: nowrap;
}

.shore-scale__row--total .shore-scale__track { height: 74px; padding-bottom: 28px; }
.shore-scale__row--total .shore-scale__label b { font-weight: 600; }

.shore-scale__sum {
  font-size: .86rem;
  color: var(--c-ink-2);
  text-align: right;
  align-self: center;
}

/* Медианы полос одной строкой — запасная подача сводки для узкого экрана, где подпись под
   ступенью в 54 px не помещается ни при каком кегле. */
.shore-scale__medians { display: none; }

/* Ось стоит под треками, а не под всей строкой: подпись группы слева и сводка справа в неё
   не входят, и без этих отступов деление «500 м» встало бы левее собственной ступени. Отступы
   повторяют колонки .shore-scale__row и меняются вместе с ними на каждом брейкпоинте. */
.shore-scale__axis {
  display: flex;
  margin: 10px 0 0;
  padding: 0 166px 0 198px;
  list-style: none;
  font-size: .76rem;
  color: var(--c-muted);
}
.shore-scale__tick {
  border-left: 1px solid var(--c-edge);
  padding-left: 6px;
}
.shore-scale__tick--hard { border-left-color: var(--c-ink-2); }
.shore-scale__tick--slim { display: block; }

.shore-scale__legend {
  margin: 1.2em 0 0;
  font-size: .88rem;
  color: var(--c-muted);
}

.shore-scale__row.is-lit .shore-scale__label { color: var(--c-accent); }

@media (max-width: 1180px) {
  .shore-scale__row { grid-template-columns: 160px 1fr; }
  .shore-scale__sum { grid-column: 1; grid-row: 2; text-align: left; font-size: .8rem; }
  .shore-scale__axis { padding: 0 0 0 178px; }
}

@media (max-width: 860px) {
  .shore-scale__row {
    grid-template-columns: 1fr;
    min-height: 68px;
    gap: 6px 0;
  }
  .shore-scale__sum { grid-column: 1; grid-row: 3; }
  .shore-scale__label { align-self: start; }
  .shore-scale__axis { padding: 0; }
}

@media (max-width: 560px) {
  .shore-scale__row { min-height: 64px; }
  .shore-scale__track { height: 38px; }
  /* Отметка «40 м» уходит, но её место на оси остаётся: у делений заданы ширины полос, и
     выброшенное из потока деление сдвинуло бы все следующие мимо своих ступеней. */
  .shore-scale__tick--slim { visibility: hidden; }
  .shore-scale__row--total .shore-scale__track { height: 38px; padding-bottom: 0; }
  .shore-scale__median { display: none; }
  .shore-scale__medians {
    display: block;
    margin: .8em 0 0;
    font-size: .8rem;
    color: var(--c-muted);
  }
}

/* ── мини-инструмент ───────────────────────────────────────────────────────── */

.reach-tool {
  margin-top: clamp(28px, 4vw, 46px);
  padding: clamp(18px, 2.6vw, 28px);
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
}
.reach-tool h3 { margin-bottom: .7em; }

.reach-tool__controls {
  display: grid;
  grid-template-columns: minmax(240px, 2fr) minmax(180px, 1fr);
  gap: 14px 26px;
  align-items: end;
}
@media (max-width: 860px) {
  .reach-tool__controls { grid-template-columns: 1fr; }
}

.reach-tool__field label {
  display: block;
  font-size: .86rem;
  color: var(--c-muted);
  margin-bottom: .35em;
}
.reach-tool__field input[type="range"] { width: 100%; accent-color: var(--c-accent); }
.reach-tool__field select {
  width: 100%;
  padding: .55em .7em;
  font: inherit;
  color: var(--c-ink);
  background: var(--c-bg);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round-tight);
}
.reach-tool__value {
  font-family: var(--c-serif);
  font-size: 1.2rem;
}

.reach-tool__out {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 10px;
  margin: 1.4em 0 0;
  padding: 0;
  list-style: none;
}
@media (max-width: 560px) {
  .reach-tool__out { grid-template-columns: repeat(2, 1fr); }
}

.reach-tool__cell {
  border-top: 2px solid var(--c-ink);
  padding-top: .5em;
}
.reach-tool__cell b {
  display: block;
  font: 300 1.7rem/1.1 var(--c-serif);
}
.reach-tool__cell span {
  font-size: .82rem;
  color: var(--c-muted);
}

.reach-tool__nearest {
  margin: 1.2em 0 0;
  font-size: .96rem;
  color: var(--c-ink-2);
}
.reach-tool__link { font-weight: 600; }

/* ── рубрикатор ────────────────────────────────────────────────────────────── */

.rubricator {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(216px, 1fr));
  gap: 18px;
}

.rubricator__group {
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  padding: 18px 20px 20px;
}
.rubricator__group h3 {
  font-family: var(--c-sans);
  font-size: .82rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--c-muted);
  margin-bottom: .9em;
}

.rubricator__list { margin: 0; padding: 0; list-style: none; }
.rubricator__list li + li { border-top: 1px solid var(--c-edge); }
.rubricator__list a {
  display: flex;
  justify-content: space-between;
  gap: 1em;
  padding: .5em 0;
  color: var(--c-ink);
  text-decoration: none;
}
.rubricator__list a:hover { color: var(--c-accent); }
.rubricator__list i {
  font-style: normal;
  color: var(--c-muted);
  font-size: .9rem;
}

/* ── указатель географии ───────────────────────────────────────────────────── */

.coast-index {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: 0 clamp(24px, 3vw, 48px);
}
@media (min-width: 900px)  { .coast-index { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1400px) { .coast-index { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.coast-index__item {
  padding: 1.05em 0;
  border-top: 1px solid var(--c-edge);
}
.coast-index__item:last-child { border-bottom: 1px solid var(--c-edge); }

.coast-index__name {
  font: 300 clamp(1.2rem, 2vw, 1.55rem)/1.2 var(--c-serif);
  color: var(--c-ink);
  text-decoration: none;
}
.coast-index__name:hover { color: var(--c-accent); }

.coast-index__facts {
  margin: .3em 0 0;
  font-size: .9rem;
  color: var(--c-muted);
}

.resort-index {
  display: flex;
  flex-wrap: wrap;
  gap: .35em 1.1em;
  margin: .7em 0 0;
  padding: 0;
  list-style: none;
  font-size: .94rem;
}
.resort-index a { color: var(--c-ink-2); text-decoration: none; }
.resort-index a:hover { color: var(--c-accent); text-decoration: underline; }
.resort-index i { font-style: normal; color: var(--c-muted); font-size: .84rem; }

/* ── карточки объектов ─────────────────────────────────────────────────────── */

.residence-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(268px, 1fr));
  gap: 20px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.residence-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  overflow: hidden;
  color: var(--c-ink);
  text-decoration: none;
  transition: border-color 200ms var(--c-ease), transform 200ms var(--c-ease);
}
.residence-card:hover { border-color: var(--c-ink-2); transform: translateY(-2px); }

.residence-card__frame { position: relative; display: block; background: var(--c-band); }
.residence-card__frame img { width: 100%; height: 176px; object-fit: cover; }

.residence-card__stage {
  position: absolute;
  left: 10px;
  bottom: 10px;
  background: var(--c-dark);
  color: var(--c-sand);
  font-size: .76rem;
  padding: .25em .6em;
  border-radius: var(--c-round-tight);
}

.residence-card__format {
  position: absolute;
  right: 10px;
  top: 10px;
  background: var(--c-accent);
  color: #FFFFFF;
  font-size: .74rem;
  letter-spacing: .04em;
  padding: .25em .6em;
  border-radius: var(--c-round-tight);
}

.residence-card__text {
  display: flex;
  flex-direction: column;
  gap: .3em;
  padding: 16px 18px 18px;
  flex: 1;
}

.residence-card__name { font: 500 1.16rem/1.25 var(--c-serif); }
.residence-card__place { font-size: .88rem; color: var(--c-muted); }
.residence-card__reach { font-size: .9rem; color: var(--c-ink-2); }

.residence-card__sum {
  margin-top: auto;
  padding-top: .6em;
  font-size: 1.06rem;
  font-weight: 600;
}
.residence-card__sum i {
  display: block;
  font-style: normal;
  font-weight: 300;
  font-size: .84rem;
  color: var(--c-muted);
}
.residence-card__sum--ask { color: var(--c-ink-2); font-weight: 400; }

.residence-card__facts {
  display: flex;
  flex-wrap: wrap;
  gap: .3em .9em;
  padding-top: .5em;
  border-top: 1px solid var(--c-edge);
  font-size: .84rem;
  color: var(--c-muted);
}

.more-line { margin: 1.8em 0 0; text-align: center; }
.more-line__act {
  font: inherit;
  color: var(--c-accent);
  background: transparent;
  border: 1px solid var(--c-accent);
  border-radius: var(--c-round-tight);
  padding: .6em 1.6em;
  cursor: pointer;
}
.more-line__act:hover { background: var(--c-accent); color: #FFFFFF; }
/* Тот же класс носит ссылка «Все N объектов каталога» — у кнопки это `<button>`,
   а у перехода `<a>`: инлайновой ссылке нужны блочность (иначе вертикальные отступы
   не раздвигают строку) и снятое подчёркивание. */
a.more-line__act { display: inline-block; text-decoration: none; }
.more-line__act[hidden] { display: none; }

/* ── плотный указатель объектов ────────────────────────────────────────────── */

.residence-list { margin: 0; padding: 0; list-style: none; }
.residence-list__group { margin-top: 2.2em; }
.residence-list__group:first-child { margin-top: 0; }
.residence-list__group h3 {
  font-family: var(--c-sans);
  font-size: .84rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--c-muted);
  padding-bottom: .5em;
  border-bottom: 1px solid var(--c-ink-2);
}
.residence-list__rows { margin: 0; padding: 0; list-style: none; }
.residence-list__rows li { border-bottom: 1px solid var(--c-edge); }
.residence-list__rows a {
  display: grid;
  /* Средняя колонка шире крайних: в ней курорт и расчётное расстояние — самая длинная
     строка указателя, и на «Туапсинский район · около 48 м до берега по прямой» она рвётся
     надвое. Колонка цены фиксирована: «от 28,54 млн ₽» шире не станет. */
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 2fr) 150px;
  gap: .2em 1.2em;
  padding: .5em 0;
  color: var(--c-ink);
  text-decoration: none;
  font-size: .94rem;
}
.residence-list__rows a:hover { color: var(--c-accent); }
.residence-list__rows em { font-style: normal; color: var(--c-muted); }
.residence-list__rows b { font-weight: 600; text-align: right; }

@media (max-width: 860px) {
  .residence-list__rows a { grid-template-columns: 1fr auto; }
  .residence-list__rows em { grid-column: 1; font-size: .84rem; }
  .residence-list__rows b { grid-column: 2; grid-row: 1; }
}

/* ── полоса-утверждение и пронумерованные пункты ───────────────────────────── */

.statement { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); gap: 26px; }
.statement__figure { font: 300 clamp(2.4rem, 5vw, 3.8rem)/1.05 var(--c-serif); color: #FFFFFF; }
.statement p { color: var(--c-sand); margin-bottom: 0; }
@media (max-width: 860px) {
  .statement { grid-template-columns: 1fr; gap: 14px; }
}

.principles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 22px;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: principle;
}
.principles__item {
  border-top: 2px solid var(--c-ink);
  padding-top: .8em;
  counter-increment: principle;
}
.principles__item::before {
  content: "0" counter(principle);
  display: block;
  font-family: var(--c-serif);
  font-size: .96rem;
  color: var(--c-accent);
  margin-bottom: .3em;
}
.principles__item h3 { font-family: var(--c-sans); font-size: 1rem; font-weight: 600; }
.principles__item p { font-size: .94rem; color: var(--c-ink-2); margin-bottom: 0; }

/* ── проза, цифры, пометки ─────────────────────────────────────────────────── */

.copy { max-width: 74ch; }
.copy h2 { margin-top: 1.6em; }
.copy h3 { margin-top: 1.4em; }
.copy ul, .copy ol { padding-left: 1.2em; }
.copy li { margin-bottom: .35em; }

.fact-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 18px;
  margin: 0 0 2em;
  padding: 0;
  list-style: none;
}
.fact { border-top: 2px solid var(--c-ink); padding-top: .5em; }
.fact b { display: block; font: 300 1.6rem/1.15 var(--c-serif); }
.fact span { font-size: .84rem; color: var(--c-muted); }

.marker-row { display: flex; flex-wrap: wrap; gap: .5em; margin: 0 0 1.4em; padding: 0; list-style: none; }
.marker {
  display: inline-block;
  padding: .28em .7em;
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round-tight);
  font-size: .84rem;
  color: var(--c-ink-2);
  text-decoration: none;
  background: var(--c-surface);
}
a.marker:hover { border-color: var(--c-accent); color: var(--c-accent); }
.marker--format { border-color: var(--c-accent); color: var(--c-accent); }

.grid-table {
  width: 100%;
  border-collapse: collapse;
  font-size: .94rem;
}
.grid-table th, .grid-table td {
  text-align: left;
  padding: .55em .8em .55em 0;
  border-bottom: 1px solid var(--c-edge);
}
.grid-table th { font-weight: 600; color: var(--c-muted); font-size: .84rem; }
.grid-table td:last-child, .grid-table th:last-child { text-align: right; padding-right: 0; }
.table-scroll { overflow-x: auto; }

/* ── FAQ ───────────────────────────────────────────────────────────────────── */

.qa { margin: 0; padding: 0; list-style: none; }
.qa__item { border-top: 1px solid var(--c-edge); }
.qa__item:last-child { border-bottom: 1px solid var(--c-edge); }
.qa__item summary {
  cursor: pointer;
  padding: .9em 0;
  font-weight: 600;
  list-style: none;
}
.qa__item summary::-webkit-details-marker { display: none; }
.qa__item summary::after { content: " +"; color: var(--c-accent); }
.qa__item[open] summary::after { content: " –"; }
.qa__item p { font-size: .96rem; color: var(--c-ink-2); }

/* ── форма заявки ──────────────────────────────────────────────────────────── */

.request {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px 20px;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  padding: clamp(18px, 2.6vw, 28px);
}
@media (max-width: 560px) {
  .request { grid-template-columns: 1fr; }
}
.request--compact { grid-template-columns: 1fr; }

.request__cell label {
  display: block;
  font-size: .86rem;
  color: var(--c-muted);
  margin-bottom: .3em;
}
.request__cell input[type="text"], .request__cell select, .request__cell textarea {
  width: 100%;
  padding: .6em .75em;
  font: inherit;
  color: var(--c-ink);
  background: var(--c-bg);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round-tight);
}
.request__cell--wide { grid-column: 1 / -1; }

.request__trap { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.request__agree {
  display: flex;
  gap: .6em;
  font-size: .88rem;
  color: var(--c-ink-2);
  margin-bottom: 0;
}
.request__agree input { margin-top: .25em; accent-color: var(--c-accent); }

.request__send {
  font: inherit;
  font-weight: 600;
  width: 100%;
  color: #FFFFFF;
  background: var(--c-accent);
  border: 1px solid var(--c-accent);
  border-radius: var(--c-round-tight);
  padding: .75em 1.4em;
  cursor: pointer;
  transition: background-color 180ms var(--c-ease);
}
.request__send:hover { background: #8C3616; }

/* ── подвал ────────────────────────────────────────────────────────────────── */

.sitefoot {
  margin-top: var(--c-step);
  padding: calc(var(--c-step) * .7) 0 40px;
  background: var(--c-dark);
  color: var(--c-sand);
}
.sitefoot a { color: var(--c-sand); text-decoration: none; }
.sitefoot a:hover { color: var(--c-accent-soft); text-decoration: underline; }

.sitefoot__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.5fr) repeat(3, minmax(0, 1fr));
  gap: 28px 26px;
}
@media (max-width: 1180px) {
  .sitefoot__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 560px) {
  .sitefoot__grid { grid-template-columns: 1fr; }
}

.sitefoot__brand b { font: 500 1.3rem/1 var(--c-serif); color: #FFFFFF; }
.sitefoot__brand p { font-size: .92rem; margin-top: .7em; }

.sitefoot h3 {
  font-family: var(--c-sans);
  font-size: .8rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--c-accent-soft);
  margin-bottom: .8em;
}

.sitefoot__cols { margin: 0; padding: 0; list-style: none; font-size: .93rem; }
.sitefoot__cols li { padding: .18em 0; }
.sitefoot__cols i { font-style: normal; color: #9FB0A5; font-size: .82rem; }

.sitefoot__brands { margin-top: 34px; padding-top: 26px; border-top: 1px solid rgba(255,255,255,.14); }
.sitefoot__brands-cols {
  columns: 4;
  column-gap: 26px;
  margin: 0 0 .8em;
  padding: 0;
  list-style: none;
  font-size: .93rem;
}
.sitefoot__brands-cols li { break-inside: avoid; padding: .18em 0; }
@media (max-width: 900px) { .sitefoot__brands-cols { columns: 2; } }
.sitefoot h3 + .sitefoot__cols { margin-top: .4em; }
.sitefoot__cols + h3 { margin-top: 1.4em; }

.sitefoot__legal {
  margin-top: 34px;
  padding-top: 20px;
  border-top: 1px solid #2C4C44;
  font-size: .84rem;
  color: #9FB0A5;
}
.sitefoot__legal p { max-width: 92ch; margin-bottom: .5em; }

/* ── уведомление о хранилище ───────────────────────────────────────────────── */

.consent-bar {
  position: fixed;
  left: 16px;
  right: 16px;
  bottom: 16px;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 640px;
  margin: 0 auto;
  padding: 14px 18px;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  box-shadow: 0 12px 34px rgba(18, 49, 43, .16);
  font-size: .88rem;
}
.consent-bar[hidden] { display: none; }
.consent-bar__ok {
  font: inherit;
  color: #FFFFFF;
  background: var(--c-ink);
  border: 0;
  border-radius: var(--c-round-tight);
  padding: .5em 1.2em;
  cursor: pointer;
}

/* ── доступность движения ──────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* ── печать ────────────────────────────────────────────────────────────────── */

@media print {
  .masthead__panel, .masthead__act, .consent-bar, .more-line,
  .request, .hero-form { display: none; }
  body { background: #FFFFFF; font-size: 12pt; }
  a { text-decoration: none; color: #000000; }
}

/* ── страница объекта ──────────────────────────────────────────────────────────
   Дополнение к словарю классов выше — блоки, которые живут только на 216 страницах
   объектов и ни разу не встречаются на главной и в хабах:
     .skip-to           ссылка «к содержанию» для клавиатуры
     .page-trail        хлебные крошки
     .object-body       проза карточки + сводка справа
     .copy__lead        вводка карточки, набирается крупнее
     .ledger            сводка объекта колонкой
     .tally-set .tally  разбивка остатка полосами
     .shore-brief       «Море и курорт» — отступ от воды, курорт, лента полос
     .nearby            соседи по курорту
   Блок стоит после печати, а не среди компонентов, чтобы правки страниц объектов не
   пересекались с правками главной: у файла четыре генератора-потребителя сразу.        */

.skip-to {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 40;
  padding: .6em 1.2em;
  background: var(--c-ink);
  color: #FFFFFF;
}
.skip-to:focus { left: 0; }

.page-trail {
  display: flex;
  flex-wrap: wrap;
  gap: .3em .6em;
  margin-bottom: 1.6em;
  font-size: .88rem;
  color: var(--c-muted);
}
.page-trail a { color: var(--c-ink-2); text-decoration: none; }
.page-trail a:hover { color: var(--c-accent); }
.page-trail a::after { content: " →"; color: var(--c-edge); }
.page-trail span { color: var(--c-muted); }

/* Первый экран объекта продолжается фактами — слипание секций здесь читается как обрыв. */
.opening + .slab { padding-top: clamp(28px, 4vw, 52px); }
/* Повтор с той же защитой, что и у обнуления отступа в §5.1: у того селектора шесть
   классов, у строки выше — два, и без повтора обнуление перебило бы исключение по
   специфичности — факты объекта снова слиплись бы с первым экраном. */
.slab.opening:not(.slab--band):not(.slab--dark) + .slab:not(.slab--band):not(.slab--dark) {
  padding-top: clamp(28px, 4vw, 52px);
}

/* На странице объекта кадр первого экрана — <figure> с подписью, а у <figure> в браузере
   свои отступы по умолчанию, в том числе левый в 40 px: без сброса кадр уезжает вправо
   относительно заголовка. */
figure.opening__frame { margin-right: 0; margin-bottom: 0; margin-left: 0; }

.object-body {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(280px, .9fr);
  gap: clamp(26px, 4vw, 56px);
  align-items: start;
}
@media (max-width: 1180px) {
  .object-body { grid-template-columns: 1fr; }
}

.copy__lead {
  font-size: clamp(1.08rem, 1.5vw, 1.26rem);
  color: var(--c-ink-2);
  margin-bottom: 1.2em;
}

.ledger {
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  padding: clamp(18px, 2.4vw, 26px);
  position: sticky;
  top: 20px;
}
@media (max-width: 1180px) {
  .ledger { position: static; }
}

.ledger__sum {
  font: 300 1.24rem/1.3 var(--c-serif);
  margin: 0 0 1em;
  padding-bottom: .8em;
  border-bottom: 2px solid var(--c-ink);
}

.ledger dl { margin: 0; display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .45em 1.2em; }
.ledger dt { font-size: .86rem; color: var(--c-muted); }
.ledger dd { margin: 0; font-size: .93rem; text-align: right; }

/* ── таблицы объекта ───────────────────────────────────────────────────────── */

.grid-table caption {
  text-align: left;
  padding-bottom: .7em;
  font-size: .84rem;
  color: var(--c-muted);
}
.grid-table tbody th {
  font-weight: 600;
  color: var(--c-ink);
  font-size: .94rem;
  white-space: nowrap;
}
.grid-table--matrix td, .grid-table--matrix th:not(:first-child) { text-align: right; }
.grid-table__none { color: var(--c-muted); }

/* ── разбивка остатка ──────────────────────────────────────────────────────── */

.tally-set {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 28px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.tally .kicker { margin-bottom: .8em; }

.tally__row { margin-bottom: .7em; }
.tally__name { font-size: .92rem; }
.tally__num { float: right; font-size: .86rem; color: var(--c-muted); }
.tally__bar {
  display: block;
  clear: both;
  height: 4px;
  margin-top: .3em;
  background: var(--c-edge);
  border-radius: 2px;
}
.tally__bar i { display: block; height: 100%; background: var(--c-ink-2); border-radius: 2px; }

/* ── море и курорт ─────────────────────────────────────────────────────────── */

.shore-brief__figure {
  font: 300 clamp(1.8rem, 4vw, 2.9rem)/1.1 var(--c-serif);
  margin-bottom: .5em;
}
.shore-brief__where { max-width: 62ch; }

.shore-brief__bands {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 6px;
  margin: 1.6em 0 0;
}
@media (max-width: 560px) {
  .shore-brief__bands { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.shore-brief__band {
  padding: .55em .7em;
  border-top: 3px solid var(--c-edge);
  background: var(--c-surface);
  color: var(--c-ink-2);
  font-size: .86rem;
  text-decoration: none;
}
.shore-brief__band:hover { border-top-color: var(--c-accent); color: var(--c-accent); }
.shore-brief__band--here {
  border-top-color: var(--c-ink);
  background: var(--c-ink);
  color: var(--c-sand);
  font-weight: 600;
}
.shore-brief__band--here:hover { color: #FFFFFF; border-top-color: var(--c-accent-soft); }

/* ── соседи ────────────────────────────────────────────────────────────────── */

.nearby {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 16px;
}

.nearby__card {
  display: flex;
  flex-direction: column;
  gap: .25em;
  padding: 16px 18px;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  color: var(--c-ink);
  text-decoration: none;
}
.nearby__card:hover { border-color: var(--c-ink-2); }
.nearby__card b { font: 500 1.08rem/1.25 var(--c-serif); }
.nearby__card span { font-size: .86rem; color: var(--c-muted); }

/* ── карта побережья ──────────────────────────────────────────────────────────
   Task 12 (docs/superpowers/plans/2026-08-18-umorya-karta-i-zastroyshchiki.md), в нынешнем
   виде — задачи 13–16 плана 2026-08-20.
   Разметка приходит из двух мест, которые обязаны совпасть по именам классов:
     tools/modul_homepage_builder/sites/umorya.com/map_widget.py   — SVG карты целиком (берег,
       суша, точки-ссылки), заголовок/интро, обёртка, кнопки зума, подсказка, попап-контейнер,
       фильтры-ссылки, атрибуция;
     sites/umorya.com/assets/js/um.js                              — содержимое попапа
       (renderMarkerCard), смена уровня детализации (attachLod), вид и управление
       (attachSvgView, attachMapControls).
   Ни `.um-map__canvas`, ни DOM-маркеров (`.um-map__marker`, `.um-map__cluster`) здесь больше
   нет: канвасную подложку вместе с placeMarkers/clusterize удалила задача 14 плана
   2026-08-20 — точки карты рисует сама сборка обычными ссылками внутри SVG, а стилей на
   классы, которых никто не создаёт, файл не держит.
   Цвета воды и суши стоят в палитре (`--c-map-sea`/`--c-map-land`, `:root` выше в этом
   файле): литералами они держались, только пока их дублировал канвас. */

.um-map { margin-block: 2rem; }

.um-map__title { margin-bottom: .5em; }

.um-map__intro {
  font-size: clamp(1.06rem, 1.5vw, 1.24rem);
  color: var(--c-ink-2);
  max-width: 62ch;
}

.um-map__wrap {
  position: relative;
  aspect-ratio: 5 / 3;
  overflow: hidden;
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  /* Море. Прямоугольника воды внутри SVG нет намеренно (см. static_svg, map_widget.py):
     при зуме и панорамировании viewBox уезжает, и фигура фиксированного размера открыла бы
     пустоту по краям — фон обёртки покрывает видимую область всегда. */
  background: var(--c-map-sea);
  /* Высота карты ограничена (спека §9.4): на странице объекта карта — иллюстрация внутри
     длинного текста, и при `aspect-ratio: 5/3` на узком экране она занимала бы его целиком,
     превращая прокрутку страницы в блуждание по карте. Исключение — `/karta/` ниже: там
     карта и есть содержимое страницы. */
  max-height: min(70vh, 520px);
  /* Один палец прокручивает страницу, карту масштабируют Ctrl+колесом, кнопками ± и
     клавишами (UmMap.attachMapControls). Прежнее `none` отдавало карте любой жест над ней —
     читатель, доскроллив до карты на телефоне, застревал в ней. */
  touch-action: pan-y pinch-zoom;
}
.karta-page .um-map__wrap { max-height: none; }   /* на /karta/ карта и есть содержимое */

/* Обёртка становится фокусируемой сама (UmMap.attachMapControls, um.js: wrapEl.tabIndex = 0) —
   клавиатурный пан/зум нужен явный индикатор, глобальное правило фокуса (выше в файле)
   охватывает только a/summary/button/input/select, не произвольный div с tabindex. */
.um-map__wrap:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 2px; }

/* touch-action повторено с .um-map__wrap намеренно: UmMap.attachMapControls (um.js) вешает
   pointer/wheel-слушатели на саму обёртку, но касание физически принимает верхний видимый
   слой — сам SVG; без touch-action на этом слое браузер может забрать жест под собственный
   скролл/зум раньше, чем событие дойдёт до обработчика на обёртке. Значение обязано совпадать
   с обёрткой: разойдись они, верхний слой решал бы судьбу жеста по своим правилам. */
.um-map__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: pan-y pinch-zoom;
}

/* Суша поверх фона-моря обёртки, линия берега поверх суши — порядок задаёт разметка
   (static_svg), здесь только заливка и обводка. */
.um-map__land { fill: var(--c-map-land); stroke: none; }

/* vector-effect: non-scaling-stroke обязателен: без него при приближении (Task 14) линия
   берега растолстеет пропорционально зуму и съест мелкие бухты. */
.um-map__coast {
  fill: none;
  stroke: #2b6b73;
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
}

.um-map__point {
  fill: var(--c-accent);
  stroke: #FFFFFF;
  stroke-width: 1;
}

/* Точка отзывается на наведение и на клавиатурный фокус одинаково — без JS это
   единственная обратная связь у ссылки-кружка (`<title>` покажет название, но только при
   наведении мышью). `r` — презентационный SVG-атрибут, переопределимый через CSS, тот же
   приём, что у `.um-map__point--highlight` ниже. */
.um-map__svg a:hover .um-map__point,
.um-map__svg a:focus .um-map__point { r: 7; fill: var(--c-accent); }

/* Приглушение/подсветка по членству в срезе хаба (Task 29.5, Ruling SPEC43-1, спека §4.3):
   `--muted` — геостраницы и хаб застройщика, карта уже сужена рамкой на срез, приглушается то,
   что видно снаружи; `--highlight` — перекрёстные срезовые хабы («до 500 м», «Бизнес» и т.п.),
   рамки нет, видно все 216 точек, подсвечивается подмножество внутри среза. Правила стоят
   после `.um-map__point`, а не смешаны в одно составное селектором — модификатор должен
   перебивать базовый цвет без борьбы за специфичность (те же две голые одноклассовые
   селекторы, что и `.um-map__point`).
   `--muted` берёт `--c-accent-soft` (уже определён как более светлая ступень акцента, Task 12
   переменные) вместо нового цвета — приглушение читается как «тот же акцент, но тише», а не
   как посторонний оттенок на карте. `--highlight` берёт `--c-ink` — тот же цвет, что уже стоит
   у `.um-map__marker:hover` ниже: подсвеченная точка выглядит как «постоянно наведённая»,
   готовый смысл для читателя, а не новый визуальный язык. `r`/`cx`/`cy` — презентационные
   SVG-атрибуты, переопределимые через CSS (Chrome/Firefox/Safari, актуальные версии); увеличенный
   радиус — не только цвет отличает подсвеченную точку, это заметно и на маленьком экране. */
.um-map__point--muted { fill: var(--c-accent-soft); opacity: .45; }
.um-map__point--highlight { fill: var(--c-ink); stroke: var(--c-accent); stroke-width: 1.5; r: 5.5; }

/* Кнопки зума. В разметке они есть всегда, но с атрибутом `hidden`: без JS зумить нечем,
   а видимая кнопка, которая ничего не делает, хуже отсутствующей. Атрибут снимает um.js
   (задача 14 плана 2026-08-20), поэтому `display: flex` обязан уступать `hidden` — отдельным
   правилом ниже, тем же приёмом, что у `.um-map__popup[hidden]`. */
.um-map__zoom {
  position: absolute;
  right: 12px;
  bottom: 12px;
  z-index: 4;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.um-map__zoom[hidden] { display: none; }
.um-map__zoom button {
  width: 34px;
  height: 34px;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--c-ink);
  cursor: pointer;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round-tight);
}
.um-map__zoom button:hover { background: var(--c-accent-soft); }

/* Подсказка «Ctrl + колесо»: всплывает на пару секунд, когда колесо крутанули над картой без
   Ctrl (спека §9.4). Молчаливое ничего-не-происходит читается как сломанная карта — а карта в
   этот момент работает как задумано, просто прокручивает страницу. Позиция по центру снизу
   не спорит с кнопками зума (они в правом нижнем углу) и с карточкой объекта (z-index 5 —
   карточка перекрывает подсказку, а не наоборот: подсказка временная). Атрибут `hidden` снимает
   и возвращает um.js, поэтому у подсказки есть парное правило `[hidden] { display: none }` — то
   же, что у `.um-map__zoom` и `.um-map__popup` рядом. Обязательным оно бывает там, где элемент
   задаёт свой `display` и тем перебивает браузерное `[hidden] { display: none }` (`.um-map__zoom`
   с его `flex`). Подсказка `display` не задаёт и скрылась бы и без правила: оно стоит ради
   единообразия трёх наложенных слоёв и на случай, если `display` появится здесь позже. */
.um-map__hint {
  position: absolute;
  inset: auto 0 16px 0;
  margin: 0 auto;
  width: max-content;
  max-width: calc(100% - 24px);
  z-index: 4;
  padding: .5em 1em;
  border-radius: var(--c-round-tight);
  background: rgba(18, 49, 43, .86);
  color: #FFFFFF;
  font-size: .86rem;
}
.um-map__hint[hidden] { display: none; }

.um-map__popup {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 5;
  width: 224px;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round-tight);
  box-shadow: 0 12px 34px rgba(18, 49, 43, .22);
  overflow: hidden;
}
.um-map__popup[hidden] { display: none; }

.um-map__card {
  display: flex;
  gap: .6em;
  padding: .6em;
  color: var(--c-ink);
  text-decoration: none;
}
.um-map__card:hover .um-map__card-name { color: var(--c-accent); }

.um-map__card-img {
  width: 96px;
  height: 72px;
  flex-shrink: 0;
  object-fit: cover;
  border-radius: var(--c-round-tight);
  background: var(--c-band);
}

.um-map__card-body { display: flex; flex-direction: column; gap: .2em; min-width: 0; }

.um-map__card-name { font: 600 .92rem/1.24 var(--c-sans); }

.um-map__card-meta { font-size: .8rem; color: var(--c-muted); }

.um-map__filters-static {
  display: flex;
  flex-wrap: wrap;
  gap: .5em;
  margin: .9em 0 0;
  padding: 0;
  list-style: none;
}
.um-map__filters-static a {
  display: inline-block;
  padding: .34em .9em;
  border-radius: 999px;
  background: var(--c-band);
  color: var(--c-ink);
  font-size: .86rem;
  text-decoration: none;
}
.um-map__filters-static a:hover { color: var(--c-accent); }

.um-map__attribution {
  margin: .6em 0 0;
  font-size: .75rem;
  color: var(--c-muted);
}

/* Кнопка-ссылка «Карта на весь экран» под картой на главной (index.template.html) — ведёт на
   `/karta/`. Ни одного правила у неё не было (найдено финальным ревью, Important, вместе с
   `.karta-page`): без класса-обёртки `.hold`/`.slab` она наследовала браузерный дефолт ссылки.
   Форма — тот же «таблетка» приём, что у `.um-map__filters-static a` прямо выше: карта уже
   несёт визуальный язык бейджей-ссылок под собой, кнопка полного экрана продолжает его, а не
   вводит третий стиль ссылки на этой же странице. */
.um-map__fullscreen {
  display: inline-block;
  margin: .9em 0 0;
  padding: .4em 1.05em;
  border-radius: 999px;
  background: var(--c-ink);
  color: #FFFFFF;
  font: 500 .88rem/1.2 var(--c-sans);
  text-decoration: none;
}
.um-map__fullscreen:hover { background: var(--c-accent); }

/* ── /karta/ — полная карта на всю ширину ─────────────────────────────────────
   Task FINAL (находка 1 финального ревью, Important): `karta.template.html` заворачивал
   `<main>` без `.hold`/`.hold--wide` — единственный шаблон страницы с этим пробелом (сравни
   с `.obj-map`/`.builder-page` выше в файле, оба сидят внутри `.hold hold--wide` в своих
   шаблонах). Итог на живой `dist/umorya.com/karta/` при 1366px: H1 (`clamp(2.6rem, 6.4vw,
   4.6rem)`, глобальное правило h1 выше в файле) стоял впритык к краю вьюпорта без отступов
   страницы, а `.karta-page__layout` был обычным `display: block` — список объектов уезжал под
   карту, хотя спека §4.2 требует «фильтры и список объектов сбоку».
   `.karta-page` не переиспользует `.slab.opening` буквально (нет класса в разметке) — страница
   однa секция без соседей сверху/снизу, поэтому верстается своим блоком с тем же отступом
   сверху, что и `.opening` (Task 29.5 паттерн), без добавления второго класса в шаблон. */
.karta-page {
  padding: clamp(34px, 5vw, 68px) 0 clamp(48px, 6vw, 84px);
}
.karta-page h1 { margin-bottom: .38em; }

/* Отбивка первого экрана от блока карты (находка ревью Task 8, Important). Отступ раньше
   давал `margin-bottom` у `.karta-page__intro`: абзац и `.karta-page__layout` были прямыми
   соседями в одном `.hold`. С формой первого экрана абзац уехал внутрь `.opening__text`, а
   тот стал grid-элементом `.opening--split .hold` — внешний отступ грид-элемента наружу не
   выходит, и высоту строки задаёт более высокая колонка (карточка формы), так что 1.8em
   просто растворялись внутри строки. Оба верхнеуровневых блока `/karta/` — обычные `<div>`,
   не `.slab`-секции, поэтому соседские правила `.opening + .slab` и `.slab + .slab` (§5.1)
   сюда не достают, и отступ приходится задать явно.
   Значение — тот же `clamp(28px, 4vw, 52px)`, что `.opening + .slab` даёт после первого
   экрана на всех остальных страницах сайта, а не `--c-step` (56–112px, шаг между полными
   полосами): у `/karta/` та же ситуация «первый экран → следующий блок», и ритм должен
   совпадать с хабами, объектами и главной, а не быть вдвое шире их. Совпадение значений
   держит тест `test_gap_matches_the_opening_rhythm_of_other_pages`. */
.karta-page .opening--split { margin-bottom: clamp(28px, 4vw, 52px); }

.karta-page__intro {
  font-size: clamp(1.06rem, 1.5vw, 1.24rem);
  color: var(--c-ink-2);
  max-width: 68ch;
  margin-bottom: 1.8em;
}

/* Карта — широкая колонка, список объектов — узкая колонка сбоку (спека §4.2), не блок под
   блоком. `align-items: start` — колонка списка не растягивается по высоте карты, у неё свой
   скролл (`.karta-page__list` ниже) короче или длиннее её соседа. Брейкпоинт складывает
   колонки в одну на планшете/телефоне — 280px минимума списка уже не помещается рядом с
   картой на среднем экране без того, чтобы сама карта не сжалась до нечитаемой ширины. */
.karta-page__layout {
  display: grid;
  grid-template-columns: minmax(0, 1.7fr) minmax(280px, .9fr);
  gap: clamp(20px, 2.6vw, 40px);
  align-items: start;
}
@media (max-width: 860px) {
  .karta-page__layout { grid-template-columns: 1fr; }
}

/* Тот же приём поверхности, что и `.builder-page__facts` (карточка со своими рамкой/фоном/
   скруглением) — список внутри своей рамки читается как отдельная панель рядом с картой, а
   не голый текст без границ. Собственный скролл с ограничением по высоте — список из 216 строк
   иначе растягивал бы страницу далеко вниз карты на десктопе, где карта сама куда компактнее. */
.karta-page__list {
  max-height: 640px;
  overflow-y: auto;
  padding: clamp(12px, 1.6vw, 18px);
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
}
@media (max-width: 860px) {
  .karta-page__list { max-height: none; }
}

/* ── переключатель карты объекта ──────────────────────────────────────────────
   Task 18 разметила `.obj-map`/`.obj-map__tabs`/`.obj-map__panel` (build_pages.py,
   object_map_block) без единого правила CSS — содержимое обеих панелей уже полностью
   стилизовано (`.um-map` изнутри, `map_build.build_html` несёт свой инлайн `<style>` для
   «Что вокруг»), не хватало только чрома самого переключателя (Task 29.5, Ruling SPEC43-1).
   `.obj-map--single` — без JS-переключателя вовсе (объект без окрестностей, только «Где на
   берегу», см. докстринг object_map_block) — не нуждается в своих правилах: внутри неё сразу
   стоит `.um-map`, вкладок нет. */

.obj-map__tabs {
  display: flex;
  gap: .3em;
  margin: 0 0 1.1em;
  border-bottom: 1px solid var(--c-edge);
}
.obj-map__tabs button {
  appearance: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin: 0 0 -1px;
  padding: .7em 1.05em;
  background: none;
  font: 500 .96rem/1.2 var(--c-sans);
  color: var(--c-muted);
  cursor: pointer;
}
.obj-map__tabs button:hover { color: var(--c-ink); }
/* Активная вкладка читается по `aria-selected` из разметки (um.js, обработчик клика ниже в
   файле), а не по отдельному классу — состояние живёт в одном месте (атрибут), а не в двух
   рассинхронизируемых (атрибут для a11y + класс для вида). */
.obj-map__tabs button[aria-selected="true"] {
  color: var(--c-ink);
  border-bottom-color: var(--c-accent);
}

.obj-map__panel[hidden] { display: none; }

/* ── хаб застройщика и корень раздела ─────────────────────────────────────────
   Task 27 разметила `.builder-page__*`/`.builders-root__*` (builder.template.html,
   builders-root.template.html) без единого правила CSS — общий site-chrome (шапка/подвал) уже
   стилизован, но дисклеймер под H1, сводка фактов (`<dl>`) и плитка брендов на корне раздела
   оставались обычным браузерным дефолтом (Task 29.5, Ruling SPEC43-1). */

.builder-page__disclaimer {
  margin: .8em 0 0;
  max-width: 62ch;
  font-size: .86rem;
  color: var(--c-muted);
}

.builder-page__intro { margin-bottom: 1.6em; }

/* Сетка `dt`/`dd`, обёрнутых в `<div>` (build_builders.py::facts_block) — та же пара, что и
   `.ledger dl` выше (в блоке «таблицы объекта») для карточки объекта, но не сама `.ledger`:
   та — липкий сайдбар в гриде `.object-body`, а сводка застройщика — блок на всю ширину
   колонки, вне грида.
   Переиспользуется цветовая/пространственная логика поверхности (`--c-surface`/`--c-edge`/
   `--c-round`, тот же набор, что у `.nearby__card`/`.ledger`), не сам класс. */
.builder-page__facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 1em 1.6em;
  margin: 0 0 2em;
  padding: clamp(18px, 2.4vw, 26px);
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
}
.builder-page__facts dt { font-size: .82rem; color: var(--c-muted); margin-bottom: .2em; }
.builder-page__facts dd { margin: 0; font: 500 .96rem/1.32 var(--c-sans); color: var(--c-ink); }

/* Плитка 19 брендов — тот же паттерн карточки-ссылки, что `.nearby__card` выше: поверхность,
   рамка, скругление, смена цвета рамки на hover. Не переиспользован сам класс —
   `.nearby__card` держит `<b>`/`<span>` в отдельной колонке текста, а плитка бренда проще
   (имя + счётчик одной строкой на карточку). */
.builders-root__tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: 14px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.builders-root__tiles a {
  display: flex;
  flex-direction: column;
  gap: .3em;
  padding: 1.1em 1.3em;
  background: var(--c-surface);
  border: 1px solid var(--c-edge);
  border-radius: var(--c-round);
  color: var(--c-ink);
  text-decoration: none;
  font: 500 1.04rem/1.3 var(--c-sans);
}
.builders-root__tiles a:hover { border-color: var(--c-ink-2); color: var(--c-accent); }
.builders-root__tiles span { font-size: .82rem; color: var(--c-muted); font-weight: 400; }
