:root {
  --bg: #f6f7f9;
  --panel: #ffffff;
  --ink: #12161c;
  --ink-2: #5a6472;
  --ink-3: #8a94a3;
  --line: #e7eaef;
  --line-2: #eef1f5;
  --brand: #1f6feb;
  --brand-ink: #0f4fbf;
  --hot: #e8663d;
  --cold: #2f9bd6;
  --elec: #e0a92c;
  --heat: #c0492f;
  --gas: #7b8794;
  --emerg: #d9433a;
  --plan: #2f9bd6;
  --shadow: 0 8px 30px rgba(20, 30, 50, .10);
  --shadow-sm: 0 2px 10px rgba(20, 30, 50, .08);
  --radius: 16px;
  --radius-sm: 11px;
  --sans: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}
/* Казахская локаль — Inter; RU/остальное — Manrope. Переключается по <html lang> (см. applyLang в app.js) */
html[lang="kk"] {
  --sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
}

* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; }
body {
  font-family: var(--sans);
  color: var(--ink);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

#map { position: absolute; inset: 0; z-index: 1; background: #eef1f4; }
#connBanner { position: fixed; top: 0; left: 0; right: 0; z-index: 10000; display: flex; align-items: center;
  justify-content: center; gap: 8px; background: #3a1414; color: #ffb4ab; font-family: var(--sans); font-size: 13px;
  font-weight: 700; padding: 9px 14px; text-align: center; }
#connBanner[hidden] { display: none; }
#connBanner .cb-dot { width: 7px; height: 7px; border-radius: 50%; background: #ff8a80; flex: none; }

/* ---------- Top bar ---------- */
.topbar {
  position: absolute; z-index: 20; top: 14px; left: 14px; right: 14px;
  display: flex; justify-content: center; align-items: flex-start; gap: 12px; pointer-events: none;
}
.topbar > * { pointer-events: auto; }
.topbar .tb-right { position: absolute; right: 0; top: 0; display: flex; gap: 10px; align-items: flex-start; }
/* Бренд в шапке карты — на десктопе он есть в левой панели, поэтому здесь только для мобилки */
.mapbrand { display: none; }

/* Инфо-плашка (честный контекст, напр. общегородской ремонт ГВС) — плавающая, закрываемая */
.mapnotice {
  position: absolute; z-index: 19; top: 70px; left: 352px; right: 20px; max-width: 600px;
  display: flex; align-items: flex-start; gap: 9px; padding: 10px 40px 10px 14px;
  background: #fff6e5; border: 1px solid #f1dca6; border-radius: 12px; box-shadow: var(--shadow-sm);
  color: #7a5a12; font-size: 12.5px; font-weight: 600; line-height: 1.4;
}
.mapnotice[hidden] { display: none; }
.mapnotice > svg { width: 17px; height: 17px; flex: none; color: #c9821a; margin-top: 1px; }
.mapnotice .mn-x { position: absolute; right: 7px; top: 7px; width: 26px; height: 26px; border: 0;
  background: transparent; color: #9a7a3a; cursor: pointer; display: grid; place-items: center; border-radius: 50%; }
.mapnotice .mn-x svg { width: 13px; height: 13px; }
.mapnotice .mn-x:hover { background: rgba(120,90,20,.1); }
@media (max-width: 900px) { .mapnotice { top: 176px; left: 12px; right: 12px; max-width: none; } }
.topbar .lang { position: static; }
.mapcity { position: relative; }
.mapcity-btn { display: inline-flex; align-items: center; gap: 6px; height: 46px; padding: 0 14px;
  background: #fff; border: 1px solid var(--line); border-radius: 999px; font-family: var(--sans);
  font-weight: 700; font-size: 13.5px; color: var(--ink); cursor: pointer; box-shadow: var(--shadow-sm); }
.mapcity-btn:hover { border-color: var(--ink-3); }
.mapcity-btn .cpin { width: 14px; height: 14px; color: var(--brand); flex: none; }
.mapcity-btn .cchev { transition: transform .2s; }
.mapcity[data-open="1"] .cchev { transform: rotate(180deg); }
.mapcity-menu { position: absolute; top: calc(100% + 6px); right: 0; min-width: 190px; background: #fff;
  border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow); padding: 5px;
  opacity: 0; visibility: hidden; transform: translateY(-6px); transition: .16s; }
.mapcity[data-open="1"] .mapcity-menu { opacity: 1; visibility: visible; transform: none; }
.mapcity-menu a, .mapcity-menu button { display: flex; align-items: center; justify-content: space-between;
  gap: 10px; width: 100%; text-decoration: none; background: none; border: 0; font-family: var(--sans);
  font-size: 14px; font-weight: 600; color: var(--ink); padding: 9px 11px; border-radius: 8px; cursor: pointer; text-align: left; }
.mapcity-menu a.on { color: var(--brand-ink); }
.mapcity-menu a:hover { background: var(--bg); }
.mapcity-menu button:disabled { color: var(--ink-3); cursor: default; }
.mapcity-menu .soon { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: .4px;
  color: var(--ink-3); background: var(--line-2); border-radius: 999px; padding: 2px 7px; }
/* «Войти» — выбор кабинета (жителя или КСК). На десктопе в верхней панели,
   на телефоне — значок в шапке шторки: в верхней строке телефона нет места. */
.mapacct, .sacct { position: relative; }
.mapacct-btn { display: inline-flex; align-items: center; gap: 7px; height: 46px; padding: 0 15px;
  background: #fff; border: 1px solid var(--line); border-radius: 999px; font-family: var(--sans);
  font-weight: 700; font-size: 13.5px; color: var(--ink); cursor: pointer; box-shadow: var(--shadow-sm); }
.mapacct-btn:hover { border-color: var(--ink-3); }
.mapacct-btn:active, .sacct-btn:active { transform: translateY(1px); }
.mapacct-btn svg, .sacct-btn svg { width: 16px; height: 16px; color: var(--brand); flex: none; }
.mapacct-menu { position: absolute; top: calc(100% + 6px); right: 0; width: 290px; background: #fff; z-index: 40;
  border: 1px solid var(--line); border-radius: 14px; box-shadow: var(--shadow); padding: 5px;
  opacity: 0; visibility: hidden; transform: translateY(-6px); transition: .16s; }
.mapacct[data-open="1"] .mapacct-menu, .sacct[data-open="1"] .mapacct-menu { opacity: 1; visibility: visible; transform: none; }
.mapacct-menu a { display: block; text-decoration: none; padding: 10px 11px; border-radius: 9px; color: var(--ink); }
.mapacct-menu a:hover { background: var(--bg); }
.mapacct-menu b { display: block; font-size: 14px; }
.mapacct-menu span { display: block; font-size: 12.5px; line-height: 1.4; color: var(--ink-2); margin-top: 2px; font-weight: 500; }
.mapacct-btn { white-space: nowrap; }
.mapacct-btn span { max-width: 160px; overflow: hidden; text-overflow: ellipsis; }
.mapacct-btn.in { border-color: var(--brand); color: var(--brand-ink); }
.mapacct-btn.in::after, .sacct-btn.in::after { content: ""; width: 7px; height: 7px; border-radius: 50%; background: #1f9e63; }
.sacct-btn.in { border-color: var(--brand); position: relative; }
.sacct-btn.in::after { position: absolute; right: 1px; top: 1px; }
.mapacct-menu .acct-alt { font-size: 13px; font-weight: 700; color: var(--brand); }
.mapacct-menu .acct-out { display: block; width: 100%; text-align: left; border: 0; border-top: 1px solid var(--line-2);
  background: none; font-family: var(--sans); font-weight: 600; font-size: 13.5px; color: var(--ink-2); padding: 10px 11px;
  margin-top: 4px; cursor: pointer; }
.mapacct-menu .acct-out:hover { color: #b4232a; background: var(--bg); }
.sacct { display: none; }
.mapacct-menu.sacct-pop { position: fixed; width: auto; z-index: 1200; box-shadow: 0 18px 40px -12px rgba(20,30,50,.35); }
.mapacct-menu.sacct-pop[data-open="1"] { opacity: 1; visibility: visible; transform: none; }
.sacct-btn { width: 36px; height: 36px; border-radius: 50%; border: 1px solid var(--line); background: #fff;
  display: grid; place-items: center; cursor: pointer; }
@media (max-width: 900px) {
  .topbar .tb-right { position: static; margin-left: auto; gap: 8px; }
  .mapacct { display: none; }
  .sacct { display: block; flex: none; }

  .mapcity-btn { height: 42px; }
  .mapcity-menu { left: 0; right: auto; }
}

.brand {
  display: flex; align-items: center; gap: 9px;
  background: var(--panel); border: 1px solid var(--line);
  padding: 9px 14px; border-radius: 999px; box-shadow: var(--shadow-sm);
  text-decoration: none; color: var(--ink);
}
.brand .mark {
  width: 24px; height: 24px; display: grid; place-items: center;
}
.brand b { font-size: 15px; letter-spacing: -.2px; }
.brand .kk { color: var(--ink-3); font-weight: 600; }

/* Search */
.search {
  position: relative; flex: 1; max-width: 460px;
}
.search input {
  width: 100%; height: 46px; border: 1px solid var(--line);
  background: var(--panel); border-radius: 999px; padding: 0 44px 0 44px;
  font-size: 15px; color: var(--ink); box-shadow: var(--shadow-sm); outline: none;
}
.search input:focus { border-color: var(--brand); box-shadow: 0 0 0 4px rgba(31,111,235,.12); }
.search .ico {
  position: absolute; left: 15px; top: 50%; transform: translateY(-50%);
  color: var(--ink-3); font-size: 17px;
}
.search .clear {
  position: absolute; right: 12px; top: 50%; transform: translateY(-50%);
  border: 0; background: var(--line-2); color: var(--ink-2); width: 24px; height: 24px;
  border-radius: 50%; cursor: pointer; display: none; align-items: center; justify-content: center;
}
.search .clear.show { display: flex; }

.suggest {
  position: absolute; top: 52px; left: 0; right: 0;
  background: var(--panel); border: 1px solid var(--line); border-radius: 14px;
  box-shadow: var(--shadow); overflow: hidden; display: none; max-height: 360px; overflow-y: auto;
}
.suggest.show { display: block; }
.suggest .sg {
  padding: 11px 15px; cursor: pointer; display: flex; align-items: center; gap: 11px;
  border-bottom: 1px solid var(--line-2);
}
.suggest .sg:last-child { border-bottom: 0; }
.suggest .sg:hover, .suggest .sg.active { background: #f3f6fb; }
.suggest .sg .dot { width: 9px; height: 9px; border-radius: 50%; flex: none; }
.suggest .sg .t { font-size: 14.5px; }
.suggest .sg .t small { color: var(--ink-3); }
.suggest .sg .tag {
  margin-left: auto; font-size: 11px; color: var(--ink-3); background: var(--line-2);
  padding: 3px 8px; border-radius: 999px; white-space: nowrap;
}
.suggest .sg-head { padding: 8px 15px 4px; font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--ink-3); }
.suggest .empty { padding: 18px 15px; color: var(--ink-3); font-size: 14px; text-align: center; }

.lang {
  display: flex; background: var(--panel); border: 1px solid var(--line);
  border-radius: 999px; box-shadow: var(--shadow-sm); overflow: hidden; height: 46px;
}
.lang button {
  border: 0; background: transparent; padding: 0 14px; font-size: 13.5px; font-weight: 700;
  color: var(--ink-3); cursor: pointer;
}
.lang button.on { background: var(--brand); color: #fff; }

/* ---------- Left panel (desktop) ---------- */
.panel {
  position: absolute; z-index: 15; top: 14px; left: 14px; width: 328px;
  bottom: 14px; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow); display: flex; flex-direction: column;
  overflow: hidden;
}
.panel .head { padding: 16px 16px 12px; border-bottom: 1px solid var(--line-2); }
.panel .head .map-title { margin: 0; font-size: 16px; letter-spacing: -.2px; }
.panel .head p { margin: 3px 0 0; font-size: 12.5px; color: var(--ink-3); }
.panel .head .count { font-weight: 700; color: var(--brand-ink); }

.filters { padding: 12px 16px; border-bottom: 1px solid var(--line-2); }
.filters .fg { margin-bottom: 14px; }
.filters .fg:last-child { margin-bottom: 2px; }
.filters .fg > .lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--ink-3); margin-bottom: 8px; }
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 11px;
  border: 1px solid var(--line); border-radius: 999px; background: #fff; cursor: pointer;
  font-size: 12.5px; color: var(--ink-2); user-select: none; transition: .12s;
}
.chip .sw { width: 9px; height: 9px; border-radius: 50%; }
.chip.on { border-color: transparent; color: #fff; font-weight: 600; }
.chip.off { opacity: .5; }

.seg { display: flex; gap: 6px; }
.seg button {
  flex: 1; border: 1px solid var(--line); background: #fff; padding: 7px 8px;
  border-radius: 9px; font-size: 12.5px; color: var(--ink-2); cursor: pointer; font-weight: 600;
}
.seg button.on { background: var(--ink); color: #fff; border-color: var(--ink); }

.list { flex: 1; overflow-y: auto; padding: 8px; }
.card {
  border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 12px;
  margin-bottom: 8px; cursor: pointer; transition: .12s; background: #fff;
}
.card:hover { border-color: #d3dae4; box-shadow: var(--shadow-sm); }
.card .r1 { display: flex; align-items: center; gap: 9px; }
.card .ricon {
  width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center;
  font-size: 15px; flex: none;
}
.card .rname { font-weight: 700; font-size: 14px; }
.badge.citizen { background: #efeaff; color: #5b3fd6; }
.card .badge {
  margin-left: auto; font-size: 10.5px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  text-transform: uppercase; letter-spacing: .3px;
}
.badge.emergency { background: #fdecea; color: var(--emerg); }
.badge.planned { background: #eaf4fb; color: #2075b0; }
.card .addr { font-size: 13px; color: var(--ink); margin: 8px 0 4px; }
.card .meta { font-size: 12px; color: var(--ink-3); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.card .when { font-size: 12.5px; color: var(--ink-2); margin-top: 6px; display: flex; align-items: center; gap: 7px; }
.card .when .live { width: 7px; height: 7px; border-radius: 50%; background: var(--emerg); box-shadow: 0 0 0 3px rgba(217,67,58,.18); }
.card .when .soon { width: 7px; height: 7px; border-radius: 50%; background: var(--elec); }

.list .none { text-align: center; padding: 40px 20px; color: var(--ink-3); font-size: 14px; }

/* ---------- Map markers ---------- */
.pin {
  position: relative;
  border-radius: 50%; display: grid; place-items: center; color: #fff;
  font-weight: 800; box-shadow: 0 2px 8px rgba(0,0,0,.28); border: 2px solid #fff;
}
.pin-badge {
  position: absolute; top: -5px; right: -5px; min-width: 15px; height: 15px; padding: 0 3px;
  border-radius: 999px; background: #15171c; color: #fff; font-size: 9px; font-weight: 800;
  line-height: 1; display: grid; place-items: center; border: 1.5px solid #fff; box-sizing: border-box;
}
/* Несколько услуг у дома: тёмная метка «!» и красное число (app.js, PIN_MULTI). */
.pin-badge.pin-badge-multi { background: #e5484d; min-width: 16px; height: 16px; font-size: 10px; }
/* Пин «сообщение жителя» — белый, пунктирная рамка цвета ресурса + уголковая метка */
.pin.pin-citizen {
  background: #fff; border: 2px dashed currentColor;
  box-shadow: 0 2px 8px rgba(0,0,0,.22);
}
.pin.pin-citizen .pin-cz {
  position: absolute; bottom: -4px; right: -4px; width: 13px; height: 13px; border-radius: 50%;
  background: #7c5cff; border: 1.5px solid #fff; box-sizing: border-box;
}
.pin.pin-citizen .pin-cz::after {
  content: ''; position: absolute; inset: 3px; border-radius: 50% 50% 50% 2px; background: #fff;
}
.cluster {
  border-radius: 50%; display: grid; place-items: center; color: #fff; font-weight: 800;
  border: 3px solid #fff; box-shadow: 0 3px 12px rgba(0,0,0,.28);
}
/* Ghost — «рядом с проблемой», не подтверждено (см. computeGhostHouses в app.js).
   Полая точка (не залитый пин с иконкой) — сознательно светлее confirmed-маркера,
   чтобы читалось как подсказка, а не как факт отключения по этому адресу. */
.pin-ghost {
  position: relative;   /* якорь для счётчика ресурсов (.pin-badge-ghost) */
  border-radius: 50%; box-sizing: border-box; display: grid; place-items: center;
  background: rgba(255,255,255,.6); border: 2px solid currentColor;
  box-shadow: 0 1px 5px rgba(0,0,0,.18);
}
.pin-ghost::after { content: ''; width: 38%; height: 38%; border-radius: 50%; background: currentColor; }
/* Счётчик «рядом больше одной проблемы» (напр. плановое электричество + авария
   по воде). Мельче обычного .pin-badge — ghost-маркер сам всего ~20px. */
.pin-badge-ghost {
  top: -5px; right: -5px; min-width: 13px; height: 13px; font-size: 8.5px;
  border-width: 1.5px; padding: 0 2px;
}
/* Крестик закрытия — чёткая круглая кнопка на синей шапке карточки.
 *
 * ⚠️ Размер живёт в переменной --hc-close, и от неё же считается отступ справа
 * у шапки (.hc-head). Раньше это были два независимых числа (кнопка 30px,
 * padding-right 50px) — и стоило тронуть одно, как длинный адрес заезжал под
 * крестик. Теперь зазор считается, а не подбирается: 12px от края + кнопка +
 * 12px до текста.
 *
 * ⚠️ Все размеры кратны 4 (правило владельца): 40 — на десктопе, 44 — на
 * телефоне (минимальная площадь пальца по гайдлайнам, тоже кратна 4).
 *
 * ⚠️ !important обязателен: Leaflet задаёт размеры и положение своей кнопки
 * собственными правилами, без него они выигрывают. */
.house-popup { --hc-close: 40px; }
.house-popup .leaflet-popup-close-button {
  width: var(--hc-close) !important; height: var(--hc-close) !important;
  top: 12px !important; right: 12px !important;
  padding: 0 !important; border-radius: 50%;
  /* ⚠️ !important И НА ФОНЕ. У Leaflet свой селектор на эту кнопку —
     `.leaflet-container a.leaflet-popup-close-button` (два класса + элемент), и
     он специфичнее нашего: его `background: transparent` побеждал, круг НЕ
     рисовался вовсе, и от кнопки оставался один тонкий крестик. Отсюда и
     ощущение «крестик маленький»: увеличивать надо было не глиф, а вернуть
     подложку. */
  background: rgba(255, 255, 255, .22) !important;
  color: #fff !important; font: 400 24px/1 var(--sans) !important; text-align: center;
  display: flex; align-items: center; justify-content: center; transition: background .15s, transform .1s;
}
.house-popup .leaflet-popup-close-button:hover { background: rgba(255, 255, 255, .4) !important; color: #fff !important; }
.house-popup .leaflet-popup-close-button:active { transform: scale(.92); }
.leaflet-popup-content-wrapper { border-radius: 14px; box-shadow: var(--shadow); }
.leaflet-popup-content { margin: 0; }
.pop { width: 250px; font-family: var(--sans); }
.pop .ph { display: flex; align-items: center; gap: 9px; padding: 13px 14px 10px; }
.pop .ph .ricon { width: 30px; height: 30px; border-radius: 9px; display: grid; place-items: center; font-size: 15px; }
.pop .ph b { font-size: 14.5px; }
.pop .pb { padding: 0 14px 8px; }
.pop .addr { font-size: 14px; font-weight: 700; margin-bottom: 6px; }
.pop .row { display: flex; justify-content: space-between; font-size: 12.5px; padding: 4px 0; border-top: 1px solid var(--line-2); }
.pop .row span:first-child { color: var(--ink-3); }
.pop .reason { font-size: 12.5px; color: var(--ink-2); padding: 8px 0 2px; }
.pop .sub {
  display: block; text-align: center; margin: 8px 14px 14px; padding: 9px;
  background: var(--brand); color: #fff; border-radius: 10px; font-weight: 700; font-size: 13px;
  border: 0; cursor: pointer; width: calc(100% - 28px);
}

/* ---------- Mobile bottom sheet ---------- */
.sheet { display: none; }
.fab { display: none; }

@media (max-width: 900px) {
  .panel { display: none; }
  /* ⚠️ Мёртвые правила .topbar/.brand/.search/.lang здесь УДАЛЕНЫ — они давно
     перекрыты более специфичным блоком ниже (@media 900px, селекторы `.topbar .search`
     и т.п. побеждают по специфичности независимо от порядка в файле). `.brand` вообще
     не используется в разметке (переименован в `.mapbrand` при редизайне шапки) —
     держать здесь мёртвый селектор с тем же именем, что и у активного, было плохой
     идеей: путает при отладке (см. фикс переноса шапки на 375px, ниже). Актуальная
     раскладка шапки — в блоке, начинающемся `.topbar { flex-wrap: wrap;... }`. */

  /* По умолчанию шторка СВЁРНУТА — акцент на карте. Тянем вверх, чтобы раскрыть. */
  .sheet {
    display: flex; flex-direction: column;
    position: absolute; z-index: 18; left: 0; right: 0; bottom: 0;
    background: var(--panel); border-radius: 20px 20px 0 0; box-shadow: 0 -8px 30px rgba(20,30,50,.16);
    height: 108px; overflow: hidden;
    /* плавный «резиновый» снап; во время перетаскивания transition снимается классом .dragging */
    transition: height .38s cubic-bezier(.22, 1, .36, 1);
  }
  .sheet.dragging { transition: none; }
  .sheet.half { height: 46vh; }
  /* раскрытая шторка НЕ заходит под шапку/поиск — оставляем сверху место под них */
  .sheet.expanded { height: calc(100dvh - 180px); max-height: calc(100vh - 180px); }
  .sheet.collapsed { height: 108px; }
  /* шапка (ручка + заголовок) — зона перетаскивания: тач-скролл гасим здесь,
     а списку ниже разрешаем pan-y, иначе он не прокручивался (был touch-action:none на всей шторке). */
  .sheet .grip, .sheet .shead { touch-action: none; }
  .sheet .list { touch-action: pan-y; }
  .sheet .grip { padding: 10px 0 6px; display: grid; place-items: center; cursor: grab; }
  .sheet.dragging .grip { cursor: grabbing; }
  .sheet .grip .bar { width: 42px; height: 5px; border-radius: 999px; background: #cfd6e0; transition: background .2s; }
  .sheet .grip:active .bar { background: #aeb7c4; }
  .sheet .shead { padding: 2px 16px 10px; display: flex; align-items: center; gap: 10px; border-bottom: 1px solid var(--line-2); cursor: grab; }
  .sheet .shead .map-title { margin: 0; font-size: calc(15px * var(--fs, 1)); }
  .sheet .shead .count { color: var(--brand-ink); font-weight: 700; }
  .sheet .shead .fbtn {
    margin-left: auto; border: 1px solid var(--line); background: #fff; border-radius: 999px;
    padding: calc(7px * var(--fs, 1)) calc(13px * var(--fs, 1)); font-size: calc(13px * var(--fs, 1)); font-weight: 600; color: var(--ink-2); cursor: pointer;
    display: flex; align-items: center; gap: 6px;
  }
  .sheet .filters { display: none; }
  .sheet.filters-open .filters { display: block; }
  .sheet .list { padding: 8px 10px; }
  /* чипы ресурсов (Горячая/Холодная вода, Электричество...) и карточки списка —
     тот же автомасштаб, что и у шапки выше */
  .sheet .rchip { padding: calc(6px * var(--fs, 1)) calc(10px * var(--fs, 1)) calc(6px * var(--fs, 1)) calc(7px * var(--fs, 1));
    font-size: calc(12.5px * var(--fs, 1)); }
  .sheet .rchip .ic { width: calc(20px * var(--fs, 1)); height: calc(20px * var(--fs, 1)); }
  .sheet .card { padding: calc(12px * var(--fs, 1)); }
  .sheet .card .rname { font-size: calc(14px * var(--fs, 1)); }
  .sheet .card .badge { font-size: calc(10.5px * var(--fs, 1)); padding: calc(3px * var(--fs, 1)) calc(8px * var(--fs, 1)); }
  .sheet .card .addr { font-size: calc(13px * var(--fs, 1)); }
  .sheet .card .meta { font-size: calc(12px * var(--fs, 1)); }
  .sheet .card .when { font-size: calc(12.5px * var(--fs, 1)); }
  .sheet .card .ricon { width: calc(30px * var(--fs, 1)); height: calc(30px * var(--fs, 1)); font-size: calc(15px * var(--fs, 1)); }

  .fab {
    display: grid; position: absolute; z-index: 16; right: 14px; bottom: calc(42vh + 14px);
    width: 46px; height: 46px; border-radius: 50%; background: var(--panel); border: 1px solid var(--line);
    box-shadow: var(--shadow); place-items: center; cursor: pointer; font-size: 20px; transition: bottom .25s ease;
  }
}

/* Zoom controls reposition */
.leaflet-control-zoom { border: 1px solid var(--line) !important; box-shadow: var(--shadow-sm) !important; }
.leaflet-bottom.leaflet-right { margin-bottom: 6px; }
@media (max-width: 900px) { .leaflet-control-zoom { display: none; } }

/* ============ v2: houses, cards, ads, source ============ */
.head .source { font-size: 11px; color: var(--ink-3); margin-top: 6px; line-height: 1.35; }
.head .source .demo { color: var(--brand-ink); }

/* List cards (house-centric) */
.lcard { border: 1px solid var(--line); border-radius: var(--radius-sm); padding: 11px 12px; margin-bottom: 8px;
  cursor: pointer; transition: .12s; background: #fff; }
.lcard:hover { border-color: #d3dae4; box-shadow: var(--shadow-sm); }
.lc-top { display: flex; align-items: center; gap: 8px; margin-bottom: 7px; }
.lc-chips { display: flex; gap: 5px; }
.lc-chips .rc { width: 26px; height: 26px; border-radius: 8px; display: grid; place-items: center; font-size: 14px; }
.lc-chips .rc.more { font-family: var(--mono, monospace); font-size: 11px; font-weight: 700; background: var(--line-2); color: var(--ink-2); }
.lc-top .badge { margin-left: auto; }
.lc-addr { font-weight: 700; font-size: 14px; letter-spacing: -.2px; }
.lc-meta { font-size: 12px; color: var(--ink-3); margin-top: 3px; }
.badge { font-size: 10.5px; font-weight: 700; padding: 3px 8px; border-radius: 999px; text-transform: uppercase; letter-spacing: .3px; }
.badge.emergency { background: #fdecea; color: var(--emerg); }
.badge.planned { background: #eaf4fb; color: #2075b0; }

/* House card popup */
.house-popup .leaflet-popup-content-wrapper { border-radius: 16px; padding: 0; overflow: hidden; }
/* ⚠️ Второй набор правил для .leaflet-popup-close-button ОТСЮДА УДАЛЁН.
   Их было два: верхний (с !important) задавал размер и положение, нижний —
   фон и шрифт, потому что выигрывал по порядку. Читая любой из них по
   отдельности, нельзя было сказать, как кнопка выглядит на самом деле.
   Единственное место — блок «Крестик закрытия» выше. */
/* Ширина карточки дома.
   ⚠️ Именно ЭТА строка задаёт ширину — не опция maxWidth у L.popup. Раньше
   здесь стояло жёсткое `width: 300px`, и карточка оставалась узкой, сколько бы
   ни увеличивали maxWidth: адрес переносился на вторую строку, а длинные
   подписи кнопок («Следить за этим вместо прежнего») занимали её целиком.
   ⚠️ `!important` нужен потому, что Leaflet выставляет ширину инлайном после
   замера содержимого — без него правило проигрывает.
   На телефоне берём ширину экрана минус поля, на десктопе — фиксированную
   комфортную. ⚠️ clamp, а не min: если 100vw по какой-то причине окажется
   крошечным (встроенная панель, нестандартный webview), min() дал бы нулевую
   ширину и карточка схлопнулась бы в полоску. Нижняя граница это исключает. */
/* ⚠️ Нижняя граница ширины — НЕ жёсткие 280px. При зуме 200% на телефоне 375px
   остаётся ~188 CSS-пикселей, и карточка в 280px вылезала за экран: текст
   обрезался справа, появлялся горизонтальный скролл (поймано 20.09.2026 на
   проверке зума). Теперь минимум сам сжимается, когда экран уже него, но
   никогда не схлопывается в полоску — этого и боялись, ставя clamp. */
.house-popup .leaflet-popup-content {
  margin: 0;
  width: clamp(min(280px, calc(100vw - 24px)), calc(100vw - 32px), 380px) !important;
}
.house-card { font-family: var(--sans); }
/* padding-right считается от размера крестика, а не подбирается числом:
   12px от края карточки + сама кнопка + 12px до текста (см. --hc-close выше).
   При длинном адресе в две строки текст раньше залезал под кнопку. */
.hc-head { background: linear-gradient(135deg, #1f6feb, #4f93ff); color: #fff;
  padding: 16px calc(var(--hc-close, 40px) + 24px) 12px 16px;
  /* ⚠️ Шапка обязана быть выше кнопки, иначе круг свисает на белый контент под
     ней: 12px сверху + кнопка + 12px снизу. Короткий адрес в одну строку давал
     шапку в 47px, а кнопка 44px — свисало на 9px. */
  min-height: calc(var(--hc-close, 40px) + 24px);
  display: flex; flex-direction: column; justify-content: center; }
.hc-addr { font-size: 16px; font-weight: 700; letter-spacing: -.3px; line-height: 1.2; }
.hc-district { font-size: 12.5px; opacity: .85; margin-top: 3px; }
/* ---------- Карточка адреса: состояние, секции, две формы строки ----------
 *
 * ⚠️ ГЛАВНОЕ ПРАВИЛО ЭТОГО БЛОКА: идущее отключение и будущее НЕ ДОЛЖНЫ
 * выглядеть одинаково. Раньше у них была общая геометрия строки, и одинаковая
 * форма убеждала сильнее слов — плановое на послезавтра читалось как «воды
 * нет». Поэтому: у идущего — красная метка состояния и два факта в рамке
 * (когда началось / когда обещают), у планового — спокойная строка с датой и
 * окном времени, без alarm-цветов.
 *
 * ⚠️ Разделяем ЗАГОЛОВКАМИ СЕКЦИЙ и отступами, а не вложенными карточками с
 * рамками (требование ТЗ §7): вложенные рамки в попапе шириной 343px съедают
 * ширину и превращают карточку в матрёшку. */
.hc-status { padding: 12px 16px 10px; display: flex; flex-direction: column; gap: 3px; border-bottom: 1px solid var(--line-2); }
.hc-status b { font-size: 14.5px; line-height: 1.25; }
.hc-status span { font-size: 12.5px; color: var(--ink-3); }
.hc-status.off b { color: var(--emerg); }
.hc-status.ok b { color: #177a43; }

.hc-sec { padding: 8px 4px 2px; }
/* ⚠️ Заголовок секции — не декоративная надпись, а единственное, что отличает
   «сейчас» от «будет». Держим его контрастным и липким внутри прокрутки
   списка, иначе при скролле человек теряет, к какой группе относится строка. */
/* ⚠️ ЗАГОЛОВОК СЕКЦИИ НЕ ЛИПКИЙ — и это осознанно.
   Сначала он был `position: sticky`, чтобы при прокрутке было видно, к какой
   группе относится строка. На практике это дало ровно то, на что пожаловались с
   телефона: липкий элемент прилипает к краю ПРОКРУТОЧНОЙ ОБЛАСТИ, позиция
   прокрутки на тач-экране всегда дробная, и над заголовком оставалась щель
   меньше пикселя — в неё просвечивала уезжающая строка предыдущего события.
   Затыкать её фоном-тенью можно, но под заголовком всё равно оставалась
   наполовину срезанная строка — мусор на месте, которое должно читаться чисто.
   Список в карточке короткий (1–3 строки в секции), и «потерять контекст» в нём
   негде: заголовок просто уезжает вместе с содержимым. */
.hc-sec h4 { margin: 0 0 2px; padding: 7px 4px 7px; background: var(--panel);
  border-bottom: 1px solid var(--line-2);
  font-size: 11.5px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase; color: var(--ink-3); }
.hc-sec h4 .n { display: inline-grid; place-items: center; min-width: 16px; height: 16px; padding: 0 4px; margin-left: 4px;
  border-radius: 999px; background: var(--line-2); color: var(--ink-2); font-size: 10.5px; letter-spacing: 0; }

/* ⚠️ padding-top: 0 — обязательно. В прокручиваемом контейнере содержимое
   видно и в зоне верхнего внутреннего отступа: с `padding-top: 4px` над липким
   заголовком оставалась живая полоска, по которой ехал текст. Отступ сверху
   даёт сама секция, он прокручивается вместе с ней. */
.hc-list { padding: 0 12px 6px; max-height: 260px; overflow-y: auto;
  /* ---- ВИДНО, ЧТО СПИСОК ПРОКРУЧИВАЕТСЯ ----
   * ⚠️ С телефона: «нет видимости, что есть скролл». И правда: полоса прокрутки
   * на iOS появляется только во время движения пальца, а до этого карточка
   * выглядит законченной — человек не знает, что под кнопками есть ещё события.
   *
   * Классический приём «теней прокрутки» на четырёх фонах, БЕЗ JS:
   *   — две ЛОКАЛЬНЫЕ (background-attachment: local) заливки цветом панели
   *     едут вместе с содержимым и стоят у его начала и конца;
   *   — две ТЕНИ (scroll) прибиты к краям контейнера.
   * Пока есть что прокручивать, тень видна; у самого верха/низа её закрывает
   * приехавшая локальная заливка. То есть подсказка сама появляется и сама
   * исчезает — ровно тогда, когда должна.
   * ⚠️ Порядок слоёв важен: локальные заливки идут ПЕРВЫМИ (выше), иначе они не
   * перекроют тени. */
  background:
    linear-gradient(var(--panel) 40%, rgba(255,255,255,0)) top / 100% 20px no-repeat local,
    linear-gradient(rgba(255,255,255,0), var(--panel) 60%) bottom / 100% 20px no-repeat local,
    radial-gradient(farthest-side at 50% 0, rgba(20,30,50,.16), rgba(20,30,50,0)) top / 100% 8px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%, rgba(20,30,50,.16), rgba(20,30,50,0)) bottom / 100% 8px no-repeat scroll;
}
.hc-row { display: flex; gap: 11px; padding: 10px 4px; border-top: 1px solid var(--line-2); }
.hc-sec .hc-row:first-of-type { border-top: 0; }
.hc-row .ic { width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center; font-size: 16px; flex: none; }
.hc-main { flex: 1; min-width: 0; }
/* Имя ресурса — на всю ширину строки; бейдж (в т.ч. длинный «Сообщение жителя») —
   отдельной строкой под ним, а не втиснут рядом (раньше переносился криво). */
.hc-r1 { display: flex; flex-direction: column; align-items: flex-start; gap: 5px; }
.hc-r1 b { font-size: 14px; line-height: 1.25; }
.hc-r1 .badge { width: fit-content; }

/* Идущее: два факта подряд, «когда включат» — главный. */
.hc-facts { margin-top: 7px; display: flex; flex-direction: column; gap: 4px; }
.hc-fact { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12.5px; }
.hc-fact .k { color: var(--ink-3); }
.hc-fact .v { font-variant-numeric: tabular-nums; white-space: nowrap; }
.hc-fact.eta .k { color: var(--ink-2); font-weight: 600; }
.hc-fact.eta .v { font-weight: 700; }
.hc-fact.eta.overdue .k, .hc-fact.eta.overdue .v { color: #c2703a; }
.hc-row.active .ic { box-shadow: 0 0 0 3px rgba(217,67,58,.14); }

/* Плановое: дата и окно — крупно, всё остальное тише. Никакого «восстановят». */
.hc-plan { margin-top: 6px; display: flex; flex-direction: column; gap: 1px; }
.hc-plan b { font-size: 13.5px; line-height: 1.25; }
.hc-plan span { font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.hc-row.planned { opacity: .96; }

.hc-where { font-size: 12px; color: var(--ink-2); margin-top: 5px; }
.hc-where.muted { color: var(--ink-3); }

/* «Что происходит рядом» сворачивается, когда по самому адресу есть что
   показать (ТЗ §11). Нативный <details>: попапы Leaflet пересоздаются при
   каждом открытии, и любой JS-обработчик пришлось бы вешать заново. */
.hc-near { margin-top: 6px; border-top: 1px solid var(--line-2); }
.hc-near > summary { list-style: none; cursor: pointer; padding: 10px 4px; font-size: 12.5px; font-weight: 700; color: var(--brand-ink);
  display: flex; align-items: center; gap: 7px; }
.hc-near > summary::-webkit-details-marker { display: none; }
.hc-near > summary::after { content: ''; width: 7px; height: 7px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translateY(-2px); transition: transform .18s; }
.hc-near[open] > summary::after { transform: rotate(-135deg) translateY(-2px); }
/* Цветная точка перед "Рядом: <адрес>" — тот же цвет ресурса, что и у иконки
   строки выше, чтобы при беглом просмотре карточки сразу было видно, к какому
   ресурсу относится соседний дом, не читая текст. */
.hc-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; margin-right: 5px; vertical-align: middle; }
.hc-reason { font-size: 12px; color: var(--ink-2); margin-top: 6px; line-height: 1.4; }
.hc-sub { display: block; width: calc(100% - 24px); margin: 6px 12px 14px; padding: 11px; background: var(--brand); color: #fff;
  border: 0; border-radius: 11px; font-weight: 700; font-size: 13.5px; cursor: pointer; font-family: var(--sans); transition: .15s; }
.hc-sub:hover { background: var(--brand-ink); }
.hc-sub:active { transform: translateY(1px); }
.hc-sub.done { background: #1f9d55; }

/* Ad slots (advertiser inventory placeholders) */
.ad { display: block; text-decoration: none; color: inherit; position: relative; }
.ad-tag { position: absolute; top: 8px; left: 8px; font-size: 9px; font-weight: 700; text-transform: uppercase; letter-spacing: .6px;
  color: var(--ink-3); background: rgba(255,255,255,.9); border: 1px solid var(--line); padding: 2px 6px; border-radius: 5px; }
.ad-mpu { flex: none; margin: 10px; border: 1.5px dashed #c9d2de; border-radius: 14px; background:
  repeating-linear-gradient(135deg, #fafbfc, #fafbfc 12px, #f4f6f9 12px, #f4f6f9 24px); min-height: 150px; }
.ad-mpu .ad-body { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; text-align: center; }
.ad-mpu .ad-size { font-family: var(--mono, monospace); font-size: 12px; color: var(--ink-3); }
.ad-mpu .ad-text { font-size: 14px; font-weight: 600; color: var(--ink-2); }
.ad-mpu .ad-cta { font-size: 12px; color: var(--brand-ink); font-weight: 600; border: 1px solid rgba(31,111,235,.3); padding: 5px 12px; border-radius: 999px; margin-top: 4px; }
.ad-mpu:hover .ad-cta { background: var(--brand); color: #fff; border-color: var(--brand); }
.ad-mobile { display: none; }

@media (max-width: 900px) {
  .ad-mpu { display: none; }
  .ad-mobile { display: flex; align-items: center; gap: 10px; margin: 4px 12px 8px; padding: 12px 14px;
    border: 1.5px dashed #c9d2de; border-radius: 12px; background: #fafbfc; }
  .ad-mobile .ad-tag { position: static; }
  .ad-mobile .ad-text { flex: 1; font-size: 13px; font-weight: 600; color: var(--ink-2); }
  .ad-mobile .ad-cta { font-size: 12px; color: #fff; background: var(--brand); padding: 6px 12px; border-radius: 999px; font-weight: 600; }
}

/* Скрытие рекламных слотов до запуска рекламы (см. barjok.md §13). Вернуть — убрать класс ads-off с <body>. */
body.ads-off [data-ad-slot] { display: none !important; }

/* ============ v3: merged header, source popover, mini-search, pictogram filters ============ */
/* panel header: logo + title + info */
.panel .head { padding: 14px 16px 10px; }
.head-row { display: flex; align-items: center; gap: 10px; }
.head-row .mark {
  width: 30px; height: 30px; flex: none; text-decoration: none;
  display: grid; place-items: center;
}
.head-row .map-title { margin: 0; font-size: 16px; letter-spacing: -.3px; flex: 1; }
.info-btn {
  width: 22px; height: 22px; border-radius: 50%; border: 1px solid var(--line-2); background: #fff;
  color: var(--ink-3); font-family: Georgia, serif; font-style: italic; font-size: 13px; cursor: pointer; flex: none;
}
.info-btn:hover, .info-btn.on { border-color: var(--brand); color: var(--brand); }
.head p[data-subtitle] { margin: 6px 0 0; font-size: 12.5px; color: var(--ink-3); }
.head .count { font-weight: 700; color: var(--brand-ink); }
/* source popover */
.source-pop {
  display: none; margin-top: 10px; padding: 10px 12px; background: #f3f6fb; border: 1px solid var(--line);
  border-radius: 10px; font-size: 12px; color: var(--ink-2); line-height: 1.4;
}
.source-pop.open { display: block; }

/* mini-search inside panel */
.mini-search { position: relative; flex: 0 0 auto; max-width: none; margin: 2px 14px 4px; }
.mini-search input {
  width: 100%; height: 40px; border: 1px solid var(--line); background: var(--bg); border-radius: 12px;
  padding: 0 38px 0 38px; font-size: 14px; color: var(--ink); outline: none; font-family: var(--sans);
}
.mini-search input:focus { border-color: var(--brand); background: #fff; box-shadow: 0 0 0 3px rgba(31,111,235,.1); }
.mini-search .ico { position: absolute; left: 13px; top: 50%; transform: translateY(-50%); color: var(--ink-3); font-size: 15px; }
.mini-search .clear { right: 10px; }
.mini-search .suggest { top: 44px; }

/* filter bar */
.filterbar { padding: 6px 14px 10px; border-bottom: 1px solid var(--line-2); }
.res-row { display: flex; flex-wrap: wrap; gap: 6px; }
.rchip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 10px 6px 7px; border-radius: 999px;
  border: 1px solid var(--line); background: #fff; cursor: pointer; user-select: none; transition: .12s;
  font-size: 12.5px; color: var(--ink-2);
}
.rchip .ic { width: 20px; height: 20px; border-radius: 6px; display: grid; place-items: center; font-size: 12px; }
.rchip.on { color: #fff; border-color: transparent; font-weight: 600; }
.rchip.on .ic { background: rgba(255,255,255,.25); }
.rchip.off { opacity: .55; }
.rchip.off .ic { color: #fff; }

.filters-toggle {
  margin-top: 10px; width: 100%; display: flex; align-items: center; justify-content: center; gap: 6px;
  background: var(--bg); border: 1px solid var(--line); border-radius: 10px; padding: 8px; cursor: pointer;
  font-size: 12.5px; font-weight: 600; color: var(--ink-2); font-family: var(--sans);
}
.filters-toggle:hover { background: #eef1f5; }
.filters-toggle .chev { transition: transform .2s; font-size: 11px; }
.filterbar.open .filters-toggle .chev { transform: rotate(180deg); }
.filters-extra { max-height: 0; overflow: hidden; transition: max-height .28s ease; }
.filterbar.open .filters-extra { max-height: 220px; }
.filters-extra .fg { margin-top: 14px; }
.filters-extra .fg > .lbl { font-size: 11px; text-transform: uppercase; letter-spacing: .6px; color: var(--ink-3); margin-bottom: 8px; }

@media (max-width: 900px) {
  .panel { display: none; }
  /* Мобильная шапка: верхняя строка — бренд слева, город и язык справа;
     под ними поиск на всю ширину, крупнее (главное действие). */
  .topbar { flex-wrap: wrap; justify-content: flex-start; align-items: center; gap: 10px 8px;
    top: 10px; left: 12px; right: 12px; }
  /* Автомасштаб (--fs, см. <script> в map/index.html): высота/шрифт растут вместе
     с шириной экрана вместо того, чтобы оставаться "мелкими" на больших телефонах
     при том же наборе фиксированных px, что и на iPhone SE. */
  .topbar .mapbrand { order: 0; display: inline-flex; align-items: center; gap: 7px; height: calc(42px * var(--fs, 1));
    padding: 0 13px 0 10px; background: #fff; border: 1px solid var(--line); border-radius: 999px;
    box-shadow: var(--shadow-sm); text-decoration: none; color: var(--ink); }
  .topbar .mapbrand .logo-img { height: calc(26px * var(--fs, 1)); width: auto; display: block; }
  .topbar .tb-right { position: static; order: 1; margin-left: auto; width: auto;
    display: flex; align-items: center; gap: 8px; }
  .topbar .mapcity { flex: 0 1 auto; min-width: 0; }
  .topbar .mapcity-btn { height: calc(42px * var(--fs, 1)); max-width: 100%; font-size: calc(13.5px * var(--fs, 1)); }
  .topbar .mapcity-btn #mapCityName { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 84px; }
  .topbar .lang { position: static; flex: none; height: calc(42px * var(--fs, 1)); }
  .topbar .search { order: 2; width: 100%; flex: 1 1 100%; max-width: none; min-width: 0; }
  .topbar .search input { height: calc(52px * var(--fs, 1)); font-size: calc(16px * var(--fs, 1)); padding: 0 48px;
    box-shadow: 0 4px 16px rgba(20,30,50,.10); }
  .topbar .search .ico { left: 17px; }
  .topbar .search input::placeholder { color: var(--ink-3); opacity: 1; }
  .lang button { padding: 0 13px; font-size: calc(13px * var(--fs, 1)); }
  /* Раньше прятали ЛЮБОЙ .mini-search на мобильном (десктопная копия внутри
     .panel, которая и так недостижима — .panel{display:none} на этой ширине).
     Теперь своя копия поиска есть и внутри .sheet (жалоба: раньше искать
     можно было только через топбар) — её скрывать не нужно, поэтому правило
     сузили до .panel .mini-search. */
  .panel .mini-search { display: none; }
  .sheet .mini-search { margin: 8px 14px 4px; }
  .shead .mark { width: 28px; height: 28px; text-decoration: none; display: grid; place-items: center; }
  .shead .map-title { font-size: calc(14px * var(--fs, 1)); }
  .filterbar { border-bottom: 0; }
  .sheet .filters-extra { max-height: 0; }
  .sheet.filters-open .filters-extra { max-height: 220px; }
  .sheet .filters-toggle { display: none; }
}

/*
 * Узкие телефоны: бренд-пилюля + город + RU/KZ не помещались в одну строку.
 * Замер на живой проде (375px, iPhone SE): topbar 351px, а .mapbrand(111) + gap(8) +
 * .tb-right(233) = 352px — ПЕРЕПОЛНЕНИЕ РОВНО НА 1px. Flex-wrap переносил .tb-right
 * на новую строку целиком (шапка «съезжала» на 3 строки вместо 2, см. скриншот бага).
 * На реальных Android-экранах (часто 360px, у некоторых 340px) переполнение уже
 * 16–36px — там расползалось гарантированно, не «иногда».
 * Порог 400px — с большим запасом ниже реальных ширин узких телефонов, но выше их
 * не трогает (там достаточно места, сжимать нечего и незачем портить читаемость).
 */
@media (max-width: 400px) {
  .topbar { left: 10px; right: 10px; gap: 8px 6px; }
  .topbar .tb-right { gap: 6px; }
  .topbar .mapbrand { padding: 0 8px 0 7px; }
  .topbar .mapcity-btn { padding: 0 10px; }
  /* «Павлодар» = 66px natural width — 60px обрезал его до «Павло…» (жалоба
     пользователя). 72px даёт +6px запаса под разные рендереры шрифта, а
     недостающие ~12px забраны экономией на paddings выше (gap/brand/lang) —
     замерено на живом проде на 340px: раньше не помещалось на ~1px, теперь
     запас ~12px. На 320px (редкий/устаревший размер) шапка переносилась на
     2 строки уже ДО этой правки — не стало хуже, но и не стало идеально. */
  .topbar .mapcity-btn #mapCityName { max-width: 72px; }
  .lang button { padding: 0 7px; }
}

/* SVG-пиктограммы вместо эмодзи */
.ic-svg { width: 1em; height: 1em; display: block; }
.ui-svg { width: 1em; height: 1em; display: block; }
.search .ico .ui-svg, .mini-search .ico .ui-svg { width: 18px; height: 18px; }
.search .clear .ui-svg { width: 14px; height: 14px; }
.pin .ic-svg { width: 1em; height: 1em; }
.rchip .ic .ic-svg { width: 14px; height: 14px; }
.card .ricon .ic-svg, .lc-chips .rc .ic-svg { width: 15px; height: 15px; }
.hc-row .ic .ic-svg { width: 16px; height: 16px; }
.pop .ph .ricon .ic-svg { width: 15px; height: 15px; }
.fab .ui-svg { width: 20px; height: 20px; }
.fbtn .ui-svg { width: 15px; height: 15px; display: inline-block; vertical-align: -2px; }
.chev .ui-svg { width: 12px; height: 12px; }

/* Карточка «отключений нет» + тост */
.hc-ok { display: flex; align-items: center; gap: 12px; padding: 14px 4px 6px; }
.hc-ok .hc-checked{display:block;margin-top:4px;font-size:11.5px;color:var(--ink-3);opacity:.85}
.hc-ok svg { width: 30px; height: 30px; flex: none; color: #1f9d55; background: rgba(31,157,85,.12); border-radius: 50%; padding: 6px; }
.hc-ok b { display: block; font-size: 15px; color: #177a43; }
.hc-ok span { font-size: 12.5px; color: var(--ink-3); }
.toast {
  position: fixed; left: 50%; bottom: 26px; transform: translate(-50%, 10px);
  background: rgba(15,20,27,.9); color: #fff; font-size: 13.5px; font-weight: 600;
  padding: 10px 18px; border-radius: 999px; z-index: 60; opacity: 0; pointer-events: none;
  transition: opacity .2s, transform .2s; font-family: var(--sans);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
#map { cursor: pointer; }

/* Подсветка улицы целиком (когда в источнике указана только улица) */
.street-hl { cursor: pointer; filter: drop-shadow(0 1px 2px rgba(0,0,0,.25)); }
.street-hl:hover { opacity: 1 !important; }

/* Подсказка адреса без отключений */
.suggest .sg .tag.ok { background: rgba(31,157,85,.12); color: #177a43; font-weight: 600; }
.suggest .sg .tag.warn { background: rgba(232,102,61,.14); color: #b8471f; font-weight: 600; }

/* ---------- Выбор города ----------
   ⚠️ z-index выше шапки: пока город не выбран, показывать нечего, и любые
   элементы карты под модалкой — только шум. Это единственное место, где мы
   перекрываем шапку намеренно.
   ⚠️ Фон затемнения непрозрачный по краям: под ним карта города по умолчанию,
   и просвечивающие чужие отключения выглядели бы как «данные уже показаны». */
.city-modal {
  position: fixed; inset: 0; z-index: 5000;
  display: flex; align-items: center; justify-content: center; padding: 20px;
  background: rgba(16, 20, 30, .55); backdrop-filter: blur(3px);
}
.city-box {
  width: min(420px, 100%); background: #fff; border-radius: 18px;
  padding: 26px 24px 22px; box-shadow: 0 24px 60px -20px rgba(16,20,30,.45);
}
.city-box h2 { margin: 0 0 6px; font-size: 21px; font-weight: 800; letter-spacing: -.02em; color: var(--ink); }
.city-box p { margin: 0 0 18px; font-size: 13.5px; line-height: 1.5; color: var(--ink-3); }
.city-list { display: flex; flex-direction: column; gap: 8px; }
.city-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; min-height: 52px; padding: 0 16px; text-align: left; text-decoration: none;
  border: 1px solid var(--line); border-radius: 12px; background: #fff; color: var(--ink);
  font-family: var(--sans); font-weight: 700; font-size: 15px; cursor: pointer;
  transition: border-color .15s, background .15s, transform .1s;
}
.city-item:hover { border-color: var(--brand); background: color-mix(in srgb, var(--brand) 4%, #fff); }
.city-item:active { transform: translateY(1px); }
/* Город без данных: виден, но не выбирается — обещать нечего. */
.city-item.off { cursor: default; color: var(--ink-3); background: var(--bg, #f7f8fa); }
.city-item.off:hover { border-color: var(--line); background: var(--bg, #f7f8fa); }
.city-item em {
  font-style: normal; font-size: 11.5px; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase; color: var(--ink-3);
  border: 1px solid var(--line); border-radius: 999px; padding: 3px 9px;
}
.city-load { font-size: 13.5px; color: var(--ink-3); padding: 8px 2px; }
/* Пока выбираем город — под модалкой не должно быть кликабельного интерфейса. */
body.choosing-city .topbar,
body.choosing-city .panel,
body.choosing-city .sheet,
body.choosing-city .fab,
body.choosing-city .report-fab { display: none; }

/* ---------- Карточка дома перекрывает всё, кроме шапки ----------
 *
 * ⚠️ ПОДНЯТЬ КАРТОЧКУ НЕЛЬЗЯ. Она живёт внутри `.leaflet-map-pane`, которому
 * Leaflet ставит `transform` при каждом сдвиге карты, — а transform создаёт
 * контекст наложения. Никакой z-index на попапе не выведет его выше элементов,
 * лежащих рядом с `#map`. Поэтому уступают ОНИ.
 *
 * ⚠️ display: none, БЕЗ АНИМАЦИИ. Сначала здесь было
 * `visibility: hidden; opacity: 0; transition: … visibility .15s` — и оно НЕ
 * СРАБОТАЛО: правило выигрывало каскад (computed `transition` был наш), но
 * `visibility` намертво оставалась `visible`. Переход по дискретному свойству
 * не доигрывал, и значение залипало. Тот же класс граблей, что в v47, где
 * незавершённый переход оставлял opacity равной 1.
 * Кнопки позиционированы абсолютно, поэтому display: none ничего не сдвигает —
 * зато не оставляет места для «не доиграло».
 *
 * Левый список на ДЕСКТОПЕ не прячем: он у края, и карточку от него уводит
 * отступами автоподгонки (popupPanPadding) — прятать список адресов посреди
 * работы было бы хуже перекрытия.
 *
 * ⚠️ А вот НИЖНЮЮ ШТОРКУ на телефоне прячем. Отступами её обойти нельзя:
 * шторка прибита к низу на всю ширину, и высокая карточка (сводка + список
 * отключений + кнопки + блок «Следить за этим адресом») в остаток экрана
 * физически не влезает. keepPopupOnScreen в этом случае прижимает карточку к
 * ВЕРХУ — и низ с кнопкой Telegram оказывался под шторкой, недосягаемым:
 * доскроллить картой нельзя (карта под шторкой), прокрутить карточку тоже
 * (скролла не было). Поэтому на телефоне выбранная карточка — главный объект,
 * а шторка уступает ей место целиком и возвращается при закрытии карточки.
 * Специфичности `body.has-card .sheet` (0,2,1) хватает, чтобы победить
 * `.sheet.expanded` (0,2,0) внутри @media — держать отдельный медиа-блок
 * не нужно, на десктопе шторка и так display:none.
 */
body.has-card .fab,
body.has-card .report-fab,
body.has-card .mapnotice,
body.has-card .sheet { display: none; }

/* ⚠️ НА ТЕЛЕФОНЕ ПРЯЧЕМ И ШАПКУ С ПОИСКОМ. Карточка — ответ на вопрос, который
   человек только что задал этим самым поиском; пока она открыта, поиск ему не
   нужен, а место занимает: на 375px шапка с брендом, городом, языком и строкой
   поиска съедает ~170px сверху, и карточка начинается под ними. Закрыл карточку
   — всё вернулось. На десктопе шапку не трогаем: там карточка открывается
   правее панели и ничего не перекрывает. */
@media (max-width: 900px) {
  body.has-card .topbar { display: none; }
}

/* Карточка не влезает в экран → прокручивается ЦЕЛИКОМ, одним скроллом.
 *
 * ⚠️ ИСТОРИЯ ЭТОГО МЕСТА — два разных решения, и второе принято по живому сбою.
 * Сначала прокручивалась вся карточка. Потом её прибили: шапка и кнопки
 * зафиксированы, скроллится только середина — чтобы кнопка Telegram всегда была
 * на виду. На узком экране в 100% масштаба это работало.
 *
 * ⚠️ 20.09.2026 пришёл случай, который так НЕ чинится: встроенный браузер
 * Instagram + крупный системный шрифт + зум 200%. Прибитые шапка, статус и две
 * кнопки занимают больше, чем весь экран, середине не остаётся ничего, и до
 * блока «Следить за этим адресом» дойти НЕЧЕМ — скроллить можно только то, что
 * уже схлопнуто в ноль. Вложенный скролл здесь не спасает, а гарантирует потерю
 * нижней части (ТЗ «мобильный скролл карточки», P0).
 *
 * Поэтому на телефоне: ОДИН скролл на всю карточку, шапка с адресом — липкая
 * (адрес и крестик доступны всегда), вложенных скроллов нет вовсе. Вся высота
 * уходит содержимому, и до Telegram можно доскроллить при любом масштабе.
 *
 * ⚠️ Высоту приходится протягивать через ВСЮ цепочку Leaflet
 * (.leaflet-popup-content-wrapper → .leaflet-popup-content → .house-card):
 * ограничение на одном контейнере не доходит до внука, и .hc-list снова
 * вырастает во всю длину. Каждому промежуточному нужен min-height: 0 —
 * без него flex-элемент не даёт себя сжать ниже содержимого, и скролла нет.
 *
 * ⚠️ Крестик закрытия живёт ВНЕ этой цепочки (Leaflet вешает его на
 * .leaflet-popup). Поэтому здесь НЕТ z-index: любое положительное значение
 * внутри карточки перекрывает крестик — он позиционирован без z-index, и
 * `z-index: 1` на шапке его прятал (карточку становилось нечем закрыть).
 */
@media (max-width: 900px) {
  /* Палец — не курсор: 44px это минимальная надёжная цель по гайдлайнам
     (и кратно 4). Отступ шапки пересчитается сам. */
  .house-popup { --hc-close: 44px; }
}
/* ⚠️ И НА НИЗКОМ ОКНЕ ДЕСКТОПА ТОЖЕ. Дело не в телефоне, а в высоте: в окне
   ~600px карточка так же не помещается, keepPopupOnScreen прижимает её к верху,
   и кнопки оказываются за нижним краем — доскроллить нечем, карта под ними не
   двигает карточку. Правила одни и те же, поэтому и медиазапрос один. */
@media (max-width: 900px), (max-height: 760px) {
  /* ЕДИНСТВЕННЫЙ скролл-контейнер карточки. */
  .house-popup .leaflet-popup-content-wrapper {
    /* 56px = поля экрана (16 сверху и 24 снизу, см. popupPanPadding) плюс
       «хвостик» попапа. ⚠️ Вырезы экрана вычитаем отдельно: на телефоне с
       чёлкой и жестовой полосой без этого нижняя кнопка оказывается под
       системной полосой. Все числа кратны 4 (правило владельца). */
    display: block;
    max-height: calc(100dvh - 56px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
    overflow-y: auto; overflow-x: hidden;
    /* ⚠️ contain — чтобы «дотянув» карточку до конца, палец не начинал тащить
       страницу под ней (в Instagram/Telegram это закрывает встроенный браузер). */
    overscroll-behavior: contain; -webkit-overflow-scrolling: touch; touch-action: pan-y;
    /* Полоса прокрутки видна постоянно, а не только в движении: на iOS иначе
       карточка выглядит законченной и человек не знает, что ниже есть ещё. */
    scrollbar-width: thin; scrollbar-color: #c9d2de transparent;
  }
  .house-popup .leaflet-popup-content-wrapper::-webkit-scrollbar { width: 4px; }
  .house-popup .leaflet-popup-content-wrapper::-webkit-scrollbar-thumb { background: #c9d2de; border-radius: 999px; }
  .house-popup .leaflet-popup-content-wrapper::-webkit-scrollbar-track { background: transparent; }
  .house-popup .leaflet-popup-content { display: block; }
  .house-popup .house-card { display: block; width: 100%; }

  /* Шапка с адресом — липкая: при любой длине списка видно, ЧЕЙ это адрес. */
  .house-popup .hc-head { position: sticky; top: 0; z-index: 2; }
  /* ⚠️ Крестик Leaflet живёт ВНЕ прокручиваемой части (он на .leaflet-popup), и
     без явного z-index липкая шапка накрывала его собой — карточку становилось
     нечем закрыть. Раньше это чинили запретом z-index внутри карточки; теперь
     порядок задан явно и в одном месте. */
  .house-popup .leaflet-popup-close-button { z-index: 3 !important; }

  /* ⚠️ ВЛОЖЕННЫХ СКРОЛЛОВ НА ТЕЛЕФОНЕ НЕТ (ТЗ P0). Список отдаёт свою высоту
     общему скроллу; заодно снимаем «тени прокрутки» — им больше нечего
     показывать, а на статичном списке они читаются как лишние полосы. */
  .house-popup .hc-list {
    max-height: none; overflow: visible; background: none; min-height: 0;
  }
}

/* ---------- Точка входа в уведомления (ТЗ §6) ----------
 * Стоит и в панели десктопа, и в нижней шторке телефона — между фильтрами и
 * списком. Раньше подписаться можно было только изнутри карточки дома: человек,
 * который зашёл посмотреть на карту, про уведомления не узнавал вовсе.
 * Оформление — карточка панели из дизайн-системы карты: та же подложка, те же
 * линии и та же кнопка бренда, что у подписки в карточке дома.
 */
.notify-cta {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: 8px 12px 0; padding: 12px;
  background: var(--panel); border: 1px solid var(--line-2); border-radius: 12px;
  transition: border-color .2s, box-shadow .2s;
}
.notify-cta .nc-text { flex: 1 1 160px; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.notify-cta .nc-text b { font-size: 13.5px; line-height: 1.25; color: var(--ink); }
.notify-cta .nc-text span { font-size: 12px; line-height: 1.35; color: var(--ink-3); }
.notify-cta .nc-btn {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 40px; padding: 0 14px; border: 0; border-radius: 10px; cursor: pointer;
  background: var(--brand); color: #fff;
  font-family: var(--sans); font-weight: 700; font-size: 13px;
  box-shadow: 0 6px 16px -8px rgba(31,111,235,.7);
  transition: background .2s, transform .1s;
}
.notify-cta .nc-btn svg { width: 16px; height: 16px; flex: none; }
.notify-cta .nc-btn:hover { background: var(--brand-ink); }
.notify-cta .nc-btn:active { transform: translateY(1px); }
/* Какой адрес возьмёт кнопка — видно до нажатия, а не после. Строка занимает
   всю ширину блока: адрес длинный, рядом с кнопкой он ужимался бы в многоточие,
   то есть ровно то, что нужно прочитать, и пропадало бы. */
.notify-cta .nc-addr {
  flex: 1 0 100%; display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
  font-size: 12px; line-height: 1.35; color: var(--ink-2);
}
.notify-cta .nc-addr[hidden] { display: none; }
.notify-cta .nc-addr-val { min-width: 0; overflow-wrap: anywhere; }
.notify-cta .nc-other {
  flex: none; padding: 0; border: 0; background: none; cursor: pointer;
  font-family: var(--sans); font-size: 12px; color: var(--brand-ink);
  text-decoration: underline; text-underline-offset: 2px;
}
.notify-cta .nc-other:hover { color: var(--brand); }
/* Адрес ещё не выбран — подсказываем, куда смотреть, вместо молчаливого фокуса. */
.notify-cta .nc-hint { flex: 1 0 100%; font-size: 12px; color: var(--brand-ink); }
.notify-cta.ask { border-color: var(--brand); box-shadow: 0 0 0 3px rgba(47,107,237,.12); }
/* Пока открыта карточка адреса, блок не нужен: подписка уже внутри неё. */
body.has-card .notify-cta { display: none; }
/* Вошли только как КСК/ОСИ (владелец 28.09.2026): подписка жителя председателю не нужна —
   его уведомления идут из кабинета КСК. Класс ставит buildAccountMenus в app.js. */
body.as-org .notify-cta, body.as-org .hc-watch { display: none; }
/* На узкой шторке кнопка становится во всю ширину — иначе текст в две строки
   ужимает её до нечитаемой. */
@media (max-width: 420px) {
  .notify-cta { gap: 10px; }
  .notify-cta .nc-btn { flex: 1 0 100%; }
}

/* ---------- Липкая кнопка «Следить за этим адресом» (ТЗ P1) ----------
 * Держится у нижнего края прокручиваемой карточки и исчезает, как только блок
 * подписки виден сам (наблюдатель в map/app.js) — чтобы не стоять поверх той
 * кнопки, к которой ведёт.
 * ⚠️ Вырез экрана учитываем здесь же: на телефоне с жестовой полосой кнопка
 * иначе оказывается ровно под ней.
 * Оформление — из дизайн-системы карточки: та же кнопка бренда, что и в блоке
 * подписки (.hc-watch-btn), на подложке панели с верхней линией.
 */
.hc-cta {
  position: sticky; bottom: 0; z-index: 1;
  padding: 8px 14px calc(12px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(rgba(255,255,255,0), var(--panel) 40%);
  border-top: 1px solid var(--line-2);
  backdrop-filter: blur(6px);
}
.hc-cta[hidden] { display: none; }
.hc-cta-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; min-height: 44px; padding: 0 16px;
  border: 0; border-radius: 12px; cursor: pointer; text-decoration: none;
  background: var(--brand); color: #fff;
  box-shadow: 0 6px 16px -6px rgba(31,111,235,.6);
  font-family: var(--sans); font-weight: 700; font-size: 13.5px;
  transition: background .2s, transform .1s;
}
.hc-cta-btn svg { width: 17px; height: 17px; flex: none; fill: currentColor; }
.hc-cta-btn:hover { background: var(--brand-ink); }
.hc-cta-btn:active { transform: translateY(1px); }
/* Уже подписан — состояние, а не призыв: спокойная вторичная кнопка. */
.hc-cta-btn.ghost {
  background: #eef3fb; color: var(--brand-ink); box-shadow: none;
  border: 1px solid var(--line-2);
}
.hc-cta-btn.ghost:hover { background: #e4ecf8; }

/* ⚠️ На десктопе липкой кнопки нет: карточка там помещается целиком, а лишняя
   полоса поверх содержимого только съедает высоту. */
@media (min-width: 901px) and (min-height: 761px) {
  .hc-cta { display: none !important; }
}

/* ============ ПЛАНШЕТ И «УВЕЛИЧЕННЫЙ ЭКРАН» ============
 * ⚠️ ЗАЧЕМ ОТДЕЛЬНЫЙ РЕЖИМ. Жалоба владельца 22.09.2026: «люди сидят с
 * увеличенным экраном». Ноутбук 1440×900 в масштабе 125–150% — это 960–1150
 * CSS-пикселей в ширину и 600–720 в высоту: слишком широко для мобильной
 * шторки, но слишком НИЗКО для десктопной панели. Замер на 1080×630: из 602px
 * панели шапка брала 79, плашки ресурсов в три ряда — 177, блок уведомлений —
 * 129, второе поле поиска — 46, и списку отключений оставалось 162px — ОДНА
 * карточка. А верхний поиск заезжал на панель на 32px.
 *
 * ⚠️ Режим включается по ВЫСОТЕ, а не только по ширине: уменьшенная высота и
 * есть главный признак увеличенного масштаба (и iPad в горизонтали). Обычный
 * десктоп (высота > 820) этими правилами не затрагивается вовсе.
 */

/* Ширина 901–1279: верхняя строка начинается ПОСЛЕ панели, а не по центру
   экрана — иначе центрированный поиск перекрывал правый край панели. */
@media (min-width: 901px) and (max-width: 1279px) {
  .topbar { left: calc(14px + 328px + 12px); justify-content: flex-start; }
  .topbar .search { flex: 1 1 auto; max-width: 520px; min-width: 0; }
  .topbar .tb-right { position: static; margin-left: auto; flex: none; }
  .mapnotice { left: calc(14px + 328px + 12px); }
}

/* Низкое окно: высоту панели отдаём СПИСКУ, а не обвязке вокруг него. */
@media (min-width: 901px) and (max-height: 820px) {
  .panel .head { padding: 10px 14px 8px; }
  .panel .head p { margin-top: 2px; }

  /* Плашки ресурсов — ОДНОЙ строкой с горизонтальной прокруткой вместо трёх
     рядов. Край затухает: видно, что справа есть ещё (и это работает и
     пальцем, и тачпадом). */
  .panel .filterbar { padding: 6px 14px 8px; }
  .panel .res-row {
    flex-wrap: nowrap; overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; padding-bottom: 2px;
    -webkit-mask-image: linear-gradient(90deg, #000 86%, transparent);
            mask-image: linear-gradient(90deg, #000 86%, transparent);
  }
  .panel .res-row::-webkit-scrollbar { display: none; }
  .panel .rchip { flex: none; }
  .panel .filters-toggle { margin-top: 8px; padding: 6px; }

  /* Блок уведомлений — одна кнопка: подпись «Настроить уведомления» с
     колокольчиком объясняет себя сама, а заголовок с подтекстом стоили 129px. */
  .panel .notify-cta { margin: 6px 12px 0; padding: 0; border: 0; background: transparent; }
  .panel .notify-cta .nc-text { display: none; }
  .panel .notify-cta .nc-btn { flex: 1 1 100%; min-height: 38px; }

  /* Второе поле поиска в панели дублирует верхнее — на низком экране
     оставляем одно, основное. */
  .panel .mini-search { display: none; }
}

/* Планшет в ПОРТРЕТЕ (iPad 768–834px): здесь работает мобильная раскладка, но
   шторка во всю ширину экрана выглядит как растянутый телефон, а строка
   поиска в 744px — как поле для абзаца. Делаем их плавающей колонкой у левого
   края, как в картах на планшетах: карта справа остаётся видна целиком.
   ⚠️ Только ширина и отступы — механику шторки (высоты, перетаскивание) не
   трогаем, она считается от высоты, а не от ширины. */
@media (min-width: 601px) and (max-width: 900px) {
  .sheet {
    left: 12px; right: auto; width: min(560px, calc(100% - 24px));
    border-radius: 20px 20px 0 0;
  }
  .topbar .search { max-width: 560px; }
}

/* Палец, а не курсор (планшет в любой ориентации): цели не меньше 40px. */
@media (min-width: 901px) and (pointer: coarse) {
  .rchip { padding: 9px 12px 9px 8px; }
  .filters-toggle { padding: 10px; }
  .notify-cta .nc-btn { min-height: 44px; }
}

.report-fab:hover { background: var(--brand-ink); }
.report-fab:active { transform: translateY(1px); }
.report-fab svg { width: 18px; height: 18px; }

/* Кнопки внутри карточки дома — отделены от контента, с отступами со всех сторон,
   чтобы читались как самостоятельные целевые кнопки, а не футер-полоса.
   «Поделиться с соседями» — вторичная (ghost), «Сообщить о ситуации» — основная (brand),
   друг над другом (не в ряд — на узкой карточке текст в две строки читался тесно). */
.hc-actions { display: flex; flex-direction: column; gap: 8px; margin: 12px 14px 14px; }
.hc-report, .hc-share {
  display: flex; align-items: center; justify-content: center; gap: 7px;
  flex: none; width: 100%; height: 44px;
  border-radius: 12px; cursor: pointer;
  font-family: var(--sans); font-weight: 700; font-size: 13.5px;
  transition: background .2s, transform .1s, box-shadow .2s, border-color .2s;
}
.hc-report {
  border: 0; background: var(--brand); color: #fff;
  box-shadow: 0 6px 16px -6px rgba(31,111,235,.6);
}
.hc-report::before {
  content: ''; width: 17px; height: 17px; flex: none;
  background: currentColor;
  -webkit-mask: var(--report-ico) center/contain no-repeat; mask: var(--report-ico) center/contain no-repeat;
}
.hc-report:hover { background: var(--brand-ink); }
.hc-report:active { transform: translateY(1px); box-shadow: 0 3px 10px -4px rgba(31,111,235,.6); }
.hc-share {
  border: 1px solid var(--line); background: #fff; color: var(--ink);
}
.hc-share::before {
  content: ''; width: 16px; height: 16px; flex: none;
  background: currentColor;
  -webkit-mask: var(--share-ico) center/contain no-repeat; mask: var(--share-ico) center/contain no-repeat;
}
.hc-share:hover { border-color: var(--ink-3, #8a93a6); }
.hc-share:active { transform: translateY(1px); }
/* ---------- «Следить за этим адресом» → Telegram ----------
   Отдельный блок ПОД основными действиями, а не третья кнопка в ряду:
   «Поделиться» и «Сообщить о ситуации» — про текущее отключение, а подписка —
   про будущее. Смешать их в один ряд значило бы уравнять разовое действие
   с постоянным обязательством сервиса перед человеком. */
.hc-watch { margin: 0 14px 14px; padding-top: 13px; border-top: 1px solid var(--line-2); }
/* Заголовок блока: «следить за адресом» — это СУЩНОСТЬ, а не действие.
   Кнопка ниже называет канал, и они не должны выглядеть одинаково. */
.hc-watch-head { display: flex; align-items: center; gap: 7px; margin-bottom: 4px; }
.hc-watch-head b { font-size: 14.5px; font-weight: 800; letter-spacing: -.01em; color: var(--ink); }
.hc-watch-head .ui-svg { width: 16px; height: 16px; flex: none; color: var(--brand); }
.hc-watch-lead { margin: 0 0 11px; font-size: 12.5px; line-height: 1.5; color: var(--ink-3); }
.hc-watch-lead.warn { color: var(--ink-2); font-weight: 600; }
.hc-watch-btn {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; height: 44px; cursor: pointer;
  border: 0; border-radius: 12px;
  background: var(--brand); color: #fff;
  box-shadow: 0 6px 16px -6px rgba(31,111,235,.6);
  font-family: var(--sans); font-weight: 700; font-size: 13.5px;
  transition: background .2s, transform .1s, box-shadow .2s;
}
.hc-watch-btn svg { width: 17px; height: 17px; flex: none; fill: currentColor; }
.hc-watch-btn:hover { background: var(--brand-ink); }
.hc-watch-btn:active { transform: translateY(1px); box-shadow: 0 3px 10px -4px rgba(31,111,235,.6); }
.hc-watch-btn:disabled { opacity: .55; cursor: default; transform: none; }
/* ⚠️ Без этой строки `btn.hidden = true` НЕ РАБОТАЕТ: браузерное правило
   `[hidden]{display:none}` слабее нашего `display:flex` по специфичности, и
   кнопка остаётся на экране. В карточке тогда стоят две синие кнопки подряд —
   «Получать уведомления» и «Открыть Telegram», — и непонятно, какую нажимать.
   На тех же граблях в проекте уже стояли с opacity вместо visibility (v47). */
.hc-watch-btn[hidden] { display: none; }
/* Карточка улицы: вместо подписки — переход к выбору своего дома. */
.hc-watch-pick {
  width: 100%; min-height: 44px; padding: 0 16px; border-radius: 12px;
  border: 1.5px solid var(--brand); background: transparent; color: var(--brand);
  font-family: var(--sans); font-weight: 700; font-size: 13.5px; cursor: pointer;
}
.hc-watch-pick:hover { background: rgba(31,111,235,.08); }
.hc-watch-pick:active { transform: translateY(1px); }
/* Уже подписан — блок не зовёт к действию, а сообщает состояние. */
.hc-watch.is-on .hc-watch-head b { color: #1f7a4d; }
.hc-watch.is-on .hc-watch-head .ui-svg { color: #1f7a4d; }
.hc-watch-settings {
  align-self: flex-start; margin-top: 8px; height: 36px; padding: 0 16px;
  display: inline-flex; align-items: center; border-radius: 10px;
  border: 1px solid var(--line); background: #fff; color: var(--ink);
  font-weight: 700; font-size: 13px; text-decoration: none;
}
.hc-watch-settings:hover { border-color: var(--ink-3); color: var(--ink); }
.hc-watch-state {
  display: flex; flex-direction: column; gap: 4px;
  margin-top: 9px; font-size: 12.5px; line-height: 1.5; color: var(--ink-2);
}
.hc-watch-state b { color: var(--ink); font-size: 13px; }
.hc-watch-state.err { color: #b4232a; }
.hc-watch-state.done b { color: #1f7a4d; }
/* ⚠️ Селектор с .hc-watch, а не просто .hc-watch-go: у самого Leaflet есть
   правило `.leaflet-container a { color:#0078A8 }` — две единицы специфичности
   против одной, и оно перебивало белый текст. Кнопка получалась тёмно-серой
   на синем и не читалась вовсе. Та же причина у ссылки в кабинет ниже. */
.hc-watch .hc-watch-go {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 42px; border-radius: 11px; text-decoration: none;
  background: var(--brand); color: #fff; font-weight: 700; font-size: 13.5px;
  box-shadow: 0 6px 16px -6px rgba(31,111,235,.6);
  transition: background .2s, transform .1s;
}
.hc-watch .hc-watch-go:hover { background: var(--brand-ink); color: #fff; }
.hc-watch .hc-watch-go:active { transform: translateY(1px); }
/* Логотип Telegram — заливкой, чтобы был узнаваем; наследует белый цвет кнопки. */
.hc-watch .hc-watch-go svg { width: 17px; height: 17px; flex: none; fill: currentColor; }
.hc-watch .hc-watch-cab { align-self: flex-start; margin-top: 2px; font-size: 12.5px; font-weight: 700;
  color: var(--brand-ink); text-decoration: none; }
.hc-watch .hc-watch-cab:hover { text-decoration: underline; color: var(--brand-ink); }

/* разделитель над кнопками — визуально отделяет от списка отключений */
.hc-list { border-bottom: 1px solid var(--line-2); margin-bottom: 2px; }

/* ADS: нативный контекстный компонент (§21 документа) — НЕ баннер: та же карточка,
   что и остальной контент дома, с обязательной подписью «Реклама» (её нельзя убрать,
   в отличие от secondary label вроде «Может пригодиться»). */
.ad-card {
  margin: 4px 14px 10px; padding: 10px 12px; border-radius: 12px;
  background: var(--panel-2, #f4f6fb); border: 1px solid var(--line-2);
  font-family: var(--sans); text-decoration: none; color: inherit; display: block;
}
.ad-card .ad-eyebrow { display: flex; justify-content: space-between; align-items: center; margin-bottom: 6px; }
.ad-card .ad-secondary { font-size: 11px; color: var(--ink-3, #8a93a6); font-weight: 600; }
.ad-card .ad-label { font-size: 10px; color: var(--ink-3, #8a93a6); text-transform: uppercase; letter-spacing: .04em; }
.ad-card .ad-body { display: flex; gap: 10px; align-items: flex-start; }
.ad-card .ad-logo { width: 36px; height: 36px; border-radius: 8px; object-fit: cover; flex: none; background: #fff; }
.ad-card .ad-text { min-width: 0; flex: 1; }
.ad-card .ad-headline { font-weight: 700; font-size: 13.5px; color: var(--ink); line-height: 1.3; }
.ad-card .ad-desc { font-size: 12px; color: var(--ink-2); margin-top: 2px; line-height: 1.35; }
.ad-card .ad-cta { display: inline-block; margin-top: 8px; padding: 6px 12px; border-radius: 8px; background: var(--brand); color: #fff; font-size: 12.5px; font-weight: 700; }
.ad-card:hover .ad-cta { background: var(--brand-ink); }
:root { --report-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 9v4M12 17h.01M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z'/%3E%3C/svg%3E"); }
:root { --share-ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'/%3E%3Ccircle cx='6' cy='12' r='3'/%3E%3Ccircle cx='18' cy='19' r='3'/%3E%3Cline x1='8.59' y1='13.51' x2='15.42' y2='17.49'/%3E%3Cline x1='15.41' y1='6.51' x2='8.59' y2='10.49'/%3E%3C/svg%3E"); }

/* Модалка */
.report-modal { position: fixed; inset: 0; z-index: 1000; display: none; }
.report-modal.show { display: block; }
.report-modal .rm-back { position: absolute; inset: 0; background: rgba(16,22,32,.5); backdrop-filter: blur(2px); }
.report-modal .rm-card {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: min(460px, calc(100vw - 28px)); max-height: calc(100dvh - 32px); overflow-y: auto;
  background: var(--panel); border-radius: 20px; box-shadow: 0 30px 70px -20px rgba(16,22,32,.55);
  padding: 24px 22px 22px;
}
.report-modal .rm-x {
  position: absolute; right: 14px; top: 14px; width: 32px; height: 32px; border: 0; border-radius: 50%;
  background: var(--line-2); color: var(--ink-2); cursor: pointer; display: grid; place-items: center;
}
.report-modal .rm-x svg { width: 15px; height: 15px; }
.report-modal .rm-x:hover { background: #e3e8ef; }
.report-modal .rm-title { margin: 0 34px 4px 0; font-size: 19px; letter-spacing: -.2px; }
.report-modal .rm-sub { margin: 0 0 16px; font-size: 13.5px; color: var(--ink-3); line-height: 1.45; }

.report-modal .rm-seg { display: flex; gap: 6px; background: var(--bg); border: 1px solid var(--line); border-radius: 12px; padding: 4px; margin-bottom: 16px; }
.report-modal .rm-seg button { flex: 1; border: 0; background: transparent; padding: 9px 8px; border-radius: 9px; cursor: pointer; font-family: var(--sans); font-weight: 700; font-size: 14px; color: var(--ink-3); }
.report-modal .rm-seg button.on { background: var(--panel); color: var(--brand-ink); box-shadow: var(--shadow-sm); }

.report-modal .rm-field { margin-bottom: 14px; }
.report-modal .rm-lbl { display: block; font-size: 12.5px; font-weight: 700; color: var(--ink-2); margin-bottom: 7px; }
.report-modal .rm-req { color: var(--emerg); }
.report-modal .rm-select, .report-modal #rmAddress, .report-modal #rmMessage {
  width: 100%; border: 1px solid var(--line); background: var(--panel); border-radius: 11px;
  padding: 12px 13px; font-family: var(--sans); font-size: 15px; color: var(--ink); outline: none;
}
.report-modal .rm-select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%238a94a3' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 12px center; padding-right: 38px; cursor: pointer; }
.report-modal #rmMessage { resize: vertical; min-height: 76px; line-height: 1.45; }
.report-modal .rm-select:focus, .report-modal #rmAddress:focus, .report-modal #rmMessage:focus { border-color: var(--brand); box-shadow: 0 0 0 4px rgba(31,111,235,.12); }
.report-modal .rm-hint { font-size: 12px; color: var(--ink-3); margin-top: 6px; }

/* ============ .csel — кастомный (не системный) select ============
   Оборачивает обычный <select>: сам select становится визуально скрытым
   (position:absolute, opacity:0 — НЕ display:none, чтобы форма/автосабмит и
   значение оставались рабочими без переписывания остального JS), поверх —
   кнопка + выпадающий список в стиле сайта. Список опций генерируется из
   <option> самого select'а — один источник правды, ничего дублировать не надо. */
.csel { position: relative; }
.csel-native {
  position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none;
}
.csel-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  border: 1px solid var(--line); background: var(--panel); border-radius: 11px; padding: 12px 13px;
  font-family: var(--sans); font-size: 15px; color: var(--ink); text-align: left; cursor: pointer;
}
.csel-btn:focus-visible, .csel.open .csel-btn { border-color: var(--brand); box-shadow: 0 0 0 4px rgba(31,111,235,.12); }
.csel-val { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.csel-val.placeholder { color: var(--ink-3); }
.csel-chev { flex: none; color: #8a94a3; transition: transform .18s; }
.csel.open .csel-chev { transform: rotate(180deg); }
.csel-menu {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 20; max-height: 260px; overflow-y: auto;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);
  padding: 5px; opacity: 0; visibility: hidden; transform: translateY(-6px); transition: .16s;
}
.csel.open .csel-menu { opacity: 1; visibility: visible; transform: none; }
.csel-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 10px; width: 100%;
  background: none; border: 0; font-family: var(--sans); font-size: 14.5px; font-weight: 600; color: var(--ink);
  padding: 10px 11px; border-radius: 8px; cursor: pointer; text-align: left;
}
.csel-opt:hover, .csel-opt.active { background: var(--bg); }
.csel-opt.on { color: var(--brand-ink); }
.csel-opt .csel-check { width: 16px; height: 16px; flex: none; color: var(--brand); visibility: hidden; }
.csel-opt.on .csel-check { visibility: visible; }
.csel-opt[disabled] { color: var(--ink-3); cursor: default; }

.report-modal .rm-addr { position: relative; }
.report-modal .rm-suggest {
  position: absolute; top: calc(100% + 6px); left: 0; right: 0; z-index: 5; display: none;
  background: var(--panel); border: 1px solid var(--line); border-radius: 12px; box-shadow: var(--shadow);
  max-height: 240px; overflow-y: auto;
}
.report-modal .rm-suggest.show { display: block; }
.report-modal .rm-sg { display: flex; align-items: center; gap: 10px; padding: 11px 13px; cursor: pointer; font-size: 14.5px; border-bottom: 1px solid var(--line-2); }
.report-modal .rm-sg:last-child { border-bottom: 0; }
.report-modal .rm-sg:hover { background: #f3f6fb; }
.report-modal .rm-sg .d { width: 8px; height: 8px; border-radius: 50%; background: var(--brand); flex: none; }

.report-modal .rm-err { display: none; color: var(--emerg); font-size: 13px; font-weight: 600; margin: 2px 0 12px; }
.report-modal .rm-err.show { display: block; }
.report-modal .rm-submit {
  width: 100%; height: 48px; border: 0; border-radius: 12px; background: var(--brand); color: #fff;
  font-family: var(--sans); font-weight: 700; font-size: 15px; cursor: pointer; transition: background .2s, transform .1s;
}
.report-modal .rm-submit:hover { background: var(--brand-ink); }
.report-modal .rm-submit:active { transform: translateY(1px); }
.report-modal .rm-submit:disabled { opacity: .65; cursor: default; }

@media (max-width: 900px) {
  /* компактная круглая кнопка над свёрнутой шторкой */
  .report-fab { right: 14px; bottom: 122px; height: 52px; width: 52px; padding: 0; justify-content: center; }
  .report-fab span { display: none; }
  .report-fab svg { width: 22px; height: 22px; }
  .report-modal .rm-card { top: auto; bottom: 0; transform: translateX(-50%); width: 100vw;
    max-width: 100vw; border-radius: 20px 20px 0 0; max-height: 92dvh; padding-bottom: 26px; }
}

/* --- Источник данных и просроченный срок в карточке (достоверность статуса) --- */
.hc-src{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 6px;margin-top:6px;font-size:11.5px;line-height:1.35}
.hc-src .hc-src-l{font-weight:700;padding:1px 7px;border-radius:999px;white-space:nowrap}
/* ⚠️ Длинное «Проверено администратором BARJOK по обращениям жителей» стояло
   под КАЖДЫМ событием в две строки и вытесняло то, ради чего карточку
   открывали. Прячем под ⓘ (ТЗ §8) — details, без JS. */
details.hc-src{display:block}
details.hc-src>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:5px}
details.hc-src>summary::-webkit-details-marker{display:none}
.hc-src .hc-i{display:inline-grid;place-items:center;width:14px;height:14px;border-radius:50%;border:1px solid currentColor;
  font-size:9.5px;font-weight:700;font-style:italic;opacity:.75;flex:none}
details.hc-src .hc-src-n{display:block;margin-top:4px;color:var(--ink-3)}
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0}
.hc-src .hc-src-n{color:var(--ink-3);min-width:0;overflow-wrap:anywhere}
.hc-src.src-official .hc-src-l{background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok)}
.hc-src.src-confirmed .hc-src-l{background:color-mix(in srgb,#2f6bed 14%,transparent);color:#2f6bed}
.hc-src.src-citizen .hc-src-l{background:color-mix(in srgb,#c2703a 16%,transparent);color:#c2703a}
.hc-overdue{margin-top:3px;font-size:11.5px;font-weight:600;color:#c2703a}

/* --- Пустая выдача с объяснением, «Ваш адрес», доступность списка --- */
.none-filtered{display:flex;flex-direction:column;align-items:center;gap:10px;padding:22px 16px;text-align:center}
.none-filtered b{font-size:14px}
.none-filtered > span{font-size:12.5px;line-height:1.5;color:var(--ink-3);max-width:34ch}
.none-f{display:flex;flex-wrap:wrap;justify-content:center;align-items:center;gap:6px;font-size:12px}
.none-f-l{color:var(--ink-3)}
.none-chip{background:var(--bg);border:1px solid var(--line);border-radius:999px;padding:3px 10px;font-weight:600}
.none-reset{background:var(--brand);color:#fff;border:0;border-radius:10px;padding:9px 16px;
  font-family:inherit;font-size:13px;font-weight:700;cursor:pointer}
.none-reset:hover{background:var(--brand-ink)}

.lfocus{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 10px;padding:10px 12px;
  background:color-mix(in srgb,var(--brand) 8%,var(--panel));border:1px solid color-mix(in srgb,var(--brand) 25%,var(--line));
  border-radius:12px}
.lfocus-t{min-width:0;flex:1}
.lfocus-l{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--ink-3);font-weight:700}
.lfocus-t b{font-size:13.5px;overflow-wrap:anywhere}
.lfocus-back{background:none;border:1px solid var(--line);border-radius:9px;padding:7px 12px;
  font-family:inherit;font-size:12.5px;font-weight:600;color:var(--ink);cursor:pointer;white-space:nowrap}
.lfocus-back:hover{background:var(--bg)}

/* Карточка списка объявлена кнопкой — значит должна показывать фокус клавиатуры */
.lcard:focus-visible{outline:2px solid var(--brand);outline-offset:2px}
