diff --git a/frontend/textbooks/algebra_11_ch3.html b/frontend/textbooks/algebra_11_ch3.html
index bbdfab3..f45bc7b 100644
--- a/frontend/textbooks/algebra_11_ch3.html
+++ b/frontend/textbooks/algebra_11_ch3.html
@@ -130,6 +130,26 @@ a{color:inherit;text-decoration:none}
.spoiler[open] summary::before{content:'\2212'}
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
+.dnd-pool{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;min-height:54px;transition:border-color .18s,background .18s}
+.dnd-pool.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid}
+.dnd-pool.col{flex-direction:column;align-items:stretch}
+.dnd-pool.col .dnd-chip{width:auto}
+.dnd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--card);border:1.5px solid var(--border);border-radius:10px;cursor:grab;user-select:none;font-size:.92rem;line-height:1.4;transition:transform .12s,box-shadow .12s,border-color .12s;touch-action:none;max-width:100%}
+.dnd-chip:hover{transform:translateY(-1px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)}
+.dnd-chip:active{cursor:grabbing}
+.dnd-chip.armed{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:0 0 0 3px rgba(217,119,6,.22);transform:translateY(-1px)}
+.dnd-chip.dragging{opacity:.28}
+.dnd-chip.placed{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
+.dnd-chip .dnd-x{padding:0 5px;color:var(--muted);font-weight:700;font-size:1.05rem;border-radius:4px;cursor:pointer}
+.dnd-chip .dnd-x:hover{color:var(--bad,var(--fail));background:var(--fail-bg)}
+.drop-box{background:var(--card);border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:90px;transition:border-color .15s,background .15s}
+.drop-box:hover{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
+.drop-box h5{font-family:'Unbounded',sans-serif;font-size:.78rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em}
+.drop-box.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid;transform:scale(1.015)}
+.drop-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px}
+.dnd-hint{font-size:.82rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
+.dnd-hint svg{width:14px;height:14px;flex-shrink:0}
+
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
@@ -450,6 +470,19 @@ function makeCard(kind, title, num, body){
const labels = {repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно'};
return '
';
}
+function setupSorter(cfg){
+ const placed = {}; const pool = document.getElementById(cfg.poolId); const scope = document.querySelector(cfg.scopeSelector);
+ if(!pool||!scope) return {placed,render:()=>{},reset:()=>{}};
+ pool.classList.add('dnd-pool'); if(cfg.columnLayout) pool.classList.add('col');
+ let armed = null;
+ function buildChip(it,isPlaced){ const e=document.createElement('div'); e.className='dnd-chip'+(isPlaced?' placed':''); e.dataset.id=it.id; e.innerHTML=''+it.html+'\xd7'; attach(e,it.id); return e; }
+ function attach(elm,itId){ let ghost=null,dragging=false,sx=0,sy=0; elm.addEventListener('pointerdown',ev=>{ if(ev.button!==undefined&&ev.button!==0) return;
+ ev.preventDefault(); if(ev.target.classList&&ev.target.classList.contains('dnd-x')){ ev.stopPropagation(); if(placed[itId]){delete placed[itId];render();}else if(armed===itId){armed=null;render();} return; } sx=ev.clientX;sy=ev.clientY; const r=elm.getBoundingClientRect(); const ox=ev.clientX-r.left,oy=ev.clientY-r.top; try{elm.setPointerCapture(ev.pointerId);}catch(e){} function onMove(e){ const dx=e.clientX-sx,dy=e.clientY-sy; if(!dragging&&Math.hypot(dx,dy)>8){ dragging=true; ghost=elm.cloneNode(true); ghost.classList.remove('armed'); ghost.style.cssText='position:fixed;z-index:9999;pointer-events:none;opacity:.9;transform:rotate(-2.5deg);box-shadow:0 14px 36px rgba(0,0,0,.32);width:'+r.width+'px;left:'+(e.clientX-ox)+'px;top:'+(e.clientY-oy)+'px'; document.body.appendChild(ghost); elm.classList.add('dragging'); } if(dragging&&ghost){ ghost.style.left=(e.clientX-ox)+'px';ghost.style.top=(e.clientY-oy)+'px'; const under=document.elementsFromPoint(e.clientX,e.clientY); scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); const tgt=under.find(n=>n.classList&&(n.classList.contains('drop-box')||n.classList.contains('dnd-pool'))); if(tgt)tgt.classList.add('over'); } } function onUp(e){ elm.removeEventListener('pointermove',onMove);elm.removeEventListener('pointerup',onUp);elm.removeEventListener('pointercancel',onUp);elm.classList.remove('dragging'); if(ghost){ghost.remove();ghost=null;} scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); if(dragging){ const under=document.elementsFromPoint(e.clientX,e.clientY); const box=under.find(n=>n.classList&&n.classList.contains('drop-box')); const pl=under.find(n=>n.classList&&n.classList.contains('dnd-pool')); if(box){const di=box.querySelector('[data-cat]');if(di){placed[itId]=di.dataset.cat;armed=null;render();return;}}else if(pl){delete placed[itId];armed=null;render();return;} }else{ if(placed[itId]){delete placed[itId];armed=null;render();}else{armed=(armed===itId)?null:itId;render();} } dragging=false; } elm.addEventListener('pointermove',onMove);elm.addEventListener('pointerup',onUp);elm.addEventListener('pointercancel',onUp); }); }
+ function attachBoxTaps(){ scope.querySelectorAll('.drop-box').forEach(box=>{ box.addEventListener('click',ev=>{ if(!armed)return; if(ev.target.closest('.dnd-chip'))return; const di=box.querySelector('[data-cat]'); if(di){placed[armed]=di.dataset.cat;armed=null;render();} }); }); }
+ function render(){ pool.innerHTML=''; cfg.items.forEach(it=>{if(placed[it.id])return;const c=buildChip(it,false);if(armed===it.id)c.classList.add('armed');pool.appendChild(c);}); cfg.cats.forEach(cat=>{const box=scope.querySelector('.drop-items[data-cat="'+cat+'"]');if(!box)return;box.innerHTML='';cfg.items.forEach(it=>{if(placed[it.id]!==cat)return;box.appendChild(buildChip(it,true));});}); if(window.renderMathInElement)try{renderMath(scope);}catch(_){} }
+ attachBoxTaps(); render();
+ return {placed,render,reset(){ for(const k in placed)delete placed[k];armed=null;render(); }};
+}
/* === SVG-хелперы (axes2D, plotFunc, pointWithDrop, asymptote, snapToValue, геом.) === */
@@ -604,15 +637,422 @@ function wireReadBtn(paraId){
function buildP7(){
const box = document.getElementById('p7-body');
let html = '';
- html += makeCard('theory', 'В разработке', '7.0', `
- Содержание параграфа Свойства логарифмов будет добавлено в Phase 1+.
- Раздел Phase 0 — skeleton. Здесь появятся теория, примеры и интерактивы.
- Ключевая формула: $\log_a(bc) = \log_a b + \log_a c$
+
+ /* === ТЕОРИЯ === */
+ html += makeCard('theory', 'Произведение, частное, степень', '7.1', `
+ Пусть $a > 0$, $a \\ne 1$ и $b > 0$, $c > 0$. Тогда справедливы три основных свойства:
+ $\\log_a(bc) = \\log_a b + \\log_a c$
+ $\\log_a \\dfrac{b}{c} = \\log_a b - \\log_a c$
+ $\\log_a b^n = n \\cdot \\log_a b$
+ Доказательство свойства произведения
+
Пусть $\\log_a b = p$ и $\\log_a c = q$. По определению логарифма $b = a^p$ и $c = a^q$.
+
Тогда $bc = a^p \\cdot a^q = a^{p+q}$, значит $\\log_a(bc) = p + q = \\log_a b + \\log_a c$.
+
Свойства для частного и степени доказываются аналогично — через определение логарифма и свойства степеней.
+
+ Примеры:
+ $\\log_2 6 = \\log_2(2 \\cdot 3) = \\log_2 2 + \\log_2 3 = 1 + \\log_2 3$.
+ $\\log_5 \\dfrac{25}{8} = \\log_5 25 - \\log_5 8 = 2 - 3 \\log_5 2$.
+ $\\log_2 8^3 = 3 \\log_2 8 = 3 \\cdot 3 = 9$.
`);
+
+ html += makeCard('rule', 'Корень и перенос показателя из основания', '7.2', `
+ Логарифм корня. Поскольку $\\sqrt[n]{b} = b^{1/n}$, по свойству степени:
+ $\\log_a \\sqrt[n]{b} = \\log_a b^{1/n} = \\dfrac{1}{n} \\log_a b$
+ Перенос показателя из основания.
+ $\\log_{a^n} b = \\dfrac{1}{n} \\log_a b$
+ Эти два свойства часто объединяют в одно:
+ $\\log_{a^k} b^m = \\dfrac{m}{k} \\log_a b$
+ Примеры:
+ $\\log_2 \\sqrt{8} = \\dfrac{1}{2} \\log_2 8 = \\dfrac{3}{2}$.
+ $\\log_4 16 = \\log_{2^2} 2^4 = \\dfrac{4}{2} \\log_2 2 = 2$.
+ $\\log_{27} \\sqrt[3]{9} = \\log_{3^3} 3^{2/3} = \\dfrac{2/3}{3} = \\dfrac{2}{9}$.
+ `);
+
+ html += makeCard('example', 'Переход к новому основанию', '7.3', `
+ Иногда удобно перейти от $\\log_a b$ к логарифму по другому основанию $c$ ($c > 0$, $c \\ne 1$):
+ $\\log_a b = \\dfrac{\\log_c b}{\\log_c a}$
+ Чаще всего берут $c = 10$ (десятичные) или $c = e$ (натуральные). Полезное следствие при $a \\ne 1$, $b \\ne 1$:
+ $\\log_a b = \\dfrac{1}{\\log_b a}$
+ Применение:
+ $\\log_2 7 = \\dfrac{\\lg 7}{\\lg 2} \\approx \\dfrac{0{,}845}{0{,}301} \\approx 2{,}807$.
+ $\\log_3 5 = \\dfrac{1}{\\log_5 3}$.
+ Связь $\\lg$ и $\\ln$:
+ $\\lg b = \\dfrac{\\ln b}{\\ln 10} \\approx \\dfrac{\\ln b}{2{,}303}$, $\\quad \\ln b = \\dfrac{\\lg b}{\\lg e} \\approx \\dfrac{\\lg b}{0{,}4343}$.
+ `);
+
+ /* === ИНТЕРАКТИВ 1 — пошаговый «применитель» свойств === */
+ html += `
+
+
Выбери выражение ползунком и нажимай «Следующий шаг ▶», чтобы открывать решение по одному шагу. Просмотри все 5 выражений — получишь XP.
+
+
+
+
+
+
+
+
+
+
+
`;
+
+ /* === ИНТЕРАКТИВ 2 — калькулятор логарифмов === */
+ html += `
+
+
Выбери свойство, заполни поля и нажми «Вычислить» — увидишь применение свойства пошагово и численное приближение.
+
+
+
+
+
+
+
+
+
+
+
`;
+
+ /* === ИНТЕРАКТИВ 3 — DnD-сортер === */
+ html += `
+
+
Перетащи каждое выражение в ящик с верным значением. Используй свойства логарифмов: сумму, разность, степень и корень.
+
+
+
+
+
+
`;
+
+ /* === ИНТЕРАКТИВ 4 — тренажёр === */
+ html += `
+
+
6 задач на применение свойств. Введи число (целое или десятичное, допуск $\\pm 0{,}05$).
+
Задача 1 / 6Очки: 0 / 6
+
+
+ ответ =
+
+
+
+
+
+
`;
+
html += secNavFor('p7');
html += readButton('p7');
+
box.innerHTML = html;
renderMath(box);
+
+ /* === IV1 — пошаговый «применитель» === */
+ (function(){
+ const TASKS = [
+ {
+ q: '$\\log_2 24 - \\log_2 3$',
+ steps: [
+ 'Используем свойство логарифма частного: $\\log_a b - \\log_a c = \\log_a \\dfrac{b}{c}$.',
+ 'Получаем $\\log_2 24 - \\log_2 3 = \\log_2 \\dfrac{24}{3} = \\log_2 8$.',
+ 'Так как $8 = 2^3$, имеем $\\log_2 8 = 3$.',
+ 'Ответ: $3$.'
+ ]
+ },
+ {
+ q: '$\\log_3 5 + \\log_3 18$',
+ steps: [
+ 'Используем свойство логарифма произведения: $\\log_a b + \\log_a c = \\log_a(bc)$.',
+ 'Получаем $\\log_3 5 + \\log_3 18 = \\log_3(5 \\cdot 18) = \\log_3 90$.',
+ 'Заметим, что $90 = 9 \\cdot 10$, поэтому $\\log_3 90 = \\log_3 9 + \\log_3 10 = 2 + \\log_3 10$.',
+ 'Ответ: $2 + \\log_3 10 \\approx 4{,}096$.'
+ ]
+ },
+ {
+ q: '$2 \\log_5 3 + \\log_5 \\dfrac{25}{9}$',
+ steps: [
+ 'По свойству степени: $2 \\log_5 3 = \\log_5 3^2 = \\log_5 9$.',
+ 'Получаем $\\log_5 9 + \\log_5 \\dfrac{25}{9} = \\log_5\\left(9 \\cdot \\dfrac{25}{9}\\right) = \\log_5 25$.',
+ 'Так как $25 = 5^2$, имеем $\\log_5 25 = 2$.',
+ 'Ответ: $2$.'
+ ]
+ },
+ {
+ q: '$\\log_2 \\sqrt[3]{32}$',
+ steps: [
+ 'Применяем свойство логарифма корня: $\\log_a \\sqrt[n]{b} = \\dfrac{1}{n} \\log_a b$.',
+ 'Получаем $\\log_2 \\sqrt[3]{32} = \\dfrac{1}{3} \\log_2 32$.',
+ 'Так как $32 = 2^5$, имеем $\\log_2 32 = 5$, значит $\\dfrac{1}{3} \\cdot 5 = \\dfrac{5}{3}$.',
+ 'Ответ: $\\dfrac{5}{3} \\approx 1{,}667$.'
+ ]
+ },
+ {
+ q: '$\\log_{16} 8$',
+ steps: [
+ 'Перепишем основание и аргумент по основанию $2$: $16 = 2^4$, $8 = 2^3$.',
+ 'Применяем формулу $\\log_{a^k} b^m = \\dfrac{m}{k} \\log_a b$: $\\log_{2^4} 2^3 = \\dfrac{3}{4} \\log_2 2 = \\dfrac{3}{4}$.',
+ 'Ответ: $\\dfrac{3}{4} = 0{,}75$.'
+ ]
+ }
+ ];
+ const sn = document.getElementById('p7-iv1-sn');
+ const nL = document.getElementById('p7-iv1-n');
+ const qEl = document.getElementById('p7-iv1-q');
+ const stepsEl = document.getElementById('p7-iv1-steps');
+ const nextBtn = document.getElementById('p7-iv1-next');
+ const allBtn = document.getElementById('p7-iv1-all');
+ const resetBtn = document.getElementById('p7-iv1-reset');
+ const seen = new Set();
+ let _done = false;
+ let cur = 0, shown = 0;
+
+ function render(){
+ const t = TASKS[cur];
+ nL.textContent = (cur + 1);
+ qEl.innerHTML = t.q;
+ stepsEl.innerHTML = t.steps.map((s, i) => {
+ const visible = i < shown;
+ const isLast = i === t.steps.length - 1 && visible;
+ const bg = isLast ? '#dcfce7' : 'var(--card)';
+ const brd = isLast ? '2px solid #16a34a' : '1px solid var(--border)';
+ return 'Шаг '+(i+1)+':'+s+'
';
+ }).join('');
+ renderMath(qEl);
+ renderMath(stepsEl);
+ if(shown >= t.steps.length){
+ seen.add(cur);
+ if(!_done && seen.size >= 5){ _done = true; addXp(10, 'p7-iv1'); bumpProgress('p7', 15); }
+ }
+ }
+ function load(n){ cur = Math.max(0, Math.min(TASKS.length - 1, n)); shown = 1; render(); }
+ sn.addEventListener('input', () => load((+sn.value) - 1));
+ nextBtn.addEventListener('click', () => {
+ if(shown < TASKS[cur].steps.length){ shown++; render(); }
+ });
+ allBtn.addEventListener('click', () => { shown = TASKS[cur].steps.length; render(); });
+ resetBtn.addEventListener('click', () => { shown = 1; render(); });
+ load(0);
+ })();
+
+ /* === IV2 — калькулятор === */
+ (function(){
+ const modes = ['prod','quot','pow','base'];
+ const inputsEl = document.getElementById('p7-iv2-inputs');
+ const outEl = document.getElementById('p7-iv2-out');
+ const fbEl = document.getElementById('p7-iv2-fb');
+ const goBtn = document.getElementById('p7-iv2-go');
+ let mode = 'prod';
+ let used = new Set();
+ let _done = false;
+
+ function setMode(m){
+ mode = m;
+ modes.forEach(mm => {
+ const btn = document.getElementById('p7-iv2-m-'+mm);
+ if(btn) btn.classList.toggle('primary', mm === m);
+ });
+ fbEl.style.display = 'none';
+ outEl.innerHTML = 'Нажми «Вычислить», чтобы увидеть шаги.';
+ if(m === 'prod'){
+ inputsEl.innerHTML =
+ '$a$ ='+
+ ''+
+ '$b$ ='+
+ ''+
+ '$c$ ='+
+ '';
+ } else if(m === 'quot'){
+ inputsEl.innerHTML =
+ '$a$ ='+
+ ''+
+ '$b$ ='+
+ ''+
+ '$c$ ='+
+ '';
+ } else if(m === 'pow'){
+ inputsEl.innerHTML =
+ '$a$ ='+
+ ''+
+ '$b$ ='+
+ ''+
+ '$n$ ='+
+ '';
+ } else { // base
+ inputsEl.innerHTML =
+ '$a$ ='+
+ ''+
+ '$b$ ='+
+ ''+
+ '$c$ ='+
+ '';
+ }
+ renderMath(inputsEl);
+ }
+ modes.forEach(m => {
+ const btn = document.getElementById('p7-iv2-m-'+m);
+ if(btn) btn.addEventListener('click', () => setMode(m));
+ });
+ setMode('prod');
+
+ function num(id){ const el = document.getElementById(id); return el ? +el.value : NaN; }
+ function r(n){ return (Math.abs(n - Math.round(n)) < 1e-9) ? Math.round(n) : (+n.toFixed(4)); }
+
+ goBtn.addEventListener('click', () => {
+ fbEl.style.display = 'none';
+ const a = num('p7-iv2-a'), b = num('p7-iv2-b'), c = num('p7-iv2-c'), n = num('p7-iv2-n');
+ // Базовая валидация
+ if(mode !== 'pow'){
+ if(!isFinite(a) || a <= 0 || a === 1 || !isFinite(b) || b <= 0 || !isFinite(c) || c <= 0){
+ feedback(fbEl, false, '✗ Требуется $a > 0$, $a \\ne 1$, $b > 0$, $c > 0$.'); return;
+ }
+ } else {
+ if(!isFinite(a) || a <= 0 || a === 1 || !isFinite(b) || b <= 0 || !isFinite(n)){
+ feedback(fbEl, false, '✗ Требуется $a > 0$, $a \\ne 1$, $b > 0$.'); return;
+ }
+ }
+ let out = '';
+ if(mode === 'prod'){
+ const sum = Math.log(b*c) / Math.log(a);
+ const lb = Math.log(b) / Math.log(a);
+ const lc = Math.log(c) / Math.log(a);
+ out =
+ '$\\log_{'+r(a)+'}('+r(b)+' \\cdot '+r(c)+') = \\log_{'+r(a)+'} '+r(b)+' + \\log_{'+r(a)+'} '+r(c)+'$
'+
+ '$= '+r(lb)+' + '+r(lc)+' \\approx '+r(sum)+'$
'+
+ 'Проверка через Math.log: $\\log_{'+r(a)+'}('+r(b*c)+') \\approx '+r(sum)+'$.
';
+ } else if(mode === 'quot'){
+ const diff = Math.log(b/c) / Math.log(a);
+ const lb = Math.log(b) / Math.log(a);
+ const lc = Math.log(c) / Math.log(a);
+ out =
+ '$\\log_{'+r(a)+'} \\dfrac{'+r(b)+'}{'+r(c)+'} = \\log_{'+r(a)+'} '+r(b)+' - \\log_{'+r(a)+'} '+r(c)+'$
'+
+ '$= '+r(lb)+' - '+r(lc)+' \\approx '+r(diff)+'$
'+
+ 'Проверка: $\\log_{'+r(a)+'}('+r(b/c)+') \\approx '+r(diff)+'$.
';
+ } else if(mode === 'pow'){
+ const lb = Math.log(b) / Math.log(a);
+ const val = n * lb;
+ out =
+ '$\\log_{'+r(a)+'} '+r(b)+'^{'+r(n)+'} = '+r(n)+' \\cdot \\log_{'+r(a)+'} '+r(b)+'$
'+
+ '$= '+r(n)+' \\cdot '+r(lb)+' \\approx '+r(val)+'$
'+
+ 'Проверка: $\\log_{'+r(a)+'}('+r(Math.pow(b,n))+') \\approx '+r(val)+'$.
';
+ } else { // base
+ if(c === 1){ feedback(fbEl, false, '✗ Новое основание $c$ не должно быть равно $1$.'); return; }
+ const lab = Math.log(b) / Math.log(a);
+ const lcb = Math.log(b) / Math.log(c);
+ const lca = Math.log(a) / Math.log(c);
+ out =
+ '$\\log_{'+r(a)+'} '+r(b)+' = \\dfrac{\\log_{'+r(c)+'} '+r(b)+'}{\\log_{'+r(c)+'} '+r(a)+'}$
'+
+ '$\\approx \\dfrac{'+r(lcb)+'}{'+r(lca)+'} \\approx '+r(lab)+'$
'+
+ 'Прямое значение: $\\log_{'+r(a)+'} '+r(b)+' \\approx '+r(lab)+'$.
';
+ }
+ outEl.innerHTML = out;
+ renderMath(outEl);
+ used.add(mode);
+ if(!_done && used.size >= 3){ _done = true; addXp(10, 'p7-iv2'); bumpProgress('p7', 15); }
+ });
+ })();
+
+ /* === IV3 — DnD-сортер === */
+ (function(){
+ const items = [
+ {id:'s1', html:'$\\log_2 8 + \\log_2 4$', cat:'v5'},
+ {id:'s2', html:'$\\log_3 81 - \\log_3 3$', cat:'v3'},
+ {id:'s3', html:'$2 \\log_5 5$', cat:'v2'},
+ {id:'s4', html:'$\\log_2 32 - \\log_2 8$', cat:'v2'},
+ {id:'s5', html:'$\\log_3 9 + \\log_3 3$', cat:'v3'},
+ {id:'s6', html:'$\\log_2 \\sqrt[3]{8}$', cat:'v1'},
+ {id:'s7', html:'$\\log_5 125 + \\log_5 1$', cat:'v3'},
+ {id:'s8', html:'$\\log_4 16 + \\log_4 4$', cat:'v3'}
+ ];
+ const cats = ['v1','v2','v3','v5'];
+ const sorter = setupSorter({
+ poolId: 'p7-iv3-pool',
+ scopeSelector: '#p7-iv3',
+ items, cats
+ });
+ const checkBtn = document.getElementById('p7-iv3-check');
+ const resetBtn = document.getElementById('p7-iv3-reset');
+ const fbEl = document.getElementById('p7-iv3-fb');
+ let _done = false;
+
+ checkBtn.addEventListener('click', () => {
+ let ok = 0, total = items.length;
+ let missed = [];
+ items.forEach(it => {
+ if(sorter.placed[it.id] === it.cat) ok++;
+ else if(!sorter.placed[it.id]) missed.push(it.id);
+ });
+ if(ok === total){
+ feedback(fbEl, true, '✓ Отлично! Все 8 выражений на месте.');
+ if(!_done){ _done = true; addXp(15, 'p7-iv3'); bumpProgress('p7', 25); }
+ } else {
+ const left = missed.length;
+ feedback(fbEl, false, '✗ Верно: '+ok+' / '+total+'. '+(left ? 'Не размещено: '+left+'.' : 'Проверь свойства логарифмов.'));
+ }
+ });
+ resetBtn.addEventListener('click', () => {
+ sorter.reset();
+ fbEl.style.display = 'none';
+ });
+ })();
+
+ /* === IV4 — тренажёр === */
+ (function(){
+ const TASKS = [
+ { q: '$\\log_2 6 + \\log_2 \\dfrac{16}{3}$', a: 5, hint: '$\\log_2(6 \\cdot 16/3) = \\log_2 32 = 5$.' },
+ { q: '$\\log_3 \\sqrt{27}$', a: 1.5, hint: '$\\dfrac{1}{2} \\log_3 27 = \\dfrac{3}{2}$.' },
+ { q: '$\\log_5 100 - \\log_5 4$', a: 2, hint: '$\\log_5 (100/4) = \\log_5 25 = 2$.' },
+ { q: '$\\log_4 64$', a: 3, hint: '$\\log_{2^2} 2^6 = 6/2 = 3$.' },
+ { q: '$\\log_2 3 \\cdot \\log_3 8$', a: 3, hint: '$\\log_2 3 \\cdot \\dfrac{\\log_2 8}{\\log_2 3} = \\log_2 8 = 3$.' },
+ { q: '$\\dfrac{\\lg 100}{\\lg 10}$', a: 2, hint: '$\\lg 100 / \\lg 10 = 2/1 = 2$.' }
+ ];
+ const qEl = document.getElementById('p7-iv4-q');
+ const ansEl = document.getElementById('p7-iv4-ans');
+ const goBtn = document.getElementById('p7-iv4-go');
+ const startBtn = document.getElementById('p7-iv4-start');
+ const iEl = document.getElementById('p7-iv4-i');
+ const sEl = document.getElementById('p7-iv4-s');
+ const fbEl = document.getElementById('p7-iv4-fb');
+ let idx = 0, score = 0;
+ let _done = false;
+
+ function render(){
+ iEl.textContent = (idx + 1);
+ sEl.textContent = score;
+ if(idx >= TASKS.length){
+ qEl.innerHTML = 'Все задачи решены! Очков: '+score+' / '+TASKS.length+'.';
+ ansEl.disabled = true; goBtn.disabled = true;
+ if(!_done){ _done = true; addXp(15, 'p7-iv4'); bumpProgress('p7', 25); }
+ renderMath(qEl);
+ return;
+ }
+ qEl.innerHTML = TASKS[idx].q;
+ ansEl.value = '';
+ ansEl.disabled = false; goBtn.disabled = false;
+ fbEl.style.display = 'none';
+ renderMath(qEl);
+ setTimeout(() => ansEl.focus(), 30);
+ }
+ goBtn.addEventListener('click', () => {
+ if(idx >= TASKS.length) return;
+ const v = +ansEl.value;
+ if(!isFinite(v) || ansEl.value === ''){ feedback(fbEl, false, '✗ Введи число.'); return; }
+ const t = TASKS[idx];
+ if(Math.abs(v - t.a) < 0.05){
+ score++; sEl.textContent = score;
+ feedback(fbEl, true, '✓ Верно! '+t.hint);
+ setTimeout(() => { idx++; render(); }, 950);
+ } else {
+ feedback(fbEl, false, '✗ Неверно. Подсказка: '+t.hint+' Правильный ответ: '+t.a+'.');
+ setTimeout(() => { idx++; render(); }, 1900);
+ }
+ });
+ ansEl.addEventListener('keydown', e => { if(e.key === 'Enter'){ e.preventDefault(); goBtn.click(); } });
+ startBtn.addEventListener('click', () => { idx = 0; score = 0; _done = false; render(); });
+ render();
+ })();
+
wireReadBtn('p7');
}