Files
Learn_System/frontend/lab.html
T
Maxim Dolgolyov 8f30a8cef6 feat(labs): wave 2 — depth features across 6 sims
Электрические цепи (circuit):
- Индуктивность L как новый компонент (1–1000 мГн, шорт в DC, jωL в AC)
- RLC preset для демонстрации резонанса
- Осциллограф: U(t)/I(t) для выбранного компонента, 100 sample, dual-axis
- Heatmap мощности: радиальный градиент halo от blue→red пропорционально P=UI

Стереометрия 3D (stereo):
- Сечение через 3 произвольные точки: pick на гранях/рёбрах/вершинах
- Плоскость + полигон пересечения с авто-определением типа (3–6-угольник) и площадью
- Step-by-step режим: визуализация P1→линия→P2→линия→P3→плоскость→сечение
- Поддержка всех solids (включая cylinder/cone через sampling fallback)

Планиметрия (geometry):
- Задачник framework: CHALLENGES[] с setup/check функциями
- 5 стартовых задач: серединный перпендикуляр, биссектриса, описанная окружность, ГМТ, касательная
- Авто-checker: толерантности ±0.5° для углов, ±1–5% для расстояний
- UI: collapsible панель с статус-иконками, конфетти + «Молодец!» на success

Электромагнитные поля (emfield):
- Preset «Тороид»: 16+16 проводов в концентрических кольцах
- Поверхность Гаусса: draggable круг, считает Φ = q_enc/ε₀, подсвечивает охваченные заряды
- Motional EMF: draggable rod, arrow-keys управление, считает ε = ∫(v×B)·dl

Химическая песочница (chemsandbox):
- Live-overlay с уравнением реакции: молекулярное / полное ионное / сокращённое ионное
- Coverage: 49/49 молекулярных, 34/49 ионных, 36/49 сокращённых
- Auto-hide через 5 сек, fade-in animation, цветовая кодировка типов

Волны и звук (waves):
- Doppler: source+observer drag, expanding wavefronts, f_obs формула, Mach cone при v>c
- Beats: f1+f2, sum waveform с envelope, индикация f_beat=|f1-f2|
- Spectrum (DFT): N=256 samples pure JS, bar-chart с пиками и labels, «Добавить гармонику»

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 12:48:14 +03:00

3723 lines
294 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Лаборатория — LearnSpace</title>
<link rel="icon" href="/favicon.svg" type="image/svg+xml" />
<link href="https://fonts.googleapis.com/css2?family=Unbounded:wght@400;700;800&family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="/css/ls.css" />
<link rel="stylesheet" href="/css/lab.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
<script src="https://cdn.jsdelivr.net/npm/lucide@0.469.0/dist/umd/lucide.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
</head>
<body>
<div class="app-layout">
<aside class="sidebar" id="app-sidebar"></aside>
<div class="notif-drop" id="notif-drop"></div>
<div class="sb-content">
<!-- ══════════ HOME VIEW ══════════ -->
<div id="lab-home">
<div class="lab-hero">
<div class="lab-hero-icon">
<i data-lucide="atom" style="width:30px;height:30px;stroke:var(--violet);stroke-width:1.5"></i>
</div>
<div>
<div class="lab-hero-title">Лаборатория</div>
<div class="lab-hero-sub">Интерактивные симуляции по математике и физике</div>
</div>
</div>
<div class="lab-filters">
<button class="lab-filter active" onclick="filterSims('all',this)">Все</button>
<button class="lab-filter" onclick="filterSims('math',this)">
<i data-lucide="sigma" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Математика
</button>
<button class="lab-filter" onclick="filterSims('phys',this)">
<i data-lucide="zap" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Физика
</button>
<button class="lab-filter" onclick="filterSims('chem',this)">
<i data-lucide="flask-conical" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Химия
</button>
<button class="lab-filter" onclick="filterSims('bio',this)">
<i data-lucide="dna" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Биология
</button>
<button class="lab-filter" onclick="filterSims('game',this)">
<i data-lucide="gamepad-2" style="width:12px;height:12px;vertical-align:-2px;margin-right:4px"></i>Игры
</button>
</div>
<div class="sim-grid" id="sim-grid"></div>
</div>
<!-- ══════════ SIM VIEW ══════════ -->
<div id="lab-sim">
<!-- top bar -->
<div class="sim-topbar">
<button class="sim-back" onclick="closeSim()">
<svg viewBox="0 0 24 24" fill="none"><polyline points="15 18 9 12 15 6"/></svg>
Назад
</button>
<div class="sim-topbar-title" id="sim-topbar-title"></div>
<!-- graph controls -->
<div id="ctrl-graph" class="sim-zoom-btns">
<button class="zoom-btn" onclick="gSim.zoomIn()" title="Приблизить">
<svg viewBox="0 0 24 24" fill="none"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="11" y1="8" x2="11" y2="14"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
</button>
<button class="zoom-btn" onclick="gSim.zoomOut()" title="Отдалить">
<svg viewBox="0 0 24 24" fill="none"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/><line x1="8" y1="11" x2="14" y2="11"/></svg>
</button>
<button class="zoom-btn" onclick="gSim.resetView()" title="Сброс вида">
<svg viewBox="0 0 24 24" fill="none"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- projectile controls -->
<div id="ctrl-proj" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" id="proj-play-btn" onclick="projPlayPause()" title="Запустить">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
</button>
<button class="zoom-btn" onclick="pSim && pSim.reset(); _projSyncPlayBtn()" title="Сброс">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 2px"></div>
<button class="zoom-btn" onclick="projSaveGhost()" title="Зафиксировать траекторию" style="font-size:.65rem;font-weight:800"><svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M12 2a7 7 0 00-7 7c0 5.25 7 13 7 13s7-7.75 7-13a7 7 0 00-7-7z"/><circle cx="12" cy="9" r="2.5"/></svg></button>
<button class="zoom-btn" onclick="projClearGhosts()" title="Очистить следы" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
</div>
<!-- emfield controls -->
<div id="ctrl-emfield" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" id="em-sign-pos" onclick="emSign(1)" title="Добавлять + заряды" style="font-size:1.1rem;font-weight:900;color:#EF476F">+</button>
<button class="zoom-btn" id="em-sign-neg" onclick="emSign(-1)" title="Добавлять − заряды" style="font-size:1.1rem;font-weight:900;color:#4CC9F0"></button>
<button class="zoom-btn" id="em-dir-out" onclick="emWireDir('out')" title="Провод • (ток на нас)" style="font-size:1rem"></button>
<button class="zoom-btn" id="em-dir-in" onclick="emWireDir('in')" title="Провод × (ток от нас)" style="font-size:1rem">×</button>
<button class="zoom-btn" onclick="emSim && emSim.clearAll()" title="Очистить">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
</button>
</div>
<!-- triangle controls -->
<div id="ctrl-tri" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="tSim && tSim.reset()" title="Сбросить треугольник">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- geometry controls -->
<div id="ctrl-geometry" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="geomSim&&geomSim.undo()" title="Отменить (Ctrl+Z)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 7v6h6"/><path d="M3 13A9 9 0 1 0 6 6.3L3 7"/></svg>
</button>
<button class="zoom-btn" onclick="geomSim&&geomSim.redo()" title="Повторить (Ctrl+Y)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M21 7v6h-6"/><path d="M21 13A9 9 0 1 1 18 6.3L21 7"/></svg>
</button>
<button class="zoom-btn" onclick="geomSim&&geomSim.deleteSelected()" title="Удалить выбранное">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4h6v2"/></svg>
</button>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.1);margin:0 2px"></div>
<button class="zoom-btn" onclick="geomSim&&geomSim.resetView()" title="Сброс вида">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
<button class="zoom-btn" onclick="geomSim&&geomSim.exportPNG()" title="Экспорт PNG">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
</button>
</div>
<!-- trig circle controls -->
<div id="ctrl-trigcircle" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="trigReset()" title="Сбросить на 45°">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- collision controls -->
<div id="ctrl-coll" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" id="coll-play-btn" onclick="collPlayPause()" title="Запустить">
<svg viewBox="0 0 24 24" fill="currentColor"><polygon points="5 3 19 12 5 21 5 3"/></svg>
</button>
<button class="zoom-btn" onclick="cSim && cSim.reset()" title="Сброс">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- molphys controls (unified: gas + brownian + states + diffusion) -->
<div id="ctrl-molphys" class="sim-zoom-btns" style="display:none">
<!-- diffusion-only: partition button -->
<span id="ctrl-mol-diff" style="display:none">
<button class="zoom-btn" onclick="diffSim && diffSim.togglePartition(); diffPartitionBtn()" title="Снять/поставить раздел" style="font-size:0.72rem;font-weight:800;font-family:Manrope,sans-serif" id="diffusion-part-btn">
‖ Раздел
</button>
</span>
<button class="zoom-btn" onclick="molReset()" title="Сброс">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- (coulomb merged into ctrl-emfield) -->
<!-- circuit controls -->
<div id="ctrl-circuit" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn circ-top-btn active" id="ctool-wire" onclick="circTool('wire',this)" title="Провод (W)" style="font-size:.7rem;font-weight:800">~</button>
<button class="zoom-btn circ-top-btn" id="ctool-resistor" onclick="circTool('resistor',this)" title="Резистор (R)" style="font-size:.6rem;font-weight:800">R</button>
<button class="zoom-btn circ-top-btn" id="ctool-battery" onclick="circTool('battery',this)" title="Батарея (B)" style="font-size:.6rem;font-weight:800">U</button>
<button class="zoom-btn circ-top-btn" id="ctool-capacitor" onclick="circTool('capacitor',this)" title="Конденсатор (C)" style="font-size:.6rem;font-weight:800">C</button>
<button class="zoom-btn circ-top-btn" id="ctool-inductor" onclick="circTool('inductor',this)" title="Катушка индуктивности (I)" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M2 12 Q4 8 6 12 Q8 8 10 12 Q12 8 14 12"/><line x1="14" y1="12" x2="22" y2="12"/><line x1="2" y1="12" x2="2" y2="12"/></svg></button>
<button class="zoom-btn circ-top-btn" id="ctool-diode" onclick="circTool('diode',this)" title="Диод (D)" style="font-size:.75rem"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg>|</button>
<button class="zoom-btn circ-top-btn" id="ctool-led" onclick="circTool('led',this)" title="LED" style="font-size:.6rem;font-weight:800">LED</button>
<button class="zoom-btn circ-top-btn" id="ctool-ac" onclick="circTool('ac',this)" title="AC источник" style="font-size:.65rem;font-weight:800">AC</button>
<button class="zoom-btn circ-top-btn" id="ctool-switch" onclick="circTool('switch',this)" title="Выключатель (S)" style="font-size:.7rem"><svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="9" y2="12"/><line x1="15" y1="12" x2="21" y2="12"/><line x1="9" y1="12" x2="17" y2="6"/></svg></button>
<button class="zoom-btn circ-top-btn" id="ctool-lamp" onclick="circTool('lamp',this)" title="Лампа (L)" style="font-size:.75rem"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8"/><circle cx="12" cy="12" r="3"/></svg></button>
<button class="zoom-btn circ-top-btn" id="ctool-ammeter" onclick="circTool('ammeter',this)" title="Амперметр (A)" style="font-size:.6rem;font-weight:800">А</button>
<button class="zoom-btn circ-top-btn" id="ctool-voltmeter" onclick="circTool('voltmeter',this)" title="Вольтметр (V)" style="font-size:.6rem;font-weight:800">V</button>
<button class="zoom-btn circ-top-btn" id="ctool-erase" onclick="circTool('erase',this)" title="Ластик (E)">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M20 20H7L3 16l11.5-11.5a2 2 0 0 1 2.83 0l3.17 3.17a2 2 0 0 1 0 2.83L13 18"/><line x1="6" y1="14" x2="18" y2="2"/></svg>
</button>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 2px"></div>
<button class="zoom-btn" onclick="cirSim&&cirSim.undo()" title="Отменить (Ctrl+Z)" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24"><polyline points="9 14 4 9 9 4"/><path d="M20 20v-7a4 4 0 0 0-4-4H4"/></svg></button>
<button class="zoom-btn" onclick="cirSim&&cirSim.redo()" title="Повторить (Ctrl+Y)" style="font-size:.65rem"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 14 20 9 15 4"/><path d="M4 20v-7a4 4 0 0 1 4-4h12"/></svg></button>
<button class="zoom-btn" onclick="cirSim&&cirSim.preset('clear')" title="Очистить">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
</button>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 2px"></div>
<button class="zoom-btn" id="ctool-heat" onclick="circToggleHeat()" title="Тепловая карта мощности" style="font-size:.6rem;font-weight:700">
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M12 2C8 6 6 10 8 14c1 2 3 4 4 6"/><path d="M16 6c-2 3-3 6-1 9 1 1.5 1 3 0 4"/><path d="M8 6C6 9 5 12 7 15"/></svg>
</button>
<button class="zoom-btn" id="btn-osc-toggle" onclick="circToggleOsc()" title="Осциллограф U(t) / I(t)" style="font-size:.6rem;font-weight:700">
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><rect x="2" y="4" width="20" height="16" rx="2"/><polyline points="6 16 8 10 11 14 13 8 16 16"/></svg>
</button>
</div>
<!-- reactions controls -->
<!-- chemistry controls (unified) -->
<div id="ctrl-chemistry" class="sim-zoom-btns" style="display:none">
<!-- kinetics tools -->
<span id="ctrl-chem-kin" style="display:contents">
<button class="zoom-btn" id="reac-pause-btn" onclick="reacTogglePause()" title="Пауза реакций" style="font-size:.68rem;font-weight:800;font-family:Manrope,sans-serif"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg> Пауза</button>
</span>
<!-- flask tools -->
<span id="ctrl-chem-flask" style="display:none">
<button class="zoom-btn" onclick="flaskSim && flaskSim.dropMetal()" title="Бросить металл" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> Металл</button>
<button class="zoom-btn" id="flask-flame-btn" onclick="flaskToggleFlame()" title="Поджечь H₂" style="font-size:.75rem"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M12 2c.5 3.5-1.5 6-1.5 6 1 1.5 3 2 3 5a4 4 0 01-8 0c0-2 .5-3 1.5-4.5C8.5 6.5 7 4.5 7 4.5S9.5 2 12 2z"/></svg></button>
<button class="zoom-btn" id="flask-pause-btn" onclick="flaskTogglePause()" title="Пауза" style="font-size:.68rem;font-weight:800;font-family:Manrope,sans-serif"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg></button>
</span>
<!-- redox tools -->
<span id="ctrl-chem-redox" style="display:none">
<button class="zoom-btn" onclick="redoxStart()" title="Начать" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Старт</button>
</span>
<!-- ionex tools -->
<span id="ctrl-chem-ionex" style="display:none">
<button class="zoom-btn" onclick="ionexStart()" title="Смешать" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><path d="M9 3h6m-4.5 0v5.5l-4 7.5a1 1 0 0 0 .9 1.5h8.2a1 1 0 0 0 .9-1.5l-4-7.5V3"/></svg> Смешать</button>
</span>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 3px"></div>
<button class="zoom-btn" onclick="chemReset()" title="Сброс">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- newton controls -->
<!-- dynamics controls (unified newton + sandbox) -->
<div id="ctrl-dynamics" class="sim-zoom-btns" style="display:none">
<!-- sandbox tools (shown in sandbox mode) -->
<span id="ctrl-dyn-sb" style="display:contents">
<button class="zoom-btn sb-tool-btn active" id="sbt-box" onclick="sbTool('box',this)" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/></svg> Блок</button>
<button class="zoom-btn sb-tool-btn" id="sbt-ball" onclick="sbTool('ball',this)" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" fill="currentColor" stroke="none"/></svg> Шар</button>
<button class="zoom-btn sb-tool-btn" id="sbt-spring" onclick="sbTool('spring',this)" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Пружина</button>
<button class="zoom-btn sb-tool-btn" id="sbt-rope" onclick="sbTool('rope',this)" style="font-size:.65rem;font-weight:800">— Нить</button>
<button class="zoom-btn sb-tool-btn" id="sbt-anchor" onclick="sbTool('anchor',this)" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><path d="M12 2 2 12 12 22 22 12Z"/></svg> Якорь</button>
<button class="zoom-btn sb-tool-btn" id="sbt-erase" onclick="sbTool('erase',this)" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Ластик</button>
</span>
<!-- newton tools (shown in law modes) -->
<span id="ctrl-dyn-nw" style="display:none">
<button class="zoom-btn nscene-btn active" id="nscn-A" onclick="newtonScene('A',this)" style="font-size:.65rem;font-weight:800">A</button>
<button class="zoom-btn nscene-btn" id="nscn-B" onclick="newtonScene('B',this)" style="font-size:.65rem;font-weight:800">B</button>
<button class="zoom-btn nscene-btn" id="nscn-C" onclick="newtonScene('C',this)" style="font-size:.65rem;font-weight:800">C</button>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 3px"></div>
<button class="zoom-btn" id="newton-action-top" onclick="newtonAction()" style="font-size:.65rem;font-weight:800;font-family:Manrope,sans-serif"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Действие</button>
</span>
<div style="width:1px;height:20px;background:rgba(255,255,255,0.15);margin:0 3px"></div>
<button class="zoom-btn" onclick="dynPause()" title="Пауза" style="font-size:.75rem"><svg class="ic" viewBox="0 0 24 24"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg></button>
<button class="zoom-btn" onclick="dynReset()" title="Сброс">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- chemsandbox controls -->
<div id="ctrl-chemsandbox" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="chemSandResetReaction()" title="Сбросить реакцию" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс реакции</button>
<button class="zoom-btn" onclick="chemSandReset()" title="Очистить всё" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Очистить</button>
</div>
<!-- celldivision controls -->
<div id="ctrl-celldivision" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="cdPrevPhase()" title="Предыдущая фаза" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polygon points="19 20 9 12 19 4 19 20"/></svg> Назад</button>
<button class="zoom-btn" onclick="cdNextPhase()" title="Следующая фаза" style="font-size:.65rem;font-weight:800">Далее <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg></button>
<button class="zoom-btn" id="ctrl-cd-auto" onclick="cdAutoPlay(document.getElementById('cd-auto-btn'))" title="Авто" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Авто</button>
</div>
<!-- photosynthesis controls -->
<div id="ctrl-photosynthesis" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="psReset()" title="Сброс" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
</div>
<div id="ctrl-angrybirds" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" onclick="angryBirdsRestart()" title="Начать уровень заново" style="font-size:.65rem;font-weight:800"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сначала</button>
</div>
<!-- waves controls -->
<div id="ctrl-waves" class="sim-zoom-btns" style="display:none">
<button class="zoom-btn" id="waves-play-btn" onclick="wavesPlayPause()" title="Пауза/Старт">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>
</button>
<button class="zoom-btn" onclick="wavesSim && wavesSim.reset()" title="Сброс">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
</button>
</div>
<!-- hydrostatics controls -->
<div id="ctrl-hydro" class="sim-zoom-btns" style="display:none">
<select id="hydro-mode-sel" onchange="hydroMode(this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 8px;font-size:.72rem;cursor:pointer">
<option value="pressure">Давление P=ρgh</option>
<option value="surface">Пов. натяжение</option>
<option value="communicating">Сообщ. сосуды</option>
<option value="archimedes">Архимед</option>
</select>
<select id="hydro-liq-sel" onchange="hydroSim&&hydroSim.setLiquid(this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 8px;font-size:.72rem;cursor:pointer">
<option value="water">Вода</option>
<option value="saltwater">Солёная вода</option>
<option value="oil">Масло</option>
<option value="alcohol">Спирт</option>
<option value="glycerin">Глицерин</option>
<option value="mercury">Ртуть</option>
</select>
<div id="hydro-arch-ctrl" style="display:none;gap:4px;align-items:center">
<select id="hydro-mat-sel" onchange="hydroSim&&hydroSim.setMaterial(this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 8px;font-size:.72rem;cursor:pointer">
<option value="styrofoam">Пенопласт</option>
<option value="cork">Пробка</option>
<option value="wood">Дерево</option>
<option value="ice">Лёд</option>
<option value="plastic">Пластик</option>
<option value="glass">Стекло</option>
<option value="aluminum">Алюминий</option>
<option value="iron">Железо</option>
<option value="gold">Золото</option>
</select>
<button class="zoom-btn" onclick="hydroSim&&hydroSim.addBody()" title="Добавить тело">+ Тело</button>
<button class="zoom-btn" onclick="hydroSim&&hydroSim.clearBodies()" title="Очистить">Очистить</button>
</div>
<div id="hydro-comm-ctrl" style="display:none;gap:4px;align-items:center">
<label style="font-size:.72rem;color:rgba(255,255,255,.5)">Сосудов:</label>
<select onchange="hydroSim&&hydroSim.setNumVessels(+this.value)" style="background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.15);border-radius:7px;padding:3px 6px;font-size:.72rem;cursor:pointer">
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
</select>
<button class="zoom-btn" id="hydro-valve-btn" onclick="hydroToggleValve()" title="Кран">Кран: откр.</button>
</div>
<div id="hydro-surf-ctrl" style="display:none;gap:4px;align-items:center">
<label style="font-size:.72rem;color:rgba(255,255,255,.5);white-space:nowrap">θ:</label>
<input type="range" min="0" max="160" value="20" step="5" style="width:72px;accent-color:var(--violet)" oninput="hydroSim&&hydroSim.setContactAngle(+this.value);document.getElementById('hydro-theta-val').textContent=this.value+'\u00B0';document.getElementById('hydro-theta-lbl').textContent=this.value+'\u00B0';document.querySelector('#hydro-panel-theta input[type=range]').value=this.value">
<span id="hydro-theta-val" style="font-size:.72rem;color:var(--violet);min-width:28px;white-space:nowrap">20°</span>
<button class="zoom-btn" id="hydro-surf-toggle" onclick="hydroToggleSurface()" title="Переключить: капилляры / капля" style="white-space:nowrap">Капилляры</button>
</div>
</div>
<!-- theory toggle (all sims) -->
<button class="zoom-btn" id="theory-toggle" onclick="toggleTheory()" title="Теория и формулы" style="margin-left:auto">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M2 3h6a4 4 0 014 4v14a3 3 0 00-3-3H2z"/><path d="M22 3h-6a4 4 0 00-4 4v14a3 3 0 013-3h7z"/></svg>
</button>
</div>
<!-- ── GRAPH sim body ── -->
<div id="sim-graph" class="sim-body-wrap">
<!-- left panel -->
<div class="graph-panel">
<div class="gp-section-title">Функции</div>
<!-- fn 1 -->
<div style="--fn-color:var(--violet)">
<div class="fn-row">
<div class="fn-dot"></div>
<span class="fn-label">y =</span>
<input class="fn-input" id="fn0" placeholder="sin(x)" autocomplete="off" spellcheck="false" oninput="updateFn(0)" />
</div>
<div class="fn-preview" id="fn0-prev"></div>
<div class="fn-err" id="fn0-err">Синтаксическая ошибка</div>
</div>
<!-- fn 2 -->
<div style="--fn-color:var(--cyan)">
<div class="fn-row">
<div class="fn-dot"></div>
<span class="fn-label">y =</span>
<input class="fn-input" id="fn1" placeholder="x^2 - 4" autocomplete="off" spellcheck="false" oninput="updateFn(1)" />
</div>
<div class="fn-preview" id="fn1-prev"></div>
<div class="fn-err" id="fn1-err">Синтаксическая ошибка</div>
</div>
<!-- fn 3 -->
<div style="--fn-color:var(--pink)">
<div class="fn-row">
<div class="fn-dot"></div>
<span class="fn-label">y =</span>
<input class="fn-input" id="fn2" placeholder="tg(x)" autocomplete="off" spellcheck="false" oninput="updateFn(2)" />
</div>
<div class="fn-preview" id="fn2-prev"></div>
<div class="fn-err" id="fn2-err">Синтаксическая ошибка</div>
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title">Примеры</div>
<div class="gp-preset-group">
<div class="gp-preset-label">Линейные / степенные</div>
<div class="presets-wrap">
<button class="preset-btn" onclick="applyPreset('2x-1')">2x1</button>
<button class="preset-btn" onclick="applyPreset('x^2')"></button>
<button class="preset-btn" onclick="applyPreset('x^2-4')">x²−4</button>
<button class="preset-btn" onclick="applyPreset('x^3-3x')">x³−3x</button>
<button class="preset-btn" onclick="applyPreset('x^4-4x^2+3')">x⁴−4x²+3</button>
</div>
</div>
<div class="gp-preset-group">
<div class="gp-preset-label">Тригонометрия</div>
<div class="presets-wrap">
<button class="preset-btn" onclick="applyPreset('sin(x)')">sin x</button>
<button class="preset-btn" onclick="applyPreset('cos(x)')">cos x</button>
<button class="preset-btn" onclick="applyPreset('tg(x)')">tg x</button>
<button class="preset-btn" onclick="applyPreset('sin(2x)')">sin 2x</button>
<button class="preset-btn" onclick="applyPreset('x*sin(x)')">x·sin x</button>
<button class="preset-btn" onclick="applyPreset('sin(x)/x')">sin(x)/x</button>
</div>
</div>
<div class="gp-preset-group">
<div class="gp-preset-label">Показательные / логарифмы</div>
<div class="presets-wrap">
<button class="preset-btn" onclick="applyPreset('exp(x)')"></button>
<button class="preset-btn" onclick="applyPreset('2^x')"></button>
<button class="preset-btn" onclick="applyPreset('ln(x)')">ln x</button>
<button class="preset-btn" onclick="applyPreset('log(x)')">log x</button>
</div>
</div>
<div class="gp-preset-group">
<div class="gp-preset-label">Прочие</div>
<div class="presets-wrap">
<button class="preset-btn" onclick="applyPreset('sqrt(x)')">√x</button>
<button class="preset-btn" onclick="applyPreset('1/x')">1/x</button>
<button class="preset-btn" onclick="applyPreset('abs(x)')">|x|</button>
<button class="preset-btn" onclick="applyPreset('floor(x)')">⌊x⌋</button>
<button class="preset-btn" onclick="applyPreset('1/(1+exp(-x))')">σ(x)</button>
</div>
</div>
<div style="margin-top:auto;padding-top:14px"></div>
<button class="gp-btn" onclick="clearAll()">
<svg viewBox="0 0 24 24" fill="none"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4h6v2"/></svg>
Очистить всё
</button>
</div>
<!-- canvas area -->
<div class="graph-canvas-outer">
<div class="graph-canvas-wrap">
<canvas id="graph-canvas"></canvas>
</div>
<div class="graph-info-bar" id="graph-info-bar">
<div class="info-coord">
<span class="ic-label">x =</span>
<span class="ic-val" id="info-x"></span>
</div>
<div class="info-fn-val">
<div class="info-fn-dot" style="background:var(--violet);box-shadow:0 0 5px var(--violet)"></div>
<span class="ic-label">y₁ =</span>
<span class="ic-val" id="info-y0"></span>
</div>
<div class="info-fn-val">
<div class="info-fn-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></div>
<span class="ic-label">y₂ =</span>
<span class="ic-val" id="info-y1"></span>
</div>
<div class="info-fn-val">
<div class="info-fn-dot" style="background:var(--pink);box-shadow:0 0 5px var(--pink)"></div>
<span class="ic-label">y₃ =</span>
<span class="ic-val" id="info-y2"></span>
</div>
<div class="info-hint">Скролл — зум · Перетащи — панорама</div>
</div>
</div>
</div><!-- /#sim-graph -->
<!-- ══ ЭЛЕКТРОМАГНИТНЫЕ ПОЛЯ (EMField) ══
replaces sim-mag + sim-coulomb -->
<div id="sim-emfield" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:258px;gap:0">
<!-- Mode tabs -->
<div style="display:flex;gap:4px;margin-bottom:12px">
<button id="em-tab-E" class="mag-mode-btn active" onclick="emSwitchMode('E')" style="flex:1;font-size:.72rem">Электрическое</button>
<button id="em-tab-B" class="mag-mode-btn" onclick="emSwitchMode('B')" style="flex:1;font-size:.72rem">Магнитное</button>
<button id="em-tab-combined" class="mag-mode-btn" onclick="emSwitchMode('combined')" style="flex:1;font-size:.72rem">Комбо</button>
</div>
<!-- E controls -->
<div id="em-ctrl-E">
<div class="gp-section-title" style="margin-bottom:6px">Заряд</div>
<div style="display:flex;gap:6px;margin-bottom:10px">
<button class="mag-mode-btn active" id="em-sign-pos" onclick="emSign(1)" style="flex:1">
<span style="font-size:1.2rem;font-weight:900;color:#EF476F">+</span> Полож.
</button>
<button class="mag-mode-btn" id="em-sign-neg" onclick="emSign(-1)" style="flex:1">
<span style="font-size:1.2rem;font-weight:900;color:#4CC9F0">&#8722;</span> Отриц.
</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Слои E</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
<label class="tri-layer-row active" onclick="emLayer('E','colormap',this)">
<span class="tri-dot" style="background:linear-gradient(90deg,#EF476F,#9B5DE5,#4CC9F0)"></span>
<span class="tri-layer-name">Карта потенциала</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">V</span>
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
</label>
<label class="tri-layer-row active" onclick="emLayer('E','fieldlines',this)">
<span class="tri-dot" style="background:rgba(255,255,255,0.8)"></span>
<span class="tri-layer-name">Линии поля E</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">E</span>
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
</label>
<label class="tri-layer-row" onclick="emLayer('E','vectors',this)">
<span class="tri-dot" style="background:rgba(255,255,255,0.4)"></span>
<span class="tri-layer-name">Векторы E</span>
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
<label class="tri-layer-row active" onclick="emLayer('E','equipotentials',this)">
<span class="tri-dot" style="background:rgba(255,255,255,0.5)"></span>
<span class="tri-layer-name">Эквипотенциали</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.3)">V=const</span>
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
</label>
<label class="tri-layer-row" onclick="emLayer('E','forces',this)">
<span class="tri-dot" style="background:#FFD166;box-shadow:0 0 5px #FFD166"></span>
<span class="tri-layer-name">Силы Кулона</span>
<span class="tri-layer-hint" style="color:#FFD166">F</span>
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Поверхность Гаусса</div>
<label class="tri-layer-row" id="em-gauss-row" onclick="emGaussToggle(this)" style="margin-bottom:6px">
<span class="tri-dot" style="background:#34d399;box-shadow:0 0 5px #34d399"></span>
<span class="tri-layer-name">Поток Гаусса &#934;&#8336;</span>
<span class="tri-layer-hint" style="color:#34d399">&#934;=q/&#949;&#8320;</span>
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
<div class="param-block" id="em-gauss-r-block" style="display:none;margin-bottom:10px">
<div class="param-header">
<span class="param-name">Радиус поверхности</span>
<span class="param-val" id="em-gaussR-val">70 пкс</span>
</div>
<input type="range" class="param-slider" id="sl-emGaussR" min="20" max="200" value="70" oninput="emGaussRChange()">
</div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты E</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip" onclick="emPresetE('dipole')">Диполь &#177;</button>
<button class="proj-preset-chip" onclick="emPresetE('equal')">Два + заряда</button>
<button class="proj-preset-chip" onclick="emPresetE('quadrupole')">Квадруполь</button>
<button class="proj-preset-chip" onclick="emPresetE('ring')">Кольцо</button>
</div>
</div><!-- /#em-ctrl-E -->
<!-- B controls -->
<div id="em-ctrl-B" style="display:none">
<div class="gp-section-title" style="margin-bottom:6px">Провод</div>
<div style="display:flex;gap:6px;margin-bottom:10px">
<button class="mag-mode-btn active" id="em-dir-out" onclick="emWireDir('out')" style="flex:1">
<span style="font-size:1.2rem;font-weight:900;color:#06D6E0">&#8226;</span> Ток на нас
</button>
<button class="mag-mode-btn" id="em-dir-in" onclick="emWireDir('in')" style="flex:1">
<span style="font-size:1.1rem;font-weight:900;color:#F15BB5">&#215;</span> Ток от нас
</button>
</div>
<div class="param-block" style="margin-bottom:10px">
<div class="param-header">
<span class="param-name">Сила тока I</span>
<span class="param-val" id="em-curI-val">6 А</span>
</div>
<input type="range" class="param-slider" id="sl-emI" min="1" max="20" value="6" oninput="emCurrentChange()">
</div>
<div class="gp-section-title" style="margin-bottom:6px">Слои B</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
<label class="tri-layer-row active" onclick="emLayer('B','colormap',this)">
<span class="tri-dot" style="background:linear-gradient(90deg,#9B5DE5,#06D6E0,#F15BB5)"></span>
<span class="tri-layer-name">Карта поля B</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">hue=угол</span>
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
</label>
<label class="tri-layer-row active" onclick="emLayer('B','fieldlines',this)">
<span class="tri-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></span>
<span class="tri-layer-name">Силовые линии B</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)">+ стрелки</span>
<span class="tri-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
</label>
<label class="tri-layer-row" onclick="emLayer('B','vectors',this)">
<span class="tri-dot" style="background:var(--violet);box-shadow:0 0 5px var(--violet)"></span>
<span class="tri-layer-name">Векторное поле B</span>
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Проводник в поле</div>
<label class="tri-layer-row" id="em-cond-row" onclick="emCondToggle(this)" style="margin-bottom:6px">
<span class="tri-dot" style="background:#fbbf24;box-shadow:0 0 5px #fbbf24"></span>
<span class="tri-layer-name">Проводник (Ампер)</span>
<span class="tri-layer-hint" style="color:#fbbf24">F=IL&#215;B</span>
<span class="tri-toggle"></span>
</label>
<div class="param-block" id="em-cond-I-block" style="display:none;margin-bottom:10px">
<div class="param-header">
<span class="param-name">Ток проводника I&#42;</span>
<span class="param-val" id="em-condI-val">8 А</span>
</div>
<input type="range" class="param-slider" id="sl-emCondI" min="1" max="20" value="8" oninput="emCondCurrentChange()">
</div>
<div class="gp-section-title" style="margin-bottom:6px">Магнитный поток</div>
<label class="tri-layer-row" id="em-flux-row" onclick="emFluxToggle(this)" style="margin-bottom:10px">
<span class="tri-dot" style="background:#34d399;box-shadow:0 0 5px #34d399"></span>
<span class="tri-layer-name">Индикатор потока</span>
<span class="tri-layer-hint" style="color:#34d399">&#934;=B&#183;S</span>
<span class="tri-toggle"></span>
</label>
<div class="gp-section-title" style="margin-bottom:6px">ЭДС индукции</div>
<label class="tri-layer-row" id="em-rod-row" onclick="emRodToggle(this)" style="margin-bottom:6px">
<span class="tri-dot" style="background:#f59e0b;box-shadow:0 0 5px #f59e0b"></span>
<span class="tri-layer-name">Движущийся проводник</span>
<span class="tri-layer-hint" style="color:#f59e0b">&#949;=&#8747;vBdl</span>
<span class="tri-toggle"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты B</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip" onclick="emPresetB('single')">Один провод</button>
<button class="proj-preset-chip" onclick="emPresetB('parallel')">Параллельные</button>
<button class="proj-preset-chip" onclick="emPresetB('anti')">Антипарал.</button>
<button class="proj-preset-chip" onclick="emPresetB('solenoid')">Соленоид</button>
<button class="proj-preset-chip" onclick="emPresetB('quadrupole')">Квадруполь</button>
<button class="proj-preset-chip" onclick="emPresetB('ring')">Кольцо</button>
<button class="proj-preset-chip" onclick="emPresetB('toroid')">Тороид</button>
</div>
</div><!-- /#em-ctrl-B -->
<!-- combined extra -->
<div id="em-ctrl-combined" style="display:none">
<div class="gp-section-title" style="margin-bottom:6px">Тип добавляемого</div>
<div style="display:flex;gap:6px;margin-bottom:10px">
<button class="mag-mode-btn active" id="em-add-charge" onclick="emAddTypeSwitch('charge')" style="flex:1;font-size:.72rem">Заряд</button>
<button class="mag-mode-btn" id="em-add-wire" onclick="emAddTypeSwitch('wire')" style="flex:1;font-size:.72rem">Провод</button>
</div>
</div>
<!-- Particle -->
<div class="gp-section-title" style="margin-bottom:6px">Частица</div>
<label class="tri-layer-row" id="em-particle-row" onclick="emParticle(this)" style="margin-bottom:10px">
<span class="tri-dot" style="background:#ffff50;box-shadow:0 0 5px #ffff50"></span>
<span class="tri-layer-name">Заряженная частица</span>
<span class="tri-layer-hint" style="color:#ffff50">Лоренц</span>
<span class="tri-toggle"></span>
</label>
<div style="margin-top:auto;padding-top:6px;display:flex;flex-direction:column;gap:5px">
<div class="tri-stats-grid" style="grid-template-columns:auto 1fr">
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Зарядов</div>
<div class="tri-stat-v" id="embar-charges" style="color:#EF476F">0</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Проводов</div>
<div class="tri-stat-v" id="embar-wires" style="color:var(--cyan)">0</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Курсор |E|</div>
<div class="tri-stat-v" id="embar-curE" style="color:rgba(255,255,255,0.6)">&#8212;</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Курсор V</div>
<div class="tri-stat-v" id="embar-curV" style="color:rgba(255,255,255,0.5)">&#8212;</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Курсор |B|</div>
<div class="tri-stat-v" id="embar-curB" style="color:var(--cyan)">&#8212;</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">&#934;&#8336; Гаусса</div>
<div class="tri-stat-v" id="embar-gauss" style="color:#34d399">&#8212;</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">ЭДС &#949;</div>
<div class="tri-stat-v" id="embar-rod" style="color:#f59e0b">&#8212;</div>
</div>
<div style="font-size:0.68rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:4px">
Клик &#8212; добавить &nbsp;&#183;&nbsp; ПКМ / 2&#215;клик &#8212; удалить<br>
Перетащи источник для перемещения
</div>
</div>
</div><!-- /.proj-panel -->
<div class="proj-canvas-outer">
<canvas id="emfield-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<div class="proj-stats-bar">
<div class="pstat"><div class="pstat-label">Зарядов</div><div class="pstat-val" id="embar-charges-bar" style="color:#EF476F">0</div></div>
<div class="pstat"><div class="pstat-label">Проводов</div><div class="pstat-val" id="embar-wires-bar" style="color:var(--cyan)">0</div></div>
<div class="pstat"><div class="pstat-label">Частица</div><div class="pstat-val" id="embar-particle">выкл</div></div>
<div class="pstat"><div class="pstat-label">|E| курсора</div><div class="pstat-val" id="embar-curE-bar" style="color:#EF476F">&#8212;</div></div>
<div class="pstat"><div class="pstat-label">|B| курсора</div><div class="pstat-val" id="embar-curB-bar" style="color:var(--cyan)">&#8212;</div></div>
<div class="pstat"><div class="pstat-label">Сила Ампера</div><div class="pstat-val" id="embar-ampere" style="color:#fbbf24">&#8212;</div></div>
<div class="pstat"><div class="pstat-label">Поток &#934;</div><div class="pstat-val" id="embar-flux" style="color:#34d399">&#8212;</div></div>
<div class="pstat"><div class="pstat-label">&#934;&#8336; Гаусса</div><div class="pstat-val" id="embar-gauss-bar" style="color:#34d399">&#8212;</div></div>
<div class="pstat"><div class="pstat-label">ЭДС &#949;</div><div class="pstat-val" id="embar-rod-bar" style="color:#f59e0b">&#8212;</div></div>
</div>
</div><!-- /#sim-emfield -->
<!-- ── TRIANGLE sim body ── -->
<div id="sim-tri" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<!-- left panel -->
<div class="proj-panel" style="width:240px;gap:0">
<!-- Layer toggles -->
<div class="gp-section-title" style="margin-bottom:10px">Слои</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
<label class="tri-layer-row" onclick="triToggle('medians',this)">
<span class="tri-dot" style="background:#22d55e;box-shadow:0 0 5px #22d55e"></span>
<span class="tri-layer-name">Медианы</span>
<span class="tri-layer-hint" style="color:#22d55e">G — центроид</span>
<span class="tri-toggle" id="tl-medians"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('altitudes',this)">
<span class="tri-dot" style="background:#f59e0b;box-shadow:0 0 5px #f59e0b"></span>
<span class="tri-layer-name">Высоты</span>
<span class="tri-layer-hint" style="color:#f59e0b">H — ортоцентр</span>
<span class="tri-toggle" id="tl-altitudes"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('bisectors',this)">
<span class="tri-dot" style="background:#ec4899;box-shadow:0 0 5px #ec4899"></span>
<span class="tri-layer-name">Биссектрисы</span>
<span class="tri-layer-hint" style="color:#ec4899">I — инцентр</span>
<span class="tri-toggle" id="tl-bisectors"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('circumcircle',this)">
<span class="tri-dot" style="background:var(--pink);box-shadow:0 0 5px var(--pink)"></span>
<span class="tri-layer-name">Описанная окружность</span>
<span class="tri-layer-hint" style="color:var(--pink)">O, R</span>
<span class="tri-toggle" id="tl-circumcircle"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('incircle',this)">
<span class="tri-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></span>
<span class="tri-layer-name">Вписанная окружность</span>
<span class="tri-layer-hint" style="color:var(--cyan)">I, r</span>
<span class="tri-toggle" id="tl-incircle"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('eulerLine',this)">
<span class="tri-dot" style="background:rgba(255,255,100,0.8);box-shadow:0 0 5px yellow"></span>
<span class="tri-layer-name">Прямая Эйлера</span>
<span class="tri-layer-hint" style="color:rgba(255,255,100,0.7)">O<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>G<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>H</span>
<span class="tri-toggle" id="tl-eulerLine"></span>
</label>
</div>
<div class="gp-section-title" style="margin-bottom:10px">Теоремы</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
<label class="tri-layer-row" onclick="triToggle('sineLaw',this)">
<span class="tri-dot" style="background:#60a5fa;box-shadow:0 0 5px #60a5fa"></span>
<span class="tri-layer-name">Теорема синусов</span>
<span class="tri-layer-hint" style="color:#60a5fa">a/sinA = 2R</span>
<span class="tri-toggle" id="tl-sineLaw"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('cosineLaw',this)">
<span class="tri-dot" style="background:#fbbf24;box-shadow:0 0 5px #fbbf24"></span>
<span class="tri-layer-name">Теорема косинусов</span>
<span class="tri-layer-hint" style="color:#fbbf24">c²=a²+b²−2ab·cosC</span>
<span class="tri-toggle" id="tl-cosineLaw"></span>
</label>
<label class="tri-layer-row" onclick="triToggle('pythagorean',this)">
<span class="tri-dot" style="background:#EF476F;box-shadow:0 0 5px #EF476F"></span>
<span class="tri-layer-name">Теорема Пифагора</span>
<span class="tri-layer-hint" style="color:#EF476F">a²+b² = c²</span>
<span class="tri-toggle" id="tl-pythagorean"></span>
</label>
</div>
<!-- Stats -->
<div class="gp-section-title" style="margin-bottom:8px">Стороны</div>
<div class="tri-stats-grid" style="margin-bottom:10px">
<span class="tri-stat-k" style="color:var(--violet)">a</span><span class="tri-stat-v" id="ts-a"></span>
<span class="tri-stat-k" style="color:var(--cyan)">b</span><span class="tri-stat-v" id="ts-b"></span>
<span class="tri-stat-k" style="color:var(--pink)">c</span><span class="tri-stat-v" id="ts-c"></span>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Углы</div>
<div class="tri-stats-grid" style="margin-bottom:10px">
<span class="tri-stat-k" style="color:var(--violet)">∠A</span><span class="tri-stat-v" id="ts-A"></span>
<span class="tri-stat-k" style="color:var(--cyan)">∠B</span><span class="tri-stat-v" id="ts-B"></span>
<span class="tri-stat-k" style="color:var(--pink)">∠C</span><span class="tri-stat-v" id="ts-C"></span>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Вычисляемые</div>
<div class="tri-stats-grid" style="margin-bottom:10px">
<span class="tri-stat-k">S</span><span class="tri-stat-v" id="ts-S"></span>
<span class="tri-stat-k">P</span><span class="tri-stat-v" id="ts-P"></span>
<span class="tri-stat-k">R</span><span class="tri-stat-v" id="ts-R"></span>
<span class="tri-stat-k">r</span><span class="tri-stat-v" id="ts-r"></span>
</div>
<!-- Type badge -->
<div style="margin-top:auto;padding-top:10px">
<div style="font-size:0.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);margin-bottom:6px">Тип</div>
<div id="ts-type" style="
padding:8px 14px;border-radius:12px;
background:rgba(155,93,229,0.12);border:1.5px solid rgba(155,93,229,0.25);
font-family:'Manrope',sans-serif;font-size:0.82rem;font-weight:700;
color:var(--violet);text-align:center;
"></div>
<div style="margin-top:8px;font-size:0.7rem;color:var(--text-3);text-align:center;line-height:1.5">
Перетащи вершины<br>A, B, C для изменения
</div>
</div>
</div><!-- /.proj-panel -->
<!-- canvas -->
<div class="proj-canvas-outer">
<canvas id="tri-canvas"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<!-- stats bar -->
<div class="proj-stats-bar">
<div class="pstat">
<div class="pstat-label">Сторона a</div>
<div class="pstat-val" id="tbar-a"></div>
</div>
<div class="pstat">
<div class="pstat-label">Сторона b</div>
<div class="pstat-val" id="tbar-b"></div>
</div>
<div class="pstat">
<div class="pstat-label">Сторона c</div>
<div class="pstat-val" id="tbar-c"></div>
</div>
<div class="pstat">
<div class="pstat-label">Площадь S</div>
<div class="pstat-val" id="tbar-S"></div>
</div>
<div class="pstat">
<div class="pstat-label">Периметр P</div>
<div class="pstat-val" id="tbar-P"></div>
</div>
<div class="pstat">
<div class="pstat-label">R / r</div>
<div class="pstat-val" id="tbar-Rr"></div>
</div>
</div>
</div><!-- /#sim-tri -->
<!-- ══════════════════════════════════════════════
ТРИГОНОМЕТРИЧЕСКАЯ ОКРУЖНОСТЬ
══════════════════════════════════════════════ -->
<div id="sim-trigcircle" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<!-- left panel -->
<div class="proj-panel" style="width:240px;gap:0">
<!-- Function toggles -->
<div class="gp-section-title" style="margin-bottom:10px">Отрезки</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
<label class="tri-layer-row active" onclick="trigToggle('sin',this)">
<span class="tri-dot" style="background:#EF476F;box-shadow:0 0 5px #EF476F"></span>
<span class="tri-layer-name">sin</span>
<span class="tri-layer-hint" style="color:#EF476F">вертикаль</span>
<span class="tri-toggle" id="trig-tl-sin"></span>
</label>
<label class="tri-layer-row active" onclick="trigToggle('cos',this)">
<span class="tri-dot" style="background:var(--cyan);box-shadow:0 0 5px var(--cyan)"></span>
<span class="tri-layer-name">cos</span>
<span class="tri-layer-hint" style="color:var(--cyan)">горизонталь</span>
<span class="tri-toggle" id="trig-tl-cos"></span>
</label>
<label class="tri-layer-row" onclick="trigToggle('tan',this)">
<span class="tri-dot" style="background:#FFD166;box-shadow:0 0 5px #FFD166"></span>
<span class="tri-layer-name">tg</span>
<span class="tri-layer-hint" style="color:#FFD166">касательная</span>
<span class="tri-toggle" id="trig-tl-tan"></span>
</label>
<label class="tri-layer-row" onclick="trigToggle('cot',this)">
<span class="tri-dot" style="background:#7BF5A4;box-shadow:0 0 5px #7BF5A4"></span>
<span class="tri-layer-name">ctg</span>
<span class="tri-layer-hint" style="color:#7BF5A4">кокасательная</span>
<span class="tri-toggle" id="trig-tl-cot"></span>
</label>
</div>
<!-- Graph function selector -->
<div class="gp-section-title" style="margin-bottom:8px">График</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:14px">
<button class="trig-fn-btn active" onclick="trigSetGraphFn('sin',this)" style="--fc:#EF476F">sin</button>
<button class="trig-fn-btn" onclick="trigSetGraphFn('cos',this)" style="--fc:#06D6E0">cos</button>
<button class="trig-fn-btn" onclick="trigSetGraphFn('tan',this)" style="--fc:#FFD166">tg</button>
<button class="trig-fn-btn" onclick="trigSetGraphFn('cot',this)" style="--fc:#7BF5A4">ctg</button>
</div>
<!-- Values display -->
<div class="gp-section-title" style="margin-bottom:8px">Значения</div>
<div class="tri-stats-grid" style="margin-bottom:14px">
<span class="tri-stat-k" style="color:#EF476F">sin</span><span class="tri-stat-v" id="trig-v-sin"></span>
<span class="tri-stat-k" style="color:#06D6E0">cos</span><span class="tri-stat-v" id="trig-v-cos"></span>
<span class="tri-stat-k" style="color:#FFD166">tg</span><span class="tri-stat-v" id="trig-v-tan"></span>
<span class="tri-stat-k" style="color:#7BF5A4">ctg</span><span class="tri-stat-v" id="trig-v-cot"></span>
</div>
<!-- Notable angles -->
<div class="gp-section-title" style="margin-bottom:8px">Табличные углы</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:14px">
<button class="preset-btn" onclick="trigGoTo(0)"></button>
<button class="preset-btn" onclick="trigGoTo(Math.PI/6)">30°</button>
<button class="preset-btn" onclick="trigGoTo(Math.PI/4)">45°</button>
<button class="preset-btn" onclick="trigGoTo(Math.PI/3)">60°</button>
<button class="preset-btn" onclick="trigGoTo(Math.PI/2)">90°</button>
<button class="preset-btn" onclick="trigGoTo(2*Math.PI/3)">120°</button>
<button class="preset-btn" onclick="trigGoTo(Math.PI)">180°</button>
<button class="preset-btn" onclick="trigGoTo(3*Math.PI/2)">270°</button>
</div>
<!-- Angle info -->
<div style="margin-top:auto;padding-top:10px">
<div style="font-size:0.62rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3);margin-bottom:6px">Угол</div>
<div id="trig-angle-badge" style="
padding:10px 14px;border-radius:12px;
background:rgba(155,93,229,0.12);border:1.5px solid rgba(155,93,229,0.25);
font-family:'Manrope',sans-serif;font-size:0.85rem;font-weight:700;
color:var(--violet);text-align:center;line-height:1.6;
">45° = π/4</div>
<div style="margin-top:8px;font-size:0.7rem;color:var(--text-3);text-align:center;line-height:1.5">
Перетащи точку по окружности<br>или выбери табличный угол
</div>
</div>
</div><!-- /.proj-panel -->
<!-- canvas -->
<div class="proj-canvas-outer">
<canvas id="trigcircle-canvas"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<!-- stats bar -->
<div class="proj-stats-bar">
<div class="pstat">
<div class="pstat-label">Угол</div>
<div class="pstat-val" id="trigbar-angle" style="color:var(--violet)">45°</div>
</div>
<div class="pstat">
<div class="pstat-label">sin</div>
<div class="pstat-val" id="trigbar-sin" style="color:#EF476F"></div>
</div>
<div class="pstat">
<div class="pstat-label">cos</div>
<div class="pstat-val" id="trigbar-cos" style="color:#06D6E0"></div>
</div>
<div class="pstat">
<div class="pstat-label">tg</div>
<div class="pstat-val" id="trigbar-tan" style="color:#FFD166"></div>
</div>
<div class="pstat">
<div class="pstat-label">ctg</div>
<div class="pstat-val" id="trigbar-cot" style="color:#7BF5A4"></div>
</div>
<div class="pstat">
<div class="pstat-label">Четверть</div>
<div class="pstat-val" id="trigbar-quad" style="color:var(--violet)"></div>
</div>
</div>
</div><!-- /#sim-trigcircle -->
<!-- ══════════════════════════════════════════════
ИДЕАЛЬНЫЙ ГАЗ
══════════════════════════════════════════════ -->
<!-- ══════════════════════════════════════════════
МОЛЕКУЛЯРНАЯ ФИЗИКА (газ + броуновское + состояния + диффузия)
══════════════════════════════════════════════ -->
<div id="sim-molphys" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:248px;gap:0">
<!-- Mode selector -->
<div style="display:flex;gap:3px;margin-bottom:12px;padding:3px;background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid var(--border)">
<button class="mag-mode-btn mol-mode active" id="mol-mode-gas" onclick="molMode('gas',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Газ</button>
<button class="mag-mode-btn mol-mode" id="mol-mode-brownian" onclick="molMode('brownian',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Броуновское</button>
<button class="mag-mode-btn mol-mode" id="mol-mode-states" onclick="molMode('states',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Фазы</button>
<button class="mag-mode-btn mol-mode" id="mol-mode-diffusion" onclick="molMode('diffusion',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Диффузия</button>
</div>
<!-- ── Gas panel ── -->
<div id="mol-panel-gas">
<div class="gp-section-title" style="margin-bottom:8px">Параметры газа</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Число молекул N</span><span class="param-val" id="g-N">80</span></div>
<input type="range" class="param-slider" id="sl-gN" min="20" max="200" value="80" oninput="gasNChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="g-T">1.0 у.е.</span></div>
<input type="range" class="param-slider" id="sl-gT" min="2" max="30" value="10" oninput="gasTChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Поршень (объём)</span><span class="param-val" id="g-piston">100%</span></div>
<input type="range" class="param-slider" id="sl-gPiston" min="30" max="100" value="100" oninput="gasPistonChange()">
</div>
<div style="margin-bottom:10px">
<button class="proj-preset-chip" id="gas-vec-btn" onclick="gasToggleVectors(this)" style="width:100%">Векторы скоростей: Выкл</button>
</div>
<div class="gp-section-title" style="margin-top:4px;margin-bottom:8px">Состояние</div>
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Давление P</div>
<div class="tri-stat-v" id="gstat-P" style="text-align:center;color:var(--violet)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Объём V</div>
<div class="tri-stat-v" id="gstat-V" style="text-align:center;color:var(--cyan)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">PV</div>
<div class="tri-stat-v" id="gstat-PV" style="text-align:center;color:#34d399"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">⟨v⟩ средн.</div>
<div class="tri-stat-v" id="gstat-v" style="text-align:center;color:#FFD166"></div>
</div>
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">Стенки светятся по P · Поршень перетащи мышью</div>
</div>
<!-- ── Brownian panel ── -->
<div id="mol-panel-brownian" style="display:none">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Молекул газа N</span><span class="param-val" id="br-N">120</span></div>
<input type="range" class="param-slider" id="sl-brN" min="30" max="300" value="120" oninput="brownNChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="br-T">1.0 у.е.</span></div>
<input type="range" class="param-slider" id="sl-brT" min="2" max="20" value="10" oninput="brownTChange()">
</div>
<div class="gp-section-title" style="margin-top:10px;margin-bottom:8px">Статистика частицы B</div>
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">|Δr| смещение</div>
<div class="tri-stat-v" id="brstat-dr" style="text-align:center;color:#FFD166">0</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">MSD</div>
<div class="tri-stat-v" id="brstat-msd" style="text-align:center;color:var(--violet)">0</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Скорость v</div>
<div class="tri-stat-v" id="brstat-v" style="text-align:center;color:var(--cyan)">0</div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Шагов</div>
<div class="tri-stat-v" id="brstat-steps" style="text-align:center;color:#34d399">0</div>
</div>
<div style="margin-bottom:10px">
<button class="proj-preset-chip" onclick="if(brownSim) brownSim.resetOrigin()" style="width:100%">Сбросить отсчёт (Origin)</button>
</div>
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">График MSD нарастает линейно — закон диффузии</div>
</div>
<!-- ── States panel ── -->
<div id="mol-panel-states" style="display:none">
<div class="gp-section-title" style="margin-bottom:8px">Управление</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="st-T">0.15</span></div>
<input type="range" class="param-slider" id="sl-stT" min="1" max="100" value="15" oninput="statesTChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Частиц N</span><span class="param-val" id="st-N">64</span></div>
<input type="range" class="param-slider" id="sl-stN" min="16" max="100" step="4" value="64" oninput="statesNChange()">
</div>
<div style="display:flex;gap:6px;margin-bottom:14px;flex-wrap:wrap">
<button class="proj-preset-chip" onclick="statesPreset(0.05)">Твёрдое</button>
<button class="proj-preset-chip" onclick="statesPreset(0.30)">Жидкость</button>
<button class="proj-preset-chip" onclick="statesPreset(0.75)">Газ</button>
</div>
<button id="states-vec-btn" class="proj-preset-chip" style="margin-bottom:10px;width:100%" onclick="statesToggleVectors(this)">Векторы скоростей: Выкл</button>
<div class="gp-section-title" style="margin-bottom:8px">Фаза и энергия</div>
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Фаза</div>
<div class="tri-stat-v" id="ststat-phase" style="text-align:center"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Кин. энергия</div>
<div class="tri-stat-v" id="ststat-KE" style="text-align:center;color:#FFD166"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Пот. энергия</div>
<div class="tri-stat-v" id="ststat-PE" style="text-align:center;color:var(--violet)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Давление</div>
<div class="tri-stat-v" id="ststat-P" style="text-align:center;color:#EF476F"></div>
</div>
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">LJ потенциал · g(r) — структура · цвет = скорость</div>
</div>
<!-- ── Diffusion panel ── -->
<div id="mol-panel-diffusion" style="display:none">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Молекул каждого вида</span><span class="param-val" id="df-N">60</span></div>
<input type="range" class="param-slider" id="sl-dfN" min="20" max="120" value="60" oninput="diffNChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="df-T">1.0 у.е.</span></div>
<input type="range" class="param-slider" id="sl-dfT" min="2" max="20" value="10" oninput="diffTChange()">
</div>
<label class="tri-layer-row active" id="df-part-row" onclick="diffPartitionToggle(this)" style="margin-bottom:6px">
<span class="tri-dot" style="background:rgba(255,255,255,0.5)"></span>
<span class="tri-layer-name">Перегородка</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)"></span>
<span class="tri-toggle" id="df-part-toggle" style="background:var(--violet)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:14px"></span></span>
</label>
<label class="tri-layer-row" id="df-pore-row" onclick="diffPoreToggle(this)" style="margin-bottom:10px">
<span class="tri-dot" style="background:rgba(255,179,71,0.5)"></span>
<span class="tri-layer-name">Пора (щель)</span>
<span class="tri-layer-hint" style="color:rgba(255,255,255,.4)"></span>
<span class="tri-toggle" id="df-pore-toggle" style="background:rgba(255,255,255,0.15)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
<div class="gp-section-title" style="margin-bottom:8px">Концентрации</div>
<div class="tri-stats-grid" style="grid-template-columns:1fr 1fr;margin-bottom:8px">
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--cyan)">Лево A</div>
<div class="tri-stat-v" id="dfstat-LA" style="text-align:center;color:var(--cyan)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--pink)">Лево B</div>
<div class="tri-stat-v" id="dfstat-LB" style="text-align:center;color:var(--pink)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--cyan)">Право A</div>
<div class="tri-stat-v" id="dfstat-RA" style="text-align:center;color:var(--cyan)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--pink)">Право B</div>
<div class="tri-stat-v" id="dfstat-RB" style="text-align:center;color:var(--pink)"></div>
<div style="font-size:.68rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--text-3)">Смешивание</div>
<div class="tri-stat-v" id="dfstat-mix" style="text-align:center;color:#34d399"></div>
</div>
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.6;margin-top:auto">A (cyan) — лево · B (розовый) — право</div>
</div>
</div><!-- /.proj-panel -->
<div class="proj-canvas-outer">
<canvas id="gas-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
<canvas id="brownian-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
<canvas id="states-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
<canvas id="diffusion-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<div class="proj-stats-bar" id="mol-stats-bar">
<div class="pstat"><div class="pstat-label" id="mpbar-l1"></div><div class="pstat-val" id="mpbar-v1" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label" id="mpbar-l2"></div><div class="pstat-val" id="mpbar-v2" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label" id="mpbar-l3"></div><div class="pstat-val" id="mpbar-v3" style="color:var(--violet)"></div></div>
<div class="pstat"><div class="pstat-label" id="mpbar-l4"></div><div class="pstat-val" id="mpbar-v4" style="color:#34d399"></div></div>
<div class="pstat"><div class="pstat-label" id="mpbar-l5"></div><div class="pstat-val" id="mpbar-v5"></div></div>
</div>
</div><!-- /#sim-molphys -->
<!-- ══════════════════════════════════════════════
ЗАКОН КУЛОНА
══════════════════════════════════════════════ -->
<!-- sim-coulomb removed: merged into sim-emfield -->
<!-- ══════════════════════════════════════════════
ЭЛЕКТРИЧЕСКИЕ ЦЕПИ
══════════════════════════════════════════════ -->
<div id="sim-circuit" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:240px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Инструмент</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip circ-tool-btn active" id="ptool-wire" onclick="circTool('wire',this)" data-tool="wire">Провод</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-resistor" onclick="circTool('resistor',this)" data-tool="resistor">Резистор</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-battery" onclick="circTool('battery',this)" data-tool="battery">Батарея</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-capacitor" onclick="circTool('capacitor',this)" data-tool="capacitor">Конденсатор</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-inductor" onclick="circTool('inductor',this)" data-tool="inductor">Катушка L</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-diode" onclick="circTool('diode',this)" data-tool="diode">Диод</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-led" onclick="circTool('led',this)" data-tool="led">LED</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-ac" onclick="circTool('ac',this)" data-tool="ac">AC источник</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-switch" onclick="circTool('switch',this)" data-tool="switch">Выключатель</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-lamp" onclick="circTool('lamp',this)" data-tool="lamp">Лампа</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-ammeter" onclick="circTool('ammeter',this)" data-tool="ammeter">Амперметр</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-voltmeter" onclick="circTool('voltmeter',this)" data-tool="voltmeter">Вольтметр</button>
<button class="proj-preset-chip circ-tool-btn" id="ptool-erase" onclick="circTool('erase',this)" data-tool="erase">Ластик</button>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Сопротивление R</span>
<span class="param-val" id="circ-R-val">10 Ω</span>
</div>
<input type="range" class="param-slider" id="sl-circR" min="1" max="100" value="10" oninput="circRChange()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Напряжение U</span>
<span class="param-val" id="circ-U-val">9 В</span>
</div>
<input type="range" class="param-slider" id="sl-circU" min="1" max="24" value="9" oninput="circUChange()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Ёмкость C</span>
<span class="param-val" id="circ-C-val">100 µF</span>
</div>
<input type="range" class="param-slider" id="sl-circC" min="10" max="1000" value="100" step="10" oninput="circCChange()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Индуктивность L</span>
<span class="param-val" id="circ-L-val">10 мГн</span>
</div>
<input type="range" class="param-slider" id="sl-circL" min="1" max="1000" value="10" step="1" oninput="circLChange()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Частота AC</span>
<span class="param-val" id="circ-F-val">2 Гц</span>
</div>
<input type="range" class="param-slider" id="sl-circF" min="1" max="20" value="2" oninput="circFChange()">
</div>
<div class="gp-section-title" style="margin-bottom:8px;margin-top:4px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip" onclick="circPreset('serial')">Последовательное</button>
<button class="proj-preset-chip" onclick="circPreset('parallel')">Параллельное</button>
<button class="proj-preset-chip" onclick="circPreset('lamp')">Лампа + выкл</button>
<button class="proj-preset-chip" onclick="circPreset('divider')">Делитель V</button>
<button class="proj-preset-chip" onclick="circPreset('bridge')">Мост Уитстона</button>
<button class="proj-preset-chip" onclick="circPreset('diode')">Диод</button>
<button class="proj-preset-chip" onclick="circPreset('led')">LED</button>
<button class="proj-preset-chip" onclick="circPreset('rc')">RC-цепь</button>
<button class="proj-preset-chip" onclick="circPreset('ac')">AC-цепь</button>
<button class="proj-preset-chip" onclick="circPreset('rlc')">RLC-резонанс</button>
</div>
<div style="margin-top:auto;font-size:0.68rem;color:var(--text-3);text-align:center;line-height:1.7;padding-top:4px">
Тяни узлы для рисования · ПКМ — удалить<br>
2×клик по выключателю — вкл/выкл · Ctrl+Z отмена
</div>
</div><!-- /.proj-panel -->
<div class="proj-canvas-outer">
<canvas id="circuit-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
<div id="osc-panel" style="display:none;position:absolute;bottom:8px;right:8px;z-index:10;background:rgba(6,6,22,0.95);border:1px solid rgba(255,255,255,0.12);border-radius:8px;padding:6px">
<div style="font-size:0.7rem;color:rgba(255,255,255,0.45);margin-bottom:4px;text-align:center">Осциллограф</div>
<canvas id="osc-canvas" width="300" height="180" style="display:block;border-radius:4px"></canvas>
</div>
</div>
</div><!-- /.sim-body-wrap -->
<div class="proj-stats-bar">
<div class="pstat"><div class="pstat-label">Компонентов</div><div class="pstat-val" id="cirbar-comps">0</div></div>
<div class="pstat"><div class="pstat-label">Напряжение U</div><div class="pstat-val" id="cirbar-U" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">Ток I</div><div class="pstat-val" id="cirbar-I" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Мощность P</div><div class="pstat-val" id="cirbar-P" style="color:#7BF5A4"></div></div>
<div class="pstat"><div class="pstat-label">Статус</div><div class="pstat-val" id="cirbar-status"></div></div>
</div>
</div><!-- /#sim-circuit -->
<!-- ══════════════════════════════════════════════
КИНЕТИКА РЕАКЦИЙ
══════════════════════════════════════════════ -->
<!-- ══════════════════════════════════════════════
ХИМИЯ (unified: кинетика + колба + ОВР + ионный обмен)
══════════════════════════════════════════════ -->
<div id="sim-chemistry" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:248px;gap:0">
<!-- Mode selector -->
<div style="display:flex;gap:3px;margin-bottom:12px;padding:3px;background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid var(--border)">
<button class="mag-mode-btn chem-mode active" id="chem-mode-kinetics" onclick="chemMode('kinetics',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Кинетика</button>
<button class="mag-mode-btn chem-mode" id="chem-mode-flask" onclick="chemMode('flask',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Колба</button>
<button class="mag-mode-btn chem-mode" id="chem-mode-redox" onclick="chemMode('redox',this)" style="flex:1;font-size:.63rem;padding:5px 2px">ОВР</button>
<button class="mag-mode-btn chem-mode" id="chem-mode-ionex" onclick="chemMode('ionex',this)" style="flex:1;font-size:.63rem;padding:5px 2px">Ионный</button>
</div>
<!-- ── Kinetics panel ── -->
<div id="chem-panel-kinetics">
<div class="gp-section-title" style="margin-bottom:6px">Параметры</div>
<div class="param-block" style="margin-bottom:7px">
<div class="param-header"><span class="param-name">Молекул N</span><span class="param-val" id="reac-N-val">28</span></div>
<input type="range" class="param-slider" id="sl-reacN" min="5" max="60" value="28" oninput="reacNChange()">
</div>
<div class="param-block" style="margin-bottom:7px">
<div class="param-header"><span class="param-name">Температура T</span><span class="param-val" id="reac-T-val">1.2</span></div>
<input type="range" class="param-slider" id="sl-reacT" min="2" max="40" value="12" oninput="reacTChange()">
</div>
<div class="param-block" style="margin-bottom:7px">
<div class="param-header"><span class="param-name">Энергия активации Ea</span><span class="param-val" id="reac-Ea-val">2.0</span></div>
<input type="range" class="param-slider" id="sl-reacEa" min="5" max="50" value="20" oninput="reacEaChange()">
</div>
<div class="gp-section-title" style="margin-bottom:6px">Режим</div>
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:8px">
<button class="proj-preset-chip reac-mode-btn active" id="rmode-forward" onclick="reacMode('forward',this)" style="text-align:left"><svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> Прямая (A+B<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>C)</button>
<button class="proj-preset-chip reac-mode-btn" id="rmode-reversible" onclick="reacMode('reversible',this)" style="text-align:left">⇌ Обратимая</button>
<button class="proj-preset-chip reac-mode-btn" id="rmode-chain" onclick="reacMode('chain',this)" style="text-align:left"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg> Цепная</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:5px">
<button class="proj-preset-chip" onclick="reacPreset('simple')">Простая</button>
<button class="proj-preset-chip" onclick="reacPreset('reversible')">Равновесие</button>
<button class="proj-preset-chip" onclick="reacPreset('hot')">Горячая</button>
<button class="proj-preset-chip" onclick="reacPreset('cold')">Холодная</button>
<button class="proj-preset-chip" onclick="reacPreset('chain')">Цепная</button>
</div>
</div><!-- /chem-panel-kinetics -->
<!-- ── Flask panel ── -->
<div id="chem-panel-flask" style="display:none">
<div class="gp-section-title" style="margin-bottom:8px">Металл</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip flask-metal-btn active" id="fmetal-Zn" onclick="flaskMetal('Zn',this)">Zn</button>
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Fe" onclick="flaskMetal('Fe',this)">Fe</button>
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Mg" onclick="flaskMetal('Mg',this)">Mg</button>
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Cu" onclick="flaskMetal('Cu',this)">Cu</button>
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Na" onclick="flaskMetal('Na',this)">Na</button>
<button class="proj-preset-chip flask-metal-btn" id="fmetal-Al" onclick="flaskMetal('Al',this)">Al</button>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Реагент</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip flask-acid-btn active" id="facid-HCl" onclick="flaskAcid('HCl',this)">HCl</button>
<button class="proj-preset-chip flask-acid-btn" id="facid-H2SO4" onclick="flaskAcid('H2SO4',this)">H₂SO₄</button>
<button class="proj-preset-chip flask-acid-btn" id="facid-H2O" onclick="flaskAcid('H2O',this)">H₂O</button>
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Концентрация</span><span class="param-val" id="flask-conc-val">35%</span></div>
<input type="range" class="param-slider" id="sl-flask-conc" min="5" max="98" value="35" oninput="flaskConcChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Темп. окружения</span><span class="param-val" id="flask-temp-val">20°C</span></div>
<input type="range" class="param-slider" id="sl-flask-temp" min="5" max="80" value="20" oninput="flaskTempChange()">
</div>
<div style="display:flex;gap:6px;margin-bottom:10px;margin-top:2px">
<button class="proj-preset-chip" style="flex:1;background:rgba(239,71,111,0.18);border-color:rgba(239,71,111,0.4)"
onclick="flaskSim && flaskSim.dropMetal()"><svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> Бросить металл</button>
<button class="proj-preset-chip" id="flask-flame-panel" style="flex:0 0 auto"
onclick="flaskToggleFlame()"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M12 2c.5 3.5-1.5 6-1.5 6 1 1.5 3 2 3 5a4 4 0 01-8 0c0-2 .5-3 1.5-4.5C8.5 6.5 7 4.5 7 4.5S9.5 2 12 2z"/></svg></button>
</div>
<div style="font-size:.65rem;color:var(--text-3);text-align:center;line-height:1.7;margin-top:auto;padding-top:4px">
Выбери металл + кислоту<br>H₂ накапливается — поднеси огонь!
</div>
</div><!-- /chem-panel-flask -->
<!-- ── Redox panel ── -->
<div id="chem-panel-redox" style="display:none">
<div class="gp-section-title" style="margin-bottom:8px">Реакция</div>
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:12px">
<button class="proj-preset-chip redox-rxn-btn active" id="rdxrxn-fe_cu" onclick="redoxRxn('fe_cu',this)" style="text-align:left;font-size:.72rem">Fe + CuSO₄ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> FeSO₄ + Cu<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-zn_hcl" onclick="redoxRxn('zn_hcl',this)" style="text-align:left;font-size:.72rem">Zn + 2HCl <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> ZnCl₂ + H₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></button>
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-cl2_ki" onclick="redoxRxn('cl2_ki',this)" style="text-align:left;font-size:.72rem">Cl₂ + 2KI <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> I₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> + 2KCl</button>
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-kmno4" onclick="redoxRxn('kmno4',this)" style="text-align:left;font-size:.72rem">KMnO₄ + FeSO₄ (кислая)</button>
<button class="proj-preset-chip redox-rxn-btn" id="rdxrxn-cu_fecl3" onclick="redoxRxn('cu_fecl3',this)" style="text-align:left;font-size:.72rem">Cu + 2FeCl₃ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> CuCl₂ + 2FeCl₂</button>
</div>
<button class="proj-launch-btn" style="margin-bottom:8px" onclick="redoxStart()"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Начать реакцию</button>
<button class="proj-reset-btn" onclick="redoxReset()"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
<div style="margin-top:auto;padding-top:6px;font-size:.65rem;color:var(--text-3);line-height:1.7;text-align:center">
Синие e⁻ — перенос электронов<br>Цифры — степень окисления
</div>
</div><!-- /chem-panel-redox -->
<!-- ── Ion exchange panel ── -->
<div id="chem-panel-ionex" style="display:none">
<div class="gp-section-title" style="margin-bottom:8px">Реакция</div>
<div style="display:flex;flex-direction:column;gap:4px;margin-bottom:12px">
<button class="proj-preset-chip ionex-rxn-btn active" id="ioxrxn-ba_so4" onclick="ionexRxn('ba_so4',this)" style="text-align:left;font-size:.72rem">BaCl₂ + Na₂SO₄ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> BaSO₄<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-ag_cl" onclick="ionexRxn('ag_cl',this)" style="text-align:left;font-size:.72rem">AgNO₃ + NaCl <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> AgCl<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-co3_hcl" onclick="ionexRxn('co3_hcl',this)" style="text-align:left;font-size:.72rem">Na₂CO₃ + 2HCl <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> CO₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></button>
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-pb_i" onclick="ionexRxn('pb_i',this)" style="text-align:left;font-size:.72rem">Pb(NO₃)₂ + 2KI <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> PbI₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
<button class="proj-preset-chip ionex-rxn-btn" id="ioxrxn-ca_co3" onclick="ionexRxn('ca_co3',this)" style="text-align:left;font-size:.72rem">CaCl₂ + Na₂CO₃ <svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> CaCO₃<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
</div>
<button class="proj-launch-btn" style="margin-bottom:8px" onclick="ionexStart()"><svg class="ic" viewBox="0 0 24 24"><path d="M9 3h6m-4.5 0v5.5l-4 7.5a1 1 0 0 0 .9 1.5h8.2a1 1 0 0 0 .9-1.5l-4-7.5V3"/></svg> Смешать растворы</button>
<button class="proj-reset-btn" onclick="ionexReset()"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
<div style="margin-top:auto;padding-top:6px;font-size:.65rem;color:var(--text-3);line-height:1.7;text-align:center">
Яркие ионы = реагируют<br>Тусклые = зрители · <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg> осадок · <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg> газ
</div>
</div><!-- /chem-panel-ionex -->
</div><!-- /.proj-panel -->
<div class="proj-canvas-outer">
<canvas id="reactions-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
<canvas id="flask-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
<canvas id="redox-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
<canvas id="ionexchange-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<div class="proj-stats-bar" id="chem-stats-bar">
<div class="pstat"><div class="pstat-label" id="chbar-l1"></div><div class="pstat-val" id="chbar-v1" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label" id="chbar-l2"></div><div class="pstat-val" id="chbar-v2" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label" id="chbar-l3"></div><div class="pstat-val" id="chbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label" id="chbar-l4"></div><div class="pstat-val" id="chbar-v4"></div></div>
<div class="pstat"><div class="pstat-label" id="chbar-l5"></div><div class="pstat-val" id="chbar-v5" style="color:#7BF5A4"></div></div>
</div>
</div><!-- /#sim-chemistry -->
<!-- ── DYNAMICS sim body (Newton + Sandbox unified) ── -->
<div id="sim-dynamics" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:248px;gap:0">
<!-- ══ Mode selector ══ -->
<div style="display:flex;gap:4px;margin-bottom:12px;padding:3px;background:rgba(255,255,255,0.04);border-radius:10px;border:1px solid var(--border)">
<button class="mag-mode-btn dyn-mode active" id="dyn-mode-sandbox" onclick="dynMode('sandbox',this)" style="flex:1;font-size:.68rem;padding:5px 0">Песочница</button>
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law1" onclick="dynMode('law1',this)" style="flex:1;font-size:.68rem;padding:5px 0">I закон</button>
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law2" onclick="dynMode('law2',this)" style="flex:1;font-size:.68rem;padding:5px 0">II закон</button>
<button class="mag-mode-btn dyn-mode" id="dyn-mode-law3" onclick="dynMode('law3',this)" style="flex:1;font-size:.68rem;padding:5px 0">III закон</button>
</div>
<!-- ══ Newton controls (shown in law modes) ══ -->
<div id="dyn-newton-panel" style="display:none">
<!-- Scene selector -->
<div class="gp-section-title" style="margin-bottom:8px">Сцена</div>
<div style="display:flex;gap:5px;margin-bottom:12px" id="newton-scene-row">
<button class="mag-mode-btn nscene-btn active" id="nscn-panel-A" onclick="newtonScene('A',null,this)" style="flex:1;font-size:.72rem">A</button>
<button class="mag-mode-btn nscene-btn" id="nscn-panel-B" onclick="newtonScene('B',null,this)" style="flex:1;font-size:.72rem">B</button>
<button class="mag-mode-btn nscene-btn" id="nscn-panel-C" onclick="newtonScene('C',null,this)" style="flex:1;font-size:.72rem">C</button>
</div>
<!-- Scene description -->
<div id="newton-scene-desc" style="font-size:0.71rem;color:var(--text-3);line-height:1.6;margin-bottom:10px;padding:6px 8px;background:rgba(255,255,255,0.03);border-radius:8px;border:1px solid var(--border)">
Закон инерции: тело движется равномерно при отсутствии сил.
</div>
<!-- Parameter sliders -->
<div id="newton-mu-block" class="param-block">
<div class="param-header"><span class="param-name">Коэфф. трения μ</span><span class="param-val" id="newton-mu-val">0.20</span></div>
<input type="range" class="param-slider" id="sl-newton-mu" min="0" max="1" step="0.01" value="0.20" oninput="newtonMuChange()">
</div>
<div id="newton-mass1-block" class="param-block" style="display:none">
<div class="param-header"><span class="param-name">Масса m₁ (кг)</span><span class="param-val" id="newton-m1-val">5 кг</span></div>
<input type="range" class="param-slider" id="sl-newton-m1" min="1" max="20" value="5" oninput="newtonMass1Change()">
</div>
<div id="newton-mass2-block" class="param-block" style="display:none">
<div class="param-header"><span class="param-name">Масса m₂ (кг)</span><span class="param-val" id="newton-m2-val">5 кг</span></div>
<input type="range" class="param-slider" id="sl-newton-m2" min="1" max="20" value="5" oninput="newtonMass2Change()">
</div>
<div id="newton-force-block" class="param-block" style="display:none">
<div class="param-header"><span class="param-name">Сила F (Н)</span><span class="param-val" id="newton-F-val">20 Н</span></div>
<input type="range" class="param-slider" id="sl-newton-F" min="1" max="60" value="20" oninput="newtonForceChange()">
</div>
<!-- Presets -->
<div class="gp-section-title" style="margin-top:6px">Пресеты</div>
<div id="newton-presets" style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip" onclick="newtonPreset('space')">Космос</button>
<button class="proj-preset-chip" onclick="newtonPreset('ice')">Лёд</button>
<button class="proj-preset-chip" onclick="newtonPreset('asphalt')">Асфальт</button>
<button class="proj-preset-chip" onclick="newtonPreset('rubber')">Резина</button>
</div>
<!-- Action -->
<div style="margin-top:auto;padding-top:10px;display:flex;flex-direction:column;gap:6px">
<button class="proj-launch-btn" id="newton-action-main" onclick="newtonAction()">
<span id="newton-action-label"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Действие</span>
</button>
<button class="proj-reset-btn" onclick="_resetNewtonScene()">
<svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2.2"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
Сброс сцены
</button>
</div>
</div><!-- /#dyn-newton-panel -->
<!-- ══ Sandbox controls (shown in sandbox mode) ══ -->
<div id="dyn-sandbox-panel">
<div class="gp-section-title" style="margin-bottom:8px">Инструмент</div>
<div style="display:flex;gap:5px;margin-bottom:4px">
<button class="mag-mode-btn sb-panel-tool active" id="sbpt-box" onclick="sbTool('box',this)" style="flex:1;font-size:.72rem"><svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18" rx="2"/></svg> Блок</button>
<button class="mag-mode-btn sb-panel-tool" id="sbpt-ball" onclick="sbTool('ball',this)" style="flex:1;font-size:.72rem"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8" fill="currentColor" stroke="none"/></svg> Шар</button>
<button class="mag-mode-btn sb-panel-tool" id="sbpt-erase" onclick="sbTool('erase',this)" style="flex:1;font-size:.72rem"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg></button>
</div>
<div style="display:flex;gap:5px;margin-bottom:10px">
<button class="mag-mode-btn sb-panel-tool" id="sbpt-spring" onclick="sbTool('spring',this)" style="flex:1;font-size:.72rem"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Пружина</button>
<button class="mag-mode-btn sb-panel-tool" id="sbpt-rope" onclick="sbTool('rope',this)" style="flex:1;font-size:.72rem">— Нить</button>
<button class="mag-mode-btn sb-panel-tool" id="sbpt-anchor" onclick="sbTool('anchor',this)" style="flex:1;font-size:.72rem"><svg class="ic" viewBox="0 0 24 24"><path d="M12 2 2 12 12 22 22 12Z"/></svg> Якорь</button>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Режим силы</div>
<div style="display:flex;gap:5px;margin-bottom:10px">
<button class="mag-mode-btn sb-fmode active" id="sbfm-constant" onclick="sbForceMode('constant',this)" style="flex:1;font-size:.72rem">Постоянная</button>
<button class="mag-mode-btn sb-fmode" id="sbfm-impulse" onclick="sbForceMode('impulse',this)" style="flex:1;font-size:.72rem">Импульс</button>
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Масса нового тела</span><span class="param-val" id="sb-mass-val">5 кг</span></div>
<input type="range" class="param-slider" id="sl-sb-mass" min="1" max="30" value="5" oninput="sbMassChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Упругость</span><span class="param-val" id="sb-rest-val">0.65</span></div>
<input type="range" class="param-slider" id="sl-sb-rest" min="0" max="1" step="0.05" value="0.65" oninput="sbRestChange()">
</div>
<div class="param-block" id="sb-spring-block" style="display:none">
<div class="param-header"><span class="param-name">Жёсткость пружины k</span><span class="param-val" id="sb-springk-val">120 Н</span></div>
<input type="range" class="param-slider" id="sl-sb-springk" min="10" max="600" step="10" value="120" oninput="sbSpringKChange()">
</div>
<div class="gp-section-title" style="margin-top:6px;margin-bottom:6px">Мир</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-gravity" checked onchange="sbWorldToggle()"> Гравитация</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-floor" checked onchange="sbWorldToggle()"> Пол</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-walls" checked onchange="sbWorldToggle()"> Стенки</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-airdrag" onchange="sbWorldToggle()"> Сопротивление воздуха</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-ramp" onchange="sbRampToggle()"> Наклонная плоскость</label>
</div>
<div id="sb-ramp-block" style="display:none">
<div class="param-block">
<div class="param-header"><span class="param-name">Угол α</span><span class="param-val" id="sb-angle-val">30°</span></div>
<input type="range" class="param-slider" id="sl-sb-angle" min="5" max="75" value="30" oninput="sbAngleChange()">
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Трение горки μ</span><span class="param-val" id="sb-rampmu-val">0.20</span></div>
<input type="range" class="param-slider" id="sl-sb-rampmu" min="0" max="1" step="0.01" value="0.20" oninput="sbRampMuChange()">
</div>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer;margin-bottom:6px"><input type="checkbox" id="sb-decomp" checked onchange="sbDecompToggle()"> Разложение сил</label>
</div>
<div class="param-block">
<div class="param-header"><span class="param-name">Трение пола μ</span><span class="param-val" id="sb-floormu-val">0.30</span></div>
<input type="range" class="param-slider" id="sl-sb-floormu" min="0" max="1" step="0.01" value="0.30" oninput="sbFloorMuChange()">
</div>
<div class="gp-section-title" style="margin-top:6px;margin-bottom:6px">Отображение</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:10px">
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-forces" checked onchange="sbDisplayToggle()"> Силы</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-vel" checked onchange="sbDisplayToggle()"> Скорости</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-fbd" onchange="sbDisplayToggle()"> FBD-диаграмма</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-energy" checked onchange="sbDisplayToggle()"> Энергия</label>
<label style="display:flex;align-items:center;gap:6px;font-size:.72rem;color:var(--text-2);cursor:pointer"><input type="checkbox" id="sb-trail" checked onchange="sbDisplayToggle()"> Стробоскоп</label>
</div>
<div class="gp-section-title" style="margin-top:2px;margin-bottom:6px">Время</div>
<div style="display:flex;gap:5px;margin-bottom:10px">
<button class="mag-mode-btn sb-time" onclick="sbTimeScale(0.25,this)" style="flex:1;font-size:.68rem">×0.25</button>
<button class="mag-mode-btn sb-time" onclick="sbTimeScale(0.5,this)" style="flex:1;font-size:.68rem">×0.5</button>
<button class="mag-mode-btn sb-time active" onclick="sbTimeScale(1,this)" style="flex:1;font-size:.68rem">×1</button>
<button class="mag-mode-btn sb-time" onclick="sbTimeScale(2,this)" style="flex:1;font-size:.68rem">×2</button>
</div>
<div class="gp-section-title" style="margin-top:2px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:5px;margin-bottom:10px">
<button class="proj-preset-chip" onclick="sbPreset('freefall')">Падение</button>
<button class="proj-preset-chip" onclick="sbPreset('collision')">Столкновение</button>
<button class="proj-preset-chip" onclick="sbPreset('friction')">Трение</button>
<button class="proj-preset-chip" onclick="sbPreset('tug')">Перетягивание</button>
<button class="proj-preset-chip" onclick="sbPreset('balance')">Равновесие</button>
<button class="proj-preset-chip" onclick="sbPreset('ramp_slide')">Горка</button>
<button class="proj-preset-chip" onclick="sbPreset('ramp_angle')"><svg class="ic" viewBox="0 0 24 24"><path d="m8 3 4 8 5-5 5 15H2L8 3z"/></svg> Крутой спуск</button>
<button class="proj-preset-chip" onclick="sbPreset('ramp_friction')"><svg class="ic" viewBox="0 0 24 24"><rect width="20" height="5" x="2" y="3" rx="1"/><rect width="8" height="5" x="2" y="11" rx="1"/><rect width="8" height="5" x="14" y="11" rx="1"/><rect width="20" height="5" x="2" y="19" rx="1"/></svg> Трение на горке</button>
<button class="proj-preset-chip" onclick="sbPreset('spring_bounce')"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Пружина</button>
<button class="proj-preset-chip" onclick="sbPreset('spring_chain')"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Цепочка</button>
<button class="proj-preset-chip" onclick="sbPreset('pendulum')">⬤ Маятник</button>
<button class="proj-preset-chip" onclick="sbPreset('atwood')"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93 17.66 6.34M21 12h-2M19.07 19.07l-1.41-1.41M12 21v-2M6.34 17.66 4.93 19.07M3 12h2M4.93 4.93l1.41 1.41M12 3v2"/><circle cx="12" cy="12" r="7"/></svg> Машина Атвуда</button>
<button class="proj-preset-chip" onclick="sbPreset('two_body')"><svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="21" x2="12" y2="3"/><polyline points="7 8 12 3 17 8"/><polyline points="17 16 12 21 7 16"/></svg> Два тела</button>
<button class="proj-preset-chip" onclick="sbPreset('elastic_collision')"><svg class="ic" viewBox="0 0 24 24"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg> Упругий удар</button>
<button class="proj-preset-chip" onclick="sbPreset('inelastic_collision')"><svg class="ic" viewBox="0 0 24 24"><path d="m12 3-1.9 5.8a2 2 0 0 1-1.3 1.3L3 12l5.8 1.9a2 2 0 0 1 1.3 1.3L12 21l1.9-5.8a2 2 0 0 1 1.3-1.3L21 12l-5.8-1.9a2 2 0 0 1-1.3-1.3z"/></svg> Неупругий</button>
<button class="proj-preset-chip" onclick="sbPreset('newton_cradle')"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.07 4.93 17.66 6.34M21 12h-2M19.07 19.07l-1.41-1.41M12 21v-2M6.34 17.66 4.93 19.07M3 12h2M4.93 4.93l1.41 1.41M12 3v2"/><circle cx="12" cy="12" r="7"/></svg> Колыбель Ньютона</button>
<button class="proj-preset-chip" onclick="sbPreset('harmonic_oscillator')"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Осциллятор</button>
<button class="proj-preset-chip" onclick="sbPreset('double_pendulum')">⬤⬤ Двойной маятник</button>
<button class="proj-preset-chip" onclick="sbPreset('coupled_oscillators')"><svg class="ic" viewBox="0 0 24 24" fill="none"><path d="M3 12 L6 8 L9 16 L12 8 L15 16 L18 8 L21 12"/></svg> Связанные</button>
<button class="proj-preset-chip" onclick="sbPreset('stacked_boxes')"><svg class="ic" viewBox="0 0 24 24"><rect width="20" height="5" x="2" y="3" rx="1"/><rect width="8" height="5" x="2" y="11" rx="1"/><rect width="8" height="5" x="14" y="11" rx="1"/><rect width="20" height="5" x="2" y="19" rx="1"/></svg> Стопка</button>
<button class="proj-preset-chip" onclick="sbPreset('pulley_ramp')"><svg class="ic" viewBox="0 0 24 24"><path d="m8 3 4 8 5-5 5 15H2L8 3z"/></svg> Горка+блок</button>
<button class="proj-preset-chip" onclick="sbPreset('circular_motion')">⭕ Круговое</button>
<button class="proj-preset-chip" onclick="sbPreset('projectile_angle')"><svg class="ic" viewBox="0 0 24 24"><line x1="7" y1="17" x2="17" y2="7"/><polyline points="7 7 17 7 17 17"/></svg> Снаряд 45°</button>
</div>
<div style="font-size:.65rem;color:var(--text-3);line-height:1.5;margin-top:auto;padding:6px 8px;background:rgba(255,255,255,0.03);border-radius:8px;border:1px solid var(--border)">
ЛКМ — создать тело · Drag — сила<br>
Shift+drag — импульс · ПКМ — удалить<br>
DblClick — закрепить / открепить<br>
Пружина / Нить — кликни 2 тела
</div>
</div><!-- /#dyn-sandbox-panel -->
</div><!-- /.proj-panel -->
<div class="proj-canvas-outer">
<canvas id="newton-canvas" style="display:none;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
<canvas id="sandbox-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<div class="proj-stats-bar" id="dyn-stats-bar">
<div class="pstat"><div class="pstat-label" id="dbar-l1">Тел</div><div class="pstat-val" id="dbar-v1" style="color:var(--cyan)">0</div></div>
<div class="pstat"><div class="pstat-label" id="dbar-l2">KE (Дж)</div><div class="pstat-val" id="dbar-v2" style="color:#4CC9F0">0</div></div>
<div class="pstat"><div class="pstat-label" id="dbar-l3">PE (Дж)</div><div class="pstat-val" id="dbar-v3" style="color:#7BF5A4">0</div></div>
<div class="pstat"><div class="pstat-label" id="dbar-l4">ΣF</div><div class="pstat-val" id="dbar-v4" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label" id="dbar-l5">Время</div><div class="pstat-val" id="dbar-v5" style="color:#FFD166">0 с</div></div>
</div>
</div><!-- /#sim-dynamics -->
<!-- ── PROJECTILE sim body ── -->
<div id="sim-proj" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<!-- controls panel -->
<div class="proj-panel" style="width:240px">
<div class="gp-section-title">Параметры</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Скорость v₀</span>
<span class="param-val" id="p-v0">20 м/с</span>
</div>
<input type="range" class="param-slider" id="sl-v0" min="1" max="100" value="20" oninput="projParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Угол θ</span>
<span class="param-val" id="p-angle">45°</span>
</div>
<input type="range" class="param-slider" id="sl-angle" min="0" max="90" value="45" oninput="projParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Высота h₀</span>
<span class="param-val" id="p-h0">2 м</span>
</div>
<input type="range" class="param-slider" id="sl-h0" min="0" max="50" value="2" oninput="projParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Сила тяжести g</span>
<span class="param-val" id="p-g">9.81 м/с²</span>
</div>
<input type="range" class="param-slider" id="sl-g" min="1" max="25" step="0.01" value="9.81" oninput="projParam()">
</div>
<!-- Air resistance -->
<div class="gp-section-title" style="margin-top:6px">Сопротивление воздуха</div>
<label class="tri-layer-row" id="drag-row" onclick="projToggleDrag(this)" style="margin-bottom:6px">
<span class="tri-dot" style="background:rgba(239,71,111,0.5)"></span>
<span class="tri-layer-name">Воздух</span>
<span class="tri-toggle" id="drag-toggle" style="background:rgba(255,255,255,0.12)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px"></span></span>
</label>
<div id="drag-params" style="display:none">
<div class="param-block">
<div class="param-header">
<span class="param-name">Коэф. Cd</span>
<span class="param-val" id="p-cd">0.30</span>
</div>
<input type="range" class="param-slider" id="sl-cd" min="1" max="100" value="30" oninput="projCdChange()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Масса тела m</span>
<span class="param-val" id="p-mass">1 кг</span>
</div>
<input type="range" class="param-slider" id="sl-mass" min="1" max="20" value="1" oninput="projMassChange()">
</div>
</div>
<!-- Wind -->
<div class="gp-section-title" style="margin-top:6px">Ветер</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Скорость ветра</span>
<span class="param-val" id="p-wind">0 м/с</span>
</div>
<input type="range" class="param-slider" id="sl-wind" min="-20" max="20" value="0" step="1" oninput="projWindChange()">
</div>
<!-- Bounce -->
<div class="gp-section-title" style="margin-top:6px">Отскок</div>
<label class="tri-layer-row" id="bounce-row" onclick="projToggleBounce(this)" style="margin-bottom:6px">
<span class="tri-dot" style="background:rgba(123,245,164,0.5)"></span>
<span class="tri-layer-name">Отскок при ударе</span>
<span class="tri-toggle" id="bounce-toggle" style="background:rgba(255,255,255,0.12)"><span style="display:block;width:12px;height:12px;border-radius:50%;background:#fff;margin:2px;margin-left:2px;transition:margin-left .15s"></span></span>
</label>
<div id="bounce-params" style="display:none">
<div class="param-block">
<div class="param-header">
<span class="param-name">Коэф. упругости e</span>
<span class="param-val" id="p-restitution">0.70</span>
</div>
<input type="range" class="param-slider" id="sl-restitution" min="0" max="100" value="70" oninput="projRestitutionChange()">
</div>
</div>
<div class="gp-section-title" style="margin-top:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:6px">
<button class="proj-preset-chip" onclick="projPreset(20,45,0,9.81)">Земля 45°</button>
<button class="proj-preset-chip" onclick="projPreset(20,30,0,9.81)">30°</button>
<button class="proj-preset-chip" onclick="projPreset(20,60,0,9.81)">60°</button>
<button class="proj-preset-chip" onclick="projPreset(20,45,15,9.81)">С высоты</button>
<button class="proj-preset-chip" onclick="projPreset(30,45,0,1.62)">Луна</button>
<button class="proj-preset-chip" onclick="projPreset(30,45,0,3.72)">Марс</button>
<button class="proj-preset-chip" onclick="projPreset(50,45,0,9.81)">Дальний</button>
<button class="proj-preset-chip" onclick="projPreset(20,90,0,9.81)">Вверх</button>
</div>
<!-- Speed -->
<div class="gp-section-title" style="margin-top:8px">Скорость симуляции</div>
<div style="display:flex;gap:5px;margin-bottom:8px">
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(0.25,this)" style="flex:1;font-size:.68rem">×0.25</button>
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(0.5,this)" style="flex:1;font-size:.68rem">×0.5</button>
<button class="mag-mode-btn proj-speed active" onclick="projSetSpeed(1,this)" style="flex:1;font-size:.68rem">×1</button>
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(2,this)" style="flex:1;font-size:.68rem">×2</button>
<button class="mag-mode-btn proj-speed" onclick="projSetSpeed(4,this)" style="flex:1;font-size:.68rem">×4</button>
</div>
<!-- Ghost trails -->
<div class="gp-section-title" style="margin-top:10px">Сравнение</div>
<div style="display:flex;gap:6px;flex-wrap:wrap">
<button class="proj-preset-chip" onclick="projSaveGhost()" style="border-color:rgba(255,214,102,.4);color:#FFD166">Зафиксировать</button>
<button class="proj-preset-chip" onclick="projClearGhosts()" style="border-color:rgba(255,255,255,.15)"><svg class="ic" viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Очистить следы</button>
</div>
<div style="font-size:.6rem;color:var(--text-3);margin-top:4px">Сохрани траекторию, измени параметры и сравни</div>
<!-- Feature 1: Target mode -->
<div class="gp-section-title" style="margin-top:10px">Режим целей</div>
<button id="proj-target-btn" class="proj-preset-chip" onclick="projToggleTargetMode()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>
<span>Режим целей: Выкл</span>
</button>
<div id="proj-target-panel" style="display:none;margin-top:6px">
<button class="proj-preset-chip" onclick="projGenTargets()" style="width:100%;text-align:center">
<svg class="ic" viewBox="0 0 24 24"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/></svg>
Новые цели
</button>
<div id="proj-target-hud" style="font-size:.72rem;font-weight:700;color:#FFD166;margin-top:6px;text-align:center">Цели: 0/3 Попыток: 0</div>
</div>
<!-- Feature 2: Graphs toggle -->
<div class="gp-section-title" style="margin-top:10px">Графики</div>
<button id="proj-graphs-btn" class="proj-preset-chip" onclick="projToggleGraphs()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
<svg class="ic" viewBox="0 0 24 24"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>
<span>x(t), y(t), vx(t), vy(t)</span>
</button>
<!-- Feature 3: Dual throw -->
<div class="gp-section-title" style="margin-top:10px">Двойной бросок</div>
<button id="proj-dual-btn" class="proj-preset-chip" onclick="projToggleDual()" style="width:100%;text-align:left;display:flex;align-items:center;gap:6px">
<svg class="ic" viewBox="0 0 24 24"><circle cx="8" cy="18" r="3"/><circle cx="18" cy="6" r="3"/><path d="M8 15V9l10-6"/></svg>
<span>Двойной: Выкл</span>
</button>
<div id="proj-dual-panel" style="display:none;margin-top:6px">
<div style="font-size:.65rem;color:rgba(0,230,255,.8);font-weight:700;margin-bottom:4px">Тело 2 (cyan)</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Скорость v₀₂</span>
<span class="param-val" id="p2-v0" style="color:#00E6FF">25 м/с</span>
</div>
<input type="range" class="param-slider proj-dual-slider" id="sl-p2-v0" min="1" max="100" value="25" oninput="projP2Param()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Угол θ₂</span>
<span class="param-val" id="p2-angle" style="color:#00E6FF">30°</span>
</div>
<input type="range" class="param-slider proj-dual-slider" id="sl-p2-angle" min="0" max="90" value="30" oninput="projP2Param()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Высота h₀₂</span>
<span class="param-val" id="p2-h0" style="color:#00E6FF">0 м</span>
</div>
<input type="range" class="param-slider proj-dual-slider" id="sl-p2-h0" min="0" max="50" value="0" oninput="projP2Param()">
</div>
</div>
<!-- LAUNCH BUTTON -->
<div style="margin-top:auto; padding-top:16px; display:flex; flex-direction:column; gap:8px;">
<button class="proj-launch-btn" id="proj-launch-main" onclick="projPlayPause()">
<svg id="proj-launch-icon" viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
<polygon points="5 3 19 12 5 21 5 3"/>
</svg>
<span id="proj-launch-label">Запустить</span>
</button>
<button class="proj-reset-btn" onclick="pSim && pSim.reset(); _projSyncPlayBtn()">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2">
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>
</svg>
Сброс
</button>
</div>
</div>
<!-- canvas -->
<div class="proj-canvas-outer">
<canvas id="proj-canvas"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<!-- graphs panel (Feature 2) -->
<div id="proj-graphs-panel" style="display:none;background:#05050e;border-top:1px solid rgba(255,255,255,.07)">
<canvas id="proj-graphs-canvas" class="proj-graphs-canvas"></canvas>
</div>
<!-- stats bar -->
<div class="proj-stats-bar">
<div class="pstat">
<div class="pstat-label">Дальность</div>
<div class="pstat-val" id="ps-range"></div>
</div>
<div class="pstat">
<div class="pstat-label">Макс. высота</div>
<div class="pstat-val" id="ps-hmax"></div>
</div>
<div class="pstat">
<div class="pstat-label">Время полёта</div>
<div class="pstat-val" id="ps-tf"></div>
</div>
<div class="pstat">
<div class="pstat-label">Скор. удара</div>
<div class="pstat-val" id="ps-vland"></div>
</div>
<div class="pstat">
<div class="pstat-label">Текущее t</div>
<div class="pstat-val" id="ps-t">0.00 с</div>
</div>
<div class="pstat">
<div class="pstat-label">Угол посадки</div>
<div class="pstat-val" id="ps-land-angle"></div>
</div>
<div class="pstat" id="ps-loss-wrap" style="display:none">
<div class="pstat-label">Δ дальность</div>
<div class="pstat-val" id="ps-loss"></div>
</div>
<!-- dual throw stats (Feature 3) -->
<div class="pstat" id="ps-p2-wrap" style="display:none">
<div class="pstat-label" style="color:rgba(0,230,255,.7)">Дальн.&#8202;2</div>
<div class="pstat-val" id="ps-p2-range" style="color:#00E6FF"></div>
</div>
<div class="pstat" id="ps-p2-tf-wrap" style="display:none">
<div class="pstat-label" style="color:rgba(0,230,255,.7)">Время&#8202;2</div>
<div class="pstat-val" id="ps-p2-tf" style="color:#00E6FF"></div>
</div>
</div>
</div><!-- /#sim-proj -->
<!-- ── COLLISION sim body ── -->
<div id="sim-coll" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<!-- controls panel -->
<div class="proj-panel" style="width:240px">
<div class="gp-section-title">Параметры</div>
<div class="param-block">
<div class="param-header">
<span class="param-name" style="color:var(--violet)">Масса m₁</span>
<span class="param-val" id="c-m1">4 кг</span>
</div>
<input type="range" class="param-slider" id="sl-m1" min="1" max="20" value="4" oninput="collParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name" style="color:var(--cyan)">Масса m₂</span>
<span class="param-val" id="c-m2">4 кг</span>
</div>
<input type="range" class="param-slider" id="sl-m2" min="1" max="20" value="4" oninput="collParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name" style="color:var(--violet)">Скорость v₁</span>
<span class="param-val" id="c-v1">8 м/с</span>
</div>
<input type="range" class="param-slider" id="sl-cv1" min="0" max="30" value="8" oninput="collParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name" style="color:var(--cyan)">Скорость v₂</span>
<span class="param-val" id="c-v2">8 м/с</span>
</div>
<input type="range" class="param-slider" id="sl-cv2" min="0" max="30" value="8" oninput="collParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Угол v₂</span>
<span class="param-val" id="c-angle"></span>
</div>
<input type="range" class="param-slider" id="sl-cangle" min="-60" max="60" value="0" oninput="collParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Упругость e</span>
<span class="param-val" id="c-e">1.00</span>
</div>
<input type="range" class="param-slider" id="sl-e" min="0" max="1" step="0.01" value="1" oninput="collParam()">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name"><svg class="ic" viewBox="0 0 24 24"><polygon points="13 19 22 12 13 5 13 19"/><polygon points="2 19 11 12 2 5 2 19"/></svg> Скорость</span>
<span class="param-val" id="c-speed" style="color:var(--cyan)">1.00×</span>
</div>
<input type="range" class="param-slider" id="sl-speed" min="0.1" max="4" step="0.05" value="1"
oninput="collParam()" style="--track-color:#06D6E0">
</div>
<div class="gp-section-title" style="margin-top:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:6px">
<button class="proj-preset-chip" onclick="collPreset(4,4,8,8,0,1)">Упругий 1:1</button>
<button class="proj-preset-chip" onclick="collPreset(4,4,8,8,0,0)">Абс. неупругий</button>
<button class="proj-preset-chip" onclick="collPreset(4,4,8,8,0,0.5)">e = 0.5</button>
<button class="proj-preset-chip" onclick="collPreset(4,4,12,0,0,1)">Бильярд</button>
<button class="proj-preset-chip" onclick="collPreset(2,8,14,0,0,1)">Лёгкий<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>тяжёлый</button>
<button class="proj-preset-chip" onclick="collPreset(8,2,6,0,0,1)">Тяжёлый<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>лёгкий</button>
<button class="proj-preset-chip" onclick="collPreset(2,14,18,0,0,1)">Большая разница</button>
<button class="proj-preset-chip" onclick="collPreset(5,5,8,8,30,1)">Косой 30°</button>
<button class="proj-preset-chip" onclick="collPreset(5,5,8,8,50,0.8)">Скользящий</button>
<button class="proj-preset-chip" onclick="collPreset(6,6,10,10,0,0)">Слипание</button>
</div>
<!-- launch button -->
<div style="margin-top:auto; padding-top:16px; display:flex; flex-direction:column; gap:8px;">
<button class="proj-launch-btn" id="coll-launch-main" onclick="collPlayPause()">
<svg id="coll-launch-icon" viewBox="0 0 24 24" width="20" height="20" fill="currentColor">
<polygon points="5 3 19 12 5 21 5 3"/>
</svg>
<span id="coll-launch-label">Запустить</span>
</button>
<button class="proj-reset-btn" onclick="cSim && cSim.reset(); _collSyncBtn()">
<svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2.2">
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/><path d="M3 3v5h5"/>
</svg>
Сброс
</button>
</div>
</div>
<!-- canvas -->
<div class="proj-canvas-outer">
<canvas id="coll-canvas"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
<!-- stats bar -->
<div class="proj-stats-bar">
<div class="pstat">
<div class="pstat-label">Импульс до</div>
<div class="pstat-val" id="cs-pbefore"></div>
</div>
<div class="pstat">
<div class="pstat-label">Импульс после</div>
<div class="pstat-val" id="cs-pafter"></div>
</div>
<div class="pstat">
<div class="pstat-label">КЭ до</div>
<div class="pstat-val" id="cs-kebefore"></div>
</div>
<div class="pstat">
<div class="pstat-label">КЭ после</div>
<div class="pstat-val" id="cs-keafter"></div>
</div>
<div class="pstat">
<div class="pstat-label">Столкновений</div>
<div class="pstat-val" id="cs-count">0</div>
</div>
</div>
</div><!-- /#sim-coll -->
<!-- ── CRYSTAL sim body ── -->
<div id="sim-crystal" class="sim-body-wrap" style="display:none">
<div class="graph-panel">
<div class="gp-section-title">Тип решётки</div>
<button class="gp-btn crystal-type-btn active" id="crys-nacl" onclick="setCrystal('nacl',this)" style="margin-bottom:6px"><svg class="ic" viewBox="0 0 24 24"><path d="M3 18a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V7H3z"/><path d="M3 7V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v2"/><path d="M12 11v4M10 13h4"/></svg> NaCl (ионная)</button>
<button class="gp-btn crystal-type-btn" id="crys-diamond" onclick="setCrystal('diamond',this)" style="margin-bottom:6px"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="display:inline-block;vertical-align:middle"><path d="M6 3l-3 7 9 11 9-11-3-7H6z"/><path d="M3 10h18"/><path d="M12 21L6 3"/><path d="M12 21l6-18"/></svg> Алмаз (ковалентная)</button>
<button class="gp-btn crystal-type-btn" id="crys-bcc" onclick="setCrystal('bcc',this)" style="margin-bottom:6px">ОЦК (металл)</button>
<button class="gp-btn crystal-type-btn" id="crys-fcc" onclick="setCrystal('fcc',this)" style="margin-bottom:6px">ГЦК (металл)</button>
<div class="gp-section-title" style="margin-top:12px">Управление</div>
<div class="tp-text" style="font-size:0.72rem">Вращение: зажмите и тяните<br>Зум: колёсико мыши</div>
</div>
<div class="graph-canvas-outer">
<div class="graph-canvas-wrap" id="crystal-container"></div>
</div>
</div>
<!-- ── ORBITALS sim body ── -->
<div id="sim-orbitals" class="sim-body-wrap" style="display:none">
<div class="graph-panel">
<div class="gp-section-title">Орбиталь</div>
<button class="gp-btn orbital-mode-btn active" id="orb-s" onclick="setOrbital('s',this)" style="margin-bottom:6px"<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#4CC9F0;margin-right:4px"></span>s-орбиталь</button>
<button class="gp-btn orbital-mode-btn" id="orb-p" onclick="setOrbital('p',this)" style="margin-bottom:6px"<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#06D6A0;margin-right:4px"></span>p-орбитали</button>
<button class="gp-btn orbital-mode-btn" id="orb-d" onclick="setOrbital('d',this)" style="margin-bottom:6px"<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:#FFD166;margin-right:4px"></span>d-орбитали</button>
<div class="gp-section-title" style="margin-top:12px">Молекулы</div>
<button class="gp-btn orbital-mode-btn" id="orb-h2" onclick="setOrbital('h2',this)" style="margin-bottom:6px">H₂ (σ-связь)</button>
<button class="gp-btn orbital-mode-btn" id="orb-h2o" onclick="setOrbital('h2o',this)" style="margin-bottom:6px">H₂O (угловая)</button>
<div class="gp-section-title" style="margin-top:12px">Управление</div>
<div class="tp-text" style="font-size:0.72rem">Вращение: зажмите и тяните<br>Зум: колёсико мыши</div>
</div>
<div class="graph-canvas-outer">
<div class="graph-canvas-wrap" id="orbitals-container"></div>
</div>
</div>
<!-- ── CHEM SANDBOX sim body ── -->
<div id="sim-chemsandbox" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<!-- Category filter -->
<div class="gp-section-title" style="margin-bottom:6px">Реагенты</div>
<div style="display:flex;flex-wrap:wrap;gap:3px;margin-bottom:10px">
<button class="proj-preset-chip reac-mode-btn chemsand-cat active" onclick="chemSandCat('all',this)">Все</button>
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('acid',this)">Кислоты</button>
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('base',this)">Основания</button>
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('salt',this)">Соли</button>
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('metal',this)">Металлы</button>
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('indicator',this)">Индикаторы</button>
<button class="proj-preset-chip reac-mode-btn chemsand-cat" onclick="chemSandCat('other',this)">Другое</button>
</div>
<!-- Reagent list -->
<div id="chemsand-reagents" style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px;max-height:180px;overflow-y:auto"></div>
<!-- Presets -->
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="proj-preset-chip" onclick="chemSandPreset('neutralization')">Нейтрализация</button>
<button class="proj-preset-chip" onclick="chemSandPreset('gas_evolution')">Газ CO₂</button>
<button class="proj-preset-chip" onclick="chemSandPreset('precipitate')">Осадок AgCl</button>
<button class="proj-preset-chip" onclick="chemSandPreset('displacement')">Замещение Cu</button>
<button class="proj-preset-chip" onclick="chemSandPreset('indicator')">Индикатор</button>
<button class="proj-preset-chip" onclick="chemSandPreset('violent')">Na + H₂O</button>
<button class="proj-preset-chip" onclick="chemSandPreset('yellow_precip')">PbCrO₄<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
<button class="proj-preset-chip" onclick="chemSandPreset('blue_precip')">Cu(OH)₂<svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><polyline points="19 12 12 19 5 12"/></svg></button>
</div>
<!-- Sliders -->
<div class="gp-section-title" style="margin-bottom:4px;margin-top:4px">Условия</div>
<div class="param-block" style="margin-bottom:5px">
<div class="param-header"><span class="param-name" style="font-size:.7rem">Концентрация</span><span class="param-val" id="csand-conc-val" style="font-size:.7rem;min-width:40px">35%</span></div>
<input type="range" class="param-slider" id="sl-csand-conc" min="5" max="95" value="35" oninput="chemSandConcChange()">
</div>
<div class="param-block" style="margin-bottom:5px">
<div class="param-header"><span class="param-name" style="font-size:.7rem">Температура</span><span class="param-val" id="csand-temp-val" style="font-size:.7rem;min-width:40px">20°C</span></div>
<input type="range" class="param-slider" id="sl-csand-temp" min="0" max="100" value="20" oninput="chemSandTempChange()">
</div>
<!-- Quiz mode -->
<div class="pp-group" style="margin-top:8px">
<div class="pp-label" style="font-size:.65rem">Режим</div>
<div style="display:flex;gap:6px;align-items:center">
<button class="proj-preset-chip reac-mode-btn chemsand-mode active" id="csand-mode-free" onclick="chemSandSetMode('free',this)">Свободный</button>
<button class="proj-preset-chip reac-mode-btn chemsand-mode" id="csand-mode-quiz" onclick="chemSandSetMode('quiz',this)">Задания</button>
<span id="csand-quiz-score" style="font-size:.7rem;color:rgba(255,255,255,.4);margin-left:8px"></span>
</div>
<div id="csand-quiz-question" style="display:none;margin-top:6px;padding:6px 10px;border-radius:8px;background:rgba(155,93,229,.10);border:1px solid rgba(155,93,229,.25);font-size:.72rem;color:#C9A0FF;line-height:1.3"></div>
<div id="csand-quiz-result" style="display:none;margin-top:4px;font-size:.72rem;font-weight:700"></div>
<button id="csand-quiz-next" style="display:none;margin-top:4px" class="proj-preset-chip" onclick="chemSandQuizNext()">Следующее задание</button>
</div>
<!-- Hint -->
<div class="tp-text" style="font-size:.65rem;opacity:.4;line-height:1.3">Клик на панели — добавить/убрать · Drag с полки в колбу · ПКМ — сбросить</div>
</div>
<div class="proj-canvas-outer">
<canvas id="chemsandbox-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:default"></canvas>
<!-- equation overlay: shown when reaction fires -->
<div id="chemsand-eq-overlay" class="chemsand-eq-overlay">
<div id="chemsand-eq-type" class="chemsand-eq-type"></div>
<div class="chemsand-eq-row chemsand-eq-row--mol">
<span class="chemsand-eq-label">Молекулярное</span>
<span id="chemsand-eq-mol" class="chemsand-eq-text chemsand-eq-text--mol"></span>
</div>
<div class="chemsand-eq-row chemsand-eq-row--full">
<span class="chemsand-eq-label">Полное ионное</span>
<span id="chemsand-eq-full" class="chemsand-eq-text chemsand-eq-text--full"></span>
</div>
<div class="chemsand-eq-row chemsand-eq-row--net">
<span class="chemsand-eq-label">Сокращённое ионное</span>
<span id="chemsand-eq-net" class="chemsand-eq-text chemsand-eq-text--net"></span>
</div>
</div>
</div>
</div>
<!-- Stats bar -->
<div class="proj-stats-bar" id="chemsand-stats-bar">
<div class="pstat"><div class="pstat-label">В зоне</div><div class="pstat-val" id="csbar-v1" style="color:var(--cyan)">0</div></div>
<div class="pstat"><div class="pstat-label">Тип</div><div class="pstat-val" id="csbar-v3" style="color:#7BF5A4"></div></div>
<div class="pstat"><div class="pstat-label">Уравнение</div><div class="pstat-val" id="csbar-v4" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">Сокр. ионное</div><div class="pstat-val" id="csbar-v6" style="color:#9BD4FF"></div></div>
<div class="pstat"><div class="pstat-label">Продукты</div><div class="pstat-val" id="csbar-v5" style="color:#4CC9F0"></div></div>
</div>
</div>
<!-- ── CELL DIVISION sim body ── -->
<div id="sim-celldivision" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:200px;gap:0">
<div class="gp-section-title" style="margin-bottom:6px">Режим</div>
<div style="display:flex;gap:4px;margin-bottom:12px">
<button class="proj-preset-chip reac-mode-btn cd-mode-btn active" onclick="cdSetMode('mitosis',this)">Митоз</button>
<button class="proj-preset-chip reac-mode-btn cd-mode-btn" onclick="cdSetMode('meiosis',this)">Мейоз</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Фазы</div>
<div id="cd-phase-dots" style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px"></div>
<div style="display:flex;gap:4px;margin-bottom:12px">
<button class="gp-btn" onclick="cdPrevPhase()" style="flex:1"><svg class="ic" viewBox="0 0 24 24"><polygon points="19 20 9 12 19 4 19 20"/></svg> Назад</button>
<button class="gp-btn" onclick="cdNextPhase()" style="flex:1">Далее <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg></button>
</div>
<button class="gp-btn" id="cd-auto-btn" onclick="cdAutoPlay(this)" style="width:100%;margin-bottom:10px"><svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> Авто</button>
<div class="pp-hint">Нажми фазу или используй кнопки для пошагового просмотра</div>
</div>
<div class="proj-canvas-outer">
<canvas id="celldiv-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="cdbar">
<div class="pstat"><div class="pstat-label">Фаза</div><div class="pstat-val" id="cdbar-v1" style="color:#7BF5A4"></div></div>
<div class="pstat"><div class="pstat-label">Хромосомы</div><div class="pstat-val" id="cdbar-v2" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">ДНК</div><div class="pstat-val" id="cdbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Шаг</div><div class="pstat-val" id="cdbar-v4" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="cdbar-v5" style="color:var(--violet)"></div></div>
</div>
</div>
<!-- ── PHOTOSYNTHESIS sim body ── -->
<div id="sim-photosynthesis" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:200px;gap:0">
<div class="gp-section-title" style="margin-bottom:6px">Процесс</div>
<div style="display:flex;gap:4px;margin-bottom:12px">
<button class="proj-preset-chip reac-mode-btn ps-mode-btn active" onclick="psSetMode('photo',this)">Фотосинтез</button>
<button class="proj-preset-chip reac-mode-btn ps-mode-btn" onclick="psSetMode('resp',this)">Дыхание</button>
</div>
<div class="gp-section-title" style="margin-bottom:4px">Интенсивность света</div>
<div class="sl-row" style="margin-bottom:10px">
<input type="range" id="sl-ps-light" min="0" max="100" value="70" oninput="psLightChange()" style="flex:1">
<span class="sl-val" id="ps-light-val">70%</span>
</div>
<div class="gp-section-title" style="margin-bottom:4px">Концентрация CO₂</div>
<div class="sl-row" style="margin-bottom:10px">
<input type="range" id="sl-ps-co2" min="0" max="100" value="50" oninput="psCO2Change()" style="flex:1">
<span class="sl-val" id="ps-co2-val">50%</span>
</div>
<button class="gp-btn" onclick="psReset()" style="width:100%;margin-top:4px"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сброс</button>
<div class="pp-hint" style="margin-top:10px">Меняй параметры и наблюдай за скоростью реакций</div>
</div>
<div class="proj-canvas-outer">
<canvas id="photosyn-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="psbar">
<div class="pstat"><div class="pstat-label">АТФ/с</div><div class="pstat-val" id="psbar-v1" style="color:#FFD166">0</div></div>
<div class="pstat"><div class="pstat-label">O₂ выд.</div><div class="pstat-val" id="psbar-v2" style="color:#7BF5A4">0</div></div>
<div class="pstat"><div class="pstat-label">CO₂ усв.</div><div class="pstat-val" id="psbar-v3" style="color:var(--cyan)">0</div></div>
<div class="pstat"><div class="pstat-label">КПД</div><div class="pstat-val" id="psbar-v4" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="psbar-v5" style="color:var(--violet)"></div></div>
</div>
</div>
<!-- ── ANGRY BIRDS sim body ── -->
<div id="sim-angrybirds" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:200px;gap:0">
<div class="gp-section-title" style="margin-bottom:6px">Уровень</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:6px" id="ab-level-btns">
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn active" onclick="abLevel(0,this)">1</button>
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(1,this)">2</button>
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(2,this)">3</button>
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(3,this)">4</button>
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(4,this)">5</button>
<button class="proj-preset-chip reac-mode-btn ab-lvl-btn" onclick="abLevel(5,this)">6</button>
</div>
<button onclick="angryBirdsRestart()" style="width:100%;padding:6px 10px;border-radius:8px;border:1.5px solid rgba(255,255,255,.15);background:rgba(255,255,255,.06);color:#e0e0e0;font-size:.76rem;font-weight:700;cursor:pointer;margin-bottom:12px" title="Начать уровень заново"><svg class="ic" viewBox="0 0 24 24"><polyline points="1 4 1 10 7 10"/><path d="M3.51 15a9 9 0 1 0 .49-4.12"/></svg> Сначала</button>
<div class="gp-section-title" style="margin-bottom:6px">Планеты</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg> Земля</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">9.81 м/с²</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="currentColor" stroke="none"/></svg> Луна</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">1.62 м/с²</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="currentColor" stroke="none"/></svg> Марс</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">3.71 м/с²</span>
</div>
<div style="display:flex;justify-content:space-between;align-items:center;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="font-size:.75rem;color:#e0e0e0"><svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="currentColor" stroke="none"/></svg> Юпитер</span><span style="font-size:.72rem;color:var(--cyan);font-weight:700">24.8 м/с²</span>
</div>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Птицы</div>
<div style="display:flex;flex-direction:column;gap:5px;margin-bottom:14px">
<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="width:14px;height:14px;border-radius:50%;background:#e63946;flex-shrink:0;display:inline-block"></span>
<span style="font-size:.73rem;color:#e0e0e0">Красная — обычная</span>
</div>
<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="width:14px;height:14px;border-radius:50%;background:#888;flex-shrink:0;display:inline-block"></span>
<span style="font-size:.73rem;color:#e0e0e0">Тяжёлая — высокий урон</span>
</div>
<div style="display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:7px;background:rgba(255,255,255,.06)">
<span style="width:14px;height:14px;border-radius:50%;background:#ffd166;flex-shrink:0;display:inline-block"></span>
<span style="font-size:.73rem;color:#e0e0e0">Жёлтая — быстрая</span>
</div>
</div>
<div class="pp-hint">Тяни птицу мышью · отпусти — выстрел</div>
</div>
<div class="proj-canvas-outer">
<canvas id="angrybirds-canvas" style="display:block;position:absolute;top:0;left:0;width:100%;height:100%;cursor:crosshair"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="abbar">
<div class="pstat"><div class="pstat-label">Уровень</div><div class="pstat-val" id="abbar-v1" style="color:var(--cyan)">1</div></div>
<div class="pstat"><div class="pstat-label">Птиц</div><div class="pstat-val" id="abbar-v2" style="color:#ffd166">3</div></div>
<div class="pstat"><div class="pstat-label">Свиней</div><div class="pstat-val" id="abbar-v3" style="color:#7bf5a4">1</div></div>
<div class="pstat"><div class="pstat-label">Очки</div><div class="pstat-val" id="abbar-v4" style="color:#ef476f">0</div></div>
<div class="pstat"><div class="pstat-label">Планета</div><div class="pstat-val" id="abbar-v5" style="color:var(--violet)">Земля <svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="2" y1="12" x2="22" y2="12"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/></svg></div></div>
</div>
</div>
<!-- ── QUADRATIC sim body ── -->
<div id="sim-quadratic" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Коэффициенты</div>
<div class="proj-slider-row" style="margin-bottom:10px">
<label style="font-size:.78rem;color:#ccc;width:60px">a = <span id="quad-a-val" style="color:var(--violet);font-weight:700">1</span></label>
<input type="range" id="sl-quad-a" min="-5" max="5" step="0.1" value="1" oninput="quadParam('a',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:10px">
<label style="font-size:.78rem;color:#ccc;width:60px">b = <span id="quad-b-val" style="color:var(--cyan);font-weight:700">0</span></label>
<input type="range" id="sl-quad-b" min="-10" max="10" step="0.1" value="0" oninput="quadParam('b',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:10px">
<label style="font-size:.78rem;color:#ccc;width:60px">c = <span id="quad-c-val" style="color:var(--pink);font-weight:700">-1</span></label>
<input type="range" id="sl-quad-c" min="-10" max="10" step="0.1" value="-1" oninput="quadParam('c',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Примеры</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn" onclick="quadPreset(1,0,-4)">x²−4</button>
<button class="preset-btn" onclick="quadPreset(1,-2,1)">(x1)²</button>
<button class="preset-btn" onclick="quadPreset(1,0,1)">x²+1</button>
<button class="preset-btn" onclick="quadPreset(-1,0,4)">x²+4</button>
<button class="preset-btn" onclick="quadPreset(2,-3,-2)">2x²−3x2</button>
<button class="preset-btn" onclick="quadPreset(0.5,1,-3)">½x²+x3</button>
</div>
<div class="pp-hint">Скролл — зум · Тащи — панорама</div>
</div>
<div class="proj-canvas-outer">
<canvas id="quadratic-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="quadbar">
<div class="pstat"><div class="pstat-label">Дискриминант</div><div class="pstat-val" id="qbar-v1" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Корни</div><div class="pstat-val" id="qbar-v2" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">Вершина</div><div class="pstat-val" id="qbar-v3" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">Уравнение</div><div class="pstat-val" id="qbar-v4" style="color:var(--violet)"></div></div>
</div>
</div>
<!-- ── NORMAL DISTRIBUTION sim body ── -->
<div id="sim-normaldist" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:10px">
<label style="font-size:.78rem;color:#ccc;width:60px">μ = <span id="nd-mu-val" style="color:var(--cyan);font-weight:700">0</span></label>
<input type="range" id="sl-nd-mu" min="-5" max="5" step="0.1" value="0" oninput="ndParam('mu',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:10px">
<label style="font-size:.78rem;color:#ccc;width:60px">σ = <span id="nd-sigma-val" style="color:var(--violet);font-weight:700">1</span></label>
<input type="range" id="sl-nd-sigma" min="0.2" max="4" step="0.1" value="1" oninput="ndParam('sigma',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Закрасить область</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn nd-shade-btn active" onclick="ndShade('1s',this)">μ ± 1σ</button>
<button class="preset-btn nd-shade-btn" onclick="ndShade('2s',this)">μ ± 2σ</button>
<button class="preset-btn nd-shade-btn" onclick="ndShade('3s',this)">μ ± 3σ</button>
<button class="preset-btn nd-shade-btn" onclick="ndShade('none',this)">Нет</button>
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn" onclick="ndPreset(0,1)">Стандартное</button>
<button class="preset-btn" onclick="ndPreset(0,0.5)">Узкое σ=0.5</button>
<button class="preset-btn" onclick="ndPreset(0,2)">Широкое σ=2</button>
<button class="preset-btn" onclick="ndPreset(3,1)">Сдвиг μ=3</button>
</div>
<div class="pp-hint">Наведи курсор — Z-score и плотность</div>
</div>
<div class="proj-canvas-outer">
<canvas id="normaldist-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="ndbar">
<div class="pstat"><div class="pstat-label">μ</div><div class="pstat-val" id="ndbar-v1" style="color:var(--cyan)">0</div></div>
<div class="pstat"><div class="pstat-label">σ</div><div class="pstat-val" id="ndbar-v2" style="color:var(--violet)">1</div></div>
<div class="pstat"><div class="pstat-label">Пик f(μ)</div><div class="pstat-val" id="ndbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Область</div><div class="pstat-val" id="ndbar-v4" style="color:#7BF5A4"></div></div>
</div>
</div>
<!-- ── GRAPH TRANSFORM sim body ── -->
<div id="sim-graphtransform" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:230px;gap:0">
<div class="gp-section-title" style="margin-bottom:6px">Базовая функция f(x)</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:12px">
<button class="preset-btn gt-base-btn active" onclick="gtBase('sin',this)">sin x</button>
<button class="preset-btn gt-base-btn" onclick="gtBase('cos',this)">cos x</button>
<button class="preset-btn gt-base-btn" onclick="gtBase('x^2',this)"></button>
<button class="preset-btn gt-base-btn" onclick="gtBase('x^3',this)"></button>
<button class="preset-btn gt-base-btn" onclick="gtBase('sqrt',this)">√x</button>
<button class="preset-btn gt-base-btn" onclick="gtBase('|x|',this)">|x|</button>
<button class="preset-btn gt-base-btn" onclick="gtBase('1/x',this)">1/x</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">y = a · f(k·x + b) + c</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">a = <span id="gt-a-val" style="color:var(--violet);font-weight:700">1</span></label>
<input type="range" id="sl-gt-a" min="-3" max="3" step="0.1" value="1" oninput="gtParam('a',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">k = <span id="gt-k-val" style="color:var(--cyan);font-weight:700">1</span></label>
<input type="range" id="sl-gt-k" min="-3" max="3" step="0.1" value="1" oninput="gtParam('k',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">b = <span id="gt-b-val" style="color:#FFD166;font-weight:700">0</span></label>
<input type="range" id="sl-gt-b" min="-5" max="5" step="0.1" value="0" oninput="gtParam('b',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">c = <span id="gt-c-val" style="color:#EF476F;font-weight:700">0</span></label>
<input type="range" id="sl-gt-c" min="-5" max="5" step="0.1" value="0" oninput="gtParam('c',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Эффекты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="gtEffect(2,1,0,0)">Растяжение <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="21" x2="12" y2="3"/><polyline points="7 8 12 3 17 8"/><polyline points="17 16 12 21 7 16"/></svg></button>
<button class="preset-btn" onclick="gtEffect(1,2,0,0)">Сжатие <svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><polyline points="8 17 3 12 8 7"/><polyline points="16 7 21 12 16 17"/></svg></button>
<button class="preset-btn" onclick="gtEffect(-1,1,0,0)">Отражение <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="21" x2="12" y2="3"/><polyline points="7 8 12 3 17 8"/><polyline points="17 16 12 21 7 16"/></svg></button>
<button class="preset-btn" onclick="gtEffect(1,-1,0,0)">Отражение <svg class="ic" viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><polyline points="8 17 3 12 8 7"/><polyline points="16 7 21 12 16 17"/></svg></button>
<button class="preset-btn" onclick="gtEffect(1,1,2,0)">Сдвиг <svg class="ic" viewBox="0 0 24 24"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg></button>
<button class="preset-btn" onclick="gtEffect(1,1,0,3)">Сдвиг <svg class="ic" viewBox="0 0 24 24"><line x1="12" y1="19" x2="12" y2="5"/><polyline points="5 12 12 5 19 12"/></svg></button>
</div>
<button class="preset-btn" onclick="gtEffect(1,1,0,0)" style="width:100%;margin-top:4px">Сброс</button>
<div class="pp-hint">Скролл — зум · Тащи — панорама</div>
</div>
<div class="proj-canvas-outer">
<canvas id="graphtransform-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="gtbar">
<div class="pstat"><div class="pstat-label">f(x)</div><div class="pstat-val" id="gtbar-v1" style="color:var(--cyan)">sin(x)</div></div>
<div class="pstat"><div class="pstat-label">a</div><div class="pstat-val" id="gtbar-v2" style="color:var(--violet)">1</div></div>
<div class="pstat"><div class="pstat-label">k</div><div class="pstat-val" id="gtbar-v3" style="color:var(--cyan)">1</div></div>
<div class="pstat"><div class="pstat-label">b</div><div class="pstat-val" id="gtbar-v4" style="color:#FFD166">0</div></div>
<div class="pstat"><div class="pstat-label">c</div><div class="pstat-val" id="gtbar-v5" style="color:#EF476F">0</div></div>
</div>
</div>
<!-- ── PENDULUM sim body ── -->
<div id="sim-pendulum" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">θ = <span id="pend-theta-val" style="color:var(--violet);font-weight:700">45</span>°</label>
<input type="range" id="sl-pend-theta" min="5" max="170" step="1" value="45" oninput="pendParam('theta',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">L = <span id="pend-L-val" style="color:var(--cyan);font-weight:700">200</span></label>
<input type="range" id="sl-pend-L" min="60" max="300" step="5" value="200" oninput="pendParam('L',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">g = <span id="pend-g-val" style="color:#FFD166;font-weight:700">9.81</span></label>
<input type="range" id="sl-pend-g" min="1" max="25" step="0.1" value="9.81" oninput="pendParam('g',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:70px">Затух. <span id="pend-damp-val" style="color:#EF476F;font-weight:700">0</span></label>
<input type="range" id="sl-pend-damp" min="0" max="2" step="0.05" value="0" oninput="pendParam('damping',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="pendPreset(45,200,9.81,0)">Земля</button>
<button class="preset-btn" onclick="pendPreset(45,200,1.62,0)">Луна</button>
<button class="preset-btn" onclick="pendPreset(170,200,9.81,0)">Большой θ</button>
<button class="preset-btn" onclick="pendPreset(45,200,9.81,0.5)">Затухание</button>
</div>
<div class="pp-hint">Тащи грузик мышью для установки угла</div>
</div>
<div class="proj-canvas-outer">
<canvas id="pendulum-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="pendbar">
<div class="pstat"><div class="pstat-label">Угол</div><div class="pstat-val" id="pendbar-v1" style="color:var(--violet)">45°</div></div>
<div class="pstat"><div class="pstat-label">ω</div><div class="pstat-val" id="pendbar-v2" style="color:var(--cyan)">0</div></div>
<div class="pstat"><div class="pstat-label">Период T</div><div class="pstat-val" id="pendbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Энергия</div><div class="pstat-val" id="pendbar-v4" style="color:#EF476F"></div></div>
</div>
</div>
<!-- ── EQUILIBRIUM sim body ── -->
<div id="sim-equilibrium" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">T = <span id="eq-T-val" style="color:#FFD166;font-weight:700">300</span> K</label>
<input type="range" id="sl-eq-T" min="200" max="500" step="10" value="300" oninput="eqParam('T',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">Ea<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg> <span id="eq-Eaf-val" style="color:#7BF5A4;font-weight:700">50</span></label>
<input type="range" id="sl-eq-Eaf" min="20" max="80" step="1" value="50" oninput="eqParam('Ea_f',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">Ea<svg class="ic" viewBox="0 0 24 24"><line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/></svg> <span id="eq-Ear-val" style="color:#EF476F;font-weight:700">55</span></label>
<input type="range" id="sl-eq-Ear" min="20" max="80" step="1" value="55" oninput="eqParam('Ea_r',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="eqPreset('default')">По умолч.</button>
<button class="preset-btn" onclick="eqPreset('exothermic')">Экзо</button>
<button class="preset-btn" onclick="eqPreset('endothermic')">Эндо</button>
<button class="preset-btn" onclick="eqPreset('excess_A')">Избыток A</button>
</div>
<div class="pp-hint">A + B ⇌ C + D — принцип Ле Шателье</div>
</div>
<div class="proj-canvas-outer">
<canvas id="equilibrium-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="eqbar">
<div class="pstat"><div class="pstat-label">Keq</div><div class="pstat-val" id="eqbar-v1" style="color:#7BF5A4"></div></div>
<div class="pstat"><div class="pstat-label">Q</div><div class="pstat-val" id="eqbar-v2" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Направление</div><div class="pstat-val" id="eqbar-v3" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">A|B|C|D</div><div class="pstat-val" id="eqbar-v4" style="color:var(--violet)"></div></div>
</div>
</div>
<!-- ── THIN LENS sim body ── -->
<div id="sim-thinlens" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">f = <span id="lens-f-val" style="color:var(--cyan);font-weight:700">100</span></label>
<input type="range" id="sl-lens-f" min="-200" max="200" step="5" value="100" oninput="lensParam('f',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">d = <span id="lens-d-val" style="color:var(--violet);font-weight:700">200</span></label>
<input type="range" id="sl-lens-d" min="30" max="400" step="5" value="200" oninput="lensParam('d',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">h = <span id="lens-h-val" style="color:#EF476F;font-weight:700">50</span></label>
<input type="range" id="sl-lens-h" min="20" max="80" step="2" value="50" oninput="lensParam('h',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="lensPreset(100,200,50)">Собирающая</button>
<button class="preset-btn" onclick="lensPreset(-100,200,50)">Рассеивающая</button>
<button class="preset-btn" onclick="lensPreset(100,100,50)">d = f</button>
<button class="preset-btn" onclick="lensPreset(100,60,50)">d &lt; f</button>
</div>
<div class="pp-hint">Тащи стрелку-предмет или фокус мышью</div>
</div>
<div class="proj-canvas-outer">
<canvas id="thinlens-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="lensbar">
<div class="pstat"><div class="pstat-label">f</div><div class="pstat-val" id="lensbar-v1" style="color:var(--cyan)">100</div></div>
<div class="pstat"><div class="pstat-label">d'</div><div class="pstat-val" id="lensbar-v2" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">M</div><div class="pstat-val" id="lensbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Тип</div><div class="pstat-val" id="lensbar-v4" style="color:var(--violet)"></div></div>
</div>
</div>
<!-- ── MIRRORS sim body ── -->
<div id="sim-mirrors" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:264px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Тип зеркала</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn mirror-type-btn" id="mtype-flat" onclick="mirrorType('flat',this)" style="font-size:.72rem">Плоское</button>
<button class="preset-btn mirror-type-btn active" id="mtype-concave" onclick="mirrorType('concave',this)" style="font-size:.72rem">Вогнутое</button>
<button class="preset-btn mirror-type-btn" id="mtype-convex" onclick="mirrorType('convex',this)" style="font-size:.72rem">Выпуклое</button>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px" id="mirror-f-row">
<label style="font-size:.78rem;color:#ccc;width:60px">f = <span id="mirror-f-val" style="color:var(--cyan);font-weight:700">120</span></label>
<input type="range" id="sl-mirror-f" min="30" max="300" step="5" value="120" oninput="mirrorParam('f',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:60px">d = <span id="mirror-d-val" style="color:var(--violet);font-weight:700">240</span></label>
<input type="range" id="sl-mirror-d" min="30" max="500" step="5" value="240" oninput="mirrorParam('d',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:60px">h = <span id="mirror-h-val" style="color:#EF476F;font-weight:700">60</span></label>
<input type="range" id="sl-mirror-h" min="20" max="80" step="2" value="60" oninput="mirrorParam('h',this.value)" style="flex:1">
</div>
<div style="display:flex;gap:6px;margin-top:8px;margin-bottom:8px;align-items:center">
<button id="mirror-play-btn" onclick="mirrorTogglePlay(this)" style="flex:1;padding:6px 0;border-radius:8px;border:none;background:linear-gradient(135deg,var(--cyan),var(--violet));color:#fff;font-size:.78rem;font-weight:700;cursor:pointer">▶ Анимация</button>
<div style="display:flex;flex-direction:column;align-items:center;gap:2px">
<span style="font-size:.62rem;color:#888">скорость</span>
<select id="mirror-speed-sel" onchange="mirrorSetSpeed(this.value)" style="background:#1a1a2e;color:#ccc;border:1px solid #333;border-radius:4px;font-size:.7rem;padding:2px 4px">
<option value="0.25">×¼</option><option value="0.5">×½</option>
<option value="1" selected>×1</option><option value="2">×2</option>
</select>
</div>
</div>
<div style="display:flex;gap:4px;margin-bottom:10px">
<button onclick="mirrorStepNext()" style="flex:1;padding:5px 0;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#7BF5A4;font-size:.73rem;cursor:pointer" title="Показать следующий луч">① Пошагово</button>
<button onclick="mirrorStepReset()" style="padding:5px 9px;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.78rem;cursor:pointer" title="Показать все лучи"></button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Отображение</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:3px 10px;margin-bottom:10px">
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-normals" checked onchange="mirrorToggle('normals',this.checked)"> Нормали</label>
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-dims" checked onchange="mirrorToggle('dims',this.checked)"> Размеры</label>
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-angles" checked onchange="mirrorToggle('angles',this.checked)"> Углы θ</label>
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-photons" checked onchange="mirrorToggle('photons',this.checked)"> Фотоны</label>
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-grid" onchange="mirrorToggle('grid',this.checked)"> Сетка</label>
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer"><input type="checkbox" id="mtog-zones" checked onchange="mirrorToggle('zones',this.checked)"> Зоны</label>
<label style="display:flex;align-items:center;gap:4px;font-size:.72rem;color:#ccc;cursor:pointer;grid-column:span 2"><input type="checkbox" id="mtog-point" onchange="mirrorSetPointMode(this.checked)"> Точечный объект</label>
</div>
<button onclick="if(mirrorSim)mirrorSim.exportPng()" style="width:100%;padding:5px 0;border-radius:6px;border:1px solid #333;background:#1a1a2e;color:#888;font-size:.72rem;cursor:pointer;margin-bottom:8px"><svg class="ic" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg> Экспорт PNG</button>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="mirrorPreset('flat')">Плоское</button>
<button class="preset-btn" onclick="mirrorPreset('far')">d &gt; 2f</button>
<button class="preset-btn" onclick="mirrorPreset('2f')">d = 2f</button>
<button class="preset-btn" onclick="mirrorPreset('between')">f &lt; d &lt; 2f</button>
<button class="preset-btn" onclick="mirrorPreset('near')">d &lt; f</button>
<button class="preset-btn" onclick="mirrorPreset('convex')">Выпуклое</button>
</div>
<div class="pp-hint">Тащи предмет, фокус или изображение мышью</div>
</div>
<div class="proj-canvas-outer">
<canvas id="mirror-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="mirrorbar">
<div class="pstat"><div class="pstat-label">f</div><div class="pstat-val" id="mirrorbar-v1" style="color:var(--cyan)">120</div></div>
<div class="pstat"><div class="pstat-label">d</div><div class="pstat-val" id="mirrorbar-v5" style="color:var(--violet)">240</div></div>
<div class="pstat"><div class="pstat-label">d'</div><div class="pstat-val" id="mirrorbar-v2" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">M</div><div class="pstat-val" id="mirrorbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Тип изобр.</div><div class="pstat-val" id="mirrorbar-v4" style="color:var(--violet)"></div></div>
</div>
</div>
<!-- ── ISOPROCESS sim body ── -->
<div id="sim-isoprocess" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Процесс</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn iso-proc-btn active" id="iproc-isothermal" onclick="isoProc('isothermal',this)" style="font-size:.72rem">Изотерма</button>
<button class="preset-btn iso-proc-btn" id="iproc-isochoric" onclick="isoProc('isochoric',this)" style="font-size:.72rem">Изохора</button>
<button class="preset-btn iso-proc-btn" id="iproc-isobaric" onclick="isoProc('isobaric',this)" style="font-size:.72rem">Изобара</button>
<button class="preset-btn iso-proc-btn" id="iproc-adiabatic" onclick="isoProc('adiabatic',this)" style="font-size:.72rem">Адиабата</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Газ γ</div>
<div style="display:flex;gap:4px;margin-bottom:10px">
<button class="preset-btn iso-gamma-btn" id="igamma-14" onclick="isoGamma(1.4,this)" style="font-size:.72rem">Двухат. 1.4</button>
<button class="preset-btn iso-gamma-btn active" id="igamma-167" onclick="isoGamma(1.667,this)" style="font-size:.72rem">Одноат. 5/3</button>
</div>
<div class="gp-section-title" style="margin-bottom:8px">Начальное состояние</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:70px">P₁ = <span id="iso-p1-val" style="color:var(--violet);font-weight:700">3.0</span></label>
<input type="range" id="sl-iso-p1" min="0.5" max="8" step="0.1" value="3.0" oninput="isoParam('P1',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:70px">V₁ = <span id="iso-v1-val" style="color:var(--violet);font-weight:700">10</span></label>
<input type="range" id="sl-iso-v1" min="2" max="28" step="1" value="10" oninput="isoParam('V1',this.value)" style="flex:1">
</div>
<div class="gp-section-title" style="margin-bottom:8px">Конечное состояние</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:70px;white-space:nowrap">Сжат./расш.</label>
<input type="range" id="sl-iso-ratio" min="0.01" max="0.99" step="0.01" value="0.5" oninput="isoRatio(this.value)" style="flex:1">
</div>
<div style="margin-top:6px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="isoPreset('iso_expand')">Изотерма расш.</button>
<button class="preset-btn" onclick="isoPreset('iso_comp')">Изотерма сжат.</button>
<button class="preset-btn" onclick="isoPreset('heat_iso')">Изохора нагрев</button>
<button class="preset-btn" onclick="isoPreset('adiab_exp')">Адиабата расш.</button>
</div>
<div class="pp-hint">Тащи точки 1 и 2 по диаграмме</div>
</div>
<div class="proj-canvas-outer">
<canvas id="isoprocess-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="isobar">
<div class="pstat"><div class="pstat-label">T₁, K</div><div class="pstat-val" id="isobar-t1" style="color:var(--violet)"></div></div>
<div class="pstat"><div class="pstat-label">T₂, K</div><div class="pstat-val" id="isobar-t2" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">W, Дж</div><div class="pstat-val" id="isobar-w" style="color:#7BF5A4"></div></div>
<div class="pstat"><div class="pstat-label">Q, Дж</div><div class="pstat-val" id="isobar-q" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">ΔU, Дж</div><div class="pstat-val" id="isobar-du" style="color:#EF476F"></div></div>
</div>
</div>
<!-- ── TITRATION sim body ── -->
<div id="sim-titration" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:75px">C(кисл) <span id="titr-ac-val" style="color:#EF476F;font-weight:700">0.10</span> М</label>
<input type="range" id="sl-titr-ac" min="0.05" max="1" step="0.05" value="0.1" oninput="titrParam('acidConc',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:75px">C(осн) <span id="titr-bc-val" style="color:var(--violet);font-weight:700">0.10</span> М</label>
<input type="range" id="sl-titr-bc" min="0.05" max="1" step="0.05" value="0.1" oninput="titrParam('baseConc',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:75px">V(кисл) <span id="titr-vol-val" style="color:var(--cyan);font-weight:700">50</span> мл</label>
<input type="range" id="sl-titr-vol" min="25" max="100" step="5" value="50" oninput="titrParam('acidVol',this.value)" style="flex:1">
</div>
<div style="margin-top:4px;margin-bottom:8px">
<div class="gp-section-title" style="margin-bottom:4px">Индикатор</div>
<div style="display:flex;flex-wrap:wrap;gap:4px">
<button class="preset-btn titr-ind-btn active" onclick="titrIndicator('phenolphthalein',this)" style="font-size:.72rem">Фенолф.</button>
<button class="preset-btn titr-ind-btn" onclick="titrIndicator('methyl_orange',this)" style="font-size:.72rem">Метилор.</button>
<button class="preset-btn titr-ind-btn" onclick="titrIndicator('litmus',this)" style="font-size:.72rem">Лакмус</button>
</div>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="titrPreset('strong_strong')">HCl+NaOH</button>
<button class="preset-btn" onclick="titrPreset('weak_strong')">CH₃COOH</button>
<button class="preset-btn" onclick="titrPreset('concentrated')">Конц.</button>
</div>
<div class="pp-hint">Нажми <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> — основание добавляется каплями</div>
</div>
<div class="proj-canvas-outer">
<canvas id="titration-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="titrbar">
<div class="pstat"><div class="pstat-label">pH</div><div class="pstat-val" id="titrbar-v1" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">Добавлено</div><div class="pstat-val" id="titrbar-v2" style="color:var(--violet)">0.0 мл</div></div>
<div class="pstat"><div class="pstat-label">Точка экв.</div><div class="pstat-val" id="titrbar-v3" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">Тип</div><div class="pstat-val" id="titrbar-v4" style="color:#FFD166"></div></div>
</div>
</div>
<!-- ── REFRACTION sim body ── -->
<div id="sim-refraction" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">n₁ = <span id="refr-n1-val" style="color:var(--violet);font-weight:700">1.00</span></label>
<input type="range" id="sl-refr-n1" min="1" max="2.5" step="0.01" value="1" oninput="refrParam('n1',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">n₂ = <span id="refr-n2-val" style="color:var(--cyan);font-weight:700">1.50</span></label>
<input type="range" id="sl-refr-n2" min="1" max="2.5" step="0.01" value="1.5" oninput="refrParam('n2',this.value)" style="flex:1">
</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">θ = <span id="refr-angle-val" style="color:#FFD166;font-weight:700">30</span>°</label>
<input type="range" id="sl-refr-angle" min="0" max="89" step="1" value="30" oninput="refrParam('angle',this.value)" style="flex:1">
</div>
<div style="margin-top:8px"></div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="refrPreset(1,1.5,30)">Воздух<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>Стекло</button>
<button class="preset-btn" onclick="refrPreset(1.5,1,30)">Стекло<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>Воздух</button>
<button class="preset-btn" onclick="refrPreset(1.33,1.5,30)">Вода<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>Стекло</button>
<button class="preset-btn" onclick="refrPreset(1,2.42,45)">Алмаз</button>
</div>
<div class="pp-hint">Тащи луч мышью для изменения угла</div>
</div>
<div class="proj-canvas-outer">
<canvas id="refraction-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="refrbar">
<div class="pstat"><div class="pstat-label">θ₁</div><div class="pstat-val" id="refrbar-v1" style="color:var(--violet)">30°</div></div>
<div class="pstat"><div class="pstat-label">θ₂</div><div class="pstat-val" id="refrbar-v2" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">Крит. угол</div><div class="pstat-val" id="refrbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">ПВО</div><div class="pstat-val" id="refrbar-v4" style="color:#EF476F">Нет</div></div>
</div>
</div>
<!-- ── PROBABILITY sim body ── -->
<div id="sim-probability" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Режим</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn prob-mode-btn active" onclick="probMode('coin',this)">Монета</button>
<button class="preset-btn prob-mode-btn" onclick="probMode('dice',this)">Кубик</button>
<button class="preset-btn prob-mode-btn" onclick="probMode('dice2',this)">2 кубика</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="probPreset('coin',100)">100 бросков</button>
<button class="preset-btn" onclick="probPreset('coin',1000)">1000</button>
<button class="preset-btn" onclick="probPreset('dice',100)">Кубик ×100</button>
<button class="preset-btn" onclick="probPreset('dice2',500)">2 куб. ×500</button>
</div>
<div class="pp-hint">Нажми <svg class="ic" viewBox="0 0 24 24"><polygon points="5 3 19 12 5 21 5 3"/></svg> — броски идут автоматически</div>
</div>
<div class="proj-canvas-outer">
<canvas id="probability-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="probbar">
<div class="pstat"><div class="pstat-label">Бросков</div><div class="pstat-val" id="probbar-v1" style="color:var(--violet)">0</div></div>
<div class="pstat"><div class="pstat-label">Макс. отклон.</div><div class="pstat-val" id="probbar-v2" style="color:#EF476F"></div></div>
<div class="pstat"><div class="pstat-label">χ²</div><div class="pstat-val" id="probbar-v3" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">Режим</div><div class="pstat-val" id="probbar-v4" style="color:#FFD166">Монета</div></div>
</div>
</div>
<!-- ── BOHR ATOM sim body ── -->
<div id="sim-bohratom" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Уровень</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn" onclick="bohrLevel(1)">n=1</button>
<button class="preset-btn" onclick="bohrLevel(2)">n=2</button>
<button class="preset-btn" onclick="bohrLevel(3)">n=3</button>
<button class="preset-btn" onclick="bohrLevel(4)">n=4</button>
<button class="preset-btn" onclick="bohrLevel(5)">n=5</button>
<button class="preset-btn" onclick="bohrLevel(6)">n=6</button>
</div>
<div class="gp-section-title" style="margin-bottom:6px">Переходы</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:8px">
<button class="preset-btn" onclick="bohrTransition(2,1)">2<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>1 (УФ)</button>
<button class="preset-btn" onclick="bohrTransition(3,2)">3<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>2 (красн.)</button>
<button class="preset-btn" onclick="bohrTransition(4,2)">4<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>2 (голуб.)</button>
<button class="preset-btn" onclick="bohrTransition(4,3)">4<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>3 (ИК)</button>
<button class="preset-btn" onclick="bohrTransition(1,3)">1<svg class="ic" viewBox="0 0 24 24"><line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/></svg>3 (поглощ.)</button>
</div>
<div class="pp-hint">Кликни на уровень для перехода электрона</div>
</div>
<div class="proj-canvas-outer">
<canvas id="bohratom-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="bohrbar">
<div class="pstat"><div class="pstat-label">Уровень n</div><div class="pstat-val" id="bohrbar-v1" style="color:var(--violet)">1</div></div>
<div class="pstat"><div class="pstat-label">E (эВ)</div><div class="pstat-val" id="bohrbar-v2" style="color:var(--cyan)">-13.6</div></div>
<div class="pstat"><div class="pstat-label">λ (нм)</div><div class="pstat-val" id="bohrbar-v3" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Серия</div><div class="pstat-val" id="bohrbar-v4" style="color:#EF476F"></div></div>
</div>
</div>
<!-- ── ELECTROLYSIS sim body ── -->
<div id="sim-electrolysis" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:220px;gap:0">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<div class="proj-slider-row" style="margin-bottom:8px">
<label style="font-size:.78rem;color:#ccc;width:55px">U = <span id="elec-V-val" style="color:#FFD166;font-weight:700">6</span> В</label>
<input type="range" id="sl-elec-V" min="1" max="12" step="0.5" value="6" oninput="elecParam('voltage',this.value)" style="flex:1">
</div>
<div style="margin-top:4px;margin-bottom:8px">
<div class="gp-section-title" style="margin-bottom:4px">Электролит</div>
<div style="display:flex;flex-wrap:wrap;gap:4px">
<button class="preset-btn elec-type-btn active" onclick="elecPreset('nacl',this)">NaCl</button>
<button class="preset-btn elec-type-btn" onclick="elecPreset('cuso4',this)">CuSO₄</button>
<button class="preset-btn elec-type-btn" onclick="elecPreset('h2so4',this)">H₂SO₄</button>
</div>
</div>
<div class="pp-hint">Ионы движутся к электродам, на электродах — газ и осадок</div>
</div>
<div class="proj-canvas-outer">
<canvas id="electrolysis-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="elecbar">
<div class="pstat"><div class="pstat-label">I (А)</div><div class="pstat-val" id="elecbar-v1" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">Масса</div><div class="pstat-val" id="elecbar-v2" style="color:var(--violet)"></div></div>
<div class="pstat"><div class="pstat-label">Газ (мл)</div><div class="pstat-val" id="elecbar-v3" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">Время</div><div class="pstat-val" id="elecbar-v4" style="color:#EF476F">0 с</div></div>
</div>
</div>
<!-- ── WAVES sim body ── -->
<div id="sim-waves" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<div class="proj-panel" style="width:228px;gap:0;overflow-y:auto">
<!-- Mode selector -->
<div class="gp-section-title" style="margin-bottom:6px">Режим</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:4px;margin-bottom:12px">
<button class="wave-mode-btn active" onclick="wavesMode('transverse',this)">Поперечная</button>
<button class="wave-mode-btn" onclick="wavesMode('longitudinal',this)">Продольная</button>
<button class="wave-mode-btn" onclick="wavesMode('superposition',this)">Суперпозиция</button>
<button class="wave-mode-btn" onclick="wavesMode('standing',this)">Стоячая</button>
<button class="wave-mode-btn" onclick="wavesMode('doppler',this)">Доплер</button>
<button class="wave-mode-btn" onclick="wavesMode('beats',this)">Биения</button>
<button class="wave-mode-btn" onclick="wavesMode('spectrum',this)" style="grid-column:span 2">Спектр (ДПФ)</button>
</div>
<!-- Wave 1 -->
<div class="gp-section-title" style="margin-bottom:6px">Волна 1</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Амплитуда A₁</span>
<span class="param-val" id="waves-A1-val" style="color:var(--violet)">50</span>
</div>
<input type="range" id="sl-waves-A1" class="param-slider" min="10" max="90" step="2" value="50" oninput="wavesParam('A1',this.value)">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Частота f₁</span>
<span class="param-val" id="waves-f1-val" style="color:var(--violet)">1.0 Гц</span>
</div>
<input type="range" id="sl-waves-f1" class="param-slider" min="0.3" max="4" step="0.1" value="1.0" oninput="wavesParam('f1',this.value)">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Фаза φ₁</span>
<span class="param-val" id="waves-phi1-val" style="color:var(--violet)">0</span>
</div>
<input type="range" id="sl-waves-phi1" class="param-slider" min="0" max="6.28" step="0.1" value="0" oninput="wavesParam('phi1',this.value)">
</div>
<!-- Wave 2 (superposition only) -->
<div id="waves-w2-section" style="display:none">
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Волна 2</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Амплитуда A₂</span>
<span class="param-val" id="waves-A2-val" style="color:var(--cyan)">40</span>
</div>
<input type="range" id="sl-waves-A2" class="param-slider" min="10" max="90" step="2" value="40" oninput="wavesParam('A2',this.value)">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Частота f₂</span>
<span class="param-val" id="waves-f2-val" style="color:var(--cyan)">1.5 Гц</span>
</div>
<input type="range" id="sl-waves-f2" class="param-slider" min="0.3" max="4" step="0.1" value="1.5" oninput="wavesParam('f2',this.value)">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Фаза φ₂</span>
<span class="param-val" id="waves-phi2-val" style="color:var(--cyan)">0</span>
</div>
<input type="range" id="sl-waves-phi2" class="param-slider" min="0" max="6.28" step="0.1" value="0" oninput="wavesParam('phi2',this.value)">
</div>
<div class="pp-hint" style="margin-bottom:8px">φ₂=0: конструктивная · φ₂=π: деструктивная интерференция</div>
</div>
<!-- Standing wave harmonics -->
<div id="waves-n-section" style="display:none">
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Гармоника n</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn wave-n-btn active" onclick="wavesN(1,this)">n=1</button>
<button class="preset-btn wave-n-btn" onclick="wavesN(2,this)">n=2</button>
<button class="preset-btn wave-n-btn" onclick="wavesN(3,this)">n=3</button>
<button class="preset-btn wave-n-btn" onclick="wavesN(4,this)">n=4</button>
<button class="preset-btn wave-n-btn" onclick="wavesN(5,this)">n=5</button>
</div>
</div>
<!-- Doppler controls -->
<div id="waves-doppler-section" style="display:none">
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Эффект Доплера</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Скорость источника v<sub>s</sub></span>
<span class="param-val" id="waves-dopVs-val" style="color:var(--gold)">0.35c</span>
</div>
<input type="range" id="sl-waves-dopVs" class="param-slider" min="0" max="1.8" step="0.05" value="0.35" oninput="wavesParam('dopVs',this.value)" style="accent-color:#FFD166">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Частота источника f₀</span>
<span class="param-val" id="waves-f1-dop-val" style="color:var(--violet)"></span>
</div>
<input type="range" id="sl-waves-f1-dop" class="param-slider" min="0.3" max="4" step="0.1" value="1.0" oninput="wavesParam('f1',this.value)">
</div>
<div class="pp-hint" style="margin-bottom:8px">S — источник (перетащи), O — наблюдатель (перетащи)</div>
</div>
<!-- Beats controls -->
<div id="waves-beats-section" style="display:none">
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Биения</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Частота f₁</span>
<span class="param-val" id="waves-beatsF1-val" style="color:var(--violet)">440 Гц</span>
</div>
<input type="range" id="sl-waves-beatsF1" class="param-slider" min="100" max="1000" step="1" value="440" oninput="wavesParam('beatsF1',this.value)">
</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Частота f₂</span>
<span class="param-val" id="waves-beatsF2-val" style="color:var(--cyan)">444 Гц</span>
</div>
<input type="range" id="sl-waves-beatsF2" class="param-slider" min="100" max="1000" step="1" value="444" oninput="wavesParam('beatsF2',this.value)">
</div>
<div class="pp-hint" style="margin-bottom:8px">f<sub>бие</sub> = |f₁ − f₂|, огибающая — золотая кривая</div>
</div>
<!-- Spectrum controls -->
<div id="waves-spectrum-section" style="display:none">
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Спектр (ДПФ)</div>
<div class="param-block">
<div class="param-header">
<span class="param-name">Гармоника для добавления</span>
<span class="param-val" id="waves-specNewF-val" style="color:var(--pink)">5 Гц</span>
</div>
<input type="range" id="sl-waves-specNewF" class="param-slider" min="1" max="50" step="1" value="5" oninput="wavesParam('specNewF',this.value)" style="accent-color:var(--pink)">
</div>
<div style="display:flex;gap:6px;margin-bottom:8px">
<button class="preset-btn" onclick="wavesSpecAdd()" style="flex:1">Добавить гармонику</button>
<button class="preset-btn" onclick="wavesSpecClear()" style="flex:1;color:var(--pink)">Очистить</button>
</div>
<div class="pp-hint" style="margin-bottom:8px">ДПФ N=256, fs=100 Гц. Пики подписаны в Гц.</div>
</div>
<!-- Presets -->
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Пресеты</div>
<div style="display:flex;flex-wrap:wrap;gap:4px;margin-bottom:10px">
<button class="preset-btn" onclick="wavesPreset('constructive')">Конструктивная</button>
<button class="preset-btn" onclick="wavesPreset('destructive')">Деструктивная</button>
<button class="preset-btn" onclick="wavesPreset('beats')">Биения</button>
</div>
<!-- Speed -->
<div class="param-block" style="margin-top:4px">
<div class="param-header">
<span class="param-name">Скорость анимации</span>
<span class="param-val" id="waves-speed-val" style="color:#FFD166">×2.0</span>
</div>
<input type="range" id="sl-waves-speed" class="param-slider" min="0.3" max="5" step="0.1" value="2.0" oninput="wavesParam('speed',this.value)" style="accent-color:#FFD166">
</div>
<div class="pp-hint" style="margin-top:10px">v = λ·f — основное волновое уравнение</div>
</div>
<div class="proj-canvas-outer">
<canvas id="waves-canvas"></canvas>
</div>
</div>
<div class="proj-stats-bar" id="wavesbar">
<div class="pstat"><div class="pstat-label">T (с)</div><div class="pstat-val" id="wavesbar-T" style="color:var(--violet)"></div></div>
<div class="pstat"><div class="pstat-label">λ (px)</div><div class="pstat-val" id="wavesbar-lam" style="color:var(--cyan)"></div></div>
<div class="pstat"><div class="pstat-label">v (px/с)</div><div class="pstat-val" id="wavesbar-v" style="color:#FFD166"></div></div>
<div class="pstat"><div class="pstat-label">f (Гц)</div><div class="pstat-val" id="wavesbar-f" style="color:var(--pink)"></div></div>
</div>
</div>
<!-- ── STEREO sim body ── -->
<div id="sim-stereo" class="sim-body-wrap" style="display:none">
<div class="stereo-panel">
<!-- ── Фигуры ── -->
<div class="gp-section-title" style="margin-bottom:6px">Многогранники</div>
<div class="stereo-fig-grid">
<button class="st-fig-btn stereo-fig-btn active" onclick="setStereoFigure('cube',this)" title="Куб">
<svg viewBox="0 0 24 24"><rect x="3" y="7" width="12" height="12"/><path d="M3 7l4-4h12v12l-4 4"/><path d="M15 3v12M3 19l4-4"/></svg>Куб
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('parallelepiped',this)" title="Прямоугольный параллелепипед">
<svg viewBox="0 0 24 24"><rect x="2" y="8" width="13" height="11"/><path d="M2 8l4-5h13v11l-4 5"/><path d="M15 3v11M2 19l4-5"/></svg>Параллел.
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('prism',this)" title="Правильная призма">
<svg viewBox="0 0 24 24"><polygon points="12,3 3,8 3,19 12,21 21,19 21,8"/><line x1="12" y1="3" x2="12" y2="21"/></svg>Призма
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('pyramid',this)" title="Правильная пирамида">
<svg viewBox="0 0 24 24"><polygon points="12,2 22,20 2,20"/><line x1="12" y1="2" x2="12" y2="20"/></svg>Пирамида
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('truncpyramid',this)" title="Усечённая пирамида">
<svg viewBox="0 0 24 24"><polygon points="6,6 18,6 22,20 2,20"/><line x1="9" y1="6" x2="4" y2="20"/><line x1="15" y1="6" x2="20" y2="20"/></svg>Усеч. пир.
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('tetrahedron',this)" title="Правильный тетраэдр">
<svg viewBox="0 0 24 24"><polygon points="12,2 22,20 2,20"/><line x1="12" y1="2" x2="12" y2="20"/><line x1="2" y1="20" x2="12" y2="14"/><line x1="22" y1="20" x2="12" y2="14"/></svg>Тетраэдр
</button>
</div>
<div class="gp-section-title" style="margin-top:6px;margin-bottom:6px">Правильные многогранники</div>
<div class="stereo-fig-grid">
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('octahedron',this)" title="Правильный октаэдр">
<svg viewBox="0 0 24 24"><polygon points="12,2 22,12 12,22 2,12"/><line x1="12" y1="2" x2="2" y2="12"/><line x1="12" y1="2" x2="22" y2="12"/><line x1="2" y1="12" x2="12" y2="22"/><line x1="22" y1="12" x2="12" y2="22"/></svg>Октаэдр
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('icosahedron',this)" title="Правильный икосаэдр">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><polygon points="12,3 20,8 18,17 6,17 4,8"/><line x1="12" y1="3" x2="12" y2="21"/></svg>Икосаэдр
</button>
<button class="st-fig-btn stereo-fig-btn st-fig-btn-wide" onclick="setStereoFigure('dodecahedron',this)" title="Правильный додекаэдр">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" stroke-dasharray="4,2"/><polygon points="12,2 20,8 17,17 7,17 4,8"/></svg>Додекаэдр
</button>
</div>
<div class="gp-section-title" style="margin-top:6px;margin-bottom:6px">Тела вращения</div>
<div class="stereo-fig-grid">
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('cylinder',this)" title="Цилиндр">
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="5" rx="9" ry="3"/><ellipse cx="12" cy="19" rx="9" ry="3"/><line x1="3" y1="5" x2="3" y2="19"/><line x1="21" y1="5" x2="21" y2="19"/></svg>Цилиндр
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('cone',this)" title="Конус">
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="19" rx="9" ry="3"/><line x1="3" y1="19" x2="12" y2="4"/><line x1="21" y1="19" x2="12" y2="4"/></svg>Конус
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('trunccone',this)" title="Усечённый конус">
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="18" rx="9" ry="3"/><ellipse cx="12" cy="7" rx="5" ry="2"/><line x1="3" y1="18" x2="7" y2="7"/><line x1="21" y1="18" x2="17" y2="7"/></svg>Усеч. конус
</button>
<button class="st-fig-btn stereo-fig-btn" onclick="setStereoFigure('sphere',this)" title="Шар">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><ellipse cx="12" cy="12" rx="9" ry="3"/></svg>Шар
</button>
</div>
<!-- ── Параметры ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Параметры</div>
<div id="stereo-params">
<div class="stereo-sl-row" id="sp-a-row">
<label>Сторона <b>a</b> <span id="sp-a-val">4</span></label>
<input type="range" id="sl-sp-a" min="1" max="10" step="0.5" value="4" oninput="stereoParamChange('a',this.value)">
</div>
<div class="stereo-sl-row" id="sp-b-row" style="display:none">
<label>Сторона <b>b</b> <span id="sp-b-val">3</span></label>
<input type="range" id="sl-sp-b" min="1" max="10" step="0.5" value="3" oninput="stereoParamChange('b',this.value)">
</div>
<div class="stereo-sl-row" id="sp-c-row" style="display:none">
<label>Сторона <b>c</b> <span id="sp-c-val">5</span></label>
<input type="range" id="sl-sp-c" min="1" max="10" step="0.5" value="5" oninput="stereoParamChange('c',this.value)">
</div>
<div class="stereo-sl-row" id="sp-h-row" style="display:none">
<label>Высота <b>h</b> <span id="sp-h-val">5</span></label>
<input type="range" id="sl-sp-h" min="1" max="12" step="0.5" value="5" oninput="stereoParamChange('h',this.value)">
</div>
<div class="stereo-sl-row" id="sp-r-row" style="display:none">
<label>Радиус <b>r</b> <span id="sp-r-val">2</span></label>
<input type="range" id="sl-sp-r" min="0.5" max="8" step="0.5" value="2" oninput="stereoParamChange('r',this.value)">
</div>
<div class="stereo-sl-row" id="sp-R-row" style="display:none">
<label>Радиус осн. <b>R</b> <span id="sp-R-val">3</span></label>
<input type="range" id="sl-sp-R" min="0.5" max="8" step="0.5" value="3" oninput="stereoParamChange('R',this.value)">
</div>
<div class="stereo-sl-row" id="sp-n-row" style="display:none">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:4px">
<span style="font-size:0.72rem;color:var(--text-2)">Граней основания <b>n</b></span>
<div class="st-n-ctrl">
<button class="st-n-btn" onclick="stereoNChange(-1)"><svg viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg></button>
<span class="st-n-val" id="sp-n-val">4</span>
<button class="st-n-btn" onclick="stereoNChange(+1)"><svg viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg></button>
</div>
</div>
</div>
</div>
<div class="stereo-sl-row" style="margin-top:2px">
<label>Прозрачность <span id="sp-opacity-val">0.3</span></label>
<input type="range" id="sl-sp-opacity" min="0" max="1" step="0.05" value="0.3" oninput="stereoOpacityChange(this.value)">
</div>
<!-- ── Отображение ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Отображение</div>
<div onclick="stereoToggleSt('edges',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/></svg>Рёбра</span>
<div class="st-toggle on" id="stg-edges"></div>
</div>
<div onclick="stereoToggleSt('vertices',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4" fill="currentColor"/></svg>Вершины</span>
<div class="st-toggle on" id="stg-vertices"></div>
</div>
<div onclick="stereoToggleSt('labels',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><path d="M4 7h16M4 12h10M4 17h7"/></svg>Подписи</span>
<div class="st-toggle on" id="stg-labels"></div>
</div>
<div onclick="stereoToggleSt('axes',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="2" y1="12" x2="22" y2="12"/><line x1="12" y1="2" x2="12" y2="22"/></svg>Оси</span>
<div class="st-toggle on" id="stg-axes"></div>
</div>
<div onclick="stereoToggleSt('grid',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/><line x1="3" y1="9" x2="21" y2="9"/><line x1="3" y1="15" x2="21" y2="15"/><line x1="9" y1="3" x2="9" y2="21"/><line x1="15" y1="3" x2="15" y2="21"/></svg>Сетка</span>
<div class="st-toggle on" id="stg-grid"></div>
</div>
<!-- ── Элементы фигуры ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Элементы</div>
<div onclick="stereoToggleElem('height',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="12" y1="3" x2="12" y2="21" stroke-dasharray="4,2"/><line x1="9" y1="21" x2="15" y2="21"/></svg>Высота</span>
<div class="st-toggle" id="stg-height"></div>
</div>
<div onclick="stereoToggleElem('apothem',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="12" y1="5" x2="12" y2="19"/><line x1="6" y1="19" x2="18" y2="19"/></svg>Апофема</span>
<div class="st-toggle" id="stg-apothem"></div>
</div>
<div onclick="stereoToggleElem('diagonals',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/><line x1="3" y1="3" x2="21" y2="21" stroke-dasharray="4,2"/><line x1="21" y1="3" x2="3" y2="21" stroke-dasharray="4,2"/></svg>Диагонали</span>
<div class="st-toggle" id="stg-diagonals"></div>
</div>
<div onclick="stereoToggleElem('midpoints',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>Середины рёбер</span>
<div class="st-toggle" id="stg-midpoints"></div>
</div>
<div onclick="stereoToggleElem('inscribed',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="5" stroke-dasharray="3,2"/><rect x="3" y="3" width="18" height="18"/></svg>Вписанная сфера</span>
<div class="st-toggle" id="stg-inscribed"></div>
</div>
<div onclick="stereoToggleElem('circumscribed',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="9" stroke-dasharray="4,2"/><polygon points="6,18 18,18 12,6"/></svg>Описанная сфера</span>
<div class="st-toggle" id="stg-circumscribed"></div>
</div>
<div onclick="stereoToggleElem('edgelengths',this.querySelector('.st-toggle'))" class="st-toggle-row">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="9" x2="4" y2="15"/><line x1="20" y1="9" x2="20" y2="15"/></svg>Длины рёбер</span>
<div class="st-toggle" id="stg-edgelengths"></div>
</div>
<div id="sect-area-display" style="font-size:0.7rem;color:var(--cyan);margin-top:2px;display:none"></div>
<div id="sphere-radius-info" style="font-size:0.7rem;color:#F59E0B;margin-top:2px;display:none"></div>
<!-- ── Сечение ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Сечение</div>
<div class="st-tool-grid" style="margin-bottom:4px">
<button class="st-tool-btn stereo-sect-btn st-tool-btn-wide" id="sect-toggle" onclick="stereoSectionToggle(this)">
<svg viewBox="0 0 24 24"><path d="M3 12h18M12 3v18" stroke-dasharray="4,2"/></svg>Показать сечение
</button>
<button class="st-tool-btn stereo-sect-type active" data-type="horizontal" onclick="stereoSectionType('horizontal',this)">
<svg viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/></svg>Горизонт.
</button>
<button class="st-tool-btn stereo-sect-type" data-type="diagonal" onclick="stereoSectionType('diagonal',this)">
<svg viewBox="0 0 24 24"><line x1="4" y1="18" x2="20" y2="6"/></svg>Диагональ
</button>
<button class="st-tool-btn stereo-sect-type st-tool-btn-wide" data-type="custom" onclick="stereoSectionType('custom',this)">
<svg viewBox="0 0 24 24"><circle cx="5" cy="19" r="2" fill="currentColor"/><circle cx="12" cy="5" r="2" fill="currentColor"/><circle cx="19" cy="15" r="2" fill="currentColor"/><polyline points="5,19 12,5 19,15 5,19"/></svg>По 3+ точкам
</button>
</div>
<div class="stereo-sl-row">
<label>Высота <span id="sp-sect-val">50%</span></label>
<input type="range" id="sl-sp-sect" min="0" max="100" step="1" value="50" oninput="stereoSectionHeight(this.value)">
</div>
<div class="stereo-sl-row" id="sp-angle-row" style="display:none">
<label>Наклон <span id="sp-angle-val">50%</span></label>
<input type="range" id="sl-sp-angle" min="0" max="100" step="1" value="50" oninput="stereoSectionAngle(this.value)">
</div>
<!-- ── Инструменты ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Инструменты</div>
<div class="st-tool-grid">
<button class="st-tool-btn" id="stereo-point-btn" onclick="stereoPointMode(this)" title="Поставить точку на ребро">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="4" fill="currentColor"/><line x1="3" y1="12" x2="21" y2="12"/></svg>Точка
</button>
<button class="st-tool-btn" id="stereo-connect-btn" onclick="stereoConnectMode(this)" title="Соединить две точки отрезком">
<svg viewBox="0 0 24 24"><circle cx="5" cy="19" r="2.5" fill="currentColor"/><circle cx="19" cy="5" r="2.5" fill="currentColor"/><line x1="5" y1="19" x2="19" y2="5" stroke-dasharray="4,2"/></svg>Соединить
</button>
<button class="st-tool-btn" id="stereo-measure-btn" onclick="stereoMeasure(this)" title="Измерить расстояние между двумя точками">
<svg viewBox="0 0 24 24"><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="9" x2="4" y2="15"/><line x1="20" y1="9" x2="20" y2="15"/></svg>Измерение
</button>
<button class="st-tool-btn" id="stereo-unfold-btn" onclick="stereoUnfold(this)" title="Развернуть в сетку">
<svg viewBox="0 0 24 24"><rect x="3" y="10" width="18" height="11"/><path d="M8 10V6a4 4 0 0 1 8 0v4"/></svg>Развёртка
</button>
</div>
<div class="st-action-grid" style="margin-top:3px">
<button class="st-action-btn" onclick="stereoUndoPoint()">Удалить точку</button>
<button class="st-action-btn" onclick="stereoClearPoints()">Очист. точки</button>
<button class="st-action-btn" onclick="stereoMeasureUndo()">Удалить изм.</button>
<button class="st-action-btn" onclick="stereoMeasureClear()">Очист. изм.</button>
</div>
<div id="points-info" style="font-size:0.65rem;color:rgba(255,255,255,0.4);margin-top:2px"></div>
<!-- ── Метки рёбер ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Метки рёбер</div>
<div class="st-tool-grid">
<button class="st-tool-btn" id="stereo-mark-tick-btn" onclick="stereoMarkMode('ticks',this)" title="Засечки равных рёбер — кликните ребро (до 3 штрихов)">
<svg viewBox="0 0 24 24"><line x1="5" y1="19" x2="19" y2="5"/><line x1="9" y1="9" x2="11" y2="11"/><line x1="13" y1="13" x2="15" y2="15"/></svg>Засечки =
</button>
<button class="st-tool-btn" id="stereo-mark-par-btn" onclick="stereoMarkMode('parallel',this)" title="Метки параллельных рёбер — кликните ребро">
<svg viewBox="0 0 24 24"><line x1="3" y1="8" x2="21" y2="8"/><line x1="3" y1="16" x2="21" y2="16"/><polyline points="15 5 18 8 15 11"/><polyline points="15 13 18 16 15 19"/></svg>Паралл. →
</button>
</div>
<div class="st-action-grid" style="margin-top:3px">
<button class="st-action-btn st-tool-btn-wide" onclick="stereoMarkClear()" style="grid-column:span 2">Очистить метки</button>
</div>
<!-- ── Производные точки ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Производные точки</div>
<div class="st-tool-grid">
<button class="st-tool-btn" id="stereo-derive-mid-btn" onclick="stereoDerive('midpoint',this)" title="Середина ребра — кликните ребро">
<svg viewBox="0 0 24 24"><line x1="3" y1="12" x2="21" y2="12"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg>Сер. ребра
</button>
<button class="st-tool-btn" id="stereo-derive-fc-btn" onclick="stereoDerive('face_centroid',this)" title="Центр грани — кликните грань">
<svg viewBox="0 0 24 24"><polygon points="12,3 21,21 3,21"/><circle cx="12" cy="15" r="2.5" fill="currentColor"/></svg>Центр грани
</button>
<button class="st-tool-btn" id="stereo-derive-alt-btn" onclick="stereoDerive('alt_foot',this)" title="Основание высоты: вершина → ребро">
<svg viewBox="0 0 24 24"><line x1="3" y1="20" x2="21" y2="20"/><line x1="10" y1="4" x2="10" y2="20" stroke-dasharray="4,2"/><path d="M10 20 L13 20 L13 17" fill="none"/></svg>Осн. высоты
</button>
<button class="st-tool-btn" id="stereo-derive-cen-btn" onclick="stereoDerive('solid_centroid',this)" title="Центроид тела — точка G">
<svg viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="18"/><circle cx="12" cy="12" r="3" fill="currentColor"/><line x1="3" y1="3" x2="21" y2="21" stroke-dasharray="4,2" opacity=".4"/><line x1="21" y1="3" x2="3" y2="21" stroke-dasharray="4,2" opacity=".4"/></svg>Центроид G
</button>
</div>
<div class="st-action-grid" style="margin-top:3px">
<button class="st-action-btn" onclick="stereoDeriveUndo()">Удалить послед.</button>
<button class="st-action-btn" onclick="stereoDeriveClear()">Очистить</button>
</div>
<!-- ── Углы и расстояния ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Углы и расстояния</div>
<div class="st-tool-grid">
<button class="st-tool-btn" id="stereo-angle-edge-btn" onclick="stereoAngleMode('edge',this)" title="Угол между рёбрами: 3 точки A-B-C">
<svg viewBox="0 0 24 24"><line x1="12" y1="19" x2="4" y2="5"/><line x1="12" y1="19" x2="20" y2="6"/><path d="M7 16 Q12 13 17 15" fill="none" stroke-dasharray="3,2"/></svg>∠ рёбер
</button>
<button class="st-tool-btn" id="stereo-angle-lp-btn" onclick="stereoAngleMode('linePlane',this)" title="Угол прямой к плоскости: 2 точки → грань">
<svg viewBox="0 0 24 24"><line x1="4" y1="20" x2="20" y2="4"/><ellipse cx="12" cy="18" rx="9" ry="3" fill="none" opacity=".6"/></svg>∠ пр.–пл.
</button>
<button class="st-tool-btn" id="stereo-angle-dih-btn" onclick="stereoAngleMode('dihedral',this)" title="Двугранный угол: 2 точки общего ребра">
<svg viewBox="0 0 24 24"><line x1="12" y1="3" x2="12" y2="21"/><line x1="3" y1="12" x2="12" y2="21"/><line x1="21" y1="7" x2="12" y2="21"/></svg>∠ двугр.
</button>
<button class="st-tool-btn" id="stereo-angle-pp-btn" onclick="stereoAngleMode('pointPlane',this)" title="Расстояние точка–плоскость">
<svg viewBox="0 0 24 24"><ellipse cx="12" cy="18" rx="9" ry="3" fill="none"/><line x1="12" y1="5" x2="12" y2="18" stroke-dasharray="3,2"/><circle cx="12" cy="5" r="2.5" fill="currentColor"/></svg>d(т→пл)
</button>
<button class="st-tool-btn st-tool-btn-wide" id="stereo-angle-skew-btn" onclick="stereoAngleMode('skewLines',this)" title="Угол и расстояние скрещивающихся прямых: P1,P2→P3,P4">
<svg viewBox="0 0 24 24"><line x1="3" y1="6" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="12" opacity=".5"/><circle cx="12" cy="9" r="2" fill="currentColor"/></svg>∠ скрещивающихся прямых
</button>
</div>
<div class="st-action-grid" style="margin-top:3px">
<button class="st-action-btn" style="grid-column:span 2" onclick="stereoAngleClear()">Очистить углы</button>
</div>
<div id="angle-hint" style="font-size:0.63rem;color:rgba(255,255,255,0.38);margin-top:3px;line-height:1.4"></div>
<!-- ── Сечение через 3 точки ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:6px">Сечение через 3 точки</div>
<div class="st-tool-grid" style="margin-bottom:4px">
<button class="st-tool-btn st-tool-btn-wide" id="stereo-sect3p-btn" onclick="stereoSection3P(this)" title="Выбрать 3 точки — построить сечение">
<svg viewBox="0 0 24 24"><circle cx="5" cy="19" r="2.5" fill="currentColor"/><circle cx="12" cy="4" r="2.5" fill="currentColor"/><circle cx="19" cy="14" r="2.5" fill="currentColor"/><polyline points="5,19 12,4 19,14 5,19" fill="none" stroke-dasharray="3,2"/></svg>Сечение через 3 точки
</button>
</div>
<div class="st-action-grid" style="margin-top:3px">
<button class="st-action-btn" onclick="stereoSection3PClear()" style="grid-column:span 2">Сбросить сечение</button>
</div>
<div id="sect3p-hint" style="font-size:0.63rem;color:rgba(255,255,255,0.38);margin-top:3px;line-height:1.4"></div>
<div id="sect3p-info" style="font-size:0.7rem;margin-top:4px;line-height:1.6"></div>
<div class="st-toggle-row" style="margin-top:4px" onclick="stereoSection3PStepBy(this.querySelector('.st-toggle'))">
<span class="st-toggle-label"><svg viewBox="0 0 24 24"><line x1="4" y1="12" x2="20" y2="12"/><polyline points="13 5 20 12 13 19"/></svg>Пошагово</span>
<div class="st-toggle" id="stg-sect3p-step"></div>
</div>
<div class="st-action-grid" style="margin-top:3px">
<button class="st-action-btn" onclick="stereoSection3PPrevStep()">Назад</button>
<button class="st-action-btn" onclick="stereoSection3PNextStep()">Вперёд</button>
</div>
<!-- ── Формулы ── -->
<div class="gp-section-title" style="margin-top:8px;margin-bottom:4px">Формулы</div>
<div id="stereo-formulas" style="font-size:0.72rem;color:rgba(255,255,255,0.7);line-height:1.5;margin-bottom:6px"></div>
</div>
<div class="graph-canvas-outer">
<div class="graph-canvas-wrap" id="stereo-container"></div>
</div>
</div>
<!-- stats bar for stereo -->
<div class="proj-stats-bar" id="stereo-stats" style="display:none">
<div class="pstat"><div class="pstat-label">Объём</div><div class="pstat-val" id="stbar-vol"></div></div>
<div class="pstat"><div class="pstat-label">Полная S</div><div class="pstat-val" id="stbar-area"></div></div>
<div class="pstat"><div class="pstat-label">Бок. S</div><div class="pstat-val" id="stbar-side"></div></div>
<div class="pstat"><div class="pstat-label">Высота</div><div class="pstat-val" id="stbar-h"></div></div>
<div class="pstat"><div class="pstat-label">Диагональ</div><div class="pstat-val" id="stbar-d"></div></div>
</div>
<!-- ── HYDROSTATICS sim body ── -->
<div id="sim-hydro" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<!-- left panel -->
<div class="proj-panel" style="width:230px;gap:0;overflow-y:auto">
<div class="gp-section-title" style="margin-bottom:8px">Параметры</div>
<!-- liquid -->
<div style="margin-bottom:10px">
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">Жидкость</div>
<select onchange="hydroSim&&hydroSim.setLiquid(this.value);document.getElementById('hydro-liq-sel').value=this.value" style="width:100%;background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.12);border-radius:8px;padding:5px 8px;font-size:.78rem">
<option value="water">Вода (1000 кг/м³)</option>
<option value="saltwater">Солёная вода (1030)</option>
<option value="oil">Масло (900)</option>
<option value="alcohol">Спирт (790)</option>
<option value="glycerin">Глицерин (1260)</option>
<option value="mercury">Ртуть (13600)</option>
</select>
</div>
<!-- material (Archimedes only) -->
<div id="hydro-panel-mat" style="margin-bottom:10px;display:none">
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">Материал тела</div>
<select onchange="hydroSim&&hydroSim.setMaterial(this.value)" style="width:100%;background:#1a1030;color:#f0e8ff;border:1px solid rgba(255,255,255,.12);border-radius:8px;padding:5px 8px;font-size:.78rem">
<option value="styrofoam">Пенопласт (30 кг/м³)</option>
<option value="cork">Пробка (120)</option>
<option value="wood">Дерево (500)</option>
<option value="ice">Лёд (900)</option>
<option value="plastic">Пластик (1100)</option>
<option value="glass">Стекло (2500)</option>
<option value="aluminum">Алюминий (2700)</option>
<option value="iron">Железо (7800)</option>
<option value="gold">Золото (19300)</option>
</select>
<div style="display:flex;gap:5px;margin-top:6px">
<button class="gp-btn" onclick="hydroSim&&hydroSim.addBody()" style="flex:1">+ Тело</button>
<button class="gp-btn" onclick="hydroSim&&hydroSim.clearBodies()" style="flex:1">Очистить</button>
</div>
</div>
<!-- contact angle (surface tension) -->
<div id="hydro-panel-theta" style="margin-bottom:10px;display:none">
<div style="display:flex;justify-content:space-between;font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">
<span>Краевой угол θ</span>
<span id="hydro-theta-lbl" style="color:var(--violet)">20°</span>
</div>
<input type="range" min="0" max="160" value="20" step="5" style="width:100%;accent-color:var(--violet)" oninput="hydroSim&&hydroSim.setContactAngle(+this.value);document.getElementById('hydro-theta-lbl').textContent=this.value+'\u00B0';document.getElementById('hydro-theta-val').textContent=this.value+'\u00B0';document.querySelector('#hydro-surf-ctrl input[type=range]').value=this.value">
<div style="display:flex;justify-content:space-between;font-size:.65rem;color:rgba(255,255,255,.25);margin-top:2px">
<span>Смачивание</span><span>Несмачивание</span>
</div>
<div style="margin-top:6px">
<button class="gp-btn" id="hydro-surf-toggle-panel" onclick="hydroToggleSurface()" style="width:100%">Капилляры</button>
</div>
</div>
<!-- communicating vessels -->
<div id="hydro-panel-comm" style="margin-bottom:10px;display:none">
<div style="font-size:.72rem;color:rgba(255,255,255,.4);margin-bottom:4px">Сосудов</div>
<div style="display:flex;gap:5px">
<button class="gp-btn hydro-nv active" onclick="hydroSetVessels(2,this)" style="flex:1">2</button>
<button class="gp-btn hydro-nv" onclick="hydroSetVessels(3,this)" style="flex:1">3</button>
<button class="gp-btn hydro-nv" onclick="hydroSetVessels(4,this)" style="flex:1">4</button>
</div>
<div style="margin-top:8px">
<button class="gp-btn" id="hydro-valve-panel-btn" onclick="hydroToggleValve()" style="width:100%;color:#06D6A0;border-color:rgba(6,214,160,.3)">Кран: открыт</button>
</div>
<div style="margin-top:6px;display:flex;gap:5px">
<button class="gp-btn" onclick="hydroSim&&hydroSim.addLiquid(0)" style="flex:1">+ Жидкость</button>
<button class="gp-btn" onclick="hydroSim&&hydroSim.removeLiquid()" style="flex:1">- Жидкость</button>
</div>
</div>
<!-- formula display -->
<div class="gp-section-title" style="margin-top:4px;margin-bottom:6px">Формулы</div>
<div id="hydro-formulas" style="font-size:.72rem;font-family:'JetBrains Mono',monospace;color:rgba(255,255,255,.6);line-height:1.7;background:rgba(255,255,255,.03);border-radius:8px;padding:8px 10px;min-height:80px"></div>
<!-- result badge -->
<div id="hydro-result" style="margin-top:8px;font-size:.82rem;font-weight:700;text-align:center;padding:8px;border-radius:8px;display:none"></div>
</div><!-- /.proj-panel -->
<!-- canvas area -->
<div style="flex:1;min-width:0;position:relative">
<canvas id="hydro-canvas" style="width:100%;height:100%;display:block"></canvas>
</div>
</div><!-- /.sim-body-wrap -->
</div><!-- /#sim-hydro -->
<!-- ══════════════════════════════════════════════
ПЛАНИМЕТРИЯ
══════════════════════════════════════════════ -->
<div id="sim-geometry" class="sim-proj-wrap" style="display:none">
<div class="sim-body-wrap">
<!-- left panel -->
<div class="geo-panel">
<!-- Tool: select + point -->
<div class="gp-section-title">Инструмент</div>
<div class="geo-tool-grid">
<button id="geo-btn-select" class="geo-tool-btn active" onclick="geoSetTool('select',this)" title="Выделить / переместить (Esc)">
<svg viewBox="0 0 24 24" fill="none"><path d="M5 3l14 9-7 1-4 7z" stroke-width="2"/></svg>
Выбор
</button>
<button id="geo-btn-point" class="geo-tool-btn" onclick="geoSetTool('point',this)" title="Поставить точку">
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="4" fill="currentColor"/></svg>
Точка
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Построения</div>
<div class="geo-tool-grid">
<button id="geo-btn-segment" class="geo-tool-btn" onclick="geoSetTool('segment',this)" title="Отрезок — 2 точки">
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="20" x2="20" y2="4" stroke-width="2.5"/><circle cx="4" cy="20" r="2.5" fill="currentColor"/><circle cx="20" cy="4" r="2.5" fill="currentColor"/></svg>
Отрезок
</button>
<button id="geo-btn-line" class="geo-tool-btn" onclick="geoSetTool('line',this)" title="Прямая — 2 точки">
<svg viewBox="0 0 24 24" fill="none"><line x1="2" y1="22" x2="22" y2="2" stroke-width="2" stroke-dasharray="3,2"/></svg>
Прямая
</button>
<button id="geo-btn-ray" class="geo-tool-btn" onclick="geoSetTool('ray',this)" title="Луч — начало + направление">
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="20" x2="22" y2="4" stroke-width="2"/><polyline points="17 4 22 4 22 9" stroke-width="2"/><circle cx="4" cy="20" r="2.5" fill="currentColor"/></svg>
Луч
</button>
<button id="geo-btn-circle" class="geo-tool-btn" onclick="geoSetTool('circle',this)" title="Окружность — центр + радиус">
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="8" stroke-width="2"/><circle cx="12" cy="12" r="2" fill="currentColor"/></svg>
Круг
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Фигуры</div>
<div class="geo-tool-grid">
<button id="geo-btn-triangle" class="geo-tool-btn" onclick="geoSetTool('triangle',this)" title="Треугольник — 3 точки">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 22,21 2,21" stroke-width="2"/></svg>
Треуг.
</button>
<button id="geo-btn-quad" class="geo-tool-btn" onclick="geoSetTool('quad',this)" title="Четырёхугольник — 4 точки">
<svg viewBox="0 0 24 24" fill="none"><polygon points="3,6 21,4 20,19 4,20" stroke-width="2"/></svg>
Четырёх.
</button>
<button id="geo-btn-polygon" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('polygon',this)" title="Многоугольник — N точек, Enter/двойной клик для завершения">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,2 22,8 19,21 5,21 2,8" stroke-width="2"/></svg>
Многоугольник
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Построения</div>
<div class="geo-tool-grid">
<button id="geo-btn-midpoint" class="geo-tool-btn" onclick="geoSetTool('midpoint',this)" title="Середина отрезка — 2 точки">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" stroke-width="2"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg>
Середина
</button>
<button id="geo-btn-perpbisect" class="geo-tool-btn" onclick="geoSetTool('perpbisect',this)" title="Серединный перпендикуляр — 2 точки">
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="18" x2="20" y2="6" stroke-width="2"/><line x1="12" y1="2" x2="12" y2="22" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="12" cy="12" r="2.5" fill="currentColor"/></svg>
⊥ биссект.
</button>
<button id="geo-btn-anglebisect" class="geo-tool-btn" onclick="geoSetTool('anglebisect',this)" title="Биссектриса угла — 3 точки: A, вершина, B">
<svg viewBox="0 0 24 24" fill="none"><polyline points="4,20 12,4 20,20" stroke-width="2"/><line x1="12" y1="4" x2="12" y2="20" stroke-width="1.5" stroke-dasharray="3,2"/></svg>
∠ биссект.
</button>
<button id="geo-btn-parallel" class="geo-tool-btn" onclick="geoSetTool('parallel',this)" title="Параллельная прямая — клик на линию, затем на точку">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="8" x2="21" y2="8" stroke-width="2"/><line x1="3" y1="16" x2="21" y2="16" stroke-width="2" opacity=".5" stroke-dasharray="4,3"/></svg>
|| прямая
</button>
<button id="geo-btn-perpendicular" class="geo-tool-btn" onclick="geoSetTool('perpendicular',this)" title="Перпендикулярная прямая — клик на линию, затем на точку">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" stroke-width="2"/><line x1="12" y1="4" x2="12" y2="20" stroke-width="2" opacity=".5" stroke-dasharray="4,3"/></svg>
⊥ прямая
</button>
<button id="geo-btn-intersect" class="geo-tool-btn" onclick="geoSetTool('intersect',this)" title="Точка пересечения — клик на две прямые">
<svg viewBox="0 0 24 24" fill="none"><line x1="4" y1="20" x2="20" y2="4" stroke-width="2"/><line x1="4" y1="4" x2="20" y2="20" stroke-width="2"/><circle cx="12" cy="12" r="3.5" fill="currentColor"/></svg>
Пересеч.
</button>
<button id="geo-btn-foot" class="geo-tool-btn" onclick="geoSetTool('foot',this)" title="Основание перпендикуляра — клик на прямую, затем на точку">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="18" x2="21" y2="18" stroke-width="2"/><line x1="12" y1="18" x2="12" y2="4" stroke-width="1.5" stroke-dasharray="3,2"/><path d="M12 18 L15 18 L15 15" stroke-width="1.5" fill="none"/><circle cx="12" cy="4" r="2.5" fill="currentColor"/></svg>
Основание
</button>
<button id="geo-btn-circumcircle" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('circumcircle',this)" title="Описанная окружность — 3 точки треугольника">
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="9" stroke-width="1.5" stroke-dasharray="4,3"/><polygon points="6,18 18,18 12,6" stroke-width="1.5" fill="none"/></svg>
Описанная
</button>
<button id="geo-btn-incircle" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('incircle',this)" title="Вписанная окружность — 3 точки треугольника">
<svg viewBox="0 0 24 24" fill="none"><polygon points="4,20 20,20 12,4" stroke-width="1.5" fill="none"/><circle cx="12" cy="15" r="5" stroke-width="1.5" stroke-dasharray="4,3"/></svg>
Вписанная
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Преобразования</div>
<div class="geo-tool-grid">
<button id="geo-btn-reflect" class="geo-tool-btn" onclick="geoSetTool('reflect',this)" title="Симметрия точки относительно прямой — клик на ось, затем на точку">
<svg viewBox="0 0 24 24" fill="none"><line x1="12" y1="2" x2="12" y2="22" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="6" cy="12" r="3" stroke-width="1.5"/><circle cx="18" cy="12" r="2.5" stroke-width="1.5" opacity=".5"/><line x1="9" y1="12" x2="15" y2="12" stroke-width="1" opacity=".6"/></svg>
Симметрия
</button>
<button id="geo-btn-translate" class="geo-tool-btn" onclick="geoSetTool('translate',this)" title="Параллельный перенос — вектор AB, затем точка P">
<svg viewBox="0 0 24 24" fill="none"><circle cx="6" cy="18" r="2.5" stroke-width="1.5"/><circle cx="18" cy="6" r="2.5" stroke-width="1.5"/><line x1="6" y1="18" x2="18" y2="6" stroke-width="1.5" marker-end="url(#arrow)"/><circle cx="14" cy="18" r="2.5" stroke-width="1.5" opacity=".4"/><circle cx="21" cy="9" r="2" stroke-width="1.5" stroke-dasharray="3,2"/></svg>
Перенос
</button>
<button id="geo-btn-tangent" class="geo-tool-btn geo-tool-wide" onclick="geoSetTool('tangent',this)" title="Касательные из точки к окружности — клик на окружность, затем на точку">
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="7" stroke-width="1.5"/><line x1="4" y1="4" x2="19" y2="12" stroke-width="1.5" stroke-dasharray="4,3"/><line x1="4" y1="20" x2="19" y2="12" stroke-width="1.5" stroke-dasharray="4,3"/><circle cx="4" cy="12" r="2.5" fill="currentColor"/></svg>
Касательные
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Элементы треугольника</div>
<div class="geo-tool-grid">
<button id="geo-btn-altitude" class="geo-tool-btn" onclick="geoSetTool('altitude',this)" title="Высота — клик на сторону, затем на вершину">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="20" x2="21" y2="20" stroke-width="1.5"/><line x1="10" y1="4" x2="10" y2="20" stroke-width="1.5" stroke-dasharray="4,3"/><rect x="10" y="14" width="4" height="4" stroke-width="1.2"/><polygon points="10,4 3,20 21,20" stroke-width="1.5" fill="none"/></svg>
Высота
</button>
<button id="geo-btn-median" class="geo-tool-btn" onclick="geoSetTool('median',this)" title="Медиана — клик вершина A, B, C">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="12" y1="3" x2="12" y2="20" stroke-width="1.5"/><circle cx="12" cy="20" r="2.5" fill="currentColor"/></svg>
Медиана
</button>
<button id="geo-btn-centroid" class="geo-tool-btn" onclick="geoSetTool('centroid',this)" title="Центроид — 3 точки треугольника, строит 3 медианы">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="12" y1="3" x2="12" y2="20" stroke-width="1.2" opacity=".6"/><line x1="3" y1="20" x2="16.5" y2="11.5" stroke-width="1.2" opacity=".6"/><line x1="21" y1="20" x2="7.5" y2="11.5" stroke-width="1.2" opacity=".6"/><circle cx="12" cy="14.3" r="2.5" fill="currentColor"/></svg>
Центроид
</button>
<button id="geo-btn-orthocenter" class="geo-tool-btn" onclick="geoSetTool('orthocenter',this)" title="Ортоцентр — 3 точки треугольника, строит 3 высоты">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="12" y1="3" x2="12" y2="20" stroke-width="1.2" stroke-dasharray="3,2" opacity=".6"/><line x1="3" y1="20" x2="16" y2="12" stroke-width="1.2" stroke-dasharray="3,2" opacity=".6"/><line x1="21" y1="20" x2="8" y2="12" stroke-width="1.2" stroke-dasharray="3,2" opacity=".6"/><circle cx="12" cy="14" r="2.5" fill="currentColor"/></svg>
Ортоцентр
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Средняя линия и четырёхугольники</div>
<div class="geo-tool-grid">
<button id="geo-btn-midline" class="geo-tool-btn" onclick="geoSetTool('midline',this)" title="Средняя линия треугольника — 3 вершины A, B, C">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 3,20 21,20" stroke-width="1.5" fill="none"/><line x1="7.5" y1="11.5" x2="16.5" y2="11.5" stroke-width="2"/><circle cx="7.5" cy="11.5" r="2" fill="currentColor"/><circle cx="16.5" cy="11.5" r="2" fill="currentColor"/></svg>
Средняя линия
</button>
<button id="geo-btn-parallelogram" class="geo-tool-btn" onclick="geoSetTool('parallelogram',this)" title="Параллелограмм — 3 точки A, B, C → вычисляет D">
<svg viewBox="0 0 24 24" fill="none"><polygon points="6,19 3,5 18,5 21,19" stroke-width="1.5" fill="none"/></svg>
Параллелограмм
</button>
<button id="geo-btn-diagonal" class="geo-tool-btn" onclick="geoSetTool('diagonal',this)" title="Диагонали — клик внутри многоугольника (4+ вершин)">
<svg viewBox="0 0 24 24" fill="none"><rect x="3" y="3" width="18" height="18" stroke-width="1.5" fill="none"/><line x1="3" y1="3" x2="21" y2="21" stroke-width="1.5" stroke-dasharray="4,2"/><line x1="21" y1="3" x2="3" y2="21" stroke-width="1.5" stroke-dasharray="4,2"/></svg>
Диагонали
</button>
<button id="geo-btn-scale" class="geo-tool-btn" onclick="geoSetTool('scale',this)" title="Подобие — клик центр O, затем клик точку P → P&#39; = O + k·(P O)">
<svg viewBox="0 0 24 24" fill="none"><circle cx="12" cy="12" r="2" fill="currentColor"/><line x1="12" y1="12" x2="20" y2="6" stroke-width="1.5"/><circle cx="20" cy="6" r="2.5" stroke-width="1.5"/><line x1="12" y1="12" x2="17" y2="18" stroke-width="1.5" stroke-dasharray="3,2"/><circle cx="17" cy="18" r="2.5" stroke-width="1.5" stroke-dasharray="3,2"/></svg>
Подобие
</button>
</div>
<div class="geo-ngon-ctrl" id="geo-scale-ctrl" style="gap:6px;padding:2px 0 4px">
<span style="font-size:11px;opacity:.7">k =</span>
<button class="geo-ngon-btn" onclick="geoScaleK(-0.5)">
<svg viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<span id="geo-scale-k">2</span>
<button class="geo-ngon-btn" onclick="geoScaleK(+0.5)">
<svg viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
</button>
</div>
<div class="gp-section-title" style="margin-top:4px">Правильный многоугольник</div>
<div class="geo-tool-grid">
<button id="geo-btn-ngon" class="geo-tool-btn" onclick="geoSetTool('ngon',this)" title="Правильный n-угольник — клик центр, клик вершина">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 20.2,8.5 17.3,18 6.7,18 3.8,8.5" stroke-width="1.5" fill="none"/></svg>
n-угольник
</button>
<div class="geo-ngon-ctrl" id="geo-ngon-ctrl">
<button class="geo-ngon-btn" onclick="geoNgonN(-1)">
<svg viewBox="0 0 16 16" fill="none"><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
</button>
<span id="geo-ngon-n">6</span>
<button class="geo-ngon-btn" onclick="geoNgonN(+1)">
<svg viewBox="0 0 16 16" fill="none"><line x1="8" y1="3" x2="8" y2="13" stroke-width="2" stroke-linecap="round"/><line x1="3" y1="8" x2="13" y2="8" stroke-width="2" stroke-linecap="round"/></svg>
</button>
</div>
</div>
<!-- Thales theorem -->
<div class="gp-section-title" style="margin-top:4px">Теорема Фалеса</div>
<div class="geo-tool-grid">
<button id="geo-btn-thales" class="geo-tool-btn" onclick="geoSetTool('thales',this)" title="Теорема Фалеса — клик O, затем A, затем B → A&#39;B&#39; ∥ AB">
<svg viewBox="0 0 24 24" fill="none"><circle cx="4" cy="20" r="2" fill="currentColor"/><line x1="4" y1="20" x2="22" y2="4" stroke-width="1.5"/><line x1="4" y1="20" x2="22" y2="12" stroke-width="1.5"/><line x1="10" y1="15" x2="13" y2="12" stroke-width="2" stroke-dasharray="0"/><line x1="17" y1="9" x2="20" y2="7" stroke-width="2" opacity=".6"/></svg>
Фалес
</button>
</div>
<!-- Mark tools -->
<div class="gp-section-title" style="margin-top:4px">Метки</div>
<div class="geo-tool-grid">
<button id="geo-btn-tick" class="geo-tool-btn" onclick="geoSetTool('tick',this)" title="Метки равных сторон — клик на отрезок или сторону (1–3 штриха)">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="20" x2="21" y2="4" stroke-width="1.5"/><line x1="11" y1="7" x2="8" y2="11" stroke-width="2" stroke-linecap="round"/><line x1="13" y1="9" x2="10" y2="13" stroke-width="2" stroke-linecap="round"/></svg>
Штрихи
</button>
<button id="geo-btn-arcmark" class="geo-tool-btn" onclick="geoSetTool('arcmark',this)" title="Метки равных углов — клик на вершину полигона (1–3 дуги)">
<svg viewBox="0 0 24 24" fill="none"><path d="M4 20 L20 20 L20 4" stroke-width="1.5" fill="none"/><path d="M8 20 A12 12 0 0 1 20 8" stroke-width="1.5" fill="none"/><path d="M11 20 A9 9 0 0 1 20 11" stroke-width="1.5" fill="none"/></svg>
Дуги
</button>
<button id="geo-btn-parallelmark" class="geo-tool-btn" onclick="geoSetTool('parallelmark',this)" title="Метки параллельных сторон — клик на отрезок (1–2 стрелки)">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="8" x2="21" y2="8" stroke-width="1.5"/><polyline points="9,5 13,8 9,11" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/><line x1="3" y1="16" x2="21" y2="16" stroke-width="1.5"/><polyline points="9,13 13,16 9,19" stroke-width="1.8" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg>
Параллельность
</button>
</div>
<!-- Constrained points for locus -->
<div class="gp-section-title" style="margin-top:4px">Точки на объектах</div>
<div class="geo-tool-grid">
<button id="geo-btn-point_on_segment" class="geo-tool-btn" onclick="geoSetTool('point_on_segment',this)" title="Точка на отрезке — кликни на отрезок, получишь скользящую точку">
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" y1="20" x2="21" y2="4"/><circle cx="12" cy="12" r="3" fill="currentColor" stroke="none"/></svg>
На отрезке
</button>
<button id="geo-btn-point_on_circle" class="geo-tool-btn" onclick="geoSetTool('point_on_circle',this)" title="Точка на окружности — кликни на окружность, получишь скользящую точку">
<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><circle cx="12" cy="3" r="2.5" fill="currentColor" stroke="none"/></svg>
На окружности
</button>
</div>
<!-- Measurement + Locus tools -->
<div class="gp-section-title" style="margin-top:4px">Измерения и ГМТ</div>
<div class="geo-tool-grid">
<button id="geo-btn-measure_length" class="geo-tool-btn" onclick="geoSetTool('measure_length',this)" title="Длина отрезка — кликни на отрезок, получишь живой чип">
<svg viewBox="0 0 24 24" fill="none"><line x1="3" y1="12" x2="21" y2="12" stroke-width="2"/><line x1="3" y1="8" x2="3" y2="16" stroke-width="2" stroke-linecap="round"/><line x1="21" y1="8" x2="21" y2="16" stroke-width="2" stroke-linecap="round"/></svg>
Длина
</button>
<button id="geo-btn-measure_angle" class="geo-tool-btn" onclick="geoSetTool('measure_angle',this)" title="Угол — 3 клика: точка A, вершина, точка B">
<svg viewBox="0 0 24 24" fill="none"><path d="M3 20 L20 20" stroke-width="2" stroke-linecap="round"/><path d="M3 20 L14 6" stroke-width="2" stroke-linecap="round"/><path d="M7 20 A10 10 0 0 1 11.5 12" stroke-width="1.5" fill="none"/></svg>
Угол
</button>
<button id="geo-btn-measure_area" class="geo-tool-btn" onclick="geoSetTool('measure_area',this)" title="Площадь многоугольника — кликни на полигон">
<svg viewBox="0 0 24 24" fill="none"><polygon points="12,3 21,9 18,20 6,20 3,9" stroke-width="2" fill="none"/></svg>
Площадь
</button>
<button id="geo-btn-locus" class="geo-tool-btn" onclick="geoSetTool('locus',this)" title="ГМТ — выбери точку-мовер (on_segment/on_circle), затем целевую точку">
<svg viewBox="0 0 24 24" fill="none"><path d="M4 20 Q8 4 12 12 Q16 20 20 6" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/><circle cx="8" cy="14" r="2" fill="currentColor"/></svg>
ГМТ
</button>
</div>
<!-- Display options -->
<div class="gp-section-title" style="margin-top:6px">Параметры</div>
<label class="geo-toggle-row" onclick="geoToggle('showGrid',this)">
<span class="geo-toggle-label">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/></svg>
Сетка
</span>
<div class="geo-toggle on" id="geo-tog-showGrid"></div>
</label>
<label class="geo-toggle-row" onclick="geoToggle('showAxes',this)">
<span class="geo-toggle-label">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="12" y1="20" x2="12" y2="4"/><line x1="4" y1="12" x2="20" y2="12"/></svg>
Оси
</span>
<div class="geo-toggle on" id="geo-tog-showAxes"></div>
</label>
<label class="geo-toggle-row" onclick="geoToggle('showLabels',this)">
<span class="geo-toggle-label">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 20h9"/><path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"/></svg>
Метки
</span>
<div class="geo-toggle on" id="geo-tog-showLabels"></div>
</label>
<label class="geo-toggle-row" onclick="geoToggle('showLengths',this)">
<span class="geo-toggle-label">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="8" x2="4" y2="16"/><line x1="20" y1="8" x2="20" y2="16"/></svg>
Длины
</span>
<div class="geo-toggle" id="geo-tog-showLengths"></div>
</label>
<label class="geo-toggle-row" onclick="geoToggle('showAngles',this)">
<span class="geo-toggle-label">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M3 20 L20 20 L20 4"/><path d="M7 20 A13 13 0 0 1 20 9"/></svg>
Углы
</span>
<div class="geo-toggle" id="geo-tog-showAngles"></div>
</label>
<!-- Stats -->
<div class="gp-section-title" style="margin-top:6px">Объектов</div>
<div style="display:flex;flex-direction:column;gap:0">
<div class="geo-stat-row"><span>Точки</span><b id="geo-st-pts">0</b></div>
<div class="geo-stat-row"><span>Отрезки</span><b id="geo-st-segs">0</b></div>
<div class="geo-stat-row"><span>Окружности</span><b id="geo-st-circs">0</b></div>
<div class="geo-stat-row"><span>Многоугольники</span><b id="geo-st-polys">0</b></div>
<div class="geo-stat-row"><span>Построения</span><b id="geo-st-constr">0</b></div>
</div>
<!-- Actions -->
<div style="margin-top:auto;padding-top:8px;display:flex;flex-direction:column;gap:4px">
<button class="gp-btn" onclick="geomSim&&geomSim.reset()" title="Очистить всё">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14H6L5 6"/></svg>
Очистить
</button>
<button class="geo-challenge-toggle" id="geo-chall-toggle-btn" onclick="geoToggleChallengePanel()" title="Открыть задачник">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>
Задачник
<span class="chall-count" id="geo-chall-count">0/5</span>
</button>
</div>
</div><!-- /.geo-panel -->
<!-- canvas area -->
<div class="geo-canvas-outer">
<canvas id="geo-canvas"></canvas>
<div class="geo-hint-bar" id="geo-hint">Кликни для добавления точки</div>
<div class="geo-del-confirm" id="geo-del-confirm">
<span id="geo-del-msg"></span>
<button class="geo-del-btn geo-del-btn-soft" id="geo-del-soft">Только этот</button>
<button class="geo-del-btn geo-del-btn-hard" id="geo-del-hard">Со всеми зависимыми</button>
<button class="geo-del-btn geo-del-btn-cancel" id="geo-del-cancel">Отмена</button>
</div>
<!-- Challenge panel (slides in from right) -->
<div class="geo-challenge-panel" id="geo-challenge-panel">
<div class="geo-chall-header">
<span class="geo-chall-header-title">Задачник</span>
<button class="geo-chall-close" onclick="geoToggleChallengePanel()">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
</div>
<div class="geo-chall-list" id="geo-chall-list">
<!-- Populated by JS -->
</div>
</div>
</div>
</div><!-- /.sim-body-wrap -->
</div><!-- /#sim-geometry -->
<!-- ── Theory panel (overlay right) ── -->
<div class="theory-panel" id="theory-panel">
<div class="theory-panel-inner" id="theory-content"></div>
</div>
</div><!-- /#lab-sim -->
</div><!-- /.sb-content -->
</div><!-- /.app-layout -->
<script src="/js/api.js"></script>
<script src="/js/sidebar.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.149.0/build/three.min.js"></script>
<script src="/js/labs/graph.js"></script>
<script src="/js/labs/emfield.js"></script>
<script src="/js/labs/triangle.js"></script>
<script src="/js/labs/projectile.js"></script>
<script src="/js/labs/collision.js"></script>
<script src="/js/labs/gas.js"></script>
<script src="/js/labs/states.js"></script>
<script src="/js/labs/brownian.js"></script>
<script src="/js/labs/diffusion.js"></script>
<!-- coulomb.js removed: merged into emfield.js -->
<script src="/js/labs/circuit.js"></script>
<script src="/js/labs/reactions.js"></script>
<script src="/js/labs/flask.js"></script>
<script src="/js/labs/redox.js"></script>
<script src="/js/labs/ionexchange.js"></script>
<script src="/js/labs/stereo.js?v=2"></script>
<script src="/js/notifications.js"></script>
<script src="/js/search.js"></script>
<script src="/js/mobile.js"></script>
<script src="/js/labs/lab-init.js"></script>
<script src="/js/labs/lab-glue.js"></script>
<script src="/js/labs/newton.js"></script>
<script src="/js/labs/forcesandbox.js"></script>
<script src="/js/labs/angrybirds.js"></script>
<script src="/js/labs/waves.js"></script>
<script src="/js/labs/chemsandbox.js"></script>
<script src="/js/labs/celldivision.js"></script>
<script src="/js/labs/photosynthesis.js"></script>
<script src="/js/labs/crystal.js"></script>
<script src="/js/labs/orbitals.js"></script>
<script src="/js/labs/trigcircle.js"></script>
<script src="/js/labs/_util.js"></script>
<script src="/js/labs/quadratic.js"></script>
<script src="/js/labs/normaldist.js"></script>
<script src="/js/labs/graphtransform.js"></script>
<script src="/js/labs/pendulum.js"></script>
<script src="/js/labs/equilibrium.js"></script>
<script src="/js/labs/thinlens.js"></script>
<script src="/js/labs/mirror.js"></script>
<script src="/js/labs/isoprocess.js"></script>
<script src="/js/labs/titration.js"></script>
<script src="/js/labs/refraction.js"></script>
<script src="/js/labs/probability.js"></script>
<script src="/js/labs/bohratom.js"></script>
<script src="/js/labs/electrolysis.js"></script>
<script src="/js/labs/hydrostatics.js"></script>
<script src="/js/labs/geometry.js"></script>
</body>
</html>