Files
Learn_System/frontend/textbooks/geometry_8_ch2.html
T
Maxim Dolgolyov faf0fc5b41 fix(geom8 ch2): §5 трапеция — высота между основаниями + правильные диагональ/треугольники
Было:
- 5.1: высота нарисована из вершины (некорректно как иллюстрация
  'расстояние между параллельными сторонами')
- 5.2: координаты треугольников ABD/BCD и диагонали указывали на точки
  ВНЕ трапеции (диагональ заканчивалась в (215,30) вместо вершины D=(65,30))
- 5.3: то же — высота из вершины

Стало:
- Высота — вертикальная пунктирная линия в середине трапеции от верхнего
  основания до нижнего, с прямым углом
- Все вершины ABCD подписаны и отмечены точками
- В 5.2 диагональ BD корректно проведена, треугольники ABD/BCD точно
  совпадают с половинами трапеции, добавлены подписи S₁=½ah, S₂=½bh

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

3946 lines
348 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:()=>buildP9stub(),p10:()=>buildP10stub(),
p11:()=>buildP11stub(),p12:()=>buildP12stub(),p13:()=>buildP13stub(),p14:()=>buildP14stub(),p15:()=>buildP15stub(),
final2:()=>buildFinal2stub(),
};
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" marker-end="url(#a2)" 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=400, H=260;
const AX=40, AY=200, BW=220;
let topB=100, topOff=40, trapH=110;
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 midX=(dx+cx)/2, midY=dy;
const Sval=Math.round((BW+topB)/2*trapH);
let s='<svg id="p5-trap-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">';
// height dashes
s+='<line x1="'+ax+'" y1="'+ay+'" x2="'+ax+'" y2="'+dy+'" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5 3"/>';
s+='<text x="'+(ax-14)+'" y="'+((ay+dy)/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>';
// right angle
s+='<polyline points="'+(ax+8)+','+ay+' '+(ax+8)+','+(ay-8)+' '+ax+','+(ay-8)+'" fill="none" stroke="#f59e0b" stroke-width="1.5"/>';
// trapezoid fill
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"/>';
// base a label
s+='<text x="'+((ax+bx)/2)+'" y="'+(ay+18)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#0369a1" font-family="JetBrains Mono,monospace">a='+BW+'</text>';
// top b label
s+='<text x="'+midX+'" y="'+(cy-8)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#0369a1" font-family="JetBrains Mono,monospace">b='+topB+'</text>';
// S label
const cxLabel=Math.round((ax+bx+cx+dx)/4), cyLabel=Math.round((ay+ay+cy+dy)/4);
s+='<text x="'+cxLabel+'" y="'+cyLabel+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">S='+Sval+'</text>';
// drag handles
const hTop=cx, hTopY=cy;
s+='<circle cx="'+hTop+'" cy="'+hTopY+'" r="12" fill="rgba(2,132,199,.18)"/>';
s+='<circle cx="'+hTop+'" cy="'+hTopY+'" r="7" fill="#0284c7" stroke="#fff" stroke-width="2" id="p5-drag-top" style="cursor:ew-resize"/>';
const hH=ax, hHY=Math.round(ay-trapH/2);
s+='<circle cx="'+hH+'" cy="'+hHY+'" r="12" fill="rgba(245,158,11,.18)"/>';
s+='<circle cx="'+hH+'" cy="'+hHY+'" r="7" fill="#f59e0b" stroke="#fff" stroke-width="2" id="p5-drag-h" style="cursor:ns-resize"/>';
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)/2·h</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(40,Math.min(160,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=400, H=220;
const ax=30, ay=180, bw=200, h=100, off=50;
const steps=[
{desc:'Исходная трапеция ABCD. Основания: $a=AB$ (нижнее) и $b=CD$ (верхнее), высота $h$.',
draw(){
const bx=ax+bw, dx=ax+off, cx=dx+Math.round(bw*0.55);
const dy=ay-h, cy=dy;
return '<polygon points="'+ax+','+ay+' '+bx+','+ay+' '+cx+','+cy+' '+dx+','+dy+'" fill="rgba(2,132,199,.15)" stroke="#0284c7" stroke-width="2.2"/>'
+'<line x1="'+ax+'" y1="'+ay+'" x2="'+ax+'" y2="'+dy+'" 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="#0369a1" font-family="JetBrains Mono,monospace">a</text>'
+'<text x="'+((dx+cx)/2)+'" y="'+(dy-6)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#0369a1" font-family="JetBrains Mono,monospace">b</text>'
+'<text x="'+(ax-14)+'" y="'+((ay+dy)/2)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>'
+'<text x="'+ax+'" y="'+(ay+14)+'" font-size="11" fill="#0369a1" font-weight="700">A</text>'
+'<text x="'+bx+'" y="'+(ay+14)+'" font-size="11" fill="#0369a1" font-weight="700">B</text>'
+'<text x="'+(cx+4)+'" y="'+(cy-4)+'" font-size="11" fill="#0369a1" font-weight="700">C</text>'
+'<text x="'+(dx-14)+'" y="'+(dy-4)+'" font-size="11" fill="#0369a1" font-weight="700">D</text>';
}},
{desc:'Повернём копию трапеции на 180° и приложим сверху-справа так, чтобы стороны CD совпали.',
draw(){
const bx=ax+bw, dx=ax+off, cx=dx+Math.round(bw*0.55);
const dy=ay-h, cy=dy;
const bw2=Math.round(bw*0.55);
const ax2=cx, ay2=cy, bx2=cx+bw, by2=cy, cx2=cx+bw-off, cy2=cy-h, dx2=cx, dy2=cy-h;
return '<polygon points="'+ax+','+ay+' '+bx+','+ay+' '+cx+','+cy+' '+dx+','+dy+'" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="2"/>'
+'<polygon points="'+ax2+','+ay2+' '+bx2+','+by2+' '+cx2+','+cy2+' '+dx2+','+dy2+'" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="2" stroke-dasharray="6 3"/>'
+'<text x="'+((ax+bx)/2)+'" y="'+(ay+16)+'" text-anchor="middle" font-size="11" fill="#0369a1" font-weight="700">a</text>'
+'<text x="'+((ax2+bx2)/2)+'" y="'+(ay2+14)+'" text-anchor="middle" font-size="11" fill="#6d28d9" font-weight="700">копия (перевёрнута)</text>';
}},
{desc:'Две трапеции образуют параллелограмм! Его основание $a+b$, высота $h$.',
draw(){
const bx=ax+bw, dx=ax+off, cx=dx+Math.round(bw*0.55);
const dy=ay-h, cy=dy;
const fullW=bw+Math.round(bw*0.55);
return '<polygon points="'+ax+','+ay+' '+(ax+fullW)+','+ay+' '+(ax+fullW-off)+','+(ay-h)+' '+(ax+off)+','+(ay-h)+'" fill="rgba(5,150,105,.18)" stroke="#059669" stroke-width="2.5"/>'
+'<text x="'+((ax+ax+fullW)/2)+'" y="'+(ay+16)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a+b</text>'
+'<text x="'+(ax-14)+'" y="'+((ay+ay-h)/2)+'" text-anchor="middle" font-size="12" font-weight="700" fill="#b45309" font-family="JetBrains Mono,monospace">h</text>'
+'<text x="'+((ax*2+fullW)/2)+'" y="'+((ay+ay-h)/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="700" fill="#047857" font-family="Unbounded,sans-serif">паралл.</text>';
}},
{desc:'Площадь параллелограмма $S_{\\text{пар}}=(a+b)\\cdot h$. Трапеция — его <b>половина</b>, значит $S=\\dfrac{(a+b)}{2}\\cdot h$.',
draw(){
const fullW=bw+Math.round(bw*0.55);
return '<polygon points="'+ax+','+ay+' '+(ax+fullW)+','+ay+' '+(ax+fullW-off)+','+(ay-h)+' '+(ax+off)+','+(ay-h)+'" fill="rgba(5,150,105,.12)" stroke="#059669" stroke-width="2"/>'
+'<polygon points="'+ax+','+ay+' '+(ax+bw)+','+ay+' '+(ax+Math.round(bw*0.55)+off)+','+(ay-h)+' '+(ax+off)+','+(ay-h)+'" fill="rgba(2,132,199,.28)" stroke="#0284c7" stroke-width="2.5"/>'
+'<line x1="'+(ax+bw)+'" y1="'+ay+'" x2="'+(ax+Math.round(bw*0.55)+off)+'" y2="'+(ay-h)+'" stroke="#0284c7" stroke-width="2" stroke-dasharray="5 3"/>'
+'<text x="'+((ax*2+bw)/2)+'" y="'+((ay+ay-h)/2)+'" text-anchor="middle" dominant-baseline="middle" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">S=½(a+b)h</text>';
}},
];
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">
<!-- main right triangle A(20,150) B(260,150) C(80,40) -->
<polygon points="20,150 260,150 80,40" fill="rgba(5,150,105,.12)" stroke="#059669" stroke-width="2.5"/>
<!-- right angle at C -->
<polyline points="90,40 90,50 80,50" fill="none" stroke="#059669" stroke-width="1.5"/>
<!-- foot of altitude H on AB: project C onto AB -->
<!-- AB horizontal y=150, foot is (80,150) -->
<line x1="80" y1="40" x2="80" y2="150" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<!-- right angle at H -->
<polyline points="80,140 90,140 90,150" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<!-- sub-triangle 1: A,H,C -->
<polygon points="20,150 80,150 80,40" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="1.2"/>
<!-- sub-triangle 2: H,B,C -->
<polygon points="80,150 260,150 80,40" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="1.2"/>
<!-- labels -->
<text x="14" y="162" font-size="11" font-weight="700" fill="#047857">A</text>
<text x="262" y="162" font-size="11" font-weight="700" fill="#047857">B</text>
<text x="67" y="36" font-size="11" font-weight="700" fill="#047857">C</text>
<text x="82" y="162" font-size="11" font-weight="700" fill="#b45309">H</text>
<text x="44" y="100" font-size="10" fill="#0284c7" font-family="JetBrains Mono,monospace">b</text>
<text x="185" y="100" font-size="10" fill="#7c3aed" font-family="JetBrains Mono,monospace">a</text>
<text x="140" y="163" text-anchor="middle" font-size="10" fill="#047857" font-family="JetBrains Mono,monospace">c</text>
<text x="88" y="100" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">h_c</text>
<text x="47" y="163" text-anchor="middle" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">a_c</text>
<text x="170" y="163" text-anchor="middle" font-size="9" fill="#7c3aed" font-family="JetBrains Mono,monospace">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 280 160" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Triangle with both height visualizations side by side -->
<!-- Left: via catheti a,b -->
<polygon points="20,140 110,140 20,40" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/>
<polyline points="32,140 32,128 20,128" fill="none" stroke="#059669" stroke-width="1.5"/>
<text x="65" y="154" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a</text>
<text x="8" y="90" text-anchor="middle" dominant-baseline="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace" transform="rotate(-90,8,90)">b</text>
<text x="60" y="100" text-anchor="middle" font-size="11" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S=ab/2</text>
<text x="65" y="20" text-anchor="middle" font-size="9" fill="#047857">катеты a, b</text>
<!-- Equals sign -->
<text x="135" y="100" text-anchor="middle" font-size="20" font-weight="900" fill="#059669">=</text>
<!-- Right: via hypotenuse c and h_c -->
<polygon points="160,140 260,140 200,40" fill="rgba(5,150,105,.15)" stroke="#059669" stroke-width="2"/>
<line x1="200" y1="40" x2="200" y2="140" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="200,130 210,130 210,140" fill="none" stroke="#f59e0b" stroke-width="1.5"/>
<text x="210" y="100" font-size="10" fill="#b45309" font-family="JetBrains Mono,monospace">h_c</text>
<text x="210" y="154" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">c</text>
<text x="210" y="20" text-anchor="middle" font-size="9" fill="#047857">гипотенуза c, h_c</text>
<text x="174" y="100" text-anchor="middle" font-size="11" font-weight="800" fill="#047857" font-family="Unbounded,sans-serif">S=ch_c/2</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 160" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- CLEAN: right angle at C(30,140). B(30,44) vertical cathetus b=6. D(158,140) horizontal cathetus a=8. H≈(76,79) -->
<!-- sub-triangles -->
<polygon points="30,140 76,79 30,44" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="1.2"/>
<polygon points="30,140 76,79 158,140" fill="rgba(124,58,237,.18)" stroke="#7c3aed" stroke-width="1.2"/>
<!-- main triangle -->
<polygon points="30,44 158,140 30,140" fill="none" stroke="#059669" stroke-width="2.5"/>
<!-- right angle at C(30,140) -->
<polyline points="42,140 42,128 30,128" fill="none" stroke="#059669" stroke-width="1.5"/>
<!-- altitude from C to hyp -->
<line x1="30" y1="140" x2="76" y2="79" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5 3"/>
<polyline points="68,85 74,70 82,76" fill="none" stroke="#f59e0b" stroke-width="1.3"/>
<!-- labels -->
<text x="18" y="144" font-size="11" font-weight="700" fill="#047857">C</text>
<text x="160" y="152" font-size="11" font-weight="700" fill="#047857">B</text>
<text x="18" y="40" font-size="11" font-weight="700" fill="#047857">A</text>
<text x="79" y="76" font-size="11" font-weight="700" fill="#b45309">H</text>
<text x="18" y="96" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">b=6</text>
<text x="92" y="152" text-anchor="middle" font-size="10" font-weight="700" fill="#047857" font-family="JetBrains Mono,monospace">a=8</text>
<text x="106" y="98" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">c=10</text>
<text x="42" y="108" font-size="9" fill="#b45309" 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 buildP9stub(){ document.getElementById('p9-body').innerHTML='<div class="card"><div class="card-body"><p><b>§9 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p8','p10'); }
function buildP10stub(){ document.getElementById('p10-body').innerHTML='<div class="card"><div class="card-body"><p><b>§10 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p9','p11'); }
function buildP11stub(){ document.getElementById('p11-body').innerHTML='<div class="card"><div class="card-body"><p><b>§11 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p10','p12'); }
function buildP12stub(){ document.getElementById('p12-body').innerHTML='<div class="card"><div class="card-body"><p><b>§12 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p11','p13'); }
function buildP13stub(){ document.getElementById('p13-body').innerHTML='<div class="card"><div class="card-body"><p><b>§13 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p12','p14'); }
function buildP14stub(){ document.getElementById('p14-body').innerHTML='<div class="card"><div class="card-body"><p><b>§14 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p13','p15'); }
function buildP15stub(){ document.getElementById('p15-body').innerHTML='<div class="card"><div class="card-body"><p><b>§15 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p14','final2'); }
function buildFinal2stub(){ document.getElementById('final2-body').innerHTML='<div class="card"><div class="card-body"><p><b>Финал главы 2 — Волна 1</b>: боссы и итоги появятся в следующем обновлении.</p></div></div>'+secNav('p15',null); }
</script>
</body>
</html>