/* =====================================================================
   Barren Lands — стили.
   Мобильный портрет — целевая раскладка. Десктоп получает тот же
   интерфейс в колонке шириной с телефон.
   Анимируются только transform и opacity: всё остальное на телефоне
   вызывает перекомпоновку и роняет частоту кадров.
   ===================================================================== */

:root {
  --bg:        #14120f;
  --bg-2:      #1c1916;
  --bg-3:      #262220;
  --line:      #3a342e;
  --ink:       #e6ddd0;
  --ink-dim:   #9c9184;
  --ink-faint: #6b6258;
  --accent:    #c8a86a;
  --accent-dk: #8a7444;
  --danger:    #b8564a;
  --ok:        #7d9460;

  --thirst:  #5f8fa8;
  --hunger:  #a8825f;
  --fatigue: #8a7fa8;

  --pad: 16px;
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);

  --tap: 44px;
  --radius: 10px;
  --shell: 480px;          /* ширина «телефона» на десктопе */
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* Атрибут hidden должен побеждать ВСЕГДА.
   Он работает через display:none в стилях браузера, а любое авторское правило
   с display сильнее — и элемент, который мы считаем спрятанным, остаётся на
   экране и перехватывает тапы. Без этой строки пустая модалка висит поверх
   титульного экрана и кнопка под ней не нажимается. */
[hidden] { display: none !important; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overscroll-behavior: none;       /* без pull-to-refresh поверх жестов игры */
}

body {
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.5 ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  touch-action: manipulation;       /* двойной тап не масштабирует */
}

/* Текст интерфейса не выделяется: долгий тап по кнопке — это жест, а не
   попытка скопировать слово. Ссылку для входа выделять наоборот можно. */
.app, .app * { user-select: none; -webkit-user-select: none; }
.linkbox__url, .journal { user-select: text; -webkit-user-select: text; }

.app {
  position: relative;
  max-width: var(--shell);
  margin: 0 auto;
  min-height: 100%;
  background: var(--bg);
}

@media (min-width: 520px) {
  body { background: #0b0a09; }
  .app { box-shadow: 0 0 60px rgba(0,0,0,.6); }
}

/* --- экраны ---------------------------------------------------------- */

.screen {
  display: none;
  min-height: 100vh;
  min-height: 100dvh;
  flex-direction: column;
  padding-top: var(--safe-t);
}
.screen.is-active { display: flex; }

/* --- типовые элементы ------------------------------------------------ */

.btn {
  appearance: none;
  border: 1px solid var(--line);
  background: var(--bg-3);
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  min-height: var(--tap);
  padding: 0 20px;
  border-radius: var(--radius);
  cursor: pointer;
  transition: transform .08s ease, opacity .15s ease;
}
.btn:active { transform: scale(.97); }
.btn--primary { background: var(--accent); border-color: var(--accent); color: #17140f; }
.btn--ghost   { background: transparent; color: var(--ink-dim); }
.btn--small   { min-height: 36px; font-size: 14px; padding: 0 14px; }
.btn--wide    { width: 100%; }
.btn[disabled] { opacity: .4; pointer-events: none; }

.pane { flex: 1; padding: var(--pad); padding-bottom: calc(var(--pad) + var(--safe-b)); display: flex; flex-direction: column; gap: 14px; }
.pane__title { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: .01em; }
.pane__text  { margin: 0; color: var(--ink-dim); font-size: 15px; }
.pane__foot  { margin-top: auto; display: flex; flex-direction: column; gap: 10px; }
.pane__about { margin-top: auto; color: var(--ink-faint); font-size: 13px; text-align: center; }

.field { display: block; }
.field__label { display: block; font-size: 13px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-faint); margin-bottom: 6px; }
.field__label--block { margin-top: 4px; }
.field__input {
  width: 100%;
  min-height: var(--tap);
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  font: inherit;
  padding: 0 14px;
}
.field__input:focus { outline: none; border-color: var(--accent-dk); }

.row {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; min-height: var(--tap);
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--ink); font: inherit; padding: 0 14px; cursor: pointer;
}
.row b { color: var(--accent); font-weight: 600; }

/* --- загрузка -------------------------------------------------------- */

.boot { margin: auto; text-align: center; }
.boot__mark {
  width: 34px; height: 34px; margin: 0 auto 14px;
  border: 2px solid var(--line); border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
.boot__note { color: var(--ink-faint); font-size: 14px; }
@keyframes spin { to { transform: rotate(360deg); } }

/* --- титул ----------------------------------------------------------- */

.title {
  flex: 1; display: flex; flex-direction: column; align-items: center;
  padding: 12vh var(--pad) calc(var(--pad) + var(--safe-b));
  gap: 16px; text-align: center;
}
.title__name {
  margin: 0; font-size: 40px; line-height: 1.05; font-weight: 800;
  letter-spacing: -.02em; color: var(--ink);
}
.title__epigraph { margin: 0; color: var(--ink-dim); font-style: italic; font-size: 17px; }
.title__epigraph p { margin: 0 0 6px; }
.title__epigraph cite { font-style: normal; font-size: 13px; color: var(--ink-faint); }
.title__spacer { flex: 1; }
.title .btn { width: 100%; max-width: 320px; }

/* --- выбор языка ------------------------------------------------------ */

.langpick {
  display: flex; gap: 6px;
  width: 100%; max-width: 320px;
  padding: 4px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.langpick__btn {
  flex: 1; min-height: 36px;
  background: none; border: 0; border-radius: 7px;
  color: var(--ink-dim); font: inherit; font-size: 14px; cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
.langpick__btn.is-on { background: var(--accent); color: #17140f; font-weight: 600; }

/* --- архетипы -------------------------------------------------------- */

.archetypes { display: flex; flex-direction: column; gap: 8px; }

/* Строка архетипа: «i» слева, имя со строчкой посередине, значок справа.
   Тап по середине выбирает, тап по «i» рассказывает — это разные намерения,
   и делать их одной кнопкой нельзя. */
.arch {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--ink); padding: 0 12px 0 6px;
  transition: border-color .12s ease, transform .08s ease;
}
.arch:active { transform: scale(.99); }
.arch.is-on { border-color: var(--accent); background: var(--bg-3); }

.arch__pick {
  flex: 1 1 auto; min-width: 0; text-align: left;
  background: none; border: 0; color: inherit; font: inherit;
  padding: 12px 0; cursor: pointer;
}
.arch__info {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 50%;
  background: none; border: 1px solid var(--line); color: var(--ink-dim);
  font: 600 14px/1 serif; font-style: italic; cursor: pointer;
  transition: border-color .12s ease, color .12s ease;
}
.arch__info:active { border-color: var(--accent); color: var(--accent); }
.arch__ic {
  flex: 0 0 auto; width: 30px; height: 30px; color: var(--ink-dim);
  display: flex; align-items: center; justify-content: center;
}
.arch__ic svg, .arch__ic img { width: 100%; height: 100%; object-fit: contain; }
.arch.is-on .arch__ic { color: var(--accent); }

.arch__name  { display: block; font-weight: 700; margin-bottom: 2px; }
.arch__about {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 13px; color: var(--ink-dim); line-height: 1.3;
}

/* Попап архетипа: то, что не влезло на строку. */
.sheet__art--arch { background: var(--bg-3); color: var(--accent) }
.sheet__art--arch svg { width: 46px; height: 46px }
.archgroup {
  font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--ink-faint); margin: 16px 0 8px; font-weight: 500;
}
.archcards, .archres { display: flex; flex-wrap: wrap; gap: 6px }
.archcard {
  display: flex; align-items: center; gap: 6px;
  padding: 4px 9px 4px 6px; border-radius: 6px;
  font-size: 12px; color: var(--paper-ink); font-weight: 600;
}
.archcard__ic { width: 15px; height: 15px; display: flex }
.archcard__ic svg, .archcard__ic img.ic { width: 100%; height: 100% }
.archcard b { margin-left: 1px; opacity: .65 }

/* --- ссылка для входа ------------------------------------------------ */

.linkbox { display: flex; gap: 8px; align-items: center; background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius); padding: 10px 12px; }
.linkbox__url { flex: 1; font-size: 12px; word-break: break-all; color: var(--accent); font-family: ui-monospace, monospace; }

/* --- HUD ------------------------------------------------------------- */

/* Экран клетки — колонка фиксированных блоков и одной гибкой середины.
   Без min-height:0 гибкая середина не сжимается ниже своего содержимого,
   колонка вылезает за экран, и нижние вкладки уходят за край. */
.screen--cell > * { flex-shrink: 0; }
/* Список целей — единственная растяжимая часть колонки, но не меньше двух
   строк: схлопнувшись, он оставляет карты без цели. */
.screen--cell > .spots { flex: 1 1 auto; min-height: 88px; overflow-y: auto; }

.hud { padding: 8px var(--pad) 6px; border-bottom: 1px solid var(--line); }
.hud__line { display: flex; align-items: baseline; gap: 8px; font-size: 13px; }
.hud__day   { font-weight: 700; color: var(--accent); white-space: nowrap; }
.hud__place { flex: 1; color: var(--ink-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hud__tod   { color: var(--ink-faint); white-space: nowrap; }

.hud__needs { display: flex; gap: 6px; margin-top: 6px; }
.need { flex: 1; height: 4px; background: var(--bg-3); border-radius: 2px; overflow: hidden; position: relative; }
.need i { position: absolute; inset: 0; transform-origin: left center; transform: scaleX(0); transition: transform .4s ease; }
.need b { display: none; }
.need[data-need="thirst"]  i { background: var(--thirst); }
.need[data-need="hunger"]  i { background: var(--hunger); }
.need[data-need="fatigue"] i { background: var(--fatigue); }
.need.is-high i { background: var(--danger); }

/* --- вид (квадрат 1:1) ----------------------------------------------- */

.view {
  position: relative;
  width: 100%;
  /* Кадр квадратный, но на коротком экране колонка не помещается целиком.
     Ограничиваем высоту и обрезаем кадр по краям: композиция центральная,
     терять по бокам безопаснее, чем отнимать место у текста и спотов.
     С появлением пояса (этап 3) доля кадра ужата ещё: цели должны быть
     видны, иначе играть картой не во что. */
  height: min(100vw, 40dvh);
  aspect-ratio: 1 / 1;
  background: #0d0c0a;
  overflow: hidden;
  /* Свайп по кадру — поворот. Браузер не должен перехватывать его на скролл. */
  touch-action: pan-y;
}
.view__canvas { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Слои арта. Порядок снизу вверх: даль → земля → средний план.
   Пока файла нет, слой прозрачен и сквозь него видно процедурную заглушку —
   поэтому картинки можно выкладывать по одной, и каждая появляется сразу. */
.view__layer {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0;
  transition: opacity .2s ease;
  pointer-events: none;
}
.view__layer.is-on { opacity: 1; }
#layerFar    { z-index: 1; }
#layerGround { z-index: 2; }
#layerMid    { z-index: 3; }
.view__compass, .view__ahead { z-index: 7; }

/* Слой света: время суток и погода одной строкой CSS, без единой картинки. */
.view__grade { position: absolute; inset: 0; pointer-events: none; mix-blend-mode: multiply; transition: background .8s ease; }

.view__compass {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; align-items: center; justify-content: space-between;
  padding: 6px 4px;
  background: linear-gradient(to top, rgba(10,9,8,.85), rgba(10,9,8,0));
}
.compass__arrow {
  width: var(--tap); height: var(--tap);
  background: none; border: 0; color: var(--ink); font-size: 26px; line-height: 1;
  cursor: pointer; opacity: .75;
}
.compass__arrow:active { opacity: 1; transform: scale(.9); }
.compass__dir { font-size: 13px; letter-spacing: .18em; text-transform: uppercase; color: var(--ink); }

.view__ahead {
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%);
  font-size: 12px; color: var(--ink-dim);
  background: rgba(10,9,8,.6); padding: 3px 10px; border-radius: 99px;
  max-width: 80%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* --- споты ------------------------------------------------------------ */

.sidetext {
  margin: 0; padding: 7px var(--pad) 6px;
  font-size: 13px; line-height: 1.38; color: var(--ink-dim);
  border-bottom: 1px solid var(--bg-3);
}
.spots { padding: 0; }
.spot {
  display: flex; align-items: center; gap: 10px;
  width: 100%; min-height: var(--tap);
  padding: 0 var(--pad);
  background: none; border: 0; border-bottom: 1px solid var(--bg-3);
  color: var(--ink); font: inherit; text-align: left; cursor: pointer;
}
.spot svg, .spot img.ic { width: 17px; height: 17px; flex: none; color: var(--ink-faint); }
.spot.is-on svg { color: var(--accent); }
.spot.is-on { background: var(--bg-2); color: var(--accent); }
.spots__empty { padding: 14px var(--pad); color: var(--ink-faint); font-size: 14px; }

/* Тварь, которая тебя не заметила (§8.2), — не добыча, и в списке целей это
   должно быть видно раньше, чем игрок прочтёт название. Поэтому она одна
   здесь тревожного цвета, и значок у неё не притушен, как у ящиков. */
.spot[data-kind="beast"] { color: var(--danger); }
.spot[data-kind="beast"] svg { color: currentColor; }
.spot[data-kind="beast"].is-on { background: var(--bg-2); }

/* --- ресурсы ---------------------------------------------------------- */

.res {
  display: flex; gap: 4px; justify-content: space-between;
  padding: 4px var(--pad);
  border-top: 1px solid var(--line);
  font-size: 13px;
}
.res__item { display: flex; align-items: center; gap: 5px; color: var(--ink-dim); }
.res__item b { color: var(--ink); font-weight: 700; font-variant-numeric: tabular-nums; }
.res__item svg, .res__item img.ic { width: 15px; height: 15px; display: block; flex: none; }
.res__item.is-zero { opacity: .35; }

/* --- пояс карт (заглушка до этапа 3) ---------------------------------- */

.belt {
  min-height: 66px;
  border-top: 1px solid var(--line);
  background: var(--bg-2);
  display: flex; align-items: center;
  padding: 12px var(--pad);
}
.belt__empty { color: var(--ink-faint); font-size: 13px; line-height: 1.45; }

/* --- нижние вкладки --------------------------------------------------- */

.tabs {
  display: flex; border-top: 1px solid var(--line);
  padding-bottom: var(--safe-b);
  background: var(--bg-2);
}
.tab {
  flex: 1; min-height: var(--tap);
  background: none; border: 0; color: var(--ink-dim);
  font: inherit; font-size: 13px; cursor: pointer;
}
.tab:active { color: var(--accent); }

/* --- шапка внутренних экранов ----------------------------------------- */

.bar {
  display: flex; align-items: center; gap: 4px;
  padding: 4px var(--pad) 4px 4px;
  border-bottom: 1px solid var(--line);
}
.bar__back { width: var(--tap); height: var(--tap); background: none; border: 0; color: var(--ink); font-size: 28px; line-height: 1; cursor: pointer; }
.bar__title { flex: 1; margin: 0; font-size: 16px; font-weight: 700; }
.bar__act { min-width: 64px; min-height: 36px; background: none; border: 0; color: var(--accent); font: inherit; font-size: 13px; cursor: pointer; text-align: right; padding-right: 8px; }

/* --- карта ------------------------------------------------------------ */

.mapwrap {
  flex: 1; position: relative; overflow: hidden; background: #0a0908;
  touch-action: none;              /* pan и pinch обрабатываем сами */
}
#mapCanvas { position: absolute; top: 0; left: 0; }

.maplegend {
  display: flex; flex-wrap: wrap; gap: 10px;
  padding: 8px var(--pad); border-top: 1px solid var(--line);
  font-size: 11px; color: var(--ink-faint);
}
.maplegend span { display: flex; align-items: center; gap: 5px; }
.maplegend i { width: 9px; height: 9px; border-radius: 2px; display: block; }

.routebar {
  padding: 10px var(--pad) calc(10px + var(--safe-b));
  border-top: 1px solid var(--line);
  background: var(--bg-2);
  display: flex; flex-direction: column; gap: 8px;
}
.routebar__info { font-size: 14px; color: var(--ink-dim); }
.routebar__info b { color: var(--ink); }
.routebar__info.is-error { color: var(--danger); }

/* --- дневник ---------------------------------------------------------- */

.journal { flex: 1; overflow-y: auto; padding: var(--pad); padding-bottom: calc(var(--pad) + var(--safe-b)); }
.jentry { padding: 10px 0; border-bottom: 1px solid var(--bg-3); }
.jentry__day { font-size: 11px; text-transform: uppercase; letter-spacing: .1em; color: var(--accent-dk); margin-bottom: 3px; }
.jentry__text { font-size: 15px; color: var(--ink-dim); }

/* --- в пути ----------------------------------------------------------- */

.travel { margin: auto; padding: var(--pad); text-align: center; display: flex; flex-direction: column; align-items: center; gap: 14px; max-width: 360px; }
.travel__mark {
  width: 10px; height: 10px; border-radius: 50%; background: var(--accent);
  animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: .25; transform: scale(.8); } 50% { opacity: 1; transform: scale(1.3); } }
.travel__title { margin: 0; font-size: 22px; }
.travel__eta { color: var(--ink-dim); font-size: 15px; }
.travel__eta b { color: var(--ink); font-variant-numeric: tabular-nums; }
/* Полоса пути. На этапе 12 дорога стала стоить две реальные минуты за
   квартал, и этот экран из пятисекундной заставки превратился в главный на
   ближайший час. Поэтому полоса не прячется за overflow, а несёт на себе
   точку — это ты, и она ползёт. */
.travel__bar { position: relative; width: 100%; height: 3px; background: var(--bg-3); border-radius: 2px; }
.travel__bar i { display: block; height: 100%; background: var(--accent); border-radius: 2px; transform-origin: left; transform: scaleX(0); transition: transform 1s linear; }
.travel__dot {
  position: absolute; top: 50%; left: 0;
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%; background: var(--ink); box-shadow: 0 0 0 3px var(--bg);
  transition: left 1s linear;
}
.travel__where { margin: 0; color: var(--accent); font-size: 17px; }
.travel__at { margin: 0; color: var(--ink-faint); font-size: 13px; font-variant-numeric: tabular-nums; }
.travel__legs { margin: 0; color: var(--ink-faint); font-size: 13px; font-variant-numeric: tabular-nums; }
.travel__note { margin: 0; color: var(--ink-faint); font-size: 13px; }
.travel__hint { margin: 0; color: var(--ink-faint); font-size: 12px; }

/* --- модалка ---------------------------------------------------------- */

.modal { position: fixed; inset: 0; z-index: 50; display: flex; align-items: flex-end; justify-content: center; background: rgba(8,7,6,.7); }
.modal__sheet {
  width: 100%; max-width: var(--shell);
  background: var(--bg-2); border-top: 1px solid var(--line);
  border-radius: 16px 16px 0 0;
  padding: var(--pad); padding-bottom: calc(var(--pad) + var(--safe-b));
  display: flex; flex-direction: column; gap: 12px;
  max-height: 85vh;
  animation: sheet .25s cubic-bezier(.2,.8,.3,1);
}
@keyframes sheet { from { transform: translateY(100%); } }
.modal__title { margin: 0; font-size: 20px; }
.modal__body { overflow-y: auto; font-size: 15px; color: var(--ink-dim); display: flex; flex-direction: column; gap: 10px; }
.rline { border-left: 2px solid var(--bg-3); padding-left: 10px; }
.rline__gain { color: var(--ok); font-size: 13px; }
.rsum { display: flex; gap: 14px; font-size: 13px; color: var(--ink-faint); }
.rsum b { color: var(--ink); }

/* --- всплывашка -------------------------------------------------------- */

.toast {
  position: fixed; left: 50%; bottom: calc(76px + var(--safe-b));
  transform: translateX(-50%);
  background: var(--bg-3); border: 1px solid var(--line);
  color: var(--ink); font-size: 14px;
  padding: 10px 16px; border-radius: 99px; z-index: 60;
  max-width: 88%; text-align: center;
  animation: toast .25s ease;
}
@keyframes toast { from { opacity: 0; transform: translate(-50%, 8px); } }

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: .001s !important; transition-duration: .001s !important; }
}

/* =====================================================================
   ЭТАП 3 — КАРТЫ
   Всё внизу экрана: пояс лежит под большим пальцем, а не под курсором.
   Анимируются только transform и opacity — иначе на телефоне трёхлетней
   давности не будет шестидесяти кадров.
   ===================================================================== */

.beltbar{
  display:flex; align-items:stretch; gap:6px;
  padding:5px 8px calc(6px + env(safe-area-inset-bottom,0px));
  border-top:1px solid var(--line); background:var(--bg-2);
  flex-shrink:0;
}
.belt{
  display:flex; gap:6px; overflow-x:auto; overflow-y:hidden;
  flex:1 1 0; min-width:0; padding:2px 0 4px;
  scroll-snap-type:x proximity; -webkit-overflow-scrolling:touch;
  scrollbar-width:none;
}
.belt::-webkit-scrollbar{display:none}
.belt__empty{color:var(--ink-faint);font-size:12px;align-self:center;padding:0 6px}
.belt__pack{
  flex:0 0 44px; border:1px solid var(--line); border-radius:8px;
  background:var(--bg-3); color:var(--ink-dim); font-size:11px;
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:2px;
}
.belt__pack::before{content:'';width:18px;height:18px;background:currentColor;
  -webkit-mask:var(--pack-mask) center/contain no-repeat;mask:var(--pack-mask) center/contain no-repeat}
:root{--pack-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M5.4 1.8h5.2v2.4H5.4zM3 4.6h10v8.2a1.4 1.4 0 0 1-1.4 1.4H4.4A1.4 1.4 0 0 1 3 12.8zM6.6 7h2.8v1.6H6.6z'/%3E%3C/svg%3E")}

/* --- карта ------------------------------------------------------------ */
/* --- карта --------------------------------------------------------------
   Карта — бумажная, значок — чернильный. Так это и рисуют в туши: тёмное
   по светлому, а не наоборот. И так карта читается как предмет, который
   держат в руке, а не как кнопка в тёмном интерфейсе: пояс тёмный, карты
   на нём светлые, и рука сразу видит, где что.

   Значок и подпись по центру. Левое выравнивание годится для списка, а
   карта — не строка списка: у неё одна мысль, и она посередине. */
.card{
  position:relative; flex:0 0 auto; width:84px; scroll-snap-align:center;
  border:1px solid #0000; border-radius:9px;
  background:var(--plate-resource);
  padding:5px 5px 6px; text-align:center; color:var(--paper-ink);
  display:flex; flex-direction:column; gap:4px;
  transition:transform .12s ease, opacity .12s ease;
  will-change:transform;
  box-shadow:0 1px 2px rgba(0,0,0,.45);
}
.card:active{transform:translateY(-6px) scale(1.03)}

/* Погашенная карта не просто бледнеет: она уходит в цвет пояса, как будто
   её отложили. Просто opacity на светлой карте поверх тёмного фона даёт
   грязь, а не «нельзя». */
.card.is-off{ filter:grayscale(.85) brightness(.62); opacity:.7 }

/* Обводка = «сработает по выбранной цели». Выбрал ящик — обвелись обыск,
   лом и отмычка; выбрал воду — фляга. Ответ на «чем это брать» виден
   раньше, чем успеваешь задать вопрос. Порядок карт при этом НЕ меняется:
   место карты — то, что палец запоминает первым. */
.card.is-ready{
  box-shadow:0 0 0 2px var(--accent), 0 2px 10px rgba(200,168,106,.35);
}
.card.is-ready::after{
  content:''; position:absolute; inset:-4px; border-radius:12px;
  border:1px solid var(--accent); opacity:.5;
  animation:cardpulse 1.9s ease-in-out infinite;
}
@keyframes cardpulse{0%,100%{opacity:.12}50%{opacity:.7}}

.card__art{
  height:40px; border-radius:6px;
  display:flex; align-items:center; justify-content:center; overflow:hidden;
  position:relative;
}
.card__art img{width:100%;height:100%;object-fit:cover}
/* Значок — не арт: он ложится поверх плашки и не закрывает её. Размер задан
   долей, чтобы в поясе, в рюкзаке и в листе он вёл себя одинаково. */
.card__art img.is-icon{width:74%;height:74%;object-fit:contain}
.card__art svg{width:26px;height:26px;color:var(--paper-ink)}
.card__art img.ic{width:26px;height:26px}

.card__name{
  font-size:10px;line-height:1.12;letter-spacing:-.01em;
  color:var(--paper-ink); font-weight:600;
  overflow:hidden;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  min-height:22px
}

/* Метки на карте — чернильные штампики: светлое по тёмному внутри тёмного
   по светлому. Сами по себе мелкие, и только так их видно на бумаге. */
.card__lvl,.card__cost,.card__count{
  position:absolute;font-size:9px;font-weight:700;line-height:1.5;
  background:var(--paper-ink);color:var(--plate-resource);
  border-radius:3px;padding:0 3px
}
.card__lvl{top:4px;right:5px;color:var(--accent)}
/* Число припасов и цена — обе в правом нижнем углу САМОЙ КАРТЫ. Вместе они
   не встречаются: у припаса нет цены, у карты с ценой нет числа. */
.card__cost{bottom:4px;right:5px;display:flex;align-items:center;gap:2px}
.card__cost svg,.card__cost img.ic{width:9px;height:9px}
.card__count{bottom:4px;right:5px;font-size:13px;padding:0 6px;line-height:1.35}

/* Цвет бумаги — по типу карты, выставляется сам. Рисовать фон на значке или
   арте не нужно: тип решает, на какой бумаге предмет лежит. Эти же значения
   перечислены в ART.md §3.1. */
:root{
  --paper-ink:        #14120f;
  --plate-skill:      #dfe3d6;
  --plate-gear:       #e9dcc6;
  --plate-conditional:#dcdde6;
  --plate-knowledge:  #efe6c9;
  --plate-resource:   #dcd7cd;
  /* Рана — бумага не цветная, а бурая: её ни с чем не спутаешь в поясе, и
     смотреть на неё неприятно ровно настолько, насколько надо. */
  --plate-wound:      #c9b0a4;
  --plate-consumable: #e4e7dd;
}
.card--type-skill       { background:var(--plate-skill) }
.card--type-gear        { background:var(--plate-gear) }
.card--type-conditional { background:var(--plate-conditional) }
.card--type-knowledge   { background:var(--plate-knowledge) }
.card--type-resource    { background:var(--plate-resource) }
.card--type-wound       { background:var(--plate-wound) }
.card--type-consumable  { background:var(--plate-consumable) }
/* Рана не гаснет как «нельзя сыграть»: она не действие, она состояние.
   Погашенная, она терялась бы среди неподходящих карт. */
.card--type-wound.is-off{ filter:none; opacity:1 }
.card--type-wound::after{
  content:''; position:absolute; inset:0; border-radius:9px; pointer-events:none;
  box-shadow:inset 0 0 0 1px rgba(90,30,20,.5);
}
.card--type-skill       .card__lvl,.card--type-skill       .card__cost,.card--type-skill       .card__count{color:var(--plate-skill)}
.card--type-gear        .card__lvl,.card--type-gear        .card__cost,.card--type-gear        .card__count{color:var(--plate-gear)}
.card--type-conditional .card__lvl,.card--type-conditional .card__cost,.card--type-conditional .card__count{color:var(--plate-conditional)}
.card--type-knowledge   .card__lvl,.card--type-knowledge   .card__cost,.card--type-knowledge   .card__count{color:var(--plate-knowledge)}
.card--type-resource    .card__lvl,.card--type-resource    .card__cost,.card--type-resource    .card__count{color:var(--plate-resource)}
.card--type-wound       .card__lvl,.card--type-wound       .card__cost,.card--type-wound       .card__count{color:var(--plate-wound)}
.card--type-consumable  .card__lvl,.card--type-consumable  .card__cost,.card--type-consumable  .card__count{color:var(--plate-consumable)}
.card .card__lvl{color:var(--accent)}

/* Сломанная карта — выцветшая бумага с трещиной наискось. Одного обесцвечивания
   мало: на экране рюкзака половина карт и так приглушена, и «сломано» терялось
   среди «не здесь». Трещина видна с любого расстояния и ни с чем не путается. */
.card.is-broken{filter:grayscale(1) brightness(.78) contrast(.9)}
.card.is-broken::before{
  content:''; position:absolute; inset:0; border-radius:9px; pointer-events:none;
  background:linear-gradient(115deg,transparent 46%,var(--paper-ink) 46%,var(--paper-ink) 48%,
             transparent 48%,transparent 52%,var(--paper-ink) 52%,var(--paper-ink) 54%,transparent 54%);
  opacity:.5;
}

/* --- соединение карт (§4.8а) -------------------------------------------- */

/* Режим включается кнопкой в шапке рюкзака и гаснет сам, как только пара
   сведена. Постоянно жить в нём незачем: соединять нечего девяносто девять
   заходов из ста. */
.craftbar{
  display:flex;align-items:center;gap:10px;
  padding:8px 12px;border-bottom:1px solid var(--line);background:var(--bg-2);
}
.craftbar__hint{flex:1;margin:0;font-size:12px;line-height:1.35;color:var(--ink-dim)}
.craftbar__off{flex:0 0 auto;padding:6px 10px;font-size:12px}

/* В режиме соединения карта либо участвует, либо нет. Полутонов здесь быть не
   должно: игрок ищет пару, а не читает состояние колоды. */
.is-crafting .cardgrid .card{opacity:.32;filter:grayscale(1)}
.is-crafting .cardgrid .card.can-craft{opacity:1;filter:none}
.is-crafting .cardgrid .card.is-picked{
  opacity:1;filter:none;
  box-shadow:0 0 0 2px var(--accent),0 4px 14px rgba(200,168,106,.4);
  transform:translateY(-3px);
}
.card.can-craft::after{
  content:''; position:absolute; inset:-3px; border-radius:11px;
  border:1px dashed var(--accent); opacity:.55; pointer-events:none;
}

/* Вспышка на месте сведённой пары: две карты сошлись — и осталась одна. */
.card.is-merged{animation:merge .5s ease-out}
@keyframes merge{
  0%{transform:scale(.86);filter:brightness(2.4)}
  55%{transform:scale(1.06);filter:brightness(1.3)}
  100%{transform:none;filter:none}
}

/* --- рюкзак ------------------------------------------------------------ */
.packwrap{flex:1 1 0;min-height:0;overflow-y:auto;padding:10px 12px 20px}
.packgroup{margin-bottom:18px}
.packgroup__t{font-size:11px;letter-spacing:.08em;text-transform:uppercase;
  color:var(--ink-dim);margin:0 0 8px;display:flex;justify-content:space-between}
.packgroup__t b{color:#c8a86a;font-weight:500}
.cardgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(84px,1fr));gap:8px}
.cardgrid .card{width:auto}
.cardgrid--res .card__art{height:36px}

/* --- лист карты --------------------------------------------------------- */
.sheet{position:fixed;inset:0;z-index:40;display:flex;flex-direction:column}
.sheet__pad{flex:1 1 auto;background:#0a0908aa}
.sheet__body{
  background:var(--bg-2);border-top:1px solid var(--line);
  border-radius:14px 14px 0 0; padding:14px 16px calc(18px + env(safe-area-inset-bottom,0px));
  animation:sheetup .18s ease-out;
}
@keyframes sheetup{from{transform:translateY(18px);opacity:0}to{transform:none;opacity:1}}
.sheet__head{display:flex;gap:12px;align-items:flex-start}
.sheet__art{flex:0 0 78px;height:78px;border-radius:8px;background:var(--plate-gear);
  display:flex;align-items:center;justify-content:center;overflow:hidden}
.sheet__art img{width:100%;height:100%;object-fit:cover}
.sheet__art img.is-icon{width:64%;height:64%;object-fit:contain}
.sheet__art svg{width:38px;height:38px;color:var(--paper-ink)}
.sheet__art img.ic{width:38px;height:38px}
.sheet__title{font-size:17px;margin:0 0 2px}
.sheet__kind{font-size:11px;color:var(--ink-dim);letter-spacing:.04em}
.sheet__text{font-size:13px;color:var(--ink-dim);margin:10px 0 0;line-height:1.5}
.sheet__meta{display:flex;flex-wrap:wrap;gap:6px;margin-top:10px}
.chip{font-size:11px;color:var(--ink-dim);border:1px solid var(--line);
  border-radius:20px;padding:2px 9px;display:flex;align-items:center;gap:4px}
.chip svg,.chip img.ic{width:11px;height:11px}
.chip--warn{color:#c8a86a;border-color:#4a3f2a}
.sheet__acts{display:flex;gap:8px;margin-top:14px;flex-wrap:wrap}
.sheet__acts .btn{flex:1 1 40%}

/* --- находки ------------------------------------------------------------ */
.finds{display:flex;flex-direction:column;gap:8px}
.find{display:flex;align-items:center;gap:10px;font-size:13px}
/* Нарисованный значок вместо встроенного (§9.8 ASSETS). Размер ему задаёт
   место, в котором он стоит, — те же пары `svg, img.ic` ниже; здесь только
   общее: картинка вписывается в отведённый квадрат, а не растягивается. */
img.ic{object-fit:contain}
.find__ic{flex:0 0 30px;height:30px;border-radius:6px;background:var(--plate-resource);
  display:flex;align-items:center;justify-content:center}
.find__ic svg,.find__ic img.ic{width:17px;height:17px;color:var(--paper-ink)}
.find__zone{margin-left:auto;font-size:11px;color:var(--ink-faint)}
.find--none{color:var(--ink-faint);font-style:italic}
/* Сколько вещей лежит в куче — числом у цели, а не словом. */
.spot__tag--n{background:var(--accent);color:#14120f;font-weight:700;
  border-radius:3px;padding:0 5px}
/* Сломалось — последней строкой в том же списке: сперва что нашёл, потом чем
   за это заплатил. Отдельным окном поверх окна это читалось бы как авария. */
.find--broke{color:#c06a5a;border-top:1px solid var(--line);padding-top:8px;margin-top:2px}
.find--broke .find__zone{color:#c06a5a}
.readnote{font-size:14px;line-height:1.6;color:var(--ink);
  border-left:2px solid #4a3f2a;padding:2px 0 2px 12px;margin:4px 0}

/* =====================================================================
   ГЛУБИНА

   Художник рисует все три слоя одинаково контрастно — иначе каждую новую
   картинку пришлось бы подгонять к соседям вручную. Воздух между планами
   ставит движок, и потому он одинаков во всей игре.

   Работает как в природе: чем дальше, тем ниже контраст и тем ближе цвет к
   цвету воздуха. Плюс дымка у горизонта — там, где дальше всего.

   Всё держится на transform/opacity и композитных слоях, попиксельной
   работы нет: на телефоне это бесплатно.
   ===================================================================== */

:root{
  --depth-color: 90,96,112;   /* цвет воздуха. Холодный — он отодвигает */
  --depth-veil: .42;          /* насколько даль уведена в этот цвет */
  --depth-haze: .78;          /* дымка у самого горизонта */
  --depth-punch: 1.22;        /* ближний план — самый резкий в кадре */
  --depth-feather: 0%;        /* растушёвка верхнего края земли. Ноль: если арт
                                 выровнен по линии горизонта, стыка нет. Поднимать
                                 только если на стыке видна линейка */
  --horizon: 58%;
}

.view__veil, .view__haze{
  position:absolute; inset:0; pointer-events:none;
}
/* Ровная вуаль поверх дали: и небо, и силуэты уходят в цвет воздуха. */
.view__veil{
  z-index:2;
  background: rgb(var(--depth-color));
  opacity: var(--depth-veil);
}
/* Дымка. Резкий пик у горизонта и быстрый спад вниз: под ногами воздуха нет. */
.view__haze{
  z-index:4;
  background: linear-gradient(to bottom,
    rgba(var(--depth-color), 0) 16%,
    rgba(var(--depth-color), var(--depth-haze)) var(--horizon),
    rgba(var(--depth-color), 0) 68%);
}

#layerFar    { z-index: 1; }
#layerGround { z-index: 3; }
#layerMid    { z-index: 5; filter: contrast(var(--depth-punch)); }
#viewGrade   { z-index: 6; }

/* Верхний край земли. Пока планы были одного тона, стык не читался; как
   только даль ушла в холод — проступил линейкой. */
#layerGround{
  -webkit-mask-image: linear-gradient(to bottom,
    transparent calc(var(--horizon) - 1px),
    #000 calc(var(--horizon) + var(--depth-feather)));
  mask-image: linear-gradient(to bottom,
    transparent calc(var(--horizon) - 1px),
    #000 calc(var(--horizon) + var(--depth-feather)));
}


/* =====================================================================
   ВНУТРИ ТЕМНЕЕ

   Интерьеры рисуются тем же чёрным по белому, что и улица: заводить второй
   стиль ради шести файлов — значит заводить второй стиль. Разницу делает свет.

   Внутри меньше света, а меньше света значит не только темнее, но и ниже
   контраст: глазу не за что зацепиться. Поэтому вместе с затемнением слегка
   гасим и контраст — без этого получается просто прикрученная яркость.
   ===================================================================== */

:root{
  --env-dark-indoor: .36;
  --env-dark-under: .58;
  --env-flat-indoor: .88;   /* контраст */
  --env-flat-under: .76;
}

.view__env{
  position:absolute; inset:0; z-index:6; pointer-events:none;
  background:#0a0c10; opacity:0;
  transition:opacity .35s ease;
}
.view[data-env="indoor"] .view__env{ opacity: var(--env-dark-indoor); }
.view[data-env="underground"] .view__env{ opacity: var(--env-dark-under); }

/* Контраст снимаем с самих слоёв: накладывать его поверх нечем. */
.view[data-env="indoor"] #layerFar,
.view[data-env="indoor"] #layerGround{ filter: contrast(var(--env-flat-indoor)); }
.view[data-env="indoor"] #layerMid{
  filter: contrast(calc(var(--depth-punch) * var(--env-flat-indoor)));
}
.view[data-env="underground"] #layerFar,
.view[data-env="underground"] #layerGround{ filter: contrast(var(--env-flat-under)); }
.view[data-env="underground"] #layerMid{
  filter: contrast(calc(var(--depth-punch) * var(--env-flat-under)));
}

#viewGrade { z-index: 7; }
/* Небо (§15.1) ложится поверх света и под компас: пелена не должна накрывать
   стрелки поворота — по ним ходят. */
.view__sky { z-index: 8; }
.view__compass, .view__ahead { z-index: 9; }

/* =====================================================================
   ЭТАП 3б — правки по игре на живом телефоне
   ===================================================================== */

/* --- никакого выделения текста в игре --------------------------------
   Долгое нажатие на карту в поясе открывает лист, и по дороге браузер
   успевал выделить надпись на кнопке под пальцем. Играем пальцем, а не
   читаем — выделение тут только мешает. Полям ввода оно, наоборот,
   необходимо. */
.app, .sheet, .modal {
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none;
}
input, textarea, .linkbox__url { -webkit-user-select: text; user-select: text; }

/* --- кадр: квадрат, и обрезается снизу -------------------------------
   Было: высота 40dvh при полной ширине, картинка квадратная — и cover
   срезал ей верх, то есть небо и силуэт города, ради которых слой и
   рисуется. Теперь кадр держит квадрат, а когда экран короткий и квадрат
   не влезает, обрезается НИЗ: у земли отнять ближний метр безболезненно,
   у неба — нет.

   Доля поднята с 40 до 56 процентов высоты, а всё, что ниже, поджато —
   об этом следующий блок. */
.view {
  height: auto;
  aspect-ratio: 1 / 1;
  max-height: 52dvh;
}

/* Экрану клетки нужна ЖЁСТКАЯ высота, а не только минимальная: иначе колонка
   растёт под содержимое, и нижние вкладки честно уезжают за край экрана —
   а список целей, который для того и растяжимый, так и не начинает
   прокручиваться. */
.screen--cell { height: 100dvh; max-height: 100dvh; }

/* Кадр — единственное, что уступает место, и уступает последним. Проценты
   высоты подбирать под каждый телефон бессмысленно: пусть кадр берёт
   квадрат, если квадрат влезает, и сжимается ровно настолько, насколько
   не влезает. Срезается при этом низ — см. object-position выше. */
.screen--cell > .view { flex: 0 1 auto; min-height: 30dvh; }
.view__canvas, .view__layer { object-position: center top; }

/* --- поджимаем всё, что ниже кадра ------------------------------------
   Каждые несколько пикселей отсюда — это несколько пикселей картинки,
   которые не придётся срезать. Ничего не выкинуто: строки стали плотнее. */
/* Описание стороны — РОВНО две строки, всегда. Плавающая высота двигала
   кадр при каждом повороте: город будто дышал. Длинное обрезается
   многоточием, весь текст всё равно про то, что и так нарисовано. */
.sidetext {
  padding: 5px var(--pad); font-size: 12.5px; line-height: 1.34;
  height: calc(2 * 1.34em + 10px); overflow: hidden;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
}
/* Список целей — ПОСТОЯННОЙ высоты, чуть больше двух строк. Растяжимым он
   быть не может: на разных сторонах одной клетки объектов разное число, и
   кадр прыгал бы при каждом повороте. Третья строка видна краем — этого
   хватает, чтобы понять, что список продолжается. */
.screen--cell > .spots { flex: 0 0 auto; height: 92px; min-height: 0; }
.spot { min-height: 40px; gap: 9px; }
.res { padding: 3px var(--pad); font-size: 12px; }
.beltbar { padding: 8px 10px; }
.tab { min-height: 40px; }

/* --- плашки и стрелки поверх кадра -----------------------------------
   Арт монохромный и светлый сверху, тёмный снизу: белый текст пропадает
   на небе, тёмный — в проёмах. Подложка решает это раз и навсегда, а не
   подбором цвета под каждую картинку. */
.view__ahead {
  top: 10px;
  background: rgba(10, 9, 8, .78);
  border: 1px solid rgba(230, 221, 208, .14);
  color: var(--ink);
  font-size: 12.5px;
  padding: 4px 12px;
  backdrop-filter: blur(3px);
}
.view__compass { padding: 8px 8px; }
.compass__dir {
  background: rgba(10, 9, 8, .78);
  border: 1px solid rgba(230, 221, 208, .14);
  border-radius: 99px;
  padding: 5px 14px;
  backdrop-filter: blur(3px);
}
.compass__arrow {
  width: 40px; height: 40px;
  border-radius: 99px;
  background: rgba(10, 9, 8, .78);
  border: 1px solid rgba(230, 221, 208, .14);
  opacity: 1;
  backdrop-filter: blur(3px);
  display: flex; align-items: center; justify-content: center;
  padding-bottom: 3px;              /* шеврон рисуется выше базовой линии */
}
.compass__arrow:active { background: rgba(200, 168, 106, .3); transform: scale(.92); }

/* --- шкалы нужд: буква, полоса, число --------------------------------- */
.hud__needs { gap: 12px; align-items: center; }
.need { display: flex; align-items: center; gap: 5px; height: auto; background: none; border-radius: 0; }
.need__l { font-size: 10px; letter-spacing: .04em; color: var(--ink-faint); width: 9px; flex: none; }
.need__bar {
  flex: 1; height: 4px; background: var(--bg-3); border-radius: 2px;
  overflow: hidden; position: relative;
}
.need b {
  display: block; font-size: 11px; font-weight: 600; width: 20px; flex: none;
  text-align: right; color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
.need.is-high b { color: var(--danger); }

/* --- экран создания: шапка и подвал прибиты ---------------------------
   Экрану нужна ЖЁСТКАЯ высота: с одним min-height колонка растёт под
   содержимое, и подвал честно оказывается за нижним краем — прокрутке
   внутри списка тогда неоткуда взяться. */
.screen--create { height: 100dvh; max-height: 100dvh; }
.screen--create .pane { min-height: 0; }
.pane--locked { gap: 10px; min-height: 0; }
.pane--locked .pane__top { flex: none; }
.pane--locked .pane__scroll {
  flex: 1 1 auto; min-height: 96px; overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  /* Тень у нижней кромки говорит, что список продолжается. */
  mask-image: linear-gradient(to bottom, #000 calc(100% - 18px), transparent);
}
.pane--locked .pane__foot { flex: none; margin-top: 0; }
.pane--locked .pane__foot-row {
  display: flex; align-items: center; gap: 10px;
}
.pane--locked .pane__foot-row .langpick { margin-left: auto; }

/* --- споты: разобранное и расслышанное -------------------------------- */
.spot__tag {
  margin-left: auto; flex: none;
  font-size: 10px; text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-faint); border: 1px solid var(--bg-3);
  border-radius: 99px; padding: 2px 7px;
}
/* Разобранный объект гасим целиком, но оставляем нажимаемым: по нему ещё
   играют отмычкой и ломом. */
.spot.is-done { color: var(--ink-faint); }
.spot.is-done svg, .spot.is-done img.ic { opacity: .45; }
.spot.is-done.is-on { color: var(--ink-dim); }

/* --- карта, которой сейчас работают ----------------------------------- */
/* Карта, которой сейчас работают, притушена целиком — вместе с подписью,
   значком и рамкой: пока идёт отсчёт, она не кнопка. Цифра крупная и
   чернильная, поверх приглушённой бумаги, и видна через весь пояс. */
.card.is-running { filter: brightness(.72) saturate(.55); }
.card.is-running .card__art,
.card.is-running .card__name { opacity: .22; }
.card__timer {
  position: absolute; inset: 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 34px; line-height: 1; font-weight: 800;
  color: var(--paper-ink); opacity: 1;
  font-variant-numeric: tabular-nums;
}
.card.is-running { animation: busy 1s ease-in-out infinite; }
@keyframes busy { 50% { border-color: var(--accent); } }

/* --- лист карты по центру экрана --------------------------------------
   Снизу он оказывался ровно под пальцем, которым его и открыли: палец
   закрывал половину, а долгое нажатие норовило попасть в кнопку. */
.sheet { justify-content: center; align-items: center; padding: var(--pad); }
.sheet__pad { position: absolute; inset: 0; flex: none; }
.sheet__body {
  position: relative;
  width: 100%; max-width: 420px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  max-height: 80dvh; overflow-y: auto;
}
.sheet__row { display: flex; align-items: baseline; gap: 8px; }
.sheet__stars {
  margin-left: auto; flex: none; font-size: 12px; letter-spacing: .04em;
  color: var(--ink-faint);
}
.sheet__stars b { color: var(--accent); font-weight: 400; }
.sheet__passive {
  margin: 10px 0 0; padding: 9px 11px;
  background: var(--bg-3); border-radius: 8px;
  font-size: 13px; line-height: 1.45; color: var(--ink-dim);
}

/* --- ожидание после дороги -------------------------------------------- */
.travel__arriving {
  display: none; align-items: center; justify-content: center; gap: 9px;
  font-size: 14px; color: var(--ink-dim);
}
.screen--travel.is-arriving .travel__arriving { display: flex; }
.screen--travel.is-arriving .travel__eta { display: none; }
.spinner {
  width: 15px; height: 15px; flex: none;
  border: 2px solid var(--bg-3); border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Зеркальные даль и земля. Переворот делает игра, не художник: обе плоскости
   во всю ширину, у обеих нет своей стороны, и отражение читается как другое
   место. Двадцать одна картинка превращается в сорок две даром. */
.view__layer.is-flipped { transform: scaleX(-1); }

/* =====================================================================
   ЭТАП 3Б — ТАКТИЛЬНОСТЬ

   Анимируются только transform и opacity. Всё остальное на телефоне
   вызывает перекомпоновку и роняет кадры (§4.9).
   ===================================================================== */

/* --- карты разлетаются в руку ------------------------------------------ */
.card.is-dealt { animation: deal .26s cubic-bezier(.2, .9, .3, 1) backwards; }
@keyframes deal {
  from { opacity: 0; transform: translateY(26px) rotate(-4deg) scale(.94); }
  to   { opacity: 1; transform: none; }
}

/* --- счётчик припасов щёлкает ------------------------------------------ */
.res__item.is-tick { animation: tick .5s ease; }
.res__item.is-tick b { color: var(--accent); }
@keyframes tick {
  30% { transform: translateY(-4px) scale(1.14); }
  to  { transform: none; }
}

/* --- смахивание вниз ---------------------------------------------------- */
.modal__sheet, .sheet__body { will-change: transform; }

/* --- кто не любит анимаций --------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .card.is-dealt, .res__item.is-tick, .card.is-running, .card.is-ready::after { animation: none; }
}

/* Ориентир в плашке над кадром. Соседняя клетка — это «куда шагну»,
   ориентир — «куда иду», и второе важнее: его видно за десять кварталов и
   к нему идут полчаса. Поэтому он подсвечен, а не просто подписан. */
.view__ahead.is-beacon {
  color: var(--accent);
  border-color: rgba(200, 168, 106, .45);
  letter-spacing: .02em;
}


/* --- сон и смерть (этап 5) ---------------------------------------------- */

.screen--rest, .screen--death{ justify-content:center }
.rest, .death{ padding:0 22px; text-align:center; max-width:420px; margin:0 auto }
.rest__t{ font-size:22px; margin:0 0 6px }
.rest__where{ color:var(--ink-dim); font-size:13px; margin:0 0 20px }
.rest__eta{ font-size:34px; font-variant-numeric:tabular-nums; color:var(--accent); margin-bottom:6px }
.rest__at{ margin:0 0 18px; color:var(--ink-faint); font-size:13px; font-variant-numeric:tabular-nums }
.rest__close{ margin:14px 0 0; color:var(--ink-faint); font-size:13px }
.rest__note{ color:var(--ink-faint); font-size:12px; line-height:1.5; margin:0 }

/* Смерть — экран, а не окошко поверх игры: делать вид, что под ним всё ещё
   идёт партия, было бы неправдой. */
.death__t{ font-size:24px; margin:0 0 4px }
.death__days{ color:var(--ink-dim); font-size:13px; margin:0 0 18px }
.death__cause{
  font-size:18px; color:#c06a5a; margin:0 0 18px;
  padding:10px 0; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
}
.death__last{ font-style:italic; color:var(--ink-dim); font-size:14px; line-height:1.55; margin:0 0 18px }
.death__note{ color:var(--ink-faint); font-size:12px; line-height:1.5; margin:0 0 24px }
.death__acts{ display:flex; flex-direction:column; gap:8px }


/* --- клетка ориентира (§5.5.4) ------------------------------------------ */

/* Сторон света у подножия нет: стрелки поворота убираются совсем, а не
   гасятся. Погашенная стрелка — это обещание, что когда-нибудь она заработает;
   здесь она не заработает никогда. */
.screen--cell.is-at-landmark [data-turn] { display: none }
.screen--cell.is-at-landmark .compass__dir {
  color: var(--accent); letter-spacing: .04em;
}
/* Имя ориентира вместо имени соседней клетки — всегда акцентом: ты пришёл
   именно сюда, и место должно себя назвать. */
.screen--cell.is-at-landmark .view__ahead { color: var(--accent) }

/* Ориентир в списке «что видно сверху» — не добыча, а направление. */
.find--lm .find__ic { color: var(--accent) }
.find--lm .find__zone { color: var(--ink-dim) }


/* --- стычка (§8) --------------------------------------------------------- */

/* Здесь стояло `.screen--fight { display: flex }`. Оно было лишним (колонка
   и так задана в `.screen`) и вдобавок перебивало `display: none` базового
   правила — экран стычки висел развёрнутым НА СТО ПРОЦЕНТОВ ВЫСОТЫ всегда,
   а всё, что лежит в разметке после него (событие, сон, смерть, дорога),
   уезжало на экран вниз. Тесты этого не видели: Playwright сам прокручивает
   до элемента перед кликом, а проверки читали DOM, а не картинку. */

/* Экран стычки стоит на кадре клетки, а не на чёрном. Драка в пустоте
   отнимала место: не видно ни улицы, ни того, что ты под землёй, — а район
   и среда в драке значат много. Кадр берётся тот же самый, клонированный:
   второго набора картинок для этого не нужно. */
.screen--fight { position: relative }
.fightbg { position: absolute; inset: 0; z-index: 0; overflow: hidden; pointer-events: none }
.fightbg .view {
  width: 100%; height: 100%; max-height: none; min-height: 0; aspect-ratio: auto;
  /* Размытие небольшое: фон должен читаться как место, а не превращаться в
     абстрактное пятно. Увеличение — чтобы край размытия не обнажал подложку. */
  /* Четыре пикселя, а не два: на среднем плане бывают надписи, и читаемая
     надпись за спиной твари уводит взгляд с твари. */
  filter: blur(4px) saturate(.6);
  transform: scale(1.08);
}
/* Затемнение неровное, и темнее всего — ЗА ТВАРЬЮ. Ровная вуаль оставляла
   силуэт серым пятном на серой стене: место читалось, противник — нет.
   Низ, наоборот, отпущен: там карты, они и так светлые. */
.fightbg::after {
  content: ''; position: absolute; inset: 0;
  background:
    radial-gradient(62% 30% at 50% 32%, rgba(10,9,8,.88), rgba(10,9,8,0) 72%),
    radial-gradient(130% 80% at 50% 46%, rgba(10,9,8,.55), rgba(10,9,8,.9) 78%);
}
.screen--fight > *:not(.fightbg) { position: relative; z-index: 1 }

/* Противник занимает верх экрана, рука — низ, как и в клетке. Палец знает,
   где карты, и в драке переучиваться ему некогда. */
.foe {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 0 20px; text-align: center; gap: 4px;
}
/* Тень под силуэтом отделяет его от кадра позади. Без неё тварь на светлой
   стене пропадала — а она здесь главное, на что смотрят. */
.foe__art {
  width: 140px; height: 140px; color: var(--ink); margin-bottom: 8px;
  filter: drop-shadow(0 2px 22px rgba(8,7,6,.95));
}
.foe__art svg, .foe__art img { width: 100%; height: 100%; object-fit: contain }
.foe__name { font-size: 19px; margin: 0 }
.foe__about { font-size: 12px; color: var(--ink-faint); margin: 0 0 8px; line-height: 1.4 }

/* Устойчивость — не здоровье, а счётчик ударов, которые тварь ещё держит.
   Цифра рядом с полоской: «ещё два» надо читать точно, а не на глаз. */
/* Число над полоской, а не сбоку: сбоку оно упиралось в край экрана и
   обрезалось ровно тогда, когда на него надо смотреть. */
.foe__resist {
  width: 190px; height: 7px; border-radius: 4px; background: var(--bg-3);
  overflow: visible; position: relative; margin-top: 16px;
}
.foe__resist i {
  display: block; height: 100%; border-radius: 4px; background: #b8604e;
  transform-origin: left center; transition: transform .25s ease;
}
.foe__resist::after {
  content: attr(data-n); position: absolute; right: 0; top: -17px;
  font-size: 11px; color: var(--ink-faint); font-variant-numeric: tabular-nums;
}
.foe__resist::before {
  content: ''; position: absolute; inset: 0; border-radius: 4px;
  box-shadow: inset 0 0 0 1px var(--line);
}

/* Намерение — единственное, на чём держится тактика, поэтому оно крупное. */
.foe__intent {
  margin: 18px 0 0; font-size: 15px; color: var(--ink-dim); min-height: 22px;
}
.foe__intent.is-danger { color: #e0a08c; font-weight: 600 }
.foe__intent.is-pierce::after { content: ' ⟋'; color: #c06a5a }

/* Раны за эту драку — точками: их мало, и считать их глазами быстрее. */
.hurt { display: flex; gap: 7px; justify-content: center; padding: 10px 0 2px }
.hurt__dot {
  width: 9px; height: 9px; border-radius: 50%;
  border: 1px solid var(--line); background: transparent;
}
.hurt__dot.is-on { background: #c06a5a; border-color: #c06a5a }

.fight__log {
  text-align: center; font-size: 12px; color: var(--ink-faint);
  margin: 4px 0 8px; min-height: 16px;
}

.hand {
  display: flex; gap: 7px; overflow-x: auto; padding: 8px 12px calc(14px + env(safe-area-inset-bottom,0px));
  scrollbar-width: none;
}
.hand::-webkit-scrollbar { display: none }
/* Пять карт должны поместиться в ширину телефона: иначе рука выглядит
   обрезанной, а не прокручиваемой, и игрок не догадается её листать. */
.hand .card { flex: 0 0 68px }
.hand .card__name { font-size: 9px }

/* Сколько ударит или удержит — числом на карте, с оружием и курткой уже
   посчитанными. В уме это считать некогда. */
.card__pow {
  position: absolute; top: 4px; left: 5px;
  font-size: 12px; font-weight: 700; line-height: 1.4; padding: 0 5px;
  border-radius: 3px; background: #b8604e; color: #14120f;
}
.card__pow--def { background: #7f93a8 }


/* --- слух (§8.1) --------------------------------------------------------- */

/* Что слышно в эту сторону — точками у компаса. Не цифрой: густота звука
   читается взглядом, а цифра требует её прочесть. */
.ear { display: inline-flex; gap: 3px; margin-left: 8px; vertical-align: middle }
.ear__dot {
  width: 5px; height: 5px; border-radius: 50%;
  border: 1px solid var(--line); background: transparent;
}
.ear__dot.is-on { background: #d98b62; border-color: #d98b62 }
/* Показание прошлой эпохи — не ложь, но и не новость. */
.ear.is-stale { opacity: .45 }

/* Главное в «Оглядеться» — не список замков, а сколько их рядом. Поэтому
   строка про звук стоит первой и крупнее всего остального в окне. */
.hearline {
  margin: 0 0 4px; font-size: 16px; line-height: 1.4; color: var(--ink);
}
.hearline.is-loud { color: #e0a08c; font-weight: 600 }
.hearwhere { margin: 0 0 6px; font-size: 12px; color: var(--ink-faint) }


/* --- текстовые события (§9) ---------------------------------------------- */

.screen--event { overflow-y: auto }
.evwrap { padding: 22px 18px calc(24px + env(safe-area-inset-bottom,0px)); max-width: 460px; margin: 0 auto }
.ev__title { font-size: 20px; margin: 0 0 14px; line-height: 1.25 }
.ev__text { font-size: 15px; line-height: 1.6; color: var(--ink-dim); margin: 0 0 18px }

/* Исход прошлого шага остаётся над новым текстом: история из двух шагов
   должна читаться как история, а не как две карточки подряд. */
.ev__result {
  font-size: 14px; line-height: 1.55; font-style: italic;
  color: var(--ink-faint); margin: 0 0 16px;
  padding-left: 12px; border-left: 2px solid var(--line);
}

.ev__opts { display: flex; flex-direction: column; gap: 9px }

/* Недоступный вариант НЕ ПРЯЧЕТСЯ. Игрок должен видеть, что здесь можно было
   бы сделать ломом, — иначе он не узнает, что лом стоило взять. */
.evopt {
  display: flex; flex-direction: column; gap: 5px; align-items: flex-start;
  width: 100%; text-align: left; cursor: pointer;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius);
  color: var(--ink); font: inherit; padding: 13px 15px;
  transition: border-color .12s ease, transform .08s ease;
}
.evopt:active:not(:disabled) { transform: scale(.99); border-color: var(--accent) }
.evopt.is-off { opacity: .5; cursor: default }
.evopt__t { font-size: 15px; line-height: 1.35 }
.evopt__bits { display: flex; flex-wrap: wrap; gap: 6px }
.evopt__need {
  display: inline-flex; align-items: center; gap: 3px;
  font-size: 11px; color: var(--accent);
  border: 1px solid var(--line); border-radius: 4px; padding: 1px 6px;
}
.evopt__need svg, .evopt__need img.ic { width: 11px; height: 11px }
.evopt__why { font-size: 11px; color: #c06a5a }

/* --- качества (§11) ------------------------------------------------------ */

/* Числа нет и не будет: игрок видит только ярлык, и только когда ступень
   перейдена. Число он начал бы набивать, а качество — не цель, а след. */
.qual { display: flex; flex-direction: column; gap: 10px; padding: 4px 0 }
.qual__row { display: flex; flex-direction: column; gap: 2px }
.qual__name { font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--ink-faint) }
.qual__label { font-size: 14px; line-height: 1.45; color: var(--ink-dim); font-style: italic }


/* --- дневник: вкладки и экспедиции (§15.2) ------------------------------ */

/* Две вкладки одного экрана: своя жизнь и чужие. Разводить их по разным
   экранам незачем — и то и другое читают, а не играют. */
.jtabs {
  display: flex; gap: 6px; padding: 8px 14px 0;
  flex: 0 0 auto;
}
.jtab {
  flex: 1 1 0; min-height: 38px;
  background: var(--bg-2); color: var(--ink-dim);
  border: 1px solid var(--line); border-radius: 10px;
  font-size: 14px; letter-spacing: .04em; cursor: pointer;
}
.jtab.is-on { background: var(--bg-3); color: var(--ink); border-color: var(--accent) }

.exp { padding: 12px 14px; border-bottom: 1px solid var(--line) }
.exp__name { font-size: 15px; color: var(--ink); margin-bottom: 8px }
.exp__nos { display: flex; flex-wrap: wrap; gap: 6px }

/* Номер — кнопка, дырка — нет. Разница читается без подписи: найденное можно
   нажать и перечитать, ненайденное нельзя даже тронуть. */
.expno {
  min-width: 34px; height: 34px; padding: 0 6px;
  background: var(--bg-3); color: var(--ink);
  border: 1px solid var(--line); border-radius: 8px;
  font-size: 14px; cursor: pointer;
}
.expno.is-gap {
  background: none; color: var(--ink-dim); opacity: .45;
  border-style: dashed; cursor: default;
}

/* Куда они пошли дальше — ради этой строки журналы и ищут, поэтому она
   отделена от текста записи, а не дописана к нему. */
.readnote--next {
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--line);
  color: var(--accent);
}
.readnote--dim { color: var(--ink-dim); font-size: 13px; margin-top: 10px }

/* Кто здесь был (§14.4). Строка редкая и важная, поэтому выделена цветом
   акцента, но мелкая: это не событие, а след. */
.visits {
  flex: 0 0 auto;
  margin: 0; padding: 4px var(--pad) 0;
  font-size: 12px; line-height: 1.35; color: var(--accent);
}
.bodywho { margin: 0 0 2px; font-size: 18px; color: var(--ink) }


/* --- надписи на стенах (§14.4) ------------------------------------------ */

/* Чужой текст в клетке — редкость и событие, поэтому он выделен бумагой на
   тёмном, а не растворён в описании стороны. */
.wall {
  flex: 0 0 auto;
  margin: 4px var(--pad) 0;
  padding: 6px 10px;
  background: var(--bg-2);
  border-left: 2px solid var(--accent);
  border-radius: 0 8px 8px 0;
  max-height: 22dvh; overflow-y: auto;
}
.wall__row { padding: 3px 0 }
.wall__text { font-size: 13px; line-height: 1.35; color: var(--ink) }
.wall__by { font-size: 11px; color: var(--ink-dim) }
.wall__add {
  margin-top: 4px; padding: 6px 10px;
  background: none; border: 1px dashed var(--line); border-radius: 8px;
  color: var(--accent); font: inherit; font-size: 12px; cursor: pointer;
}

/* Поле для своего текста. Счётчик обязателен: фраза, обрезанная на полуслове,
   хуже ненаписанной. */
.writebox {
  width: 100%; margin-top: 10px; padding: 10px;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink); font: inherit; font-size: 15px; line-height: 1.4;
  resize: none;
}
.writecount { text-align: right; font-size: 12px; color: var(--ink-dim); margin: 4px 0 10px }


/* --- другие игроки рядом (§14.1) ---------------------------------------- */

/* Встреча — редкость: за всю игру их может не случиться ни одной. Поэтому
   строка выделена так же, как чужая надпись, а не растворена в интерфейсе. */
.people {
  flex: 0 0 auto;
  margin: 4px var(--pad) 0;
  padding: 6px 10px;
  background: var(--bg-2);
  border-left: 2px solid #7fa86a;
  border-radius: 0 8px 8px 0;
}
.person { display: flex; align-items: center; gap: 8px; padding: 3px 0 }
.person__ic { width: 18px; height: 18px; color: var(--ink-dim); flex: 0 0 auto }
.person__ic svg { width: 100%; height: 100% }
.person__name { font-size: 13px; color: var(--ink) }
.person__sub { font-size: 11px; color: var(--ink-dim); margin-left: auto }
.person__talk {
  margin-top: 4px; padding: 6px 10px;
  background: none; border: 1px dashed var(--line); border-radius: 8px;
  color: #9ec487; font: inherit; font-size: 12px; cursor: pointer;
}

/* Разговор. Своё слева бледнее — не из вежливости, а чтобы глаз цеплялся за
   чужое: своё игрок и так помнит. */
.chat { max-height: 46dvh; overflow-y: auto; margin-bottom: 10px }
.chat__row { padding: 5px 0; border-bottom: 1px solid var(--bg-3) }
.chat__who { font-size: 11px; color: var(--ink-dim) }
.chat__text { font-size: 14px; line-height: 1.35; color: var(--ink) }
.chat__row.is-mine .chat__text { color: var(--ink-dim) }

/* --- лавка (§14.3) ------------------------------------------------------- */

.shop { flex: 1; overflow-y: auto; padding: var(--pad) }
.shop__foot {
  flex: 0 0 auto; padding: 8px var(--pad) calc(8px + var(--safe-b));
  font-size: 12px; color: var(--ink-dim); border-top: 1px solid var(--line);
}
.offer__wrap { margin-bottom: 12px }
.offer {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px; background: var(--bg-2);
  border: 1px solid var(--line); border-radius: 10px 10px 0 0;
}
/* Недоступная цена гаснет, но остаётся на виду — как недоступный вариант
   события (§9): игрок должен знать, чего ему не хватает. */
.offer.is-off { opacity: .5 }
.offer__ic { width: 26px; height: 26px; color: var(--ink); flex: 0 0 auto }
.offer__ic svg, .offer__ic img.ic { width: 100%; height: 100% }
.offer__body { display: flex; flex-direction: column; min-width: 0 }
.offer__name { font-size: 14px; color: var(--ink) }
.offer__by { font-size: 11px; color: var(--ink-dim) }
.offer__price { margin-left: auto; display: flex; align-items: center; gap: 8px; font-size: 14px }
.offer__price svg, .offer__price img.ic { width: 14px; height: 14px; vertical-align: -2px; margin-right: 2px }
.offer__wrap .btn { width: 100%; border-radius: 0 0 10px 10px }

.pricegrid { margin: 12px 0 }
.pricerow {
  display: flex; align-items: center; gap: 8px;
  padding: 6px 0; border-bottom: 1px solid var(--bg-3);
}
.pricerow__ic { width: 18px; height: 18px; color: var(--ink-dim) }
.pricerow__ic svg, .pricerow__ic img.ic { width: 100%; height: 100% }
.pricerow__n { font-size: 14px; color: var(--ink) }
.priceinp {
  margin-left: auto; width: 68px; padding: 6px 8px; text-align: center;
  background: var(--bg-3); border: 1px solid var(--line); border-radius: 8px;
  color: var(--ink); font: inherit; font-size: 15px;
}

/* --- эфир (§14.2) -------------------------------------------------------- */

/* Шапка — единственное место, где игра говорит, куда идти за вышкой. Она
   должна читаться сразу и не спорить со списком. */
.radio__head {
  flex: 0 0 auto; padding: 8px var(--pad);
  border-bottom: 1px solid var(--line);
}
.radio__sig { font-size: 13px; color: var(--ink-dim) }
.radio__tower { margin-top: 3px; font-size: 12px; color: #9ec487 }
.radio__no { font-size: 14px; color: var(--ink-faint) }

.radio { flex: 1; overflow-y: auto; padding: var(--pad) }
.radio__foot {
  flex: 0 0 auto; padding: 8px var(--pad) calc(8px + var(--safe-b));
  border-top: 1px solid var(--line);
}

/* Реплика. Побитая помехами набрана тем же кеглем, что и чистая: разница
   видна по тексту, и подчёркивать её шрифтом значило бы сказать игроку то,
   что он и так слышит. */
.air { padding: 7px 0; border-bottom: 1px solid var(--bg-3) }
.air__who { font-size: 11px; color: var(--ink-faint) }
.air__text { font-size: 15px; line-height: 1.35; color: var(--ink-dim) }
/* Личное от друга — единственная надёжная связь в игре, и её видно с первого
   взгляда: полоска слева, как у чужой надписи на стене. */
.air.is-personal { border-left: 2px solid #7fa86a; padding-left: 8px }
.air.is-personal .air__text { color: var(--ink) }
.air.is-noisy .air__text { color: var(--ink-faint) }

/* Друзья. Список короткий всегда — звать можно только тех, кого встретил. */
.friends { margin-top: 10px }
.friends__t {
  font-size: 11px; text-transform: uppercase; letter-spacing: .1em;
  color: var(--accent-dk); margin-bottom: 4px;
}
.friends__none { font-size: 13px; color: var(--ink-faint) }
.friend {
  display: flex; align-items: center; gap: 8px;
  padding: 5px 0; border-bottom: 1px solid var(--bg-3);
}
.friend__name { font-size: 14px; color: var(--ink); min-width: 0 }
.friend__wait { font-size: 11px; color: var(--ink-faint) }
.friend__act {
  margin-left: auto; padding: 4px 9px;
  background: none; border: 1px dashed var(--line); border-radius: 8px;
  color: var(--ink-dim); font: inherit; font-size: 12px; cursor: pointer;
}
.friend__act + .friend__act { margin-left: 0 }
.friend__act.is-yes { color: #9ec487; border-style: solid }

/* Позвать в друзья — прямо в строке встречи: другого случая не будет. */
.person__add {
  margin-left: auto; padding: 3px 8px;
  background: none; border: 1px dashed var(--line); border-radius: 8px;
  color: var(--ink-dim); font: inherit; font-size: 11px; cursor: pointer;
}
.person__sub + .person__add { margin-left: 8px }

/* Вышка под ногами (§14.5): единственная клетка, где ничего не случается.
   Строка зелёная — тем же цветом, что и всё безопасное в игре. */
.tower {
  flex: 0 0 auto; margin: 4px var(--pad) 0; padding: 6px 10px;
  background: var(--bg-2); border-left: 2px solid #7fa86a;
  border-radius: 0 8px 8px 0;
  font-size: 13px; line-height: 1.35; color: #9ec487;
}

/* --- личная задача (§13) ------------------------------------------------- */

/* Завязка — голос, а не заголовок: с неё задача начинается и ею объясняется. */
.quest__open {
  margin: 0 0 10px; font-size: 15px; line-height: 1.45; color: var(--ink);
  border-left: 2px solid var(--accent-dk); padding-left: 10px;
}
.quest__goal { margin: 0 0 6px; font-size: 14px; color: var(--ink-dim) }
/* Куда идти — единственная строка, ради которой экран открывают в дороге. */
.quest__aim { margin: 0 0 6px; font-size: 14px; color: #9ec487 }
.quest__count { margin: 0 0 6px; font-size: 13px; color: var(--ink-faint) }
.quest__end {
  margin: 0 0 10px; font-size: 15px; line-height: 1.45; color: var(--ink);
  border-left: 2px solid #9ec487; padding-left: 10px;
}

/* --- Хроника (§16) -------------------------------------------------------- */

/* Память, а не прогрессия: ни чисел роста, ни бонусов — только кем ты был. */
.chron { padding: 12px 0; border-bottom: 1px solid var(--bg-3) }
.chron__head { display: flex; align-items: baseline; gap: 8px }
.chron__name { font-size: 16px; color: var(--ink) }
.chron__days { font-size: 12px; color: var(--ink-faint); margin-left: auto }
.chron__cause { font-size: 13px; color: var(--danger); margin-top: 2px }
.chron__goal { font-size: 14px; color: var(--ink-dim); margin-top: 4px }
.chron__state { font-size: 12px; color: var(--ink-faint); margin-top: 2px }
.chron__state.is-done { color: #9ec487 }
.chron__end {
  margin-top: 6px; padding-left: 10px; border-left: 2px solid #9ec487;
  font-size: 14px; line-height: 1.4; color: var(--ink-dim);
}
/* Последняя строка дневника — курсивом: это голос, а не поле карточки. */
.chron__last { margin-top: 6px; font-size: 13px; font-style: italic; color: var(--ink-faint) }
/* Живой — тот, кем играют сейчас. Полоска слева, как у всего своего. */
.chron.is-alive { border-left: 2px solid var(--accent-dk); padding-left: 10px }

/* --- погода (§15.1) ------------------------------------------------------- */

/* Строка неба стоит рядом со временем суток: и то и другое про «сейчас», и
   читаются они вместе — «Ливень · Ночь». */
.hud__sky {
  color: #8fa6c0; white-space: nowrap;
  background: none; border: 0; padding: 0; font: inherit; font-size: 13px;
  cursor: pointer;
}
/* Под крышей небо идёт, но его не видно: строка гаснет, а не исчезает —
   игрок должен знать, что его ждёт на улице. */
.hud__sky.is-off { color: var(--ink-faint); opacity: .55 }

/* Пелена поверх кадра. Рисуется кодом, а не картинкой: дождю нужна не
   текстура, а движение, и три слоя градиента делают это убедительнее одного
   png. Арт, когда появится, ляжет сверху тем же способом, что слои вида. */
.view__sky { position: absolute; inset: 0; z-index: 8; pointer-events: none; overflow: hidden }
.view__sky::before, .view__sky::after { content: ''; position: absolute; inset: -20%; opacity: 0;
  transition: opacity 1.2s ease }

/* Дождь: две косые сетки с разной скоростью — одна читается как стена воды. */
.view__sky[data-sky="rain"]::before,
.view__sky[data-sky="downpour"]::before {
  opacity: .5;
  background: repeating-linear-gradient(107deg,
    rgba(190,210,235,0) 0 7px, rgba(190,210,235,.30) 7px 8px, rgba(190,210,235,0) 8px 15px);
  animation: rainfall 420ms linear infinite;
}
.view__sky[data-sky="downpour"]::before { opacity: .78; animation-duration: 260ms }
.view__sky[data-sky="rain"]::after,
.view__sky[data-sky="downpour"]::after {
  opacity: .34;
  background: repeating-linear-gradient(99deg,
    rgba(210,225,245,0) 0 11px, rgba(210,225,245,.22) 11px 12px, rgba(210,225,245,0) 12px 23px);
  animation: rainfall 700ms linear infinite;
}
.view__sky[data-sky="downpour"]::after { opacity: .5; animation-duration: 420ms }
@keyframes rainfall { to { transform: translate3d(-90px, 290px, 0) } }

/* Туман: не серая заливка, а два пятна, которые дышат. Заливка читается как
   сломанный экран, движение — как воздух. */
.view__sky[data-sky="fog"]::before {
  opacity: .78;
  background: radial-gradient(120% 70% at 50% 92%, rgba(196,202,206,.92), rgba(196,202,206,0) 70%);
  animation: fogdrift 17s ease-in-out infinite alternate;
}
.view__sky[data-sky="fog"]::after {
  opacity: .5;
  background: linear-gradient(0deg, rgba(196,202,206,.85) 0%, rgba(196,202,206,.1) 55%, rgba(196,202,206,0) 100%);
}
@keyframes fogdrift { to { transform: translate3d(5%, -3%, 0) scale(1.06) } }

/* Пыль: тёплая муть и несомая рябь поперёк кадра. */
.view__sky[data-sky="dust"]::before {
  opacity: .62;
  background: linear-gradient(0deg, rgba(166,128,74,.85), rgba(166,128,74,.22));
}
.view__sky[data-sky="dust"]::after {
  opacity: .4;
  background: repeating-linear-gradient(84deg,
    rgba(214,186,140,0) 0 12px, rgba(214,186,140,.3) 12px 15px, rgba(214,186,140,0) 15px 34px);
  animation: dustblow 900ms linear infinite;
}
@keyframes dustblow { to { transform: translate3d(-160px, 26px, 0) } }

/* Пасмурно — только вес сверху, без движения: это не событие, это фон. */
.view__sky[data-sky="overcast"]::before {
  opacity: .34;
  background: linear-gradient(180deg, rgba(104,112,124,.85), rgba(104,112,124,0) 62%);
}

/* Кому в глаза не светит — тому и анимации не надо. */
@media (prefers-reduced-motion: reduce) {
  .view__sky::before, .view__sky::after { animation: none !important }
}

/* --- глобальные события (§15.1) ------------------------------------------- */

/* Событие стоит в той же строке, что и погода, и своей строки на экране
   клетки не получает: каждая строка там отнимает у кадра ровно столько же,
   сколько у текста, — а событие идёт помногу часов. Подробности по тапу. */
.hud__sky.is-event { color: #d9a96a; font-weight: 600 }
/* Без рации игрок знает только то, что заметил сам: та же строка, но глуше и
   без названия. Разница видна с первого взгляда — в этом и смысл. */
.hud__sky.is-vague { color: var(--ink-dim); font-weight: 400; font-style: italic }

/* Объявление города в эфире — не чей-то голос, а голос города. */
.air.is-city { border-left: 2px solid #c08a4a; padding-left: 8px }
.air.is-city .air__who { color: #d9a96a }
.air.is-city .air__text { color: var(--ink) }

/* --- обучение (§17) ------------------------------------------------------- */

/* Строка шага живёт ровно семь шагов и исчезает навсегда. Одна строка, с
   многоточием: подробности и кнопка «я знаю, как играть» — по тапу.
   Лежит ПОВЕРХ кадра, над стрелками поворота: ряд в потоке стоил бы кадру
   тридцать пикселей, а кадр — единственное, что уступает место всему
   остальному, и на экране в 664 px он после этого уходил ниже своей доли.
   Субтитр не стоит ничего. */
.view__bottom {
  position: absolute; left: 0; right: 0; bottom: 0; z-index: 9;
}
/* Стрелки теперь внутри стопки, и низ держит она. */
.view__bottom .view__compass { position: static; }
.tut {
  display: block; width: 100%; text-align: left;
  margin: 0; padding: 6px var(--pad);
  background: rgba(10, 9, 8, .82); border: 0;
  border-top: 1px solid rgba(230, 221, 208, .14);
  color: var(--accent); font: inherit; font-size: 13px; line-height: 1.3;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  cursor: pointer; backdrop-filter: blur(3px);
}
