:root {
  /* палитра снята с ассетов Atom Fishing (реског коллеги) */
  --steel:       #1b1b1b;   /* уголь-сталь фон */
  --denim:       #23272e;   /* тёмный деним-канвас */
  --denim-2:     #2b3038;
  --leather:     #3a2418;   /* тёмная потрескавшаяся кожа */
  --leather-2:   #4a3020;
  --panel:       #1e2126;   /* полупрозрачный уголь панелей */
  --line:        #3a3f47;   /* стальной борт */
  --line-2:      #14161a;
  --amber:       #e8b820;   /* радиоактивный янтарь (лого) */
  --amber-dim:   #9a7c1a;
  --acid:        #9acd32;   /* кислотно-зелёные ссылки */
  --red:         #ff3b30;   /* активный/опасность */
  --text:        #e0e0d0;   /* светлый статус-текст */
  --muted:       #808078;
  --head: 'Oswald', 'PT Sans Narrow', 'Arial Narrow', sans-serif;
  --body: 'PT Sans', 'Segoe UI', system-ui, sans-serif;
}

* { box-sizing: border-box; }
/* Курсор: стрелка с вращающимся знаком радиации. Исходник — анимированный
   .ani, но CSS анимацию курсора не поддерживает, поэтому кадры разложены в
   PNG и подменяются из app.js через эту переменную. Кадр уменьшен до 24px —
   на 32 знак радиации перетягивал внимание. */
:root { --cur: url('/cursor/wib0.png'); }
html, body { margin: 0; height: 100%; background: var(--steel); color: var(--text); font-family: var(--body);
  cursor: var(--cur) 0 0, default; }
/* Кликабельное оставляем системным: по курсору должно быть видно, что нажимается. */
button, a, select, .pin-wrap, summary, input[type=checkbox], label.check { cursor: pointer; }
input[type=text], input:not([type]), input[type=password], input[type=email], textarea { cursor: text; }
/* MapLibre ставит холсту собственный курсор (grab), и он перекрывает наш на
   всей площади карты — а карта занимает почти весь экран. Возвращаем свой,
   кроме перетаскивания: там «зажатая рука» осмысленна. */
#map .maplibregl-canvas-container,
#map .maplibregl-canvas-container.maplibregl-interactive,
#map .maplibregl-canvas-container.maplibregl-interactive .maplibregl-canvas,
#map canvas { cursor: var(--cur) 0 0, default; }
/* При перетаскивании курсор тот же, только замирает — вращение отключается
   из app.js, чтобы во время движения карты ничего не мельтешило. */
#map .maplibregl-canvas-container.maplibregl-track-pointer,
#map .maplibregl-canvas-container:active,
#map .maplibregl-canvas-container:active .maplibregl-canvas { cursor: var(--cur) 0 0, default; }
.hidden { display: none !important; }
a { color: var(--acid); text-decoration: none; }
a:hover { color: var(--amber); }
h2 { font-family: var(--head); }

/* стальная кнопка «PLAY» */
button {
  font-family: var(--head); font-weight: 600; letter-spacing: .5px; text-transform: uppercase;
  cursor: pointer; color: #eef1e6; padding: 8px 16px; border-radius: 2px;
  border: 1px solid #11141a; font-size: 14px;
  /* Металл вместо ровной заливки. Градиент остаётся снизу и держит объём:
     одна текстура делает кнопку плоской наклейкой. Смешивание overlay
     сохраняет светлую фаску сверху и тень снизу. */
  background:
    linear-gradient(180deg, rgba(74,82,92,.55) 0%, rgba(45,50,58,.62) 48%, rgba(34,39,45,.66) 52%, rgba(24,28,33,.72) 100%),
    url('/tex/button.jpg') center / cover;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.12), inset 0 -1px 0 rgba(0,0,0,.5), 0 1px 2px rgba(0,0,0,.6);
  text-shadow: 0 1px 2px rgba(0,0,0,.7);
}
button:hover { filter: brightness(1.18); border-color: var(--amber-dim); }
button:active { filter: brightness(.9); }
button.ghost {
  background:
    linear-gradient(180deg, rgba(38,42,48,.66), rgba(24,27,32,.76)),
    url('/tex/button.jpg') center / cover;
  color: var(--acid); border-color: var(--line);
}
button.ghost:hover { color: var(--amber); }

/* ---- Экран входа: нуар ---------------------------------------------------
   Слои от дальнего к ближнему: небо, луч прожектора, слот под иллюстрацию,
   силуэт промзоны, зерно, виньетка. Растровой картинки нет — атмосфера
   набрана градиентами, поэтому ничего не весит и не грузится по сети.      */
.auth-screen {
  position: fixed; inset: 0; display: grid; place-items: center;
  background: #0a0b0c; overflow: hidden;
}
.noir { position: absolute; inset: 0; pointer-events: none; }

/* Небо: холодное вверху, тёплое зарево у горизонта. */
.noir-sky {
  position: absolute; inset: 0;
  background:
    radial-gradient(120% 70% at 50% 100%, rgba(232,184,32,.20) 0%, rgba(90,60,20,.10) 32%, transparent 62%),
    linear-gradient(180deg, #0b0d10 0%, #14171c 46%, #1b1a18 78%, #241f18 100%);
}

/* Дымка: два медленных пятна, разведённые по фазе — «дышит» без мерцания. */
.noir-haze {
  position: absolute; inset: -25%;
  background:
    radial-gradient(38% 30% at 28% 62%, rgba(150,170,150,.10), transparent 70%),
    radial-gradient(46% 34% at 74% 74%, rgba(200,180,130,.08), transparent 72%);
  filter: blur(24px);
  animation: haze-drift 34s ease-in-out infinite alternate;
}
@keyframes haze-drift {
  from { transform: translate3d(-2%, 1%, 0) scale(1); }
  to   { transform: translate3d(3%, -2%, 0) scale(1.08); }
}

/* Световые лучи: три полосы под разными углами вместо одного прожектора.
   Каждая дышит своим циклом — суммарный ритм не читается как пульсация. */
.noir-beam {
  position: absolute; inset: -30% -40%;
  background:
    linear-gradient(107deg, transparent 38%, rgba(240,220,170,.10) 46%,
      rgba(240,220,170,.17) 50%, rgba(240,220,170,.06) 55%, transparent 62%),
    linear-gradient(97deg, transparent 60%, rgba(220,235,255,.05) 66%,
      rgba(220,235,255,.09) 69%, transparent 75%),
    linear-gradient(118deg, transparent 20%, rgba(154,205,50,.045) 26%,
      rgba(154,205,50,.07) 29%, transparent 35%);
  filter: blur(3px);
  animation: beam-breathe 13s ease-in-out infinite;
}
/* Опорные кадры несимметричны: спад дольше подъёма, иначе читается «миганием». */
@keyframes beam-breathe {
  0%, 100% { opacity: 1; }
  38%      { opacity: .62; }
  70%      { opacity: .84; }
}

/* Техно-слой: разметочная сетка, почти на грани видимости. Уводится
   маской к краям, чтобы не спорить с формой в центре. */
.noir-grid {
  position: absolute; inset: -10%;
  opacity: .5;
  background-image:
    linear-gradient(rgba(154,205,50,.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(154,205,50,.055) 1px, transparent 1px);
  background-size: 64px 64px;
  -webkit-mask-image: radial-gradient(70% 60% at 50% 52%, transparent 20%, #000 85%);
          mask-image: radial-gradient(70% 60% at 50% 52%, transparent 20%, #000 85%);
  transform: perspective(600px) rotateX(58deg) translateY(18%);
  transform-origin: 50% 100%;
}

/* Пыль/частицы — рисует hero.js. Слой поверх лучей, под силуэтом. */
.noir-dust { position: absolute; inset: 0; width: 100%; height: 100%; }

/* Слот под иллюстрацию: положи файл и раскомментируй background-image. */
.noir-art {
  position: absolute; inset: 0;
  /* background-image: url('/noir.webp'); */
  background-size: cover; background-position: center bottom;
  opacity: .85;
  -webkit-mask-image: radial-gradient(75% 60% at 50% 55%, #000 55%, transparent 92%);
          mask-image: radial-gradient(75% 60% at 50% 55%, #000 55%, transparent 92%);
}

/* Силуэт промзоны по нижней кромке: трубы, корпуса, вышки. */
.noir-skyline {
  position: absolute; left: 0; right: 0; bottom: 0; height: 34vh; width: 100%;
  fill: #07080a; opacity: .95;
  filter: drop-shadow(0 -2px 14px rgba(232,184,32,.12));
}

/* Плёночное зерно. Слой увеличен и подёргивается шагами по 8 к/с: непрерывный
   сдвиг выглядел бы как ползущая текстура, а не как зерно плёнки. */
.noir-grain {
  position: absolute; inset: -50%; opacity: .05; mix-blend-mode: overlay;
  background-image:
    repeating-linear-gradient(0deg, rgba(255,255,255,.5) 0 1px, transparent 1px 2px),
    repeating-linear-gradient(90deg, rgba(255,255,255,.4) 0 1px, transparent 1px 3px);
  animation: grain-jitter 1s steps(1) infinite;
}
@keyframes grain-jitter {
  0%   { transform: translate3d(0,0,0); }
  20%  { transform: translate3d(-3px,2px,0); }
  40%  { transform: translate3d(2px,-3px,0); }
  60%  { transform: translate3d(-2px,-2px,0); }
  80%  { transform: translate3d(3px,1px,0); }
}

/* Виньетка прижимает взгляд к форме. */
.noir-vign {
  position: absolute; inset: 0;
  background: radial-gradient(70% 60% at 50% 48%, transparent 35%, rgba(0,0,0,.55) 78%, rgba(0,0,0,.85) 100%);
}

/* Экономия движения: гасим всю анимацию задника и прячем частицы. Сцена
   остаётся той же по композиции, просто застывшей. hero.js в этом режиме
   не запускает ни параллакс, ни канвас. */
@media (prefers-reduced-motion: reduce) {
  .noir-beam, .noir-haze, .noir-grain { animation: none; }
  .noir-dust { display: none; }
}

.auth-mark {
  position: relative; z-index: 2;
  display: block; width: 64px; height: 64px; margin: 0 auto 10px;
  overflow: visible;
  filter: drop-shadow(0 0 14px rgba(232,184,32,.28));
}
.auth-mark .mark-ring {
  fill: none; stroke: var(--amber-dim); stroke-width: 1.5; opacity: .75;
}
.auth-mark .mark-tref { fill: var(--amber); }

.auth-brand {
  position: relative; z-index: 2; text-align: center;
  font-family: var(--head); font-weight: 700; font-size: 40px; letter-spacing: 12px;
  color: var(--amber); margin-bottom: 18px; text-indent: 12px;
  text-shadow: 0 0 26px rgba(232,184,32,.35), 0 2px 4px #000;
}
.terminal {
  position: relative; z-index: 2; width: min(92vw, 360px);
  border: 1px solid rgba(120,110,90,.35); border-top-color: rgba(190,170,120,.35);
  background: linear-gradient(180deg, rgba(24,26,30,.78), rgba(12,13,16,.88));
  padding: 22px; border-radius: 2px;
  /* Размытие держит контраст текста над «живым» задником: частицы и лучи
     проходят под формой, но не мешают читать. Обводку не усиливаем — за
     читаемость отвечает блюр, а не рамка. */
  backdrop-filter: blur(14px) saturate(.85);
  -webkit-backdrop-filter: blur(14px) saturate(.85);
  box-shadow: 0 18px 60px rgba(0,0,0,.75), inset 0 1px 0 rgba(255,255,255,.05);
}
.auth-form { display: flex; flex-direction: column; gap: 12px; }
.auth-form label { display: flex; }
.auth-form input {
  flex: 1; min-width: 0;
  background: rgba(10,11,13,.9); border: 1px solid rgba(120,110,90,.28);
  color: var(--text); font-family: var(--body); font-size: 15px;
  padding: 11px 12px; border-radius: 2px; outline: none;
}
.auth-form input::placeholder { color: #6d6f68; }
.auth-form input:focus { border-color: var(--amber-dim); box-shadow: 0 0 0 2px rgba(232,184,32,.12); }
#auth-submit {
  margin-top: 4px; padding: 12px; font-size: 15px; letter-spacing: 2px;
  color: #1d1808; border: 1px solid #6b5a3a;
  background: linear-gradient(180deg, #e6c268 0%, #c09a42 50%, #9a7a2c 100%);
  text-shadow: 0 1px 0 rgba(255,240,200,.3);
}
.tag {
  font-family: var(--head); color: var(--muted); font-size: 12px;
  letter-spacing: 3px; text-transform: uppercase;
}
.prompt-line { text-align: center; margin-bottom: 2px; }
.switch { text-align: center; font-size: 13px; margin-top: 4px; }
.switch a { color: var(--muted); }
.switch a:hover { color: var(--amber); }
.blink { animation: blink 1s steps(1) infinite; color: var(--amber); }
@keyframes blink { 50% { opacity: 0; } }

/* ---- Основной ---- */
.topbar {
  position: fixed; top: 0; left: 0; right: 0; height: 50px; z-index: 900;
  display: flex; align-items: center; gap: 8px; padding: 0 12px;
  background:
    linear-gradient(180deg, rgba(38,42,48,.62), rgba(22,25,29,.74)),
    url('/tex/bar.jpg') center / cover;
  border-bottom: 1px solid #0b0c0e; box-shadow: 0 2px 6px rgba(0,0,0,.5);
}
.brand {
  font-family: var(--head); font-weight: 700; font-size: 22px; letter-spacing: 4px;
  color: var(--amber); text-shadow: 0 0 12px rgba(232,184,32,.35), 0 1px 2px #000;
  flex: 0 0 auto; white-space: nowrap;
}
.spacer { flex: 1; min-width: 0; }
/* Кнопки шапки не переносят текст и не сжимаются — иначе «+ метка» встаёт
   в две строки и вылезает за 50px топбара. */
.topbar button { flex: 0 0 auto; white-space: nowrap; }
#map { position: fixed; inset: 50px 0 0 0; background: var(--steel); }
/* Подсказка режима постановки метки. Раньше висела над нижней панелью и
   наезжала на строку поиска — увели наверх, под фильтры, и уменьшили. */
.hint {
  position: fixed; top: 96px; left: 50%; transform: translateX(-50%); z-index: 900;
  font-family: var(--head); text-transform: uppercase; letter-spacing: 1px; font-size: 11px;
  background: rgba(232,184,32,.12); border: 1px solid var(--amber-dim); color: var(--amber);
  padding: 4px 10px; border-radius: 2px; pointer-events: none; white-space: nowrap;
}

/* ---- Модалки ---- */
.modal { position: fixed; inset: 0; z-index: 1000; display: grid; place-items: center; background: rgba(0,0,0,.72); }
.panel {
  width: min(92vw, 400px);
  /* Ограничение обязательно: на маленьком экране панель модерации выходила
     за пределы окна и не прокручивалась — кнопка закрытия становилась
     недостижимой, окно можно было только перезагрузить. */
  max-height: 92vh; overflow-y: auto;
  background:
    linear-gradient(180deg, rgba(30,34,40,.84), rgba(20,23,27,.9)),
    url('/tex/panel.jpg') center / cover;
  border: 1px solid var(--line); border-top-color: #565d67;
  padding: 20px; border-radius: 2px; display: flex; flex-direction: column; gap: 12px;
  box-shadow: 0 12px 44px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.05);
}
.panel h2 {
  margin: 0; color: var(--amber); font-size: 17px; letter-spacing: 2px; text-transform: uppercase;
  border-bottom: 1px solid var(--line); padding-bottom: 8px; font-weight: 600;
}
.panel label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .5px; }
.panel input, .panel textarea, .panel select {
  background: #101216; border: 1px solid var(--line-2); color: var(--text);
  font-family: var(--body); padding: 8px; border-radius: 2px; font-size: 14px;
}
.panel input:focus, .panel textarea:focus, .panel select:focus {
  border-color: var(--amber-dim); outline: none; box-shadow: 0 0 0 2px rgba(232,184,32,.12);
}
.row { display: flex; gap: 8px; justify-content: flex-end; margin-top: 4px; }
.coords { font-family: var(--head); font-size: 13px; color: var(--acid); letter-spacing: 1px; }
.err { color: var(--red); font-size: 13px; min-height: 14px; }

/* ---- Метки на карте ---- */
.pin {
  width: 28px; height: 28px; display: grid; place-items: center; font-size: 14px;
  background: radial-gradient(circle at 50% 40%, #2a2e34, #14161a);
  border: 1px solid var(--amber); border-radius: 2px 2px 2px 0;
  transform: rotate(-45deg); box-shadow: 0 0 10px rgba(232,184,32,.5), inset 0 0 6px rgba(0,0,0,.6);
  color: var(--amber);
}
.pin span { transform: rotate(45deg); }
.leaflet-popup-content-wrapper, .leaflet-popup-tip {
  background: var(--panel); color: var(--text); border: 1px solid var(--line);
}
.leaflet-popup-content { font-family: var(--body); font-size: 13px; }
.leaflet-popup-content b { color: var(--amber); font-family: var(--head); font-weight: 600; letter-spacing: .5px; }
.leaflet-container { background: var(--steel); }
/* Цвет карты задаётся в map-style.js по слоям, поэтому CSS-фильтр поверх
   тайлов больше не нужен — он и был причиной мутных подписей. */
.pin-wrap { cursor: pointer; will-change: transform; }
/* Своя позиция — круглая точка. Ромб путали с меткой объекта: угловатых
   значков на карте и так хватает, а «я» должно читаться сразу. */
.you-dot {
  width: 14px; height: 14px; border-radius: 50%;
  background: var(--acid); border: 2px solid rgba(154,205,50,.35);
  box-shadow: 0 0 12px rgba(154,205,50,.8);
}
/* MapLibre скругляет свои кнопки сам — приводим к общему угловатому строю. */
.maplibregl-ctrl-group,
.maplibregl-ctrl-group button,
.maplibregl-ctrl-attrib,
.maplibregl-popup-content { border-radius: 2px !important; }

/* Элементы управления MapLibre под общую тёмную тему. */
.maplibregl-ctrl-group {
  background: linear-gradient(180deg, #2a2e34, #1a1d22) !important;
  border: 1px solid var(--line) !important; box-shadow: 0 2px 8px rgba(0,0,0,.5) !important;
}
.maplibregl-ctrl-group button + button { border-top: 1px solid var(--line) !important; }
.maplibregl-ctrl-group button span { filter: invert(1) brightness(1.6) sepia(.6) hue-rotate(-15deg); }
.maplibregl-ctrl-attrib {
  background: rgba(20,22,26,.8) !important; color: var(--muted) !important; font-size: 10px !important;
}
.maplibregl-ctrl-attrib a { color: var(--muted) !important; }
.maplibregl-popup-content {
  background: var(--panel) !important; color: var(--text) !important;
  border: 1px solid var(--line) !important; font-family: var(--body); font-size: 13px;
}
.maplibregl-popup-tip { border-top-color: var(--line) !important; }

.badge {
  display: inline-block; padding: 1px 7px; border: 1px solid var(--amber-dim); border-radius: 2px;
  color: var(--amber); font-family: var(--head); font-size: 11px; letter-spacing: .5px; text-transform: uppercase;
}

/* ---- Чип профиля в топбаре ---- */
.profile-chip {
  display: flex; align-items: center; gap: 7px; padding: 4px 10px 4px 4px;
  background: linear-gradient(180deg, #2a2e34, #1a1d22); color: var(--acid);
  border: 1px solid var(--line); border-radius: 2px; text-transform: none;
  font-family: var(--head); font-size: 13px; letter-spacing: .5px;
  min-width: 0; max-width: 42vw;
}
/* Длинный ник обрезаем многоточием, а не краем экрана. */
#chip-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.profile-chip:hover { color: var(--amber); border-color: var(--amber-dim); }
/* Чуть крупнее прежнего: рамка съедает часть габарита, и на 26px от самого
   аватара оставалось меньше половины. */
.chip-av { width: 32px; height: 32px; border-radius: 2px; object-fit: cover; background: #14161a; display: block; }
#chip-frame { flex: 0 0 auto; }

/* ---- Плашка профиля под топбаром ---- */
/* Профиль — шторка справа, а не полоса во всю ширину: раньше она ложилась
   поверх карты и съедала верх экрана, при этом больше половины её площади
   было пустой заливкой. */
.profile-panel {
  /* Слой выше нижней панели с поиском (880): при равных z-index побеждала
     она — идёт в разметке ниже, — и шторка уезжала под латунный механизм.
     Ниже топбара (900), чтобы кнопка профиля оставалась нажимаемой. */
  position: fixed; top: 50px; right: 0; bottom: 0; z-index: 890;
  width: min(88vw, 330px);
  background:
    linear-gradient(180deg, rgba(30,33,39,.78), rgba(19,21,25,.86)),
    url('/tex/panel.jpg') center / cover fixed;
  border-left: 1px solid #0b0c0e; box-shadow: -8px 0 26px rgba(0,0,0,.55);
  padding: 14px 16px 20px; overflow-y: auto;
  transition: transform .22s ease;
}
.profile-panel.hidden { display: block !important; transform: translateX(105%); pointer-events: none; }
.pp-gear, .pp-close {
  position: absolute; top: 12px; background: transparent; border: 1px solid var(--line);
  color: var(--muted); padding: 3px 9px; font-size: 15px;
}
.pp-gear { right: 46px; } .pp-close { right: 12px; font-size: 11px; }
.pp-gear:hover { color: var(--amber); border-color: var(--amber-dim); }
/* Узкая шторка: аватар мельче, имя не растягивает колонку, статистика
   строкой — иначе половина панели уходила под пустую заливку. */
.pp-main { display: flex; align-items: center; gap: 12px; padding-right: 62px; }
.pp-avatar { width: 54px; height: 54px; border-radius: 2px; object-fit: cover; background: #14161a; display: block; }
.pp-info { min-width: 0; }
.pp-name {
  font-family: var(--head); font-size: 20px; font-weight: 700; letter-spacing: .5px;
  color: var(--amber); line-height: 1.1;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pp-rank { margin-top: 3px; display: flex; flex-wrap: wrap; gap: 3px; }
.pp-stats { color: var(--muted); font-size: 11px; margin-top: 8px; line-height: 1.55; }

/* ---- Ачивки ---- */
.pp-ach { margin-top: 14px; }
.ach-total { color: var(--muted); font-size: 12px; letter-spacing: 1px; text-transform: uppercase; margin-bottom: 8px; }
.ach-group { margin-bottom: 10px; }
.ach-group-title { color: var(--amber-dim); font-size: 11px; letter-spacing: 1px; text-transform: uppercase; margin-bottom: 4px; }
.ach-row { display: flex; flex-wrap: wrap; gap: 5px; }
.ach {
  font-size: 11px; padding: 3px 8px; border: 1px solid var(--line);
  border-radius: 2px; cursor: default; white-space: nowrap;
}
.ach.on { color: var(--amber); border-color: var(--amber-dim); background: rgba(255,176,32,.08); }
.ach.off { color: #5c6068; opacity: .65; }
.check {
  display: flex; align-items: center; gap: 7px; margin: 6px 0;
  color: var(--muted); font-size: 12px; cursor: pointer;
}
.check input { width: auto; margin: 0; accent-color: var(--amber); }
/* Внутри .panel все подписи подняты в верхний регистр — галочкам это не идёт,
   они читаются как обычная фраза. */
.panel .check { text-transform: none; letter-spacing: 0; flex-direction: row; }
.check-right { justify-content: flex-end; text-align: right; margin: 10px 0 2px; }

/* ---- Карточка объекта: действия, ответы, адрес ---- */
.d-actions { display: flex; gap: 8px; margin: 10px 0; }
.d-actions button { flex: 1; font-size: 12px; text-transform: none; }
.d-actions button.on { color: var(--amber); border-color: var(--amber-dim); }

.comment { position: relative; }
.comment.is-reply { margin-left: 14px; border-left: 2px solid var(--line); padding-left: 10px; }
.reply-head {
  color: var(--muted); font-size: 11px; font-style: italic;
  border-left: 2px solid var(--amber-dim); padding-left: 6px; margin: 2px 0 4px;
}
.reply-btn {
  margin-top: 6px; padding: 2px 8px; font-size: 11px; text-transform: none;
  background: transparent; border-color: var(--line-2); color: var(--muted);
}
.reply-btn:hover { color: var(--amber); border-color: var(--amber-dim); }
.reply-to {
  display: flex; align-items: center; gap: 8px; margin-bottom: 6px;
  color: var(--amber); font-size: 12px;
}
.reply-to button { padding: 0 6px; font-size: 12px; background: transparent; border: none; color: var(--muted); }
/* Подсветка комментария, к которому пришли из уведомления. */
.comment.flash { animation: flash 2.2s ease-out; }
@keyframes flash {
  0%, 40% { background: rgba(232,184,32,.16); }
  100% { background: transparent; }
}
.guide-mark { color: var(--amber); }
.badge.guide { color: var(--amber); border-color: var(--amber-dim); }

.addr-box { margin-top: 16px; border-top: 1px solid var(--line-2); padding-top: 10px; }
.addr-line { display: flex; align-items: baseline; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.addr-label {
  color: var(--muted); font-size: 10px; letter-spacing: 1px; text-transform: uppercase;
  flex: 0 0 78px;
}
.addr-val { color: var(--text); font-size: 13px; flex: 1 1 120px; word-break: break-word; }
.copy-btn {
  padding: 2px 8px; font-size: 11px; text-transform: none;
  background: transparent; border-color: var(--line-2); color: var(--muted);
}
.copy-btn:hover { color: var(--amber); border-color: var(--amber-dim); }

/* ---- Уведомления об ответах ---- */
.ntf {
  border: 1px solid var(--line-2); padding: 9px 11px; margin-bottom: 7px; cursor: pointer;
}
.ntf:hover { border-color: var(--amber-dim); }
.ntf.unread { border-left: 3px solid var(--amber); background: rgba(232,184,32,.05); }
.ntf-head { color: var(--text); font-size: 12px; }
.ntf-loc { color: var(--amber-dim); font-size: 11px; margin: 2px 0 4px; }
#msg-btn.has-unread { color: var(--amber); border-color: var(--amber-dim); }
.unread-dot {
  display: grid; place-items: center; min-width: 14px; height: 14px; padding: 0 3px;
  font-size: 9px; color: #1b1b1b; font-weight: 700; border-radius: 2px;
}

/* ---- Избранное и посещённые в профиле ---- */
/* В колонку: в шторке шириной 330px два списка рядом не помещаются. */
.pp-lists { margin-top: 12px; display: flex; flex-direction: column; gap: 10px; }
.pl-block { min-width: 0; }
/* Пустой список — одна строка, без разворота на подсказку. */
.pl-empty { display: flex; align-items: baseline; gap: 6px; }
.pl-empty .pl-title { margin-bottom: 0; }
.pl-empty .pl-count { font-size: 11px; }
.pl-title {
  color: var(--amber-dim); font-size: 11px; letter-spacing: 1px;
  text-transform: uppercase; margin-bottom: 5px;
}
.pl-count { color: var(--muted); }
.pl-items { display: flex; flex-wrap: wrap; gap: 5px; }
.pl-item {
  padding: 3px 8px; font-size: 11px; text-transform: none; max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  background: transparent; border-color: var(--line-2); color: var(--text);
}
.pl-item:hover { color: var(--amber); border-color: var(--amber-dim); }
.search-out .row-hit.is-local { border-left: 2px solid var(--amber-dim); }

/* ---- Пальцевые размеры ----------------------------------------------------
   На мышке мелкие кнопки не мешают, пальцем в них не попасть. Поднимаем
   высоту до 34px везде, где элемент нажимается: фильтры, ответы, копирование,
   вкладки модерации, списки в профиле. Кегль не трогаем — растёт только
   область нажатия за счёт внутренних отступов.                              */
@media (hover: none), (max-width: 560px) {
  .filters .fcat, .filters .fgroup-head,
  .reply-btn, .copy-btn, .pl-item, .mod-tabs button,
  .fmsg-act button, .frame-swatch button, .d-actions button,
  .rate-row button, .mod-item button {
    min-height: 34px; padding-top: 6px; padding-bottom: 6px;
  }
  .ach { min-height: 30px; display: inline-flex; align-items: center; }
  /* Кнопки правки просили мельче, но пальцем в них всё же надо попадать:
     30 px — нижняя граница, ниже начинаются промахи. */
  .d-edit button, .pp-donate { min-height: 30px; }
  /* Крестик закрытия карточки и стрелка сворачивания профиля — самые
     промахиваемые: они у самого края экрана. */
  .drawer-close, .pp-close, .pp-gear { min-width: 38px; min-height: 34px; }
}

/* ---- Модерация: вкладки и лента комментариев ---- */
.mod-tabs { display: flex; gap: 6px; margin-bottom: 10px; }
.mod-tabs button {
  flex: 1; padding: 5px 8px; font-size: 11px;
  background: transparent; border-color: var(--line-2); color: var(--muted); box-shadow: none;
}
.mod-tabs button.on { color: var(--amber); border-color: var(--amber-dim); }
.mod-feed { max-height: 52vh; overflow-y: auto; }
.fmsg { border: 1px solid var(--line-2); border-left: 2px solid var(--amber-dim);
        padding: 7px 9px; margin-bottom: 6px; background: rgba(0,0,0,.25); }
.fmsg.gone { opacity: .45; border-left-color: var(--red); }
.fmsg-head { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; font-size: 11px; }
.fmsg-who { color: var(--acid); }
.fmsg-loc { color: var(--amber-dim); }
.fmsg .txt { font-size: 13px; margin: 3px 0; word-break: break-word; }
.fmsg-act { display: flex; gap: 6px; align-items: center; }
.fmsg-act button { padding: 2px 8px; font-size: 10px; background: transparent;
                   border-color: var(--line-2); color: var(--muted); box-shadow: none; }
.fmsg-act .del:hover { color: var(--red); border-color: var(--red); }
.gone-mark { color: var(--red); font-size: 10px; text-transform: uppercase; letter-spacing: 1px; }

/* ---- «О себе» и чужой профиль ---- */
.pp-about {
  margin-top: 10px; color: var(--text); font-size: 12px; line-height: 1.55;
  white-space: pre-wrap; word-break: break-word;
}
.pp-about:empty { display: none; }
/* Донат мелкой строкой: он должен быть заметен, но не спорить по весу с
   самим профилем — это не главное действие в шторке. */
.pp-donate {
  width: 100%; margin-top: 16px; padding: 7px 10px;
  font-size: 11px; letter-spacing: .5px; color: var(--amber);
  background: linear-gradient(180deg, rgba(38,42,48,.66), rgba(24,27,32,.76));
  border-color: var(--amber-dim); box-shadow: none;
}
.pp-donate:hover { filter: brightness(1.2); }
.pp-support {
  margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line-2);
  color: var(--muted); font-size: 11px;
}
.user-link { color: var(--acid); cursor: pointer; }
.user-link:hover { color: var(--amber); text-decoration: underline; }
/* Ачивок может быть полсотни — без ограничения высоты панель уезжает
   за край экрана и кнопка закрытия становится недосягаемой. */
.user-panel { width: min(94vw, 420px); max-height: 88vh; overflow-y: auto; }
.user-head { display: flex; gap: 14px; align-items: flex-start; margin-bottom: 12px; }
.user-av { width: 72px; height: 72px; object-fit: cover; border-radius: 2px; display: block; }
.user-info { min-width: 0; }
/* Ник до 32 символов, и на узком экране длинный рвётся посреди слова.
   Кегль плавающий: чем уже экран, тем мельче. */
.user-nick {
  font-family: var(--head); font-size: clamp(16px, 4.6vw, 22px); font-weight: 700;
  color: var(--amber); letter-spacing: .5px; line-height: 1.15;
  overflow-wrap: anywhere;
}
.user-rank { margin: 4px 0; display: flex; flex-wrap: wrap; gap: 4px; }
.user-stats { color: var(--muted); font-size: 11px; line-height: 1.5; }
.user-about {
  border-left: 2px solid var(--amber-dim); padding: 6px 0 6px 10px;
  font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word;
}
.user-ach { margin-top: 12px; }
#p-about { font-family: var(--body); line-height: 1.5; resize: vertical; }
/* На телефоне кнопку удобнее жать во всю ширину, чем целиться в угол. */
@media (max-width: 480px) {
  .user-panel .row { display: block; }
  .user-panel .row button { width: 100%; }
  .user-head { gap: 10px; }
  .user-av { width: 60px; height: 60px; }
}

/* ---- Шаг подтверждения почты ---- */
.verify-note { color: var(--muted); font-size: 12px; line-height: 1.5; margin-bottom: 10px; }
.verify-note span { color: var(--amber); }
#f-code { letter-spacing: 6px; text-align: center; font-size: 20px; font-family: var(--head); }

/* ---- Страница настроек ---- */
.settings-page {
  position: fixed; inset: 0; z-index: 1100; overflow-y: auto;
  /* Настройки — единственный экран без карты под ним, поэтому фон здесь
     звучит громче: отдельная ржавая текстура и вуаль слабее, чем на панелях. */
  background:
    linear-gradient(180deg, rgba(22,20,18,.62), rgba(14,13,12,.74)),
    url('/tex/rust.jpg') center / cover fixed;
}
.settings-head {
  position: sticky; top: 0; z-index: 2; display: flex; align-items: center; gap: 10px;
  padding: 10px 14px; border-bottom: 1px solid #0b0c0e;
  background:
    linear-gradient(180deg, rgba(38,42,48,.62), rgba(22,25,29,.74)),
    url('/tex/bar.jpg') center / cover;
}
.settings-title { flex: 1; font-family: var(--head); text-transform: uppercase; letter-spacing: 1px; color: var(--amber); }
.settings-body { max-width: 640px; margin: 0 auto; padding: 16px 16px 60px; }
.set-hero { display: flex; align-items: center; gap: 16px; padding: 10px 0 20px; }
.set-avatar { width: 84px; height: 84px; border-radius: 2px; object-fit: cover; background: #14161a; display: block; }
.set-name { font-family: var(--head); font-size: 24px; font-weight: 700; color: var(--amber); letter-spacing: 1px; }
.set-rank { margin-top: 4px; }
.set-section { padding: 16px 0; border-top: 1px solid var(--line); }
.set-label { font-family: var(--head); text-transform: uppercase; letter-spacing: 1px; color: var(--acid); font-size: 13px; }
.set-hint { color: var(--muted); font-size: 12px; margin: 3px 0 10px; }
.set-select { width: 100%; background: #101216; border: 1px solid var(--line-2); color: var(--text); font-family: var(--body); padding: 9px; border-radius: 2px; font-size: 14px; }
.danger { color: #ff9a94 !important; border-color: var(--red) !important; }

/* сетка аватаров */
.avatar-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(72px, 1fr)); gap: 10px; }
.av-cell { position: relative; aspect-ratio: 1; border-radius: 2px; cursor: pointer; border: 2px solid transparent; }
.av-cell img { width: 100%; height: 100%; border-radius: 2px; object-fit: cover; display: block; }
.av-cell.on { border-color: var(--amber); box-shadow: 0 0 10px rgba(232,184,32,.5); }
.av-cell.locked { cursor: not-allowed; }
.av-cell.locked img { filter: grayscale(1) brightness(.4); }
.av-cell .lock { position: absolute; inset: 0; display: grid; place-items: center; font-size: 22px; color: var(--muted); }

/* подсказка у курсора */
.cursor-tip {
  position: fixed; z-index: 2000; pointer-events: none;
  background: rgba(20,22,26,.96); border: 1px solid var(--amber-dim); color: var(--amber);
  font-family: var(--head); font-size: 12px; letter-spacing: .3px; padding: 5px 9px; border-radius: 2px;
  box-shadow: 0 4px 14px rgba(0,0,0,.5); max-width: 220px;
}

/* ---- Фильтры категорий ---- */
/* Кнопка фильтров — как на досках объявлений: значок ползунков и счётчик
   выбранного. Панель под ней раскрывается, а не висит поверх карты всегда. */
.filters-btn {
  position: fixed; top: 58px; left: 12px; z-index: 851;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px; font-size: 12px;
}
.filters-btn svg {
  width: 16px; height: 16px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round;
}
.filters-btn.on { color: var(--amber); border-color: var(--amber-dim); }
.filters-n {
  min-width: 17px; height: 17px; padding: 0 4px; border-radius: 9px;
  background: var(--amber); color: #1d1808;
  font-size: 10px; line-height: 17px; text-align: center;
}

.filters {
  position: fixed; top: 96px; left: 12px; right: 12px; z-index: 850;
  max-height: 60vh; overflow-y: auto;
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px; border-radius: 2px;
  border: 1px solid var(--line); border-top-color: #4a4238;
  background: linear-gradient(180deg, rgba(30,33,39,.95), rgba(17,19,22,.97));
  box-shadow: 0 12px 34px rgba(0,0,0,.65);
}
.ftop {
  display: flex; align-items: center; gap: 8px;
  font-family: var(--head); font-size: 12px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--muted);
}
.ftop button { margin-left: auto; padding: 3px 8px; font-size: 10px; }
.ftop button + button { margin-left: 0; }
.filters button.fcat, .filters button.fgroup-head {
  padding: 5px 10px; font-size: 12px; text-transform: none; letter-spacing: 0;
  font-family: var(--body);
  background: linear-gradient(180deg, #2a2e34, #1a1d22); color: var(--muted); border-color: var(--line-2);
}
.filters button.on { color: var(--amber); border-color: var(--amber-dim); box-shadow: 0 0 8px rgba(232,184,32,.2); }

/* Группа — своя строка с заголовком: тринадцать тегов подряд читаются кашей. */
.fgroup { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.fgroup + .fgroup { border-top: 1px solid var(--line-2); padding-top: 8px; }
.filters .fgroup-head {
  color: var(--acid); font-family: var(--head); letter-spacing: 1px;
  text-transform: uppercase; font-size: 11px; background: transparent; border-color: transparent;
  width: 100%; text-align: left; padding-left: 0;
}
.filters .fgroup-head:hover { color: var(--amber); }

/* Теги объекта в его карточке и в форме правки. */
.badge.tag { margin-left: 4px; color: var(--muted); border-color: var(--line-2); }
.tags-row { align-items: flex-start; flex-direction: column; gap: 6px; }
.tag-pick { display: flex; flex-wrap: wrap; gap: 5px; }
.tag-pick .fcat {
  padding: 4px 9px; font-size: 11px; text-transform: none; letter-spacing: 0;
  font-family: var(--body);
  background: linear-gradient(180deg, #2a2e34, #1a1d22); color: var(--muted); border-color: var(--line-2);
}
.tag-pick .fcat.on { color: var(--amber); border-color: var(--amber-dim); }
/* Основной тип — залит янтарём, а не просто подсвечен: он один и отвечает за
   значок на карте, спутать его с остальными отмеченными нельзя. */
.tag-pick .fcat.main {
  color: #1d1808; border-color: #6b5a3a; font-weight: 700;
  background: linear-gradient(180deg, #e6c268 0%, #c09a42 50%, #9a7a2c 100%);
  text-shadow: none;
}
/* Заголовок группы внутри набора — просто подпись, не кнопка. */
.tag-group-head {
  width: 100%; margin: 4px 0 1px;
  font-family: var(--head); font-size: 11px; letter-spacing: 1px;
  text-transform: uppercase; color: var(--muted);
}
.tag-group-head:first-child { margin-top: 0; }

/* Подсказка по удержанию тега. Поверх всего и мимо пальца: она появляется
   под самым пальцем, поэтому не должна ловить нажатия. */
.tag-hint {
  position: fixed; z-index: 2100; pointer-events: none;
  padding: 8px 10px; border-radius: 2px;
  background: rgba(14,16,19,.97); border: 1px solid var(--amber-dim);
  color: var(--text); font-size: 12px; line-height: 1.35;
  box-shadow: 0 8px 24px rgba(0,0,0,.7);
}

/* ---- Боковая карточка ---- */
.drawer {
  position: fixed; top: 50px; right: 0; bottom: 0; width: min(92vw, 420px); z-index: 950;
  background:
    linear-gradient(180deg, rgba(28,31,36,.84), rgba(18,20,24,.9)),
    url('/tex/panel.jpg') center / cover fixed;
  border-left: 1px solid var(--line); box-shadow: -8px 0 30px rgba(0,0,0,.5);
  overflow-y: auto; padding: 18px; transition: transform .2s ease;
}
/* Убранная карточка не должна перехватывать клики: она остаётся в потоке,
   просто уезжает вбок, и без этого ловила нажатия поверх плашки профиля. */
.drawer.hidden { display: block !important; transform: translateX(105%); pointer-events: none; }
.drawer-close {
  position: absolute; top: 12px; right: 12px; padding: 2px 9px; font-size: 15px;
  background: transparent; border: 1px solid var(--line); color: var(--muted);
}
.drawer h2 { margin: 0 30px 4px 0; color: var(--amber); font-size: 20px; text-transform: uppercase; letter-spacing: 1px; }
.drawer h3 {
  font-family: var(--head); color: var(--acid); font-size: 14px; letter-spacing: 1px; text-transform: uppercase;
  margin: 20px 0 8px; padding-bottom: 5px; border-bottom: 1px solid var(--line);
}
.drawer .meta { color: var(--muted); font-size: 12px; margin-bottom: 10px; }
.drawer .desc { color: var(--text); line-height: 1.5; font-size: 14px; }
.locked-note {
  background: rgba(255,59,48,.08); border: 1px solid var(--red); color: #ff9a94;
  padding: 8px 12px; border-radius: 2px; font-size: 13px; margin: 10px 0;
}
.rate-row { display: flex; align-items: center; gap: 10px; margin: 12px 0; }

/* Кулак и счётчик в одной кнопке: нажимается вся плашка целиком, а не только
   картинка — попадать пальцем в иконку 28 px на телефоне неудобно. */
.vote-btn { display: inline-flex; align-items: center; gap: 8px; padding: 6px 12px; }
/* image-rendering: pixelated — рисунок пиксельный, сглаживание при уменьшении
   превращает ступеньки контура в грязь. */
.vote-btn img { width: 28px; height: 28px; display: block; image-rendering: pixelated; }
/* Счётчик переносится по три цифры в строку: шестизначное число в одну
   строку растянуло бы кнопку через всю карточку и уронило вторую под неё.
   Вместо этого кнопка растёт вверх-вниз: 123456 читается как 123 / 456. */
/* Строки счётчика собраны в app.js по три цифры, здесь только укладка:
   колонкой, по центру, без разрядки — иначе третья цифра съезжает. */
.vote-n {
  display: flex; flex-direction: column; align-items: center;
  font-family: var(--head); font-size: 17px; line-height: 1.05; color: var(--text);
  font-variant-numeric: tabular-nums; letter-spacing: 0;
}
.vote-btn.on { border-color: var(--amber); }
.vote-btn.on .vote-n { color: var(--amber); }
.vote-btn:disabled { opacity: .45; }

.item { border: 1px solid var(--line-2); border-radius: 2px; padding: 10px; margin-bottom: 8px; background: rgba(0,0,0,.2); }
.item .who { font-family: var(--head); color: var(--acid); font-size: 12px; letter-spacing: .5px; }
.item .when { color: var(--muted); font-size: 11px; }
.item .txt { color: var(--text); font-size: 14px; line-height: 1.45; margin-top: 4px; white-space: pre-wrap; }

.voice-rec { margin-top: 8px; display: flex; flex-direction: column; gap: 6px; }
.voice-rec .frow { display: flex; gap: 6px; }
/* Диктофон — та же панель, что у готовых заметок, поэтому своих размеров ей
   не нужно: отличается только красной клавишей во время записи. */
#rec-btn.rec-on {
  border-color: var(--red); color: #fff;
  background: linear-gradient(180deg,#7a2420,#4a1512);
  animation: recpulse 1s infinite;
}
@keyframes recpulse { 50% { filter: brightness(1.4); } }
.vrec .vp-title { color: var(--amber); }
.tts-fallback { margin-top: 10px; }
.tts-fallback summary { color: var(--muted); font-size: 12px; cursor: pointer; }
/* ---- Плеер голосовухи: ржавая панель ------------------------------------
   Корпус собран из той же текстуры ржавчины, что и фон настроек, поэтому
   плеер читается как кусок железа на стене, а не как виджет поверх неё.
   Тёмный градиент поверх текстуры держит контраст текста. */
.vplayer {
  display: flex; align-items: center; gap: 10px;
  padding: 10px; margin-bottom: 8px; border-radius: 2px;
  border: 1px solid #0f1114; border-top-color: #4a4238;
  background:
    linear-gradient(180deg, rgba(34,30,24,.62), rgba(16,15,15,.78)),
    url('/tex/rust.jpg') center / cover;
  box-shadow: inset 0 1px 0 rgba(255,235,190,.07), inset 0 -2px 6px rgba(0,0,0,.6), 0 2px 6px rgba(0,0,0,.5);
}
.vplayer.on { border-top-color: var(--amber-dim); box-shadow: inset 0 0 0 1px rgba(232,184,32,.18), 0 2px 10px rgba(0,0,0,.6); }

/* Блок клавиш деки: перемотка по заметкам слева и справа от пуска, как на
   кассетнике. Стрелки мельче пуска — жмут их реже. */
.vp-keys { display: flex; align-items: center; gap: 4px; flex: none; }
.vp-step {
  letter-spacing: -2px;
  width: 30px; height: 38px; padding: 0; font-size: 11px; line-height: 1;
  border-radius: 2px; color: var(--muted);
}
.vp-step:hover { color: var(--amber); }
.vp-count { color: var(--muted); font-size: 11px; font-family: var(--head); }

/* Список заметок под декой: видно, сколько их и какая играет. */
.vdeck-list { display: flex; flex-direction: column; gap: 2px; margin: -4px 0 8px; }
.vd-row {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 6px 10px; font-family: var(--body); text-transform: none;
  font-size: 12px; letter-spacing: 0; color: var(--muted);
  background: rgba(0,0,0,.25); border: 1px solid var(--line-2);
  box-shadow: none; text-shadow: none;
}
.vd-row .vd-n { font-family: var(--head); min-width: 14px; }
.vd-row .vd-who { flex: 1; text-align: left; color: var(--text); }
.vd-row.on { border-color: var(--amber-dim); color: var(--amber); }
.vd-row.on .vd-who { color: var(--amber); }

/* Пуск — крупная квадратная клавиша, как на железном пульте. */
.vp-play {
  flex: none; width: 46px; height: 46px; padding: 0;
  font-size: 17px; line-height: 1; border-radius: 2px;
}
.vplayer.on .vp-play { color: var(--amber); border-color: var(--amber-dim); }

.vp-body { flex: 1; min-width: 0; }
.vp-title { font-family: var(--head); color: var(--acid); font-size: 13px; letter-spacing: .5px; }
.vp-sub { color: var(--muted); font-size: 11px; margin-top: 3px; }
.vp-tone-name { color: var(--amber); }
.vp-body .txt { font-size: 13px; margin-top: 4px; }

/* Полоса прогресса: показывает, сколько осталось. Перемотки нет намеренно —
   заметки короткие, а ползунок на телефоне ворует нажатия у кнопки пуска. */
.vp-bar {
  height: 4px; margin-top: 5px; border-radius: 2px; overflow: hidden;
  background: rgba(0,0,0,.55); border: 1px solid rgba(0,0,0,.6);
}
.vp-bar i { display: block; height: 100%; width: 0; background: var(--amber); box-shadow: 0 0 6px rgba(232,184,32,.7); }

/* Крестик сноса заметки — у правого края деки, подальше от пуска. */
.vd-del {
  flex: none; width: 28px; height: 28px; padding: 0; font-size: 12px; line-height: 1;
  color: var(--muted); border-radius: 2px;
}
.vd-del:hover { color: #fff; background: var(--red); border-color: var(--red); }

/* Пометка «ещё не проверено» — и в деке, и под описанием. */
.pending-mark { color: var(--red); }
.pending-note {
  color: var(--red); font-size: 12px; margin: -4px 0 8px;
}

/* ---- Правка объекта (автор и модератор) ---- */
.d-edit {
  display: flex; flex-direction: column; gap: 8px;
  margin: 10px 0; padding: 10px; border-radius: 2px;
  border: 1px solid var(--line-2); background: rgba(0,0,0,.22);
}
.d-edit .edit-row { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--muted); }
.d-edit select, .d-edit textarea, .d-edit input {
  flex: 1; min-width: 0; background: #101216; border: 1px solid var(--line-2);
  color: var(--text); font-family: var(--body); padding: 7px; border-radius: 2px; font-size: 13px;
}
/* Кнопки правки мельче обычных: это служебный блок, а не то, ради чего
   карточку открывают. Крупные клавиши перетягивали внимание с самого объекта. */
.d-edit .frow { display: flex; gap: 6px; }
.d-edit button { padding: 6px 10px; font-size: 11px; letter-spacing: .5px; }
.d-edit .frow button { flex: 1; }
.d-edit button.danger { align-self: flex-start; padding: 5px 12px; font-size: 11px; }
/* Снос объекта — единственная необратимая кнопка в карточке, поэтому она
   красная и стоит отдельно, под правками, а не в одном ряду с ними. */
button.danger { color: #ffd9d5; border-color: #6b1f1a; background: linear-gradient(180deg,#7a2420,#4a1512); }
button.danger:hover { filter: brightness(1.25); border-color: var(--red); }

.mini-form { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.mini-form textarea, .mini-form input, .mini-form select {
  background: #101216; border: 1px solid var(--line-2); color: var(--text);
  font-family: var(--body); padding: 7px; border-radius: 2px; font-size: 13px;
}
.mini-form .frow { display: flex; gap: 6px; }
.mini-form .frow > * { flex: 1; }
.mini-form button { align-self: flex-end; padding: 6px 14px; font-size: 12px; }
.empty { color: var(--muted); font-size: 13px; font-style: italic; }

/* ---- Фото-галерея ---- */
.gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.gallery a { display: block; aspect-ratio: 1; border: 1px solid var(--line-2); border-radius: 2px; overflow: hidden; position: relative; }
.gallery img { width: 100%; height: 100%; object-fit: cover; }
.gallery .pending {
  position: absolute; inset: auto 0 0 0; background: rgba(255,59,48,.75); color: #fff;
  font-family: var(--head); font-size: 9px; text-align: center; letter-spacing: .5px; padding: 1px;
}
/* Обёртка кадра: крестик лежит поверх снимка, поэтому ему нужен свой
   контейнер — кнопка открытия растянута под превью целиком. */
.shot { position: relative; }
/* Превью — кнопка, но выглядеть должна голым снимком: сбрасываем всё, что
   рисует обычная клавиша. */
.shot-open {
  display: block; width: 100%; aspect-ratio: 1; padding: 0; overflow: hidden;
  position: relative; border-radius: 2px; border: 1px solid var(--line-2);
  background: #000; box-shadow: none; text-shadow: none;
}
.shot-open img { width: 100%; height: 100%; object-fit: cover; }

/* Ник автора — водяной знак: мелкий, полупрозрачный, в углу кадра. Подпись
   нужна, чтобы снимок не гулял безымянным, но смотреть она мешать не должна. */
.shot-sign {
  position: absolute; right: 4px; bottom: 3px;
  font-family: var(--body); font-size: 9px; letter-spacing: .3px;
  color: rgba(255,255,255,.62); text-transform: none;
  text-shadow: 0 1px 2px rgba(0,0,0,.9);
  pointer-events: none;
}
.shot-sign.big { right: 10px; bottom: 8px; font-size: 12px; }
.shot-del {
  position: absolute; top: 3px; right: 3px; z-index: 2;
  /* 26 px — минимум, в который попадают пальцем. Меньше делали, и на телефоне
     вместо удаления открывалось фото на весь экран. */
  width: 26px; height: 26px; padding: 0; line-height: 1; font-size: 13px;
  border-radius: 2px; color: #fff;
  background: rgba(20,22,26,.82); border: 1px solid var(--line);
  box-shadow: 0 1px 4px rgba(0,0,0,.6);
}
.shot-del:hover { background: var(--red); border-color: var(--red); }
.shot-del:disabled { opacity: .5; }
.upload-btn { align-self: flex-start; }

/* ---- Просмотр фото ---- */
.shot-card {
  position: relative; display: flex; align-items: center; gap: 6px;
  width: min(96vw, 900px);
}
/* Рамка вокруг снимка — тот же стальной борт, что у панелей: кадр читается
   как экспонат на стене, а не как картинка, вываленная поверх карты. */
.shot-frame {
  position: relative; flex: 1; min-width: 0;
  padding: 8px; border-radius: 2px;
  border: 1px solid #0f1114; border-top-color: #4a4238;
  background: linear-gradient(180deg, rgba(30,28,24,.9), rgba(12,12,13,.95));
  box-shadow: inset 0 1px 0 rgba(255,235,190,.07), 0 10px 40px rgba(0,0,0,.75);
}
.shot-frame img {
  display: block; width: 100%; max-height: 78vh; object-fit: contain;
  background: #000; border: 1px solid #000;
}
.shot-count {
  position: absolute; left: 14px; bottom: 14px;
  font-family: var(--head); font-size: 12px; color: var(--amber);
  text-shadow: 0 1px 3px #000; pointer-events: none;
}
/* Стрелки просвечивают кадр: сплошные клавиши по бокам съедали снимок. */
.shot-nav {
  flex: none; width: 42px; height: 84px; padding: 0;
  font-size: 30px; line-height: 1; border-radius: 2px;
  color: rgba(255,255,255,.7);
  background: rgba(20,22,26,.28); border: 1px solid rgba(255,255,255,.14);
  box-shadow: none; text-shadow: 0 1px 4px rgba(0,0,0,.8);
}
.shot-nav:hover { background: rgba(20,22,26,.55); color: var(--amber); border-color: var(--amber-dim); }
.shot-x {
  position: absolute; top: -14px; right: -6px; z-index: 2;
  width: 34px; height: 30px; padding: 0; font-size: 13px;
  background: rgba(20,22,26,.6); border: 1px solid rgba(255,255,255,.16); box-shadow: none;
}
.shot-x:hover { background: var(--red); border-color: var(--red); }

@media (max-width: 430px) {
  .shot-card { gap: 2px; }
  .shot-nav { width: 32px; height: 70px; font-size: 24px; }
}

/* «Сохранить» в самом низу карточки: последний элемент, отбит от адреса. */
.drawer-done {
  width: 100%; margin-top: 16px; padding: 12px; font-size: 15px; letter-spacing: 2px;
  color: #1d1808; border: 1px solid #6b5a3a;
  background: linear-gradient(180deg, #e6c268 0%, #c09a42 50%, #9a7a2c 100%);
  text-shadow: 0 1px 0 rgba(255,240,200,.3);
}

/* ---- Значки субкультур (§6.3) ---- */
.sub-icon { color: var(--acid); font-weight: 700; margin-left: 4px; cursor: default; }

/* ---- Рамки профиля (награды) ---- */
/* Аватары квадратные со скруглением: рамка вокруг круга смотрелась
   несогласованно, а рисованные рамки лягут на прямоугольник ровно. */
/* Рамка — рисованная картинка с прозрачным окном, она ложится поверх аватара.
   Вылет подобран по размеру окна каждой рамки: у «золота» и «легендарной»
   оно вдвое уже, чем у остальных, поэтому им нужен больший запас. */
/* Рамка занимает габарит целиком, а аватар ужимается до её окна. Обратный
   приём — растить рамку наружу — ломал вёрстку: она вылезала за пределы
   блока и перекрывала имя рядом. */
.frame { position: relative; display: inline-block; line-height: 0; }
.frame > img { transform: scale(var(--hole, 1)); }
.frame::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background: center / 100% 100% no-repeat;
}
.frame-standart { --hole: .74; } .frame-standart::after { background-image: url('/frames/standart.png'); }
.frame-rjavaya  { --hole: .77; } .frame-rjavaya::after  { background-image: url('/frames/rjavaya.png'); }
.frame-bronza   { --hole: .76; } .frame-bronza::after   { background-image: url('/frames/bronza.png'); }
.frame-zoloto   { --hole: .58; } .frame-zoloto::after   { background-image: url('/frames/zoloto.png'); }
.frame-legenda  { --hole: .58; } .frame-legenda::after  { background-image: url('/frames/legenda.png'); }

/* Выбор рамки: показываем сами рамки поверх текущего аватара — по слову
   «бронза» не понять, что получишь. */
.frame-swatch { display: flex; gap: 18px; flex-wrap: wrap; padding: 12px 0; }
.frame-pick {
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  background: transparent; border: 1px solid transparent; box-shadow: none;
  padding: 12px 10px 6px; text-transform: none; letter-spacing: 0;
  color: var(--muted); font-size: 11px;
}
.frame-pick .frame { width: 68px; height: 68px; }
.frame-pick img { width: 100%; height: 100%; object-fit: cover; border-radius: 2px; display: block; }
.frame-pick:hover { border-color: var(--line); color: var(--text); filter: none; }
.frame-pick.on { border-color: var(--amber-dim); color: var(--amber); }
.frame-pick.locked { opacity: .35; cursor: default; }
.frame-pick.locked:hover { border-color: transparent; }

/* ---- Непрочитанные / ЛС ---- */
.unread-dot {
  position: absolute; top: 4px; right: 4px; width: 8px; height: 8px; border-radius: 1px;
  background: var(--red); box-shadow: 0 0 6px var(--red);
}
#msg-btn { position: relative; }
.msg-panel { width: min(94vw, 440px); }
#msg-list .dlg {
  display: flex; justify-content: space-between; align-items: center; padding: 10px;
  border: 1px solid var(--line-2); border-radius: 2px; margin-bottom: 6px; cursor: pointer; background: rgba(0,0,0,.2);
}
#msg-list .dlg:hover { border-color: var(--amber-dim); }
#msg-list .dlg .nick { font-family: var(--head); color: var(--acid); }
#msg-list .dlg .u { background: var(--red); color: #fff; font-size: 11px; border-radius: 2px; padding: 0 6px; font-family: var(--head); }
.thread-body { max-height: 46vh; overflow-y: auto; display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.bubble { max-width: 78%; padding: 7px 10px; border-radius: 2px; font-size: 13px; line-height: 1.4; }
.bubble.me  { align-self: flex-end; background: var(--green-dim, #3d5e2f); background: linear-gradient(180deg,#37502a,#2a3d20); color: #eaf3e2; }
.bubble.them { align-self: flex-start; background: #23272e; border: 1px solid var(--line-2); color: var(--text); }
.bubble .t { display: block; font-size: 10px; color: var(--muted); margin-top: 3px; }
.back-link { color: var(--acid); cursor: pointer; font-size: 13px; }
.mod-item { display: flex; gap: 8px; align-items: center; border: 1px solid var(--line-2); border-radius: 2px; padding: 8px; margin-bottom: 6px; }
.mod-item img { width: 56px; height: 56px; object-fit: cover; border-radius: 2px; }
.mod-item .mi { flex: 1; min-width: 0; font-size: 12px; }
.mod-item button { padding: 3px 8px; font-size: 11px; }

/* ---- Узкие экраны: шапка целиком должна влезать в 390px ---- */
@media (max-width: 430px) {
  .topbar { gap: 6px; padding: 0 8px; }
  .brand { font-size: 18px; letter-spacing: 2px; }
  .topbar button { padding: 7px 10px; font-size: 12px; }
  /* Ник прячем — он всё равно виден в плашке профиля, которая под аватаром. */
  #chip-name { display: none; }
  .profile-chip { padding: 4px; max-width: none; }
  .filters { top: 56px; left: 8px; right: 8px; }
  .filters button { padding: 4px 9px; font-size: 11px; }
}

/* Подпись источников: компактная строка внизу, не отъедающая карту. */
.maplibregl-ctrl-attrib.maplibregl-compact { margin: 0 0 4px 4px !important; }
.maplibregl-ctrl-attrib-inner { font-size: 9px; line-height: 1.3; }

/* ---- Нижняя панель: латунный механизм ----------------------------------- */
/* Стимпанк держится на трёх вещах: тёплая латунь против холодной стали фона,
   заклёпки по кромке и живые шестерни. Палитра проекта не меняется — латунь
   набрана из --amber/--leather, которые здесь уже были. */
.deck {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: max(10px, env(safe-area-inset-bottom)); z-index: 880;
  display: flex; align-items: center; gap: 0;
  width: min(96vw, 620px); pointer-events: none;
}
.deck > * { pointer-events: auto; }

.deck-core {
  position: relative; flex: 1; min-width: 0;
  padding: 10px 14px;
  background:
    linear-gradient(180deg, rgba(74,64,50,.96), rgba(38,33,26,.97)),
    repeating-linear-gradient(90deg, rgba(0,0,0,.12) 0 2px, transparent 2px 5px);
  border: 1px solid #6b5a3a; border-top-color: #9a8250;
  border-radius: 2px;
  box-shadow:
    inset 0 1px 0 rgba(232,184,32,.25), inset 0 -2px 6px rgba(0,0,0,.6),
    0 6px 20px rgba(0,0,0,.6);
}
/* Заклёпки по верхней и нижней кромке. */
.deck-rivets { position: absolute; inset: 3px 8px; pointer-events: none; border-radius: 2px;
  background:
    radial-gradient(circle, #c9a44c 38%, #6b5a3a 60%, transparent 62%) 0 0/14px 6px repeat-x,
    radial-gradient(circle, #c9a44c 38%, #6b5a3a 60%, transparent 62%) 0 100%/14px 6px repeat-x;
  opacity: .5;
}

.search { display: flex; align-items: center; gap: 8px; }
.search-lens { color: var(--amber); font-size: 17px; text-shadow: 0 0 8px rgba(232,184,32,.5); }
.search input {
  flex: 1; min-width: 0;
  background: #14120e; border: 1px solid #4a4032; border-top-color: #2a241c;
  color: var(--text); font-family: var(--body); font-size: 14px;
  padding: 7px 9px; border-radius: 2px; outline: none;
  box-shadow: inset 0 2px 5px rgba(0,0,0,.7);
}
.search input:focus { border-color: var(--amber-dim); box-shadow: inset 0 2px 5px rgba(0,0,0,.7), 0 0 0 2px rgba(232,184,32,.14); }
.search input::placeholder { color: #7a6f5c; }
.search-go {
  flex: 0 0 auto; padding: 7px 12px; font-size: 12px; letter-spacing: 1px;
  color: #2a2214; border: 1px solid #6b5a3a;
  background: linear-gradient(180deg, #e0bc63 0%, #b8933f 48%, #97762f 52%, #6d5520 100%);
  text-shadow: 0 1px 0 rgba(255,235,180,.35);
  box-shadow: inset 0 1px 0 rgba(255,240,200,.5), 0 2px 4px rgba(0,0,0,.5);
}
.search-go:hover { filter: brightness(1.12); }
.search-go:active { filter: brightness(.92); transform: translateY(1px); }

/* Шестерни по краям: вращаются медленно и в разные стороны. */
.cog { width: 46px; height: 46px; flex: 0 0 auto; filter: drop-shadow(0 3px 5px rgba(0,0,0,.6)); }
.cog-l { margin-right: -12px; animation: cog-cw 24s linear infinite; }
.cog-r { margin-left: -12px; animation: cog-ccw 24s linear infinite; }
.cog-body { fill: #8a7038; stroke: #c9a44c; stroke-width: 2; }
.cog-hole { fill: #1a1611; }
.cog-rivet { fill: #c9a44c; opacity: .7; }
@keyframes cog-cw { to { transform: rotate(360deg); } }
@keyframes cog-ccw { to { transform: rotate(-360deg); } }
.cog { transform-origin: 50% 50%; }
/* Уважаем системную настройку «меньше движения». */
@media (prefers-reduced-motion: reduce) { .cog-l, .cog-r { animation: none; } }

/* Выдача поиска. */
.search-out {
  margin-top: 8px; max-height: 40vh; overflow-y: auto;
  border-top: 1px solid #6b5a3a; padding-top: 6px;
}
.search-out .row-hit {
  display: block; width: 100%; text-align: left; padding: 7px 8px; margin-bottom: 4px;
  background: rgba(20,18,14,.7); border: 1px solid #4a4032; color: var(--text);
  font-family: var(--body); font-size: 13px; text-transform: none; letter-spacing: 0;
  border-radius: 2px; cursor: pointer;
}
.search-out .row-hit:hover { border-color: var(--amber-dim); color: var(--amber); }
.search-out .hit-sub { display: block; color: var(--muted); font-size: 11px; margin-top: 2px; }
.search-out .note { color: var(--muted); font-size: 12px; padding: 4px 2px; }

/* Метка результата поиска — латунная, чтобы отличалась от меток локаций. */
/* Найденная точка — прицел, а не капля. Капля читалась как ещё один объект
   на карте, хотя это лишь «сюда я смотрю». Ставится центром на координаты
   (anchor: 'center' в showFound), поэтому перекрестье совпадает с точкой. */
.found-dot {
  width: 30px; height: 30px; border-radius: 50%;
  border: 2px solid var(--amber);
  background: rgba(232,184,32,.10);
  box-shadow: 0 0 14px rgba(232,184,32,.55), inset 0 0 8px rgba(232,184,32,.35);
  position: relative;
}
/* Перекрестье: две планки через центр с разрывом под кружком. */
.found-dot::before, .found-dot::after {
  content: ''; position: absolute; background: var(--amber);
  box-shadow: 0 0 6px rgba(232,184,32,.8);
}
.found-dot::before { left: 50%; top: -8px; bottom: -8px; width: 2px; margin-left: -1px; }
.found-dot::after  { top: 50%; left: -8px; right: -8px; height: 2px; margin-top: -1px; }

/* На узких экранах шестерни только мешают месту под ввод. */
@media (max-width: 430px) {
  .deck { width: 96vw; bottom: max(8px, env(safe-area-inset-bottom)); }
  .cog { width: 34px; height: 34px; }
  .search-go { padding: 7px 9px; font-size: 11px; }
}

/* Кнопки зума MapLibre поднимаем над панелью, иначе она их накрывает. */
.maplibregl-ctrl-bottom-right { bottom: 78px !important; }

/* ---- Курс до локации ---- */
.route-btn {
  margin-top: 10px; width: 100%; font-size: 13px; letter-spacing: 1px;
  color: #2a2214; border: 1px solid #6b5a3a;
  background: linear-gradient(180deg, #e0bc63 0%, #b8933f 48%, #97762f 52%, #6d5520 100%);
  text-shadow: 0 1px 0 rgba(255,235,180,.35);
  box-shadow: inset 0 1px 0 rgba(255,240,200,.5), 0 2px 4px rgba(0,0,0,.5);
}
/* Крестик на конце курса — «здесь копать».
   Анимацию вешаем на вложенный span, а не на корень: MapLibre держит
   положение метки в inline transform корневого узла, и своя transform-анимация
   на нём затирает координаты — крестик уезжает в сторону от маршрута. */
.route-x {
  width: 30px; height: 30px; display: grid; place-items: center;
  color: #f0d48a; font-size: 22px; font-weight: 700;
  text-shadow: 0 0 10px rgba(232,184,32,.9), 0 2px 3px #000;
}
.route-x span { display: block; animation: x-pulse 1.8s ease-in-out infinite; }
@keyframes x-pulse { 50% { transform: scale(1.18); } }
@media (prefers-reduced-motion: reduce) { .route-x span { animation: none; } }

.route-info {
  position: absolute; left: 0; right: 0; bottom: calc(100% + 8px);
  background: linear-gradient(180deg, rgba(74,64,50,.96), rgba(38,33,26,.97));
  border: 1px solid #6b5a3a; border-radius: 2px; padding: 7px 10px;
  color: #f0d48a; font-family: var(--head); font-size: 13px; letter-spacing: .5px;
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  box-shadow: 0 6px 18px rgba(0,0,0,.6);
}
.route-info .route-off {
  padding: 3px 9px; font-size: 11px; background: transparent;
  border: 1px solid #6b5a3a; color: var(--muted); box-shadow: none; text-shadow: none;
}
.route-info .route-off:hover { color: var(--amber); border-color: var(--amber-dim); }
