/* Движение в интерфейсе: отклики, появления, подсветка.
   Подключается последним, после board.css и встроенного <style>, — правила
   ниже намеренно перекрывают их по нескольким свойствам (#hint, transition у
   кнопок).

   Почему отдельным файлом: index.html правят двое, и его уже дважды
   перезаписывали целиком вместе с чужими правками. Разметка — общая
   территория, а движение — цельный кусок, который спокойно живёт отдельно.
   В index.html от него остаётся одна строка <link>: если пропадёт и она, это
   видно сразу и чинится одной строкой. См. CLAUDE.md и COORD.md рядом.

   Свет на половине табло сюда не входит: он не украшение, а способ показать,
   чей ход, и живёт вместе с самим табло в board.css. */

/* --- забитый шар ---------------------------------------------------------
   Ряд перекладывается только когда в нём что-то изменилось (см. paintRack в
   main.ts), поэтому появление можно отдать CSS: шар падает на рейку, и
   забитый виден боковым зрением, даже если смотришь на стол. Пустые ячейки
   молчат — им прыгать не с чего. */
.chip:not(.empty) {
  animation: chip-in 0.3s cubic-bezier(0.2, 1.4, 0.45, 1) both;
}
@keyframes chip-in {
  from { opacity: 0; transform: scale(0.5) translateY(-7px); }
  to { opacity: 1; transform: scale(1) translateY(0); }
}

/* --- подсказка прицела ---------------------------------------------------
   Не просто проявляется, а чуть подъезжает снизу: движение ловится
   периферийным зрением, пока целишься. Сдвиг держим в базовом состоянии,
   чтобы к нему же и возвращаться, — и повторяем центрирующий translateX,
   иначе он потеряется. */
#hint {
  transform: translateX(-50%) translateY(6px);
  transition: opacity 0.18s, transform 0.18s;
}
#hint.on {
  transform: translateX(-50%) translateY(0);
}

/* --- отклик кнопок -------------------------------------------------------
   Нажатие проваливается под палец: без отклика по короткому клику не понять,
   попал ты в кнопку или мимо. Кнопки партии живут внизу вместе со звуком и
   полноэкранкой, поэтому и отзываются одинаково. */
#swap,
#reset,
#sound,
#full {
  transition: opacity 0.18s, transform 0.1s;
}
#swap:active:not(:disabled),
#reset:active:not(:disabled),
#sound:active,
#full:active {
  transform: translateY(1px);
}
.over button {
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}
.over button:active {
  transform: translateY(1px);
}

/* --- значки в углу -------------------------------------------------------
   Они мелкие, и одной проявляющейся прозрачности мало: подрост подтверждает,
   что курсор именно на кнопке. */
#sound svg,
#full svg,
#swap svg,
#reset svg {
  transition: transform 0.15s;
}
#sound:hover svg,
#full:hover svg,
#swap:hover:not(:disabled) svg,
#reset:hover svg {
  transform: scale(1.15);
}

/* --- риски на ползунке наклона -------------------------------------------
   Сами риски расставляет controls.ts из того же списка TILT_STOPS, по которому
   считается притяжение: распиши мы их в разметке — завели бы второй список, и
   ручка липла бы мимо нарисованного. Здесь только вид. */
#tilt .tick {
  position: absolute;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 6px;
  height: 1px;
  background: rgba(255, 255, 255, 0.3);
}

/* --- дыхание лампы -------------------------------------------------------
   Свет не стоит мёртво: он едва заметно дышит, как лампа над столом. Период
   долгий, размах маленький — это признак жизни, а не сигнал. Мигай он
   заметно, от него пришлось бы прятать глаза всю партию.

   Задержка равна времени переезда: пока лампа переходит на другую половину,
   дыхание молчит и не мешает ей проявиться. Правило одно на обе стороны —
   иначе при смене хода анимация начиналась бы заново. */
#board.lit-l .lamp,
#board.lit-r .lamp {
  animation: lamp-breathe 3.4s ease-in-out 0.3s infinite;
}
@keyframes lamp-breathe {
  0%, 100% { opacity: 0.76; }
  50% { opacity: 1; }
}

/* --- новый фол -----------------------------------------------------------
   Точки мелкие, а фол — событие редкое и неприятное: без толчка его легко
   пропустить. Ряд перекладывается только при изменении (см. paintFouls),
   поэтому толчок и приходится ровно на новый фол. */
#board .pip.on {
  animation: pip-in 0.26s cubic-bezier(0.2, 1.5, 0.4, 1) both;
}
@keyframes pip-in {
  from { transform: scale(0.2); }
  to { transform: scale(1); }
}

/* --- время на исходе -----------------------------------------------------
   Единственное место, где мигать уместно: цифры не просто краснеют, а зовут.
   Кольцо к этому моменту почти пусто, и одного цвета мало. */
#turn.low {
  animation: clock-urge 1s ease-in-out infinite;
}
@keyframes clock-urge {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}

/* --- появление табло -----------------------------------------------------
   Один раз при загрузке: табло висит на нитках, и опуститься сверху ему
   естественно. Дальше оно неподвижно — это знакомство, а не украшение. */
#board {
  animation: board-drop 0.5s cubic-bezier(0.2, 0.9, 0.3, 1) both;
}
@keyframes board-drop {
  from { opacity: 0; transform: translateY(-16px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Кому движение мешает — тому его и не надо. Дыхание и мигание гасим совсем:
   их не укорачивают, от короткой длительности они начнут частить. Смысл при
   этом не теряется — чей ход, говорят место и цвет, а время на исходе видно
   по кольцу и по красному. */
@media (prefers-reduced-motion: reduce) {
  .chip:not(.empty),
  #board .pip.on,
  #board { animation-duration: 0.01s; }
  #board.lit-l .lamp,
  #board.lit-r .lamp,
  #turn.low { animation: none; }
  .lamp { transition-duration: 0.01s; }
  #hint,
  #swap,
  #reset,
  #sound,
  #full,
  .over button,
  #sound svg,
  #full svg,
  #swap svg,
  #reset svg {
    transition-duration: 0.01s;
  }
}
