diff --git a/frontend/textbooks/algebra_9_ch4.html b/frontend/textbooks/algebra_9_ch4.html
index 8f2fb18..4784466 100644
--- a/frontend/textbooks/algebra_9_ch4.html
+++ b/frontend/textbooks/algebra_9_ch4.html
@@ -1718,38 +1718,588 @@ function buildP17(){
}
function buildP18(){
- const root = document.getElementById('p18-body');
- root.innerHTML = `
-
- `;
+
+ /* INTERACTIVE 3 — сравни формулы */
+ html += `
+
+
Перед тобой утверждение. Реши, верное оно или содержит ошибку в применении формулы $S_n = \\dfrac{b_1(q^n - 1)}{q - 1}$.
+
Задача: 1 / 6 · Очки: 0
+
+
+
+
+
+
+
`;
+
+ /* INTERACTIVE 4 — тренажёр */
+ html += `
+
+
Вычисляй суммы по формуле $S_n = \\dfrac{b_1(q^n - 1)}{q - 1}$. Ответ — целое число.
+
Задача: 1 / 6 · Очки: 0
+
+
+ Ответ:
+
+
+
+
+
`;
+
+ box.innerHTML = html + secNav('p17', 'p19') + readButton('p18');
+ renderMath(box);
+
+ /* ===== IV1 wiring ===== */
+ (function(){
+ const b1Sl = document.getElementById('p18-iv1-b1');
+ const qSl = document.getElementById('p18-iv1-q');
+ const nSl = document.getElementById('p18-iv1-n');
+ const bv = document.getElementById('p18-iv1-bv');
+ const qv = document.getElementById('p18-iv1-qv');
+ const nv = document.getElementById('p18-iv1-nv');
+ const termsEl = document.getElementById('p18-iv1-terms');
+ const fEl = document.getElementById('p18-iv1-formula');
+ const outEl = document.getElementById('p18-iv1-out');
+ let bumped = false;
+
+ function fmtQ(q){
+ if (Math.abs(q - 0.5) < 1e-9) return '\\dfrac{1}{2}';
+ if (Math.abs(q + 0.5) < 1e-9) return '-\\dfrac{1}{2}';
+ if (Math.abs(q - 1.5) < 1e-9) return '\\dfrac{3}{2}';
+ if (Math.abs(q + 1.5) < 1e-9) return '-\\dfrac{3}{2}';
+ return fmt(q);
+ }
+
+ function redraw(){
+ const b1 = +b1Sl.value, q = +qSl.value, n = +nSl.value;
+ bv.textContent = b1; qv.textContent = q; nv.textContent = n;
+
+ // первые n членов
+ const terms = [];
+ for (let i = 0; i < n; i++) terms.push(b1 * Math.pow(q, i));
+ const sum = terms.reduce((a,b)=>a+b, 0);
+ const termsStr = terms.map(t => fmt(+t.toFixed(4))).join('\\ +\\ ');
+ termsEl.innerHTML = '
Члены: $' + termsStr + '$';
+
+ if (Math.abs(q - 1) < 1e-9){
+ fEl.innerHTML = '
Особый случай $q = 1$: $S_n = n \\cdot b_1 = ' + n + ' \\cdot ' + b1 + ' = \\mathbf{' + (n*b1) + '}$.';
+ outEl.innerHTML = '$S_{' + n + '} = \\mathbf{' + (n*b1) + '}$';
+ } else {
+ const qN = Math.pow(q, n);
+ fEl.innerHTML = '$S_{' + n + '} = \\dfrac{b_1(q^n - 1)}{q - 1} = \\dfrac{' + b1 + '\\,((' + fmtQ(q) + ')^{' + n + '} - 1)}{' + fmtQ(q) + ' - 1}$';
+ outEl.innerHTML = '$q^n = ' + fmt(+qN.toFixed(4)) + ',\\quad S_{' + n + '} = \\mathbf{' + fmt(+sum.toFixed(4)) + '}$';
+ }
+ renderMath(termsEl); renderMath(fEl); renderMath(outEl);
+ if (!bumped){ bumped = true; bumpProgress('p18', 15); addXp(10,'p18-iv1'); }
+ }
+ b1Sl.addEventListener('input', redraw);
+ qSl.addEventListener('input', redraw);
+ nSl.addEventListener('input', redraw);
+ redraw();
+ })();
+
+ /* ===== IV2 wiring ===== */
+ (function(){
+ const out = document.getElementById('p18-iv2-out');
+ let bumped = false;
+ document.getElementById('p18-iv2-go').addEventListener('click', ()=>{
+ const b1 = +document.getElementById('p18-iv2-b1').value;
+ const q = +document.getElementById('p18-iv2-q').value;
+ const n = +document.getElementById('p18-iv2-n').value;
+ if (!Number.isInteger(n) || n < 1){ out.innerHTML = 'Число членов $n$ должно быть натуральным.'; renderMath(out); return; }
+ if (b1 === 0){ out.innerHTML = 'Должно быть $b_1 \\ne 0$.'; renderMath(out); return; }
+ if (q === 0){ out.innerHTML = 'Знаменатель $q$ должен быть $\\ne 0$.'; renderMath(out); return; }
+ if (Math.abs(q - 1) < 1e-9){
+ out.innerHTML = '$q = 1$: $S_n = n \\cdot b_1 = ' + n + ' \\cdot ' + b1 + ' = \\mathbf{' + (n*b1) + '}$';
+ renderMath(out);
+ } else {
+ const qN = Math.pow(q, n);
+ const S = b1 * (qN - 1) / (q - 1);
+ out.innerHTML = '$q^n = ' + fmt(q) + '^{' + n + '} = ' + fmt(+qN.toFixed(6))
+ + '$
$S_n = \\dfrac{b_1(q^n - 1)}{q - 1} = \\dfrac{' + b1 + '\\,(' + fmt(+qN.toFixed(6)) + ' - 1)}{' + fmt(q) + ' - 1} = \\mathbf{' + fmt(+S.toFixed(6)) + '}$';
+ renderMath(out);
+ }
+ if (!bumped){ bumped = true; bumpProgress('p18', 15); addXp(10,'p18-iv2'); }
+ });
+ })();
+
+ /* ===== IV3 wiring ===== */
+ (function(){
+ const items = [
+ { q:'$1 + 2 + 4 + 8 = \\dfrac{1 \\cdot (2^4 - 1)}{2 - 1} = 15$',
+ ans:true, hint:'$b_1 = 1,\\ q = 2,\\ n = 4$: $\\dfrac{16 - 1}{1} = 15$. Верно.' },
+ { q:'$1 + 3 + 9 + 27 = \\dfrac{1 \\cdot (3^4 - 1)}{2} = 40$',
+ ans:true, hint:'$b_1 = 1,\\ q = 3,\\ n = 4$: $\\dfrac{81 - 1}{2} = 40$. Верно.' },
+ { q:'Для $q \\ne 1$ верно $S_n = \\dfrac{b_1\\,q^n}{q - 1}$',
+ ans:false, hint:'Ошибка: в числителе должно быть $q^n - 1$, а не просто $q^n$.' },
+ { q:'$5 + 5 + 5 + 5 + 5 = 5 \\cdot 5 = 25$ (при $q = 1$)',
+ ans:true, hint:'При $q = 1$ формула $S_n = n \\cdot b_1 = 5 \\cdot 5 = 25$. Верно.' },
+ { q:'Для $q \\ne 1$ верно $S_3 = b_1 + b_1 q + b_1 q^2 = 3 b_1$',
+ ans:false, hint:'Сумма равна $3 b_1$ только при $q = 1$. В общем случае это $b_1(1 + q + q^2)$.' },
+ { q:'$1 - 2 + 4 - 8 + 16 = \\dfrac{1 \\cdot ((-2)^5 - 1)}{-2 - 1} = \\dfrac{-33}{-3} = 11$',
+ ans:true, hint:'$b_1 = 1,\\ q = -2,\\ n = 5$: $(-2)^5 = -32$, $\\dfrac{-33}{-3} = 11$. Верно.' }
+ ];
+ let i = 0, sc = 0;
+ const idxEl = document.getElementById('p18-iv3-idx');
+ const scEl = document.getElementById('p18-iv3-sc');
+ const qEl = document.getElementById('p18-iv3-q');
+ const fb = document.getElementById('p18-iv3-fb');
+ const yBtn = document.getElementById('p18-iv3-y');
+ const nBtn = document.getElementById('p18-iv3-n');
+ let bumped = false;
+ function render(){
+ idxEl.textContent = Math.min(i+1, items.length);
+ scEl.textContent = sc;
+ if (i >= items.length){
+ qEl.innerHTML = '
Готово! Результат: ' + sc + ' / ' + items.length;
+ yBtn.disabled = true; nBtn.disabled = true;
+ yBtn.style.opacity = .5; nBtn.style.opacity = .5;
+ if (!bumped){ bumped = true; bumpProgress('p18', 25); addXp(15,'p18-iv3'); }
+ return;
+ }
+ qEl.innerHTML = items[i].q;
+ fb.style.display = 'none';
+ renderMath(qEl);
+ }
+ function answer(v){
+ if (i >= items.length) return;
+ const it = items[i];
+ const ok = (v === it.ans);
+ if (ok) sc++;
+ feedback(fb, ok, (ok?'✓ Верно. ':'✗ Неверно. ') + it.hint);
+ i++;
+ setTimeout(render, 1200);
+ }
+ yBtn.addEventListener('click', ()=>answer(true));
+ nBtn.addEventListener('click', ()=>answer(false));
+ render();
+ })();
+
+ /* ===== IV4 wiring ===== */
+ (function(){
+ const items = [
+ { q:'Найди $1 + 2 + 4 + 8 + 16$.', ans: 31 },
+ { q:'$b_1 = 3,\\ q = 2$. Найти $S_5$.', ans: 93 },
+ { q:'Найди $1 + 3 + 9 + 27$.', ans: 40 },
+ { q:'$b_1 = 4,\\ q = -1$. Найти $S_5$.', ans: 4 },
+ { q:'$b_1 = 8,\\ q = \\dfrac{1}{2}$. Найти $S_4$.', ans: 15 },
+ { q:'Геом. прогрессия $1, 4, 16, \\ldots, 256$. Найти сумму всех её членов.', ans: 341 }
+ ];
+ let i = 0, sc = 0;
+ const idxEl = document.getElementById('p18-iv4-idx');
+ const scEl = document.getElementById('p18-iv4-sc');
+ const qEl = document.getElementById('p18-iv4-q');
+ const inp = document.getElementById('p18-iv4-ans');
+ const btn = document.getElementById('p18-iv4-go');
+ const fb = document.getElementById('p18-iv4-fb');
+ let bumped = false;
+ function render(){
+ idxEl.textContent = Math.min(i+1, items.length);
+ scEl.textContent = sc;
+ if (i >= items.length){
+ qEl.innerHTML = '
Готово! Результат: ' + sc + ' / ' + items.length;
+ inp.disabled = true; btn.disabled = true;
+ inp.style.opacity = .5; btn.style.opacity = .5;
+ if (!bumped){ bumped = true; bumpProgress('p18', 25); addXp(15,'p18-iv4'); }
+ return;
+ }
+ qEl.innerHTML = items[i].q;
+ inp.value = ''; fb.style.display = 'none';
+ renderMath(qEl);
+ }
+ btn.addEventListener('click', ()=>{
+ if (i >= items.length) return;
+ const v = +inp.value;
+ const it = items[i];
+ const ok = (v === it.ans);
+ if (ok) sc++;
+ feedback(fb, ok, ok ? '✓ Верно: $'+it.ans+'$' : '✗ Неверно. Правильный ответ: $'+it.ans+'$');
+ i++;
+ setTimeout(render, 1100);
+ });
+ inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); btn.click(); } });
+ render();
+ })();
+
wireReadBtn('p18');
}
function buildP19(){
- const root = document.getElementById('p19-body');
- root.innerHTML = `
-
- `;
+
+ /* INTERACTIVE 3 — можно ли применить формулу */
+ html += `
+
+
Формула работает только при $|q| < 1$ и $q \\ne 0$. Реши, подходит ли данная прогрессия.
+
Задача: 1 / 6 · Очки: 0
+
+
+
+
+
+
+
`;
+
+ /* INTERACTIVE 4 — тренажёр */
+ html += `
+
+
В каждой задаче указано, что вводить (целое значение, или числитель / знаменатель ответа).
+
Задача: 1 / 6 · Очки: 0
+
+
+ Ответ:
+
+
+
+
+
`;
+
+ box.innerHTML = html + secNav('p18', 'final4') + readButton('p19');
+ renderMath(box);
+
+ /* ===== IV1 wiring — визуализация ===== */
+ (function(){
+ const svg = document.getElementById('p19-iv1-svg');
+ const b1Sl = document.getElementById('p19-iv1-b1');
+ const qSl = document.getElementById('p19-iv1-q');
+ const bv = document.getElementById('p19-iv1-bv');
+ const qv = document.getElementById('p19-iv1-qv');
+ const fEl = document.getElementById('p19-iv1-formula');
+ const outEl = document.getElementById('p19-iv1-out');
+ let bumped = false;
+
+ function redraw(){
+ const b1 = +b1Sl.value, q = +qSl.value;
+ bv.textContent = b1; qv.textContent = q.toFixed(2);
+
+ const N = 15;
+ const terms = [];
+ const partial = [];
+ let s = 0;
+ for (let i = 0; i < N; i++){
+ const t = b1 * Math.pow(q, i);
+ terms.push(t); s += t; partial.push(s);
+ }
+ const Sinf = (Math.abs(q) < 1 - 1e-9) ? b1 / (1 - q) : NaN;
+
+ // SVG: верх — столбики членов, низ — частичные суммы
+ const W = 480, H = 280, pad = 22;
+ const barAreaH = 130;
+ const partAreaTop = 160;
+ const partAreaH = 100;
+ const ux = (W - 2*pad) / N;
+
+ // вертикальный масштаб для членов
+ const tmax = Math.max(...terms.map(Math.abs), 1e-6);
+ const tScale = (barAreaH / 2 - 6) / tmax;
+ const tMid = pad + barAreaH / 2;
+
+ // масштаб для частичных
+ const allP = partial.concat([Sinf||0, 0]);
+ let pMin = Math.min(...allP), pMax = Math.max(...allP);
+ if (pMax === pMin){ pMin -= 1; pMax += 1; }
+ const padP = (pMax - pMin) * 0.15;
+ pMin -= padP; pMax += padP;
+ const pScale = (partAreaH - 12) / (pMax - pMin);
+ const pToY = v => partAreaTop + 6 + (pMax - v) * pScale;
+
+ let g = '';
+ // фон областей
+ g += '
';
+ g += '
';
+ // средняя линия для членов (ось 0)
+ g += '
';
+ g += '
Члены $b_n$';
+ g += '
Частичные суммы $S_n$';
+
+ // столбики членов
+ const barW = ux * 0.7;
+ for (let i = 0; i < N; i++){
+ const x = pad + ux * (i + 0.15);
+ const h = Math.abs(terms[i]) * tScale;
+ const y = terms[i] >= 0 ? tMid - h : tMid;
+ const color = terms[i] >= 0 ? '#0891b2' : '#ef4444';
+ g += '
';
+ }
+
+ // линия Sinf
+ if (isFinite(Sinf)){
+ const ySinf = pToY(Sinf);
+ g += '
';
+ g += '
$S = '+fmt(+Sinf.toFixed(4))+'$';
+ }
+ // линия 0 в нижней области
+ const yZero = pToY(0);
+ if (yZero >= partAreaTop && yZero <= partAreaTop + partAreaH){
+ g += '
';
+ }
+ // точки и ломаная частичных сумм
+ let path = '';
+ for (let i = 0; i < N; i++){
+ const x = pad + ux * (i + 0.5);
+ const y = pToY(partial[i]);
+ path += (i === 0 ? 'M' : ' L') + x.toFixed(1) + ',' + y.toFixed(1);
+ }
+ g += '
';
+ for (let i = 0; i < N; i++){
+ const x = pad + ux * (i + 0.5);
+ const y = pToY(partial[i]);
+ g += '
';
+ }
+
+ svg.innerHTML = g;
+
+ // формула
+ if (isFinite(Sinf)){
+ fEl.innerHTML = '$S = \\dfrac{b_1}{1 - q} = \\dfrac{' + b1 + '}{1 - (' + q.toFixed(2) + ')} = \\mathbf{' + fmt(+Sinf.toFixed(4)) + '}$';
+ // частичные S_1..S_10
+ const ps = partial.slice(0, 10).map((s,i)=>'$S_{'+(i+1)+'}\\!=\\!'+fmt(+s.toFixed(3))+'$').join(',\\ ');
+ outEl.innerHTML = '
Частичные суммы: ' + ps + ' — стремятся к $S$.';
+ } else {
+ fEl.innerHTML = '
$|q| \\ge 1$: прогрессия не является бесконечно убывающей.';
+ outEl.innerHTML = '
Частичные суммы расходятся — формула $\\dfrac{b_1}{1 - q}$ не применима.';
+ }
+ renderMath(fEl); renderMath(outEl);
+ if (!bumped){ bumped = true; bumpProgress('p19', 15); addXp(10,'p19-iv1'); }
+ }
+ b1Sl.addEventListener('input', redraw);
+ qSl.addEventListener('input', redraw);
+ redraw();
+ })();
+
+ /* ===== IV2 wiring ===== */
+ (function(){
+ const out = document.getElementById('p19-iv2-out');
+ let bumped = false;
+ document.getElementById('p19-iv2-go').addEventListener('click', ()=>{
+ const b1 = +document.getElementById('p19-iv2-b1').value;
+ const qn = +document.getElementById('p19-iv2-qn').value;
+ const qd = +document.getElementById('p19-iv2-qd').value;
+ if (qd === 0){ out.innerHTML = 'Знаменатель $q$ не может быть нулём.'; renderMath(out); return; }
+ if (b1 === 0){ out.innerHTML = 'Должно быть $b_1 \\ne 0$.'; renderMath(out); return; }
+ const q = qn / qd;
+ if (q === 0){ out.innerHTML = '$q$ должен быть отличен от $0$.'; renderMath(out); return; }
+ if (Math.abs(q) >= 1){
+ out.innerHTML = '$q = \\dfrac{'+qn+'}{'+qd+'} = '+fmt(q)+'$.
$|q| \\ge 1$ — прогрессия не бесконечно убывающая!';
+ renderMath(out); return;
+ }
+ // S = b1 / (1 - q) = b1 * qd / (qd - qn)
+ const num = b1 * qd;
+ const den = qd - qn;
+ const g = gcd(num, den);
+ const sNum = num / g, sDen = den / g;
+ // знак в числитель
+ let nn = sNum, dd = sDen;
+ if (dd < 0){ nn = -nn; dd = -dd; }
+ const S = b1 / (1 - q);
+ let frac;
+ if (dd === 1) frac = '' + nn;
+ else frac = '\\dfrac{' + nn + '}{' + dd + '}';
+ out.innerHTML = '$q = \\dfrac{'+qn+'}{'+qd+'},\\ |q| < 1$ ✓
$S = \\dfrac{b_1}{1 - q} = \\dfrac{'+b1+'}{1 - \\tfrac{'+qn+'}{'+qd+'}} = \\dfrac{'+b1+' \\cdot '+qd+'}{'+qd+' - ('+qn+')} = \\mathbf{'+frac+'} \\approx '+fmt(+S.toFixed(4))+'$';
+ renderMath(out);
+ if (!bumped){ bumped = true; bumpProgress('p19', 15); addXp(10,'p19-iv2'); }
+ });
+ })();
+
+ /* ===== IV3 wiring ===== */
+ (function(){
+ const items = [
+ { q:'$b_1 = 1,\\ q = \\dfrac{1}{2}$', ans:true, hint:'$|q| = \\tfrac{1}{2} < 1$ — формула применима.' },
+ { q:'$b_1 = 1,\\ q = 2$', ans:false, hint:'$|q| = 2 > 1$ — прогрессия расходится, формула неприменима.' },
+ { q:'$b_1 = 5,\\ q = -\\dfrac{1}{3}$', ans:true, hint:'$|q| = \\tfrac{1}{3} < 1$ — формула применима.' },
+ { q:'$b_1 = 100,\\ q = 0{,}99$', ans:true, hint:'$|q| = 0{,}99 < 1$ — формула применима (сходимость медленная, но есть).' },
+ { q:'$b_1 = 1,\\ q = -1$', ans:false, hint:'$|q| = 1$ — граница, формула неприменима ($1 - 1 + 1 - 1 + \\ldots$ не сходится).' },
+ { q:'$b_1 = 1,\\ q = 1$', ans:false, hint:'$|q| = 1$ — это вообще не убывающая прогрессия ($1 + 1 + 1 + \\ldots = \\infty$).' }
+ ];
+ let i = 0, sc = 0;
+ const idxEl = document.getElementById('p19-iv3-idx');
+ const scEl = document.getElementById('p19-iv3-sc');
+ const qEl = document.getElementById('p19-iv3-q');
+ const fb = document.getElementById('p19-iv3-fb');
+ const yBtn = document.getElementById('p19-iv3-y');
+ const nBtn = document.getElementById('p19-iv3-n');
+ let bumped = false;
+ function render(){
+ idxEl.textContent = Math.min(i+1, items.length);
+ scEl.textContent = sc;
+ if (i >= items.length){
+ qEl.innerHTML = '
Готово! Результат: ' + sc + ' / ' + items.length;
+ yBtn.disabled = true; nBtn.disabled = true;
+ yBtn.style.opacity = .5; nBtn.style.opacity = .5;
+ if (!bumped){ bumped = true; bumpProgress('p19', 25); addXp(15,'p19-iv3'); }
+ return;
+ }
+ qEl.innerHTML = items[i].q;
+ fb.style.display = 'none';
+ renderMath(qEl);
+ }
+ function answer(v){
+ if (i >= items.length) return;
+ const it = items[i];
+ const ok = (v === it.ans);
+ if (ok) sc++;
+ feedback(fb, ok, (ok?'✓ Верно. ':'✗ Неверно. ') + it.hint);
+ i++;
+ setTimeout(render, 1200);
+ }
+ yBtn.addEventListener('click', ()=>answer(true));
+ nBtn.addEventListener('click', ()=>answer(false));
+ render();
+ })();
+
+ /* ===== IV4 wiring ===== */
+ (function(){
+ const items = [
+ { q:'$1 + \\dfrac{1}{2} + \\dfrac{1}{4} + \\ldots = \\ ?$ Введи целое значение $S$.', ans: 2, expl:'$S = \\dfrac{1}{1 - 1/2} = 2$.' },
+ { q:'$4 + 2 + 1 + \\dfrac{1}{2} + \\ldots = \\ ?$ Введи целое значение $S$.', ans: 8, expl:'$b_1 = 4,\\ q = \\tfrac{1}{2}$: $S = \\dfrac{4}{1 - 1/2} = 8$.' },
+ { q:'$1 - \\dfrac{1}{2} + \\dfrac{1}{4} - \\ldots = \\dfrac{2}{?}$ Введи знаменатель.', ans: 3, expl:'$S = \\dfrac{1}{1 + 1/2} = \\dfrac{2}{3}$.' },
+ { q:'$0{,}(6) = 0{,}666\\ldots = \\dfrac{2}{?}$ Введи знаменатель.', ans: 3, expl:'$S = \\dfrac{0{,}6}{1 - 0{,}1} = \\dfrac{0{,}6}{0{,}9} = \\dfrac{2}{3}$.' },
+ { q:'$9 + 3 + 1 + \\dfrac{1}{3} + \\ldots = \\dfrac{?}{2}$ Введи числитель.', ans: 27, expl:'$S = \\dfrac{9}{1 - 1/3} = \\dfrac{9 \\cdot 3}{2} = \\dfrac{27}{2}$.' },
+ { q:'$0{,}(12) = 0{,}1212\\ldots = \\dfrac{4}{?}$ Введи знаменатель.', ans: 33, expl:'$S = \\dfrac{0{,}12}{1 - 0{,}01} = \\dfrac{12}{99} = \\dfrac{4}{33}$.' }
+ ];
+ let i = 0, sc = 0;
+ const idxEl = document.getElementById('p19-iv4-idx');
+ const scEl = document.getElementById('p19-iv4-sc');
+ const qEl = document.getElementById('p19-iv4-q');
+ const inp = document.getElementById('p19-iv4-ans');
+ const btn = document.getElementById('p19-iv4-go');
+ const fb = document.getElementById('p19-iv4-fb');
+ let bumped = false;
+ function render(){
+ idxEl.textContent = Math.min(i+1, items.length);
+ scEl.textContent = sc;
+ if (i >= items.length){
+ qEl.innerHTML = '
Готово! Результат: ' + sc + ' / ' + items.length;
+ inp.disabled = true; btn.disabled = true;
+ inp.style.opacity = .5; btn.style.opacity = .5;
+ if (!bumped){ bumped = true; bumpProgress('p19', 25); addXp(15,'p19-iv4'); }
+ return;
+ }
+ qEl.innerHTML = items[i].q;
+ inp.value = ''; fb.style.display = 'none';
+ renderMath(qEl);
+ }
+ btn.addEventListener('click', ()=>{
+ if (i >= items.length) return;
+ const v = +inp.value;
+ const it = items[i];
+ const ok = (v === it.ans);
+ if (ok) sc++;
+ feedback(fb, ok, (ok ? '✓ Верно: $'+it.ans+'$. ' : '✗ Неверно. Правильный ответ: $'+it.ans+'$. ') + it.expl);
+ i++;
+ setTimeout(render, 1300);
+ });
+ inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ e.preventDefault(); btn.click(); } });
+ render();
+ })();
+
wireReadBtn('p19');
}