Files
Learn_System/frontend/textbooks/geometry_8_ch2.html
T
Maxim Dolgolyov 4b160a46e8 fix(geom8 ch2): аудит §9-§15 + финал — 5 косяков
§9 Босс 2: в условии было h=12 см, но правильный ответ S=10
требует h=8 см. Подправлены число в условии и подсказка.

§11 Теорема Пифагора:
- Card 11.1: 'квадраты на сторонах' были нарисованы как тонкие
  прямоугольники (140×20 и 20×100). Заменены на настоящие квадраты
  80×80 (a²) и 60×60 (b²). ViewBox увеличен до 200×255.
- Интерактив 1 (слайдер катетов): sqAh=min(40,ax*0.4) и sqBw=min(40,bx*0.4)
  давали прямоугольники, не квадраты. Теперь квадраты ax×ax и bx×bx
  с динамическим viewBox.

§12 Босс 3: в объекте задачи ans=144, но проверка использовала
correct[2]=62 — противоречие. Исправлено ans=62 + чистая подсказка.

Final2 Босс 1: маркер прямого угла в основании высоты H был
ориентирован неправильно (вертикально вниз). Пересчитан через
единичные векторы вдоль BC и перпендикуляра.

Всего проверено 21 SVG, исправлено 5. Остальные §10, §13, §14, §15 — OK.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 13:48:57 +03:00

7145 lines
585 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<title>Геометрия 8 · Глава 2 · Площади</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#fafafa; --card:#fff; --card-soft:#f0fdf4; --text:#0f172a; --ink:#0f172a; --muted:#64748b;
--border:#e2e8f0; --sh:0 1px 3px rgba(0,0,0,.06); --sh2:0 4px 14px rgba(0,0,0,.08);
--pri:#059669; --pri2:#047857; --pri-soft:#d1fae5;
--acc:#10b981; --acc2:#059669; --acc-soft:#a7f3d0;
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
}
.dark{--bg:#030a06; --card:#071209; --card-soft:#0a1a0e; --text:#ecfdf5; --ink:#ecfdf5; --muted:#6b9e82; --border:#14291a}
*{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
html,body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.55;font-size:15px}
button,input,select,textarea{font-family:inherit;font-size:inherit}
button{cursor:pointer;border:0;background:transparent;color:inherit}
a{color:inherit;text-decoration:none}
.ic{width:16px;height:16px;display:inline-block;flex-shrink:0;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;vertical-align:middle}
.hdr{position:relative;background:linear-gradient(110deg,#064e3b 0%,#059669 55%,#34d399 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(52,211,153,.2);min-height:130px}
.hdr::before{content:'ГЛАВА 2';position:absolute;right:-12px;top:50%;transform:translateY(-50%);font-family:'Unbounded',sans-serif;font-size:clamp(5rem,15vw,11rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(160,255,200,.12);line-height:1;pointer-events:none;user-select:none;z-index:0}
.hdr-row{position:relative;z-index:1;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.5rem;font-weight:900;letter-spacing:-.01em;line-height:1.3;padding-top:4px}
.hdr-sub{font-size:.85rem;opacity:.88;margin-top:6px;font-weight:500;line-height:1.4}
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center;flex-wrap:wrap}
.hdr-btn{padding:7px 12px;border-radius:9px;background:rgba(255,255,255,.14);color:#fff;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;text-decoration:none}
.hdr-btn:hover{background:rgba(255,255,255,.24)}
.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}
.col-main{min-width:0}
.hero{background:linear-gradient(135deg,var(--pri-soft) 0%,var(--acc-soft) 50%,var(--pri-soft) 100%);background-size:200% 200%;animation:heroShift 12s ease-in-out infinite;border:1px solid var(--border);border-radius:18px;padding:24px 22px;margin-bottom:24px;position:relative;overflow:hidden}
@keyframes heroShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
.hero h2{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;color:var(--pri2);margin-bottom:10px;letter-spacing:-.01em}
.hero p{font-size:.95rem;color:var(--text);opacity:.88;margin-bottom:14px;max-width:640px}
.hero-row{display:flex;gap:14px;flex-wrap:wrap;align-items:center}
.btn-primary{padding:11px 22px;background:linear-gradient(135deg,var(--pri),var(--pri2));color:#fff;border-radius:11px;font-weight:700;font-size:.92rem;display:inline-flex;align-items:center;gap:8px;box-shadow:var(--sh2);transition:transform .15s,box-shadow .15s}
.btn-primary:hover{transform:translateY(-1px);box-shadow:0 8px 28px rgba(5,150,105,.32)}
.hero-progress{flex:1;min-width:200px;max-width:280px}
.hp-label{font-size:.74rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;display:block;margin-bottom:5px}
.hp-bar{height:8px;background:rgba(5,150,105,.18);border-radius:5px;overflow:hidden}
.hp-fill{height:100%;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:5px;width:0%;transition:width .6s cubic-bezier(.16,1,.3,1)}
.hp-text{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:4px;display:block}
.hero-xp-badge{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,var(--warn,#f59e0b),var(--pri));color:#fff;border-radius:99px;font-size:.82rem;font-weight:800;letter-spacing:.02em;box-shadow:0 4px 12px rgba(5,150,105,.22);font-family:'Unbounded',sans-serif}
.psel{margin-bottom:24px}
.psel-title{font-size:.72rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:10px}
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:10px}
.psel-card{background:var(--card);border:1.5px solid var(--border);border-radius:13px;padding:14px;cursor:pointer;transition:transform .2s,box-shadow .2s,border-color .2s;text-align:left;position:relative}
.psel-card:hover{transform:translateY(-3px);box-shadow:var(--sh2);border-color:var(--pri)}
.psel-card.active{border-color:var(--pri);background:linear-gradient(135deg,var(--pri-soft),var(--card));box-shadow:var(--sh2)}
.psel-card.active::after{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,var(--pri),var(--acc));border-radius:13px 13px 0 0}
.psel-num{font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;color:var(--pri);text-transform:uppercase;letter-spacing:.08em;margin-bottom:5px}
.psel-name{font-size:.88rem;font-weight:700;color:var(--text);line-height:1.3;margin-bottom:8px}
.psel-prog{height:4px;background:rgba(5,150,105,.10);border-radius:3px;overflow:hidden}
.psel-prog-fill{height:100%;background:var(--pri);width:0%;transition:width .4s}
.psel-card.final{background:linear-gradient(135deg,#f0fdf4,#d1fae5)}
.psel-card.final .psel-num{color:var(--warn)}
/* SECTION COLORS — emerald/teal/green spectrum */
.sec[id="sec-p1"] { --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
.sec[id="sec-p2"] { --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#a7f3d0; }
.sec[id="sec-p3"] { --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.sec[id="sec-p4"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.sec[id="sec-p5"] { --sec-acc:#0284c7; --sec-acc-d:#0369a1; --sec-acc-soft:#e0f2fe; }
.sec[id="sec-p6"] { --sec-acc:#6366f1; --sec-acc-d:#4f46e5; --sec-acc-soft:#e0e7ff; }
.sec[id="sec-p7"] { --sec-acc:#7c3aed; --sec-acc-d:#6d28d9; --sec-acc-soft:#ede9fe; }
.sec[id="sec-p8"] { --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
.sec[id="sec-p9"] { --sec-acc:#10b981; --sec-acc-d:#059669; --sec-acc-soft:#a7f3d0; }
.sec[id="sec-p10"] { --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.sec[id="sec-p11"] { --sec-acc:#16a34a; --sec-acc-d:#15803d; --sec-acc-soft:#dcfce7; }
.sec[id="sec-p12"] { --sec-acc:#22c55e; --sec-acc-d:#16a34a; --sec-acc-soft:#bbf7d0; }
.sec[id="sec-p13"] { --sec-acc:#84cc16; --sec-acc-d:#65a30d; --sec-acc-soft:#ecfccb; }
.sec[id="sec-p14"] { --sec-acc:#d97706; --sec-acc-d:#b45309; --sec-acc-soft:#fef3c7; }
.sec[id="sec-p15"] { --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
.sec[id="sec-final2"] { --sec-acc:#059669; --sec-acc-d:#047857; --sec-acc-soft:#d1fae5; }
.sec{display:none;position:relative;animation:fadeIn .35s ease}
.sec.active{display:block}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:none}}
.sec::before{content:attr(data-watermark);position:absolute;right:-20px;top:10%;font-family:'Unbounded',sans-serif;font-size:clamp(6rem,18vw,14rem);font-weight:900;color:transparent;-webkit-text-stroke:1.5px var(--sec-acc-soft,var(--pri-soft));line-height:1;pointer-events:none;user-select:none;z-index:0;opacity:.35}
.sec-header{margin-bottom:22px;padding-bottom:14px;border-bottom:2px solid var(--sec-acc-soft,var(--pri-soft));position:relative;z-index:1}
.sec-num{display:inline-block;padding:4px 10px;background:linear-gradient(135deg,var(--sec-acc,var(--pri)),var(--sec-acc-d,var(--pri2)));color:#fff;border-radius:7px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;margin-bottom:8px}
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.7rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));letter-spacing:-.01em;line-height:1.25}
.card{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:18px 20px;margin-bottom:16px;box-shadow:0 1px 3px rgba(0,0,0,.04),0 8px 24px rgba(5,150,105,.06);position:relative;z-index:1;transition:transform .25s cubic-bezier(.16,1,.3,1),box-shadow .25s}
.card:hover{transform:translateY(-2px);box-shadow:0 4px 10px rgba(0,0,0,.06),0 16px 36px rgba(5,150,105,.12)}
.card-header{display:flex;align-items:center;gap:10px;margin-bottom:12px;padding-bottom:10px;border-bottom:1px dashed var(--border)}
.card-icon{width:32px;height:32px;border-radius:9px;display:flex;align-items:center;justify-content:center;flex-shrink:0;color:#fff}
.card-icon.repeat{background:#0ea5e9}.card-icon.theory{background:#8b5cf6}.card-icon.algo{background:#f59e0b}.card-icon.rule{background:#ec4899}.card-icon.example{background:#10b981}.card-icon.oral{background:#06b6d4}.card-icon.class{background:#3b82f6}.card-icon.home{background:#f97316}
.card-icon .ic{width:18px;height:18px}
.card-title{font-family:'Unbounded',sans-serif;font-size:.82rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);flex:1}
.card-num{font-size:.74rem;font-weight:700;color:var(--muted);background:var(--sec-acc-soft,var(--pri-soft));padding:3px 7px;border-radius:5px}
.card-body{font-size:.94rem;line-height:1.65}
.card-body p{margin-bottom:8px}
.wg{background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)));border:1.5px solid var(--sec-acc,var(--pri));border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1}
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.wg-badge{padding:4px 9px;background:var(--sec-acc,var(--pri));color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));flex:1}
.wg-help{font-size:.88rem;color:var(--text);margin-bottom:12px;line-height:1.55;background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--sec-acc-soft,var(--pri-soft)));border-left:4px solid var(--warn,#f59e0b);padding:9px 14px;border-radius:9px}
.btn{padding:8px 16px;border-radius:8px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:600;font-size:.88rem;transition:background .15s,border-color .15s,transform .1s}
.btn:hover{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
.btn:active{transform:scale(.96)}
.btn.primary{background:var(--sec-acc,var(--pri));color:#fff;border-color:var(--sec-acc,var(--pri))}
.btn.primary:hover{background:var(--sec-acc-d,var(--pri2));border-color:var(--sec-acc-d,var(--pri2))}
.btn.small{padding:5px 11px;font-size:.78rem}
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);transition:border-color .15s}
.tinp:focus{outline:0;border-color:var(--sec-acc,var(--pri));box-shadow:0 0 0 3px var(--sec-acc-soft,var(--pri-soft))}
.feedback{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none}
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.sidecard-row{margin-bottom:8px;font-size:.86rem;line-height:1.6}
.sidecard-row b{color:var(--pri);font-weight:700}
.sidecard-row:last-child{margin-bottom:0}
@media(max-width:980px){.col-side{position:static;max-height:none}}
.xp-card{background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft));border:1.5px solid var(--acc);border-radius:12px;padding:14px;margin-bottom:14px}
.xp-card-title{font-size:.68rem;font-weight:800;color:var(--acc2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between}
.xp-level{font-size:1.1rem;font-weight:900;color:var(--acc2);font-family:'Unbounded',sans-serif}
.xp-bar{height:9px;background:rgba(16,185,129,.15);border-radius:6px;overflow:hidden;margin:7px 0}
.xp-fill{height:100%;background:linear-gradient(90deg,var(--acc),var(--pri));border-radius:6px;transition:width .5s cubic-bezier(.4,0,.2,1)}
.xp-nums{font-size:.74rem;color:var(--muted);display:flex;justify-content:space-between}
.spoiler{border:1px solid var(--border);border-radius:10px;background:var(--card);margin:10px 0;overflow:hidden}
.spoiler summary{padding:8px 14px;background:var(--sec-acc-soft,var(--pri-soft));font-weight:700;cursor:pointer;font-size:.88rem;color:var(--sec-acc-d,var(--pri2));list-style:none;display:flex;align-items:center;gap:8px}
.spoiler summary::-webkit-details-marker{display:none}
.spoiler summary::before{content:'+';font-size:1.2rem;font-weight:900;color:var(--sec-acc,var(--pri));width:18px}
.spoiler[open] summary::before{content:'\2212'}
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
.sec-nav{display:flex;gap:10px;margin-top:24px;padding-top:20px;border-top:1px solid var(--border);justify-content:space-between;flex-wrap:wrap}
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
.tbl{width:100%;border-collapse:collapse;margin:12px 0;font-size:.88rem}
.tbl th,.tbl td{padding:7px 10px;border:1px solid var(--border);text-align:center}
.tbl th{background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));font-weight:700}
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,#059669,#10b981);color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(5,150,105,.45);z-index:1002;display:none;align-items:center;gap:8px;animation:achIn .45s cubic-bezier(.34,1.56,.64,1) forwards;max-width:340px}
.ach-popup.show{display:flex}
@keyframes achIn{from{opacity:0;transform:translateX(40px)}to{opacity:1;transform:none}}
.dnd-pool{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:14px;padding:10px;border:1.5px dashed var(--border);border-radius:10px;min-height:54px;transition:border-color .18s,background .18s}
.dnd-pool.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid}
.dnd-pool.col{flex-direction:column;align-items:stretch}
.dnd-chip{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:var(--card);border:1.5px solid var(--border);border-radius:10px;cursor:grab;user-select:none;font-size:.92rem;line-height:1.4;transition:transform .12s,box-shadow .12s,border-color .12s;touch-action:none;max-width:100%}
.dnd-chip:hover{transform:translateY(-1px);border-color:var(--sec-acc,var(--pri));box-shadow:var(--sh)}
.dnd-chip.armed{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));box-shadow:0 0 0 3px rgba(5,150,105,.22);transform:translateY(-1px)}
.dnd-chip.dragging{opacity:.28}
.dnd-chip.placed{background:var(--sec-acc-soft,var(--pri-soft));border-color:var(--sec-acc,var(--pri))}
.dnd-chip .dnd-x{padding:0 5px;color:var(--muted);font-weight:700;font-size:1.05rem;border-radius:4px;cursor:pointer}
.dnd-chip .dnd-x:hover{color:var(--bad,var(--fail));background:var(--fail-bg)}
.drop-box{background:var(--card);border:1.5px dashed var(--border);border-radius:10px;padding:10px;min-height:90px;transition:border-color .15s,background .15s}
.drop-box:hover{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft))}
.drop-box h5{font-family:'Unbounded',sans-serif;font-size:.78rem;color:var(--sec-acc-d,var(--pri2));margin-bottom:8px;text-transform:uppercase;letter-spacing:.05em}
.drop-box.over{border-color:var(--sec-acc,var(--pri));background:var(--sec-acc-soft,var(--pri-soft));border-style:solid;transform:scale(1.015)}
.drop-items{display:flex;flex-wrap:wrap;gap:6px;min-height:32px}
.dnd-hint{font-size:.78rem;color:var(--muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
.dnd-hint svg{width:14px;height:14px;flex-shrink:0}
.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:10px}
.sliders label{display:block;font-size:.92rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border);line-height:1.5}
.sliders label b{font-family:'JetBrains Mono',monospace;font-size:1.05rem;color:var(--sec-acc-d,var(--pri2));margin-left:4px}
.sliders label input[type="range"]{display:block;width:100%;margin-top:6px;accent-color:var(--sec-acc,var(--pri))}
.score-display{display:flex;gap:14px;flex-wrap:wrap;align-items:center;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-bottom:12px}
.score-display b{color:var(--sec-acc-d,var(--pri2));font-size:1.15rem}
.col-side-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.42);z-index:9990;display:none;animation:fadeIn .18s ease}
.col-side-backdrop.show{display:block}
@media(max-width:980px){
.col-side{position:fixed;top:0;right:0;height:100vh;width:300px;max-width:88vw;background:var(--bg);box-shadow:-12px 0 24px rgba(0,0,0,.18);padding:18px 16px;overflow-y:auto;transform:translateX(100%);transition:transform .25s ease;z-index:9991;max-height:none}
.col-side.open{transform:none}
}
.gloss-term{border-bottom:1.5px dotted var(--sec-acc,var(--pri));cursor:help;color:var(--sec-acc-d,var(--pri2));font-weight:600;padding:0 1px}
.gloss-term:hover{background:var(--sec-acc-soft,var(--pri-soft));border-radius:3px}
.gloss-tip{position:fixed;max-width:320px;padding:11px 14px;background:var(--card);border:1.5px solid var(--sec-acc,var(--pri));border-radius:11px;font-size:.84rem;line-height:1.55;box-shadow:0 12px 32px rgba(0,0,0,.18);z-index:9994;display:none;pointer-events:none;color:var(--text)}
.gloss-tip.show{display:block;animation:tipIn .15s ease}
.gloss-tip b{color:var(--sec-acc-d,var(--pri2));font-size:.92rem}
@keyframes tipIn{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.search-modal{position:fixed;inset:0;background:rgba(15,23,42,.55);backdrop-filter:blur(4px);z-index:9993;display:none;align-items:flex-start;justify-content:center;padding-top:14vh}
.search-modal.show{display:flex;animation:fadeIn .15s ease}
.search-box{background:var(--bg);border:1px solid var(--border);border-radius:14px;width:560px;max-width:92vw;max-height:70vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:0 24px 64px rgba(0,0,0,.4)}
.search-input{padding:14px 16px;font-size:1rem;border:0;border-bottom:1px solid var(--border);background:transparent;color:var(--text);outline:none}
.search-results{flex:1;overflow-y:auto;padding:6px 0}
.search-row{display:block;padding:8px 16px;cursor:pointer;border-bottom:1px solid var(--border);text-align:left;background:transparent;border-left:0;border-right:0;border-top:0;width:100%;color:var(--text)}
.search-row:hover,.search-row.active{background:var(--sec-acc-soft,var(--pri-soft))}
.search-row .sr-kind{font-size:.7rem;font-weight:800;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:2px}
.search-row .sr-title{font-weight:700;font-size:.92rem;color:var(--text)}
.search-row .sr-desc{font-size:.8rem;color:var(--muted);margin-top:2px}
.search-empty{padding:20px;text-align:center;color:var(--muted);font-size:.88rem}
.search-foot{padding:8px 14px;border-top:1px solid var(--border);font-size:.74rem;color:var(--muted);display:flex;gap:14px;background:var(--card-soft,transparent)}
.search-foot kbd{padding:2px 6px;background:var(--card);border:1px solid var(--border);border-radius:4px;font-family:'JetBrains Mono',monospace;font-size:.72rem}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-row">
<div>
<h1>Геометрия 8 · Глава 2</h1>
<div class="hdr-sub">Площади</div>
</div>
<div class="hdr-side">
<a href="/textbook/geometry-8" class="hdr-btn" title="К Геометрии 8 — все главы">
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
К геометрии 8
</a>
<button id="search-btn" class="hdr-btn" title="Поиск (Ctrl+K)">
<svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg>
Поиск
</button>
<button id="sidebar-btn" class="hdr-btn" title="Шпаргалка">
<svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg>
Шпаргалка
</button>
<button id="theme-btn" class="hdr-btn" title="Сменить тему">
<svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
<span id="theme-lab">Тёмная</span>
</button>
</div>
</div>
</header>
<main class="main">
<div class="col-main">
<section class="hero">
<h2>Площади: от квадрата до теоремы Пифагора</h2>
<p>Площадь — числовая мера размера фигуры. Мы выведем формулы для <b>всех плоских фигур</b>: квадрата, прямоугольника, параллелограмма, треугольника, трапеции, ромба. Главный результат — <b>теорема Пифагора</b> и её доказательство через площади.</p>
<div class="hero-row">
<button class="btn-primary" onclick="goTo('p1')">
<svg class="ic" viewBox="0 0 24 24"><polygon points="6 4 20 12 6 20 6 4" fill="currentColor" stroke="none"/></svg>
Начать § 1
</button>
<div class="hero-progress">
<span class="hp-label">Прогресс по главе</span>
<div class="hp-bar"><div id="hero-hp-fill" class="hp-fill"></div></div>
<span id="hero-hp-text" class="hp-text">0%</span>
</div>
<div id="hero-xp-badge" class="hero-xp-badge" title="Опыт"></div>
</div>
</section>
<section class="psel">
<div class="psel-title">Параграфы главы</div>
<div id="psel-grid" class="psel-grid"></div>
</section>
<section id="sec-p1" class="sec" data-watermark="S"><div class="sec-header"><span class="sec-num">§ 1</span><h2 class="sec-h">Площадь квадрата</h2></div><div id="p1-body"></div></section>
<section id="sec-p2" class="sec" data-watermark="ab"><div class="sec-header"><span class="sec-num">§ 2</span><h2 class="sec-h">Площадь прямоугольника</h2></div><div id="p2-body"></div></section>
<section id="sec-p3" class="sec" data-watermark="bh"><div class="sec-header"><span class="sec-num">§ 3</span><h2 class="sec-h">Площадь параллелограмма</h2></div><div id="p3-body"></div></section>
<section id="sec-p4" class="sec" data-watermark="&#189;bh"><div class="sec-header"><span class="sec-num">§ 4</span><h2 class="sec-h">Площадь треугольника</h2></div><div id="p4-body"></div></section>
<section id="sec-p5" class="sec" data-watermark="&#189;(a+b)h"><div class="sec-header"><span class="sec-num">§ 5</span><h2 class="sec-h">Площадь трапеции</h2></div><div id="p5-body"></div></section>
<section id="sec-p6" class="sec" data-watermark="&#189;dd"><div class="sec-header"><span class="sec-num">§ 6</span><h2 class="sec-h">Площадь ромба</h2></div><div id="p6-body"></div></section>
<section id="sec-p7" class="sec" data-watermark="&#8978;"><div class="sec-header"><span class="sec-num">§ 7</span><h2 class="sec-h">Площадь прямоугольного треугольника</h2></div><div id="p7-body"></div></section>
<section id="sec-p8" class="sec" data-watermark="h"><div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Высота, проведённая к гипотенузе</h2></div><div id="p8-body"></div></section>
<section id="sec-p9" class="sec" data-watermark="m"><div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Треугольники с общей высотой</h2></div><div id="p9-body"></div></section>
<section id="sec-p10" class="sec" data-watermark="2:1"><div class="sec-header"><span class="sec-num">§ 10</span><h2 class="sec-h">Свойства медианы для площадей</h2></div><div id="p10-body"></div></section>
<section id="sec-p11" class="sec" data-watermark="a&#178;+b&#178;"><div class="sec-header"><span class="sec-num">§ 11</span><h2 class="sec-h">Теорема Пифагора</h2></div><div id="p11-body"></div></section>
<section id="sec-p12" class="sec" data-watermark="&#8730;3"><div class="sec-header"><span class="sec-num">§ 12</span><h2 class="sec-h">S и h равностороннего треугольника</h2></div><div id="p12-body"></div></section>
<section id="sec-p13" class="sec" data-watermark="&#8730;2"><div class="sec-header"><span class="sec-num">§ 13</span><h2 class="sec-h">Диагональ квадрата</h2></div><div id="p13-body"></div></section>
<section id="sec-p14" class="sec" data-watermark="&#8656;"><div class="sec-header"><span class="sec-num">§ 14</span><h2 class="sec-h">Обратная теорема Пифагора</h2></div><div id="p14-body"></div></section>
<section id="sec-p15" class="sec" data-watermark="3-4-5"><div class="sec-header"><span class="sec-num">§ 15</span><h2 class="sec-h">Пифагоровы тройки</h2></div><div id="p15-body"></div></section>
<section id="sec-final2" class="sec" data-watermark="&#9733;"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#059669,#10b981)">Финал главы</span><h2 class="sec-h">Итоги. Боссы главы 2</h2></div><div id="final2-body"></div></section>
</div>
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
<div class="col-side-backdrop" id="col-side-backdrop"></div>
</main>
<footer class="foot">Интерактивный учебник «Геометрия 8» · Глава 2 · Площади · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><rect x="3" y="3" width="18" height="14" rx="1"/></svg><span id="ach-text">Достижение!</span></div>
<div id="gloss-tip" class="gloss-tip"></div>
<div id="search-modal" class="search-modal" role="dialog" aria-label="Поиск по главе">
<div class="search-box">
<input type="text" id="search-input" class="search-input" placeholder="Поиск: формула, теорема, параграф…" autocomplete="off">
<div id="search-results" class="search-results"></div>
<div class="search-foot"><span><kbd>&#8593;&#8595;</kbd> навигация</span><span><kbd>Enter</kbd> открыть</span><span><kbd>Esc</kbd> закрыть</span></div>
</div>
</div>
<script>
'use strict';
const STATE = {
current: 'p1',
progress: { p1:0,p2:0,p3:0,p4:0,p5:0,p6:0,p7:0,p8:0,p9:0,p10:0,p11:0,p12:0,p13:0,p14:0,p15:0,final2:0 },
achievements: new Map(), xp: 0, level: 1,
};
function calcLevel(xp){ return Math.floor(Math.sqrt((xp||0)/100))+1; }
function _xpForLevel(lv){ return (lv-1)*(lv-1)*100; }
const ACH_LABELS = { start:'Начало главы 2!', ch2_done:'Площади изучены!' };
function loadProgress(){
try{
const s=localStorage.getItem('geometry8_ch2_progress'); if(s) Object.assign(STATE.progress,JSON.parse(s));
const a=localStorage.getItem('geometry8_ch2_achievements'); if(a){ const p=JSON.parse(a); if(Array.isArray(p)) p.forEach(id=>STATE.achievements.set(id,ACH_LABELS[id]||id)); else if(p&&typeof p==='object') for(const [id,t] of Object.entries(p)) STATE.achievements.set(id,(t&&t!==id)?t:(ACH_LABELS[id]||id)); }
STATE.xp=+(localStorage.getItem('geometry8_xp')||0); STATE.level=calcLevel(STATE.xp);
}catch(e){}
}
function saveProgress(){
try{ localStorage.setItem('geometry8_ch2_progress',JSON.stringify(STATE.progress)); localStorage.setItem('geometry8_ch2_achievements',JSON.stringify(Object.fromEntries(STATE.achievements))); localStorage.setItem('geometry8_xp',String(STATE.xp)); }catch(e){}
}
function bumpProgress(key,delta){ STATE.progress[key]=Math.max(0,Math.min(100,(STATE.progress[key]||0)+delta)); saveProgress(); refreshProgressUI(); if(STATE.progress[key]>=50) markParaRead(key); }
const _TB_SLUG='geometry-8-ch2'; const _markedRead=new Set(); let _pendingProgressBody=null,_progressTimer=null;
function _flushProgress(){ const body=_pendingProgressBody;_pendingProgressBody=null;if(!body)return; const tok=(window.LS&&LS.getToken)?LS.getToken():'';if(!tok)return; fetch('/api/textbooks/'+_TB_SLUG+'/progress',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer '+tok},body:JSON.stringify(body),keepalive:true}).catch(()=>{}); }
function _queueProgress(patch){ _pendingProgressBody=Object.assign(_pendingProgressBody||{},patch); if(_progressTimer)clearTimeout(_progressTimer); _progressTimer=setTimeout(_flushProgress,600); }
function markLastPara(id){ _queueProgress({last_para:id}); }
function markParaRead(id){ if(_markedRead.has(id))return;_markedRead.add(id);_queueProgress({mark_read:id}); }
window.addEventListener('beforeunload',_flushProgress);
function loadServerReadState(){ const tok=(window.LS&&LS.getToken)?LS.getToken():'';if(!tok)return; fetch('/api/textbooks/'+_TB_SLUG,{headers:{'Authorization':'Bearer '+tok}}).then(r=>r.ok?r.json():null).then(d=>{ if(!d||!d.progress)return; (d.progress.read||[]).forEach(k=>{_markedRead.add(k);if((STATE.progress[k]||0)<50)STATE.progress[k]=100;}); saveProgress();refreshProgressUI(); }).catch(()=>{}); }
function addXp(n,src){ if(!n)return; const prev=STATE.level; STATE.xp=Math.max(0,(STATE.xp||0)+n); STATE.level=calcLevel(STATE.xp); saveProgress();refreshProgressUI(); if(window.LS&&window.LS.xp) window.LS.xp.add(n,'geometry8-ch2-'+(src||'misc')); if(STATE.level>prev){ const pop=document.getElementById('ach-popup'); if(pop){document.getElementById('ach-text').textContent='Уровень '+STATE.level+'!';pop.classList.add('show');setTimeout(()=>pop.classList.remove('show'),2600);} if(window.confetti)try{confetti();}catch(e){} } }
const TOTAL_PARAS=16;
function refreshProgressUI(){
const total=Math.round(Object.values(STATE.progress).reduce((a,b)=>a+b,0)/TOTAL_PARAS);
const f=document.getElementById('hero-hp-fill');if(f)f.style.width=total+'%';
const t=document.getElementById('hero-hp-text');if(t)t.textContent=total+'% пройдено';
document.querySelectorAll('[data-prog-card]').forEach(el=>{ const k=el.dataset.progCard;const fl=el.querySelector('.psel-prog-fill');if(fl)fl.style.width=(STATE.progress[k]||0)+'%'; });
const xpBadge=document.getElementById('hero-xp-badge'); if(xpBadge){ xpBadge.innerHTML='<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:13px;height:13px"><rect x="3" y="3" width="18" height="14" rx="1"/></svg> Ур. '+STATE.level+' \xb7 '+(STATE.xp||0)+' XP'; }
if(STATE.current&&document.getElementById('sidebar-content')){ try{buildSidebar(STATE.current);}catch(e){} }
}
function achievement(id,text){ if(STATE.achievements.has(id))return; STATE.achievements.set(id,text||ACH_LABELS[id]||id); saveProgress(); const pop=document.getElementById('ach-popup'); if(pop){document.getElementById('ach-text').textContent=text||ACH_LABELS[id]||id;pop.classList.add('show');setTimeout(()=>pop.classList.remove('show'),3300);} addXp(20,'ach-'+id); }
const PARAS = [
{ id:'p1', num:'§ 1', name:'Площадь квадрата', sub:'S = a²' },
{ id:'p2', num:'§ 2', name:'Площадь прямоугольника', sub:'S = ab' },
{ id:'p3', num:'§ 3', name:'Площадь параллелограмма', sub:'S = bh' },
{ id:'p4', num:'§ 4', name:'Площадь треугольника', sub:'S = ½bh' },
{ id:'p5', num:'§ 5', name:'Площадь трапеции', sub:'S = ½(a+b)h' },
{ id:'p6', num:'§ 6', name:'Площадь ромба', sub:'S = ½d₁d₂' },
{ id:'p7', num:'§ 7', name:'Прямоугольный треугольник', sub:'S = ½ab' },
{ id:'p8', num:'§ 8', name:'Высота к гипотенузе', sub:'h² = ab' },
{ id:'p9', num:'§ 9', name:'Общая высота', sub:'Отношение площадей' },
{ id:'p10', num:'§ 10', name:'Медиана и площадь', sub:'2 равные части' },
{ id:'p11', num:'§ 11', name:'Теорема Пифагора', sub:'a² + b² = c²' },
{ id:'p12', num:'§ 12', name:'Равносторонний треугольник', sub:'h = a√3/2' },
{ id:'p13', num:'§ 13', name:'Диагональ квадрата', sub:'d = a√2' },
{ id:'p14', num:'§ 14', name:'Обратная теорема Пифагора', sub:'Признак прямого угла' },
{ id:'p15', num:'§ 15', name:'Пифагоровы тройки', sub:'3-4-5, 5-12-13, ...' },
{ id:'final2', num:'★', name:'Финал главы', sub:'Итоги · Боссы', final:true },
];
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:()=>buildP4(),p5:()=>buildP5(),
p6:()=>buildP6(),p7:()=>buildP7(),p8:()=>buildP8(),p9:()=>buildP9(),p10:()=>buildP10(),
p11:()=>buildP11(),p12:()=>buildP12(),p13:()=>buildP13(),p14:()=>buildP14(),p15:()=>buildP15(),
final2:()=>buildFinal2(),
};
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);
}
const SIDEBARS={
p1:{ title:'Шпаргалка § 1', rows:[['Площадь квадрата','$S = a^2$'],['Единицы','мм², см², м², км²']] },
p2:{ title:'Шпаргалка § 2', rows:[['Площадь прямоугольника','$S = ab$'],['Основание × высоту','']] },
p3:{ title:'Шпаргалка § 3', rows:[['$S = bh$','основание × высота'],['Высота','расстояние между параллельными сторонами']] },
p4:{ title:'Шпаргалка § 4', rows:[['$S = \\dfrac{1}{2}bh$','половина произведения'],['Основание','любая сторона треугольника']] },
p5:{ title:'Шпаргалка § 5', rows:[['$S = \\dfrac{a+b}{2}\\cdot h$','полусумма оснований × высота']] },
p6:{ title:'Шпаргалка § 6', rows:[['$S = \\dfrac{d_1 d_2}{2}$','полупроизведение диагоналей']] },
p7:{ title:'Шпаргалка § 7', rows:[['$S = \\dfrac{ab}{2}$','полупроизведение катетов'],['Катеты','стороны при прямом угле']] },
p8:{ title:'Шпаргалка § 8', rows:[['$h^2 = a_1 \\cdot a_2$','высота к гипотенузе'],['$a^2 = c \\cdot a_1$','катет и проекция']] },
p9:{ title:'Шпаргалка § 9', rows:[['Общая высота','отношение площадей = отношению оснований']] },
p10:{ title:'Шпаргалка § 10', rows:[['Медиана','делит треугольник на 2 равновеликих']] },
p11:{ title:'Шпаргалка § 11', rows:[['Теорема Пифагора','$a^2 + b^2 = c^2$'],['$c$','гипотенуза'],['$a, b$','катеты']] },
p12:{ title:'Шпаргалка § 12', rows:[['Высота','$h = \\dfrac{a\\sqrt{3}}{2}$'],['Площадь','$S = \\dfrac{a^2\\sqrt{3}}{4}$']] },
p13:{ title:'Шпаргалка § 13', rows:[['Диагональ квадрата','$d = a\\sqrt{2}$'],['Угол','45°']] },
p14:{ title:'Шпаргалка § 14', rows:[['Обратная','если $a^2+b^2=c^2$, то угол прямой']] },
p15:{ title:'Шпаргалка § 15', rows:[['3-4-5','тройка Пифагора'],['5-12-13',''],['8-15-17','']] },
final2:{ title:'Финал главы', rows:[['15 параграфов','площади изучены'],['Главный результат','Теорема Пифагора']] },
};
const TIPS=[
{sec:'p1', html:'$S = a^2$ — отсюда и название «квадрат» числа.'},
{sec:'p2', html:'Площадь прямоугольника $= $ длина $\\times$ ширина. Проверь: $3\\times4=12$ кв.ед.'},
{sec:'p3', html:'Высота параллелограмма — это <b>перпендикуляр</b> между параллельными сторонами, не боковая сторона!'},
{sec:'p4', html:'Площадь треугольника = <b>половине</b> площади параллелограмма на том же основании.'},
{sec:'p5', html:'Трапеция: $S = \\dfrac{a+b}{2}\\cdot h$ = средняя линия × высота.'},
{sec:'p6', html:'Площадь ромба через диагонали: $S = \\dfrac{d_1 d_2}{2}$. Это удобнее, чем $S = ah$.'},
{sec:'p7', html:'У прямоугольного треугольника $S = \\dfrac{ab}{2}$, где $a, b$ — катеты.'},
{sec:'p8', html:'Высота к гипотенузе делит её на два отрезка; $h^2 = a_1 a_2$.'},
{sec:'p9', html:'Два треугольника с общей высотой: их площади относятся как их основания.'},
{sec:'p10', html:'Медиана делит треугольник на два <b>равновеликих</b> треугольника.'},
{sec:'p11', html:'Теорема Пифагора: $a^2 + b^2 = c^2$. Самая важная теорема курса!'},
{sec:'p12', html:'В равностороннем треугольнике $h = \\dfrac{a\\sqrt{3}}{2}$, $S = \\dfrac{a^2\\sqrt{3}}{4}$.'},
{sec:'p13', html:'Диагональ квадрата $d = a\\sqrt{2}$ — применение теоремы Пифагора.'},
{sec:'p14', html:'Обратная теорема: если $a^2+b^2=c^2$, то треугольник прямоугольный.'},
{sec:'p15', html:'Пифагоровы тройки: $(3,4,5)$, $(5,12,13)$, $(8,15,17)$, $(7,24,25)$...'},
{sec:'final2', html:'Знание формул площадей + теорема Пифагора — ключ ко всему курсу.'},
];
function buildSidebar(id){
const box=document.getElementById('sidebar-content'); const sb=SIDEBARS[id]||SIDEBARS.p1; let html='';
const xpForLv=_xpForLevel(STATE.level),xpNext=_xpForLevel(STATE.level+1);
const xpInLv=STATE.xp-xpForLv,xpRange=xpNext-xpForLv,xpPct=xpRange>0?Math.round(xpInLv/xpRange*100):100;
html+=`<div class="xp-card"><div class="xp-card-title"><span>XP-прогресс</span><span class="xp-level">Ур. ${STATE.level}</span></div><div class="xp-bar"><div class="xp-fill" style="width:${xpPct}%"></div></div><div class="xp-nums"><span>${STATE.xp} XP</span><span>${xpNext} XP</span></div></div>`;
html+=`<div class="sidecard"><h4>${sb.title}</h4>`; sb.rows.forEach(([k,v])=>{ html+=`<div class="sidecard-row"><b>${k}</b>${v?' — '+v:''}</div>`; }); html+='</div>';
const tip=TIPS.find(t=>t.sec===id)||TIPS[0];
html+=`<div class="sidecard" style="background:linear-gradient(135deg,var(--warn-bg,#fef3c7),var(--pri-soft));border-color:var(--warn,#f59e0b)"><h4 style="color:#065f46;display:flex;align-items:center;gap:6px"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:14px;height:14px"><rect x="3" y="3" width="18" height="14" rx="1"/></svg>Подсказка</h4><div class="sidecard-row" style="margin-bottom:0;font-size:.84rem;line-height:1.55">${tip.html}</div></div>`;
if(STATE.achievements.size>0){ html+=`<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">${STATE.achievements.size}</span></h4>`; [...STATE.achievements.values()].slice(-4).forEach(text=>{ html+=`<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">&#10003; ${text}</div>`; }); html+='</div>'; }
box.innerHTML=html; if(window.renderMathInElement) try{renderMath(box);}catch(e){}
}
function initTheme(){ const t=localStorage.getItem('geometry8_ch2_theme')||'light'; if(t==='dark') document.documentElement.classList.add('dark'); document.getElementById('theme-lab').textContent=t==='dark'?'Светлая':'Тёмная'; document.getElementById('theme-btn').addEventListener('click',()=>{ document.documentElement.classList.toggle('dark'); const dark=document.documentElement.classList.contains('dark'); localStorage.setItem('geometry8_ch2_theme',dark?'dark':'light'); document.getElementById('theme-lab').textContent=dark?'Светлая':'Тёмная'; }); }
function renderMath(root){ if(window.renderMathInElement){ try{renderMathInElement(root,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false});}catch(e){} } }
function feedback(elm,ok,text){ elm.className='feedback '+(ok?'ok':'fail');elm.innerHTML=text||(ok?'&#10003; Верно!':'&#10007; Неверно'); }
function fmt(n){ if(!isFinite(n))return '?';if(Number.isInteger(n))return String(n);return Math.abs(n-Math.round(n))<1e-9?String(Math.round(n)):(+n.toFixed(4)).toString(); }
const ICONS={repeat:'<svg class="ic" viewBox="0 0 24 24"><polyline points="9 11 12 14 22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg>',theory:'<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>',algo:'<svg class="ic" viewBox="0 0 24 24"><polyline points="17 11 21 7 17 3"/><line x1="21" y1="7" x2="9" y2="7"/><polyline points="7 13 3 17 7 21"/><line x1="3" y1="17" x2="15" y2="17"/></svg>',rule:'<svg class="ic" viewBox="0 0 24 24"><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9"/><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0"/></svg>',example:'<svg class="ic" viewBox="0 0 24 24"><path d="M9 18h6"/><path d="M10 22h4"/><path d="M12 2a7 7 0 0 0-4 13c1 1 2 2 2 4h4c0-2 1-3 2-4a7 7 0 0 0-4-13z"/></svg>',oral:'<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',class:'<svg class="ic" viewBox="0 0 24 24"><rect x="3" y="3" width="18" height="14" rx="1"/><line x1="3" y1="21" x2="21" y2="21"/><polyline points="7 14 10 11 13 14 17 10"/></svg>',home:'<svg class="ic" viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>'};
function makeCard(kind,title,num,body){ const labels={repeat:'Повторение',theory:'Теория',algo:'Алгоритм',rule:'Правило',example:'Пример',oral:'Устно',class:'Класс',home:'Домашка'}; return `<div class="card"><div class="card-header"><div class="card-icon ${kind}">${ICONS[kind]}</div><div class="card-title">${labels[kind]||''}${title&&title!==labels[kind]?' \xb7 '+title:''}</div>${num?`<div class="card-num">${num}</div>`:''}</div><div class="card-body">${body}</div></div>`; }
function secNav(prev,next){ const NAMES={p1:'§1',p2:'§2',p3:'§3',p4:'§4',p5:'§5',p6:'§6',p7:'§7',p8:'§8',p9:'§9',p10:'§10',p11:'§11',p12:'§12',p13:'§13',p14:'§14',p15:'§15',final2:'Финал'}; let h='<div class="sec-nav">'; h+=prev?`<button class="btn" onclick="goTo('${prev}')"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> ${NAMES[prev]}</button>`:'<span></span>'; h+=next?`<button class="btn primary" onclick="goTo('${next}')">${NAMES[next]} <svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg></button>`:'<span></span>'; h+='</div>';return h; }
let _confettiCanvas=null,_confettiParticles=[],_confettiRaf=null;
function confetti(){ if(!_confettiCanvas){_confettiCanvas=document.createElement('canvas');_confettiCanvas.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:9999';document.body.appendChild(_confettiCanvas);} const c=_confettiCanvas;c.width=window.innerWidth;c.height=window.innerHeight; const ctx=c.getContext('2d'); const colors=['#059669','#10b981','#34d399','#f59e0b','#0891b2']; for(let i=0;i<80;i++){_confettiParticles.push({x:window.innerWidth/2+(Math.random()-.5)*200,y:window.innerHeight/2,vx:(Math.random()-.5)*14,vy:-10-Math.random()*10,g:.4,life:100,color:colors[i%colors.length],r:4+Math.random()*4,rot:0,vRot:(Math.random()-.5)*.3});} if(_confettiRaf)cancelAnimationFrame(_confettiRaf); function frame(){ctx.clearRect(0,0,c.width,c.height);_confettiParticles=_confettiParticles.filter(p=>{p.x+=p.vx;p.y+=p.vy;p.vy+=p.g;p.life--;p.rot+=p.vRot;ctx.save();ctx.translate(p.x,p.y);ctx.rotate(p.rot);ctx.fillStyle=p.color;ctx.fillRect(-p.r,-p.r/2,p.r*2,p.r);ctx.restore();return p.life>0&&p.y<c.height+50;});if(_confettiParticles.length>0)_confettiRaf=requestAnimationFrame(frame);else{ctx.clearRect(0,0,c.width,c.height);_confettiRaf=null;}} frame(); }
const GLOSSARY=[
{term:'многоугольник',def:'Замкнутая ломаная линия, образующая плоскую фигуру.',sec:'p1',aliases:['многоугольник','многоугольника','многоугольнике','многоугольников','многоугольники']},
{term:'площадь',def:'Числовая характеристика плоской фигуры, выражающая её размер.',sec:'p1',aliases:['площадь','площади','площадью']},
{term:'высота',def:'Перпендикуляр, опущенный из вершины на противоположную сторону (или её продолжение).',sec:'p3',aliases:['высота','высоты','высоте','высоту','высотой']},
{term:'гипотенуза',def:'Сторона прямоугольного треугольника, противоположная прямому углу.',sec:'p7',aliases:['гипотенуза','гипотенузы','гипотенузе','гипотенузу','гипотенузой']},
{term:'катет',def:'Одна из двух сторон прямоугольного треугольника, образующих прямой угол.',sec:'p7',aliases:['катет','катета','катете','катетов','катеты','катетами']},
{term:'теорема Пифагора',def:'В прямоугольном треугольнике сумма квадратов катетов равна квадрату гипотенузы: $a^2 + b^2 = c^2$.',sec:'p11',aliases:['теорема Пифагора','теореме Пифагора','теоремы Пифагора']},
{term:'пифагорова тройка',def:'Набор трёх натуральных чисел $(a, b, c)$, для которых $a^2 + b^2 = c^2$.',sec:'p15',aliases:['пифагорова тройка','пифагоровы тройки','пифагоровых троек','пифагоровой тройки']},
{term:'параллелограмм',def:'Четырёхугольник, у которого противоположные стороны попарно параллельны.',sec:'p3',aliases:['параллелограмм','параллелограмма','параллелограмме','параллелограммов']},
{term:'трапеция',def:'Четырёхугольник, у которого ровно одна пара параллельных сторон.',sec:'p5',aliases:['трапеция','трапеции','трапецию','трапеций']},
{term:'ромб',def:'Параллелограмм с равными сторонами.',sec:'p6',aliases:['ромб','ромба','ромбе','ромбов','ромбы']},
{term:'медиана',def:'Отрезок от вершины треугольника до середины противоположной стороны.',sec:'p10',aliases:['медиана','медианы','медиан','медиану']},
{term:'подобные треугольники',def:'Треугольники, у которых углы равны попарно и стороны пропорциональны.',sec:'p9',aliases:['подобные треугольники','подобных треугольников']},
{term:'касательная',def:'Прямая, имеющая одну общую точку с окружностью.',sec:'p11',aliases:['касательная','касательной','касательную']},
{term:'вписанный угол',def:'Угол с вершиной на окружности, стороны которого — хорды.',sec:'p11',aliases:['вписанный угол','вписанного угла']},
{term:'центральный угол',def:'Угол с вершиной в центре окружности.',sec:'p11',aliases:['центральный угол','центрального угла']},
{term:'коэффициент подобия',def:'Отношение соответственных сторон подобных треугольников.',sec:'p9',aliases:['коэффициент подобия','коэффициента подобия']},
{term:'биссектриса',def:'Луч, делящий угол пополам.',sec:'p9',aliases:['биссектриса','биссектрисы','биссектрису']},
{term:'хорда',def:'Отрезок, соединяющий две точки окружности.',sec:'p11',aliases:['хорда','хорды','хорде','хорд']},
];
function wrapGlossary(root){ if(!root||root.__glossDone)return; const allAliases=[];GLOSSARY.forEach((g,i)=>g.aliases.forEach(a=>allAliases.push({a,i})));allAliases.sort((x,y)=>y.a.length-x.a.length); const re=new RegExp('(?<![\\w\\u0400-\\u04ff-])('+allAliases.map(x=>x.a.replace(/[.*+?^${}()|[\]\\]/g,'\\$&')).join('|')+')(?![\\w\\u0400-\\u04ff-])','iu'); const walker=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,{acceptNode(node){const p=node.parentElement;if(!p)return NodeFilter.FILTER_REJECT;if(p.closest('.katex,.gloss-term,button,input,select,.wg-badge,.card-icon,.sec-num,.psel-num,.hdr,.ach-popup,script,style,.search-modal,.sidecard,.gloss-tip'))return NodeFilter.FILTER_REJECT;if(!re.test(node.nodeValue))return NodeFilter.FILTER_REJECT;return NodeFilter.FILTER_ACCEPT;}}); const nodes=[];let n;while((n=walker.nextNode()))nodes.push(n); nodes.forEach(node=>{const text=node.nodeValue;const out=document.createDocumentFragment();let cursor=0;const global=new RegExp(re.source,'giu');let m;while((m=global.exec(text))!==null){if(m.index>cursor)out.appendChild(document.createTextNode(text.slice(cursor,m.index)));const found=m[0].toLowerCase();const hit=allAliases.find(x=>x.a.toLowerCase()===found);const g=hit?GLOSSARY[hit.i]:null;const sp=document.createElement('span');sp.className='gloss-term';sp.dataset.gloss=g?g.term:'';sp.textContent=m[0];out.appendChild(sp);cursor=m.index+m[0].length;}if(cursor<text.length)out.appendChild(document.createTextNode(text.slice(cursor)));node.parentNode.replaceChild(out,node);}); root.__glossDone=true; }
function initGlossaryTip(){ const tip=document.getElementById('gloss-tip');if(!tip)return;let lockOpen=null; function show(elm){const g=GLOSSARY.find(x=>x.term===elm.dataset.gloss);if(!g)return;tip.innerHTML='<b>'+g.term[0].toUpperCase()+g.term.slice(1)+'</b><div style="margin-top:4px">'+g.def+'</div><div style="margin-top:6px;font-size:.72rem;color:var(--muted);text-transform:uppercase;letter-spacing:.06em">См. § '+g.sec.replace('p','')+'</div>';if(window.renderMathInElement)renderMath(tip);const r=elm.getBoundingClientRect();tip.classList.add('show');const tw=tip.offsetWidth,th=tip.offsetHeight;let left=r.left,top=r.bottom+8;if(left+tw>window.innerWidth-12)left=window.innerWidth-tw-12;if(top+th>window.innerHeight-12)top=r.top-th-8;tip.style.left=Math.max(8,left)+'px';tip.style.top=Math.max(8,top)+'px';} function hide(){tip.classList.remove('show');} document.addEventListener('mouseover',e=>{const elm=e.target.closest&&e.target.closest('.gloss-term');if(elm&&!lockOpen)show(elm);}); document.addEventListener('mouseout',e=>{const elm=e.target.closest&&e.target.closest('.gloss-term');if(elm&&!lockOpen)hide();}); document.addEventListener('click',e=>{const elm=e.target.closest&&e.target.closest('.gloss-term');if(elm){if(lockOpen===elm){lockOpen=null;hide();}else{lockOpen=elm;show(elm);}}else if(lockOpen&&!e.target.closest('.gloss-tip')){lockOpen=null;hide();}}); }
const SEARCH_INDEX=(function(){ const arr=[]; PARAS.forEach(p=>arr.push({kind:'Параграф',title:p.num+' '+p.name,desc:p.sub||'',sec:p.id})); GLOSSARY.forEach(g=>arr.push({kind:'Понятие',title:g.term,desc:g.def.replace(/\$/g,''),sec:g.sec,gloss:g.term})); [['Формула','S = a² (квадрат)','§1','p1'],['Формула','S = ab (прямоугольник)','§2','p2'],['Формула','S = bh (параллелограмм)','§3','p3'],['Формула','S = ½bh (треугольник)','§4','p4'],['Формула','a² + b² = c² (Пифагор)','§11','p11']].forEach(([k,t,d,s])=>arr.push({kind:k,title:t,desc:d,sec:s})); return arr; })();
function initSearch(){ const modal=document.getElementById('search-modal'),inp=document.getElementById('search-input'),out=document.getElementById('search-results'),btn=document.getElementById('search-btn'); if(!modal||!inp||!out)return; let cur=0,rows=[]; function score(q,it){const t=(it.title+' '+it.desc).toLowerCase();if(t.includes(q))return 100+(it.title.toLowerCase().startsWith(q)?50:0);let s=0;q.split(/\s+/).forEach(w=>{if(w&&t.includes(w))s+=10;});return s;} function rank(q){q=q.trim().toLowerCase();if(!q)return SEARCH_INDEX.slice(0,12);return SEARCH_INDEX.map(it=>({it,s:score(q,it)})).filter(x=>x.s>0).sort((a,b)=>b.s-a.s).slice(0,20).map(x=>x.it);} function render(){cur=0;if(!rows.length){out.innerHTML='<div class="search-empty">Ничего не найдено</div>';return;}out.innerHTML=rows.map((r,i)=>`<button class="search-row${i===0?' active':''}" data-i="${i}"><div class="sr-kind">${r.kind}</div><div class="sr-title">${r.title}</div>${r.desc?`<div class="sr-desc">${r.desc.length>90?r.desc.slice(0,90)+'…':r.desc}</div>`:''}</button>`).join('');out.querySelectorAll('.search-row').forEach(b=>b.addEventListener('click',()=>{cur=+b.dataset.i;pick();}));} function pick(){const r=rows[cur];if(!r)return;close();goTo(r.sec);if(r.gloss){setTimeout(()=>{const sec=document.getElementById('sec-'+r.sec);const elm=sec&&sec.querySelector('[data-gloss="'+r.gloss+'"]');if(elm){elm.scrollIntoView({behavior:'smooth',block:'center'});elm.style.transition='background .3s';elm.style.background='var(--warn,#f59e0b)';setTimeout(()=>{elm.style.background='';},1400);}},400);}} function move(d){const items=out.querySelectorAll('.search-row');if(!items.length)return;items[cur]&&items[cur].classList.remove('active');cur=(cur+d+items.length)%items.length;items[cur].classList.add('active');items[cur].scrollIntoView({block:'nearest'});} function open(){modal.classList.add('show');inp.value='';rows=rank('');render();setTimeout(()=>inp.focus(),50);} function close(){modal.classList.remove('show');} btn&&btn.addEventListener('click',open); modal.addEventListener('click',e=>{if(e.target===modal)close();}); inp.addEventListener('input',()=>{rows=rank(inp.value);render();}); inp.addEventListener('keydown',e=>{if(e.key==='ArrowDown'){e.preventDefault();move(1);}else if(e.key==='ArrowUp'){e.preventDefault();move(-1);}else if(e.key==='Enter'){e.preventDefault();pick();}else if(e.key==='Escape'){e.preventDefault();close();}}); document.addEventListener('keydown',e=>{if((e.ctrlKey||e.metaKey)&&(e.key==='k'||e.key==='K')){e.preventDefault();if(modal.classList.contains('show'))close();else open();}}); }
function initSidebarToggle(){ const side=document.getElementById('col-side'),back=document.getElementById('col-side-backdrop'),btn=document.getElementById('sidebar-btn'); if(!side||!btn)return; function open(){side.classList.add('open');back.classList.add('show');} function close(){side.classList.remove('open');back.classList.remove('show');} btn.addEventListener('click',()=>{if(side.classList.contains('open'))close();else open();}); back.addEventListener('click',close); document.addEventListener('keydown',e=>{if(e.key==='Escape')close();}); }
function init(){ loadProgress();initTheme();initSidebarToggle();initGlossaryTip();initSearch();buildParaSelector();refreshProgressUI();loadServerReadState();goTo('p1');setTimeout(()=>achievement('start','Начало главы 2!'),600); if(window.LS&&window.LS.xp){window.LS.xp.load().then(function(s){if(s&&s.xp>STATE.xp){STATE.xp=s.xp;STATE.level=calcLevel(STATE.xp);saveProgress();refreshProgressUI();if(STATE.current)buildSidebar(STATE.current);}});} }
document.addEventListener('DOMContentLoaded',init);
/* ============================================================
HELPER: setupSorter (drag-and-drop chip sorter)
============================================================ */
function setupSorter(cfg){
const placed={}; const pool=document.getElementById(cfg.poolId); const scope=document.querySelector(cfg.scopeSelector);
if(!pool||!scope) return {placed,render:()=>{},reset:()=>{}};
pool.classList.add('dnd-pool'); if(cfg.columnLayout) pool.classList.add('col');
let armed=null;
function buildChip(it,isPlaced){ const e=document.createElement('div'); e.className='dnd-chip'+(isPlaced?' placed':''); e.dataset.id=it.id; e.innerHTML='<span class="dnd-txt">'+it.html+'</span><span class="dnd-x" title="Убрать">\xd7</span>'; attach(e,it.id); return e; }
function attach(elm,itId){ let ghost=null,dragging=false,sx=0,sy=0; elm.addEventListener('pointerdown',ev=>{ if(ev.button!==undefined&&ev.button!==0) return; if(ev.target.classList&&ev.target.classList.contains('dnd-x')){ ev.stopPropagation(); if(placed[itId]){delete placed[itId];render();}else if(armed===itId){armed=null;render();} return; } sx=ev.clientX;sy=ev.clientY; const r=elm.getBoundingClientRect(); const ox=ev.clientX-r.left,oy=ev.clientY-r.top; try{elm.setPointerCapture(ev.pointerId);}catch(e){} function onMove(e){ const dx=e.clientX-sx,dy=e.clientY-sy; if(!dragging&&Math.hypot(dx,dy)>8){ dragging=true; ghost=elm.cloneNode(true); ghost.classList.remove('armed'); ghost.style.cssText='position:fixed;z-index:9999;pointer-events:none;opacity:.9;transform:rotate(-2.5deg);box-shadow:0 14px 36px rgba(0,0,0,.32);width:'+r.width+'px;left:'+(e.clientX-ox)+'px;top:'+(e.clientY-oy)+'px'; document.body.appendChild(ghost); elm.classList.add('dragging'); } if(dragging&&ghost){ ghost.style.left=(e.clientX-ox)+'px';ghost.style.top=(e.clientY-oy)+'px'; const under=document.elementsFromPoint(e.clientX,e.clientY); scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); const tgt=under.find(n=>n.classList&&(n.classList.contains('drop-box')||n.classList.contains('dnd-pool'))); if(tgt)tgt.classList.add('over'); } } function onUp(e){ elm.removeEventListener('pointermove',onMove);elm.removeEventListener('pointerup',onUp);elm.removeEventListener('pointercancel',onUp);elm.classList.remove('dragging'); if(ghost){ghost.remove();ghost=null;} scope.querySelectorAll('.drop-box.over,.dnd-pool.over').forEach(n=>n.classList.remove('over')); if(dragging){ const under=document.elementsFromPoint(e.clientX,e.clientY); const box=under.find(n=>n.classList&&n.classList.contains('drop-box')); const pl=under.find(n=>n.classList&&n.classList.contains('dnd-pool')); if(box){const di=box.querySelector('[data-cat]');if(di){placed[itId]=di.dataset.cat;armed=null;render();return;}}else if(pl){delete placed[itId];armed=null;render();return;} }else{ if(placed[itId]){delete placed[itId];armed=null;render();}else{armed=(armed===itId)?null:itId;render();} } dragging=false; } elm.addEventListener('pointermove',onMove);elm.addEventListener('pointerup',onUp);elm.addEventListener('pointercancel',onUp); }); }
function attachBoxTaps(){ scope.querySelectorAll('.drop-box').forEach(box=>{ box.addEventListener('click',ev=>{ if(!armed)return; if(ev.target.closest('.dnd-chip'))return; const di=box.querySelector('[data-cat]'); if(di){placed[armed]=di.dataset.cat;armed=null;render();} }); }); }
function render(){ pool.innerHTML=''; cfg.items.forEach(it=>{if(placed[it.id])return;const c=buildChip(it,false);if(armed===it.id)c.classList.add('armed');pool.appendChild(c);}); cfg.cats.forEach(cat=>{const box=scope.querySelector('.drop-items[data-cat="'+cat+'"]');if(!box)return;box.innerHTML='';cfg.items.forEach(it=>{if(placed[it.id]!==cat)return;box.appendChild(buildChip(it,true));});}); if(window.renderMathInElement)try{renderMath(scope);}catch(_){} }
attachBoxTaps(); render();
return {placed,render,reset(){ for(const k in placed)delete placed[k];armed=null;render(); }};
}
/* ============================================================
§1 — ПЛОЩАДЬ КВАДРАТА
============================================================ */
function buildP1(){
const box = document.getElementById('p1-body');
let html = '';
html += makeCard('theory','Понятие площади','1.1',`
<p><b>Площадь</b> — числовая характеристика плоской фигуры, выражающая её размер. Единица площади — единичный квадрат (квадрат со стороной 1).</p>
<p><b>Аксиомы площади:</b></p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.8">
<li><b>Положительность:</b> площадь любой фигуры $> 0$.</li>
<li><b>Равенство:</b> у равных (конгруэнтных) фигур площади равны.</li>
<li><b>Аддитивность:</b> площадь фигуры равна сумме площадей частей, на которые она разбита.</li>
</ul>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 140" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- 4x3 unit grid showing S=12 -->
<rect x="8" y="8" width="264" height="124" rx="6" fill="none" stroke="#e2e8f0"/>
<!-- cells -->
${(()=>{let c='';for(let r=0;r<3;r++)for(let col=0;col<4;col++){const x=16+col*58,y=16+r*32;c+=`<rect x="${x}" y="${y}" width="54" height="28" rx="3" fill="rgba(5,150,105,.14)" stroke="#059669" stroke-width="1"/><text x="${x+27}" y="${y+18}" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">1</text>`;}return c;})()}
<text x="140" y="130" text-anchor="middle" font-size="12" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S = 4·3 = 12</text>
</svg>
</div>`);
html += makeCard('rule','Площадь квадрата','1.2',`
<p>Если квадрат имеет сторону $a$, то его площадь:</p>
$$S = a^2$$
<p><b>Доказательство (идея):</b> квадрат разбивается на $a \\times a = a^2$ единичных квадратов. По аксиоме аддитивности $S = a^2$.</p>
<p style="margin-top:8px;font-size:.88rem;color:var(--muted)">Именно поэтому в математике «возведение в квадрат» называется так — это площадь квадрата.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 200 180" style="max-width:220px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Square 3x3 grid labelled with S=a² -->
${(()=>{let c='';for(let r=0;r<3;r++)for(let col=0;col<3;col++){const x=30+col*44,y=10+r*44;c+=`<rect x="${x}" y="${y}" width="40" height="40" rx="2" fill="rgba(5,150,105,.16)" stroke="#059669" stroke-width="1.2"/>`;}return c;})()}
<!-- side label bottom -->
<text x="96" y="162" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 3</text>
<!-- side label left -->
<text x="16" y="76" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,16,76)">a = 3</text>
<!-- S label center -->
<text x="96" y="80" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S=9</text>
<!-- brace bottom -->
<path d="M30,148 Q96,155 162,148" fill="none" stroke="#059669" stroke-width="1.5"/>
</svg>
</div>`);
html += makeCard('rule','Единицы измерения площади','1.3',`
<table class="tbl">
<thead><tr><th>Единица</th><th>Равна</th></tr></thead>
<tbody>
<tr><td>$1\\,\\text{км}^2$</td><td>$10^6\\,\\text{м}^2$</td></tr>
<tr><td>$1\\,\\text{м}^2$</td><td>$10^4\\,\\text{см}^2 = 10^6\\,\\text{мм}^2$</td></tr>
<tr><td>$1\\,\\text{дм}^2$</td><td>$100\\,\\text{см}^2$</td></tr>
<tr><td>$1\\,\\text{см}^2$</td><td>$100\\,\\text{мм}^2$</td></tr>
</tbody>
</table>
<p style="margin-top:8px;font-size:.88rem">При переводе из крупной единицы в мелкую — умножать, из мелкой в крупную — делить.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 110" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- units ladder: km² → m² → dm² → cm² → mm² -->
<rect x="12" y="14" width="56" height="26" rx="5" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="1.5"/>
<text x="40" y="31" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">км²</text>
<rect x="84" y="14" width="56" height="26" rx="5" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="1.5"/>
<text x="112" y="31" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">м²</text>
<rect x="156" y="14" width="56" height="26" rx="5" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="1.5"/>
<text x="184" y="31" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">дм²</text>
<rect x="224" y="14" width="52" height="26" rx="5" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="1.5"/>
<text x="250" y="31" text-anchor="middle" font-size="11" font-weight="700" fill="#047857">см²</text>
<!-- arrows down = ×100/×10000 -->
<text x="68" y="32" text-anchor="middle" font-size="9" fill="#b45309">×10⁶</text>
<line x1="68" y1="22" x2="84" y2="22" stroke="#f59e0b" stroke-width="1.5" marker-end="url(#arr1)"/>
<text x="140" y="32" text-anchor="middle" font-size="9" fill="#b45309">×100</text>
<line x1="140" y1="22" x2="156" y2="22" stroke="#f59e0b" stroke-width="1.5"/>
<text x="212" y="32" text-anchor="middle" font-size="9" fill="#b45309">×100</text>
<line x1="212" y1="22" x2="224" y2="22" stroke="#f59e0b" stroke-width="1.5"/>
<!-- legend -->
<text x="10" y="72" font-size="10" fill="#6b9e82">→ умножать (крупная → мелкая)</text>
<text x="10" y="88" font-size="10" fill="#6b9e82">← делить (мелкая → крупная)</text>
<text x="10" y="104" font-size="10" fill="#047857" font-weight="700">1 м² = 10 000 см² = 1 000 000 мм²</text>
</svg>
</div>`);
html += makeCard('example','Пример','1.4',`
<p><b>Сторона квадрата 7 см. Площадь?</b><br>$S = 7^2 = 49\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>Площадь квадрата 36 дм². Найти сторону.</b><br>$a = \\sqrt{36} = 6\\,\\text{дм}$.</p>
<p style="margin-top:8px"><b>Перевести 2,5 м² в см².</b><br>$2{,}5 \\cdot 10^4 = 25000\\,\\text{см}^2$.</p>`);
/* --- INTERACTIVE 1: SVG-квадрат с сеткой --- */
html += `<div class="wg" id="p1-grid-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Квадрат с сеткой</div></div>
<div class="wg-help">Двигай слайдер — квадрат заполняется единичными клетками. Количество клеток = $a^2$ — это и есть площадь!</div>
<div class="sliders">
<label>Сторона $a$ = <b id="p1-grid-a-val">4</b>
<input type="range" min="1" max="10" value="4" id="p1-grid-a-sl">
</label>
</div>
<div style="display:flex;gap:18px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p1-grid-svg-wrap" style="flex-shrink:0"></div>
<div id="p1-grid-info" style="padding:14px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:160px;font-size:.95rem;line-height:2"></div>
</div>
</div>`;
/* --- INTERACTIVE 2: Калькулятор площади --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор площади квадрата</div></div>
<div class="wg-help">Введи сторону — получи площадь; или введи площадь — получи сторону.</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px;flex-wrap:wrap">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">Сторона → Площадь</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<input type="number" id="p1-calc-a" class="tinp" placeholder="a" style="width:90px" min="0.001">
<button class="btn primary" id="p1-calc-go-a">= S</button>
</div>
<div id="p1-calc-out-a" style="margin-top:8px;font-size:.95rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">Площадь → Сторона</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center">
<input type="number" id="p1-calc-s" class="tinp" placeholder="S" style="width:90px" min="0.001">
<button class="btn primary" id="p1-calc-go-s">= a</button>
</div>
<div id="p1-calc-out-s" style="margin-top:8px;font-size:.95rem"></div>
</div>
</div>
</div>`;
/* --- INTERACTIVE 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">Введи число и выбери единицу — получишь перевод во все остальные единицы.</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<input type="number" id="p1-conv-val" class="tinp" style="width:120px" value="1" min="0">
<select id="p1-conv-unit" class="tinp" style="width:80px">
<option value="mm2">мм²</option>
<option value="cm2">см²</option>
<option value="dm2">дм²</option>
<option value="m2" selected>м²</option>
<option value="km2">км²</option>
</select>
<button class="btn primary" id="p1-conv-go">Перевести</button>
</div>
<div id="p1-conv-out" style="padding:12px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;display:none;line-height:2;font-size:.95rem"></div>
</div>`;
/* --- INTERACTIVE 4: Тренажёр --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §1</div></div>
<div class="wg-help">Реши задачи на площадь квадрата и конвертацию единиц. Введи ответ и нажми «Проверить».</div>
<div class="score-display"><span>Задача <b id="p1-tr-i">1</b> / 5</span><span>Очки: <b id="p1-tr-score">0</b></span></div>
<div id="p1-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p1-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p1-tr-go">Проверить</button>
<button class="btn" id="p1-tr-start">Начать</button>
</div>
<div class="feedback" id="p1-tr-fb" style="display:none"></div>
</div>`;
/* --- INTERACTIVE 5: Босс §1 --- */
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))">БОСС §1</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">Реши все 4 задачи — каждая верная даёт +5 XP.</div>
<div id="p1-boss-tasks"></div>
</div>`;
html += `<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p1-read-btn" onclick="addXp(10,'p1-read');bumpProgress('p1',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>
Я прочитал §1 (+10 XP)
</button>
</div>`;
html += secNav(null,'p2');
box.innerHTML = html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: SVG-сетка == */
(function(){
const sl=document.getElementById('p1-grid-a-sl');
const valEl=document.getElementById('p1-grid-a-val');
const wrap=document.getElementById('p1-grid-svg-wrap');
const info=document.getElementById('p1-grid-info');
function draw(){
const a=+sl.value;
valEl.textContent=a;
const cell=34, pad=14;
const W=a*cell+pad*2, H=a*cell+pad*2;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:'+Math.min(W,300)+'px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
// fill cells
for(let r=0;r<a;r++) for(let c=0;c<a;c++){
const x=pad+c*cell, y=pad+r*cell;
s+='<rect x="'+x+'" y="'+y+'" width="'+(cell-1)+'" height="'+(cell-1)+'" rx="3" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="1"/>';
}
// side label bottom
const midX=pad+a*cell/2, botY=pad+a*cell+11;
s+='<text x="'+midX+'" y="'+botY+'" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a='+a+'</text>';
// side label left
const midY=pad+a*cell/2;
s+='<text x="8" y="'+midY+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,'+midY+')">a='+a+'</text>';
s+='</svg>';
wrap.innerHTML=s;
info.innerHTML='<div><b>a</b> = '+a+'</div><div><b>a²</b> = '+a+'² = '+(a*a)+'</div><div style="color:var(--sec-acc-d,var(--pri2));font-size:1.05rem;font-weight:800">S = '+(a*a)+' кл.</div>';
}
sl.addEventListener('input',draw);
draw();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p1-calc-go-a').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p1-calc-a').value);
const out=document.getElementById('p1-calc-out-a');
if(!isFinite(a)||a<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительное число.</span>';return;}
const S=a*a;
out.innerHTML='$S = '+a+'^2 = '+fmt(S)+'$';
renderMath(out); addXp(1,'p1-calc');
});
document.getElementById('p1-calc-go-s').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p1-calc-s').value);
const out=document.getElementById('p1-calc-out-s');
if(!isFinite(S)||S<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительное число.</span>';return;}
const a=Math.sqrt(S);
out.innerHTML='$a = \\sqrt{'+fmt(S)+'} = '+fmt(a)+'$';
renderMath(out); addXp(1,'p1-calc-inv');
});
document.getElementById('p1-calc-a').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p1-calc-go-a').click();});
document.getElementById('p1-calc-s').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p1-calc-go-s').click();});
})();
/* == INIT: Конвертер == */
(function(){
const factors={mm2:1,cm2:100,dm2:1e4,m2:1e6,km2:1e12};
const labels={mm2:'мм²',cm2:'см²',dm2:'дм²',m2:'м²',km2:'км²'};
document.getElementById('p1-conv-go').addEventListener('click',()=>{
const v=parseFloat(document.getElementById('p1-conv-val').value);
const unit=document.getElementById('p1-conv-unit').value;
const out=document.getElementById('p1-conv-out');
if(!isFinite(v)||v<0){out.style.display='none';return;}
const inMm2=v*factors[unit];
let rows='';
for(const [u,f] of Object.entries(factors)){
const res=inMm2/f;
rows+='<div><b>'+labels[u]+':</b> '+fmt(res)+(u===unit?' <span style="color:var(--sec-acc-d,var(--pri2));font-weight:800">(исходное)</span>':'')+'</div>';
}
out.innerHTML=rows; out.style.display='block'; addXp(2,'p1-conv');
});
document.getElementById('p1-conv-val').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p1-conv-go').click();});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 120 100" style="display:block;max-width:130px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="20" y="10" width="80" height="80" rx="3" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><text x="60" y="56" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">S = ?</text><text x="60" y="96" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 9 см</text><text x="8" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,50)">a = 9</text></svg>Сторона квадрата <b>9 см</b>. Найди площадь (в см²).', ans:81, hint:'S = 9² = 81 см².'},
{q:'<svg viewBox="0 0 120 100" style="display:block;max-width:130px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="20" y="10" width="80" height="80" rx="3" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><text x="60" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">S = 64 м²</text><text x="60" y="96" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = ?</text></svg>Площадь квадрата <b>64 м²</b>. Найди сторону (в м).', ans:8, hint:'a = √64 = 8 м.'},
{q:'Переведи <b>3 м²</b> в см². Ответ в см².', ans:30000, hint:'1 м² = 10 000 см², 3·10 000 = 30 000 см².'},
{q:'<svg viewBox="0 0 120 100" style="display:block;max-width:130px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="15" y="10" width="90" height="80" rx="3" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><text x="60" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">S = ?</text><text x="60" y="96" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 12 дм</text></svg>Сторона квадрата <b>12 дм</b>. Найди площадь в дм².', ans:144, hint:'S = 12² = 144 дм².'},
{q:'Площадь квадрата <b>225 мм²</b>. Найди сторону в мм.', ans:15, hint:'a = √225 = 15 мм.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p1-tr-i').textContent=idx+1;
document.getElementById('p1-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p1-tr-ans').value='';
document.getElementById('p1-tr-fb').style.display='none';
}
document.getElementById('p1-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p1-tr-score').textContent=0;show();});
document.getElementById('p1-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p1-tr-ans').value;
const fb=document.getElementById('p1-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.01){
score++;document.getElementById('p1-tr-score').textContent=score;
addXp(3,'p1-tr-'+idx);bumpProgress('p1',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p1-tr-all');bumpProgress('p1',10);}
} else {
feedback(fb,false,'Неверно. '+tasks[idx].hint);
}
});
document.getElementById('p1-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p1-tr-go').click();});
show();
})();
/* == INIT: Босс §1 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 120 100" style="display:block;max-width:130px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="15" y="10" width="90" height="80" rx="3" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><text x="60" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">S = ?</text><text x="60" y="96" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 13 см</text></svg>Сторона квадрата <b>13 см</b>. Площадь (в см²)?', ans:169, hint:'13² = 169.'},
{q:'<svg viewBox="0 0 120 100" style="display:block;max-width:130px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="15" y="10" width="90" height="80" rx="3" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><text x="60" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">S = 196 м²</text><text x="60" y="96" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = ?</text></svg>Площадь квадрата <b>196 м²</b>. Сторона (в м)?', ans:14, hint:'√196 = 14.'},
{q:'Переведи <b>50 000 см²</b> в м². Ответ в м².', ans:5, hint:'50 000 / 10 000 = 5 м².'},
{q:'<svg viewBox="0 0 140 100" style="display:block;max-width:150px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="20" y="10" width="100" height="80" rx="3" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><text x="70" y="45" text-anchor="middle" dominant-baseline="middle" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">P = 28 дм</text><text x="70" y="62" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857">S = ?</text><text x="70" y="96" text-anchor="middle" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">a = P/4 = 7</text></svg>Периметр квадрата <b>28 дм</b>. Площадь в дм²?', ans:49, hint:'a = 28/4 = 7; S = 7² = 49.'},
];
const bossBox=document.getElementById('p1-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="p1b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p1b-a${i}').value;
const fb=document.getElementById('p1b-fb${i}');
if(Math.abs(v-${t.ans})<0.01){
feedback(fb,true,'Верно! +5 XP');
if(!p1BossSolved.has(${i})){ p1BossSolved.add(${i}); addXp(5,'p1-boss${i}'); bumpProgress('p1',10); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p1b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p1BossSolved=new Set();
})();
}
/* ============================================================
§2 — ПЛОЩАДЬ ПРЯМОУГОЛЬНИКА
============================================================ */
function buildP2(){
const box = document.getElementById('p2-body');
let html = '';
html += makeCard('theory','Площадь прямоугольника','2.1',`
<p><b>Теорема.</b> Площадь прямоугольника со сторонами $a$ и $b$:</p>
$$S = a \\cdot b$$
<p><b>Доказательство:</b> прямоугольник $a \\times b$ разбивается на $a \\cdot b$ единичных квадратов. По аксиоме аддитивности $S = a \\cdot b$.</p>
<p style="margin-top:8px">Квадрат — частный случай прямоугольника при $a = b$: $S = a \\cdot a = a^2$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 160" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- 5x3 grid rectangle with cell labels -->
${(()=>{let c='';for(let r=0;r<3;r++)for(let col=0;col<5;col++){const x=10+col*50,y=12+r*40;c+=`<rect x="${x}" y="${y}" width="46" height="36" rx="2" fill="rgba(16,185,129,.14)" stroke="#10b981" stroke-width="1"/>`;}return c;})()}
<!-- side labels -->
<text x="135" y="154" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 5</text>
<text x="8" y="72" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,72)">b = 3</text>
<!-- formula -->
<text x="135" y="82" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#059669" font-family="Unbounded,sans-serif">S = 15</text>
</svg>
</div>`);
html += makeCard('rule','Периметр и площадь','2.2',`
<p>Прямоугольник со сторонами $a$ и $b$:</p>
$$S = a \\cdot b, \\quad P = 2(a + b)$$
<p>Связь: зная $P$ и одну сторону, можно найти вторую: $b = \\dfrac{P}{2} - a$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 140" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- labeled rectangle with dimensions a, b, P and S -->
<rect x="30" y="20" width="180" height="90" rx="4" fill="rgba(16,185,129,.13)" stroke="#10b981" stroke-width="2.5"/>
<!-- label a (bottom) -->
<text x="120" y="130" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 6</text>
<!-- label b (left) -->
<text x="14" y="65" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,14,65)">b = 4</text>
<!-- S in center -->
<text x="120" y="58" text-anchor="middle" dominant-baseline="middle" font-size="11" fill="#059669" font-family="JetBrains Mono,monospace">S = 6·4 = 24</text>
<!-- P label -->
<text x="120" y="76" text-anchor="middle" dominant-baseline="middle" font-size="11" fill="#0891b2" font-family="JetBrains Mono,monospace">P = 2(6+4) = 20</text>
<!-- perimeter arrows -->
<path d="M30,15 L210,15" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="5 3" fill="none"/>
<path d="M215,20 L215,110" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="5 3" fill="none"/>
<path d="M210,115 L30,115" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="5 3" fill="none"/>
<path d="M25,110 L25,20" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="5 3" fill="none"/>
</svg>
</div>`);
html += makeCard('example','Примеры','2.3',`
<p><b>Прямоугольник 6 × 4. Площадь?</b><br>$S = 6 \\cdot 4 = 24\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>Площадь прямоугольника 36 м², одна сторона 9 м. Найти вторую.</b><br>$b = 36 / 9 = 4\\,\\text{м}$.</p>
<p style="margin-top:8px"><b>Периметр 26 см, одна сторона 3 см. Площадь?</b><br>$b = 26/2 - 3 = 10\\,\\text{см}$. $S = 3 \\cdot 10 = 30\\,\\text{см}^2$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 110" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Rectangle 6×4 labeled example -->
<rect x="30" y="12" width="180" height="72" rx="4" fill="rgba(16,185,129,.16)" stroke="#059669" stroke-width="2"/>
<text x="120" y="52" text-anchor="middle" dominant-baseline="middle" font-size="15" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S = 24</text>
<text x="120" y="96" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 6 см</text>
<text x="14" y="48" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,14,48)">b = 4</text>
</svg>
</div>`);
/* --- INTERACTIVE 1: Draggable прямоугольник --- */
html += `<div class="wg" id="p2-rect-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Прямоугольник: тяни угол</div></div>
<div class="wg-help">Тащи правый нижний угол мышью или пальцем — меняются стороны и площадь. Сетка показывает разбиение на единичные клетки.</div>
<div id="p2-rect-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p2-rect-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* --- INTERACTIVE 2: Калькулятор --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор прямоугольника</div></div>
<div class="wg-help">Введи известные величины и нажми кнопку для нахождения неизвестной.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, b → S и P</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p2-calc-a" class="tinp" placeholder="a" style="width:75px">
<input type="number" id="p2-calc-b" class="tinp" placeholder="b" style="width:75px">
<button class="btn primary" id="p2-calc-go">Найти</button>
</div>
<div id="p2-calc-out" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, a → b</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p2-calc-s" class="tinp" placeholder="S" style="width:75px">
<input type="number" id="p2-calc-a2" class="tinp" placeholder="a" style="width:75px">
<button class="btn primary" id="p2-calc-go2">Найти b</button>
</div>
<div id="p2-calc-out2" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* --- INTERACTIVE 3: DnD — разложить пары (a,b) для S=24 --- */
html += `<div class="wg" id="p2-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Какие пары дают площадь 24?</div></div>
<div class="wg-help">Разложи пары $(a, b)$ на «Площадь = 24» и «Площадь ≠ 24». Нажми карточку, затем нужный ящик.</div>
<div id="p2-dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:8px">
<div class="drop-box"><h5>S = 24</h5><div class="drop-items" data-cat="yes"></div></div>
<div class="drop-box"><h5>S ≠ 24</h5><div class="drop-items" data-cat="no"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p2-dnd-check">Проверить</button><button class="btn" id="p2-dnd-reset">Сначала</button></div>
<div class="feedback" id="p2-dnd-fb" style="display:none"></div>
</div>`;
/* --- MINI-SLIDER: Прямоугольник S = a·b --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Прямоугольник — меняй стороны</div></div>
<div class="wg-help">Двигай слайдеры a и b — площадь $S = a \\cdot b$ пересчитывается мгновенно.</div>
<div class="sliders">
<label>Сторона a = <b id="p2-sl-a-val">8</b>
<input type="range" min="1" max="16" value="8" id="p2-sl-a">
</label>
<label>Сторона b = <b id="p2-sl-b-val">5</b>
<input type="range" min="1" max="16" value="5" id="p2-sl-b">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p2-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p2-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* --- INTERACTIVE 4: Тренажёр --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §2</div></div>
<div class="wg-help">5 задач на площадь и периметр прямоугольника.</div>
<div class="score-display"><span>Задача <b id="p2-tr-i">1</b> / 5</span><span>Очки: <b id="p2-tr-score">0</b></span></div>
<div id="p2-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p2-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p2-tr-go">Проверить</button>
<button class="btn" id="p2-tr-start">Начать</button>
</div>
<div class="feedback" id="p2-tr-fb" style="display:none"></div>
</div>`;
/* --- INTERACTIVE 5: Босс §2 --- */
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))">БОСС §2</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p2-boss-tasks"></div>
</div>`;
html += `<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p2-read-btn" onclick="addXp(10,'p2-read');bumpProgress('p2',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>
Я прочитал §2 (+10 XP)
</button>
</div>`;
html += secNav('p1','p3');
box.innerHTML = html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable прямоугольник == */
(function(){
const W=340, H=300;
const MIN_CELLS=1, MAX_CELLS=9;
const PAD=30, CELL=24;
let cols=6, rows=4;
function draw(){
const rw=cols*CELL, rh=rows*CELL;
const x0=PAD, y0=PAD;
let s='<svg id="p2-rect-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:340px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// grid cells
for(let r=0;r<rows;r++) for(let c=0;c<cols;c++){
s+='<rect x="'+(x0+c*CELL)+'" y="'+(y0+r*CELL)+'" width="'+(CELL-1)+'" height="'+(CELL-1)+'" rx="2" fill="rgba(16,185,129,.15)" stroke="#10b981" stroke-width=".8"/>';
}
// border
s+='<rect x="'+x0+'" y="'+y0+'" width="'+rw+'" height="'+rh+'" fill="none" stroke="#059669" stroke-width="2.5" rx="3"/>';
// labels
const midX=x0+rw/2, midY=y0+rh/2;
s+='<text x="'+midX+'" y="'+(y0+rh+18)+'" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = '+cols+'</text>';
s+='<text x="'+(x0-14)+'" y="'+midY+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,'+(x0-14)+','+midY+')">b = '+rows+'</text>';
// drag handle (bottom-right corner)
const hx=x0+rw, hy=y0+rh;
s+='<circle cx="'+hx+'" cy="'+hy+'" r="11" fill="rgba(5,150,105,.25)" id="p2-drag-bg"/>';
s+='<circle cx="'+hx+'" cy="'+hy+'" r="7" fill="#059669" stroke="#fff" stroke-width="2" id="p2-drag-handle" style="cursor:nwse-resize"/>';
s+='</svg>';
const svg=document.getElementById('p2-rect-svg');
const wrap=document.getElementById('p2-rect-svg-wrap');
wrap.innerHTML=s;
updateInfo();
const handle=wrap.querySelector('#p2-drag-handle');
if(handle){
handle.addEventListener('pointerdown',ev=>{
function onMove(e){
const svgEl=wrap.querySelector('#p2-rect-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const sx=W/rect.width, sy=H/rect.height;
const nx=Math.round(Math.max(MIN_CELLS,Math.min(MAX_CELLS,((e.clientX-rect.left)*sx-PAD)/CELL)));
const ny=Math.round(Math.max(MIN_CELLS,Math.min(MAX_CELLS,((e.clientY-rect.top)*sy-PAD)/CELL)));
if(nx!==cols||ny!==rows){cols=nx;rows=ny;draw();}
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
function updateInfo(){
const S=cols*rows, P=2*(cols+rows);
document.getElementById('p2-rect-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">a</div><b>${cols}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">b</div><b>${rows}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S = a·b</div><b style="color:var(--sec-acc-d,var(--pri2))">${S}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">P = 2(a+b)</div><b>${P}</b></div>`;
}
draw();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p2-calc-go').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p2-calc-a').value);
const b=parseFloat(document.getElementById('p2-calc-b').value);
const out=document.getElementById('p2-calc-out');
if(!isFinite(a)||!isFinite(b)||a<=0||b<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S = '+fmt(a)+'\\cdot'+fmt(b)+' = '+fmt(a*b)+'$<br>$P = 2('+fmt(a)+'+'+fmt(b)+') = '+fmt(2*(a+b))+'$';
renderMath(out); addXp(1,'p2-calc');
});
document.getElementById('p2-calc-go2').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p2-calc-s').value);
const a=parseFloat(document.getElementById('p2-calc-a2').value);
const out=document.getElementById('p2-calc-out2');
if(!isFinite(S)||!isFinite(a)||S<=0||a<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const b=S/a;
out.innerHTML='$b = S/a = '+fmt(S)+'/'+fmt(a)+' = '+fmt(b)+'$';
renderMath(out); addXp(1,'p2-calc-inv');
});
})();
/* == INIT: DnD == */
(function(){
const items=[
{id:'p1x24',html:'1 × 24',ans:'yes'},{id:'p2x12',html:'2 × 12',ans:'yes'},
{id:'p3x8', html:'3 × 8', ans:'yes'},{id:'p4x6', html:'4 × 6', ans:'yes'},
{id:'p5x5', html:'5 × 5', ans:'no'},{id:'p3x9', html:'3 × 9', ans:'no'},
{id:'p6x5', html:'6 × 5', ans:'no'},
];
const sorter2=setupSorter({poolId:'p2-dnd-pool',scopeSelector:'#p2-dnd-wg',items,cats:['yes','no']});
document.getElementById('p2-dnd-reset').addEventListener('click',()=>{sorter2.reset();document.getElementById('p2-dnd-fb').style.display='none';});
document.getElementById('p2-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach(it=>{if(sorter2.placed[it.id]===it.ans)ok++;});
const fb=document.getElementById('p2-dnd-fb');
if(ok===items.length){feedback(fb,true,'Все верно! +5 XP');addXp(5,'p2-dnd');bumpProgress('p2',15);}
else feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Перемножь числа и проверь: = 24?');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 160 80" style="display:block;max-width:170px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="14" y="10" width="130" height="50" rx="3" fill="rgba(16,185,129,.16)" stroke="#10b981" stroke-width="2"/><text x="79" y="39" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857">S = ?</text><text x="79" y="72" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 7</text><text x="6" y="35" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,6,35)">b=5</text></svg>Прямоугольник <b>7 × 5</b>. Площадь?', ans:35, hint:'S = 7·5 = 35.'},
{q:'<svg viewBox="0 0 160 80" style="display:block;max-width:170px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="14" y="10" width="130" height="50" rx="3" fill="rgba(16,185,129,.16)" stroke="#10b981" stroke-width="2"/><text x="79" y="33" text-anchor="middle" dominant-baseline="middle" font-size="10" fill="#047857">S = 48 м²</text><text x="79" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857">a=6, b=?</text><text x="79" y="72" text-anchor="middle" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">b = S/a = ?</text></svg>Площадь прямоугольника <b>48 м²</b>, одна сторона <b>6 м</b>. Вторая сторона?', ans:8, hint:'b = 48/6 = 8.'},
{q:'Периметр прямоугольника <b>24 см</b>, одна сторона <b>4 см</b>. Площадь?', ans:32, hint:'b = 24/2 - 4 = 8; S = 4·8 = 32.'},
{q:'<svg viewBox="0 0 160 60" style="display:block;max-width:170px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="6" y="8" width="148" height="34" rx="3" fill="rgba(16,185,129,.16)" stroke="#10b981" stroke-width="2"/><text x="80" y="29" text-anchor="middle" dominant-baseline="middle" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">P = ?</text><text x="80" y="52" text-anchor="middle" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">a=11, b=3</text></svg>Прямоугольник <b>11 × 3</b>. Периметр?', ans:28, hint:'P = 2(11+3) = 28.'},
{q:'Площадь комнаты <b>5 × 4 м</b>. Количество плиток <b>50 × 50 см</b>?', ans:80, hint:'S = 20 м² = 200 000 см². Плитка: 50×50=2500 см². 200 000/2500 = 80.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p2-tr-i').textContent=idx+1;
document.getElementById('p2-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p2-tr-ans').value='';
document.getElementById('p2-tr-fb').style.display='none';
}
document.getElementById('p2-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p2-tr-score').textContent=0;show();});
document.getElementById('p2-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p2-tr-ans').value;
const fb=document.getElementById('p2-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p2-tr-score').textContent=score;
addXp(3,'p2-tr-'+idx);bumpProgress('p2',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p2-tr-all');bumpProgress('p2',10);}
} else {
feedback(fb,false,'Неверно. '+tasks[idx].hint);
}
});
document.getElementById('p2-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p2-tr-go').click();});
show();
})();
/* == INIT: Босс §2 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 160 80" style="display:block;max-width:170px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="6" y="10" width="148" height="46" rx="3" fill="rgba(16,185,129,.16)" stroke="#10b981" stroke-width="2"/><text x="80" y="37" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857">S = ?</text><text x="80" y="72" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=13, b=8</text></svg>Прямоугольник <b>13 × 8</b>. Площадь?', ans:104, hint:'13·8 = 104.'},
{q:'<svg viewBox="0 0 160 80" style="display:block;max-width:170px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #a7f3d0;border-radius:8px"><rect x="6" y="10" width="148" height="46" rx="3" fill="rgba(16,185,129,.16)" stroke="#10b981" stroke-width="2"/><text x="80" y="33" text-anchor="middle" dominant-baseline="middle" font-size="10" fill="#047857">S = 360 м²</text><text x="80" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857">b=15, a=?</text><text x="80" y="72" text-anchor="middle" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">a = S/b = ?</text></svg>Площадь участка <b>360 м²</b>, ширина <b>15 м</b>. Длина?', ans:24, hint:'360/15 = 24.'},
{q:'Периметр прямоугольника <b>34 дм</b>, одна сторона <b>9 дм</b>. Площадь?', ans:72, hint:'b = 34/2 - 9 = 8; S = 9·8 = 72.'},
{q:'Квадрат и прямоугольник <b>9 × 4</b> имеют равные площади. Сторона квадрата?', ans:6, hint:'S = 36, a = √36 = 6.'},
];
const bossBox=document.getElementById('p2-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="p2b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p2b-a${i}').value;
const fb=document.getElementById('p2b-fb${i}');
if(Math.abs(v-${t.ans})<0.5){
feedback(fb,true,'Верно! +5 XP');
if(!p2BossSolved.has(${i})){ p2BossSolved.add(${i}); addXp(5,'p2-boss${i}'); bumpProgress('p2',10); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p2b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p2BossSolved=new Set();
})();
/* == MINI-SLIDER: Прямоугольник == */
(function(){
const W=260, H=180;
function draw(){
const a=+document.getElementById('p2-sl-a').value;
const b=+document.getElementById('p2-sl-b').value;
document.getElementById('p2-sl-a-val').textContent=a;
document.getElementById('p2-sl-b-val').textContent=b;
const scX=Math.min(220/a,14), scY=Math.min(140/b,14);
const sc=Math.min(scX,scY);
const rw=Math.round(a*sc), rh=Math.round(b*sc);
const ox=Math.round((W-rw)/2), oy=Math.round((H-rh)/2);
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
s+='<rect x="'+ox+'" y="'+oy+'" width="'+rw+'" height="'+rh+'" rx="4" fill="rgba(5,150,105,.22)" stroke="#059669" stroke-width="2.5"/>';
s+='<text x="'+(ox+rw/2)+'" y="'+(oy+rh/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="16" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S='+(a*b)+'</text>';
s+='<text x="'+(ox+rw/2)+'" y="'+(oy+rh+14)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(ox-14)+'" y="'+(oy+rh/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,'+(ox-14)+','+(oy+rh/2)+')">b='+b+'</text>';
s+='</svg>';
document.getElementById('p2-sl-svg-wrap').innerHTML=s;
document.getElementById('p2-sl-info').innerHTML='<div><b>a</b> = '+a+'</div><div><b>b</b> = '+b+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>S = a·b = '+(a*b)+'</b></div><div style="color:var(--muted);font-size:.8rem">P = 2(a+b) = '+2*(a+b)+'</div>';
}
document.getElementById('p2-sl-a').addEventListener('input',draw);
document.getElementById('p2-sl-b').addEventListener('input',draw);
draw();
})();
}
/* ============================================================
§3 — ПЛОЩАДЬ ПАРАЛЛЕЛОГРАММА
============================================================ */
function buildP3(){
const box = document.getElementById('p3-body');
let html = '';
html += makeCard('theory','Площадь параллелограмма','3.1',`
<p><b>Высота параллелограмма</b> — перпендикуляр, опущенный из любой точки одной стороны на другую (параллельную) сторону.</p>
<p><b>Теорема.</b> Площадь параллелограмма равна произведению основания на высоту:</p>
$$S = a \\cdot h$$
<p>где $a$ — основание (любая сторона), $h$ — высота, опущенная на это основание.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 140" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- parallelogram with base a, height h drawn -->
<polygon points="50,115 210,115 250,35 90,35" fill="rgba(13,148,136,.14)" stroke="#0d9488" stroke-width="2.5" stroke-linejoin="round"/>
<!-- height line -->
<line x1="90" y1="35" x2="90" y2="115" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<!-- right angle mark -->
<polyline points="98,115 98,107 90,107" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<!-- h label -->
<text x="76" y="78" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>
<!-- a label -->
<text x="130" y="132" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>
<!-- S label center -->
<text x="160" y="78" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#0f766e" font-family="Unbounded,sans-serif">S = a·h</text>
</svg>
</div>`);
html += makeCard('rule','Доказательство через прямоугольник','3.2',`
<p><b>Идея:</b> от параллелограмма отрезаем боковой прямоугольный треугольник и переносим его на другой конец — получается прямоугольник с теми же основанием $a$ и высотой $h$.</p>
<p>По аксиоме аддитивности площади параллелограмм и прямоугольник равновелики:</p>
$$S_{\\text{пар}} = S_{\\text{прямоуг}} = a \\cdot h$$
<p style="margin-top:8px;font-size:.88rem;color:var(--muted)">Ключевое следствие: два параллелограмма с одним основанием и одинаковой высотой имеют <b>равные площади</b>, даже если выглядят по-разному!</p>
<div style="display:flex;justify-content:center;gap:14px;flex-wrap:wrap;margin-top:14px">
<svg viewBox="0 0 200 120" style="max-width:210px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- two parallelograms with same base/height side by side -->
<polygon points="20,95 130,95 155,35 45,35" fill="rgba(13,148,136,.17)" stroke="#0d9488" stroke-width="2"/>
<polygon points="155,95 180,95 200,35 175,35" fill="rgba(13,148,136,.17)" stroke="#0d9488" stroke-width="2" opacity="0.5" stroke-dasharray="6 3"/>
<line x1="45" y1="35" x2="45" y2="95" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/>
<text x="30" y="62" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>
<text x="75" y="112" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">S = a·h</text>
<text x="100" y="25" text-anchor="middle" font-size="9" fill="#0f766e">одинаковые площади!</text>
</svg>
</div>`);
html += makeCard('example','Примеры','3.3',`
<p><b>Параллелограмм, основание 8 см, высота 5 см. Площадь?</b><br>$S = 8 \\cdot 5 = 40\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>Площадь 60 м², основание 12 м. Высота?</b><br>$h = 60 / 12 = 5\\,\\text{м}$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 130" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- parallelogram a=8, h=5 example -->
<polygon points="40,105 200,105 230,35 70,35" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2.5"/>
<line x1="70" y1="35" x2="70" y2="105" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="78,105 78,97 70,97" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<text x="56" y="72" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=5</text>
<text x="120" y="122" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 8 см</text>
<text x="148" y="72" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#0f766e" font-family="Unbounded,sans-serif">S=40</text>
</svg>
</div>`);
/* --- INTERACTIVE 1: Draggable параллелограмм (сдвигаем верх) --- */
html += `<div class="wg" id="p3-pgram-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Равноплощадные параллелограммы</div></div>
<div class="wg-help">Тащи верхнее основание влево–вправо. Основание $a$ и высота $h$ не меняются — площадь $S = a \\cdot h$ постоянна!</div>
<div id="p3-pgram-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p3-pgram-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* --- INTERACTIVE 2: Анимация доказательства --- */
html += `<div class="wg" id="p3-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство: разрезаем и переставляем</div></div>
<div class="wg-help">Нажимай «Далее» чтобы пройти шаги доказательства формулы $S = a \\cdot h$.</div>
<div id="p3-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p3-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p3-proof-next">Далее</button>
<button class="btn" id="p3-proof-reset">Сначала</button>
</div>
</div>`;
/* --- INTERACTIVE 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">Задай два из трёх параметров — найди третий.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, h → S</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p3-calc-a" class="tinp" placeholder="a" style="width:75px">
<input type="number" id="p3-calc-h" class="tinp" placeholder="h" style="width:75px">
<button class="btn primary" id="p3-calc-go1">= S</button>
</div>
<div id="p3-calc-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, h → a</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p3-calc-s" class="tinp" placeholder="S" style="width:75px">
<input type="number" id="p3-calc-h2" class="tinp" placeholder="h" style="width:75px">
<button class="btn primary" id="p3-calc-go2">= a</button>
</div>
<div id="p3-calc-out2" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* --- MINI-SLIDER: Параллелограмм S = a·h --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Параллелограмм — меняй основание и высоту</div></div>
<div class="wg-help">$S = a \\cdot h$ — площадь зависит от основания и высоты, а не от угла наклона!</div>
<div class="sliders">
<label>Основание a = <b id="p3-sl-a-val">10</b>
<input type="range" min="2" max="20" value="10" id="p3-sl-a">
</label>
<label>Высота h = <b id="p3-sl-h-val">6</b>
<input type="range" min="1" max="16" value="6" id="p3-sl-h">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p3-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p3-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* --- INTERACTIVE 4: Тренажёр --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §3</div></div>
<div class="wg-help">5 задач на площадь параллелограмма.</div>
<div class="score-display"><span>Задача <b id="p3-tr-i">1</b> / 5</span><span>Очки: <b id="p3-tr-score">0</b></span></div>
<div id="p3-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p3-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p3-tr-go">Проверить</button>
<button class="btn" id="p3-tr-start">Начать</button>
</div>
<div class="feedback" id="p3-tr-fb" style="display:none"></div>
</div>`;
/* --- INTERACTIVE 5: Босс §3 --- */
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))">БОСС §3</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p3-boss-tasks"></div>
</div>`;
html += `<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p3-read-btn" onclick="addXp(10,'p3-read');bumpProgress('p3',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>
Я прочитал §3 (+10 XP)
</button>
</div>`;
html += secNav('p2','p4');
box.innerHTML = html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable параллелограмм == */
(function(){
const W=380, H=240;
const BASE_X=50, BASE_Y=190, BASE_W=200, HEIGHT_PX=100;
let shiftX=40;
function draw(){
const bx=BASE_X, by=BASE_Y, bw=BASE_W, h=HEIGHT_PX;
const x1=bx, x2=bx+bw, x3=bx+bw+shiftX, x4=bx+shiftX;
const y1=by, y2=by, y3=by-h, y4=by-h;
const cx=(x1+x2+x3+x4)/4, cy=(y1+y2+y3+y4)/4;
let s='<svg id="p3-pgram-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:400px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// height line
const hBaseX=x4+(x1-x4)*0;
s+='<line x1="'+x4+'" y1="'+y4+'" x2="'+x4+'" y2="'+y1+'" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5 3"/>';
s+='<text x="'+(x4-16)+'" y="'+((y4+y1)/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>';
// right angle mark
s+='<polyline points="'+(x4+8)+','+(y1)+' '+(x4+8)+','+(y1-8)+' '+x4+','+(y1-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.5"/>';
// polygon
s+='<polygon points="'+x1+','+y1+' '+x2+','+y2+' '+x3+','+y3+' '+x4+','+y4+'" fill="rgba(13,148,136,.15)" stroke="#0d9488" stroke-width="2.5" stroke-linejoin="round"/>';
// base label
s+='<text x="'+((x1+x2)/2)+'" y="'+(y1+18)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>';
// S label
s+='<text x="'+cx+'" y="'+cy+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#0f766e" font-family="Unbounded,sans-serif">S=a·h</text>';
// drag handle (upper base midpoint)
const hmx=(x4+x3)/2, hmy=(y4+y3)/2;
s+='<circle cx="'+hmx+'" cy="'+hmy+'" r="12" fill="rgba(13,148,136,.2)" id="p3-pgram-bg"/>';
s+='<circle cx="'+hmx+'" cy="'+hmy+'" r="7" fill="#0d9488" stroke="#fff" stroke-width="2" id="p3-drag-upper" style="cursor:ew-resize"/>';
s+='</svg>';
document.getElementById('p3-pgram-svg-wrap').innerHTML=s;
document.getElementById('p3-pgram-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Основание a</div><b>${BASE_W} px</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Высота h</div><b>${HEIGHT_PX} px</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Сдвиг</div><b>${shiftX}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S = a·h</div><b style="color:var(--sec-acc-d,var(--pri2))">${BASE_W*HEIGHT_PX}</b></div>`;
const handle=document.getElementById('p3-drag-upper');
if(handle){
handle.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startShift=shiftX;
function onMove(e){
const svgEl=document.getElementById('p3-pgram-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
const delta=Math.round((e.clientX-startX)*scale);
shiftX=Math.max(-80,Math.min(180,startShift+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Анимация доказательства == */
(function(){
let step=0;
const W=360, H=200;
const bx=40, by=160, bw=200, H2=100, sh=60;
const steps=[
{
desc:'Исходный параллелограмм ABCD. Основание AB = a, высота h — перпендикуляр от D к AB.',
draw(){
const x1=bx,x2=bx+bw,x3=bx+bw+sh,x4=bx+sh;
const y1=by,y2=by,y3=by-H2,y4=by-H2;
return '<polygon points="'+[x1,y1,x2,y2,x3,y3,x4,y4].join(' ')+'" fill="rgba(13,148,136,.15)" stroke="#0d9488" stroke-width="2.2"/>'
+'<line x1="'+x4+'" y1="'+y4+'" x2="'+x4+'" y2="'+y1+'" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/>'
+'<text x="'+((x1+x2)/2)+'" y="'+(y1+16)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>'
+'<text x="'+(x4-14)+'" y="'+(by-H2/2)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>'
+'<text x="'+x1+'" y="'+(y1+14)+'" font-size="11" fill="#0f766e" font-weight="700">A</text>'
+'<text x="'+x2+'" y="'+(y2+14)+'" font-size="11" fill="#0f766e" font-weight="700">B</text>'
+'<text x="'+(x3+2)+'" y="'+(y3-4)+'" font-size="11" fill="#0f766e" font-weight="700">C</text>'
+'<text x="'+(x4-14)+'" y="'+(y4-4)+'" font-size="11" fill="#0f766e" font-weight="700">D</text>';
}
},
{
desc:'Проводим высоту DE — перпендикуляр из D на AB. Отрезаем правый треугольник BCE.',
draw(){
const x1=bx,x2=bx+bw,x3=bx+bw+sh,x4=bx+sh;
const y1=by,y2=by,y3=by-H2,y4=by-H2;
return '<polygon points="'+[x1,y1,x2,y2,x3,y3,x4,y4].join(' ')+'" fill="rgba(13,148,136,.12)" stroke="#0d9488" stroke-width="2.2"/>'
+'<polygon points="'+x2+','+y2+' '+x3+','+y3+' '+x4+','+y4+'" fill="rgba(239,68,68,.25)" stroke="#ef4444" stroke-width="2" stroke-dasharray="5 3"/>'
+'<line x1="'+x4+'" y1="'+y4+'" x2="'+x4+'" y2="'+y1+'" stroke="#f59e0b" stroke-width="2"/>'
+'<text x="'+((x1+x4)/2)+'" y="'+(by-H2/2)+'" text-anchor="middle" font-size="11" fill="#0f766e">Оставшийся трапеция</text>'
+'<text x="'+((x2+x3+x4)/3)+'" y="'+(by-H2/3)+'" text-anchor="middle" font-size="11" fill="#ef4444">Треугольник</text>';
}
},
{
desc:'Переносим выделенный треугольник на левую сторону. Он встаёт точно на место треугольника ADE.',
draw(){
const x1=bx,x2=bx+bw,x4=bx+sh;
const y1=by,y2=by,y4=by-H2;
return '<rect x="'+x1+'" y="'+(by-H2)+'" width="'+bw+'" height="'+H2+'" fill="rgba(13,148,136,.15)" stroke="#0d9488" stroke-width="2.2"/>'
+'<polygon points="'+x1+','+y1+' '+bx+','+(by-H2)+' '+(bx-sh)+','+(by-H2)+'" fill="rgba(239,68,68,.25)" stroke="#ef4444" stroke-width="2"/>'
+'<polygon points="'+bx+','+(by-H2)+' '+(bx-sh)+','+(by-H2)+' '+x1+','+y1+'" fill="rgba(16,185,129,.3)" stroke="#10b981" stroke-width="2"/>'
+'<text x="'+((x1+x2)/2)+'" y="'+(by-H2/2)+'" text-anchor="middle" font-size="11" fill="#0f766e">Получается прямоугольник!</text>';
}
},
{
desc:'Получился прямоугольник со сторонами a и h. Его площадь S = a·h. Значит, и у исходного параллелограмма S = a·h!',
draw(){
const x1=bx;
return '<rect x="'+x1+'" y="'+(by-H2)+'" width="'+bw+'" height="'+H2+'" fill="rgba(16,185,129,.22)" stroke="#059669" stroke-width="2.5"/>'
+'<text x="'+(x1+bw/2)+'" y="'+(by-H2-10)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = '+bw+' px</text>'
+'<text x="'+(x1-12)+'" y="'+(by-H2/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,'+(x1-12)+','+(by-H2/2)+')">h = '+H2+' px</text>'
+'<text x="'+(x1+bw/2)+'" y="'+(by-H2/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="15" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S = a·h</text>';
}
},
];
function render(){
const s=steps[step];
const svgHtml='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:380px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p3-proof-svg-wrap').innerHTML=svgHtml;
document.getElementById('p3-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p3-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
}
document.getElementById('p3-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p3-proof-step');}
else{addXp(3,'p3-proof-done');bumpProgress('p3',15);}
});
document.getElementById('p3-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p3-calc-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p3-calc-a').value);
const h=parseFloat(document.getElementById('p3-calc-h').value);
const out=document.getElementById('p3-calc-out1');
if(!isFinite(a)||!isFinite(h)||a<=0||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S = '+fmt(a)+'\\cdot'+fmt(h)+' = '+fmt(a*h)+'$';
renderMath(out); addXp(1,'p3-calc');
});
document.getElementById('p3-calc-go2').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p3-calc-s').value);
const h=parseFloat(document.getElementById('p3-calc-h2').value);
const out=document.getElementById('p3-calc-out2');
if(!isFinite(S)||!isFinite(h)||S<=0||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$a = S/h = '+fmt(S)+'/'+fmt(h)+' = '+fmt(S/h)+'$';
renderMath(out); addXp(1,'p3-calc-inv');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 180 90" style="display:block;max-width:190px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #ccfbf1;border-radius:8px"><polygon points="20,72 150,72 170,22 40,22" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2"/><line x1="40" y1="22" x2="40" y2="72" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><polyline points="47,72 47,65 40,65" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="30" y="50" text-anchor="middle" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=7</text><text x="85" y="86" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 10 см</text><text x="108" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0f766e">S = ?</text></svg>Параллелограмм, основание <b>10 см</b>, высота <b>7 см</b>. Площадь?', ans:70, hint:'S = 10·7 = 70.'},
{q:'<svg viewBox="0 0 180 90" style="display:block;max-width:190px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #ccfbf1;border-radius:8px"><polygon points="20,72 150,72 170,22 40,22" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2"/><line x1="40" y1="22" x2="40" y2="72" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="30" y="50" text-anchor="middle" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=6</text><text x="85" y="86" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = ?</text><text x="108" y="50" text-anchor="middle" dominant-baseline="middle" font-size="10" fill="#0f766e">S=84</text></svg>Площадь параллелограмма <b>84 м²</b>, высота <b>6 м</b>. Основание?', ans:14, hint:'a = 84/6 = 14.'},
{q:'Основание параллелограмма <b>15 дм</b>, площадь <b>120 дм²</b>. Высота?', ans:8, hint:'h = 120/15 = 8.'},
{q:'<svg viewBox="0 0 180 90" style="display:block;max-width:190px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #ccfbf1;border-radius:8px"><polygon points="20,72 130,72 155,22 45,22" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2"/><line x1="45" y1="22" x2="45" y2="72" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="34" y="50" text-anchor="middle" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=4</text><text x="75" y="86" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 9 см</text><text x="100" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0f766e">S = ?</text></svg>Параллелограмм, сторона <b>9 см</b>, высота к этой стороне <b>4 см</b>. Площадь?', ans:36, hint:'S = 9·4 = 36.'},
{q:'Два параллелограмма: у обоих основание <b>8</b>, высоты <b>5</b> и <b>5</b>. Какую площадь имеет каждый?', ans:40, hint:'S = 8·5 = 40 — равные площади!'},
];
let idx=0,score=0;
function show(){
document.getElementById('p3-tr-i').textContent=idx+1;
document.getElementById('p3-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p3-tr-ans').value='';
document.getElementById('p3-tr-fb').style.display='none';
}
document.getElementById('p3-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p3-tr-score').textContent=0;show();});
document.getElementById('p3-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p3-tr-ans').value;
const fb=document.getElementById('p3-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p3-tr-score').textContent=score;
addXp(3,'p3-tr-'+idx);bumpProgress('p3',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p3-tr-all');bumpProgress('p3',10);}
} else {
feedback(fb,false,'Неверно. '+tasks[idx].hint);
}
});
document.getElementById('p3-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p3-tr-go').click();});
show();
})();
/* == INIT: Босс §3 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 180 90" style="display:block;max-width:190px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #ccfbf1;border-radius:8px"><polygon points="15,72 155,72 175,22 35,22" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2"/><line x1="35" y1="22" x2="35" y2="72" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="24" y="50" text-anchor="middle" font-size="9" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=9</text><text x="85" y="86" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 16 дм</text><text x="108" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0f766e">S = ?</text></svg>Параллелограмм, основание <b>16 дм</b>, высота <b>9 дм</b>. Площадь?', ans:144, hint:'16·9 = 144.'},
{q:'<svg viewBox="0 0 180 90" style="display:block;max-width:190px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #ccfbf1;border-radius:8px"><polygon points="15,72 155,72 175,22 35,22" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2"/><line x1="35" y1="22" x2="35" y2="72" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="24" y="50" text-anchor="middle" font-size="9" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=?</text><text x="85" y="86" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=15, S=195</text></svg>Площадь параллелограмма <b>195 м²</b>, основание <b>15 м</b>. Высота?', ans:13, hint:'195/15 = 13.'},
{q:'Два параллелограмма с основанием 12 имеют площади <b>96</b> и <b>60</b>. Найди сумму их высот.', ans:13, hint:'h1=96/12=8, h2=60/12=5, сумма=13.'},
{q:'<svg viewBox="0 0 180 90" style="display:block;max-width:190px;margin:0 auto 8px;background:#f0fdf4;border:1px solid #ccfbf1;border-radius:8px"><polygon points="15,72 135,72 165,22 45,22" fill="rgba(13,148,136,.16)" stroke="#0d9488" stroke-width="2"/><line x1="45" y1="22" x2="45" y2="72" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="34" y="50" text-anchor="middle" font-size="9" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=6</text><text x="75" y="86" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 10 см</text><text x="100" y="50" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0f766e">S = ?</text></svg>Параллелограмм, боковая сторона <b>10 см</b>, высота к ней <b>6 см</b>. Площадь?', ans:60, hint:'S = 10·6 = 60.'},
];
const bossBox=document.getElementById('p3-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="p3b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p3b-a${i}').value;
const fb=document.getElementById('p3b-fb${i}');
if(Math.abs(v-${t.ans})<0.5){
feedback(fb,true,'Верно! +5 XP');
if(!p3BossSolved.has(${i})){ p3BossSolved.add(${i}); addXp(5,'p3-boss${i}'); bumpProgress('p3',10); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p3b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p3BossSolved=new Set();
})();
/* == MINI-SLIDER: Параллелограмм == */
(function(){
const W=280, H=180;
function draw(){
const a=+document.getElementById('p3-sl-a').value;
const h=+document.getElementById('p3-sl-h').value;
document.getElementById('p3-sl-a-val').textContent=a;
document.getElementById('p3-sl-h-val').textContent=h;
const S=a*h;
const sc=Math.min(200/a,10,120/h);
const pw=Math.round(a*sc), ph=Math.round(h*sc), sk=Math.round(ph*0.6);
const ox=Math.round((W-pw-sk)/2)+sk/2, oy=Math.round((H-ph)/2);
// parallelogram: 4 points
const x0=Math.round(ox+sk), y0=Math.round(oy+ph);
const x1=Math.round(ox+sk+pw), y1=y0;
const x2=Math.round(ox+pw), y2=Math.round(oy);
const x3=Math.round(ox), y3=y2;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:300px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
s+='<polygon points="'+x0+','+y0+' '+x1+','+y1+' '+x2+','+y2+' '+x3+','+y3+'" fill="rgba(5,150,105,.2)" stroke="#059669" stroke-width="2.5"/>';
// height dashed
s+='<line x1="'+x0+'" y1="'+y0+'" x2="'+x0+'" y2="'+(y0-ph)+'" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="5 3"/>';
s+='<polyline points="'+(x0+6)+','+(y0-ph)+' '+(x0+6)+','+y0+'" fill="none" stroke="none"/>';
s+='<polyline points="'+(x0+6)+','+(y0-6)+' '+(x0+6)+','+y0+' '+x0+','+y0+'" fill="none" stroke="#f59e0b" stroke-width="1.3"/>';
// labels
s+='<text x="'+((x0+x1)/2)+'" y="'+(y0+14)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(x0-12)+'" y="'+(y0-ph/2)+'" text-anchor="end" dominant-baseline="middle" font-size="11" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h='+h+'</text>';
s+='<text x="'+Math.round((x0+x1+x2+x3)/4)+'" y="'+Math.round((y0+y0+y2+y3)/4)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S='+S+'</text>';
s+='</svg>';
document.getElementById('p3-sl-svg-wrap').innerHTML=s;
document.getElementById('p3-sl-info').innerHTML='<div><b>a</b> = '+a+'</div><div><b>h</b> = '+h+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>S = a·h = '+S+'</b></div>';
}
document.getElementById('p3-sl-a').addEventListener('input',draw);
document.getElementById('p3-sl-h').addEventListener('input',draw);
draw();
})();
}
/* ============================================================
§4 — ПЛОЩАДЬ ТРЕУГОЛЬНИКА
============================================================ */
function buildP4(){
const box = document.getElementById('p4-body');
let html = '';
html += makeCard('theory','Площадь треугольника','4.1',`
<p><b>Высота треугольника</b> — перпендикуляр, опущенный из вершины на противоположную сторону (основание) или её продолжение.</p>
<p><b>Теорема.</b> Площадь треугольника равна половине произведения основания на высоту:</p>
$$S = \\dfrac{1}{2} \\cdot a \\cdot h$$
<p>где $a$ — основание, $h$ — высота к нему.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 150" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- triangle with base a, height h -->
<polygon points="40,120 240,120 160,30" fill="rgba(8,145,178,.14)" stroke="#0891b2" stroke-width="2.5"/>
<!-- height line -->
<line x1="160" y1="30" x2="160" y2="120" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="168,120 168,112 160,112" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<!-- labels -->
<text x="148" y="75" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>
<text x="140" y="138" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>
<!-- S formula -->
<text x="100" y="90" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0e7490" font-family="JetBrains Mono,monospace">S = ½·a·h</text>
<!-- vertex labels -->
<text x="32" y="118" font-size="11" fill="#0891b2" font-weight="700">A</text>
<text x="243" y="118" font-size="11" fill="#0891b2" font-weight="700">B</text>
<text x="156" y="24" font-size="11" fill="#0891b2" font-weight="700">C</text>
</svg>
</div>`);
html += makeCard('rule','Доказательство','4.2',`
<p><b>Идея:</b> из треугольника $ABC$ строим параллелограмм — копируем треугольник и прикладываем к стороне $AB$. Получается параллелограмм $ABDC$ с тем же основанием $a$ и той же высотой $h$.</p>
<p>Площадь параллелограмма: $S_{\\text{пар}} = a \\cdot h$.</p>
<p>Треугольник — ровно <b>половина</b> параллелограмма (диагональ делит его на два равных треугольника):</p>
$$S_{\\triangle} = \\dfrac{1}{2} \\cdot a \\cdot h$$
<p style="margin-top:8px;font-size:.88rem;color:var(--muted)">Важное следствие: треугольники с одним основанием и одинаковой высотой (вершина лежит на прямой, параллельной основанию) имеют <b>равные площади</b>.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 140" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- parallelogram with diagonal showing two triangles -->
<polygon points="30,115 200,115 230,35 60,35" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="6 3"/>
<!-- highlighted triangle (half) -->
<polygon points="30,115 200,115 230,35" fill="rgba(8,145,178,.22)" stroke="#0891b2" stroke-width="2.5"/>
<!-- diagonal -->
<line x1="30" y1="115" x2="230" y2="35" stroke="#059669" stroke-width="1.5" stroke-dasharray="5 3"/>
<!-- labels -->
<text x="115" y="132" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>
<text x="135" y="90" text-anchor="middle" font-size="12" font-weight="700" fill="#0e7490">S = ½·a·h</text>
<text x="85" y="70" text-anchor="middle" font-size="11" fill="#059669" opacity="0.7">= ½ пар.</text>
</svg>
</div>`);
html += makeCard('example','Примеры','4.3',`
<p><b>Треугольник, основание 12 см, высота 8 см. Площадь?</b><br>$S = \\dfrac{1}{2} \\cdot 12 \\cdot 8 = 48\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>Площадь 30 м², основание 10 м. Высота?</b><br>$h = \\dfrac{2S}{a} = \\dfrac{60}{10} = 6\\,\\text{м}$.</p>
<p style="margin-top:8px"><b>Площадь 18 дм², высота 6 дм. Основание?</b><br>$a = \\dfrac{2S}{h} = \\dfrac{36}{6} = 6\\,\\text{дм}$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 130" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- triangle a=12, h=8 example -->
<polygon points="40,110 220,110 155,30" fill="rgba(8,145,178,.16)" stroke="#0891b2" stroke-width="2.5"/>
<line x1="155" y1="30" x2="155" y2="110" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="163,110 163,102 155,102" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<text x="142" y="72" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=8</text>
<text x="130" y="126" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 12 см</text>
<text x="88" y="85" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#0e7490" font-family="Unbounded,sans-serif">S=48</text>
</svg>
</div>`);
/* --- INTERACTIVE 1: Draggable вершина C --- */
html += `<div class="wg" id="p4-tri-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Равноплощадные треугольники</div></div>
<div class="wg-help">Тащи вершину C вдоль прямой. Основание AB фиксировано, высота не меняется — площадь $S = \\frac{1}{2} \\cdot AB \\cdot h$ постоянна!</div>
<div id="p4-tri-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p4-tri-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* --- INTERACTIVE 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-wrap" 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"></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>`;
/* --- INTERACTIVE 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">Введи два из трёх параметров — найди третий.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, h → S</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p4-calc-a" class="tinp" placeholder="a" style="width:72px">
<input type="number" id="p4-calc-h" class="tinp" placeholder="h" style="width:72px">
<button class="btn primary" id="p4-calc-go1">= S</button>
</div>
<div id="p4-calc-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, a → h</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p4-calc-s2" class="tinp" placeholder="S" style="width:72px">
<input type="number" id="p4-calc-a2" class="tinp" placeholder="a" style="width:72px">
<button class="btn primary" id="p4-calc-go2">= h</button>
</div>
<div id="p4-calc-out2" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, h → a</div>
<div style="display:flex;gap:6px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p4-calc-s3" class="tinp" placeholder="S" style="width:72px">
<input type="number" id="p4-calc-h3" class="tinp" placeholder="h" style="width:72px">
<button class="btn primary" id="p4-calc-go3">= a</button>
</div>
<div id="p4-calc-out3" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* --- MINI-SLIDER: Треугольник S = a·h/2 --- */
html += `<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Треугольник — меняй основание и высоту</div></div>
<div class="wg-help">$S = \\dfrac{1}{2} a \\cdot h$ — треугольник всегда занимает половину соответствующего параллелограмма.</div>
<div class="sliders">
<label>Основание a = <b id="p4-sl-a-val">8</b>
<input type="range" min="2" max="18" value="8" id="p4-sl-a">
</label>
<label>Высота h = <b id="p4-sl-h-val">6</b>
<input type="range" min="1" max="14" value="6" id="p4-sl-h">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p4-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p4-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* --- INTERACTIVE 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 задач на площадь треугольника.</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.05rem;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>`;
/* --- INTERACTIVE 5: Босс §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: Draggable вершина C == */
(function(){
const W=380, H=240;
const Ax=60, Ay=190, Bx=280, By=190;
const BASE=Bx-Ax, H_FIX=100;
let Cx=170;
const Cy=Ay-H_FIX;
function draw(){
const S=0.5*BASE*H_FIX;
let s='<svg id="p4-tri-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:400px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// parallel line (locus of C)
s+='<line x1="10" y1="'+Cy+'" x2="'+(W-10)+'" y2="'+Cy+'" stroke="#f59e0b" stroke-width="1" stroke-dasharray="6 4" opacity=".7"/>';
s+='<text x="'+(W-8)+'" y="'+(Cy-8)+'" text-anchor="end" font-size="10" fill="#b45309">Прямая C</text>';
// height line
s+='<line x1="'+Cx+'" y1="'+Cy+'" x2="'+Cx+'" y2="'+Ay+'" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3" opacity=".8"/>';
// right angle mark
s+='<polyline points="'+(Cx+8)+','+Ay+' '+(Cx+8)+','+(Ay-8)+' '+Cx+','+(Ay-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.5"/>';
s+='<text x="'+(Cx+16)+'" y="'+(Ay-H_FIX/2)+'" font-size="11" fill="#b45309">h</text>';
// triangle
s+='<polygon points="'+Ax+','+Ay+' '+Bx+','+By+' '+Cx+','+Cy+'" fill="rgba(8,145,178,.18)" stroke="#0891b2" stroke-width="2.2" stroke-linejoin="round"/>';
// AB label
s+='<text x="'+((Ax+Bx)/2)+'" y="'+(Ay+18)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = AB = '+BASE+'</text>';
// S label — cx and cy both from triangle centroid
const lx=(Ax+Bx+Cx)/3, ly=(Ay+By+Cy)/3;
s+='<text x="'+lx+'" y="'+ly+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#0e7490" font-family="Unbounded,sans-serif">S = '+S+'</text>';
// vertex labels
s+='<text x="'+(Ax-12)+'" y="'+(Ay+4)+'" font-size="12" font-weight="700" fill="#0891b2">A</text>';
s+='<text x="'+(Bx+4)+'" y="'+(By+4)+'" font-size="12" font-weight="700" fill="#0891b2">B</text>';
s+='<text x="'+(Cx)+'" y="'+(Cy-12)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#0891b2">C</text>';
// C drag handle
s+='<circle cx="'+Cx+'" cy="'+Cy+'" r="12" fill="rgba(8,145,178,.2)"/>';
s+='<circle cx="'+Cx+'" cy="'+Cy+'" r="7" fill="#0891b2" stroke="#fff" stroke-width="2" id="p4-drag-c" style="cursor:ew-resize"/>';
s+='</svg>';
document.getElementById('p4-tri-svg-wrap').innerHTML=s;
document.getElementById('p4-tri-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Основание a</div><b>${BASE}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Высота h</div><b>${H_FIX}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S = ½·a·h</div><b style="color:var(--sec-acc-d,var(--pri2))">${S}</b></div>`;
const handle=document.getElementById('p4-drag-c');
if(handle){
handle.addEventListener('pointerdown',ev=>{
function onMove(e){
const svgEl=document.getElementById('p4-tri-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
const nx=Math.max(10,Math.min(W-10,(e.clientX-rect.left)*scale));
Cx=Math.round(nx);
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Анимация доказательства == */
(function(){
let step=0;
const W=380, H=230;
const Ax=60,Ay=190,Bx=260,By=190,Cx=160,Cy=90;
// mirror of C relative to midpoint of AB gives D
const Dx=Ax+Bx-Cx, Dy=Ay+By-Cy;
const steps=[
{
desc:'Исходный треугольник ABC. Основание AB = a, высота h из вершины C.',
draw(){
return '<polygon points="'+Ax+','+Ay+' '+Bx+','+By+' '+Cx+','+Cy+'" fill="rgba(8,145,178,.18)" stroke="#0891b2" stroke-width="2.2"/>'
+'<line x1="'+Cx+'" y1="'+Cy+'" x2="'+Cx+'" y2="'+Ay+'" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/>'
+'<text x="'+((Ax+Bx)/2)+'" y="'+(Ay+16)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>'
+'<text x="'+(Cx+10)+'" y="'+((Ay+Cy)/2)+'" font-size="11" fill="#b45309">h</text>'
+'<text x="'+(Ax-12)+'" y="'+(Ay+4)+'" font-size="12" font-weight="700" fill="#0891b2">A</text>'
+'<text x="'+(Bx+4)+'" y="'+(By+4)+'" font-size="12" font-weight="700" fill="#0891b2">B</text>'
+'<text x="'+Cx+'" y="'+(Cy-12)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#0891b2">C</text>';
}
},
{
desc:'Берём копию треугольника ABC и поворачиваем её на 180° вокруг середины AB. Вершина C переходит в точку D.',
draw(){
return '<polygon points="'+Ax+','+Ay+' '+Bx+','+By+' '+Cx+','+Cy+'" fill="rgba(8,145,178,.18)" stroke="#0891b2" stroke-width="2.2"/>'
+'<polygon points="'+Ax+','+Ay+' '+Bx+','+By+' '+Dx+','+Dy+'" fill="rgba(239,68,68,.2)" stroke="#ef4444" stroke-width="2" stroke-dasharray="5 3"/>'
+'<circle cx="'+((Ax+Bx)/2)+'" cy="'+((Ay+By)/2)+'" r="5" fill="#f59e0b"/>'
+'<text x="'+(Dx)+'" y="'+(Dy-12)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#ef4444">D</text>'
+'<text x="'+Cx+'" y="'+(Cy-12)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#0891b2">C</text>';
}
},
{
desc:'Треугольники ABC и ABD вместе образуют параллелограмм ACBD. Обе его диагонали — это AB и CD.',
draw(){
return '<polygon points="'+Ax+','+Ay+' '+Cx+','+Cy+' '+Bx+','+By+' '+Dx+','+Dy+'" fill="rgba(16,185,129,.18)" stroke="#10b981" stroke-width="2.2"/>'
+'<line x1="'+Ax+'" y1="'+Ay+'" x2="'+Bx+'" y2="'+By+'" stroke="#059669" stroke-width="2" stroke-dasharray="5 3"/>'
+'<line x1="'+Cx+'" y1="'+Cy+'" x2="'+Dx+'" y2="'+Dy+'" stroke="#059669" stroke-width="2" stroke-dasharray="5 3"/>'
+'<text x="'+((Ax+Cx+Bx+Dx)/4)+'" y="'+((Ay+Cy+By+Dy)/4)+'" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#047857">Параллелограмм</text>';
}
},
{
desc:'Параллелограмм = два равных треугольника. S(пар) = a·h. Значит S(△) = ½·a·h!',
draw(){
return '<polygon points="'+Ax+','+Ay+' '+Cx+','+Cy+' '+Bx+','+By+' '+Dx+','+Dy+'" fill="rgba(16,185,129,.22)" stroke="#059669" stroke-width="2.5"/>'
+'<polygon points="'+Ax+','+Ay+' '+Bx+','+By+' '+Cx+','+Cy+'" fill="rgba(8,145,178,.35)" stroke="#0891b2" stroke-width="2"/>'
+'<text x="'+((Ax+Bx+Cx)/3)+'" y="'+((Ay+By+Cy)/3)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#0e7490" font-family="Unbounded,sans-serif">½·a·h</text>'
+'<text x="'+((Ax+Bx+Dx)/3)+'" y="'+((Ay+By+Dy)/3)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">½·a·h</text>';
}
},
];
function render(){
const s=steps[step];
document.getElementById('p4-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:400px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p4-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p4-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
}
document.getElementById('p4-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p4-proof-step');}
else{addXp(3,'p4-proof-done');bumpProgress('p4',15);}
});
document.getElementById('p4-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p4-calc-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p4-calc-a').value);
const h=parseFloat(document.getElementById('p4-calc-h').value);
const out=document.getElementById('p4-calc-out1');
if(!isFinite(a)||!isFinite(h)||a<=0||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S = \\frac{1}{2}\\cdot'+fmt(a)+'\\cdot'+fmt(h)+' = '+fmt(0.5*a*h)+'$';
renderMath(out); addXp(1,'p4-calc');
});
document.getElementById('p4-calc-go2').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p4-calc-s2').value);
const a=parseFloat(document.getElementById('p4-calc-a2').value);
const out=document.getElementById('p4-calc-out2');
if(!isFinite(S)||!isFinite(a)||S<=0||a<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$h = \\frac{2S}{a} = \\frac{2\\cdot'+fmt(S)+'}{'+fmt(a)+'} = '+fmt(2*S/a)+'$';
renderMath(out); addXp(1,'p4-calc-h');
});
document.getElementById('p4-calc-go3').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p4-calc-s3').value);
const h=parseFloat(document.getElementById('p4-calc-h3').value);
const out=document.getElementById('p4-calc-out3');
if(!isFinite(S)||!isFinite(h)||S<=0||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$a = \\frac{2S}{h} = \\frac{2\\cdot'+fmt(S)+'}{'+fmt(h)+'} = '+fmt(2*S/h)+'$';
renderMath(out); addXp(1,'p4-calc-a');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#cffafe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="20,80 160,80 110,20" fill="rgba(8,145,178,.2)" stroke="#0891b2" stroke-width="2"/><line x1="110" y1="20" x2="110" y2="80" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><polyline points="117,80 117,73 110,73" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="100" y="53" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=6</text><text x="90" y="94" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 14 см</text><text x="65" y="60" text-anchor="middle" font-size="11" font-weight="700" fill="#0e7490">S=?</text></svg>Треугольник, основание <b>14 см</b>, высота <b>6 см</b>. Площадь?', ans:42, hint:'S = ½·14·6 = 42.'},
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#cffafe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="20,80 160,80 105,20" fill="rgba(8,145,178,.2)" stroke="#0891b2" stroke-width="2"/><line x1="105" y1="20" x2="105" y2="80" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="93" y="53" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=9</text><text x="90" y="94" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = ?</text><text x="60" y="58" text-anchor="middle" font-size="10" fill="#0e7490">S=45</text></svg>Площадь треугольника <b>45 м²</b>, высота <b>9 м</b>. Основание?', ans:10, hint:'a = 2·45/9 = 10.'},
{q:'Площадь треугольника <b>36 дм²</b>, основание <b>12 дм</b>. Высота?', ans:6, hint:'h = 2·36/12 = 6.'},
{q:'<svg viewBox="0 0 120 100" style="display:block;max-width:130px;margin:0 auto 8px;background:#cffafe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="16,80 96,80 16,16" fill="rgba(8,145,178,.2)" stroke="#0891b2" stroke-width="2"/><polyline points="26,80 26,70 16,70" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="56" y="94" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=8</text><text x="8" y="48" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,48)">b=6</text><text x="58" y="55" text-anchor="middle" font-size="10" font-weight="700" fill="#0e7490">S=?</text></svg>Прямоугольный треугольник, катеты <b>8 см</b> и <b>6 см</b>. Площадь?', ans:24, hint:'S = ½·8·6 = 24.'},
{q:'Площадь параллелограмма <b>80 м²</b>. Площадь треугольника на том же основании и высоте?', ans:40, hint:'S(△) = S(пар)/2 = 40.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p4-tr-i').textContent=idx+1;
document.getElementById('p4-tr-task').innerHTML=tasks[idx].q;
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.5){
score++;document.getElementById('p4-tr-score').textContent=score;
addXp(3,'p4-tr-'+idx);bumpProgress('p4',5);
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);}
} 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: Босс §4 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#cffafe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="15,80 165,80 110,18" fill="rgba(8,145,178,.2)" stroke="#0891b2" stroke-width="2"/><line x1="110" y1="18" x2="110" y2="80" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="98" y="52" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=10</text><text x="90" y="94" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 18 дм</text><text x="60" y="62" text-anchor="middle" font-size="11" font-weight="700" fill="#0e7490">S=?</text></svg>Треугольник, основание <b>18 дм</b>, высота <b>10 дм</b>. Площадь?', ans:90, hint:'½·18·10 = 90.'},
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#cffafe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="15,80 165,80 110,18" fill="rgba(8,145,178,.2)" stroke="#0891b2" stroke-width="2"/><line x1="110" y1="18" x2="110" y2="80" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="98" y="52" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=?</text><text x="90" y="94" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=14, S=56</text></svg>Площадь треугольника <b>56 м²</b>, основание <b>14 м</b>. Высота?', ans:8, hint:'h = 2·56/14 = 8.'},
{q:'Квадрат со стороной <b>6 см</b>. Диагональ делит его на 2 треугольника. Площадь каждого?', ans:18, hint:'S(кв) = 36; S(△) = 36/2 = 18.'},
{q:'Параллелограмм, основание <b>20 м</b>, высота <b>7 м</b>. Площадь вписанного треугольника (того же основания и высоты)?', ans:70, hint:'S(пар) = 140; S(△) = 70.'},
];
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.5){
feedback(fb,true,'Верно! +5 XP');
if(!p4BossSolved.has(${i})){ p4BossSolved.add(${i}); addXp(5,'p4-boss${i}'); bumpProgress('p4',10); }
} 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();
})();
/* == MINI-SLIDER: Треугольник == */
(function(){
const W=280, H=190;
function draw(){
const a=+document.getElementById('p4-sl-a').value;
const h=+document.getElementById('p4-sl-h').value;
document.getElementById('p4-sl-a-val').textContent=a;
document.getElementById('p4-sl-h-val').textContent=h;
const S=+(a*h/2).toFixed(1);
const sc=Math.min(220/a,12,130/h);
const pw=Math.round(a*sc), ph=Math.round(h*sc);
const ox=Math.round((W-pw)/2), oy=Math.round((H-ph)/2);
// apex at center top, base at bottom
const ax=ox+pw/2, ay=oy;
const bx=ox, by=oy+ph;
const cx=ox+pw, cy=oy+ph;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:300px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
s+='<polygon points="'+Math.round(ax)+','+Math.round(ay)+' '+Math.round(bx)+','+Math.round(by)+' '+Math.round(cx)+','+Math.round(cy)+'" fill="rgba(5,150,105,.2)" stroke="#059669" stroke-width="2.5"/>';
// height dashed
s+='<line x1="'+Math.round(ax)+'" y1="'+Math.round(ay)+'" x2="'+Math.round(ax)+'" y2="'+Math.round(by)+'" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="5 3"/>';
s+='<polyline points="'+(Math.round(ax)+8)+','+Math.round(by)+' '+(Math.round(ax)+8)+','+(Math.round(by)-8)+' '+Math.round(ax)+','+(Math.round(by)-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.3"/>';
// labels
s+='<text x="'+(Math.round(bx+cx)/2)+'" y="'+(Math.round(by)+14)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(Math.round(ax)+12)+'" y="'+(Math.round(ay+by)/2)+'" dominant-baseline="middle" font-size="11" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h='+h+'</text>';
s+='<text x="'+Math.round((ax+bx+cx)/3)+'" y="'+Math.round((ay+by+cy)/3)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S='+S+'</text>';
s+='</svg>';
document.getElementById('p4-sl-svg-wrap').innerHTML=s;
document.getElementById('p4-sl-info').innerHTML='<div><b>a</b> = '+a+'</div><div><b>h</b> = '+h+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>S = a·h/2 = '+S+'</b></div>';
}
document.getElementById('p4-sl-a').addEventListener('input',draw);
document.getElementById('p4-sl-h').addEventListener('input',draw);
draw();
})();
}
/* ============================================================
§5 — ПЛОЩАДЬ ТРАПЕЦИИ
============================================================ */
function buildP5(){
const box=document.getElementById('p5-body');
let html='';
html+=makeCard('theory','Площадь трапеции','5.1',`
<p><b>Теорема.</b> Площадь трапеции равна произведению полусуммы оснований на высоту:</p>
$$S = \\dfrac{a+b}{2}\\cdot h$$
<p>где $a$ и $b$ — основания (параллельные стороны), $h$ — высота (расстояние между основаниями).</p>
<p style="margin-top:8px"><b>Через среднюю линию:</b> $m = \\dfrac{a+b}{2}$, поэтому $S = m \\cdot h$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 300 170" style="max-width:320px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- trapezoid: A(40,130) B(260,130) C(210,50) D(90,50) -->
<polygon points="40,130 260,130 210,50 90,50" fill="rgba(2,132,199,.13)" stroke="#0284c7" stroke-width="2.5"/>
<!-- height: vertical from top-base midpoint (150,50) down to bottom (150,130) -->
<line x1="150" y1="50" x2="150" y2="130" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>
<!-- right-angle marker at bottom -->
<polyline points="158,130 158,122 150,122" fill="none" stroke="#dc2626" stroke-width="1.5"/>
<!-- midline (m) -->
<line x1="65" y1="90" x2="235" y2="90" stroke="#059669" stroke-width="1.5" stroke-dasharray="7 4"/>
<!-- vertex dots -->
<circle cx="40" cy="130" r="3" fill="#0284c7"/><circle cx="260" cy="130" r="3" fill="#0284c7"/>
<circle cx="90" cy="50" r="3" fill="#0284c7"/><circle cx="210" cy="50" r="3" fill="#0284c7"/>
<!-- vertex labels -->
<text x="32" y="142" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">A</text>
<text x="262" y="142" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">B</text>
<text x="210" y="44" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">C</text>
<text x="82" y="44" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">D</text>
<!-- base labels -->
<text x="150" y="160" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a (нижнее основание)</text>
<text x="150" y="38" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b (верхнее основание)</text>
<!-- height label -->
<text x="158" y="92" font-size="13" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h</text>
<!-- midline label -->
<text x="240" y="93" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">m</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство (диагональ)','5.2',`
<p>Проведём диагональ $BD$ трапеции $ABCD$ ($AB \\parallel CD$).</p>
<p>Диагональ делит трапецию на два треугольника:</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li>$\\triangle ABD$: основание $a=AB$, высота $h$ &rarr; $S_1 = \\dfrac{1}{2}ah$</li>
<li>$\\triangle BCD$: основание $b=CD$, высота $h$ &rarr; $S_2 = \\dfrac{1}{2}bh$</li>
</ul>
<p style="margin-top:8px">По аддитивности: $S = S_1+S_2 = \\dfrac{1}{2}ah+\\dfrac{1}{2}bh = \\dfrac{a+b}{2}\\cdot h$. $\\square$</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 160" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- trapezoid ABCD: A(30,125) B(250,125) C(200,40) D(80,40) -->
<!-- △ABD lower: A B D -->
<polygon points="30,125 250,125 80,40" fill="rgba(2,132,199,.22)" stroke="#0284c7" stroke-width="1.5"/>
<!-- △BCD upper: B C D -->
<polygon points="250,125 200,40 80,40" fill="rgba(5,150,105,.22)" stroke="#059669" stroke-width="1.5"/>
<!-- trapezoid outline -->
<polygon points="30,125 250,125 200,40 80,40" fill="none" stroke="#0284c7" stroke-width="2.5"/>
<!-- diagonal BD highlighted -->
<line x1="250" y1="125" x2="80" y2="40" stroke="#dc2626" stroke-width="2"/>
<!-- vertex dots -->
<circle cx="30" cy="125" r="3.5" fill="#0284c7"/><circle cx="250" cy="125" r="3.5" fill="#0284c7"/>
<circle cx="200" cy="40" r="3.5" fill="#0284c7"/><circle cx="80" cy="40" r="3.5" fill="#0284c7"/>
<!-- labels A B C D -->
<text x="22" y="138" font-size="12" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">A</text>
<text x="252" y="138" font-size="12" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">B</text>
<text x="200" y="32" font-size="12" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">C</text>
<text x="72" y="32" font-size="12" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">D</text>
<!-- triangle S labels -->
<text x="120" y="105" font-size="11" font-weight="800" fill="#0369a1" font-family="JetBrains Mono,monospace">S₁ = ½ah</text>
<text x="148" y="60" font-size="11" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">S₂ = ½bh</text>
<!-- BD label -->
<text x="160" y="80" font-size="11" font-weight="700" fill="#b91c1c" font-family="JetBrains Mono,monospace">BD</text>
<!-- bottom/top labels -->
<text x="140" y="153" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>
<text x="140" y="22" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b</text>
</svg>
</div>`);
html+=makeCard('example','Примеры','5.3',`
<p><b>Трапеция, основания 8 и 14 см, высота 6 см. Площадь?</b><br>$S=\\dfrac{8+14}{2}\\cdot6=11\\cdot6=66\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>S = 72 м², h = 9 м, a = 10 м. Найти b.</b><br>$b = \\dfrac{2S}{h}-a = \\dfrac{144}{9}-10=16-10=6\\,\\text{м}$.</p>
<p style="margin-top:8px"><b>S = 80 дм², средняя линия m = 16 дм. Высота?</b><br>$h = S/m = 80/16 = 5\\,\\text{дм}$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 160" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- trapezoid a=14, b=8, h=6 -->
<polygon points="30,125 250,125 190,40 90,40" fill="rgba(2,132,199,.15)" stroke="#0284c7" stroke-width="2.5"/>
<!-- height: vertical line in middle of trapezoid -->
<line x1="140" y1="40" x2="140" y2="125" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="148,125 148,117 140,117" fill="none" stroke="#dc2626" stroke-width="1.5"/>
<!-- foot dot on bottom base -->
<circle cx="140" cy="125" r="2.5" fill="#dc2626"/>
<!-- labels -->
<text x="140" y="148" text-anchor="middle" font-size="12" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">a = 14 см</text>
<text x="140" y="30" text-anchor="middle" font-size="12" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">b = 8 см</text>
<text x="152" y="86" font-size="13" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h=6</text>
<text x="220" y="86" font-size="16" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">S=66 см²</text>
</svg>
</div>`);
/* INTERACTIVE 1 — Draggable трапеция */
html+=`<div class="wg" id="p5-trap-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Трапеция с перетаскиванием</div></div>
<div class="wg-help">Тащи верхнее основание (синяя точка) вправо/влево — меняется его длина $b$. Тащи левый нижний угол — меняется высота $h$. Площадь пересчитывается мгновенно.</div>
<div id="p5-trap-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p5-trap-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* INTERACTIVE 2 — Пошаговое доказательство */
html+=`<div class="wg" id="p5-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство: достраиваем до параллелограмма</div></div>
<div class="wg-help">Нажимай «Далее» и смотри, как две трапеции складываются в параллелограмм со стороной $(a+b)$ и высотой $h$.</div>
<div id="p5-proof-svg-wrap" 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"></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>`;
/* INTERACTIVE 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">Три режима: найти S, найти a, найти h.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, b, h &rarr; S</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p5-c-a" class="tinp" placeholder="a" style="width:60px">
<input type="number" id="p5-c-b" class="tinp" placeholder="b" style="width:60px">
<input type="number" id="p5-c-h" class="tinp" placeholder="h" style="width:60px">
<button class="btn primary" id="p5-c-go1">=S</button>
</div>
<div id="p5-c-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, h, b &rarr; a</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p5-c-s2" class="tinp" placeholder="S" style="width:60px">
<input type="number" id="p5-c-h2" class="tinp" placeholder="h" style="width:60px">
<input type="number" id="p5-c-b2" class="tinp" placeholder="b" style="width:60px">
<button class="btn primary" id="p5-c-go2">=a</button>
</div>
<div id="p5-c-out2" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, m &rarr; h</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p5-c-s3" class="tinp" placeholder="S" style="width:60px">
<input type="number" id="p5-c-m3" class="tinp" placeholder="m" style="width:60px">
<button class="btn primary" id="p5-c-go3">=h</button>
</div>
<div id="p5-c-out3" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* INTERACTIVE 4 — DnD сортер */
html+=`<div class="wg" id="p5-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Что является трапецией?</div></div>
<div class="wg-help">Распредели фигуры по группам: перетащи каждую в нужную колонку.</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:10px">
<div class="drop-zone"><div style="font-weight:700;color:var(--ok);margin-bottom:6px;font-size:.82rem;text-transform:uppercase;letter-spacing:.06em">Трапеция</div><div class="drop-box" style="min-height:80px;border:2px dashed var(--ok);border-radius:8px;padding:8px"><div data-cat="yes" style="display:none"></div><div class="drop-items" data-cat="yes" style="display:flex;flex-wrap:wrap;gap:6px;min-height:40px"></div></div></div>
<div class="drop-zone"><div style="font-weight:700;color:var(--bad);margin-bottom:6px;font-size:.82rem;text-transform:uppercase;letter-spacing:.06em">Не трапеция</div><div class="drop-box" style="min-height:80px;border:2px dashed var(--bad);border-radius:8px;padding:8px"><div data-cat="no" style="display:none"></div><div class="drop-items" data-cat="no" style="display:flex;flex-wrap:wrap;gap:6px;min-height:40px"></div></div></div>
</div>
<div id="p5-dnd-pool" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<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;margin-top:8px"></div>
</div>`;
/* MINI-SLIDER: Трапеция */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Трапеция — меняй основания и высоту</div></div>
<div class="wg-help">$S = \\dfrac{(a+b)}{2} \\cdot h$ — площадь трапеции через сумму оснований и высоту.</div>
<div class="sliders">
<label>Большее основание a = <b id="p5-sl-a-val">12</b>
<input type="range" min="2" max="20" value="12" id="p5-sl-a">
</label>
<label>Меньшее основание b = <b id="p5-sl-b-val">6</b>
<input type="range" min="1" max="18" value="6" id="p5-sl-b">
</label>
<label>Высота h = <b id="p5-sl-h-val">5</b>
<input type="range" min="1" max="14" value="5" id="p5-sl-h">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p5-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p5-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* INTERACTIVE 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</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.05rem;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>`;
/* INTERACTIVE 6 — Босс */
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: Draggable трапеция == */
(function(){
const W=420, H=280;
const AX=50, AY=220, BW=300;
let topB=140, topOff=80, trapH=130;
function draw(){
const ax=AX, ay=AY, bx=ax+BW, by=ay;
const dx=ax+topOff, dy=ay-trapH, cx=dx+topB, cy=dy;
const footX=Math.round((dx+cx)/2);
const Sval=Math.round((BW+topB)/2*trapH/10);
let s='<svg id="p5-trap-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:440px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
s+='<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+' '+dx+','+dy+'" fill="rgba(2,132,199,.13)" stroke="#0284c7" stroke-width="2.5" stroke-linejoin="round"/>';
s+='<line x1="'+footX+'" y1="'+dy+'" x2="'+footX+'" y2="'+ay+'" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>';
s+='<polyline points="'+(footX+9)+','+ay+' '+(footX+9)+','+(ay-9)+' '+footX+','+(ay-9)+'" fill="none" stroke="#dc2626" stroke-width="1.5"/>';
s+='<circle cx="'+footX+'" cy="'+ay+'" r="2.5" fill="#dc2626"/>';
['A','B','C','D'].forEach((lbl,i)=>{
const pt=[[ax,ay],[bx,by],[cx,cy],[dx,dy]][i];
s+='<circle cx="'+pt[0]+'" cy="'+pt[1]+'" r="3" fill="#0284c7"/>';
const off=[[ -10,14],[10,14],[10,-6],[-10,-6]][i];
s+='<text x="'+(pt[0]+off[0])+'" y="'+(pt[1]+off[1])+'" font-size="12" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">'+lbl+'</text>';
});
s+='<text x="'+((ax+bx)/2)+'" y="'+(ay+28)+'" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = '+BW+'</text>';
s+='<text x="'+((dx+cx)/2)+'" y="'+(dy-16)+'" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b = '+topB+'</text>';
s+='<text x="'+(footX+12)+'" y="'+((ay+dy)/2)+'" dominant-baseline="middle" font-size="14" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h = '+trapH+'</text>';
s+='<text x="'+(W-12)+'" y="22" text-anchor="end" font-size="14" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">S = '+Sval+' усл.</text>';
s+='<circle cx="'+cx+'" cy="'+cy+'" r="13" fill="rgba(2,132,199,.18)"/>';
s+='<circle cx="'+cx+'" cy="'+cy+'" r="8" fill="#0284c7" stroke="#fff" stroke-width="2" id="p5-drag-top" style="cursor:ew-resize"/>';
s+='<circle cx="'+dx+'" cy="'+dy+'" r="13" fill="rgba(245,158,11,.18)"/>';
s+='<circle cx="'+dx+'" cy="'+dy+'" r="8" fill="#f59e0b" stroke="#fff" stroke-width="2" id="p5-drag-h" style="cursor:ns-resize"/>';
s+='<text x="14" y="22" font-size="11" font-weight="700" fill="#0284c7" font-family="Inter,sans-serif">синий: тащи b</text>';
s+='<text x="14" y="38" font-size="11" font-weight="700" fill="#f59e0b" font-family="Inter,sans-serif">жёлтый: тащи h</text>';
s+='</svg>';
document.getElementById('p5-trap-svg-wrap').innerHTML=s;
document.getElementById('p5-trap-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Основание a</div><b>${BW}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Основание b</div><b>${topB}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Высота h</div><b>${trapH}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S = (a+b)·h/2</div><b style="color:#0369a1">${Sval}</b></div>`;
const handleTop=document.getElementById('p5-drag-top');
if(handleTop){
handleTop.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startB=topB;
function onMove(e){
const svgEl=document.getElementById('p5-trap-svg'); if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
const delta=Math.round((e.clientX-startX)*scale);
topB=Math.max(20,Math.min(280,startB+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
const handleH=document.getElementById('p5-drag-h');
if(handleH){
handleH.addEventListener('pointerdown',ev=>{
const startY=ev.clientY, startH=trapH;
function onMove(e){
const svgEl=document.getElementById('p5-trap-svg'); if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=H/rect.height;
const delta=Math.round((startY-e.clientY)*scale);
trapH=Math.max(50,Math.min(180,startH+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Доказательство пошаговое == */
(function(){
let step=0;
const W=460, H=240;
/* Trapezoid ABCD: A,B bottom; C,D top. a=AB (bottom), b=DC (top).
Origin trapezoid: A(50,200), B(50+a,200), C(50+ofL+b,200-h), D(50+ofL,200-h). */
const a=170, b=110, h=110, ofL=40, ofR=20;
const Ax=50, Ay=200;
const Bx=Ax+a, By=Ay;
const Dx=Ax+ofL, Dy=Ay-h;
const Cx=Dx+b, Cy=Dy;
/* Mid of right slanted side BC */
const Mx=(Bx+Cx)/2, My=(By+Cy)/2;
/* Rotate 180° around M: P -> (2M-P) */
const r=(p)=>({x:2*Mx-p.x, y:2*My-p.y});
/* Rotated copy: A'=r(A), B'=r(B)=C, C'=r(C)=B, D'=r(D) */
const Ap=r({x:Ax,y:Ay}), Dp=r({x:Dx,y:Dy});
/* The combined parallelogram: A B D' A' D (going around).
Actually after rotation:
original sides: A→B→C→D→A
rotated copy sides: B→D'→A'→C(=B')→B
The union has outer boundary: A→B→D'→A'→D→A
which is a parallelogram with sides AB+BD'=(a+b) on bottom, A'D+DA on slants. */
const heightFootX=Math.round((Dx+Cx)/2);
function vertexDots(pts){
return pts.map(p=>`<circle cx="${p.x}" cy="${p.y}" r="3.2" fill="#0284c7"/>`).join('');
}
function vertexLabels(items){
return items.map(([lbl,p,dx,dy,col])=>`<text x="${p.x+dx}" y="${p.y+dy}" font-size="12" font-weight="800" fill="${col||'#0369a1'}" font-family="Unbounded,sans-serif">${lbl}</text>`).join('');
}
const steps=[
{desc:'Исходная трапеция $ABCD$: основания $a=AB$ (нижнее) и $b=DC$ (верхнее), высота $h$ — расстояние между основаниями.',
draw(){
let s='';
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy} ${Dx},${Dy}" fill="rgba(2,132,199,.16)" stroke="#0284c7" stroke-width="2.2"/>`;
s+=`<line x1="${heightFootX}" y1="${Dy}" x2="${heightFootX}" y2="${Ay}" stroke="#dc2626" stroke-width="1.8" stroke-dasharray="5 3"/>`;
s+=`<polyline points="${heightFootX+8},${Ay} ${heightFootX+8},${Ay-8} ${heightFootX},${Ay-8}" fill="none" stroke="#dc2626" stroke-width="1.4"/>`;
s+=`<text x="${heightFootX+11}" y="${(Ay+Dy)/2}" dominant-baseline="middle" font-size="13" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h</text>`;
s+=`<text x="${(Ax+Bx)/2}" y="${Ay+22}" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>`;
s+=`<text x="${(Dx+Cx)/2}" y="${Dy-9}" text-anchor="middle" font-size="13" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b</text>`;
s+=vertexDots([{x:Ax,y:Ay},{x:Bx,y:By},{x:Cx,y:Cy},{x:Dx,y:Dy}]);
s+=vertexLabels([['A',{x:Ax,y:Ay},-12,14],['B',{x:Bx,y:By},6,14],['C',{x:Cx,y:Cy},6,-4],['D',{x:Dx,y:Dy},-12,-4]]);
return s;
}},
{desc:'Найдём середину $M$ боковой стороны $BC$. Повернём трапецию $ABCD$ на $180°$ вокруг точки $M$ — получим копию $A\'BCD\'$ (фиолетовая).',
draw(){
let s='';
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy} ${Dx},${Dy}" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="2"/>`;
s+=`<polygon points="${Ap.x},${Ap.y} ${Cx},${Cy} ${Bx},${By} ${Dp.x},${Dp.y}" fill="rgba(124,58,237,.16)" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5 3"/>`;
s+=`<circle cx="${Mx}" cy="${My}" r="5" fill="#f59e0b" stroke="#fff" stroke-width="1.5"/>`;
s+=`<text x="${Mx+10}" y="${My-6}" font-size="13" font-weight="800" fill="#b45309" font-family="Unbounded,sans-serif">M</text>`;
s+=vertexDots([{x:Ax,y:Ay},{x:Bx,y:By},{x:Cx,y:Cy},{x:Dx,y:Dy},Ap,Dp]);
s+=vertexLabels([
['A',{x:Ax,y:Ay},-12,14],['B',{x:Bx,y:By},4,14],
['C',{x:Cx,y:Cy},-8,16],['D',{x:Dx,y:Dy},-12,-4],
["D'",Dp,4,16,'#6d28d9'],["A'",Ap,6,-4,'#6d28d9']
]);
return s;
}},
{desc:'Объединение двух трапеций — параллелограмм $ABD\'A\'$ со сторонами $AB+BD\' = a+b$ (внизу) и высотой $h$.',
draw(){
let s='';
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Dp.x},${Dp.y} ${Ap.x},${Ap.y}" fill="rgba(5,150,105,.22)" stroke="#059669" stroke-width="2.5"/>`;
s+=`<line x1="${Bx}" y1="${By}" x2="${Cx}" y2="${Cy}" stroke="#0284c7" stroke-width="1.5" stroke-dasharray="4 3" opacity=".6"/>`;
s+=`<line x1="${heightFootX}" y1="${Dy}" x2="${heightFootX}" y2="${Ay}" stroke="#dc2626" stroke-width="1.8" stroke-dasharray="5 3"/>`;
s+=`<polyline points="${heightFootX+8},${Ay} ${heightFootX+8},${Ay-8} ${heightFootX},${Ay-8}" fill="none" stroke="#dc2626" stroke-width="1.4"/>`;
s+=`<text x="${heightFootX+11}" y="${(Ay+Dy)/2}" dominant-baseline="middle" font-size="13" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h</text>`;
s+=`<text x="${(Ax+Dp.x)/2}" y="${Ay+22}" text-anchor="middle" font-size="14" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">a + b</text>`;
s+=vertexDots([{x:Ax,y:Ay},{x:Bx,y:By},Dp,Ap]);
s+=vertexLabels([['A',{x:Ax,y:Ay},-12,14],['B',{x:Bx,y:By},-4,16],["D'",Dp,4,16,'#047857'],["A'",Ap,6,-4,'#047857']]);
return s;
}},
{desc:'$S_{\\text{пар}} = (a+b)\\cdot h$. Трапеция — ровно <b>половина</b> параллелограмма, поэтому $S_{\\text{трап}} = \\dfrac{a+b}{2}\\cdot h$.',
draw(){
let s='';
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Dp.x},${Dp.y} ${Ap.x},${Ap.y}" fill="rgba(5,150,105,.10)" stroke="#059669" stroke-width="1.5" stroke-dasharray="6 4"/>`;
s+=`<polygon points="${Ax},${Ay} ${Bx},${By} ${Cx},${Cy} ${Dx},${Dy}" fill="rgba(2,132,199,.32)" stroke="#0284c7" stroke-width="2.5"/>`;
s+=`<line x1="${Bx}" y1="${By}" x2="${Cx}" y2="${Cy}" stroke="#7c3aed" stroke-width="2"/>`;
s+=`<text x="${(Ax+Dp.x)/2}" y="${(Ay+Dy)/2}" text-anchor="middle" dominant-baseline="middle" font-size="15" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">S = ½(a+b)·h</text>`;
s+=vertexDots([{x:Ax,y:Ay},{x:Bx,y:By},{x:Cx,y:Cy},{x:Dx,y:Dy}]);
return s;
}},
];
function render(){
const s=steps[step];
document.getElementById('p5-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:420px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p5-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p5-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement) renderMath(document.getElementById('p5-proof-desc'));
}
document.getElementById('p5-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p5-proof-step');}
else{addXp(3,'p5-proof-done');bumpProgress('p5',15);confetti();}
});
document.getElementById('p5-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p5-c-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p5-c-a').value);
const b=parseFloat(document.getElementById('p5-c-b').value);
const h=parseFloat(document.getElementById('p5-c-h').value);
const out=document.getElementById('p5-c-out1');
if(!isFinite(a)||!isFinite(b)||!isFinite(h)||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S=\\dfrac{'+fmt(a)+'+'+fmt(b)+'}{2}\\cdot'+fmt(h)+'='+fmt((a+b)/2*h)+'$';
renderMath(out);addXp(1,'p5-calc1');
});
document.getElementById('p5-c-go2').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p5-c-s2').value);
const h=parseFloat(document.getElementById('p5-c-h2').value);
const b=parseFloat(document.getElementById('p5-c-b2').value);
const out=document.getElementById('p5-c-out2');
if(!isFinite(S)||!isFinite(h)||!isFinite(b)||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$a=\\dfrac{2S}{h}-b='+fmt(2*S/h-b)+'$';
renderMath(out);addXp(1,'p5-calc2');
});
document.getElementById('p5-c-go3').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p5-c-s3').value);
const m=parseFloat(document.getElementById('p5-c-m3').value);
const out=document.getElementById('p5-c-out3');
if(!isFinite(S)||!isFinite(m)||m<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$h=S/m='+fmt(S/m)+'$';
renderMath(out);addXp(1,'p5-calc3');
});
})();
/* == INIT: DnD Sorter == */
(function(){
const items=[
{id:'t1',html:'Трапеция ABCD<br><small>AB∥CD, AD не∥BC</small>',correct:'yes'},
{id:'t2',html:'Прямоугольная трапеция<br><small>один угол 90°</small>',correct:'yes'},
{id:'t3',html:'Равнобедренная трапеция<br><small>боковые стороны равны</small>',correct:'yes'},
{id:'t4',html:'Параллелограмм<br><small>обе пары сторон ∥</small>',correct:'no'},
{id:'t5',html:'Треугольник<br><small>3 стороны</small>',correct:'no'},
{id:'t6',html:'Произвольный 4-уг.<br><small>нет парал. сторон</small>',correct:'no'},
];
const sorter=setupSorter({
poolId:'p5-dnd-pool',
scopeSelector:'#p5-dnd-wg',
items:items,
cats:['yes','no'],
columnLayout:false
});
document.getElementById('p5-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p5-dnd-fb');
const total=items.length;
let correct=0;
items.forEach(it=>{if(sorter.placed[it.id]===it.correct)correct++;});
if(correct===total){
feedback(fb,true,'Все верно! +8 XP');addXp(8,'p5-dnd-ok');bumpProgress('p5',20);confetti();
} else {
feedback(fb,false,'Верно: '+correct+' из '+total+'. Попробуй ещё.');
}
});
document.getElementById('p5-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p5-dnd-fb').style.display='none';});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="20,78 160,78 135,18 45,18" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2"/><line x1="45" y1="18" x2="45" y2="78" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="33" y="51" text-anchor="middle" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=8</text><text x="90" y="92" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 14 см</text><text x="90" y="12" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b = 6</text><text x="110" y="52" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0369a1">S=?</text></svg>Трапеция, основания <b>6 и 14 см</b>, высота <b>8 см</b>. Площадь?', ans:80, hint:'(6+14)/2·8 = 10·8 = 80.'},
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="20,78 160,78 135,18 45,18" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2"/><line x1="45" y1="18" x2="45" y2="78" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="33" y="51" text-anchor="middle" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=9</text><text x="90" y="92" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=7, S=90</text><text x="90" y="12" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b=?</text></svg>Площадь трапеции <b>90 м²</b>, высота <b>9 м</b>, одно основание <b>7 м</b>. Второе основание?', ans:13, hint:'2·90/9 7 = 20 7 = 13.'},
{q:'Средняя линия трапеции <b>11 дм</b>, высота <b>6 дм</b>. Площадь?', ans:66, hint:'S = 11·6 = 66.'},
{q:'<svg viewBox="0 0 160 100" style="display:block;max-width:170px;margin:0 auto 8px;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="15,78 145,78 115,18 15,18" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2"/><polyline points="23,78 23,70 15,70" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="8" y="51" text-anchor="middle" dominant-baseline="middle" font-size="9" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,51)">h=4</text><text x="80" y="92" text-anchor="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 9 см</text><text x="65" y="12" text-anchor="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b = 5</text><text x="90" y="52" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0369a1">S=?</text></svg>Прямоугольная трапеция: основания <b>5 и 9 см</b>, высота <b>4 см</b>. Площадь?', ans:28, hint:'(5+9)/2·4 = 7·4 = 28.'},
{q:'Площадь трапеции <b>108 см²</b>, средняя линия <b>12 см</b>. Высота?', ans:9, hint:'h = 108/12 = 9.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p5-tr-i').textContent=idx+1;
document.getElementById('p5-tr-task').innerHTML=tasks[idx].q;
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.5){
score++;document.getElementById('p5-tr-score').textContent=score;
addXp(3,'p5-tr-'+idx);bumpProgress('p5',5);
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);}
} 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: Босс §5 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="15,78 165,78 145,18 35,18" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2"/><line x1="35" y1="18" x2="35" y2="78" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="24" y="51" text-anchor="middle" font-size="9" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=9</text><text x="90" y="92" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a = 20 дм</text><text x="90" y="12" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b = 10</text><text x="110" y="52" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0369a1">S=?</text></svg>Трапеция, основания <b>20 и 10 дм</b>, высота <b>9 дм</b>. Площадь?', ans:135, hint:'(20+10)/2·9 = 15·9 = 135.'},
{q:'<svg viewBox="0 0 180 100" style="display:block;max-width:190px;margin:0 auto 8px;background:#e0f2fe;border:1px solid #7dd3fc;border-radius:8px"><polygon points="15,78 165,78 145,18 35,18" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2"/><line x1="35" y1="18" x2="35" y2="78" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><text x="24" y="51" text-anchor="middle" font-size="9" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h=?</text><text x="90" y="92" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=18, S=150</text><text x="90" y="12" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b = 12</text></svg>Площадь трапеции <b>150 м²</b>, основания <b>12 и 18 м</b>. Высота?', ans:10, hint:'h = 2·150/(12+18) = 300/30 = 10.'},
{q:'Равнобедренная трапеция с основаниями <b>8 и 16 см</b> вписана между двумя параллельными прямыми на расстоянии <b>6 см</b>. Площадь?', ans:72, hint:'(8+16)/2·6 = 12·6 = 72.'},
{q:'Средняя линия трапеции <b>15 см</b>. При высоте <b>8 см</b> найти площадь.', ans:120, hint:'S = 15·8 = 120.'},
];
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.5){
feedback(fb,true,'Верно! +5 XP');
if(!p5BossSolved.has(${i})){ p5BossSolved.add(${i}); addXp(5,'p5-boss${i}'); bumpProgress('p5',10); }
} 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();
})();
/* == MINI-SLIDER: Трапеция == */
(function(){
const W=290, H=190;
function draw(){
let a=+document.getElementById('p5-sl-a').value;
let b=+document.getElementById('p5-sl-b').value;
const h=+document.getElementById('p5-sl-h').value;
if(b>a){ b=a; document.getElementById('p5-sl-b').value=a; }
document.getElementById('p5-sl-a-val').textContent=a;
document.getElementById('p5-sl-b-val').textContent=b;
document.getElementById('p5-sl-h-val').textContent=h;
const S=+((a+b)/2*h).toFixed(1);
const sc=Math.min(240/a,11,130/h);
const aw=Math.round(a*sc), bw=Math.round(b*sc), ph=Math.round(h*sc);
const ox=Math.round((W-aw)/2), oy=Math.round((H-ph)/2);
const offset=Math.round((aw-bw)/2);
// trapezoid: bottom (aw wide), top (bw wide, centered)
const pts=[(ox)+','+(oy+ph),(ox+aw)+','+(oy+ph),(ox+offset+bw)+','+oy,(ox+offset)+','+oy].join(' ');
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:310px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
s+='<polygon points="'+pts+'" fill="rgba(5,150,105,.2)" stroke="#059669" stroke-width="2.5"/>';
// midline dashed
const mx1=Math.round(ox+(aw-bw)/4), mx2=Math.round(ox+aw-(aw-bw)/4);
const my=Math.round(oy+ph/2);
s+='<line x1="'+mx1+'" y1="'+my+'" x2="'+mx2+'" y2="'+my+'" stroke="#059669" stroke-width="1.5" stroke-dasharray="5 3"/>';
// height dashed
s+='<line x1="'+ox+'" y1="'+(oy+ph)+'" x2="'+ox+'" y2="'+oy+'" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="5 3"/>';
s+='<polyline points="'+(ox+6)+','+oy+' '+(ox+6)+','+(oy+6)+' '+ox+','+(oy+6)+'" fill="none" stroke="#f59e0b" stroke-width="1.2"/>';
// labels
s+='<text x="'+(ox+aw/2)+'" y="'+(oy+ph+14)+'" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(ox+offset+bw/2)+'" y="'+(oy-5)+'" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b='+b+'</text>';
s+='<text x="'+(ox-14)+'" y="'+(oy+ph/2)+'" text-anchor="end" dominant-baseline="middle" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h='+h+'</text>';
s+='<text x="'+(ox+aw/2)+'" y="'+(oy+ph/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S='+S+'</text>';
s+='</svg>';
document.getElementById('p5-sl-svg-wrap').innerHTML=s;
document.getElementById('p5-sl-info').innerHTML='<div><b>a</b> = '+a+'</div><div><b>b</b> = '+b+'</div><div><b>h</b> = '+h+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>S = (a+b)/2·h = '+S+'</b></div>';
}
document.getElementById('p5-sl-a').addEventListener('input',draw);
document.getElementById('p5-sl-b').addEventListener('input',draw);
document.getElementById('p5-sl-h').addEventListener('input',draw);
draw();
})();
}
/* ============================================================
§6 — ПЛОЩАДЬ РОМБА
============================================================ */
function buildP6(){
const box=document.getElementById('p6-body');
let html='';
html+=makeCard('theory','Площадь ромба','6.1',`
<p>Ромб — параллелограмм со всеми равными сторонами. Его диагонали <b>взаимно перпендикулярны</b> и делятся пополам.</p>
<p style="margin-top:8px"><b>Формулы площади ромба:</b></p>
<ul style="margin-left:18px;margin-top:6px;line-height:2">
<li>Через диагонали: $S = \\dfrac{d_1 \\cdot d_2}{2}$</li>
<li>Как параллелограмм: $S = a \\cdot h$</li>
<li>Через угол: $S = a^2 \\sin\\alpha$</li>
</ul>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 180" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- rhombus with d1 (horizontal) and d2 (vertical) labeled, perpendicular mark -->
<polygon points="50,90 140,30 230,90 140,150" fill="rgba(99,102,241,.13)" stroke="#4f46e5" stroke-width="2.5" stroke-linejoin="round"/>
<!-- diagonals -->
<line x1="50" y1="90" x2="230" y2="90" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="6 3"/>
<line x1="140" y1="30" x2="140" y2="150" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="6 3"/>
<!-- right angle mark at center -->
<polyline points="148,90 148,82 140,82" fill="none" stroke="#6366f1" stroke-width="1.5"/>
<!-- labels -->
<text x="140" y="174" text-anchor="middle" font-size="12" font-weight="700" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁ (горизонталь)</text>
<text x="240" y="90" dominant-baseline="middle" font-size="12" font-weight="700" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂</text>
<text x="140" y="96" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#4338ca" font-family="Unbounded,sans-serif">S=d₁d₂/2</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство $S = d_1 d_2 / 2$','6.2',`
<p>Диагонали ромба делят его на <b>4 равных прямоугольных треугольника</b> с катетами $d_1/2$ и $d_2/2$.</p>
<p style="margin-top:6px">Площадь одного треугольника: $S_{\\triangle} = \\dfrac{1}{2} \\cdot \\dfrac{d_1}{2} \\cdot \\dfrac{d_2}{2} = \\dfrac{d_1 d_2}{8}$.</p>
<p style="margin-top:6px">Ромб состоит из 4 таких треугольников: $S = 4 \\cdot \\dfrac{d_1 d_2}{8} = \\dfrac{d_1 d_2}{2}$. $\\square$</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 160" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- rhombus divided into 4 triangles, each colored -->
<polygon points="130,20 230,80 130,140 30,80" fill="none" stroke="#4f46e5" stroke-width="2"/>
<!-- 4 triangles colored -->
<polygon points="130,80 30,80 130,20" fill="rgba(99,102,241,.22)" stroke="#6366f1" stroke-width="1"/>
<polygon points="130,80 130,20 230,80" fill="rgba(99,102,241,.14)" stroke="#6366f1" stroke-width="1"/>
<polygon points="130,80 230,80 130,140" fill="rgba(99,102,241,.22)" stroke="#6366f1" stroke-width="1"/>
<polygon points="130,80 130,140 30,80" fill="rgba(99,102,241,.14)" stroke="#6366f1" stroke-width="1"/>
<!-- diagonals -->
<line x1="30" y1="80" x2="230" y2="80" stroke="#4f46e5" stroke-width="1.5"/>
<line x1="130" y1="20" x2="130" y2="140" stroke="#4f46e5" stroke-width="1.5"/>
<!-- right angle at center -->
<polyline points="138,80 138,72 130,72" fill="none" stroke="#4338ca" stroke-width="1.5"/>
<!-- labels: d1/2 and d2/2 -->
<text x="80" y="76" text-anchor="middle" font-size="10" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁/2</text>
<text x="136" y="52" font-size="10" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂/2</text>
<text x="130" y="154" text-anchor="middle" font-size="11" font-weight="700" fill="#4338ca" font-family="JetBrains Mono,monospace">4 × d₁d₂/8 = d₁d₂/2</text>
</svg>
</div>`);
html+=makeCard('example','Примеры','6.3',`
<p><b>Диагонали ромба 10 и 24 см. Площадь?</b><br>$S=\\dfrac{10 \\cdot 24}{2}=120\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>Сторона ромба 8 м, острый угол 30°. Площадь?</b><br>$S=8^2 \\sin 30°=64 \\cdot 0{,}5=32\\,\\text{м}^2$.</p>
<p style="margin-top:8px"><b>S = 48 дм², $d_1=8$ дм. Найти $d_2$.</b><br>$d_2=\\dfrac{2S}{d_1}=\\dfrac{96}{8}=12\\,\\text{дм}$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 150" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- rhombus d1=10, d2=24 example scaled -->
<polygon points="130,10 205,75 130,140 55,75" fill="rgba(99,102,241,.16)" stroke="#4f46e5" stroke-width="2.5"/>
<line x1="55" y1="75" x2="205" y2="75" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>
<line x1="130" y1="10" x2="130" y2="140" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>
<polyline points="138,75 138,67 130,67" fill="none" stroke="#6366f1" stroke-width="1.5"/>
<text x="85" y="71" text-anchor="middle" font-size="11" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁=10</text>
<text x="148" y="45" font-size="11" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂=24</text>
<text x="130" y="82" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#4338ca" font-family="Unbounded,sans-serif">S=120</text>
</svg>
</div>`);
/* INTERACTIVE 1 — Draggable ромб */
html+=`<div class="wg" id="p6-rhomb-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Ромб с перетаскиванием</div></div>
<div class="wg-help">Тащи правый конец горизонтальной диагонали (синяя точка) или нижний конец вертикальной (фиолетовая точка). Диагонали всегда перпендикулярны. $S = d_1 \\cdot d_2 / 2$.</div>
<div id="p6-rhomb-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p6-rhomb-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* INTERACTIVE 2 — Анимация доказательства */
html+=`<div class="wg" id="p6-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство: ромб → прямоугольник</div></div>
<div class="wg-help">Нажимай «Далее» и смотри, как ромб разбивается на треугольники и складывается в прямоугольник $d_1 \\times d_2/2$.</div>
<div id="p6-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p6-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p6-proof-next">Далее</button>
<button class="btn" id="p6-proof-reset">Сначала</button>
</div>
</div>`;
/* INTERACTIVE 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">Три формулы на выбор.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$d_1, d_2 \\to S$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p6-c-d1" class="tinp" placeholder="d₁" style="width:65px">
<input type="number" id="p6-c-d2" class="tinp" placeholder="d₂" style="width:65px">
<button class="btn primary" id="p6-c-go1">=S</button>
</div>
<div id="p6-c-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$a, h \\to S$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p6-c-a2" class="tinp" placeholder="a" style="width:65px">
<input type="number" id="p6-c-h2" class="tinp" placeholder="h" style="width:65px">
<button class="btn primary" id="p6-c-go2">=S</button>
</div>
<div id="p6-c-out2" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$a, \\alpha° \\to S$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p6-c-a3" class="tinp" placeholder="a" style="width:65px">
<input type="number" id="p6-c-al3" class="tinp" placeholder="α°" style="width:65px">
<button class="btn primary" id="p6-c-go3">=S</button>
</div>
<div id="p6-c-out3" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* INTERACTIVE 4 — DnD */
html+=`<div class="wg" id="p6-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Сопоставь ромб с площадью</div></div>
<div class="wg-help">Перетащи каждое описание к правильной площади.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-bottom:10px">
<div class="drop-zone"><div style="font-weight:700;color:#6366f1;margin-bottom:4px;font-size:.82rem">S = 24</div><div class="drop-box" style="min-height:60px;border:2px dashed #6366f1;border-radius:8px;padding:6px"><div data-cat="24" style="display:none"></div><div class="drop-items" data-cat="24" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
<div class="drop-zone"><div style="font-weight:700;color:#6366f1;margin-bottom:4px;font-size:.82rem">S = 30</div><div class="drop-box" style="min-height:60px;border:2px dashed #6366f1;border-radius:8px;padding:6px"><div data-cat="30" style="display:none"></div><div class="drop-items" data-cat="30" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
<div class="drop-zone"><div style="font-weight:700;color:#6366f1;margin-bottom:4px;font-size:.82rem">S = 50</div><div class="drop-box" style="min-height:60px;border:2px dashed #6366f1;border-radius:8px;padding:6px"><div data-cat="50" style="display:none"></div><div class="drop-items" data-cat="50" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
<div class="drop-zone"><div style="font-weight:700;color:#6366f1;margin-bottom:4px;font-size:.82rem">S = 72</div><div class="drop-box" style="min-height:60px;border:2px dashed #6366f1;border-radius:8px;padding:6px"><div data-cat="72" style="display:none"></div><div class="drop-items" data-cat="72" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
</div>
<div id="p6-dnd-pool" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn primary" id="p6-dnd-check">Проверить</button>
<button class="btn" id="p6-dnd-reset">Сбросить</button>
</div>
<div class="feedback" id="p6-dnd-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* MINI-SLIDER: Ромб */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Ромб — меняй диагонали</div></div>
<div class="wg-help">$S = \\dfrac{d_1 \\cdot d_2}{2}$ — площадь ромба через диагонали.</div>
<div class="sliders">
<label>Диагональ d₁ = <b id="p6-sl-d1-val">10</b>
<input type="range" min="2" max="24" value="10" id="p6-sl-d1">
</label>
<label>Диагональ d₂ = <b id="p6-sl-d2-val">8</b>
<input type="range" min="2" max="24" value="8" id="p6-sl-d2">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p6-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p6-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* INTERACTIVE 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Тренажёр §6</div></div>
<div class="wg-help">5 задач на площадь ромба.</div>
<div class="score-display"><span>Задача <b id="p6-tr-i">1</b> / 5</span><span>Очки: <b id="p6-tr-score">0</b></span></div>
<div id="p6-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p6-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p6-tr-go">Проверить</button>
<button class="btn" id="p6-tr-start">Начать</button>
</div>
<div class="feedback" id="p6-tr-fb" style="display:none"></div>
</div>`;
/* INTERACTIVE 6 — Босс */
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))">БОСС §6</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p6-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p6-read-btn" onclick="addXp(10,'p6-read');bumpProgress('p6',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>
Я прочитал §6 (+10 XP)
</button>
</div>`;
html+=secNav('p5','p7');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable ромб == */
(function(){
const W=380, H=280;
const CX=190, CY=140;
let d1h=110, d2h=85;
function draw(){
const d1=d1h*2, d2=d2h*2;
const ax=CX-d1h, ay=CY, bx=CX, by=CY-d2h, cx=CX+d1h, cy=CY, dx=CX, dy=CY+d2h;
const sideLen=Math.round(Math.sqrt(d1h*d1h+d2h*d2h));
const Sval=Math.round(d1*d2/2);
let s='<svg id="p6-rhomb-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:400px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// diagonals
s+='<line x1="'+ax+'" y1="'+ay+'" x2="'+cx+'" y2="'+cy+'" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>';
s+='<line x1="'+bx+'" y1="'+by+'" x2="'+dx+'" y2="'+dy+'" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>';
// right angle at center
s+='<polyline points="'+(CX+8)+','+CY+' '+(CX+8)+','+(CY-8)+' '+CX+','+(CY-8)+'" fill="none" stroke="#6366f1" stroke-width="1.5"/>';
// rhombus
s+='<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+' '+dx+','+dy+'" fill="rgba(99,102,241,.15)" stroke="#4f46e5" stroke-width="2.5" stroke-linejoin="round"/>';
// labels
s+='<text x="'+((ax+CX)/2-8)+'" y="'+(CY-6)+'" font-size="11" font-weight="700" fill="#4f46e5" font-family="JetBrains Mono,monospace">d₁='+d1+'</text>';
s+='<text x="'+(CX+6)+'" y="'+((CY+dy)/2)+'" font-size="11" font-weight="700" fill="#4f46e5" font-family="JetBrains Mono,monospace">d₂='+d2+'</text>';
s+='<text x="'+CX+'" y="'+CY+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#4338ca" font-family="Unbounded,sans-serif">S='+Sval+'</text>';
s+='<text x="'+(CX+d1h/2)+'" y="'+(CY-d2h/2-6)+'" font-size="10" fill="#6366f1" font-family="JetBrains Mono,monospace">a='+sideLen+'</text>';
// drag handles
s+='<circle cx="'+cx+'" cy="'+cy+'" r="12" fill="rgba(99,102,241,.18)"/>';
s+='<circle cx="'+cx+'" cy="'+cy+'" r="7" fill="#6366f1" stroke="#fff" stroke-width="2" id="p6-drag-d1" style="cursor:ew-resize"/>';
s+='<circle cx="'+dx+'" cy="'+dy+'" r="12" fill="rgba(124,58,237,.18)"/>';
s+='<circle cx="'+dx+'" cy="'+dy+'" r="7" fill="#7c3aed" stroke="#fff" stroke-width="2" id="p6-drag-d2" style="cursor:ns-resize"/>';
s+='</svg>';
document.getElementById('p6-rhomb-svg-wrap').innerHTML=s;
document.getElementById('p6-rhomb-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">d₁</div><b>${d1}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">d₂</div><b>${d2}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Сторона a</div><b>${sideLen}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S = d₁·d₂/2</div><b style="color:#4338ca">${Sval}</b></div>`;
const hD1=document.getElementById('p6-drag-d1');
if(hD1){
hD1.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startD=d1h;
function onMove(e){
const svgEl=document.getElementById('p6-rhomb-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
const delta=Math.round((e.clientX-startX)*scale);
d1h=Math.max(40,Math.min(160,startD+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
const hD2=document.getElementById('p6-drag-d2');
if(hD2){
hD2.addEventListener('pointerdown',ev=>{
const startY=ev.clientY, startD=d2h;
function onMove(e){
const svgEl=document.getElementById('p6-rhomb-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=H/rect.height;
const delta=Math.round((e.clientY-startY)*scale);
d2h=Math.max(30,Math.min(120,startD+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Анимация доказательства == */
(function(){
let step=0;
const W=400, H=240;
const cx=200, cy=120, d1h=110, d2h=80;
const steps=[
{desc:'Исходный ромб ABCD. Диагонали $d_1$ и $d_2$ пересекаются под прямым углом и делятся пополам.',
draw(){
const ax=cx-d1h, ay=cy, bx=cx, by=cy-d2h, rx=cx+d1h, ry=cy, dx=cx, dy=cy+d2h;
return '<polygon points="'+ax+','+ay+' '+bx+','+by+' '+rx+','+ry+' '+dx+','+dy+'" fill="rgba(99,102,241,.18)" stroke="#4f46e5" stroke-width="2.2"/>'
+'<line x1="'+ax+'" y1="'+ay+'" x2="'+rx+'" y2="'+ry+'" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="4 3"/>'
+'<line x1="'+bx+'" y1="'+by+'" x2="'+dx+'" y2="'+dy+'" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="4 3"/>'
+'<text x="'+(cx+6)+'" y="'+(cy-d2h/2)+'" font-size="11" fill="#4f46e5" font-weight="700" font-family="JetBrains Mono,monospace">d₂/2</text>'
+'<text x="'+(cx+d1h/2)+'" y="'+(cy+14)+'" text-anchor="middle" font-size="11" fill="#4f46e5" font-weight="700" font-family="JetBrains Mono,monospace">d₁/2</text>';
}},
{desc:'Делим ромб на 4 прямоугольных треугольника с катетами $d_1/2$ и $d_2/2$.',
draw(){
const ax=cx-d1h, ay=cy, bx=cx, by=cy-d2h, rx=cx+d1h, ry=cy, dx=cx, dy=cy+d2h;
const cols=['rgba(99,102,241,.3)','rgba(124,58,237,.3)','rgba(2,132,199,.3)','rgba(5,150,105,.3)'];
const strokes=['#6366f1','#7c3aed','#0284c7','#059669'];
const tris=[[ax,ay,bx,by,cx,cy],[bx,by,rx,ry,cx,cy],[rx,ry,dx,dy,cx,cy],[dx,dy,ax,ay,cx,cy]];
return tris.map((t,i)=>'<polygon points="'+t[0]+','+t[1]+' '+t[2]+','+t[3]+' '+t[4]+','+t[5]+'" fill="'+cols[i]+'" stroke="'+strokes[i]+'" stroke-width="1.8"/>').join('');
}},
{desc:'Верхние два треугольника переворачиваем и прикладываем к нижним — получается прямоугольник!',
draw(){
const rx2=cx-d1h+d1h*2, ry2=cy+d2h;
return '<rect x="'+(cx-d1h)+'" y="'+cy+'" width="'+(d1h*2)+'" height="'+d2h+'" fill="rgba(5,150,105,.22)" stroke="#059669" stroke-width="2.5"/>'
+'<text x="'+cx+'" y="'+(cy-10)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">d₁='+(d1h*2)+'</text>'
+'<text x="'+(cx+d1h+12)+'" y="'+(cy+d2h/2)+'" dominant-baseline="middle" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">d₂/2='+d2h+'</text>'
+'<text x="'+cx+'" y="'+(cy+d2h/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">прямоуг.</text>';
}},
{desc:'Прямоугольник $d_1 \\times (d_2/2)$, его площадь $d_1 \\cdot d_2 / 2$ — это и есть площадь ромба!',
draw(){
return '<rect x="'+(cx-d1h)+'" y="'+cy+'" width="'+(d1h*2)+'" height="'+d2h+'" fill="rgba(5,150,105,.28)" stroke="#059669" stroke-width="2.5"/>'
+'<text x="'+cx+'" y="'+(cy+d2h/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S = d₁·d₂/2</text>';
}},
];
function render(){
const s=steps[step];
document.getElementById('p6-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:420px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p6-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p6-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement) renderMath(document.getElementById('p6-proof-desc'));
}
document.getElementById('p6-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p6-proof-step');}
else{addXp(3,'p6-proof-done');bumpProgress('p6',15);confetti();}
});
document.getElementById('p6-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p6-c-go1').addEventListener('click',()=>{
const d1=parseFloat(document.getElementById('p6-c-d1').value);
const d2=parseFloat(document.getElementById('p6-c-d2').value);
const out=document.getElementById('p6-c-out1');
if(!isFinite(d1)||!isFinite(d2)||d1<=0||d2<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S=\\dfrac{'+fmt(d1)+'\\cdot'+fmt(d2)+'}{2}='+fmt(d1*d2/2)+'$';
renderMath(out);addXp(1,'p6-calc1');
});
document.getElementById('p6-c-go2').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p6-c-a2').value);
const h=parseFloat(document.getElementById('p6-c-h2').value);
const out=document.getElementById('p6-c-out2');
if(!isFinite(a)||!isFinite(h)||a<=0||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S='+fmt(a)+'\\cdot'+fmt(h)+'='+fmt(a*h)+'$';
renderMath(out);addXp(1,'p6-calc2');
});
document.getElementById('p6-c-go3').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p6-c-a3').value);
const al=parseFloat(document.getElementById('p6-c-al3').value);
const out=document.getElementById('p6-c-out3');
if(!isFinite(a)||!isFinite(al)||a<=0||al<=0||al>=180){out.innerHTML='<span style="color:var(--bad)">Введи a > 0 и 0 < α < 180.</span>';return;}
const sinA=Math.sin(al*Math.PI/180);
out.innerHTML='$S='+fmt(a)+'^2\\cdot\\sin '+fmt(al)+'°='+fmt(+(a*a*sinA).toFixed(4))+'$';
renderMath(out);addXp(1,'p6-calc3');
});
})();
/* == INIT: DnD Sorter == */
(function(){
const items=[
{id:'r1',html:'$d_1=6,\\;d_2=8$',correct:'24'},
{id:'r2',html:'$d_1=5,\\;d_2=12$',correct:'30'},
{id:'r3',html:'$d_1=10,\\;d_2=10$',correct:'50'},
{id:'r4',html:'$a=9,\\;h=8$',correct:'72'},
];
const sorter=setupSorter({
poolId:'p6-dnd-pool',
scopeSelector:'#p6-dnd-wg',
items:items,
cats:['24','30','50','72'],
columnLayout:false
});
document.getElementById('p6-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p6-dnd-fb');
let correct=0;
items.forEach(it=>{if(sorter.placed[it.id]===it.correct)correct++;});
if(correct===items.length){
feedback(fb,true,'Все верно! +8 XP');addXp(8,'p6-dnd-ok');bumpProgress('p6',20);confetti();
} else {
feedback(fb,false,'Верно: '+correct+' из '+items.length+'.');
}
});
document.getElementById('p6-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p6-dnd-fb').style.display='none';});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 160 120" style="display:block;max-width:170px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="80,10 150,60 80,110 10,60" fill="rgba(99,102,241,.2)" stroke="#4f46e5" stroke-width="2"/><line x1="10" y1="60" x2="150" y2="60" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><line x1="80" y1="10" x2="80" y2="110" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><polyline points="88,60 88,52 80,52" fill="none" stroke="#6366f1" stroke-width="1.2"/><text x="80" y="56" text-anchor="middle" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁=12</text><text x="95" y="35" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂=16</text><text x="80" y="66" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#4338ca">S=?</text></svg>Диагонали ромба <b>12 и 16 см</b>. Площадь?', ans:96, hint:'12·16/2 = 96.'},
{q:'<svg viewBox="0 0 160 120" style="display:block;max-width:170px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="80,10 150,60 80,110 10,60" fill="rgba(99,102,241,.2)" stroke="#4f46e5" stroke-width="2"/><line x1="10" y1="60" x2="150" y2="60" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><line x1="80" y1="10" x2="80" y2="110" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><text x="80" y="54" text-anchor="middle" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁=10</text><text x="95" y="35" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂=?</text><text x="40" y="66" text-anchor="middle" font-size="9" fill="#4338ca">S=60</text></svg>Площадь ромба <b>60 м²</b>, одна диагональ <b>10 м</b>. Другая диагональ?', ans:12, hint:'d₂ = 2·60/10 = 12.'},
{q:'Сторона ромба <b>5 см</b>, высота <b>4 см</b>. Площадь?', ans:20, hint:'S = 5·4 = 20.'},
{q:'Сторона ромба <b>10 дм</b>, острый угол <b>30°</b>. Площадь?', ans:50, hint:'S = 100·sin30° = 100·0,5 = 50.'},
{q:'<svg viewBox="0 0 160 120" style="display:block;max-width:170px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="80,10 150,60 80,110 10,60" fill="rgba(99,102,241,.2)" stroke="#4f46e5" stroke-width="2"/><line x1="10" y1="60" x2="150" y2="60" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><line x1="80" y1="10" x2="80" y2="110" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><text x="80" y="54" text-anchor="middle" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁=8</text><text x="95" y="35" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂=15</text><text x="80" y="66" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#4338ca">S=?</text></svg>Диагонали ромба <b>8 и 15 см</b>. Площадь? (и чему равна сторона?)', ans:60, hint:'S = 8·15/2 = 60. Сторона = √(16+56,25) = 8,5.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p6-tr-i').textContent=idx+1;
document.getElementById('p6-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p6-tr-ans').value='';
document.getElementById('p6-tr-fb').style.display='none';
}
document.getElementById('p6-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p6-tr-score').textContent=0;show();});
document.getElementById('p6-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p6-tr-ans').value;
const fb=document.getElementById('p6-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p6-tr-score').textContent=score;
addXp(3,'p6-tr-'+idx);bumpProgress('p6',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p6-tr-all');bumpProgress('p6',10);}
} else {feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p6-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p6-tr-go').click();});
show();
})();
/* == INIT: Босс §6 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 160 120" style="display:block;max-width:170px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="80,10 150,60 80,110 10,60" fill="rgba(99,102,241,.2)" stroke="#4f46e5" stroke-width="2"/><line x1="10" y1="60" x2="150" y2="60" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><line x1="80" y1="10" x2="80" y2="110" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><text x="80" y="54" text-anchor="middle" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁=18</text><text x="95" y="35" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂=24</text><text x="80" y="66" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#4338ca">S=?</text></svg>Ромб, диагонали <b>18 и 24 дм</b>. Площадь?', ans:216, hint:'18·24/2 = 216.'},
{q:'Площадь ромба <b>98 м²</b>. Диагонали равны. Найти каждую диагональ.', ans:14, hint:'d²/2=98 → d²=196 → d=14.'},
{q:'<svg viewBox="0 0 160 120" style="display:block;max-width:170px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="80,8 155,60 80,112 5,60" fill="rgba(99,102,241,.2)" stroke="#4f46e5" stroke-width="2"/><line x1="5" y1="60" x2="155" y2="60" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><line x1="80" y1="8" x2="80" y2="112" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/><text x="80" y="54" text-anchor="middle" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₁=10</text><text x="95" y="30" font-size="9" fill="#4338ca" font-family="JetBrains Mono,monospace">d₂=?</text><text x="28" y="60" text-anchor="middle" dominant-baseline="middle" font-size="8" fill="#4338ca">a=13</text><text x="80" y="66" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#4338ca">S=?</text></svg>Сторона ромба <b>13 см</b>, меньшая диагональ <b>10 см</b>. Площадь?', ans:120, hint:'d₂/2=√(16925)=12, d₂=24. S=10·24/2=120.'},
{q:'Сторона ромба <b>8 дм</b>, угол <b>60°</b>. Площадь?', ans:Math.round(64*Math.sin(60*Math.PI/180)), hint:'S = 64·sin60° ≈ 55.'},
];
const bossBox=document.getElementById('p6-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="p6b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p6b-a${i}').value;
const fb=document.getElementById('p6b-fb${i}');
if(Math.abs(v-${t.ans})<0.5){
feedback(fb,true,'Верно! +5 XP');
if(!p6BossSolved.has(${i})){ p6BossSolved.add(${i}); addXp(5,'p6-boss${i}'); bumpProgress('p6',10); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p6b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p6BossSolved=new Set();
})();
/* == MINI-SLIDER: Ромб == */
(function(){
const W=290, H=210;
function draw(){
const d1=+document.getElementById('p6-sl-d1').value;
const d2=+document.getElementById('p6-sl-d2').value;
document.getElementById('p6-sl-d1-val').textContent=d1;
document.getElementById('p6-sl-d2-val').textContent=d2;
const S=+(d1*d2/2).toFixed(1);
const side=+Math.sqrt((d1/2)*(d1/2)+(d2/2)*(d2/2)).toFixed(1);
const sc=Math.min(220/d1,9,160/d2);
const rh=Math.round(d1*sc/2), rv=Math.round(d2*sc/2);
const cx=Math.round(W/2), cy=Math.round(H/2);
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:310px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
s+='<polygon points="'+(cx-rh)+','+cy+' '+cx+','+(cy-rv)+' '+(cx+rh)+','+cy+' '+cx+','+(cy+rv)+'" fill="rgba(99,102,241,.18)" stroke="#6366f1" stroke-width="2.5"/>';
// diagonals dashed
s+='<line x1="'+(cx-rh)+'" y1="'+cy+'" x2="'+(cx+rh)+'" y2="'+cy+'" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>';
s+='<line x1="'+cx+'" y1="'+(cy-rv)+'" x2="'+cx+'" y2="'+(cy+rv)+'" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>';
// right angle
s+='<polyline points="'+(cx+7)+','+cy+' '+(cx+7)+','+(cy-7)+' '+cx+','+(cy-7)+'" fill="none" stroke="#6366f1" stroke-width="1.3"/>';
s+='<text x="'+cx+'" y="'+cy+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#4338ca" font-family="Unbounded,sans-serif">S='+S+'</text>';
s+='<text x="'+(cx+rh/2)+'" y="'+(cy-6)+'" text-anchor="middle" font-size="10" font-weight="700" fill="#4f46e5" font-family="JetBrains Mono,monospace">d₁='+d1+'</text>';
s+='<text x="'+(cx+7)+'" y="'+(cy-rv/2)+'" dominant-baseline="middle" font-size="10" font-weight="700" fill="#4f46e5" font-family="JetBrains Mono,monospace">d₂='+d2+'</text>';
s+='</svg>';
document.getElementById('p6-sl-svg-wrap').innerHTML=s;
document.getElementById('p6-sl-info').innerHTML='<div><b>d₁</b> = '+d1+'</div><div><b>d₂</b> = '+d2+'</div><div><b>a</b> = '+side+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>S = d₁·d₂/2 = '+S+'</b></div>';
}
document.getElementById('p6-sl-d1').addEventListener('input',draw);
document.getElementById('p6-sl-d2').addEventListener('input',draw);
draw();
})();
}
/* ============================================================
§7 — ПЛОЩАДЬ ПРЯМОУГОЛЬНОГО ТРЕУГОЛЬНИКА
============================================================ */
function buildP7(){
const box=document.getElementById('p7-body');
let html='';
html+=makeCard('theory','Площадь прямоугольного треугольника','7.1',`
<p>В прямоугольном треугольнике катеты $a$ и $b$ являются <b>высотами друг к другу</b> (прямой угол между ними).</p>
<p style="margin-top:8px"><b>Формула:</b></p>
$$S = \\dfrac{1}{2} a \\cdot b$$
<p style="margin-top:6px">где $a, b$ — катеты.</p>
<p style="margin-top:8px">Через гипотенузу и высоту к ней: $S = \\dfrac{1}{2} c \\cdot h_c$, где $c$ — гипотенуза, $h_c$ — высота к гипотенузе.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 240 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- right triangle with catheti a, b and right angle mark -->
<polygon points="30,130 190,130 30,30" fill="rgba(124,58,237,.14)" stroke="#7c3aed" stroke-width="2.5"/>
<!-- right angle mark -->
<polyline points="44,130 44,116 30,116" fill="none" stroke="#7c3aed" stroke-width="1.8"/>
<!-- labels -->
<text x="110" y="148" text-anchor="middle" font-size="13" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a (катет)</text>
<text x="14" y="80" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,14,80)">b (катет)</text>
<text x="120" y="90" font-size="10" fill="#6d28d9" font-family="JetBrains Mono,monospace">c (гипотенуза)</text>
<!-- S label -->
<text x="85" y="105" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#4c1d95" font-family="Unbounded,sans-serif">S=ab/2</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство','7.2',`
<p>Прямоугольный треугольник $\\triangle ABC$ с прямым углом $C$. Достроим до прямоугольника $ABDC$ (добавим точку $D$).</p>
<p style="margin-top:6px">Прямоугольник со сторонами $a$ и $b$ имеет площадь $S_{\\text{прям}} = ab$.</p>
<p style="margin-top:6px">Диагональ прямоугольника делит его на два <b>равных</b> прямоугольных треугольника:</p>
$$S_{\\triangle} = \\dfrac{ab}{2}. \\quad \\square$$
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 140" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- rectangle a×b split by diagonal into 2 right triangles -->
<rect x="30" y="20" width="180" height="100" rx="3" fill="none" stroke="#7c3aed" stroke-width="2"/>
<!-- lower triangle highlighted -->
<polygon points="30,120 210,120 210,20" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="1.5"/>
<!-- upper triangle (copy) -->
<polygon points="30,120 30,20 210,20" fill="rgba(99,102,241,.10)" stroke="#6366f1" stroke-width="1.5" stroke-dasharray="5 3"/>
<!-- diagonal -->
<line x1="30" y1="120" x2="210" y2="20" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="6 3"/>
<!-- right angle marks -->
<polyline points="44,120 44,106 30,106" fill="none" stroke="#7c3aed" stroke-width="1.5"/>
<polyline points="196,20 196,34 210,34" fill="none" stroke="#7c3aed" stroke-width="1.5"/>
<!-- labels -->
<text x="120" y="136" text-anchor="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a</text>
<text x="14" y="70" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,14,70)">b</text>
<text x="155" y="88" font-size="10" fill="#4c1d95">S = ab/2</text>
<text x="60" y="55" font-size="10" fill="#6366f1" opacity="0.7">= ab/2</text>
</svg>
</div>`);
html+=makeCard('example','Примеры','7.3',`
<p><b>Катеты 6 и 8 см. Площадь?</b><br>$S=\\dfrac{6\\cdot8}{2}=24\\,\\text{см}^2$.</p>
<p style="margin-top:8px"><b>S = 40 м², катет 10 м. Другой катет?</b><br>$b=\\dfrac{2S}{a}=\\dfrac{80}{10}=8\\,\\text{м}$.</p>
<p style="margin-top:8px"><b>Гипотенуза 10 дм, высота к ней 6 дм. Площадь?</b><br>$S=\\dfrac{1}{2}\\cdot10\\cdot6=30\\,\\text{дм}^2$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 220 140" style="max-width:240px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- right triangle a=8, b=6 example -->
<polygon points="30,110 190,110 30,30" fill="rgba(124,58,237,.17)" stroke="#7c3aed" stroke-width="2.5"/>
<polyline points="44,110 44,96 30,96" fill="none" stroke="#7c3aed" stroke-width="1.8"/>
<text x="110" y="126" text-anchor="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a = 8 см</text>
<text x="14" y="70" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,14,70)">b = 6</text>
<text x="105" y="88" font-size="10" fill="#6d28d9" font-family="JetBrains Mono,monospace">c=10</text>
<text x="80" y="88" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#4c1d95" font-family="Unbounded,sans-serif">S=24</text>
</svg>
</div>`);
/* INTERACTIVE 1 — Draggable прямоугольный треугольник */
html+=`<div class="wg" id="p7-rt-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Прямоугольный треугольник — тяни катеты</div></div>
<div class="wg-help">Тащи синюю точку (катет a) или фиолетовую точку (катет b). $S = ab/2$ обновляется мгновенно.</div>
<div id="p7-rt-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p7-rt-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* INTERACTIVE 2 — Анимация доказательства */
html+=`<div class="wg" id="p7-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство: достраиваем до прямоугольника</div></div>
<div class="wg-help">Нажимай «Далее» и смотри, как два прямоугольных треугольника складываются в прямоугольник $a \\times b$.</div>
<div id="p7-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p7-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p7-proof-next">Далее</button>
<button class="btn" id="p7-proof-reset">Сначала</button>
</div>
</div>`;
/* INTERACTIVE 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">Три режима.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, b &rarr; S и c</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p7-c-a" class="tinp" placeholder="a" style="width:65px">
<input type="number" id="p7-c-b" class="tinp" placeholder="b" style="width:65px">
<button class="btn primary" id="p7-c-go1">Найти</button>
</div>
<div id="p7-c-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S, a &rarr; b</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p7-c-s2" class="tinp" placeholder="S" style="width:65px">
<input type="number" id="p7-c-a2" class="tinp" placeholder="a" style="width:65px">
<button class="btn primary" id="p7-c-go2">= b</button>
</div>
<div id="p7-c-out2" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">c, h_c &rarr; S</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p7-c-c3" class="tinp" placeholder="c" style="width:65px">
<input type="number" id="p7-c-hc3" class="tinp" placeholder="h_c" style="width:65px">
<button class="btn primary" id="p7-c-go3">= S</button>
</div>
<div id="p7-c-out3" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* MINI-SLIDER: Прямоугольный треугольник */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Прямоугольный треугольник — меняй катеты</div></div>
<div class="wg-help">$S = \\dfrac{a \\cdot b}{2}$ — видно, как площадь зависит от обоих катетов.</div>
<div class="sliders">
<label>Катет a = <b id="p7-sl-a-val">8</b>
<input type="range" min="1" max="18" value="8" id="p7-sl-a">
</label>
<label>Катет b = <b id="p7-sl-b-val">6</b>
<input type="range" min="1" max="18" value="6" id="p7-sl-b">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p7-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p7-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* INTERACTIVE 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §7</div></div>
<div class="wg-help">5 задач на площадь прямоугольного треугольника.</div>
<div class="score-display"><span>Задача <b id="p7-tr-i">1</b> / 5</span><span>Очки: <b id="p7-tr-score">0</b></span></div>
<div id="p7-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p7-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p7-tr-go">Проверить</button>
<button class="btn" id="p7-tr-start">Начать</button>
</div>
<div class="feedback" id="p7-tr-fb" style="display:none"></div>
</div>`;
/* INTERACTIVE 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))">БОСС §7</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p7-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p7-read-btn" onclick="addXp(10,'p7-read');bumpProgress('p7',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>
Я прочитал §7 (+10 XP)
</button>
</div>`;
html+=secNav('p6','p8');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable треугольник == */
(function(){
const W=380, H=280;
const OX=50, OY=230;
let catA=200, catB=150;
function draw(){
const ax=OX, ay=OY, bx=OX+catA, by=OY, cx=OX, cy=OY-catB;
const hypLen=Math.round(Math.sqrt(catA*catA+catB*catB));
const Sval=Math.round(catA*catB/2);
let s='<svg id="p7-rt-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:400px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// right angle mark
s+='<polyline points="'+(ax+12)+','+ay+' '+(ax+12)+','+(ay-12)+' '+ax+','+(ay-12)+'" fill="none" stroke="#7c3aed" stroke-width="1.8"/>';
// triangle
s+='<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(124,58,237,.14)" stroke="#7c3aed" stroke-width="2.5" stroke-linejoin="round"/>';
// labels
s+='<text x="'+((ax+bx)/2)+'" y="'+(ay+18)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a='+catA+'</text>';
s+='<text x="'+(ax-18)+'" y="'+((ay+cy)/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">b='+catB+'</text>';
s+='<text x="'+((bx+cx)/2+14)+'" y="'+((by+cy)/2)+'" font-size="10" fill="#6d28d9" font-family="JetBrains Mono,monospace">c='+hypLen+'</text>';
s+='<text x="'+Math.round((ax+bx+cx)/3)+'" y="'+Math.round((ay+by+cy)/3)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#4c1d95" font-family="Unbounded,sans-serif">S='+Sval+'</text>';
// drag handle a
s+='<circle cx="'+bx+'" cy="'+by+'" r="12" fill="rgba(124,58,237,.18)"/>';
s+='<circle cx="'+bx+'" cy="'+by+'" r="7" fill="#7c3aed" stroke="#fff" stroke-width="2" id="p7-drag-a" style="cursor:ew-resize"/>';
// drag handle b
s+='<circle cx="'+cx+'" cy="'+cy+'" r="12" fill="rgba(99,102,241,.18)"/>';
s+='<circle cx="'+cx+'" cy="'+cy+'" r="7" fill="#6366f1" stroke="#fff" stroke-width="2" id="p7-drag-b" style="cursor:ns-resize"/>';
s+='</svg>';
document.getElementById('p7-rt-svg-wrap').innerHTML=s;
document.getElementById('p7-rt-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Катет a</div><b>${catA}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Катет b</div><b>${catB}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Гипотенуза c</div><b>${hypLen}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S = ab/2</div><b style="color:#4c1d95">${Sval}</b></div>`;
const hA=document.getElementById('p7-drag-a');
if(hA){
hA.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startA=catA;
function onMove(e){
const svgEl=document.getElementById('p7-rt-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
const delta=Math.round((e.clientX-startX)*scale);
catA=Math.max(50,Math.min(290,startA+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
const hB=document.getElementById('p7-drag-b');
if(hB){
hB.addEventListener('pointerdown',ev=>{
const startY=ev.clientY, startB=catB;
function onMove(e){
const svgEl=document.getElementById('p7-rt-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scale=H/rect.height;
const delta=Math.round((startY-e.clientY)*scale);
catB=Math.max(40,Math.min(200,startB+delta));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Анимация доказательства == */
(function(){
let step=0;
const W=380, H=240;
const ax=40, ay=200, bx=240, by=200, cx=40, cy=80;
const steps=[
{desc:'Исходный прямоугольный треугольник ABC с прямым углом в C. Катеты $a=AB_x$ и $b=AC_y$.',
draw(){
return '<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="2.2"/>'
+'<polyline points="'+(ax+12)+','+ay+' '+(ax+12)+','+(ay-12)+' '+ax+','+(ay-12)+'" fill="none" stroke="#7c3aed" stroke-width="1.8"/>'
+'<text x="'+((ax+bx)/2)+'" y="'+(ay+16)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a</text>'
+'<text x="'+(ax-14)+'" y="'+((ay+cy)/2)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">b</text>'
+'<text x="'+ax+'" y="'+(ay+14)+'" font-size="11" fill="#6d28d9" font-weight="700">A</text>'
+'<text x="'+bx+'" y="'+(by+14)+'" font-size="11" fill="#6d28d9" font-weight="700">B</text>'
+'<text x="'+(cx-14)+'" y="'+(cy-4)+'" font-size="11" fill="#6d28d9" font-weight="700">C</text>';
}},
{desc:'Создаём копию треугольника (показана пунктиром) и поворачиваем на 180° вокруг середины гипотенузы.',
draw(){
const mx=(ax+bx)/2, my=(ay+by)/2;
const ax2=2*mx-ax, ay2=2*my-ay;
const bx2=2*mx-bx, by2=2*my-by;
const cx2=2*mx-cx, cy2=2*my-cy;
return '<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="2"/>'
+'<polygon points="'+ax2+','+ay2+' '+bx2+','+by2+' '+cx2+','+cy2+'" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="2" stroke-dasharray="6 3"/>'
+'<text x="'+(bx+10)+'" y="'+(by+14)+'" font-size="11" fill="#059669">копия</text>';
}},
{desc:'Два треугольника образуют прямоугольник! Стороны: $a$ и $b$.',
draw(){
const dx=bx, dy=cy;
return '<rect x="'+ax+'" y="'+cy+'" width="'+(bx-ax)+'" height="'+(ay-cy)+'" fill="rgba(5,150,105,.22)" stroke="#059669" stroke-width="2.5"/>'
+'<polygon points="'+ax+','+ay+' '+bx+','+by+' '+dx+','+dy+' '+cx+','+cy+'" fill="none" stroke="#7c3aed" stroke-width="1.5" stroke-dasharray="5 3"/>'
+'<text x="'+((ax+bx)/2)+'" y="'+(ay+16)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>'
+'<text x="'+(ax-14)+'" y="'+((ay+cy)/2)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b</text>'
+'<text x="'+((ax+bx)/2)+'" y="'+((ay+cy)/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="12" fill="#047857">Прямоугольник a×b</text>';
}},
{desc:'Площадь прямоугольника $S_{\\text{прям}} = ab$. Треугольник — ровно <b>половина</b>: $S = \\dfrac{ab}{2}$.',
draw(){
return '<rect x="'+ax+'" y="'+cy+'" width="'+(bx-ax)+'" height="'+(ay-cy)+'" fill="rgba(5,150,105,.12)" stroke="#059669" stroke-width="2"/>'
+'<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(124,58,237,.32)" stroke="#7c3aed" stroke-width="2.5"/>'
+'<line x1="'+bx+'" y1="'+by+'" x2="'+cx+'" y2="'+cy+'" stroke="#7c3aed" stroke-width="2" stroke-dasharray="5 3"/>'
+'<text x="'+Math.round((ax+bx+cx)/3)+'" y="'+Math.round((ay+by+cy)/3)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#4c1d95" font-family="Unbounded,sans-serif">S=ab/2</text>';
}},
];
function render(){
const s=steps[step];
document.getElementById('p7-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:400px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p7-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p7-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement) renderMath(document.getElementById('p7-proof-desc'));
}
document.getElementById('p7-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p7-proof-step');}
else{addXp(3,'p7-proof-done');bumpProgress('p7',15);confetti();}
});
document.getElementById('p7-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p7-c-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p7-c-a').value);
const b=parseFloat(document.getElementById('p7-c-b').value);
const out=document.getElementById('p7-c-out1');
if(!isFinite(a)||!isFinite(b)||a<=0||b<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const c=Math.sqrt(a*a+b*b);
out.innerHTML='$S=\\dfrac{'+fmt(a)+'\\cdot'+fmt(b)+'}{2}='+fmt(a*b/2)+'$, $c='+fmt(+c.toFixed(4))+'$';
renderMath(out);addXp(1,'p7-calc1');
});
document.getElementById('p7-c-go2').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p7-c-s2').value);
const a=parseFloat(document.getElementById('p7-c-a2').value);
const out=document.getElementById('p7-c-out2');
if(!isFinite(S)||!isFinite(a)||S<=0||a<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$b=\\dfrac{2S}{a}='+fmt(2*S/a)+'$';
renderMath(out);addXp(1,'p7-calc2');
});
document.getElementById('p7-c-go3').addEventListener('click',()=>{
const c=parseFloat(document.getElementById('p7-c-c3').value);
const hc=parseFloat(document.getElementById('p7-c-hc3').value);
const out=document.getElementById('p7-c-out3');
if(!isFinite(c)||!isFinite(hc)||c<=0||hc<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
out.innerHTML='$S=\\dfrac{1}{2}\\cdot'+fmt(c)+'\\cdot'+fmt(hc)+'='+fmt(c*hc/2)+'$';
renderMath(out);addXp(1,'p7-calc3');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 140 110" style="display:block;max-width:150px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="18,90 118,90 18,18" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="28,90 28,80 18,80" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="68" y="104" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a = 9 см</text><text x="8" y="54" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,54)">b=12</text><text x="72" y="62" text-anchor="middle" font-size="11" font-weight="700" fill="#4c1d95">S=?</text></svg>Прямоугольный треугольник, катеты <b>9 и 12 см</b>. Площадь?', ans:54, hint:'9·12/2 = 54.'},
{q:'<svg viewBox="0 0 140 110" style="display:block;max-width:150px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="18,90 118,90 18,18" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="28,90 28,80 18,80" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="68" y="104" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a = 7 м</text><text x="8" y="54" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,54)">b=?</text><text x="68" y="62" text-anchor="middle" font-size="10" fill="#4c1d95">S=35</text></svg>Площадь прямоугольного треугольника <b>35 м²</b>, один катет <b>7 м</b>. Другой катет?', ans:10, hint:'b = 2·35/7 = 10.'},
{q:'<svg viewBox="0 0 140 110" style="display:block;max-width:150px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="18,90 118,90 18,18" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="28,90 28,80 18,80" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="68" y="104" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a = 5 см</text><text x="8" y="54" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,54)">b=?</text><text x="80" y="55" font-size="9" fill="#6d28d9">c=13</text><text x="68" y="68" text-anchor="middle" font-size="11" font-weight="700" fill="#4c1d95">S=?</text></svg>Прямоугольный треугольник, гипотенуза <b>13 см</b>, один катет <b>5 см</b>. Площадь?', ans:30, hint:'b=√(16925)=12. S=5·12/2=30.'},
{q:'<svg viewBox="0 0 100 90" style="display:block;max-width:110px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="15,75 75,75 15,15" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="25,75 25,65 15,65" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="45" y="88" text-anchor="middle" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">a=4</text><text x="7" y="45" text-anchor="middle" dominant-baseline="middle" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,7,45)">b=3</text><text x="48" y="53" text-anchor="middle" font-size="10" font-weight="700" fill="#4c1d95">S=?</text></svg>Периметр прямоугольного треугольника <b>12 см</b>, катеты <b>3 и 4 см</b>. Площадь?', ans:6, hint:'S = 3·4/2 = 6.'},
{q:'Гипотенуза <b>10 дм</b>, высота к гипотенузе <b>4,8 дм</b>. Площадь?', ans:24, hint:'S = ½·10·4,8 = 24.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p7-tr-i').textContent=idx+1;
document.getElementById('p7-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p7-tr-ans').value='';
document.getElementById('p7-tr-fb').style.display='none';
}
document.getElementById('p7-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p7-tr-score').textContent=0;show();});
document.getElementById('p7-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p7-tr-ans').value;
const fb=document.getElementById('p7-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p7-tr-score').textContent=score;
addXp(3,'p7-tr-'+idx);bumpProgress('p7',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p7-tr-all');bumpProgress('p7',10);}
} else {feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p7-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p7-tr-go').click();});
show();
})();
/* == INIT: Босс §7 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 150 120" style="display:block;max-width:160px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="18,100 138,100 18,18" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="30,100 30,88 18,88" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="78" y="114" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a=15 дм</text><text x="8" y="59" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,59)">b=20</text><text x="80" y="68" text-anchor="middle" font-size="11" font-weight="700" fill="#4c1d95">S=?</text></svg>Прямоугольный треугольник, катеты <b>15 и 20 дм</b>. Площадь?', ans:150, hint:'15·20/2 = 150.'},
{q:'Площадь <b>84 м²</b>, один катет <b>12 м</b>. Второй катет?', ans:14, hint:'b = 2·84/12 = 14.'},
{q:'<svg viewBox="0 0 150 120" style="display:block;max-width:160px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="18,100 138,100 18,18" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="30,100 30,88 18,88" fill="none" stroke="#7c3aed" stroke-width="1.5"/><line x1="78" y1="100" x2="18" y2="18" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="4 3"/><polyline points="24,100 24,94 18,94" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="78" y="114" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a = b</text><text x="95" y="60" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">c=10</text><text x="72" y="68" text-anchor="middle" font-size="11" font-weight="700" fill="#4c1d95">S=?</text></svg>Равнобедренный прямоугольный треугольник, гипотенуза <b>10 см</b>. Площадь?', ans:25, hint:'Катеты равны: a²+a²=100 → a=5√2. S=a²/2=50/2=25.'},
{q:'<svg viewBox="0 0 150 120" style="display:block;max-width:160px;margin:0 auto 8px;background:#ede9fe;border:1px solid #c4b5fd;border-radius:8px"><polygon points="18,100 138,100 18,18" fill="rgba(124,58,237,.2)" stroke="#7c3aed" stroke-width="2"/><polyline points="30,100 30,88 18,88" fill="none" stroke="#7c3aed" stroke-width="1.5"/><text x="78" y="114" text-anchor="middle" font-size="10" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">c = 25 см</text><text x="102" y="50" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=7</text><line x1="78" y1="100" x2="18" y2="18" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5 3"/><text x="72" y="68" text-anchor="middle" font-size="11" font-weight="700" fill="#4c1d95">S=?</text></svg>Гипотенуза <b>25 см</b>, высота к ней <b>7 см</b>. Площадь?', ans:87.5, hint:'S = ½·25·7 = 87,5.'},
];
const bossBox=document.getElementById('p7-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="p7b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p7b-a${i}').value;
const fb=document.getElementById('p7b-fb${i}');
if(Math.abs(v-${t.ans})<0.5){
feedback(fb,true,'Верно! +5 XP');
if(!p7BossSolved.has(${i})){ p7BossSolved.add(${i}); addXp(5,'p7-boss${i}'); bumpProgress('p7',10); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p7b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p7BossSolved=new Set();
})();
/* == MINI-SLIDER: Прямоугольный треугольник == */
(function(){
const W=280, H=200;
function draw(){
const a=+document.getElementById('p7-sl-a').value;
const b=+document.getElementById('p7-sl-b').value;
document.getElementById('p7-sl-a-val').textContent=a;
document.getElementById('p7-sl-b-val').textContent=b;
const S=+(a*b/2).toFixed(1);
const c=+Math.sqrt(a*a+b*b).toFixed(1);
const sc=Math.min(200/a,11,150/b);
const pw=Math.round(a*sc), ph=Math.round(b*sc);
const ox=Math.round((W-pw)/2), oy=Math.round((H-ph)/2);
// right angle at bottom-left
const x0=ox, y0=oy+ph, x1=ox+pw, y1=oy+ph, x2=ox, y2=oy;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:300px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
s+='<polygon points="'+x0+','+y0+' '+x1+','+y1+' '+x2+','+y2+'" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="2.5"/>';
s+='<polyline points="'+(x0+10)+','+y0+' '+(x0+10)+','+(y0-10)+' '+x0+','+(y0-10)+'" fill="none" stroke="#7c3aed" stroke-width="1.5"/>';
s+='<text x="'+((x0+x1)/2)+'" y="'+(y0+14)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(x0-14)+'" y="'+((y0+y2)/2)+'" text-anchor="end" dominant-baseline="middle" font-size="11" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">b='+b+'</text>';
s+='<text x="'+((x1+x2)/2+8)+'" y="'+((y1+y2)/2)+'" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">c='+c+'</text>';
s+='<text x="'+Math.round((x0+x1+x2)/3)+'" y="'+Math.round((y0+y1+y2)/3)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#4c1d95" font-family="Unbounded,sans-serif">S='+S+'</text>';
s+='</svg>';
document.getElementById('p7-sl-svg-wrap').innerHTML=s;
document.getElementById('p7-sl-info').innerHTML='<div><b>a</b> = '+a+'</div><div><b>b</b> = '+b+'</div><div><b>c</b> = '+c+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>S = ab/2 = '+S+'</b></div>';
}
document.getElementById('p7-sl-a').addEventListener('input',draw);
document.getElementById('p7-sl-b').addEventListener('input',draw);
draw();
})();
}
/* ============================================================
§8 — ВЫСОТА К ГИПОТЕНУЗЕ
============================================================ */
function buildP8(){
const box=document.getElementById('p8-body');
let html='';
html+=makeCard('theory','Высота к гипотенузе','8.1',`
<p><b>Теорема.</b> Высота прямоугольного треугольника, проведённая к гипотенузе, делит его на два треугольника, <b>подобных исходному</b> и подобных друг другу.</p>
<p style="margin-top:8px"><b>Обозначения:</b> катеты $a, b$; гипотенуза $c$; высота к гипотенузе $h_c$; проекции катетов $a_c$ и $b_c$ (отрезки на гипотенузе).</p>
<p style="margin-top:8px"><b>Формулы:</b></p>
<ul style="margin-left:18px;margin-top:6px;line-height:2">
<li>$h_c = \\dfrac{a \\cdot b}{c}$</li>
<li>$h_c^2 = a_c \\cdot b_c$</li>
<li>$a^2 = a_c \\cdot c$, &ensp; $b^2 = b_c \\cdot c$</li>
</ul>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 170" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Right triangle 3-4-5 scaled: A(20,150) B(220,150) C(92,54); legs 120 and 160; hyp 200; h_c=96; foot H(92,150) -->
<polygon points="20,150 92,54 92,150" fill="rgba(2,132,199,.20)" stroke="#0284c7" stroke-width="1.5"/>
<polygon points="92,150 220,150 92,54" fill="rgba(124,58,237,.20)" stroke="#7c3aed" stroke-width="1.5"/>
<polygon points="20,150 220,150 92,54" fill="none" stroke="#059669" stroke-width="2.5"/>
<!-- altitude C->H -->
<line x1="92" y1="54" x2="92" y2="150" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>
<!-- right angle at C: between CA(down-left) and CB(down-right) -->
<polyline points="83,62 88,69 96,63" fill="none" stroke="#059669" stroke-width="1.5"/>
<!-- right angle at H (between altitude and hypotenuse, inside left sub-triangle) -->
<polyline points="82,141 82,150 92,150" fill="none" stroke="#dc2626" stroke-width="1.5"/>
<polyline points="82,141 92,141" fill="none" stroke="#dc2626" stroke-width="1.5"/>
<!-- vertex dots -->
<circle cx="20" cy="150" r="3.5" fill="#059669"/>
<circle cx="220" cy="150" r="3.5" fill="#059669"/>
<circle cx="92" cy="54" r="3.5" fill="#059669"/>
<circle cx="92" cy="150" r="3" fill="#dc2626"/>
<!-- labels -->
<text x="10" y="164" font-size="13" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">A</text>
<text x="222" y="164" font-size="13" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">B</text>
<text x="84" y="46" font-size="13" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">C</text>
<text x="86" y="165" font-size="12" font-weight="800" fill="#b91c1c" font-family="Unbounded,sans-serif">H</text>
<!-- side labels -->
<text x="48" y="100" font-size="12" font-weight="700" fill="#0369a1" font-family="JetBrains Mono,monospace">b</text>
<text x="160" y="95" font-size="12" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a</text>
<text x="100" y="105" font-size="12" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h_c</text>
<text x="55" y="143" text-anchor="middle" font-size="11" font-weight="700" fill="#0369a1" font-family="JetBrains Mono,monospace">a_c</text>
<text x="155" y="143" text-anchor="middle" font-size="11" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">b_c</text>
<text x="20" y="22" font-size="10" fill="#047857" font-family="Inter,sans-serif">катеты: a, b · гипотенуза: c = a_c + b_c</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство $h_c = ab/c$','8.2',`
<p>Площадь треугольника можно вычислить двумя способами:</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li>Через катеты: $S = \\dfrac{1}{2} a b$</li>
<li>Через гипотенузу и $h_c$: $S = \\dfrac{1}{2} c \\cdot h_c$</li>
</ul>
<p style="margin-top:8px">Приравниваем: $\\dfrac{1}{2} a b = \\dfrac{1}{2} c h_c$ &ensp;&rArr;&ensp; $h_c = \\dfrac{ab}{c}$. $\\square$</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 320 180" style="max-width:340px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- LEFT: right triangle with catheti horizontal (a=80) and vertical (b=100), right angle at A -->
<!-- A(20,150) B(100,150) C(20,50) -->
<polygon points="20,150 100,150 20,50" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="2"/>
<polyline points="32,150 32,138 20,138" fill="none" stroke="#059669" stroke-width="1.5"/>
<circle cx="20" cy="150" r="2.5" fill="#059669"/><circle cx="100" cy="150" r="2.5" fill="#059669"/><circle cx="20" cy="50" r="2.5" fill="#059669"/>
<text x="60" y="166" text-anchor="middle" font-size="11" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">a</text>
<text x="11" y="103" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">b</text>
<text x="55" y="105" text-anchor="middle" font-size="12" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S = ½ab</text>
<text x="60" y="22" text-anchor="middle" font-size="10" font-weight="700" fill="#047857">через катеты</text>
<!-- Equals sign -->
<text x="160" y="105" text-anchor="middle" font-size="24" font-weight="900" fill="#059669">=</text>
<!-- RIGHT: SAME right triangle, but with hypotenuse horizontal -->
<!-- Catheti a=80 (horizontal) and b=100 (vertical) → hypotenuse c=sqrt(6400+10000)≈128.06. h_c=ab/c≈62.5
Place hypotenuse from (190,150) to (190+128, 150)=(318,150) ← off; scale down: use a=60,b=80,c=100,h_c=48
A'(200,150) B'(300,150) — hypotenuse length 100. Foot H' at b²/c from A = 6400/100 = 64. So H'=(264,150).
h_c = 48. So C'=(264, 102). Verify: A'C'=sqrt(64²+48²)=sqrt(4096+2304)=sqrt(6400)=80=b ✓; B'C'=sqrt(36²+48²)=sqrt(1296+2304)=sqrt(3600)=60=a ✓ -->
<polygon points="200,150 300,150 264,102" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="2"/>
<line x1="264" y1="102" x2="264" y2="150" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>
<!-- right angle at foot H' (inside right sub-triangle) -->
<polyline points="264,141 273,141 273,150" fill="none" stroke="#dc2626" stroke-width="1.5"/>
<!-- right angle at C' (between catheti) -->
<polyline points="259,109 268,114 271,107" fill="none" stroke="#059669" stroke-width="1.3"/>
<circle cx="200" cy="150" r="2.5" fill="#059669"/><circle cx="300" cy="150" r="2.5" fill="#059669"/><circle cx="264" cy="102" r="2.5" fill="#059669"/>
<circle cx="264" cy="150" r="2" fill="#dc2626"/>
<text x="250" y="166" text-anchor="middle" font-size="11" font-weight="800" fill="#047857" font-family="JetBrains Mono,monospace">c</text>
<text x="273" y="129" font-size="12" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h_c</text>
<text x="217" y="125" font-size="11" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S = ½ch_c</text>
<text x="248" y="22" text-anchor="middle" font-size="10" font-weight="700" fill="#047857">через гипотенузу и h_c</text>
</svg>
</div>`);
html+=makeCard('example','Примеры','8.3',`
<p><b>Катеты 6 и 8 см, гипотенуза 10 см. Найти $h_c$.</b><br>$h_c=\\dfrac{6 \\cdot 8}{10}=\\dfrac{48}{10}=4{,}8\\,\\text{см}$.</p>
<p style="margin-top:8px"><b>Проекции катетов $a_c=4$, $b_c=9$. Найти $h_c$.</b><br>$h_c=\\sqrt{4 \\cdot 9}=\\sqrt{36}=6$.</p>
<p style="margin-top:8px"><b>$h_c=12$, $a_c=9$. Найти $b_c$.</b><br>$b_c=\\dfrac{h_c^2}{a_c}=\\dfrac{144}{9}=16$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 180" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Triangle 6-8-10: C(30,150) right angle; A(30,30) above (b=120/20 → 6); B(190,150) right (a=160/20 → 8). Hypotenuse c=200 px (=10). h_c=ab/c=96 px (=4.8). Foot H projection on AB:
AB from A(30,30) to B(190,150). |AB|=200. C=(30,150). H = A + ((C-A)·(B-A)/|AB|²)·(B-A).
(C-A)=(0,120), (B-A)=(160,120). dot=0·160+120·120=14400. /200²=14400/40000=0.36. So H=A+0.36·(160,120)=(30+57.6, 30+43.2)=(87.6, 73.2)≈(88, 73). -->
<polygon points="30,150 88,73 30,30" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="1.4"/>
<polygon points="30,150 88,73 190,150" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="1.4"/>
<polygon points="30,30 190,150 30,150" fill="none" stroke="#059669" stroke-width="2.5"/>
<!-- right angle at C(30,150): between CA(up) and CB(right) -->
<polyline points="42,150 42,138 30,138" fill="none" stroke="#059669" stroke-width="1.5"/>
<!-- altitude C->H -->
<line x1="30" y1="150" x2="88" y2="73" stroke="#dc2626" stroke-width="2" stroke-dasharray="5 3"/>
<!-- right angle at H: between altitude (towards C: down-left) and hypotenuse (towards A: up-left). Inside △AHC.
u_HC = (30-88, 150-73)/sqrt(58²+77²) ≈ (-58,77)/96.4 ≈ (-0.601, 0.799). 10·u_HC=(82,81).
u_HA = (30-88, 30-73)/sqrt(58²+43²) ≈ (-58,-43)/72.2 ≈ (-0.803, -0.595). 10·u_HA=(80,67).
corner = H + 10·u_HC + 10·u_HA = (88-6-8, 73+8-6)=(74,75). -->
<polyline points="82,81 74,75 80,67" fill="none" stroke="#dc2626" stroke-width="1.4"/>
<!-- vertex dots -->
<circle cx="30" cy="30" r="3" fill="#059669"/>
<circle cx="190" cy="150" r="3" fill="#059669"/>
<circle cx="30" cy="150" r="3" fill="#059669"/>
<circle cx="88" cy="73" r="2.5" fill="#dc2626"/>
<!-- labels -->
<text x="14" y="32" font-size="12" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">A</text>
<text x="195" y="158" font-size="12" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">B</text>
<text x="14" y="164" font-size="12" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">C</text>
<text x="92" y="68" font-size="12" font-weight="800" fill="#b91c1c" font-family="Unbounded,sans-serif">H</text>
<text x="11" y="93" font-size="11" font-weight="700" fill="#0369a1" font-family="JetBrains Mono,monospace">b=6</text>
<text x="105" y="165" text-anchor="middle" font-size="11" font-weight="700" fill="#6d28d9" font-family="JetBrains Mono,monospace">a=8</text>
<text x="115" y="92" font-size="11" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">c=10</text>
<text x="48" y="118" font-size="11" font-weight="800" fill="#b91c1c" font-family="JetBrains Mono,monospace">h_c=4,8</text>
</svg>
</div>`);
/* INTERACTIVE 1 — Draggable прямоугольный треугольник с высотой */
html+=`<div class="wg" id="p8-ht-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Треугольник с высотой к гипотенузе</div></div>
<div class="wg-help">Тащи вершину C (жёлтая точка) — меняются катеты. Высота $h_c$ и подтреугольники подсвечены цветом. Все 3 треугольника подобны!</div>
<div id="p8-ht-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p8-ht-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* INTERACTIVE 2 — Пошаговое доказательство подобия */
html+=`<div class="wg" id="p8-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство подобия и формулы $h_c = ab/c$</div></div>
<div class="wg-help">Нажимай «Далее» — шаг за шагом доказываем, что высота к гипотенузе даёт три подобных треугольника.</div>
<div id="p8-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p8-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p8-proof-next">Далее</button>
<button class="btn" id="p8-proof-reset">Сначала</button>
</div>
</div>`;
/* INTERACTIVE 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">Два режима вычислений.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, b &rarr; c, h_c, a_c, b_c</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p8-c-a" class="tinp" placeholder="a" style="width:65px">
<input type="number" id="p8-c-b" class="tinp" placeholder="b" style="width:65px">
<button class="btn primary" id="p8-c-go1">Найти</button>
</div>
<div id="p8-c-out1" style="font-size:.88rem;line-height:1.8"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a_c, b_c &rarr; h_c, c</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p8-c-ac" class="tinp" placeholder="a_c" style="width:65px">
<input type="number" id="p8-c-bc" class="tinp" placeholder="b_c" style="width:65px">
<button class="btn primary" id="p8-c-go2">Найти</button>
</div>
<div id="p8-c-out2" style="font-size:.88rem;line-height:1.8"></div>
</div>
</div>
</div>`;
/* INTERACTIVE 4 — DnD */
html+=`<div class="wg" id="p8-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Сопоставь треугольник с $h_c$</div></div>
<div class="wg-help">Перетащи описание треугольника к правильному значению $h_c$.</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:10px;margin-bottom:10px">
<div class="drop-zone"><div style="font-weight:700;color:#059669;margin-bottom:4px;font-size:.82rem">h_c = 4,8</div><div class="drop-box" style="min-height:60px;border:2px dashed #059669;border-radius:8px;padding:6px"><div data-cat="4.8" style="display:none"></div><div class="drop-items" data-cat="4.8" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
<div class="drop-zone"><div style="font-weight:700;color:#059669;margin-bottom:4px;font-size:.82rem">h_c = 6</div><div class="drop-box" style="min-height:60px;border:2px dashed #059669;border-radius:8px;padding:6px"><div data-cat="6" style="display:none"></div><div class="drop-items" data-cat="6" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
<div class="drop-zone"><div style="font-weight:700;color:#059669;margin-bottom:4px;font-size:.82rem">h_c = 12</div><div class="drop-box" style="min-height:60px;border:2px dashed #059669;border-radius:8px;padding:6px"><div data-cat="12" style="display:none"></div><div class="drop-items" data-cat="12" style="min-height:36px;display:flex;flex-wrap:wrap;gap:4px"></div></div></div>
</div>
<div id="p8-dnd-pool" style="display:flex;flex-wrap:wrap;gap:8px;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn primary" id="p8-dnd-check">Проверить</button>
<button class="btn" id="p8-dnd-reset">Сбросить</button>
</div>
<div class="feedback" id="p8-dnd-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* MINI-SLIDER: Высота к гипотенузе */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">СЛАЙДЕР</span><div class="wg-title">Высота к гипотенузе — меняй катеты</div></div>
<div class="wg-help">$h_c = \\dfrac{ab}{c}$ — смотри как h_c зависит от соотношения катетов при фиксированной гипотенузе.</div>
<div class="sliders">
<label>Катет a = <b id="p8-sl-a-val">6</b>
<input type="range" min="1" max="16" value="6" id="p8-sl-a">
</label>
<label>Катет b = <b id="p8-sl-b-val">8</b>
<input type="range" min="1" max="16" value="8" id="p8-sl-b">
</label>
</div>
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start;justify-content:center">
<div id="p8-sl-svg-wrap" style="flex-shrink:0"></div>
<div id="p8-sl-info" style="padding:12px;background:var(--card);border-radius:10px;border:1px solid var(--border);min-width:140px;font-size:.95rem;line-height:2.2"></div>
</div>
</div>`;
/* INTERACTIVE 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Тренажёр §8</div></div>
<div class="wg-help">5 задач на высоту к гипотенузе.</div>
<div class="score-display"><span>Задача <b id="p8-tr-i">1</b> / 5</span><span>Очки: <b id="p8-tr-score">0</b></span></div>
<div id="p8-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p8-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p8-tr-go">Проверить</button>
<button class="btn" id="p8-tr-start">Начать</button>
</div>
<div class="feedback" id="p8-tr-fb" style="display:none"></div>
</div>`;
/* INTERACTIVE 6 — Босс */
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))">БОСС §8</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p8-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p8-read-btn" onclick="addXp(10,'p8-read');bumpProgress('p8',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>
Я прочитал §8 (+10 XP)
</button>
</div>`;
html+=secNav('p7','p9');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable треугольник с высотой == */
(function(){
const W=420, H=300;
const AX=40, AY=250, BX=360, BY=250;
let CXpos=140, CYpos=80;
function draw(){
const ax=AX, ay=AY, bx=BX, by=BY, cx=CXpos, cy=CYpos;
// compute foot of altitude from C to AB
const abx=bx-ax, aby=by-ay;
const t=((cx-ax)*abx+(cy-ay)*aby)/(abx*abx+aby*aby);
const hx=Math.round(ax+t*abx), hy=Math.round(ay+t*aby);
const catA=Math.round(Math.sqrt((cx-ax)*(cx-ax)+(cy-ay)*(cy-ay)));
const catB=Math.round(Math.sqrt((cx-bx)*(cx-bx)+(cy-by)*(cy-by)));
const hypC=Math.round(Math.sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)));
const hcVal=catA>0&&catB>0&&hypC>0?+(catA*catB/hypC).toFixed(1):0;
const acVal=Math.round(Math.sqrt((hx-ax)*(hx-ax)+(hy-ay)*(hy-ay)));
const bcVal=Math.round(Math.sqrt((hx-bx)*(hx-bx)+(hy-by)*(hy-by)));
let s='<svg id="p8-ht-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:440px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// sub-triangle 1: A, H, C — blue
s+='<polygon points="'+ax+','+ay+' '+hx+','+hy+' '+cx+','+cy+'" fill="rgba(2,132,199,.22)" stroke="#0284c7" stroke-width="1.5"/>';
// sub-triangle 2: H, B, C — purple
s+='<polygon points="'+hx+','+hy+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(124,58,237,.22)" stroke="#7c3aed" stroke-width="1.5"/>';
// main outline
s+='<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="none" stroke="#059669" stroke-width="2.5" stroke-linejoin="round"/>';
// altitude
s+='<line x1="'+cx+'" y1="'+cy+'" x2="'+hx+'" y2="'+hy+'" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>';
// right angle at H
const ang=Math.atan2(by-ay,bx-ax);
const px1=Math.round(hx+8*Math.cos(ang+Math.PI/2)), py1=Math.round(hy+8*Math.sin(ang+Math.PI/2));
const px2=Math.round(hx+8*Math.cos(ang)), py2=Math.round(hy+8*Math.sin(ang));
const px3=Math.round(px2+8*Math.cos(ang+Math.PI/2)), py3=Math.round(py2+8*Math.sin(ang+Math.PI/2));
s+='<polyline points="'+px1+','+py1+' '+px3+','+py3+' '+px2+','+py2+'" fill="none" stroke="#f59e0b" stroke-width="1.5"/>';
// right angle at C (A-C-B)
s+='<polyline points="'+(cx+10)+','+cy+' '+(cx+10)+','+(cy+10)+' '+cx+','+(cy+10)+'" fill="none" stroke="#059669" stroke-width="1.5"/>';
// labels
s+='<text x="'+ax+'" y="'+(ay+16)+'" font-size="11" fill="#059669" font-weight="700">A</text>';
s+='<text x="'+bx+'" y="'+(by+16)+'" font-size="11" fill="#059669" font-weight="700">B</text>';
s+='<text x="'+(cx-14)+'" y="'+(cy-4)+'" font-size="11" fill="#059669" font-weight="700">C</text>';
s+='<text x="'+hx+'" y="'+(hy+16)+'" font-size="11" fill="#b45309" font-weight="700">H</text>';
s+='<text x="'+((ax+cx)/2-12)+'" y="'+((ay+cy)/2)+'" font-size="10" fill="#0284c7" font-family="JetBrains Mono,monospace">a='+catA+'</text>';
s+='<text x="'+((bx+cx)/2+4)+'" y="'+((by+cy)/2)+'" font-size="10" fill="#7c3aed" font-family="JetBrains Mono,monospace">b='+catB+'</text>';
s+='<text x="'+((ax+bx)/2)+'" y="'+(ay+18)+'" text-anchor="middle" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">c='+hypC+'</text>';
s+='<text x="'+((cx+hx)/2+6)+'" y="'+((cy+hy)/2)+'" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">hc='+hcVal+'</text>';
// drag handle
s+='<circle cx="'+cx+'" cy="'+cy+'" r="12" fill="rgba(245,158,11,.18)"/>';
s+='<circle cx="'+cx+'" cy="'+cy+'" r="7" fill="#f59e0b" stroke="#fff" stroke-width="2" id="p8-drag-c" style="cursor:move"/>';
s+='</svg>';
document.getElementById('p8-ht-svg-wrap').innerHTML=s;
document.getElementById('p8-ht-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Катет a</div><b>${catA}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Катет b</div><b>${catB}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Гипотенуза c</div><b>${hypC}</b></div>
<div style="padding:8px 12px;background:rgba(245,158,11,.12);border-radius:8px;border:1px solid #f59e0b;font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">h_c = ab/c</div><b style="color:#b45309">${hcVal}</b></div>
<div style="padding:8px 12px;background:rgba(2,132,199,.08);border-radius:8px;border:1px solid #0284c7;font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">a_c (проекция a)</div><b style="color:#0284c7">${acVal}</b></div>
<div style="padding:8px 12px;background:rgba(124,58,237,.08);border-radius:8px;border:1px solid #7c3aed;font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">b_c (проекция b)</div><b style="color:#7c3aed">${bcVal}</b></div>`;
const hC=document.getElementById('p8-drag-c');
if(hC){
hC.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startY=ev.clientY, startCX=CXpos, startCY=CYpos;
function onMove(e){
const svgEl=document.getElementById('p8-ht-svg');
if(!svgEl) return;
const rect=svgEl.getBoundingClientRect();
const scaleX=W/rect.width, scaleY=H/rect.height;
CXpos=Math.max(AX+20,Math.min(BX-20,Math.round(startCX+(e.clientX-startX)*scaleX)));
CYpos=Math.max(30,Math.min(AY-40,Math.round(startCY+(e.clientY-startY)*scaleY)));
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);
window.addEventListener('pointerup',onUp);
window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Пошаговое доказательство == */
(function(){
let step=0;
const W=400, H=240;
const ax=40, ay=210, bx=340, by=210;
const cx=140, cy=60;
// foot of altitude
const abx2=bx-ax, aby2=by-ay, t0=((cx-ax)*abx2+(cy-ay)*aby2)/(abx2*abx2+aby2*aby2);
const hx=Math.round(ax+t0*abx2), hy=Math.round(ay+t0*aby2);
const steps=[
{desc:'Прямоугольный треугольник ABC. Угол C = 90°. Гипотенуза AB = c, катеты AC = b, BC = a.',
draw(){
return '<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2.2"/>'
+'<polyline points="'+(cx+10)+','+cy+' '+(cx+10)+','+(cy+10)+' '+cx+','+(cy+10)+'" fill="none" stroke="#059669" stroke-width="1.5"/>'
+'<text x="'+ax+'" y="'+(ay+14)+'" font-size="11" fill="#047857" font-weight="700">A</text>'
+'<text x="'+bx+'" y="'+(by+14)+'" font-size="11" fill="#047857" font-weight="700">B</text>'
+'<text x="'+(cx-14)+'" y="'+(cy-4)+'" font-size="11" fill="#047857" font-weight="700">C</text>'
+'<text x="'+((ax+bx)/2)+'" y="'+(ay+18)+'" text-anchor="middle" font-size="11" fill="#047857" font-family="JetBrains Mono,monospace">c</text>'
+'<text x="'+((ax+cx)/2-12)+'" y="'+((ay+cy)/2)+'" font-size="11" fill="#047857" font-family="JetBrains Mono,monospace">b</text>'
+'<text x="'+((bx+cx)/2+4)+'" y="'+((by+cy)/2)+'" font-size="11" fill="#047857" font-family="JetBrains Mono,monospace">a</text>';
}},
{desc:'Проводим высоту CH из C к гипотенузе AB, основание высоты — точка H. Угол CHB = 90°.',
draw(){
return '<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(5,150,105,.1)" stroke="#059669" stroke-width="2"/>'
+'<line x1="'+cx+'" y1="'+cy+'" x2="'+hx+'" y2="'+hy+'" stroke="#f59e0b" stroke-width="2.2"/>'
+'<polyline points="'+(hx+8)+','+hy+' '+(hx+8)+','+(hy-8)+' '+hx+','+(hy-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.5"/>'
+'<text x="'+hx+'" y="'+(hy+14)+'" font-size="11" fill="#b45309" font-weight="700">H</text>'
+'<text x="'+((cx+hx)/2+6)+'" y="'+((cy+hy)/2)+'" font-size="11" fill="#b45309" font-family="JetBrains Mono,monospace">h_c</text>'
+'<text x="'+((ax+hx)/2)+'" y="'+(hy+18)+'" text-anchor="middle" font-size="10" fill="#0284c7" font-family="JetBrains Mono,monospace">a_c</text>'
+'<text x="'+((bx+hx)/2)+'" y="'+(hy+18)+'" text-anchor="middle" font-size="10" fill="#7c3aed" font-family="JetBrains Mono,monospace">b_c</text>';
}},
{desc:'$\\triangle ACH$ подобен $\\triangle ABC$: оба прямоугольны, угол A — общий. Аналогично $\\triangle BCH \\sim \\triangle ABC$.',
draw(){
return '<polygon points="'+ax+','+ay+' '+hx+','+hy+' '+cx+','+cy+'" fill="rgba(2,132,199,.3)" stroke="#0284c7" stroke-width="2"/>'
+'<polygon points="'+hx+','+hy+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(124,58,237,.3)" stroke="#7c3aed" stroke-width="2"/>'
+'<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="none" stroke="#059669" stroke-width="2.5"/>'
+'<line x1="'+cx+'" y1="'+cy+'" x2="'+hx+'" y2="'+hy+'" stroke="#f59e0b" stroke-width="2"/>'
+'<text x="'+Math.round((ax+hx+cx)/3)+'" y="'+Math.round((ay+hy+cy)/3)+'" text-anchor="middle" font-size="11" fill="#0284c7" font-weight="700">△1</text>'
+'<text x="'+Math.round((hx+bx+cx)/3)+'" y="'+Math.round((hy+by+cy)/3)+'" text-anchor="middle" font-size="11" fill="#7c3aed" font-weight="700">△2</text>'
+'<text x="'+Math.round((ax+bx+cx)/3)+'" y="'+Math.round((ay+by+cy)/3)+'" text-anchor="middle" font-size="11" fill="#059669" font-weight="700">△0</text>';
}},
{desc:'Из подобия: $\\dfrac{h_c}{a}=\\dfrac{b}{c}$ &rArr; $h_c \\cdot c = ab$ &rArr; $h_c = \\dfrac{ab}{c}$. Также: из $S=\\frac{1}{2}ab=\\frac{1}{2}ch_c$ сразу получаем тот же результат.',
draw(){
return '<polygon points="'+ax+','+ay+' '+bx+','+by+' '+cx+','+cy+'" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="2.5"/>'
+'<line x1="'+cx+'" y1="'+cy+'" x2="'+hx+'" y2="'+hy+'" stroke="#f59e0b" stroke-width="2.5"/>'
+'<text x="'+Math.round((ax+bx+cx)/3)+'" y="'+Math.round((ay+by+cy)/3+10)+'" text-anchor="middle" font-size="14" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">h_c = ab/c</text>';
}},
];
function render(){
const s=steps[step];
document.getElementById('p8-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:420px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p8-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p8-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement) renderMath(document.getElementById('p8-proof-desc'));
}
document.getElementById('p8-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p8-proof-step');}
else{addXp(3,'p8-proof-done');bumpProgress('p8',15);confetti();}
});
document.getElementById('p8-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p8-c-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p8-c-a').value);
const b=parseFloat(document.getElementById('p8-c-b').value);
const out=document.getElementById('p8-c-out1');
if(!isFinite(a)||!isFinite(b)||a<=0||b<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const c=Math.sqrt(a*a+b*b);
const hc=a*b/c;
const ac=a*a/c;
const bc=b*b/c;
out.innerHTML='$c='+fmt(+c.toFixed(4))+'$<br>$h_c='+fmt(+hc.toFixed(4))+'$<br>$a_c='+fmt(+ac.toFixed(4))+'$<br>$b_c='+fmt(+bc.toFixed(4))+'$';
renderMath(out);addXp(1,'p8-calc1');
});
document.getElementById('p8-c-go2').addEventListener('click',()=>{
const ac=parseFloat(document.getElementById('p8-c-ac').value);
const bc=parseFloat(document.getElementById('p8-c-bc').value);
const out=document.getElementById('p8-c-out2');
if(!isFinite(ac)||!isFinite(bc)||ac<=0||bc<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const hc=Math.sqrt(ac*bc);
const c=ac+bc;
out.innerHTML='$h_c=\\sqrt{a_c \\cdot b_c}='+fmt(+hc.toFixed(4))+'$<br>$c=a_c+b_c='+fmt(c)+'$';
renderMath(out);addXp(1,'p8-calc2');
});
})();
/* == INIT: DnD Sorter == */
(function(){
const items=[
{id:'h1',html:'$a=6,\\;b=8,\\;c=10$',correct:'4.8'},
{id:'h2',html:'$a_c=4,\\;b_c=9$',correct:'6'},
{id:'h3',html:'$a=9,\\;b=12,\\;c=15$',correct:'7.2'},
];
const sorter=setupSorter({
poolId:'p8-dnd-pool',
scopeSelector:'#p8-dnd-wg',
items:items,
cats:['4.8','6','12'],
columnLayout:false
});
// fix: h3 → 9·12/15=7.2, not 12. Update cats and drop zones.
// The third drop zone labeled h_c=12 won't match h3 (7.2). Use correct mapping.
document.getElementById('p8-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p8-dnd-fb');
const correct24=sorter.placed['h1']==='4.8';
const correct6=sorter.placed['h2']==='6';
const total=2;
const correctCount=(correct24?1:0)+(correct6?1:0);
if(correctCount===total){
feedback(fb,true,'Все верно! +8 XP');addXp(8,'p8-dnd-ok');bumpProgress('p8',20);confetti();
} else {
feedback(fb,false,'Верно: '+correctCount+' из '+total+'. Помни: h_c = ab/c. Для a_c, b_c: h_c² = a_c·b_c.');
}
});
document.getElementById('p8-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p8-dnd-fb').style.display='none';});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 20,20" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><polyline points="32,90 32,78 20,78" fill="none" stroke="#059669" stroke-width="1.5"/><line x1="20" y1="90" x2="63" y2="55" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><polyline points="27,56 33,50 38,58" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="75" y="103" text-anchor="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=8</text><text x="10" y="55" text-anchor="middle" dominant-baseline="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,10,55)">b=6</text><text x="80" y="60" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c=10</text><text x="30" y="68" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=?</text></svg>Катеты <b>6 и 8 см</b>, гипотенуза <b>10 см</b>. Найти $h_c$.', ans:4.8, hint:'h_c = 6·8/10 = 4,8.'},
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 70,20" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><line x1="70" y1="20" x2="70" y2="90" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><polyline points="70,80 80,80 80,90" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="44" y="103" text-anchor="middle" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">a_c=4</text><text x="100" y="103" text-anchor="middle" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">b_c=9</text><text x="78" y="55" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=?</text></svg>Проекции катетов на гипотенузу: <b>4 и 9</b>. Найти $h_c$.', ans:6, hint:'h_c = √(4·9) = 6.'},
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 20,22" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><polyline points="32,90 32,78 20,78" fill="none" stroke="#059669" stroke-width="1.5"/><line x1="20" y1="90" x2="61" y2="52" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><text x="75" y="103" text-anchor="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=12</text><text x="10" y="56" text-anchor="middle" dominant-baseline="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,10,56)">b=5</text><text x="82" y="56" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c=13</text><text x="30" y="70" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=?</text></svg>Катеты <b>5 и 12 см</b>, гипотенуза <b>13 см</b>. Найти $h_c$.', ans:+(5*12/13).toFixed(2), hint:'h_c = 60/13 ≈ 4,62.'},
{q:'$h_c = 12$ см, $a_c = 9$ см. Найти $b_c$.', ans:16, hint:'b_c = h_c²/a_c = 144/9 = 16.'},
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 56,20" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><line x1="56" y1="20" x2="56" y2="90" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><polyline points="56,80 66,80 66,90" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="36" y="103" text-anchor="middle" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">a_c=9</text><text x="93" y="103" text-anchor="middle" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">b_c=?</text><text x="75" y="103" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace"></text><text x="136" y="55" text-anchor="end" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c=25</text><text x="64" y="55" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=?</text></svg>Гипотенуза <b>25 см</b>, $a_c = 9$ см. Найти $h_c$.', ans:12, hint:'b_c=16, h_c=√(9·16)=12.'},
];
let idx=0,score=0;
function show(){
document.getElementById('p8-tr-i').textContent=idx+1;
document.getElementById('p8-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p8-tr-ans').value='';
document.getElementById('p8-tr-fb').style.display='none';
if(window.renderMathInElement) renderMath(document.getElementById('p8-tr-task'));
}
document.getElementById('p8-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p8-tr-score').textContent=0;show();});
document.getElementById('p8-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p8-tr-ans').value;
const fb=document.getElementById('p8-tr-fb');
if(Math.abs(ans-tasks[idx].ans)<0.05){
score++;document.getElementById('p8-tr-score').textContent=score;
addXp(3,'p8-tr-'+idx);bumpProgress('p8',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p8-tr-all');bumpProgress('p8',10);}
} else {feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p8-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p8-tr-go').click();});
show();
})();
/* == INIT: Босс §8 == */
(function(){
const tasks=[
{q:'Катеты прямоугольного треугольника <b>9 и 12 дм</b>. Найти высоту к гипотенузе.', ans:+(9*12/15).toFixed(1), hint:'c=15, h_c=108/15=7,2.'},
{q:'Высота к гипотенузе равна <b>8 см</b>, проекция одного катета <b>4 см</b>. Найти проекцию другого катета.', ans:16, hint:'b_c = h_c²/a_c = 64/4 = 16.'},
{q:'Проекции катетов на гипотенузу: <b>1 и 4</b>. Найти высоту $h_c$ и гипотенузу.', ans:5, hint:'h_c=√4=2. c=5. Ответ на «гипотенуза»: 5.'},
{q:'Проекции катетов <b>4 и 9</b>. Чему равен меньший катет?', ans:6, hint:'a²=a_c·c=4·13=52, a=√52≈7.2. Нет. a²=4·13? c=13, a²=4·13=52. Нет — меньший катет: a=√(a_c·c)=√(4·13)≈7,2? Нет — проще: a=√(a_c·c)=√(4·13). Ответ: 6 (для a_c=4,b_c=9: h_c=6, a=√(4·13)≈7,2). Исправлен вопрос: чему равна h_c? Ответ: 6.'},
];
// Fix task 3 and 4 to be unambiguous
const cleanTasks=[
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 20,18" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><polyline points="32,90 32,78 20,78" fill="none" stroke="#059669" stroke-width="1.5"/><line x1="20" y1="90" x2="63" y2="54" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><text x="75" y="103" text-anchor="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=12</text><text x="10" y="54" text-anchor="middle" dominant-baseline="middle" font-size="9" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,10,54)">b=9</text><text x="82" y="54" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c=15</text><text x="30" y="70" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=?</text></svg>Катеты прямоугольного треугольника <b>9 и 12 дм</b>. Найти высоту к гипотенузе $h_c$.', ans:7.2, hint:'c=√(81+144)=15. h_c=9·12/15=7,2.'},
{q:'Высота к гипотенузе <b>$h_c = 8$</b>, $a_c = 4$. Найти $b_c$.', ans:16, hint:'b_c = 64/4 = 16.'},
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 60,20" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><line x1="60" y1="20" x2="60" y2="90" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><polyline points="60,80 70,80 70,90" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="38" y="103" text-anchor="middle" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">a_c=1</text><text x="95" y="103" text-anchor="middle" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">b_c=4</text><text x="75" y="55" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c=?</text></svg>Проекции катетов на гипотенузу: <b>1 и 4</b>. Найти гипотенузу.', ans:5, hint:'c = 1+4 = 5.'},
{q:'<svg viewBox="0 0 150 110" style="display:block;max-width:160px;margin:0 auto 8px;background:#ecfdf5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,90 130,90 67,20" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/><line x1="67" y1="20" x2="67" y2="90" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4 3"/><polyline points="67,80 77,80 77,90" fill="none" stroke="#f59e0b" stroke-width="1.2"/><text x="42" y="103" text-anchor="middle" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">a_c=4</text><text x="100" y="103" text-anchor="middle" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">b_c=9</text><text x="75" y="55" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h_c=?</text></svg>Проекции катетов <b>4 и 9</b>. Найти высоту $h_c$.', ans:6, hint:'h_c = √(4·9) = 6.'},
];
const bossBox=document.getElementById('p8-boss-tasks');
bossBox.innerHTML=cleanTasks.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="p8b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p8b-a${i}').value;
const fb=document.getElementById('p8b-fb${i}');
if(Math.abs(v-${t.ans})<0.05){
feedback(fb,true,'Верно! +5 XP');
if(!p8BossSolved.has(${i})){ p8BossSolved.add(${i}); addXp(5,'p8-boss${i}'); bumpProgress('p8',10); }
} else feedback(fb,false,'Неверно. ${t.hint}');
})()">Проверить</button>
</div>
<div class="feedback" id="p8b-fb${i}" style="display:none;margin-top:8px"></div>
</div>`).join('');
window.p8BossSolved=new Set();
})();
/* == MINI-SLIDER: Высота к гипотенузе == */
(function(){
const W=300, H=210;
const AX=20, AY=180, BX=260, BY=180;
function draw(){
const a=+document.getElementById('p8-sl-a').value;
const b=+document.getElementById('p8-sl-b').value;
document.getElementById('p8-sl-a-val').textContent=a;
document.getElementById('p8-sl-b-val').textContent=b;
const c=+Math.sqrt(a*a+b*b).toFixed(2);
const hc=+(a*b/c).toFixed(2);
const ac=+(a*a/c).toFixed(2);
const bc=+(b*b/c).toFixed(2);
// Draw triangle scaled to fit: A bottom-left, right angle at A, B along x, C up
const scX=(BX-AX)/a, scY=140/b;
const sc=Math.min(scX,scY,10);
const ax=AX, ay=AY;
const dx=AX+Math.round(a*sc), dy=AY; // D = horizontal point
const cx2=AX, cy2=AY-Math.round(b*sc); // C = vertical point
// compute H on hypotenuse CD: H = foot from A to CD
const abx=dx-cx2, aby=dy-cy2;
const tt=((ax-cx2)*abx+(ay-cy2)*aby)/(abx*abx+aby*aby);
const hx=Math.round(cx2+tt*abx), hy=Math.round(cy2+tt*aby);
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:320px;background:var(--card);border:1px solid var(--border);border-radius:12px">';
// triangle
s+='<polygon points="'+ax+','+ay+' '+dx+','+dy+' '+cx2+','+cy2+'" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2.5"/>';
s+='<polyline points="'+(ax+10)+','+ay+' '+(ax+10)+','+(ay-10)+' '+ax+','+(ay-10)+'" fill="none" stroke="#059669" stroke-width="1.5"/>';
// altitude
s+='<line x1="'+ax+'" y1="'+ay+'" x2="'+hx+'" y2="'+hy+'" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>';
// labels
s+='<text x="'+((ax+dx)/2)+'" y="'+(ay+14)+'" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(ax-14)+'" y="'+((ay+cy2)/2)+'" text-anchor="end" dominant-baseline="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b='+b+'</text>';
s+='<text x="'+((dx+cx2)/2+12)+'" y="'+((dy+cy2)/2)+'" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c='+c+'</text>';
s+='<text x="'+((ax+hx)/2+6)+'" y="'+((ay+hy)/2)+'" font-size="10" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h_c='+hc+'</text>';
s+='</svg>';
document.getElementById('p8-sl-svg-wrap').innerHTML=s;
document.getElementById('p8-sl-info').innerHTML='<div><b>a</b> = '+a+'</div><div><b>b</b> = '+b+'</div><div><b>c</b> = '+c+'</div><div style="border-top:1px solid var(--border);margin-top:4px;padding-top:4px"><b>h_c = ab/c = '+hc+'</b></div><div style="color:var(--muted);font-size:.8rem">a_c='+ac+', b_c='+bc+'</div>';
}
document.getElementById('p8-sl-a').addEventListener('input',draw);
document.getElementById('p8-sl-b').addEventListener('input',draw);
draw();
})();
}
function buildP9(){
const box=document.getElementById('p9-body');
let html='';
html+=makeCard('theory','Теорема: общая высота','9.1',`
<p>Если два треугольника имеют <b>общую высоту</b> $h$, то их площади относятся как соответствующие основания:</p>
$$\\dfrac{S_1}{S_2} = \\dfrac{a_1}{a_2}$$
<p style="margin-top:8px"><b>Доказательство:</b> $S_1=\\tfrac{1}{2}a_1 h$, $S_2=\\tfrac{1}{2}a_2 h$. Делим: $\\dfrac{S_1}{S_2}=\\dfrac{a_1}{a_2}$. $\\square$</p>
<p style="margin-top:8px"><b>Следствие:</b> если $a_1=a_2$, то $S_1=S_2$ (равные основания при общей высоте дают равные площади).</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 160" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- baseline -->
<line x1="20" y1="130" x2="260" y2="130" stroke="#e2e8f0" stroke-width="1.5"/>
<!-- triangle 1: A=20,130 B=110,130 apex=60,40 -->
<polygon points="20,130 110,130 60,40" fill="rgba(16,185,129,.18)" stroke="#059669" stroke-width="2"/>
<!-- triangle 2: A=110,130 B=220,130 apex=60,40 (shared apex) -->
<polygon points="110,130 220,130 60,40" fill="rgba(13,148,136,.18)" stroke="#0d9488" stroke-width="2"/>
<!-- height line -->
<line x1="60" y1="40" x2="60" y2="130" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5 3"/>
<!-- right angle at foot -->
<polyline points="68,130 68,122 60,122" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<!-- labels -->
<text x="65" y="128" text-anchor="middle" dominant-baseline="middle" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">H</text>
<text x="30" y="30" font-size="11" font-weight="700" fill="#065f46">h</text>
<text x="65" y="148" text-anchor="middle" font-size="11" font-weight="700" fill="#059669" font-family="JetBrains Mono,monospace">a₁</text>
<text x="165" y="148" text-anchor="middle" font-size="11" font-weight="700" fill="#0d9488" font-family="JetBrains Mono,monospace">a₂</text>
<text x="55" y="90" text-anchor="middle" font-size="10" font-weight="700" fill="#047857">S₁</text>
<text x="140" y="95" text-anchor="middle" font-size="10" font-weight="700" fill="#0f766e">S₂</text>
<text x="140" y="20" text-anchor="middle" font-size="10" fill="#475569">S₁/S₂ = a₁/a₂</text>
</svg>
</div>`);
html+=makeCard('rule','Геометрический смысл','9.2',`
<p>Треугольники $\\triangle ABС$ и $\\triangle ABD$ имеют <b>общую сторону AB</b> как основание. Точки $C$ и $D$ лежат на одной прямой, параллельной $AB$. Тогда их высоты совпадают — $h$ одинакова для обоих. Отношение площадей:</p>
$$\\dfrac{S_{\\triangle ABC}}{S_{\\triangle ABD}} = \\dfrac{BC_\\perp}{BD_\\perp} = 1 \\quad \\text{(равные площади)}$$
<p style="margin-top:8px">Если же вершины на одной горизонтали, а основания разные, отношение пропорционально основаниям.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 150" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Two triangles sharing apex A, on same baseline -->
<line x1="15" y1="125" x2="265" y2="125" stroke="#cbd5e1" stroke-width="1.2"/>
<polygon points="30,125 120,125 90,30" fill="rgba(16,185,129,.2)" stroke="#059669" stroke-width="2"/>
<polygon points="120,125 230,125 90,30" fill="rgba(13,148,136,.2)" stroke="#0d9488" stroke-width="2"/>
<line x1="90" y1="30" x2="90" y2="125" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5 3"/>
<polyline points="98,125 98,117 90,117" fill="none" stroke="#f59e0b" stroke-width="1.4"/>
<text x="75" y="125" text-anchor="middle" font-size="10" font-weight="700" fill="#059669" font-family="JetBrains Mono,monospace">a₁</text>
<text x="175" y="125" text-anchor="middle" font-size="10" font-weight="700" fill="#0d9488" font-family="JetBrains Mono,monospace">a₂</text>
<text x="75" y="85" font-size="10" font-weight="700" fill="#047857">S₁</text>
<text x="165" y="85" font-size="10" font-weight="700" fill="#0f766e">S₂</text>
<text x="140" y="16" text-anchor="middle" font-size="9" fill="#475569">Общая вершина → общая высота h</text>
<text x="100" y="16" font-size="9" fill="#b45309">h</text>
</svg>
</div>`);
html+=makeCard('example','Примеры применения','9.3',`
<p><b>Пример 1.</b> $\\triangle ABC$ и $\\triangle ABD$ имеют общую высоту. $a_1=6$, $a_2=9$, $S_1=24$. Найти $S_2$.</p>
<p style="margin-top:4px">$\\dfrac{S_1}{S_2}=\\dfrac{a_1}{a_2} \\Rightarrow S_2=S_1\\cdot\\dfrac{a_2}{a_1}=24\\cdot\\dfrac{9}{6}=36$.</p>
<p style="margin-top:10px"><b>Пример 2.</b> Точка $M$ делит $BC$ в отношении $2:3$. Чему равно $\\dfrac{S_{\\triangle ABM}}{S_{\\triangle ACM}}$?</p>
<p style="margin-top:4px">Обе имеют общую высоту из $A$. $\\dfrac{S_1}{S_2}=\\dfrac{BM}{CM}=\\dfrac{2}{3}$.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 240 140" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<polygon points="30,120 150,120 90,20" fill="none" stroke="#059669" stroke-width="2"/>
<!-- M on BC at 2:5 from B: Bx=30,By=120 Cx=150,Cy=120 -->
<!-- M = B + 2/5*(C-B) = 30+48=78, 120 -->
<line x1="90" y1="20" x2="78" y2="120" stroke="#0d9488" stroke-width="1.8" stroke-dasharray="5 3"/>
<circle cx="78" cy="120" r="3.5" fill="#0d9488"/>
<!-- height from A to BC -->
<line x1="90" y1="20" x2="90" y2="120" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="4 3"/>
<polyline points="98,120 98,112 90,112" fill="none" stroke="#f59e0b" stroke-width="1.3"/>
<text x="84" y="134" font-size="9" fill="#0d9488" font-weight="700" font-family="JetBrains Mono,monospace">M</text>
<text x="24" y="133" font-size="9" fill="#059669" font-weight="700">B</text>
<text x="152" y="133" font-size="9" fill="#059669" font-weight="700">C</text>
<text x="85" y="14" font-size="9" fill="#059669" font-weight="700">A</text>
<text x="50" y="78" font-size="10" font-weight="700" fill="#047857">S₁</text>
<text x="110" y="85" font-size="10" font-weight="700" fill="#0f766e">S₂</text>
<text x="52" y="134" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">2</text>
<text x="110" y="134" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">3</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — Draggable два треугольника с общей вершиной */
html+=`<div class="wg" id="p9-drag-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Два треугольника с общей вершиной — тяни основания</div></div>
<div class="wg-help">Тащи точки C и D вдоль горизонтали. Оба треугольника имеют общую вершину A и общую высоту. $S_1/S_2 = a_1/a_2$ обновляется мгновенно.</div>
<div id="p9-drag-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p9-drag-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Анимация доказательства */
html+=`<div class="wg" id="p9-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство шаг за шагом</div></div>
<div class="wg-help">4 шага — от двух треугольников к формуле $S_1/S_2 = a_1/a_2$.</div>
<div id="p9-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p9-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p9-proof-next">Далее</button>
<button class="btn" id="p9-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 style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a₁, a₂, S₁ → S₂</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p9-c-a1" class="tinp" placeholder="a₁" style="width:60px">
<input type="number" id="p9-c-a2" class="tinp" placeholder="a₂" style="width:60px">
<input type="number" id="p9-c-s1" class="tinp" placeholder="S₁" style="width:60px">
<button class="btn primary" id="p9-c-go1">= S₂</button>
</div>
<div id="p9-c-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S₁/S₂, a₁ → a₂</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p9-c-r1" class="tinp" placeholder="S₁" style="width:55px">
<input type="number" id="p9-c-r2" class="tinp" placeholder="S₂" style="width:55px">
<input type="number" id="p9-c-ra1" class="tinp" placeholder="a₁" style="width:55px">
<button class="btn primary" id="p9-c-go2">= a₂</button>
</div>
<div id="p9-c-out2" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §9</div></div>
<div class="wg-help">5 задач на отношения площадей при общей высоте.</div>
<div class="score-display"><span>Задача <b id="p9-tr-i">1</b> / 5</span><span>Очки: <b id="p9-tr-score">0</b></span></div>
<div id="p9-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p9-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p9-tr-go">Проверить</button>
<button class="btn" id="p9-tr-start">Начать</button>
</div>
<div class="feedback" id="p9-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Босс §9 */
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))">БОСС §9</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p9-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p9-read-btn" onclick="addXp(10,'p9-read');bumpProgress('p9',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>
Я прочитал §9 (+10 XP)
</button>
</div>`;
html+=secNav('p8','p10');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable два треугольника == */
(function(){
const W=400, H=260;
const apexX=120, apexY=40;
const baseY=210;
let B=80, C=170, D=290; // B fixed left base, C shared middle, D right base; A=apex
function clamp(v,lo,hi){return Math.max(lo,Math.min(hi,v));}
function draw(){
const a1=C-B, a2=D-C;
const h=baseY-apexY;
const S1=Math.round(a1*h/2);
const S2=Math.round(a2*h/2);
const ratio=a2>0?(+(S1/S2).toFixed(2)):0;
let s='<svg id="p9-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:420px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
// triangles
s+='<polygon points="'+B+','+baseY+' '+C+','+baseY+' '+apexX+','+apexY+'" fill="rgba(16,185,129,.2)" stroke="#059669" stroke-width="2.2"/>';
s+='<polygon points="'+C+','+baseY+' '+D+','+baseY+' '+apexX+','+apexY+'" fill="rgba(13,148,136,.2)" stroke="#0d9488" stroke-width="2.2"/>';
// height
s+='<line x1="'+apexX+'" y1="'+apexY+'" x2="'+apexX+'" y2="'+baseY+'" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5 3"/>';
s+='<polyline points="'+(apexX+8)+','+baseY+' '+(apexX+8)+','+(baseY-8)+' '+apexX+','+(baseY-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.4"/>';
// labels
s+='<text x="'+(apexX-18)+'" y="'+(apexY-4)+'" font-size="11" font-weight="700" fill="#059669">A</text>';
s+='<text x="'+Math.round((B+C)/2)+'" y="'+(baseY+18)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#059669" font-family="JetBrains Mono,monospace">a₁='+a1+'</text>';
s+='<text x="'+Math.round((C+D)/2)+'" y="'+(baseY+18)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#0d9488" font-family="JetBrains Mono,monospace">a₂='+a2+'</text>';
s+='<text x="'+Math.round((B+C+apexX)/3)+'" y="'+Math.round((baseY+baseY+apexY)/3)+'" text-anchor="middle" font-size="12" font-weight="800" fill="#047857">S₁='+S1+'</text>';
s+='<text x="'+Math.round((C+D+apexX)/3)+'" y="'+Math.round((baseY+baseY+apexY)/3)+'" text-anchor="middle" font-size="12" font-weight="800" fill="#0f766e">S₂='+S2+'</text>';
// drag C
s+='<circle cx="'+C+'" cy="'+baseY+'" r="11" fill="rgba(16,185,129,.18)"/>';
s+='<circle cx="'+C+'" cy="'+baseY+'" r="7" fill="#059669" stroke="#fff" stroke-width="2" id="p9-drag-c" style="cursor:ew-resize"/>';
// drag D
s+='<circle cx="'+D+'" cy="'+baseY+'" r="11" fill="rgba(13,148,136,.18)"/>';
s+='<circle cx="'+D+'" cy="'+baseY+'" r="7" fill="#0d9488" stroke="#fff" stroke-width="2" id="p9-drag-d" style="cursor:ew-resize"/>';
s+='</svg>';
document.getElementById('p9-drag-svg-wrap').innerHTML=s;
document.getElementById('p9-drag-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Основание a₁</div><b>${a1}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Основание a₂</div><b>${a2}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S₁</div><b style="color:#047857">${S1}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S₁/S₂</div><b style="color:#0f766e">${ratio}</b></div>`;
const hC=document.getElementById('p9-drag-c');
if(hC){
hC.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startC=C;
function onMove(e){
const svgEl=document.getElementById('p9-svg'); if(!svgEl)return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
C=clamp(Math.round(startC+(e.clientX-startX)*scale),B+20,D-20);
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);window.addEventListener('pointerup',onUp);window.addEventListener('pointercancel',onUp);
});
}
const hD=document.getElementById('p9-drag-d');
if(hD){
hD.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startD=D;
function onMove(e){
const svgEl=document.getElementById('p9-svg'); if(!svgEl)return;
const rect=svgEl.getBoundingClientRect();
const scale=W/rect.width;
D=clamp(Math.round(startD+(e.clientX-startX)*scale),C+20,370);
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);window.addEventListener('pointerup',onUp);window.addEventListener('pointercancel',onUp);
});
}
}
draw();
})();
/* == INIT: Анимация доказательства == */
(function(){
let step=0;
const W=360, H=220;
const apxX=100, apxY=30, bY=180;
const B=30, C=140, D=260;
const steps=[
{desc:'Два треугольника $\\triangle_1$ (зелёный) и $\\triangle_2$ (голубой) с общей вершиной $A$ и разными основаниями $a_1$, $a_2$.',
draw(){return '<polygon points="'+B+','+bY+' '+C+','+bY+' '+apxX+','+apxY+'" fill="rgba(16,185,129,.2)" stroke="#059669" stroke-width="2"/>'
+'<polygon points="'+C+','+bY+' '+D+','+bY+' '+apxX+','+apxY+'" fill="rgba(13,148,136,.2)" stroke="#0d9488" stroke-width="2"/>'
+'<text x="'+Math.round((B+C)/2)+'" y="'+(bY+15)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#059669">a₁</text>'
+'<text x="'+Math.round((C+D)/2)+'" y="'+(bY+15)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#0d9488">a₂</text>'
+'<text x="'+(apxX-14)+'" y="'+(apxY-4)+'" font-size="11" font-weight="700" fill="#059669">A</text>';}},
{desc:'Проводим общую высоту $h$ из $A$ перпендикулярно основаниям.',
draw(){return '<polygon points="'+B+','+bY+' '+C+','+bY+' '+apxX+','+apxY+'" fill="rgba(16,185,129,.2)" stroke="#059669" stroke-width="2"/>'
+'<polygon points="'+C+','+bY+' '+D+','+bY+' '+apxX+','+apxY+'" fill="rgba(13,148,136,.2)" stroke="#0d9488" stroke-width="2"/>'
+'<line x1="'+apxX+'" y1="'+apxY+'" x2="'+apxX+'" y2="'+bY+'" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>'
+'<polyline points="'+(apxX+8)+','+bY+' '+(apxX+8)+','+(bY-8)+' '+apxX+','+(bY-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.5"/>'
+'<text x="'+(apxX-18)+'" y="'+Math.round((apxY+bY)/2)+'" font-size="11" font-weight="700" fill="#b45309">h</text>';}},
{desc:'Записываем площади: $S_1=\\tfrac{1}{2}a_1 h$, $S_2=\\tfrac{1}{2}a_2 h$. Оба содержат $h$.',
draw(){return '<polygon points="'+B+','+bY+' '+C+','+bY+' '+apxX+','+apxY+'" fill="rgba(16,185,129,.3)" stroke="#059669" stroke-width="2"/>'
+'<polygon points="'+C+','+bY+' '+D+','+bY+' '+apxX+','+apxY+'" fill="rgba(13,148,136,.3)" stroke="#0d9488" stroke-width="2"/>'
+'<line x1="'+apxX+'" y1="'+apxY+'" x2="'+apxX+'" y2="'+bY+'" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>'
+'<text x="70" y="120" text-anchor="middle" font-size="11" font-weight="800" fill="#047857">S₁=½a₁h</text>'
+'<text x="200" y="120" text-anchor="middle" font-size="11" font-weight="800" fill="#0f766e">S₂=½a₂h</text>';}},
{desc:'Делим $S_1$ на $S_2$: $\\dfrac{S_1}{S_2}=\\dfrac{\\tfrac{1}{2}a_1 h}{\\tfrac{1}{2}a_2 h}=\\dfrac{a_1}{a_2}$. Высота сокращается!',
draw(){return '<polygon points="'+B+','+bY+' '+C+','+bY+' '+apxX+','+apxY+'" fill="rgba(16,185,129,.25)" stroke="#059669" stroke-width="2"/>'
+'<polygon points="'+C+','+bY+' '+D+','+bY+' '+apxX+','+apxY+'" fill="rgba(13,148,136,.25)" stroke="#0d9488" stroke-width="2"/>'
+'<text x="145" y="80" text-anchor="middle" font-size="13" font-weight="800" fill="#047857">S₁/S₂ = a₁/a₂</text>'
+'<line x1="60" y1="88" x2="232" y2="88" stroke="#059669" stroke-width="1.5"/>';}}
];
function render(){
const s=steps[step];
document.getElementById('p9-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:380px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p9-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p9-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement)renderMath(document.getElementById('p9-proof-desc'));
}
document.getElementById('p9-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p9-proof-step');}
else{addXp(3,'p9-proof-done');bumpProgress('p9',15);confetti();}
});
document.getElementById('p9-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p9-c-go1').addEventListener('click',()=>{
const a1=parseFloat(document.getElementById('p9-c-a1').value);
const a2=parseFloat(document.getElementById('p9-c-a2').value);
const s1=parseFloat(document.getElementById('p9-c-s1').value);
const out=document.getElementById('p9-c-out1');
if(!isFinite(a1)||!isFinite(a2)||!isFinite(s1)||a1<=0||a2<=0||s1<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const s2=s1*a2/a1;
out.innerHTML='$S_2='+fmt(s1)+'\\cdot\\dfrac{'+fmt(a2)+'}{'+fmt(a1)+'}='+fmt(s2)+'$';
renderMath(out);addXp(1,'p9-calc1');
});
document.getElementById('p9-c-go2').addEventListener('click',()=>{
const s1=parseFloat(document.getElementById('p9-c-r1').value);
const s2=parseFloat(document.getElementById('p9-c-r2').value);
const a1=parseFloat(document.getElementById('p9-c-ra1').value);
const out=document.getElementById('p9-c-out2');
if(!isFinite(s1)||!isFinite(s2)||!isFinite(a1)||s1<=0||s2<=0||a1<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const a2=a1*s2/s1;
out.innerHTML='$a_2='+fmt(a1)+'\\cdot\\dfrac{'+fmt(s2)+'}{'+fmt(s1)+'}='+fmt(a2)+'$';
renderMath(out);addXp(1,'p9-calc2');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'Два треугольника с общей высотой. Основания <b>6 и 10 см</b>, меньшая площадь <b>24 см²</b>. Большая площадь?', ans:40, hint:'S₂=24·10/6=40.'},
{q:'<svg viewBox="0 0 180 120" style="display:block;max-width:190px;margin:0 auto 8px;background:#d1fae5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,100 90,100 60,20" fill="rgba(16,185,129,.25)" stroke="#059669" stroke-width="2"/><polygon points="90,100 160,100 60,20" fill="rgba(13,148,136,.25)" stroke="#0d9488" stroke-width="2"/><text x="55" y="114" text-anchor="middle" font-size="9" font-weight="700" fill="#059669" font-family="JetBrains Mono,monospace">a₁=8</text><text x="125" y="114" text-anchor="middle" font-size="9" font-weight="700" fill="#0d9488" font-family="JetBrains Mono,monospace">a₂=12</text><text x="52" y="68" font-size="9" font-weight="700" fill="#047857">S₁=32</text><text x="105" y="68" font-size="9" font-weight="700" fill="#0f766e">S₂=?</text></svg>Основания 8 и 12, $S_1=32$. Найди $S_2$.', ans:48, hint:'S₂=32·12/8=48.'},
{q:'Точка $M$ делит сторону $BC$ в отношении $3:5$. Чему равно отношение $S_{ABM}:S_{ACM}$ ? (ответ: числитель отношения)', ans:3, hint:'Отношение площадей = отношению оснований BM:MC = 3:5, числитель = 3.'},
{q:'Два треугольника с общей высотой <b>8 см</b>. Основания <b>5 и 7 см</b>. Разность площадей?', ans:8, hint:'S₁=20, S₂=28. Разность = 8.'},
{q:'$S_1=45$, $S_2=75$, $a_1=9$. Найди $a_2$.', ans:15, hint:'a₂=9·75/45=15.'},
];
let idx=0, score=0;
function show(){
document.getElementById('p9-tr-i').textContent=idx+1;
document.getElementById('p9-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p9-tr-ans').value='';
document.getElementById('p9-tr-fb').style.display='none';
if(window.renderMathInElement)renderMath(document.getElementById('p9-tr-task'));
}
document.getElementById('p9-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p9-tr-score').textContent=0;show();});
document.getElementById('p9-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p9-tr-ans').value;
const fb=document.getElementById('p9-tr-fb');
fb.style.display='block';
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p9-tr-score').textContent=score;
addXp(3,'p9-tr-'+idx);bumpProgress('p9',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p9-tr-all');bumpProgress('p9',10);}
} else {feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p9-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p9-tr-go').click();});
show();
})();
/* == INIT: Босс §9 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 200 130" style="display:block;max-width:210px;margin:0 auto 8px;background:#d1fae5;border:1px solid #6ee7b7;border-radius:8px"><polygon points="20,110 90,110 60,20" fill="rgba(16,185,129,.25)" stroke="#059669" stroke-width="2"/><polygon points="90,110 180,110 60,20" fill="rgba(13,148,136,.25)" stroke="#0d9488" stroke-width="2"/><text x="55" y="124" text-anchor="middle" font-size="9" font-weight="700" fill="#059669" font-family="JetBrains Mono,monospace">a₁=15</text><text x="135" y="124" text-anchor="middle" font-size="9" font-weight="700" fill="#0d9488" font-family="JetBrains Mono,monospace">a₂=25</text><text x="52" y="75" font-size="9" fill="#047857">S₁=60</text><text x="120" y="75" font-size="9" fill="#0f766e">S₂=?</text></svg>Основания 15 и 25, $S_1=60$. Найти $S_2$.', ans:100, hint:'S₂=60·25/15=100.'},
{q:'Общая высота двух треугольников <b>h=8 см</b>. $S_1+S_2=100\\,\\text{см}^2$, $S_1:S_2=2:3$. Найти $a_1$.', ans:10, hint:'S₁=40, S₂=60. a₁=2S₁/h=2·40/8=10.'},
{q:'Точка $D$ на стороне $BC$ делит её так, что $BD:DC=4:6$. $S_{\\triangle ABD}=16\\,\\text{см}^2$. Найти $S_{\\triangle ADC}$.', ans:24, hint:'S₂=16·6/4=24.'},
{q:'Два треугольника с общей высотой. Площади <b>36 и 54 см²</b>. Меньшее основание <b>6 см</b>. Большее основание?', ans:9, hint:'a₂=6·54/36=9.'},
];
const bossBox=document.getElementById('p9-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="p9b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p9b-a${i}').value;
const ok=Math.abs(v-${t.ans})<0.5;
const fb=document.getElementById('p9b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p9-boss-${i}');bumpProgress('p9',8);}
})()">Проверить</button>
<span class="feedback" id="p9b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement)renderMath(bossBox);
})();
}
function buildP10(){
const box=document.getElementById('p10-body');
let html='';
html+=makeCard('theory','Теорема: медиана и площадь','10.1',`
<p><b>Теорема.</b> Медиана треугольника делит его на два <b>равновеликих</b> (равных по площади) треугольника.</p>
<p style="margin-top:8px"><b>Доказательство.</b> Пусть $AM$ — медиана треугольника $\\triangle ABC$, $M$ — середина $BC$. Тогда $BM=MC$. Оба треугольника $\\triangle ABM$ и $\\triangle ACM$ имеют общую высоту из $A$ к прямой $BC$. Основания равны: $BM=MC$. По теореме §9: $S_1=S_2$. $\\square$</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 160" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- triangle -->
<polygon points="30,135 200,135 100,25" fill="none" stroke="#0d9488" stroke-width="2"/>
<!-- median AM -->
<line x1="100" y1="25" x2="115" y2="135" stroke="#059669" stroke-width="2.5"/>
<!-- M midpoint of BC: (30+200)/2=115 -->
<circle cx="115" cy="135" r="4" fill="#059669"/>
<!-- half triangles -->
<polygon points="30,135 115,135 100,25" fill="rgba(16,185,129,.2)" stroke="none"/>
<polygon points="115,135 200,135 100,25" fill="rgba(13,148,136,.2)" stroke="none"/>
<!-- height from A -->
<line x1="100" y1="25" x2="100" y2="135" stroke="#f59e0b" stroke-width="1.2" stroke-dasharray="4 3"/>
<polyline points="108,135 108,127 100,127" fill="none" stroke="#f59e0b" stroke-width="1.3"/>
<!-- labels -->
<text x="94" y="16" font-size="11" font-weight="700" fill="#0d9488">A</text>
<text x="21" y="146" font-size="11" font-weight="700" fill="#0d9488">B</text>
<text x="200" y="146" font-size="11" font-weight="700" fill="#0d9488">C</text>
<text x="112" y="148" font-size="10" font-weight="700" fill="#059669">M</text>
<text x="62" y="95" font-size="11" font-weight="700" fill="#047857">S₁</text>
<text x="145" y="95" font-size="11" font-weight="700" fill="#0f766e">S₂</text>
<text x="130" y="16" font-size="9" fill="#475569">S₁ = S₂</text>
</svg>
</div>`);
html+=makeCard('rule','Три медианы: 6 равновеликих треугольников','10.2',`
<p>Три медианы треугольника пересекаются в точке $G$ (<b>центроид</b>), которая делит каждую медиану в отношении $2:1$ от вершины. При этом три медианы делят треугольник на <b>6 равновеликих</b> треугольников, каждый с площадью $S/6$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 180" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- A=100,20 B=20,160 C=220,160 midBC=120,160 midAC=160,90 midAB=60,90 -->
<!-- centroid G=(100+20+220)/3=340/3≈113, (20+160+160)/3=340/3≈113 -->
<polygon points="100,20 20,160 220,160" fill="none" stroke="#0d9488" stroke-width="2"/>
<!-- medians -->
<line x1="100" y1="20" x2="120" y2="160" stroke="#059669" stroke-width="1.8"/>
<line x1="20" y1="160" x2="160" y2="90" stroke="#059669" stroke-width="1.8"/>
<line x1="220" y1="160" x2="60" y2="90" stroke="#059669" stroke-width="1.8"/>
<!-- centroid: G=(100+20+220)/3,(20+160+160)/3 = 113.3,113.3 -->
<circle cx="113" cy="113" r="5" fill="#f59e0b" stroke="#fff" stroke-width="1.5"/>
<!-- 6 triangles colored alternately -->
<polygon points="100,20 120,160 113,113" fill="rgba(16,185,129,.18)" stroke="none"/>
<polygon points="120,160 220,160 113,113" fill="rgba(13,148,136,.22)" stroke="none"/>
<polygon points="220,160 160,90 113,113" fill="rgba(16,185,129,.18)" stroke="none"/>
<polygon points="160,90 100,20 113,113" fill="rgba(13,148,136,.22)" stroke="none"/>
<polygon points="100,20 60,90 113,113" fill="rgba(16,185,129,.18)" stroke="none"/>
<polygon points="60,90 20,160 113,113" fill="rgba(13,148,136,.22)" stroke="none"/>
<!-- labels -->
<text x="96" y="13" font-size="10" font-weight="700" fill="#0d9488">A</text>
<text x="10" y="170" font-size="10" font-weight="700" fill="#0d9488">B</text>
<text x="220" y="170" font-size="10" font-weight="700" fill="#0d9488">C</text>
<text x="118" y="116" font-size="10" font-weight="800" fill="#b45309">G</text>
<text x="100" y="100" text-anchor="middle" font-size="8" fill="#047857">S/6</text>
</svg>
</div>`);
html+=makeCard('example','Применение теоремы','10.3',`
<p><b>Пример 1.</b> Площадь $\\triangle ABC = 60\\,\\text{см}^2$, $AM$ — медиана. Найти $S_{\\triangle ABM}$.</p>
<p style="margin-top:4px">$S_{\\triangle ABM}=\\tfrac{S}{2}=30\\,\\text{см}^2$.</p>
<p style="margin-top:10px"><b>Пример 2.</b> Три медианы $\\triangle ABC$ делят его на 6 треугольников. Каждый имеет площадь $S/6$. При $S=48$: каждый $= 8\\,\\text{см}^2$.</p>
<p style="margin-top:10px"><b>Пример 3.</b> Точка $G$ — центроид. $S_{\\triangle ABG}:S_{\\triangle BCG}:S_{\\triangle ACG} = 1:1:1$, т.е. медианы делят треугольник на три равных.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 220 140" style="max-width:240px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<polygon points="80,15 15,125 185,125" fill="rgba(13,148,136,.12)" stroke="#0d9488" stroke-width="2"/>
<line x1="80" y1="15" x2="100" y2="125" stroke="#059669" stroke-width="2"/>
<circle cx="100" cy="125" r="3.5" fill="#059669"/>
<text x="76" y="9" font-size="10" font-weight="700" fill="#0d9488">A</text>
<text x="5" y="133" font-size="10" font-weight="700" fill="#0d9488">B</text>
<text x="185" y="133" font-size="10" font-weight="700" fill="#0d9488">C</text>
<text x="97" y="134" font-size="10" font-weight="700" fill="#059669">M</text>
<text x="48" y="80" font-size="11" font-weight="700" fill="#047857">S/2</text>
<text x="128" y="80" font-size="11" font-weight="700" fill="#0f766e">S/2</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — Draggable треугольник с медианой */
html+=`<div class="wg" id="p10-drag-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Медиана треугольника — тяни вершины</div></div>
<div class="wg-help">Тащи вершины $A$, $B$, $C$. Медиана $AM$ рисуется автоматически. $S_1$ и $S_2$ всегда равны!</div>
<div id="p10-drag-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p10-drag-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — 6 равновеликих треугольников */
html+=`<div class="wg" id="p10-six-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Три медианы — 6 равных частей</div></div>
<div class="wg-help">Нажимай «Далее», чтобы добавлять медианы и видеть разбиение. Каждая часть = $S/6$.</div>
<div id="p10-six-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p10-six-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p10-six-next">Далее</button>
<button class="btn" id="p10-six-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 style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S треугольника → S половины</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p10-c-s" class="tinp" placeholder="S" style="width:80px">
<button class="btn primary" id="p10-c-go1">= S/2</button>
</div>
<div id="p10-c-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">S треугольника → S / 6</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p10-c-s6" class="tinp" placeholder="S" style="width:80px">
<button class="btn primary" id="p10-c-go6">= S/6</button>
</div>
<div id="p10-c-out6" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §10</div></div>
<div class="wg-help">5 задач на свойства медианы и равновеликие треугольники.</div>
<div class="score-display"><span>Задача <b id="p10-tr-i">1</b> / 5</span><span>Очки: <b id="p10-tr-score">0</b></span></div>
<div id="p10-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p10-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p10-tr-go">Проверить</button>
<button class="btn" id="p10-tr-start">Начать</button>
</div>
<div class="feedback" id="p10-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Босс §10 */
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))">БОСС §10</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p10-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p10-read-btn" onclick="addXp(10,'p10-read');bumpProgress('p10',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>
Я прочитал §10 (+10 XP)
</button>
</div>`;
html+=secNav('p9','p11');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Draggable треугольник с медианой == */
(function(){
const W=400, H=280;
let pts={A:{x:180,y:30},B:{x:40,y:230},C:{x:340,y:230}};
function triArea(p1,p2,p3){return Math.abs((p2.x-p1.x)*(p3.y-p1.y)-(p3.x-p1.x)*(p2.y-p1.y))/2;}
function clampPt(p){return {x:Math.max(20,Math.min(W-20,p.x)),y:Math.max(20,Math.min(H-20,p.y))};}
function draw(){
const A=pts.A, B=pts.B, C=pts.C;
const Mx=Math.round((B.x+C.x)/2), My=Math.round((B.y+C.y)/2);
const S=triArea(A,B,C);
const S1=triArea(A,B,{x:Mx,y:My}), S2=triArea(A,C,{x:Mx,y:My});
let s='<svg id="p10-svg" viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:420px;background:var(--card);border:1px solid var(--border);border-radius:14px;touch-action:none">';
s+='<polygon points="'+B.x+','+B.y+' '+Mx+','+My+' '+A.x+','+A.y+'" fill="rgba(16,185,129,.2)" stroke="none"/>';
s+='<polygon points="'+Mx+','+My+' '+C.x+','+C.y+' '+A.x+','+A.y+'" fill="rgba(13,148,136,.2)" stroke="none"/>';
s+='<polygon points="'+A.x+','+A.y+' '+B.x+','+B.y+' '+C.x+','+C.y+'" fill="none" stroke="#0d9488" stroke-width="2.2"/>';
s+='<line x1="'+A.x+'" y1="'+A.y+'" x2="'+Mx+'" y2="'+My+'" stroke="#059669" stroke-width="2.5"/>';
s+='<circle cx="'+Mx+'" cy="'+My+'" r="5" fill="#059669" stroke="#fff" stroke-width="1.5"/>';
// vertex labels
['A','B','C'].forEach(name=>{
const p=pts[name];
const ox=name==='A'?-14:(name==='B'?-14:8);
const oy=name==='A'?-8:14;
s+='<text x="'+(p.x+ox)+'" y="'+(p.y+oy)+'" font-size="12" font-weight="700" fill="#0d9488">'+name+'</text>';
});
s+='<text x="'+(Mx+8)+'" y="'+(My+5)+'" font-size="11" font-weight="700" fill="#059669">M</text>';
s+='<text x="'+Math.round((A.x+B.x+Mx)/3)+'" y="'+Math.round((A.y+B.y+My)/3)+'" text-anchor="middle" font-size="12" font-weight="800" fill="#047857">S₁='+Math.round(S1)+'</text>';
s+='<text x="'+Math.round((A.x+C.x+Mx)/3)+'" y="'+Math.round((A.y+C.y+My)/3)+'" text-anchor="middle" font-size="12" font-weight="800" fill="#0f766e">S₂='+Math.round(S2)+'</text>';
// drag handles
Object.keys(pts).forEach(name=>{
const p=pts[name];
s+='<circle cx="'+p.x+'" cy="'+p.y+'" r="12" fill="rgba(13,148,136,.15)"/>';
s+='<circle cx="'+p.x+'" cy="'+p.y+'" r="7" fill="#0d9488" stroke="#fff" stroke-width="2" id="p10-drag-'+name+'" style="cursor:move"/>';
});
s+='</svg>';
document.getElementById('p10-drag-svg-wrap').innerHTML=s;
document.getElementById('p10-drag-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S треугольника</div><b>${Math.round(S)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S₁ (ABM)</div><b style="color:#047857">${Math.round(S1)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S₂ (ACM)</div><b style="color:#0f766e">${Math.round(S2)}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">S₁ = S₂?</div><b style="color:${Math.abs(S1-S2)<1?'#047857':'#dc2626'}">${Math.abs(S1-S2)<1?'Да!':'...'}</b></div>`;
Object.keys(pts).forEach(name=>{
const h=document.getElementById('p10-drag-'+name);
if(!h)return;
h.addEventListener('pointerdown',ev=>{
const startX=ev.clientX, startY=ev.clientY;
const origX=pts[name].x, origY=pts[name].y;
function onMove(e){
const svgEl=document.getElementById('p10-svg'); if(!svgEl)return;
const rect=svgEl.getBoundingClientRect();
const sx=W/rect.width, sy=H/rect.height;
pts[name]=clampPt({x:Math.round(origX+(e.clientX-startX)*sx),y:Math.round(origY+(e.clientY-startY)*sy)});
draw();
}
function onUp(){window.removeEventListener('pointermove',onMove);window.removeEventListener('pointerup',onUp);window.removeEventListener('pointercancel',onUp);}
window.addEventListener('pointermove',onMove);window.addEventListener('pointerup',onUp);window.addEventListener('pointercancel',onUp);
});
});
}
draw();
})();
/* == INIT: 6 равновеликих треугольников == */
(function(){
let step=0;
const W=280, H=220;
const A={x:120,y:18}, B={x:18,y:195}, C={x:240,y:195};
const Ma={x:Math.round((B.x+C.x)/2),y:Math.round((B.y+C.y)/2)};
const Mb={x:Math.round((A.x+C.x)/2),y:Math.round((A.y+C.y)/2)};
const Mc={x:Math.round((A.x+B.x)/2),y:Math.round((A.y+B.y)/2)};
const G={x:Math.round((A.x+B.x+C.x)/3),y:Math.round((A.y+B.y+C.y)/3)};
const colors=['rgba(16,185,129,.22)','rgba(13,148,136,.28)','rgba(5,150,105,.22)','rgba(13,148,136,.28)','rgba(16,185,129,.22)','rgba(13,148,136,.28)'];
const sixTri=[[A,Ma,G],[Ma,C,G],[C,Mb,G],[Mb,A,G],[A,Mc,G],[Mc,B,G]];
function ptStr(p){return p.x+','+p.y;}
function svgBase(showMedians, nColors){
let s='';
s+='<polygon points="'+ptStr(A)+' '+ptStr(B)+' '+ptStr(C)+'" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>';
if(nColors>0) sixTri.slice(0,nColors).forEach((t,i)=>{
s+='<polygon points="'+t.map(ptStr).join(' ')+'" fill="'+colors[i]+'" stroke="none"/>';
});
if(showMedians>=1) s+='<line x1="'+A.x+'" y1="'+A.y+'" x2="'+Ma.x+'" y2="'+Ma.y+'" stroke="#059669" stroke-width="2"/>';
if(showMedians>=2) s+='<line x1="'+B.x+'" y1="'+B.y+'" x2="'+Mb.x+'" y2="'+Mb.y+'" stroke="#059669" stroke-width="2"/>';
if(showMedians>=3) s+='<line x1="'+C.x+'" y1="'+C.y+'" x2="'+Mc.x+'" y2="'+Mc.y+'" stroke="#059669" stroke-width="2"/>';
if(showMedians>=1) s+='<circle cx="'+G.x+'" cy="'+G.y+'" r="4" fill="'+( showMedians>=3 ? '#f59e0b':'#999')+'" stroke="#fff" stroke-width="1.2"/>';
['A','B','C'].forEach(name=>{
const p=name==='A'?A:name==='B'?B:C;
const ox=name==='A'?-12:(name==='B'?-12:6); const oy=name==='A'?-6:14;
s+='<text x="'+(p.x+ox)+'" y="'+(p.y+oy)+'" font-size="11" font-weight="700" fill="#0d9488">'+name+'</text>';
});
if(showMedians>=3) s+='<text x="'+(G.x+6)+'" y="'+(G.y-4)+'" font-size="10" font-weight="700" fill="#b45309">G</text>';
return s;
}
const steps=[
{med:0,col:0,desc:'Исходный треугольник $\\triangle ABC$. Площадь $S$.'},
{med:1,col:2,desc:'Первая медиана $AM_A$ делит треугольник на 2 равные части по $S/2$.'},
{med:2,col:4,desc:'Вторая медиана $BM_B$ добавлена. Теперь 4 части.'},
{med:3,col:6,desc:'Третья медиана $CM_C$ завершает разбиение. Все 6 частей равны по $S/6$. Центроид $G$.'},
];
function render(){
const s=steps[step];
document.getElementById('p10-six-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:300px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+svgBase(s.med,s.col)+'</svg>';
document.getElementById('p10-six-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p10-six-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement)renderMath(document.getElementById('p10-six-desc'));
}
document.getElementById('p10-six-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p10-six-step');}
else{addXp(3,'p10-six-done');bumpProgress('p10',15);confetti();}
});
document.getElementById('p10-six-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p10-c-go1').addEventListener('click',()=>{
const s=parseFloat(document.getElementById('p10-c-s').value);
const out=document.getElementById('p10-c-out1');
if(!isFinite(s)||s<=0){out.innerHTML='<span style="color:var(--bad)">Введи S > 0.</span>';return;}
out.innerHTML='$S_{\\text{половина}}=\\dfrac{'+fmt(s)+'}{2}='+fmt(s/2)+'$';
renderMath(out);addXp(1,'p10-calc1');
});
document.getElementById('p10-c-go6').addEventListener('click',()=>{
const s=parseFloat(document.getElementById('p10-c-s6').value);
const out=document.getElementById('p10-c-out6');
if(!isFinite(s)||s<=0){out.innerHTML='<span style="color:var(--bad)">Введи S > 0.</span>';return;}
out.innerHTML='$S_{\\text{часть}}=\\dfrac{'+fmt(s)+'}{6}='+fmt(+(s/6).toFixed(4))+'$';
renderMath(out);addXp(1,'p10-calc6');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'Площадь $\\triangle ABC = 56\\,\\text{см}^2$, $AM$ — медиана. Найти $S_{\\triangle ABM}$.', ans:28, hint:'S_ABM = 56/2 = 28.'},
{q:'Три медианы делят $\\triangle ABC$ на 6 равных частей. $S = 72$. Площадь каждой части?', ans:12, hint:'72/6 = 12.'},
{q:'<svg viewBox="0 0 180 120" style="display:block;max-width:190px;margin:0 auto 8px;background:#ccfbf1;border:1px solid #5eead4;border-radius:8px"><polygon points="80,12 15,108 155,108" fill="rgba(13,148,136,.18)" stroke="#0d9488" stroke-width="2"/><line x1="80" y1="12" x2="85" y2="108" stroke="#059669" stroke-width="2.5"/><circle cx="85" cy="108" r="3.5" fill="#059669"/><text x="75" y="7" font-size="9" fill="#0d9488" font-weight="700">A</text><text x="6" y="116" font-size="9" fill="#0d9488" font-weight="700">B</text><text x="156" y="116" font-size="9" fill="#0d9488" font-weight="700">C</text><text x="82" y="116" font-size="9" fill="#059669" font-weight="700">M</text><text x="36" y="70" font-size="10" fill="#047857">S₁=?</text><text x="105" y="70" font-size="10" fill="#0f766e">S₂=?</text></svg>$S_{\\triangle ABC}=88$. Медиана $AM$. Найти $S_{\\triangle ACM}$.', ans:44, hint:'S_ACM = 88/2 = 44.'},
{q:'Медиана $BM$ делит $\\triangle ABC$ на два треугольника, каждый со стороной $BM$. $S_{\\triangle ABM}=30$. Какова $S_{\\triangle ABC}$?', ans:60, hint:'S_ABC = 2·30 = 60.'},
{q:'Центроид $G$ делит медиану $AM$ в отношении $AG:GM=2:1$. $S_{\\triangle ABG}=14$. Найти $S_{\\triangle ABC}$.', ans:42, hint:'Треугольники ABG, BCG, ACG равновелики, S_ABC = 3·14 = 42.'},
];
let idx=0, score=0;
function show(){
document.getElementById('p10-tr-i').textContent=idx+1;
document.getElementById('p10-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p10-tr-ans').value='';
document.getElementById('p10-tr-fb').style.display='none';
if(window.renderMathInElement)renderMath(document.getElementById('p10-tr-task'));
}
document.getElementById('p10-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p10-tr-score').textContent=0;show();});
document.getElementById('p10-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p10-tr-ans').value;
const fb=document.getElementById('p10-tr-fb');
fb.style.display='block';
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p10-tr-score').textContent=score;
addXp(3,'p10-tr-'+idx);bumpProgress('p10',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p10-tr-all');bumpProgress('p10',10);}
} else {feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p10-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p10-tr-go').click();});
show();
})();
/* == INIT: Босс §10 == */
(function(){
const tasks=[
{q:'$S_{\\triangle ABC}=120$. Медианы $AM$, $BK$, $CL$ пересекаются в $G$. Найти $S_{\\triangle ABG}$.', ans:40, hint:'Три медианы делят на 3 равные части: 120/3 = 40.'},
{q:'$S_{\\triangle ABM}=35$, где $AM$ — медиана. Найти $S_{\\triangle ABC}$.', ans:70, hint:'S_ABC = 2·35 = 70.'},
{q:'Три медианы делят $\\triangle ABC$ на 6 частей, каждая $= 18\\,\\text{см}^2$. Найти $S_{\\triangle ABC}$.', ans:108, hint:'S = 6·18 = 108.'},
{q:'Точка $M$ — середина $BC$. Точка $N$ — середина $AM$. Найти $S_{\\triangle ABN}$, если $S_{\\triangle ABC}=80$.', ans:20, hint:'S_ABM=40, N — середина AM, S_ABN = S_ABM/2 = 20.'},
];
const bossBox=document.getElementById('p10-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="p10b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p10b-a${i}').value;
const ok=Math.abs(v-${t.ans})<0.5;
const fb=document.getElementById('p10b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p10-boss-${i}');bumpProgress('p10',8);}
})()">Проверить</button>
<span class="feedback" id="p10b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement)renderMath(bossBox);
})();
}
function buildP11(){
const box=document.getElementById('p11-body');
let html='';
html+=makeCard('theory','Теорема Пифагора','11.1',`
<p><b>Теорема.</b> В прямоугольном треугольнике квадрат гипотенузы равен сумме квадратов катетов:</p>
$$c^2 = a^2 + b^2$$
<p style="margin-top:8px">где $a$, $b$ — катеты, $c$ — гипотенуза.</p>
<p style="margin-top:8px"><b>Важно:</b> гипотенуза — сторона, лежащая напротив прямого угла. Всегда наибольшая из трёх сторон.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 200 255" style="max-width:220px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- right triangle: R=(65,150) B=(145,150) A=(65,90). a=80px horiz, b=60px vert -->
<polygon points="65,150 145,150 65,90" fill="rgba(22,163,74,.18)" stroke="#16a34a" stroke-width="2.2"/>
<!-- right angle at R=(65,150): arms along +x and -y -->
<polyline points="79,150 79,136 65,136" fill="none" stroke="#16a34a" stroke-width="1.8"/>
<!-- square on a (80x80) below base: x=65..145, y=150..230 -->
<rect x="65" y="150" width="80" height="80" fill="rgba(22,163,74,.22)" stroke="#16a34a" stroke-width="1.5"/>
<text x="105" y="194" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a²</text>
<!-- square on b (60x60) left of vertical leg: x=5..65, y=90..150 -->
<rect x="5" y="90" width="60" height="60" fill="rgba(13,148,136,.22)" stroke="#0d9488" stroke-width="1.5"/>
<text x="35" y="120" text-anchor="middle" dominant-baseline="middle" font-size="11" font-weight="700" fill="#0f766e" font-family="JetBrains Mono,monospace">b²</text>
<!-- hypotenuse label midpoint: ((145+65)/2, (150+90)/2)=(105,120) -->
<text x="116" y="114" text-anchor="middle" font-size="11" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">c</text>
<!-- side labels -->
<text x="105" y="245" text-anchor="middle" font-size="10" font-weight="700" fill="#15803d">a</text>
<text x="58" y="122" text-anchor="end" font-size="10" font-weight="700" fill="#0f766e">b</text>
<!-- vertex labels -->
<text x="51" y="87" font-size="10" font-weight="700" fill="#15803d">A</text>
<text x="51" y="163" font-size="10" font-weight="700" fill="#15803d">R</text>
<text x="148" y="163" font-size="10" font-weight="700" fill="#15803d">B</text>
<text x="105" y="20" text-anchor="middle" font-size="11" font-weight="800" fill="#15803d">a²+b²=c²</text>
</svg>
</div>`);
html+=makeCard('rule','Классическое доказательство','11.2',`
<p>Возьмём квадрат со стороной $(a+b)$. Внутри расположим 4 одинаковых прямоугольных треугольника с катетами $a$, $b$.</p>
<p style="margin-top:6px"><b>Способ 1:</b> Внутри остаётся квадрат с диагональю $c$ → площадь $= c^2$.</p>
<p style="margin-top:4px">$S_{\\text{большой}} = (a+b)^2 = a^2+2ab+b^2$</p>
<p style="margin-top:4px">$S_{\\text{4 треугольника}} = 4\\cdot\\dfrac{ab}{2} = 2ab$</p>
<p style="margin-top:4px">$c^2 = (a+b)^2 - 2ab = a^2+b^2$. $\\square$</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 240 200" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Big square (a+b)=160 side, top-left at (20,20) -->
<rect x="20" y="20" width="160" height="160" fill="none" stroke="#16a34a" stroke-width="2"/>
<!-- a=100 b=60, 4 triangles inside leaving inner square of side c -->
<!-- Vertices of inner square: (20+60,20)=(80,20),(20+160,20+60)=(180,80),(20+100,20+160)=(120,180),(20,20+100)=(20,120) -->
<polygon points="80,20 180,80 120,180 20,120" fill="rgba(22,163,74,.25)" stroke="#16a34a" stroke-width="2"/>
<!-- 4 triangles: TL (20,20)(80,20)(20,120); TR (80,20)(180,20)(180,80); BR(180,80)(180,180)(120,180); BL(20,120)(120,180)(20,180) -->
<polygon points="20,20 80,20 20,120" fill="rgba(13,148,136,.28)" stroke="#0d9488" stroke-width="1.2"/>
<polygon points="80,20 180,20 180,80" fill="rgba(13,148,136,.28)" stroke="#0d9488" stroke-width="1.2"/>
<polygon points="180,80 180,180 120,180" fill="rgba(13,148,136,.28)" stroke="#0d9488" stroke-width="1.2"/>
<polygon points="20,120 120,180 20,180" fill="rgba(13,148,136,.28)" stroke="#0d9488" stroke-width="1.2"/>
<!-- labels -->
<text x="100" y="105" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#15803d">c²</text>
<text x="32" y="68" font-size="10" font-weight="700" fill="#0f766e">b</text>
<text x="50" y="14" font-size="10" font-weight="700" fill="#0f766e">a</text>
<text x="190" y="50" font-size="10" font-weight="700" fill="#0f766e">b</text>
<text x="100" y="14" text-anchor="middle" font-size="10" fill="#475569">(a+b)</text>
</svg>
</div>`);
html+=makeCard('example','Применение теоремы Пифагора','11.3',`
<p><b>Пример 1.</b> Катеты $3$ и $4$. Найти гипотенузу.</p>
<p style="margin-top:4px">$c=\\sqrt{3^2+4^2}=\\sqrt{9+16}=\\sqrt{25}=5$.</p>
<p style="margin-top:10px"><b>Пример 2.</b> Гипотенуза $13$, катет $5$. Найти другой катет.</p>
<p style="margin-top:4px">$b=\\sqrt{13^2-5^2}=\\sqrt{169-25}=\\sqrt{144}=12$.</p>
<p style="margin-top:10px"><b>Пример 3.</b> Диагональ прямоугольника $10$, одна сторона $6$. Вторая сторона?</p>
<p style="margin-top:4px">$b=\\sqrt{10^2-6^2}=\\sqrt{100-36}=\\sqrt{64}=8$.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 240 140" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- classic 3-4-5 triangle -->
<polygon points="30,120 150,120 30,40" fill="rgba(22,163,74,.2)" stroke="#16a34a" stroke-width="2.2"/>
<polyline points="44,120 44,106 30,106" fill="none" stroke="#16a34a" stroke-width="1.8"/>
<text x="90" y="136" text-anchor="middle" font-size="12" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a = 4</text>
<text x="14" y="80" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace" transform="rotate(-90,14,80)">b = 3</text>
<text x="100" y="76" font-size="11" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">c = 5</text>
<text x="85" y="100" text-anchor="middle" font-size="12" font-weight="800" fill="#166534">3²+4²=5²</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — Слайдер + квадраты на сторонах */
html+=`<div class="wg" id="p11-sq-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Квадраты на сторонах — тяни слайдеры</div></div>
<div class="wg-help">Меняй катеты — квадраты пересчитываются. Маленькие квадраты $a^2 + b^2$ равны большому $c^2$.</div>
<div class="sliders">
<label>Катет a = <b id="p11-sl-a-val">3</b>
<input type="range" min="1" max="15" value="3" id="p11-sl-a">
</label>
<label>Катет b = <b id="p11-sl-b-val">4</b>
<input type="range" min="1" max="15" value="4" id="p11-sl-b">
</label>
</div>
<div id="p11-sq-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p11-sq-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Анимация доказательства */
html+=`<div class="wg" id="p11-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство: квадрат (a+b)</div></div>
<div class="wg-help">5 шагов — классическое доказательство через два больших квадрата.</div>
<div id="p11-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p11-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p11-proof-next">Далее</button>
<button class="btn" id="p11-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 style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">a, b → c</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p11-ca" class="tinp" placeholder="a" style="width:65px">
<input type="number" id="p11-cb" class="tinp" placeholder="b" style="width:65px">
<button class="btn primary" id="p11-go1">= c</button>
</div>
<div id="p11-out1" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">c, a → b</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p11-cc" class="tinp" placeholder="c" style="width:65px">
<input type="number" id="p11-ca2" class="tinp" placeholder="a" style="width:65px">
<button class="btn primary" id="p11-go2">= b</button>
</div>
<div id="p11-out2" style="font-size:.92rem"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">Диагональ прямоугольника a×b</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p11-da" class="tinp" placeholder="a" style="width:65px">
<input type="number" id="p11-db" class="tinp" placeholder="b" style="width:65px">
<button class="btn primary" id="p11-go3">= d</button>
</div>
<div id="p11-out3" style="font-size:.92rem"></div>
</div>
</div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §11</div></div>
<div class="wg-help">5 задач — гипотенуза, катет, диагональ.</div>
<div class="score-display"><span>Задача <b id="p11-tr-i">1</b> / 5</span><span>Очки: <b id="p11-tr-score">0</b></span></div>
<div id="p11-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p11-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p11-tr-go">Проверить</button>
<button class="btn" id="p11-tr-start">Начать</button>
</div>
<div class="feedback" id="p11-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — DnD тройки Пифагора */
html+=`<div class="wg" id="p11-dnd-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:1fr 1fr;gap:12px;margin-bottom:10px">
<div class="drop-zone" style="border:2px dashed #16a34a;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#15803d;margin-bottom:6px;text-align:center">Тройка Пифагора</div>
<div class="drop-items" data-cat="yes" style="min-height:50px"></div>
</div>
<div class="drop-zone" style="border:2px dashed #dc2626;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#dc2626;margin-bottom:6px;text-align:center">Не тройка</div>
<div class="drop-items" data-cat="no" style="min-height:50px"></div>
</div>
</div>
<div id="p11-dnd-pool" style="margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn primary" id="p11-dnd-check">Проверить</button>
<button class="btn" id="p11-dnd-reset">Сброс</button>
</div>
<div class="feedback" id="p11-dnd-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §11 */
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))">БОСС §11</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">5 задач — +5 XP каждая.</div>
<div id="p11-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p11-read-btn" onclick="addXp(10,'p11-read');bumpProgress('p11',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>
Я прочитал §11 (+10 XP)
</button>
</div>`;
html+=secNav('p10','p12');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Слайдер квадраты == */
(function(){
const slA=document.getElementById('p11-sl-a');
const slB=document.getElementById('p11-sl-b');
const W=360, H=300;
function draw(){
const a=+slA.value, b=+slB.value;
document.getElementById('p11-sl-a-val').textContent=a;
document.getElementById('p11-sl-b-val').textContent=b;
const c=Math.sqrt(a*a+b*b);
// Dynamic scale: fit triangle + squares for side a (below) and side b (left)
// Total width needed: bx(square-b) + ax(triangle) + margin
// Total height needed: by(triangle) + ax(square-a) + margin
const maxSide=Math.max(a,b);
const scale=Math.min(9, Math.floor(160/maxSide));
const ax=a*scale, bx=b*scale;
const clen=+c.toFixed(3);
// Place right-angle vertex R so square-b (bx×bx) fits left and square-a (ax×ax) fits below
// Rx=bx+20 ensures square-b starts at x=20; Ry=bx+20 gives apex A at y=20
const Rx=bx+20, Ry=bx+20;
const Bx=Rx+ax, By=Ry;
const Ax=Rx, Ay=Ry-bx; // vertical leg: A is bx above R
const H_dyn=Ry+ax+30; // height: R + square-a height + label margin
const W_dyn=Rx+ax+30; // width: R + hyp end + margin
let s='<svg viewBox="0 0 '+W_dyn+' '+H_dyn+'" style="width:100%;max-width:380px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
// triangle
s+='<polygon points="'+Rx+','+Ry+' '+Bx+','+By+' '+Ax+','+Ay+'" fill="rgba(22,163,74,.25)" stroke="#16a34a" stroke-width="2.5"/>';
// right angle at R: arms +x and -y
s+='<polyline points="'+(Rx+10)+','+Ry+' '+(Rx+10)+','+(Ry-10)+' '+Rx+','+(Ry-10)+'" fill="none" stroke="#16a34a" stroke-width="1.8"/>';
// square on a (ax × ax) below base: R=(Rx,Ry)→B=(Bx,Ry), extend down
s+='<rect x="'+Rx+'" y="'+Ry+'" width="'+ax+'" height="'+ax+'" fill="rgba(22,163,74,.22)" stroke="#16a34a" stroke-width="1.5"/>';
s+='<text x="'+(Rx+ax/2)+'" y="'+(Ry+ax/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="'+Math.max(8,Math.min(12,ax*0.14))+'" font-weight="700" fill="#15803d">a²='+a*a+'</text>';
// square on b (bx × bx) left of vertical leg: A=(Rx,Ry-bx)→R=(Rx,Ry), extend left
s+='<rect x="'+(Rx-bx)+'" y="'+(Ry-bx)+'" width="'+bx+'" height="'+bx+'" fill="rgba(13,148,136,.22)" stroke="#0d9488" stroke-width="1.5"/>';
s+='<text x="'+(Rx-bx/2)+'" y="'+(Ry-bx/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="'+Math.max(8,Math.min(12,bx*0.14))+'" font-weight="700" fill="#0f766e">b²='+b*b+'</text>';
// labels
s+='<text x="'+(Rx+ax/2)+'" y="'+(Ry+ax+14)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a='+a+'</text>';
s+='<text x="'+(Rx-bx-4)+'" y="'+(Ry-bx/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#0f766e" font-family="JetBrains Mono,monospace" transform="rotate(-90,'+(Rx-bx-4)+','+(Ry-bx/2)+')">b='+b+'</text>';
s+='<text x="'+Math.round((Bx+Ax)/2+8)+'" y="'+Math.round((By+Ay)/2)+'" text-anchor="start" font-size="11" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">c='+clen+'</text>';
s+='</svg>';
document.getElementById('p11-sq-svg-wrap').innerHTML=s;
document.getElementById('p11-sq-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">a²</div><b>${a*a}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">b²</div><b>${b*b}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">a²+b²</div><b>${a*a+b*b}</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">c = √(a²+b²)</div><b style="color:#15803d">${clen}</b></div>`;
}
slA.addEventListener('input',draw);
slB.addEventListener('input',draw);
draw();
})();
/* == INIT: Анимация доказательства == */
(function(){
let step=0;
const W=360, H=240;
const S=160, off=20; // big square side, offset
// a=100, b=60 in px (a+b=160)
const a=100, b=60;
// 4 triangle vertices in big square at off,off:
// TL: (off,off+a)-(off,off)-(off+b,off)
// TR: (off+b,off)-(off+S,off)-(off+S,off+b)... wait use standard rotation:
// Let inner square vertices at: (off+b,off),(off+S,off+a),(off+a,off+S),(off,off+b)
const iv=[[off+b,off],[off+S,off+a],[off+a,off+S],[off,off+b]];
function ivStr(){return iv.map(p=>p[0]+','+p[1]).join(' ');}
const triStroke='#0d9488';
const triFill='rgba(13,148,136,.28)';
function drawTris(){
return '<polygon points="'+off+','+(off+a)+' '+off+','+off+' '+(off+b)+','+off+'" fill="'+triFill+'" stroke="'+triStroke+'" stroke-width="1.2"/>'
+'<polygon points="'+(off+b)+','+off+' '+(off+S)+','+off+' '+(off+S)+','+(off+a)+'" fill="'+triFill+'" stroke="'+triStroke+'" stroke-width="1.2"/>'
+'<polygon points="'+(off+S)+','+(off+a)+' '+(off+S)+','+(off+S)+' '+(off+a)+','+(off+S)+'" fill="'+triFill+'" stroke="'+triStroke+'" stroke-width="1.2"/>'
+'<polygon points="'+off+','+(off+b)+' '+(off+a)+','+(off+S)+' '+off+','+(off+S)+'" fill="'+triFill+'" stroke="'+triStroke+'" stroke-width="1.2"/>';
}
const steps=[
{desc:'Большой квадрат со стороной $(a+b)$. Площадь $(a+b)^2$.',
draw(){return '<rect x="'+off+'" y="'+off+'" width="'+S+'" height="'+S+'" fill="rgba(22,163,74,.10)" stroke="#16a34a" stroke-width="2.5"/>'
+'<text x="'+(off+S/2)+'" y="'+(off+S+14)+'" text-anchor="middle" font-size="11" font-weight="700" fill="#15803d">(a+b)</text>';}},
{desc:'Внутри расположим 4 прямоугольных треугольника с катетами $a$ и $b$ (голубые).',
draw(){return '<rect x="'+off+'" y="'+off+'" width="'+S+'" height="'+S+'" fill="none" stroke="#16a34a" stroke-width="2"/>'+drawTris();}},
{desc:'Внутри треугольников остаётся квадрат со стороной $c$ (гипотенуза). Его площадь $= c^2$.',
draw(){return '<rect x="'+off+'" y="'+off+'" width="'+S+'" height="'+S+'" fill="none" stroke="#16a34a" stroke-width="2"/>'+drawTris()
+'<polygon points="'+ivStr()+'" fill="rgba(22,163,74,.35)" stroke="#16a34a" stroke-width="2.2"/>'
+'<text x="'+(off+S/2)+'" y="'+(off+S/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="800" fill="#15803d">c²</text>';}},
{desc:'Площадь 4 треугольников $= 4\\cdot\\dfrac{ab}{2}=2ab$.',
draw(){return '<rect x="'+off+'" y="'+off+'" width="'+S+'" height="'+S+'" fill="rgba(22,163,74,.08)" stroke="#16a34a" stroke-width="2"/>'+drawTris()
+'<text x="'+(off+18)+'" y="'+(off+16)+'" font-size="10" fill="#0f766e">4·(ab/2)=2ab</text>';}},
{desc:'$c^2 = (a+b)^2 - 2ab = a^2+2ab+b^2-2ab = a^2+b^2$. Теорема доказана! $\\square$',
draw(){return '<rect x="'+off+'" y="'+off+'" width="'+S+'" height="'+S+'" fill="rgba(22,163,74,.06)" stroke="#16a34a" stroke-width="2"/>'+drawTris()
+'<polygon points="'+ivStr()+'" fill="rgba(22,163,74,.35)" stroke="#16a34a" stroke-width="2.2"/>'
+'<text x="'+(off+S/2)+'" y="'+(off+S/2-8)+'" text-anchor="middle" font-size="12" font-weight="800" fill="#15803d">c²=a²+b²</text>'
+'<text x="'+(off+S/2)+'" y="'+(off+S/2+10)+'" text-anchor="middle" font-size="10" fill="#15803d">Q.E.D.</text>';}},
];
function render(){
const s=steps[step];
document.getElementById('p11-proof-svg-wrap').innerHTML='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:380px;background:var(--card);border:1px solid var(--border);border-radius:14px">'+s.draw()+'</svg>';
document.getElementById('p11-proof-desc').innerHTML='<b>Шаг '+(step+1)+' / '+steps.length+'.</b> '+s.desc;
document.getElementById('p11-proof-next').textContent=step<steps.length-1?'Далее':'Готово!';
if(window.renderMathInElement)renderMath(document.getElementById('p11-proof-desc'));
}
document.getElementById('p11-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p11-proof-step');}
else{addXp(3,'p11-proof-done');bumpProgress('p11',15);confetti();}
});
document.getElementById('p11-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p11-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p11-ca').value);
const b=parseFloat(document.getElementById('p11-cb').value);
const out=document.getElementById('p11-out1');
if(!isFinite(a)||!isFinite(b)||a<=0||b<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const c=Math.sqrt(a*a+b*b);
out.innerHTML='$c=\\sqrt{'+fmt(a)+'{}^2+'+fmt(b)+'{}^2}=\\sqrt{'+fmt(a*a+b*b)+'}='+fmt(+c.toFixed(4))+'$';
renderMath(out);addXp(1,'p11-calc1');
});
document.getElementById('p11-go2').addEventListener('click',()=>{
const c=parseFloat(document.getElementById('p11-cc').value);
const a=parseFloat(document.getElementById('p11-ca2').value);
const out=document.getElementById('p11-out2');
if(!isFinite(c)||!isFinite(a)||c<=0||a<=0||c<=a){out.innerHTML='<span style="color:var(--bad)">c должна быть больше a.</span>';return;}
const b=Math.sqrt(c*c-a*a);
out.innerHTML='$b=\\sqrt{'+fmt(c)+'{}^2-'+fmt(a)+'{}^2}=\\sqrt{'+fmt(c*c-a*a)+'}='+fmt(+b.toFixed(4))+'$';
renderMath(out);addXp(1,'p11-calc2');
});
document.getElementById('p11-go3').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p11-da').value);
const b=parseFloat(document.getElementById('p11-db').value);
const out=document.getElementById('p11-out3');
if(!isFinite(a)||!isFinite(b)||a<=0||b<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительные числа.</span>';return;}
const d=Math.sqrt(a*a+b*b);
out.innerHTML='$d=\\sqrt{'+fmt(a)+'{}^2+'+fmt(b)+'{}^2}='+fmt(+d.toFixed(4))+'$';
renderMath(out);addXp(1,'p11-calc3');
});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 140 110" style="display:block;max-width:150px;margin:0 auto 8px;background:#dcfce7;border:1px solid #86efac;border-radius:8px"><polygon points="18,90 118,90 18,20" fill="rgba(22,163,74,.2)" stroke="#16a34a" stroke-width="2"/><polyline points="30,90 30,78 18,78" fill="none" stroke="#16a34a" stroke-width="1.5"/><text x="68" y="104" text-anchor="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a = 5</text><text x="8" y="55" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,55)">b=12</text><text x="78" y="62" text-anchor="middle" font-size="11" font-weight="700" fill="#166534">c=?</text></svg>Катеты <b>5 и 12</b>. Гипотенуза?', ans:13, hint:'√(25+144)=√169=13.'},
{q:'<svg viewBox="0 0 140 110" style="display:block;max-width:150px;margin:0 auto 8px;background:#dcfce7;border:1px solid #86efac;border-radius:8px"><polygon points="18,90 118,90 18,20" fill="rgba(22,163,74,.2)" stroke="#16a34a" stroke-width="2"/><polyline points="30,90 30,78 18,78" fill="none" stroke="#16a34a" stroke-width="1.5"/><text x="68" y="104" text-anchor="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a = 9</text><text x="8" y="55" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,55)">b=?</text><text x="75" y="52" font-size="9" fill="#166534">c=15</text></svg>Катет <b>9</b>, гипотенуза <b>15</b>. Второй катет?', ans:12, hint:'√(22581)=√144=12.'},
{q:'<svg viewBox="0 0 150 100" style="display:block;max-width:160px;margin:0 auto 8px;background:#dcfce7;border:1px solid #86efac;border-radius:8px"><rect x="15" y="15" width="120" height="70" fill="rgba(22,163,74,.15)" stroke="#16a34a" stroke-width="2"/><line x1="15" y1="15" x2="135" y2="85" stroke="#f59e0b" stroke-width="2.2" stroke-dasharray="5 3"/><text x="75" y="94" text-anchor="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a = 6 см</text><text x="4" y="50" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace" transform="rotate(-90,4,50)">b=8</text><text x="75" y="50" text-anchor="middle" font-size="10" font-weight="700" fill="#b45309">d=?</text></svg>Прямоугольник <b>6×8 см</b>. Диагональ?', ans:10, hint:'d=√(36+64)=√100=10.'},
{q:'Квадрат со стороной <b>7 см</b>. Диагональ? (Ответ в формате, используй √2≈1,414, ответ округли до целых)', ans:10, hint:'d=7√2≈9,9≈10.'},
{q:'Катет <b>6 дм</b>, гипотенуза <b>10 дм</b>. Другой катет?', ans:8, hint:'b=√(10036)=√64=8.'},
];
let idx=0, score=0;
function show(){
document.getElementById('p11-tr-i').textContent=idx+1;
document.getElementById('p11-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p11-tr-ans').value='';
document.getElementById('p11-tr-fb').style.display='none';
if(window.renderMathInElement)renderMath(document.getElementById('p11-tr-task'));
}
document.getElementById('p11-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p11-tr-score').textContent=0;show();});
document.getElementById('p11-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p11-tr-ans').value;
const fb=document.getElementById('p11-tr-fb');
fb.style.display='block';
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p11-tr-score').textContent=score;
addXp(3,'p11-tr-'+idx);bumpProgress('p11',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p11-tr-all');bumpProgress('p11',10);}
} else {feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p11-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p11-tr-go').click();});
show();
})();
/* == INIT: DnD тройки Пифагора == */
(function(){
function isPyth(a,b,c){const s=[a,b,c].sort((x,y)=>x-y);return s[0]*s[0]+s[1]*s[1]===s[2]*s[2];}
const items=[
{id:'t1',html:'3, 4, 5',cat:'yes'},
{id:'t2',html:'5, 12, 13',cat:'yes'},
{id:'t3',html:'6, 8, 10',cat:'yes'},
{id:'t4',html:'7, 24, 25',cat:'yes'},
{id:'t5',html:'2, 3, 4',cat:'no'},
{id:'t6',html:'1, 1, 2',cat:'no'},
{id:'t7',html:'9, 12, 15',cat:'yes'},
{id:'t8',html:'4, 5, 7',cat:'no'},
];
const sorter=setupSorter({poolId:'p11-dnd-pool',scopeSelector:'#p11-dnd-wg',
items:items.map(x=>({id:x.id,html:x.html})),
cats:['yes','no']});
document.getElementById('p11-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p11-dnd-fb');
fb.style.display='block';
let ok=0,total=0;
items.forEach(it=>{
if(sorter.placed[it.id]!==undefined){total++;if(sorter.placed[it.id]===it.cat)ok++;}
});
if(ok===items.length){feedback(fb,true,'Всё верно! +5 XP');addXp(5,'p11-dnd');bumpProgress('p11',10);confetti();}
else{feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Проверь: (3,4,5),(5,12,13),(6,8,10),(7,24,25),(9,12,15) — тройки.');}
});
document.getElementById('p11-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p11-dnd-fb').style.display='none';});
})();
/* == INIT: Босс §11 == */
(function(){
const tasks=[
{q:'<svg viewBox="0 0 160 120" style="display:block;max-width:170px;margin:0 auto 8px;background:#dcfce7;border:1px solid #86efac;border-radius:8px"><polygon points="20,100 140,100 20,20" fill="rgba(22,163,74,.2)" stroke="#16a34a" stroke-width="2"/><polyline points="34,100 34,86 20,86" fill="none" stroke="#16a34a" stroke-width="1.5"/><text x="80" y="114" text-anchor="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a=24</text><text x="8" y="60" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,60)">b=10</text><text x="95" y="65" text-anchor="middle" font-size="11" font-weight="700" fill="#166534">c=?</text></svg>Катеты <b>10 и 24</b>. Гипотенуза?', ans:26, hint:'√(100+576)=√676=26.'},
{q:'<svg viewBox="0 0 160 110" style="display:block;max-width:170px;margin:0 auto 8px;background:#dcfce7;border:1px solid #86efac;border-radius:8px"><rect x="20" y="15" width="120" height="75" fill="rgba(22,163,74,.15)" stroke="#16a34a" stroke-width="2"/><line x1="20" y1="15" x2="140" y2="90" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/><text x="80" y="102" text-anchor="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace">a=? см</text><text x="8" y="52" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#15803d" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,52)">b=9</text><text x="75" y="52" text-anchor="middle" font-size="9" fill="#b45309">d=15</text></svg>Диагональ прямоугольника <b>15 см</b>, одна сторона <b>9 см</b>. Другая сторона?', ans:12, hint:'a=√(22581)=√144=12.'},
{q:'Равнобедренный прямоугольный треугольник, гипотенуза <b>10√2 ≈ 14,1</b>. Катет? (целое число)', ans:10, hint:'a²+a²=(10√2)²=200 → a²=100 → a=10.'},
{q:'В прямоугольном треугольнике гипотенуза <b>25</b>, один катет <b>7</b>. Площадь треугольника?', ans:84, hint:'b=√(62549)=√576=24. S=7·24/2=84.'},
{q:'Квадрат со стороной <b>5 м</b>. Диагональ (целое число, используй √2≈1,414)?', ans:7, hint:'d=5√2≈7,07≈7.'},
];
const bossBox=document.getElementById('p11-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="p11b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p11b-a${i}').value;
const ok=Math.abs(v-${t.ans})<1.5;
const fb=document.getElementById('p11b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p11-boss-${i}');bumpProgress('p11',8);}
})()">Проверить</button>
<span class="feedback" id="p11b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement)renderMath(bossBox);
})();
}
function buildP12(){
const box=document.getElementById('p12-body');
let html='';
html+=makeCard('theory','Равносторонний треугольник','12.1',`
<p><b>Равносторонний треугольник</b> — треугольник, у которого все три стороны равны: $AB=BC=CA=a$.</p>
<p style="margin-top:8px">Все углы равны $60°$. Высота, медиана, биссектриса из каждой вершины совпадают.</p>
<p style="margin-top:8px"><b>Высота:</b> $h = \\dfrac{a\\sqrt{3}}{2}$</p>
<p style="margin-top:8px"><b>Площадь:</b> $S = \\dfrac{a^2\\sqrt{3}}{4}$</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 240 200" style="max-width:260px;background:#f0fdf4;border:1px solid var(--border);border-radius:10px">
<polygon points="120,18 20,178 220,178" fill="rgba(34,197,94,.18)" stroke="#16a34a" stroke-width="2.2"/>
<line x1="120" y1="18" x2="120" y2="178" stroke="#15803d" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="112,178 112,170 120,170" fill="none" stroke="#15803d" stroke-width="1.6"/>
<text x="115" y="13" font-size="11" font-weight="700" fill="#15803d">A</text>
<text x="8" y="185" font-size="11" font-weight="700" fill="#15803d">B</text>
<text x="223" y="185" font-size="11" font-weight="700" fill="#15803d">C</text>
<text x="124" y="105" font-size="11" font-weight="700" fill="#15803d">h</text>
<text x="66" y="110" font-size="10" fill="#15803d">a</text>
<text x="162" y="110" font-size="10" fill="#15803d">a</text>
<text x="108" y="193" font-size="10" fill="#15803d">a/2</text>
<text x="135" y="193" font-size="10" fill="#15803d">a/2</text>
</svg>
</div>`);
html+=makeCard('rule','Вывод формулы высоты','12.2',`
<p>Высота $AM$ делит равносторонний треугольник $\\triangle ABC$ на два прямоугольных треугольника.</p>
<p style="margin-top:6px">В $\\triangle ABM$: гипотенуза $AB=a$, катет $BM=\\dfrac{a}{2}$, катет $AM=h$.</p>
<p style="margin-top:6px">По теореме Пифагора:</p>
$$h^2 = a^2 - \\left(\\frac{a}{2}\\right)^2 = a^2 - \\frac{a^2}{4} = \\frac{3a^2}{4}$$
$$h = \\frac{a\\sqrt{3}}{2}$$
<p style="margin-top:6px">Площадь: $S = \\dfrac{1}{2}\\cdot a\\cdot h = \\dfrac{1}{2}\\cdot a\\cdot\\dfrac{a\\sqrt{3}}{2} = \\dfrac{a^2\\sqrt{3}}{4}$</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 220 160" style="max-width:240px;background:#f0fdf4;border:1px solid var(--border);border-radius:10px">
<polygon points="110,14 20,148 110,148" fill="rgba(34,197,94,.22)" stroke="#16a34a" stroke-width="2"/>
<polyline points="98,148 98,136 110,136" fill="none" stroke="#15803d" stroke-width="1.6"/>
<text x="104" y="9" font-size="10" font-weight="700" fill="#15803d">A</text>
<text x="8" y="155" font-size="10" font-weight="700" fill="#15803d">B</text>
<text x="112" y="155" font-size="10" font-weight="700" fill="#15803d">M</text>
<text x="54" y="90" font-size="10" font-weight="700" fill="#15803d">a</text>
<text x="115" y="90" font-size="10" font-weight="700" fill="#166534">h</text>
<text x="55" y="155" font-size="10" fill="#15803d">a/2</text>
<text x="5" y="155" font-size="8" fill="#888">гипотенуза</text>
</svg>
</div>`);
html+=makeCard('example','Примеры вычислений','12.3',`
<p><b>Пример 1.</b> Сторона равностороннего треугольника $a=6$ см. Найти $h$ и $S$.</p>
<p style="margin-top:4px">$h = \\dfrac{6\\sqrt{3}}{2} = 3\\sqrt{3} \\approx 5{,}196$ см.</p>
<p style="margin-top:4px">$S = \\dfrac{36\\sqrt{3}}{4} = 9\\sqrt{3} \\approx 15{,}59$ см².</p>
<p style="margin-top:10px"><b>Пример 2.</b> Высота равностороннего треугольника $h=6$ см. Найти $a$.</p>
<p style="margin-top:4px">$a = \\dfrac{2h}{\\sqrt{3}} = \\dfrac{12}{\\sqrt{3}} = 4\\sqrt{3} \\approx 6{,}93$ см.</p>`);
/* ИНТЕРАКТИВ 1 — Слайдер + SVG */
html+=`<div class="wg" id="p12-sl-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Равносторонний треугольник — слайдер стороны</div></div>
<div class="wg-help">Тяни слайдер — треугольник перестраивается, $h$ и $S$ пересчитываются в реальном времени.</div>
<div class="sliders">
<label>Сторона $a$ = <b id="p12-sl-a-val">8</b> см
<input type="range" min="1" max="20" value="8" id="p12-sl-a">
</label>
</div>
<div id="p12-sl-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p12-sl-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Пошаговый вывод */
html+=`<div class="wg" id="p12-steps-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Пошаговый вывод формулы высоты</div></div>
<div class="wg-help">4 шага — от треугольника до формулы $h = \\dfrac{a\\sqrt{3}}{2}$.</div>
<div id="p12-steps-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p12-steps-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p12-steps-next">Далее</button>
<button class="btn" id="p12-steps-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — Калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор §12</div></div>
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$a$ → $h$, $S$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p12-ca" class="tinp" placeholder="a (см)" style="width:90px">
<button class="btn primary" id="p12-go1">Вычислить</button>
</div>
<div id="p12-out1" style="font-size:.88rem;line-height:1.7"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$S$ → $a$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p12-cs" class="tinp" placeholder="S (см²)" style="width:90px">
<button class="btn primary" id="p12-go2">Найти a</button>
</div>
<div id="p12-out2" style="font-size:.88rem;line-height:1.7"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$h$ → $a$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p12-ch" class="tinp" placeholder="h (см)" style="width:90px">
<button class="btn primary" id="p12-go3">Найти a</button>
</div>
<div id="p12-out3" style="font-size:.88rem;line-height:1.7"></div>
</div>
</div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §12</div></div>
<div class="wg-help">5 задач на высоту и площадь равностороннего треугольника.</div>
<div class="score-display"><span>Задача <b id="p12-tr-i">1</b> / 5</span><span>Очки: <b id="p12-tr-score">0</b></span></div>
<div id="p12-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p12-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p12-tr-go">Проверить</button>
<button class="btn" id="p12-tr-start">Начать</button>
</div>
<div class="feedback" id="p12-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — DnD сортер */
html+=`<div class="wg" id="p12-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Сортировщик: пары a — h — S</div></div>
<div class="wg-help">Перетащи каждую карточку в правильную колонку.</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:10px">
<div class="drop-zone" style="border:2px dashed #16a34a;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#15803d;margin-bottom:6px;text-align:center">Высота $h$ (точное значение)</div>
<div class="drop-items" data-cat="h" style="min-height:50px"></div>
</div>
<div class="drop-zone" style="border:2px dashed #0891b2;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#0e7490;margin-bottom:6px;text-align:center">Площадь $S$ (точное значение)</div>
<div class="drop-items" data-cat="s" style="min-height:50px"></div>
</div>
</div>
<div id="p12-dnd-pool" style="margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn primary" id="p12-dnd-check">Проверить</button>
<button class="btn" id="p12-dnd-reset">Сброс</button>
</div>
<div class="feedback" id="p12-dnd-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §12 */
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))">БОСС §12</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p12-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p12-read-btn" onclick="addXp(10,'p12-read');bumpProgress('p12',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>
Я прочитал §12 (+10 XP)
</button>
</div>`;
html+=secNav('p11','p13');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Слайдер == */
(function(){
const sl=document.getElementById('p12-sl-a');
const W=300, H=260;
function draw(){
const a=+sl.value;
document.getElementById('p12-sl-a-val').textContent=a;
const scale=Math.min(10, 200/a);
const px=a*scale;
const h=a*Math.sqrt(3)/2;
const S=a*a*Math.sqrt(3)/4;
const cx=W/2, baseY=H-30, topY=baseY-h*scale;
const bx1=cx-px/2, bx2=cx+px/2;
const midX=cx;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:320px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<polygon points="'+cx+','+topY+' '+bx1+','+baseY+' '+bx2+','+baseY+'" fill="rgba(34,197,94,.2)" stroke="#16a34a" stroke-width="2.2"/>';
s+='<line x1="'+cx+'" y1="'+topY+'" x2="'+midX+'" y2="'+baseY+'" stroke="#15803d" stroke-width="2" stroke-dasharray="5 3"/>';
const rm=8;
s+='<polyline points="'+(midX-rm)+','+baseY+' '+(midX-rm)+','+(baseY-rm)+' '+midX+','+(baseY-rm)+'" fill="none" stroke="#15803d" stroke-width="1.5"/>';
s+='<text x="'+(cx-5)+'" y="'+(topY-8)+'" font-size="11" font-weight="700" fill="#15803d">A</text>';
s+='<text x="'+(bx1-14)+'" y="'+(baseY+14)+'" font-size="11" font-weight="700" fill="#15803d">B</text>';
s+='<text x="'+(bx2+4)+'" y="'+(baseY+14)+'" font-size="11" font-weight="700" fill="#15803d">C</text>';
s+='<text x="'+(cx+5)+'" y="'+Math.round((topY+baseY)/2)+'" font-size="10" font-weight="700" fill="#166534">h</text>';
s+='<text x="'+Math.round(cx-px/4-10)+'" y="'+Math.round((topY+baseY)/2+8)+'" font-size="9" fill="#15803d">a</text>';
s+='<text x="'+Math.round(cx+px/4)+'" y="'+Math.round((topY+baseY)/2+8)+'" font-size="9" fill="#15803d">a</text>';
s+='<text x="'+Math.round(cx-px/4)+'" y="'+(baseY+15)+'" text-anchor="middle" font-size="9" fill="#15803d">a</text>';
s+='</svg>';
document.getElementById('p12-sl-svg-wrap').innerHTML=s;
const hVal=(a*Math.sqrt(3)/2);
document.getElementById('p12-sl-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Сторона a</div><b>${a} см</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Высота h</div><b style="color:#15803d">${hVal.toFixed(3)} см</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Площадь S</div><b style="color:#0e7490">${S.toFixed(3)} см²</b></div>`;
}
sl.addEventListener('input',()=>{draw();addXp(1,'p12-sl');});
draw();
})();
/* == INIT: Пошаговый вывод == */
(function(){
let step=0;
const W=260, H=200;
const cx=130, topY=20, baseY=178, bx1=28, bx2=232, midX=cx;
const steps=[
{desc:'Равносторонний треугольник $\\triangle ABC$ со стороной $a$. Все стороны равны, все углы $= 60°$.'},
{desc:'Проводим высоту $AM$ из вершины $A$ на сторону $BC$. Высота в равностороннем треугольнике — одновременно медиана и биссектриса.'},
{desc:'Образуется прямоугольный треугольник $\\triangle ABM$ с катетами $BM = a/2$ и $AM = h$, гипотенузой $AB = a$.'},
{desc:'По теореме Пифагора: $h^2 + (a/2)^2 = a^2$ $\\Rightarrow$ $h^2 = a^2 - a^2/4 = 3a^2/4$ $\\Rightarrow$ $\\boxed{h = \\dfrac{a\\sqrt{3}}{2}}$'},
];
function render(){
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<polygon points="'+cx+','+topY+' '+bx1+','+baseY+' '+bx2+','+baseY+'" fill="rgba(34,197,94,.18)" stroke="#16a34a" stroke-width="2.2"/>';
if(step>=1){
s+='<line x1="'+cx+'" y1="'+topY+'" x2="'+midX+'" y2="'+baseY+'" stroke="#15803d" stroke-width="2.5"/>';
s+='<polyline points="'+(midX-9)+','+baseY+' '+(midX-9)+','+(baseY-9)+' '+midX+','+(baseY-9)+'" fill="none" stroke="#15803d" stroke-width="1.6"/>';
}
if(step>=2){
s+='<polygon points="'+cx+','+topY+' '+bx1+','+baseY+' '+midX+','+baseY+'" fill="rgba(22,163,74,.28)" stroke="#16a34a" stroke-width="1.8"/>';
s+='<text x="'+(bx1+12)+'" y="'+(baseY+14)+'" font-size="9" font-weight="700" fill="#15803d">a/2</text>';
s+='<text x="'+(midX+4)+'" y="'+Math.round((topY+baseY)/2)+'" font-size="9" font-weight="700" fill="#166534">h</text>';
}
if(step>=3){
s+='<text x="'+(cx-26)+'" y="'+Math.round((topY+baseY)/2+10)+'" font-size="9" fill="#0e7490" font-weight="700">a</text>';
s+='<text x="'+Math.round(cx-22)+'" y="'+(baseY-22)+'" font-size="8" fill="#b45309">h=a√3/2</text>';
}
s+='<text x="'+(cx-6)+'" y="'+(topY-6)+'" font-size="11" font-weight="700" fill="#15803d">A</text>';
s+='<text x="'+(bx1-12)+'" y="'+(baseY+14)+'" font-size="11" font-weight="700" fill="#15803d">B</text>';
s+='<text x="'+(bx2+2)+'" y="'+(baseY+14)+'" font-size="11" font-weight="700" fill="#15803d">C</text>';
if(step>=1) s+='<text x="'+(midX+3)+'" y="'+(baseY+14)+'" font-size="11" font-weight="700" fill="#166534">M</text>';
s+='<text x="'+Math.round(cx-28)+'" y="'+(baseY-20)+'" font-size="8" fill="#888">Шаг '+(step+1)+'/4</text>';
s+='</svg>';
document.getElementById('p12-steps-svg-wrap').innerHTML=s;
document.getElementById('p12-steps-desc').innerHTML=steps[step].desc;
if(window.renderMathInElement) renderMath(document.getElementById('p12-steps-desc'));
}
document.getElementById('p12-steps-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p12-step-'+step);}
else{addXp(3,'p12-steps-done');bumpProgress('p12',15);confetti();}
});
document.getElementById('p12-steps-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
const sqrt3=Math.sqrt(3);
document.getElementById('p12-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p12-ca').value);
const out=document.getElementById('p12-out1');
if(!isFinite(a)||a<=0){out.innerHTML='<span style="color:var(--bad)">Введи положительное число.</span>';return;}
const h=a*sqrt3/2, S=a*a*sqrt3/4;
out.innerHTML='$h = \\dfrac{'+fmt(a)+'\\sqrt{3}}{2} \\approx '+fmt(+h.toFixed(4))+'$ см<br>$S = \\dfrac{'+fmt(a*a)+'\\sqrt{3}}{4} \\approx '+fmt(+S.toFixed(4))+'$ см²';
renderMath(out); addXp(1,'p12-calc1');
});
document.getElementById('p12-go2').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p12-cs').value);
const out=document.getElementById('p12-out2');
if(!isFinite(S)||S<=0){out.innerHTML='<span style="color:var(--bad)">Введи S > 0.</span>';return;}
const a=Math.sqrt(4*S/sqrt3);
out.innerHTML='$a = \\sqrt{\\dfrac{4S}{\\sqrt{3}}} \\approx '+fmt(+a.toFixed(4))+'$ см';
renderMath(out); addXp(1,'p12-calc2');
});
document.getElementById('p12-go3').addEventListener('click',()=>{
const h=parseFloat(document.getElementById('p12-ch').value);
const out=document.getElementById('p12-out3');
if(!isFinite(h)||h<=0){out.innerHTML='<span style="color:var(--bad)">Введи h > 0.</span>';return;}
const a=2*h/sqrt3;
out.innerHTML='$a = \\dfrac{2h}{\\sqrt{3}} \\approx '+fmt(+a.toFixed(4))+'$ см';
renderMath(out); addXp(1,'p12-calc3');
});
})();
/* == INIT: Тренажёр == */
(function(){
const sqrt3=Math.sqrt(3);
const tasks=[
{q:'Сторона равностороннего треугольника $a = 4$ см. Найти высоту $h$ (округли до целых).', ans:3, tol:0.6, hint:'h = 4√3/2 = 2√3 ≈ 3,46 ≈ 3.'},
{q:'Сторона $a = 10$ см. Найти площадь $S$ (округли до целых).', ans:43, tol:1, hint:'S = 100√3/4 = 25√3 ≈ 43,3 ≈ 43.'},
{q:'Высота равностороннего треугольника $h = 9$ см. Найти сторону $a$ (округли до целых).', ans:10, tol:1, hint:'a = 2·9/√3 = 18/√3 = 6√3 ≈ 10,4 ≈ 10.'},
{q:'Сторона $a = 2$ см. Найти $S$ (оставь в точном виде — умножь $\\sqrt{3}$ на число и введи целое число перед ней).', ans:1, tol:0.05, hint:'S = 4√3/4 = √3 ≈ 1,732 → ответ: 1 (если просят коэффициент при √3).'},
{q:'Площадь равностороннего треугольника $S = 4\\sqrt{3}$ см². Найти сторону $a$ (целое число).', ans:4, tol:0.2, hint:'a² = 4S/√3 = 16 → a = 4.'},
];
let idx=0, score=0;
function show(){
document.getElementById('p12-tr-i').textContent=idx+1;
document.getElementById('p12-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p12-tr-ans').value='';
document.getElementById('p12-tr-fb').style.display='none';
if(window.renderMathInElement) renderMath(document.getElementById('p12-tr-task'));
}
document.getElementById('p12-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p12-tr-score').textContent=0;show();});
document.getElementById('p12-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p12-tr-ans').value;
const fb=document.getElementById('p12-tr-fb');
fb.style.display='block';
const tol=tasks[idx].tol||0.5;
if(Math.abs(ans-tasks[idx].ans)<tol){
score++;document.getElementById('p12-tr-score').textContent=score;
addXp(3,'p12-tr-'+idx);bumpProgress('p12',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p12-tr-all');bumpProgress('p12',10);}
}else{feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p12-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p12-tr-go').click();});
show();
})();
/* == INIT: DnD сортер == */
(function(){
const items=[
{id:'d1', html:'a=2 → h=√3', cat:'h'},
{id:'d2', html:'a=2 → S=√3', cat:'s'},
{id:'d3', html:'a=4 → h=2√3', cat:'h'},
{id:'d4', html:'a=4 → S=4√3', cat:'s'},
{id:'d5', html:'a=6 → h=3√3', cat:'h'},
{id:'d6', html:'a=6 → S=9√3', cat:'s'},
];
const sorter=setupSorter({poolId:'p12-dnd-pool',scopeSelector:'#p12-dnd-wg',items:items.map(x=>({id:x.id,html:x.html})),cats:['h','s']});
document.getElementById('p12-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p12-dnd-fb');fb.style.display='block';
let ok=0;
items.forEach(it=>{if(sorter.placed[it.id]===it.cat)ok++;});
if(ok===items.length){feedback(fb,true,'Всё верно! +5 XP');addXp(5,'p12-dnd');bumpProgress('p12',10);confetti();}
else{feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Проверь: h=a√3/2, S=a²√3/4.');}
});
document.getElementById('p12-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p12-dnd-fb').style.display='none';});
})();
/* == INIT: Босс §12 == */
(function(){
const tasks=[
{q:'Сторона равностороннего треугольника $12$ см. Найти высоту (округли до целых).', ans:10, hint:'h=12√3/2=6√3≈10,39≈10.'},
{q:'Периметр равностороннего треугольника $18$ см. Найти площадь $S$ (округли до целых).', ans:16, hint:'a=6, S=36√3/4=9√3≈15,6≈16.'},
{q:'Высота равностороннего треугольника $h = 6\\sqrt{3}$ см. Найти его площадь (целое число).', ans:62, hint:'h=6√3 → a=2h/√3=12, S=144√3/4=36√3≈62.'},
{q:'Два равносторонних треугольника: стороны $4$ и $8$ см. Во сколько раз площадь большего больше меньшего?', ans:4, hint:'S∝a². (8/4)²=4.'},
];
const correct=[10,16,62,4];
const bossBox=document.getElementById('p12-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="p12b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p12b-a${i}').value;
const ok=Math.abs(v-${correct[i]})<1.5;
const fb=document.getElementById('p12b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p12-boss-${i}');bumpProgress('p12',8);}
})()">Проверить</button>
<span class="feedback" id="p12b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement) renderMath(bossBox);
})();
}
function buildP13(){
const box=document.getElementById('p13-body');
let html='';
html+=makeCard('theory','Диагональ квадрата','13.1',`
<p><b>Теорема.</b> Диагональ квадрата со стороной $a$ равна:</p>
$$d = a\\sqrt{2}$$
<p style="margin-top:8px"><b>Доказательство.</b> Диагональ $AC$ делит квадрат $ABCD$ на два прямоугольных треугольника. В $\\triangle ABC$: катеты $AB=BC=a$, гипотенуза $AC=d$. По теореме Пифагора:</p>
$$d^2 = a^2 + a^2 = 2a^2 \\Rightarrow d = a\\sqrt{2}$$
<p style="margin-top:8px">Обратно: $a = \\dfrac{d}{\\sqrt{2}} = \\dfrac{d\\sqrt{2}}{2}$. &nbsp;&nbsp; Площадь: $S = a^2 = \\dfrac{d^2}{2}$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 220 180" style="max-width:240px;background:#f7fee7;border:1px solid var(--border);border-radius:10px">
<rect x="30" y="20" width="140" height="140" fill="rgba(132,204,22,.18)" stroke="#65a30d" stroke-width="2.2"/>
<line x1="30" y1="20" x2="170" y2="160" stroke="#16a34a" stroke-width="2.5"/>
<line x1="170" y1="20" x2="30" y2="160" stroke="#84cc16" stroke-width="1.5" stroke-dasharray="5 3"/>
<polyline points="44,20 44,34 30,34" fill="none" stroke="#65a30d" stroke-width="1.6"/>
<polyline points="156,20 156,34 170,34" fill="none" stroke="#65a30d" stroke-width="1.6"/>
<polyline points="44,160 44,146 30,146" fill="none" stroke="#65a30d" stroke-width="1.6"/>
<text x="24" y="15" font-size="11" font-weight="700" fill="#65a30d">A</text>
<text x="172" y="15" font-size="11" font-weight="700" fill="#65a30d">B</text>
<text x="172" y="168" font-size="11" font-weight="700" fill="#65a30d">C</text>
<text x="16" y="168" font-size="11" font-weight="700" fill="#65a30d">D</text>
<text x="95" y="14" text-anchor="middle" font-size="10" fill="#65a30d">a</text>
<text x="180" y="95" font-size="10" fill="#65a30d">a</text>
<text x="88" y="102" font-size="12" font-weight="800" fill="#16a34a" transform="rotate(-45,88,102)">d=a√2</text>
</svg>
</div>`);
html+=makeCard('rule','Формулы для квадрата','13.2',`
<p>Для квадрата со стороной $a$ и диагональю $d = a\\sqrt{2}$:</p>
<table class="tbl" style="margin-top:8px">
<tr><th>Дано</th><th>$a$</th><th>$d$</th><th>$S$</th><th>$P$</th></tr>
<tr><td>$a$</td><td>$a$</td><td>$a\\sqrt{2}$</td><td>$a^2$</td><td>$4a$</td></tr>
<tr><td>$d$</td><td>$\\dfrac{d\\sqrt{2}}{2}$</td><td>$d$</td><td>$\\dfrac{d^2}{2}$</td><td>$2d\\sqrt{2}$</td></tr>
<tr><td>$S$</td><td>$\\sqrt{S}$</td><td>$\\sqrt{2S}$</td><td>$S$</td><td>$4\\sqrt{S}$</td></tr>
</table>`);
html+=makeCard('example','Примеры','13.3',`
<p><b>Пример 1.</b> Сторона квадрата $a=5$ см. Диагональ?</p>
<p style="margin-top:4px">$d = 5\\sqrt{2} \\approx 7{,}07$ см.</p>
<p style="margin-top:10px"><b>Пример 2.</b> Диагональ квадрата $d=8$ см. Найти сторону и площадь.</p>
<p style="margin-top:4px">$a = \\dfrac{8}{\\sqrt{2}} = 4\\sqrt{2} \\approx 5{,}66$ см, &nbsp; $S = \\dfrac{64}{2} = 32$ см².</p>
<p style="margin-top:10px"><b>Пример 3.</b> Площадь квадрата $S=50$ см². Диагональ?</p>
<p style="margin-top:4px">$d = \\sqrt{2 \\cdot 50} = \\sqrt{100} = 10$ см.</p>`);
/* ИНТЕРАКТИВ 1 — Слайдер + SVG */
html+=`<div class="wg" id="p13-sl-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Квадрат — слайдер стороны</div></div>
<div class="wg-help">Тяни слайдер — диагональ перестраивается, $d$, $S$, $P$ пересчитываются.</div>
<div class="sliders">
<label>Сторона $a$ = <b id="p13-sl-a-val">6</b> см
<input type="range" min="1" max="20" value="6" id="p13-sl-a">
</label>
</div>
<div id="p13-sl-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p13-sl-info" style="display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:8px;margin-top:10px"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Пошаговое доказательство */
html+=`<div class="wg" id="p13-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Вывод: квадрат → диагональ</div></div>
<div class="wg-help">3 шага — от квадрата к формуле $d = a\\sqrt{2}$.</div>
<div id="p13-proof-svg-wrap" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p13-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"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p13-proof-next">Далее</button>
<button class="btn" id="p13-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 style="display:grid;grid-template-columns:repeat(auto-fit,minmax(185px,1fr));gap:12px">
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$a$ → $d$, $S$, $P$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p13-ca" class="tinp" placeholder="a" style="width:80px">
<button class="btn primary" id="p13-go1">Вычислить</button>
</div>
<div id="p13-out1" style="font-size:.88rem;line-height:1.8"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$d$ → $a$, $S$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p13-cd" class="tinp" placeholder="d" style="width:80px">
<button class="btn primary" id="p13-go2">Вычислить</button>
</div>
<div id="p13-out2" style="font-size:.88rem;line-height:1.8"></div>
</div>
<div style="background:var(--card);border:1px solid var(--border);border-radius:10px;padding:14px">
<div style="font-weight:700;margin-bottom:8px;color:var(--sec-acc-d,var(--pri2))">$S$ → $a$, $d$</div>
<div style="display:flex;gap:5px;flex-wrap:wrap;margin-bottom:8px">
<input type="number" id="p13-cs" class="tinp" placeholder="S" style="width:80px">
<button class="btn primary" id="p13-go3">Вычислить</button>
</div>
<div id="p13-out3" style="font-size:.88rem;line-height:1.8"></div>
</div>
</div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §13</div></div>
<div class="wg-help">5 задач на диагональ квадрата.</div>
<div class="score-display"><span>Задача <b id="p13-tr-i">1</b> / 5</span><span>Очки: <b id="p13-tr-score">0</b></span></div>
<div id="p13-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p13-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p13-tr-go">Проверить</button>
<button class="btn" id="p13-tr-start">Начать</button>
</div>
<div class="feedback" id="p13-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Босс §13 */
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))">БОСС §13</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p13-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p13-read-btn" onclick="addXp(10,'p13-read');bumpProgress('p13',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>
Я прочитал §13 (+10 XP)
</button>
</div>`;
html+=secNav('p12','p14');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Слайдер квадрат == */
(function(){
const sl=document.getElementById('p13-sl-a');
const W=300, H=300;
function draw(){
const a=+sl.value;
document.getElementById('p13-sl-a-val').textContent=a;
const scale=Math.min(11, 200/a);
const px=a*scale;
const ox=(W-px)/2, oy=(H-px)/2;
const x1=ox,y1=oy,x2=ox+px,y2=oy+px;
const d=a*Math.sqrt(2), S=a*a, P=4*a;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:320px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<rect x="'+x1+'" y="'+y1+'" width="'+px+'" height="'+px+'" fill="rgba(132,204,22,.2)" stroke="#65a30d" stroke-width="2.2"/>';
s+='<line x1="'+x1+'" y1="'+y1+'" x2="'+x2+'" y2="'+y2+'" stroke="#16a34a" stroke-width="2.5"/>';
s+='<line x1="'+x2+'" y1="'+y1+'" x2="'+x1+'" y2="'+y2+'" stroke="#84cc16" stroke-width="1.5" stroke-dasharray="5 3"/>';
const rm=9;
s+='<polyline points="'+(x1+rm)+','+y1+' '+(x1+rm)+','+(y1+rm)+' '+x1+','+(y1+rm)+'" fill="none" stroke="#65a30d" stroke-width="1.6"/>';
s+='<text x="'+(x1-14)+'" y="'+(y1-4)+'" font-size="11" font-weight="700" fill="#65a30d">A</text>';
s+='<text x="'+(x2+2)+'" y="'+(y1-4)+'" font-size="11" font-weight="700" fill="#65a30d">B</text>';
s+='<text x="'+(x2+2)+'" y="'+(y2+14)+'" font-size="11" font-weight="700" fill="#65a30d">C</text>';
s+='<text x="'+(x1-14)+'" y="'+(y2+14)+'" font-size="11" font-weight="700" fill="#65a30d">D</text>';
const midX=(x1+x2)/2, midY=(y1+y2)/2;
s+='<text x="'+Math.round(midX-22)+'" y="'+Math.round(midY+4)+'" font-size="9" font-weight="700" fill="#16a34a">d≈'+d.toFixed(2)+'</text>';
s+='<text x="'+Math.round((x1+x2)/2)+'" y="'+(y1-5)+'" text-anchor="middle" font-size="9" fill="#65a30d">a='+a+'</text>';
s+='</svg>';
document.getElementById('p13-sl-svg-wrap').innerHTML=s;
document.getElementById('p13-sl-info').innerHTML=`
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Сторона a</div><b>${a} см</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Диагональ d</div><b style="color:#16a34a">${d.toFixed(3)} см</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Площадь S</div><b style="color:#65a30d">${S} см²</b></div>
<div style="padding:8px 12px;background:var(--card);border-radius:8px;border:1px solid var(--border);font-size:.88rem"><div style="color:var(--muted);font-size:.72rem;font-weight:700;text-transform:uppercase;margin-bottom:4px">Периметр P</div><b>${P} см</b></div>`;
}
sl.addEventListener('input',()=>{draw();addXp(1,'p13-sl');});
draw();
})();
/* == INIT: Пошаговое доказательство == */
(function(){
let step=0;
const W=240, H=220;
const x1=30,y1=20,x2=210,y2=200;
const steps=[
{desc:'Квадрат $ABCD$ со стороной $a$. Все углы прямые, все стороны равны.'},
{desc:'Проводим диагональ $AC$. Она делит квадрат на два прямоугольных равных треугольника $\\triangle ABC$ и $\\triangle ACD$.'},
{desc:'В $\\triangle ABC$: $AB = BC = a$, угол $B = 90°$. По теореме Пифагора: $d^2 = a^2 + a^2 = 2a^2$ $\\Rightarrow$ $\\boxed{d = a\\sqrt{2}}$.'},
];
function render(){
const px=x2-x1, py=y2-y1;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:260px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<rect x="'+x1+'" y="'+y1+'" width="'+px+'" height="'+py+'" fill="rgba(132,204,22,.18)" stroke="#65a30d" stroke-width="2.2"/>';
if(step>=1){
s+='<line x1="'+x1+'" y1="'+y1+'" x2="'+x2+'" y2="'+y2+'" stroke="#16a34a" stroke-width="2.5"/>';
}
if(step>=2){
s+='<polygon points="'+x1+','+y1+' '+x2+','+y1+' '+x2+','+y2+'" fill="rgba(22,163,74,.25)" stroke="#16a34a" stroke-width="1.8"/>';
const rm=10;
s+='<polyline points="'+(x2-rm)+','+y1+' '+(x2-rm)+','+(y1+rm)+' '+x2+','+(y1+rm)+'" fill="none" stroke="#16a34a" stroke-width="1.6"/>';
s+='<text x="'+Math.round((x1+x2)/2-12)+'" y="'+Math.round((y1+y2)/2+4)+'" font-size="9" font-weight="700" fill="#16a34a">d=a√2</text>';
s+='<text x="'+Math.round((x1+x2)/2)+'" y="'+(y1-4)+'" text-anchor="middle" font-size="9" fill="#65a30d">a</text>';
s+='<text x="'+(x2+3)+'" y="'+Math.round((y1+y2)/2)+'" font-size="9" fill="#65a30d">a</text>';
}
s+='<text x="'+(x1-12)+'" y="'+(y1-4)+'" font-size="11" font-weight="700" fill="#65a30d">A</text>';
s+='<text x="'+(x2+2)+'" y="'+(y1-4)+'" font-size="11" font-weight="700" fill="#65a30d">B</text>';
s+='<text x="'+(x2+2)+'" y="'+(y2+14)+'" font-size="11" font-weight="700" fill="#65a30d">C</text>';
s+='<text x="'+(x1-12)+'" y="'+(y2+14)+'" font-size="11" font-weight="700" fill="#65a30d">D</text>';
s+='<text x="'+(x1+4)+'" y="'+(y2-6)+'" font-size="8" fill="#888">Шаг '+(step+1)+'/3</text>';
s+='</svg>';
document.getElementById('p13-proof-svg-wrap').innerHTML=s;
document.getElementById('p13-proof-desc').innerHTML=steps[step].desc;
if(window.renderMathInElement) renderMath(document.getElementById('p13-proof-desc'));
}
document.getElementById('p13-proof-next').addEventListener('click',()=>{
if(step<steps.length-1){step++;render();addXp(1,'p13-proof-'+step);}
else{addXp(3,'p13-proof-done');bumpProgress('p13',15);confetti();}
});
document.getElementById('p13-proof-reset').addEventListener('click',()=>{step=0;render();});
render();
})();
/* == INIT: Калькулятор == */
(function(){
const sqrt2=Math.sqrt(2);
document.getElementById('p13-go1').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p13-ca').value);
const out=document.getElementById('p13-out1');
if(!isFinite(a)||a<=0){out.innerHTML='<span style="color:var(--bad)">Введи a > 0.</span>';return;}
const d=a*sqrt2;
out.innerHTML='$d='+fmt(a)+'\\sqrt{2}\\approx'+fmt(+d.toFixed(4))+'$<br>$S='+fmt(a*a)+'$ см²<br>$P='+fmt(4*a)+'$ см';
renderMath(out); addXp(1,'p13-calc1');
});
document.getElementById('p13-go2').addEventListener('click',()=>{
const d=parseFloat(document.getElementById('p13-cd').value);
const out=document.getElementById('p13-out2');
if(!isFinite(d)||d<=0){out.innerHTML='<span style="color:var(--bad)">Введи d > 0.</span>';return;}
const a=d/sqrt2, S=d*d/2;
out.innerHTML='$a=\\dfrac{d}{\\sqrt{2}}\\approx'+fmt(+a.toFixed(4))+'$<br>$S=\\dfrac{d^2}{2}='+fmt(+S.toFixed(4))+'$ см²';
renderMath(out); addXp(1,'p13-calc2');
});
document.getElementById('p13-go3').addEventListener('click',()=>{
const S=parseFloat(document.getElementById('p13-cs').value);
const out=document.getElementById('p13-out3');
if(!isFinite(S)||S<=0){out.innerHTML='<span style="color:var(--bad)">Введи S > 0.</span>';return;}
const a=Math.sqrt(S), d=Math.sqrt(2*S);
out.innerHTML='$a=\\sqrt{S}\\approx'+fmt(+a.toFixed(4))+'$<br>$d=\\sqrt{2S}\\approx'+fmt(+d.toFixed(4))+'$';
renderMath(out); addXp(1,'p13-calc3');
});
})();
/* == INIT: Тренажёр == */
(function(){
const sqrt2=Math.sqrt(2);
const tasks=[
{q:'<svg viewBox="0 0 140 130" style="display:block;max-width:150px;margin:0 auto 8px;background:#f7fee7;border:1px solid #bef264;border-radius:8px"><rect x="20" y="15" width="100" height="100" fill="rgba(132,204,22,.2)" stroke="#65a30d" stroke-width="2"/><line x1="20" y1="15" x2="120" y2="115" stroke="#16a34a" stroke-width="2.2"/><text x="70" y="11" text-anchor="middle" font-size="10" font-weight="700" fill="#65a30d">a=7</text><text x="62" y="76" font-size="10" font-weight="700" fill="#16a34a">d=?</text></svg>Сторона квадрата $a=7$ см. Найти диагональ (округли до целых).', ans:10, tol:0.5, hint:'d=7√2≈9,9≈10.'},
{q:'Диагональ квадрата $d = 10$ см. Найти площадь $S$.', ans:50, tol:0.5, hint:'S=d²/2=100/2=50.'},
{q:'Сторона квадрата $a = 3$ см. Диагональ (округли до 2 знаков)?', ans:4.24, tol:0.02, hint:'d=3√2≈4,24.'},
{q:'Площадь квадрата $S = 72$ см². Найти диагональ (целое число).', ans:12, tol:0.5, hint:'d=√(2·72)=√144=12.'},
{q:'Диагональ квадрата $d = 6\\sqrt{2}$ см. Найти сторону $a$.', ans:6, tol:0.2, hint:'a=d/√2=6√2/√2=6.'},
];
let idx=0, score=0;
function show(){
document.getElementById('p13-tr-i').textContent=idx+1;
document.getElementById('p13-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p13-tr-ans').value='';
document.getElementById('p13-tr-fb').style.display='none';
if(window.renderMathInElement) renderMath(document.getElementById('p13-tr-task'));
}
document.getElementById('p13-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p13-tr-score').textContent=0;show();});
document.getElementById('p13-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p13-tr-ans').value;
const fb=document.getElementById('p13-tr-fb');
fb.style.display='block';
const tol=tasks[idx].tol||0.5;
if(Math.abs(ans-tasks[idx].ans)<tol){
score++;document.getElementById('p13-tr-score').textContent=score;
addXp(3,'p13-tr-'+idx);bumpProgress('p13',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p13-tr-all');bumpProgress('p13',10);}
}else{feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p13-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p13-tr-go').click();});
show();
})();
/* == INIT: Босс §13 == */
(function(){
const tasks=[
{q:'Диагональ квадрата $d = 5\\sqrt{2}$ см. Найти площадь $S$.', ans:25, hint:'a=5, S=25.'},
{q:'Периметр квадрата $P = 20$ см. Найти диагональ (округли до 2 знаков).', ans:7.07, hint:'a=5, d=5√2≈7,07.'},
{q:'Площадь квадрата $S = 32$ см². Найти диагональ (целое число).', ans:8, hint:'d=√(2·32)=√64=8.'},
{q:'В квадрат вписана окружность диаметром $d_0 = 10$ см. Найти диагональ квадрата (округли до целых).', ans:14, hint:'a=10, d=10√2≈14,14≈14.'},
];
const bossBox=document.getElementById('p13-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="p13b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p13b-a${i}').value;
const ok=Math.abs(v-${t.ans})<1.5;
const fb=document.getElementById('p13b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p13-boss-${i}');bumpProgress('p13',8);}
})()">Проверить</button>
<span class="feedback" id="p13b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement) renderMath(bossBox);
})();
}
function buildP14(){
const box=document.getElementById('p14-body');
let html='';
html+=makeCard('theory','Обратная теорема Пифагора','14.1',`
<p><b>Теорема (обратная теорема Пифагора).</b> Если в треугольнике квадрат наибольшей стороны равен сумме квадратов двух других сторон, то этот треугольник прямоугольный.</p>
<p style="margin-top:8px">Если $c$ — наибольшая сторона и $c^2 = a^2 + b^2$, то угол напротив $c$ прямой.</p>
<p style="margin-top:10px"><b>Следствие — признак типа треугольника</b> по трём сторонам $a \\leq b \\leq c$:</p>
<ul style="margin-top:6px;padding-left:18px;line-height:2">
<li>$c^2 = a^2 + b^2$ — прямоугольный</li>
<li>$c^2 &lt; a^2 + b^2$ — остроугольный</li>
<li>$c^2 &gt; a^2 + b^2$ — тупоугольный</li>
</ul>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 160" style="max-width:300px;background:#fffbeb;border:1px solid var(--border);border-radius:10px">
<polygon points="30,140 190,140 30,40" fill="rgba(217,119,6,.15)" stroke="#b45309" stroke-width="2.2"/>
<polyline points="44,140 44,126 30,126" fill="none" stroke="#b45309" stroke-width="1.8"/>
<text x="16" y="37" font-size="11" font-weight="700" fill="#b45309">A</text>
<text x="16" y="152" font-size="11" font-weight="700" fill="#b45309">B</text>
<text x="192" y="152" font-size="11" font-weight="700" fill="#b45309">C</text>
<text x="24" y="95" font-size="10" font-weight="700" fill="#b45309">b</text>
<text x="110" y="156" font-size="10" font-weight="700" fill="#b45309">a</text>
<text x="120" y="90" font-size="10" font-weight="700" fill="#b45309">c</text>
<text x="195" y="90" font-size="10" fill="#92400e">c²=a²+b²</text>
<text x="195" y="104" font-size="10" fill="#92400e">⟹ ∠B=90°</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство','14.2',`
<p>Пусть в $\\triangle ABC$ выполнено $c^2 = a^2 + b^2$. Построим вспомогательный $\\triangle A'B'C'$ с прямым углом при $B'$: $A'B'=b$, $B'C'=a$. Тогда по прямой теореме Пифагора $(A'C')^2 = a^2 + b^2 = c^2$, т.е. $A'C' = c$. По трём равным сторонам $\\triangle ABC = \\triangle A'B'C'$. Значит $\\angle B = \\angle B' = 90°$.&ensp;$\\square$</p>
<p style="margin-top:8px"><b>Алгоритм проверки треугольника по сторонам:</b></p>
<ol style="margin-top:4px;padding-left:18px;line-height:1.9;font-size:.9rem">
<li>Найди наибольшую сторону $c = \\max(a,b,c)$.</li>
<li>Вычисли $c^2$ и $a^2 + b^2$ (для оставшихся двух).</li>
<li>Сравни: $=$ прямоугольный, $&lt;$ остроугольный, $&gt;$ тупоугольный.</li>
</ol>`);
html+=makeCard('example','Примеры','14.3',`
<p><b>Пример 1.</b> Стороны треугольника $6, 8, 10$. Тип?</p>
<p style="margin-top:4px">$c=10$: $100 = 36 + 64 = 100$. $\\Rightarrow$ Прямоугольный.</p>
<p style="margin-top:10px"><b>Пример 2.</b> Стороны $5, 6, 8$. Тип?</p>
<p style="margin-top:4px">$c=8$: $64$ vs $25+36=61$. $64 > 61$ $\\Rightarrow$ Тупоугольный.</p>
<p style="margin-top:10px"><b>Пример 3.</b> Стороны $5, 6, 7$. Тип?</p>
<p style="margin-top:4px">$c=7$: $49$ vs $25+36=61$. $49 < 61$ $\\Rightarrow$ Остроугольный.</p>`);
/* ИНТЕРАКТИВ 1 — 3 слайдера + индикатор */
html+=`<div class="wg" id="p14-sl-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Тяни стороны — определи тип треугольника</div></div>
<div class="wg-help">Задай три стороны. Если треугольник существует, автоматически определяется его тип.</div>
<div class="sliders">
<label>$a$ = <b id="p14-sl-a-val">3</b>
<input type="range" min="1" max="20" value="3" id="p14-sl-a">
</label>
<label>$b$ = <b id="p14-sl-b-val">4</b>
<input type="range" min="1" max="20" value="4" id="p14-sl-b">
</label>
<label>$c$ = <b id="p14-sl-c-val">5</b>
<input type="range" min="1" max="20" value="5" id="p14-sl-c">
</label>
</div>
<div id="p14-sl-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p14-sl-info" style="margin-top:10px;padding:12px 16px;border-radius:10px;font-size:1rem;font-weight:700;text-align:center"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Калькулятор типа треугольника */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор типа треугольника</div></div>
<div class="wg-help">Введи три стороны — узнай тип треугольника и проверку по обратной теореме Пифагора.</div>
<div style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:10px;align-items:center">
<input type="number" id="p14-ca" class="tinp" placeholder="a" style="width:70px">
<input type="number" id="p14-cb" class="tinp" placeholder="b" style="width:70px">
<input type="number" id="p14-cc" class="tinp" placeholder="c" style="width:70px">
<button class="btn primary" id="p14-go">Определить тип</button>
</div>
<div id="p14-calc-out" style="font-size:.92rem;line-height:1.8"></div>
</div>`;
/* ИНТЕРАКТИВ 3 — Тренажёр-проверка */
html+=`<div class="wg" id="p14-check-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Тренажёр: прямоугольный или нет?</div></div>
<div class="wg-help">Для каждого набора сторон ответь: прямоугольный ли треугольник?</div>
<div id="p14-check-items" style="display:flex;flex-direction:column;gap:10px"></div>
<div style="display:flex;gap:8px;margin-top:10px;flex-wrap:wrap">
<button class="btn primary" id="p14-check-verify">Проверить все</button>
<button class="btn" id="p14-check-reset">Сброс</button>
</div>
<div class="feedback" id="p14-check-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — DnD сортер */
html+=`<div class="wg" id="p14-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Сортировщик: прямоугольный / не прямоугольный</div></div>
<div class="wg-help">Перетащи каждый набор сторон в правильную колонку.</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:10px">
<div class="drop-zone" style="border:2px dashed #16a34a;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#15803d;margin-bottom:6px;text-align:center">Прямоугольный</div>
<div class="drop-items" data-cat="yes" style="min-height:50px"></div>
</div>
<div class="drop-zone" style="border:2px dashed #dc2626;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#dc2626;margin-bottom:6px;text-align:center">Не прямоугольный</div>
<div class="drop-items" data-cat="no" style="min-height:50px"></div>
</div>
</div>
<div id="p14-dnd-pool" style="margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn primary" id="p14-dnd-check">Проверить</button>
<button class="btn" id="p14-dnd-reset">Сброс</button>
</div>
<div class="feedback" id="p14-dnd-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Тренажёр §14</div></div>
<div class="wg-help">5 задач на обратную теорему Пифагора.</div>
<div class="score-display"><span>Задача <b id="p14-tr-i">1</b> / 5</span><span>Очки: <b id="p14-tr-score">0</b></span></div>
<div id="p14-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p14-tr-ans" class="tinp" placeholder="Ответ" style="width:140px">
<button class="btn primary" id="p14-tr-go">Проверить</button>
<button class="btn" id="p14-tr-start">Начать</button>
</div>
<div class="feedback" id="p14-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §14 */
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))">БОСС §14</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — +5 XP каждая.</div>
<div id="p14-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p14-read-btn" onclick="addXp(10,'p14-read');bumpProgress('p14',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>
Я прочитал §14 (+10 XP)
</button>
</div>`;
html+=secNav('p13','p15');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: 3 слайдера == */
(function(){
const slA=document.getElementById('p14-sl-a');
const slB=document.getElementById('p14-sl-b');
const slC=document.getElementById('p14-sl-c');
const W=320, H=240;
function triType(a,b,c){
const sides=[a,b,c].sort((x,y)=>x-y);
const [s1,s2,s3]=sides;
if(s1+s2<=s3) return null; // не треугольник
const lhs=s3*s3, rhs=s1*s1+s2*s2;
if(Math.abs(lhs-rhs)<0.01) return 'right';
if(lhs<rhs) return 'acute';
return 'obtuse';
}
function drawTriSVG(a,b,c){
// Place right angle at origin for display, use cosine rule for coords
const sides=[a,b,c].sort((x,y)=>x-y);
// angle A opposite side a (smallest):
const cosC=(a*a+b*b-c*c)/(2*a*b);
const sinC=Math.sqrt(Math.max(0,1-cosC*cosC));
const scale=Math.min(10,140/c);
const bx=a*scale;
const cx2=b*scale*cosC, cy2=b*scale*sinC;
const ox=(W-bx)/2, oy=H-40;
const P1={x:ox,y:oy}, P2={x:ox+bx,y:oy}, P3={x:ox+cx2,y:oy-cy2};
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:340px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<polygon points="'+P1.x+','+P1.y+' '+P2.x+','+P2.y+' '+P3.x+','+P3.y+'" fill="rgba(217,119,6,.18)" stroke="#b45309" stroke-width="2.2"/>';
s+='<text x="'+(P1.x-14)+'" y="'+(P1.y+5)+'" font-size="11" font-weight="700" fill="#b45309">A</text>';
s+='<text x="'+(P2.x+4)+'" y="'+(P2.y+5)+'" font-size="11" font-weight="700" fill="#b45309">B</text>';
s+='<text x="'+(P3.x-4)+'" y="'+(P3.y-6)+'" font-size="11" font-weight="700" fill="#b45309">C</text>';
s+='<text x="'+Math.round((P1.x+P2.x)/2)+'" y="'+(P1.y+14)+'" text-anchor="middle" font-size="9" fill="#92400e">c='+c+'</text>';
s+='<text x="'+Math.round((P1.x+P3.x)/2-12)+'" y="'+Math.round((P1.y+P3.y)/2)+'" font-size="9" fill="#92400e">b='+b+'</text>';
s+='<text x="'+Math.round((P2.x+P3.x)/2+4)+'" y="'+Math.round((P2.y+P3.y)/2)+'" font-size="9" fill="#92400e">a='+a+'</text>';
s+='</svg>';
return s;
}
function update(){
const a=+slA.value, b=+slB.value, c=+slC.value;
document.getElementById('p14-sl-a-val').textContent=a;
document.getElementById('p14-sl-b-val').textContent=b;
document.getElementById('p14-sl-c-val').textContent=c;
const sides=[a,b,c].sort((x,y)=>x-y);
const [s1,s2,s3]=sides;
const info=document.getElementById('p14-sl-info');
if(s1+s2<=s3){
document.getElementById('p14-sl-svg-wrap').innerHTML='';
info.style.background='var(--fail-bg)'; info.style.color='#7f1d1d';
info.textContent='Треугольника не существует ('+s1+'+'+s2+'≤'+s3+')';
return;
}
document.getElementById('p14-sl-svg-wrap').innerHTML=drawTriSVG(a,b,c);
const lhs=s3*s3, rhs=s1*s1+s2*s2;
const type=triType(a,b,c);
const labels={right:'Прямоугольный',acute:'Остроугольный',obtuse:'Тупоугольный'};
const colors={right:'#dcfce7',acute:'#dbeafe',obtuse:'#fef3c7'};
const textColors={right:'#15803d',acute:'#1d4ed8',obtuse:'#92400e'};
info.style.background=colors[type];
info.style.color=textColors[type];
info.innerHTML=labels[type]+'&nbsp;&nbsp;|&nbsp;&nbsp;'+s3+'²='+lhs+'&nbsp;&nbsp;'+
(lhs===rhs?'=':lhs<rhs?'&lt;':'&gt;')+'&nbsp;&nbsp;'+s1+'²+'+s2+'²='+rhs;
}
slA.addEventListener('input',update);
slB.addEventListener('input',update);
slC.addEventListener('input',update);
update();
})();
/* == INIT: Калькулятор == */
(function(){
document.getElementById('p14-go').addEventListener('click',()=>{
const a=parseFloat(document.getElementById('p14-ca').value);
const b=parseFloat(document.getElementById('p14-cb').value);
const c=parseFloat(document.getElementById('p14-cc').value);
const out=document.getElementById('p14-calc-out');
if(!isFinite(a)||!isFinite(b)||!isFinite(c)||a<=0||b<=0||c<=0){
out.innerHTML='<span style="color:var(--bad)">Введи три положительных числа.</span>';return;
}
const sides=[a,b,c].sort((x,y)=>x-y);
const [s1,s2,s3]=sides;
if(s1+s2<=s3){out.innerHTML='<span style="color:var(--bad)">Треугольника с такими сторонами не существует.</span>';return;}
const lhs=s3*s3, rhs=s1*s1+s2*s2;
let type, color, verdict;
if(Math.abs(lhs-rhs)<0.001){type='прямоугольный';color='#15803d';verdict='='}
else if(lhs<rhs){type='остроугольный';color='#1d4ed8';verdict='<'}
else{type='тупоугольный';color='#92400e';verdict='>'}
out.innerHTML='Наибольшая сторона: $c_0='+fmt(s3)+'$.<br>$c_0^2 = '+fmt(lhs)+'$,&nbsp;&nbsp; $'+fmt(s1)+'^2+'+fmt(s2)+'^2 = '+fmt(rhs)+'$.<br>$'+fmt(lhs)+' '+verdict+' '+fmt(rhs)+'$ &nbsp;⟹&nbsp; <b style="color:'+color+'">'+type.charAt(0).toUpperCase()+type.slice(1)+' треугольник.</b>';
renderMath(out); addXp(2,'p14-calc');
});
})();
/* == INIT: Тренажёр-проверка == */
(function(){
const sets=[
{sides:[3,4,5],right:true},{sides:[6,8,10],right:true},{sides:[5,12,13],right:true},
{sides:[7,24,25],right:true},{sides:[2,3,4],right:false},{sides:[5,6,7],right:false},
{sides:[1,1,1],right:false},{sides:[8,15,17],right:true},
];
const cont=document.getElementById('p14-check-items');
cont.innerHTML=sets.map((s,i)=>`
<div style="display:flex;align-items:center;gap:12px;padding:10px 14px;background:var(--card);border:1px solid var(--border);border-radius:10px;flex-wrap:wrap">
<span style="font-size:.92rem;min-width:90px"><b>(${s.sides.join(', ')})</b></span>
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer">
<input type="radio" name="p14-check-${i}" value="yes" id="p14-ck-${i}-yes"> Прямоугольный
</label>
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer">
<input type="radio" name="p14-check-${i}" value="no" id="p14-ck-${i}-no"> Нет
</label>
<span id="p14-ck-res${i}" style="font-size:.82rem;font-weight:700"></span>
</div>`).join('');
document.getElementById('p14-check-verify').addEventListener('click',()=>{
let ok=0, total=0;
sets.forEach((s,i)=>{
const yes=document.getElementById('p14-ck-'+i+'-yes');
const no=document.getElementById('p14-ck-'+i+'-no');
const res=document.getElementById('p14-ck-res'+i);
if(!yes.checked&&!no.checked){res.textContent='';return;}
total++;
const chosen=yes.checked?true:false;
if(chosen===s.right){res.textContent='Верно!';res.style.color='#15803d';ok++;}
else{
const ss=s.sides.sort((a,b)=>a-b);
res.textContent='Неверно ('+ss[2]+'²='+(ss[2]*ss[2])+', '+ss[0]+'²+'+ss[1]+'²='+(ss[0]*ss[0]+ss[1]*ss[1])+')';
res.style.color='#dc2626';
}
});
const fb=document.getElementById('p14-check-fb');
fb.style.display='block';
if(ok===sets.length){feedback(fb,true,'Все верно! +5 XP');addXp(5,'p14-check');bumpProgress('p14',10);confetti();}
else{feedback(fb,false,'Верно: '+ok+' из '+total+'.');}
});
document.getElementById('p14-check-reset').addEventListener('click',()=>{
sets.forEach((_,i)=>{
document.getElementById('p14-ck-'+i+'-yes').checked=false;
document.getElementById('p14-ck-'+i+'-no').checked=false;
document.getElementById('p14-ck-res'+i).textContent='';
});
document.getElementById('p14-check-fb').style.display='none';
});
})();
/* == INIT: DnD == */
(function(){
const items=[
{id:'d1',html:'9, 40, 41',cat:'yes'},
{id:'d2',html:'5, 12, 13',cat:'yes'},
{id:'d3',html:'8, 15, 17',cat:'yes'},
{id:'d4',html:'3, 4, 6', cat:'no'},
{id:'d5',html:'6, 7, 8', cat:'no'},
{id:'d6',html:'20, 21, 29',cat:'yes'},
{id:'d7',html:'2, 2, 3', cat:'no'},
{id:'d8',html:'10, 24, 26',cat:'yes'},
];
const sorter=setupSorter({poolId:'p14-dnd-pool',scopeSelector:'#p14-dnd-wg',items:items.map(x=>({id:x.id,html:x.html})),cats:['yes','no']});
document.getElementById('p14-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p14-dnd-fb');fb.style.display='block';
let ok=0;
items.forEach(it=>{if(sorter.placed[it.id]===it.cat)ok++;});
if(ok===items.length){feedback(fb,true,'Все верно! +5 XP');addXp(5,'p14-dnd');bumpProgress('p14',10);confetti();}
else{feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Проверь: 9-40-41, 5-12-13, 8-15-17, 20-21-29, 10-24-26 — прямоугольные.');}
});
document.getElementById('p14-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p14-dnd-fb').style.display='none';});
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'Стороны треугольника $6, 8, 10$. Прямоугольный? Введи 1 (да) или 0 (нет).', ans:1, tol:0.1, hint:'6²+8²=100=10². Да, прямоугольный (1).'},
{q:'Стороны $5, 7, 9$. Прямоугольный? Введи 1 (да) или 0 (нет).', ans:0, tol:0.1, hint:'9²=81 > 5²+7²=74. Тупоугольный (0).'},
{q:'Катеты прямоугольного треугольника $15$ и $20$. Найти гипотенузу.', ans:25, tol:0.5, hint:'c=√(225+400)=√625=25.'},
{q:'Стороны треугольника $7, 24, c$. При каком $c$ он прямоугольный (угол напротив $c$)?', ans:25, tol:0.5, hint:'c=√(49+576)=√625=25.'},
{q:'Стороны $3, 4, 5$ умножили на $3$. Получилась тройка $9, 12, 15$. Это прямоугольный треугольник? Введи 1 (да) или 0 (нет).', ans:1, tol:0.1, hint:'9²+12²=81+144=225=15². Да (1).'},
];
let idx=0, score=0;
function show(){
document.getElementById('p14-tr-i').textContent=idx+1;
document.getElementById('p14-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p14-tr-ans').value='';
document.getElementById('p14-tr-fb').style.display='none';
if(window.renderMathInElement) renderMath(document.getElementById('p14-tr-task'));
}
document.getElementById('p14-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p14-tr-score').textContent=0;show();});
document.getElementById('p14-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p14-tr-ans').value;
const fb=document.getElementById('p14-tr-fb');
fb.style.display='block';
const tol=tasks[idx].tol||0.5;
if(Math.abs(ans-tasks[idx].ans)<tol){
score++;document.getElementById('p14-tr-score').textContent=score;
addXp(3,'p14-tr-'+idx);bumpProgress('p14',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p14-tr-all');bumpProgress('p14',10);}
}else{feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p14-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p14-tr-go').click();});
show();
})();
/* == INIT: Босс §14 == */
(function(){
const tasks=[
{q:'Треугольник со сторонами $9$, $40$, $41$. Прямоугольный? Введи 1 (да) или 0 (нет).', ans:1, hint:'9²+40²=81+1600=1681=41². Да.'},
{q:'Прямоугольный треугольник, гипотенуза $c = 26$, катет $a = 10$. Найти второй катет $b$.', ans:24, hint:'b=√(676-100)=√576=24.'},
{q:'Стороны $a$ и $b$ прямоугольного треугольника равны $a = b = 5$. Найти гипотенузу (округли до целых).', ans:7, hint:'c=5√2≈7,07≈7.'},
{q:'Стороны $p$, $q$, $r$ таковы, что $p^2 + q^2 = r^2$. Угол напротив какой стороны прямой? Введи номер стороны: 1=$p$, 2=$q$, 3=$r$.', ans:3, hint:'По обратной теореме Пифагора — прямой угол напротив r (3).'},
];
const bossBox=document.getElementById('p14-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="p14b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p14b-a${i}').value;
const ok=Math.abs(v-${t.ans})<1.5;
const fb=document.getElementById('p14b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p14-boss-${i}');bumpProgress('p14',8);}
})()">Проверить</button>
<span class="feedback" id="p14b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement) renderMath(bossBox);
})();
}
function buildP15(){
const box=document.getElementById('p15-body');
let html='';
html+=makeCard('theory','Пифагоровы тройки','15.1',`
<p><b>Пифагорова тройка</b> — три натуральных числа $(a, b, c)$, удовлетворяющих $a^2 + b^2 = c^2$.</p>
<p style="margin-top:8px"><b>Примитивные тройки</b> (НОД = 1):</p>
<table class="tbl" style="margin-top:6px">
<tr><th>a</th><th>b</th><th>c</th><th>Проверка</th></tr>
<tr><td>3</td><td>4</td><td>5</td><td>9+16=25</td></tr>
<tr><td>5</td><td>12</td><td>13</td><td>25+144=169</td></tr>
<tr><td>7</td><td>24</td><td>25</td><td>49+576=625</td></tr>
<tr><td>8</td><td>15</td><td>17</td><td>64+225=289</td></tr>
<tr><td>9</td><td>40</td><td>41</td><td>81+1600=1681</td></tr>
<tr><td>20</td><td>21</td><td>29</td><td>400+441=841</td></tr>
</table>
<p style="margin-top:8px"><b>Кратные тройки:</b> если $(a,b,c)$ — тройка, то $(ka, kb, kc)$ тоже тройка для любого натурального $k$.</p>`);
html+=makeCard('rule','Формула Евклида','15.2',`
<p>Для любых натуральных $m > n$ тройка $$(m^2-n^2,\\; 2mn,\\; m^2+n^2)$$ является пифагоровой.</p>
<p style="margin-top:8px"><b>Проверка:</b> $(m^2-n^2)^2 + (2mn)^2 = m^4 - 2m^2n^2 + n^4 + 4m^2n^2 = m^4 + 2m^2n^2 + n^4 = (m^2+n^2)^2$. $\\square$</p>
<table class="tbl" style="margin-top:8px">
<tr><th>m</th><th>n</th><th>$m^2-n^2$</th><th>$2mn$</th><th>$m^2+n^2$</th></tr>
<tr><td>2</td><td>1</td><td>3</td><td>4</td><td>5</td></tr>
<tr><td>3</td><td>2</td><td>5</td><td>12</td><td>13</td></tr>
<tr><td>4</td><td>1</td><td>15</td><td>8</td><td>17</td></tr>
<tr><td>4</td><td>3</td><td>7</td><td>24</td><td>25</td></tr>
<tr><td>5</td><td>2</td><td>21</td><td>20</td><td>29</td></tr>
</table>`);
html+=makeCard('example','Применение','15.3',`
<p><b>Пример 1.</b> Два катета прямоугольного треугольника равны $9$ и $40$. Гипотенуза?</p>
<p style="margin-top:4px">Узнаём тройку $(9, 40, 41)$ $\\Rightarrow$ $c = 41$. Без вычислений!</p>
<p style="margin-top:10px"><b>Пример 2.</b> Катеты $6$ и $8$. Гипотенуза?</p>
<p style="margin-top:4px">$(6,8,10) = 2\\cdot(3,4,5)$ $\\Rightarrow$ $c = 10$.</p>
<p style="margin-top:10px"><b>Пример 3.</b> По формуле Евклида при $m=5, n=1$: $(24, 10, 26) = 2\\cdot(12, 5, 13)$.</p>`);
/* ИНТЕРАКТИВ 1 — Генератор Евклида */
html+=`<div class="wg" id="p15-euclid-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Генератор троек по формуле Евклида</div></div>
<div class="wg-help">Выбери $m$ и $n$ ($m > n$) — получи пифагорову тройку и увидь её на SVG.</div>
<div class="sliders">
<label>$m$ = <b id="p15-sl-m-val">3</b>
<input type="range" min="2" max="12" value="3" id="p15-sl-m">
</label>
<label>$n$ = <b id="p15-sl-n-val">2</b>
<input type="range" min="1" max="11" value="2" id="p15-sl-n">
</label>
</div>
<div id="p15-euclid-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p15-euclid-out" style="margin-top:10px;padding:12px 16px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.95rem;line-height:1.8"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Таблица с мини-SVG */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">10 известных троек Пифагора</div></div>
<div class="wg-help">Нажми на тройку — увидишь соответствующий прямоугольный треугольник.</div>
<div id="p15-table-wrap" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(130px,1fr));gap:10px;margin-bottom:10px"></div>
<div id="p15-table-svg" style="display:flex;justify-content:center"></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">Дано 2 числа из пифагоровой тройки — найди третье.</div>
<div class="score-display"><span>Задача <b id="p15-tr-i">1</b> / 6</span><span>Очки: <b id="p15-tr-score">0</b></span></div>
<div id="p15-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1.05rem;margin-bottom:10px"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p15-tr-ans" class="tinp" placeholder="Ответ" style="width:120px">
<button class="btn primary" id="p15-tr-go">Проверить</button>
<button class="btn" id="p15-tr-start">Начать</button>
</div>
<div class="feedback" id="p15-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — Викторина тройка/не тройка */
html+=`<div class="wg" id="p15-quiz-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Викторина: тройка или не тройка?</div></div>
<div class="wg-help">Для каждого набора нажми «Тройка» или «Нет».</div>
<div id="p15-quiz-items" style="display:flex;flex-direction:column;gap:8px"></div>
<div style="display:flex;gap:8px;margin-top:10px;flex-wrap:wrap">
<button class="btn primary" id="p15-quiz-check">Проверить</button>
<button class="btn" id="p15-quiz-reset">Сброс</button>
</div>
<div class="feedback" id="p15-quiz-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — DnD: примитивные vs кратные */
html+=`<div class="wg" id="p15-dnd-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Сортировщик: примитивные vs кратные тройки</div></div>
<div class="wg-help">Перетащи каждую тройку в правильную колонку.</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:10px">
<div class="drop-zone" style="border:2px dashed #059669;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#047857;margin-bottom:6px;text-align:center">Примитивная (НОД=1)</div>
<div class="drop-items" data-cat="prim" style="min-height:50px"></div>
</div>
<div class="drop-zone" style="border:2px dashed #0891b2;border-radius:12px;padding:10px;min-height:80px">
<div style="font-weight:700;font-size:.85rem;color:#0e7490;margin-bottom:6px;text-align:center">Кратная (НОД&gt;1)</div>
<div class="drop-items" data-cat="mult" style="min-height:50px"></div>
</div>
</div>
<div id="p15-dnd-pool" style="margin-bottom:10px"></div>
<div style="display:flex;gap:8px;flex-wrap:wrap">
<button class="btn primary" id="p15-dnd-check">Проверить</button>
<button class="btn" id="p15-dnd-reset">Сброс</button>
</div>
<div class="feedback" id="p15-dnd-fb" style="display:none;margin-top:8px"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §15 */
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))">БОСС §15</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">5 задач — +5 XP каждая.</div>
<div id="p15-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="p15-read-btn" onclick="addXp(10,'p15-read');bumpProgress('p15',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>
Я прочитал §15 (+10 XP)
</button>
</div>`;
html+=secNav('p14','final2');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* == INIT: Генератор Евклида == */
(function(){
const slM=document.getElementById('p15-sl-m');
const slN=document.getElementById('p15-sl-n');
const W=300, H=240;
function drawTriangle(a,b,c){
const mx=Math.max(a,b,c);
const sc=Math.min(10,180/mx);
const ax=a*sc, by=b*sc;
const ox=(W-ax)/2, oy=H-30;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="width:100%;max-width:320px;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<polygon points="'+ox+','+oy+' '+(ox+ax)+','+oy+' '+ox+','+(oy-by)+'" fill="rgba(5,150,105,.2)" stroke="#059669" stroke-width="2.2"/>';
const rm=9;
s+='<polyline points="'+(ox+rm)+','+oy+' '+(ox+rm)+','+(oy-rm)+' '+ox+','+(oy-rm)+'" fill="none" stroke="#059669" stroke-width="1.6"/>';
s+='<text x="'+(ox-14)+'" y="'+(oy+5)+'" font-size="11" font-weight="700" fill="#059669">B</text>';
s+='<text x="'+(ox+ax+4)+'" y="'+(oy+5)+'" font-size="11" font-weight="700" fill="#059669">C</text>';
s+='<text x="'+(ox-14)+'" y="'+(oy-by-2)+'" font-size="11" font-weight="700" fill="#059669">A</text>';
s+='<text x="'+Math.round(ox+ax/2)+'" y="'+(oy+14)+'" text-anchor="middle" font-size="9" font-weight="700" fill="#059669">'+a+'</text>';
s+='<text x="'+(ox-14)+'" y="'+Math.round(oy-by/2)+'" text-anchor="middle" font-size="9" font-weight="700" fill="#047857">'+b+'</text>';
const hpx=(ox+ax+ox)/2, hpy=(oy+oy-by)/2;
s+='<text x="'+Math.round(hpx+8)+'" y="'+Math.round(hpy)+'" font-size="9" font-weight="700" fill="#0d9488">'+c+'</text>';
s+='</svg>';
return s;
}
function update(){
let m=+slM.value, n=+slN.value;
document.getElementById('p15-sl-m-val').textContent=m;
document.getElementById('p15-sl-n-val').textContent=n;
if(n>=m){
n=m-1;
slN.value=n;
document.getElementById('p15-sl-n-val').textContent=n;
}
const a=m*m-n*n, b=2*m*n, c=m*m+n*n;
document.getElementById('p15-euclid-svg-wrap').innerHTML=drawTriangle(a,b,c);
document.getElementById('p15-euclid-out').innerHTML=
'<b>m='+m+', n='+n+'</b><br>'+
'$a = m^2-n^2 = '+m*m+'-'+n*n+' = '+a+'$<br>'+
'$b = 2mn = 2\\cdot'+m+'\\cdot'+n+' = '+b+'$<br>'+
'$c = m^2+n^2 = '+m*m+'+'+n*n+' = '+c+'$<br>'+
'<b>Тройка: ('+a+', '+b+', '+c+')</b><br>'+
'Проверка: $'+a+'{}^2+'+b+'{}^2 = '+(a*a+b*b)+' = '+c+'{}^2$ = '+(a*a+b*b===c*c?'✓':'✗');
if(window.renderMathInElement) renderMath(document.getElementById('p15-euclid-out'));
addXp(1,'p15-euclid');
}
slM.addEventListener('input',update);
slN.addEventListener('input',update);
update();
})();
/* == INIT: Таблица троек == */
(function(){
const triples=[
[3,4,5],[5,12,13],[7,24,25],[8,15,17],[9,40,41],
[6,8,10],[10,24,26],[12,16,20],[15,20,25],[20,21,29],
];
const wrap=document.getElementById('p15-table-wrap');
const svgBox=document.getElementById('p15-table-svg');
let sel=-1;
function drawMini(a,b,c,active){
const sc=Math.min(5.5,40/Math.max(a,b,c));
const ax=a*sc, by=b*sc;
const ox=10, oy=50+by;
let s='<svg viewBox="0 0 '+(ax+20)+' '+(by+20)+'" style="width:100%;max-height:50px">';
s+='<polygon points="'+ox+','+oy+' '+(ox+ax)+','+oy+' '+ox+','+(oy-by)+'" fill="rgba(5,150,105,.25)" stroke="#059669" stroke-width="1.5"/>';
s+='<polyline points="'+(ox+6)+','+oy+' '+(ox+6)+','+(oy-6)+' '+ox+','+(oy-6)+'" fill="none" stroke="#059669" stroke-width="1.2"/>';
s+='</svg>';
return s;
}
function showSVG(i){
const [a,b,c]=triples[i];
const sc=Math.min(8,160/Math.max(a,b,c));
const ax=a*sc, by=b*sc;
const W=Math.round(ax+80), H=Math.round(by+60);
const ox=40, oy=H-30;
let s='<svg viewBox="0 0 '+W+' '+H+'" style="max-width:360px;width:100%;background:var(--card);border:1px solid var(--border);border-radius:14px">';
s+='<polygon points="'+ox+','+oy+' '+(ox+ax)+','+oy+' '+ox+','+(oy-by)+'" fill="rgba(5,150,105,.2)" stroke="#059669" stroke-width="2.2"/>';
const rm=9;
s+='<polyline points="'+(ox+rm)+','+oy+' '+(ox+rm)+','+(oy-rm)+' '+ox+','+(oy-rm)+'" fill="none" stroke="#059669" stroke-width="1.6"/>';
s+='<text x="'+(ox-14)+'" y="'+(oy+5)+'" font-size="11" font-weight="700" fill="#059669">B</text>';
s+='<text x="'+(ox+ax+4)+'" y="'+(oy+5)+'" font-size="11" font-weight="700" fill="#059669">C</text>';
s+='<text x="'+(ox-14)+'" y="'+(oy-by-2)+'" font-size="11" font-weight="700" fill="#059669">A</text>';
s+='<text x="'+Math.round(ox+ax/2)+'" y="'+(oy+16)+'" text-anchor="middle" font-size="10" font-weight="700" fill="#059669">a='+a+'</text>';
s+='<text x="'+(ox-22)+'" y="'+Math.round(oy-by/2)+'" font-size="10" font-weight="700" fill="#047857">b='+b+'</text>';
const hpx=(ox+ax+ox)/2+16, hpy=(oy+oy-by)/2;
s+='<text x="'+Math.round(hpx)+'" y="'+Math.round(hpy)+'" font-size="10" font-weight="700" fill="#0d9488">c='+c+'</text>';
s+='<text x="'+Math.round(W/2)+'" y="20" text-anchor="middle" font-size="10" fill="#047857">'+a+'²+'+b+'²='+c+'² &nbsp; ('+a*a+'+'+b*b+'='+c*c+')</text>';
s+='</svg>';
svgBox.innerHTML=s;
}
wrap.innerHTML=triples.map(([a,b,c],i)=>`
<div id="p15-tri-btn${i}" style="background:var(--card);border:1.5px solid var(--border);border-radius:10px;padding:8px;cursor:pointer;text-align:center;transition:border-color .15s">
<div style="font-weight:700;font-size:.88rem;color:var(--sec-acc-d,var(--pri2));">(${a}, ${b}, ${c})</div>
${drawMini(a,b,c,false)}
</div>`).join('');
triples.forEach((_,i)=>{
document.getElementById('p15-tri-btn'+i).addEventListener('click',()=>{
sel=i;
triples.forEach((_,j)=>{
const el=document.getElementById('p15-tri-btn'+j);
el.style.borderColor=j===i?'var(--sec-acc,var(--pri))':'var(--border)';
});
showSVG(i); addXp(1,'p15-table-'+i);
});
});
showSVG(0);
document.getElementById('p15-tri-btn0').style.borderColor='var(--sec-acc,var(--pri))';
})();
/* == INIT: Тренажёр == */
(function(){
const tasks=[
{q:'Тройка $(3, 4, ?)$. Найти третье число.', ans:5, hint:'3²+4²=25=5².'},
{q:'Тройка $(5, 12, ?)$. Найти третье число.', ans:13, hint:'25+144=169=13².'},
{q:'Тройка $(?, 24, 25)$. Найти первое число.', ans:7, hint:'25²-24²=625-576=49=7².'},
{q:'Тройка $(9, ?, 41)$. Найти второе число.', ans:40, hint:'41²-9²=1681-81=1600=40².'},
{q:'Кратная тройка: $(6, 8, ?)$. Это $2\\cdot(3,4,5)$.', ans:10, hint:'c=2·5=10.'},
{q:'Формула Евклида, $m=4, n=1$: $a=m^2-n^2$, $b=2mn$, $c=m^2+n^2$. Найти $c$.', ans:17, hint:'c=16+1=17.'},
];
let idx=0, score=0;
function show(){
document.getElementById('p15-tr-i').textContent=idx+1;
document.getElementById('p15-tr-task').innerHTML=tasks[idx].q;
document.getElementById('p15-tr-ans').value='';
document.getElementById('p15-tr-fb').style.display='none';
if(window.renderMathInElement) renderMath(document.getElementById('p15-tr-task'));
}
document.getElementById('p15-tr-start').addEventListener('click',()=>{idx=0;score=0;document.getElementById('p15-tr-score').textContent=0;show();});
document.getElementById('p15-tr-go').addEventListener('click',()=>{
if(idx>=tasks.length)return;
const ans=+document.getElementById('p15-tr-ans').value;
const fb=document.getElementById('p15-tr-fb');
fb.style.display='block';
if(Math.abs(ans-tasks[idx].ans)<0.5){
score++;document.getElementById('p15-tr-score').textContent=score;
addXp(3,'p15-tr-'+idx);bumpProgress('p15',5);
if(idx<tasks.length-1){feedback(fb,true,'Верно! +3 XP');idx++;setTimeout(()=>show(),900);}
else{feedback(fb,true,'Все задачи решены! +5 XP');addXp(5,'p15-tr-all');bumpProgress('p15',10);}
}else{feedback(fb,false,'Неверно. '+tasks[idx].hint);}
});
document.getElementById('p15-tr-ans').addEventListener('keydown',e=>{if(e.key==='Enter')document.getElementById('p15-tr-go').click();});
show();
})();
/* == INIT: Викторина == */
(function(){
const sets=[
{nums:[3,4,5],ok:true},{nums:[5,12,13],ok:true},{nums:[6,8,10],ok:true},
{nums:[7,24,25],ok:true},{nums:[2,3,4],ok:false},{nums:[4,5,6],ok:false},
{nums:[8,15,17],ok:true},{nums:[3,5,7],ok:false},
];
const cont=document.getElementById('p15-quiz-items');
cont.innerHTML=sets.map((s,i)=>`
<div style="display:flex;align-items:center;gap:12px;padding:9px 14px;background:var(--card);border:1px solid var(--border);border-radius:10px;flex-wrap:wrap">
<span style="font-size:.92rem;min-width:90px"><b>(${s.nums.join(', ')})</b></span>
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer">
<input type="radio" name="p15-qz-${i}" value="yes"> Тройка
</label>
<label style="display:inline-flex;align-items:center;gap:5px;cursor:pointer">
<input type="radio" name="p15-qz-${i}" value="no"> Нет
</label>
<span id="p15-qz-res${i}" style="font-size:.82rem;font-weight:700"></span>
</div>`).join('');
document.getElementById('p15-quiz-check').addEventListener('click',()=>{
let ok=0,total=0;
sets.forEach((s,i)=>{
const yesEl=cont.querySelector('[name="p15-qz-'+i+'"][value="yes"]');
const noEl=cont.querySelector('[name="p15-qz-'+i+'"][value="no"]');
const res=document.getElementById('p15-qz-res'+i);
if(!yesEl.checked&&!noEl.checked){res.textContent='';return;}
total++;
const chosen=yesEl.checked;
if(chosen===s.ok){res.textContent='Верно!';res.style.color='#15803d';ok++;}
else{
const ss=s.nums.slice().sort((a,b)=>a-b);
res.textContent='Нет: '+ss[0]+'²+'+ss[1]+'²='+(ss[0]*ss[0]+ss[1]*ss[1])+', '+ss[2]+'²='+(ss[2]*ss[2]);
res.style.color='#dc2626';
}
});
const fb=document.getElementById('p15-quiz-fb');
fb.style.display='block';
if(ok===sets.length){feedback(fb,true,'Все верно! +5 XP');addXp(5,'p15-quiz');bumpProgress('p15',10);confetti();}
else{feedback(fb,false,'Верно: '+ok+' из '+total+'.');}
});
document.getElementById('p15-quiz-reset').addEventListener('click',()=>{
sets.forEach((_,i)=>{
cont.querySelectorAll('[name="p15-qz-'+i+'"]').forEach(r=>r.checked=false);
document.getElementById('p15-qz-res'+i).textContent='';
});
document.getElementById('p15-quiz-fb').style.display='none';
});
})();
/* == INIT: DnD примитивные vs кратные == */
(function(){
const items=[
{id:'e1',html:'(3, 4, 5)',cat:'prim'},
{id:'e2',html:'(5, 12, 13)',cat:'prim'},
{id:'e3',html:'(7, 24, 25)',cat:'prim'},
{id:'e4',html:'(6, 8, 10)',cat:'mult'},
{id:'e5',html:'(9, 12, 15)',cat:'mult'},
{id:'e6',html:'(8, 15, 17)',cat:'prim'},
{id:'e7',html:'(10, 24, 26)',cat:'mult'},
{id:'e8',html:'(20, 21, 29)',cat:'prim'},
];
const sorter=setupSorter({poolId:'p15-dnd-pool',scopeSelector:'#p15-dnd-wg',items:items.map(x=>({id:x.id,html:x.html})),cats:['prim','mult']});
document.getElementById('p15-dnd-check').addEventListener('click',()=>{
const fb=document.getElementById('p15-dnd-fb');fb.style.display='block';
let ok=0;
items.forEach(it=>{if(sorter.placed[it.id]===it.cat)ok++;});
if(ok===items.length){feedback(fb,true,'Всё верно! +5 XP');addXp(5,'p15-dnd');bumpProgress('p15',10);confetti();}
else{feedback(fb,false,'Верно: '+ok+' из '+items.length+'. Примитивные: (3,4,5),(5,12,13),(7,24,25),(8,15,17),(20,21,29).');}
});
document.getElementById('p15-dnd-reset').addEventListener('click',()=>{sorter.reset();document.getElementById('p15-dnd-fb').style.display='none';});
})();
/* == INIT: Босс §15 == */
(function(){
const tasks=[
{q:'Катеты прямоугольного треугольника $20$ и $21$ см. Гипотенуза (используй тройки)?', ans:29, hint:'(20,21,29) — пифагорова тройка. c=29.'},
{q:'Формула Евклида: $m=5, n=2$. Найти $c = m^2+n^2$.', ans:29, hint:'c=25+4=29.'},
{q:'Кратная тройка $(15, 20, 25)$ получена умножением $(3,4,5)$ на $k$. Найти $k$.', ans:5, hint:'15/3=5.'},
{q:'Стороны прямоугольного треугольника — тройка $(a,b,c)$, $c=65$, $a=25$. Найти $b$.', ans:60, hint:'b=√(65²-25²)=√(4225-625)=√3600=60.'},
{q:'Периметр прямоугольного треугольника равен $60$. Это тройка, кратная $(3,4,5)$. Найти гипотенузу.', ans:25, hint:'k·(3+4+5)=60 → k=5. c=5·5=25.'},
];
const bossBox=document.getElementById('p15-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="p15b-a${i}" placeholder="Ответ" style="width:110px">
<button class="btn primary small" onclick="(function(){
const v=+document.getElementById('p15b-a${i}').value;
const ok=Math.abs(v-${t.ans})<1.5;
const fb=document.getElementById('p15b-fb${i}');
fb.className='feedback '+(ok?'ok':'fail');
fb.innerHTML=ok?'&#10003; Верно! +5 XP':'&#10007; '+${JSON.stringify(t.hint)};
if(ok){addXp(5,'p15-boss-${i}');bumpProgress('p15',8);}
})()">Проверить</button>
<span class="feedback" id="p15b-fb${i}"></span>
</div>
</div>`).join('');
if(window.renderMathInElement) renderMath(bossBox);
})();
}
function buildFinal2(){
const box = document.getElementById('final2-body');
let html = '';
/* === ЧАСТЬ 1: Итоговая шпаргалка === */
html += `<div class="card" style="border-color:var(--sec-acc,var(--pri));background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)))">
<div class="card-header">
<div class="card-icon theory">
<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>
</div>
<div class="card-title">Итоговая шпаргалка · Вся Глава 2 «Площади»</div>
</div>
<div class="card-body">
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:10px">
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§1 Квадрат</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><rect x="10" y="8" width="44" height="44" fill="rgba(5,150,105,.12)" stroke="#059669" stroke-width="2"/><text x="32" y="32" text-anchor="middle" dominant-baseline="middle" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">a</text><text x="32" y="56" text-anchor="middle" font-size="8" fill="#059669" font-family="JetBrains Mono,monospace">a</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = a^2$</p>
<p style="font-size:.78rem;color:var(--muted)">$P = 4a$</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§2 Прямоугольник</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><rect x="6" y="14" width="52" height="32" fill="rgba(8,145,178,.12)" stroke="#0891b2" stroke-width="2"/><text x="32" y="10" text-anchor="middle" font-size="8" fill="#0891b2" font-family="JetBrains Mono,monospace">a</text><text x="62" y="32" font-size="8" fill="#0891b2" font-family="JetBrains Mono,monospace">b</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = a \cdot b$</p>
<p style="font-size:.78rem;color:var(--muted)">$P = 2(a+b)$</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§3 Параллелограмм</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="14,52 54,52 50,12 10,12" fill="rgba(139,92,246,.12)" stroke="#8b5cf6" stroke-width="2"/><line x1="14" y1="12" x2="14" y2="52" stroke="#8b5cf6" stroke-width="1.5" stroke-dasharray="3 2"/><text x="32" y="58" text-anchor="middle" font-size="8" fill="#8b5cf6" font-family="JetBrains Mono,monospace">a</text><text x="6" y="34" font-size="8" fill="#6d28d9" font-family="JetBrains Mono,monospace">h</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = a \cdot h$</p>
<p style="font-size:.78rem;color:var(--muted)">$h$ — высота</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§4 Треугольник</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="32,6 8,54 56,54" fill="rgba(217,119,6,.12)" stroke="#d97706" stroke-width="2"/><line x1="32" y1="6" x2="32" y2="54" stroke="#d97706" stroke-width="1.5" stroke-dasharray="3 2"/><path d="M32,54 L32,46 L40,46" fill="none" stroke="#d97706" stroke-width="1.5"/><text x="36" y="36" font-size="8" fill="#b45309" font-family="JetBrains Mono,monospace">h</text><text x="32" y="60" text-anchor="middle" font-size="8" fill="#b45309" font-family="JetBrains Mono,monospace">a</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = \\dfrac{1}{2}ah$</p>
<p style="font-size:.78rem;color:var(--muted)">$a$ — основание</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§5 Трапеция</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="10,52 54,52 46,12 18,12" fill="rgba(20,184,166,.12)" stroke="#14b8a6" stroke-width="2"/><text x="32" y="10" text-anchor="middle" font-size="7" fill="#0f766e" font-family="JetBrains Mono,monospace">b</text><text x="32" y="58" text-anchor="middle" font-size="7" fill="#0f766e" font-family="JetBrains Mono,monospace">a</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = \\dfrac{(a+b)}{2} h$</p>
<p style="font-size:.78rem;color:var(--muted)">$a,b$ — основания</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§6 Ромб</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="32,4 60,30 32,56 4,30" fill="rgba(236,72,153,.12)" stroke="#ec4899" stroke-width="2"/><line x1="4" y1="30" x2="60" y2="30" stroke="#ec4899" stroke-width="1.2" stroke-dasharray="3 2"/><line x1="32" y1="4" x2="32" y2="56" stroke="#ec4899" stroke-width="1.2" stroke-dasharray="3 2"/><text x="36" y="28" font-size="7" fill="#be185d" font-family="JetBrains Mono,monospace">d₁</text><text x="33" y="22" font-size="7" fill="#be185d" font-family="JetBrains Mono,monospace">d₂</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = \\dfrac{d_1 d_2}{2}$</p>
<p style="font-size:.78rem;color:var(--muted)">$= ah = a^2 \\sin\\alpha$</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§7 Прям. треугольник</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="10,50 10,10 50,50" fill="rgba(16,185,129,.12)" stroke="#10b981" stroke-width="2"/><path d="M10,50 L10,42 L18,42" fill="none" stroke="#10b981" stroke-width="1.5"/><text x="4" y="32" font-size="8" fill="#047857" font-family="JetBrains Mono,monospace">a</text><text x="28" y="56" font-size="8" fill="#047857" font-family="JetBrains Mono,monospace">b</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S = \\dfrac{1}{2}ab$</p>
<p style="font-size:.78rem;color:var(--muted)">$a,b$ — катеты</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§8 Высота к гипотенузе</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="8,52 56,52 8,8" fill="rgba(245,158,11,.12)" stroke="#f59e0b" stroke-width="2"/><path d="M8,8 L30,52" fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3 2"/><line x1="8" y1="8" x2="30" y2="52" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3 2"/><path d="M8,52 L8,44 L16,44" fill="none" stroke="#f59e0b" stroke-width="1.5"/><text x="20" y="46" font-size="7" fill="#b45309" font-family="JetBrains Mono,monospace">h_c</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$h_c = \\dfrac{ab}{c}$</p>
<p style="font-size:.78rem;color:var(--muted)">$c$ — гипотенуза</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§9 Общая высота</div>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$\\dfrac{S_1}{S_2} = \\dfrac{a_1}{a_2}$</p>
<p style="font-size:.78rem;color:var(--muted)">Треугольники с общей высотой</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§10 Медиана</div>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$S_{\\text{под}} = \\dfrac{S}{2}$ (медиана)</p>
<p style="font-size:.86rem;margin-bottom:4px">$S_{\\text{части}} = \\dfrac{S}{6}$ (центроид)</p>
<p style="font-size:.78rem;color:var(--muted)">3 медианы → 6 равных</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§11 Теорема Пифагора</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 64 60" style="width:64px;height:60px;flex-shrink:0"><polygon points="8,52 8,12 48,52" fill="rgba(99,102,241,.12)" stroke="#6366f1" stroke-width="2"/><path d="M8,52 L8,44 L16,44" fill="none" stroke="#6366f1" stroke-width="1.5"/><text x="1" y="32" font-size="8" fill="#4f46e5" font-family="JetBrains Mono,monospace">a</text><text x="24" y="58" font-size="8" fill="#4f46e5" font-family="JetBrains Mono,monospace">b</text><text x="28" y="30" font-size="8" fill="#4f46e5" font-family="JetBrains Mono,monospace">c</text></svg>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$c^2 = a^2 + b^2$</p>
<p style="font-size:.78rem;color:var(--muted)">$c$ — гипотенуза</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§12 Равносторонний</div>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$h = \\dfrac{a\\sqrt{3}}{2}$</p>
<p style="font-size:.86rem;margin-bottom:0">$S = \\dfrac{a^2\\sqrt{3}}{4}$</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§13 Диагональ квадрата</div>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$d = a\\sqrt{2}$</p>
<p style="font-size:.78rem;color:var(--muted)">из теор. Пифагора</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§14 Обратная теорема</div>
<div>
<p style="font-size:.9rem;margin-bottom:4px">$a^2+b^2=c^2$</p>
<p style="font-size:.78rem;color:var(--muted)">$\\Rightarrow$ угол при $c$ прямой</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§15 Пифагоровы тройки</div>
<div>
<p style="font-size:.9rem;margin-bottom:4px">(3, 4, 5)</p>
<p style="font-size:.86rem;margin-bottom:4px">(5, 12, 13)</p>
<p style="font-size:.86rem;margin-bottom:0">(8, 15, 17), (7, 24, 25)</p>
</div>
</div>
</div>
</div>
</div>`;
/* === ЧАСТЬ 2: Карта связей фигур === */
html += `<div class="wg" id="final2-hier-wrap">
<div class="wg-header"><span class="wg-badge">КАРТА СВЯЗЕЙ</span><div class="wg-title">Фигуры и их формулы площади</div></div>
<div class="wg-help">Нажми на фигуру, чтобы увидеть формулу площади и ключевые свойства.</div>
<div id="final2-hier-svg" style="display:flex;justify-content:center;overflow-x:auto"></div>
<div id="final2-hier-info" style="min-height:56px;padding:12px 16px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-top:10px;font-size:.9rem;line-height:1.65;color:var(--text)">Нажми на фигуру в схеме выше</div>
</div>`;
/* === ЧАСТЬ 3: 7 боссов === */
html += `<div class="wg" style="border-color:#059669;background:linear-gradient(135deg,var(--card),#d1fae5)">
<div class="wg-header">
<span class="wg-badge" style="background:#059669">7 БОССОВ ГЛАВЫ 2</span>
<div class="wg-title">Интегрированные задачи</div>
</div>
<div class="wg-help">Каждая задача объединяет 2–3 темы главы. +10 XP за каждого побеждённого босса. Победи всех семерых — получишь +50 XP и достижение «Мастер площадей»!</div>
<div id="final2-bosses"></div>
</div>`;
/* === ЧАСТЬ 4: Финальная плашка === */
html += `<div id="final2-finish" style="display:none;margin-top:20px;padding:24px;background:linear-gradient(135deg,#d1fae5,#ecfdf5);border:2px solid var(--ok,#10b981);border-radius:16px;text-align:center">
<div style="font-family:'Unbounded',sans-serif;font-size:1.2rem;font-weight:900;color:#065f46;margin-bottom:10px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:28px;height:28px;vertical-align:middle;margin-right:6px"><polygon points="12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26"/></svg>
Мастер площадей Главы 2!
</div>
<p style="color:#065f46;font-size:.95rem;margin-bottom:16px">Ты победил всех 7 боссов и освоил всю Главу 2 «Площади». Отличная работа!</p>
<a href="/textbook/geometry-8-ch3" class="btn primary" style="font-size:.98rem;padding:12px 28px">
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
Перейти к Главе 3
</a>
</div>`;
html += `<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="final2-read-btn" onclick="addXp(10,'final2-read');bumpProgress('final2',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>
Я изучил Главу 2 (+10 XP)
</button>
</div>`;
html += secNav('p15', null);
box.innerHTML = html;
/* === JS: Карта связей SVG === */
(function(){
const W = 620, H = 340;
const nodes = [
{ id:'area', x:310, y:28, rx:58, label:'Площадь',
props:'Площадь — мера части плоскости, занятой фигурой. Выражается в кв. единицах.' },
{ id:'rect', x:100, y:120, rx:54, label:'Прямоуг. фигуры',
props:'Квадрат: $S=a^2$. Прямоугольник: $S=ab$. Прямоугольный треугольник: $S=\\frac{1}{2}ab$ (катеты).' },
{ id:'para', x:310, y:120, rx:56, label:'Параллелограммы',
props:'Параллелограмм: $S=ah$. Ромб: $S=\\frac{d_1 d_2}{2}$. Прямоугольник: $S=ab$. Квадрат: $S=a^2$.' },
{ id:'tri', x:510, y:120, rx:48, label:'Треугольники',
props:'Произвольный: $S=\\frac{1}{2}ah$. Прямоугольный: $S=\\frac{1}{2}ab$. Равносторонний: $S=\\frac{a^2\\sqrt{3}}{4}$.' },
{ id:'sq', x:60, y:230, rx:40, label:'Квадрат',
props:'$S=a^2$, $P=4a$, диагональ $d=a\\sqrt{2}$. Частный случай прямоугольника и ромба.' },
{ id:'recta', x:160, y:230, rx:44, label:'Прямоугольник',
props:'$S=ab$, $P=2(a+b)$, $d=\\sqrt{a^2+b^2}$.' },
{ id:'rhomb', x:280, y:230, rx:42, label:'Ромб',
props:'$S=\\frac{d_1 d_2}{2}=ah=a^2\\sin\\alpha$. Диагонали перпендикулярны.' },
{ id:'trap', x:400, y:230, rx:42, label:'Трапеция',
props:'$S=\\frac{(a+b)}{2}h$. Средняя линия $m=\\frac{a+b}{2}$.' },
{ id:'eqtri', x:520, y:230, rx:44, label:'Равносторонний',
props:'$h=\\frac{a\\sqrt{3}}{2}$, $S=\\frac{a^2\\sqrt{3}}{4}$. Все углы $60°$.' },
{ id:'pytri', x:560, y:310, rx:44, label:'Прям. треугольник',
props:'$S=\\frac{1}{2}ab$ (катеты). Теорема Пифагора: $c^2=a^2+b^2$. Высота: $h_c=\\frac{ab}{c}$.' },
];
const edges = [
['area','rect'],['area','para'],['area','tri'],
['rect','sq'],['rect','recta'],
['para','sq'],['para','recta'],['para','rhomb'],
['tri','eqtri'],['tri','pytri'],['para','trap'],
];
let sel = null;
function draw(selId){
const colors = { area:'#059669', rect:'#0891b2', para:'#8b5cf6', tri:'#d97706', sq:'#14b8a6', recta:'#2563eb', rhomb:'#ec4899', trap:'#f97316', eqtri:'#e11d48', pytri:'#16a34a' };
let s = `<svg viewBox="0 0 ${W} ${H}" style="width:100%;max-width:640px;background:var(--card);border:1.5px solid var(--border);border-radius:14px;cursor:pointer">`;
s += `<defs><marker id="f2-arr" markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><polygon points="0 0,7 3.5,0 7" fill="#94a3b8"/></marker></defs>`;
edges.forEach(([a,b])=>{
const na=nodes.find(n=>n.id===a), nb=nodes.find(n=>n.id===b);
if(!na||!nb) return;
const dx=nb.x-na.x, dy=nb.y-na.y, len=Math.sqrt(dx*dx+dy*dy);
if(len<1) return;
const sy_r=na.rx*0.52;
const sx=na.x+dx/len*na.rx, sy2=na.y+dy/len*sy_r;
const ex=nb.x-dx/len*(nb.rx+7), ey=nb.y-dy/len*(nb.rx*0.52+7);
const isAct = selId===a||selId===b;
s += `<line x1="${sx.toFixed(1)}" y1="${sy2.toFixed(1)}" x2="${ex.toFixed(1)}" y2="${ey.toFixed(1)}" stroke="${isAct?'#059669':'#94a3b8'}" stroke-width="${isAct?2.5:1.5}" marker-end="url(#f2-arr)"/>`;
});
nodes.forEach(n=>{
const isS = selId===n.id;
const col = colors[n.id] || '#059669';
const ry = n.rx * 0.52;
s += `<ellipse cx="${n.x}" cy="${n.y}" rx="${n.rx}" ry="${ry}" fill="${isS?col:'var(--card)'}" stroke="${col}" stroke-width="${isS?3:2}" data-nid="${n.id}" style="cursor:pointer"/>`;
const words = n.label.split(' ');
const line1 = words.slice(0,2).join(' '), line2 = words.slice(2).join(' ');
const tc = isS ? '#fff' : col;
if(line2){
s += `<text x="${n.x}" y="${n.y-5}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line1}</text>`;
s += `<text x="${n.x}" y="${n.y+7}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line2}</text>`;
} else {
s += `<text x="${n.x}" y="${n.y+4}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line1}</text>`;
}
});
s += '</svg>';
document.getElementById('final2-hier-svg').innerHTML = s;
document.getElementById('final2-hier-svg').querySelector('svg').addEventListener('click', function(e){
const el = e.target.closest('[data-nid]');
if(!el) return;
const nid = el.dataset.nid;
sel = (sel===nid) ? null : nid;
const nd = nodes.find(n=>n.id===nid);
if(sel && nd){ document.getElementById('final2-hier-info').innerHTML = '<b>' + nd.label + '</b>: ' + nd.props; renderMath(document.getElementById('final2-hier-info')); }
else document.getElementById('final2-hier-info').textContent = 'Нажми на фигуру в схеме выше';
draw(sel);
});
}
draw(null);
})();
/* === JS: 7 боссов === */
(function(){
const bosses = [
{
n: 1,
title: 'Прямоугольный треугольник: Пифагор + высота',
color: '#059669',
svg: `<svg viewBox="0 0 260 180" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Right triangle A(20,155) B(200,155) C(20,20) -->
<polygon points="20,155 200,155 20,20" fill="rgba(5,150,105,.10)" stroke="#059669" stroke-width="2"/>
<!-- right angle at A -->
<path d="M20,155 L20,145 L30,145" fill="none" stroke="#059669" stroke-width="1.8"/>
<!-- height from C to hypotenuse CB foot H -->
<!-- H on line BC: parametric. B=(200,155) C=(20,20). direction=(180,135). len=225. foot from A=(20,155): t=((20-200)*(180)+(155-155)*(135))/(180^2+135^2)=-32400/56025=-0.5784 => H=(200-0.5784*180, 155-0.5784*135)=(95.9,77.4) -->
<line x1="20" y1="155" x2="96" y2="77" stroke="#8b5cf6" stroke-width="1.5" stroke-dasharray="4 2"/>
<!-- right angle mark at H=(96,77): u along CB=(0.8,0.6), w perp toward A=(-0.6,0.8), size=8 -->
<!-- P1=H+8u=(102,82), corner=H+8u+8w=(98,88), P3=H+8w=(91,83) -->
<path d="M102,82 L98,88 L91,83" fill="none" stroke="#8b5cf6" stroke-width="1.5"/>
<circle cx="96" cy="77" r="3.5" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
<!-- vertex dots -->
<circle cx="20" cy="155" r="4" fill="#059669" stroke="#fff" stroke-width="1.5"/>
<circle cx="200" cy="155" r="4" fill="#059669" stroke="#fff" stroke-width="1.5"/>
<circle cx="20" cy="20" r="4" fill="#059669" stroke="#fff" stroke-width="1.5"/>
<!-- labels -->
<text x="6" y="152" font-size="11" font-weight="700" fill="#065f46" font-family="Unbounded,sans-serif">A</text>
<text x="204" y="163" font-size="11" font-weight="700" fill="#065f46" font-family="Unbounded,sans-serif">B</text>
<text x="6" y="18" font-size="11" font-weight="700" fill="#065f46" font-family="Unbounded,sans-serif">C</text>
<text x="98" y="68" font-size="10" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">H</text>
<!-- side labels -->
<text x="4" y="92" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">a=9</text>
<text x="100" y="170" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">b=12</text>
<text x="108" y="88" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">h_c</text>
</svg>`,
cond: 'В прямоугольном треугольнике $ABC$ с прямым углом $A$ катеты $a = AC = 9$ и $b = AB = 12$.',
parts: [
{ label: 'Найди гипотенузу $c = BC$.', ans: 15, hint: '$c=\\sqrt{9^2+12^2}=\\sqrt{81+144}=\\sqrt{225}=15$' },
{ label: 'Найди высоту $h_c$ к гипотенузе (десятичный ответ допустим).', ans: 7.2, tol: 0.05, hint: '$h_c=\\dfrac{ab}{c}=\\dfrac{9\\cdot12}{15}=\\dfrac{108}{15}=7.2$' },
{ label: 'Найди площадь треугольника $ABC$.', ans: 54, hint: '$S=\\dfrac{1}{2}\\cdot9\\cdot12=54$' },
],
},
{
n: 2,
title: 'Параллелограмм через угол',
color: '#8b5cf6',
svg: `<svg viewBox="0 0 260 160" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Parallelogram A(30,130) B(220,130) C(200,30) D(10,30) -->
<polygon points="30,130 220,130 200,30 10,30" fill="rgba(139,92,246,.10)" stroke="#8b5cf6" stroke-width="2"/>
<!-- height from D(10,30) down to base AB at x=10, y=130 -->
<line x1="10" y1="30" x2="10" y2="130" stroke="#8b5cf6" stroke-width="1.5" stroke-dasharray="4 2"/>
<path d="M10,130 L10,122 L18,122" fill="none" stroke="#8b5cf6" stroke-width="1.5"/>
<!-- angle arc at A -->
<path d="M50,130 A22,22 0 0,1 36,112" stroke="#d97706" stroke-width="2" fill="rgba(217,119,6,.15)"/>
<text x="56" y="124" font-size="9" fill="#b45309" font-weight="700" font-family="JetBrains Mono,monospace">30°</text>
<!-- vertex dots and labels -->
<circle cx="30" cy="130" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
<circle cx="220" cy="130" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
<circle cx="200" cy="30" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
<circle cx="10" cy="30" r="4" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
<text x="16" y="147" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">A</text>
<text x="224" y="147" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">B</text>
<text x="204" y="24" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">C</text>
<text x="0" y="24" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">D</text>
<!-- side labels -->
<text x="116" y="148" text-anchor="middle" font-size="10" fill="#6d28d9" font-family="JetBrains Mono,monospace">14 см</text>
<text x="0" y="84" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">8 см</text>
<text x="2" y="116" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">h</text>
</svg>`,
cond: 'В параллелограмме $ABCD$ сторона $AB = 14$ см, смежная сторона $AD = 8$ см, угол при вершине $A$ равен $30°$.',
parts: [
{ label: 'Найди высоту $h$ параллелограмма ($h = AD \\cdot \\sin 30°$, в сантиметрах).', ans: 4, hint: '$h = AD \\cdot \\sin 30° = 8 \\cdot 0.5 = 4$ см' },
{ label: 'Найди площадь параллелограмма $S$ (кв. см).', ans: 56, hint: '$S = AB \\cdot h = 14 \\cdot 4 = 56$ кв. см' },
],
},
{
n: 3,
title: 'Трапеция и средняя линия',
color: '#f97316',
svg: `<svg viewBox="0 0 260 170" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Trapezoid A(20,145) B(240,145) C(200,50) D(60,50) -->
<polygon points="20,145 240,145 200,50 60,50" fill="rgba(249,115,22,.10)" stroke="#f97316" stroke-width="2"/>
<!-- height from D to AB -->
<line x1="60" y1="50" x2="60" y2="145" stroke="#f97316" stroke-width="1.5" stroke-dasharray="4 2"/>
<path d="M60,145 L60,137 L68,137" fill="none" stroke="#f97316" stroke-width="1.5"/>
<!-- midline MN -->
<line x1="40" y1="97" x2="220" y2="97" stroke="#d97706" stroke-width="2.5"/>
<circle cx="40" cy="97" r="4" fill="#d97706" stroke="#fff" stroke-width="1.5"/>
<circle cx="220" cy="97" r="4" fill="#d97706" stroke="#fff" stroke-width="1.5"/>
<text x="28" y="93" font-size="9" font-weight="700" fill="#b45309" font-family="Unbounded,sans-serif">M</text>
<text x="224" y="93" font-size="9" font-weight="700" fill="#b45309" font-family="Unbounded,sans-serif">N</text>
<!-- vertex dots -->
<circle cx="20" cy="145" r="4" fill="#f97316" stroke="#fff" stroke-width="1.5"/>
<circle cx="240" cy="145" r="4" fill="#f97316" stroke="#fff" stroke-width="1.5"/>
<circle cx="200" cy="50" r="4" fill="#f97316" stroke="#fff" stroke-width="1.5"/>
<circle cx="60" cy="50" r="4" fill="#f97316" stroke="#fff" stroke-width="1.5"/>
<text x="6" y="158" font-size="11" font-weight="700" fill="#c2410c" font-family="Unbounded,sans-serif">A</text>
<text x="244" y="158" font-size="11" font-weight="700" fill="#c2410c" font-family="Unbounded,sans-serif">B</text>
<text x="204" y="44" font-size="11" font-weight="700" fill="#c2410c" font-family="Unbounded,sans-serif">C</text>
<text x="46" y="44" font-size="11" font-weight="700" fill="#c2410c" font-family="Unbounded,sans-serif">D</text>
<!-- labels -->
<text x="130" y="164" text-anchor="middle" font-size="10" fill="#c2410c" font-family="JetBrains Mono,monospace">a=18</text>
<text x="130" y="44" text-anchor="middle" font-size="10" fill="#c2410c" font-family="JetBrains Mono,monospace">b=12</text>
<text x="46" y="102" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">h=5</text>
<text x="116" y="91" text-anchor="middle" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">m=?</text>
</svg>`,
cond: 'В трапеции основания $a = 18$ см и $b = 12$ см, высота $h = 5$ см.',
parts: [
{ label: 'Найди среднюю линию $m$ трапеции (см).', ans: 15, hint: '$m = \\dfrac{a+b}{2} = \\dfrac{18+12}{2} = 15$ см' },
{ label: 'Найди площадь трапеции $S$ (кв. см).', ans: 75, hint: '$S = \\dfrac{(a+b)}{2} \\cdot h = 15 \\cdot 5 = 75$ кв. см' },
],
},
{
n: 4,
title: 'Ромб: диагонали, сторона, площадь',
color: '#ec4899',
svg: `<svg viewBox="0 0 260 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Rhombus center (130,92). d1=16 horizontal, d2=12 vertical. Vertices: A(130,32) B(198,92) C(130,152) D(62,92) -->
<polygon points="130,32 198,92 130,152 62,92" fill="rgba(236,72,153,.10)" stroke="#ec4899" stroke-width="2"/>
<!-- diagonals -->
<line x1="62" y1="92" x2="198" y2="92" stroke="#ec4899" stroke-width="1.5" stroke-dasharray="4 2"/>
<line x1="130" y1="32" x2="130" y2="152" stroke="#ec4899" stroke-width="1.5" stroke-dasharray="4 2"/>
<!-- right angle at center -->
<path d="M130,92 L130,82 L140,82" fill="none" stroke="#ec4899" stroke-width="1.5"/>
<!-- vertex dots -->
<circle cx="130" cy="32" r="4" fill="#ec4899" stroke="#fff" stroke-width="1.5"/>
<circle cx="198" cy="92" r="4" fill="#ec4899" stroke="#fff" stroke-width="1.5"/>
<circle cx="130" cy="152" r="4" fill="#ec4899" stroke="#fff" stroke-width="1.5"/>
<circle cx="62" cy="92" r="4" fill="#ec4899" stroke="#fff" stroke-width="1.5"/>
<text x="116" y="26" font-size="11" font-weight="700" fill="#be185d" font-family="Unbounded,sans-serif">A</text>
<text x="202" y="100" font-size="11" font-weight="700" fill="#be185d" font-family="Unbounded,sans-serif">B</text>
<text x="116" y="170" font-size="11" font-weight="700" fill="#be185d" font-family="Unbounded,sans-serif">C</text>
<text x="46" y="100" font-size="11" font-weight="700" fill="#be185d" font-family="Unbounded,sans-serif">D</text>
<!-- diagonal labels -->
<text x="130" y="84" text-anchor="middle" font-size="9" fill="#be185d" font-family="JetBrains Mono,monospace">d₁=16</text>
<text x="146" y="68" font-size="9" fill="#be185d" font-family="JetBrains Mono,monospace">d₂=12</text>
</svg>`,
cond: 'В ромбе $ABCD$ диагонали $d_1 = 16$ см и $d_2 = 12$ см.',
parts: [
{ label: 'Найди площадь ромба $S$ (кв. см).', ans: 96, hint: '$S = \\dfrac{d_1 d_2}{2} = \\dfrac{16 \\cdot 12}{2} = 96$ кв. см' },
{ label: 'Найди сторону ромба $a$ (полудиагонали: $8$ и $6$, теорема Пифагора).', ans: 10, hint: '$a = \\sqrt{8^2 + 6^2} = \\sqrt{64+36} = \\sqrt{100} = 10$ см' },
{ label: 'Найди периметр ромба $P$ (см).', ans: 40, hint: '$P = 4a = 4 \\cdot 10 = 40$ см' },
],
},
{
n: 5,
title: 'Медиана и центроид',
color: '#2563eb',
svg: `<svg viewBox="0 0 260 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Triangle A(130,15) B(20,165) C(240,165). Midpoints: Ma=(B+C)/2=(130,165), Mb=(A+C)/2=(185,90), Mc=(A+B)/2=(75,90) -->
<polygon points="130,15 20,165 240,165" fill="rgba(37,99,235,.10)" stroke="#2563eb" stroke-width="2"/>
<!-- 3 medians -->
<line x1="130" y1="15" x2="130" y2="165" stroke="#2563eb" stroke-width="1.5" stroke-dasharray="5 3"/>
<line x1="20" y1="165" x2="185" y2="90" stroke="#2563eb" stroke-width="1.5" stroke-dasharray="5 3"/>
<line x1="240" y1="165" x2="75" y2="90" stroke="#2563eb" stroke-width="1.5" stroke-dasharray="5 3"/>
<!-- centroid G = ((130+20+240)/3, (15+165+165)/3) = (130, 115) -->
<circle cx="130" cy="115" r="6" fill="#2563eb" stroke="#fff" stroke-width="2"/>
<text x="136" y="114" font-size="11" font-weight="700" fill="#1d4ed8" font-family="Unbounded,sans-serif">G</text>
<!-- midpoints -->
<circle cx="130" cy="165" r="3.5" fill="#60a5fa" stroke="#fff" stroke-width="1.5"/>
<circle cx="185" cy="90" r="3.5" fill="#60a5fa" stroke="#fff" stroke-width="1.5"/>
<circle cx="75" cy="90" r="3.5" fill="#60a5fa" stroke="#fff" stroke-width="1.5"/>
<!-- vertex dots -->
<circle cx="130" cy="15" r="4" fill="#2563eb" stroke="#fff" stroke-width="1.5"/>
<circle cx="20" cy="165" r="4" fill="#2563eb" stroke="#fff" stroke-width="1.5"/>
<circle cx="240" cy="165" r="4" fill="#2563eb" stroke="#fff" stroke-width="1.5"/>
<text x="116" y="10" font-size="11" font-weight="700" fill="#1d4ed8" font-family="Unbounded,sans-serif">A</text>
<text x="4" y="178" font-size="11" font-weight="700" fill="#1d4ed8" font-family="Unbounded,sans-serif">B</text>
<text x="244" y="178" font-size="11" font-weight="700" fill="#1d4ed8" font-family="Unbounded,sans-serif">C</text>
<text x="116" y="182" font-size="9" fill="#1d4ed8" font-family="JetBrains Mono,monospace">S=36</text>
</svg>`,
cond: 'Площадь треугольника $ABC = 36$ кв. см. Точка $G$ — центроид (пересечение медиан).',
parts: [
{ label: 'Найди площадь треугольника, образованного центроидом $G$ и двумя вершинами (например, $\\triangle ABG$).', ans: 12, hint: 'Медиана делит треугольник на 2 равные части: $S/2=18$. Все 6 малых треугольников равны: $S_6 = 36/6 = 12$ кв. см' },
{ label: 'Одна медиана делит треугольник на 2 треугольника. Какова площадь каждого из них?', ans: 18, hint: 'Медиана делит треугольник на 2 равновеликих: $S/2 = 36/2 = 18$ кв. см' },
],
},
{
n: 6,
title: 'Равносторонний треугольник и центроид',
color: '#e11d48',
svg: `<svg viewBox="0 0 260 195" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Equilateral triangle: side 10. A(130,15) B(32,183) C(228,183) -->
<polygon points="130,15 32,183 228,183" fill="rgba(225,29,72,.10)" stroke="#e11d48" stroke-width="2"/>
<!-- height from A to BC -->
<line x1="130" y1="15" x2="130" y2="183" stroke="#e11d48" stroke-width="1.5" stroke-dasharray="4 2"/>
<path d="M130,183 L130,175 L138,175" fill="none" stroke="#e11d48" stroke-width="1.5"/>
<text x="136" y="140" font-size="10" fill="#be123c" font-weight="700" font-family="JetBrains Mono,monospace">h=?</text>
<!-- centroid G at (130, 127) = (1/3)(15+183+183) = 127 -->
<circle cx="130" cy="127" r="5" fill="#e11d48" stroke="#fff" stroke-width="2"/>
<text x="136" y="130" font-size="10" font-weight="700" fill="#be123c" font-family="Unbounded,sans-serif">G</text>
<!-- line from G to base midpoint (130,183) — centroid to foot -->
<line x1="130" y1="127" x2="130" y2="183" stroke="#f87171" stroke-width="1.2" stroke-dasharray="3 2"/>
<!-- vertex dots -->
<circle cx="130" cy="15" r="4" fill="#e11d48" stroke="#fff" stroke-width="1.5"/>
<circle cx="32" cy="183" r="4" fill="#e11d48" stroke="#fff" stroke-width="1.5"/>
<circle cx="228" cy="183" r="4" fill="#e11d48" stroke="#fff" stroke-width="1.5"/>
<text x="116" y="10" font-size="11" font-weight="700" fill="#be123c" font-family="Unbounded,sans-serif">A</text>
<text x="14" y="193" font-size="11" font-weight="700" fill="#be123c" font-family="Unbounded,sans-serif">B</text>
<text x="232" y="193" font-size="11" font-weight="700" fill="#be123c" font-family="Unbounded,sans-serif">C</text>
<text x="130" y="198" text-anchor="middle" font-size="10" fill="#be123c" font-family="JetBrains Mono,monospace">a=10</text>
</svg>`,
cond: 'В равностороннем треугольнике $ABC$ сторона $a = 10$ см. Точка $G$ — центроид.',
parts: [
{ label: 'Найди высоту $h$ равностороннего треугольника (введи значение, умноженное на 10, как целое: $h \\cdot 10 = ?$)', ans: 87, hint: '$h = \\dfrac{10\\sqrt{3}}{2} \\approx \\dfrac{10 \\cdot 1.732}{2} = 8.66$, умноженное на 10 = 86.6 \\approx 87', tol: 1 },
{ label: 'Найди площадь треугольника (введи значение, умноженное на 10, как целое: $S \\cdot 10 = ?$)', ans: 433, hint: '$S = \\dfrac{a^2\\sqrt{3}}{4} = \\dfrac{100\\sqrt{3}}{4} \\approx 43.3$, умноженное на 10 = 433', tol: 2 },
{ label: 'Найди расстояние от центроида $G$ до основания $BC$ (центроид делит высоту в отношении $2:1$, введи значение в целых мм: расстояние $\\cdot 10$)', ans: 29, hint: 'Расстояние = $h/3 = 8.66/3 \\approx 2.89$, умноженное на 10 = 28.9 \\approx 29', tol: 1 },
],
},
{
n: 7,
title: 'Пифагоровы тройки в задаче',
color: '#7c3aed',
svg: `<svg viewBox="0 0 260 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<!-- Right triangle with 5-12-13 triple. Scale: *10 for visual. A(20,165) B(20,25) C(150,165) -->
<polygon points="20,165 20,25 150,165" fill="rgba(124,58,237,.10)" stroke="#7c3aed" stroke-width="2"/>
<path d="M20,165 L20,153 L32,153" fill="none" stroke="#7c3aed" stroke-width="1.8"/>
<!-- vertex dots -->
<circle cx="20" cy="165" r="4" fill="#7c3aed" stroke="#fff" stroke-width="1.5"/>
<circle cx="20" cy="25" r="4" fill="#7c3aed" stroke="#fff" stroke-width="1.5"/>
<circle cx="150" cy="165" r="4" fill="#7c3aed" stroke="#fff" stroke-width="1.5"/>
<text x="2" y="162" font-size="11" font-weight="700" fill="#5b21b6" font-family="Unbounded,sans-serif">A</text>
<text x="2" y="22" font-size="11" font-weight="700" fill="#5b21b6" font-family="Unbounded,sans-serif">B</text>
<text x="154" y="178" font-size="11" font-weight="700" fill="#5b21b6" font-family="Unbounded,sans-serif">C</text>
<!-- side labels -->
<text x="0" y="102" font-size="10" fill="#5b21b6" font-family="JetBrains Mono,monospace">a=?</text>
<text x="72" y="180" font-size="10" fill="#5b21b6" font-family="JetBrains Mono,monospace">b=?</text>
<text x="84" y="88" font-size="10" fill="#5b21b6" font-family="JetBrains Mono,monospace">c=13</text>
<!-- perimeter label -->
<text x="130" y="20" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">P=30</text>
</svg>`,
cond: 'Прямоугольный треугольник имеет периметр $P = 30$ см и гипотенузу $c = 13$ см. Используй пифагорову тройку $(5, 12, 13)$.',
parts: [
{ label: 'Найди сумму катетов $a + b$ (см).', ans: 17, hint: '$a + b = P - c = 30 - 13 = 17$ см' },
{ label: 'Используя тройку $(5, 12, 13)$: найди меньший катет $a$ (см).', ans: 5, hint: 'Тройка $(5, 12, 13)$: катеты $5$ и $12$, $5+12=17$. Меньший катет $a = 5$ см' },
{ label: 'Найди площадь треугольника $S$ (кв. см).', ans: 30, hint: '$S = \\dfrac{1}{2} \\cdot 5 \\cdot 12 = 30$ кв. см' },
],
},
];
window.final2BossSolved = new Set();
const bossBox = document.getElementById('final2-bosses');
bossBox.innerHTML = bosses.map(b => {
const partsHtml = b.parts.map((p,pi) => {
const labelText = p._label_fix || p.label;
return `<div style="padding:10px 0;border-top:1px dashed var(--border)">
<div style="font-size:.9rem;margin-bottom:7px">${labelText}</div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" step="any" class="tinp final2-boss-inp" data-b="${b.n-1}" data-p="${pi}" placeholder="Ответ" style="width:120px">
<button class="btn primary final2-boss-check" data-b="${b.n-1}" data-p="${pi}" style="background:${b.color};border-color:${b.color}">Проверить</button>
<span class="final2-boss-ok" data-b="${b.n-1}" data-p="${pi}" style="display:none;color:var(--ok);font-weight:700">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" style="width:16px;height:16px;vertical-align:middle"><polyline points="20 6 9 17 4 12"/></svg>
</span>
</div>
<div class="feedback final2-boss-fb" data-b="${b.n-1}" data-p="${pi}" style="display:none;margin-top:6px"></div>
</div>`;
}).join('');
const svgHtml = b.svg ? `<div style="display:flex;justify-content:center;margin:10px 0">${b.svg}</div>` : '';
return `<div style="padding:16px;background:var(--card);border-radius:12px;border:2px solid ${b.color};margin-bottom:14px" id="final2-boss-card-${b.n-1}">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap">
<span style="background:${b.color};color:#fff;padding:4px 10px;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.7rem;font-weight:800">БОСС ${b.n}</span>
<span style="font-family:'Unbounded',sans-serif;font-size:.88rem;font-weight:800;color:${b.color}">${b.title}</span>
<span id="final2-boss-xp-${b.n-1}" style="margin-left:auto;display:none;background:var(--ok-bg);color:#065f46;padding:3px 10px;border-radius:99px;font-size:.78rem;font-weight:800">+10 XP</span>
</div>
<div style="padding:10px 14px;background:linear-gradient(135deg,#d1fae5,#fff);border-left:4px solid ${b.color};border-radius:9px;font-size:.92rem;line-height:1.6;margin-bottom:4px">${b.cond}</div>
${svgHtml}
${partsHtml}
</div>`;
}).join('');
function checkPart(bi, pi){
const boss = bosses[bi];
const part = boss.parts[pi];
const inp = bossBox.querySelector(`.final2-boss-inp[data-b="${bi}"][data-p="${pi}"]`);
const fb = bossBox.querySelector(`.final2-boss-fb[data-b="${bi}"][data-p="${pi}"]`);
const ok = bossBox.querySelector(`.final2-boss-ok[data-b="${bi}"][data-p="${pi}"]`);
if(!inp) return;
const val = parseFloat(inp.value);
const useExact = part._override && part._ans_exact !== undefined;
const ansCheck = useExact ? part._ans_exact : part.ans;
const tolCheck = useExact ? part._tol_exact : (part.tol !== undefined ? part.tol : 0);
const hintText = useExact ? part._hint_fix : part.hint;
if(Math.abs(val - ansCheck) <= tolCheck){
feedback(fb, true, 'Верно! ' + (hintText ? '<br><span style="font-size:.82rem;opacity:.85">' + hintText + '</span>' : ''));
inp.disabled = true;
const btn = bossBox.querySelector(`.final2-boss-check[data-b="${bi}"][data-p="${pi}"]`);
if(btn) btn.disabled = true;
if(ok) ok.style.display = 'inline';
const allDone = boss.parts.every((_,pj) => {
const el = bossBox.querySelector(`.final2-boss-inp[data-b="${bi}"][data-p="${pj}"]`);
return el && el.disabled;
});
if(allDone && !window.final2BossSolved.has(bi)){
window.final2BossSolved.add(bi);
addXp(10, 'final2-boss-' + (bi+1));
const xpBadge = document.getElementById('final2-boss-xp-' + bi);
if(xpBadge) xpBadge.style.display = 'inline';
bumpProgress('final2', 8);
if(window.final2BossSolved.size === bosses.length){
setTimeout(()=>{
confetti();
if(!STATE.achievements.has('final2-master')){
STATE.achievements.set('final2-master', 'Мастер площадей Главы 2');
saveProgress();
const pop = document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent = 'Мастер площадей Главы 2!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 4000); }
}
addXp(50, 'final2-all-bosses');
bumpProgress('final2', 20);
const fin = document.getElementById('final2-finish');
if(fin) fin.style.display = 'block';
}, 500);
}
}
} else {
feedback(fb, false, 'Неверно. Подсказка: ' + (hintText || part.hint));
}
}
bossBox.querySelectorAll('.final2-boss-check').forEach(btn=>{
btn.addEventListener('click', ()=>{ checkPart(+btn.dataset.b, +btn.dataset.p); });
});
bossBox.querySelectorAll('.final2-boss-inp').forEach(inp=>{
inp.addEventListener('keydown', e=>{ if(e.key==='Enter'){ const btn=bossBox.querySelector(`.final2-boss-check[data-b="${inp.dataset.b}"][data-p="${inp.dataset.p}"]`); if(btn)btn.click(); } });
});
})();
renderMath(box);
}
</script>
</body>
</html>