/*
 * ТЕХНОМАГИЯ — оболочка.
 *
 * Игра занимает весь экран, интерфейс лежит поверх холста. Всё, что
 * можно, сделано на CSS: свечение не должно стоить кадров, их и так мало
 * на телефоне.
 *
 * Палитра — ночной кибер-парк: холодная зелень земли, мятный и голубой
 * свет фонарей, янтарь на предупреждениях. Прежняя кассетная лиловая
 * гамма ушла вместе с плёночными слоями: она принадлежала другой игре, и
 * две игры одного автора не должны выглядеть одной.
 */

:root {
  --ink: #050b0c;
  --acid: #3dffb4;
  --violet: #7df3ff;
  --pink: #ff5d8f;
  --amber: #ffc95a;
  --paper: #e8fbf6;
  --mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--ink);
  color: var(--paper);
  font-family: var(--mono);
  -webkit-user-select: none;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
}

#screen {
  position: fixed;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: crosshair;
}


/*
 * Кнопка возврата. На сайте такая же лежит в общем /game-menu.css, но
 * игра живёт отдельным репозиторием и обязана открываться сама по себе —
 * из папки, с флешки, откуда угодно. Двадцать строк дешевле зависимости.
 */
/*
 * Область нажатия не меньше 44 точек по обеим сторонам — это не вкус, а
 * порог, ниже которого палец промахивается. Было 54x19: девятнадцать
 * точек это меньше трёх миллиметров, и попасть в такое на ходу нельзя.
 *
 * Размер задаётся самому элементу, а не невидимой подложкой: подложку не
 * видно ни в замере, ни глазом, и «кнопка выглядит крошечной, но нажать
 * можно» — это всё равно плохая кнопка.
 */
.game-home-menu {
  position: fixed;
  top: max(10px, env(safe-area-inset-top));
  right: max(10px, env(safe-area-inset-right));
  z-index: 1000;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid var(--acid);
  background: #0b1010f2;
  color: var(--paper);
  font: 700 10px var(--mono);
  letter-spacing: .08em;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
  box-shadow: 0 0 14px #76ff9f20;
}

.game-home-menu:hover,
.game-home-menu:focus-visible {
  background: #153725;
  color: #fff;
  outline: 2px solid var(--violet);
  outline-offset: 3px;
}

@media (max-height: 600px) and (orientation: landscape) {
  .game-home-menu { padding: 8px 10px; }   /* min-height 44 держится сверху */
}


/* =========================================================
   HUD
   ========================================================= */

.hud {
  position: fixed;
  top: max(10px, env(safe-area-inset-top));
  left: max(10px, env(safe-area-inset-left));
  /* Справа сверху живёт кнопка «НА САЙТ» — HUD в неё не заезжает. */
  right: max(112px, env(safe-area-inset-right));
  z-index: 10;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: flex-start;
  pointer-events: none;
}

/* Атрибут hidden обязан побеждать раскладку: иначе спрятанный блок
   исправно занимает место, а игрок читает пустую строку как поломку. */
.hud-slot[hidden] { display: none; }

.hud-slot {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 8px 11px;
  border: 1px solid #ffffff1c;
  background: #0b0713cc;
  backdrop-filter: blur(3px);
}

.hud-slot b {
  font: 800 13px/1 var(--mono);
  letter-spacing: .1em;
  color: var(--acid);
}

.hud-label {
  font: 700 8px/1 var(--mono);
  letter-spacing: .16em;
  color: #8a7c99;
}

.hud-score {
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.hud-score b { color: var(--paper); }

.ammo {
  display: flex;
  gap: 3px;
  min-height: 7px;
}

.ammo i {
  width: 3px;
  height: 9px;
  background: var(--amber);
  box-shadow: 0 0 6px #ffe06b60;
}

.ammo[data-empty="1"] i { background: #5b4b2a; }

.hud-points {
  position: relative;
  flex-direction: row;
  align-items: center;
  gap: 8px;
}

.hud-points b { color: var(--amber); }

/*
 * Цепочка убийств. Полоска — не украшение: по ней видно, сколько осталось
 * до обнуления множителя, а это и есть весь риск в счёте.
 */
.combo {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 34px;
  padding: 3px 6px;
  border: 1px solid var(--pink);
  background: #2a0a1b;
  animation: comboPop .18s ease-out;
}

/*
 * Съёмка витрины. Из кадра убирается всё, что не игра: показания, кнопки,
 * подсказки, ссылка на сайт. Три секунды чистого кадра — иначе на карточке
 * половину места занимает интерфейс, а не то, ради чего её снимали.
 *
 * Перечислено поимённо намеренно. Общее правило вида «спрятать всё, кроме
 * холста» переживёт ровно до первого нового блока в разметке, и тот молча
 * окажется в кадре.
 */
body.is-shooting .operation-hud,
body.is-shooting .hud,
body.is-shooting .daemons,
body.is-shooting .pad,
body.is-shooting .toast,
body.is-shooting .found,
body.is-shooting .ghost,
body.is-shooting .camctl,
body.is-shooting .mute,
body.is-shooting .game-home-menu,
body.is-shooting .veil,
body.is-shooting .tome {
  display: none !important;
}

/*
 * Ячейка, в которую только что легла стихия. Вспышка короткая и резкая:
 * она отмечает событие, а не рисует состояние, и к следующему нажатию
 * должна успеть погаснуть — иначе три вспышки сольются в одно свечение
 * и разница между «набираю» и «набрал» снова пропадёт.
 */
.stack .is-landed {
  animation: stack-land .22s ease-out;
}

@keyframes stack-land {
  0% { transform: scale(1.9); filter: brightness(2.4); }
  60% { transform: scale(.92); filter: brightness(1.4); }
  100% { transform: scale(1); filter: brightness(1); }
}

.combo[hidden] { display: none; }

.combo b {
  color: var(--pink);
  font: 900 13px/1 var(--mono);
}

.combo i {
  display: block;
  height: 2px;
  background: var(--pink);
  transform-origin: left center;
}

@keyframes comboPop {
  from { transform: scale(1.25); }
  to { transform: scale(1); }
}

.hud-target b { color: var(--violet); }

/* Время вышло за чужой результат — цель уже не побить, и это видно сразу. */
.hud-target[data-late="1"] b { color: var(--pink); }

.hud-stack {
  flex-direction: row;
  align-items: center;
  gap: 7px;
}

.stack {
  display: flex;
  gap: 4px;
}

.stack i {
  width: 15px;
  height: 15px;
  border: 1px solid #ffffff2a;
  background: transparent;
}

/* Рука, которой ещё нет («Лестница»): видна, но погашена и перечёркнута
   пунктиром — ячейка впереди, а не сломанная. */
.stack i.is-locked {
  border-style: dashed;
  border-color: #ffffff1a;
  opacity: .45;
}

/* Набираемая стихия мигает, пока не легла в очередь: это и есть та секунда,
   которую игрок стоит замедленным. */
.stack i.is-charging {
  border-width: 2px;
  animation: chargePulse .26s linear infinite;
}

@keyframes chargePulse {
  from { opacity: .35; }
  to { opacity: 1; }
}

.form {
  color: var(--paper);
  font: 900 13px var(--mono) !important;
  letter-spacing: .1em;
  white-space: nowrap;
}

.form[hidden] { display: none; }

/*
 * ПРИБОР ВИДИМОСТИ (слой «б», «Башня»). Цвет — порог: в тени холодный,
 * в полумраке тёплый, на свету горит. Число под словом — дальность
 * взгляда стража на тебя сейчас, в клетках.
 */
.hud-vidno {
  flex-direction: row;
  align-items: center;
  gap: 7px;
}

.hud-vidno i {
  font: 700 8px/1 var(--mono);
  font-style: normal;
  letter-spacing: .12em;
  color: #8a7c99;
}

.hud-vidno[data-level="ten"] b { color: #8fb0ff; }
.hud-vidno[data-level="polumrak"] b { color: #ffd27f; }
.hud-vidno[data-level="svet"] { border-color: #ffe14d88; }
.hud-vidno[data-level="svet"] b { color: #ffe14d; text-shadow: 0 0 8px #ffe14d99; }

/* Тот же прибор на телефоне — строкой в шапке операции, под «РУКИ».
   Внизу HUD у телефона и так в две строки, и третья поднимала счёт под
   кнопку КНИГА. На компьютере эта строка не нужна: прибор в HUD. */
.op-vidno[data-level="ten"] { color: #8fb0ff; }
.op-vidno[data-level="polumrak"] { color: #ffd27f; }
.op-vidno[data-level="svet"] { color: #ffe14d; text-shadow: 0 0 6px #ffe14d99; }

@media (pointer: coarse), (max-width: 700px) {
  .hud-vidno { display: none !important; }
}

@media (pointer: fine) and (min-width: 701px) {
  .op-vidno { display: none !important; }
}

/* =========================================================
   ПЯТЬ КЛАВИШ
   =========================================================
   Панель висит всегда. Состав — весь язык игры, и держать
   его в памяти игрок не обязан: пока клавиши на экране,
   заклинание собирается глазами, а не по памяти.
   ========================================================= */

.daemons {
  position: fixed;
  left: 50%;
  bottom: max(14px, env(safe-area-inset-bottom));
  z-index: 9;
  display: flex;
  gap: 8px;
  transform: translateX(-50%);
}

.daemon-key {
  display: grid;
  justify-items: center;
  gap: 2px;
  width: 62px;
  min-height: 44px;
  padding: 7px 4px 6px;
  border: 1px solid currentColor;
  border-radius: 3px;
  background: #0a0f10e6;
  cursor: pointer;
  touch-action: none;
  transition: transform .08s, background .12s;
}

.daemon-key b {
  font: 900 17px/1 var(--mono);
  color: inherit;
}

.daemon-key i {
  font: 700 8px/1 var(--mono);
  font-style: normal;
  letter-spacing: .1em;
  color: #8fa39b;
}

.daemon-key:hover { background: #10201ce6; }
.daemon-key.is-held,
.daemon-key[data-active="1"] {
  transform: translateY(2px);
  background: currentColor;
}
.daemon-key[data-active="1"] b { color: #050b0c; }
.daemon-key[data-active="1"] i { color: #050b0c; }

/* Недоступное на этаже не прячется, а тушится: так видно, что стихий пять
   и какие ещё впереди. Обещания при этом нет — по такой кнопке видно, что
   она закрыта. */
.daemon-key[data-locked="1"] {
  opacity: .3;
  filter: grayscale(1);
  cursor: default;
}

.daemon-key[data-element="fire"] { border-color: #ff5a1f; color: #ff5a1f; }
.daemon-key[data-element="water"] { border-color: #4de1ff; color: #4de1ff; }
.daemon-key[data-element="wind"] { border-color: #76ff9f; color: #76ff9f; }
.daemon-key[data-element="earth"] { border-color: #d08a3e; color: #d08a3e; }
.daemon-key[data-element="bolt"] { border-color: #ffe14d; color: #ffe14d; }

/* Монета (слой «б»): серебро — ни одна стихия так не светится, и кнопку
   не спутать с шестой стихией. Взведена — мигает «КУДА?». Атрибут hidden
   обязан побеждать display: grid ряда. */
.daemon-key[data-element="coin"] { border-color: #cfd8dc; color: #cfd8dc; }
.daemon-key[hidden] { display: none; }
.daemon-key[data-armed="1"] {
  background: #cfd8dc33;
  animation: chargePulse .4s linear infinite alternate;
}
.daemon-key[data-empty="1"] { opacity: .45; }

.mute {
  position: fixed;
  top: calc(max(10px, env(safe-area-inset-top)) + 44px);
  right: max(10px, env(safe-area-inset-right));
  z-index: 1000;
  min-height: 44px;
  padding: 8px 10px;
  border: 1px solid #ffffff22;
  background: #0b0713e6;
  color: #a596b3;
  font: 700 9px var(--mono);
  letter-spacing: .1em;
  cursor: pointer;
}

.mute[data-off="1"] { color: var(--pink); border-color: #ff2d9555; }

/* Вторая кнопка того же ряда: книга стоит под звуком, а не в углу карты. */
.mute-second { top: calc(max(10px, env(safe-area-inset-top)) + 104px); }

.toast {
  position: fixed;
  left: 50%;
  bottom: max(22vh, 140px);
  z-index: 10;
  padding: 9px 14px;
  border-left: 3px solid var(--acid);
  background: #0b0713e6;
  color: var(--paper);
  font: 800 11px var(--mono);
  letter-spacing: .14em;
  /*
   * Перенос, а не одна строка. Подсказка «СНАЧАЛА НАБЕРИ» в одну строку
   * занимала около 470 пикселей при экране 390 и обрезалась с обеих
   * сторон, «ДЕРЖИТ УДАР — НУЖЕН СОСТАВ…» — тоже. Ширина по тексту, но не
   * шире экрана без полей по 16 пикселей; длинное переносится по словам.
   */
  white-space: normal;
  width: max-content;
  max-width: calc(100vw - 32px);
  box-sizing: border-box;
  overflow-wrap: anywhere;
  text-align: center;
  line-height: 1.45;
  transform: translateX(-50%);
  pointer-events: none;
}

.operation-hud {
  position: fixed;
  left: 50%;
  top: max(76px, calc(env(safe-area-inset-top) + 70px));
  z-index: 8;
  display: grid;
  gap: 3px;
  width: min(560px, calc(100vw - 160px));
  padding: 8px 12px;
  border: 1px solid #7ffcff55;
  background: #061013d9;
  color: #d9ffff;
  font: 700 10px var(--mono);
  letter-spacing: .1em;
  text-align: center;
  transform: translateX(-50%);
  pointer-events: none;
}

.operation-hud[hidden], .operation-hud span[hidden] { display: none; }
.operation-hud b { color: #7ffcff; font-size: 12px; }
#operationOptional { color: #ffd27f; }
/* Тревога МГС в строке «РУКИ … · СТИХИИ …» (слой «б»): цвет — как у
   взгляда стражи в том же состоянии (vidimost.js, CONE_TINT). */
#operationOptional[data-alarm="alert"] { color: #ff2d5a; }
#operationOptional[data-alarm="search"] { color: #cd78ff; }
#operationOptional[data-alarm="caution"] { color: #ffd64d; }
#operationLesson { color: #ffffffaa; }

.physical-observation {
  position: fixed;
  left: 50%;
  top: max(152px, calc(env(safe-area-inset-top) + 146px));
  z-index: 8;
  width: min(520px, calc(100vw - 180px));
  padding: 7px 11px;
  border-left: 2px solid #7ffcff;
  background: #050b0cdd;
  color: #d9ffff;
  font: 700 10px/1.35 var(--mono);
  letter-spacing: .08em;
  text-align: center;
  transform: translateX(-50%);
  pointer-events: none;
}

.physical-observation[hidden] { display: none; }

@media (max-width: 700px) {
  .operation-hud {
    top: max(68px, calc(env(safe-area-inset-top) + 62px));
    width: calc(100vw - 118px);
    font-size: 8px;
    letter-spacing: .06em;
  }

  .physical-observation {
    top: max(137px, calc(env(safe-area-inset-top) + 131px));
    width: calc(100vw - 132px);
    font-size: 8px;
    letter-spacing: .04em;
  }
}


/* =========================================================
   ПАЛЬЦЫ
   ========================================================= */

.ghost {
  position: fixed;
  z-index: 8;
  width: 0;
  height: 0;
  pointer-events: none;
}

.ghost::before {
  content: '';
  position: absolute;
  left: -46px;
  top: -46px;
  width: 92px;
  height: 92px;
  border: 1px solid #ffffff20;
  border-radius: 50%;
}

.ghost i {
  position: absolute;
  left: -17px;
  top: -17px;
  width: 34px;
  height: 34px;
  border: 1px solid var(--acid);
  border-radius: 50%;
  background: #76ff9f1f;
}

/*
 * Кнопки стоят столбиком у правой кромки, а не в углу. Угол занят: там
 * лежит большой палец, который целится плавающим стиком, и кнопка в том
 * же месте отбирает у него прицел.
 */
.pad {
  position: fixed;
  right: max(10px, env(safe-area-inset-right));
  /* Внизу, а не по центру правого края: посередине она легла прямо на
     поле и перехватывала клики по тому, во что игрок целился. */
  bottom: max(14px, env(safe-area-inset-bottom));
  z-index: 9;
  /* Кнопка видна и на мыши. Играть одной мышью должно быть можно целиком:
     стихии набираются кликом по нижнему ряду, а выпускать было нечем —
     пробел оставался единственным выходом, и это уже не «одной мышью». */
  display: grid;
  opacity: .82;
  grid-auto-flow: row;
  gap: 9px;
  justify-items: end;
}

/* На мыши она скромнее: там есть пробел и клик, и кнопка — запасной путь. */
.pad-big { width: 86px; height: 86px; border-radius: 50%; font: 900 13px var(--mono); }

.pad-key {
  border: 1px solid var(--acid);
  background: #0b1010cc;
  color: var(--paper);
  font: 800 9px var(--mono);
  letter-spacing: .08em;
  border-radius: 50%;
  touch-action: none;
}

.pad-small {
  width: 62px;
  height: 62px;
}

.pad-big {
  order: -1;
  width: 76px;
  height: 76px;
  border-width: 2px;
  border-color: var(--pink);
  color: var(--pink);
  font-size: 11px;
  box-shadow: 0 0 24px #ff2d9525;
}

.pad-key.is-held {
  background: #76ff9f28;
  transform: scale(.94);
}

/* =========================================================
   ТЕЛЕФОН
   =========================================================
   Порядок важности задан игрой, а не вкусом: поле, кнопки
   магии, книга, всё остальное. Поэтому поле забирает почти
   весь экран, магия лежит сразу под ним, книга остаётся
   различимой кнопкой, а звук и часы ужимаются до строчки.
   ========================================================= */

@media (pointer: coarse) and (orientation: portrait),
       (max-width: 700px) and (orientation: portrait) {
  /* Нижние игровые кнопки остаются поверх книги. Запас не даёт им закрыть
     последние наблюдения: карточку можно прокрутить так, чтобы текст целиком
     оказался выше управления. */
  .tome-card::after {
    content: "";
    display: block;
    height: calc(112px + env(safe-area-inset-bottom));
  }

  #screen {
    inset: 0 0 auto 0;
    height: 74%;
  }

  /* Стихии — сразу под полем, во всю ширину и первыми под пальцем. */
  .daemons {
    bottom: auto;
    top: calc(74% + 8px);
    gap: 5px;
  }

  /* Палец — не курсор: клетка ниже сорока четырёх точек промахивается. */
  .daemon-key {
    width: 68px;
    min-height: 46px;
    padding: 6px 3px;
    display: grid;
    align-content: center;
  }

  .daemon-key b { display: none; }
  .daemon-key i { font-size: 10px; }

  /* Шесть в ряд («Башня»: пять стихий и монета) — все одного размера
     (свод, п.13), уже на десять точек, но не меньше 44: на 390 точках
     выходит 57, на 360 — 52. */
  .daemons[data-coin="1"] { gap: 4px; }
  .daemons[data-coin="1"] .daemon-key { width: min(68px, calc((100vw - 44px) / 6)); }

  /* Выпуск — под правым большим пальцем. По нему бьют не глядя. */
  .pad {
    top: auto;
    right: max(12px, env(safe-area-inset-right));
    bottom: max(12px, env(safe-area-inset-bottom));
    display: grid;
    transform: none;
  }

  .pad-big {
    width: 116px;
    height: 116px;
    border-radius: 50%;
    font: 900 17px var(--mono);
  }

  /* Книга — третья по важности, значит остаётся кнопкой, а не строчкой. */
  .mute-second {
    top: auto;
    left: max(12px, env(safe-area-inset-left));
    right: auto;
    bottom: calc(max(12px, env(safe-area-inset-bottom)) + 46px);
    padding: 11px 18px;
    font: 800 12px var(--mono);
    border-color: var(--violet);
    color: var(--paper);
  }

  /* Часы, счёт, звук и ссылка — последние. Строчкой, мелко. */
  .hud {
    top: auto;
    bottom: max(12px, env(safe-area-inset-bottom));
    left: max(12px, env(safe-area-inset-left));
    right: auto;
    justify-content: flex-start;
    max-width: 58vw;
    gap: 4px;
  }

  .hud-slot { padding: 3px 6px; }
  .hud-slot b { font-size: 10px; }
  .hud-label { font-size: 7px; }
  .hud-stack { display: none; }

  /* Кнопка книги тоже .mute, поэтому здесь она исключена явно: иначе это
     правило садит её ровно на кнопку звука. */
  .mute:not(.mute-second),
  .game-home-menu {
    top: auto;
    right: auto;
    left: max(12px, env(safe-area-inset-left));
    bottom: calc(max(12px, env(safe-area-inset-bottom)) + 94px);
    padding: 4px 10px;
    font: 700 8px var(--mono);
  }

  .game-home-menu { left: calc(max(12px, env(safe-area-inset-left)) + 82px); }

  .toast { bottom: calc(26% + 12px); }
  .found { top: 32%; }
}

/*
 * Телефон боком. Полосы снизу тут быть не может: высоты и так мало, и
 * любая полка съедает половину поля. Всё лежит поверх, по углам, и всё
 * прозрачное — под кнопками должно быть видно, что происходит.
 */
@media (pointer: coarse) and (orientation: landscape) {
  .pad {
    top: auto;
    right: max(12px, env(safe-area-inset-right));
    bottom: max(12px, env(safe-area-inset-bottom));
    display: grid;
    transform: none;
  }

  .pad-big {
    width: 96px;
    height: 96px;
    border-radius: 50%;
    font: 900 14px var(--mono);
  }

  /* Стихии — рядом вдоль нижней кромки, левее кнопки выпуска. */
  .daemons {
    left: max(12px, env(safe-area-inset-left));
    bottom: max(12px, env(safe-area-inset-bottom));
    transform: none;
    gap: 4px;
  }

  .daemon-key {
    width: 60px;
    min-height: 44px;
    padding: 5px 3px;
    display: grid;
    align-content: center;
    background: #050b0cd0;
  }

  .daemon-key b { display: none; }
  .daemon-key i { font-size: 9px; }

  /* Книга — заметной кнопкой в правом верхнем углу, подальше от пальцев. */
  .mute-second {
    top: max(10px, env(safe-area-inset-top));
    right: max(12px, env(safe-area-inset-right));
    left: auto;
    bottom: auto;
    padding: 9px 14px;
    font: 800 11px var(--mono);
    border-color: var(--violet);
    color: var(--paper);
    background: #050b0cd0;
  }

  /* Часы и счёт — мелкой строкой сверху слева, на своём месте. */
  .hud {
    top: max(8px, env(safe-area-inset-top));
    bottom: auto;
    gap: 4px;
  }

  .hud-slot { padding: 3px 6px; background: #050b0cd0; }
  .hud-slot b { font-size: 10px; }
  .hud-label { font-size: 7px; }
  .hud-stack { display: none; }

  .mute:not(.mute-second),
  .game-home-menu {
    top: calc(max(10px, env(safe-area-inset-top)) + 48px);
    right: max(12px, env(safe-area-inset-right));
    left: auto;
    bottom: auto;
    padding: 4px 10px;
    font: 700 8px var(--mono);
    background: #050b0cd0;
  }

  .game-home-menu { top: calc(max(10px, env(safe-area-inset-top)) + 96px); }

  .toast { bottom: calc(max(12px, env(safe-area-inset-bottom)) + 118px); }
  .found { top: 34%; }
}

/* =========================================================
   ЭКРАНЫ МЕЖДУ ПОПЫТКАМИ
   ========================================================= */

.veil {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: grid;
  place-items: center;
  padding: 18px;
  background: #05040ad9;
  backdrop-filter: blur(6px);
}

.veil[hidden] { display: none; }

.veil-card {
  width: min(430px, 100%);
  max-height: 92vh;
  overflow: auto;
  padding: 24px 22px 20px;
  border: 2px solid var(--acid);
  background: linear-gradient(150deg, #1a0b28, #0a1512);
  box-shadow: 10px 10px 0 #05040a, 0 0 44px #76ff9f22;
}

.veil[data-tone="dead"] .veil-card { border-color: var(--pink); box-shadow: 10px 10px 0 #05040a, 0 0 44px #ff2d9530; }
.veil[data-tone="clear"] .veil-card { border-color: var(--amber); box-shadow: 10px 10px 0 #05040a, 0 0 44px #ffe06b30; }
.veil[data-tone="pause"] .veil-card { border-color: var(--violet); box-shadow: 10px 10px 0 #05040a, 0 0 44px #bc70ff30; }

.veil-kicker {
  display: block;
  margin-bottom: 8px;
  color: var(--violet);
  font: 800 9px var(--mono);
  letter-spacing: .22em;
}

.veil h1 {
  margin: 0 0 12px;
  font: 900 30px/1 system-ui, -apple-system, sans-serif;
  letter-spacing: .01em;
  color: var(--acid);
  text-transform: uppercase;
}

.veil[data-tone="dead"] h1 { color: var(--pink); }
.veil[data-tone="clear"] h1 { color: var(--amber); }
.veil[data-tone="pause"] h1 { color: var(--violet); }

.veil p {
  margin: 0 0 16px;
  color: #cbbbd6;
  font-size: 12px;
  line-height: 1.55;
}

.veil-stats span[data-warn="1"] {
  color: var(--pink);
}

.veil-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 14px;
  margin-bottom: 18px;
  color: #8a7c99;
  font: 700 9px var(--mono);
  letter-spacing: .14em;
  line-height: 1.5;
}

.veil-score {
  margin: 0 0 18px;
  padding: 14px;
  border: 1px solid #ffffff1c;
  background: #06040c;
}

.veil-score[hidden] { display: none; }

.veil-score .rank {
  display: flex;
  align-items: baseline;
  gap: 9px;
  margin-bottom: 12px;
}

.veil-score .rank b {
  font: 900 46px/1 system-ui, -apple-system, sans-serif;
  color: var(--amber);
  text-shadow: 3px 3px 0 #05040a;
}

.veil-score .rank span {
  color: #6f6280;
  font: 800 9px var(--mono);
  letter-spacing: .2em;
}

.veil-score[data-rank="S"] .rank b { color: var(--pink); }
.veil-score[data-rank="A"] .rank b { color: var(--acid); }
.veil-score[data-rank="D"] .rank b { color: #8a7c99; }

.veil-score ul {
  display: grid;
  gap: 5px;
  margin: 0 0 11px;
  padding: 0;
  list-style: none;
}

.veil-score li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: #a596b3;
  font: 700 10px var(--mono);
  letter-spacing: .08em;
}

.veil-score li b { color: var(--paper); font-weight: 800; }

.score-total {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-top: 9px;
  border-top: 1px solid #ffffff1c;
  color: #6f6280;
  font: 800 9px var(--mono);
  letter-spacing: .18em;
}

.score-total b {
  color: var(--amber);
  font: 900 22px/1 var(--mono);
}

.score-best {
  margin: 9px 0 0;
  color: #6f6280;
  font: 700 9px var(--mono);
  letter-spacing: .12em;
}

.score-best[data-record="1"] { color: var(--acid); }

.veil-action, .veil-second {
  width: 100%;
  min-height: 48px;
  border: 2px solid var(--acid);
  background: #16412c;
  color: #fff;
  font: 800 12px var(--mono);
  letter-spacing: .12em;
  cursor: pointer;
  box-shadow: 4px 4px 0 #05040a;
}

.veil-second {
  margin-top: 9px;
  border-color: #ffffff28;
  background: transparent;
  color: #a596b3;
  box-shadow: none;
}

.veil-action:hover, .veil-second:hover { background: #1e5c3d; color: #fff; }

.veil-code {
  margin: 0 0 16px;
  padding: 12px;
  border: 1px dashed #ffffff22;
  background: #06040c;
}

.veil-code label {
  display: block;
  margin-bottom: 6px;
  color: var(--violet);
  font: 800 8px var(--mono);
  letter-spacing: .18em;
}

.code-row { display: flex; gap: 6px; }

.code-row #nickBox {
  flex: 0 0 120px;
  color: var(--acid);
  text-transform: uppercase;
}

.code-row input {
  flex: 1;
  min-width: 0;
  height: 38px;
  padding: 0 9px;
  border: 1px solid #ffffff22;
  background: #0d0817;
  color: var(--amber);
  font: 600 11px var(--mono);
  outline: none;
}

.code-row button {
  padding: 0 12px;
  border: 1px solid var(--violet);
  background: #23113a;
  color: var(--paper);
  font: 800 9px var(--mono);
  letter-spacing: .1em;
  cursor: pointer;
}

.veil-code small {
  display: block;
  margin-top: 7px;
  color: #6f6280;
  font-size: 9px;
  line-height: 1.5;
}

/* Низкий экран: карточка ужимается, иначе кнопка уезжает за кромку. */
@media (max-height: 520px) {
  .veil-card { padding: 16px; }
  .veil h1 { font-size: 22px; }
  .veil p { margin-bottom: 10px; }
}

/* =========================================================
   КНИГА ЗАКЛИНАНИЙ
   =========================================================
   Сетка из клеток, а не список: двадцать пять веществ должны
   читаться одним взглядом как заполненная наполовину доска —
   именно вид пустых клеток и заставляет их закрывать.
   ========================================================= */

.tome {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  padding: 18px;
  background: #05040ae6;
  backdrop-filter: blur(6px);
}

.tome[hidden] { display: none; }

.tome-card {
  width: min(560px, 100%);
  max-height: 92vh;
  overflow: auto;
  padding: 20px 20px 18px;
  border: 2px solid var(--violet);
  background: linear-gradient(150deg, #170c26, #0a1018);
  box-shadow: 10px 10px 0 #05040a, 0 0 44px #bc70ff2e;
}

.tome-head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 10px;
}

.tome-head .veil-kicker { margin: 0; }
.tome-head b { color: var(--amber); font: 800 12px var(--mono); }

.tome-close {
  margin-left: auto;
  padding: 5px 10px;
  border: 1px solid var(--violet);
  background: none;
  color: var(--paper);
  font: 700 9px var(--mono);
  letter-spacing: .14em;
  cursor: pointer;
}

.tome-close:hover { background: #bc70ff22; }

.tome-hint {
  margin: 0 0 14px;
  color: #9a8fae;
  font: 600 10px/1.5 var(--mono);
}

.tome-title {
  margin: 18px 0 8px;
  color: var(--violet);
  font: 800 9px var(--mono);
  letter-spacing: .22em;
}

.tome-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 6px;
}

.tome-cell {
  padding: 7px 8px;
  border: 1px solid #ffffff18;
  background: #ffffff08;
  min-height: 52px;
}

/* Неоткрытая клетка показывает форму пустоты — сколько стихий в составе.
   Пустая клетка не зовёт, «состав из трёх» зовёт. */
/*
 * Значок заклинания. Он крупнее подписи намеренно: клетка читается
 * картинкой, а имя дочитывают уже после того, как узнали вещь. Файл
 * может не приехать — набор рисуется частями, — и тогда картинка
 * убирает себя сама, а клетка остаётся прежней.
 */
.tome-icon {
  display: block;
  width: 34px;
  height: 34px;
  margin: 2px 0 3px;
  image-rendering: auto;
}

.tome-list .tome-icon {
  float: left;
  width: 28px;
  height: 28px;
  margin: 0 7px 0 0;
}

.tome-cell[data-known="0"] { opacity: .42; }
.tome-cell[data-known="0"] .tome-name { color: #6b6280; }

.tome-marks {
  display: flex;
  gap: 3px;
  margin-bottom: 4px;
}

.tome-marks i {
  width: 7px;
  height: 7px;
  border-radius: 50%;
}

.tome-name {
  display: block;
  font: 800 11px/1.2 var(--mono);
  letter-spacing: .04em;
}

.tome-note {
  display: block;
  margin-top: 3px;
  color: #9a8fae;
  font: 600 8px/1.35 var(--mono);
}

.tome-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 5px;
}

.tome-list li {
  padding: 7px 9px;
  border-left: 3px solid #ffffff20;
  background: #ffffff08;
}

.tome-list li[data-known="0"] { opacity: .5; }

.tome-sign {
  font: 800 11px var(--mono);
  letter-spacing: .05em;
}

.tome-recipe {
  color: #9a8fae;
  font: 600 9px var(--mono);
}


/* =========================================================
   НАХОДКА
   =========================================================
   Новое вещество или именное заклинание — единственное
   событие, ради которого стоит отвлечь игрока от боя. Всё
   остальное он прочитает потом в книге; это надо заметить
   сейчас, поэтому крупно и по центру.
   ========================================================= */

.found {
  position: fixed;
  left: 50%;
  top: 34%;
  z-index: 12;
  display: grid;
  justify-items: center;
  gap: 6px;
  padding: 34px 62px;
  text-align: center;
  pointer-events: none;
  transform: translate(-50%, -50%);
  animation: found-in .5s cubic-bezier(.2, 1.4, .4, 1);

  /* Подложка размытым пятном, а не панелью: объявление всплывает поверх
     боя, и рамка посреди экрана читалась бы как окно, которое надо
     закрыть. Пятно гасит фон ровно там, где стоят буквы. */
  background: radial-gradient(
    ellipse at center,
    rgba(5, 11, 12, .92) 0%,
    rgba(5, 11, 12, .74) 48%,
    rgba(5, 11, 12, 0) 76%
  );
}

.found[hidden] { display: none; }

/* Знамя нового навыка (отзыв 04.10, п.16; src/znamya.js): верхняя строка
   «ТЫ УЗНАЛ НОВЫЙ НАВЫК» — крупно, а не 10 точками серым; имя навыка
   под ней — его цветом. Поля уже, чтобы на 360 точках строка влезала
   в одну линию; сквозь знамя по-прежнему нажимается (pointer-events). */
.found[data-big="1"] {
  gap: 8px;
  padding: 26px 18px;
  max-width: calc(100vw - 24px);
  box-sizing: border-box;
}
.found[data-big="1"] .found-kicker {
  font: 900 clamp(20px, 5.6vw, 44px)/1.05 system-ui, -apple-system, sans-serif;
  letter-spacing: .03em;
  color: #ffffff;
  text-shadow: 0 0 18px #ffe14d99, 0 2px 0 #050b0c;
  white-space: nowrap;
}
.found[data-big="1"] b { font-size: clamp(26px, 6.4vw, 48px); }
.found[data-big="1"] i { font-size: 12px; color: #d9ffff; }

.found-kicker {
  font: 800 10px var(--mono);
  letter-spacing: .34em;
  color: #8fa39b;
}

.found b {
  font: 900 clamp(30px, 7vw, 58px)/1 system-ui, -apple-system, sans-serif;
  letter-spacing: .02em;
  text-transform: uppercase;
  text-shadow: 0 0 26px currentColor;
}

.found i {
  max-width: 24ch;
  font: 600 11px/1.4 var(--mono);
  font-style: normal;
  color: #b9cdc5;
}

@keyframes found-in {
  from { opacity: 0; transform: translate(-50%, -50%) scale(.86); }
  to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* =========================================================
   ИЗОМЕТРИЯ (src/view3d/igra.js)
   =========================================================
   Объёмный мир рисуется во втором холсте #screen3d, который лежит ПОД
   #screen и касаний не принимает. Место и размер он берёт у #screen из
   скрипта, а не из своих правил: на телефоне стоя #screen занимает
   верхние 74%, и вторая копия этих правил однажды разошлась бы с первой.
   #screen остаётся поверхностью ввода и прозрачной накладкой.
   ========================================================= */

#screen3d {
  position: fixed;
  display: block;
  pointer-events: none;
}

/*
 * Кнопки камеры. На компьютере — столбиком у правой кромки под кнопкой
 * книги: там нет ни поля под пальцем, ни других кнопок. Одного размера,
 * не меньше 44 точек (свод, п.13 и 29б).
 */
.camctl {
  position: fixed;
  /* +224, а не +164: с 03.10 под книгой — кнопка ЗАДАНИЯ (слой «г»). */
  top: calc(max(10px, env(safe-area-inset-top)) + 224px);
  right: max(10px, env(safe-area-inset-right));
  z-index: 9;
  display: grid;
  grid-auto-flow: row;
  gap: 6px;
}

.camctl[hidden] { display: none; }

.camctl button {
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid #7ffcff55;
  background: #061013d9;
  color: #d9ffff;
  font: 800 18px var(--mono);
  line-height: 1;
  cursor: pointer;
  touch-action: manipulation;
}

.camctl button:active { background: #7ffcff33; }

/* Телефон стоя: строкой по верхней кромке поля — шапка, звук и «НА САЙТ»
   здесь уехали вниз, и верх поля свободен; стики начинаются ниже. */
@media (pointer: coarse) and (orientation: portrait),
       (max-width: 700px) and (orientation: portrait) {
  .camctl {
    top: max(10px, env(safe-area-inset-top));
    left: max(12px, env(safe-area-inset-left));
    right: auto;
    grid-auto-flow: column;
  }
}

/* Телефон боком: строкой по верхней кромке, вплотную левее столбика
   книги, звука и «НА САЙТ». Посередине она на узком телефоне (667 точек)
   наезжала на шапку счёта слева; от правого края шапка дальше всего. */
@media (pointer: coarse) and (orientation: landscape) {
  .camctl {
    top: max(8px, env(safe-area-inset-top));
    right: calc(max(12px, env(safe-area-inset-right)) + 84px);
    grid-auto-flow: column;
  }
}

@media (prefers-reduced-motion: reduce) {
  .found { animation: none; }
}

/* =========================================================
   РАЗГОВОР И ЖУРНАЛ ЗАДАНИЙ (слой «г», 03.10)
   =========================================================
   Цвет разговора — тёплая бумага: ни одна стихия так не светится, и
   кнопку ГОВОРИТЬ не спутать с седьмой стихией. Блок стоит в конце
   файла нарочно: при равной силе правил побеждает последнее, и места,
   заданные здесь для телефона, перекрывают общие правила выше. */

/* ГОВОРИТЬ в ряду стихий: тусклая — рядом никого (нажать можно: скажет,
   к кому подойти), горит — житель рядом, «УЙТИ» — идёт разговор. */
.daemon-key[data-element="talk"] { border-color: #f2e6c9; color: #f2e6c9; }
.daemon-key[data-element="talk"][data-near="0"] { opacity: .38; }
.daemon-key[data-element="talk"][data-near="1"] {
  background: #f2e6c922;
  box-shadow: 0 0 12px #f2e6c966;
}
/* Без мигания монеты (.daemon-key[data-armed] выше — общее правило): «УЙТИ»
   — не ожидание «куда?», а ровное состояние, пока идёт разговор. */
.daemon-key[data-element="talk"][data-armed="1"] {
  background: #f2e6c940;
  border-width: 2px;
  animation: none;
}
.daemon-key[data-element="talk"][data-armed="1"] i { color: #f2e6c9; }

.talk {
  position: fixed;
  left: 50%;
  /* Над рядом стихий: на компьютере ряд — 44 точки от низа + отступ. */
  bottom: calc(max(14px, env(safe-area-inset-bottom)) + 62px);
  z-index: 11;
  width: min(560px, calc(100vw - 32px));
  padding: 10px 12px 12px;
  border: 1px solid #f2e6c955;
  border-left: 3px solid #f2e6c9;
  background: #070b0df2;
  color: var(--paper);
  transform: translateX(-50%);
}

.talk[hidden] { display: none; }

.talk-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 4px;
}

.talk-head b {
  color: #f2e6c9;
  font: 900 11px var(--mono);
  letter-spacing: .16em;
}

#talkWait {
  color: #ff8c3c;
  font: 800 9px var(--mono);
  letter-spacing: .1em;
}
#talkWait[hidden] { display: none; }

#talkLine {
  margin: 0 0 9px;
  color: #ffffff;
  font: 600 13px/1.4 var(--mono);
  letter-spacing: .02em;
}

/* Ответы — сеткой два в ряд, все клетки одного размера (свод, п.13). */
.talk-choices {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: minmax(44px, 1fr);
  gap: 6px;
}

.talk-choice {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 6px 10px;
  border: 1px solid #f2e6c977;
  border-radius: 3px;
  background: #12181ae6;
  color: var(--paper);
  font: 700 11px/1.3 var(--mono);
  letter-spacing: .03em;
  text-align: left;
  cursor: pointer;
  touch-action: manipulation;
}

.talk-choice b {
  flex: none;
  color: #f2e6c9;
  font: 900 13px/1 var(--mono);
}

.talk-choice:hover { background: #1d2a2c; }
.talk-choice:active { background: #f2e6c933; }
.talk-leave { border-color: #ffffff33; color: #a9b8b4; }
.talk-leave b { color: #a9b8b4; }

/* Пока идёт разговор, тост встаёт над полосой, а не под неё: место
   полосы считает main.js (--talk-top — от низа экрана до её верха). */
body.is-talking .toast { bottom: calc(var(--talk-top, 0px) + 8px); }

/* Журнал — карточка книги (.tome), свой только список. */
.zhurnal-list {
  display: grid;
  gap: 10px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.zhurnal-item {
  display: grid;
  gap: 6px;
  padding: 10px 12px;
  border: 1px solid #ffffff1c;
  border-left: 3px solid #ffd27f;
  background: #0b0f12cc;
}
.zhurnal-item[data-state="sdelano"] { border-left-color: #3dffb4; }
.zhurnal-item[data-state="provaleno"] { border-left-color: #ff5d8f; }

.zhurnal-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}

.zhurnal-top b {
  color: var(--paper);
  font: 800 12px var(--mono);
  letter-spacing: .1em;
}

.zhurnal-state {
  flex: none;
  padding: 2px 6px;
  border: 1px solid currentColor;
  color: #ffd27f;
  font: 800 9px var(--mono);
  letter-spacing: .14em;
}
.zhurnal-item[data-state="sdelano"] .zhurnal-state { color: #3dffb4; }
.zhurnal-item[data-state="provaleno"] .zhurnal-state { color: #ff5d8f; }

.zhurnal-next {
  margin: 0;
  color: #d9ffff;
  font: 600 10px/1.45 var(--mono);
  letter-spacing: .05em;
}

.zhurnal-ways {
  color: #8a9a96;
  font: 700 8px var(--mono);
  letter-spacing: .12em;
}

.zhurnal-track {
  justify-self: start;
  min-width: 44px;
  min-height: 44px;
  padding: 6px 14px;
  border: 1px solid #7ffcff88;
  background: #061013d9;
  color: #d9ffff;
  font: 800 10px var(--mono);
  letter-spacing: .12em;
  cursor: pointer;
}
.zhurnal-track[data-on="1"] { background: #7ffcff2e; border-color: #7ffcff; }

/* ЗАДАНИЯ — третья кнопка столбика КНИГИ на компьютере: под книгой, а
   кнопки камеры — ниже на её высоту (.camctl выше, +224). */
.mute-third { top: calc(max(10px, env(safe-area-inset-top)) + 164px); }
.mute-third[hidden] { display: none; }

/* Телефон стоя: ЗАДАНИЯ — в ряд с КНИГОЙ, правее неё, до кнопки ПУСК
   остаётся больше 30 точек. Полоса разговора — над рядом стихий, во всю
   ширину: поле выше неё, и герой в середине поля не закрыт. */
@media (pointer: coarse) and (orientation: portrait),
       (max-width: 700px) and (orientation: portrait) {
  /* КНИГА и ЗАДАНИЯ — один ряд, значит одного размера (свод, п.13). */
  .mute-second { min-width: 100px; padding-left: 8px; padding-right: 8px; }
  .mute-third {
    top: auto;
    left: calc(max(12px, env(safe-area-inset-left)) + 108px);
  }
  .mute-third .key-hint { display: none; }

  .talk {
    left: max(12px, env(safe-area-inset-left));
    right: max(12px, env(safe-area-inset-right));
    bottom: calc(26% + 8px);
    width: auto;
    transform: none;
    padding: 8px 10px 10px;
  }
  #talkLine { font-size: 12px; margin-bottom: 7px; }
  .talk-choice { font-size: 10px; padding: 5px 8px; }
  .talk-choice b { display: none; }

  /* Семь в ряд (пять стихий, монета, ГОВОРИТЬ) — одного размера и не
     уже 44 точек даже на 360: (360 − 48) / 7 = 44.6. */
  .daemons[data-coin="1"][data-talk="1"] { gap: 4px; }
  .daemons[data-coin="1"][data-talk="1"] .daemon-key { width: min(68px, calc((100vw - 48px) / 7)); padding: 6px 2px; }
  .daemons[data-talk="1"] .daemon-key i { font-size: 8px; letter-spacing: .04em; }
}

/* Телефон боком: ЗАДАНИЯ — четвёртой в столбике справа (КНИГА, ЗВУК,
   НА САЙТ), над ПУСКом остаётся больше 60 точек и на 375 в высоту.
   Полоса — слева над рядом стихий, шириной меньше половины экрана:
   герой в середине кадра не закрыт. */
@media (pointer: coarse) and (orientation: landscape) {
  .mute-third {
    top: calc(max(10px, env(safe-area-inset-top)) + 144px);
    right: max(12px, env(safe-area-inset-right));
    left: auto;
    bottom: auto;
  }
  .mute-third .key-hint { display: none; }

  .talk {
    left: max(12px, env(safe-area-inset-left));
    bottom: calc(max(12px, env(safe-area-inset-bottom)) + 56px);
    width: min(380px, 42vw);
    transform: none;
    padding: 7px 9px 9px;
  }
  #talkLine { font-size: 11px; margin-bottom: 6px; }
  .talk-choice { font-size: 9px; padding: 4px 7px; }
  .talk-choice b { display: none; }
  /* Тост при разговоре — над полосой слева, а не посреди кадра: посреди
     он ложился на героя (кадр 844×390, 03.10). */
  body.is-talking .toast {
    left: max(12px, env(safe-area-inset-left));
    max-width: min(380px, 42vw);
    transform: none;
    text-align: left;
  }

  /*
   * Приёмка 03.10, 667×375: шапка задачи («ВЫНЕСТИ ЯДРО · РУКИ…»)
   * шириной 100vw − 118 заезжала на ЗВУК справа. Справа столбик кнопок
   * шириной до 84 точек и отступ 12, слева шапке оставлено столько же —
   * она остаётся посередине и не доходит до кнопок ни на 667, ни на 844.
   * То же у строки наблюдения под ней.
   */
  .operation-hud { width: min(560px, calc(100vw - 216px)); }
  .physical-observation { width: min(520px, calc(100vw - 216px)); }
}


/* =========================================================
   КАМЕРА ОДНОЙ КНОПКОЙ И ТЕЛЕФОН СТОЯ В ОБЪЁМНОМ ВИДЕ
   (приёмка Глаз 03.10, «Башня» на 390×844)
   =========================================================
   Было: пять квадратов камеры первым делом в углу (читались отладочной
   панелью), шапка задачи висела над полем и закрывала стража, поле
   начиналось ниже 124 точек, нижняя полка — 219 точек (26%), и строка
   ВЫРЕЗАНО/ВРЕМЯ лежала под КНИГОЙ. Стало: КАМЕРА — одна кнопка, шапка
   задачи — справа от неё в одной верхней полосе, поле — между полосой и
   полкой, полка 170 точек (20%): ряд стихий, под ним КНИГА и ЗАДАНИЯ,
   под ними ЗВУК и НА САЙТ — две пары одного размера, справа ПУСК. Счёт
   попытки — строкой в КНИГЕ. Числа — pilot-vid/zamer-chitaemost.mjs.
   Плоский вид кампании это не трогает: всё ниже — только body.vid-iso
   (кнопка КАМЕРА и так видна только в объёмном виде).
   ========================================================= */

.camtoggle {
  position: fixed;
  top: calc(max(10px, env(safe-area-inset-top)) + 224px);
  right: max(10px, env(safe-area-inset-right));
  z-index: 9;
  min-width: 44px;
  min-height: 44px;
  padding: 0 10px;
  border: 1px solid #7ffcff55;
  background: #061013d9;
  color: #d9ffff;
  font: 800 10px var(--mono);
  letter-spacing: .12em;
  cursor: pointer;
  touch-action: manipulation;
}
.camtoggle[hidden] { display: none; }
.camtoggle[data-open="1"] { background: #7ffcff2e; border-color: #7ffcff; }

/* Раскрытые пять — под кнопкой КАМЕРА (компьютер). */
.camctl { top: calc(max(10px, env(safe-area-inset-top)) + 276px); }

/* Строка счёта в КНИГЕ: видна только там, где HUD со счётом спрятан. */
.tome-stats { display: none; margin: 4px 0 0; color: #ffd27f; font: 700 10px var(--mono); letter-spacing: .1em; }

body.is-shooting .camtoggle { display: none !important; }

/* Телефон боком: КАМЕРА — на месте прежней строки, раскрытые пять —
   строкой под ней, левее столбика КНИГИ. */
@media (pointer: coarse) and (orientation: landscape) {
  .camtoggle {
    top: max(8px, env(safe-area-inset-top));
    right: calc(max(12px, env(safe-area-inset-right)) + 84px);
  }
  .camctl {
    top: calc(max(8px, env(safe-area-inset-top)) + 52px);
    right: calc(max(12px, env(safe-area-inset-right)) + 84px);
  }
}

@media (pointer: coarse) and (orientation: portrait),
       (max-width: 700px) and (orientation: portrait) {
  body.vid-iso {
    /* Верх поля: полоса из кнопки КАМЕРА и шапки задачи. */
    --strip: calc(max(10px, env(safe-area-inset-top)) + 52px);
    /* Нижний отступ полки и сама полка: 12 + 158 = 170 точек. */
    --sb: max(12px, env(safe-area-inset-bottom));
    --shelf: calc(var(--sb) + 158px);
    /* Две пары кнопок слева от ПУСКа (96) одного размера. */
    --pair: calc((100vw - 24px - 96px - 20px) / 2);
  }

  body.vid-iso #screen {
    inset: var(--strip) 0 auto 0;
    height: calc(100% - var(--strip) - var(--shelf));
  }

  /* Верхняя полоса: КАМЕРА слева, шапка задачи справа от неё. */
  body.vid-iso .camtoggle {
    top: max(10px, env(safe-area-inset-top));
    left: max(12px, env(safe-area-inset-left));
    right: auto;
    width: 76px;
    height: 44px;
    padding: 0;
  }
  body.vid-iso .camctl {
    top: calc(var(--strip) + 6px);
    left: max(12px, env(safe-area-inset-left));
    right: auto;
    grid-auto-flow: column;
  }
  body.vid-iso .operation-hud {
    top: max(10px, env(safe-area-inset-top));
    left: calc(max(12px, env(safe-area-inset-left)) + 84px);
    right: max(12px, env(safe-area-inset-right));
    width: auto;
    min-height: 44px;
    box-sizing: border-box;
    padding: 4px 8px;
    gap: 2px;
    align-content: center;
    text-align: left;
    transform: none;
  }
  body.vid-iso .operation-hud > * {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  body.vid-iso .operation-hud b { font-size: 11px; }
  body.vid-iso .physical-observation { top: calc(var(--strip) + 6px); }

  /* Счёт попытки уезжает в КНИГУ. */
  body.vid-iso .hud { display: none; }
  body.vid-iso .tome-stats { display: block; }

  /* Полка: ряд стихий сверху… */
  body.vid-iso .daemons {
    top: auto;
    bottom: calc(var(--sb) + 104px);
  }
  /* …под ним КНИГА и ЗАДАНИЯ, ниже ЗВУК и НА САЙТ — одного размера… */
  body.vid-iso .mute,
  body.vid-iso .game-home-menu {
    top: auto;
    right: auto;
    width: var(--pair);
    min-width: 44px;
    height: 44px;
    min-height: 44px;
    box-sizing: border-box;
    padding: 0 6px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font: 800 10px var(--mono);
    letter-spacing: .1em;
  }
  body.vid-iso .mute-second { left: max(12px, env(safe-area-inset-left)); bottom: calc(var(--sb) + 52px); }
  body.vid-iso .mute-third { left: calc(max(12px, env(safe-area-inset-left)) + var(--pair) + 8px); bottom: calc(var(--sb) + 52px); }
  body.vid-iso .mute:not(.mute-second) { left: max(12px, env(safe-area-inset-left)); bottom: var(--sb); }
  body.vid-iso .game-home-menu { left: calc(max(12px, env(safe-area-inset-left)) + var(--pair) + 8px); bottom: var(--sb); }

  /* …справа ПУСК на обе строки. */
  body.vid-iso .pad { bottom: var(--sb); }
  body.vid-iso .pad-big { width: 96px; height: 96px; font-size: 15px; }

  /* Подсказки и разговор — над полкой, а не над прежними 26%. */
  body.vid-iso .toast { bottom: calc(var(--shelf) + 12px); }
  body.vid-iso .talk { bottom: calc(var(--shelf) + 8px); }
  /* При разговоре тост — над полосой разговора (правило выше по файлу,
     body.is-talking .toast): то же место, что без объёмного вида. */
  body.vid-iso.is-talking .toast { bottom: calc(var(--talk-top, 0px) + 8px); }
}

/* =========================================================
   ПОЛКА СТИХИЙ НА ТЕЛЕФОНЕ (изометрия; приёмка Глаз 03.10, второй заход)
   =========================================================
   Было: семь кнопок 49×46 на 390 точках, подписи 8 точек, недоступные —
   прозрачностью .3 (серое на чёрном у края читаемости). Стало: над
   подписью крупный знак — клавиша стихии (← ↑ → ↓ ⇧ — те же знаки, что в
   словах подсказки: «ДОСТАНЕТ ⇧⇧⇧»), у монеты — сколько их, у разговора —
   «…» (облачко над жителем) и «»» в разговоре; подпись 11 точек одним
   словом («ГОВОР.» и «МОНЕТА» — иначе не влезают, main.js compactRow).
   Открытая стихия — подпись её цветом; недоступная — без прозрачности,
   тусклой рамкой и серой подписью с контрастом не меньше 3:1 (#6c7974 на
   #0a0f10 — 4.2:1 по формуле WCAG). Размеры кнопок прежние — семь одного
   размера, не меньше 44 (свод, п.13). Только пальцем и только в объёмном
   виде: плоский вид и компьютер — как были. */
@media (pointer: coarse) {
  body.vid-iso .daemon-key {
    gap: 1px;
    padding: 4px 0;
    align-content: center;
  }
  body.vid-iso .daemon-key b {
    display: block;
    font: 900 17px/1 var(--mono);
  }
  body.vid-iso .daemon-key[data-element="coin"] b,
  body.vid-iso .daemon-key[data-element="talk"] b { display: none; }
  body.vid-iso .daemon-key[data-element="coin"]::before,
  body.vid-iso .daemon-key[data-element="talk"]::before {
    content: attr(data-glyph);
    font: 900 15px/1.1 var(--mono);
    color: inherit;
  }
  body.vid-iso .daemon-key i,
  body.vid-iso .daemons[data-talk="1"] .daemon-key i {
    font: 800 11px/1 var(--mono);
    letter-spacing: 0;
    white-space: nowrap;
  }
  /* Цвет — отдельным правилом с меньшей силой: серый недоступных ниже
     обязан его перебить. */
  body.vid-iso .daemon-key i { color: inherit; }
  /* Цвет кнопки стихии задан в main.js прямо в разметке (style.color) —
     поэтому серый ставится знаку и подписи, а не кнопке. */
  body.vid-iso .daemon-key[data-locked="1"],
  body.vid-iso .daemon-key[data-empty="1"] {
    opacity: 1;
    filter: none;
    border-color: #2c3533;
  }
  body.vid-iso .daemon-key[data-locked="1"] b,
  body.vid-iso .daemon-key[data-locked="1"] i,
  body.vid-iso .daemon-key[data-empty="1"] i,
  body.vid-iso .daemon-key[data-empty="1"]::before { color: #6c7974; }
  body.vid-iso .daemon-key[data-element="talk"][data-near="0"] {
    opacity: 1;
    border-color: #3d3a32;
  }
  body.vid-iso .daemon-key[data-element="talk"][data-near="0"] i,
  body.vid-iso .daemon-key[data-element="talk"][data-near="0"]::before { color: #7d786a; }
  /* Нажатая стихия — тёмная подпись на её цвете (правило выше по файлу). */
  body.vid-iso .daemon-key[data-active="1"] i { color: #050b0c; }
}

/* =========================================================
   КЛАВИШИ НА КОМПЬЮТЕРЕ ВИДНЫ ВСЕГДА (отзыв Сергея 04.10, п.7)
   =========================================================
   «Пропали подсказки клавиш магии — непонятно, что нажимать». В «Башне»
   стихии выдаются по ступеням, и в начале кнопки закрыты: до 05.10
   закрытая кнопка на компьютере была прозрачностью .3 с серым фильтром —
   знак клавиши (← ↑ → ↓ ⇧) серым на чёрном почти не читался; а в узком
   окне стоя (меньше 700 точек) знак прятался правилом телефона. Стало:
   на мыши знак клавиши есть при любой ширине окна, закрытые — без
   прозрачности, тусклой рамкой и серым знаком #6c7974 (4.2:1, как на
   телефоне); у монеты — E, у разговора — F, у СБРОСА — Q. Только
   объёмный вид: плоская кампания принята такой (свод, п.15). */
@media (pointer: fine) {
  body.vid-iso .daemon-key b { display: block; }
  body.vid-iso .daemon-key[data-locked="1"],
  body.vid-iso .daemon-key[data-empty="1"] {
    opacity: 1;
    filter: none;
    border-color: #2c3533;
  }
  body.vid-iso .daemon-key[data-locked="1"] b,
  body.vid-iso .daemon-key[data-locked="1"] i,
  body.vid-iso .daemon-key[data-empty="1"] b,
  body.vid-iso .daemon-key[data-empty="1"] i { color: #6c7974; }
}

/* =========================================================
   СБРОС ОЧЕРЕДИ (отзыв Сергея 04.10, п.9)
   =========================================================
   Кнопка в ряду стихий, того же размера (свод, п.13), последней; Q на
   компьютере, «✕» на пальце. Пустая очередь — тусклая (data-empty), но на
   месте: ряд не перестраивается. Телефон стоя: восьмая кнопка в ряду
   уже 44 точек ((375 − 52) / 8 = 40), поэтому там СБРОС — третьей в
   строке КНИГА · ЗАДАНИЯ (#btn-dump-shelf), три одного размера. */
.daemon-key[data-element="dump"] { border-color: #e6a0ad; color: #e6a0ad; }
.mute.dump-shelf { display: none; }

@media (pointer: coarse) {
  body.vid-iso .daemon-key[data-element="dump"] b { display: none; }
  body.vid-iso .daemon-key[data-element="dump"]::before {
    content: attr(data-glyph);
    font: 900 15px/1.1 var(--mono);
    color: inherit;
  }
  body.vid-iso .daemon-key[data-element="dump"][data-empty="1"]::before { color: #6c7974; }
}

@media (pointer: coarse) and (orientation: portrait),
       (max-width: 700px) and (orientation: portrait) {
  body.vid-iso {
    /* Три одного размера слева от ПУСКа (96) в строке КНИГА · ЗАДАНИЯ. */
    --trio: calc((100vw - 24px - 96px - 20px - 8px) / 3);
  }
  body.vid-iso .daemons .daemon-key[data-element="dump"] { display: none; }
  body.vid-iso .mute-second,
  body.vid-iso .mute-third { width: var(--trio); }
  body.vid-iso .mute-third { left: calc(max(12px, env(safe-area-inset-left)) + var(--trio) + 8px); }
  body.vid-iso .mute.dump-shelf:not([hidden]) {
    display: inline-flex;
    left: calc(max(12px, env(safe-area-inset-left)) + 2 * (var(--trio) + 8px));
    bottom: calc(var(--sb) + 52px);
    width: var(--trio);
    border-color: #e6a0ad88;
    color: #e6a0ad;
    touch-action: none;
  }
  body.vid-iso .mute.dump-shelf[data-empty="1"] { color: #6c7974; border-color: #2c3533; }
}

/* =========================================================
   ЗАДАНИЯ СЛЕВА (отзыв Сергея 04.10, п.20; src/treker.js)
   =========================================================
   Компьютер: левый край под строкой счёта, шириной до 300 точек — шапка
   задачи посередине, кнопки справа, герой в центре не закрыт. Телефон
   стоя: под полосой КАМЕРА/шапка, левее середины (до 56% ширины), не
   больше двух строк заданий — до героя в середине поля остаётся больше
   150 точек. Телефон боком: свёрнут с начала (main.js), шапкой 44 точки. */
.treker {
  position: fixed;
  top: calc(max(10px, env(safe-area-inset-top)) + 70px);
  left: max(10px, env(safe-area-inset-left));
  z-index: 8;
  display: grid;
  gap: 4px;
  width: min(300px, 30vw);
  pointer-events: none;
}
.treker[hidden] { display: none; }
.treker-head {
  justify-self: start;
  min-height: 32px;
  padding: 0 10px;
  border: 1px solid #7ffcff55;
  background: #061013d9;
  color: #7ffcff;
  font: 800 10px var(--mono);
  letter-spacing: .12em;
  cursor: pointer;
  pointer-events: auto;
  touch-action: manipulation;
}
.treker-list {
  display: grid;
  gap: 4px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.treker-list li {
  display: grid;
  gap: 2px;
  padding: 6px 9px;
  border-left: 3px solid #7ffcff88;
  background: #061013c7;
  color: #d9ffff;
  cursor: pointer;
  pointer-events: auto;
}
.treker-list li[data-tracked="1"] { border-left-color: #7ffcff; background: #0a2226d9; }
.treker-list b { font: 800 11px/1.2 var(--mono); letter-spacing: .06em; color: #ffd27f; }
.treker-list span { font: 600 10px/1.35 var(--mono); color: #cfe3e0; }
.treker-list .treker-empty { border-left-color: #2c3533; color: #8fa39b; font: 600 10px var(--mono); cursor: default; }
body.is-shooting .treker { display: none !important; }
/* Задания уступают героя и цель подсказки (приёмка Глаз 05.10; igra.js,
   PANEL): пока под ними тот, на кого смотрят, — почти прозрачные и не
   ловят касаний. */
.treker { transition: opacity .18s; }
.treker[data-yield="1"] { opacity: .16; }
.treker[data-yield="1"] .treker-head,
.treker[data-yield="1"] .treker-list li { pointer-events: none; }

@media (pointer: coarse) and (orientation: portrait),
       (max-width: 700px) and (orientation: portrait) {
  body.vid-iso .treker {
    top: calc(var(--strip) + 56px);
    left: max(8px, env(safe-area-inset-left));
    width: min(56vw, 240px);
  }
  body.vid-iso .treker-head { min-height: 44px; }
  /* Две строки заданий, третья — в журнале. */
  body.vid-iso .treker-list li:nth-child(n + 3):not(.treker-empty) { display: none; }
  .treker-list b { font-size: 10px; }
  /* Шаг — одной строкой (кадр дыма v9: две строки по три строки текста
     занимали 250 точек верха поля); целиком — в журнале. */
  .treker-list span { font-size: 9px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
}

@media (pointer: coarse) and (orientation: landscape) {
  .treker {
    top: calc(max(8px, env(safe-area-inset-top)) + 52px);
    left: max(12px, env(safe-area-inset-left));
    width: min(240px, 32vw);
  }
  .treker-head { min-height: 44px; }
}
