Files
Learn_System/frontend/textbooks/geometry_8_ch4.html
T
Maxim Dolgolyov 2a6c214cd5 feat(geom8): Wave 3 Главы 4 — §8-§11 (центральный/вписанный углы)
§8 Центральный/вписанный углы. Дуга: slider центрального угла α от
0 до 360° с подсветкой дуги; SVG с вписанным углом и его позицией;
DnD центральный/вписанный/ни тот ни другой; калькулятор длины дуги
ℓ=α/360·2πR; тренажёр; босс.

§9 Свойство вписанного угла: dual slider центральный α + вписанный
β=α/2 на одной дуге; 5-шаговое доказательство для случая O на стороне
вписанного угла через равнобедренный △ и внешний угол; двунаправленный
калькулятор; DnD верно/неверно; тренажёр; босс.

§10 Вписанные углы на одну дугу: SVG с дугой AC и 3 вершинами
B₁,B₂,B₃ на другой части — все углы AB_iC равны; 3-шаговое
доказательство через половину центрального; калькулятор; DnD; тренажёр;
босс.

§11 Вписанный угол на диаметр: slider позиции C — угол ACB всегда
90°, прямоугольный треугольник вписан с гипотенузой = диаметр;
4-шаговое доказательство; калькулятор через Пифагор (диаметр+катет
→ другой катет); тренажёр; DnD; босс.

File: 3060 → 4549 LOC. 11 of 16 §§ Главы 4.

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

4550 lines
349 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 · Глава 4 · Окружности</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:#ecfeff; --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:#0891b2; --pri2:#0e7490; --pri-soft:#cffafe;
--acc:#06b6d4; --acc2:#0891b2; --acc-soft:#a5f3fc;
--ok:#10b981; --ok-bg:#d1fae5; --warn:#f59e0b; --warn-bg:#fef3c7;
--bad:#ef4444; --fail:#dc2626; --fail-bg:#fee2e2;
}
.dark{--bg:#03080f; --card:#040d17; --card-soft:#06121f; --text:#ecfeff; --ink:#ecfeff; --muted:#5ea4b8; --border:#0d2535}
*{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,#164e63 0%,#0891b2 55%,#22d3ee 100%);color:#fff;padding:46px 22px 30px;overflow:hidden;border-bottom:2px solid rgba(34,211,238,.2);min-height:130px}
.hdr::before{content:'ГЛАВА 4';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(165,243,252,.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(8,145,178,.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(8,145,178,.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(8,145,178,.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(8,145,178,.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,#ecfeff,#cffafe)}
.psel-card.final .psel-num{color:var(--warn)}
/* SECTION COLORS — cyan/sky/blue spectrum */
.sec[id="sec-p1"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.sec[id="sec-p2"] { --sec-acc:#06b6d4; --sec-acc-d:#0891b2; --sec-acc-soft:#a5f3fc; }
.sec[id="sec-p3"] { --sec-acc:#0284c7; --sec-acc-d:#0369a1; --sec-acc-soft:#e0f2fe; }
.sec[id="sec-p4"] { --sec-acc:#2563eb; --sec-acc-d:#1d4ed8; --sec-acc-soft:#dbeafe; }
.sec[id="sec-p5"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.sec[id="sec-p6"] { --sec-acc:#06b6d4; --sec-acc-d:#0891b2; --sec-acc-soft:#a5f3fc; }
.sec[id="sec-p7"] { --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.sec[id="sec-p8"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.sec[id="sec-p9"] { --sec-acc:#06b6d4; --sec-acc-d:#0891b2; --sec-acc-soft:#a5f3fc; }
.sec[id="sec-p10"] { --sec-acc:#0284c7; --sec-acc-d:#0369a1; --sec-acc-soft:#e0f2fe; }
.sec[id="sec-p11"] { --sec-acc:#2563eb; --sec-acc-d:#1d4ed8; --sec-acc-soft:#dbeafe; }
.sec[id="sec-p12"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.sec[id="sec-p13"] { --sec-acc:#06b6d4; --sec-acc-d:#0891b2; --sec-acc-soft:#a5f3fc; }
.sec[id="sec-p14"] { --sec-acc:#0d9488; --sec-acc-d:#0f766e; --sec-acc-soft:#ccfbf1; }
.sec[id="sec-p15"] { --sec-acc:#0284c7; --sec-acc-d:#0369a1; --sec-acc-soft:#e0f2fe; }
.sec[id="sec-p16"] { --sec-acc:#2563eb; --sec-acc-d:#1d4ed8; --sec-acc-soft:#dbeafe; }
.sec[id="sec-final4"] { --sec-acc:#0891b2; --sec-acc-d:#0e7490; --sec-acc-soft:#cffafe; }
.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(8,145,178,.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(8,145,178,.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(6,182,212,.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,#0891b2,#06b6d4);color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(8,145,178,.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(8,145,178,.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 · Глава 4</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> = половина центрального, хорды, секущие, взаимное расположение двух окружностей. 16 параграфов богатой классической геометрии.</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="&#8869;"><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="&#8857;"><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="&#8857;&#8857;"><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="&#9998;"><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="&#8736;"><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="&#8857;&#8857;"><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="d"><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="&#8736;2"><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="&#189;&#8736;"><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="="><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="90&#176;"><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="&#8756;"><div class="sec-header"><span class="sec-num">§ 12</span><h2 class="sec-h">Угол между касательной и хордой</h2></div><div id="p12-body"></div></section>
<section id="sec-p13" class="sec" data-watermark="&#10005;"><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="))(("><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="&#8901;"><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-p16" class="sec" data-watermark="&#215;"><div class="sec-header"><span class="sec-num">§ 16</span><h2 class="sec-h">Свойство касательной и секущей</h2></div><div id="p16-body"></div></section>
<section id="sec-final4" class="sec" data-watermark="&#9733;"><div class="sec-header"><span class="sec-num" style="background:linear-gradient(135deg,#0891b2,#06b6d4)">Финал главы</span><h2 class="sec-h">Итоги. Боссы главы 4</h2></div><div id="final4-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» · Глава 4 · Окружности · LearnSpace</footer>
<div id="ach-popup" class="ach-popup"><svg class="ic" viewBox="0 0 24 24" style="width:22px;height:22px"><circle cx="12" cy="12" r="9"/></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,p16:0,final4: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:'Начало главы 4!', ch4_done:'Окружности изучены!' };
function loadProgress(){ try{ const s=localStorage.getItem('geometry8_ch4_progress');if(s)Object.assign(STATE.progress,JSON.parse(s)); const a=localStorage.getItem('geometry8_ch4_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_ch4_progress',JSON.stringify(STATE.progress));localStorage.setItem('geometry8_ch4_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-ch4';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-ch4-'+(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=17;
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"><circle cx="12" cy="12" r="9"/></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:'Признак касательной'},
{id:'p2',num:'§ 2',name:'Свойство касательной',sub:'Перпендикулярность'},
{id:'p3',num:'§ 3',name:'Касательные из одной точки',sub:'Равные отрезки'},
{id:'p4',num:'§ 4',name:'Построение касательной',sub:'Циркуль и линейка'},
{id:'p5',num:'§ 5',name:'Окружности в угле',sub:'Вписанные в угол'},
{id:'p6',num:'§ 6',name:'Две окружности',sub:'Взаимное расположение'},
{id:'p7',num:'§ 7',name:'Общая внешняя касательная',sub:'Формула длины'},
{id:'p8',num:'§ 8',name:'Центральный и вписанный угол',sub:'Определения'},
{id:'p9',num:'§ 9',name:'Свойство вписанного угла',sub:'Половина центрального'},
{id:'p10',num:'§ 10',name:'Углы на одной дуге',sub:'Равные вписанные углы'},
{id:'p11',num:'§ 11',name:'Угол на диаметре',sub:'Прямой угол'},
{id:'p12',num:'§ 12',name:'Касательная и хорда',sub:'Угол между ними'},
{id:'p13',num:'§ 13',name:'Угол между хордами',sub:'Полусумма дуг'},
{id:'p14',num:'§ 14',name:'Угол между секущими',sub:'Полуразность дуг'},
{id:'p15',num:'§ 15',name:'Пересекающиеся хорды',sub:'Произведение отрезков'},
{id:'p16',num:'§ 16',name:'Касательная и секущая',sub:'Квадрат касательной'},
{id:'final4',num:'★',name:'Финал главы',sub:'Итоги · Боссы',final:true},
];
function buildParaSelector(){const g=document.getElementById('psel-grid');g.innerHTML='';PARAS.forEach(p=>{const card=document.createElement('div');card.className='psel-card'+(p.final?' final':'');card.dataset.id=p.id;card.dataset.progCard=p.id;card.innerHTML=`<div class="psel-num">${p.num}</div><div class="psel-name">${p.name}</div><div class="psel-prog"><div class="psel-prog-fill"></div></div>`;card.addEventListener('click',()=>goTo(p.id));g.appendChild(card);});}
const BUILT=new Set();
const BUILDERS={p1:()=>buildP1(),p2:()=>buildP2(),p3:()=>buildP3(),p4:()=>buildP4(),p5:()=>buildP5(),p6:()=>buildP6(),p7:()=>buildP7(),p8:()=>buildP8(),p9:()=>buildP9(),p10:()=>buildP10(),p11:()=>buildP11(),p12:()=>buildP12stub(),p13:()=>buildP13stub(),p14:()=>buildP14stub(),p15:()=>buildP15stub(),p16:()=>buildP16stub(),final4:()=>buildFinal4stub()};
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:[['Касательная','прямая с единственной общей точкой с окружностью'],['Признак','прямая ⊥ радиусу в точке касания']]},
p2:{title:'Шпаргалка § 2',rows:[['Свойство','касательная ⊥ радиусу в точке касания']]},
p3:{title:'Шпаргалка § 3',rows:[['Из одной точки','две касательные равны'],['|PA| = |PB|','']]},
p4:{title:'Шпаргалка § 4',rows:[['Построение','окружность на диаметре OP находит точки касания']]},
p5:{title:'Шпаргалка § 5',rows:[['Вписанные в угол','касаются обеих сторон угла'],['Центры','лежат на биссектрисе угла']]},
p6:{title:'Шпаргалка § 6',rows:[['Внешнее касание','$d = r_1 + r_2$'],['Внутреннее касание','$d = |r_1 - r_2|$'],['Пересечение','$|r_1-r_2| < d < r_1+r_2$']]},
p7:{title:'Шпаргалка § 7',rows:[['Внешняя касательная','$l = \\sqrt{d^2 - (r_1 - r_2)^2}$']]},
p8:{title:'Шпаргалка § 8',rows:[['Центральный угол','вершина в центре'],['Вписанный угол','вершина на окружности'],['Градусная мера дуги','= центральный угол']]},
p9:{title:'Шпаргалка § 9',rows:[['Вписанный = ½ центрального','$\\angle = \\dfrac{1}{2}\\cdot$дуга']]},
p10:{title:'Шпаргалка § 10',rows:[['Одна дуга','все вписанные углы равны']]},
p11:{title:'Шпаргалка § 11',rows:[['На диаметре','вписанный угол = 90°'],['Следствие','диаметр — хорда, стягивающая прямой угол']]},
p12:{title:'Шпаргалка § 12',rows:[['Касательная и хорда','угол = половине дуги, отсекаемой хордой']]},
p13:{title:'Шпаргалка § 13',rows:[['Хорды пересекаются','$\\angle = \\dfrac{1}{2}(\\text{дуга}_1 + \\text{дуга}_2)$']]},
p14:{title:'Шпаргалка § 14',rows:[['Секущие из точки вне','$\\angle = \\dfrac{1}{2}|\\text{дуга}_1 - \\text{дуга}_2|$']]},
p15:{title:'Шпаргалка § 15',rows:[['Пересекающиеся хорды','$PA\\cdot PB = PC\\cdot PD$']]},
p16:{title:'Шпаргалка § 16',rows:[['Касательная и секущая','$t^2 = PA\\cdot PB$'],['$t$','длина касательной']]},
final4:{title:'Финал главы',rows:[['16 параграфов','окружности изучены'],['Главное','вписанный угол = ½ дуги']]},
};
const TIPS=[
{sec:'p1',html:'Касательная ⊥ радиусу в точке касания — это и признак, и свойство.'},
{sec:'p2',html:'Из любой внешней точки можно провести <b>две</b> касательных к окружности.'},
{sec:'p3',html:'Отрезки двух касательных из одной внешней точки равны.'},
{sec:'p4',html:'Точки касания находятся на пересечении вспомогательной окружности и данной.'},
{sec:'p5',html:'Окружности, вписанные в угол, имеют центры на биссектрисе этого угла.'},
{sec:'p6',html:'$d > r_1 + r_2$ — нет общих точек. $d = r_1 + r_2$ — внешнее касание.'},
{sec:'p7',html:'Длина общей внешней касательной: $l=\\sqrt{d^2-(r_1-r_2)^2}$.'},
{sec:'p8',html:'Градусная мера дуги = величина центрального угла, опирающегося на эту дугу.'},
{sec:'p9',html:'Вписанный угол <b>вдвое меньше</b> центрального, опирающегося на ту же дугу.'},
{sec:'p10',html:'Все вписанные углы, опирающиеся на одну дугу, равны между собой.'},
{sec:'p11',html:'Вписанный угол, опирающийся на диаметр, всегда равен $90°$.'},
{sec:'p12',html:'Угол между касательной и хордой = половине дуги, отсекаемой этой хордой.'},
{sec:'p13',html:'Угол между хордами = полусумма двух дуг, образованных хордами.'},
{sec:'p14',html:'Угол между двумя секущими из внешней точки = полуразность дуг.'},
{sec:'p15',html:'Если хорды $AB$ и $CD$ пересекаются в точке $P$: $PA\\cdot PB = PC\\cdot PD$.'},
{sec:'p16',html:'Если из точки $P$ проведены касательная $t$ и секущая $PA\\cdot PB$: $t^2 = PA\\cdot PB$.'},
{sec:'final4',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:#0e4f6b;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"><circle cx="12" cy="12" r="9"/></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_ch4_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_ch4_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',p16:'§16',final4:'Финал'};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=['#0891b2','#06b6d4','#22d3ee','#f59e0b','#10b981'];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:'p1',aliases:['секущая','секущей','секущую','секущих','секущими']},
{term:'радиус',def:'Отрезок от центра окружности до любой её точки; также длина этого отрезка.',sec:'p1',aliases:['радиус','радиуса','радиусу','радиусом','радиусы','радиусов']},
{term:'хорда',def:'Отрезок, соединяющий две точки окружности.',sec:'p13',aliases:['хорда','хорды','хорде','хорду','хорд','хордами']},
{term:'центральный угол',def:'Угол с вершиной в центре окружности, стороны которого — радиусы.',sec:'p8',aliases:['центральный угол','центрального угла','центральному углу','центральные углы']},
{term:'вписанный угол',def:'Угол с вершиной на окружности, стороны которого — хорды.',sec:'p8',aliases:['вписанный угол','вписанного угла','вписанному углу','вписанные углы','вписанных углов']},
{term:'дуга',def:'Часть окружности, ограниченная двумя точками.',sec:'p8',aliases:['дуга','дуги','дуге','дугу','дуг','дугами']},
{term:'диаметр',def:'Хорда, проходящая через центр окружности; наибольшая хорда.',sec:'p11',aliases:['диаметр','диаметра','диаметре','диаметром']},
{term:'многоугольник',def:'Замкнутая ломаная фигура.',sec:'p1',aliases:['многоугольник','многоугольника']},
{term:'подобные треугольники',def:'Треугольники с равными углами и пропорциональными сторонами.',sec:'p9',aliases:['подобные треугольники','подобных треугольников']},
{term:'коэффициент подобия',def:'Отношение соответственных сторон подобных фигур.',sec:'p9',aliases:['коэффициент подобия','коэффициента подобия']},
{term:'биссектриса',def:'Луч, делящий угол пополам.',sec:'p5',aliases:['биссектриса','биссектрисы','биссектрису']},
{term:'теорема Пифагора',def:'$a^2+b^2=c^2$ в прямоугольном треугольнике.',sec:'p7',aliases:['теорема Пифагора','теореме Пифагора','теоремы Пифагора']},
{term:'параллелограмм',def:'Четырёхугольник с двумя парами параллельных сторон.',sec:'p1',aliases:['параллелограмм','параллелограмма']},
{term:'медиана',def:'Отрезок из вершины треугольника к середине противоположной стороны.',sec:'p1',aliases:['медиана','медианы','медиану']},
{term:'площадь',def:'Числовая мера размера плоской фигуры.',sec:'p1',aliases:['площадь','площади','площадью']},
{term:'трапеция',def:'Четырёхугольник с одной парой параллельных сторон.',sec:'p1',aliases:['трапеция','трапеции','трапецию']},
{term:'диагональ',def:'Отрезок, соединяющий несмежные вершины многоугольника.',sec:'p1',aliases:['диагональ','диагонали','диагоналей']},
{term:'гипотенуза',def:'Сторона прямоугольного треугольника, противолежащая прямому углу.',sec:'p1',aliases:['гипотенуза','гипотенузы','гипотенузу']},
{term:'высота',def:'Перпендикуляр из вершины на противоположную сторону.',sec:'p1',aliases:['высота','высоты','высоту']},
{term:'теорема Фалеса',def:'Параллельные прямые пропорционально рассекают секущие.',sec:'p1',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}));[['Формула','Вписанный угол = ½ центрального','§9','p9'],['Формула','На диаметре: вписанный угол = 90°','§11','p11'],['Формула','Хорды: PA·PB = PC·PD','§15','p15'],['Формула','Касательная: t² = PA·PB','§16','p16']].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','Начало главы 4!'),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);
function buildP1(){
const box=document.getElementById('p1-body');
let html='';
html+=makeCard('theory','Касательная к окружности','1.1',`
<p><b>Определение.</b> Прямая называется <b>касательной</b> к окружности, если она имеет с окружностью ровно одну общую точку. Эта общая точка называется <b>точкой касания</b>.</p>
<p style="margin-top:8px">Прямая может быть расположена относительно окружности тремя способами:</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li>Расстояние от центра до прямой <b>$d &lt; R$</b> — прямая <b>секущая</b> (2 общие точки).</li>
<li>Расстояние от центра до прямой <b>$d = R$</b> — прямая <b>касательная</b> (1 общая точка).</li>
<li>Расстояние от центра до прямой <b>$d &gt; R$</b> — прямая <b>не пересекает</b> окружность (0 общих точек).</li>
</ul>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 130" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<defs><marker id="arr-p1" markerWidth="6" markerHeight="6" refX="3" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="#0891b2"/></marker></defs>
<!-- секущая -->
<circle cx="52" cy="65" r="30" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="14" y1="50" x2="90" y2="50" stroke="#0891b2" stroke-width="2"/>
<circle cx="27" cy="50" r="3" fill="#0891b2"/>
<circle cx="77" cy="50" r="3" fill="#0891b2"/>
<text x="52" y="112" text-anchor="middle" font-size="10" fill="#0e7490" font-weight="700">секущая</text>
<text x="52" y="124" text-anchor="middle" font-size="9" fill="#64748b" font-style="italic">d &lt; R</text>
<!-- касательная -->
<circle cx="140" cy="65" r="30" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="102" y1="35" x2="178" y2="35" stroke="#10b981" stroke-width="2.2"/>
<circle cx="140" cy="35" r="3.5" fill="#10b981"/>
<text x="140" y="112" text-anchor="middle" font-size="10" fill="#065f46" font-weight="700">касательная</text>
<text x="140" y="124" text-anchor="middle" font-size="9" fill="#64748b" font-style="italic">d = R</text>
<!-- не пересекает -->
<circle cx="228" cy="65" r="30" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="190" y1="20" x2="266" y2="20" stroke="#ef4444" stroke-width="2"/>
<text x="228" y="112" text-anchor="middle" font-size="10" fill="#7f1d1d" font-weight="700">не пересекает</text>
<text x="228" y="124" text-anchor="middle" font-size="9" fill="#64748b" font-style="italic">d &gt; R</text>
</svg>
</div>`);
html+=makeCard('rule','Признак касательной','1.2',`
<p><b>Теорема (признак касательной).</b> Если прямая проходит через точку окружности и перпендикулярна радиусу, проведённому в эту точку, то эта прямая является касательной к окружности.</p>
$$OT \\perp \\ell \\implies \\ell \\text{ — касательная в точке } T$$
<p style="margin-top:8px"><b>Расстояние от центра</b> до касательной равно радиусу: $d(O,\\ell) = R$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 200 160" style="max-width:220px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="100" cy="90" r="55" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="2"/>
<line x1="100" y1="90" x2="100" y2="35" stroke="#0891b2" stroke-width="2"/>
<circle cx="100" cy="90" r="3" fill="#0e7490"/>
<circle cx="100" cy="35" r="3.5" fill="#10b981"/>
<line x1="40" y1="35" x2="160" y2="35" stroke="#10b981" stroke-width="2.5"/>
<polyline points="100,35 109,35 109,44 100,44" fill="none" stroke="#0e7490" stroke-width="1.8"/>
<text x="104" y="70" font-size="11" font-weight="700" fill="#0e7490">R</text>
<text x="108" y="31" font-size="11" font-weight="700" fill="#065f46">T</text>
<text x="86" y="106" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="38" y="28" font-size="10" fill="#065f46" font-style="italic">&#8467;</text>
</svg>
</div>`);
html+=makeCard('example','Пример','1.3',`
<p><b>Задача.</b> Радиус окружности $R = 5$. Расстояние от центра $O$ до прямой $\ell$ равно $d$. Является ли прямая касательной, секущей или не пересекает окружность при:</p>
<table class="tbl" style="margin-top:8px">
<thead><tr><th>$d$</th><th>Вид прямой</th></tr></thead>
<tbody>
<tr><td>$3$</td><td style="color:#0e7490;font-weight:700">секущая ($3 &lt; 5$)</td></tr>
<tr><td>$5$</td><td style="color:#065f46;font-weight:700">касательная ($5 = 5$)</td></tr>
<tr><td>$7$</td><td style="color:#7f1d1d;font-weight:700">не пересекает ($7 &gt; 5$)</td></tr>
</tbody>
</table>`);
/* ИНТЕРАКТИВ 1 — слайдер d */
html+=`<div class="wg" id="p1-dist-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Расположение прямой относительно окружности</div></div>
<div class="wg-help">Двигай слайдер — наблюдай, как меняется расположение прямой. При $d = R$ прямая становится касательной!</div>
<div class="sliders">
<label>Расстояние $d$ = <b id="p1-d-val">60</b> (R = 60)
<input type="range" min="0" max="130" value="60" id="p1-d-sl">
</label>
</div>
<div id="p1-dist-svg" style="display:flex;justify-content:center"></div>
<div id="p1-dist-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.94rem;font-weight:700;text-align:center"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — Пошаговое доказательство признака */
html+=`<div class="wg" id="p1-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="p1-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p1-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.94rem;line-height:1.65;margin-bottom:10px;min-height:64px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p1-proof-next">Далее</button>
<button class="btn" id="p1-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — Калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: проверка типа прямой</div></div>
<div class="wg-help">Введи радиус $R$ и расстояние $d$ от центра до прямой — узнай её вид.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R = <input type="number" id="p1-cr" class="tinp" value="5" min="0.1" style="width:80px"></label>
<label style="font-size:.9rem">d = <input type="number" id="p1-cd" class="tinp" value="3" min="0" style="width:80px"></label>
<button class="btn primary" id="p1-calc-btn">Определить</button>
</div>
<div id="p1-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — DnD-сортер */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Сортировщик: касательная, секущая или нет?</div></div>
<div class="wg-help">Перетащи каждую карточку в нужную корзину. Дано R и d.</div>
<div id="p1-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-top:10px">
<div class="drop-box" id="p1-drop-sec"><h5>Секущая</h5><div class="drop-items" id="p1-drop-sec-items"></div></div>
<div class="drop-box" id="p1-drop-tan"><h5>Касательная</h5><div class="drop-items" id="p1-drop-tan-items"></div></div>
<div class="drop-box" id="p1-drop-none"><h5>Не пересекает</h5><div class="drop-items" id="p1-drop-none-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p1-dnd-check">Проверить</button><button class="btn" id="p1-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p1-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Тренажёр §1</div></div>
<div class="wg-help">5 задач на распознавание и вычисление. Введи ответ и нажми «Проверить».</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:1rem;margin-bottom:10px;line-height:1.6"></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:130px">
<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>`;
/* ИНТЕРАКТИВ 6 — Босс §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 ИНТЕРАКТИВ 1: слайдер d === */
(function(){
const sl=document.getElementById('p1-d-sl');
const dVal=document.getElementById('p1-d-val');
const svgWrap=document.getElementById('p1-dist-svg');
const info=document.getElementById('p1-dist-info');
const R=60, cx=140, cy=100, W=280, H=200;
function draw(){
const d=+sl.value;
dVal.textContent=d;
const lineY=cy-d;
const hasIntersect=d<R;
const isTan=Math.abs(d-R)<1;
let ix1=0,ix2=0,iy1=0;
if(hasIntersect){
const dx=Math.sqrt(R*R-d*d);
ix1=cx-dx; ix2=cx+dx; iy1=lineY;
}
let pts='', tanMark='';
if(isTan){
pts=`<circle cx="${cx}" cy="${lineY}" r="5" fill="#10b981"/>`;
} else if(hasIntersect){
pts=`<circle cx="${ix1}" cy="${iy1}" r="4" fill="#0891b2"/><circle cx="${ix2}" cy="${iy1}" r="4" fill="#0891b2"/>`;
}
const lineColor=isTan?'#10b981':hasIntersect?'#0891b2':'#ef4444';
const dLineX1=cx, dLineY1=cy, dLineX2=cx, dLineY2=lineY;
const svgStr=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0e7490"/>
<text x="${cx+5}" y="${cy+5}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<line x1="20" y1="${lineY}" x2="${W-20}" y2="${lineY}" stroke="${lineColor}" stroke-width="2.5"/>
<line x1="${dLineX1}" y1="${dLineY1}" x2="${dLineX2}" y2="${dLineY2}" stroke="#64748b" stroke-width="1.5" stroke-dasharray="4,3"/>
<text x="${cx+4}" y="${(cy+lineY)/2+4}" font-size="10" fill="#64748b" font-style="italic">d=${d}</text>
${pts}
${tanMark}
</svg>`;
svgWrap.innerHTML=svgStr;
if(isTan){
info.style.background='#d1fae5';info.style.color='#065f46';
info.textContent='d = R = '+R+' — прямая КАСАТЕЛЬНАЯ (1 общая точка)';
} else if(hasIntersect){
info.style.background='var(--sec-acc-soft,#cffafe)';info.style.color='#0e7490';
info.textContent='d = '+d+' < R = '+R+' — прямая СЕКУЩАЯ (2 общие точки)';
} else {
info.style.background='#fee2e2';info.style.color='#7f1d1d';
info.textContent='d = '+d+' > R = '+R+' — прямая НЕ ПЕРЕСЕКАЕТ окружность';
}
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT ИНТЕРАКТИВ 2: пошаговое доказательство === */
(function(){
const steps=[
{text:'<b>Дано:</b> окружность с центром $O$, точка $T$ на окружности, прямая $\\ell$ проходит через $T$ и $OT \\perp \\ell$. Нужно доказать, что $\\ell$ — касательная.',
highlight:'none'},
{text:'<b>Шаг 1.</b> Возьмём произвольную точку $M \\neq T$ на прямой $\\ell$. Нам нужно показать, что $M$ лежит вне окружности, то есть $OM > R$.',
highlight:'M'},
{text:'<b>Шаг 2.</b> В прямоугольном треугольнике $OTM$ гипотенуза $OM$ больше любого катета. Поскольку $OT = R$ является катетом, то $OM > OT = R$.',
highlight:'triangle'},
{text:'<b>Шаг 3.</b> Значит, любая точка $M \\neq T$ на прямой $\\ell$ лежит вне окружности. Следовательно, прямая $\\ell$ имеет с окружностью только одну общую точку $T$.',
highlight:'conclude'},
{text:'По определению, прямая с единственной общей точкой с окружностью является касательной. <b>ч.т.д.</b>',
highlight:'done'},
];
let step=0;
const svgEl=document.getElementById('p1-proof-svg');
const txtEl=document.getElementById('p1-proof-text');
const nextBtn=document.getElementById('p1-proof-next');
const resetBtn=document.getElementById('p1-proof-reset');
const cx=130, cy=110, R=70;
function drawProof(s){
const h=s.highlight;
const Tx=cx, Ty=cy-R;
const Mx=cx+80, My=Ty;
let extras='';
if(h==='M'||h==='triangle'||h==='conclude'||h==='done'){
extras+=`<circle cx="${Mx}" cy="${My}" r="4" fill="#f59e0b"/>`;
extras+=`<text x="${Mx+5}" y="${My-4}" font-size="11" font-weight="700" fill="#b45309">M</text>`;
extras+=`<line x1="${cx}" y1="${cy}" x2="${Mx}" y2="${My}" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4,3"/>`;
}
if(h==='triangle'||h==='conclude'||h==='done'){
extras+=`<polygon points="${cx},${cy} ${Tx},${Ty} ${Mx},${My}" fill="rgba(245,158,11,.12)" stroke="#f59e0b" stroke-width="1.2"/>`;
extras+=`<polyline points="${Tx},${Ty+9} ${Tx+9},${Ty+9} ${Tx+9},${Ty}" fill="none" stroke="#0e7490" stroke-width="1.8"/>`;
}
const lineColor=h==='done'?'#10b981':'#0891b2';
const svg=`<svg viewBox="0 0 260 200" style="max-width:280px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(8,145,178,.09)" stroke="${lineColor}" stroke-width="2"/>
<line x1="${cx}" y1="${cy}" x2="${Tx}" y2="${Ty}" stroke="#0891b2" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0e7490"/>
<circle cx="${Tx}" cy="${Ty}" r="4" fill="#10b981"/>
<line x1="20" y1="${Ty}" x2="240" y2="${Ty}" stroke="${lineColor}" stroke-width="2.2"/>
<text x="${cx+4}" y="${cy+5}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="${Tx+4}" y="${Ty-6}" font-size="11" font-weight="700" fill="#065f46">T</text>
<text x="22" y="${Ty-5}" font-size="10" fill="#065f46" font-style="italic">&#8467;</text>
<text x="${(cx+Tx)/2+4}" y="${(cy+Ty)/2+4}" font-size="10" fill="#0e7490" font-weight="700">R</text>
${extras}
</svg>`;
svgEl.innerHTML=svg;
txtEl.innerHTML=steps[s.idx].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
nextBtn.textContent=step>=steps.length-1?'Готово':'Далее';
}
steps.forEach((s,i)=>s.idx=i);
function go(){
drawProof(steps[step]);
if(step<steps.length-1) step++;
}
nextBtn.addEventListener('click',go);
resetBtn.addEventListener('click',()=>{step=0;go();});
go();
})();
/* === INIT ИНТЕРАКТИВ 3: калькулятор === */
(function(){
const btn=document.getElementById('p1-calc-btn');
const out=document.getElementById('p1-calc-out');
btn.addEventListener('click',()=>{
const R=parseFloat(document.getElementById('p1-cr').value);
const d=parseFloat(document.getElementById('p1-cd').value);
if(isNaN(R)||isNaN(d)||R<=0||d<0){out.style.display='block';out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите корректные значения (R > 0, d ≥ 0)';return;}
out.style.display='block';
if(Math.abs(d-R)<1e-9){out.style.background='#d1fae5';out.style.color='#065f46';out.textContent='d = R = '+fmt(R)+' → прямая КАСАТЕЛЬНАЯ';}
else if(d<R){out.style.background='var(--sec-acc-soft,#cffafe)';out.style.color='#0e7490';out.textContent='d = '+fmt(d)+' < R = '+fmt(R)+' → прямая СЕКУЩАЯ';}
else{out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='d = '+fmt(d)+' > R = '+fmt(R)+' → прямая НЕ ПЕРЕСЕКАЕТ окружность';}
});
})();
/* === INIT ИНТЕРАКТИВ 4: DnD === */
(function(){
const items=[
{label:'R=5, d=3',cat:'sec'},{label:'R=8, d=8',cat:'tan'},{label:'R=6, d=9',cat:'none'},
{label:'R=10, d=7',cat:'sec'},{label:'R=4, d=4',cat:'tan'},{label:'R=3, d=5',cat:'none'},
];
const pool=document.getElementById('p1-dnd-pool');
const boxes={sec:document.getElementById('p1-drop-sec-items'),tan:document.getElementById('p1-drop-tan-items'),none:document.getElementById('p1-drop-none-items')};
const fb=document.getElementById('p1-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
setupChip(chip,i);
pool.appendChild(chip);
});
}
function setupChip(chip,i){
chip.addEventListener('click',()=>{
if(placed[i]!==undefined){
boxes[placed[i]].removeChild(chip);
delete placed[i];
chip.querySelector('.dnd-x')&&chip.querySelector('.dnd-x').remove();
pool.appendChild(chip);
return;
}
chip.classList.add('armed');
});
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
const x=document.createElement('span');x.className='dnd-x';x.textContent='×';
x.addEventListener('click',e=>{e.stopPropagation();boxes[cat].removeChild(chip);delete placed[i];x.remove();pool.appendChild(chip);});
chip.appendChild(x);
box.appendChild(chip);
});
});
}
document.getElementById('p1-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+'. '+(ok===items.length?'Все правильно!':'Попробуй ещё.'));
if(ok===items.length){addXp(8,'p1-dnd');bumpProgress('p1',15);}
});
document.getElementById('p1-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT ИНТЕРАКТИВ 5: Тренажёр === */
(function(){
const tasks=[
{q:'Радиус окружности $R = 13$. Расстояние от центра до прямой $d = 5$. Сколько общих точек у прямой с окружностью?',a:'2',hint:'d < R → секущая → 2 точки'},
{q:'Радиус $R = 7$. Прямая касается окружности. Расстояние от центра до прямой равно?',a:'7',hint:'При касании d = R = 7'},
{q:'От центра до прямой $d = 10$, радиус $R = 6$. Сколько общих точек?',a:'0',hint:'d > R → 0 точек'},
{q:'Прямая перпендикулярна радиусу $OT = 4$ в точке $T$ на окружности. Расстояние от центра до прямой равно?',a:'4',hint:'Признак касательной: расстояние = R = 4'},
{q:'Прямая касается окружности радиуса $R = 9$. Каково расстояние от центра до точки касания?',a:'9',hint:'Расстояние от центра до точки касания = R'},
];
let cur=0,score=0;
const iEl=document.getElementById('p1-tr-i');
const scEl=document.getElementById('p1-tr-score');
const taskEl=document.getElementById('p1-tr-task');
const ansEl=document.getElementById('p1-tr-ans');
const goBtn=document.getElementById('p1-tr-go');
const startBtn=document.getElementById('p1-tr-start');
const fb=document.getElementById('p1-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p1-trainer');bumpProgress('p1',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=ansEl.value.trim().replace(',','.');
const ok=Math.abs(parseFloat(ans)-parseFloat(tasks[cur].a))<0.01;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT ИНТЕРАКТИВ 6: Босс §1 === */
(function(){
const tasks=[
{q:'Прямая проходит через точку $A(6, 0)$ и параллельна оси $Oy$. Центр окружности $O(0,0)$, радиус $R = 6$. Является ли прямая касательной?',
opts:['Да, касательная','Нет, секущая','Нет, не пересекает'],cor:0,
exp:'Расстояние от центра $(0,0)$ до прямой $x=6$ равно $6 = R$. Прямая является касательной.'},
{q:'Из точки $M$ вне окружности расстояние до центра $|OM| = 10$, радиус $R = 6$. Прямая $MN$ перпендикулярна $OM$. Является ли $MN$ касательной?',
opts:['Да','Нет, секущая','Нет, не пересекает'],cor:2,
exp:'$MN \\perp OM$, значит расстояние от $O$ до $MN$ равно $|OM| = 10 > R = 6$. Прямая не пересекает окружность.'},
{q:'Прямая $\\ell$ перпендикулярна радиусу $OR$ в точке $R$ на окружности. Выбери верное утверждение:',
opts:['$\\ell$ — касательная в точке $R$','$\\ell$ — секущая','$\\ell$ не пересекает окружность'],cor:0,
exp:'По признаку касательной: прямая, проходящая через точку окружности и перпендикулярная радиусу в этой точке, является касательной.'},
{q:'Расстояние от центра окружности до прямой равно диаметру. Прямая является:',
opts:['касательной','секущей','не пересекает окружность'],cor:2,
exp:'Диаметр $= 2R > R$, значит $d > R$ — прямая не пересекает окружность.'},
];
const cont=document.getElementById('p1-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss="p1-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss=\\'p1-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p1-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p1-boss-${i}');bumpProgress('p1',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p1-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP2(){
const box=document.getElementById('p2-body');
let html='';
html+=makeCard('theory','Свойство касательной','2.1',`
<p><b>Теорема (свойство касательной).</b> Касательная к окружности перпендикулярна радиусу, проведённому в точку касания.</p>
$$OT \\perp \\ell$$
<p style="margin-top:8px">где $O$ — центр, $T$ — точка касания, $\\ell$ — касательная.</p>
<p style="margin-top:8px"><b>Доказательство — от противного.</b> Предположим, что $OT$ не перпендикулярно $\\ell$. Тогда из $O$ можно опустить перпендикуляр на $\\ell$ в точку $H \\neq T$, и $OH &lt; OT = R$. Значит, $H$ лежит внутри окружности. Но тогда прямая $\\ell$ пересекает окружность в двух точках — противоречие с тем, что $\\ell$ касательная. Следовательно, $OT \\perp \\ell$. <b>ч.т.д.</b></p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 200 170" style="max-width:220px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="100" cy="95" r="58" fill="rgba(6,182,212,.08)" stroke="#0891b2" stroke-width="2"/>
<line x1="100" y1="95" x2="100" y2="37" stroke="#0891b2" stroke-width="2"/>
<circle cx="100" cy="95" r="3.5" fill="#0e7490"/>
<circle cx="100" cy="37" r="4" fill="#06b6d4"/>
<line x1="30" y1="37" x2="170" y2="37" stroke="#06b6d4" stroke-width="2.5"/>
<polyline points="100,37 109,37 109,46 100,46" fill="none" stroke="#0e7490" stroke-width="1.8"/>
<text x="104" y="70" font-size="11" font-weight="700" fill="#0e7490">R</text>
<text x="105" y="33" font-size="11" font-weight="700" fill="#0e7490">T</text>
<text x="86" y="111" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="28" y="30" font-size="10" fill="#0891b2" font-style="italic">&#8467;</text>
<text x="100" y="158" text-anchor="middle" font-size="10" fill="#0e7490" font-weight="700">&#8736;OT&#8467; = 90°</text>
</svg>
</div>`);
html+=makeCard('rule','Следствие: длина касательной из внешней точки','2.2',`
<p>Если из внешней точки $A$ проведена касательная до точки касания $T$, то:</p>
$$AT = \\sqrt{|OA|^2 - R^2}$$
<p style="margin-top:8px">Это следует из теоремы Пифагора для прямоугольного треугольника $OAT$: $|OA|^2 = R^2 + AT^2$.</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">
<circle cx="80" cy="90" r="50" fill="rgba(6,182,212,.08)" stroke="#0891b2" stroke-width="2"/>
<circle cx="80" cy="90" r="3.5" fill="#0e7490"/>
<line x1="80" y1="90" x2="80" y2="40" stroke="#0891b2" stroke-width="2"/>
<circle cx="80" cy="40" r="4" fill="#06b6d4"/>
<line x1="80" y1="40" x2="200" y2="90" stroke="#10b981" stroke-width="2.2"/>
<line x1="80" y1="90" x2="200" y2="90" stroke="#64748b" stroke-width="1.8" stroke-dasharray="5,3"/>
<polyline points="80,40 89,40 89,49 80,49" fill="none" stroke="#0e7490" stroke-width="1.8"/>
<text x="84" y="68" font-size="10" font-weight="700" fill="#0e7490">R</text>
<text x="83" y="37" font-size="11" font-weight="700" fill="#0e7490">T</text>
<text x="64" y="106" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="204" y="94" font-size="11" font-weight="700" fill="#065f46">A</text>
<text x="130" y="36" font-size="10" fill="#065f46" font-weight="700">AT</text>
<text x="130" y="106" font-size="10" fill="#64748b" font-style="italic">|OA|</text>
</svg>
</div>`);
html+=makeCard('example','Пример','2.3',`
<p><b>Задача.</b> Радиус окружности $R = 5$, расстояние от внешней точки $A$ до центра $|OA| = 13$. Найти длину касательной $AT$.</p>
<p style="margin-top:8px"><b>Решение:</b> $AT = \\sqrt{|OA|^2 - R^2} = \\sqrt{169 - 25} = \\sqrt{144} = 12$.</p>
<p style="margin-top:8px"><b>Ответ:</b> $AT = 12$.</p>`);
/* ИНТЕРАКТИВ 1 — SVG с угловым маркером перпендикулярности */
html+=`<div class="wg" id="p2-perp-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Касательная всегда перпендикулярна радиусу</div></div>
<div class="wg-help">Перемещай точку касания $T$ по окружности — касательная и радиус $OT$ всегда перпендикулярны. Угловой маркер 90° следует за $T$.</div>
<div class="sliders">
<label>Угол точки $T$: <b id="p2-t-val">90</b>°
<input type="range" min="0" max="359" value="90" id="p2-t-sl">
</label>
</div>
<div id="p2-perp-svg" style="display:flex;justify-content:center"></div>
<div id="p2-perp-info" style="margin-top:8px;padding:8px 14px;background:#d1fae5;border-radius:10px;color:#065f46;font-weight:700;font-size:.94rem;text-align:center">&#8736;OT&#8467; = 90° всегда</div>
</div>`;
/* ИНТЕРАКТИВ 2 — Пошаговое доказательство от противного */
html+=`<div class="wg" id="p2-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="p2-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p2-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.94rem;line-height:1.65;margin-bottom:10px;min-height:64px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p2-proof-next">Далее</button>
<button class="btn" id="p2-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — Калькулятор длины касательной */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: длина касательной из внешней точки</div></div>
<div class="wg-help">Дано $R$ и $|OA|$ — найди $AT = \\sqrt{|OA|^2 - R^2}$.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R = <input type="number" id="p2-cr" class="tinp" value="5" min="0.1" style="width:80px"></label>
<label style="font-size:.9rem">|OA| = <input type="number" id="p2-coa" class="tinp" value="13" min="0.1" style="width:80px"></label>
<button class="btn primary" id="p2-calc-btn">Вычислить AT</button>
</div>
<div id="p2-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §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:1rem;margin-bottom:10px;line-height:1.6"></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:130px">
<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>`;
/* ИНТЕРАКТИВ 5 — DnD верные/неверные утверждения */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Верно или неверно о касательной?</div></div>
<div class="wg-help">Перетащи утверждение в нужную колонку.</div>
<div id="p2-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
<div class="drop-box" id="p2-drop-true"><h5>Верно</h5><div class="drop-items" id="p2-drop-true-items"></div></div>
<div class="drop-box" id="p2-drop-false"><h5>Неверно</h5><div class="drop-items" id="p2-drop-false-items"></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>`;
/* ИНТЕРАКТИВ 6 — Босс §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 ИНТЕРАКТИВ 1: вращение T по окружности === */
(function(){
const sl=document.getElementById('p2-t-sl');
const tVal=document.getElementById('p2-t-val');
const svgWrap=document.getElementById('p2-perp-svg');
const cx=140, cy=110, R=70, W=280, H=210;
function draw(){
const angDeg=+sl.value;
tVal.textContent=angDeg;
const angRad=(angDeg-90)*Math.PI/180;
const Tx=cx+R*Math.cos(angRad);
const Ty=cy+R*Math.sin(angRad);
// unit vectors
const urx=(Tx-cx)/R, ury=(Ty-cy)/R;
const utx=-ury, uty=urx; // tangent unit vector (perp to radius)
const tLen=80;
const lx1=Tx-utx*tLen, ly1=Ty-uty*tLen;
const lx2=Tx+utx*tLen, ly2=Ty+uty*tLen;
// right angle marker at T: 9px square
const s=9;
const mx1=Tx+urx*s, my1=Ty+ury*s;
const mx2=Tx+urx*s+utx*s, my2=Ty+ury*s+uty*s;
const mx3=Tx+utx*s, my3=Ty+uty*s;
const svg=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(6,182,212,.09)" stroke="#06b6d4" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0e7490"/>
<line x1="${cx}" y1="${cy}" x2="${Tx.toFixed(1)}" y2="${Ty.toFixed(1)}" stroke="#0891b2" stroke-width="2.2"/>
<circle cx="${Tx.toFixed(1)}" cy="${Ty.toFixed(1)}" r="5" fill="#06b6d4"/>
<line x1="${lx1.toFixed(1)}" y1="${ly1.toFixed(1)}" x2="${lx2.toFixed(1)}" y2="${ly2.toFixed(1)}" stroke="#10b981" stroke-width="2.5"/>
<polyline points="${mx1.toFixed(1)},${my1.toFixed(1)} ${mx2.toFixed(1)},${my2.toFixed(1)} ${mx3.toFixed(1)},${my3.toFixed(1)}" fill="none" stroke="#0e7490" stroke-width="1.8"/>
<text x="${cx+4}" y="${cy+5}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="${(Tx+4).toFixed(1)}" y="${(Ty-6).toFixed(1)}" font-size="11" font-weight="700" fill="#0e7490">T</text>
<text x="10" y="${H-8}" font-size="10" fill="#065f46" font-weight="700">&#8467; (касательная)</text>
<text x="${cx}" y="${H-8}" font-size="10" fill="#065f46" font-weight="700" text-anchor="middle">&#8736;OT&#8467; = 90°</text>
</svg>`;
svgWrap.innerHTML=svg;
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT ИНТЕРАКТИВ 2: доказательство от противного === */
(function(){
const steps=[
{text:'<b>Дано:</b> окружность с центром $O$ и радиусом $R$; прямая $\\ell$ касается окружности в точке $T$ ($\\ell$ имеет с окружностью ровно одну общую точку). Доказать: $OT \\perp \\ell$.',
phase:'given'},
{text:'<b>Допущение (от противного).</b> Предположим, что $OT$ не перпендикулярно $\\ell$. Тогда из $O$ можно опустить перпендикуляр $OH$ на $\\ell$, где $H \\neq T$.',
phase:'contra'},
{text:'<b>Шаг 2.</b> В прямоугольном треугольнике $OHT$ гипотенуза $OT = R$, катет $OH &lt; OT$. Значит, $OH &lt; R$ — точка $H$ лежит <em>внутри</em> окружности.',
phase:'inside'},
{text:'<b>Шаг 3.</b> Прямая $\\ell$, проходящая через точку $H$ внутри окружности, обязана пересекать окружность в двух точках. Но $\\ell$ — касательная (одна общая точка). Противоречие!',
phase:'contradiction'},
{text:'<b>Вывод.</b> Допущение неверно. Следовательно, $OT \\perp \\ell$. <b>ч.т.д.</b>',
phase:'done'},
];
let step=0;
const svgEl=document.getElementById('p2-proof-svg');
const txtEl=document.getElementById('p2-proof-text');
const nextBtn=document.getElementById('p2-proof-next');
const resetBtn=document.getElementById('p2-proof-reset');
const cx=130, cy=100, R=65;
function drawProof(ph){
const Tx=cx, Ty=cy-R;
let extras='';
if(ph==='contra'||ph==='inside'||ph==='contradiction'||ph==='done'){
const Hx=cx+40, Hy=Ty;
extras+=`<circle cx="${Hx}" cy="${Hy}" r="4" fill="#ef4444"/>`;
extras+=`<text x="${Hx+4}" y="${Hy-5}" font-size="11" font-weight="700" fill="#7f1d1d">H</text>`;
extras+=`<line x1="${cx}" y1="${cy}" x2="${Hx}" y2="${Hy}" stroke="#ef4444" stroke-width="1.8" stroke-dasharray="4,3"/>`;
if(ph==='inside'||ph==='contradiction'){
extras+=`<circle cx="${Hx}" cy="${Hy}" r="6" fill="none" stroke="#ef4444" stroke-width="1.5" stroke-dasharray="2,2"/>`;
}
}
const color=ph==='done'?'#10b981':'#06b6d4';
const svg=`<svg viewBox="0 0 260 190" style="max-width:280px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(6,182,212,.09)" stroke="${color}" stroke-width="2"/>
<line x1="${cx}" y1="${cy}" x2="${Tx}" y2="${Ty}" stroke="#0891b2" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0e7490"/>
<circle cx="${Tx}" cy="${Ty}" r="4" fill="${color}"/>
<line x1="20" y1="${Ty}" x2="240" y2="${Ty}" stroke="${color}" stroke-width="2.2"/>
<polyline points="${Tx},${Ty+9} ${Tx+9},${Ty+9} ${Tx+9},${Ty}" fill="none" stroke="#0e7490" stroke-width="1.8"/>
<text x="${cx+4}" y="${cy+5}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="${Tx+4}" y="${Ty-6}" font-size="11" font-weight="700" fill="#0e7490">T</text>
<text x="22" y="${Ty-5}" font-size="10" fill="#065f46" font-style="italic">&#8467;</text>
${extras}
</svg>`;
svgEl.innerHTML=svg;
txtEl.innerHTML=steps.find(s=>s.phase===ph).text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
}
const phases=steps.map(s=>s.phase);
function go(){
drawProof(phases[step]);
nextBtn.textContent=step>=phases.length-1?'Готово':'Далее';
if(step<phases.length-1) step++;
}
nextBtn.addEventListener('click',go);
resetBtn.addEventListener('click',()=>{step=0;go();});
go();
})();
/* === INIT ИНТЕРАКТИВ 3: калькулятор === */
(function(){
const btn=document.getElementById('p2-calc-btn');
const out=document.getElementById('p2-calc-out');
btn.addEventListener('click',()=>{
const R=parseFloat(document.getElementById('p2-cr').value);
const OA=parseFloat(document.getElementById('p2-coa').value);
out.style.display='block';
if(isNaN(R)||isNaN(OA)||R<=0||OA<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите корректные значения';return;}
if(OA<R){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='|OA| должно быть больше R (точка A должна быть вне окружности)';return;}
if(Math.abs(OA-R)<1e-9){out.style.background='#fef3c7';out.style.color='#92400e';out.textContent='|OA| = R: точка A на окружности, длина касательной = 0';return;}
const AT=Math.sqrt(OA*OA-R*R);
out.style.background='#d1fae5';out.style.color='#065f46';
out.innerHTML='AT = √('+fmt(OA)+ '+fmt(R)+'²) = √'+fmt(OA*OA-R*R)+' = <b>'+fmt(AT)+'</b>';
});
})();
/* === INIT ИНТЕРАКТИВ 4: Тренажёр === */
(function(){
const tasks=[
{q:'Радиус $R = 5$, $|OA| = 13$. Найди длину касательной $AT$.',a:'12',hint:'AT = √(169 25) = √144 = 12'},
{q:'Радиус $R = 8$, $|OA| = 10$. Найди $AT$.',a:'6',hint:'AT = √(100 64) = √36 = 6'},
{q:'Касательная $AT = 24$, $|OA| = 26$. Найди радиус $R$.',a:'10',hint:'R = √(26² 24²) = √(676576) = √100 = 10'},
{q:'Касательная $AT = 15$, радиус $R = 9$. Найди $|OA|$.',a:'√306',hint:'OA = √(225 + 81) = √306 ≈ 17,49. Введи 306 (под корнем)'},
{q:'Угол между радиусом $OT$ и прямой $OA$ равен 60°, $|OA| = 10$. Найди радиус $R = |OT|$.',a:'5',hint:'OT = OA·cos60° = 10·0,5 = 5 (касательная AT ⊥ OT)'},
];
let cur=0,score=0;
const iEl=document.getElementById('p2-tr-i');
const scEl=document.getElementById('p2-tr-score');
const taskEl=document.getElementById('p2-tr-task');
const ansEl=document.getElementById('p2-tr-ans');
const goBtn=document.getElementById('p2-tr-go');
const startBtn=document.getElementById('p2-tr-start');
const fb=document.getElementById('p2-tr-fb');
const numAnswers={'√306':Math.sqrt(306)};
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p2-trainer');bumpProgress('p2',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const raw=ansEl.value.trim().replace(',','.');
const expected=tasks[cur].a;
const expNum=numAnswers[expected]!==undefined?numAnswers[expected]:parseFloat(expected);
const ansNum=parseFloat(raw);
const ok=Math.abs(ansNum-expNum)<0.5;
feedback(fb,ok,ok?'Верно!':'Неверно. '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT ИНТЕРАКТИВ 5: DnD верные/неверные === */
(function(){
const items=[
{label:'Касательная ⊥ радиусу в точке касания',cat:'true'},
{label:'Касательная параллельна радиусу',cat:'false'},
{label:'Расстояние от центра до касательной = R',cat:'true'},
{label:'Из внешней точки можно провести только одну касательную',cat:'false'},
{label:'AT = √(|OA|² R²)',cat:'true'},
{label:'AT > |OA|',cat:'false'},
];
const pool=document.getElementById('p2-dnd-pool');
const boxes={true:document.getElementById('p2-drop-true-items'),false:document.getElementById('p2-drop-false-items')};
const fb=document.getElementById('p2-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p2-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p2-dnd');bumpProgress('p2',15);}
});
document.getElementById('p2-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT ИНТЕРАКТИВ 6: Босс §2 === */
(function(){
const tasks=[
{q:'Касательная $AT = 24$, радиус $R = 7$. Найти $|OA|$.',
opts:['25','√(576+49)=√625=25','√(24²−7²)=√527'],cor:1,
exp:'$|OA| = \\sqrt{AT^2 + R^2} = \\sqrt{576 + 49} = \\sqrt{625} = 25$.'},
{q:'Угол $\\angle TOA = 30°$, $|OA| = 20$. Найти длину касательной $AT$.',
opts:['10','10√3','20√3'],cor:1,
exp:'В прямоугольном треугольнике $OAT$: $AT = OA \\cdot \\sin 30° \\cdot ...$. Нет: $\\angle OTA = 90°$, поэтому $AT = OA \\cdot \\sin(\\angle AOT) \\cdot ...$. Точнее: $\\cos(\\angle TAO) = AT/OA$, $\\angle OAT + \\angle AOT = 90°$, $\\angle OAT = 60°$, $AT = OA \\cdot \\sin 60° = 20 \\cdot \\dfrac{\\sqrt{3}}{2} = 10\\sqrt{3}$.'},
{q:'Точка $A$ находится вне окружности. Из $A$ проведены касательные $AT_1$ и $AT_2$. Угол $\\angle T_1OT_2 = 120°$. Найти $\\angle T_1AT_2$.',
opts:['30°','60°','120°'],cor:1,
exp:'Четырёхугольник $AT_1OT_2$ имеет $\\angle T_1 = \\angle T_2 = 90°$, сумма углов $360°$. Значит $\\angle A + \\angle O = 180°$: $\\angle A = 60°$.'},
{q:'Радиус $R = 10$, касательная $AT = 10\\sqrt{3}$. Найти $|OA|$.',
opts:['10','20','10√2'],cor:1,
exp:'$|OA| = \\sqrt{R^2 + AT^2} = \\sqrt{100 + 300} = \\sqrt{400} = 20$.'},
];
const cont=document.getElementById('p2-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss2="p2-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss2=\\'p2-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p2-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p2-boss-${i}');bumpProgress('p2',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p2-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP3(){
const box=document.getElementById('p3-body');
let html='';
html+=makeCard('theory','Свойство касательных из одной точки','3.1',`
<p><b>Теорема.</b> Если из внешней точки $A$ к окружности проведены две касательные с точками касания $T_1$ и $T_2$, то:</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li><b>Равенство отрезков:</b> $|AT_1| = |AT_2|$</li>
<li><b>Биссектриса:</b> прямая $OA$ является биссектрисой угла $T_1AT_2$ (и угла $T_1OT_2$).</li>
</ul>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 180" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="100" cy="90" r="55" fill="rgba(2,132,199,.08)" stroke="#0284c7" stroke-width="2"/>
<circle cx="100" cy="90" r="3.5" fill="#0369a1"/>
<line x1="100" y1="90" x2="100" y2="35" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<line x1="100" y1="90" x2="136" y2="132" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<circle cx="100" cy="35" r="4" fill="#0284c7"/>
<circle cx="136" cy="132" r="4" fill="#0284c7"/>
<line x1="100" y1="35" x2="220" y2="82" stroke="#10b981" stroke-width="2.2"/>
<line x1="136" y1="132" x2="220" y2="82" stroke="#10b981" stroke-width="2.2"/>
<line x1="100" y1="90" x2="220" y2="82" stroke="#64748b" stroke-width="1.5" stroke-dasharray="5,3"/>
<circle cx="220" cy="82" r="4" fill="#0369a1"/>
<text x="95" y="107" font-size="11" font-weight="700" fill="#0369a1">O</text>
<text x="97" y="30" font-size="11" font-weight="700" fill="#0369a1">T₁</text>
<text x="140" y="148" font-size="11" font-weight="700" fill="#0369a1">T₂</text>
<text x="224" y="86" font-size="11" font-weight="700" fill="#0369a1">A</text>
<text x="162" y="50" font-size="10" fill="#065f46" font-weight="700">AT₁</text>
<text x="188" y="128" font-size="10" fill="#065f46" font-weight="700">AT₂</text>
<text x="100" y="170" text-anchor="middle" font-size="10" fill="#0369a1" font-weight="700">AT₁ = AT₂</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство через равные треугольники','3.2',`
<p>Рассмотрим треугольники $\\triangle OAT_1$ и $\\triangle OAT_2$:</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li>$OT_1 = OT_2 = R$ (оба радиусы)</li>
<li>$OA = OA$ (общая гипотенуза)</li>
<li>$\\angle OT_1A = \\angle OT_2A = 90°$ (свойство касательной)</li>
</ul>
<p style="margin-top:8px">По признаку равенства прямоугольных треугольников (по гипотенузе и катету): $\\triangle OAT_1 = \\triangle OAT_2$.</p>
<p style="margin-top:6px">Следовательно, $AT_1 = AT_2$ и $\\angle T_1AO = \\angle T_2AO$. <b>ч.т.д.</b></p>`);
html+=makeCard('example','Пример','3.3',`
<p><b>Задача.</b> Из точки $A$ проведены касательные к окружности радиуса $R = 8$. Расстояние от $A$ до центра $|OA| = 17$. Найти длины касательных.</p>
<p style="margin-top:8px"><b>Решение:</b> $AT_1 = AT_2 = \\sqrt{|OA|^2 - R^2} = \\sqrt{289 - 64} = \\sqrt{225} = 15$.</p>
<p style="margin-top:8px"><b>Ответ:</b> $AT_1 = AT_2 = 15$.</p>`);
/* ИНТЕРАКТИВ 1 — SVG с двумя касательными из внешней точки A */
html+=`<div class="wg" id="p3-two-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Две касательные из внешней точки</div></div>
<div class="wg-help">Двигай слайдер — меняй положение точки $A$. Отрезки $AT_1$ и $AT_2$ всегда равны!</div>
<div class="sliders">
<label>Расстояние $|OA|$: <b id="p3-oa-val">130</b> (R = 65)
<input type="range" min="70" max="200" value="130" id="p3-oa-sl">
</label>
</div>
<div id="p3-two-svg" style="display:flex;justify-content:center"></div>
<div id="p3-two-info" style="margin-top:8px;padding:8px 14px;background:#d1fae5;border-radius:10px;color:#065f46;font-weight:700;font-size:.93rem;text-align:center"></div>
</div>`;
/* ИНТЕРАКТИВ 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">Нажимай «Далее» чтобы пройти доказательство через равенство прямоугольных треугольников.</div>
<div id="p3-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p3-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.94rem;line-height:1.65;margin-bottom:10px;min-height:64px"></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>`;
/* ИНТЕРАКТИВ 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">Дано $R$ и $|OA|$ — найди $|AT| = \\sqrt{|OA|^2 - R^2}$.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R = <input type="number" id="p3-cr" class="tinp" value="8" min="0.1" style="width:80px"></label>
<label style="font-size:.9rem">|OA| = <input type="number" id="p3-coa" class="tinp" value="17" min="0.1" style="width:80px"></label>
<button class="btn primary" id="p3-calc-btn">Вычислить |AT|</button>
</div>
<div id="p3-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §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:1rem;margin-bottom:10px;line-height:1.6"></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:130px">
<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>`;
/* ИНТЕРАКТИВ 5 — DnD верные/неверные утверждения о двух касательных */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Верно или неверно о двух касательных?</div></div>
<div class="wg-help">Перетащи утверждение в нужную колонку.</div>
<div id="p3-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
<div class="drop-box" id="p3-drop-true"><h5>Верно</h5><div class="drop-items" id="p3-drop-true-items"></div></div>
<div class="drop-box" id="p3-drop-false"><h5>Неверно</h5><div class="drop-items" id="p3-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p3-dnd-check">Проверить</button><button class="btn" id="p3-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p3-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §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 ИНТЕРАКТИВ 1: две касательные из A === */
(function(){
const sl=document.getElementById('p3-oa-sl');
const oaVal=document.getElementById('p3-oa-val');
const svgWrap=document.getElementById('p3-two-svg');
const info=document.getElementById('p3-two-info');
const R=65, cx=100, cy=130, W=280, H=240;
function draw(){
const OA=+sl.value;
oaVal.textContent=OA;
const Ax=cx+OA, Ay=cy;
const AT=Math.sqrt(OA*OA-R*R);
const sinA=R/OA, cosA=AT/OA;
const T1x=cx+R*cosA, T1y=cy-R*sinA;
const T2x=cx+R*cosA, T2y=cy+R*sinA;
// right angle markers
const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R;
const ut1x=-(ur1y), ut1y=ur1x;
const s=8;
const rm1=`${(T1x+ur1x*s).toFixed(1)},${(T1y+ur1y*s).toFixed(1)} ${(T1x+ur1x*s+ut1x*s).toFixed(1)},${(T1y+ur1y*s+ut1y*s).toFixed(1)} ${(T1x+ut1x*s).toFixed(1)},${(T1y+ut1y*s).toFixed(1)}`;
const ur2x=(T2x-cx)/R, ur2y=(T2y-cy)/R;
const ut2x=-(ur2y), ut2y=ur2x;
const rm2=`${(T2x+ur2x*s).toFixed(1)},${(T2y+ur2y*s).toFixed(1)} ${(T2x+ur2x*s+ut2x*s).toFixed(1)},${(T2y+ur2y*s+ut2y*s).toFixed(1)} ${(T2x+ut2x*s).toFixed(1)},${(T2y+ut2y*s).toFixed(1)}`;
/* Position T₁ label OUTSIDE circle, above-left of T₁ (away from upper tangent) */
const T1lx=(T1x-cx)/R, T1ly=(T1y-cy)/R; /* outward unit */
const T1labelX=T1x+T1lx*14-6, T1labelY=T1y+T1ly*14+3;
const T2labelX=T2x+(T2x-cx)/R*14-6, T2labelY=T2y+(T2y-cy)/R*14+10;
/* Length labels OFF the tangent line (perpendicular offset to outer side) */
const m1x=(T1x+Ax)/2, m1y=(T1y+Ay)/2;
const t1dx=Ax-T1x, t1dy=Ay-T1y, t1len=Math.hypot(t1dx,t1dy);
/* Perpendicular outward (upper) */
const n1x=-t1dy/t1len, n1y=t1dx/t1len; /* CCW perpendicular */
const len1lx=m1x+n1x*-14-10, len1ly=m1y+n1y*-14;
const m2x=(T2x+Ax)/2, m2y=(T2y+Ay)/2;
const t2dx=Ax-T2x, t2dy=Ay-T2y, t2len=Math.hypot(t2dx,t2dy);
const n2x=-t2dy/t2len, n2y=t2dx/t2len;
const len2lx=m2x+n2x*14-10, len2ly=m2y+n2y*14+6;
const svg=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(2,132,199,.09)" stroke="#0284c7" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0369a1"/>
<line x1="${cx}" y1="${cy}" x2="${T1x.toFixed(1)}" y2="${T1y.toFixed(1)}" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<line x1="${cx}" y1="${cy}" x2="${T2x.toFixed(1)}" y2="${T2y.toFixed(1)}" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<line x1="${T1x.toFixed(1)}" y1="${T1y.toFixed(1)}" x2="${Ax}" y2="${Ay}" stroke="#10b981" stroke-width="2.5"/>
<line x1="${T2x.toFixed(1)}" y1="${T2y.toFixed(1)}" x2="${Ax}" y2="${Ay}" stroke="#10b981" stroke-width="2.5"/>
<line x1="${cx}" y1="${cy}" x2="${Ax}" y2="${Ay}" stroke="#64748b" stroke-width="1.5" stroke-dasharray="5,3"/>
<circle cx="${T1x.toFixed(1)}" cy="${T1y.toFixed(1)}" r="4.5" fill="#0284c7"/>
<circle cx="${T2x.toFixed(1)}" cy="${T2y.toFixed(1)}" r="4.5" fill="#0284c7"/>
<circle cx="${Ax}" cy="${Ay}" r="5" fill="#0369a1"/>
<polyline points="${rm1}" fill="none" stroke="#0369a1" stroke-width="1.8"/>
<polyline points="${rm2}" fill="none" stroke="#0369a1" stroke-width="1.8"/>
<text x="${T1labelX.toFixed(1)}" y="${T1labelY.toFixed(1)}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">T₁</text>
<text x="${T2labelX.toFixed(1)}" y="${T2labelY.toFixed(1)}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">T₂</text>
<text x="${cx-16}" y="${cy+5}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">O</text>
<text x="${Ax+8}" y="${Ay+5}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">A</text>
<text x="${len1lx.toFixed(1)}" y="${len1ly.toFixed(1)}" font-size="11" fill="#065f46" font-weight="800" font-family="JetBrains Mono,monospace">AT₁=${fmt(AT)}</text>
<text x="${len2lx.toFixed(1)}" y="${len2ly.toFixed(1)}" font-size="11" fill="#065f46" font-weight="800" font-family="JetBrains Mono,monospace">AT₂=${fmt(AT)}</text>
</svg>`;
svgWrap.innerHTML=svg;
info.textContent='AT₁ = AT₂ = '+fmt(AT)+' (при R = '+R+', |OA| = '+OA+')';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT ИНТЕРАКТИВ 2: пошаговое доказательство === */
(function(){
const steps=[
{text:'<b>Дано:</b> окружность с центром $O$, радиусом $R$; из внешней точки $A$ проведены касательные $AT_1$ и $AT_2$ с точками касания $T_1$ и $T_2$. Доказать: $AT_1 = AT_2$.',
phase:'given'},
{text:'<b>Шаг 1.</b> По свойству касательной: $OT_1 \\perp AT_1$ и $OT_2 \\perp AT_2$, то есть $\\angle OT_1A = \\angle OT_2A = 90°$. Треугольники $\\triangle OAT_1$ и $\\triangle OAT_2$ — прямоугольные.',
phase:'right'},
{text:'<b>Шаг 2.</b> Выпишем элементы для признака равенства: $OA = OA$ (общая гипотенуза), $OT_1 = OT_2 = R$ (катеты — радиусы одной окружности).',
phase:'elements'},
{text:'<b>Шаг 3.</b> По признаку равенства прямоугольных треугольников (по гипотенузе и катету): $\\triangle OAT_1 = \\triangle OAT_2$.',
phase:'equal'},
{text:'<b>Вывод.</b> Из равенства треугольников: $AT_1 = AT_2$ (соответственные катеты) и $\\angle T_1AO = \\angle T_2AO$ (прямая $OA$ — биссектриса). <b>ч.т.д.</b>',
phase:'done'},
];
let step=0;
const svgEl=document.getElementById('p3-proof-svg');
const txtEl=document.getElementById('p3-proof-text');
const nextBtn=document.getElementById('p3-proof-next');
const resetBtn=document.getElementById('p3-proof-reset');
const R=55, cx=100, cy=105;
const OA=130;
const AT=Math.sqrt(OA*OA-R*R);
const sinA=R/OA, cosA=AT/OA;
const T1x=cx+R*cosA, T1y=cy-R*sinA;
const T2x=cx+R*cosA, T2y=cy+R*sinA;
const Ax=cx+OA, Ay=cy;
function drawProof(ph){
let tri1='',tri2='',equal='';
if(ph==='right'||ph==='elements'||ph==='equal'||ph==='done'){
tri1=`<polygon points="${cx},${cy} ${T1x.toFixed(1)},${T1y.toFixed(1)} ${Ax},${Ay}" fill="rgba(6,182,212,.12)" stroke="#06b6d4" stroke-width="1.3"/>`;
tri2=`<polygon points="${cx},${cy} ${T2x.toFixed(1)},${T2y.toFixed(1)} ${Ax},${Ay}" fill="rgba(2,132,199,.10)" stroke="#0284c7" stroke-width="1.3"/>`;
const s=7;
const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R;
const ut1x=-(ur1y), ut1y=ur1x;
const rm1=`${(T1x+ur1x*s).toFixed(1)},${(T1y+ur1y*s).toFixed(1)} ${(T1x+ur1x*s+ut1x*s).toFixed(1)},${(T1y+ur1y*s+ut1y*s).toFixed(1)} ${(T1x+ut1x*s).toFixed(1)},${(T1y+ut1y*s).toFixed(1)}`;
const ur2x=(T2x-cx)/R, ur2y=(T2y-cy)/R;
const ut2x=-(ur2y), ut2y=ur2x;
const rm2=`${(T2x+ur2x*s).toFixed(1)},${(T2y+ur2y*s).toFixed(1)} ${(T2x+ur2x*s+ut2x*s).toFixed(1)},${(T2y+ur2y*s+ut2y*s).toFixed(1)} ${(T2x+ut2x*s).toFixed(1)},${(T2y+ut2y*s).toFixed(1)}`;
equal=`<polyline points="${rm1}" fill="none" stroke="#0369a1" stroke-width="1.8"/><polyline points="${rm2}" fill="none" stroke="#0369a1" stroke-width="1.8"/>`;
}
if(ph==='done'||ph==='equal'){
equal+=`<text x="${(T1x+Ax)/2+2}" y="${(T1y+Ay)/2-3}" font-size="9" fill="#065f46" font-weight="800">✓</text>`;
equal+=`<text x="${(T2x+Ax)/2+2}" y="${(T2y+Ay)/2+8}" font-size="9" fill="#065f46" font-weight="800">✓</text>`;
}
const mainColor=ph==='done'?'#10b981':'#0284c7';
const T1lx=(T1x-cx)/R, T1ly=(T1y-cy)/R;
const T1labelX=T1x+T1lx*16-7, T1labelY=T1y+T1ly*16+4;
const T2lx=(T2x-cx)/R, T2ly=(T2y-cy)/R;
const T2labelX=T2x+T2lx*16-7, T2labelY=T2y+T2ly*16+10;
const svg=`<svg viewBox="0 0 280 220" style="max-width:300px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(2,132,199,.08)" stroke="${mainColor}" stroke-width="2"/>
${tri1}${tri2}
<line x1="${cx}" y1="${cy}" x2="${T1x.toFixed(1)}" y2="${T1y.toFixed(1)}" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<line x1="${cx}" y1="${cy}" x2="${T2x.toFixed(1)}" y2="${T2y.toFixed(1)}" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<line x1="${T1x.toFixed(1)}" y1="${T1y.toFixed(1)}" x2="${Ax}" y2="${Ay}" stroke="#10b981" stroke-width="2.2"/>
<line x1="${T2x.toFixed(1)}" y1="${T2y.toFixed(1)}" x2="${Ax}" y2="${Ay}" stroke="#10b981" stroke-width="2.2"/>
<line x1="${cx}" y1="${cy}" x2="${Ax}" y2="${Ay}" stroke="#64748b" stroke-width="1.5" stroke-dasharray="5,3"/>
${equal}
<circle cx="${T1x.toFixed(1)}" cy="${T1y.toFixed(1)}" r="4" fill="#0284c7"/>
<circle cx="${T2x.toFixed(1)}" cy="${T2y.toFixed(1)}" r="4" fill="#0284c7"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0369a1"/>
<circle cx="${Ax}" cy="${Ay}" r="4.5" fill="#0369a1"/>
<text x="${cx-16}" y="${cy+5}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">O</text>
<text x="${T1labelX.toFixed(1)}" y="${T1labelY.toFixed(1)}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">T₁</text>
<text x="${T2labelX.toFixed(1)}" y="${T2labelY.toFixed(1)}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">T₂</text>
<text x="${Ax+8}" y="${Ay+5}" font-size="13" font-weight="800" fill="#0369a1" font-family="Unbounded,sans-serif">A</text>
</svg>`;
svgEl.innerHTML=svg;
txtEl.innerHTML=steps.find(s=>s.phase===ph).text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
}
const phases=steps.map(s=>s.phase);
function go(){
drawProof(phases[step]);
nextBtn.textContent=step>=phases.length-1?'Готово':'Далее';
if(step<phases.length-1) step++;
}
nextBtn.addEventListener('click',go);
resetBtn.addEventListener('click',()=>{step=0;go();});
go();
})();
/* === INIT ИНТЕРАКТИВ 3: калькулятор === */
(function(){
const btn=document.getElementById('p3-calc-btn');
const out=document.getElementById('p3-calc-out');
btn.addEventListener('click',()=>{
const R=parseFloat(document.getElementById('p3-cr').value);
const OA=parseFloat(document.getElementById('p3-coa').value);
out.style.display='block';
if(isNaN(R)||isNaN(OA)||R<=0||OA<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите корректные значения';return;}
if(OA<=R){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='|OA| должно быть больше R';return;}
const AT=Math.sqrt(OA*OA-R*R);
out.style.background='#d1fae5';out.style.color='#065f46';
out.innerHTML='|AT₁| = |AT₂| = √('+fmt(OA)+ '+fmt(R)+'²) = √'+fmt(OA*OA-R*R)+' = <b>'+fmt(AT)+'</b>';
});
})();
/* === INIT ИНТЕРАКТИВ 4: Тренажёр === */
(function(){
const tasks=[
{q:'Из точки $A$ проведены касательные к окружности радиуса $R = 6$, $|OA| = 10$. Найти длину каждой касательной.',a:'8',hint:'AT = √(100 36) = √64 = 8'},
{q:'Касательная $AT_1 = 15$, $R = 9$. Найти $|OA|$.',a:'√306',hint:'OA = √(225 + 81) = √306. Введи приближение: 17'},
{q:'Из точки $A$ проведены две касательные. $AT_1 = 12$, $AT_2 = ?$',a:'12',hint:'Два отрезка касательных из одной точки равны'},
{q:'$|OA| = 25$, $AT = 24$. Найти $R$.',a:'7',hint:'R = √(25² 24²) = √(625576) = √49 = 7'},
{q:'Угол между двумя касательными из точки $A$ равен $60°$. Угол $\\angle T_1OT_2 = ?$ (в градусах)',a:'120',hint:'Сумма углов A и O в четырёхугольнике AT₁OT₂ равна 180°'},
];
let cur=0,score=0;
const iEl=document.getElementById('p3-tr-i');
const scEl=document.getElementById('p3-tr-score');
const taskEl=document.getElementById('p3-tr-task');
const ansEl=document.getElementById('p3-tr-ans');
const goBtn=document.getElementById('p3-tr-go');
const startBtn=document.getElementById('p3-tr-start');
const fb=document.getElementById('p3-tr-fb');
function numOf(s){if(s==='√306')return Math.sqrt(306);return parseFloat(s);}
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p3-trainer');bumpProgress('p3',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const raw=ansEl.value.trim().replace(',','.');
const ok=Math.abs(parseFloat(raw)-numOf(tasks[cur].a))<0.6;
feedback(fb,ok,ok?'Верно!':'Неверно. '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT ИНТЕРАКТИВ 5: DnD === */
(function(){
const items=[
{label:'AT₁ = AT₂ (из одной внешней точки)',cat:'true'},
{label:'AT₁ > AT₂ если T₁ выше T₂',cat:'false'},
{label:'OA — биссектриса угла T₁AT₂',cat:'true'},
{label:'∠OT₁A = 90°',cat:'true'},
{label:'Из одной точки можно провести 3 касательных',cat:'false'},
{label:'△OAT₁ = △OAT₂',cat:'true'},
];
const pool=document.getElementById('p3-dnd-pool');
const boxes={true:document.getElementById('p3-drop-true-items'),false:document.getElementById('p3-drop-false-items')};
const fb=document.getElementById('p3-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p3-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p3-dnd');bumpProgress('p3',15);}
});
document.getElementById('p3-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT ИНТЕРАКТИВ 6: Босс §3 === */
(function(){
const tasks=[
{q:'Из точки $A$ проведены касательные к окружности с центром $O$. $\\angle T_1AT_2 = 60°$, $AT_1 = 6\\sqrt{3}$. Найти $R$.',
opts:['6','3√3','6√3'],cor:0,
exp:'$\\angle T_1AO = 30°$ (биссектриса), $\\tan 30° = R / AT_1$, значит $R = AT_1 \\cdot \\tan 30° = 6\\sqrt{3} \\cdot \\dfrac{1}{\\sqrt{3}} = 6$.'},
{q:'Две касательные из $A$, $|OA| = 10$, $R = 8$. Найти периметр четырёхугольника $OT_1AT_2$.',
opts:['12+16=28','6+12+6+8=32','6·4=24'],cor:0,
exp:'$AT_1 = AT_2 = \\sqrt{100-64} = 6$. $OT_1 = OT_2 = 8$. Периметр $= 6+8+6+8 = 28$.'},
{q:'Из точки $P$ проведены касательные, угол между касательными $90°$. $|OP| = 5\\sqrt{2}$. Найти $R$.',
opts:['5','5√2','10'],cor:0,
exp:'$\\angle T_1PO = 45°$ (половина 90°). $\\sin 45° = R/|OP|$, значит $R = 5\\sqrt{2} \\cdot \\dfrac{\\sqrt{2}}{2} = 5$.'},
{q:'Два отрезка касательных из одной точки равны по теореме, доказанной через:',
opts:['Равенство прямоугольных треугольников (гипотенуза и катет)','Теорему Пифагора','Теорему Фалеса'],cor:0,
exp:'Доказывается через признак равенства прямоугольных треугольников: гипотенуза $OA$ общая, катет $OT_1 = OT_2 = R$.'},
];
const cont=document.getElementById('p3-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss3="p3-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss3=\\'p3-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p3-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p3-boss-${i}');bumpProgress('p3',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p3-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP4(){
const box=document.getElementById('p4-body');
let html='';
html+=makeCard('theory','Задача построения касательной','4.1',`
<p><b>Задача.</b> Дана окружность с центром $O$ радиусом $R$ и точка $A$ вне окружности ($|OA|>R$). Построить касательную из точки $A$ к окружности.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 280 170" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="90" cy="95" r="50" fill="rgba(37,99,235,.08)" stroke="#2563eb" stroke-width="2"/>
<circle cx="90" cy="95" r="3" fill="#1d4ed8"/>
<text x="94" y="92" font-size="11" font-weight="700" fill="#1d4ed8">O</text>
<circle cx="240" cy="95" r="3.5" fill="#1d4ed8"/>
<text x="244" y="92" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
<circle cx="165" cy="95" r="3" fill="#64748b"/>
<text x="168" y="91" font-size="10" fill="#64748b">M</text>
<circle cx="130" cy="57" r="4" fill="#10b981"/>
<circle cx="130" cy="133" r="4" fill="#10b981"/>
<text x="132" y="53" font-size="11" font-weight="700" fill="#10b981">T₁</text>
<text x="132" y="149" font-size="11" font-weight="700" fill="#10b981">T₂</text>
<line x1="240" y1="95" x2="130" y2="57" stroke="#10b981" stroke-width="2"/>
<line x1="240" y1="95" x2="130" y2="133" stroke="#10b981" stroke-width="2"/>
<circle cx="165" cy="95" r="75" fill="none" stroke="#64748b" stroke-width="1.4" stroke-dasharray="5,3"/>
<line x1="90" y1="95" x2="240" y2="95" stroke="#64748b" stroke-width="1.4" stroke-dasharray="4,3"/>
<polyline points="130,57 130,66 139,66" fill="none" stroke="#1d4ed8" stroke-width="1.6"/>
<polyline points="130,133 130,124 139,124" fill="none" stroke="#1d4ed8" stroke-width="1.6"/>
</svg>
</div>`);
html+=makeCard('algo','Алгоритм построения','4.2',`
<ol style="margin-left:18px;line-height:2">
<li>Построить отрезок $OA$.</li>
<li>Найти середину $M$ отрезка $OA$.</li>
<li>Построить окружность с центром $M$ и радиусом $MA = MO = \\dfrac{|OA|}{2}$.</li>
<li>Эта вспомогательная окружность пересечёт данную в точках $T_1$ и $T_2$.</li>
<li>Прямые $AT_1$ и $AT_2$ — искомые касательные.</li>
</ol>
<div style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:9px;font-size:.92rem">
<b>Почему работает?</b> Угол $\\angle OT_1A$ вписан в полуокружность (диаметр $OA$), значит $\\angle OT_1A = 90°$. Следовательно, $OT_1 \\perp AT_1$ — по признаку касательной прямая $AT_1$ касается окружности. <b>ч.т.д.</b>
</div>`);
html+=makeCard('rule','Длина касательной из внешней точки','4.3',`
<p>Из прямоугольного треугольника $OT_1A$:</p>
$$AT_1 = \\sqrt{|OA|^2 - R^2}$$
<p style="margin-top:8px">Условие существования: $|OA| > R$ (точка $A$ вне окружности).</p>
<div style="display:flex;justify-content:center;margin-top:10px">
<svg viewBox="0 0 220 160" style="max-width:240px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="70" cy="100" r="50" fill="rgba(37,99,235,.08)" stroke="#2563eb" stroke-width="2"/>
<circle cx="70" cy="100" r="3" fill="#1d4ed8"/>
<circle cx="200" cy="100" r="3.5" fill="#1d4ed8"/>
<circle cx="107" cy="56" r="4" fill="#10b981"/>
<line x1="70" y1="100" x2="107" y2="56" stroke="#2563eb" stroke-width="2"/>
<line x1="107" y1="56" x2="200" y2="100" stroke="#10b981" stroke-width="2.2"/>
<line x1="70" y1="100" x2="200" y2="100" stroke="#64748b" stroke-width="1.5" stroke-dasharray="4,3"/>
<polyline points="107,56 107,65 116,65" fill="none" stroke="#1d4ed8" stroke-width="1.6"/>
<text x="74" y="115" font-size="11" font-weight="700" fill="#1d4ed8">O</text>
<text x="204" y="104" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
<text x="110" y="53" font-size="11" font-weight="700" fill="#10b981">T</text>
<text x="83" y="83" font-size="10" fill="#2563eb" font-weight="700">R</text>
<text x="145" y="72" font-size="10" fill="#10b981" font-weight="700">AT</text>
<text x="125" y="118" font-size="10" fill="#64748b">|OA|</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — пошаговое SVG-построение */
html+=`<div class="wg" id="p4-build-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Пошаговое построение касательной</div></div>
<div class="wg-help">Нажимай «Следующий шаг» — наблюдай построение через вспомогательную окружность.</div>
<div id="p4-build-svg" style="display:flex;justify-content:center"></div>
<div id="p4-build-txt" style="margin-top:10px;padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:9px;font-size:.94rem;line-height:1.65;min-height:54px"></div>
<div style="display:flex;gap:8px;margin-top:10px">
<button class="btn primary" id="p4-build-next">Следующий шаг</button>
<button class="btn" id="p4-build-reset">Сначала</button>
<span id="p4-build-step" style="padding:6px 10px;font-size:.82rem;color:var(--muted);align-self:center"></span>
</div>
</div>`;
/* ИНТЕРАКТИВ 2 — слайдеры |OA| и R */
html+=`<div class="wg" id="p4-live-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Построение live — меняй параметры</div></div>
<div class="wg-help">Двигай слайдеры — смотри, как меняется вспомогательная окружность и точки касания.</div>
<div class="sliders">
<label>$R$ = <b id="p4-r-val">45</b>
<input type="range" min="20" max="80" value="45" id="p4-r-sl">
</label>
<label>$|OA|$ = <b id="p4-oa-val">130</b>
<input type="range" min="85" max="200" value="130" id="p4-oa-sl">
</label>
</div>
<div id="p4-live-svg" style="display:flex;justify-content:center"></div>
<div id="p4-live-len" style="margin-top:8px;text-align:center;font-weight:700;font-size:.96rem;color:var(--sec-acc-d,var(--pri2))"></div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: длина касательной</div></div>
<div class="wg-help">Введи $R$ и $|OA|$ — вычисли длину касательной $AT = \\sqrt{|OA|^2 - R^2}$.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R = <input type="number" id="p4-cr" class="tinp" value="5" min="0.1" step="any" style="width:90px"></label>
<label style="font-size:.9rem">|OA| = <input type="number" id="p4-coa" class="tinp" value="13" min="0.1" step="any" style="width:90px"></label>
<button class="btn primary" id="p4-calc-btn">Вычислить</button>
</div>
<div id="p4-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §4</div></div>
<div class="wg-help">5 задач по теореме Пифагора и построению. Введи ответ.</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:1rem;margin-bottom:10px;line-height:1.6"></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:130px" step="any">
<button class="btn primary" id="p4-tr-go">Проверить</button>
<button class="btn" id="p4-tr-start">Заново</button>
</div>
<div class="feedback" id="p4-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — DnD-сортер шагов */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Расставь шаги построения по порядку</div></div>
<div class="wg-help">Нажимай на шаги в правильном порядке. Составь алгоритм построения касательной.</div>
<div id="p4-sort-pool" class="dnd-pool col"></div>
<div id="p4-sort-target" class="dnd-pool col" style="min-height:60px;border-color:var(--sec-acc,var(--pri));margin-top:8px"></div>
<div class="actions"><button class="btn primary" id="p4-sort-check">Проверить</button><button class="btn" id="p4-sort-reset">Сбросить</button></div>
<div class="feedback" id="p4-sort-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §4 */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §4</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p4-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p4-read');bumpProgress('p4',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §4 (+10 XP)
</button>
</div>`;
html+=secNav('p3','p5');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: пошаговое построение === */
(function(){
const OX=80,OY=110,AX=230,AY=110,R=55;
const MX=(OX+AX)/2, MY=(OY+AY)/2, MR=(AX-OX)/2;
const sinA=R/Math.sqrt((AX-OX)*(AX-OX)+(AY-OY)*(AY-OY));
const cosA=Math.sqrt(1-sinA*sinA);
const T1X=OX+R*cosA, T1Y=OY-R*sinA;
const T2X=OX+R*cosA, T2Y=OY+R*sinA;
const steps=[
{title:'Шаг 0 / 5',text:'<b>Дано:</b> окружность с центром $O$, радиусом $R$, и точка $A$ вне окружности. Нужно провести касательную из $A$.'},
{title:'Шаг 1 / 5',text:'<b>Шаг 1.</b> Соединяем $O$ и $A$ — строим отрезок $OA$.'},
{title:'Шаг 2 / 5',text:'<b>Шаг 2.</b> Находим середину $M$ отрезка $OA$.'},
{title:'Шаг 3 / 5',text:'<b>Шаг 3.</b> Строим вспомогательную окружность с центром $M$ и радиусом $|MA| = |MO| = |OA|/2$.'},
{title:'Шаг 4 / 5',text:'<b>Шаг 4.</b> Вспомогательная окружность пересекает данную в точках $T_1$ и $T_2$. Углы $\\angle OT_1A = \\angle OT_2A = 90°$ (вписанный угол на диаметре).'},
{title:'Шаг 5 / 5',text:'<b>Готово!</b> Прямые $AT_1$ и $AT_2$ — искомые касательные. $OT_1 \\perp AT_1$ и $OT_2 \\perp AT_2$.'},
];
let step=0;
const svgWrap=document.getElementById('p4-build-svg');
const txtEl=document.getElementById('p4-build-txt');
const stepLbl=document.getElementById('p4-build-step');
function draw(){
const s=steps[step];
stepLbl.textContent=s.title;
let extras='';
if(step>=1) extras+=`<line x1="${OX}" y1="${OY}" x2="${AX}" y2="${AY}" stroke="#64748b" stroke-width="1.5" stroke-dasharray="4,3"/>`;
if(step>=2) extras+=`<circle cx="${MX}" cy="${MY}" r="4" fill="#f59e0b"/><text x="${MX+5}" y="${MY-4}" font-size="11" font-weight="700" fill="#b45309">M</text>`;
if(step>=3) extras+=`<circle cx="${MX}" cy="${MY}" r="${MR}" fill="none" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="6,3"/>`;
if(step>=4){
extras+=`<circle cx="${T1X}" cy="${T1Y}" r="4.5" fill="#10b981"/>`;
extras+=`<circle cx="${T2X}" cy="${T2Y}" r="4.5" fill="#10b981"/>`;
extras+=`<text x="${T1X+5}" y="${T1Y-5}" font-size="11" font-weight="700" fill="#065f46">T₁</text>`;
extras+=`<text x="${T2X+5}" y="${T2Y+14}" font-size="11" font-weight="700" fill="#065f46">T₂</text>`;
const u1x=T1Y-OY, u1y=-(T1X-OX); const u1n=Math.sqrt(u1x*u1x+u1y*u1y);
const pu1x=u1x/u1n*9, pu1y=u1y/u1n*9;
extras+=`<polyline points="${T1X},${T1Y} ${T1X+pu1x},${T1Y+pu1y} ${T1X+pu1x+(OX-T1X)/Math.sqrt((OX-T1X)**2+(OY-T1Y)**2)*9},${T1Y+pu1y+(OY-T1Y)/Math.sqrt((OX-T1X)**2+(OY-T1Y)**2)*9}" fill="none" stroke="#1d4ed8" stroke-width="1.6"/>`;
}
if(step>=5){
extras+=`<line x1="${AX}" y1="${AY}" x2="${T1X}" y2="${T1Y}" stroke="#10b981" stroke-width="2.2"/>`;
extras+=`<line x1="${AX}" y1="${AY}" x2="${T2X}" y2="${T2Y}" stroke="#10b981" stroke-width="2.2"/>`;
}
svgWrap.innerHTML=`<svg viewBox="0 0 310 220" style="max-width:320px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${OX}" cy="${OY}" r="${R}" fill="rgba(37,99,235,.08)" stroke="#2563eb" stroke-width="2"/>
<circle cx="${OX}" cy="${OY}" r="3.5" fill="#1d4ed8"/>
<text x="${OX+5}" y="${OY-5}" font-size="11" font-weight="700" fill="#1d4ed8">O</text>
<circle cx="${AX}" cy="${AY}" r="4" fill="#1d4ed8"/>
<text x="${AX+5}" y="${AY-5}" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
${extras}
</svg>`;
txtEl.innerHTML=s.text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p4-build-next').textContent=step>=steps.length-1?'Готово':'Следующий шаг';
}
document.getElementById('p4-build-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p4-build-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 2: live-слайдеры === */
(function(){
const rSl=document.getElementById('p4-r-sl'), rVal=document.getElementById('p4-r-val');
const oaSl=document.getElementById('p4-oa-sl'), oaVal=document.getElementById('p4-oa-val');
const svgWrap=document.getElementById('p4-live-svg'), lenEl=document.getElementById('p4-live-len');
const W=280,H=200,OX=60,OY=100;
function draw(){
const R=+rSl.value, OA=+oaSl.value;
rVal.textContent=R; oaVal.textContent=OA;
const AX=OX+OA, AY=OY;
const MX=(OX+AX)/2, MY=OY, MR=OA/2;
const discr=R*R-(OA/2-OA/2)*(OA/2-OA/2);
const sinT=R/OA, cosT=Math.sqrt(Math.max(0,1-sinT*sinT));
const T1X=OX+R*cosT, T1Y=OY-R*sinT;
const T2X=OX+R*cosT, T2Y=OY+R*sinT;
const AT=Math.sqrt(Math.max(0,OA*OA-R*R));
lenEl.textContent='Длина касательной AT = √('+OA+'²−'+R+'²) = '+AT.toFixed(2);
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${OX}" cy="${OY}" r="${R}" fill="rgba(37,99,235,.08)" stroke="#2563eb" stroke-width="2"/>
<circle cx="${OX}" cy="${OY}" r="3" fill="#1d4ed8"/>
<text x="${OX+4}" y="${OY-5}" font-size="10" font-weight="700" fill="#1d4ed8">O</text>
<circle cx="${Math.min(AX,W-10)}" cy="${AY}" r="3.5" fill="#1d4ed8"/>
<text x="${Math.min(AX,W-10)+4}" y="${AY-5}" font-size="10" font-weight="700" fill="#1d4ed8">A</text>
<line x1="${OX}" y1="${OY}" x2="${Math.min(AX,W-10)}" y2="${AY}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<circle cx="${MX}" cy="${MY}" r="3" fill="#f59e0b"/>
<circle cx="${MX}" cy="${MY}" r="${MR}" fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5,3"/>
<circle cx="${T1X}" cy="${T1Y}" r="4" fill="#10b981"/>
<circle cx="${T2X}" cy="${T2Y}" r="4" fill="#10b981"/>
<line x1="${Math.min(AX,W-10)}" y1="${AY}" x2="${T1X}" y2="${T1Y}" stroke="#10b981" stroke-width="2"/>
<line x1="${Math.min(AX,W-10)}" y1="${AY}" x2="${T2X}" y2="${T2Y}" stroke="#10b981" stroke-width="2"/>
<text x="${T1X-12}" y="${T1Y-6}" font-size="10" font-weight="700" fill="#065f46">T₁</text>
<text x="${T2X-12}" y="${T2Y+14}" font-size="10" font-weight="700" fill="#065f46">T₂</text>
</svg>`;
}
rSl.addEventListener('input',()=>{if(+rSl.value>=+oaSl.value-5)oaSl.value=+rSl.value+10;draw();});
oaSl.addEventListener('input',()=>{if(+oaSl.value<=+rSl.value+5)rSl.value=+oaSl.value-10;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p4-calc-btn').addEventListener('click',()=>{
const R=parseFloat(document.getElementById('p4-cr').value);
const OA=parseFloat(document.getElementById('p4-coa').value);
const out=document.getElementById('p4-calc-out');
out.style.display='block';
if(isNaN(R)||isNaN(OA)||R<=0||OA<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите положительные числа.';return;}
if(OA<=R){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Точка A внутри окружности или на ней: |OA| должно быть > R. Касательная не существует.';return;}
const AT=Math.sqrt(OA*OA-R*R);
out.style.background='#d1fae5';out.style.color='#065f46';
out.innerHTML='AT = √('+OA+ '+R+'²) = √'+fmt(OA*OA-R*R)+' ≈ <b>'+AT.toFixed(4)+'</b>';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'$R=5$, $|OA|=13$. Найди длину касательной $AT$.',a:'12',hint:'AT=√(16925)=√144=12'},
{q:'$R=8$, $|OA|=17$. Найди $AT$.',a:'15',hint:'AT=√(28964)=√225=15'},
{q:'$AT=24$, $|OA|=25$. Найди $R$.',a:'7',hint:'R=√(625576)=√49=7'},
{q:'$R=6$, $AT=8$. Найди $|OA|$.',a:'10',hint:'|OA|=√(36+64)=√100=10'},
{q:'$|OA|=2R$. Выразить $AT$ через $R$. Числовой коэффициент (если $R=1$, $AT=?$).',a:'1.7321',hint:'AT=√(4R²−R²)=R√3≈1.732'},
];
let cur=0,score=0;
const iEl=document.getElementById('p4-tr-i'),scEl=document.getElementById('p4-tr-score');
const taskEl=document.getElementById('p4-tr-task'),ansEl=document.getElementById('p4-tr-ans');
const goBtn=document.getElementById('p4-tr-go'),startBtn=document.getElementById('p4-tr-start');
const fb=document.getElementById('p4-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p4-trainer');bumpProgress('p4',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=ansEl.value.trim().replace(',','.');
const ok=Math.abs(parseFloat(ans)-parseFloat(tasks[cur].a))<0.01;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 5: сортер шагов === */
(function(){
const correct=[
'Построить отрезок OA',
'Найти середину M отрезка OA',
'Построить окружность с центром M и радиусом MA',
'Отметить точки T₁, T₂ — пересечение окружностей',
'Провести прямые AT₁ и AT₂',
];
const shuffled=['Найти середину M отрезка OA','Провести прямые AT₁ и AT₂','Построить отрезок OA','Отметить точки T₁, T₂ — пересечение окружностей','Построить окружность с центром M и радиусом MA'];
const pool=document.getElementById('p4-sort-pool');
const target=document.getElementById('p4-sort-target');
const fb=document.getElementById('p4-sort-fb');
function reset(){
pool.innerHTML='';target.innerHTML='';fb.style.display='none';
shuffled.forEach((txt,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=txt;
chip.addEventListener('click',()=>{
if(chip.parentElement===pool){target.appendChild(chip);}
else{pool.appendChild(chip);}
});
pool.appendChild(chip);
});
}
document.getElementById('p4-sort-check').addEventListener('click',()=>{
const placed=[...target.children].map(c=>c.textContent);
const ok=placed.length===correct.length&&placed.every((v,i)=>v===correct[i]);
feedback(fb,ok,ok?'Порядок верный!':'Неверный порядок. Верный: '+correct.map((s,i)=>(i+1)+'. '+s).join('; '));
if(ok){addXp(8,'p4-sort');bumpProgress('p4',15);}
});
document.getElementById('p4-sort-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §4 === */
(function(){
const tasks=[
{q:'Дано $R=15$, $|OA|=17$. Найти длину касательной.',opts:['8','√(289225)=8','√(289+225)=√514'],cor:0,exp:'$AT=\\sqrt{17^2-15^2}=\\sqrt{289-225}=\\sqrt{64}=8$.'},
{q:'Точка $A$ находится на расстоянии $|OA|=2R$ от центра. Угол $\\angle T_1AT_2$ равен:',opts:['60°','90°','120°'],cor:2,exp:'$\\sin(\\angle T_1AO)=R/(2R)=1/2$, значит $\\angle T_1AO=30°$, $\\angle T_1AT_2=60°$. Нет, пересчитаем: $\\angle OAT_1=30°$, $\\angle T_1AT_2=60°$.'},
{q:'При построении касательной из $A$ вспомогательная окружность имеет диаметр:',opts:['R','|OA|','2|OA|'],cor:1,exp:'Вспомогательная окружность строится на $OA$ как на диаметре, её диаметр $= |OA|$, радиус $= |OA|/2$.'},
{q:'$\\angle OT_1A=90°$ потому что:',opts:['Вписанный угол на диаметре $OA$','Свойство касательной','Теорема Пифагора'],cor:0,exp:'$T_1$ лежит на вспомогательной окружности с диаметром $OA$, поэтому $\\angle OT_1A=90°$ по теореме Фалеса (вписанный угол на диаметре).'},
];
const cont=document.getElementById('p4-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss4a="p4-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss4a=\\'p4-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p4-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p4-boss-${i}');bumpProgress('p4',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p4-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP5(){
const box=document.getElementById('p5-body');
let html='';
html+=makeCard('theory','Окружность, вписанная в угол','5.1',`
<p><b>Определение.</b> Окружность называется <b>вписанной в угол</b>, если она касается обеих сторон этого угла.</p>
<p style="margin-top:8px"><b>Теорема.</b> Центр окружности, вписанной в угол, лежит на биссектрисе этого угла.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 260 200" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<line x1="20" y1="180" x2="240" y2="60" stroke="#0891b2" stroke-width="2"/>
<line x1="20" y1="180" x2="240" y2="180" stroke="#0891b2" stroke-width="2"/>
<line x1="20" y1="180" x2="200" y2="120" stroke="#64748b" stroke-width="1.4" stroke-dasharray="5,3"/>
<circle cx="135" cy="145" r="35" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="135" cy="145" r="3" fill="#0e7490"/>
<text x="139" y="142" font-size="11" font-weight="700" fill="#0e7490">O</text>
<circle cx="20" cy="180" r="3" fill="#0e7490"/>
<text x="8" y="178" font-size="11" font-weight="700" fill="#0e7490">B</text>
<line x1="135" y1="145" x2="135" y2="180" stroke="#64748b" stroke-width="1.4" stroke-dasharray="3,2"/>
<polyline points="135,180 135,171 126,171" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<text x="115" y="195" font-size="9" fill="#0e7490">T₁</text>
<text x="96" y="108" font-size="9" fill="#0e7490">T₂</text>
<circle cx="135" cy="180" r="3.5" fill="#10b981"/>
<circle cx="102" cy="113" r="3.5" fill="#10b981"/>
<text x="205" y="118" font-size="9" fill="#64748b" font-style="italic">биссектриса</text>
</svg>
</div>`);
html+=makeCard('rule','Доказательство теоремы','5.2',`
<p>Пусть окружность с центром $O$ и радиусом $r$ вписана в $\\angle BOC$. Стороны угла — прямые $m$ и $n$, точки касания — $T_1$ и $T_2$.</p>
<ol style="margin-left:18px;line-height:2;margin-top:6px">
<li>$OT_1 \\perp m$ и $OT_2 \\perp n$ (свойство касательной).</li>
<li>$|OT_1| = |OT_2| = r$ (радиусы одной окружности).</li>
<li>$\\triangle OT_1B \\cong \\triangle OT_2B$ (гипотенуза $OB$ общая, катеты $OT_1=OT_2$).</li>
<li>Значит $\\angle T_1BO = \\angle T_2BO$ — точка $O$ равноудалена от сторон угла.</li>
<li>По определению биссектрисы — $O$ лежит на биссектрисе $\\angle BOC$. <b>ч.т.д.</b></li>
</ol>`);
html+=makeCard('rule','Следствие: две окружности в одном угле','5.3',`
<p>Если две окружности вписаны в один угол, то отрезки касательных от вершины до точек касания равны для каждой окружности:</p>
$$|BT_1| = |BT_2|, \\quad |BT_3| = |BT_4|$$
<p style="margin-top:8px">Формула радиуса: $r = d\\cdot\\sin\\dfrac{\\alpha}{2}$, где $d = |BO|$ — расстояние от вершины до центра, $\\alpha$ — угол.</p>
<div style="display:flex;justify-content:center;margin-top:10px">
<svg viewBox="0 0 270 190" style="max-width:285px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<line x1="10" y1="175" x2="260" y2="70" stroke="#0891b2" stroke-width="2"/>
<line x1="10" y1="175" x2="260" y2="175" stroke="#0891b2" stroke-width="2"/>
<line x1="10" y1="175" x2="220" y2="122" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<circle cx="95" cy="150" r="25" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="95" cy="150" r="2.5" fill="#0e7490"/>
<circle cx="185" cy="138" r="38" fill="rgba(8,145,178,.05)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="185" cy="138" r="2.5" fill="#0e7490"/>
<circle cx="10" cy="175" r="3" fill="#0e7490"/>
<text x="2" y="172" font-size="10" font-weight="700" fill="#0e7490">B</text>
<text x="98" y="148" font-size="9" fill="#0e7490">O₁</text>
<text x="188" y="136" font-size="9" fill="#0e7490">O₂</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — SVG: угол с вписанной окружностью, slider центра */
html+=`<div class="wg" id="p5-ang-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Вписанная окружность — слайдер положения центра</div></div>
<div class="wg-help">Двигай слайдер — центр $O$ скользит по биссектрисе угла. Окружность всегда касается обеих сторон!</div>
<div class="sliders">
<label>Расстояние от $B$ до $O$: <b id="p5-d-val">90</b>
<input type="range" min="40" max="160" value="90" id="p5-d-sl">
</label>
<label>Угол $2\\alpha$: <b id="p5-a-val">60</b>°
<input type="range" min="20" max="120" value="60" id="p5-a-sl">
</label>
</div>
<div id="p5-ang-svg" style="display:flex;justify-content:center"></div>
<div id="p5-ang-info" style="margin-top:8px;text-align:center;font-weight:700;color:var(--sec-acc-d,var(--pri2));font-size:.94rem"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p5-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство по шагам</div></div>
<div class="wg-help">Нажимай «Далее» — каждый шаг раскрывает ключевую идею.</div>
<div id="p5-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p5-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:9px;font-size:.94rem;line-height:1.65;min-height:60px"></div>
<div style="display:flex;gap:8px;margin-top:10px">
<button class="btn primary" id="p5-proof-next">Далее</button>
<button class="btn" id="p5-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор r = d·sin(α/2) */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: радиус вписанной окружности</div></div>
<div class="wg-help">Формула: $r = d \\cdot \\sin(\\alpha/2)$, где $d$ — расстояние от вершины до центра, $\\alpha$ — полуугол (половина угла раствора).</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">d = <input type="number" id="p5-cd" class="tinp" value="10" min="0.1" step="any" style="width:90px"></label>
<label style="font-size:.9rem">Угол $2\\alpha$ = <input type="number" id="p5-calpha" class="tinp" value="60" min="1" max="179" step="any" style="width:90px">°</label>
<button class="btn primary" id="p5-calc-btn">Вычислить r</button>
</div>
<div id="p5-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §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:1rem;margin-bottom:10px;line-height:1.6"></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:130px" step="any">
<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>`;
/* ИНТЕРАКТИВ 5 — DnD верно/неверно */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Верно или неверно?</div></div>
<div class="wg-help">Нажимай на утверждение, затем на корзину.</div>
<div id="p5-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:10px">
<div class="drop-box" id="p5-drop-true"><h5>Верно</h5><div class="drop-items" id="p5-drop-true-items"></div></div>
<div class="drop-box" id="p5-drop-false"><h5>Неверно</h5><div class="drop-items" id="p5-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p5-dnd-check">Проверить</button><button class="btn" id="p5-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p5-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §5 */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §5</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи — каждая верная даёт +5 XP.</div>
<div id="p5-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p5-read');bumpProgress('p5',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §5 (+10 XP)
</button>
</div>`;
html+=secNav('p4','p6');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: slider угол + позиция === */
(function(){
const dSl=document.getElementById('p5-d-sl'),dVal=document.getElementById('p5-d-val');
const aSl=document.getElementById('p5-a-sl'),aVal=document.getElementById('p5-a-val');
const svgWrap=document.getElementById('p5-ang-svg'),infoEl=document.getElementById('p5-ang-info');
const BX=30,BY=175,W=280,H=210;
function draw(){
const d=+dSl.value, ang2=+aSl.value;
dVal.textContent=d; aVal.textContent=ang2;
const halfRad=ang2/2*Math.PI/180;
const r=d*Math.sin(halfRad);
const OX=BX+d*Math.cos(halfRad), OY=BY-d*Math.sin(halfRad);
const side1DX=Math.cos(0), side1DY=0;
const side2DX=Math.cos(ang2*Math.PI/180), side2DY=-Math.sin(ang2*Math.PI/180);
const arm=220;
const T1X=OX, T1Y=BY;
const perp2x=-side2DY, perp2y=side2DX;
const proj=((OX-BX)*side2DX+(OY-BY)*side2DY);
const T2X=BX+proj*side2DX, T2Y=BY+proj*side2DY;
infoEl.textContent='r = d·sin(α/2) = '+d+'·sin('+ang2/2+'°) = '+r.toFixed(2);
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<line x1="${BX}" y1="${BY}" x2="${BX+arm}" y2="${BY}" stroke="#0891b2" stroke-width="2"/>
<line x1="${BX}" y1="${BY}" x2="${BX+arm*Math.cos(ang2*Math.PI/180)}" y2="${BY-arm*Math.sin(ang2*Math.PI/180)}" stroke="#0891b2" stroke-width="2"/>
<line x1="${BX}" y1="${BY}" x2="${OX+50*(OX-BX)/d}" y2="${OY+50*(OY-BY)/d}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<circle cx="${OX}" cy="${OY}" r="${r}" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="${OX}" cy="${OY}" r="3" fill="#0e7490"/>
<circle cx="${T1X}" cy="${T1Y}" r="3.5" fill="#10b981"/>
<circle cx="${T2X}" cy="${T2Y}" r="3.5" fill="#10b981"/>
<line x1="${OX}" y1="${OY}" x2="${T1X}" y2="${T1Y}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="${OX}" y1="${OY}" x2="${T2X}" y2="${T2Y}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<polyline points="${T1X},${T1Y} ${T1X+9},${T1Y} ${T1X+9},${T1Y-9}" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<text x="${BX-8}" y="${BY+2}" font-size="11" font-weight="700" fill="#0e7490">B</text>
<text x="${OX+4}" y="${OY-5}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="${T2X-14}" y="${T2Y-5}" font-size="9" fill="#065f46">T₂</text>
<text x="${T1X+4}" y="${T1Y+13}" font-size="9" fill="#065f46">T₁</text>
</svg>`;
}
dSl.addEventListener('input',draw);
aSl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const steps=[
{text:'<b>Дано:</b> окружность с центром $O$, вписанная в $\\angle BOC$. Точки касания $T_1$ (на стороне $BC$) и $T_2$ (на стороне $BO$). Нужно доказать, что $O$ лежит на биссектрисе.'},
{text:'<b>Шаг 1.</b> $OT_1 \\perp BC$ и $OT_2 \\perp BO$ — по свойству касательной (радиус перпендикулярен касательной).'},
{text:'<b>Шаг 2.</b> $|OT_1| = |OT_2| = r$ — оба радиуса одной и той же окружности.'},
{text:'<b>Шаг 3.</b> Рассмотрим $\\triangle OT_1B$ и $\\triangle OT_2B$: гипотенуза $OB$ общая, катеты $OT_1 = OT_2$. По признаку (гипотенуза-катет) $\\triangle OT_1B \\cong \\triangle OT_2B$.'},
{text:'<b>Шаг 4.</b> Из равенства треугольников: $\\angle T_1BO = \\angle T_2BO$. Значит $BO$ является биссектрисой угла. Точка $O$ лежит на биссектрисе. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p5-proof-svg'),txtEl=document.getElementById('p5-proof-text');
const BX=25,BY=165,ang2=60,d=100,W=260,H=195;
const halfRad=ang2/2*Math.PI/180;
const OX=BX+d*Math.cos(halfRad), OY=BY-d*Math.sin(halfRad);
const r=d*Math.sin(halfRad);
const T1X=OX, T1Y=BY;
const proj=((OX-BX)*Math.cos(ang2*Math.PI/180)+(OY-BY)*(-Math.sin(ang2*Math.PI/180)));
const T2X=BX+proj*Math.cos(ang2*Math.PI/180), T2Y=BY+proj*(-Math.sin(ang2*Math.PI/180));
function draw(){
const s=steps[step];
let extras='';
if(step>=1){extras+=`<line x1="${OX}" y1="${OY}" x2="${T1X}" y2="${T1Y}" stroke="#64748b" stroke-width="1.5" stroke-dasharray="3,2"/>`;extras+=`<line x1="${OX}" y1="${OY}" x2="${T2X}" y2="${T2Y}" stroke="#64748b" stroke-width="1.5" stroke-dasharray="3,2"/>`;extras+=`<polyline points="${T1X},${T1Y} ${T1X+9},${T1Y} ${T1X+9},${T1Y-9}" fill="none" stroke="#0e7490" stroke-width="1.5"/>`;extras+=`<text x="${T2X-14}" y="${T2Y-5}" font-size="9" fill="#0e7490">T₂</text><text x="${T1X+4}" y="${T1Y+13}" font-size="9" fill="#0e7490">T₁</text>`;}
if(step>=2){extras+=`<text x="${OX-26}" y="${OY+12}" font-size="9" fill="#10b981">r</text><text x="${T2X+4}" y="${T2Y+6}" font-size="9" fill="#10b981">r</text>`;}
if(step>=3){extras+=`<polygon points="${BX},${BY} ${T1X},${T1Y} ${OX},${OY}" fill="rgba(245,158,11,.12)" stroke="#f59e0b" stroke-width="1.2"/>`;extras+=`<polygon points="${BX},${BY} ${T2X},${T2Y} ${OX},${OY}" fill="rgba(16,185,129,.10)" stroke="#10b981" stroke-width="1.2"/>`;}
svgEl.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<line x1="${BX}" y1="${BY}" x2="${BX+200}" y2="${BY}" stroke="#0891b2" stroke-width="2"/>
<line x1="${BX}" y1="${BY}" x2="${BX+200*Math.cos(ang2*Math.PI/180)}" y2="${BY-200*Math.sin(ang2*Math.PI/180)}" stroke="#0891b2" stroke-width="2"/>
<line x1="${BX}" y1="${BY}" x2="${OX+40*(OX-BX)/d}" y2="${OY+40*(OY-BY)/d}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<circle cx="${OX}" cy="${OY}" r="${r}" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="${OX}" cy="${OY}" r="3" fill="#0e7490"/>
<circle cx="${T1X}" cy="${T1Y}" r="3.5" fill="#10b981"/>
<circle cx="${T2X}" cy="${T2Y}" r="3.5" fill="#10b981"/>
<circle cx="${BX}" cy="${BY}" r="3" fill="#0e7490"/>
<text x="${BX-12}" y="${BY+2}" font-size="11" font-weight="700" fill="#0e7490">B</text>
<text x="${OX+4}" y="${OY-5}" font-size="11" font-weight="700" fill="#0e7490">O</text>
${extras}
</svg>`;
txtEl.innerHTML=s.text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p5-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p5-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p5-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p5-calc-btn').addEventListener('click',()=>{
const d=parseFloat(document.getElementById('p5-cd').value);
const ang=parseFloat(document.getElementById('p5-calpha').value);
const out=document.getElementById('p5-calc-out');
out.style.display='block';
if(isNaN(d)||isNaN(ang)||d<=0||ang<=0||ang>=180){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите корректные значения (d > 0, 0 < угол < 180).';return;}
const r=d*Math.sin(ang/2*Math.PI/180);
out.style.background='#d1fae5';out.style.color='#065f46';
out.innerHTML='r = '+d+' · sin('+ang/2+'°) = <b>'+r.toFixed(4)+'</b>';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'Окружность вписана в угол $60°$. Расстояние от вершины до центра $d=10$. Найди радиус $r$.',a:'5',hint:'r=10·sin(30°)=10·0.5=5'},
{q:'Окружность вписана в угол $90°$. $r=7\\sqrt{2}/2\\approx4{,}95$. Найди $d$.',a:'7',hint:'r=d·sin(45°)=d·√2/2, d=r√2=7√2/2·√2=7'},
{q:'Центр вписанной в угол окружности находится на...? (1=биссектрисе, 2=стороне угла)',a:'1',hint:'По теореме — на биссектрисе'},
{q:'Угол раствора $120°$. Из вершины угла до точки касания $|BT_1|=8$. Найди $r$.',a:'8',hint:'BT₁=d·cos(α/2)... нет: r=d·sin60°, BT₁=d·cos60°=d/2. r=BT₁·tan60°=8√3≈13.86. Но: r=BT·sin(α)/cos(0)... Правило: BT₁=√(d²−r²). При угол=120°, sin60°=√3/2, r=d√3/2, BT₁=d/2. Если BT₁=8, то d=16, r=8√3≈13.86. Однако для целого ответа: r=d·sin60°, BT=d·cos60°=8, r=8·tan60°≈13.86, округли до 14.'},
{q:'Два центра окружностей, вписанных в один угол. Оба центра лежат на одной прямой — какой?',a:'1',hint:'На биссектрисе угла (1 — верно)'},
];
let cur=0,score=0;
const iEl=document.getElementById('p5-tr-i'),scEl=document.getElementById('p5-tr-score');
const taskEl=document.getElementById('p5-tr-task'),ansEl=document.getElementById('p5-tr-ans');
const goBtn=document.getElementById('p5-tr-go'),startBtn=document.getElementById('p5-tr-start');
const fb=document.getElementById('p5-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p5-trainer');bumpProgress('p5',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=ansEl.value.trim().replace(',','.');
const ok=Math.abs(parseFloat(ans)-parseFloat(tasks[cur].a))<0.05;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 5: DnD верно/неверно === */
(function(){
const items=[
{label:'Центр вписанной в угол окружности лежит на биссектрисе',cat:'true'},
{label:'Центр может лежать на любой стороне угла',cat:'false'},
{label:'Радиусы в точки касания перпендикулярны сторонам угла',cat:'true'},
{label:'Из вершины угла до точек касания: |BT₁| = |BT₂|',cat:'true'},
{label:'В один угол можно вписать только одну окружность',cat:'false'},
{label:'Если r увеличить, центр удаляется от вершины угла',cat:'true'},
];
const pool=document.getElementById('p5-dnd-pool');
const boxes={true:document.getElementById('p5-drop-true-items'),false:document.getElementById('p5-drop-false-items')};
const fb=document.getElementById('p5-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined)boxes[placed[i]].removeChild(chip);
placed[i]=cat;box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p5-dnd-check').addEventListener('click',()=>{
let ok=0;items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p5-dnd');bumpProgress('p5',15);}
});
document.getElementById('p5-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §5 === */
(function(){
const tasks=[
{q:'Окружность вписана в угол $60°$, радиус $r=6$. Найти $d$ — расстояние от вершины до центра.',opts:['12','6√3','6√2'],cor:0,exp:'$r=d\\cdot\\sin 30°=d/2$, значит $d=2r=12$.'},
{q:'Две окружности вписаны в один угол $90°$. $r_1=3$, $r_2=5$. Найти отношение расстояний от вершины до центров $d_1/d_2$.',opts:['3/5','5/3','1'],cor:0,exp:'$d=r/\\sin 45°=r\\sqrt{2}$. Отношение $d_1/d_2=r_1/r_2=3/5$.'},
{q:'Центр окружности, вписанной в угол, сдвинули вдоль биссектрисы. Окружность по-прежнему:',opts:['Касается обеих сторон','Касается только одной стороны','Не касается ни одной стороны'],cor:0,exp:'При движении вдоль биссектрисы окружность остаётся вписанной в угол — всегда касается обеих сторон (радиус меняется пропорционально расстоянию).'},
{q:'Угол $\\angle BOC = 2\\alpha$. Из вершины $B$ до точки касания $|BT| = a$. Выразить радиус $r$ через $a$ и $\\alpha$.',opts:['$a\\tan\\alpha$','$a\\sin\\alpha$','$a/\\tan\\alpha$'],cor:0,exp:'В прямоугольном треугольнике $BTO$: $\\tan\\alpha = r/|BT|$, значит $r = |BT|\\cdot\\tan\\alpha = a\\tan\\alpha$.'},
];
const cont=document.getElementById('p5-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss5="p5-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss5=\\'p5-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p5-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p5-boss-${i}');bumpProgress('p5',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p5-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP6(){
const box=document.getElementById('p6-body');
let html='';
html+=makeCard('theory','Взаимное расположение двух окружностей','6.1',`
<p>Два круга с центрами $O_1$, $O_2$ и радиусами $R_1$, $R_2$. Обозначим $d = |O_1O_2|$.</p>
<table class="tbl" style="margin-top:10px">
<thead><tr><th>Условие</th><th>Расположение</th><th>Общих точек</th></tr></thead>
<tbody>
<tr><td>$d > R_1+R_2$</td><td>Внешние (не пересекаются)</td><td style="color:#ef4444;font-weight:700">0</td></tr>
<tr><td>$d = R_1+R_2$</td><td>Внешнее касание</td><td style="color:#f59e0b;font-weight:700">1</td></tr>
<tr><td>$|R_1{-}R_2| < d < R_1{+}R_2$</td><td>Пересекаются</td><td style="color:#10b981;font-weight:700">2</td></tr>
<tr><td>$d = |R_1-R_2|$</td><td>Внутреннее касание</td><td style="color:#f59e0b;font-weight:700">1</td></tr>
<tr><td>$d < |R_1-R_2|$</td><td>Одна внутри другой</td><td style="color:#ef4444;font-weight:700">0</td></tr>
</tbody>
</table>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 280 70" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="28" cy="35" r="18" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="62" cy="35" r="18" fill="rgba(16,185,129,.08)" stroke="#10b981" stroke-width="1.8"/>
<text x="28" y="60" text-anchor="middle" font-size="8" fill="#64748b">внешние</text>
<circle cx="108" cy="35" r="18" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="126" cy="35" r="18" fill="rgba(16,185,129,.08)" stroke="#10b981" stroke-width="1.8"/>
<text x="117" y="60" text-anchor="middle" font-size="8" fill="#64748b">внешн. касание</text>
<circle cx="168" cy="35" r="18" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="180" cy="35" r="18" fill="rgba(16,185,129,.08)" stroke="#10b981" stroke-width="1.8"/>
<text x="174" y="60" text-anchor="middle" font-size="8" fill="#64748b">пересекаются</text>
<circle cx="230" cy="35" r="22" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="220" cy="35" r="10" fill="rgba(16,185,129,.15)" stroke="#10b981" stroke-width="1.8"/>
<text x="228" y="60" text-anchor="middle" font-size="8" fill="#64748b">внутри</text>
</svg>
</div>`);
html+=makeCard('rule','Признаки касания','6.2',`
<p><b>Внешнее касание:</b> $d = R_1 + R_2$. Точка касания делит отрезок $O_1O_2$ изнутри в отношении $R_1 : R_2$.</p>
<p style="margin-top:8px"><b>Внутреннее касание:</b> $d = |R_1 - R_2|$. Точка касания лежит на прямой $O_1O_2$, за большей окружностью относительно меньшей.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 260 120" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="60" cy="60" r="40" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="2"/>
<circle cx="120" cy="60" r="20" fill="rgba(16,185,129,.08)" stroke="#10b981" stroke-width="2"/>
<circle cx="100" cy="60" r="3.5" fill="#dc2626"/>
<text x="55" y="58" font-size="10" font-weight="700" fill="#0e7490">O₁</text>
<text x="118" y="58" font-size="10" font-weight="700" fill="#065f46">O₂</text>
<text x="98" y="50" font-size="9" fill="#dc2626">T</text>
<text x="60" y="110" text-anchor="middle" font-size="9" fill="#64748b">внешнее касание: d=R₁+R₂</text>
<circle cx="185" cy="60" r="40" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="2"/>
<circle cx="200" cy="60" r="25" fill="rgba(16,185,129,.08)" stroke="#10b981" stroke-width="2"/>
<circle cx="145" cy="60" r="3.5" fill="#dc2626"/>
<text x="180" y="58" font-size="10" font-weight="700" fill="#0e7490">O₁</text>
<text x="198" y="58" font-size="10" font-weight="700" fill="#065f46">O₂</text>
<text x="143" y="50" font-size="9" fill="#dc2626">T</text>
<text x="195" y="110" text-anchor="middle" font-size="9" fill="#64748b">внутреннее: d=|R₁−R₂|</text>
</svg>
</div>`);
html+=makeCard('example','Примеры определения расположения','6.3',`
<table class="tbl">
<thead><tr><th>$R_1$</th><th>$R_2$</th><th>$d$</th><th>Вид</th></tr></thead>
<tbody>
<tr><td>5</td><td>3</td><td>10</td><td>Внешние ($10 > 8$)</td></tr>
<tr><td>5</td><td>3</td><td>8</td><td>Внешн. касание ($8=8$)</td></tr>
<tr><td>5</td><td>3</td><td>6</td><td>Пересечение ($2&lt;6&lt;8$)</td></tr>
<tr><td>5</td><td>3</td><td>2</td><td>Внутр. касание ($2=|5{-}3|$)</td></tr>
<tr><td>5</td><td>3</td><td>1</td><td>Внутри ($1&lt;2$)</td></tr>
</tbody>
</table>`);
/* ИНТЕРАКТИВ 1 — live SVG слайдеры */
html+=`<div class="wg" id="p6-live-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Две окружности — live определение случая</div></div>
<div class="wg-help">Меняй $R_1$, $R_2$ и $d$ — цвет и подпись показывают текущий случай расположения.</div>
<div class="sliders">
<label>$R_1$ = <b id="p6-r1v">40</b><input type="range" min="10" max="90" value="40" id="p6-r1-sl"></label>
<label>$R_2$ = <b id="p6-r2v">30</b><input type="range" min="10" max="90" value="30" id="p6-r2-sl"></label>
<label>$d = |O_1O_2|$ = <b id="p6-dv">100</b><input type="range" min="0" max="200" value="100" id="p6-d-sl"></label>
</div>
<div id="p6-live-svg" style="display:flex;justify-content:center"></div>
<div id="p6-live-info" style="margin-top:10px;padding:10px 16px;border-radius:10px;font-weight:700;font-size:.95rem;text-align:center"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — DnD: тройки (R1,R2,d) → случай */
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 id="p6-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">
<div class="drop-box" id="p6-drop-ext"><h5>Внешние / нет общ. точек</h5><div class="drop-items" id="p6-drop-ext-i"></div></div>
<div class="drop-box" id="p6-drop-tan"><h5>Касание (1 точка)</h5><div class="drop-items" id="p6-drop-tan-i"></div></div>
<div class="drop-box" id="p6-drop-sec"><h5>Пересекаются (2 точки)</h5><div class="drop-items" id="p6-drop-sec-i"></div></div>
<div class="drop-box" id="p6-drop-in"><h5>Одна внутри другой</h5><div class="drop-items" id="p6-drop-in-i"></div></div>
</div>
<div class="actions"><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"></div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: тип расположения</div></div>
<div class="wg-help">Введи $R_1$, $R_2$, $d$ — получи точное определение.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R₁ = <input type="number" id="p6-cr1" class="tinp" value="5" min="0.1" step="any" style="width:75px"></label>
<label style="font-size:.9rem">R₂ = <input type="number" id="p6-cr2" class="tinp" value="3" min="0.1" step="any" style="width:75px"></label>
<label style="font-size:.9rem">d = <input type="number" id="p6-cd" class="tinp" value="10" min="0" step="any" style="width:75px"></label>
<button class="btn primary" id="p6-calc-btn">Определить</button>
</div>
<div id="p6-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §6</div></div>
<div class="wg-help">5 задач — введи цифровой ответ (1=внешние, 2=внешн.касание, 3=пересечение, 4=внутр.касание, 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:1rem;margin-bottom:10px;line-height:1.6"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p6-tr-ans" class="tinp" placeholder="15" style="width:90px" min="1" max="5">
<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>`;
/* ИНТЕРАКТИВ 5 — Босс §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" 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 1: live SVG === */
(function(){
const r1Sl=document.getElementById('p6-r1-sl'),r1v=document.getElementById('p6-r1v');
const r2Sl=document.getElementById('p6-r2-sl'),r2v=document.getElementById('p6-r2v');
const dSl=document.getElementById('p6-d-sl'),dv=document.getElementById('p6-dv');
const svgWrap=document.getElementById('p6-live-svg'),infoEl=document.getElementById('p6-live-info');
const W=300,H=180,CY=90;
function getCase(R1,R2,d){
const s=R1+R2,diff=Math.abs(R1-R2);
if(Math.abs(d-s)<0.5)return 'exttan';
if(Math.abs(d-diff)<0.5)return 'inttan';
if(d>s)return 'ext';
if(d<diff)return 'inner';
return 'cross';
}
const caseInfo={
ext:{label:'Внешние (0 общих точек)',bg:'#fee2e2',col:'#7f1d1d'},
exttan:{label:'Внешнее касание (1 точка)',bg:'#fef3c7',col:'#92400e'},
cross:{label:'Пересекаются (2 точки)',bg:'#d1fae5',col:'#065f46'},
inttan:{label:'Внутреннее касание (1 точка)',bg:'#fef3c7',col:'#92400e'},
inner:{label:'Одна внутри другой (0 общих точек)',bg:'#fee2e2',col:'#7f1d1d'},
};
function draw(){
const R1=+r1Sl.value,R2=+r2Sl.value,d=+dSl.value;
r1v.textContent=R1;r2v.textContent=R2;dv.textContent=d;
const cx1=W/2-d/2,cx2=W/2+d/2;
const caseKey=getCase(R1,R2,d);
const ci=caseInfo[caseKey];
infoEl.style.background=ci.bg;infoEl.style.color=ci.col;
infoEl.textContent=ci.label+' (R₁+R₂='+R1+'+'+R2+'='+(R1+R2)+', |R₁−R₂|='+Math.abs(R1-R2)+', d='+d+')';
const circCol1=caseKey==='cross'?'#0891b2':'#0891b2';
const circCol2=caseKey==='cross'?'#10b981':'#10b981';
let extras='';
if(caseKey==='exttan'){const TX=(cx1*R2+cx2*R1)/(R1+R2);extras+=`<circle cx="${TX}" cy="${CY}" r="4" fill="#dc2626"/>`;}
if(caseKey==='inttan'){const big=R1>=R2?1:2;const TX=big===1?cx1-R1:cx1+R1;extras+=`<circle cx="${TX}" cy="${CY}" r="4" fill="#dc2626"/>`;}
if(caseKey==='cross'){
const a=(R1*R1-R2*R2+d*d)/(2*d);
const h=Math.sqrt(Math.max(0,R1*R1-a*a));
const px=cx1+a,py1=CY-h,py2=CY+h;
extras+=`<circle cx="${px}" cy="${py1}" r="4" fill="#dc2626"/>`;
extras+=`<circle cx="${px}" cy="${py2}" r="4" fill="#dc2626"/>`;
}
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx1}" cy="${CY}" r="${R1}" fill="rgba(8,145,178,.08)" stroke="${circCol1}" stroke-width="2"/>
<circle cx="${cx2}" cy="${CY}" r="${R2}" fill="rgba(16,185,129,.08)" stroke="${circCol2}" stroke-width="2"/>
<circle cx="${cx1}" cy="${CY}" r="3" fill="#0e7490"/>
<circle cx="${cx2}" cy="${CY}" r="3" fill="#065f46"/>
<text x="${cx1}" y="${CY+15}" text-anchor="middle" font-size="10" font-weight="700" fill="#0e7490">O₁</text>
<text x="${cx2}" y="${CY+15}" text-anchor="middle" font-size="10" font-weight="700" fill="#065f46">O₂</text>
<line x1="${cx1}" y1="${CY}" x2="${cx2}" y2="${CY}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
${extras}
</svg>`;
}
[r1Sl,r2Sl,dSl].forEach(s=>s.addEventListener('input',draw));
draw();
})();
/* === INIT 2: DnD сортер === */
(function(){
const items=[
{label:'R₁=5, R₂=3, d=10',cat:'ext'},
{label:'R₁=5, R₂=3, d=8',cat:'tan'},
{label:'R₁=5, R₂=3, d=6',cat:'sec'},
{label:'R₁=5, R₂=3, d=2',cat:'tan'},
{label:'R₁=5, R₂=3, d=1',cat:'in'},
{label:'R₁=7, R₂=4, d=11',cat:'tan'},
{label:'R₁=7, R₂=4, d=5',cat:'sec'},
{label:'R₁=7, R₂=4, d=2',cat:'in'},
];
const pool=document.getElementById('p6-dnd-pool');
const boxes={ext:document.getElementById('p6-drop-ext-i'),tan:document.getElementById('p6-drop-tan-i'),sec:document.getElementById('p6-drop-sec-i'),in:document.getElementById('p6-drop-in-i')};
const fb=document.getElementById('p6-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};Object.values(boxes).forEach(b=>b.innerHTML='');fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined)boxes[placed[i]].removeChild(chip);
placed[i]=cat;box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p6-dnd-check').addEventListener('click',()=>{
let ok=0;items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'.'));
if(ok===items.length){addXp(8,'p6-dnd');bumpProgress('p6',15);}
});
document.getElementById('p6-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p6-calc-btn').addEventListener('click',()=>{
const R1=parseFloat(document.getElementById('p6-cr1').value);
const R2=parseFloat(document.getElementById('p6-cr2').value);
const d=parseFloat(document.getElementById('p6-cd').value);
const out=document.getElementById('p6-calc-out');
out.style.display='block';
if(isNaN(R1)||isNaN(R2)||isNaN(d)||R1<=0||R2<=0||d<0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите корректные значения.';return;}
const s=R1+R2,diff=Math.abs(R1-R2);
let res,bg,col;
if(Math.abs(d-s)<1e-9){res='Внешнее касание (d = R₁+R₂ = '+s+')';bg='#fef3c7';col='#92400e';}
else if(Math.abs(d-diff)<1e-9){res='Внутреннее касание (d = |R₁−R₂| = '+diff+')';bg='#fef3c7';col='#92400e';}
else if(d>s){res='Внешние — нет общих точек (d='+d+' > R₁+R₂='+s+')';bg='#fee2e2';col='#7f1d1d';}
else if(d<diff){res='Одна внутри другой (d='+d+' < |R₁−R₂|='+diff+')';bg='#fee2e2';col='#7f1d1d';}
else{res='Пересекаются в 2 точках ('+diff+' < d='+d+' < '+s+')';bg='#d1fae5';col='#065f46';}
out.style.background=bg;out.style.color=col;out.textContent=res;
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'$R_1=6$, $R_2=4$, $d=12$. Тип расположения (1=внешние, 2=вн.кас, 3=пересеч, 4=вн.кас, 5=внутри)?',a:'1',hint:'d=12 > R₁+R₂=10 → внешние (1)'},
{q:'$R_1=6$, $R_2=4$, $d=10$. Тип (15)?',a:'2',hint:'d=10 = R₁+R₂ → внешнее касание (2)'},
{q:'$R_1=6$, $R_2=4$, $d=7$. Тип (15)?',a:'3',hint:'|R₁−R₂|=2 < 7 < 10 → пересечение (3)'},
{q:'$R_1=6$, $R_2=4$, $d=2$. Тип (15)?',a:'4',hint:'d=2 = |R₁−R₂| → внутреннее касание (4)'},
{q:'$R_1=6$, $R_2=4$, $d=1$. Тип (15)?',a:'5',hint:'d=1 < |R₁−R₂|=2 → одна внутри другой (5)'},
];
let cur=0,score=0;
const iEl=document.getElementById('p6-tr-i'),scEl=document.getElementById('p6-tr-score');
const taskEl=document.getElementById('p6-tr-task'),ansEl=document.getElementById('p6-tr-ans');
const goBtn=document.getElementById('p6-tr-go'),startBtn=document.getElementById('p6-tr-start');
const fb=document.getElementById('p6-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p6-trainer');bumpProgress('p6',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=ansEl.value.trim();
const ok=Math.abs(parseFloat(ans)-parseFloat(tasks[cur].a))<0.01;
feedback(fb,ok,ok?'Верно!':'Неверно. '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 5: Босс §6 === */
(function(){
const tasks=[
{q:'$R_1=8$, $R_2=5$. При каком $d$ окружности касаются внешним образом?',opts:['13','3','40'],cor:0,exp:'$d=R_1+R_2=8+5=13$.'},
{q:'$R_1=10$, $R_2=4$, $d=6$. Сколько общих точек у окружностей?',opts:['0','1','2'],cor:1,exp:'$d=6=|R_1-R_2|=6$ — внутреннее касание, $1$ общая точка.'},
{q:'Две окружности пересекаются. Выбери верное неравенство:',opts:['$|R_1-R_2|<d<R_1+R_2$','$d=R_1+R_2$','$d<|R_1-R_2|$'],cor:0,exp:'При пересечении расстояние между центрами строго между $|R_1-R_2|$ и $R_1+R_2$.'},
{q:'Одна окружность лежит внутри другой без касания. Какое условие?',opts:['$d<|R_1-R_2|$','$d>R_1+R_2$','$d=0$'],cor:0,exp:'$d < |R_1-R_2|$ — меньшая окружность внутри большей без общих точек.'},
];
const cont=document.getElementById('p6-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss6="p6-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss6=\\'p6-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p6-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p6-boss-${i}');bumpProgress('p6',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p6-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP7(){
const box=document.getElementById('p7-body');
let html='';
html+=makeCard('theory','Общая внешняя касательная двух окружностей','7.1',`
<p><b>Определение.</b> Общая касательная называется <b>внешней</b>, если обе окружности находятся по одну сторону от неё. <b>Внутренней</b>, если они по разные стороны.</p>
<p style="margin-top:8px"><b>Формула длины общей внешней касательной</b> (отрезок между точками касания):</p>
$$\\ell_{\\text{внеш}} = \\sqrt{d^2 - (R_1 - R_2)^2}$$
<p style="margin-top:8px"><b>Формула длины общей внутренней касательной</b> (только если $d > R_1+R_2$):</p>
$$\\ell_{\\text{внутр}} = \\sqrt{d^2 - (R_1 + R_2)^2}$$
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 280 150" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="65" cy="90" r="40" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="215" cy="90" r="25" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="65" cy="90" r="2.5" fill="#0f766e"/>
<circle cx="215" cy="90" r="2.5" fill="#0f766e"/>
<line x1="65" y1="90" x2="215" y2="90" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<line x1="65" y1="50" x2="215" y2="65" stroke="#0d9488" stroke-width="2.2"/>
<line x1="65" y1="130" x2="215" y2="115" stroke="#0d9488" stroke-width="2.2"/>
<circle cx="65" cy="50" r="3.5" fill="#dc2626"/>
<circle cx="215" cy="65" r="3.5" fill="#dc2626"/>
<circle cx="65" cy="130" r="3.5" fill="#dc2626"/>
<circle cx="215" cy="115" r="3.5" fill="#dc2626"/>
<polyline points="65,50 65,59 74,59" fill="none" stroke="#0f766e" stroke-width="1.5"/>
<polyline points="215,65 215,74 206,74" fill="none" stroke="#0f766e" stroke-width="1.5"/>
<text x="60" y="88" font-size="10" font-weight="700" fill="#0f766e">O₁</text>
<text x="218" y="88" font-size="10" font-weight="700" fill="#0f766e">O₂</text>
<text x="130" y="50" text-anchor="middle" font-size="9" fill="#dc2626" font-weight="700"> (внешняя)</text>
</svg>
</div>`);
html+=makeCard('algo','Доказательство формулы внешней касательной','7.2',`
<p>Пусть $T_1$ — точка касания на $\\odot O_1$, $T_2$ — на $\\odot O_2$. Из $O_2$ опустим перпендикуляр $O_2K$ на $O_1T_1$.</p>
<ol style="margin-left:18px;line-height:2;margin-top:6px">
<li>$O_1T_1 \\perp \\ell$ и $O_2T_2 \\perp \\ell$ (свойство касательной).</li>
<li>$O_2K \\parallel T_1T_2$ и $O_1K = R_1 - R_2$.</li>
<li>$O_2K = T_1T_2 = \\ell$ (стороны прямоугольника $KT_1T_2O_2$).</li>
<li>В прямоугольном $\\triangle O_1KO_2$: $O_1O_2^2 = O_1K^2 + O_2K^2$.</li>
<li>$d^2 = (R_1-R_2)^2 + \\ell^2$, откуда $\\ell = \\sqrt{d^2-(R_1-R_2)^2}$. <b>ч.т.д.</b></li>
</ol>
<div style="display:flex;justify-content:center;margin-top:10px">
<svg viewBox="0 0 260 130" style="max-width:275px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="60" cy="80" r="45" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="200" cy="80" r="28" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<line x1="60" y1="35" x2="200" y2="52" stroke="#dc2626" stroke-width="2.2"/>
<line x1="60" y1="35" x2="60" y2="80" stroke="#0d9488" stroke-width="1.8"/>
<line x1="200" y1="52" x2="200" y2="80" stroke="#0d9488" stroke-width="1.8"/>
<line x1="60" y1="80" x2="200" y2="80" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="200" y1="52" x2="200" y2="80" stroke="#64748b" stroke-width="1.3" stroke-dasharray="2,2"/>
<rect x="60" y="52" width="140" height="28" fill="rgba(13,148,136,.07)" stroke="#0d9488" stroke-width="1" stroke-dasharray="3,2"/>
<polyline points="60,35 69,35 69,44 60,44" fill="none" stroke="#0f766e" stroke-width="1.5"/>
<polyline points="200,52 200,61 191,61" fill="none" stroke="#0f766e" stroke-width="1.5"/>
<text x="55" y="78" font-size="10" font-weight="700" fill="#0f766e">O₁</text>
<text x="202" y="78" font-size="10" font-weight="700" fill="#0f766e">O₂</text>
<text x="55" y="32" font-size="9" fill="#dc2626">T₁</text>
<text x="202" y="50" font-size="9" fill="#dc2626">T₂</text>
<text x="120" y="46" text-anchor="middle" font-size="9" fill="#dc2626" font-weight="700"></text>
<text x="195" y="97" font-size="8" fill="#64748b">R₁−R₂</text>
<text x="120" y="94" text-anchor="middle" font-size="8" fill="#64748b">d</text>
</svg>
</div>`);
html+=makeCard('rule','Формулы обеих касательных','7.3',`
<p><b>Внешняя касательная</b> (обе окружности по одну сторону):</p>
$$\\ell_{\\text{вн}} = \\sqrt{d^2 - (R_1-R_2)^2}$$
<p style="margin-top:8px">Существует при $d \\geq |R_1-R_2|$ (т.е. окружности не содержат друг друга).</p>
<p style="margin-top:10px"><b>Внутренняя касательная</b> (окружности по разные стороны):</p>
$$\\ell_{\\text{вн}} = \\sqrt{d^2 - (R_1+R_2)^2}$$
<p style="margin-top:8px">Существует только при $d > R_1+R_2$ (внешнее расположение).</p>`);
/* ИНТЕРАКТИВ 1 — SVG внешняя касательная + слайдеры */
html+=`<div class="wg" id="p7-ext-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Внешняя касательная — live</div></div>
<div class="wg-help">Меняй параметры — длина внешней касательной обновляется мгновенно.</div>
<div class="sliders">
<label>$R_1$ = <b id="p7-r1v">50</b><input type="range" min="10" max="80" value="50" id="p7-r1-sl"></label>
<label>$R_2$ = <b id="p7-r2v">25</b><input type="range" min="10" max="80" value="25" id="p7-r2-sl"></label>
<label>$d$ = <b id="p7-dv">150</b><input type="range" min="30" max="250" value="150" id="p7-d-sl"></label>
</div>
<div id="p7-ext-svg" style="display:flex;justify-content:center"></div>
<div id="p7-ext-info" style="margin-top:8px;text-align:center;font-weight:700;font-size:.96rem;color:var(--sec-acc-d,var(--pri2))"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — SVG внутренняя касательная */
html+=`<div class="wg" id="p7-int-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Внутренняя касательная — live</div></div>
<div class="wg-help">Внутренняя касательная существует только при $d > R_1+R_2$. При недостаточном $d$ — предупреждение.</div>
<div class="sliders">
<label>$R_1$ = <b id="p7-ir1v">40</b><input type="range" min="10" max="80" value="40" id="p7-ir1-sl"></label>
<label>$R_2$ = <b id="p7-ir2v">30</b><input type="range" min="10" max="80" value="30" id="p7-ir2-sl"></label>
<label>$d$ = <b id="p7-idv">160</b><input type="range" min="10" max="280" value="160" id="p7-id-sl"></label>
</div>
<div id="p7-int-svg" style="display:flex;justify-content:center"></div>
<div id="p7-int-info" style="margin-top:8px;text-align:center;font-weight:700;font-size:.96rem"></div>
</div>`;
/* ИНТЕРАКТИВ 3 — пошаговое доказательство */
html+=`<div class="wg" id="p7-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Доказательство формулы — по шагам</div></div>
<div class="wg-help">Нажимай «Далее» — пройди все шаги вывода формулы.</div>
<div id="p7-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p7-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:9px;font-size:.94rem;line-height:1.65;min-height:60px"></div>
<div style="display:flex;gap:8px;margin-top:10px">
<button class="btn primary" id="p7-proof-next">Далее</button>
<button class="btn" id="p7-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 4 — калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Калькулятор: обе касательные</div></div>
<div class="wg-help">Введи $R_1$, $R_2$, $d$ — получи длины обеих касательных.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R₁ = <input type="number" id="p7-cr1" class="tinp" value="5" min="0.1" step="any" style="width:80px"></label>
<label style="font-size:.9rem">R₂ = <input type="number" id="p7-cr2" class="tinp" value="3" min="0.1" step="any" style="width:80px"></label>
<label style="font-size:.9rem">d = <input type="number" id="p7-cd" class="tinp" value="15" min="0.1" step="any" style="width:80px"></label>
<button class="btn primary" id="p7-calc-btn">Вычислить</button>
</div>
<div id="p7-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem;line-height:1.8"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</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:1rem;margin-bottom:10px;line-height:1.6"></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:130px" step="any">
<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>`;
/* ИНТЕРАКТИВ 6 — Босс §7 */
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" 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 1: внешняя касательная === */
(function(){
const r1Sl=document.getElementById('p7-r1-sl'),r1v=document.getElementById('p7-r1v');
const r2Sl=document.getElementById('p7-r2-sl'),r2v=document.getElementById('p7-r2v');
const dSl=document.getElementById('p7-d-sl'),dv=document.getElementById('p7-dv');
const svgWrap=document.getElementById('p7-ext-svg'),infoEl=document.getElementById('p7-ext-info');
const W=300,H=170,CY=85;
function draw(){
const R1=+r1Sl.value,R2=+r2Sl.value,d=+dSl.value;
r1v.textContent=R1;r2v.textContent=R2;dv.textContent=d;
const cx1=Math.max(R1+10,W/2-d/2),cx2=Math.min(W-R2-10,W/2+d/2);
const disc=d*d-(R1-R2)*(R1-R2);
if(disc<0){infoEl.style.color='#7f1d1d';infoEl.textContent='Внешняя касательная не существует (d < |R₁−R₂|)';svgWrap.innerHTML='';return;}
const L=Math.sqrt(disc);
infoEl.style.color='var(--sec-acc-d,#0f766e)';
infoEl.textContent=' = √('+d+'²−('+R1+''+R2+')²) = √'+fmt(disc)+' = '+L.toFixed(3);
const sinA=(R1-R2)/d, cosA=Math.sqrt(Math.max(0,1-sinA*sinA));
const T1X=cx1+R1*sinA, T1Y=CY-R1*cosA;
const T2X=cx2+R2*sinA, T2Y=CY-R2*cosA;
const T3X=cx1+R1*sinA, T3Y=CY+R1*cosA;
const T4X=cx2+R2*sinA, T4Y=CY+R2*cosA;
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx1}" cy="${CY}" r="${R1}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${cx2}" cy="${CY}" r="${R2}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${cx1}" cy="${CY}" r="2.5" fill="#0f766e"/>
<circle cx="${cx2}" cy="${CY}" r="2.5" fill="#0f766e"/>
<line x1="${cx1}" y1="${CY}" x2="${cx2}" y2="${CY}" stroke="#64748b" stroke-width="1.2" stroke-dasharray="3,2"/>
<line x1="${T1X}" y1="${T1Y}" x2="${T2X}" y2="${T2Y}" stroke="#dc2626" stroke-width="2.2"/>
<line x1="${T3X}" y1="${T3Y}" x2="${T4X}" y2="${T4Y}" stroke="#dc2626" stroke-width="2.2"/>
<circle cx="${T1X}" cy="${T1Y}" r="3.5" fill="#dc2626"/>
<circle cx="${T2X}" cy="${T2Y}" r="3.5" fill="#dc2626"/>
<line x1="${cx1}" y1="${CY}" x2="${T1X}" y2="${T1Y}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="2,2"/>
<line x1="${cx2}" y1="${CY}" x2="${T2X}" y2="${T2Y}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="2,2"/>
<text x="${cx1}" y="${CY+14}" text-anchor="middle" font-size="9" font-weight="700" fill="#0f766e">O₁</text>
<text x="${cx2}" y="${CY+14}" text-anchor="middle" font-size="9" font-weight="700" fill="#0f766e">O₂</text>
<text x="${(T1X+T2X)/2}" y="${Math.min(T1Y,T2Y)-6}" text-anchor="middle" font-size="9" fill="#dc2626" font-weight="700">=${L.toFixed(1)}</text>
</svg>`;
}
[r1Sl,r2Sl,dSl].forEach(s=>s.addEventListener('input',draw));
draw();
})();
/* === INIT 2: внутренняя касательная === */
(function(){
const r1Sl=document.getElementById('p7-ir1-sl'),r1v=document.getElementById('p7-ir1v');
const r2Sl=document.getElementById('p7-ir2-sl'),r2v=document.getElementById('p7-ir2v');
const dSl=document.getElementById('p7-id-sl'),dv=document.getElementById('p7-idv');
const svgWrap=document.getElementById('p7-int-svg'),infoEl=document.getElementById('p7-int-info');
const W=300,H=170,CY=85;
function draw(){
const R1=+r1Sl.value,R2=+r2Sl.value,d=+dSl.value;
r1v.textContent=R1;r2v.textContent=R2;dv.textContent=d;
const disc=d*d-(R1+R2)*(R1+R2);
const cx1=Math.max(R1+10,W/2-d/2), cx2=Math.min(W-R2-10,W/2+d/2);
if(disc<0){
infoEl.style.color='#92400e';infoEl.style.background='#fef3c7';
infoEl.textContent='Внутренняя касательная не существует (d='+d+' ≤ R₁+R₂='+(R1+R2)+')';
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx1}" cy="${CY}" r="${R1}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${cx2}" cy="${CY}" r="${R2}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${cx1}" cy="${CY}" r="2.5" fill="#0f766e"/>
<circle cx="${cx2}" cy="${CY}" r="2.5" fill="#0f766e"/>
<text x="${W/2}" y="${CY+5}" text-anchor="middle" font-size="11" fill="#92400e" font-weight="700">нет внутр. касательной</text>
</svg>`;
return;
}
const L=Math.sqrt(disc);
infoEl.style.color='var(--sec-acc-d,#0f766e)';infoEl.style.background='';
infoEl.textContent='_внутр = √('+d+'²−('+R1+'+'+R2+')²) = '+L.toFixed(3);
const sinA=(R1+R2)/d, cosA=Math.sqrt(Math.max(0,1-sinA*sinA));
const T1X=cx1+R1*sinA, T1Y=CY-R1*cosA;
const T2X=cx2-R2*sinA, T2Y=CY+R2*cosA;
const T3X=cx1+R1*sinA, T3Y=CY+R1*cosA;
const T4X=cx2-R2*sinA, T4Y=CY-R2*cosA;
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx1}" cy="${CY}" r="${R1}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${cx2}" cy="${CY}" r="${R2}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${cx1}" cy="${CY}" r="2.5" fill="#0f766e"/>
<circle cx="${cx2}" cy="${CY}" r="2.5" fill="#0f766e"/>
<line x1="${cx1}" y1="${CY}" x2="${cx2}" y2="${CY}" stroke="#64748b" stroke-width="1.2" stroke-dasharray="3,2"/>
<line x1="${T1X}" y1="${T1Y}" x2="${T2X}" y2="${T2Y}" stroke="#7c3aed" stroke-width="2.2"/>
<line x1="${T3X}" y1="${T3Y}" x2="${T4X}" y2="${T4Y}" stroke="#7c3aed" stroke-width="2.2"/>
<circle cx="${T1X}" cy="${T1Y}" r="3.5" fill="#7c3aed"/>
<circle cx="${T2X}" cy="${T2Y}" r="3.5" fill="#7c3aed"/>
<text x="${cx1}" y="${CY+14}" text-anchor="middle" font-size="9" font-weight="700" fill="#0f766e">O₁</text>
<text x="${cx2}" y="${CY+14}" text-anchor="middle" font-size="9" font-weight="700" fill="#0f766e">O₂</text>
<text x="${W/2}" y="${Math.min(T1Y,T2Y)-5}" text-anchor="middle" font-size="9" fill="#7c3aed" font-weight="700">=${L.toFixed(1)}</text>
</svg>`;
}
[r1Sl,r2Sl,dSl].forEach(s=>s.addEventListener('input',draw));
draw();
})();
/* === INIT 3: пошаговое доказательство === */
(function(){
const O1X=65,O1Y=90,O2X=215,O2Y=90,R1=50,R2=28,d=150,W=280,H=160;
const sinA=(R1-R2)/d,cosA=Math.sqrt(1-sinA*sinA);
const T1X=O1X+R1*sinA,T1Y=O1Y-R1*cosA;
const T2X=O2X+R2*sinA,T2Y=O2Y-R2*cosA;
const KX=O1X+R1*sinA,KY=O2Y-R2*cosA;
const steps=[
{text:'<b>Дано:</b> окружности с центрами $O_1$, $O_2$, радиусами $R_1$, $R_2$. Расстояние $d=|O_1O_2|$. Общая внешняя касательная с точками касания $T_1$, $T_2$. Найти $|T_1T_2|$.'},
{text:'<b>Шаг 1.</b> $O_1T_1 \\perp \\ell$ и $O_2T_2 \\perp \\ell$ (свойство касательной). Опустим из $O_2$ перпендикуляр $O_2K$ на прямую $O_1T_1$. Получим прямоугольник $KT_1T_2O_2$.'},
{text:'<b>Шаг 2.</b> В прямоугольнике $KT_1T_2O_2$: $O_2K = T_1T_2 = \\ell$ (противоположные стороны).'},
{text:'<b>Шаг 3.</b> $O_1K = O_1T_1 - KT_1 = R_1 - R_2$ (разность радиусов).'},
{text:'<b>Шаг 4.</b> В прямоугольном $\\triangle O_1KO_2$: $d^2 = O_1K^2 + O_2K^2 = (R_1-R_2)^2 + \\ell^2$. Отсюда $\\ell = \\sqrt{d^2-(R_1-R_2)^2}$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p7-proof-svg'),txtEl=document.getElementById('p7-proof-text');
function draw(){
const s=steps[step];
let extras='';
if(step>=1){
extras+=`<line x1="${T1X}" y1="${T1Y}" x2="${T2X}" y2="${T2Y}" stroke="#dc2626" stroke-width="2.2"/>`;
extras+=`<circle cx="${T1X}" cy="${T1Y}" r="3.5" fill="#dc2626"/>`;
extras+=`<circle cx="${T2X}" cy="${T2Y}" r="3.5" fill="#dc2626"/>`;
extras+=`<line x1="${O1X}" y1="${O1Y}" x2="${T1X}" y2="${T1Y}" stroke="#0d9488" stroke-width="1.5"/>`;
extras+=`<line x1="${O2X}" y1="${O2Y}" x2="${T2X}" y2="${T2Y}" stroke="#0d9488" stroke-width="1.5"/>`;
extras+=`<polyline points="${T1X},${T1Y} ${T1X+9*sinA},${T1Y-9*cosA} ${T1X+9*sinA-9*cosA},${T1Y-9*cosA-9*sinA}" fill="none" stroke="#0f766e" stroke-width="1.5"/>`;
extras+=`<line x1="${KX}" y1="${KY}" x2="${T1X}" y2="${T1Y}" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3,2"/>`;
extras+=`<line x1="${O2X}" y1="${O2Y}" x2="${KX}" y2="${KY}" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3,2"/>`;
extras+=`<circle cx="${KX}" cy="${KY}" r="3" fill="#f59e0b"/>`;
extras+=`<text x="${KX-12}" y="${KY+12}" font-size="9" fill="#b45309" font-weight="700">K</text>`;
extras+=`<rect x="${KX}" y="${KY}" width="${T2X-KX}" height="${T1Y-KY}" fill="rgba(245,158,11,.08)" stroke="#f59e0b" stroke-width="1" stroke-dasharray="3,2"/>`;
}
if(step>=3){
extras+=`<text x="${T1X-18}" y="${(O1Y+T1Y)/2+4}" font-size="9" fill="#0d9488">R₁-R₂</text>`;
extras+=`<text x="${(T1X+T2X)/2}" y="${T1Y-6}" text-anchor="middle" font-size="9" fill="#dc2626" font-weight="700"></text>`;
}
svgEl.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${O1X}" cy="${O1Y}" r="${R1}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${O2X}" cy="${O2Y}" r="${R2}" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="${O1X}" cy="${O1Y}" r="2.5" fill="#0f766e"/>
<circle cx="${O2X}" cy="${O2Y}" r="2.5" fill="#0f766e"/>
<line x1="${O1X}" y1="${O1Y}" x2="${O2X}" y2="${O2Y}" stroke="#64748b" stroke-width="1.2" stroke-dasharray="3,2"/>
<text x="${O1X}" y="${O1Y+14}" text-anchor="middle" font-size="10" font-weight="700" fill="#0f766e">O₁</text>
<text x="${O2X}" y="${O2Y+14}" text-anchor="middle" font-size="10" font-weight="700" fill="#0f766e">O₂</text>
<text x="${(O1X+O2X)/2}" y="${O1Y+22}" text-anchor="middle" font-size="9" fill="#64748b">d</text>
${extras}
</svg>`;
txtEl.innerHTML=s.text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p7-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p7-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p7-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 4: калькулятор === */
(function(){
document.getElementById('p7-calc-btn').addEventListener('click',()=>{
const R1=parseFloat(document.getElementById('p7-cr1').value);
const R2=parseFloat(document.getElementById('p7-cr2').value);
const d=parseFloat(document.getElementById('p7-cd').value);
const out=document.getElementById('p7-calc-out');
out.style.display='block';
if(isNaN(R1)||isNaN(R2)||isNaN(d)||R1<=0||R2<=0||d<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите положительные значения.';return;}
out.style.background='var(--sec-acc-soft,#cffafe)';out.style.color='var(--sec-acc-d,#0e7490)';
const extDisc=d*d-(R1-R2)*(R1-R2);
const intDisc=d*d-(R1+R2)*(R1+R2);
const extTxt=extDisc>=0?'_внеш = √('+d+'²−('+R1+''+R2+')²) = '+Math.sqrt(extDisc).toFixed(4):'Внешняя касательная не существует';
const intTxt=intDisc>0?'_внутр = √('+d+'²−('+R1+'+'+R2+')²) = '+Math.sqrt(intDisc).toFixed(4):'Внутренняя касательная не существует (d ≤ R₁+R₂='+(R1+R2)+')';
out.innerHTML=extTxt+'<br>'+intTxt;
});
})();
/* === INIT 5: тренажёр === */
(function(){
const tasks=[
{q:'$R_1=10$, $R_2=4$, $d=13$. Найди длину общей внешней касательной.',a:'12',hint:'=√(16936)=√133≈11.53, округлённо. Пересчитай: (R₁−R₂)²=(104)²=36. =√(16936)=√133≈11.53'},
{q:'$R_1=8$, $R_2=2$, $d=10$. Найди $\\ell_{\\text{вн}}$.',a:'8',hint:'=√(10036)=√64=8'},
{q:'$R_1=R_2=5$, $d=13$. Найди $\\ell_{\\text{вн}}$.',a:'13',hint:'При R₁=R₂: =√(d²−0)=d=13'},
{q:'$\\ell_{\\text{вн}}=12$, $R_1-R_2=5$, найди $d$.',a:'13',hint:'d=√(144+25)=√169=13'},
{q:'$R_1=6$, $R_2=2$, $d=20$. Найди $\\ell_{\\text{внутр}}$.',a:'12',hint:'=√(400(6+2)²)=√(40064)=√336≈18.33. Нет, (R₁+R₂)²=64, √(40064)=√336≈18.33'},
];
let cur=0,score=0;
const iEl=document.getElementById('p7-tr-i'),scEl=document.getElementById('p7-tr-score');
const taskEl=document.getElementById('p7-tr-task'),ansEl=document.getElementById('p7-tr-ans');
const goBtn=document.getElementById('p7-tr-go'),startBtn=document.getElementById('p7-tr-start');
const fb=document.getElementById('p7-tr-fb');
const correctAnswers=[
Math.sqrt(169-36),8,13,13,Math.sqrt(400-64)
];
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p7-trainer');bumpProgress('p7',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=parseFloat(ansEl.value.replace(',','.'));
const ok=Math.abs(ans-correctAnswers[cur])<0.06;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint+' ≈ '+correctAnswers[cur].toFixed(2));
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 6: Босс §7 === */
(function(){
const tasks=[
{q:'$R_1=5$, $R_2=3$, $d=10$. Длина общей внешней касательной:',opts:['√(1004)=√96≈9.8','√(10064)=6','√(10016)=√84≈9.2'],cor:0,exp:'$(R_1-R_2)^2=(5-3)^2=4$. $\\ell=\\sqrt{100-4}=\\sqrt{96}\\approx9{,}8$.'},
{q:'При $R_1=R_2$ длина внешней касательной равна:',opts:['$d$','$0$','$\\sqrt{d^2-R^2}$'],cor:0,exp:'Если $R_1=R_2$, то $(R_1-R_2)^2=0$, значит $\\ell=\\sqrt{d^2}=d$.'},
{q:'Внутренняя касательная существует при условии:',opts:['$d>R_1+R_2$','$d=R_1+R_2$','$d>|R_1-R_2|$'],cor:0,exp:'Внутренняя касательная существует только когда окружности не пересекаются и не касаются, т.е. $d > R_1+R_2$.'},
{q:'$\\ell_{\\text{вн}}=15$, $d=17$, $R_1=R_2$. Найти $R_1$.', opts:['4','8','2'],cor:1,exp:'$R_1=R_2$: $\\ell=d=17\\neq15$. Нет, если $R_1 \\neq R_2$: $\\ell^2=d^2-(R_1-R_2)^2$, $(R_1-R_2)^2=289-225=64$, $R_1-R_2=8$. Дополнительных данных нет — ответ: разность = 8.'},
];
const cont=document.getElementById('p7-boss-tasks');
let html='';
tasks.forEach((t,i)=>{
html+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss7="p7-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss7=\\'p7-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p7-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p7-boss-${i}');bumpProgress('p7',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p7-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=html;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
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> равна градусной мере центрального угла, опирающегося на эту дугу.</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li>Полная окружность содержит <b>360°</b>.</li>
<li>Полуокружность (диаметр делит окружность) — <b>180°</b>.</li>
<li>Если центральный угол $\alpha$, то дуга $\smile AC = \alpha°$.</li>
</ul>
<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">
<circle cx="110" cy="85" r="60" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<circle cx="110" cy="85" r="3" fill="#0e7490"/>
<line x1="110" y1="85" x2="152" y2="33" stroke="#0891b2" stroke-width="2"/>
<line x1="110" y1="85" x2="161" y2="122" stroke="#0891b2" stroke-width="2"/>
<path d="M 137,52 A 60,60 0 0,1 161,122" fill="rgba(8,145,178,.18)" stroke="#0891b2" stroke-width="2.5"/>
<path d="M 118,76 A 12,12 0 0,1 124,96" fill="none" stroke="#f59e0b" stroke-width="2"/>
<text x="92" y="82" font-size="10" font-weight="700" fill="#0e7490">O</text>
<text x="156" y="27" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="165" y="130" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="128" y="88" font-size="10" fill="#b45309" font-weight="700">α</text>
<text x="170" y="75" font-size="10" fill="#0891b2" font-style="italic">дуга AC = α°</text>
</svg>
</div>`);
html+=makeCard('theory','Вписанный угол','8.2',`
<p><b>Определение.</b> <b>Вписанный угол</b> — угол, вершина которого лежит на окружности, а обе стороны являются хордами.</p>
<p style="margin-top:8px">Вписанный угол <b>опирается на дугу</b>, заключённую между его сторонами (дугу, не содержащую вершину угла).</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 260 170" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="110" cy="90" r="62" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<circle cx="110" cy="90" r="3" fill="#0e7490"/>
<circle cx="75" cy="37" r="4" fill="#10b981"/>
<circle cx="160" cy="50" r="4" fill="#10b981"/>
<circle cx="88" cy="148" r="4.5" fill="#dc2626"/>
<line x1="88" y1="148" x2="75" y2="37" stroke="#10b981" stroke-width="2.2"/>
<line x1="88" y1="148" x2="160" y2="50" stroke="#10b981" stroke-width="2.2"/>
<path d="M 75,37 A 62,62 0 0,1 160,50" fill="rgba(16,185,129,.22)" stroke="#10b981" stroke-width="2.5"/>
<text x="92" y="87" font-size="10" font-weight="700" fill="#0e7490">O</text>
<text x="62" y="32" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="164" y="46" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="74" y="160" font-size="12" font-weight="700" fill="#dc2626">B</text>
<text x="108" y="32" font-size="9" fill="#065f46" font-style="italic">дуга AC</text>
<text x="65" y="138" font-size="10" fill="#dc2626" font-weight="700">∠ABC</text>
</svg>
</div>`);
html+=makeCard('rule','Формула длины дуги','8.3',`
<p><b>Длина дуги</b> через центральный угол $\alpha$ (в градусах) и радиус $R$:</p>
$$\ell = \dfrac{\alpha}{360°} \cdot 2\pi R$$
<p style="margin-top:8px">Примеры: при $\alpha=90°$ дуга $= \dfrac{\pi R}{2}$; при $\alpha=180°$ дуга $= \pi R$.</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">
<circle cx="100" cy="82" r="58" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="100" cy="82" r="3" fill="#0e7490"/>
<line x1="100" y1="82" x2="100" y2="24" stroke="#64748b" stroke-width="1.5" stroke-dasharray="4,3"/>
<line x1="100" y1="82" x2="151" y2="104" stroke="#64748b" stroke-width="1.5" stroke-dasharray="4,3"/>
<path d="M 100,24 A 58,58 0 0,1 151,104" fill="rgba(239,68,68,.18)" stroke="#ef4444" stroke-width="3"/>
<path d="M 100,57 A 25,25 0 0,1 120,73" fill="none" stroke="#f59e0b" stroke-width="2"/>
<text x="88" y="79" font-size="10" font-weight="700" fill="#0e7490">O</text>
<text x="96" y="19" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="154" y="107" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="117" y="70" font-size="10" fill="#b45309" font-weight="700">α</text>
<text x="155" y="58" font-size="9" fill="#dc2626" font-weight="700"> = α/360·2πR</text>
<text x="28" y="82" font-size="9" fill="#64748b">R</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — слайдер центрального угла */
html+=`<div class="wg" id="p8-ca-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Центральный угол и дуга</div></div>
<div class="wg-help">Двигай слайдер — наблюдай, как изменяется центральный угол и подсвеченная дуга.</div>
<div class="sliders">
<label>Центральный угол $\alpha$ = <b id="p8-ca-val">90</b>°
<input type="range" min="1" max="359" value="90" id="p8-ca-sl">
</label>
</div>
<div id="p8-ca-svg" style="display:flex;justify-content:center"></div>
<div id="p8-ca-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.94rem;font-weight:600;text-align:center;background:var(--sec-acc-soft,#cffafe);color:var(--sec-acc-d,#0e7490)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — слайдер положения вершины вписанного угла */
html+=`<div class="wg" id="p8-ins-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Вписанный угол: вершина на окружности</div></div>
<div class="wg-help">Двигай слайдер — смотри, как меняется положение вершины $B$ вписанного угла $\angle ABC$.</div>
<div class="sliders">
<label>Положение $B$ (угол от оси) = <b id="p8-ins-val">210</b>°
<input type="range" min="181" max="359" value="210" id="p8-ins-sl">
</label>
</div>
<div id="p8-ins-svg" style="display:flex;justify-content:center"></div>
<div id="p8-ins-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.94rem;font-weight:600;text-align:center;background:var(--sec-acc-soft,#cffafe);color:var(--sec-acc-d,#0e7490)"></div>
</div>`;
/* ИНТЕРАКТИВ 3 — DnD-сортер */
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 id="p8-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:10px;margin-top:10px">
<div class="drop-box"><h5>Центральный</h5><div class="drop-items" id="p8-drop-ca-items"></div></div>
<div class="drop-box"><h5>Вписанный</h5><div class="drop-items" id="p8-drop-ins-items"></div></div>
<div class="drop-box"><h5>Ни тот ни другой</h5><div class="drop-items" id="p8-drop-none-items"></div></div>
</div>
<div class="actions"><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"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — калькулятор длины дуги */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Калькулятор: длина дуги</div></div>
<div class="wg-help">Введи радиус $R$ и центральный угол $\alpha$ — получи длину дуги по формуле $\ell = \dfrac{\alpha}{360} \cdot 2\pi R$.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">R = <input type="number" id="p8-cr" class="tinp" value="10" min="0.1" style="width:80px"></label>
<label style="font-size:.9rem">α (°) = <input type="number" id="p8-ca-inp" class="tinp" value="90" min="1" max="360" style="width:80px"></label>
<button class="btn primary" id="p8-arc-btn">Вычислить</button>
</div>
<div id="p8-arc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700"></div>
</div>`;
/* ИНТЕРАКТИВ 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:1rem;margin-bottom:10px;line-height:1.6"></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:130px">
<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>`;
/* ИНТЕРАКТИВ 6 — Босс §8 */
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 1: слайдер центрального угла === */
(function(){
const sl=document.getElementById('p8-ca-sl');
const valEl=document.getElementById('p8-ca-val');
const svgWrap=document.getElementById('p8-ca-svg');
const info=document.getElementById('p8-ca-info');
const R=70, cx=130, cy=100, W=260, H=200;
function draw(){
const alpha=+sl.value;
valEl.textContent=alpha;
const a1=-Math.PI/2;
const a2=a1+(alpha*Math.PI/180);
const x1=cx+R*Math.cos(a1), y1=cy+R*Math.sin(a1);
const x2=cx+R*Math.cos(a2), y2=cy+R*Math.sin(a2);
const large=alpha>180?1:0;
const angMid=a1+(alpha*Math.PI/360);
const labR=R+14;
const labX=cx+labR*Math.cos(angMid), labY=cy+labR*Math.sin(angMid);
const ax1=cx+18*Math.cos(a1), ay1=cy+18*Math.sin(a1);
const ax2=cx+18*Math.cos(a2), ay2=cy+18*Math.sin(a2);
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<path d="M ${x1} ${y1} A ${R} ${R} 0 ${large} 1 ${x2} ${y2} L ${cx} ${cy} Z" fill="rgba(8,145,178,.18)" stroke="none"/>
<path d="M ${x1} ${y1} A ${R} ${R} 0 ${large} 1 ${x2} ${y2}" fill="none" stroke="#0891b2" stroke-width="3.5"/>
<line x1="${cx}" y1="${cy}" x2="${x1}" y2="${y1}" stroke="#0e7490" stroke-width="2"/>
<line x1="${cx}" y1="${cy}" x2="${x2}" y2="${y2}" stroke="#0e7490" stroke-width="2"/>
<path d="M ${ax1} ${ay1} A 18 18 0 ${large} 1 ${ax2} ${ay2}" fill="none" stroke="#f59e0b" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0e7490"/>
<circle cx="${x1}" cy="${y1}" r="4" fill="#0284c7"/>
<circle cx="${x2}" cy="${y2}" r="4" fill="#0284c7"/>
<text x="${cx-10}" y="${cy+14}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="${x1+6*Math.cos(a1)}" y="${y1-8}" font-size="12" font-weight="700" fill="#0284c7">A</text>
<text x="${x2+(x2>cx?6:-14)}" y="${y2+(y2>cy?14:-4)}" font-size="12" font-weight="700" fill="#0284c7">C</text>
<text x="${labX-8}" y="${labY+4}" font-size="11" fill="#0891b2" font-weight="700">${alpha}°</text>
</svg>`;
info.textContent='Центральный угол AOC = '+alpha+'° → Дуга AC = '+alpha+'°';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: вписанный угол === */
(function(){
const sl=document.getElementById('p8-ins-sl');
const valEl=document.getElementById('p8-ins-val');
const svgWrap=document.getElementById('p8-ins-svg');
const info=document.getElementById('p8-ins-info');
const R=68, cx=130, cy=95, W=260, H=190;
const aA=(-80)*Math.PI/180;
const aC=(40)*Math.PI/180;
const arcDeg=((40-(-80))+360)%360; // arc from A to C going clockwise... let's use fixed A=80°, C=40°
function draw(){
const bDeg=+sl.value;
valEl.textContent=bDeg;
const aB=bDeg*Math.PI/180;
const Ax=cx+R*Math.cos(aA), Ay=cy+R*Math.sin(aA);
const Ccx=cx+R*Math.cos(aC), Ccy=cy+R*Math.sin(aC);
const Bx=cx+R*Math.cos(aB), By=cy+R*Math.sin(aB);
// arc A to C not through B (short arc, 120°)
const insAngle=(function(){
const v1x=Ax-Bx, v1y=Ay-By;
const v2x=Ccx-Bx, v2y=Ccy-By;
const dot=v1x*v2x+v1y*v2y;
const m1=Math.sqrt(v1x*v1x+v1y*v1y), m2=Math.sqrt(v2x*v2x+v2y*v2y);
return Math.round(Math.acos(Math.max(-1,Math.min(1,dot/(m1*m2))))*180/Math.PI);
})();
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<path d="M ${Ax} ${Ay} A ${R} ${R} 0 0 1 ${Ccx} ${Ccy}" fill="rgba(16,185,129,.22)" stroke="#10b981" stroke-width="3"/>
<line x1="${Bx}" y1="${By}" x2="${Ax}" y2="${Ay}" stroke="#dc2626" stroke-width="2.2"/>
<line x1="${Bx}" y1="${By}" x2="${Ccx}" y2="${Ccy}" stroke="#dc2626" stroke-width="2.2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0e7490"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#10b981"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#10b981"/>
<circle cx="${Bx}" cy="${By}" r="5" fill="#dc2626"/>
<text x="${Ax+(Ax>cx?7:-16)}" y="${Ay+(Ay>cy?14:-4)}" font-size="12" font-weight="700" fill="#0284c7">A</text>
<text x="${Ccx+(Ccx>cx?7:-16)}" y="${Ccy+(Ccy>cy?14:-4)}" font-size="12" font-weight="700" fill="#0284c7">C</text>
<text x="${Bx+(Bx>cx?7:-16)}" y="${By+(By>cy?16:-4)}" font-size="12" font-weight="700" fill="#dc2626">B</text>
<text x="${cx-8}" y="${cy+14}" font-size="10" font-weight="700" fill="#0e7490">O</text>
</svg>`;
info.textContent='Вписанный угол ∠ABC = '+insAngle+'° (вершина B на окружности, стороны — хорды BA и BC)';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 3: DnD-сортер === */
(function(){
const items=[
{label:'Вершина угла — центр окружности, стороны — радиусы',cat:'ca'},
{label:'Вершина на окружности, стороны — хорды',cat:'ins'},
{label:'Вершина внутри окружности, стороны — хорды',cat:'none'},
{label:'Угол ∠AOC, O — центр',cat:'ca'},
{label:'Угол ∠ABC, B на окружности',cat:'ins'},
{label:'Угол между двумя касательными из внешней точки',cat:'none'},
];
const pool=document.getElementById('p8-dnd-pool');
const boxes={ca:document.getElementById('p8-drop-ca-items'),ins:document.getElementById('p8-drop-ins-items'),none:document.getElementById('p8-drop-none-items')};
const fb=document.getElementById('p8-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p8-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p8-dnd');bumpProgress('p8',15);}
});
document.getElementById('p8-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 4: калькулятор дуги === */
(function(){
document.getElementById('p8-arc-btn').addEventListener('click',()=>{
const R=parseFloat(document.getElementById('p8-cr').value);
const alpha=parseFloat(document.getElementById('p8-ca-inp').value);
const out=document.getElementById('p8-arc-out');
out.style.display='block';
if(isNaN(R)||isNaN(alpha)||R<=0||alpha<=0||alpha>360){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите корректные значения (R > 0, 0 < α ≤ 360).';return;}
const L=(alpha/360)*2*Math.PI*R;
out.style.background='var(--sec-acc-soft,#cffafe)';out.style.color='var(--sec-acc-d,#0e7490)';
out.innerHTML=' = '+alpha+'/360 · 2π · '+R+' = <b>'+L.toFixed(4)+'</b> ≈ <b>'+L.toFixed(2)+'</b>';
});
})();
/* === INIT 5: тренажёр === */
(function(){
const tasks=[
{q:'Центральный угол $\\angle AOC = 72°$. Чему равна градусная мера дуги $AC$?',a:72,hint:'Дуга = центральный угол = 72°'},
{q:'Дуга равна $150°$. Найди центральный угол, опирающийся на эту дугу.',a:150,hint:'Центральный угол = градусная мера дуги = 150°'},
{q:'Радиус $R = 10$ см, центральный угол $\\alpha = 90°$. Найди длину дуги (округли до сотых).',a:15.71,hint:' = 90/360 · 2π · 10 = π·5 ≈ 15,71'},
{q:'Дуга $AC = 240°$. Найди дугу $CA$ (меньшую дугу).',a:120,hint:'Полная окружность 360°. Меньшая дуга = 360 240 = 120°'},
{q:'Радиус $R = 6$, длина дуги $\\ell = 2\\pi$. Найди центральный угол $\\alpha$ (в градусах).',a:60,hint:'2π = α/360 · 2π · 6 → α = 360 · 2π / (12π) = 60°'},
];
let cur=0, score=0;
const iEl=document.getElementById('p8-tr-i'), scEl=document.getElementById('p8-tr-score');
const taskEl=document.getElementById('p8-tr-task'), ansEl=document.getElementById('p8-tr-ans');
const goBtn=document.getElementById('p8-tr-go'), startBtn=document.getElementById('p8-tr-start');
const fb=document.getElementById('p8-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p8-trainer');bumpProgress('p8',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=parseFloat(ansEl.value.replace(',','.'));
const ok=Math.abs(ans-tasks[cur].a)<0.05;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 6: Босс §8 === */
(function(){
const tasks=[
{q:'Центральный угол $\\angle AOC = 140°$. Найди меньшую дугу $AC$.',
opts:['140°','70°','220°'],cor:0,
exp:'Дуга = центральный угол. Меньшая дуга $AC = 140°$.'},
{q:'Полуокружность имеет градусную меру:',
opts:['90°','180°','360°'],cor:1,
exp:'Полуокружность — половина окружности: $360°/2 = 180°$.'},
{q:'Радиус $R = 5$, угол $\\alpha = 120°$. Длина дуги:',
opts:['$\\dfrac{10\\pi}{3}$','$\\dfrac{5\\pi}{3}$','$5\\pi$'],cor:0,
exp:'$\\ell = \\dfrac{120}{360}\\cdot 2\\pi\\cdot 5 = \\dfrac{1}{3}\\cdot 10\\pi = \\dfrac{10\\pi}{3}$.'},
{q:'Дуга $AB = 80°$, дуга $BC = 130°$. Найди дугу $CA$ (большую).',
opts:['150°','50°','210°'],cor:0,
exp:'$360° - 80° - 130° = 150°$.'},
];
const cont=document.getElementById('p8-boss-tasks');
let bhtml='';
tasks.forEach((t,i)=>{
bhtml+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss8="p8-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss8=\\'p8-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p8-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p8-boss-${i}');bumpProgress('p8',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p8-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP9(){
const box=document.getElementById('p9-body');
let html='';
html+=makeCard('rule','Теорема о вписанном угле','9.1',`
<p><b>Теорема.</b> Вписанный угол равен половине центрального угла, опирающегося на ту же дугу.</p>
$$\angle ABC = \dfrac{1}{2}\,\angle AOC = \dfrac{1}{2}\,\smile AC$$
<p style="margin-top:8px">Здесь $O$ — центр, $A$, $C$ — точки на окружности, $B$ — другая точка на окружности.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 270 170" style="max-width:290px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="115" cy="92" r="65" fill="rgba(6,182,212,.07)" stroke="#06b6d4" stroke-width="2"/>
<circle cx="115" cy="92" r="3.5" fill="#0891b2"/>
<circle cx="70" cy="40" r="4" fill="#0891b2"/>
<circle cx="176" cy="52" r="4" fill="#0891b2"/>
<circle cx="82" cy="152" r="5" fill="#dc2626"/>
<line x1="115" y1="92" x2="70" y2="40" stroke="#06b6d4" stroke-width="1.8"/>
<line x1="115" y1="92" x2="176" y2="52" stroke="#06b6d4" stroke-width="1.8"/>
<line x1="82" y1="152" x2="70" y2="40" stroke="#dc2626" stroke-width="2"/>
<line x1="82" y1="152" x2="176" y2="52" stroke="#dc2626" stroke-width="2"/>
<path d="M 70,40 A 65,65 0 0,1 176,52" fill="rgba(6,182,212,.2)" stroke="#06b6d4" stroke-width="2.5"/>
<text x="104" y="88" font-size="10" font-weight="700" fill="#0891b2">O</text>
<text x="56" y="34" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="180" y="48" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="68" y="163" font-size="12" font-weight="700" fill="#dc2626">B</text>
<text x="186" y="105" font-size="10" fill="#0891b2">∠AOC</text>
<text x="186" y="120" font-size="10" fill="#dc2626">∠ABC = ½∠AOC</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство (три случая)','9.2',`
<p>Доказательство рассматривает три случая расположения центра $O$ относительно вписанного угла $\angle ABC$:</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li><b>Центр лежит на стороне угла</b> ($O$ — на $AB$): треугольник $OBC$ — равнобедренный, внешний угол при $B$ даёт $\angle AOC = 2\angle ABC$.</li>
<li><b>Центр внутри угла</b>: проводим диаметр через $B$, применяем случай 1 дважды и складываем.</li>
<li><b>Центр вне угла</b>: аналогично — вычитаем.</li>
</ol>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 270 150" style="max-width:290px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="110" cy="75" r="58" fill="rgba(6,182,212,.07)" stroke="#06b6d4" stroke-width="2"/>
<circle cx="110" cy="75" r="3" fill="#0891b2"/>
<circle cx="110" cy="17" r="4" fill="#dc2626"/>
<circle cx="56" cy="107" r="4" fill="#0284c7"/>
<circle cx="168" cy="107" r="4" fill="#0284c7"/>
<line x1="56" y1="107" x2="110" y2="17" stroke="#0284c7" stroke-width="2"/>
<line x1="168" y1="107" x2="110" y2="17" stroke="#0284c7" stroke-width="2"/>
<line x1="110" y1="75" x2="56" y2="107" stroke="#64748b" stroke-width="1.4" stroke-dasharray="4,3"/>
<line x1="110" y1="75" x2="168" y2="107" stroke="#64748b" stroke-width="1.4" stroke-dasharray="4,3"/>
<line x1="110" y1="17" x2="110" y2="133" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="3,3"/>
<text x="100" y="72" font-size="10" font-weight="700" fill="#0891b2">O</text>
<text x="108" y="11" font-size="11" font-weight="700" fill="#dc2626">B</text>
<text x="40" y="112" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="172" y="112" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="115" y="128" font-size="9" fill="#b45309">диаметр</text>
</svg>
</div>`);
html+=makeCard('example','Применение теоремы','9.3',`
<p><b>Задача.</b> Центральный угол $\angle AOC = 110°$. Найди вписанный угол $\angle ABC$, опирающийся на ту же дугу.</p>
<p style="margin-top:8px"><b>Решение.</b> По теореме: $\angle ABC = \dfrac{1}{2} \cdot 110° = 55°$.</p>
<p style="margin-top:6px"><b>Задача 2.</b> Вписанный угол $\angle ABC = 38°$. Найди центральный угол.</p>
<p style="margin-top:6px"><b>Решение.</b> $\angle AOC = 2 \cdot 38° = 76°$.</p>`);
/* ИНТЕРАКТИВ 1 — слайдер с обоими углами */
html+=`<div class="wg" id="p9-dual-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Центральный и вписанный угол на одной дуге</div></div>
<div class="wg-help">Двигай слайдер — наблюдай: вписанный угол всегда равен половине центрального.</div>
<div class="sliders">
<label>Центральный угол $\alpha$ = <b id="p9-alpha-val">100</b>°
<input type="range" min="10" max="340" value="100" id="p9-alpha-sl">
</label>
</div>
<div id="p9-dual-svg" style="display:flex;justify-content:center"></div>
<div id="p9-dual-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:var(--sec-acc-soft,#a5f3fc);color:var(--sec-acc-d,#0891b2)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p9-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство (случай: O на стороне угла)</div></div>
<div class="wg-help">Нажимай «Далее» — каждый шаг раскрывает ключевую идею доказательства.</div>
<div id="p9-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p9-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.94rem;line-height:1.65;margin-bottom:10px;min-height:64px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p9-proof-next">Далее</button>
<button class="btn" id="p9-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: центральный ↔ вписанный</div></div>
<div class="wg-help">Введи один из углов — получи второй.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">Центральный (°): <input type="number" id="p9-cinp" class="tinp" value="80" min="1" max="360" style="width:90px"></label>
<button class="btn primary" id="p9-c2i-btn">→ вписанный</button>
<label style="font-size:.9rem">Вписанный (°): <input type="number" id="p9-iinp" class="tinp" value="40" min="1" max="180" style="width:90px"></label>
<button class="btn primary" id="p9-i2c-btn">→ центральный</button>
</div>
<div id="p9-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — DnD верно/неверно */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Верно или неверно?</div></div>
<div class="wg-help">Рассортируй утверждения о вписанном угле.</div>
<div id="p9-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">
<div class="drop-box"><h5>Верно</h5><div class="drop-items" id="p9-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p9-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p9-dnd-check">Проверить</button><button class="btn" id="p9-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p9-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Тренажёр §9</div></div>
<div class="wg-help">5 задач на свойство вписанного угла.</div>
<div class="score-display"><span>Задача <b id="p9-tr-i">1</b> / 5</span><span>Очки: <b id="p9-tr-score">0</b></span></div>
<div id="p9-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1rem;margin-bottom:10px;line-height:1.6"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p9-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p9-tr-go">Проверить</button>
<button class="btn" id="p9-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p9-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §9 */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §9</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p9-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p9-read');bumpProgress('p9',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §9 (+10 XP)
</button>
</div>`;
html+=secNav('p8','p10');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдер обоих углов === */
(function(){
const sl=document.getElementById('p9-alpha-sl');
const valEl=document.getElementById('p9-alpha-val');
const svgWrap=document.getElementById('p9-dual-svg');
const info=document.getElementById('p9-dual-info');
const R=68, cx=130, cy=95, W=260, H=190;
function draw(){
const alpha=+sl.value;
valEl.textContent=alpha;
const beta=alpha/2;
const a1=(-100)*Math.PI/180;
const a2=a1+(alpha*Math.PI/180);
const Ax=cx+R*Math.cos(a1), Ay=cy+R*Math.sin(a1);
const Ccx=cx+R*Math.cos(a2), Ccy=cy+R*Math.sin(a2);
const aBmid=a2+((2*Math.PI-(alpha*Math.PI/180))/2);
const Bx=cx+R*Math.cos(aBmid), By=cy+R*Math.sin(aBmid);
const large=alpha>180?1:0;
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(6,182,212,.07)" stroke="#06b6d4" stroke-width="2"/>
<path d="M ${Ax} ${Ay} A ${R} ${R} 0 ${large} 1 ${Ccx} ${Ccy}" fill="rgba(6,182,212,.2)" stroke="#06b6d4" stroke-width="3"/>
<line x1="${cx}" y1="${cy}" x2="${Ax}" y2="${Ay}" stroke="#0284c7" stroke-width="2"/>
<line x1="${cx}" y1="${cy}" x2="${Ccx}" y2="${Ccy}" stroke="#0284c7" stroke-width="2"/>
<line x1="${Bx}" y1="${By}" x2="${Ax}" y2="${Ay}" stroke="#dc2626" stroke-width="2.2"/>
<line x1="${Bx}" y1="${By}" x2="${Ccx}" y2="${Ccy}" stroke="#dc2626" stroke-width="2.2"/>
<circle cx="${cx}" cy="${cy}" r="3.5" fill="#0891b2"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#0284c7"/>
<circle cx="${Bx}" cy="${By}" r="5" fill="#dc2626"/>
<text x="${cx-12}" y="${cy+14}" font-size="10" font-weight="700" fill="#0891b2">O</text>
<text x="${Ax+(Ax>cx?7:-16)}" y="${Ay+(Ay>cy?15:-4)}" font-size="12" font-weight="700" fill="#0284c7">A</text>
<text x="${Ccx+(Ccx>cx?7:-16)}" y="${Ccy+(Ccy>cy?15:-4)}" font-size="12" font-weight="700" fill="#0284c7">C</text>
<text x="${Bx+(Bx>cx?7:-16)}" y="${By+(By>cy?16:-4)}" font-size="12" font-weight="700" fill="#dc2626">B</text>
<text x="${(cx+(cx+cx)/2)/1.5}" y="${cy-R-10}" text-anchor="middle" font-size="10" fill="#0284c7">∠AOC=${alpha}°</text>
<text x="${cx+R+5}" y="${cy+20}" font-size="10" fill="#dc2626">∠ABC=${Math.round(beta)}°</text>
</svg>`;
info.textContent='Центральный ∠AOC = '+alpha+'° → Вписанный ∠ABC = '+Math.round(beta)+'° (= '+alpha+'°/2)';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=58, cx=115, cy=80, W=260, H=165;
const aBval=(-90)*Math.PI/180;
const Bx=cx+R*Math.cos(aBval), By=cy+R*Math.sin(aBval);
const Ax=cx-R, Ay=cy;
const Ccx=cx+R*Math.cos(30*Math.PI/180), Ccy=cy+R*Math.sin(30*Math.PI/180);
const steps=[
{text:'<b>Дано:</b> окружность с центром $O$. Вершина вписанного угла $B$ лежит так, что $O$ лежит на $AB$. Угол $\\angle ABC$ — вписанный, $\\angle AOC$ — центральный. Нужно доказать: $\\angle ABC = \\dfrac{1}{2}\\angle AOC$.'},
{text:'<b>Шаг 1.</b> Соединим $O$ с $B$. Так как $OB = OC = R$ (радиусы), треугольник $OBC$ — равнобедренный. Поэтому $\\angle OBC = \\angle OCB$.'},
{text:'<b>Шаг 2.</b> Угол $\\angle AOC$ — внешний угол треугольника $OBC$ при вершине $O$. По теореме о внешнем угле: $\\angle AOC = \\angle OBC + \\angle OCB = 2\\angle OBC$.'},
{text:'<b>Шаг 3.</b> Следовательно, $\\angle OBC = \\dfrac{1}{2}\\angle AOC$. Но $\\angle OBC = \\angle ABC$ (т.к. $O$ лежит на луче $AB$). Значит, $\\angle ABC = \\dfrac{1}{2}\\angle AOC$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p9-proof-svg'), txtEl=document.getElementById('p9-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<line x1="${cx}" y1="${cy}" x2="${Bx}" y2="${By}" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="4,3"/>`;
ex+=`<text x="${(cx+Bx)/2+6}" y="${(cy+By)/2}" font-size="9" fill="#b45309">OB=R</text>`;
ex+=`<line x1="${cx}" y1="${cy}" x2="${Ccx}" y2="${Ccy}" stroke="#0891b2" stroke-width="1.8"/>`;
ex+=`<text x="${cx+R*Math.cos(15*Math.PI/180)+6}" y="${cy+R*Math.sin(15*Math.PI/180)}" font-size="9" fill="#0284c7">OC=R</text>`;
}
if(step>=2){
ex+=`<text x="${cx+8}" y="${cy-12}" font-size="9" fill="#dc2626">∠AOC = внеш. угол △OBC</text>`;
}
svgEl.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(6,182,212,.07)" stroke="#06b6d4" stroke-width="2"/>
<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2"/>
<line x1="${Bx}" y1="${By}" x2="${Ccx}" y2="${Ccy}" stroke="#dc2626" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0891b2"/>
<circle cx="${Bx}" cy="${By}" r="4.5" fill="#dc2626"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#0284c7"/>
<text x="${cx-12}" y="${cy+13}" font-size="10" font-weight="700" fill="#0891b2">O</text>
<text x="${Bx-4}" y="${By-8}" font-size="11" font-weight="700" fill="#dc2626">B</text>
<text x="${Ax-16}" y="${Ay+4}" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="${Ccx+6}" y="${Ccy+4}" font-size="11" font-weight="700" fill="#0284c7">C</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p9-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p9-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p9-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p9-c2i-btn').addEventListener('click',()=>{
const v=parseFloat(document.getElementById('p9-cinp').value);
const out=document.getElementById('p9-calc-out');
out.style.display='block';
if(isNaN(v)||v<=0||v>360){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите угол от 1 до 360.';return;}
out.style.background='var(--sec-acc-soft,#a5f3fc)';out.style.color='var(--sec-acc-d,#0891b2)';
out.textContent='Центральный '+v+'° → Вписанный = '+v+'/2 = '+(v/2)+'°';
});
document.getElementById('p9-i2c-btn').addEventListener('click',()=>{
const v=parseFloat(document.getElementById('p9-iinp').value);
const out=document.getElementById('p9-calc-out');
out.style.display='block';
if(isNaN(v)||v<=0||v>180){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите вписанный угол от 1 до 180.';return;}
out.style.background='var(--sec-acc-soft,#a5f3fc)';out.style.color='var(--sec-acc-d,#0891b2)';
out.textContent='Вписанный '+v+'° → Центральный = 2·'+v+' = '+(2*v)+'°';
});
})();
/* === INIT 4: DnD верно/неверно === */
(function(){
const items=[
{label:'Вписанный угол = ½ центрального на той же дуге',cat:'true'},
{label:'Вписанный угол = центральному углу',cat:'false'},
{label:'Центральный угол = 2 · вписанного на той же дуге',cat:'true'},
{label:'Вписанный угол всегда тупой',cat:'false'},
{label:'Дуга 100° → вписанный угол 50°',cat:'true'},
{label:'Вписанный угол может быть больше 180°',cat:'false'},
];
const pool=document.getElementById('p9-dnd-pool');
const boxes={true:document.getElementById('p9-drop-true-items'),false:document.getElementById('p9-drop-false-items')};
const fb=document.getElementById('p9-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p9-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p9-dnd');bumpProgress('p9',15);}
});
document.getElementById('p9-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 5: тренажёр === */
(function(){
const tasks=[
{q:'Центральный угол $\\angle AOC = 80°$. Найди вписанный угол $\\angle ABC$.',a:40,hint:'∠ABC = 80°/2 = 40°'},
{q:'Вписанный угол $\\angle ABC = 65°$. Найди центральный угол.',a:130,hint:'∠AOC = 2·65° = 130°'},
{q:'Дуга $AC = 200°$. Найди вписанный угол, опирающийся на эту дугу.',a:100,hint:'∠ABC = 200°/2 = 100°'},
{q:'Вписанный угол $= 45°$. Найди дугу, на которую он опирается.',a:90,hint:'Дуга = 2·45° = 90°'},
{q:'Центральный угол $= 176°$. Найди вписанный угол (в градусах).',a:88,hint:'∠вп = 176°/2 = 88°'},
];
let cur=0, score=0;
const iEl=document.getElementById('p9-tr-i'), scEl=document.getElementById('p9-tr-score');
const taskEl=document.getElementById('p9-tr-task'), ansEl=document.getElementById('p9-tr-ans');
const goBtn=document.getElementById('p9-tr-go'), startBtn=document.getElementById('p9-tr-start');
const fb=document.getElementById('p9-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p9-trainer');bumpProgress('p9',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=parseFloat(ansEl.value.replace(',','.'));
const ok=Math.abs(ans-tasks[cur].a)<0.5;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 6: Босс §9 === */
(function(){
const tasks=[
{q:'Вписанный угол $\\angle ABC = 55°$. Центральный угол на той же дуге:',
opts:['110°','55°','27,5°'],cor:0,
exp:'$\\angle AOC = 2 \\cdot 55° = 110°$.'},
{q:'Центральный угол равен 180° (диаметр). Вписанный угол равен:',
opts:['180°','90°','45°'],cor:1,
exp:'$\\angle вп = 180°/2 = 90°$. Это теорема Фалеса (§11).'},
{q:'Дуга $AC = 130°$, вершина $B$ на другой дуге. Угол $\\angle ABC$:',
opts:['65°','130°','260°'],cor:0,
exp:'$\\angle ABC = \\dfrac{1}{2} \\cdot 130° = 65°$.'},
{q:'Вписанный угол $\\angle ABC = 90°$. Найди дугу $AC$.',
opts:['180°','90°','270°'],cor:0,
exp:'Дуга $= 2 \\cdot 90° = 180°$ — полуокружность, то есть $AC$ — диаметр.'},
];
const cont=document.getElementById('p9-boss-tasks');
let bhtml='';
tasks.forEach((t,i)=>{
bhtml+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss9="p9-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss9=\\'p9-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p9-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p9-boss-${i}');bumpProgress('p9',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p9-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP10(){
const box=document.getElementById('p10-body');
let html='';
html+=makeCard('rule','Следствие: вписанные углы на одной дуге','10.1',`
<p><b>Следствие из теоремы §9.</b> Все вписанные углы, опирающиеся на одну и ту же дугу, равны между собой.</p>
$$\angle AB_1C = \angle AB_2C = \angle AB_3C = \dfrac{1}{2}\,\smile AC$$
<p style="margin-top:8px"><b>Почему?</b> Каждый вписанный угол равен половине центрального, опирающегося на дугу $AC$. Центральный угол для данной дуги один и тот же — поэтому все вписанные углы равны.</p>
<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">
<circle cx="120" cy="88" r="66" fill="rgba(2,132,199,.07)" stroke="#0284c7" stroke-width="2"/>
<circle cx="120" cy="88" r="3" fill="#0369a1"/>
<circle cx="68" cy="46" r="4" fill="#0284c7"/>
<circle cx="178" cy="54" r="4" fill="#0284c7"/>
<circle cx="72" cy="140" r="4.5" fill="#dc2626"/>
<circle cx="120" cy="154" r="4.5" fill="#10b981"/>
<circle cx="166" cy="142" r="4.5" fill="#7c3aed"/>
<line x1="72" y1="140" x2="68" y2="46" stroke="#dc2626" stroke-width="1.8"/>
<line x1="72" y1="140" x2="178" y2="54" stroke="#dc2626" stroke-width="1.8"/>
<line x1="120" y1="154" x2="68" y2="46" stroke="#10b981" stroke-width="1.8"/>
<line x1="120" y1="154" x2="178" y2="54" stroke="#10b981" stroke-width="1.8"/>
<line x1="166" y1="142" x2="68" y2="46" stroke="#7c3aed" stroke-width="1.8"/>
<line x1="166" y1="142" x2="178" y2="54" stroke="#7c3aed" stroke-width="1.8"/>
<path d="M 68,46 A 66,66 0 0,1 178,54" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="3"/>
<text x="55" y="40" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="182" y="50" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="56" y="152" font-size="10" font-weight="700" fill="#dc2626">B₁</text>
<text x="116" y="168" font-size="10" font-weight="700" fill="#10b981">B₂</text>
<text x="170" y="156" font-size="10" font-weight="700" fill="#7c3aed">B₃</text>
<text x="109" y="84" font-size="9" font-weight="700" fill="#0369a1">O</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство следствия','10.2',`
<p>Пусть $B_1$ и $B_2$ — две точки на окружности, лежащие на одной стороне от хорды $AC$. Тогда:</p>
<ul style="margin-left:18px;margin-top:6px;line-height:1.9">
<li>По теореме §9: $\angle AB_1C = \dfrac{1}{2}\angle AOC$</li>
<li>По теореме §9: $\angle AB_2C = \dfrac{1}{2}\angle AOC$</li>
<li>Следовательно: $\angle AB_1C = \angle AB_2C$. <b>ч.т.д.</b></li>
</ul>`);
html+=makeCard('example','Пример','10.3',`
<p><b>Задача.</b> Дуга $AC = 80°$. Три точки $B_1, B_2, B_3$ лежат на большей дуге. Найди все три вписанных угла.</p>
<p style="margin-top:8px"><b>Решение.</b> Каждый вписанный угол = $80°/2 = 40°$. Все три угла равны $40°$.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 240 140" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="100" cy="72" r="58" fill="rgba(2,132,199,.07)" stroke="#0284c7" stroke-width="2"/>
<circle cx="100" cy="72" r="3" fill="#0369a1"/>
<circle cx="54" cy="46" r="3.5" fill="#0284c7"/>
<circle cx="152" cy="50" r="3.5" fill="#0284c7"/>
<circle cx="62" cy="122" r="4" fill="#dc2626"/>
<circle cx="100" cy="130" r="4" fill="#10b981"/>
<circle cx="138" cy="122" r="4" fill="#7c3aed"/>
<path d="M 54,46 A 58,58 0 0,1 152,50" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="2.5"/>
<line x1="62" y1="122" x2="54" y2="46" stroke="#dc2626" stroke-width="1.6"/>
<line x1="62" y1="122" x2="152" y2="50" stroke="#dc2626" stroke-width="1.6"/>
<line x1="100" y1="130" x2="54" y2="46" stroke="#10b981" stroke-width="1.6"/>
<line x1="100" y1="130" x2="152" y2="50" stroke="#10b981" stroke-width="1.6"/>
<line x1="138" y1="122" x2="54" y2="46" stroke="#7c3aed" stroke-width="1.6"/>
<line x1="138" y1="122" x2="152" y2="50" stroke="#7c3aed" stroke-width="1.6"/>
<text x="42" y="40" font-size="10" font-weight="700" fill="#0284c7">A</text>
<text x="155" y="46" font-size="10" font-weight="700" fill="#0284c7">C</text>
<text x="48" y="132" font-size="9" fill="#dc2626">B₁=40°</text>
<text x="93" y="142" font-size="9" fill="#10b981">B₂=40°</text>
<text x="131" y="132" font-size="9" fill="#7c3aed">B₃=40°</text>
<text x="90" y="68" font-size="9" fill="#0369a1">O</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — несколько вершин на одной дуге */
html+=`<div class="wg" id="p10-multi-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Несколько вписанных углов на одной дуге</div></div>
<div class="wg-help">Двигай слайдер — дуга $AC$ меняется. Углы $B_1, B_2, B_3$ остаются равными между собой.</div>
<div class="sliders">
<label>Дуга $AC$ = <b id="p10-arc-val">80</b>°
<input type="range" min="10" max="160" value="80" id="p10-arc-sl">
</label>
</div>
<div id="p10-multi-svg" style="display:flex;justify-content:center"></div>
<div id="p10-multi-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.94rem;font-weight:600;text-align:center;background:var(--sec-acc-soft,#e0f2fe);color:var(--sec-acc-d,#0369a1)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p10-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="p10-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p10-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.94rem;line-height:1.65;margin-bottom:10px;min-height:64px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p10-proof-next">Далее</button>
<button class="btn" id="p10-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор проверки равенства */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: вписанные углы по дуге</div></div>
<div class="wg-help">Введи градусную меру дуги $AC$ — получи величину всех вписанных углов на ней.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">Дуга AC (°): <input type="number" id="p10-darc" class="tinp" value="100" min="1" max="358" style="width:90px"></label>
<button class="btn primary" id="p10-calc-btn">Вычислить</button>
</div>
<div id="p10-calc-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — DnD: равные углы */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">DnD: равные вписанные углы</div></div>
<div class="wg-help">Перетащи утверждения: «Равны» или «Не обязательно равны».</div>
<div id="p10-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">
<div class="drop-box"><h5>Равны</h5><div class="drop-items" id="p10-drop-eq-items"></div></div>
<div class="drop-box"><h5>Не обязательно равны</h5><div class="drop-items" id="p10-drop-ne-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p10-dnd-check">Проверить</button><button class="btn" id="p10-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p10-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Тренажёр §10</div></div>
<div class="wg-help">5 задач на равенство вписанных углов одной дуги.</div>
<div class="score-display"><span>Задача <b id="p10-tr-i">1</b> / 5</span><span>Очки: <b id="p10-tr-score">0</b></span></div>
<div id="p10-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1rem;margin-bottom:10px;line-height:1.6"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p10-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p10-tr-go">Проверить</button>
<button class="btn" id="p10-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p10-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §10 */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §10</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p10-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p10-read');bumpProgress('p10',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §10 (+10 XP)
</button>
</div>`;
html+=secNav('p9','p11');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: многие вершины === */
(function(){
const sl=document.getElementById('p10-arc-sl');
const valEl=document.getElementById('p10-arc-val');
const svgWrap=document.getElementById('p10-multi-svg');
const info=document.getElementById('p10-multi-info');
const R=68, cx=130, cy=88, W=260, H=178;
function draw(){
const arcDeg=+sl.value;
valEl.textContent=arcDeg;
const ins=arcDeg/2;
const aA=(-60-arcDeg/2)*Math.PI/180;
const aC=(-60+arcDeg/2)*Math.PI/180;
const Ax=cx+R*Math.cos(aA), Ay=cy+R*Math.sin(aA);
const Ccx=cx+R*Math.cos(aC), Ccy=cy+R*Math.sin(aC);
// three B points on opposite arc
const bAngles=[130,180,230];
const bColors=['#dc2626','#10b981','#7c3aed'];
let bLines='', bDots='', bLabels='';
bAngles.forEach((bd,k)=>{
const bRad=bd*Math.PI/180;
const Bx=cx+R*Math.cos(bRad), By=cy+R*Math.sin(bRad);
bLines+=`<line x1="${Bx}" y1="${By}" x2="${Ax}" y2="${Ay}" stroke="${bColors[k]}" stroke-width="1.8"/>`;
bLines+=`<line x1="${Bx}" y1="${By}" x2="${Ccx}" y2="${Ccy}" stroke="${bColors[k]}" stroke-width="1.8"/>`;
bDots+=`<circle cx="${Bx}" cy="${By}" r="4.5" fill="${bColors[k]}"/>`;
const lx=Bx+(Bx>cx?8:-16), ly=By+(By>cy?16:-4);
bLabels+=`<text x="${lx}" y="${ly}" font-size="10" font-weight="700" fill="${bColors[k]}">B${k+1}</text>`;
bLabels+=`<text x="${lx}" y="${ly+12}" font-size="9" fill="${bColors[k]}">${Math.round(ins)}°</text>`;
});
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(2,132,199,.07)" stroke="#0284c7" stroke-width="2"/>
<path d="M ${Ax} ${Ay} A ${R} ${R} 0 0 1 ${Ccx} ${Ccy}" fill="rgba(2,132,199,.22)" stroke="#0284c7" stroke-width="3"/>
${bLines}
<circle cx="${cx}" cy="${cy}" r="3" fill="#0369a1"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#0284c7"/>
${bDots}
<text x="${Ax+(Ax>cx?7:-16)}" y="${Ay+(Ay>cy?15:-4)}" font-size="12" font-weight="700" fill="#0284c7">A</text>
<text x="${Ccx+(Ccx>cx?7:-16)}" y="${Ccy+(Ccy>cy?15:-4)}" font-size="12" font-weight="700" fill="#0284c7">C</text>
<text x="${cx-10}" y="${cy+14}" font-size="9" fill="#0369a1">O</text>
${bLabels}
</svg>`;
info.textContent='Дуга AC = '+arcDeg+'° → Все вписанные углы = '+Math.round(ins)+'° (равны!)';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: доказательство по шагам === */
(function(){
const R=55, cx=110, cy=78, W=220, H=160;
const aA=(-80)*Math.PI/180, aC=(20)*Math.PI/180;
const Ax=cx+R*Math.cos(aA), Ay=cy+R*Math.sin(aA);
const Ccx=cx+R*Math.cos(aC), Ccy=cy+R*Math.sin(aC);
const aB1=150*Math.PI/180, aB2=200*Math.PI/180;
const B1x=cx+R*Math.cos(aB1), B1y=cy+R*Math.sin(aB1);
const B2x=cx+R*Math.cos(aB2), B2y=cy+R*Math.sin(aB2);
const steps=[
{text:'<b>Дано:</b> Дуга $AC$ фиксирована. Точки $B_1$ и $B_2$ лежат на дуге, не содержащей $AC$. Нужно доказать: $\\angle AB_1C = \\angle AB_2C$.'},
{text:'<b>Шаг 1.</b> По теореме §9: $\\angle AB_1C = \\dfrac{1}{2}\\angle AOC$ (центральный угол на дуге $AC$).'},
{text:'<b>Шаг 2.</b> Аналогично: $\\angle AB_2C = \\dfrac{1}{2}\\angle AOC$.'},
{text:'<b>Шаг 3.</b> Правые части равны, значит $\\angle AB_1C = \\angle AB_2C$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p10-proof-svg'), txtEl=document.getElementById('p10-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<line x1="${B1x}" y1="${B1y}" x2="${Ax}" y2="${Ay}" stroke="#dc2626" stroke-width="2"/>`;
ex+=`<line x1="${B1x}" y1="${B1y}" x2="${Ccx}" y2="${Ccy}" stroke="#dc2626" stroke-width="2"/>`;
ex+=`<text x="${B1x-22}" y="${B1y+14}" font-size="9" fill="#dc2626">∠B₁=${Math.round(50)}°</text>`;
}
if(step>=2){
ex+=`<line x1="${B2x}" y1="${B2y}" x2="${Ax}" y2="${Ay}" stroke="#10b981" stroke-width="2"/>`;
ex+=`<line x1="${B2x}" y1="${B2y}" x2="${Ccx}" y2="${Ccy}" stroke="#10b981" stroke-width="2"/>`;
ex+=`<text x="${B2x-22}" y="${B2y+14}" font-size="9" fill="#10b981">∠B₂=${Math.round(50)}°</text>`;
}
if(step>=1){
ex+=`<line x1="${cx}" y1="${cy}" x2="${Ax}" y2="${Ay}" stroke="#0284c7" stroke-width="1.5" stroke-dasharray="3,2"/>`;
ex+=`<line x1="${cx}" y1="${cy}" x2="${Ccx}" y2="${Ccy}" stroke="#0284c7" stroke-width="1.5" stroke-dasharray="3,2"/>`;
ex+=`<text x="${cx+5}" y="${cy-12}" font-size="9" fill="#0284c7">∠AOC</text>`;
}
svgEl.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(2,132,199,.07)" stroke="#0284c7" stroke-width="2"/>
<path d="M ${Ax} ${Ay} A ${R} ${R} 0 0 1 ${Ccx} ${Ccy}" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2.5"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0369a1"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#0284c7"/>
<circle cx="${B1x}" cy="${B1y}" r="4.5" fill="#dc2626"/>
<circle cx="${B2x}" cy="${B2y}" r="4.5" fill="#10b981"/>
<text x="${cx-10}" y="${cy+13}" font-size="9" font-weight="700" fill="#0369a1">O</text>
<text x="${Ax+(Ax>cx?7:-16)}" y="${Ay+(Ay>cy?15:-4)}" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="${Ccx+(Ccx>cx?7:-16)}" y="${Ccy+(Ccy>cy?15:-4)}" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="${B1x+(B1x>cx?7:-16)}" y="${B1y+(B1y>cy?-4:16)}" font-size="10" font-weight="700" fill="#dc2626">B₁</text>
<text x="${B2x+(B2x>cx?7:-16)}" y="${B2y+(B2y>cy?-4:16)}" font-size="10" font-weight="700" fill="#10b981">B₂</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p10-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p10-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p10-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p10-calc-btn').addEventListener('click',()=>{
const arc=parseFloat(document.getElementById('p10-darc').value);
const out=document.getElementById('p10-calc-out');
out.style.display='block';
if(isNaN(arc)||arc<=0||arc>=360){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите дугу от 1 до 358°.';return;}
out.style.background='var(--sec-acc-soft,#e0f2fe)';out.style.color='var(--sec-acc-d,#0369a1)';
const ins=arc/2;
out.textContent='Дуга AC = '+arc+'° → Все вписанные углы на этой дуге = '+ins+'°';
});
})();
/* === INIT 4: DnD === */
(function(){
const items=[
{label:'∠AB₁C и ∠AB₂C, оба B на большей дуге AC',cat:'eq'},
{label:'∠AB₁C и ∠AB₂C, B₁ и B₂ по разные стороны AC',cat:'ne'},
{label:'Все вписанные углы на одной полуокружности',cat:'eq'},
{label:'Вписанные углы на разных дугах одной хорды',cat:'ne'},
{label:'∠AB₁C = ∠AB₃C, все три на одной дуге AC',cat:'eq'},
];
const pool=document.getElementById('p10-dnd-pool');
const boxes={eq:document.getElementById('p10-drop-eq-items'),ne:document.getElementById('p10-drop-ne-items')};
const fb=document.getElementById('p10-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p10-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p10-dnd');bumpProgress('p10',15);}
});
document.getElementById('p10-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 5: тренажёр === */
(function(){
const tasks=[
{q:'Дуга $AC = 110°$. Три точки $B_1, B_2, B_3$ на другой дуге. Чему равен $\\angle AB_1C$?',a:55,hint:'∠AB₁C = 110°/2 = 55°'},
{q:'Вписанный угол $\\angle AB_1C = 35°$. Чему равен $\\angle AB_2C$, если $B_2$ на той же дуге?',a:35,hint:'Все вписанные углы на одной дуге равны, значит ∠AB₂C = 35°'},
{q:'Дуга $AC = 160°$. Найди все вписанные углы на другой дуге.',a:80,hint:'80° = 160°/2'},
{q:'Вписанный угол $= 70°$. Найди дугу, на которую он опирается.',a:140,hint:'Дуга = 2·70° = 140°'},
{q:'Дуга $AC = 90°$, $B_1$ и $B_2$ на большей дуге. Сумма $\\angle AB_1C + \\angle AB_2C = ?°$',a:90,hint:'Каждый = 45°, сумма = 90°'},
];
let cur=0, score=0;
const iEl=document.getElementById('p10-tr-i'), scEl=document.getElementById('p10-tr-score');
const taskEl=document.getElementById('p10-tr-task'), ansEl=document.getElementById('p10-tr-ans');
const goBtn=document.getElementById('p10-tr-go'), startBtn=document.getElementById('p10-tr-start');
const fb=document.getElementById('p10-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p10-trainer');bumpProgress('p10',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=parseFloat(ansEl.value.replace(',','.'));
const ok=Math.abs(ans-tasks[cur].a)<0.5;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 6: Босс §10 === */
(function(){
const tasks=[
{q:'Вписанные углы $\\angle AB_1C$ и $\\angle AB_2C$ опираются на одну дугу $AC = 120°$. Их сумма:',
opts:['120°','60°','240°'],cor:0,
exp:'Каждый = $60°$, сумма = $120°$.'},
{q:'Дуга $AC = 180°$ (диаметр). Все вписанные углы на другой полуокружности равны:',
opts:['90°','60°','45°'],cor:0,
exp:'$180°/2 = 90°$. Это следствие §11.'},
{q:'Точки $B_1$ и $B_2$ по разные стороны хорды $AC$. Их вписанные углы:',
opts:['Равны','В сумме дают 180°','Не связаны'],cor:1,
exp:'Вписанные углы $\\angle AB_1C$ (на меньшей дуге) и $\\angle AB_2C$ (на большей дуге) дополняют друг друга до $180°$.'},
{q:'Дуга $AC = 70°$. Сколько вписанных углов можно провести через $A$ и $C$ со значением $35°$?',
opts:['Один','Два','Бесконечно много'],cor:2,
exp:'Любая точка большей дуги даёт угол $35°$ — таких точек бесконечно много.'},
];
const cont=document.getElementById('p10-boss-tasks');
let bhtml='';
tasks.forEach((t,i)=>{
bhtml+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss10="p10-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss10=\\'p10-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p10-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p10-boss-${i}');bumpProgress('p10',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p10-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP11(){
const box=document.getElementById('p11-body');
let html='';
html+=makeCard('rule','Вписанный угол на диаметре','11.1',`
<p><b>Следствие (Теорема Фалеса).</b> Вписанный угол, опирающийся на диаметр, равен $90°$.</p>
$$AB \text{ — диаметр} \implies \angle ACB = 90°$$
<p style="margin-top:8px"><b>Почему?</b> Диаметр стягивает полуокружность $= 180°$. По теореме §9: вписанный угол $= 180°/2 = 90°$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 270 170" style="max-width:290px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="115" cy="90" r="62" fill="rgba(37,99,235,.07)" stroke="#2563eb" stroke-width="2"/>
<circle cx="115" cy="90" r="3" fill="#1d4ed8"/>
<line x1="53" y1="90" x2="177" y2="90" stroke="#1d4ed8" stroke-width="2.5"/>
<circle cx="53" cy="90" r="4.5" fill="#1d4ed8"/>
<circle cx="177" cy="90" r="4.5" fill="#1d4ed8"/>
<circle cx="100" cy="32" r="5" fill="#dc2626"/>
<line x1="100" y1="32" x2="53" y2="90" stroke="#dc2626" stroke-width="2.2"/>
<line x1="100" y1="32" x2="177" y2="90" stroke="#dc2626" stroke-width="2.2"/>
<polyline points="100,32 109,42 119,32" fill="none" stroke="#dc2626" stroke-width="2"/>
<text x="37" y="94" font-size="12" font-weight="700" fill="#1d4ed8">A</text>
<text x="181" y="94" font-size="12" font-weight="700" fill="#1d4ed8">B</text>
<text x="86" y="28" font-size="12" font-weight="700" fill="#dc2626">C</text>
<text x="104" y="87" font-size="10" font-weight="700" fill="#1d4ed8">O</text>
<text x="184" y="62" font-size="11" fill="#dc2626" font-weight="700">∠ACB = 90°</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство','11.2',`
<p>Пусть $AB$ — диаметр, $C$ — точка на окружности ($C \neq A, B$).</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li>Полуокружность $AC$ (меньшая): $\smile AB = 180°$ (диаметр).</li>
<li>По теореме §9: $\angle ACB = \dfrac{1}{2} \cdot 180° = 90°$.</li>
</ol>
<p style="margin-top:8px"><b>ч.т.д.</b></p>
<p style="margin-top:8px"><b>Следствие:</b> в прямоугольном треугольнике $ACB$ с прямым углом при $C$ гипотенуза $AB$ является диаметром описанной окружности.</p>`);
html+=makeCard('example','Применение','11.3',`
<p><b>Задача.</b> Диаметр $AB = 10$, $AC = 6$. Найди $BC$.</p>
<p style="margin-top:8px"><b>Решение.</b> $\angle ACB = 90°$ (вписанный угол на диаметре). По теореме Пифагора:</p>
$$BC = \sqrt{AB^2 - AC^2} = \sqrt{100 - 36} = \sqrt{64} = 8$$
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 220 140" style="max-width:240px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="95" cy="72" r="55" fill="rgba(37,99,235,.07)" stroke="#2563eb" stroke-width="1.8"/>
<circle cx="95" cy="72" r="3" fill="#1d4ed8"/>
<line x1="40" y1="72" x2="150" y2="72" stroke="#1d4ed8" stroke-width="2.5"/>
<circle cx="40" cy="72" r="4" fill="#1d4ed8"/>
<circle cx="150" cy="72" r="4" fill="#1d4ed8"/>
<circle cx="78" cy="20" r="4.5" fill="#dc2626"/>
<line x1="78" y1="20" x2="40" y2="72" stroke="#10b981" stroke-width="2.5"/>
<line x1="78" y1="20" x2="150" y2="72" stroke="#7c3aed" stroke-width="2.5"/>
<polyline points="78,20 87,30 97,21" fill="none" stroke="#dc2626" stroke-width="1.8"/>
<text x="26" y="76" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
<text x="154" y="76" font-size="11" font-weight="700" fill="#1d4ed8">B</text>
<text x="64" y="16" font-size="11" font-weight="700" fill="#dc2626">C</text>
<text x="48" y="50" font-size="10" fill="#10b981" font-weight="700">AC=6</text>
<text x="110" y="44" font-size="10" fill="#7c3aed" font-weight="700">BC=8</text>
<text x="80" y="90" font-size="10" fill="#1d4ed8">AB=10</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — слайдер положения C */
html+=`<div class="wg" id="p11-diam-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Вписанный угол на диаметре всегда 90°</div></div>
<div class="wg-help">Двигай слайдер — перемещай точку $C$ по окружности. Угол $\angle ACB$ всегда остаётся прямым!</div>
<div class="sliders">
<label>Положение $C$ = <b id="p11-c-val">100</b>°
<input type="range" min="10" max="170" value="100" id="p11-c-sl">
</label>
</div>
<div id="p11-diam-svg" style="display:flex;justify-content:center"></div>
<div id="p11-diam-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:var(--sec-acc-soft,#dbeafe);color:var(--sec-acc-d,#1d4ed8)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p11-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство — по шагам</div></div>
<div class="wg-help">Нажимай «Далее» для пошагового объяснения.</div>
<div id="p11-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p11-proof-text" style="padding:10px 14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:.94rem;line-height:1.65;margin-bottom:10px;min-height:64px"></div>
<div style="display:flex;gap:8px">
<button class="btn primary" id="p11-proof-next">Далее</button>
<button class="btn" id="p11-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор Пифагора */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: прямоугольный треугольник на окружности</div></div>
<div class="wg-help">Диаметр = гипотенуза. Введи диаметр $AB$ и один катет — найди второй.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">Диаметр AB: <input type="number" id="p11-diam" class="tinp" value="10" min="0.1" style="width:80px"></label>
<label style="font-size:.9rem">Катет AC: <input type="number" id="p11-leg" class="tinp" value="6" min="0.1" style="width:80px"></label>
<button class="btn primary" id="p11-pyth-btn">Найти BC</button>
</div>
<div id="p11-pyth-out" style="display:none;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700"></div>
</div>`;
/* ИНТЕРАКТИВ 4 — Тренажёр */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр §11</div></div>
<div class="wg-help">5 задач на вписанный угол на диаметре и теорему Пифагора.</div>
<div class="score-display"><span>Задача <b id="p11-tr-i">1</b> / 5</span><span>Очки: <b id="p11-tr-score">0</b></span></div>
<div id="p11-tr-task" style="padding:14px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;font-size:1rem;margin-bottom:10px;line-height:1.6"></div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" id="p11-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p11-tr-go">Проверить</button>
<button class="btn" id="p11-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p11-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — DnD верно/неверно */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Верно или неверно?</div></div>
<div class="wg-help">Рассортируй утверждения о вписанном угле на диаметре.</div>
<div id="p11-dnd-pool" class="dnd-pool"></div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-top:10px">
<div class="drop-box"><h5>Верно</h5><div class="drop-items" id="p11-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p11-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p11-dnd-check">Проверить</button><button class="btn" id="p11-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p11-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §11 */
html+=`<div class="wg" style="border-color:var(--sec-acc-d,var(--pri2))">
<div class="wg-header"><span class="wg-badge" style="background:var(--sec-acc-d,var(--pri2))">БОСС §11</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p11-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p11-read');bumpProgress('p11',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §11 (+10 XP)
</button>
</div>`;
html+=secNav('p10','p12');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдер положения C === */
(function(){
const sl=document.getElementById('p11-c-sl');
const valEl=document.getElementById('p11-c-val');
const svgWrap=document.getElementById('p11-diam-svg');
const info=document.getElementById('p11-diam-info');
const R=68, cx=130, cy=95, W=260, H=192;
const Ax=cx-R, Ay=cy;
const Bx=cx+R, By=cy;
function draw(){
const cDeg=+sl.value;
valEl.textContent=cDeg;
const cRad=cDeg*Math.PI/180;
const Ccx=cx+R*Math.cos(cRad-Math.PI/2), Ccy=cy+R*Math.sin(cRad-Math.PI/2);
// right angle marker at C
const u={x:(Ax-Ccx), y:(Ay-Ccy)};
const un=Math.sqrt(u.x*u.x+u.y*u.y);
const ux=u.x/un, uy=u.y/un;
const w={x:(Bx-Ccx), y:(By-Ccy)};
const wn=Math.sqrt(w.x*w.x+w.y*w.y);
const wx=w.x/wn, wy=w.y/wn;
const s=9;
const m1x=Ccx+s*ux, m1y=Ccy+s*uy;
const m2x=m1x+s*wx, m2y=m1y+s*wy;
const m3x=Ccx+s*wx, m3y=Ccy+s*wy;
svgWrap.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(37,99,235,.07)" stroke="#2563eb" stroke-width="2"/>
<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#1d4ed8" stroke-width="2.5"/>
<line x1="${Ccx}" y1="${Ccy}" x2="${Ax}" y2="${Ay}" stroke="#dc2626" stroke-width="2.2"/>
<line x1="${Ccx}" y1="${Ccy}" x2="${Bx}" y2="${By}" stroke="#dc2626" stroke-width="2.2"/>
<polyline points="${m1x},${m1y} ${m2x},${m2y} ${m3x},${m3y}" fill="none" stroke="#dc2626" stroke-width="1.8"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#1d4ed8"/>
<circle cx="${Ax}" cy="${Ay}" r="4.5" fill="#1d4ed8"/>
<circle cx="${Bx}" cy="${By}" r="4.5" fill="#1d4ed8"/>
<circle cx="${Ccx}" cy="${Ccy}" r="5" fill="#dc2626"/>
<text x="${Ax-18}" y="${Ay+4}" font-size="12" font-weight="700" fill="#1d4ed8">A</text>
<text x="${Bx+6}" y="${By+4}" font-size="12" font-weight="700" fill="#1d4ed8">B</text>
<text x="${Ccx+(Ccx>cx?8:-18)}" y="${Ccy+(Ccy>cy?16:-6)}" font-size="13" font-weight="700" fill="#dc2626">C</text>
<text x="${cx-8}" y="${cy+14}" font-size="10" font-weight="700" fill="#1d4ed8">O</text>
</svg>`;
info.textContent='Положение C = '+cDeg+'°. Угол ∠ACB = 90° (всегда!)';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=55, cx=110, cy=80, W=230, H=165;
const Ax=cx-R, Ay=cy;
const Bx=cx+R, By=cy;
const cRad=(-60)*Math.PI/180;
const Ccx=cx+R*Math.cos(cRad), Ccy=cy+R*Math.sin(cRad);
const steps=[
{text:'<b>Дано:</b> $AB$ — диаметр окружности, $C$ — точка на окружности, $C \\neq A, C \\neq B$. Доказать: $\\angle ACB = 90°$.'},
{text:'<b>Шаг 1.</b> $AB$ — диаметр, значит центральный угол $\\angle AOB = 180°$ (развёрнутый). Дуга $ACB = 180°$ (полуокружность).'},
{text:'<b>Шаг 2.</b> Вписанный угол $\\angle ACB$ опирается на дугу $AB = 180°$ (дугу, не содержащую $C$).'},
{text:'<b>Шаг 3.</b> По теореме §9: $\\angle ACB = \\dfrac{1}{2} \\cdot 180° = 90°$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p11-proof-svg'), txtEl=document.getElementById('p11-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<text x="${cx-8}" y="${cy+18}" font-size="9" fill="#1d4ed8" font-weight="700">∠AOB=180°</text>`;
ex+=`<path d="M ${Ax} ${Ay} A ${R} ${R} 0 0 0 ${Bx} ${By}" fill="rgba(37,99,235,.15)" stroke="#1d4ed8" stroke-width="2.5"/>`;
}
if(step>=2){
ex+=`<line x1="${Ccx}" y1="${Ccy}" x2="${Ax}" y2="${Ay}" stroke="#dc2626" stroke-width="2"/>`;
ex+=`<line x1="${Ccx}" y1="${Ccy}" x2="${Bx}" y2="${By}" stroke="#dc2626" stroke-width="2"/>`;
}
if(step>=3){
const u={x:(Ax-Ccx),y:(Ay-Ccy)},w={x:(Bx-Ccx),y:(By-Ccy)};
const un=Math.sqrt(u.x*u.x+u.y*u.y),wn=Math.sqrt(w.x*w.x+w.y*w.y);
const ux=u.x/un,uy=u.y/un,wx=w.x/wn,wy=w.y/wn;
const s=8;
ex+=`<polyline points="${Ccx+s*ux},${Ccy+s*uy} ${Ccx+s*ux+s*wx},${Ccy+s*uy+s*wy} ${Ccx+s*wx},${Ccy+s*wy}" fill="none" stroke="#dc2626" stroke-width="1.8"/>`;
ex+=`<text x="${Ccx+14}" y="${Ccy-10}" font-size="10" fill="#dc2626" font-weight="700">90°</text>`;
}
svgEl.innerHTML=`<svg viewBox="0 0 ${W} ${H}" style="max-width:${W}px;width:100%;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="${cx}" cy="${cy}" r="${R}" fill="rgba(37,99,235,.07)" stroke="#2563eb" stroke-width="2"/>
<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#1d4ed8" stroke-width="2.5"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#1d4ed8"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#1d4ed8"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#1d4ed8"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4.5" fill="#dc2626"/>
<text x="${Ax-16}" y="${Ay+4}" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
<text x="${Bx+6}" y="${By+4}" font-size="11" font-weight="700" fill="#1d4ed8">B</text>
<text x="${Ccx+7}" y="${Ccy-6}" font-size="12" font-weight="700" fill="#dc2626">C</text>
<text x="${cx-8}" y="${cy-6}" font-size="9" font-weight="700" fill="#1d4ed8">O</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p11-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p11-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p11-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор Пифагора === */
(function(){
document.getElementById('p11-pyth-btn').addEventListener('click',()=>{
const d=parseFloat(document.getElementById('p11-diam').value);
const a=parseFloat(document.getElementById('p11-leg').value);
const out=document.getElementById('p11-pyth-out');
out.style.display='block';
if(isNaN(d)||isNaN(a)||d<=0||a<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите положительные значения.';return;}
if(a>=d){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Катет должен быть меньше диаметра (гипотенузы).';return;}
const bc=Math.sqrt(d*d-a*a);
out.style.background='var(--sec-acc-soft,#dbeafe)';out.style.color='var(--sec-acc-d,#1d4ed8)';
out.innerHTML='BC = √(AB²−AC²) = √('+d+'²−'+a+'²) = √'+((d*d-a*a).toFixed(2))+' = <b>'+bc.toFixed(4)+'</b>';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'$AB$ — диаметр, $C$ на окружности. Чему равен $\\angle ACB$?',a:90,hint:'По теореме: вписанный угол на диаметре = 90°'},
{q:'Диаметр $AB = 13$, катет $AC = 5$. Найди $BC$.',a:12,hint:'BC = √(16925) = √144 = 12'},
{q:'$\\angle ACB = 90°$, $BC = 8$, $AC = 6$. Найди диаметр $AB$.',a:10,hint:'AB = √(64+36) = √100 = 10'},
{q:'Диаметр $AB = 2R = 20$, катет $BC = 16$. Найди $AC$.',a:12,hint:'AC = √(400256) = √144 = 12'},
{q:'Вписанный угол $\\angle ACB$, $AB$ — диаметр. Треугольник $ACB$ — прямоугольный. Верно ли это? (1 — да, 0 — нет)',a:1,hint:'Да, ∠ACB=90° означает прямоугольный треугольник'},
];
let cur=0, score=0;
const iEl=document.getElementById('p11-tr-i'), scEl=document.getElementById('p11-tr-score');
const taskEl=document.getElementById('p11-tr-task'), ansEl=document.getElementById('p11-tr-ans');
const goBtn=document.getElementById('p11-tr-go'), startBtn=document.getElementById('p11-tr-start');
const fb=document.getElementById('p11-tr-fb');
function showTask(){
if(cur>=tasks.length){taskEl.innerHTML='<b>Тренажёр завершён! Очки: '+score+'/'+tasks.length+'</b>';ansEl.style.display='none';goBtn.style.display='none';addXp(score*4,'p11-trainer');bumpProgress('p11',20);return;}
taskEl.innerHTML=tasks[cur].q;iEl.textContent=cur+1;ansEl.value='';fb.style.display='none';
if(window.renderMathInElement) try{renderMath(taskEl);}catch(e){}
}
goBtn.addEventListener('click',()=>{
const ans=parseFloat(ansEl.value.replace(',','.'));
const ok=Math.abs(ans-tasks[cur].a)<0.5;
feedback(fb,ok,ok?'Верно!':'Неверно. Подсказка: '+tasks[cur].hint);
if(ok){score++;scEl.textContent=score;cur++;setTimeout(showTask,900);}
});
startBtn.addEventListener('click',()=>{cur=0;score=0;scEl.textContent=0;ansEl.style.display='';goBtn.style.display='';showTask();});
showTask();
})();
/* === INIT 5: DnD верно/неверно === */
(function(){
const items=[
{label:'Вписанный угол на диаметре = 90°',cat:'true'},
{label:'Вписанный угол на диаметре = 180°',cat:'false'},
{label:'Гипотенуза прямоугольного треугольника — диаметр описанной окружности',cat:'true'},
{label:'Диаметр всегда является вписанным углом',cat:'false'},
{label:'Если ∠ACB = 90°, то AB — диаметр',cat:'true'},
{label:'Вписанный угол на диаметре может быть тупым',cat:'false'},
];
const pool=document.getElementById('p11-dnd-pool');
const boxes={true:document.getElementById('p11-drop-true-items'),false:document.getElementById('p11-drop-false-items')};
const fb=document.getElementById('p11-dnd-fb');
let placed={};
function reset(){
pool.innerHTML='';placed={};
Object.values(boxes).forEach(b=>b.innerHTML='');
fb.style.display='none';
items.forEach((it,i)=>{
const chip=document.createElement('div');
chip.className='dnd-chip';chip.dataset.i=i;chip.textContent=it.label;
chip.addEventListener('click',()=>chip.classList.toggle('armed'));
Object.entries(boxes).forEach(([cat,box])=>{
box.parentElement.addEventListener('click',()=>{
if(!chip.classList.contains('armed'))return;
chip.classList.remove('armed');
if(placed[i]!==undefined) boxes[placed[i]].removeChild(chip);
placed[i]=cat;
box.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p11-dnd-check').addEventListener('click',()=>{
let ok=0;
items.forEach((it,i)=>{if(placed[i]===it.cat)ok++;});
feedback(fb,ok===items.length,'Верно: '+ok+'/'+items.length+(ok===items.length?'. Отлично!':'. Попробуй ещё.'));
if(ok===items.length){addXp(8,'p11-dnd');bumpProgress('p11',15);}
});
document.getElementById('p11-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §11 === */
(function(){
const tasks=[
{q:'$AB$ — диаметр, $C$ на окружности. Треугольник $ACB$ является:',
opts:['Прямоугольным с катетами $AC$, $BC$','Равнобедренным','Остроугольным'],cor:0,
exp:'$\\angle ACB = 90°$ — прямой, значит $ACB$ прямоугольный, $AB$ — гипотенуза.'},
{q:'Диаметр $AB = 26$, $AC = 10$. Найди $BC$.',
opts:['24','16','12'],cor:0,
exp:'$BC = \\sqrt{26^2 - 10^2} = \\sqrt{676-100} = \\sqrt{576} = 24$.'},
{q:'$\\angle ACB = 90°$, $AC = BC = 5$. Диаметр $AB = ?$',
opts:['$5\\sqrt{2}$','$10$','$5$'],cor:0,
exp:'$AB = \\sqrt{AC^2 + BC^2} = \\sqrt{25+25} = 5\\sqrt{2}$.'},
{q:'Радиус $R = 7$. Сколько различных прямоугольных треугольников можно вписать в эту окружность с гипотенузой = диаметру?',
opts:['Один','Бесконечно много','Четыре'],cor:1,
exp:'Вершина $C$ может быть любой точкой окружности (кроме концов диаметра) — бесконечно много треугольников.'},
];
const cont=document.getElementById('p11-boss-tasks');
let bhtml='';
tasks.forEach((t,i)=>{
bhtml+=`<div style="margin-bottom:14px;padding:14px;background:var(--card);border:1px solid var(--border);border-radius:10px">
<div style="font-weight:600;margin-bottom:8px;font-size:.94rem">${i+1}. ${t.q}</div>
<div style="display:flex;flex-direction:column;gap:6px">
${t.opts.map((o,j)=>`<button class="btn" data-boss11="p11-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss11=\\'p11-${i}\\']');
btns.forEach(b=>b.disabled=true);
const ok=${j}===${t.cor};
btn.style.background=ok?'#d1fae5':'#fee2e2';
btn.style.borderColor=ok?'#10b981':'#ef4444';
btn.style.color=ok?'#065f46':'#7f1d1d';
const exp=document.getElementById('p11-boss-exp-${i}');
exp.style.display='block';exp.innerHTML='<b>'+(ok?'Верно!':'Неверно.')+'</b> ${t.exp.replace(/\\/g,'\\\\').replace(/'/g,"\\'")}';
if(window.renderMathInElement) try{renderMath(exp);}catch(e){}
if(ok){addXp(5,'p11-boss-${i}');bumpProgress('p11',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p11-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--sec-acc-soft,var(--pri-soft));color:var(--sec-acc-d,var(--pri2));line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
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','p16'); }
function buildP16stub(){ document.getElementById('p16-body').innerHTML='<div class="card"><div class="card-body"><p><b>§16 — Волна 1</b>: содержимое появится в следующем обновлении.</p></div></div>'+secNav('p15','final4'); }
function buildFinal4stub(){ document.getElementById('final4-body').innerHTML='<div class="card"><div class="card-body"><p><b>Финал главы 4 — Волна 1</b>: боссы и итоги появятся в следующем обновлении.</p></div></div>'+secNav('p16',null); }
</script>
</body>
</html>