feat(geom8): Wave 2 Главы 3 — §4-§5 (параллельная стороне, первый признак ДД)

§4 Свойство параллельной прямой: SVG-треугольник со слайдером положения
MN (t=0..1), live коэффициент подобия k, подсветка △AMN; 5-шаговое
доказательство через соответственные углы; калькулятор AM,AB,BC→MN+k;
DnD пропорция верна/неверна; тренажёр; босс.

§5 Первый признак подобия (по двум углам): SVG двух треугольников
с 3 слайдерами (α, β, k), оба строятся через теорему синусов с
автоподобием; 5-шаговое доказательство через сумму углов 180° и
вспомогательное построение; DnD подобны/не подобны по углам; калькулятор
2 угла + сторона → соответствующая сторона; тренажёр; босс.

File: 1557 → 2338 LOC.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-28 14:25:45 +03:00
parent a7c5f10fd4
commit ac3aaeadb2
+783 -3
View File
@@ -339,7 +339,7 @@ const PARAS=[
function buildParaSelector(){const g=document.getElementById('psel-grid');g.innerHTML='';PARAS.forEach(p=>{const card=document.createElement('div');card.className='psel-card'+(p.final?' final':'');card.dataset.id=p.id;card.dataset.progCard=p.id;card.innerHTML=`<div class="psel-num">${p.num}</div><div class="psel-name">${p.name}</div><div class="psel-prog"><div class="psel-prog-fill"></div></div>`;card.addEventListener('click',()=>goTo(p.id));g.appendChild(card);});}
const BUILT=new Set();
const BUILDERS={p1:()=>buildP1(),p2:()=>buildP2(),p3:()=>buildP3(),p4:()=>buildP4stub(),p5:()=>buildP5stub(),p6:()=>buildP6stub(),p7:()=>buildP7stub(),p8:()=>buildP8stub(),p9:()=>buildP9stub(),final3:()=>buildFinal3stub()};
const BUILDERS={p1:()=>buildP1(),p2:()=>buildP2(),p3:()=>buildP3(),p4:()=>buildP4(),p5:()=>buildP5(),p6:()=>buildP6stub(),p7:()=>buildP7stub(),p8:()=>buildP8stub(),p9:()=>buildP9stub(),final3:()=>buildFinal3stub()};
function ensureBuilt(id){if(BUILT.has(id))return;const fn=BUILDERS[id];if(fn){fn();BUILT.add(id);}}
function goTo(id){STATE.current=id;ensureBuilt(id);document.querySelectorAll('.sec').forEach(s=>s.classList.remove('active'));const el=document.getElementById('sec-'+id);if(el)el.classList.add('active');document.querySelectorAll('.psel-card').forEach(c=>c.classList.toggle('active',c.dataset.id===id));buildSidebar(id);window.scrollTo({top:0,behavior:'smooth'});if((STATE.progress[id]||0)<10)bumpProgress(id,10);if(window.renderMathInElement)setTimeout(()=>renderMath(el),0);setTimeout(()=>{try{wrapGlossary(el);}catch(e){}},60);markLastPara(id);}
@@ -1545,8 +1545,788 @@ function buildP3(){
renderMath(bossBox);
})();
}
function buildP4stub(){ document.getElementById('p4-body').innerHTML='<div class="card"><div class="card-body"><p><b>§4 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p3','p5'); }
function buildP5stub(){ document.getElementById('p5-body').innerHTML='<div class="card"><div class="card-body"><p><b>§5 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p4','p6'); }
function buildP4(){
const box=document.getElementById('p4-body');
let html='';
/* ---- Theory cards ---- */
html+=makeCard('theory','Теорема о прямой, параллельной стороне треугольника','4.1',`
<p><b>Теорема.</b> Прямая, параллельная одной из сторон треугольника и пересекающая две другие стороны, отсекает треугольник, подобный исходному.</p>
<p style="margin-top:8px"><b>Формально:</b> в $\\triangle ABC$ прямая $MN \\parallel BC$ пересекает $AB$ в точке $M$ и $AC$ в точке $N$. Тогда $\\triangle AMN \\sim \\triangle ABC$ с коэффициентом подобия:</p>
$$k = \\dfrac{AM}{AB} = \\dfrac{AN}{AC} = \\dfrac{MN}{BC}$$
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 175" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- triangle ABC -->
<polygon points="140,15 30,155 250,155" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="2"/>
<!-- MN line at t=0.45 -->
<!-- M on AB: M = A + 0.45*(B-A) = (140+0.45*(30-140), 15+0.45*(155-15)) = (89.5, 78) -->
<!-- N on AC: N = A + 0.45*(C-A) = (140+0.45*(250-140), 15+0.45*(155-15)) = (189.5, 78) -->
<polygon points="140,15 89.5,78 189.5,78" fill="rgba(99,102,241,.22)" stroke="#4f46e5" stroke-width="2"/>
<line x1="72" y1="78" x2="210" y2="78" stroke="#4f46e5" stroke-width="1.8" stroke-dasharray="5,3"/>
<!-- labels -->
<text x="140" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>
<text x="22" y="165" font-size="11" font-weight="700" fill="#4338ca">B</text>
<text x="253" y="165" font-size="11" font-weight="700" fill="#4338ca">C</text>
<text x="82" y="76" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text>
<text x="196" y="76" font-size="10" font-weight="700" fill="#4f46e5">N</text>
<text x="140" y="95" text-anchor="middle" font-size="9" fill="#4f46e5">MN ∥ BC</text>
<text x="140" y="170" text-anchor="middle" font-size="9" fill="#4338ca" font-style="italic">△AMN △ABC</text>
<!-- k label -->
<text x="265" y="30" font-size="10" fill="#4f46e5" font-weight="700">k=AM/AB</text>
</svg>
</div>`);
html+=makeCard('rule','Следствие — теорема Фалеса для треугольника','4.2',`
<p><b>Следствие.</b> Если $MN \\parallel BC$ в $\\triangle ABC$, то:</p>
$$\\dfrac{AM}{MB} = \\dfrac{AN}{NC}$$
<p style="margin-top:8px">То есть прямая, параллельная стороне треугольника, делит две другие стороны пропорционально.</p>
<p style="margin-top:8px">Это прямое следствие обобщённой теоремы Фалеса: прямые $BC$, $MN$ и $A$ порождают пропорциональное деление сторон $AB$ и $AC$.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 280 155" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<polygon points="140,12 30,140 250,140" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/>
<!-- MN at t=0.5 -->
<line x1="85" y1="76" x2="195" y2="76" stroke="#4f46e5" stroke-width="2"/>
<circle cx="85" cy="76" r="3.5" fill="#4f46e5"/>
<circle cx="195" cy="76" r="3.5" fill="#4f46e5"/>
<text x="140" y="8" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>
<text x="22" y="150" font-size="11" font-weight="700" fill="#4338ca">B</text>
<text x="253" y="150" font-size="11" font-weight="700" fill="#4338ca">C</text>
<text x="78" y="74" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text>
<text x="200" y="74" font-size="10" font-weight="700" fill="#4f46e5">N</text>
<!-- AM, MB labels -->
<text x="62" y="44" text-anchor="middle" font-size="9" fill="#4f46e5">AM</text>
<text x="56" y="112" text-anchor="middle" font-size="9" fill="#6366f1">MB</text>
<!-- AN, NC labels -->
<text x="221" y="44" text-anchor="middle" font-size="9" fill="#4f46e5">AN</text>
<text x="228" y="112" text-anchor="middle" font-size="9" fill="#6366f1">NC</text>
<text x="140" y="148" text-anchor="middle" font-size="9" fill="#4338ca" font-style="italic">AM/MB = AN/NC</text>
</svg>
</div>`);
html+=makeCard('example','Пример вычисления','4.3',`
<p><b>Пример.</b> В $\\triangle ABC$ прямая $MN \\parallel BC$. $AM = 6$, $AB = 10$, $BC = 15$. Найти $MN$.</p>
<p style="margin-top:8px"><b>Решение:</b> коэффициент подобия $k = AM/AB = 6/10 = 0{,}6$.</p>
<p style="margin-top:4px">$MN = k \\cdot BC = 0{,}6 \\cdot 15 = 9$.</p>
<p style="margin-top:8px"><b>Пример 2.</b> $AM = 4$, $MB = 6$. Найти $AN/NC$.</p>
<p style="margin-top:4px">По следствию: $AN/NC = AM/MB = 4/6 = 2/3$.</p>`);
/* ---- ИНТЕРАКТИВ 1: SVG треугольник со slider ---- */
html+=`<div class="wg" id="p4-par-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Параллельная прямая отсекает подобный треугольник</div></div>
<div class="wg-help">Перемещай прямую $MN \\parallel BC$ по высоте треугольника. Коэффициент подобия $k$ меняется — $\\triangle AMN \\sim \\triangle ABC$.</div>
<div class="sliders">
<label>Положение $MN$ (t = AM/AB): <b id="p4-t-val">0.50</b>
<input type="range" min="10" max="90" value="50" id="p4-t-sl" step="1">
</label>
</div>
<div id="p4-par-svg" style="display:flex;justify-content:center"></div>
<div id="p4-par-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
html+=`<div class="wg" id="p4-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство — по шагам</div></div>
<div class="wg-help">Нажимай «Далее» — каждый шаг раскрывает ключевую идею доказательства.</div>
<div id="p4-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p4-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p4-proof-next">Далее</button>
<button class="btn" id="p4-proof-reset">Сначала</button>
</div>
</div>`;
/* ---- ИНТЕРАКТИВ 3: Калькулятор ---- */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: параллельная сторона</div></div>
<div class="wg-help">Введи $AM$, $AB$, $BC$ → найди $MN = BC \\cdot AM/AB$. Или задай $MN$, $BC$ → найди $AM/AB$.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(80px,1fr));gap:8px;margin-bottom:10px">
<div><span style="font-size:.8rem;color:var(--muted);display:block">AM</span><input type="number" id="p4-cAM" class="tinp" placeholder="AM" style="width:100%"></div>
<div><span style="font-size:.8rem;color:var(--muted);display:block">AB</span><input type="number" id="p4-cAB" class="tinp" placeholder="AB" style="width:100%"></div>
<div><span style="font-size:.8rem;color:var(--muted);display:block">BC</span><input type="number" id="p4-cBC" class="tinp" placeholder="BC" style="width:100%"></div>
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p4-ccalc" style="width:100%">Вычислить MN</button></div>
</div>
<div id="p4-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 4: Тренажёр ---- */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §4</div></div>
<div class="wg-help">5 задач на нахождение MN, AN, AM и отношений.</div>
<div class="score-display"><span>Задача <b id="p4-tr-i">1</b> / 5</span><span>Очки: <b id="p4-tr-score">0</b></span></div>
<div id="p4-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p4-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p4-tr-go">Проверить</button>
<button class="btn" id="p4-tr-start">Начать</button>
</div>
<div class="feedback" id="p4-tr-fb" style="display:none"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 5: DnD-сортер ---- */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Соотнеси параллельные прямые и пропорции</div></div>
<div class="wg-help">Перетащи каждую карточку: «Пропорция верна» или «Пропорция неверна».</div>
<div id="p4-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
<div class="drop-box" id="p4-drop-yes"><h5>Пропорция верна</h5><div class="drop-items" id="p4-drop-yes-items"></div></div>
<div class="drop-box" id="p4-drop-no"><h5>Пропорция неверна</h5><div class="drop-items" id="p4-drop-no-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p4-dnd-check">Проверить</button><button class="btn" id="p4-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p4-dnd-fb" style="display:none"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 6: Босс §4 ---- */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §4</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
<div id="p4-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p4-read-btn" onclick="addXp(10,'p4-read');bumpProgress('p4',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §4 (+10 XP)
</button>
</div>`;
html+=secNav('p3','p5');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT ИНТЕРАКТИВ 1: slider параллельной прямой == */
(function(){
const tSl=document.getElementById('p4-t-sl');
const tVal=document.getElementById('p4-t-val');
const svgWrap=document.getElementById('p4-par-svg');
const infoEl=document.getElementById('p4-par-info');
// base triangle: A=(140,15), B=(30,155), C=(250,155)
const Ax=140,Ay=15,Bx=30,By=155,Cx=250,Cy=155;
const BC=Math.hypot(Cx-Bx,Cy-By);
const AB=Math.hypot(Bx-Ax,By-Ay);
const AC=Math.hypot(Cx-Ax,Cy-Ay);
function draw(){
const t=+tSl.value/100;
tVal.textContent=t.toFixed(2);
const Mx=Ax+t*(Bx-Ax), My=Ay+t*(By-Ay);
const Nx=Ax+t*(Cx-Ax), Ny=Ay+t*(Cy-Ay);
const MN=Math.hypot(Nx-Mx,Ny-My);
const AM=Math.hypot(Mx-Ax,My-Ay);
const AN=Math.hypot(Nx-Ax,Ny-Ay);
const W=300, H=180;
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
// full triangle light
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy}" fill="rgba(99,102,241,.07)" stroke="#6366f1" stroke-width="1.5"/>`;
// inner triangle AMN highlighted
s+=`<polygon points="${Ax},${Ay} ${Mx},${My} ${Nx},${Ny}" fill="rgba(79,70,229,.22)" stroke="#4f46e5" stroke-width="2"/>`;
// MN line
s+=`<line x1="${Mx}" y1="${My}" x2="${Nx}" y2="${Ny}" stroke="#4f46e5" stroke-width="2"/>`;
// points
s+=`<circle cx="${Mx}" cy="${My}" r="4" fill="#4f46e5"/>`;
s+=`<circle cx="${Nx}" cy="${Ny}" r="4" fill="#4f46e5"/>`;
// labels
s+=`<text x="${Ax}" y="${Ay-5}" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text>`;
s+=`<text x="${Bx-8}" y="${By+2}" font-size="11" font-weight="700" fill="#4338ca">B</text>`;
s+=`<text x="${Cx+4}" y="${Cy+2}" font-size="11" font-weight="700" fill="#4338ca">C</text>`;
s+=`<text x="${Mx-8}" y="${My}" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text>`;
s+=`<text x="${Nx+4}" y="${Ny}" font-size="10" font-weight="700" fill="#4f46e5">N</text>`;
// k badge
s+=`<text x="${W/2}" y="14" text-anchor="middle" font-size="11" font-weight="800" fill="#4338ca">k = ${t.toFixed(2)}</text>`;
s+='</svg>';
svgWrap.innerHTML=s;
infoEl.innerHTML=`$k = AM/AB = ${t.toFixed(3)}$. $MN = k \\cdot BC = ${t.toFixed(3)} \\cdot ${fmt(BC/10)} = ${fmt(MN/10)}$. <br> $AM/MB = ${fmt(t/(1-t+1e-9))}$. По следствию: $AN/NC = AM/MB = ${fmt(t/(1-t+1e-9))}$.`;
renderMath(infoEl);
addXp(1,'p4-par');
}
tSl.addEventListener('input',draw);
draw();
})();
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
(function(){
const steps=[
{desc:'<b>Шаг 1.</b> Дан $\\triangle ABC$. Прямая $MN \\parallel BC$ пересекает $AB$ в $M$ и $AC$ в $N$. Требуется доказать $\\triangle AMN \\sim \\triangle ABC$.',
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/><line x1="78" y1="81" x2="182" y2="81" stroke="#4f46e5" stroke-width="2" stroke-dasharray="5,3"/><circle cx="78" cy="81" r="3.5" fill="#4f46e5"/><circle cx="182" cy="81" r="3.5" fill="#4f46e5"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><text x="130" y="97" text-anchor="middle" font-size="9" fill="#4f46e5">MN ∥ BC</text></svg>`},
{desc:'<b>Шаг 2.</b> $\\angle AMN = \\angle ABC$, так как $MN \\parallel BC$ и $AB$ — секущая: это соответственные углы при параллельных прямых и секущей.',
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/><line x1="78" y1="81" x2="182" y2="81" stroke="#4f46e5" stroke-width="2"/><circle cx="78" cy="81" r="3.5" fill="#4f46e5"/><circle cx="182" cy="81" r="3.5" fill="#4f46e5"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><path d="M78,81 Q88,88 83,95" fill="none" stroke="#f59e0b" stroke-width="2"/><path d="M25,148 Q38,138 33,128" fill="none" stroke="#f59e0b" stroke-width="2"/><text x="96" y="100" font-size="9" fill="#b45309" font-weight="700">∠AMN = ∠ABC</text></svg>`},
{desc:'<b>Шаг 3.</b> Аналогично $\\angle ANM = \\angle ACB$: $MN \\parallel BC$ и $AC$ — секущая, получаем соответственные углы.',
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="2"/><line x1="78" y1="81" x2="182" y2="81" stroke="#4f46e5" stroke-width="2"/><circle cx="78" cy="81" r="3.5" fill="#4f46e5"/><circle cx="182" cy="81" r="3.5" fill="#4f46e5"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><path d="M182,81 Q172,88 177,95" fill="none" stroke="#10b981" stroke-width="2"/><path d="M235,148 Q222,138 227,128" fill="none" stroke="#10b981" stroke-width="2"/><text x="130" y="100" text-anchor="middle" font-size="9" fill="#047857" font-weight="700">∠ANM = ∠ACB</text></svg>`},
{desc:'<b>Шаг 4.</b> Угол $\\angle A$ общий у $\\triangle AMN$ и $\\triangle ABC$. Два угла $\\triangle AMN$ равны соответствующим двум углам $\\triangle ABC$ → по признаку ДД (два угла) $\\triangle AMN \\sim \\triangle ABC$.',
svg:`<svg viewBox="0 0 260 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="130,14 25,148 235,148" fill="rgba(99,102,241,.08)" stroke="#6366f1" stroke-width="1.5"/><polygon points="130,14 78,81 182,81" fill="rgba(79,70,229,.22)" stroke="#4f46e5" stroke-width="2"/><text x="130" y="10" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="17" y="157" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="237" y="157" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="70" y="79" text-anchor="end" font-size="10" font-weight="700" fill="#4f46e5">M</text><text x="186" y="79" font-size="10" font-weight="700" fill="#4f46e5">N</text><text x="130" y="95" text-anchor="middle" font-size="9" fill="#4f46e5">△AMN △ABC</text></svg>`},
{desc:'<b>Шаг 5.</b> Из подобия следует пропорциональность сторон: $AM/AB = AN/AC = MN/BC = k$. Следствие: $AM/MB = AN/NC$ — прямое следствие теоремы Фалеса. <b>Доказано.</b>',
svg:`<svg viewBox="0 0 260 80" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="130" y="24" text-anchor="middle" font-size="11" font-weight="800" fill="#4338ca">AM/AB = AN/AC = MN/BC = k</text><text x="130" y="46" text-anchor="middle" font-size="10" fill="#4f46e5" font-weight="700">AM/MB = AN/NC</text><text x="130" y="68" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">QED ∎</text></svg>`},
];
let step=0;
const svgEl=document.getElementById('p4-proof-svg');
const descEl=document.getElementById('p4-proof-desc');
function show(){
svgEl.innerHTML=steps[step].svg;
descEl.innerHTML=steps[step].desc;
renderMath(descEl);
}
document.getElementById('p4-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;show();addXp(1,'p4-proof-step');}
else{addXp(5,'p4-proof-done');bumpProgress('p4',10);}
});
document.getElementById('p4-proof-reset').addEventListener('click',()=>{step=0;show();});
show();
})();
/* == INIT ИНТЕРАКТИВ 3: калькулятор == */
(function(){
document.getElementById('p4-ccalc').addEventListener('click',()=>{
const AM=parseFloat(document.getElementById('p4-cAM').value);
const AB=parseFloat(document.getElementById('p4-cAB').value);
const BC=parseFloat(document.getElementById('p4-cBC').value);
const out=document.getElementById('p4-ccalc-out');
if(!isFinite(AM)||!isFinite(AB)||!isFinite(BC)||AM<=0||AB<=0||BC<=0||AM>AB){
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи положительные числа; AM должно быть ≤ AB.</span>';return;
}
const k=AM/AB;
const MN=k*BC;
const AN_over_NC=AM/(AB-AM);
out.style.display='block';
out.innerHTML=`$k = AM/AB = ${fmt(AM)}/${fmt(AB)} = ${fmt(k)}$<br>$MN = k \\cdot BC = ${fmt(k)} \\cdot ${fmt(BC)} = ${fmt(MN)}$<br>Следствие: $AM/MB = AN/NC = ${fmt(AM)}/${fmt(AB-AM)} = ${fmt(AN_over_NC)}$`;
renderMath(out);
addXp(2,'p4-calc');bumpProgress('p4',5);
});
})();
/* == INIT ИНТЕРАКТИВ 4: тренажёр == */
(function(){
const tasks=[
{q:'В $\\triangle ABC$ прямая $MN \\parallel BC$, $AM=4$, $AB=10$, $BC=20$. Найди $MN$.',ans:8,hint:'k=4/10=0.4; MN=0.4·20=8.'},
{q:'В $\\triangle ABC$ прямая $MN \\parallel BC$, $AM=6$, $AB=9$, $BC=12$. Найди $MN$.',ans:8,hint:'k=6/9=2/3; MN=2/3·12=8.'},
{q:'$MN \\parallel BC$, $AM=5$, $MB=10$. Найди $AN/NC$.',ans:0.5,hint:'AN/NC = AM/MB = 5/10 = 0.5.'},
{q:'$MN \\parallel BC$, $k=0.4$, $BC=30$. Найди $MN$.',ans:12,hint:'MN=k·BC=0.4·30=12.'},
{q:'$MN \\parallel BC$, $AM=3$, $MB=6$. Чему равно $AN/AC$?',ans:0.333,hint:'AN/AC = AM/AB = 3/(3+6) = 1/3 ≈ 0.333.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p4-tr-i').textContent=idx+1;
const t=document.getElementById('p4-tr-task');
t.innerHTML=tasks[idx].q;
renderMath(t);
document.getElementById('p4-tr-ans').value='';
document.getElementById('p4-tr-fb').style.display='none';
}
document.getElementById('p4-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p4-tr-score').textContent=0;show();});
document.getElementById('p4-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p4-tr-ans').value;
const fb=document.getElementById('p4-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.01){
score++;document.getElementById('p4-tr-score').textContent=score;
addXp(3,'p4-tr-'+idx);bumpProgress('p4',4);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p4-tr-all');bumpProgress('p4',10);confetti();}
} else {
feedback(fb,false,'Неверно. '+tasks[idx].hint);
}
});
document.getElementById('p4-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p4-tr-go').click();});
show();
})();
/* == INIT ИНТЕРАКТИВ 5: DnD-сортер == */
(function(){
const items=[
{text:'MN∥BC, AM=3, AB=6, AN=4, AC=8 → AM/MB=AN/NC',yes:true},
{text:'MN∥BC, AM=4, MB=6, AN=3, NC=5 → AM/MB≠AN/NC',yes:false},
{text:'MN∥BC, AM/AB=0.5, MN/BC=0.5',yes:true},
{text:'MN∥BC, AM=2, MB=4, AN=3, NC=6 → AM/MB=AN/NC',yes:true},
{text:'MN∥BC, k=1/3, MN=BC/2',yes:false},
];
const pool=document.getElementById('p4-dnd-pool');
const yesBox=document.getElementById('p4-drop-yes-items');
const noBox=document.getElementById('p4-drop-no-items');
let dragging=null;
function makeChip(it,idx){
const chip=document.createElement('div');
chip.className='dnd-chip';
chip.dataset.idx=idx;
chip.textContent=it.text;
chip.draggable=true;
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
return chip;
}
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
[document.getElementById('p4-drop-yes'),document.getElementById('p4-drop-no'),pool].forEach(box=>{
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
box.addEventListener('dragleave',()=>box.classList.remove('over'));
box.addEventListener('drop',e=>{
e.preventDefault();box.classList.remove('over');
if(!dragging)return;
const target=box===document.getElementById('p4-drop-yes')?yesBox:box===document.getElementById('p4-drop-no')?noBox:pool;
target.appendChild(dragging);
});
});
document.getElementById('p4-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p4-dnd-fb');
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
let ok=true;
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p4-dnd');bumpProgress('p4',8);}
else{feedback(fb,false,'Есть ошибки. Проверь: MN∥BC → AM/MB=AN/NC и MN/BC=AM/AB.');}
});
document.getElementById('p4-dnd-reset').addEventListener('click',()=>{
[...yesBox.children].forEach(c=>pool.appendChild(c));
[...noBox.children].forEach(c=>pool.appendChild(c));
document.getElementById('p4-dnd-fb').style.display='none';
});
})();
/* == INIT: Босс §4 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 240 140" style="display:block;max-width:240px;margin:0 auto 8px;background:#e0e7ff;border:1px solid #a5b4fc;border-radius:8px"><polygon points="120,12 20,128 220,128" fill="rgba(99,102,241,.12)" stroke="#6366f1" stroke-width="2"/><line x1="70" y1="70" x2="170" y2="70" stroke="#4f46e5" stroke-width="2"/><text x="120" y="8" text-anchor="middle" font-size="10" fill="#4338ca" font-weight="700">A</text><text x="12" y="136" font-size="10" fill="#4338ca" font-weight="700">B</text><text x="222" y="136" font-size="10" fill="#4338ca" font-weight="700">C</text><text x="62" y="68" text-anchor="end" font-size="10" fill="#4f46e5" font-weight="700">M</text><text x="174" y="68" font-size="10" fill="#4f46e5" font-weight="700">N</text><text x="120" y="90" text-anchor="middle" font-size="9" fill="#4f46e5">AM=5, AB=8, BC=24</text></svg>$MN \\parallel BC$. $AM=5$, $AB=8$, $BC=24$. Найди $MN$.',ans:15,hint:'k=5/8; MN=5/8·24=15.'},
{q:'$MN \\parallel BC$, $AM=6$, $MB=9$. Найди $AN/NC$.',ans:0.667,hint:'AN/NC = AM/MB = 6/9 = 2/3 ≈ 0.667.'},
{q:'$MN \\parallel BC$, $MN=8$, $BC=12$. Найди $AM/AB$.',ans:0.667,hint:'AM/AB = MN/BC = 8/12 = 2/3 ≈ 0.667.'},
{q:'В $\\triangle ABC$ прямая $MN \\parallel BC$, $AM=3$, $AB=9$, $BC=18$. Найди $MN$.',ans:6,hint:'k=3/9=1/3; MN=1/3·18=6.'},
];
const bossBox=document.getElementById('p4-boss-tasks');
bossBox.innerHTML=tasks.map((t,i)=>`
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<input type="number" class="tinp" id="p4b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p4b-a${i}').value;
const fb=document.getElementById('p4b-fb${i}');
if(Math.abs(v-${t.ans})<0.01){
feedback(fb,true,'Верно! +5 XP');
if(!window.p4BossSolved.has(${i})){ window.p4BossSolved.add(${i}); addXp(5,'p4-boss${i}'); bumpProgress('p4',8); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p4b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p4BossSolved=new Set();
renderMath(bossBox);
})();
}
function buildP5(){
const box=document.getElementById('p5-body');
let html='';
/* ---- Theory cards ---- */
html+=makeCard('theory','Первый признак подобия треугольников (ДД — два угла)','5.1',`
<p><b>Теорема (1-й признак подобия).</b> Если два угла одного треугольника соответственно равны двум углам другого треугольника, то такие треугольники подобны.</p>
<p style="margin-top:8px">Если $\\angle A = \\angle A'$ и $\\angle B = \\angle B'$, то $\\triangle ABC \\sim \\triangle A'B'C'$.</p>
<p style="margin-top:8px"><b>Почему достаточно двух углов?</b> Сумма углов треугольника равна $180°$. Если два угла равны, третий автоматически тоже равен: $\\angle C = 180° - \\angle A - \\angle B = 180° - \\angle A' - \\angle B' = \\angle C'$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 155" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- большой треугольник ABC -->
<polygon points="50,140 180,140 100,30" fill="rgba(79,70,229,.11)" stroke="#4f46e5" stroke-width="2"/>
<text x="96" y="25" font-size="11" font-weight="700" fill="#4338ca">A</text>
<text x="40" y="150" font-size="11" font-weight="700" fill="#4338ca">B</text>
<text x="183" y="150" font-size="11" font-weight="700" fill="#4338ca">C</text>
<!-- угловые метки -->
<path d="M100,30 Q112,40 105,50" fill="none" stroke="#f59e0b" stroke-width="2"/>
<path d="M50,140 Q62,130 70,136" fill="none" stroke="#10b981" stroke-width="2"/>
<!-- маленький треугольник A'B'C' -->
<polygon points="200,140 264,140 230,76" fill="rgba(99,102,241,.15)" stroke="#6366f1" stroke-width="1.8"/>
<text x="227" y="70" font-size="10" font-weight="700" fill="#4f46e5">A'</text>
<text x="193" y="150" font-size="10" font-weight="700" fill="#4f46e5">B'</text>
<text x="266" y="150" font-size="10" font-weight="700" fill="#4f46e5">C'</text>
<!-- угловые метки -->
<path d="M230,76 Q237,84 232,91" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<path d="M200,140 Q210,132 215,136" fill="none" stroke="#10b981" stroke-width="1.5"/>
<text x="140" y="15" text-anchor="middle" font-size="10" fill="#4338ca">∠A=∠A', ∠B=∠B' → △ABC∼△A'B'C'</text>
</svg>
</div>`);
html+=makeCard('rule','Следствие: прямоугольные треугольники','5.2',`
<p><b>Следствие.</b> Два прямоугольных треугольника подобны, если у них равны острые углы (достаточно одной пары).</p>
<p style="margin-top:8px">Если $\\angle C = \\angle C' = 90°$ и $\\angle A = \\angle A'$, то $\\triangle ABC \\sim \\triangle A'B'C'$.</p>
<p style="margin-top:8px">Это потому, что прямой угол — один из двух равных углов, а второй угол задан условием.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 280 130" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- прямоугольный треугольник 1: A=(40,20), B=(40,110), C=(160,110) -->
<polygon points="40,20 40,110 160,110" fill="rgba(79,70,229,.10)" stroke="#4f46e5" stroke-width="2"/>
<!-- marker угла B (прямой) — inside polygon -->
<polyline points="40,100 50,100 50,110" fill="none" stroke="#4f46e5" stroke-width="1.5"/>
<text x="34" y="16" font-size="11" font-weight="700" fill="#4338ca">A</text>
<text x="28" y="120" font-size="11" font-weight="700" fill="#4338ca">B</text>
<text x="163" y="120" font-size="11" font-weight="700" fill="#4338ca">C</text>
<text x="36" y="116" font-size="8" fill="#4f46e5">90°</text>
<!-- прямоугольный треугольник 2: A'=(185,50), B'=(185,110), C'=(250,110) -->
<polygon points="185,50 185,110 250,110" fill="rgba(99,102,241,.15)" stroke="#6366f1" stroke-width="1.8"/>
<!-- marker прямого угла B' -->
<polyline points="185,100 195,100 195,110" fill="none" stroke="#6366f1" stroke-width="1.5"/>
<text x="178" y="46" font-size="10" font-weight="700" fill="#4f46e5">A'</text>
<text x="172" y="120" font-size="10" font-weight="700" fill="#4f46e5">B'</text>
<text x="253" y="120" font-size="10" font-weight="700" fill="#4f46e5">C'</text>
<text x="140" y="14" text-anchor="middle" font-size="9" fill="#4338ca">∠B=∠B'=90°, ∠A=∠A' → подобны</text>
</svg>
</div>`);
html+=makeCard('example','Пример применения признака ДД','5.3',`
<p><b>Пример 1.</b> В $\\triangle ABC$: $\\angle A = 50°$, $\\angle B = 70°$. В $\\triangle A'B'C'$: $\\angle A' = 50°$, $\\angle C' = 60°$. Подобны ли треугольники?</p>
<p style="margin-top:6px">$\\angle C = 180° - 50° - 70° = 60°$. $\\angle B' = 180° - 50° - 60° = 70°$. Углы: $50°, 70°, 60°$ в обоих. По признаку ДД: $\\triangle ABC \\sim \\triangle A'C'B'$.</p>
<p style="margin-top:8px"><b>Пример 2.</b> Два прямоугольных треугольника, у одного острый угол $35°$, у другого $35°$. Подобны ли?</p>
<p style="margin-top:4px">Да. Оба имеют $90°$ и $35°$ — два совпадающих угла.</p>`);
/* ---- ИНТЕРАКТИВ 1: SVG два треугольника, слайдер углов ---- */
html+=`<div class="wg" id="p5-ang-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два угла задают форму — первый признак</div></div>
<div class="wg-help">Задай углы $\\alpha$ и $\\beta$. Оба треугольника строятся с этими углами — они подобны. Коэффициент $k$ определяется масштабом.</div>
<div class="sliders">
<label>Угол $\\alpha$: <b id="p5-a-val">50</b>°
<input type="range" min="20" max="130" value="50" id="p5-a-sl" step="1">
</label>
<label>Угол $\\beta$: <b id="p5-b-val">60</b>°
<input type="range" min="20" max="130" value="60" id="p5-b-sl" step="1">
</label>
<label>Масштаб $k$: <b id="p5-k-val">1.8</b>
<input type="range" min="12" max="30" value="18" id="p5-k-sl" step="1">
</label>
</div>
<div id="p5-ang-svg" style="display:flex;justify-content:center"></div>
<div id="p5-ang-info" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.92rem;line-height:1.8"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 2: Пошаговое доказательство ---- */
html+=`<div class="wg" id="p5-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство 1-го признака — по шагам</div></div>
<div class="wg-help">Нажимай «Далее» — шаг за шагом увидишь логику доказательства.</div>
<div id="p5-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p5-proof-desc" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.6;margin-bottom:10px;min-height:60px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p5-proof-next">Далее</button>
<button class="btn" id="p5-proof-reset">Сначала</button>
</div>
</div>`;
/* ---- ИНТЕРАКТИВ 3: Тренажёр ---- */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Тренажёр §5 — Признак ДД</div></div>
<div class="wg-help">5 задач на подобие по углам и нахождение сторон.</div>
<div class="score-display"><span>Задача <b id="p5-tr-i">1</b> / 5</span><span>Очки: <b id="p5-tr-score">0</b></span></div>
<div id="p5-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.02rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p5-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p5-tr-go">Проверить</button>
<button class="btn" id="p5-tr-start">Начать</button>
</div>
<div class="feedback" id="p5-tr-fb" style="display:none"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 4: DnD-сортер ---- */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Подобные пары или нет? — Сортировка по углам</div></div>
<div class="wg-help">Перетащи каждую пару треугольников в нужную колонку.</div>
<div id="p5-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
<div class="drop-box" id="p5-drop-yes"><h5>Подобны (ДД)</h5><div class="drop-items" id="p5-drop-yes-items"></div></div>
<div class="drop-box" id="p5-drop-no"><h5>Не подобны</h5><div class="drop-items" id="p5-drop-no-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p5-dnd-check">Проверить</button><button class="btn" id="p5-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p5-dnd-fb" style="display:none"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 5: Калькулятор ---- */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Калькулятор: найти сторону через подобие ДД</div></div>
<div class="wg-help">Введи два угла обоих треугольников и одну сторону первого — получи соответствующую сторону второго.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(100px,1fr));gap:8px;margin-bottom:10px">
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠A₁ (°)</span><input type="number" id="p5-cA1" class="tinp" placeholder="напр. 50" style="width:100%"></div>
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠B₁ (°)</span><input type="number" id="p5-cB1" class="tinp" placeholder="напр. 70" style="width:100%"></div>
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠A₂ (°)</span><input type="number" id="p5-cA2" class="tinp" placeholder="напр. 50" style="width:100%"></div>
<div><span style="font-size:.8rem;color:var(--muted);display:block">∠B₂ (°)</span><input type="number" id="p5-cB2" class="tinp" placeholder="напр. 70" style="width:100%"></div>
<div><span style="font-size:.8rem;color:var(--muted);display:block">сторона a₁</span><input type="number" id="p5-ca1" class="tinp" placeholder="напр. 12" style="width:100%"></div>
<div style="display:flex;align-items:flex-end"><button class="btn primary" id="p5-ccalc" style="width:100%">Найти a₂</button></div>
</div>
<div id="p5-ccalc-out" style="display:none;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ---- ИНТЕРАКТИВ 6: Босс §5 ---- */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §5</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
<div id="p5-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p5-read-btn" onclick="addXp(10,'p5-read');bumpProgress('p5',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §5 (+10 XP)
</button>
</div>`;
html+=secNav('p4','p6');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT ИНТЕРАКТИВ 1: слайдер углов == */
(function(){
const aSl=document.getElementById('p5-a-sl');
const bSl=document.getElementById('p5-b-sl');
const kSl=document.getElementById('p5-k-sl');
const aVal=document.getElementById('p5-a-val');
const bVal=document.getElementById('p5-b-val');
const kVal=document.getElementById('p5-k-val');
const svgWrap=document.getElementById('p5-ang-svg');
const infoEl=document.getElementById('p5-ang-info');
function buildTriFromAngles(alpha,beta,baseLen,ox,oy){
// alpha at A (left), beta at B (right)
// base AB horizontal, C above
const gamma=Math.PI-alpha-beta;
if(gamma<=0.05) return null;
// by sine rule: a/sin(alpha) = base/sin(gamma)
const sinG=Math.sin(gamma);
const AB=baseLen;
const BC=AB*Math.sin(alpha)/sinG;
const AC=AB*Math.sin(beta)/sinG;
// place A at (ox,oy), B at (ox+AB,oy)
const Ax=ox, Ay=oy;
const Bx=ox+AB, By=oy;
// C: from A at angle alpha above AB
const Cx=Ax+AC*Math.cos(alpha);
const Cy=Ay-AC*Math.sin(alpha);
return {Ax,Ay,Bx,By,Cx,Cy,AB,BC,AC};
}
function draw(){
const alpha=+aSl.value*Math.PI/180;
const beta=+bSl.value*Math.PI/180;
const k=+kSl.value/10;
aVal.textContent=+aSl.value;
bVal.textContent=+bSl.value;
kVal.textContent=k.toFixed(1);
const gamma=(Math.PI-alpha-beta)*180/Math.PI;
if(gamma<=3){
svgWrap.innerHTML='<div style="color:var(--bad);padding:10px">Сумма углов превышает 180°. Уменьши углы.</div>';
infoEl.innerHTML='Сумма углов не должна превышать 180°.';
return;
}
const W=360, H=170;
const t1=buildTriFromAngles(alpha,beta,90,20,145);
if(!t1){svgWrap.innerHTML='';return;}
const t2=buildTriFromAngles(alpha,beta,90/k,240,145);
if(!t2){svgWrap.innerHTML='';return;}
let s=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">`;
// triangle 1
s+=`<polygon points="${t1.Ax},${t1.Ay} ${t1.Bx},${t1.By} ${t1.Cx},${t1.Cy}" fill="rgba(79,70,229,.12)" stroke="#4f46e5" stroke-width="2"/>`;
s+=`<text x="${t1.Cx}" y="${t1.Cy-5}" text-anchor="middle" font-size="10" font-weight="700" fill="#4338ca">A</text>`;
s+=`<text x="${t1.Ax-8}" y="${t1.Ay+4}" font-size="10" font-weight="700" fill="#4338ca">B</text>`;
s+=`<text x="${t1.Bx+4}" y="${t1.By+4}" font-size="10" font-weight="700" fill="#4338ca">C</text>`;
// angle markers t1
s+=`<path d="M${t1.Cx},${t1.Cy} Q${t1.Cx+(t1.Ax-t1.Cx)*0.18+3},${t1.Cy+(t1.Ay-t1.Cy)*0.18} ${t1.Cx+(t1.Ax-t1.Cx)*0.22},${t1.Cy+(t1.Ay-t1.Cy)*0.22}" fill="none" stroke="#f59e0b" stroke-width="1.5"/>`;
s+=`<path d="M${t1.Ax},${t1.Ay} Q${t1.Ax+(t1.Cx-t1.Ax)*0.12+(t1.Bx-t1.Ax)*0.08},${t1.Ay+(t1.Cy-t1.Ay)*0.12} ${t1.Ax+(t1.Bx-t1.Ax)*0.15},${t1.Ay}" fill="none" stroke="#10b981" stroke-width="1.5"/>`;
// triangle 2 (smaller)
s+=`<polygon points="${t2.Ax},${t2.Ay} ${t2.Bx},${t2.By} ${t2.Cx},${t2.Cy}" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/>`;
s+=`<text x="${t2.Cx}" y="${t2.Cy-5}" text-anchor="middle" font-size="10" font-weight="700" fill="#4f46e5">A'</text>`;
s+=`<text x="${t2.Ax-10}" y="${t2.Ay+4}" font-size="10" font-weight="700" fill="#4f46e5">B'</text>`;
s+=`<text x="${t2.Bx+4}" y="${t2.By+4}" font-size="10" font-weight="700" fill="#4f46e5">C'</text>`;
// angle markers t2
s+=`<path d="M${t2.Cx},${t2.Cy} Q${t2.Cx+(t2.Ax-t2.Cx)*0.22+2},${t2.Cy+(t2.Ay-t2.Cy)*0.22} ${t2.Cx+(t2.Ax-t2.Cx)*0.28},${t2.Cy+(t2.Ay-t2.Cy)*0.28}" fill="none" stroke="#f59e0b" stroke-width="1.5"/>`;
s+=`<path d="M${t2.Ax},${t2.Ay} Q${t2.Ax+(t2.Cx-t2.Ax)*0.14+(t2.Bx-t2.Ax)*0.10},${t2.Ay+(t2.Cy-t2.Ay)*0.14} ${t2.Ax+(t2.Bx-t2.Ax)*0.18},${t2.Ay}" fill="none" stroke="#10b981" stroke-width="1.5"/>`;
// label
s+=`<text x="${W/2}" y="12" text-anchor="middle" font-size="10" font-weight="800" fill="#4338ca">k = ${k.toFixed(1)}</text>`;
s+='</svg>';
svgWrap.innerHTML=s;
infoEl.innerHTML=`$\\alpha=${+aSl.value}°$, $\\beta=${+bSl.value}°$, $\\gamma=${fmt(gamma)}°$. Оба треугольника имеют одинаковые углы → по признаку ДД они подобны. Коэффициент подобия $k=${k.toFixed(1)}$.`;
renderMath(infoEl);
addXp(1,'p5-ang');
}
aSl.addEventListener('input',draw);
bSl.addEventListener('input',draw);
kSl.addEventListener('input',draw);
draw();
})();
/* == INIT ИНТЕРАКТИВ 2: пошаговое доказательство == */
(function(){
const steps=[
{desc:'<b>Шаг 1.</b> Даны $\\triangle ABC$ и $\\triangle A\'B\'C\'$ с $\\angle A = \\angle A\'$ и $\\angle B = \\angle B\'$. Требуется доказать $\\triangle ABC \\sim \\triangle A\'B\'C\'$.',
svg:`<svg viewBox="0 0 280 145" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="50,130 170,130 100,30" fill="rgba(79,70,229,.10)" stroke="#4f46e5" stroke-width="2"/><polygon points="185,130 255,130 220,68" fill="rgba(99,102,241,.15)" stroke="#6366f1" stroke-width="1.8"/><text x="97" y="25" font-size="11" font-weight="700" fill="#4338ca">A</text><text x="40" y="140" font-size="11" font-weight="700" fill="#4338ca">B</text><text x="172" y="140" font-size="11" font-weight="700" fill="#4338ca">C</text><text x="218" y="63" font-size="10" font-weight="700" fill="#4f46e5">A'</text><text x="177" y="140" font-size="10" font-weight="700" fill="#4f46e5">B'</text><text x="257" y="140" font-size="10" font-weight="700" fill="#4f46e5">C'</text><text x="140" y="14" text-anchor="middle" font-size="9" fill="#4338ca">∠A=∠A', ∠B=∠B' — условие</text></svg>`},
{desc:'<b>Шаг 2.</b> Из суммы углов треугольника: $\\angle C = 180° - \\angle A - \\angle B$ и $\\angle C\' = 180° - \\angle A\' - \\angle B\'$. Так как $\\angle A=\\angle A\'$ и $\\angle B=\\angle B\'$, получаем $\\angle C = \\angle C\'$.',
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="700">∠A+∠B+∠C = 180°</text><text x="140" y="46" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700">∠A'+∠B'+∠C' = 180°</text><text x="140" y="72" text-anchor="middle" font-size="11" fill="#10b981" font-weight="800">∠C = 180°−∠A−∠B = 180°−∠A'−∠B' = ∠C'</text></svg>`},
{desc:'<b>Шаг 3.</b> На луче $A\'B\'$ откладываем отрезок $A\'M = AB$. Через $M$ проводим прямую, параллельную $B\'C\'$ — она встречает $A\'C\'$ в точке $N$. По теореме §4: $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$.',
svg:`<svg viewBox="0 0 280 145" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><polygon points="185,130 255,130 220,68" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5"/><polygon points="185,130 230,130 207,99" fill="rgba(79,70,229,.22)" stroke="#4f46e5" stroke-width="2"/><line x1="207" y1="99" x2="230" y2="130" stroke="#4f46e5" stroke-width="1.5" stroke-dasharray="4,3"/><text x="218" y="63" font-size="10" font-weight="700" fill="#4f46e5">A'</text><text x="177" y="140" font-size="10" font-weight="700" fill="#4338ca">B'</text><text x="257" y="140" font-size="10" font-weight="700" fill="#4338ca">C'</text><text x="228" y="138" font-size="9" font-weight="700" fill="#4f46e5">M</text><text x="209" y="97" font-size="9" font-weight="700" fill="#4f46e5">N</text><text x="50" y="80" font-size="9" fill="#4338ca">△A'MN∼△A'B'C'</text></svg>`},
{desc:'<b>Шаг 4.</b> Поскольку $A\'M = AB$ и углы треугольников $\\triangle A\'MN$ и $\\triangle ABC$ попарно равны (все три угла), а $\\angle A\' = \\angle A$ — вершины совпадают, то $\\triangle A\'MN \\cong \\triangle ABC$ (по условию и построению).',
svg:`<svg viewBox="0 0 280 90" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="11" fill="#4338ca" font-weight="700">A'M = AB, ∠A'=∠A, ∠B'=∠B</text><text x="140" y="46" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700">→ △A'MN ≅ △ABC (признак у-с-у)</text><text x="140" y="70" text-anchor="middle" font-size="10" fill="#6366f1">Следовательно MN = BC, A'N = AC</text></svg>`},
{desc:'<b>Шаг 5.</b> Итог: $\\triangle A\'MN \\cong \\triangle ABC$ и $\\triangle A\'MN \\sim \\triangle A\'B\'C\'$ — отсюда $\\triangle ABC \\sim \\triangle A\'B\'C\'$ (транзитивность подобия). <b>Первый признак подобия доказан.</b>',
svg:`<svg viewBox="0 0 280 80" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px"><text x="140" y="26" text-anchor="middle" font-size="12" fill="#4338ca" font-weight="800">∠A=∠A', ∠B=∠B' → △ABC △A'B'C'</text><text x="140" y="50" text-anchor="middle" font-size="10" fill="#4f46e5">Признак ДД — первый признак подобия</text><text x="140" y="70" text-anchor="middle" font-size="10" fill="#10b981" font-weight="800">QED ∎</text></svg>`},
];
let step=0;
const svgEl=document.getElementById('p5-proof-svg');
const descEl=document.getElementById('p5-proof-desc');
function show(){
svgEl.innerHTML=steps[step].svg;
descEl.innerHTML=steps[step].desc;
renderMath(descEl);
}
document.getElementById('p5-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;show();addXp(1,'p5-proof-step');}
else{addXp(5,'p5-proof-done');bumpProgress('p5',10);}
});
document.getElementById('p5-proof-reset').addEventListener('click',()=>{step=0;show();});
show();
})();
/* == INIT ИНТЕРАКТИВ 3: тренажёр == */
(function(){
const tasks=[
{q:'В $\\triangle ABC$: $\\angle A=40°$, $\\angle B=70°$. В $\\triangle A\'B\'C\'$: $\\angle A\'=40°$, $\\angle B\'=70°$. Чему равен $\\angle C\'$?',ans:70,hint:'∠C\'=1804070=70°.'},
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по признаку ДД. $AB=12$, $A\'B\'=4$. Найди коэффициент подобия $k$.',ans:3,hint:'k=AB/A\'B\'=12/4=3.'},
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$, $k=2.5$. Сторона $a\'=6$. Найди $a$.',ans:15,hint:'a=k·a\'=2.5·6=15.'},
{q:'Два прямоугольных треугольника. В первом острый угол $37°$, во втором $37°$. Сторона при прямом угле в первом — $10$, во втором — $6$. Найди коэффициент подобия.',ans:1.667,hint:'k=10/6≈1.667.'},
{q:'$\\angle A=\\angle A\'=55°$, $\\angle B=\\angle B\'=65°$. Сторона $c=18$ в $\\triangle ABC$, $c\'=9$ в $\\triangle A\'B\'C\'$. Найди $k$.',ans:2,hint:'k=c/c\'=18/9=2.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p5-tr-i').textContent=idx+1;
const t=document.getElementById('p5-tr-task');
t.innerHTML=tasks[idx].q;
renderMath(t);
document.getElementById('p5-tr-ans').value='';
document.getElementById('p5-tr-fb').style.display='none';
}
document.getElementById('p5-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p5-tr-score').textContent=0;show();});
document.getElementById('p5-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p5-tr-ans').value;
const fb=document.getElementById('p5-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.02){
score++;document.getElementById('p5-tr-score').textContent=score;
addXp(3,'p5-tr-'+idx);bumpProgress('p5',4);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p5-tr-all');bumpProgress('p5',10);confetti();}
} else {
feedback(fb,false,'Неверно. '+tasks[idx].hint);
}
});
document.getElementById('p5-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p5-tr-go').click();});
show();
})();
/* == INIT ИНТЕРАКТИВ 4: DnD-сортер == */
(function(){
const items=[
{text:'(50°,70°,60°) и (50°,70°,60°)',yes:true},
{text:'(40°,60°,80°) и (40°,50°,90°)',yes:false},
{text:'(90°,35°,55°) и (90°,35°,55°)',yes:true},
{text:'(30°,60°,90°) и (45°,45°,90°)',yes:false},
{text:'(80°,60°,40°) и (80°,40°,60°)',yes:true},
];
const pool=document.getElementById('p5-dnd-pool');
const yesBox=document.getElementById('p5-drop-yes-items');
const noBox=document.getElementById('p5-drop-no-items');
let dragging=null;
function makeChip(it,idx){
const chip=document.createElement('div');
chip.className='dnd-chip';
chip.dataset.idx=idx;
chip.textContent=it.text;
chip.draggable=true;
chip.addEventListener('dragstart',e=>{dragging=chip;chip.classList.add('dragging');e.dataTransfer.effectAllowed='move';});
chip.addEventListener('dragend',()=>{chip.classList.remove('dragging');dragging=null;});
return chip;
}
items.forEach((it,i)=>pool.appendChild(makeChip(it,i)));
[document.getElementById('p5-drop-yes'),document.getElementById('p5-drop-no'),pool].forEach(box=>{
box.addEventListener('dragover',e=>{e.preventDefault();box.classList.add('over');});
box.addEventListener('dragleave',()=>box.classList.remove('over'));
box.addEventListener('drop',e=>{
e.preventDefault();box.classList.remove('over');
if(!dragging)return;
const target=box===document.getElementById('p5-drop-yes')?yesBox:box===document.getElementById('p5-drop-no')?noBox:pool;
target.appendChild(dragging);
});
});
document.getElementById('p5-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p5-dnd-fb');
const yChips=[...yesBox.querySelectorAll('.dnd-chip')];
const nChips=[...noBox.querySelectorAll('.dnd-chip')];
if(yChips.length+nChips.length<items.length){feedback(fb,false,'Разложи все карточки.');return;}
let ok=true;
yChips.forEach(c=>{if(!items[+c.dataset.idx].yes)ok=false;});
nChips.forEach(c=>{if(items[+c.dataset.idx].yes)ok=false;});
if(ok){feedback(fb,true,'Верно! +5 XP');addXp(5,'p5-dnd');bumpProgress('p5',8);}
else{feedback(fb,false,'Есть ошибки. Два треугольника подобны, если у них есть хотя бы две пары равных углов.');}
});
document.getElementById('p5-dnd-reset').addEventListener('click',()=>{
[...yesBox.children].forEach(c=>pool.appendChild(c));
[...noBox.children].forEach(c=>pool.appendChild(c));
document.getElementById('p5-dnd-fb').style.display='none';
});
})();
/* == INIT ИНТЕРАКТИВ 5: калькулятор == */
(function(){
document.getElementById('p5-ccalc').addEventListener('click',()=>{
const A1=parseFloat(document.getElementById('p5-cA1').value);
const B1=parseFloat(document.getElementById('p5-cB1').value);
const A2=parseFloat(document.getElementById('p5-cA2').value);
const B2=parseFloat(document.getElementById('p5-cB2').value);
const a1=parseFloat(document.getElementById('p5-ca1').value);
const out=document.getElementById('p5-ccalc-out');
if([A1,B1,A2,B2,a1].some(v=>!isFinite(v)||v<=0)){
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Введи все поля.</span>';return;
}
const C1=180-A1-B1, C2=180-A2-B2;
if(C1<=0||C2<=0){
out.style.display='block';out.innerHTML='<span style="color:var(--bad)">Сумма углов превышает 180°.</span>';return;
}
// check similarity: sort angles and compare
const ang1=[A1,B1,C1].sort((a,b)=>a-b);
const ang2=[A2,B2,C2].sort((a,b)=>a-b);
const similar=ang1.every((v,i)=>Math.abs(v-ang2[i])<0.5);
if(!similar){
out.style.display='block';out.innerHTML=`$\\angle C_1=${fmt(C1)}°$, $\\angle C_2=${fmt(C2)}°$. Наборы углов различаются — треугольники <b>не подобны</b>. Признак ДД не выполнен.`;
renderMath(out);return;
}
// find matching side using sine rule: a/sin(A)=b/sin(B)
// k = a1 / (2R sin(A)) ... use ratio of sides
// match angles: find which angle in t2 corresponds to A1
// simplification: by ratio of corresponding sides via sine rule
// a1/sin(A1) = a2/sin(A2) → a2 = a1*sin(A2*pi/180)/sin(A1*pi/180)
const a2=a1*Math.sin(A2*Math.PI/180)/Math.sin(A1*Math.PI/180);
const k=a1/a2;
out.style.display='block';
out.innerHTML=`Треугольники подобны по признаку ДД.<br>$\\angle C_1 = ${fmt(C1)}°$, $\\angle C_2 = ${fmt(C2)}°$.<br>По теореме синусов: $a_2 = a_1 \\cdot \\dfrac{\\sin \\angle A_2}{\\sin \\angle A_1} = ${fmt(a1)} \\cdot \\dfrac{${fmt(Math.sin(A2*Math.PI/180).toFixed(4))}}{${fmt(Math.sin(A1*Math.PI/180).toFixed(4))}} = ${fmt(a2)}$.<br>Коэффициент подобия $k = a_1/a_2 = ${fmt(k)}$.`;
renderMath(out);
addXp(3,'p5-calc');bumpProgress('p5',5);
});
})();
/* == INIT: Босс §5 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 240 140" style="display:block;max-width:240px;margin:0 auto 8px;background:#e0e7ff;border:1px solid #a5b4fc;border-radius:8px"><polygon points="50,125 165,125 100,30" fill="rgba(79,70,229,.12)" stroke="#4f46e5" stroke-width="2"/><polygon points="175,125 230,125 200,78" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="1.8"/><text x="97" y="26" font-size="10" fill="#4338ca" font-weight="700">A</text><text x="40" y="134" font-size="10" fill="#4338ca" font-weight="700">B</text><text x="167" y="134" font-size="10" fill="#4338ca" font-weight="700">C</text><text x="197" y="74" font-size="9" fill="#4f46e5" font-weight="700">A\'</text><text x="168" y="134" font-size="9" fill="#4f46e5" font-weight="700">B\'</text><text x="232" y="134" font-size="9" fill="#4f46e5" font-weight="700">C\'</text><text x="120" y="12" text-anchor="middle" font-size="8" fill="#4338ca">∠A=∠A\'=60°, ∠B=∠B\'=80°</text></svg>$\\angle A=\\angle A\'=60°$, $\\angle B=\\angle B\'=80°$. $AB=15$, $A\'B\'=5$. Найди $k$.',ans:3,hint:'k=AB/A\'B\'=15/5=3.'},
{q:'Два прямоугольных треугольника. Острый угол одного $42°$, другого $42°$. Подобны ли? Гипотенуза первого $13$, второго $6.5$. Найди $k$.',ans:2,hint:'Подобны (ДД). k=13/6.5=2.'},
{q:'$\\triangle ABC \\sim \\triangle A\'B\'C\'$ по ДД. $k=4$. Периметр $\\triangle A\'B\'C\'=18$. Найди периметр $\\triangle ABC$.',ans:72,hint:'P=k·P\'=4·18=72.'},
{q:'В $\\triangle ABC$ и $\\triangle DEF$: $\\angle A=\\angle D=55°$, $\\angle B=\\angle E=75°$. $BC=20$, $EF=8$. Найди $k=BC/EF$.',ans:2.5,hint:'k=20/8=2.5.'},
];
const bossBox=document.getElementById('p5-boss-tasks');
bossBox.innerHTML=tasks.map((t,i)=>`
<div style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);margin-bottom:10px">
<div style="margin-bottom:8px;font-size:.95rem">${t.q}</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<input type="number" class="tinp" id="p5b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p5b-a${i}').value;
const fb=document.getElementById('p5b-fb${i}');
if(Math.abs(v-${t.ans})<0.02){
feedback(fb,true,'Верно! +5 XP');
if(!window.p5BossSolved.has(${i})){ window.p5BossSolved.add(${i}); addXp(5,'p5-boss${i}'); bumpProgress('p5',8); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p5b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p5BossSolved=new Set();
renderMath(bossBox);
})();
}
function buildP6stub(){ document.getElementById('p6-body').innerHTML='<div class="card"><div class="card-body"><p><b>§6 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p5','p7'); }
function buildP7stub(){ document.getElementById('p7-body').innerHTML='<div class="card"><div class="card-body"><p><b>§7 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p6','p8'); }
function buildP8stub(){ document.getElementById('p8-body').innerHTML='<div class="card"><div class="card-body"><p><b>§8 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p7','p9'); }