' + caption + ' Перетаскивай модель мышью, чтобы повернуть.
';
handle = A.molecule3d($(host.id + '-stage'), MOL[cur]);
host.querySelectorAll('.mv-b').forEach(function (b) { b.addEventListener('click', function () { cur = b.dataset.k; render(); }); });
}
render();
}
/* §5 — 3D-модели простых веществ */
function mount_p5() { molViewer($('p5-gal'), ['H2', 'O2', 'O3', 'N2'], 'Простое вещество — атомы одного элемента.'); }
/* §6 — классификатор простое/сложное + 3D-модели сложных веществ */
function mount_p6() {
var c = $('p6-cls');
if (c) classifier(c, {
buckets: ['Простое вещество', 'Сложное вещество'],
items: [
{ t:'O₂', b:0 }, { t:'H₂O', b:1 }, { t:'Fe', b:0 }, { t:'CO₂', b:1 },
{ t:'N₂', b:0 }, { t:'NH₃', b:1 }, { t:'S', b:0 }, { t:'CH₄', b:1 }
]
});
molViewer($('p6-gal'), ['H2O', 'CO2', 'CH4', 'NH3'], 'Сложное вещество — атомы разных элементов.');
}
/* ── Волна 3 ── */
/* §7 — разбор химической формулы на состав */
function mount_p7() {
var inp = $('p7-in'), out = $('p7-out'), go = $('p7-go'); if (!inp || inp._built) return; inp._built = 1;
function calc() {
var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null;
if (!cnt || !Object.keys(cnt).length) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу. Проверь символы элементов (например, H2SO4).'; return; }
var els = Object.keys(cnt), tot = els.reduce(function (s, e) { return s + cnt[e]; }, 0);
out.className = 'out ok';
out.innerHTML = '' + (C().formula ? C().formula(f) : f) + ' '
+ 'Элементов: ' + els.length + ' (' + (els.length === 1 ? 'простое' : 'сложное') + ' вещество) '
+ els.map(function (e) { return e + ': ' + cnt[e] + ' ' + (cnt[e] === 1 ? 'атом' : 'атома(ов)'); }).join(' ')
+ ' Всего атомов в формуле: ' + tot + '';
}
go.addEventListener('click', calc);
inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
document.querySelectorAll('.p7-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
calc();
}
/* §8 — калькулятор относительной молекулярной массы M_r */
function mount_p8() {
var inp = $('p8-in'), out = $('p8-out'), go = $('p8-go'); if (!inp || inp._built) return; inp._built = 1;
function calc() {
var f = inp.value.trim(), cnt = C().elementCounts ? C().elementCounts(f) : null, mr = C().molarMass ? C().molarMass(f) : NaN;
if (!cnt || isNaN(mr)) { out.className = 'out bad'; out.textContent = 'Не удалось разобрать формулу.'; return; }
out.className = 'out ok';
out.innerHTML = 'M_r(' + f + ') = ' + C().fmt(mr) + ' '
+ Object.keys(cnt).map(function (e) { return e + ': A_r=' + (C().arOf ? C().arOf(e) : '?') + ' × ' + cnt[e]; }).join(' | ')
+ ' Σ = ' + Object.keys(cnt).map(function (e) { return (C().arOf ? C().arOf(e) : '?') + '·' + cnt[e]; }).join(' + ') + ' = ' + C().fmt(mr) + '';
}
go.addEventListener('click', calc);
inp.addEventListener('keydown', function (e) { if (e.key === 'Enter') calc(); });
document.querySelectorAll('.p8-ex').forEach(function (b) { b.addEventListener('click', function () { inp.value = b.dataset.f; calc(); }); });
calc();
}
/* §9 — конструктор формулы по валентности (НОК индексов) */
function gcd(a, b) { return b ? gcd(b, a % b) : a; }
var VA = [ ['Na', 1], ['K', 1], ['H', 1], ['Mg', 2], ['Ca', 2], ['Zn', 2], ['Cu', 2], ['Al', 3], ['C', 4] ];
var VB = [ ['O', 2], ['Cl', 1], ['S', 2] ];
var BCOL = { O:'#ef4444', Cl:'#22c55e', S:'#eab308' };
function mount_p9() {
var m = $('p9-bld'); if (!m || m._built) return; m._built = 1;
var vanim = null;
function optA(){ return VA.map(function(e,i){ return ''; }).join(''); }
function optB(){ return VB.map(function(e,i){ return ''; }).join(''); }
m.innerHTML = '
'
+'
'
+''
+'';
function upd() {
var a = VA[+$('p9-a').value], b = VB[+$('p9-b').value];
var lcm = a[1] * b[1] / gcd(a[1], b[1]);
var ia = lcm / a[1], ib = lcm / b[1];
var raw = a[0] + (ia > 1 ? ia : '') + b[0] + (ib > 1 ? ib : '');
if (vanim) { vanim.stop(); vanim = null; }
if (W.Chem7Anim) vanim = W.Chem7Anim.valenceLink($('p9-vis'), {
a: { el:a[0], val:a[1], n:ia, color:'#6366f1' },
b: { el:b[0], val:b[1], n:ib, color:BCOL[b[0]] || '#ef4444' } });
var out = $('p9-bout'); out.className = 'out ok';
out.innerHTML = 'Валентности: ' + a[0] + ' = ' + 'I'.repeat(a[1]).replace('IIII','IV') + ', ' + b[0] + ' = ' + 'I'.repeat(b[1]) + ' '
+ 'Каждая чёрточка-связь соединена — все валентности заняты. '
+ 'НОК валентностей = ' + lcm + '; индексы: ' + a[0] + ' → ' + ia + ', ' + b[0] + ' → ' + ib + ' '
+ 'Формула: ' + (C().formula ? C().formula(raw) : raw) + '';
}
$('p9-a').addEventListener('change', upd); $('p9-b').addEventListener('change', upd); upd();
}
/* ── Волна 4 ── */
/* §10 / ЛО1 — детектор признаков химической реакции */
var DEMOS = [
{ name: 'Нагревание малахита', signs: ['изменение цвета: зелёный → чёрный', 'выделение газа (водяной пар и углекислый газ)'] },
{ name: 'Сливание растворов CuSO₄ и NaOH', signs: ['образование осадка (голубой)', 'изменение цвета раствора'] },
{ name: 'Горение серы', signs: ['выделение света и тепла (пламя)', 'появление резкого запаха'] },
{ name: 'Добавление соды в уксус', signs: ['выделение газа (пузырьки)'] }
];
// анимация на каждый опыт (через Chem7Anim, CSS-хелперы)
function demoAnim(idx, host) {
var A = W.Chem7Anim; if (!A || !host) return null;
if (idx === 0) return A.colorBlock(host, '#16a34a', '#1f2937', 'малахит → CuO + газы', 2000); // зелёный → чёрный
if (idx === 1) return A.precipField(host, { color: '#38bdf8' }); // голубой осадок
if (idx === 2) return A.flameBox(host, { color: '#3b82f6', sparks: true }); // синее пламя серы
return A.bubbleField(host, { color: 'rgba(255,255,255,.85)' }); // пузырьки газа
}
function mount_signs(mountId) {
var m = $(mountId); if (!m || m._built) return; m._built = 1;
var idx = 0, anim = null;
function stopAnim() { if (anim) { anim.stop(); anim = null; } }
function render() {
stopAnim();
m.innerHTML = '
'
+ '
'
+ ''
+ '
Выбери опыт и нажми «Провести опыт».
';
$(mountId + '-pick').addEventListener('change', function (e) { idx = +e.target.value; render(); });
$(mountId + '-go').addEventListener('click', function () {
var d = DEMOS[idx], out = $(mountId + '-out');
stopAnim(); anim = demoAnim(idx, $(mountId + '-stage'));
out.className = 'out ok';
out.innerHTML = 'Наблюдаемые признаки реакции:
'
+ d.signs.map(function (s) { return '
✓ ' + esc(s) + '
'; }).join('')
+ '
Эти признаки указывают, что произошла химическая реакция — образовались новые вещества.
';
});
}
render();
}
function mount_p10() { mount_signs('p10-signs'); }
function mount_lo1() { mount_signs('lo1-signs'); }
/* §11 — весы сохранения массы */
function mount_p11() {
var m = $('p11-bal'); if (!m || m._built) return; m._built = 1;
var mixed = false;
function scale(level) {
// level: 0 = равновесие
return '';
}
var anim = null;
function render() {
if (anim) { anim.stop(); anim = null; }
m.innerHTML = scale()
+ '
' + (mixed
? 'После реакции: осадок Cu(OH)₂ + раствор Na₂SO₄. Стрелка весов не сдвинулась — масса сохранилась (100 г = 100 г).'
: 'До реакции: раствор CuSO₄ + раствор NaOH, общая масса 100 г.') + '
'
+ ''
+ '';
if (mixed && W.Chem7Anim) anim = W.Chem7Anim.precipField($('p11-stage'), { color: '#38bdf8', h: 96 });
$('p11-mix').addEventListener('click', function () { mixed = !mixed; render(); });
}
render();
}
/* §12 — балансировщик + анимированный подсчёт атомов (слева/справа) */
var ELC = { H:'#cbd5e1', O:'#ef4444', C:'#334155', N:'#3b82f6', S:'#eab308', Fe:'#b45309', P:'#f97316', Cl:'#22c55e', Mg:'#22c55e', Ca:'#a78bfa', Na:'#a78bfa', Cu:'#ea580c', Zn:'#64748b', Al:'#6366f1', K:'#a78bfa' };
function mount_p12() {
var pick = $('p12-pick'), mount = $('p12-mount'); if (!pick || pick._built || !C().equationBalancer) return; pick._built = 1;
if (!$('p12-tally')) mount.insertAdjacentHTML('afterend', '');
function sumSide(list, coeffs, off) {
var tot = {};
list.forEach(function (sp, i) { var cnt = C().elementCounts ? C().elementCounts(sp) : {}; var co = coeffs[off + i] || 1; for (var e in cnt) tot[e] = (tot[e] || 0) + cnt[e] * co; });
return tot;
}
function dots(el, n) { var s = ''; for (var i = 0; i < n; i++) s += ''; return s; }
function col(title, tot) { return '
' + title + '
' + Object.keys(tot).map(function (e) { return '
' + e + '' + dots(e, tot[e]) + '× ' + tot[e] + '
'; }).join('') + '
'; }
function tally(skeleton, coeffs) {
var t = $('p12-tally'); if (!t) return;
var sides = skeleton.split(/->|=/);
var L = sides[0].split('+').map(function (s) { return s.trim(); });
var Rr = (sides[1] || '').split('+').map(function (s) { return s.trim(); });
var left = sumSide(L, coeffs, 0), right = sumSide(Rr, coeffs, L.length);
var ok = Object.keys(left).every(function (e) { return left[e] === right[e]; }) && Object.keys(right).every(function (e) { return left[e] === right[e]; });
t.innerHTML = '