/* ==========================================================================
   WebPhysics — интерфейс интерактивных симуляций
   --------------------------------------------------------------------------
   Общая оболочка для всех 20 опытов: холст + панель управления + показания
   приборов. Единый стиль делает переход между симуляциями предсказуемым.
   ========================================================================== */

.sim-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 18px;
  align-items: start;
}
/*
 * Порог намеренно высокий. При ширине окна около 1024 px сайдбар уже
 * занимает своё место, и на две колонки холсту оставалось меньше 400 px —
 * панель параметров налезала на сцену. Ниже 1240 px раскладываем в стопку.
 */
@media (max-width: 1240px) {
  .sim-shell { grid-template-columns: 1fr; }
  .sim-panel {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 14px 20px;
    align-items: start;
  }
  .sim-panel > .sp-title,
  .sim-panel > .sim-actions,
  .sim-panel > .sim-legend { grid-column: 1 / -1; }
}

/* --------------------------------------------------------------------------
   Компактный режим — симуляция, встроенная в параграф.
   Ширина ограничена колонкой текста, поэтому холст занимает её целиком,
   а управление располагается под ним в несколько колонок.
   -------------------------------------------------------------------------- */
.sim-shell.is-stacked { grid-template-columns: 1fr; gap: 0; }

.sim-shell.is-stacked .sim-stage {
  border-radius: 0;
  border: none;
  border-bottom: 1px solid var(--separator);
  aspect-ratio: 16 / 9;
  min-height: 320px;
}

.sim-shell.is-stacked .sim-panel {
  border-radius: 0;
  border: none;
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 14px 20px;
  align-items: start;
  padding: 18px 20px;
}
/* Заголовок «Параметры» и кнопки занимают всю ширину сетки */
.sim-shell.is-stacked .sim-panel > .sp-title,
.sim-shell.is-stacked .sim-panel > .sim-actions,
.sim-shell.is-stacked .sim-panel > .sim-legend { grid-column: 1 / -1; }

@media (max-width: 560px) {
  .sim-shell.is-stacked .sim-stage { aspect-ratio: 4 / 3; min-height: 280px; }
  .sim-shell.is-stacked .sim-panel { grid-template-columns: 1fr; }
}

/* --------------------------------------------------------------- холст */
.sim-stage {
  position: relative;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--bg-elevated);
  border: 1px solid var(--separator);
  box-shadow: var(--shadow-sm);
  /* Холст всегда занимает доступную ширину, высота задаётся аспектом */
  aspect-ratio: 16 / 10;
  min-height: 300px;
  /*
   * pan-y, а не none: со сплошной блокировкой мимо большой симуляции
   * невозможно было пролистнуть страницу пальцем. Вертикальный свайп
   * теперь прокручивает страницу, а перетаскивание объекта и щипок
   * удерживают её сами — через preventDefault в sims/engine.js.
   */
  touch-action: pan-y;
}
/*
 * Тот же touch-action дублируется на самом холсте. Событие приходит именно
 * на него, и в некоторых мобильных браузерах значение родителя применялось
 * не всегда — вертикальный свайп по большому опыту переставал прокручивать
 * страницу. Дубль обходится бесплатно и снимает вопрос.
 */
.sim-stage canvas { display: block; width: 100%; height: 100%; touch-action: pan-y; }
/* В полноэкранном режиме прокручивать нечего — жест целиком за опытом */
.sim-stage.is-fullscreen,
.sim-stage.is-fullscreen canvas { touch-action: none; }
@media (max-width: 560px) { .sim-stage { aspect-ratio: 4 / 3; min-height: 260px; } }

/*
 * Опыты, объявившие spec.tall: схемам с приборами нужен более высокий кадр.
 * На узком экране пропорция ещё выше — там сцена и так уменьшена, а высота
 * ничего не стоит: холст просто немного длиннее по вертикали.
 */
.sim-stage.is-tall,
.sim-shell.is-stacked .sim-stage.is-tall { aspect-ratio: 4 / 3; min-height: 340px; }
@media (max-width: 560px) {
  .sim-stage.is-tall,
  .sim-shell.is-stacked .sim-stage.is-tall { aspect-ratio: 1 / 1; min-height: 300px; }
}

/* Полупрозрачная плашка с показаниями поверх холста */
.sim-readout {
  position: absolute;
  top: 12px; left: 12px;
  display: flex; flex-direction: column; gap: 3px;
  padding: 10px 14px;
  border-radius: var(--r-sm);
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: blur(18px) saturate(var(--glass-saturate));
  backdrop-filter: blur(18px) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  font-size: 12.4px;
  font-variant-numeric: tabular-nums;
  pointer-events: none;
  max-width: calc(100% - 24px);
}
/*
 * Межстрочный интервал задан явно: наследуемый от body (1.55) раздувал
 * плашку почти в полтора раза, а она лежит поверх сцены — каждая лишняя
 * строка отжимает опыт вниз.
 */
.sim-readout .ro-line { display: flex; justify-content: space-between; gap: 14px; line-height: 1.28; }
.sim-readout .ro-label { color: var(--text-4); }
.sim-readout .ro-value { font-weight: 660; color: var(--text); white-space: nowrap; }

/* Показания можно свернуть — иногда они закрывают саму сцену */
.sim-readout.is-hidden {
  opacity: 0;
  visibility: hidden;
  transform: translateX(-8px);
  transition: opacity var(--dur) ease, transform var(--dur) var(--ease-out), visibility var(--dur);
}

/* --------------------------------------------------------------------------
   Приборная панель под холстом — режим узкого экрана.
   Блок физически переносится из .sim-stage в .sim-shell (см. sims/engine.js),
   потому что поверх маленького холста он закрывал половину сцены.
   -------------------------------------------------------------------------- */
.sim-readout.is-below {
  position: static;
  /* В двухколоночной раскладке блок обязан занимать всю ширину, иначе он
     встаёт в колонку панели параметров и выталкивает её вниз. */
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 2px 16px;
  margin: 12px 0 0;
  padding: 12px 16px;
  max-width: none;
  border-radius: var(--r-md);
  background: var(--fill-2);
  border: 1px solid var(--separator);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  font-size: 12.6px;
}
.sim-readout.is-below .ro-line { align-items: baseline; gap: 10px; }
.sim-readout.is-below .ro-label { min-width: 0; }
.sim-readout.is-below.is-hidden { display: none; }

/* Совсем узкие экраны — по одному показанию в строке, без переносов подписи */
@media (max-width: 420px) {
  .sim-readout.is-below { grid-template-columns: 1fr; font-size: 12.2px; }
}
.sim-shell.is-stacked .sim-readout.is-below { margin: 0; border-radius: 0; border: none; border-bottom: 1px solid var(--separator); }

/*
 * Кнопки поверх холста (показания, пауза, сброс, полный экран).
 * Размер уменьшен: четыре кнопки по 38 px перекрывали плашку показаний
 * в узких сценах. Расстояние между ними оставлено прежним.
 */
.sim-overlay-actions {
  position: absolute;
  top: 12px; right: 12px;
  display: flex; gap: 7px;
  z-index: 3;
}
.sim-overlay-actions .icon-btn {
  width: 30px;
  height: 30px;
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: blur(18px) saturate(var(--glass-saturate));
  backdrop-filter: blur(18px) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
}
.sim-overlay-actions .icon-btn svg { width: 15px; height: 15px; }

/*
 * Подсказка внизу холста.
 * Появляется, когда опыт доскроллен до экрана, и через 10 секунд исчезает,
 * чтобы не закрывать сцену (класс .is-gone ставится из sims/engine.js).
 */
.sim-hint {
  position: absolute;
  left: 12px; bottom: 12px; right: 12px;
  padding: 8px 13px;
  border-radius: var(--r-sm);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(14px) saturate(var(--glass-saturate));
  backdrop-filter: blur(14px) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  font-size: 11.8px;
  color: var(--text-3);
  text-align: center;
  pointer-events: none;
  opacity: 1;
  transform: none;
  transition: opacity .45s ease, transform .45s var(--ease-out), visibility .45s;
}
.sim-hint.is-gone {
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
}

/* ------------------------------------------------------------- панель */
.sim-panel {
  padding: 18px;
  border-radius: var(--r-lg);
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  display: flex; flex-direction: column; gap: 15px;
}
.sim-panel .sp-title {
  font-size: 11.5px; text-transform: uppercase; letter-spacing: .07em;
  color: var(--text-4); font-weight: 700;
}

/*
 * Ключевая строка: у элементов grid и flex значение min-width по умолчанию
 * равно auto, поэтому блок с длинной нерастягиваемой подписью не сжимался,
 * а вылезал из своей ячейки и налезал на соседний параметр.
 */
.sim-panel > * { min-width: 0; }

.sim-control { display: flex; flex-direction: column; gap: 7px; }
.sim-control .sc-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
  /* Заголовок ужимается, значение — никогда */
  min-width: 0;
}
.sim-control .sc-name,
.sim-panel .sc-name {
  font-size: 13.4px;
  font-weight: 570;
  color: var(--text-2);
  min-width: 0;
  line-height: 1.3;
}

/*
 * Короткий вариант подписи параметра (см. controlName() в sims/engine.js).
 * На компьютере всегда полное название; на телефоне и портретном планшете
 * длинные подписи вроде «Электрическое поле E» переставали помещаться
 * в строку и наезжали на значение — там показываем сокращение.
 */
.sc-name .scn-short { display: none; }
@media (max-width: 1023px) {
  .sc-name .scn-full { display: none; }
  .sc-name .scn-short { display: inline; }
}
/*
 * Значение всегда в одну строку: «17.90 м/с²» переносилось на две
 * и плашка вырастала в высоту.
 */
.sim-control .sc-val {
  flex: none;
  white-space: nowrap;
  font-size: 12.6px;
  font-weight: 680;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  background: var(--accent-soft);
  padding: 2px 9px;
  border-radius: var(--r-full);
}

.sim-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.sim-actions .btn { flex: 1; min-width: 88px; }

/* Небольшая легенда цветов на панели */
.sim-legend { display: flex; flex-direction: column; gap: 6px; font-size: 12.2px; color: var(--text-3); }
.sim-legend .sl-item { display: flex; align-items: center; gap: 8px; }
.sim-legend .sl-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }

/* --------------------------------------------------------------------------
   Указатель текущего приближения сцены.
   Появляется только когда пользователь развёл пальцы (см. sims/engine.js).
   -------------------------------------------------------------------------- */
/*
 * Указатель масштаба сцены. Стоит справа сверху, сразу под рядом кнопок
 * управления, и виден всегда: по нему понятно, что сцену можно приближать,
 * и в каком она сейчас состоянии.
 */
.sim-zoom {
  position: absolute;
  right: 12px;
  top: 50px;
  display: flex;
  align-items: stretch;
  padding: 2px;
  border-radius: var(--r-full);
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: blur(18px) saturate(var(--glass-saturate));
  backdrop-filter: blur(18px) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  font-size: 11px;
  font-weight: 660;
  font-variant-numeric: tabular-nums;
  color: var(--text-3);
  z-index: 3;
  transition: color var(--dur) ease;
}
/*
 * Кнопки «−» и «+» рядом с числом: на компьютере жестов нет, а отдалить
 * сцену нужно уметь и там. Клик по самому числу возвращает 100 %.
 */
.sim-zoom .sz-btn,
.sim-zoom .sz-value {
  display: grid;
  place-items: center;
  border-radius: var(--r-full);
  color: inherit;
  font: inherit;
  transition: background var(--dur-fast) ease, color var(--dur-fast) ease;
}
.sim-zoom .sz-btn {
  width: 22px;
  height: 22px;
  font-size: 14px;
  line-height: 1;
  font-weight: 700;
}
.sim-zoom .sz-value { min-width: 44px; padding: 0 4px; }
.sim-zoom .sz-btn:hover,
.sim-zoom .sz-value:hover { background: var(--hover-tint); color: var(--text); }
.sim-zoom .sz-btn:active,
.sim-zoom .sz-value:active { transform: scale(.92); }
/* Масштаб отличается от исходного — подсвечиваем акцентом */
.sim-zoom.is-changed { color: var(--accent); }

/* Курсор подсказывает, что сцену можно двигать мышью */
.sim-stage.is-panning canvas { cursor: grabbing; }

/* В полноэкранном режиме кнопки уходят под «чёлку» — плашка следом за ними */
.sim-stage.is-fullscreen .sim-zoom { top: calc(52px + var(--safe-top)); }

/* Мини-график (энергия, зависимость величин) */
.sim-chart {
  height: 92px;
  border-radius: var(--r-sm);
  background: var(--fill-2);
  border: 1px solid var(--separator);
  overflow: hidden;
}
.sim-chart canvas { width: 100%; height: 100%; display: block; }

/* Теоретическая справка под симуляцией */
.sim-theory {
  margin-top: 18px;
  padding: 20px 24px;
  border-radius: var(--r-lg);
  background: var(--bg-elevated);
  border: 1px solid var(--separator);
}
.sim-theory h3 { font-size: 16px; margin-bottom: 10px; letter-spacing: -.02em; }
.sim-theory p { font-size: 14.2px; color: var(--text-2); line-height: 1.65; }
.sim-theory .formula-block { margin-top: 14px; }

/* --------------------------------------------------------------------------
   Полноэкранный режим симуляции.
   Элемент на время переносится в <body> (см. sims/engine.js), поэтому здесь
   достаточно растянуть его на весь экран и снять ограничения по пропорциям.
   -------------------------------------------------------------------------- */
.sim-stage.is-fullscreen {
  position: fixed;
  /*
   * Именно top/left + 100vw, а не inset: 0 — иначе справа оставалась бы
   * полоска зарезервированного места под скроллбар (scrollbar-gutter).
   */
  top: 0;
  left: 0;
  right: auto;
  bottom: auto;
  z-index: 400;
  width: 100vw;
  height: 100dvh;
  max-width: none;
  max-height: none;
  min-height: 0;
  aspect-ratio: auto;
  border: none;
  border-radius: 0;
  background: var(--bg-elevated);
  /*
   * fill-mode намеренно не `both`: если кадры не выдаются (вкладка в фоне),
   * элемент навсегда застыл бы в начальном состоянии анимации. Поэтому
   * стартовая прозрачность не трогается — анимируется только масштаб.
   */
  animation: sim-fs-in .26s var(--ease-out);
}
@keyframes sim-fs-in {
  from { transform: scale(.985); }
  to { transform: none; }
}
/*
 * В развёрнутом виде показания не должны налезать на «чёлку».
 * Держим их на одной линии с кнопками управления: слева вверху,
 * напротив ряда из четырёх кнопок справа.
 */
.sim-stage.is-fullscreen .sim-readout,
.sim-stage.is-fullscreen .sim-overlay-actions { top: calc(14px + var(--safe-top)); }
.sim-stage.is-fullscreen .sim-readout { left: calc(14px + env(safe-area-inset-left, 0px)); }

/* --------------------------------------------------------------------------
   Управление в полноэкранном режиме — узкая лента поверх нижней части холста.
   Панель физически переносится внутрь .sim-stage (см. sims/engine.js),
   здесь она перестраивается из колонки в горизонтальный ряд.
   -------------------------------------------------------------------------- */
.sim-panel.is-bar {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: calc(12px + var(--safe-bottom));
  z-index: 2;
  flex-direction: row;
  align-items: center;
  flex-wrap: nowrap;
  gap: 20px;
  padding: 12px 18px;
  border-radius: var(--r-lg);
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: blur(34px) saturate(var(--glass-saturate));
  backdrop-filter: blur(34px) saturate(var(--glass-saturate));
  border: 1px solid var(--glass-border);
  box-shadow: var(--shadow-lg);
  /* Много параметров — лента прокручивается по горизонтали */
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.sim-panel.is-bar::-webkit-scrollbar { display: none; }

/* Заголовок «Параметры» и легенда в ленте лишние */
.sim-panel.is-bar > .sp-title,
.sim-panel.is-bar > .sim-legend { display: none; }

.sim-panel.is-bar .sim-control {
  flex: none;
  width: 176px;
  min-width: 0;
  gap: 4px;
}
/* Переключателю вариантов нужна колонка пошире, иначе подписи обрезаются */
.sim-panel.is-bar .sim-control:has(.sim-segment) { width: 232px; }
/* Подписи в ленте компактнее — она не должна съедать высоту сцены */
.sim-panel.is-bar .sc-name { font-size: 12.2px; }
.sim-panel.is-bar .sc-val { font-size: 11.8px; padding: 1px 8px; }
.sim-panel.is-bar .slider { height: 5px; }
.sim-panel.is-bar .slider::-webkit-slider-thumb { width: 20px; height: 20px; }
.sim-panel.is-bar .sim-segment { min-width: 0; flex-wrap: nowrap; }
.sim-panel.is-bar .sim-actions { flex: none; flex-wrap: nowrap; }
.sim-panel.is-bar .sim-actions .btn { min-width: 0; white-space: nowrap; }
.sim-panel.is-bar .row { flex: none; white-space: nowrap; }

/*
 * Кнопка-действие опыта («Нагреть середину», «Оборвать связь»).
 * В колонке она объявлена как .btn-block — на всю ширину панели. В ленте
 * width: 100 % от нулевой базы flex превращал её в узкий обрубок высотой
 * в две строки: текст переносился по буквам. В ряду ширину задаёт
 * содержимое, а сжиматься кнопке нельзя.
 */
.sim-panel.is-bar > .btn,
.sim-panel.is-bar > .btn-block {
  width: auto;
  flex: none;
  white-space: nowrap;
  align-self: center;
}

@media (max-width: 700px) {
  .sim-panel.is-bar { gap: 14px; padding: 10px 14px; }
  .sim-panel.is-bar .sim-control { width: 150px; }
}

/*
 * Переключатель вариантов внутри симуляции (например, тип соединения).
 * Длинные русские подписи не помещаются в узкую панель. Перенос на вторую
 * строку выглядел как всплывающее меню, поэтому вместо него — горизонтальная
 * прокрутка: элемент остаётся одной строкой и читается как переключатель.
 */
.sim-segment {
  display: flex;
  gap: 3px;
  padding: 3px;
  background: var(--fill-2);
  border-radius: var(--r-full);
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
}
.sim-segment::-webkit-scrollbar { display: none; }
/*
 * flex-shrink обязателен (1, а не 0): с запретом сжатия ряд длинных
 * названий вроде «Собирающая / Рассеивающая» выдавливался за пределы
 * панели и налезал на соседний параметр. Не поместившееся обрезаем
 * многоточием — это лучше, чем перекрытие соседей.
 */
.sim-segment button {
  flex: 1 1 auto;
  min-width: 0;
  padding: 7px 12px;
  border-radius: var(--r-full);
  font-size: 12.4px; font-weight: 620;
  color: var(--text-3);
  transition: color var(--dur-fast) ease, background var(--dur-fast) ease;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sim-segment button.is-active { background: var(--bg-elevated); color: var(--text); box-shadow: var(--shadow-sm); }
