/* ANTIGEN · новый клиент. Одежда взята из прототипа v2 — «Свет фонаря».
 *
 * ПОЧЕМУ НЕ КОПИЯ. Стилей v2 — 1292 строки под другую разметку, и часть
 * их ссылалась на токены, которых никто не объявил: аудит нашёл 77 таких
 * ссылок на 18 имён, из них 20 без запасного значения — панель просто
 * исчезала, оставался голый текст. Владелец увидел это как «Низина
 * совершенно не заметна». Копировать такое нельзя, и копипаст запрещён
 * решением 28 августа. Здесь тот же язык, написанный заново под классы
 * нового клиента: каждый токен объявлен ровно один раз и ниже применён.
 *
 * ПАЛИТРА СНЯТА ПИПЕТКОЙ С НАШИХ ПЕРСОНАЖЕЙ (Р-123): /art/promo/cover.jpg
 * и /art/bg/shelter.jpg. Контраст фона с самым тёмным существом 3,85.
 *
 * ТРИ МАТЕРИАЛА И НИ ОДНИМ БОЛЬШЕ (К9): ДОСКА — оправа и вкладки;
 * ЛАТУНЬ — кант, кнопка, медальоны; ПЕРГАМЕНТ — таблички и подсказки.
 *
 * ЯРКОЕ ПРИНАДЛЕЖИТ СУЩЕСТВУ (К1). Конструктивная латунь тёмная
 * и приглушённая; горящее золото оставлено за двумя объектами кадра —
 * главной кнопкой и активным состоянием.
 */
:root {
  --night:#1B1226;    /* свет фонаря: фон лавки                     */
  --shelf:#2E2438;    /* доски полки                                */
  --nook:#191322;     /* тень в глубине; брус вкладок               */
  --void:#16111E;     /* поле вокруг макета                         */
  --lamp:#D89C42;     /* латунь и ореол лампы — главное действие    */
  --lampLit:#F6D08A;  /* сердцевина пламени: блик, губа             */
  --lampTop:#E0A950;
  --lampBot:#B7802F;
  --lampDeep:#6E4718;
  --lampInk:#2A1A08;  /* надпись на кнопке, 7,0:1 к латуни          */
  --paper:#F0E4CE;    /* кремовый живот существ — основной текст    */
  --mauve:#B9A6C0;    /* лиловая шерсть — второстепенный текст      */
  --dusk:#8B7896;     /* тень между полками — третичный текст       */
  --moss:#7FB07F;     /* мох на полках — доброе                     */
  --clay:#C4665C;     /* обожжённые горшки — беда                   */
  --brass:#9A7742;    /* тело канта                                 */
  --brassDeep:#33240F;/* канавка под кантом                         */
  --parch:#D2BD91;    /* пергамент таблички                         */
  --parchInk:#3B2A17; /* надпись на пергаменте, 9,4:1               */

  /* Кант турецкой школы: витьё как ТЕКСТУРА (прозрачные нити),
     форму держит фаска — свет сверху-слева, канавка справа-снизу.
     Чистый полосатый градиент в полную силу читался парикмахерским
     столбом и был ярчайшим пятном кадра. */
  --rope:
    repeating-linear-gradient(118deg,rgba(255,228,175,.15) 0 1.5px,
      rgba(0,0,0,.2) 1.5px 4px,rgba(0,0,0,.04) 4px 6.5px),
    linear-gradient(158deg,#8B6A34 0%,#6A4E25 34%,#43300F 64%,#7A5B2A 100%);
  /* Заклёпки по углам оправы — четырьмя radial-gradient, без единого
     лишнего элемента в разметке. */
  --rivets:
    radial-gradient(circle at 10px 10px,#E8CE96 0 2px,rgba(0,0,0,.5) 2px 3px,transparent 3px),
    radial-gradient(circle at calc(100% - 10px) 10px,#E8CE96 0 2px,rgba(0,0,0,.5) 2px 3px,transparent 3px),
    radial-gradient(circle at 10px calc(100% - 10px),#E8CE96 0 2px,rgba(0,0,0,.5) 2px 3px,transparent 3px),
    radial-gradient(circle at calc(100% - 10px) calc(100% - 10px),#E8CE96 0 2px,rgba(0,0,0,.5) 2px 3px,transparent 3px);

  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  /* Веб-шрифтов в проекте нет и не будет: берём самый широкий
     из системных, недостающую массу добираем обводкой в .имя. */
  --fat:"Arial Black","Arial Bold","Helvetica Neue",-apple-system,
        BlinkMacSystemFont,Roboto,sans-serif;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
body { margin:0; background:var(--void); color:var(--paper);
  font:15px/1.45 var(--sans); }
/* Оболочка ровно в экран: вкладки внизу всегда на месте, а содержимое
   при нужде прокручивается ВНУТРИ, а не уносит их за край. Прежде
   колонка росла от содержимого, и главная страница вылезала за экран.

   РОСТ БЕРЁТСЯ ИЗ ПЕРЕМЕННОЙ, А НЕ ИЗ `100dvh` (владелец, 31 августа:
   «вкладки не появляются на экране, они внизу»). В Телеграме вебвью
   высотой во весь экран, а видна только часть выше края шторки: `dvh`
   мерит вебвью, и брус вкладок вставал под нижний край телефона.
   Число называет сам Телеграм, ставит его `/tgview.js`; `100dvh`
   остаётся запасным — в обычном браузере он и верен. */
.app { max-width:560px; margin:0 auto; height:var(--окно, 100dvh); background:var(--night);
  display:flex; flex-direction:column; overflow-x:hidden; }

/* ---------- шапка ---------- */
/* ЗАГОЛОВОК ЭКРАНА — ПОСЕРЕДИНЕ (общее правило, владелец 28 августа):
   прижатый влево, он сливался со стрелкой «назад» и читался как её
   подпись. Сетка из трёх колонок: стрелка слева, кошелёк справа,
   название ровно по центру и не съезжает от их ширины. */
.top { display:grid; grid-template-columns:34px minmax(0,1fr) auto;
  align-items:center; gap:10px; padding:10px 12px;
  background:linear-gradient(180deg,#241A30,#1B1226);
  border-bottom:2px solid var(--brassDeep);
  box-shadow:0 1px 0 rgba(232,206,150,.15) inset; }
.top .back { background:none; border:0; color:var(--lamp); cursor:pointer;
  font:900 24px/1 var(--sans); padding:0 4px; justify-self:start; }
/* Место стрелки занято всегда: без неё название прыгало бы влево
   при переходе со вкладки на экран. */
.top .back[hidden] { display:block; visibility:hidden; }
.top .who { text-align:center; font:800 14px/1.1 var(--fat); color:var(--lamp);
  letter-spacing:.02em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }

/* Валюта — капсула, из которой иконка ВЫЛЕЗАЕТ за край: турецкий
   стандарт, а не украшение. */
/* ДВЕ ВАЛЮТЫ В РЯД. Ширина шапки конечна, и вторая капсула не должна
   выдавливать имя питомника: обе сжимаются, а не переносятся. */
.кошели { display:flex; align-items:center; gap:6px; justify-self:end; }
/* Эссенция тише корма: корм тратится каждым тапом и потому кричит,
   эссенция копится неделями. Разный вес — это подсказка о ритме,
   а не украшение. */
.эссенция { padding-left:18px; font-size:14px; }
.эссенция .знак-эссенции { font-style:normal; font-size:15px;
  position:absolute; left:-2px; top:50%; transform:translateY(-50%);
  color:var(--lampLit); }
/* ИСКРЫ ТРЕТЬИМ КОШЕЛЬКОМ (владелец, 31 августа). Тем же весом, что
   эссенция: обе копятся неделями, обе участвуют в решении «идти
   ли в лавку», и обе тише корма, который тратится каждым тапом.

   Три кошелька в ряд помещаются только сжатыми: отступы и кегль
   у тихой пары меньше, а имя питомника рядом ужимается многоточием
   (`minmax(0,1fr)` в сетке шапки) — оно длинное и потерпит. */
.искры { padding-left:18px; font-size:14px; }
.искры .знак-искр { font-style:normal; font-size:15px;
  position:absolute; left:-2px; top:50%; transform:translateY(-50%);
  color:var(--lamp); }
.кошели .purse { padding-left:20px; padding-right:11px; }

.purse { display:flex; align-items:center; gap:8px; padding:5px 14px 5px 22px;
  border-radius:999px; position:relative; font:900 16px/1 var(--fat);
  background:linear-gradient(180deg,#3A2C42,#241A30);
  box-shadow:0 2px 0 rgba(0,0,0,.45), inset 0 1px 0 rgba(232,206,150,.18);
  outline:1px solid rgba(154,119,66,.5); }
/* ЗНАК КОРМА — МИСКА (владелец, 29 августа: «иконка еды на макетах лучше
   чем на сервере»). Была картинка `/art/icons/slop.png` — зелёная горка,
   которую читали как что угодно, кроме еды. Миска говорит сама за себя
   и не требует ни файла, ни загрузки. */
.знак-корма { font-style:normal; font-size:17px; line-height:1;
  position:absolute; left:-6px; top:50%; transform:translateY(-50%);
  filter:drop-shadow(0 2px 2px rgba(0,0,0,.5)); }

main { flex:1 1 auto; min-height:0; padding:12px 12px 18px; min-width:0;
  overflow-x:hidden; overflow-y:auto; display:flex; flex-direction:column; }

/* ---------- вкладки: брус со значками ----------
 * Как в v2: подсвеченное ребро сверху, латунная канавка под ним,
 * значок предметом из /art/ubor/. Активная вкладка — единственное
 * место кадра, кроме главной кнопки, где горит золото. */
.tabs { display:flex; position:sticky; bottom:0; z-index:5;
  padding-bottom:env(safe-area-inset-bottom);
  background:linear-gradient(180deg,#3A2C40 0 2px,#251D30 3px,var(--nook));
  box-shadow:0 -2px 0 var(--brass), 0 -3px 0 var(--brassDeep),
             0 -10px 18px rgba(0,0,0,.5); }
.tabs button { flex:1; background:none; border:0; cursor:pointer;
  padding:8px 2px 10px; color:var(--dusk); font:700 10.5px/1.2 var(--sans);
  position:relative; }
.ti { display:block; width:30px; height:30px; margin:0 auto 3px;
  background:center/contain no-repeat; opacity:.5; filter:grayscale(.55); }
.ti-pen { background-image:url(/art/ubor/yard_lantern.png); }
.ti-world { background-image:url(/art/ubor/fair_flag.png); }
.ti-folk { background-image:url(/art/ubor/fair_cap.png); }
.tabs button.on { color:var(--lampLit); text-shadow:0 1px 3px rgba(0,0,0,.7); }
.tabs button.on .ti { opacity:1; filter:drop-shadow(0 0 7px rgba(246,208,138,.5)); }

/* ---------- панель: доска в оправе ---------- */
/* У панели есть материал и толщина: кант, фаска, внутренняя тень,
   заклёпки по углам. Не заливка. */
.сцена, .поле, .полка, .заявка, .лог, .намёк, .весть, .беда, .пусто,
.карточка, .порог, .счёт {
  border-radius:18px;
}
.сцена {
  position:relative; padding:11px; margin-bottom:12px;
  background:var(--rivets), var(--rope);
  box-shadow:0 6px 0 rgba(0,0,0,.4), inset 0 2px 0 rgba(255,228,175,.2);
  text-align:center;
}
.сцена .герой { width:100%; max-width:100%; height:auto; max-height:46dvh;
  object-fit:contain; cursor:pointer; border-radius:12px; display:block; margin:0 auto;
  background:radial-gradient(120% 90% at 50% 30%,#3B2F45,#1E1729);
  filter:drop-shadow(0 8px 10px rgba(0,0,0,.5)); }
/* Пергаментная бирка с именем наполовину вылезает из рамы вниз. */
.сцена .имя {
  position:relative; margin:-14px auto -4px; width:max-content; max-width:88%;
  padding:7px 20px; border-radius:12px;
  background:linear-gradient(180deg,#E4D3A9,var(--parch));
  color:var(--parchInk); font:900 15px/1 var(--fat);
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.5);
}

/* ---------- места в питомнике ---------- */
.места { display:flex; gap:8px; margin:14px 0 0; overflow-x:auto;
  scrollbar-width:none; padding-bottom:4px; }
.места::-webkit-scrollbar { display:none; }
.место { width:66px; flex:none; border:0; cursor:pointer; border-radius:16px;
  padding:7px 4px 8px; position:relative; color:var(--paper);
  display:flex; flex-direction:column; align-items:center; gap:5px;
  background:linear-gradient(180deg,var(--shelf),#241A30);
  box-shadow:0 3px 0 rgba(0,0,0,.45), inset 0 1px 0 rgba(232,206,150,.14); }
.место.на { background:linear-gradient(180deg,#4B3A46,#332538);
  outline:2px solid var(--lamp); }
/* ОДНО ПРАВИЛО КАДРА НА ВСЕ АВАТАРЫ (владелец, 31 августа: «существо
   почти не видно»).

   Портрет — квадрат 1024×1024, существо в полный рост по центру,
   с полями сверху и снизу. В кружке 40×40 стояла подгонка руками:
   `width:158%` и сдвиг вниз на 6px. В круг попадала верхняя треть
   кадра — голова вместе со всем фоном вокруг неё, и существо занимало
   едва четверть кружка.

   Хуже было то, что таких подгонок в игре стояло ТРИ разных и ни одна
   не согласована с прочими: кружок ручными процентами, лицо боя
   и малыш в яслях — честным `cover`, который вписывает квадрат
   в квадрат один к одному, то есть показывает портрет ЦЕЛИКОМ вместе
   с полями.

   Теперь правило одно, а мера у каждого места своя — двумя
   переменными:
     `--фокус`    куда смотреть по высоте кадра;
     `--крупно`   насколько выйти за края, чтобы поля ушли из виду.

   Голова у портрета в полный рост приходится примерно на четверть
   высоты, отсюда 28% по умолчанию: чуть ниже макушки, чтобы в кадр
   попали глаза и пасть, а не темя. */
.морда img { width:100%; height:100%; display:block; max-width:none;
  object-fit:cover; object-position:50% var(--фокус,28%);
  transform:scale(var(--крупно,1.35)); transform-origin:50% var(--фокус,28%); }

.место .лицо { width:52px; height:52px; border-radius:50%; flex:none;
  overflow:hidden; background:rgba(0,0,0,.3);
  box-shadow:inset 0 0 0 2px rgba(154,119,66,.6); }
/* Кружок вырос с 40 до 52: сорок точек на телефоне меньше ногтя,
   и там не разглядеть ничего при любом кадрировании. */
.место b { display:block; max-width:100%; font:800 10.5px/1.1 var(--sans);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.место.свободно { background:none; opacity:.75;
  box-shadow:inset 0 0 0 1px rgba(154,119,66,.45); }
.место.свободно .лицо { background:rgba(255,255,255,.04); box-shadow:none; }

/* ---------- кнопка: предмет с губой и просадкой ---------- */
/* КНОПКА НЕ РАСТЁТ В ВЫСОТУ (владелец, 28 августа: «очень высокая
   кнопка вскрытия, она растёт от размера экрана»).
   Здесь стояло `flex:1 1 0` — задумано для РЯДА, где кнопки делят
   ширину. Но `main` — колонка, и та же строка означала «расти
   в высоту»: одинокая кнопка занимала весь остаток экрана.
   Делёж ширины оставлен ряду, где он и нужен. */
.кнопка { flex:0 0 auto; min-width:0; border:0; cursor:pointer;
  border-radius:16px; padding:14px 14px 17px; position:relative;
  color:var(--lampInk); font:900 16px/1.1 var(--fat);
  display:flex; flex-direction:column; align-items:center; gap:3px;
  background:linear-gradient(180deg,var(--lampTop),var(--lampBot));
  box-shadow:0 4px 0 var(--lampDeep), 0 6px 10px rgba(0,0,0,.45),
             inset 0 1px 0 var(--lampLit);
  transition:transform .06s, box-shadow .06s; }
.кнопка:active { transform:translateY(3px);
  box-shadow:0 1px 0 var(--lampDeep), inset 0 1px 0 var(--lampLit); }
.кнопка small { font:700 11px/1.25 var(--sans); opacity:.78; }
.кнопка b { font:900 15px/1 var(--fat); }
.кнопка.мал { flex:0 0 auto; font-size:14px; padding:14px 13px 17px; }
.кнопка.главная { font-size:18px; }
/* Кнопка действия внизу экрана: небольшая и приклеенная к нижнему ряду.
   Она и так заметна — золото на тёмном, — и расти ей незачем. */
.кнопка.широкая { width:100%; margin-top:12px; padding:12px 14px 14px;
  font-size:15px; position:sticky; bottom:8px; z-index:4; }
/* Отказ — та же кнопка, но из доски: она ведёт туда, где берут корм,
   и потому обязана оставаться живой, а не гаснуть. */
.кнопка.беднота { color:var(--paper);
  background:linear-gradient(180deg,#3A2C42,#241A30);
  box-shadow:0 4px 0 #140E1C, inset 0 1px 0 rgba(232,206,150,.16); }
.действия { display:flex; gap:8px; align-items:stretch; margin-top:14px; }
.действия .кнопка, .acts-half .кнопка { flex:1 1 0; }
/* ПАРА «Покормить ×5» — одно тело, а не две кнопки ряда.
 * Место ряда делит пара целиком; внутри «×5» занимает столько,
 * сколько нужно, и стыкуется с левой половиной без зазора.
 *
 * ИМЯ СВОЁ: `пара` в бою — это строка «мой против чужого», сетка
 * из трёх колонок. Держалось оно только на большей точности селектора
 * `.действия .пара`, то есть на случайности: вынести кнопки из ряда —
 * и они получили бы боевую сетку. */
.пара-кнопок { display:flex; flex:1 1 0; min-width:0; align-items:stretch; }
.пара-кнопок > .кнопка { flex:1 1 auto; border-radius:16px 3px 3px 16px; }
.пара-кнопок > .кнопка.мал { flex:0 0 auto; padding-left:13px; padding-right:13px;
  border-radius:3px 16px 16px 3px; margin-left:3px; }

/* ---------- поле коконов ---------- */
.поле { display:grid; grid-template-columns:repeat(5,1fr); gap:7px;
  padding:11px; background:var(--rivets), var(--rope);
  box-shadow:0 6px 0 rgba(0,0,0,.4), inset 0 2px 0 rgba(255,228,175,.2); }
/* КОКОН — ПРЕДМЕТ В ЛУНКЕ, как в прототипе v2. Слои: лунка, контактная
   тень, само яйцо картинкой по ступени, латунная бирка с числом. */
.кокон { aspect-ratio:1; border-radius:13px; cursor:pointer; position:relative;
  display:grid; place-items:center; isolation:isolate;
  background:linear-gradient(180deg,#3A2D46,#221A2E 55%,#191322);
  box-shadow:inset 0 1.5px 0 rgba(228,194,136,.26), inset 0 -6px 10px rgba(0,0,0,.5),
             0 0 0 1px #120C1C, 0 3px 0 #130D1D, 0 5px 8px rgba(0,0,0,.45);
  transition:transform .08s, box-shadow .12s; }
/* Пустая лунка: вдавленная, без предмета и без нажатия. */
.кокон.пусто-клетка { cursor:default;
  background:radial-gradient(ellipse 54% 34% at 50% 62%,rgba(0,0,0,.4),transparent 78%),
             linear-gradient(180deg,#150F20,#221A2E);
  box-shadow:inset 0 4px 9px rgba(0,0,0,.8), inset 0 -1.5px 0 rgba(228,194,136,.12),
             0 0 0 1px rgba(0,0,0,.5); }
/* Контактная тень: без неё кокон висит, с ней лежит. */
.гнездо { position:absolute; left:50%; bottom:9%; width:56%; height:9%;
  transform:translateX(-50%); border-radius:50%; background:rgba(0,0,0,.62);
  filter:blur(3px); z-index:0; pointer-events:none; }
/* Масштаб 132% и маска по краю яйца — числа из v2: при contain яйцо вышло
   бы 56% клетки при норме 78%, а маска снимает холодный ореол запечённой
   виньетки. */
.яйцо { position:absolute; inset:2%; background-position:center;
  background-size:132% auto; background-repeat:no-repeat;
  mix-blend-mode:lighten; pointer-events:none; z-index:1;
  -webkit-mask-image:radial-gradient(ellipse 46% 49% at 50% 48.5%,#000 92%,transparent 100%);
          mask-image:radial-gradient(ellipse 46% 49% at 50% 48.5%,#000 92%,transparent 100%); }
.t1 .яйцо { background-image:url(/art/cocoons/t1.webp); }
.t2 .яйцо { background-image:url(/art/cocoons/t2.webp); }
.t3 .яйцо { background-image:url(/art/cocoons/t3.webp); }
.t4 .яйцо { background-image:url(/art/cocoons/t4.webp); }
.t5 .яйцо { background-image:url(/art/cocoons/t5.webp); }
.t6 .яйцо { background-image:url(/art/cocoons/t6.webp); }
.t7 .яйцо { background-image:url(/art/cocoons/t7.webp); }
/* Число ступени обязательно всегда: размером различимы 2,4 градации
   из десяти — форма цифру не заменяет. Стоит на латунной бирке:
   это ярлык на предмете, а не подпись под ним. */
/* БИРКА ТИРА НА КОКОНЕ. Называлась `.ступень` — тем же словом, что
   ступенька лестницы захода, и правила двух разных вещей перекрывали
   друг друга: бирка отдавала лестнице `position:absolute`, лестница
   бирке — `flex`. На лестнице сезона это же столкновение спрятало
   тридцать строк целиком (владелец, 31 августа). */
.бирка-тира { position:absolute; left:3px; bottom:3px; z-index:3;
  font:900 10.5px/1 var(--fat); font-variant-numeric:tabular-nums;
  color:#FBE9C4; background:linear-gradient(180deg,#4A3520,#241705);
  border-radius:7px; padding:2.5px 4.5px;
  box-shadow:0 0 0 1px rgba(228,194,136,.4), 0 1px 2px rgba(0,0,0,.7); }
.кокон.выбран { transform:scale(1.06); z-index:2;
  box-shadow:0 0 0 2.5px var(--lampLit), 0 0 14px rgba(246,208,138,.5),
             inset 0 1.5px 0 rgba(255,255,255,.3), 0 6px 14px rgba(0,0,0,.55); }
.кокон.парный { box-shadow:0 0 0 2px rgba(246,208,138,.55),
             inset 0 1.5px 0 rgba(228,194,136,.26), 0 3px 0 #130D1D; }
/* МЕТКА — ПЛАШКА НА КОКОНЕ, а её место на клетке = часть тела.
   Плашка 17 px, глиф 11 px: анатомический адрес меняет задачу с
   «опознать один из восьми» на «подтвердить ожидаемый», и две метки
   на клетке перестают спорить. Плашка с фаской — она ЛЕЖИТ на коконе,
   а не напечатана на нём. */
.мк { position:absolute; width:17px; height:17px; border-radius:50%;
  background:radial-gradient(circle at 50% 30%,#FFFBF0,var(--paper) 55%,#C6B28F);
  color:#241B12; display:grid; place-items:center; z-index:3;
  font-size:11px; line-height:1;
  box-shadow:0 0 0 1.5px rgba(10,7,16,.85), inset 0 -1px 2px rgba(120,100,70,.5),
             0 2px 3px rgba(0,0,0,.6); }
/* Форма говорит редкость и читается без цвета. */
.мк.rare { border-radius:5px; }
.мк.anomaly { border-radius:3px; transform:rotate(45deg); }
.мк.anomaly span { display:block; transform:rotate(-45deg); }
.мк.сломана { background:linear-gradient(180deg,#9C89A6,#6E5C79); color:#1B1522;
  border-radius:7px; top:41%; left:50%; margin-left:-8.5px;
  box-shadow:0 0 0 1.5px rgba(196,102,92,.5), 0 2px 3px rgba(0,0,0,.6); }
/* Глиф не перехватывает наведение: подсказка принадлежит плашке,
   и курсор не должен проваливаться сквозь рисунок. */
.мк svg { width:11px; height:11px; display:block; fill:currentColor;
  pointer-events:none; }
.мк span { pointer-events:none; }
.мк svg.line { fill:none; stroke:currentColor; stroke-width:3; stroke-linecap:round; }
/* Анатомические адреса: метка стоит там, где признак сидит. */
.мк.extra { top:3%; left:50%; margin-left:-8.5px; }
.мк.ears  { top:9%; left:7%; }
.мк.coat  { top:9%; right:7%; }
.мк.eyes  { top:30%; left:50%; margin-left:-8.5px; }
.мк.mouth { top:52%; left:50%; margin-left:-8.5px; }
.мк.limbs { bottom:5%; left:50%; margin-left:-8.5px; }
.мк.tail  { bottom:20%; right:4%; }
.мк.body  { bottom:20%; left:4%; }

/* ---------- таблички: пергамент ---------- */
.намёк, .пусто, .весть, .беда, .счёт, .служебно {
  padding:10px 13px; margin-top:12px; font-size:13px; }
.намёк, .пусто, .счёт { background:linear-gradient(180deg,#2A2136,#221A2E);
  color:var(--mauve); box-shadow:inset 0 1px 0 rgba(232,206,150,.1); }
.весть { background:linear-gradient(180deg,#E4D3A9,var(--parch));
  color:var(--parchInk); font-weight:700;
  box-shadow:0 3px 0 rgba(0,0,0,.35), inset 0 1px 0 rgba(255,255,255,.5); }
.беда { background:rgba(196,102,92,.16); color:var(--clay);
  box-shadow:inset 0 0 0 1px rgba(196,102,92,.35); }
.тихо { color:var(--dusk); font-size:12px; }
.служебно { position:fixed; left:0; right:0; bottom:58px; max-width:560px;
  margin:0 auto; text-align:center; color:var(--dusk); background:none; }

/* ---------- разделы и строки ---------- */
.раздел { font:800 12px/1 var(--fat); letter-spacing:.08em;
  text-transform:uppercase; color:var(--brass); margin:18px 0 8px; }
.заявка { background:linear-gradient(180deg,var(--shelf),#241A30);
  padding:11px 13px; margin-bottom:8px; display:flex; flex-wrap:wrap;
  gap:6px 10px; align-items:center;
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.заявка b { font:900 14px/1 var(--fat); }
.заявка .кнопка { margin-left:auto; }
.заявка .срок { font-variant-numeric:tabular-nums; cursor:help; }
.итог-боя { border-radius:14px; padding:12px 14px; margin-top:12px;
  font:900 16px/1.2 var(--fat); text-align:center; }
.итог-боя.победа { background:rgba(120,180,90,.18); color:var(--lampLit); }
.итог-боя.поражение { background:rgba(0,0,0,.3); color:var(--clay); }
.заявка.своя { flex-direction:column; align-items:stretch; }
.цели { display:flex; flex-wrap:wrap; gap:6px; }

/* ---------- порог ---------- */
.порог .шапка { font:800 11px/1 var(--fat); letter-spacing:.14em;
  text-transform:uppercase; color:var(--dusk); }
/* Заголовок «леденцовый»: градиентная заливка плюс обводка тенями —
   веб-шрифта нет, массу добираем слоями. */
.порог h2 { margin:6px 0 12px; font:900 24px/1.1 var(--fat);
  letter-spacing:-.02em;
  background:linear-gradient(180deg,var(--lampLit),var(--lamp));
  -webkit-background-clip:text; background-clip:text; color:transparent;
  text-shadow:0 2px 0 rgba(0,0,0,.45); }
.порог .тихо { display:block; margin-bottom:12px; }
.поле-имя { width:100%; padding:13px; border:0; border-radius:14px;
  background:linear-gradient(180deg,#E4D3A9,var(--parch));
  color:var(--parchInk); font:900 17px/1 var(--fat); text-align:center;
  margin-bottom:12px;
  box-shadow:inset 0 2px 4px rgba(0,0,0,.25), 0 2px 0 rgba(0,0,0,.35); }
.карточка { background:linear-gradient(180deg,var(--shelf),#241A30);
  padding:12px; margin-bottom:12px; display:grid;
  grid-template-columns:88px 1fr; gap:12px; align-items:start;
  box-shadow:0 4px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.лицо-бол { width:88px; border-radius:14px;
  box-shadow:0 2px 0 rgba(0,0,0,.4); }
.карточка .имя { font:900 16px/1 var(--fat); color:var(--lamp);
  text-shadow:0 2px 0 rgba(0,0,0,.4); }
.про { min-width:0; }
.числа { display:grid; grid-template-columns:1fr 1fr; gap:2px 10px;
  font-size:13px; margin:7px 0; color:var(--mauve); }
.числа b { color:var(--paper); }
.карточка .кнопка { grid-column:1 / -1; }
.метка-имя { display:block; padding:5px 9px; margin-top:5px; border-radius:10px;
  background:rgba(0,0,0,.28); font-size:12px; color:var(--paper); border:0;
  cursor:pointer; text-align:left; width:100%; }
/* ВЫБРАННАЯ ЦЕЛЬ. Правило стояло на `.on` латиницей, а разметка ставит
 * `на` кириллицей — выделение не появлялось никогда, и выбор из двух
 * кнопок читался списком из двух действий (владелец, 28 августа).
 * Страж это пропустил: он собирал из разметки только латинские имена. */
.метка-имя.на { outline:2px solid var(--lamp);
  background:rgba(0,0,0,.42); color:var(--lampLit); }
.метка-имя em { display:block; font:italic 400 10px/1.3 var(--sans);
  color:var(--clay); opacity:.9; }

/* Приметы существа: нажитое — чипами, ближайшая — намёком под ними.
   Чип, а не строка списка: примет за жизнь набирается восемь-девять,
   и списком они заняли бы полэкрана. */
.приметы { display:flex; flex-wrap:wrap; gap:6px; margin:8px 0 2px; }
.примета-метка { font:800 12px/1 var(--fat); padding:6px 10px; border-radius:10px;
  background:rgba(0,0,0,.28); color:var(--paper); cursor:help;
  box-shadow:inset 0 0 0 1px rgba(232,206,150,.18); }
.примета-дальше { margin-top:8px; }
.примета-дальше b { display:block; color:var(--lampLit); }

/* ---------- опись ---------- */
.полка { background:linear-gradient(180deg,var(--shelf),#241A30);
  padding:11px 13px; margin-bottom:8px;
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.полка > b { font:800 12px/1 var(--fat); color:var(--brass);
  text-transform:uppercase; letter-spacing:.06em; }
.строки { display:flex; flex-wrap:wrap; gap:4px; margin-top:7px; }
.строка { font-size:12px; padding:4px 9px; border-radius:9px;
  background:rgba(0,0,0,.28); color:var(--dusk); }
.строка.моя { background:linear-gradient(180deg,#E4D3A9,var(--parch));
  color:var(--parchInk); font-weight:700; }

/* ---------- ясли и Служба ---------- */
/* Плашка яслей: стоит первой в питомнике и только когда там кто-то есть.
   Латунный кант — то же выделение, что у главных действий: малыш ждёт
   решения, и это не фон. */
.зов-яслей { display:flex; align-items:center; gap:10px; width:100%; border:0;
  cursor:pointer; text-align:left; margin:0 0 10px; padding:10px 12px;
  border-radius:12px; background:linear-gradient(180deg,#33283F,#241A30);
  box-shadow:inset 0 0 0 1px var(--brass); }
.про-ясли { display:block; min-width:0; }
/* Зов на сведение — тот же вид, что у плашки яслей: оба говорят
   «решение созрело, вот дверь». Разный цвет канта развёл бы два
   одинаковых по смыслу сообщения на ровном месте. */
.зов-сведения { margin-bottom:10px; }
.зов-лавки { margin:12px 0; }
/* Заход — та же плашка: «решение созрело, вот дверь». Здесь решение
   в том, чтобы не оборвать серию. */
.зов-захода { margin-bottom:10px; }

/* ---------- заход: лестница серии ---------- */
/* Лестница показывается ЦЕЛИКОМ и в строку: вся её сила в том, что
   седьмой день видно с первого. Переносится по ширине, а не скроллится
   вбок — семь коротких ступеней помещаются, а горизонтальный скролл
   в списке из семи читается как поломка. */
.заход { display:flex; flex-direction:column; gap:12px; }
.ступени { display:flex; flex-wrap:wrap; gap:6px; }
.ступень-захода { flex:1 1 auto; text-align:center; padding:8px 6px; border-radius:10px;
  background:rgba(0,0,0,.24); color:var(--mauve);
  font:800 12px/1.2 var(--sans); font-variant-numeric:tabular-nums;
  white-space:nowrap; }
/* Пройденное гасим, а не прячем: лестница без пройденных ступеней
   перестаёт показывать, сколько уже пройдено, — то есть то самое,
   что игрок теряет при обрыве. */
.ступень-захода.пройдена { opacity:.5; box-shadow:inset 0 0 0 1px rgba(255,255,255,.06); }
.ступень-захода.сейчас { color:var(--lampLit); background:linear-gradient(180deg,#33283F,#241A30);
  box-shadow:inset 0 0 0 1px var(--brass); }
/* Плашка кладки — тот же вид, что ясли и заход: все трое говорят
   «решение созрело, вот дверь». */
.зов-кладки { margin-bottom:10px; }

/* Цель, которой служит рычаг кладки: то же слово, что на доске месяца
   и в заявке. Латунью, а не серым, — это не пояснение, а связь. */
.работа-цели { display:block; color:var(--lampLit); font-weight:800; }

/* ---------- гардероб и кузница ---------- */
/* Вещь карточкой: имя со следом, число прибавки, строка «на ком».
   След — тихим, потому что он про историю, а не про силу. */
.зов-вещей { margin:12px 0; }
.вещи { display:flex; flex-direction:column; gap:8px; margin:8px 0 12px; }
.вещь { background:rgba(0,0,0,.24); border-radius:14px; padding:10px 12px;
  display:flex; flex-direction:column; gap:4px; }
.вещь-имя { font:800 13px/1.25 var(--sans); color:var(--paper); }
.вещь-имя .тихо { display:block; font-weight:600; margin-top:2px; }
.вещь-числа { font:900 15px/1.1 var(--fat); color:var(--lampLit);
  font-variant-numeric:tabular-nums; }
.вещь-низ { display:flex; align-items:center; justify-content:space-between;
  gap:8px; flex-wrap:wrap; }

/* ---------- цель сведения ---------- */
/* Четыре цели в строку и «без цели» пятой: выбор ДОЛЖЕН быть виден
   целиком, иначе игрок не сравнивает, а угадывает. Под кнопками —
   строка о том, кого приведут: без неё четыре слова неразличимы. */
.выбор-цели { display:flex; flex-direction:column; gap:6px; margin:8px 0; }
.цели { display:flex; flex-wrap:wrap; gap:6px; }
.цель { border:0; cursor:pointer; padding:7px 10px; border-radius:10px;
  background:rgba(0,0,0,.24); color:var(--mauve);
  font:800 12px/1.2 var(--sans); }
.цель.выбрана { color:var(--lampLit);
  background:linear-gradient(180deg,#33283F,#241A30);
  box-shadow:inset 0 0 0 1px var(--brass); }
/* Материал, на который не хватает эссенции: гасим, но не прячем —
   иначе исчезает объяснение, к чему копить. */
.цель.беднота { opacity:.45; }
/* Фильтр чужих заявок стоит НАД списком и отступает от него: между
   «чем смотрю» и «что вижу» должна быть пауза, иначе кнопки читаются
   первой строкой списка. */
.фильтр-заявок { margin:2px 0 10px; }

/* Цель на чужой заявке: принимающий видит, чего от него ждут. */
.цель-заявки { font:800 11px/1.2 var(--sans); color:var(--lampLit); cursor:help; }

/* ---------- задания: вкладка «Дела» ---------- */
/* Срок — это заголовок группы, а не подпись под ней: игрок сначала
   решает, во что успеет, и только потом читает сами задания. */
.срок-заданий { display:flex; align-items:baseline; justify-content:space-between;
  gap:10px; margin:14px 0 6px; font:800 13px/1.2 var(--sans); color:var(--lamp); }
/* Задание — плашка в один столбец: имя, ход, награда. Ход стоит между
   ними намеренно — это единственное, что меняется само, и глаз находит
   его на одном месте у всех заданий сразу. */
.задание { background:rgba(0,0,0,.24); border-radius:14px; padding:10px 12px;
  display:flex; flex-direction:column; gap:7px; margin-bottom:8px; }
.задание-имя { font:800 13px/1.25 var(--sans); color:var(--paper); }
.задание-имя .тихо { display:block; font-weight:600; margin-top:2px; }
.задание-ход { display:flex; align-items:center; gap:9px; }
.задание-ход .полоса { max-width:none; flex:1; }
.задание-приз { display:flex; align-items:center; justify-content:space-between;
  gap:10px; min-height:26px; }
/* СВЁРНУТАЯ СТРОКА. Заголовок — сам по себе кнопка во всю ширину:
   попасть по стрелке пальцем нельзя, а по строке можно всегда. Кнопка
   «Забрать» стоит рядом, а не внутри: кнопка в кнопке промахивается —
   нажатие на выдачу схлопывало бы строку. */
.задание-строка { display:flex; align-items:center; gap:10px; }
.задание-шапка { flex:1; min-width:0; display:flex; align-items:center; gap:10px;
  padding:0; border:0; background:none; cursor:pointer; text-align:left;
  color:var(--paper); font:800 13px/1.25 var(--sans); }
.задание-шапка b { min-width:0; overflow:hidden; text-overflow:ellipsis;
  white-space:nowrap; }
/* Ход прижат вправо, к стрелке: у всех заданий он на одном месте,
   и глаз читает столбик чисел, а не ищет их в строках разной длины. */
.задание-шапка .тихо { margin-left:auto; font-weight:600; white-space:nowrap;
  font-variant-numeric:tabular-nums; }
.задание-метка { white-space:nowrap; }
.задание-нутро { display:flex; flex-direction:column; gap:7px; }
.задание-нутро .полоса { max-width:none; }
/* Раскрытое отделено от соседей кантом: иначе описание одного задания
   читается как продолжение следующего. */
.задание.раскрыто { box-shadow:inset 0 0 0 1px rgba(228,194,136,.18); }
/* Готовое к получению отмечено кантом, а не заливкой: заливка спорила бы
   с главной кнопкой экрана, а кант читается как «отмечено». */
.задание.готово { box-shadow:inset 0 0 0 1px var(--brass); }
.задание.готово .полоса i { background:linear-gradient(90deg,#B7802F,var(--lamp)); }
/* Взятое гасится, но не исчезает: пустое место читалось бы как потеря,
   а гашёная строка — как сделанное. */
.задание.взято { opacity:.5; }

/* Ярмарка на «Делах»: одна строка и по ссылке на каждую цель. Ссылка
   несёт своё расстояние — без него выбирать, куда идти, пришлось бы
   вслепую. */
.цели-ярмарки { display:flex; flex-direction:column; gap:6px; margin:8px 0 14px; }
.ссылка-цели { display:flex; align-items:center; gap:10px; width:100%;
  padding:9px 12px; border:0; border-radius:12px; cursor:pointer;
  background:rgba(0,0,0,.24); color:var(--paper); text-align:left;
  font:800 13px/1.2 var(--sans); }
.ссылка-цели .тихо { margin-left:auto; font-weight:600; }

/* Идущее сведение на «Мире» — СВОДКА, а не действие: без кнопки
   и приглушённое. Тем же весом, что заявка, оно спорило бы с живыми
   строками, у которых кнопка есть, — а решать по нему нечего. */
.заявка.идёт { opacity:.72; }

/* ---------- карта мира ---------- */
/* У мира есть МЕСТО, а не меню. Картинка держит пропорцию сама
   (`aspect-ratio`), поэтому доли областей не разъезжаются ни на каком
   телефоне: они привязаны к картинке, а не к экрану. */
.карта-мира { position:relative; margin:0 0 10px; border-radius:16px;
  overflow:hidden; aspect-ratio:1226/515;
  box-shadow:0 4px 0 rgba(0,0,0,.4), inset 0 0 0 1px rgba(154,119,66,.45); }
.вид-мира { display:block; width:100%; height:100%; object-fit:cover; }
/* ЖИВЫЕ ТОЧКИ НА КАРТЕ (владелец, 31 августа: «одна картинка, можно
   добавить анимацию, будет красиво»).

   Двигается НЕ КАРТИНКА, а два пятна света поверх неё: тёплый ореол над
   фонарём лавки и мягкое дыхание над шатрами Ярмарки. Анимировать саму
   картинку нечем — она растровая; а два слоя поверх стоят дёшево
   и не мешают нажатиям (`pointer-events:none`).

   Координаты в процентах привязаны к КОНКРЕТНОЙ картинке — к фонарю
   и к гирлянде на ней. При замене арта их правят вместе с ним.

   ДЫХАНИЕ, А НЕ МИГАНИЕ: период больше трёх секунд и амплитуда меньше
   трети. Быстрая пульсация на экране, куда заходят каждый день,
   превращается в раздражитель, а не в уют. */
.огонёк { position:absolute; pointer-events:none; border-radius:50%;
  mix-blend-mode:screen; }
.огонёк.лавка { left:19.5%; top:44%; width:9%; padding-bottom:9%;
  background:radial-gradient(circle, rgba(255,206,128,.55), transparent 68%);
  animation: дыхание 3.6s ease-in-out infinite; }
.огонёк.ярмарка { left:80%; top:36%; width:16%; padding-bottom:12%;
  background:radial-gradient(circle, rgba(255,222,160,.32), transparent 70%);
  animation: дыхание 5.2s ease-in-out infinite .8s; }
@keyframes дыхание {
  0%, 100% { opacity:.55; transform:scale(.96); }
  50%      { opacity:1;   transform:scale(1.06); }
}
/* Кто просил покоя — получает покой. Правило общее для всей игры,
   и новый слой не исключение. */
@media (prefers-reduced-motion: reduce) {
  .огонёк { animation:none; opacity:.8; }
}

/* Область — полоса во всю высоту: пальцем в крышу избы не попасть,
   а в полосу попадают всегда. Сама она невидима — видно постройку,
   которую она накрывает. */
.место-мира { position:absolute; top:0; bottom:0; padding:0; border:0;
  background:none; cursor:pointer; display:flex; align-items:flex-end;
  justify-content:center; }
/* Нажатие подсвечивает область, а не двигает её: сдвиг на картинке
   читался бы как поломка кадра. */
.место-мира:active { background:rgba(246,208,138,.14); }
/* Бирка — латунная табличка у подножия постройки. Тень под ней жёсткая:
   картинка снизу светлая и тёмная в разных местах, и без подложки
   подпись где-то пропадала бы. */
.бирка-мира { display:flex; flex-direction:column; align-items:center;
  gap:1px; margin-bottom:6px; padding:4px 9px; border-radius:9px;
  background:linear-gradient(180deg,rgba(36,26,48,.92),rgba(20,14,30,.94));
  box-shadow:0 1px 0 rgba(0,0,0,.6), inset 0 0 0 1px rgba(154,119,66,.55);
  max-width:96%; }
.бирка-мира b { font:800 11.5px/1.15 var(--sans); color:var(--lampLit);
  white-space:nowrap; }
.бирка-мира em { font:600 10px/1.15 var(--sans); font-style:normal;
  color:var(--dusk); white-space:nowrap; overflow:hidden;
  text-overflow:ellipsis; max-width:100%; }

/* ---------- сезон: лестница на три недели ---------- */
/* Шапка сезона — три числа в столбик: уровень, полоса, остаток. Полоса
   между цифрами намеренно: она и есть перевод «сколько жетонов»
   в «сколько пути», а число рядом отвечает тем, кто считает. */
.сезон-шапка { display:flex; flex-direction:column; gap:6px;
  background:rgba(0,0,0,.24); border-radius:14px; padding:11px 13px;
  margin:8px 0 10px; }
.сезон-уровень { font:900 17px/1.1 var(--fat); color:var(--lampLit); }
.сезон-шапка .полоса { max-width:none; height:7px; }
/* Плашка сезона на «Делах» зовёт, только когда есть что забрать: кант
   на ней иначе горел бы постоянно и перестал бы значить что-либо. */
.зов-яслей.зовёт { box-shadow:inset 0 0 0 1px var(--brass); }

/* Подписи веток стоят НАД лестницей, а не в каждой строке: тридцать
   раз «Всем / По пропуску» — это тридцать раз один и тот же текст. */
.ветки { display:grid; grid-template-columns:34px 1fr 1fr; gap:8px;
  padding:0 4px 4px; }
.ветки .тихо:first-child { grid-column:2; }
/* ИМЕНА СВОИ, А НЕ ОБЩИЕ (найдено владельцем на боевом 31 августа:
   «пишет, что я могу забрать награды, но я их не вижу»).

   `.ступень` в игре уже занята ДВАЖДЫ: это бирка тира на коконе
   (`position:absolute`) и ступенька лестницы захода (`flex`). Третье
   правило с тем же именем перекрыло `display`, но НЕ перекрыло
   `position:absolute` от бирки — и все тридцать строк лестницы сезона
   легли одна на другую в углу родителя. Разметка была, данные были,
   на экране не было ничего.

   Страж стилей этого не ловил: класс описан, и описан трижды. Ловит
   он «класс есть в разметке, но не в стилях», а не «одно имя — три
   значения». Отсюда правило: экран, вводящий свои элементы, называет
   их своими именами. */
.лестница-сезона { display:flex; flex-direction:column; gap:6px; }
.ступень-сезона { display:grid; grid-template-columns:34px 1fr 1fr; gap:8px;
  align-items:stretch; }
.ступень-номер { display:flex; align-items:center; justify-content:center;
  border-radius:10px; background:rgba(0,0,0,.28); color:var(--dusk);
  font:900 13px/1 var(--fat); font-variant-numeric:tabular-nums; }
/* Достигнутая ступень отмечена номером, а не всей строкой: подсветить
   строку целиком значило бы спорить с кнопкой «Забрать» внутри неё. */
.ступень-сезона.открыта .ступень-номер { background:linear-gradient(180deg,#3A2C42,#241A30);
  color:var(--lampLit); box-shadow:inset 0 0 0 1px var(--brass); }
.ступень-приз { display:flex; flex-direction:column; gap:5px; min-width:0;
  background:rgba(0,0,0,.24); border-radius:12px; padding:8px 10px; }
.ступень-приз .тихо { overflow:hidden; text-overflow:ellipsis; }
/* НАГРАДА ЗНАКОМ И ЧИСЛОМ. Знак крупнее числа: силуэт различается
   с одного взгляда, число читают, только когда уже поняли, чтó это.
   Цифры табличные — тридцать строк выстраиваются в столбик. */
.приз-знак { display:flex; align-items:baseline; gap:6px;
  font:900 14px/1.1 var(--fat); color:var(--paper);
  font-variant-numeric:tabular-nums; }
.приз-знак i { font-style:normal; font-size:18px; line-height:1;
  color:var(--lampLit); }
/* Закрытая ветка ГАСИТСЯ, но не прячется: спрятанное не покупают,
   а главное — игрок должен видеть, что именно проходит мимо. */
.ступень-приз.закрыта { opacity:.45; }
.ступень-приз.взята { opacity:.6; }

.тарифы { display:flex; flex-direction:column; gap:8px; margin:8px 0 12px; }
/* Средний тариф выделен кантом — тем же знаком «отмечено», что у готового
   задания и проходящей доски. Своего цвета у него нет: три разных
   выделения на экране спорят друг с другом. */
.кнопка.видный { box-shadow:inset 0 0 0 2px var(--brass), 0 3px 0 rgba(0,0,0,.4); }

/* ---------- экран рейтингов ---------- */
/* Переключатели вместо четырёх чисел разом: единицы у досок разные —
   колена, признаки, победы, пары, — и рядом они не сравниваются. */
/* РОВНО ПО КРАЯМ (владелец, 31 августа): левый прижат влево, правый
   вправо, остальные разложены между ними. При растягивании кнопок
   на равную долю («Род» и «Уникальность» рядом) короткое слово получало
   столько же места, сколько длинное, и ряд читался как набор пустых
   плашек разной наполненности. */
.переключатели { display:flex; flex-wrap:wrap; justify-content:space-between;
  gap:6px; margin-bottom:10px; }
.переключатель { flex:0 1 auto; padding:7px 12px; border:0; border-radius:999px;
  cursor:pointer; background:rgba(0,0,0,.28); color:var(--dusk);
  font:800 12px/1.2 var(--sans); }
.переключатель.на { background:linear-gradient(180deg,#3A2C42,#241A30);
  color:var(--lampLit); box-shadow:inset 0 0 0 1px var(--brass); }
/* Выбранная доска показывается целиком и крупно — ради этого экран
   и заведён.

   ФОН ТЁМНЫЙ, А НЕ КАНАТ (владелец, 31 августа: «текст на плашке
   не виден»). Плашка стояла на `.сцена` — золотой канат с заклёпками,
   и приглушённые подписи («тихо») по нему не читались вовсе: рама
   рассчитана на портрет, а не на текст. */
.доска-крупно { text-align:left; padding:14px 16px; margin-bottom:12px; }
.доска-крупно .доска-число { font-size:26px; margin:4px 0 6px; }
/* Строка «что сделать», когда сделать уже нечего. Тот же кант, что
   у проходящей доски и у готового задания: один знак «отмечено»
   на всю игру. */
.счёт.проходит { box-shadow:inset 0 0 0 1px var(--brass); color:var(--lampLit); }

/* ---------- доски месяца ---------- */
/* Четыре доски сеткой по две: в столбик они уводят опись за край экрана,
   в одну строку — не помещаются на телефоне. Своё число крупное, лидер
   и место мелкие: «вы 4 712-й» не отвечает ни на один вопрос игрока. */
.доски { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:8px;
  margin:8px 0 12px; }
.доска { background:rgba(0,0,0,.24); border-radius:14px; padding:10px 12px;
  display:flex; flex-direction:column; gap:4px; min-width:0; }
.доска-имя { font:800 13px/1.2 var(--sans); color:var(--paper); }
.доска-имя .тихо { display:block; font-weight:600; margin-top:2px; }
.доска-число { font:900 20px/1.1 var(--fat); color:var(--lampLit);
  font-variant-numeric:tabular-nums; }
.доска-низ { display:flex; flex-wrap:wrap; gap:4px 8px; align-items:baseline; }
.доска-место { font:700 11px/1.2 var(--sans); color:var(--dusk);
  font-variant-numeric:tabular-nums; }
/* Доска без приза не прячется и не гасится: она честная доска, просто
   не цель Ярмарки. Гашение прочиталось бы как «недоделана». */
.доска.безприза { box-shadow:inset 0 0 0 1px rgba(255,255,255,.05); }
.доска-безприза { font:700 10.5px/1.2 var(--sans); color:var(--dusk);
  cursor:help; }
/* Доска, по которой игрок проходит на Ярмарку. Кант, а не заливка:
   заливка спорила бы с выбранной целью и с текущей ступенью захода,
   а кант читается как «отмечено», не как «нажато». */
.доска.проходит { box-shadow:inset 0 0 0 1px var(--brass); }

/* Летопись смотров — самое неспешное на вкладке, где и так всё
   неспешно. Строки в столбик, моноширинные числа: их сравнивают. */
.летопись { display:flex; flex-direction:column; gap:4px; margin:6px 0 12px; }
.строка-летописи { font:600 12px/1.35 var(--sans); color:var(--mauve);
  font-variant-numeric:tabular-nums; }
/* Зачем Круг — над кнопкой: пока не сказано, бой читается углом,
   не связанным с игрой. */
.намёк.зачем-круг { margin-bottom:8px; }
.намёк.зачем-круг b { display:block; color:var(--lampLit); }

/* Товар: что даёт — крупнее, чем как называется. Цена стоит кнопкой:
   нажать и узнать цену — это две разные вещи, и разделять их незачем. */
.товар { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:6px 12px;
  align-items:center; padding:11px 12px; margin-bottom:8px; border-radius:13px;
  background:linear-gradient(180deg,var(--shelf),#241A30);
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.товар.нельзя { opacity:.62; box-shadow:none; background:rgba(0,0,0,.25); }
.про-товар { min-width:0; }
.имя-товара { font:900 13.5px/1.15 var(--fat); }
.имя-товара em { font:italic 700 11px/1 var(--sans); color:var(--moss); }
.что-даёт { font-size:11.5px; color:var(--mauve); margin-top:2px; }
.лимит { font-size:11px; color:var(--dusk); margin-top:2px; }
.товар .отказ { grid-column:1 / -1; font-size:11.5px; color:var(--clay); }
/* Тупик — единственная плашка цветом беды: остальные предлагают
   возможность, эта сообщает, что игра встала. */
.намёк.тупик { box-shadow:inset 0 0 0 1px rgba(196,102,92,.5);
  background:rgba(196,102,92,.12); margin-bottom:10px; }
.намёк.тупик b { color:var(--clay); }
.намёк.тупик .кнопка { margin-top:8px; }
/* «Оставить себе» — решение с ценой: место навсегда. Латунный кант,
   как у прочих решений, а не цвет беды: это не поломка, а выбор. */
.намёк.оставить { box-shadow:inset 0 0 0 1px var(--brass); margin-top:10px; }
.намёк.оставить b { color:var(--lampLit); display:block; }
.намёк.оставить .кнопка { margin-top:8px; }
.про-ясли b { display:block; font:800 13px/1.2 var(--fat); color:var(--lampLit); }
.про-ясли span { font:400 11.5px/1.3 var(--sans); color:var(--mauve); }
.стрелка-яслей { margin-left:auto; font-style:normal; color:var(--lamp); font-size:18px; }

/* Строка внутри намёка: заголовок и пояснение — разные строки. Слитые,
   они читаются одним предложением, и первое слово пояснения прилипает
   к последнему слову заголовка. */
.намёк .строкой { display:block; margin-top:3px; }
/* Тихая кнопка: действие второго ряда. Золото на экране принадлежит
   тому, ради чего экран открыт, — «принять», а не «отпустить». */
.кнопка.тихая { background:linear-gradient(180deg,#2A2136,#221A2E);
  color:var(--dusk); box-shadow:inset 0 1px 0 rgba(232,206,150,.1); }

/* Малыш в яслях: лицо, признаки, числа и две кнопки. Числа здесь
   не украшение — по ним выбирают, кого принять на единственное место. */
.малыш { display:grid; grid-template-columns:64px minmax(0,1fr); gap:11px;
  padding:11px; margin-bottom:9px; border-radius:14px;
  background:linear-gradient(180deg,var(--shelf),#241A30);
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.лицо-малыша { width:64px; height:64px; border-radius:13px; overflow:hidden;
  background:rgba(0,0,0,.35); display:block; }
/* Тем же правилом, что кружок: голова в кадре, поля за краем.
   Мера по умолчанию — малыша разглядывают так же, как выбирают бойца. */
.про-малыша { min-width:0; }
.имя-малыша { font:900 14px/1.1 var(--fat); }
.откуда { font-size:11px; color:var(--dusk); margin-top:2px; }
/* Срок виден цветом беды: часы идут только у лишних, и это
   единственная в игре потеря — о ней предупреждают заранее. */
.срок-яслей { font:700 11.5px/1.2 var(--sans); color:var(--clay); margin-top:3px; }
.пр { font:700 10.5px/1 var(--sans); padding:4px 7px; border-radius:8px;
  background:rgba(0,0,0,.3); color:var(--paper);
  box-shadow:inset 0 0 0 1px rgba(154,119,66,.35); }
.кнопки-малыша { grid-column:1 / -1; display:flex; gap:7px; }
.кнопки-малыша .кнопка { flex:1; }

/* Отдел Службы: плата справа, отказ — своей строкой и своим цветом.
   Отказ говорит ПОЧЕМУ, а не гасит кнопку молча. */
.отдел { display:grid; grid-template-columns:minmax(0,1fr) auto; gap:8px 12px;
  align-items:center; padding:11px 12px; margin-bottom:8px; border-radius:13px;
  background:linear-gradient(180deg,var(--shelf),#241A30);
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.отдел.нельзя { opacity:.6; box-shadow:none; background:rgba(0,0,0,.25); }
.про-отдел { min-width:0; }
.имя-отдела { font:900 13.5px/1.15 var(--fat); }
.берут { font-size:11px; color:var(--dusk); margin-top:2px; }
.плата { text-align:right; font:900 15px/1 var(--fat); color:var(--moss);
  white-space:nowrap; }
.отдел.нельзя .плата { color:var(--dusk); }
.зачем { grid-column:1 / -1; font-size:11.5px; color:var(--mauve); }
.отказ { grid-column:1 / -1; font-size:11.5px; color:var(--clay); }
.отдел-взять { grid-column:1 / -1; }
/* Предупреждение о ценном существе — цветом беды, а не намёка:
   после этого шага записи не вернуть. */
.строгое { border-radius:12px; padding:11px 12px; margin-top:10px;
  background:rgba(196,102,92,.14); box-shadow:inset 0 0 0 1px rgba(196,102,92,.5);
  font-size:12.5px; }
.строгое b { display:block; color:var(--clay); font:900 13px/1.2 var(--fat);
  margin-bottom:4px; }
.тихо-намёк { color:var(--dusk); font-size:11.5px; }

/* ---------- показ боя ---------- */
/* Строй напротив строя: пара бьётся с парой, и это правило боя,
   а не украшение (`targetFor`). Сегодня в Круге один на один — разметка
   собрана рядами с первого дня, чтобы команды не переписывали её потом
   целиком. */
.поле-боя { position:relative; padding:10px 4px 4px; }
.пара { display:grid; grid-template-columns:1fr 34px 1fr; align-items:center;
  gap:6px; margin-bottom:8px; }
.пара:last-child { margin-bottom:0; }
.нить { height:1px; background:linear-gradient(90deg,transparent,
  rgba(232,206,150,.16),transparent); }
.поле-боя .боец { display:flex; flex-direction:column; align-items:center; gap:4px;
  min-width:0; }
.поле-боя .боец b { font:800 11px/1.1 var(--fat); max-width:110px; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.поле-боя .лицо-боя { position:relative; width:96px; height:96px; }
.боец.пал { opacity:.35; filter:grayscale(1); }
.боец.пал .лицо-боя { transform:rotate(-6deg); }
/* Полоса здоровья: своя латунная, чужая мшистая — сторону видно
   боковым зрением, не читая имён. */
.полоса { width:100%; max-width:118px; height:5px; border-radius:3px;
  background:rgba(0,0,0,.5); overflow:hidden; }
.полоса i { display:block; height:100%; transition:width .28s ease;
  background:linear-gradient(90deg,#6E9E6E,var(--moss)); }
.боец.мой .полоса i { background:linear-gradient(90deg,#B7802F,var(--lamp)); }
.вспышка { position:absolute; inset:0; background:var(--clay); opacity:0;
  pointer-events:none; }
.боец.цель .вспышка { animation:мигнуть .28s; }
.боец.цель .лицо-боя { animation:тряска .26s; }
@keyframes тряска { 0%{transform:translateX(0)} 25%{transform:translateX(5px)}
  60%{transform:translateX(-4px)} 100%{transform:translateX(0)} }
@keyframes мигнуть { 0%{opacity:.5} 100%{opacity:0} }
/* СЛЕД — сам удар. Поворот держит обёртка, растяжение — вложенный
   элемент: анимация `transform: scaleX(...)` затирает inline-поворот
   целиком, и на макете из-за этого все следы летели вправо. */
.след { position:absolute; transform-origin:0 50%; pointer-events:none; }
.след i { display:block; height:14px; border-radius:10px; filter:blur(2px);
  transform-origin:0 50%; animation:чирк .3s ease-out forwards;
  background:linear-gradient(90deg,rgba(246,208,138,0),rgba(246,208,138,.9),
    rgba(246,208,138,0)); }
.след.крит i { height:20px;
  background:linear-gradient(90deg,rgba(246,208,138,0),#FFF2CF,rgba(216,156,66,0)); }
.след.мимо i { height:10px;
  background:linear-gradient(90deg,rgba(185,166,192,0),rgba(185,166,192,.5),
    rgba(185,166,192,0)); }
@keyframes чирк { 0%{transform:scaleX(.05);opacity:0}
  30%{transform:scaleX(1);opacity:1} 100%{transform:scaleX(1);opacity:0} }
.цифра { position:absolute; font:900 15px/1 var(--fat); color:var(--clay);
  text-shadow:0 2px 0 rgba(0,0,0,.6); pointer-events:none;
  animation:всплыть .85s ease-out forwards; }
.цифра.крит { color:var(--lampLit); font-size:20px; }
@keyframes всплыть { 0%{transform:translateY(0);opacity:0}
  20%{opacity:1} 100%{transform:translateY(-26px);opacity:0} }
/* Лог во время боя занимает нижнюю половину и прокручивается сам:
   свежая строка обязана быть видна без единого движения пальцем. */
.ход-лог { max-height:38vh; overflow-y:auto; margin-top:8px; }
.поле-боя .пусто-место { visibility:hidden; }

/* ---------- бой ---------- */
/* ИТОГ БОЯ: строи, исход, рассказ, и только потом лог.
   Размер лица говорит исход раньше заголовка — победившая сторона
   на треть крупнее. Признаков и вещей вокруг нет намеренно (владелец,
   29 августа): на этом экране существо смотрят как бойца, а не как
   набор слотов.
   СТОРОНА ЦЕЛИКОМ, а не первый её боец: команды появятся позже,
   и разметка ждёт их с первого дня. */
.строи { display:flex; align-items:flex-end; justify-content:center;
  gap:12px; margin-top:12px; }
.строй { display:flex; flex-direction:column; align-items:center; gap:6px;
  min-width:0; }
.против { color:var(--dusk); font:900 16px/1 var(--fat); padding-bottom:26px; }
.боец { display:flex; flex-direction:column; align-items:center; gap:6px;
  min-width:0; }
.боец b { font:900 13px/1.1 var(--fat); color:var(--paper);
  max-width:120px; text-align:center; overflow-wrap:anywhere; }
/* Лицо ужимается с ростом строя: пятеро по 96 px в телефон не влезут. */
.лицо-боя { display:block; width:var(--лицо,96px); height:var(--лицо,96px);
  border-radius:18px; overflow:hidden; background:rgba(0,0,0,.3);
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
/* В БОЮ КАДР ШИРЕ. Здесь существо не опознают, а СМОТРЯТ, как оно
   дерётся: рывок и удар видны телом, а не мордой. Тот же приём,
   другая мера — фокус ниже, увеличение меньше. */
.лицо-боя { --фокус:40%; --крупно:1.15; }
.строй.победил .лицо-боя { width:calc(var(--лицо,96px)*1.33);
  height:calc(var(--лицо,96px)*1.33);
  box-shadow:0 3px 0 rgba(0,0,0,.4), inset 0 0 0 2px var(--lamp); }
.строй.победил b { color:var(--lampLit); }
.строй.проиграл .лицо-боя { filter:saturate(.55) brightness(.8); }
.строй.проиграл b { color:var(--dusk); }
/* Что получили и что нажили. Стоит между исходом и рассказом: это
   ответ на вопрос «а мне что с этого», и он не должен ждать под логом. */
.нажитое { display:flex; flex-direction:column; align-items:center; gap:4px;
  margin-top:10px; }
.дано { font:900 15px/1 var(--fat); color:var(--moss); }
.предел { font:700 12px/1.3 var(--sans); color:var(--dusk); text-align:center; }
/* Примета — событие, а не строка отчёта: её видно раньше, чем прочтут. */
.примета { margin-top:4px; padding:6px 12px; border-radius:12px;
  background:rgba(0,0,0,.3); box-shadow:inset 0 0 0 1px var(--brass);
  font:800 12.5px/1 var(--fat); color:var(--lampLit); }

/* Рассказ о бое — единственная строка, которую читают всегда,
   поэтому ей воздух и крупнее кегль лога. */
.рассказ { margin:10px 2px 0; font:400 14px/1.45 var(--sans);
  color:var(--paper); text-align:center; text-wrap:balance; }
/* Лог убирается под кнопку: он нужен не каждый раз, а место занимает
   всё (владелец, 29 августа: «лог боя может скрываться и открываться»). */
.ход-боя { display:block; width:100%; margin:12px 0 0; border:0; cursor:pointer;
  border-radius:12px; padding:9px 10px;
  background:linear-gradient(180deg,#2A2136,#221A2E); color:var(--dusk);
  font:800 12px/1 var(--fat);
  box-shadow:inset 0 1px 0 rgba(232,206,150,.1); }
.лог { background:linear-gradient(180deg,#2A2136,#221A2E); padding:11px 13px;
  box-shadow:inset 0 1px 0 rgba(232,206,150,.1); }
.строка-боя { font-size:12px; color:var(--mauve); padding:3px 0;
  border-bottom:1px solid rgba(255,255,255,.05); }
.строка-боя.раунд { color:var(--lamp); font-weight:800; margin-top:7px;
  border-bottom:0; }
.строка-боя.пал { color:var(--clay); font-weight:800; }
/* Ремарка без числа — единственная строка лога, которая ничего
   не считает. Курсив отделяет её от отчёта: глаз, ищущий урон,
   проходит мимо. */
.строка-боя.волосок { font-style:italic; color:var(--dusk); }

@media (prefers-reduced-motion: reduce) {
  * { animation:none !important; transition:none !important; }
}

/* ---------- карточка существа: метки по бокам, вещи под именем ----------
   Макет утверждён владельцем 28 августа. Левый столбец — верх тела,
   правый — низ: столбик читается как само существо. Пустые места видны
   рамкой — так «шесть признаков из восьми» видно без единого слова. */
/* РАЗМЕР СЧИТАЕТСЯ ОТ ЭКРАНА, А НЕ ОТ КАРТИНКИ.
   Здесь стояло `1fr` без `minmax(0,…)`: элемент сетки по умолчанию
   не уже своего содержимого, и портрет в тысячу точек растягивал
   колонку — страница уезжала вбок, у слов срезало первые буквы.
   Высота ограничена долей экрана: карточка обязана помещаться
   целиком, иначе слоты по краям не видно без прокрутки. */
.карточка-сцена .герой { max-height:34dvh; }
/* СЦЕНА НЕ РЕЗИНОВАЯ (владелец, 28 августа).
   Растягивающаяся сцена сжимала портрет на коротком экране, слоты
   признаков съезжали ниже картинки, а кнопки взамен росли в высоту.
   Теперь у сцены постоянная пропорция: слоты стоят там же относительно
   существа при любом экране. Не помещается — страница прокручивается
   внутри, и это честнее, чем менять макет под высоту окна. */
/* ХАБ ПРОКРУЧИВАЕТСЯ САМ. Без `overflow-y` содержимое, не влезшее
   в столбец, просто обрезалось: замер на 390pt — высота содержимого 821
   при окне 495, и `scrollTop` оставался нулём, потому что прокручивать
   было нечему. Так и пропадала ссылка на существо: она не «уезжала
   под кнопки», её было не достать вовсе.
   `overscroll-behavior` — чтобы прокрутка хаба не утягивала за собой
   страницу Telegram, закрывая мини-приложение жестом вниз. */
.pen-хаб { display:flex; flex-direction:column; flex:1 1 auto; min-height:0;
  gap:0; overflow-y:auto; overscroll-behavior:contain; }
.pen-хаб .сцена { flex:0 0 auto; }
/* СЦЕНА НА ХАБЕ НИЖЕ, ЧЕМ НА КАРТОЧКЕ (владелец, 29 августа:
   «сделай блок чуть меньше, чтобы снизу поднялись род, совершенство
   и характеристики»).

   Замер до правки: сцена 429 px при окне 677 — шестьдесят три процента
   экрана на портрет, а три сворачиваемых блока и кнопки уезжали
   за нижний край на 205 px.

   Пропорция остаётся постоянной — «сцена не резиновая» (28 августа),
   слоты признаков не съезжают, — но 3/2 вместо 5/4 отдаёт портрету
   на треть меньше высоты. Хабу это верно: там портрет узнают,
   а рассматривают на карточке существа. */
/* ВЫСОТУ СЦЕНЫ НА ХАБЕ ЗАДАЁТ ПОРТРЕТ, А НЕ ПРОПОРЦИЯ.
   
   `aspect-ratio` тут не работает и работать не может: высота ряда сетки
   определяется содержимым, картинка с `height:100%` от неопределённой
   высоты берёт свою природную — и растягивает рамку обратно. Замер:
   при пропорции 3/2 сцена оставалась 420 px вместо 357.
   Пропорция с потолком в картинке дала другую беду — рамка держала
   старую высоту, а под уменьшенным портретом зияла латунная пустота.

   Поэтому правило простое: потолок ставим КАРТИНКЕ, рамка следует
   за ней. Слоты признаков идут теми же четырьмя долями и остаются
   на своих местах относительно существа — то, ради чего 28 августа
   сцену делали непружинящей.

   Потолок подобран замером, а не на глаз: при 26dvh два блока из трёх
   всё ещё уходили под нижний ряд (содержимое 613 при окне 571).
   При 21dvh сцена 420 → 178 px, и все три видны сразу. */
.pen-хаб .карточка-сцена .герой { height:auto; max-height:21dvh;
  object-fit:contain; }
/* НИЖНИЙ РЯД — НЕВЫСОКИЙ (владелец, 28 августа: «сделай кнопки
   покормить и сложить коконы меньше по высоте, такие же, как на Мире»).
   Содержимое в строку, а не столбиком: цена и часы рядом с глаголом,
   а не под ним — от этого кнопка и была вдвое выше нужного. */
.pen-хаб .действия .кнопка { min-height:0; flex-direction:row; flex-wrap:wrap;
  align-items:center; justify-content:center; gap:8px;
  padding:11px 12px 13px; font-size:15px; }
.pen-хаб .действия .кнопка b { font-size:16px; }
.pen-хаб .действия .кнопка .часы { display:inline; margin:0; font-size:11px; }
.pen-хаб .вещи, .pen-хаб .ссылка-строкой, .pen-хаб .места,
.pen-хаб .действия, .pen-хаб .блок { flex:0 0 auto; }
/* КНОПКИ ПРИКЛЕЕНЫ К НИЖНЕМУ РЯДУ, А ЭКРАН ЕЗДИТ ПОД НИМИ
   (владелец, 28 августа: «кнопки ушли вниз, а должны быть прикреплены
   к нижнему меню, уходить под кнопки должен экран существа»).

   `margin-top:auto` прижимал их к низу СОДЕРЖИМОГО — а содержимое
   на большом экране длиннее окна, и кнопки уезжали вместе с ним.
   Липкий низ держит их на месте всегда: сцена прокручивается под ними.

   Ряд мест едет вместе с кнопками: выбрать, кого кормить, нужно ровно
   там же, где кормят. */
/* ОДИН ЛИПКИЙ БЛОК ВМЕСТО ТРЁХ.
   Раньше липли ряд мест и ряд кнопок по отдельности, каждый со своим
   `bottom`. Всё, что стояло в потоке ВЫШЕ них, при прокрутке до конца
   пряталось под ними — так пропадала ссылка на существо (замер 390pt:
   перекрытие 28 px). Достать её было нечем: липкий ряд держится выше
   своего места в потоке, и прокрутка на него не действует.

   Теперь низ — один блок: что попало в него, видно всегда; что осталось
   в сцене, честно прокручивается и ни подо что не уходит. Складывать
   `bottom` для каждой полосы больше не нужно, и разъехаться им негде. */
.pen-хаб .низ { position:sticky; bottom:0; z-index:4; margin-top:auto;
  background:var(--night); padding:2px 0 8px;
  box-shadow:0 -8px 12px -6px rgba(0,0,0,.6); }
.pen-хаб .низ .места { padding:6px 0 2px; }
.pen-хаб .низ .ссылка-строкой { margin:2px auto 0; }
.карточка-сцена { display:grid; grid-template-columns:52px minmax(0,1fr) 52px;
  gap:6px; align-items:stretch; }
.слоты { display:flex; flex-direction:column; justify-content:space-between;
  gap:6px; }
/* Столбцы задаются ЯВНО, а не порядком в разметке: порядок молчит,
   и перестановка двух строк местами меняла бы верх тела с низом,
   не оставляя следа ни в стилях, ни в проверке. Классы `слева`/`справа`
   стояли в разметке с самого начала и не значили ничего — их нашёл
   страж, когда научился смотреть в `shared/core/`. */
.слоты.слева { grid-column:1; }
.слоты.справа { grid-column:3; }
/* Нижний предел места метки — 36 px: ниже подпись в два слова перестаёт
   помещаться. Было 44, и именно эти четыре места держали высоту сцены
   (216 px при портрете 176): пропорция и потолок картинки упирались
   в столбик слотов, а не наоборот. */
.слот, .вещь { flex:1; min-height:36px; border-radius:12px; display:flex;
  align-items:center; justify-content:center; padding:4px; text-align:center;
  background:rgba(0,0,0,.28); box-shadow:inset 0 0 0 1px rgba(154,119,66,.35); }
/* Место, которое ещё не назвали: карточка в пути. Форма та же, надписи
   нет — иначе на долю секунды появлялся бы текст, который тут же
   сменится другим. */
.слот.ждёт { opacity:.55; }
.слот em, .вещь em { font:700 9px/1.15 var(--sans); font-style:normal;
  color:var(--dusk); overflow:hidden; }
.слот.занят, .вещь.занята {
  background:linear-gradient(180deg,#3A2C42,#241A30);
  box-shadow:inset 0 1px 0 rgba(232,206,150,.18), 0 2px 0 rgba(0,0,0,.4); }
.слот.занят em, .вещь.занята em { color:var(--paper); }
/* Ссылка строкой: нужна редко, кнопкой спорила бы за внимание
   с кормлением — а первый шаг игры именно кормление. */
/* Ссылки строкой: «Скопировать ссылку» и «Отправить на службу» равны
   по весу и стоят рядом. Значок перед словами — чтобы глаз находил
   нужную, не читая обе. */
.ссылки { display:flex; flex-wrap:wrap; justify-content:center; gap:6px 18px;
  margin-top:10px; }
.ссылка-строкой { display:inline-flex; align-items:center; gap:5px;
  margin:10px auto 0; background:none; border:0;
  cursor:pointer; color:var(--brass); font:700 12px/1 var(--sans);
  text-decoration:underline; text-underline-offset:3px; }
.ссылки .ссылка-строкой { margin:0; }
.ссылка-строкой i { font-style:normal; font-size:13px; text-decoration:none; }

/* Заголовок внешней страницы: имя существа. В игре ту же роль играет
   шапка экрана — отсюда одно правило и один вид. */
.карточка-внешняя ~ .cta { margin-top:16px; }
/* Заливка градиентом ПО ТЕКСТУ снята: вместе с тенью корпуса она
   двоила буквы на телефоне владельца — тень рисуется под всем блоком,
   а не под буквами, и вылезала из-под прозрачного текста. */
.top h1 { margin:0 0 14px; font:900 24px/1.1 var(--fat); letter-spacing:-.02em;
  color:var(--lamp); text-shadow:0 2px 0 rgba(0,0,0,.45); }
/* Три места под вещи: занятое — плашка с именем, пустое — вдавленное
   гнездо с кольцом. Слов у пустого нет: пустая рамка и так пуста,
   а три «пусто» подряд читаются как содержимое. */
.вещи { display:grid; grid-template-columns:repeat(3,1fr); gap:8px;
  margin-top:10px; }
.вещь { min-height:46px; position:relative; }
.вещь:not(.занята) { background:
    radial-gradient(ellipse 42% 30% at 50% 60%,rgba(0,0,0,.45),transparent 75%),
    linear-gradient(180deg,#150F20,#221A2E);
  box-shadow:inset 0 3px 7px rgba(0,0,0,.7), inset 0 -1px 0 rgba(228,194,136,.1); }
/* Кольцо — знак места: сюда что-то входит. Тонкое и тихое, чтобы
   не спорить с занятыми. */
.вещь:not(.занята)::after { content:''; position:absolute; width:18px; height:18px;
  border-radius:50%; border:1.5px dashed rgba(154,119,66,.55); }

/* Внешняя страница карточки: та же таблица стилей, что и в игре.
   Обёртка даёт ей поля и фон — остальное уже описано выше. */
.wrap { max-width:560px; margin:0 auto; padding:16px 12px 28px; }
.карточка-внешняя { margin-bottom:16px; }
.cta { display:block; text-align:center; text-decoration:none; border-radius:16px;
  padding:15px 14px 17px; font:900 16px/1.1 var(--fat); color:var(--lampInk);
  background:linear-gradient(180deg,var(--lampTop),var(--lampBot));
  box-shadow:0 4px 0 var(--lampDeep), inset 0 1px 0 var(--lampLit); }
.foot { color:var(--dusk); font-size:12px; text-align:center; margin-top:14px; }

/* Складывающиеся блоки карточки: `details` складывается сам, без кода,
   и потому одинаково работает в игре и на внешней странице. */
.блок { margin:0; }
.блок > summary { list-style:none; cursor:pointer; display:flex;
  align-items:center; gap:6px; }
.блок > summary::-webkit-details-marker { display:none; }
.блок > summary::after { content:'⌄'; font:900 14px/1 var(--sans);
  color:var(--brass); transition:transform .12s; }
.блок[open] > summary::after { transform:rotate(180deg); }
/* СВЁРНУТЫЙ БЛОК ПРЯЧЕТ СОДЕРЖИМОЕ ЯВНО.
   Браузер прячет содержимое `details` своим правилом, но собственный
   `display` у ребёнка его перебивает: `.числа` объявлены сеткой, и блок
   складывался только на вид — стрелка поворачивалась, числа оставались.
   Поймано замером высоты, а не глазами: 40 px до и 40 после. */
.блок:not([open]) > *:not(summary) { display:none; }

/* Кладка: что ведём и насколько подняли. Число множителя — главное
   на экране, поэтому оно и крупнее всего. */
.кладка { background:linear-gradient(180deg,var(--shelf),#241A30);
  border-radius:18px; padding:14px; text-align:center;
  box-shadow:0 4px 0 rgba(0,0,0,.4), inset 0 1px 0 rgba(232,206,150,.12); }
.кладка-цель { font:800 13px/1.2 var(--fat); color:var(--lamp); }
.кладка-множ { font:900 22px/1.2 var(--fat); margin:6px 0 2px; }
.кнопка[disabled] { opacity:.6; cursor:default; }

/* Переключатель поля и запаса: коконы одни и те же, поэтому один экран
   и две вкладки, а не два адреса с разными глаголами. */
.переключатель { display:flex; gap:6px; margin-bottom:10px; }
.пере { flex:1; border:0; cursor:pointer; border-radius:12px; padding:9px 8px;
  background:linear-gradient(180deg,#2A2136,#221A2E); color:var(--dusk);
  font:800 12px/1 var(--fat); box-shadow:inset 0 1px 0 rgba(232,206,150,.1); }
.пере.на { background:linear-gradient(180deg,#4B3A46,#332538); color:var(--lampLit);
  box-shadow:inset 0 0 0 1px var(--brass); }

/* Галочка автобоя. Кнопка, а не `input`: у настоящей галочки внутри
   ярлыка нажатие приходит дважды — на ярлык и на поле, — и общий
   обработчик оболочки переключил бы её туда и обратно. */
.галочка { display:flex; align-items:center; gap:9px; width:100%;
  margin:0 0 10px; border:0; cursor:pointer; border-radius:12px;
  padding:9px 11px; text-align:left;
  background:linear-gradient(180deg,#2A2136,#221A2E); color:var(--dusk);
  font:700 12.5px/1.2 var(--sans);
  box-shadow:inset 0 1px 0 rgba(232,206,150,.1); }
.галочка.на { color:var(--lampLit); box-shadow:inset 0 0 0 1px var(--brass); }
.птичка { width:16px; height:16px; flex:none; border-radius:5px;
  background:rgba(0,0,0,.35); box-shadow:inset 0 0 0 1px rgba(232,206,150,.25);
  position:relative; }
.галочка.на .птичка { background:var(--lamp); }
.галочка.на .птичка::after { content:''; position:absolute;
  left:5px; top:1px; width:4px; height:9px; border:solid var(--parchInk);
  border-width:0 2px 2px 0; transform:rotate(42deg); }

/* Чужая заявка: признаки — главное на строке, потому что ради них
   её и принимают. Новый для игрока выделен, ничей в мире — сильнее. */
.заявка.чужая { flex-direction:column; align-items:stretch; }
.строка-заявки { display:flex; flex-wrap:wrap; gap:6px 10px; align-items:baseline; }
.счёт-новых { margin-left:auto; font:800 11px/1 var(--fat); color:var(--moss); }
.признаки { display:flex; flex-wrap:wrap; gap:6px; margin:8px 0 2px; }
.признак { display:block; padding:5px 9px; border-radius:10px;
  background:rgba(0,0,0,.28); font-size:12px; color:var(--dusk); }
.признак b { display:block; font:800 12px/1.2 var(--fat); color:var(--paper); }
.признак em { font:400 10px/1.3 var(--sans); font-style:normal; opacity:.85; }
.признак.новый { background:rgba(127,176,127,.14); color:var(--moss); }
.признак.новый b { color:var(--paper); }

/* Часы сброса цены на кнопке кормления: тише самой цены — это условие,
   а не действие. */
.кнопка .часы { display:block; font:700 10px/1 var(--sans); font-style:normal;
  opacity:.72; margin-top:2px; }


/* ===================== КЛАДКА =====================
 * Экран отвечает «сколько признаков перейдёт» — и главное число стоит
 * первым, крупно. Ниже разбор по местам тела, ещё ниже — работы,
 * которые это число двигают. Порядок именно такой: ответ, потом
 * объяснение, потом рычаги. */

.кладка-итог { background:linear-gradient(180deg,#2A2136,#221A2E);
  border-radius:16px; padding:14px; margin-top:12px;
  box-shadow:inset 0 1px 0 rgba(255,255,255,.05); }
.кладка-число { font:900 19px/1.15 var(--fat); color:var(--lampLit);
  font-variant-numeric:tabular-nums; cursor:help; }
.кладка-пара { display:flex; gap:8px; align-items:baseline; flex-wrap:wrap;
  margin-top:6px; font:800 13px/1.2 var(--sans); color:var(--paper); }
.кладка-итог .счёт { margin-top:8px; }
.кладка-итог .тихо { margin-top:6px; cursor:help; }

.места-кладки { display:flex; flex-direction:column; gap:8px; margin-top:12px; }

/* Место тела — одна карточка. Спорное выделено рамкой: там из двух
 * признаков пройдёт один, и это единственное, чего не видно по процентам. */
.место-кладки { background:rgba(0,0,0,.24); border-radius:14px; padding:10px 12px;
  display:grid; grid-template-columns:minmax(0,1fr) auto; gap:2px 10px; }
/* Спорное место. `outline: 1px solid var(--rope)` не работал вовсе:
   `--rope` — градиент, а не цвет, и объявление отбрасывалось целиком
   (найдено разбором интерфейса 28 августа). Спор — главное, чего нельзя
   вывести из процентов, и он не был виден ни разу. */
.место-кладки.спор { outline:1px solid var(--brass);
  background:rgba(154,119,66,.14); }
.место-имя { grid-column:1; font:800 11px/1.2 var(--sans); letter-spacing:.06em;
  text-transform:uppercase; color:var(--clay); }
.место-имя em { font:italic 400 10px/1.2 var(--sans); text-transform:none;
  letter-spacing:0; color:var(--lamp); margin-left:6px; }
.место-итог { grid-column:2; grid-row:1 / span 3; align-self:center;
  font:900 16px/1 var(--fat); color:var(--lampLit);
  font-variant-numeric:tabular-nums; }

.признак-кладки { grid-column:1; display:flex; gap:7px; align-items:baseline;
  flex-wrap:wrap; font-size:12px; color:var(--paper); }
.признак-кладки.главный b { color:var(--lampLit); }
.признак-кладки .чей,
.признак-кладки .класс { font:400 10px/1.2 var(--sans); color:var(--clay); }
.признак-кладки .шанс { margin-left:auto; font:800 12px/1 var(--sans);
  color:var(--paper); font-variant-numeric:tabular-nums; }

/* Работа: что делает и чего стоит — двумя строками под глаголом.
 * Достигнутый предел не прячем: без него непонятно, почему кнопка
 * перестала помогать. */
/* Работа — НЕ `.широкая`. `.широкая` липкая (`bottom:8px`) и задумана
   как ОДНА кнопка внизу экрана; работ четыре, и все четыре прилипали
   к одному месту, наезжая друг на друга. Найдено разбором интерфейса
   28 августа: у богатой кладки нижние кнопки уезжали за экран.
   Ширину берём ту же, липкость — нет. */
.кнопка.работа { width:100%; margin-top:10px; padding:12px 14px 14px;
  font-size:15px; text-align:center; }
.кнопка.работа .работа-числа { opacity:1; color:var(--lampDeep);
  font-variant-numeric:tabular-nums; }
.кнопка.работа.беднота .работа-числа { color:var(--clay); }


/* ПОДСКАЗКА ПО КАСАНИЮ (решение владельца 29 августа).
   `title` в вебвью Телеграма не показывается ни по наведению, ни по тапу —
   на телефоне подсказок не было вовсе. Пузырь рисуем сами.
   Пергамент, а не доска: подсказка — это записка, а не часть сцены. */
.подсказка { position:fixed; z-index:60; max-width:min(280px, calc(100vw - 16px));
  background:var(--parch); color:var(--parchInk);
  font:600 12.5px/1.4 var(--sans); padding:8px 11px; border-radius:10px;
  box-shadow:0 6px 20px -6px rgba(0,0,0,.7), inset 0 1px 0 rgba(255,255,255,.35);
  pointer-events:none; }
.подсказка::after { content:''; position:absolute; left:var(--хвост, 50%);
  margin-left:-6px; border:6px solid transparent; }
.подсказка.сверху::after { top:100%; border-top-color:var(--parch); }
.подсказка.снизу::after { bottom:100%; border-bottom-color:var(--parch); }
/* Значок, у которого есть что рассказать, отличается от простого рисунка:
   иначе игрок не узнает, что по нему можно нажать. */
[data-подсказка] { cursor:help; }


/* ===================== ЭКРАН ПИТОМНИКА =====================
 * Одна разметка на игру и на внешнюю страницу, поэтому и стиль один.
 * Порядок кадра: кто это → за что его знают → кто в нём живёт. */

.top .who.дверь { cursor:pointer; text-decoration:underline;
  text-decoration-color:var(--brassDeep); text-underline-offset:4px; }

.пит-имя { background:linear-gradient(180deg,#2A2136,#221A2E); border-radius:14px;
  padding:12px 13px; margin-top:12px; }
.пит-имя h3 { margin:0; font:900 18px/1.15 var(--fat); color:var(--lampLit); }
.пит-имя p { margin:5px 0 0; font-size:12px; color:var(--mauve); }

/* Клеймо — существо с подписью, за что оно стоит. Лицо слева, потому что
 * узнают по лицу, а читают после. */
.клейма { display:flex; flex-direction:column; gap:8px; margin-top:10px; }
.клеймо { display:grid; grid-template-columns:46px minmax(0,1fr); gap:11px;
  align-items:center; background:rgba(0,0,0,.26); border-radius:13px;
  padding:9px 11px; border:0; width:100%; text-align:left; cursor:pointer;
  color:inherit; font:inherit; }
/* Клеймо без существа: рамки лица нет, текст и шкала идут во всю ширину. */
.клеймо.безлица { cursor:default; grid-template-columns:minmax(0,1fr); }
.клеймо.безлица > .лестница, .клеймо.безлица > .шкала8 { grid-column:1; }
.клеймо-лицо { width:46px; height:46px; border-radius:11px; overflow:hidden;
  background:linear-gradient(180deg,#3A2C42,#241A30);
  box-shadow:inset 0 0 0 1px rgba(154,119,66,.4); }
.клеймо-лицо img { width:100%; height:100%; object-fit:cover; display:block; }
/* Текстовая колонка клейма ужимается: без `min-width:0` длинное имя
   существа растягивает грид и выдавливает лестницу за край. */
.клеймо-текст { min-width:0; }
.клеймо-вид { font:800 9.5px/1 var(--sans); letter-spacing:.09em;
  text-transform:uppercase; color:var(--brass); }
.клеймо-кто { font:800 13.5px/1.2 var(--sans); color:var(--paper); margin-top:3px; }
.клеймо-за { font-size:11px; line-height:1.35; color:var(--mauve); margin-top:2px; }

.пусто-клейма { margin-top:10px; }
.пусто-клейма b { display:block; color:var(--paper); font:800 13.5px/1.3 var(--sans); }
.пусто-клейма p { margin:6px 0 0; font-size:12px; line-height:1.45; }

.раздел-мелко { font:800 9.5px/1 var(--sans); letter-spacing:.09em;
  text-transform:uppercase; color:var(--brass); margin:14px 0 6px; }

/* Обитатели сеткой: у обжитого питомника их бывает полсотни, и список
 * строками читался бы дольше, чем на него смотрят. */
.жильцы { display:grid; grid-template-columns:repeat(4,minmax(0,1fr)); gap:7px; }
.жилец { background:rgba(0,0,0,.26); border-radius:11px; padding:7px 4px 6px;
  text-align:center; border:0; cursor:pointer; color:inherit; font:inherit;
  min-width:0; }
/* Клеймёный обведён золотом: клеймо выше и клетка здесь — одно существо,
 * и связь показана, а не объяснена подписью. */
.жилец.клеймёный { box-shadow:inset 0 0 0 1.5px var(--lamp); }
.жилец-лицо { display:block; width:34px; height:34px; margin:0 auto 5px;
  border-radius:50%; overflow:hidden;
  background:linear-gradient(180deg,#3A2C42,#241A30);
  box-shadow:inset 0 0 0 1px rgba(154,119,66,.35); }
.жилец-лицо img { width:100%; height:100%; object-fit:cover; display:block; }
.жилец b { display:block; font:800 9.5px/1.15 var(--sans); color:var(--paper);
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.жилец i { font-style:normal; font-size:9px; color:var(--dusk); }


/* ===================== ЛЕСТНИЦА РОДА И ШКАЛА СОВЕРШЕНСТВА =====================
 * Решение владельца 29 августа: цели показываем там, где на них влияют, —
 * на клейме питомника («где мы стоим») и на карточке существа («что делать
 * с этим»). Разметка одна, стиль поэтому тоже один.
 *
 * Обе растягиваются на всю ширину клейма: они относятся к клейму целиком,
 * а не к его правой колонке. */
/* В МАКЕТЕ ЛЕСТНИЦА СТОИТ ПОД ТЕКСТОМ КЛЕЙМА, а не под всей карточкой:
   она объясняет строку «ведёт 6 колен», и её левый край держится того же
   края, что и эта строка. Растянутая на всю ширину, она читалась
   отдельным элементом — владелец это и заметил. */
.клеймо > .лестница, .клеймо > .шкала8 { grid-column:2; margin-top:8px; }

/* Имена рубежей под шкалой: где я и как называется то, к чему иду. */
.рубежи8 { display:flex; justify-content:space-between; gap:6px; margin-top:5px;
  font:700 9px/1 var(--sans); color:var(--dusk); }
.рубежи8 .взят { color:var(--lamp); }
.рубежи8 span { white-space:nowrap; }
.рубежи8 b { color:var(--lampLit); }

/* На карточке под лестницей — где стоим и сколько нас таких. */
.лестница-где { display:flex; align-items:baseline; gap:7px; margin-top:5px;
  font:400 11px/1.3 var(--sans); color:var(--mauve); }
.лестница-где b { color:var(--lampLit); font:800 13px/1 var(--sans); }

/* Высота зарубки растёт к пределу — видно, что дальше не просто «ещё одна»,
   а всё круче. Взятые горят, следующая обведена. */
.зарубки { display:flex; gap:3px; align-items:flex-end; height:26px; }
.зарубка { flex:1; border-radius:3px 3px 0 0; background:rgba(255,255,255,.07); }
.зарубка.on { background:linear-gradient(180deg,var(--lampTop),var(--lampBot)); }
.зарубка.next { background:rgba(216,156,66,.24);
  box-shadow:inset 0 0 0 1px var(--brass); }
.лестница-подпись { display:flex; justify-content:space-between; gap:8px;
  margin-top:5px; font:700 9.5px/1.25 var(--sans); color:var(--dusk); }
.лестница-подпись span:last-child { color:var(--lampLit); text-align:right; }

/* Клетка показывает не число, а КАКИХ мест не хватает: это то, чем игрок
   распоряжается, выбирая, кого с кем сводить. */
.места8 { display:flex; gap:4px; }
.место8 { flex:1; height:20px; border-radius:5px; font-style:normal;
  background:rgba(255,255,255,.06); display:grid; place-items:center;
  font:800 9px/1 var(--sans); color:var(--dusk); }
/* СОБРАННОЕ ЗАЛИТО, ЦЕЛЬ ОБВЕДЕНА ПУНКТИРОМ (владелец, 29 августа).
   Прежде и то и другое было кольцом, и два кольца рядом читались
   одинаково: шкала не отвечала на вопрос «куда идти». Заливка говорит
   «есть», пунктир — «сюда надо дойти». */
.место8.занято { background:linear-gradient(180deg,#4B3A46,#332538);
  box-shadow:none; color:var(--paper); }
.место8.рубеж { border:1.5px dashed var(--brass); color:var(--lamp);
  background:none; }
/* Взятый рубеж — и залит, и обведён: он и собран, и был целью.
   Обводка сплошная: пунктир означает «ещё нет». */
.место8.занято.рубеж { border:1.5px solid var(--lamp);
  background:linear-gradient(180deg,#5A4550,#3A2A40); color:var(--lampLit); }
.шкала-пояснение { margin-top:5px; font:400 10.5px/1.35 var(--sans);
  color:var(--dusk); }
.шкала-подпись { display:flex; align-items:baseline; gap:7px; margin-top:5px;
  font:400 11px/1.3 var(--sans); color:var(--mauve); }
.шкала-подпись b { color:var(--lampLit); font:800 13px/1 var(--sans); }
