diff --git a/frontend/textbooks/physics_8_ch3.html b/frontend/textbooks/physics_8_ch3.html
index 2539333..642f206 100644
--- a/frontend/textbooks/physics_8_ch3.html
+++ b/frontend/textbooks/physics_8_ch3.html
@@ -259,46 +259,47 @@ const ACH_LABELS = {
p38_done:"Построение изображений в тонких линзах освоен!",
p39_done:"Глаз как оптическая система освоен!",
p40_done:"Дефекты зрения. Очки освоен!",
- ch3_done:"Глава 3 пройдена!"
+ ch3_done:"Глава 3 пройдена!",
+ light_master:"Мастер света — все боссы главы 3 повержены!"
};
const SIDEBARS = {
- p32:{title:"Шпаргалка § 32",rows:[["В разработке","Phase 5 Wave 1"]]},
- p33:{title:"Шпаргалка § 33",rows:[["В разработке","Phase 5 Wave 1"]]},
- p34:{title:"Шпаргалка § 34",rows:[["В разработке","Phase 5 Wave 2"]]},
- p35:{title:"Шпаргалка § 35",rows:[["В разработке","Phase 5 Wave 2"]]},
- p36:{title:"Шпаргалка § 36",rows:[["В разработке","Phase 5 Wave 3"]]},
- p37:{title:"Шпаргалка § 37",rows:[["В разработке","Phase 5 Wave 3"]]},
- p38:{title:"Шпаргалка § 38",rows:[["В разработке","Phase 5 Wave 4"]]},
- p39:{title:"Шпаргалка § 39",rows:[["В разработке","Phase 5 Wave 4"]]},
- p40:{title:"Шпаргалка § 40",rows:[["В разработке","Phase 5 Wave 4"]]},
- final3:{title:"Шпаргалка ★",rows:[["В разработке","Phase 5 Wave 4"]]}
+ p32:{title:"Шпаргалка § 32",rows:[["Источники","естественные / искусствен."],["Тепловые","Солнце, лампа, костёр"],["Люминесцентные","экран, светодиод"],["Точечный","размер $\\ll$ расстояния"]]},
+ p33:{title:"Шпаргалка § 33",rows:[["$c$","$3 \\cdot 10^8$ м/с"],["В вакууме","максимальна"],["Прямолинейно","в однородн. среде"],["Тень","полное отсутствие света"],["Полутень","точечн. источник $\\to$ тень; протяжённый $\\to$ + полутень"]]},
+ p34:{title:"Шпаргалка § 34",rows:[["Закон","$\\alpha = \\beta$"],["От нормали","углы измеряют"],["Диффузное","шероховатая поверхность"],["Зеркальное","гладкая, отражает в одном направлении"]]},
+ p35:{title:"Шпаргалка § 35",rows:[["Изображение","мнимое, прямое, равное"],["Симметрия","относит. плоскости зеркала"],["Расстояние","предмет $=$ изобр. от зеркала"],["Размер","совпадает"]]},
+ p36:{title:"Шпаргалка § 36",rows:[["Закон Снеллиуса","$\\sin\\alpha/\\sin\\beta = n$"],["Из воздуха в воду","$\\alpha > \\beta$"],["Из воды в воздух","$\\alpha < \\beta$"],["$n$ воды","$1{,}33$"],["$n$ стекла","$1{,}5$"]]},
+ p37:{title:"Шпаргалка § 37",rows:[["Собирающая","выпукл., $F > 0$"],["Рассеивающая","вогн., $F < 0$"],["Оптическая сила","$D = 1/F$"],["[D]","дптр $=$ 1/м"],["Очки $+1$","$F = 1$ м"]]},
+ p38:{title:"Шпаргалка § 38",rows:[["Формула","$1/F = 1/d + 1/f$"],["3 «золотых» луча","через центр, парал. оси, через $F$"],["$d > 2F$","умен., перевёрн., действ."],["$d < F$","увел., прямое, мнимое (как лупа)"]]},
+ p39:{title:"Шпаргалка § 39",rows:[["Хрусталик","биол. линза"],["Аккомодация","изменение $F$ хрусталика"],["Сетчатка","экран"],["Расст. наилуч. зрения","25 см"]]},
+ p40:{title:"Шпаргалка § 40",rows:[["Близоруков.","изобр. перед сетч., $D < 0$ (рассеив.)"],["Дальнозоркость","изобр. за сетч., $D > 0$ (собир.)"]]},
+ final3:{title:"Финал главы 3",rows:[["§§32-40","свет"],["Награда","+50 XP + «Мастер света»"]]}
};
const TIPS=[
- {sec:'p32',html:"Параграф § 32 будет реализован в Phase 5 Wave 1. Используем хелперы из phys.js и optics.js."},
- {sec:'p33',html:"Параграф § 33 будет реализован в Phase 5 Wave 1. Используем хелперы из phys.js и optics.js."},
- {sec:'p34',html:"Параграф § 34 будет реализован в Phase 5 Wave 2. Используем хелперы из phys.js и optics.js."},
- {sec:'p35',html:"Параграф § 35 будет реализован в Phase 5 Wave 2. Используем хелперы из phys.js и optics.js."},
- {sec:'p36',html:"Параграф § 36 будет реализован в Phase 5 Wave 3. Используем хелперы из phys.js и optics.js."},
- {sec:'p37',html:"Параграф § 37 будет реализован в Phase 5 Wave 3. Используем хелперы из phys.js и optics.js."},
- {sec:'p38',html:"Параграф § 38 будет реализован в Phase 5 Wave 4. Используем хелперы из phys.js и optics.js."},
- {sec:'p39',html:"Параграф § 39 будет реализован в Phase 5 Wave 4. Используем хелперы из phys.js и optics.js."},
- {sec:'p40',html:"Параграф § 40 будет реализован в Phase 5 Wave 4. Используем хелперы из phys.js и optics.js."},
- {sec:'final3',html:"Параграф ★ будет реализован в Phase 5 Wave 4. Используем хелперы из phys.js и optics.js."}
+ {sec:'p32',html:"Свет излучают источники — тепловые (Солнце, лампа накаливания) или люминесцентные (светодиоды, экраны). Источник, размер которого много меньше расстояния, называют точечным ."},
+ {sec:'p33',html:"В вакууме свет летит со скоростью $c = 3 \\cdot 10^8$ м/с — это рекорд природы. От Солнца до Земли (150 млн км) свет идёт ~8 минут. В однородной среде свет распространяется прямолинейно — отсюда тени."},
+ {sec:'p34',html:"Закон отражения: угол падения $=$ угол отражения, оба от нормали. Гладкая поверхность даёт зеркальное отражение, шероховатая — диффузное . Луна светит отражённым светом Солнца — это диффузное отражение от её поверхности."},
+ {sec:'p35',html:"Зеркало даёт мнимое изображение: оно «за» зеркалом, на том же расстоянии, что и предмет, и тех же размеров. Симметричное относительно плоскости зеркала."},
+ {sec:'p36',html:"При переходе из одной среды в другую луч меняет направление — это преломление . $\\sin\\alpha/\\sin\\beta = n$. Из воздуха в воду $n = 1{,}33$ — угол $\\beta$ меньше угла $\\alpha$."},
+ {sec:'p37',html:"Линза — прозрачное тело, ограниченное двумя сферическими поверхностями. Собирающая (двусторонне выпуклая) фокусирует параллельные лучи в точку $F$. Оптическая сила $D = 1/F$, [D] = дптр. У очков $+2$ дптр $F = 0{,}5$ м."},
+ {sec:'p38',html:"Три «золотых» луча: 1) через центр линзы — без преломления; 2) параллельно оси — после линзы через $F$; 3) через ближний $F$ — после линзы параллельно оси. Точка их пересечения — изображение."},
+ {sec:'p39',html:"Глаз — оптическая система. Свет проходит через роговицу и хрусталик (биологическая собирающая линза) и фокусируется на сетчатке . При изменении расстояния мышцы меняют форму хрусталика — это аккомодация ."},
+ {sec:'p40',html:"Близорукость : изображение фокусируется перед сетчаткой. Лечится рассеивающими линзами ($D < 0$). Дальнозоркость : фокус за сетчаткой. Лечится собирающими линзами ($D > 0$)."},
+ {sec:'final3',html:"Финал — 7 боссов по 9 параграфам оптики: отражение, преломление, линзы, очки. +50 XP и ачивка «Мастер света»."}
];
const BUILDERS = {
- p32: ()=>{ const box=document.getElementById('p32-body'); box.innerHTML = buildStub('p32', 'Источники света', 'Phase 5 Wave 1') + secNavFor('p32') + readButton('p32'); renderMath(box); wireReadBtn('p32'); },
- p33: ()=>{ const box=document.getElementById('p33-body'); box.innerHTML = buildStub('p33', 'Скорость света. Прямолинейное распространение света', 'Phase 5 Wave 1') + secNavFor('p33') + readButton('p33'); renderMath(box); wireReadBtn('p33'); },
- p34: ()=>{ const box=document.getElementById('p34-body'); box.innerHTML = buildStub('p34', 'Отражение света', 'Phase 5 Wave 2') + secNavFor('p34') + readButton('p34'); renderMath(box); wireReadBtn('p34'); },
- p35: ()=>{ const box=document.getElementById('p35-body'); box.innerHTML = buildStub('p35', 'Зеркала. Изображение в плоском зеркале', 'Phase 5 Wave 2') + secNavFor('p35') + readButton('p35'); renderMath(box); wireReadBtn('p35'); },
- p36: ()=>{ const box=document.getElementById('p36-body'); box.innerHTML = buildStub('p36', 'Преломление света', 'Phase 5 Wave 3') + secNavFor('p36') + readButton('p36'); renderMath(box); wireReadBtn('p36'); },
- p37: ()=>{ const box=document.getElementById('p37-body'); box.innerHTML = buildStub('p37', 'Линзы. Оптическая сила линзы', 'Phase 5 Wave 3') + secNavFor('p37') + readButton('p37'); renderMath(box); wireReadBtn('p37'); },
- p38: ()=>{ const box=document.getElementById('p38-body'); box.innerHTML = buildStub('p38', 'Построение изображений в тонких линзах', 'Phase 5 Wave 4') + secNavFor('p38') + readButton('p38'); renderMath(box); wireReadBtn('p38'); },
- p39: ()=>{ const box=document.getElementById('p39-body'); box.innerHTML = buildStub('p39', 'Глаз как оптическая система', 'Phase 5 Wave 4') + secNavFor('p39') + readButton('p39'); renderMath(box); wireReadBtn('p39'); },
- p40: ()=>{ const box=document.getElementById('p40-body'); box.innerHTML = buildStub('p40', 'Дефекты зрения. Очки', 'Phase 5 Wave 4') + secNavFor('p40') + readButton('p40'); renderMath(box); wireReadBtn('p40'); },
- final3: ()=>{ const box=document.getElementById('final3-body'); box.innerHTML = buildStub('final3', 'Финал главы', 'Phase 5 Wave 4') + secNavFor('final3') + readButton('final3'); renderMath(box); wireReadBtn('final3'); }
+ p32: ()=>{ build_p32(); },
+ p33: ()=>{ build_p33(); },
+ p34: ()=>{ build_p34(); },
+ p35: ()=>{ build_p35(); },
+ p36: ()=>{ build_p36(); },
+ p37: ()=>{ build_p37(); },
+ p38: ()=>{ build_p38(); },
+ p39: ()=>{ build_p39(); },
+ p40: ()=>{ build_p40(); },
+ final3: ()=>{ build_final3(); }
};
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
@@ -638,6 +639,644 @@ function initSidebarToggle(){
document.addEventListener('keydown',e=>{ if(e.key==='Escape') close(); });
}
+/* ======================================================================
+ PHASE 5 — Глава 3 «Световые явления» (§32-40 + Финал)
+ ====================================================================== */
+
+const _SIMS = {};
+function _killSim(key){ if(_SIMS[key] && _SIMS[key].raf){ cancelAnimationFrame(_SIMS[key].raf); _SIMS[key].raf=0; } }
+function _isVisible(secId){ const el=document.getElementById('sec-'+secId); return el && el.classList.contains('active'); }
+
+/* ======== §32 — Источники света ======== */
+function build_p32(){
+ const box = document.getElementById('p32-body'); let h = '';
+ h += makeCard('theory', 'Источники света', '§ 32.1',
+ '
Источник света — тело, которое излучает свет. Их делят на 2 группы:
'
+ +''
+ +'Естественные : Солнце, звёзды, молния, светящиеся насекомые (светляки). '
+ +'Искусственные : лампа, костёр, свеча, светодиод, экран. '
+ +' '
+ +'Сами по себе не светят : Луна (отражает свет Солнца), книги, стены — все они освещены.
'
+ );
+ h += makeCard('rule', 'Тепловые и люминесцентные', '§ 32.2',
+ 'Тепловые источники излучают свет благодаря высокой температуре:
'
+ +'Солнце ($\\sim 6000$ °C); лампа накаливания ($\\sim 2500$ °C); пламя свечи ($\\sim 1000$ °C). '
+ +'Люминесцентные — холодные, свет за счёт квантовых процессов:
'
+ +'светодиоды, светофоры; светляки, гнилое дерево, медузы; люминесцентные лампы. '
+ );
+ h += makeCard('example', 'Точечный и протяжённый', '§ 32.3',
+ 'Если размер источника много меньше расстояния до объекта — его называют точечным . Дальняя звезда — точечный источник.
'
+ +'Протяжённый — например, длинная лампа на потолке. Он даёт мягкий свет без чётких теней.
'
+ );
+ h += ''
+ +'
Определи: источник света или просто освещённое тело.
'
+ +'
'
+ +'
Следующий
'
+ +'
Раунд: 1 /8 Правильно: 0
';
+ h += ''
+ +'
Определи природу источника.
'
+ +'
'
+ +'
Следующий
'
+ +'
Раунд: 1 /6 Правильно: 0
';
+ h += ''
+ +'
Распредели источники.
'
+ +'
'
+ +'
'
+ +'
Проверить Сброс
'
+ +'
';
+ h += ''
+ +'
4+ — +15 XP.
'
+ +'
'
+ +'
Вопрос: 1 /6 Правильно: 0
';
+ box.innerHTML = h + secNavFor('p32') + readButton('p32');
+ renderMath(box); wireReadBtn('p32');
+ _p32_quiz1(); _p32_quiz2(); _p32_dnd(); _p32_mcq();
+}
+function _p32_quiz1(){
+ const QS = [
+ {it:'Луна', ans:'O', why:'Луна отражает свет Солнца.'},
+ {it:'Солнце', ans:'S', why:'Сам излучает.'},
+ {it:'Светлячок', ans:'S', why:'Биолюминесценция.'},
+ {it:'Зеркало', ans:'O', why:'Только отражает.'},
+ {it:'Лампа', ans:'S', why:'Излучает.'},
+ {it:'Кошачьи глаза в темноте', ans:'O', why:'Отражают свет фонаря.'},
+ {it:'Молния', ans:'S', why:'Электр. разряд излучает свет.'},
+ {it:'Венера', ans:'O', why:'Отражает свет Солнца.'}
+ ];
+ let i = 0, ok = 0;
+ function r(){
+ const q = QS[i]; const w = document.getElementById('p32-quiz');
+ w.innerHTML = ''+q.it+'
'
+ +'Светит сам Отражает
'
+ +'
';
+ document.getElementById('p32-quiz-r').textContent = (i+1);
+ document.getElementById('p32-quiz-ok').textContent = ok;
+ w.querySelectorAll('[data-p]').forEach(b=>{
+ b.addEventListener('click', ()=>{
+ if(b.disabled) return; w.querySelectorAll('[data-p]').forEach(x=>x.disabled=true);
+ const fb = document.getElementById('p32-q1-fb');
+ if(b.dataset.p === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+q.why; addXp(2,'p32-q1'); bumpProgress('p32',3); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ '+q.why; }
+ document.getElementById('p32-quiz-ok').textContent = ok;
+ });
+ });
+ }
+ document.getElementById('p32-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; r(); });
+ r();
+}
+function _p32_quiz2(){
+ const QS = [
+ {it:'Солнце', ans:'T', why:'Высокая температура.'},
+ {it:'Светодиод', ans:'L', why:'Квантовый эффект.'},
+ {it:'Костёр', ans:'T', why:'Горение, $T \\sim 1000$ °C.'},
+ {it:'Светляк', ans:'L', why:'Холодная биолюминесценция.'},
+ {it:'Лампа накаливания', ans:'T', why:'Нить нагревается до 2500 °C.'},
+ {it:'Экран смартфона', ans:'L', why:'Светодиоды излучают холодно.'}
+ ];
+ let i = 0, ok = 0;
+ function r(){
+ const q = QS[i]; const w = document.getElementById('p32-quiz2');
+ w.innerHTML = ''+q.it+'
'
+ +'Тепловой Люминесцентный
'
+ +'
';
+ document.getElementById('p32-q2-r').textContent = (i+1);
+ document.getElementById('p32-q2-ok').textContent = ok;
+ w.querySelectorAll('[data-p]').forEach(b=>{
+ b.addEventListener('click', ()=>{
+ if(b.disabled) return; w.querySelectorAll('[data-p]').forEach(x=>x.disabled=true);
+ const fb = document.getElementById('p32-q2-fb');
+ if(b.dataset.p === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+q.why; addXp(2,'p32-q2'); bumpProgress('p32',3); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ '+q.why; }
+ document.getElementById('p32-q2-ok').textContent = ok;
+ });
+ });
+ }
+ document.getElementById('p32-q2-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; r(); });
+ r();
+}
+function _p32_dnd(){
+ const items = [
+ {id:'a',cat:'nat',html:'Солнце'},{id:'b',cat:'nat',html:'молния'},{id:'c',cat:'nat',html:'светляк'},{id:'d',cat:'nat',html:'звезда'},
+ {id:'e',cat:'art',html:'лампа'},{id:'f',cat:'art',html:'светодиод'},{id:'g',cat:'art',html:'свеча'},{id:'h',cat:'art',html:'экран'}
+ ];
+ const dnd = setupSorter({ poolId:'p32-dnd-pool', scopeSelector:'#sec-p32', cats:['nat','art'], items, columnLayout:false });
+ document.getElementById('p32-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p32-dnd-fb'); let wr = 0;
+ items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wr++; });
+ if(wr===0){ fb.className='feedback ok'; fb.innerHTML='✓ +15 XP'; addXp(15,'p32-dnd'); bumpProgress('p32',20); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wr+'.'; }
+ });
+ document.getElementById('p32-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); document.getElementById('p32-dnd-fb').style.display='none'; });
+}
+function _p32_mcq(){
+ const QS = [
+ {q:'Какое тело — источник света?',opts:['Луна','лампа','зеркало','страница'],ans:1,why:'Лампа излучает свет.'},
+ {q:'Что общего у Солнца и лампы накаливания?',opts:['обе люминесцентные','тепловые','холодные','одинаковая T'],ans:1,why:'Светят за счёт нагрева.'},
+ {q:'Светодиод — это …',opts:['тепловой','люминесцентный','зеркало','не источник'],ans:1,why:'Холодный квантовый источник.'},
+ {q:'Точечный источник — это …',opts:['любой','размер $\\ll$ расстояния','шар','точка'],ans:1,why:'Малый по сравнению с расстоянием.'},
+ {q:'Луна светит потому что …',opts:['горит','отражает свет Солнца','имеет атомную реакцию','остывает'],ans:1,why:'Отражает солнечный свет.'},
+ {q:'Какой источник самый «холодный»?',opts:['Солнце','свеча','светляк','лампа'],ans:2,why:'Биолюминесценция идёт при обычной T.'}
+ ];
+ let i = 0, ok = 0, done = 0, aw = false;
+ function r(){
+ const q = QS[i]; const w = document.getElementById('p32-mcq');
+ let h = ''+(i+1)+'. '+q.q+'
';
+ q.opts.forEach((o,k)=>{ h += ''+String.fromCharCode(65+k)+'. '+o+' '; });
+ h += '
Следующий
';
+ w.innerHTML = h;
+ document.getElementById('p32-mcq-i').textContent = (i+1);
+ document.getElementById('p32-mcq-ok').textContent = ok;
+ w.querySelectorAll('[data-k]').forEach(b=>{
+ b.addEventListener('click', ()=>{
+ if(b.disabled) return; w.querySelectorAll('[data-k]').forEach(x=>x.disabled=true);
+ const k = +b.dataset.k; const fb = document.getElementById('p32-mcq-fb');
+ if(k===q.ans){ ok++; done++; fb.className='feedback ok'; fb.innerHTML='✓ '+q.why; addXp(2,'p32-mcq'); bumpProgress('p32',3); }
+ else { done++; fb.className='feedback fail'; fb.innerHTML='✗ '+q.why; }
+ document.getElementById('p32-mcq-ok').textContent = ok;
+ if(done >= QS.length && !aw && ok >= 4){ aw = true; setTimeout(()=>{ const f=document.getElementById('p32-mcq-fb'); f.className='feedback ok'; f.innerHTML='✓ +15 XP — тренажёр пройден.'; addXp(15,'p32-bonus'); bumpProgress('p32',15); }, 500); }
+ });
+ });
+ document.getElementById('p32-mcq-n').addEventListener('click', ()=>{ i=(i+1)%QS.length; r(); });
+ }
+ r();
+}
+
+/* ======== §33 — Скорость света. Прямолинейное распространение ======== */
+function build_p33(){
+ const box = document.getElementById('p33-body'); let h = '';
+ h += makeCard('theory', 'Скорость света', '§ 33.1',
+ 'В вакууме свет распространяется со скоростью :
'
+ +'$$c = 3 \\cdot 10^8 \\text{ м/с} = 300\\,000 \\text{ км/с}$$
'
+ +'Это максимальная скорость в природе. Никакое тело не может двигаться быстрее.
'
+ +''
+ +'От Солнца до Земли (150 млн км): $\\sim 8$ минут . '
+ +'От Луны до Земли (384 тыс. км): $\\sim 1{,}3$ с . '
+ +'За 1 с свет пролетает в 7,5 раза вокруг Земли. '
+ +' '
+ +'В воде и стекле свет идёт медленнее: $v = c/n$.
'
+ );
+ h += makeCard('rule', 'Прямолинейное распространение', '§ 33.2',
+ 'В однородной среде свет распространяется по прямой линии. Это видно по лазерному лучу в пыльной комнате.
'
+ +'Следствие: на пути луча возникает тень от непрозрачного предмета. Тень повторяет силуэт предмета.
'
+ );
+ h += makeCard('example', 'Тень и полутень', '§ 33.3',
+ 'Если источник точечный , то за предметом образуется только тень — резкая.
'
+ +'Если источник протяжённый , то к тени добавляется полутень — переходная зона.
'
+ +'Затмения Солнца и Луны — это «космические» тени:
'
+ +'солнечное затмение — Луна закрывает Солнце для нас; лунное — Земля закрывает Солнце для Луны. '
+ );
+ h += '';
+ h += ''
+ +'
Сколько секунд свет летит до объекта?
'
+ +'
Расстояние, км: 150000000
'
+ +'
Время в пути: 500 с 8.3 мин
';
+ h += ''
+ +'
'
+ +'
'
+ +'
Проверить Сброс
'
+ +'
';
+ h += ''
+ +'
$c = 3 \\cdot 10^8$ м/с. 4+ — +15 XP.
'
+ +'
'
+ +'
Задача: 1 /5 Правильно: 0
';
+ box.innerHTML = h + secNavFor('p33') + readButton('p33');
+ renderMath(box); wireReadBtn('p33');
+ _p33_shadow(); _p33_calc(); _p33_dnd(); _p33_tasks();
+}
+function _p33_shadow(){
+ const svg = document.getElementById('p33-sim'); if(!svg) return;
+ function draw(){
+ const sSize = +document.getElementById('p33-s').value;
+ const dist = +document.getElementById('p33-d').value;
+ document.getElementById('p33-sv').textContent = sSize === 0 ? 'точечный' : sSize < 20 ? 'малый' : 'большой';
+ document.getElementById('p33-dv').textContent = dist;
+ let s = '';
+ /* источник слева */
+ const srcX = 50, srcY = 110;
+ if(sSize === 0){ s += ' '; }
+ else { s += ' '; }
+ s += 'источник ';
+ /* непрозрачный объект */
+ const objX = srcX + dist*0.5, objY = 110;
+ s += ' ';
+ /* экран справа */
+ const screenX = 400;
+ s += ' ';
+ /* лучи от краёв источника к краям объекта и дальше на экран */
+ const sTop = srcY - sSize/2, sBot = srcY + sSize/2;
+ const oTop = objY - 20, oBot = objY + 20;
+ /* лучи без полутени (от центра источника к краям объекта): тень */
+ const k1 = (oTop - srcY) / (objX - srcX);
+ const yShTop = srcY + k1 * (screenX - srcX);
+ const k2 = (oBot - srcY) / (objX - srcX);
+ const yShBot = srcY + k2 * (screenX - srcX);
+ /* лучи полутени (от противоположного края источника к краям объекта) */
+ const kp1 = (oTop - sBot) / (objX - srcX);
+ const yPenTop = sBot + kp1 * (screenX - srcX);
+ const kp2 = (oBot - sTop) / (objX - srcX);
+ const yPenBot = sTop + kp2 * (screenX - srcX);
+ /* рисуем зоны */
+ if(sSize > 0){
+ /* полутень — между yPenTop и yShTop, и между yShBot и yPenBot */
+ s += ' ';
+ s += ' ';
+ }
+ /* тень */
+ s += ' ';
+ /* лучи света */
+ s += ' ';
+ s += ' ';
+ /* подписи */
+ s += 'экран ';
+ if(sSize > 0) s += 'тень + полутень ';
+ else s += 'только тень (источник точечный) ';
+ svg.innerHTML = s;
+ }
+ document.getElementById('p33-s').addEventListener('input', draw);
+ document.getElementById('p33-d').addEventListener('input', draw);
+ draw();
+}
+function _p33_calc(){
+ function u(){
+ const r = +document.getElementById('p33-r').value;
+ document.getElementById('p33-rv').textContent = r.toLocaleString('ru');
+ const t = r*1000 / 3e8;
+ document.getElementById('p33-tv').textContent = t.toFixed(2);
+ document.getElementById('p33-tm').textContent = (t/60).toFixed(2);
+ }
+ document.getElementById('p33-r').addEventListener('input', u); u();
+}
+function _p33_dnd(){
+ const items = [
+ {id:'a',cat:'t',html:'$c = 3 \\cdot 10^8$ м/с'},
+ {id:'b',cat:'t',html:'свет идёт прямолинейно в однород. среде'},
+ {id:'c',cat:'t',html:'свет огибает большой объект'},
+ {id:'d',cat:'t',html:'тень — там, куда свет не попал'},
+ {id:'e',cat:'f',html:'свет идёт зигзагом'},
+ {id:'f',cat:'f',html:'свет летит за 1 с до Луны'},
+ {id:'g',cat:'f',html:'тень светлее объекта'},
+ {id:'h',cat:'f',html:'$c$ в воде больше, чем в вакууме'}
+ ];
+ /* исправлю c (cat) — путаница; правильно: «c» как факт — «не правда» */
+ items[2].cat = 'f'; /* свет НЕ огибает (он не дифрагирует значительно на больших объектах в школе) */
+ items[5].cat = 'f'; /* до Луны 1.3 с, не 1 с... но это близко, лучше: убираем спорный */
+ /* для безопасности — переписываем чище */
+ const items2 = [
+ {id:'a',cat:'t',html:'$c = 3 \\cdot 10^8$ м/с'},
+ {id:'b',cat:'t',html:'свет идёт прямолинейно в однород. среде'},
+ {id:'c',cat:'t',html:'тень — место, куда свет не попал'},
+ {id:'d',cat:'t',html:'свет от Солнца идёт ~8 мин'},
+ {id:'e',cat:'f',html:'свет идёт зигзагом'},
+ {id:'f',cat:'f',html:'свет — это поток жидкости'},
+ {id:'g',cat:'f',html:'$c$ в воде больше, чем в вакууме'},
+ {id:'h',cat:'f',html:'свет не отбрасывает тень'}
+ ];
+ const dnd = setupSorter({ poolId:'p33-dnd-pool', scopeSelector:'#sec-p33', cats:['t','f'], items: items2, columnLayout:false });
+ document.getElementById('p33-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p33-dnd-fb'); let wr = 0;
+ items2.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wr++; });
+ if(wr===0){ fb.className='feedback ok'; fb.innerHTML='✓ +15 XP'; addXp(15,'p33-dnd'); bumpProgress('p33',20); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wr+'.'; }
+ });
+ document.getElementById('p33-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); document.getElementById('p33-dnd-fb').style.display='none'; });
+}
+function _p33_tasks(){
+ const TASKS = [
+ {q:'За какое время свет от Солнца дойдёт до Земли? Расстояние $1{,}5 \\cdot 10^{11}$ м. Ответ в минутах (целое).', ans:8, tol:0.5, why:'$t = r/c = 1{,}5\\cdot10^{11}/3\\cdot10^8 = 500$ с $= 8{,}3$ мин.'},
+ {q:'Свет от лампы до глаза: 3 м. Время в наносекундах (1 нс = $10^{-9}$ с)?', ans:10, tol:0.5, why:'$t = 3/3\\cdot10^8 = 10^{-8}$ с = $10$ нс.'},
+ {q:'Луна на расстоянии $384\\,000$ км. Время в секундах (одна цифра после запятой)?', ans:1.3, tol:0.1, why:'$t = 3{,}84\\cdot10^8/3\\cdot10^8 = 1{,}28$ с.'},
+ {q:'Сколько км свет проходит за 1 минуту? Введи в формате $a \\cdot 10^7$ км.', ans:1.8, tol:0.1, why:'$d = c \\cdot 60 = 1{,}8 \\cdot 10^{10}$ м = $1{,}8 \\cdot 10^7$ км.'},
+ {q:'Звук в воздухе $\\sim 340$ м/с. Во сколько раз свет быстрее (порядок: $10^a$, введи $a$)?', ans:6, tol:0.5, why:'$c/v_{зв} = 3\\cdot10^8/340 \\approx 9\\cdot10^5 \\approx 10^6$. Порядок $a = 6$.'}
+ ];
+ let i = 0, ok = 0, done = 0, aw = false;
+ function r(){
+ const t = TASKS[i]; const w = document.getElementById('p33-task');
+ w.innerHTML = ''+(i+1)+'. '+t.q+'
'
+ +'Ответ Подск. След.
'
+ +''+t.why+'
';
+ document.getElementById('p33-task-i').textContent = (i+1);
+ document.getElementById('p33-task-ok').textContent = ok;
+ document.getElementById('p33-tgo').addEventListener('click', ()=>{
+ const v = parseFloat((document.getElementById('p33-tinp').value || '').replace(',','.'));
+ const fb = document.getElementById('p33-tfb');
+ if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Введи число.'; return; }
+ done++;
+ if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+t.why; addXp(4,'p33-task'); bumpProgress('p33',6); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ответ: '+t.ans+'. '+t.why; }
+ document.getElementById('p33-task-ok').textContent = ok;
+ renderMath(w);
+ if(done >= TASKS.length && !aw && ok >= 4){ aw = true; setTimeout(()=>{ const f=document.getElementById('p33-tfb'); f.className='feedback ok'; f.innerHTML='✓ +15 XP — сданы.'; addXp(15,'p33-bonus'); bumpProgress('p33',15); }, 500); }
+ });
+ document.getElementById('p33-thn').addEventListener('click', ()=>{ document.getElementById('p33-tht').classList.toggle('show'); });
+ document.getElementById('p33-tn').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; r(); });
+ renderMath(w);
+ }
+ r();
+}
+
+/* ======== §34 — Отражение света ======== */
+function build_p34(){
+ const box = document.getElementById('p34-body'); let h = '';
+ h += makeCard('theory', 'Закон отражения', '§ 34.1',
+ 'Когда луч света падает на поверхность, часть его отражается. Угол падения $\\alpha$ — между падающим лучом и нормалью к поверхности (перпендикуляром). Угол отражения $\\beta$ — между нормалью и отражённым лучом.
'
+ +'Закон отражения:
'
+ +''
+ +'Падающий, отражённый луч и нормаль лежат в одной плоскости. '
+ +'$\\alpha = \\beta$ (угол падения = угол отражения). '
+ +' '
+ );
+ h += makeCard('rule', 'Зеркальное и диффузное отражение', '§ 34.2',
+ 'Зеркальное — от гладкой поверхности (зеркало, спокойная вода). Все лучи параллельны после отражения.
'
+ +'Диффузное (рассеянное) — от шероховатой поверхности (бумага, стена). Лучи разлетаются во все стороны — поэтому мы видим стену со всех сторон.
'
+ );
+ h += makeCard('example', 'В жизни', '§ 34.3',
+ ''
+ +'Свет фар на мокром асфальте — зеркальное (бликует). '
+ +'Свет от листа бумаги — диффузное. '
+ +'Луна светит Солнечным светом, отражая его диффузно. '
+ +' '
+ );
+ h += ''
+ +'
Меняй угол падения — увидь равный угол отражения.
'
+ +'
$\\alpha$, °: 30
'
+ +'
'
+ +'
$\\alpha$ = 30° $\\beta$ = 30°
';
+ h += ''
+ +'
Определи тип отражения.
'
+ +'
'
+ +'
Следующий
'
+ +'
Раунд: 1 /6 Правильно: 0
';
+ h += ''
+ +'
'
+ +'
'
+ +'
Проверить Сброс
'
+ +'
';
+ h += ''
+ +'
4+ — +15 XP.
'
+ +'
'
+ +'
Задача: 1 /5 Правильно: 0
';
+ box.innerHTML = h + secNavFor('p34') + readButton('p34');
+ renderMath(box); wireReadBtn('p34');
+ _p34_ref(); _p34_quiz(); _p34_dnd(); _p34_tasks();
+}
+function _p34_ref(){
+ const svg = document.getElementById('p34-sim'); if(!svg) return;
+ function d(){
+ const a = +document.getElementById('p34-a').value;
+ document.getElementById('p34-av').textContent = a;
+ document.getElementById('p34-as').textContent = a+'°';
+ document.getElementById('p34-bs').textContent = a+'°';
+ svg.innerHTML = window.OPTICS.reflectRay(230, 150, a, 100);
+ }
+ document.getElementById('p34-a').addEventListener('input', d); d();
+}
+function _p34_quiz(){
+ const QS = [
+ {it:'Зеркало', ans:'M', why:'Гладкая поверхность.'},
+ {it:'Бумага', ans:'D', why:'Шероховатая.'},
+ {it:'Мокрый асфальт', ans:'M', why:'Тонкий слой воды делает поверхность гладкой.'},
+ {it:'Снег', ans:'D', why:'Кристаллики рассеивают.'},
+ {it:'Стекло окна', ans:'M', why:'Гладкое.'},
+ {it:'Стена побеленная', ans:'D', why:'Микрорельеф рассеивает.'}
+ ];
+ let i = 0, ok = 0;
+ function r(){
+ const q = QS[i]; const w = document.getElementById('p34-quiz');
+ w.innerHTML = ''+q.it+'
'
+ +'Зеркальное Диффузное
'
+ +'
';
+ document.getElementById('p34-quiz-r').textContent = (i+1);
+ document.getElementById('p34-quiz-ok').textContent = ok;
+ w.querySelectorAll('[data-p]').forEach(b=>{
+ b.addEventListener('click', ()=>{
+ if(b.disabled) return; w.querySelectorAll('[data-p]').forEach(x=>x.disabled=true);
+ const fb = document.getElementById('p34-q-fb');
+ if(b.dataset.p === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+q.why; addXp(3,'p34-q'); bumpProgress('p34',4); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ '+q.why; }
+ document.getElementById('p34-quiz-ok').textContent = ok;
+ });
+ });
+ }
+ document.getElementById('p34-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; r(); });
+ r();
+}
+function _p34_dnd(){
+ const items = [
+ {id:'a',cat:'m',html:'зеркало'},{id:'b',cat:'m',html:'спокойная вода'},{id:'c',cat:'m',html:'полировка металла'},{id:'d',cat:'m',html:'мокрый асфальт'},
+ {id:'e',cat:'d',html:'бумага'},{id:'f',cat:'d',html:'снег'},{id:'g',cat:'d',html:'ткань'},{id:'h',cat:'d',html:'штукатурка'}
+ ];
+ const dnd = setupSorter({ poolId:'p34-dnd-pool', scopeSelector:'#sec-p34', cats:['m','d'], items, columnLayout:false });
+ document.getElementById('p34-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p34-dnd-fb'); let wr = 0;
+ items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wr++; });
+ if(wr===0){ fb.className='feedback ok'; fb.innerHTML='✓ +15 XP'; addXp(15,'p34-dnd'); bumpProgress('p34',20); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wr+'.'; }
+ });
+ document.getElementById('p34-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); document.getElementById('p34-dnd-fb').style.display='none'; });
+}
+function _p34_tasks(){
+ const TASKS = [
+ {q:'$\\alpha = 30$ °. Найди $\\beta$.', ans:30, tol:0.5, why:'$\\alpha = \\beta$.'},
+ {q:'Угол между падающим и зеркалом 50°. Найди $\\alpha$ (от нормали).', ans:40, tol:0.5, why:'Нормаль к зеркалу, $\\alpha = 90-50 = 40$°.'},
+ {q:'Угол между падающим и отражённым лучами 60°. Найди $\\alpha$.', ans:30, tol:0.5, why:'$2\\alpha = 60$, $\\alpha = 30$°.'},
+ {q:'$\\alpha = 0$°. Куда отражается?', ans:0, tol:0.5, why:'Назад по той же нормали, $\\beta = 0$.'},
+ {q:'Поверхность повернули на 10° (зафиксировав луч). Как изменится $\\beta$?', ans:20, tol:0.5, why:'При повороте зеркала на $\\Delta$, отражённый поворачивается на $2\\Delta = 20$°.'}
+ ];
+ let i = 0, ok = 0, done = 0, aw = false;
+ function r(){
+ const t = TASKS[i]; const w = document.getElementById('p34-task');
+ w.innerHTML = ''+(i+1)+'. '+t.q+'
'
+ +'Ответ Подск. След.
'
+ +''+t.why+'
';
+ document.getElementById('p34-task-i').textContent = (i+1);
+ document.getElementById('p34-task-ok').textContent = ok;
+ document.getElementById('p34-tgo').addEventListener('click', ()=>{
+ const v = parseFloat((document.getElementById('p34-tinp').value || '').replace(',','.'));
+ const fb = document.getElementById('p34-tfb');
+ if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Число.'; return; }
+ done++;
+ if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+t.why; addXp(4,'p34-t'); bumpProgress('p34',6); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ '+t.ans+'. '+t.why; }
+ document.getElementById('p34-task-ok').textContent = ok;
+ renderMath(w);
+ if(done >= TASKS.length && !aw && ok >= 4){ aw = true; setTimeout(()=>{ const f=document.getElementById('p34-tfb'); f.className='feedback ok'; f.innerHTML='✓ +15 XP'; addXp(15,'p34-bonus'); bumpProgress('p34',15); }, 500); }
+ });
+ document.getElementById('p34-thn').addEventListener('click', ()=>{ document.getElementById('p34-tht').classList.toggle('show'); });
+ document.getElementById('p34-tn').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; r(); });
+ renderMath(w);
+ }
+ r();
+}
+
+/* ======== §35 — Плоское зеркало ======== */
+function build_p35(){
+ const box = document.getElementById('p35-body'); let h = '';
+ h += makeCard('theory', 'Изображение в плоском зеркале', '§ 35.1',
+ 'Плоское зеркало даёт мнимое изображение предмета:
'
+ +''
+ +'Изображение расположено за зеркалом, на том же расстоянии, что и предмет. '
+ +'Размеры предмета и изображения равны . '
+ +'Изображение симметрично предмету относительно плоскости зеркала. '
+ +'Изображение «прямое» (не перевёрнуто). '
+ +' '
+ +'«Мнимое» значит: лучи света не пересекаются в этой точке, а пересекаются их продолжения .
'
+ );
+ h += makeCard('rule', 'Как строится изображение', '§ 35.2',
+ 'От каждой точки предмета идут лучи во все стороны. Те, что попадают на зеркало, отражаются по закону отражения. Продолжения отражённых лучей собираются за зеркалом в точке изображения.
'
+ );
+ h += makeCard('example', 'Зеркало vs текст', '§ 35.3',
+ 'В зеркале правая рука выглядит как левая, а буквы переворачиваются по горизонтали. Это симметрия.
'
+ +'Поэтому надписи на машинах скорой помощи пишут «зеркально» — чтобы водитель впереди мог прочесть «АМБУЛАНС» в зеркале заднего вида.
'
+ );
+ h += ''
+ +'
Двигай предмет — увидь, как симметрично «отъезжает» изображение.
'
+ +'
Расстояние от предмета до зеркала, см: 8
'
+ +'
';
+ h += ''
+ +'
Правда или ложь?
'
+ +'
'
+ +'
Следующий
'
+ +'
Раунд: 1 /6 Правильно: 0
';
+ h += ''
+ +'
'
+ +'
'
+ +'
Проверить Сброс
'
+ +'
';
+ h += ''
+ +'
4+ — +15 XP.
'
+ +'
'
+ +'
Задача: 1 /5 Правильно: 0
';
+ box.innerHTML = h + secNavFor('p35') + readButton('p35');
+ renderMath(box); wireReadBtn('p35');
+ _p35_mir(); _p35_quiz(); _p35_dnd(); _p35_tasks();
+}
+function _p35_mir(){
+ const svg = document.getElementById('p35-sim'); if(!svg) return;
+ function d(){
+ const dist = +document.getElementById('p35-d').value;
+ document.getElementById('p35-dv').textContent = dist;
+ const cm = 12; /* px per cm */
+ const mirrorX = 230;
+ let s = '';
+ /* зеркало вертикальное */
+ s += window.OPTICS.mirrorPlane(mirrorX, 110, 160, 90);
+ /* предмет — стрелка слева */
+ const objX = mirrorX - dist*cm;
+ s += window.OPTICS.lightObject(objX, 150, 50, 'arrow');
+ s += 'предмет ';
+ /* мнимое изображение справа */
+ const imgX = mirrorX + dist*cm;
+ /* пунктирная стрелка-изображение */
+ s += ' ';
+ s += ' ';
+ s += 'мнимое изобр. ';
+ /* линии-лучи */
+ /* луч от вершины предмета к зеркалу и обратно */
+ s += ' ';
+ s += ' ';
+ /* продолжение в изображение */
+ s += ' ';
+ svg.innerHTML = s;
+ }
+ document.getElementById('p35-d').addEventListener('input', d); d();
+}
+function _p35_quiz(){
+ const QS = [
+ {st:'Изображение в плоском зеркале мнимое.', ans:'T', why:'Лучи не пересекаются за зеркалом — только их продолжения.'},
+ {st:'Размер изображения больше предмета.', ans:'F', why:'Размеры равны.'},
+ {st:'Изображение находится на том же расстоянии от зеркала, что и предмет.', ans:'T', why:'Симметрия.'},
+ {st:'Изображение перевёрнуто вверх ногами.', ans:'F', why:'Прямое (не перевёрнуто).'},
+ {st:'Зеркальное изображение нельзя проецировать на экран.', ans:'T', why:'Мнимое — невозможно поймать на экран.'},
+ {st:'Если предмет приближается к зеркалу, изображение тоже приближается.', ans:'T', why:'Симметрия сохраняется.'}
+ ];
+ let i = 0, ok = 0;
+ function r(){
+ const q = QS[i]; const w = document.getElementById('p35-quiz');
+ w.innerHTML = '"'+q.st+'"
'
+ +'Правда Ложь
'
+ +'
';
+ document.getElementById('p35-quiz-r').textContent = (i+1);
+ document.getElementById('p35-quiz-ok').textContent = ok;
+ w.querySelectorAll('[data-p]').forEach(b=>{
+ b.addEventListener('click', ()=>{
+ if(b.disabled) return; w.querySelectorAll('[data-p]').forEach(x=>x.disabled=true);
+ const fb = document.getElementById('p35-q-fb');
+ if(b.dataset.p === q.ans){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+q.why; addXp(3,'p35-q'); bumpProgress('p35',4); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ '+q.why; }
+ document.getElementById('p35-quiz-ok').textContent = ok;
+ });
+ });
+ }
+ document.getElementById('p35-quiz-next').addEventListener('click', ()=>{ i=(i+1)%QS.length; r(); });
+ r();
+}
+function _p35_dnd(){
+ const items = [
+ {id:'a',cat:'y',html:'мнимое'},{id:'b',cat:'y',html:'прямое'},{id:'c',cat:'y',html:'равное по размеру'},{id:'d',cat:'y',html:'симметричное'},
+ {id:'e',cat:'n',html:'действительное'},{id:'f',cat:'n',html:'перевёрнутое'},{id:'g',cat:'n',html:'увеличенное'},{id:'h',cat:'n',html:'на экране'}
+ ];
+ const dnd = setupSorter({ poolId:'p35-dnd-pool', scopeSelector:'#sec-p35', cats:['y','n'], items, columnLayout:false });
+ document.getElementById('p35-dnd-check').addEventListener('click', ()=>{
+ const fb = document.getElementById('p35-dnd-fb'); let wr = 0;
+ items.forEach(it=>{ if(dnd.placed[it.id] !== it.cat) wr++; });
+ if(wr===0){ fb.className='feedback ok'; fb.innerHTML='✓ +15 XP'; addXp(15,'p35-dnd'); bumpProgress('p35',20); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ Ошибок: '+wr+'.'; }
+ });
+ document.getElementById('p35-dnd-reset').addEventListener('click', ()=>{ dnd.reset(); document.getElementById('p35-dnd-fb').style.display='none'; });
+}
+function _p35_tasks(){
+ const TASKS = [
+ {q:'Предмет на расстоянии 1,5 м от зеркала. На каком расстоянии (м) изображение от предмета?', ans:3, tol:0.05, why:'Изображение в 1,5 м за зеркалом, расстояние предмет-изобр = 3 м.'},
+ {q:'Высота предмета 30 см. Высота изображения (см)?', ans:30, tol:0.5, why:'Равны.'},
+ {q:'Человек двигается к зеркалу со скоростью 1 м/с. С какой скоростью он сближается со своим изображением?', ans:2, tol:0.1, why:'Оба двигаются по 1 м/с к плоскости — сближение 2 м/с.'},
+ {q:'Изображение в плоском зеркале мнимое? (1 = да, 0 = нет)', ans:1, tol:0.1, why:'Да, мнимое.'},
+ {q:'Угол между двумя плоскими зеркалами 90°. Сколько изображений предмета возникнет?', ans:3, tol:0.1, why:'Два прямых + одно «двойное» = 3.'}
+ ];
+ let i = 0, ok = 0, done = 0, aw = false;
+ function r(){
+ const t = TASKS[i]; const w = document.getElementById('p35-task');
+ w.innerHTML = ''+(i+1)+'. '+t.q+'
'
+ +'Ответ Подск. След.
'
+ +''+t.why+'
';
+ document.getElementById('p35-task-i').textContent = (i+1);
+ document.getElementById('p35-task-ok').textContent = ok;
+ document.getElementById('p35-tgo').addEventListener('click', ()=>{
+ const v = parseFloat((document.getElementById('p35-tinp').value || '').replace(',','.'));
+ const fb = document.getElementById('p35-tfb');
+ if(isNaN(v)){ fb.className='feedback fail'; fb.innerHTML='Число.'; return; }
+ done++;
+ if(Math.abs(v - t.ans) < t.tol){ ok++; fb.className='feedback ok'; fb.innerHTML='✓ '+t.why; addXp(4,'p35-t'); bumpProgress('p35',6); }
+ else { fb.className='feedback fail'; fb.innerHTML='✗ '+t.ans+'. '+t.why; }
+ document.getElementById('p35-task-ok').textContent = ok;
+ renderMath(w);
+ if(done >= TASKS.length && !aw && ok >= 4){ aw = true; setTimeout(()=>{ const f=document.getElementById('p35-tfb'); f.className='feedback ok'; f.innerHTML='✓ +15 XP'; addXp(15,'p35-bonus'); bumpProgress('p35',15); }, 500); }
+ });
+ document.getElementById('p35-thn').addEventListener('click', ()=>{ document.getElementById('p35-tht').classList.toggle('show'); });
+ document.getElementById('p35-tn').addEventListener('click', ()=>{ i=(i+1)%TASKS.length; r(); });
+ renderMath(w);
+ }
+ r();
+}
+
+/* === Заглушки для §36..§40 и финала — будут заполнены ниже === */
+function build_p36(){ _stub_phaseN('p36','Преломление света','Phase 5 Wave 3'); }
+function build_p37(){ _stub_phaseN('p37','Линзы. Оптическая сила','Phase 5 Wave 3'); }
+function build_p38(){ _stub_phaseN('p38','Построение изображений в линзах','Phase 5 Wave 4'); }
+function build_p39(){ _stub_phaseN('p39','Глаз как оптическая система','Phase 5 Wave 4'); }
+function build_p40(){ _stub_phaseN('p40','Дефекты зрения. Очки','Phase 5 Wave 4'); }
+function build_final3(){ _stub_phaseN('final3','Финал главы 3','Phase 5 Wave 4'); }
+function _stub_phaseN(id, name, ph){
+ const box = document.getElementById(id+'-body');
+ box.innerHTML = buildStub(id, name, ph) + secNavFor(id) + readButton(id);
+ renderMath(box); wireReadBtn(id);
+}
+
function init(){
loadProgress(); initTheme(); initSidebarToggle(); initSearch();
buildParaSelector(); refreshProgressUI(); loadServerReadState(); goTo(PARAS[0].id);