/**
 * Доска сексополии. Перенесено из приложения, lib/games/sexopoly/
 * sexopoly_board.dart, и там в шапке сказано откуда взялось оно само:
 *
 *   «Сорок клеток разложены ровно как на изометрической доске сайта: обход
 *   path(3,7) в координатах сетки, проекция x=(c-r)*26, y=(c+r)*26, плитка 52,
 *   так что ромбы смыкаются кромка к кромке в стоячую петлю.»
 *
 * То есть геометрия одна и та же на бою и в приложении, и мы её не выдумываем
 * заново, а берём как есть. Сами координаты считает JS: сорок пар чисел в
 * стилях были бы мёртвым списком, который никто не сверит.
 *
 * ЧТО ОТСЮДА, А ЧТО ОТТУДА. Раскладка петли с боя, всё остальное из
 * приложения: круглая кнопка назад, полоса игроков сверху «он | vs | она»,
 * петля поверх притемнённого фона, кубики в дырке петли, полоса броска ПОД
 * полем с именем того, чей ход, и модалки снизу.
 *
 * ЧИСЛА ИЗ ПРИЛОЖЕНИЯ, не подобранные на глаз:
 *   плитка          52 в единицах сетки, ромб 0.70 от неё, поворот 45°
 *   скругление      0.1 от стороны
 *   картинка        0.62 от стороны, стоит ПРЯМО, не повёрнута
 *   фишка           0.26 от стороны, смещение ±0.5 радиуса, чтобы две
 *                   фишки на одной клетке не слились в одну
 *   подскок         sin(t·π) × высота доски × 0.045
 *   кубики          по ДЫРКЕ петли, а не по ширине доски: 0.2 ширины доски
 *                   из приложения давало два кубика шире дырки на каждом
 *                   телефоне, и они налезали на клетки по бокам
 *
 * ЦВЕТА УГЛОВЫХ КЛЕТОК тоже оттуда, и там объяснено почему именно такие: тона
 * разведены далеко и друг от друга, и от двух цветов игроков (синий 207, роза
 * 347), чтобы ничто не читалось как промах мимо чего-то другого.
 */

/* ---------- «партия не доиграна» на экране настроек ---------- */

/* Живёт здесь, а не в frame.css, потому что это часть игры, а не каркаса.
   Переедет в общие, когда вторая игра попросит того же. */
.set-resume { display: flex; flex-direction: column; gap: var(--s-3); }
.set-resume__tekst {
  margin: 0;
  font: var(--t-body-m);
  color: var(--c-muted);
}
.set-resume .btn { width: 100%; }

/* ---------- экран целиком ---------- */

/**
 * Доска занимает экран без остатка: полоса игроков сверху, поле, полоса броска
 * снизу. Прокрутки нет и быть не должно, иначе поле уезжает под палец в самый
 * момент броска.
 *
 * ВЫСОТА СЧИТАЕТСЯ ПО ВИДИМОМУ ОКНУ, А НЕ ПО БОЛЬШОМУ, и это главное здесь.
 * У элемента с position: fixed и inset: 0 высота берётся от layout viewport, а
 * он на телефоне равен окну БЕЗ адресной строки. Пока строка на экране, низ
 * уезжает под неё: на iPhone 14 не хватало 41 пиксела, на SE девяноста двух,
 * и полоса броска вместе с нижним рядом клеток оказывались за краем.
 *
 * svh, а не dvh: dvh меняется, когда адресная строка прячется при прокрутке,
 * и доска пересчитывалась бы и прыгала. svh это САМОЕ МАЛЕНЬКОЕ окно, то есть
 * со строкой на месте, и оно не меняется никогда. Доска в нём помещается
 * всегда, ценой полоски фона сверху, когда строка уедет.
 *
 * vh запасным для браузеров, которые svh ещё не знают: там останется прежнее
 * поведение, а не нулевая высота.
 */
.sx-play {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 100vh;
  height: 100svh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--c-bg);
  /* Вырез сверху и полоса жеста снизу: без этого имя игрока лезет под чёлку,
     а кнопка броска под home-индикатор. */
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}

/* На телефоне всё в одну колонку, полосы во всю ширину. */
.sx-top,
.sx-pole,
.sx-niz {
  width: 100%;
}


/* ---------- верх: круглая кнопка назад и полоса игроков ---------- */

.sx-top {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-3) var(--s-2);
  flex: 0 0 auto;
}

/* Круглая, и это единственное круглое в игре кроме лиц и фишек: она
   заканчивает партию, и её нельзя спутать с кнопкой внутри модалки. */
.sx-back {
  width: var(--tap);
  height: var(--tap);
  flex: 0 0 var(--tap);
  border-radius: 50%;
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface-high);
  color: var(--c-text);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.sx-back:active { transform: scale(.94); }

.sx-players {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex: 1 1 auto;
  min-width: 0;
}

.sx-vs {
  font: var(--t-label-s);
  letter-spacing: var(--tr-label-s);
  color: var(--c-faint);
  text-transform: lowercase;
  flex: 0 0 auto;
}

/**
 * Карточка игрока. На своём ходу она в золотой обводке и светится, в чужой
 * притушена. Это единственный указатель, чей ход, кроме подписи на полосе
 * броска, и потому разница между двумя состояниями сделана заметной.
 */
.sx-p {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex: 1 1 0;
  min-width: 0;
  padding: var(--s-2);
  border-radius: var(--r-md);
  border: 1px solid var(--c-border);
  background: rgba(29,23,22,.45);
  transition: background .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.sx-p[data-khodit="da"] {
  background: rgba(29,23,22,.9);
  border-color: rgba(212,175,55,.85);
  box-shadow: 0 0 12px -3px rgba(212,175,55,.22);
}

.sx-p__litso {
  width: 34px;
  height: 34px;
  flex: 0 0 34px;
  border-radius: 50%;
  overflow: hidden;
  border: 1.2px solid;
  border-color: color-mix(in srgb, var(--storona-tsvet) 50%, transparent);
  background: var(--c-surface-alt);
}
.sx-p[data-khodit="da"] .sx-p__litso {
  border-width: 1.6px;
  border-color: color-mix(in srgb, var(--storona-tsvet) 95%, transparent);
  box-shadow: 0 0 8px color-mix(in srgb, var(--storona-tsvet) 55%, transparent);
}
.sx-p__litso img { width: 100%; height: 100%; object-fit: cover; display: block; }

.sx-p__kto { min-width: 0; display: flex; flex-direction: column; }
.sx-p__imya {
  font: var(--t-label-l);
  color: var(--c-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sx-p[data-khodit="da"] .sx-p__imya { color: var(--c-text); }

/* Запас табличными цифрами: он меняется каждый ход, и без них строка
   дёргается по ширине на каждой смене разряда. */
.sx-p__zapas {
  font: var(--t-title-s);
  font-variant-numeric: tabular-nums;
  color: var(--c-muted);
}
.sx-p[data-khodit="da"] .sx-p__zapas { color: var(--c-gold); }

.sx-p[data-storona="0"] { --storona-tsvet: var(--c-player-1); }
.sx-p[data-storona="1"] { --storona-tsvet: var(--c-player-2); }

/* ---------- поле ---------- */

.sx-pole {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
}

/* Тёплая лужа под петлёй, картинка поверх неё, и притемнение сверху, чтобы
   плитки и кубики не терялись на свече. Три слоя, как в приложении. */
.sx-fon { position: absolute; inset: 0; pointer-events: none; }
.sx-fon::before,
.sx-fon::after {
  content: '';
  position: absolute;
  inset: 0;
}
.sx-fon::before {
  background: radial-gradient(circle at 50% 47%,
    rgba(212,175,55,.16) 0%, rgba(212,175,55,0) 75%);
}
.sx-fon img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: .78;
}
.sx-fon::after {
  background: radial-gradient(circle at 50% 47%,
    rgba(0,0,0,.28) 35%, rgba(0,0,0,.62) 100%);
}

.sx-petlya { position: absolute; inset: 0; }

/**
 * Клетка. Коробка квадратная, а видимый ромб это повёрнутый на 45° квадрат в
 * 0.70 от неё: только при таком отношении ромбы смыкаются кромка к кромке и
 * петля не разваливается на отдельные плитки.
 */
/**
 * Ромб и значок стоят друг на друге, оба по центру коробки.
 *
 * ЧЕРЕЗ position, А НЕ ЧЕРЕЗ grid, и это не вкусовщина. С гридом и
 * place-items дорожка размечается по содержимому, а оба ребёнка заданы в
 * процентах, и считать эти проценты не от чего: ромб с фоном как-то выживал,
 * а картинка схлопывалась в ноль и клетки выходили пустыми. Проверено на бою
 * первым же снимком.
 */
/**
 * ЧЁТКОСТЬ. Ни одного transform: scale на доске.
 *
 * Правило с боя, там оно записано прямо в шапке раскладки: «клетки
 * раскладываются в СВОЁМ КОНЕЧНОМ размере в пикселях, масштаб вписан прямо в
 * геометрию, никакого CSS-трансформа, поэтому ромбы и значки остаются чёткими
 * при любом размере». Ужать всю доску одним scale проще на две строки, и
 * ровно поэтому так и делают: результат это растянутая картинка, у которой
 * размылись и кромки ромбов, и мелкие значки.
 *
 * Отсюда же смещение процентами, а не через translate(-50%): translate от
 * дробной ширины даёт полпикселя, и кромка ромба размывается на них. 15% это
 * (100 − 70) / 2, 19% это (100 − 62) / 2.
 */
.sx-k { position: absolute; }
.sx-k__romb,
.sx-k__art { position: absolute; }
.sx-k__romb {
  left: 15%;
  top: 15%;
  width: 70%;
  height: 70%;
  transform: rotate(45deg);
  border-radius: 14.3%;              /* 0.1 от стороны коробки при 70% */
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface-high);
  box-shadow: 0 2px 5px rgba(0,0,0,.45);
}
/* Картинка стоит ПРЯМО: ромб повёрнут, значок нет, иначе он читается косо. */
.sx-k__art {
  left: 19%;
  top: 19%;
  width: 62%;
  height: 62%;
  object-fit: contain;
  pointer-events: none;
}

/* Особая клетка носит свой постоянный цвет, и доска читается с одного
   взгляда. Заливка слабая, рамка сильная: цвет должен назвать клетку, а не
   перекричать значок на ней. */
.sx-k[data-ugol] .sx-k__romb {
  background: color-mix(in srgb, var(--ugol) 22%, var(--c-surface-high));
  border-color: color-mix(in srgb, var(--ugol) 90%, transparent);
}
.sx-k[data-ugol="start"]         { --ugol:#e7c079; }
.sx-k[data-ugol="bdsm"]          { --ugol:#ff7a1f; }
.sx-k[data-ugol="stopword"]      { --ugol:#45d6b6; }
.sx-k[data-ugol="goToBdsm"]      { --ugol:#a988ff; }
.sx-k[data-ugol="chestPleasure"] { --ugol:#5fbf66; }
.sx-k[data-ugol="chestDesire"]   { --ugol:#d45fd4; }
.sx-k[data-ugol="strip"]         { --ugol:#b2b7c2; }

/**
 * Купленная клетка заливается цветом владельца ЦЕЛИКОМ, а не обводится: так
 * на бою, и так сразу видно, чей это квартал. Каждое улучшение делает цвет
 * гуще и свечение сильнее.
 */
.sx-k[data-chjya] .sx-k__romb {
  background: color-mix(in srgb, var(--chey) calc(40% + 15% * var(--urovenj,0)), var(--c-surface-high));
  border: 2px solid var(--chey);
  box-shadow:
    0 2px 5px rgba(0,0,0,.45),
    0 0 calc(10px + 4px * var(--urovenj,0)) -1px
      color-mix(in srgb, var(--chey) calc(24% + 14% * var(--urovenj,0)), transparent);
}
.sx-k[data-chjya="0"] { --chey: var(--c-player-1); }
.sx-k[data-chjya="1"] { --chey: var(--c-player-2); }

/* Кольцо «ты здесь»: тот же ромб, только пустой и золотой. Отдельным узлом, а
   не рамкой на клетке, потому что оно ездит, а клетки стоят. */
/* Та же геометрия, что у ромба, и по той же причине БЕЗ грида: проценты в
   дорожке по содержимому считать не от чего, и кольцо схлопнулось бы так же,
   как схлопнулись значки. */
.sx-koljtso {
  position: absolute;
  pointer-events: none;
}
.sx-koljtso::after {
  content: '';
  position: absolute;
  left: 15%;
  top: 15%;
  width: 70%;
  height: 70%;
  transform: rotate(45deg);
  border-radius: 14.3%;
  border: 2px solid var(--c-gold);
  box-sizing: border-box;
}

/* Фишка. Две на одной клетке разводятся влево и вправо, иначе они сливаются
   в один кружок и пара перестаёт понимать, где кто. */
.sx-fishka {
  position: absolute;
  border-radius: 50%;
  border: 1.5px solid #fff;
  background: var(--chey);
  box-shadow: 0 0 7px color-mix(in srgb, var(--chey) 60%, transparent);
  pointer-events: none;
}
.sx-fishka[data-storona="0"] { --chey: var(--c-player-1); }
.sx-fishka[data-storona="1"] { --chey: var(--c-player-2); }

/* ---------- кубики в дырке петли ---------- */

/* Петля стоячая, и внутри неё есть пустое место. Кубики живут там, а не под
   доской: так их видно вместе с фишкой, которая сейчас пойдёт. */
.sx-kubiki {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0;   /* ставит доска, по стороне кубика */
  pointer-events: none;
}

/* ---------- низ: полоса броска ---------- */

.sx-niz {
  flex: 0 0 auto;
  padding: var(--s-2) var(--s-4) var(--s-3);
}

/**
 * Полоса броска во всю ширину, в цвете того, чей ход, и с его именем.
 * Так на бою: «ЭНДИ · БРОСИТЬ». Кнопка называет человека, а не действие в
 * пустоту, и по ней же видно, чей сейчас ход, не поднимая глаз наверх.
 */
.sx-brosok {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 15px var(--s-4);
  border-radius: var(--r-pill);
  border: 1.4px solid color-mix(in srgb, var(--chey) 85%, transparent);
  background: rgba(29,23,22,.85);
  color: var(--c-text);
  font: var(--t-label-l);
  cursor: pointer;
  box-shadow: 0 4px 22px -6px color-mix(in srgb, var(--chey) 28%, transparent);
}
.sx-brosok[data-storona="0"] { --chey: var(--c-player-1); }
.sx-brosok[data-storona="1"] { --chey: var(--c-player-2); }
.sx-brosok[disabled] { opacity: .55; box-shadow: none; cursor: default; }
.sx-brosok__imya {
  color: var(--chey);
  max-width: 46%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.sx-brosok__tochka { color: var(--c-faint); }

/* Бесплатные ходы кончились: вместо броска два выхода. Столбиком, как все
   пары кнопок в каркасе. */
.sx-stop { display: flex; flex-direction: column; gap: var(--s-2); }
.sx-stop__tekst {
  font: var(--t-body-s);
  color: var(--c-muted);
  text-align: center;
}
.sx-stop__ryad { display: flex; gap: var(--s-3); }
.sx-stop__ryad > * { flex: 1 1 0; }

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

/* Текст задания в рамке: он единственное, что пара будет читать вслух, и он
   не должен теряться среди пояснений про деньги. */
/**
 * Блок задания. Из приложения, и раньше я взял от него только рамку.
 *
 * ЧТО БЫЛО НЕ ТАК: серая рамка на почти таком же сером фоне, и блок сливался
 * со всем остальным на шторке. Владелец так и сказал: «всё будто сливается».
 *
 * ЧТО В ПРИЛОЖЕНИИ и чего у меня не было:
 *
 *   полоса цветом  3 пиксела по одному краю, а не рамка по кругу. Рамка
 *                  обводит и уравнивает, полоса указывает
 *   надпись сверху капителью с широким трекингом: «ЗАДАНИЕ», а на
 *                  владельческом экране «ЕСЛИ СЮДА ВСТАНЕТ ВТОРОЙ». Без неё
 *                  превью читается как приказ
 *   фон светлее    surfaceContainerHigh, то есть НАД карточкой, а не вровень
 *
 * Полоса СЛЕВА, как в приложении. Если понадобится справа, меняется одна
 * строка: border-inline-start на border-inline-end.
 */
.sx-zadanie {
  margin: var(--s-3) 0 var(--s-5);
  padding: var(--s-3) var(--s-4) var(--s-4);
  border-radius: var(--r-lg);
  border-inline-start: 3px solid var(--c-gold);
  /* ВЛОЖЕННОЕ, а не приподнятое. Шторка сама уже surface-high, и блок в том же
     цвете сливался с ней в одно полотно: полоса слева была, а прямоугольника
     не было («все будто сливается», владелец). У ступени surface-alt в своде
     ровно это назначение и записано: «вложенное». */
  background: var(--c-surface-alt);
  color: var(--c-text);
}
.sx-zadanie__shapka {
  font: var(--t-label-s);
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--c-faint);
  margin-bottom: var(--s-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sx-zadanie__tekst {
  font: var(--t-title-m);
  line-height: 1.4;
}

/*
 * Имя внутри задания ПЕРЕЕХАЛО В КАРКАС (`frame.css`, `.имя`). Правило стояло
 * здесь и работало только под `.sx-задание` и `.sx-исход`, а разметку с этим
 * классом делает общий `names.js`, которого зовут одиннадцать мест. Значит,
 * в десяти из них имя было цветным, но не жирным, и увидеть это можно было
 * только рядом с сексополией, где оно жирное.
 */

/**
 * Часы внутри рамки задания: нажал и пошли, нажал ещё раз и встали.
 *
 * ПАУЗА ОБЯЗАТЕЛЬНА. Задание прерывают, и часы, которые нельзя остановить,
 * заставляют доигрывать наперегонки с числом.
 *
 * ЗАЛИВКА ПОЗАДИ показывает пройденное, не заставляя читать цифры.
 */
.sx-chasyi {
  position: relative;
  overflow: hidden;
  margin-top: var(--s-3);
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-2);
  border-radius: var(--r-ctl);
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface-high);
  color: var(--c-gold);
  font: var(--t-title-m);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.sx-chasyi__zalivka {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: color-mix(in srgb, var(--c-gold) 18%, transparent);
  transition: width 1s linear;
  pointer-events: none;
}
.sx-chasyi__znak,
.sx-chasyi__tsifryi { position: relative; }

/**
 * Значок состояния: треугольник, пауза, галочка.
 *
 * Пауза НЕ через clip-path. Полигон из двух прямоугольников замыкается сам на
 * себя, и вместо двух полосок выходит фигура с перемычкой: она и выглядела
 * странно. Две полоски это две заливки, и градиент делает их честно.
 */
.sx-chasyi__znak {
  width: 14px;
  height: 14px;
  flex: 0 0 14px;
  background: currentColor;
}
.sx-chasyi[data-sostoyanie="stoyat"] .sx-chasyi__znak {
  clip-path: polygon(15% 0, 100% 50%, 15% 100%);
}
.sx-chasyi[data-sostoyanie="idut"] .sx-chasyi__znak {
  background: linear-gradient(
    90deg,
    currentColor 0 34%,
    transparent 34% 66%,
    currentColor 66% 100%);
  clip-path: none;
}
.sx-chasyi[data-sostoyanie="vyishlo"] .sx-chasyi__znak {
  clip-path: polygon(14% 52%, 40% 78%, 88% 20%, 96% 30%, 40% 96%, 6% 62%);
}
.sx-chasyi[data-sostoyanie="idut"] { border-color: var(--c-gold); }
.sx-chasyi[data-sostoyanie="vyishlo"] {
  color: var(--c-done);
  border-color: var(--c-done);
}
.sx-chasyi[data-sostoyanie="vyishlo"] .sx-chasyi__zalivka {
  background: color-mix(in srgb, var(--c-done) 18%, transparent);
}

/**
 * Исход карты: что она сделала.
 *
 * Полоса слева, а не рамка по кругу: это НЕ задание, а сообщение, и выглядеть
 * одинаково они не должны. В приложении там же и по той же причине.
 */
.sx-iskhod {
  margin: 0 0 var(--s-5);
  padding: var(--s-3) var(--s-4) var(--s-4);
  border-radius: var(--r-lg);
  border-left: 3px solid var(--c-gold);
  background: var(--c-surface-alt);
  font: var(--t-title-m);
  color: var(--c-text);
  line-height: 1.4;
}

.sx-pod {
  font: var(--t-body-m);
  color: var(--c-muted);
  margin: 0 0 var(--s-4);
}
.sx-pripiska {
  font: var(--t-body-s);
  color: var(--c-faint);
  text-align: center;
  margin: var(--s-2) 0 0;
}

/* ==========================================================================
   ДЕСКТОП

   В КОНЦЕ ФАЙЛА, и это не вкусовщина. Медиа-запрос НЕ добавляет силы правилу:
   при равной силе побеждает тот, кто ниже. Этот блок стоял выше базовых
   правил, и «display: contents» на верхней строке проигрывал «display: flex»,
   написанному ниже: карточки игроков оставались в шапке, а колонки пустыми.
   ========================================================================== */

/* ==========================================================================
   РЕДАКТОР СВОЕЙ ДОСКИ

   Своей разметки у редактора почти нет: доска та же, и правит её тот же файл
   выше. Здесь только то, чего в партии не бывает.

   ЧТО УБИРАЕМ. Кубики, фишки, кольцо «вы здесь» и полоса игроков в редакторе
   не нужны: партии нет. Прятать их стилями, а не выкидывать из разметки,
   потому что разметку строит одна функция на оба случая, и развилка внутри
   неё это второй способ собрать доску, то есть второе место, где она может
   разойтись.

   ПОЧЕМУ visibility, А НЕ display. Кубики лежат в дырке петли и участвуют в
   раскладке: их размер считается от неё. display:none обнулил бы измерения, и
   первая же партия после редактора получила бы кубики не того размера, потому
   что наблюдатель за полем сработал на пустом месте.
   ========================================================================== */

.sx-play--pravka .sx-kubiki,
.sx-play--pravka .sx-fishka,
.sx-play--pravka .sx-koljtso { visibility: hidden; }

/* Клетка в редакторе это кнопка: и на вид, и под пальцем, и с клавиатуры. */
.sx-play--pravka .sx-k { cursor: pointer; }
.sx-play--pravka .sx-k:focus-visible {
  outline: 2px solid var(--c-gold);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

/* Клетка, которую нельзя тронуть, гасится. Не прячется: она часть доски, и
   пропавшая клетка читалась бы как дырка в поле. */
.sx-play--pravka .sx-k--neljzya { cursor: default; opacity: 0.55; }

/* ПОМЕТКА ТРОНУТОЙ КЛЕТКИ. Кружок с галкой в правом верхнем углу, как в
   приложении. Проценты, а не пиксели: клетка на телефоне вдвое меньше, чем на
   широком, и пиксельная метка на маленькой клетке накрыла бы всю картинку. */
.sx-k__metka {
  position: absolute;
  top: 12%;
  right: 12%;
  width: 26%;
  height: 26%;
  border-radius: 50%;
  background: var(--c-gold);
  opacity: 0;
  transition: opacity 0.15s ease;
  pointer-events: none;
}
.sx-k--tronuta .sx-k__metka { opacity: 1; }
/* Галка нарисована рамкой повёрнутого прямоугольника: одна фигура вместо
   картинки, и она остаётся чёткой на любом размере клетки. */
.sx-k__metka::after {
  content: '';
  position: absolute;
  left: 34%;
  top: 16%;
  width: 26%;
  height: 50%;
  border: solid var(--c-on-gold);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

/* Тронутая клетка ещё и подсвечена по кромке: метка мелкая, а глаз ищет
   изменённое издалека, не наводясь на каждую. */
.sx-k--tronuta .sx-k__romb {
  box-shadow: 0 0 0 2px var(--c-gold);
}

/* ---------- шапка редактора ---------- */

.ed-shapka {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  min-width: 0;
}
.ed-shapka__imya {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: var(--t-title-m);
  font-family: var(--f-serif);
}
.ed-shapka__kn {
  flex: none;
  background: none;
  border: 0;
  padding: var(--s-2);
  color: var(--c-gold);
  font: var(--t-label-l);
  cursor: pointer;
}
.ed-shapka__kn--opasno { color: var(--c-danger); }

/* ---------- низ редактора ---------- */

.ed-niz {
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  /* Та же ширина, что у полосы броска: кнопка во всю ширину широкого экрана
     это не кнопка, а линейка. */
  max-width: 460px;
  margin-inline: auto;
  width: 100%;
}
.ed-niz__podpisj {
  margin: 0;
  text-align: center;
  color: var(--c-muted);
  font: var(--t-body-s);
  /* Строка занимает место всегда, даже пустая: иначе поле дёргается вверх и
     вниз на каждой записи, а за ним прыгает вся доска. */
  min-height: 1.2em;
}

/* ---------- поля в шторке клетки ---------- */

/**
 * СВОЕГО ЗДЕСЬ ПОЧТИ НЕТ, и так и должно быть.
 *
 * Первая версия завела свой набор: своё поле ввода, свою рамку ошибки, свой
 * столбец кнопок, крестик буквой ×. Владелец увидел итог сразу: «всё
 * сливается, будто не наши стили, и карандаш не наш». Так и было: похожее,
 * собранное рядом, всегда чуть другое.
 *
 * Теперь ввод это `.sheet-input`, ошибка `.form-error`, кнопки `.sheet-acts`,
 * значки из `значок()`. Здесь остаётся ровно то, чего в общем своде нет:
 * подпись над полем, две колонки под числа и строка желания.
 */

.ed-pole { display: block; margin-bottom: var(--s-3); }
.ed-pole__imya {
  display: block;
  color: var(--c-muted);
  font: var(--t-label-s);
}

/* Четыре числа в две колонки: по одному в строку это четыре экрана прокрутки
   на телефоне, а числа короткие. */
.ed-chisla {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0 var(--s-3);
}

.ed-zhelanie { display: flex; align-items: flex-start; gap: var(--s-2); }
.ed-zhelanie .ed-pole { flex: 1; min-width: 0; }
/* Корзина стоит напротив поля, а не его подписи: подпись это строка сверху,
   и кнопка, выровненная по ней, висела бы над текстом. */
.ed-ubratj { margin-top: 1.7em; }

/**
 * «Добавить желание»: пунктирная рамка, потому что это МЕСТО, а не действие.
 * Сплошная кнопка того же веса, что «Сохранить», спорила бы с ней за главное
 * нажатие в шторке.
 */
.ed-dobavitj {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  width: 100%;
  margin-bottom: var(--s-4);
  padding: var(--s-3);
  background: none;
  border: 1px dashed var(--c-border-strong);
  border-radius: var(--r-ctl);
  color: var(--c-gold);
  font: var(--t-label-l);
  cursor: pointer;
}
.ed-dobavitj:hover { border-color: var(--c-gold); }



/**
 * ДЕСКТОП: ТЕАТР В ТРИ КОЛОНКИ, как на бою.
 *
 * Там это `.theatre` с `grid-template-columns: 300px 1fr 300px`: игрок слева,
 * доска посередине, игрок справа. Каждый игрок это высокая панель, а не
 * приплюснутая строка, и на широком экране это единственная раскладка,
 * которая не выглядит телефоном посреди пустоты. Моя первая версия была
 * именно телефоном посреди пустоты.
 *
 * КАК СДЕЛАНО БЕЗ ВТОРОЙ РАЗМЕТКИ. Верхняя строка и полоса игроков на
 * десктопе становятся `display: contents`: их дети всплывают наверх и
 * попадают прямо в сетку экрана. Одна разметка, две раскладки, и ни одного
 * узла, существующего только ради одной из них.
 *
 * Слева начинаем там, где кончается колонка каркаса: иначе доска накрывает её
 * собой вместе с выходом и пометкой премиума.
 */
@media (min-width: 1024px) {
  .sx-play {
    left: var(--kolonka, 264px);
    display: grid;
    grid-template-columns: 260px minmax(0, 1fr) 260px;
    grid-template-rows: auto minmax(0, 1fr) auto;
    column-gap: var(--s-5);
    padding-inline: var(--s-5);
  }

  /* Дети всплывают в сетку экрана. */
  .sx-top,
  .sx-players { display: contents; }

  /* «vs» это телефонная связка между двумя карточками в одной строке. Между
     колонками связывать нечего. */
  .sx-vs { display: none; }

  .sx-back { grid-column: 1; grid-row: 1; margin: var(--s-4) 0 0; }
  .sx-pole { grid-column: 2; grid-row: 2; }
  .sx-niz  { grid-column: 2; grid-row: 3; }

  /**
   * Игрок панелью, а не строкой: лицо крупно, имя под ним, запас засечным
   * крупным числом. Числа с боя: портрет 64, запас 38.
   */
  .sx-p {
    flex-direction: column;
    align-self: center;
    gap: var(--s-3);
    padding: var(--s-5) var(--s-4);
    text-align: center;
  }
  .sx-p[data-storona="0"] { grid-column: 1; grid-row: 2; }
  .sx-p[data-storona="1"] { grid-column: 3; grid-row: 2; }

  .sx-p__litso { width: 64px; height: 64px; flex-basis: 64px; }
  .sx-p__kto { align-items: center; width: 100%; }
  .sx-p__imya { font: var(--t-headline-m); font-family: var(--f-serif); }
  .sx-p__zapas {
    font: var(--t-display-s);
    font-family: var(--f-serif);
    font-style: italic;
    margin-top: var(--s-1);
  }

  /* Полоса броска не во всю ширину центра: кнопка в тысячу пикселей это не
     кнопка, а линейка. */
  .sx-niz { max-width: 460px; margin-inline: auto; }
}

/* ---------- объёмное поле (games/sexopoly-3d.js) ----------
 *
 * Второй вид поля, на выбор в настройках (владелец 25.09.2026: «оставить оба
 * варианта и дать выбирать»). Холст ложится на то же поле поверх бархатного
 * фона: фон прозрачный, и доска стоит на нашей свече, а не на пустоте. Петля
 * при этом прячется целиком вместе с её фишками и кубиками; если три.js не
 * поднимется, класс снимается, и петля возвращается сама.
 */
.sx-play--3d .sx-petlya { display: none; }

.sx-3d {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  touch-action: none;
  cursor: grab;
}
.sx-3d:active { cursor: grabbing; }

/* Вся доска сверху или вслед за ходом. Круглая, как «назад»: это тоже жест над
   полем, а не над партией. */
.sx-vid {
  position: absolute;
  top: var(--s-2);
  right: var(--s-3);
  z-index: 2;
  width: var(--tap);
  height: var(--tap);
  border-radius: 50%;
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface-high);
  color: var(--c-text);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.sx-vid[aria-pressed="true"] {
  color: var(--c-gold);
  border-color: var(--c-gold);
}

/* Звук под обзором, той же формы. */
.sx-zvuk {
  position: absolute;
  top: calc(var(--s-2) + var(--tap) + var(--s-2));
  right: var(--s-3);
  z-index: 2;
  width: var(--tap);
  height: var(--tap);
  border-radius: 50%;
  border: 1px solid var(--c-border-strong);
  background: var(--c-surface-high);
  color: var(--c-text);
  display: grid;
  place-items: center;
  cursor: pointer;
}
.sx-zvuk[aria-pressed="true"] { color: var(--c-muted); }

/*
 * ОБЪЁМ НА ДЕСКТОПЕ. У петли три колонки: игроки по бокам, доска в середине.
 * Для объёма это душит сцену: владелец показал снимок, где доска зажата в
 * узкой полосе, а по бокам пустые панели. Здесь сцена занимает весь экран
 * справа от меню, игроки лежат компактными карточками в верхних углах поверх
 * неё, кнопка броска внизу по центру, а обзор и звук в правом нижнем углу.
 */
@media (min-width: 1024px) {
  .sx-play--3d {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    column-gap: 0;
    padding-inline: 0;
  }
  .sx-play--3d .sx-pole { grid-column: 1; grid-row: 1; }
  /* Привязку к ячейкам петли снимаем: у абсолютного ребёнка сетки с grid-row или
     grid-column отсчёт идёт от ЭТОЙ ячейки, а в объёме ячейка одна, и браузер
     достраивал невидимый ряд за краем экрана. Карточки уезжали туда. */
  .sx-play--3d .sx-p,
  .sx-play--3d .sx-niz,
  .sx-play--3d .sx-back { grid-column: auto; grid-row: auto; }
  .sx-play--3d .sx-back {
    position: absolute;
    top: var(--s-4);
    left: var(--s-4);
    z-index: 3;
    margin: 0;
  }
  .sx-play--3d .sx-p {
    position: absolute;
    top: var(--s-4);
    z-index: 3;
    flex-direction: row;
    align-self: auto;
    gap: var(--s-3);
    padding: var(--s-2) var(--s-4) var(--s-2) var(--s-2);
    text-align: left;
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
  }
  .sx-play--3d .sx-p[data-storona="0"] { left: calc(var(--s-4) + var(--tap) + var(--s-3)); }
  .sx-play--3d .sx-p[data-storona="1"] { right: var(--s-4); }
  .sx-play--3d .sx-p__litso { width: 44px; height: 44px; flex-basis: 44px; }
  .sx-play--3d .sx-p__kto { align-items: flex-start; width: auto; }
  .sx-play--3d .sx-p__imya { font: var(--t-title-s); font-family: var(--f-sans); }
  .sx-play--3d .sx-p__zapas { font: var(--t-title-m); font-family: var(--f-serif); font-style: italic; margin-top: 0; }
  .sx-play--3d .sx-niz {
    position: absolute;
    left: 50%;
    bottom: var(--s-5);
    transform: translateX(-50%);
    width: min(460px, calc(100% - 2 * var(--s-5)));
    max-width: none;
    margin: 0;
    z-index: 3;
  }
  .sx-play--3d .sx-vid { top: auto; bottom: var(--s-5); right: var(--s-5); }
  .sx-play--3d .sx-zvuk { top: auto; bottom: calc(var(--s-5) + var(--tap) + var(--s-2)); right: var(--s-5); }
}
