Files
Learn_System/frontend/textbooks/geometry_8_ch4.html
T
Maxim Dolgolyov ac10ebdd21 feat(geom8): Wave 5 — финал Главы 4 (ПОСЛЕДНИЙ параграф Геометрии 8!)
Часть 1: 16 mini-cards со SVG-иконками и формулами в KaTeX
для всех §1-§16 (касательные, дуги, вписанные углы, произведения).

Часть 2: интерактивная карта связей (SVG 620×360):
центральный узел 'ОКРУЖНОСТЬ' → 3 ветви (Касательные §1-7,
Углы §8-14, Отрезки §15-16). Кликабельные узлы с формулами.

Часть 3: 7 интегрированных боссов (по 10 XP):
  Босс 1 (§1+§3): R=5, OP=13 → PT=12, периметр=34
  Босс 2 (§9+§11): диаметр AB, ∠CAB=35° → ∠ACB=90°, ∠ABC=55°
  Босс 3 (§10+§13): хорды, дуги 70°/50° → ∠P=60°, ∠ADC=35°
  Босс 4 (§14): две секущие, дуги 100°/40° → ∠P=30°
  Босс 5 (§15): PA=4 PB=9 PC=6 → PD=6
  Босс 6 (§16): PT=8 AB=12 → PA=4, PB=16
  Босс 7 (§7): R₁=6 R₂=2 d=10 → ℓ=√84≈9.17

Часть 4: финальная плашка с confetti + achievement
'Мастер окружностей Главы 4' + 50 XP бонус + переход к /textbooks.

File: 6712 → 7381 LOC. ГЛАВА 4 ПОЛНОСТЬЮ ЗАВЕРШЕНА.

🎉 ВСЯ ГЕОМЕТРИЯ 8 ЗАВЕРШЕНА:
  Глава 1 (Многоугольники, 16§+финал): 5560 LOC
  Глава 2 (Площади, 15§+финал): 7144 LOC
  Глава 3 (Подобие, 9§+финал): 4709 LOC
  Глава 4 (Окружности, 16§+финал): 7381 LOC

Итого: 56 параграфов + 4 финала = 60 разделов, 24,794 LOC.

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

7382 lines
550 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:()=>buildP12(),p13:()=>buildP13(),p14:()=>buildP14(),p15:()=>buildP15(),p16:()=>buildP16(),final4:()=>buildFinal4()};
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:['теорема Фалеса','теореме Фалеса','теоремы Фалеса']},
{term:'угол между касательной и хордой',def:'Угол, образованный касательной к окружности и хордой, проведённой из точки касания; равен половине дуги, заключённой между ними.',sec:'p12',aliases:['угол между касательной и хордой','угла между касательной и хордой']},
{term:'пересекающиеся хорды',def:'Две хорды окружности, имеющие общую точку внутри окружности. Произведения их отрезков равны: PA·PB = PC·PD.',sec:'p15',aliases:['пересекающиеся хорды','пересекающихся хорд','пересекающимся хордам']},
{term:'полусумма дуг',def:'Выражение вида ½(дуга₁ + дуга₂), возникающее в теореме об угле между двумя хордами, пересекающимися внутри окружности.',sec:'p13',aliases:['полусумма дуг','полусуммы дуг','полусумме дуг']},
{term:'полуразность дуг',def:'Выражение вида ½|дуга₁ − дуга₂|, возникающее в теореме об угле между секущими из внешней точки.',sec:'p14',aliases:['полуразность дуг','полуразности дуг','полуразностью дуг']},
{term:'квадрат касательной',def:'Если из внешней точки P проведены касательная PT и секущая через A и B, то PT² = PA·PB.',sec:'p16',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 270 185" style="max-width:285px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- O=(95,100) R=50 A=(220,92) — geometrically correct tangent points -->
<!-- OA=(125,-8) |OA|=125.26 AT=sqrt(OA²-R²)=sqrt(15064)=117.7 -->
<!-- R²/OA²=0.159 R·AT/OA²=0.376 perp_OA=(8,125) -->
<!-- T₂(upper)=(95+125*.159+8*.376,100-8*.159-125*.376)=(114.9,52.6) -->
<!-- T₁(lower)=(95+125*.159-8*.376,100-8*.159+125*.376)=(114.9-3,100-1.27+47)=(112,145.7) -->
<circle cx="95" cy="100" r="50" fill="rgba(2,132,199,.08)" stroke="#0284c7" stroke-width="2"/>
<circle cx="95" cy="100" r="3.5" fill="#0369a1"/>
<!-- radii to tangent points -->
<line x1="95" y1="100" x2="115" y2="53" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<line x1="95" y1="100" x2="112" y2="146" stroke="#0284c7" stroke-width="1.8" stroke-dasharray="4,3"/>
<!-- tangent points -->
<circle cx="115" cy="53" r="4" fill="#0284c7"/>
<circle cx="112" cy="146" r="4" fill="#0284c7"/>
<!-- tangent lines from A -->
<line x1="115" y1="53" x2="220" y2="92" stroke="#10b981" stroke-width="2.2"/>
<line x1="112" y1="146" x2="220" y2="92" stroke="#10b981" stroke-width="2.2"/>
<!-- OA bisector -->
<line x1="95" y1="100" x2="220" y2="92" stroke="#64748b" stroke-width="1.5" stroke-dasharray="5,3"/>
<circle cx="220" cy="92" r="4" fill="#0369a1"/>
<!-- right-angle at T₂=(115,53): arms point INWARD (toward O) and toward A -->
<!-- u_r=(0.4,-0.94) from O to T₂; toO=-u_r=(-0.4,0.94); u_t toward A=(0.938,0.348); s=8 -->
<!-- p1=T₂+8·toO=(111.8,60.5) corner=p1+8·u_t=(119.3,63.3) p2=T₂+8·u_t=(122.5,55.8) -->
<polyline points="111.8,60.5 119.3,63.3 122.5,55.8" fill="none" stroke="#0369a1" stroke-width="1.8"/>
<!-- right-angle at T₁=(112,146): u_r=(0.34,0.92) from O to T₁; toO=(-0.34,-0.92); u_t toward A=(0.895,-0.447); s=8 -->
<!-- p1=T₁+8·toO=(109.3,138.6) corner=p1+8·u_t=(116.5,135.0) p2=T₁+8·u_t=(119.2,142.4) -->
<polyline points="109.3,138.6 116.5,135.0 119.2,142.4" fill="none" stroke="#0369a1" stroke-width="1.8"/>
<!-- labels: O left of center, A right of point -->
<text x="79" y="104" font-size="11" font-weight="700" fill="#0369a1">O</text>
<text x="224" y="96" font-size="11" font-weight="700" fill="#0369a1">A</text>
<!-- T₂ label: outward from O direction (0.4,-0.94)*15 from T₂ offset -->
<text x="118" y="37" font-size="11" font-weight="700" fill="#0369a1">T₂</text>
<!-- T₁ label: outward direction (0.34,0.92)*15 from T₁ -->
<text x="107" y="165" font-size="11" font-weight="700" fill="#0369a1">T₁</text>
<!-- AT₂ label: midpoint(115,53)→(220,92)=(167.5,72.5) perp-offset outward -->
<text x="178" y="58" font-size="10" fill="#065f46" font-weight="700">AT₂</text>
<!-- AT₁ label: midpoint(112,146)→(220,92)=(166,119) perp-offset outward -->
<text x="177" y="136" font-size="10" fill="#065f46" font-weight="700">AT₁</text>
<text x="135" y="178" 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=90, cy=130, W=320, H=245;
function draw(){
const OA=+sl.value;
oaVal.textContent=OA;
const Ax=cx+OA, Ay=cy;
const AT=Math.sqrt(OA*OA-R*R);
/* sinA=R/OA is sin(∠OAT); cosA=AT/OA is cos(∠OAT).
Tangent point: T_x=O_x+R*(R/OA)=O_x+R*sinA; T_y=O_y∓R*(AT/OA)=O_y∓R*cosA */
const sinA=R/OA, cosA=AT/OA;
const T1x=cx+R*sinA, T1y=cy-R*cosA;
const T2x=cx+R*sinA, T2y=cy+R*cosA;
// right angle markers — arms must point INWARD (toward O) and toward A
const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R; // outward radial unit
const ut1x=-(ur1y), ut1y=ur1x; // CCW perp = toward A for upper T1
const s=8;
// marker: T+s·(-u_r), T+s·(-u_r)+s·u_t, T+s·u_t — uses INWARD direction (-u_r)
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; // CW perp = toward A for lower T2
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=90, cy=110;
const OA=140;
const AT=Math.sqrt(OA*OA-R*R);
const sinA=R/OA, cosA=AT/OA;
/* T_x=cx+R*sinA=cx+R²/OA, T_y=cy∓R*cosA=cy∓R*AT/OA */
const T1x=cx+R*sinA, T1y=cy-R*cosA;
const T2x=cx+R*sinA, T2y=cy+R*cosA;
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; // outward
const ut1x=-(ur1y), ut1y=ur1x; // CCW perp → toward A for upper T1
// marker INWARD: T+s·(-u_r) and T+s·u_t
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; // CW perp → toward A for lower T2
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 285 200" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- O=(90,100) R=50 A=(240,100) M=(165,100) MR=75 -->
<!-- T₂(upper)=(107,53) T₁(lower)=(107,147) — on both circles -->
<circle cx="90" cy="100" r="50" fill="rgba(37,99,235,.08)" stroke="#2563eb" stroke-width="2"/>
<!-- auxiliary circle: center M=(165,100) radius 75 — passes through O and A -->
<circle cx="165" cy="100" r="75" fill="none" stroke="#f59e0b" stroke-width="1.5" stroke-dasharray="5,3"/>
<!-- OA line -->
<line x1="90" y1="100" x2="240" y2="100" stroke="#64748b" stroke-width="1.4" stroke-dasharray="4,3"/>
<!-- radii to tangent points -->
<line x1="90" y1="100" x2="107" y2="53" stroke="#2563eb" stroke-width="1.5" stroke-dasharray="3,2"/>
<line x1="90" y1="100" x2="107" y2="147" stroke="#2563eb" stroke-width="1.5" stroke-dasharray="3,2"/>
<!-- tangent lines -->
<line x1="240" y1="100" x2="107" y2="53" stroke="#10b981" stroke-width="2.2"/>
<line x1="240" y1="100" x2="107" y2="147" stroke="#10b981" stroke-width="2.2"/>
<!-- points -->
<circle cx="90" cy="100" r="3" fill="#1d4ed8"/>
<circle cx="240" cy="100" r="3.5" fill="#1d4ed8"/>
<circle cx="165" cy="100" r="3" fill="#f59e0b"/>
<circle cx="107" cy="53" r="4" fill="#10b981"/>
<circle cx="107" cy="147" r="4" fill="#10b981"/>
<!-- right-angle at T₂=(107,53): arms toward O and toward A (INSIDE △OT₂A) -->
<!-- toO=(-0.34,0.94); u_t=(0.94,0.34); s=8 -->
<!-- p1=T₂+8·toO=(104.3,60.5) corner=(111.8,63.2) p2=T₂+8·u_t=(114.5,55.7) -->
<polyline points="104.3,60.5 111.8,63.2 114.5,55.7" fill="none" stroke="#1d4ed8" stroke-width="1.8"/>
<!-- right-angle at T₁=(107,147): toO=(-0.34,-0.94); u_t=(0.94,-0.34); s=8 -->
<!-- p1=T₁+8·toO=(104.3,139.5) corner=(111.8,136.8) p2=T₁+8·u_t=(114.5,144.3) -->
<polyline points="104.3,139.5 111.8,136.8 114.5,144.3" fill="none" stroke="#1d4ed8" stroke-width="1.8"/>
<!-- labels -->
<text x="74" y="97" font-size="11" font-weight="700" fill="#1d4ed8">O</text>
<text x="244" y="97" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
<text x="169" y="96" font-size="10" fill="#b45309">M</text>
<!-- T₂ label: outward direction (0.34,-0.94) from T₂ -->
<text x="109" y="38" font-size="11" font-weight="700" fill="#10b981">T₂</text>
<!-- T₁ label: outward direction (0.34,0.94) from T₁ -->
<text x="109" y="168" font-size="11" font-weight="700" fill="#10b981">T₁</text>
</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 230 170" style="max-width:245px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- O=(70,105) R=50 A=(205,105) T=(89,58) — correct tangent point -->
<!-- OA=135 AT=sqrt(135²-50²)=125 T_x=70+50²/135=70+18.5=88.5 T_y=105-50*125/135=105-46.3=58.7 -->
<circle cx="70" cy="105" r="50" fill="rgba(37,99,235,.08)" stroke="#2563eb" stroke-width="2"/>
<circle cx="70" cy="105" r="3" fill="#1d4ed8"/>
<circle cx="205" cy="105" r="3.5" fill="#1d4ed8"/>
<circle cx="89" cy="59" r="4" fill="#10b981"/>
<!-- radius OT -->
<line x1="70" y1="105" x2="89" y2="59" stroke="#2563eb" stroke-width="2"/>
<!-- tangent line TA -->
<line x1="89" y1="59" x2="205" y2="105" stroke="#10b981" stroke-width="2.2"/>
<!-- OA base line -->
<line x1="70" y1="105" x2="205" y2="105" stroke="#64748b" stroke-width="1.5" stroke-dasharray="4,3"/>
<!-- right-angle at T=(89,59): toO=(-0.38,0.92) u_t toward A=(0.92,0.38) s=8 -->
<!-- p1=T+8·toO=(85.96,66.36) corner=(93.36,69.4) p2=T+8·u_t=(96.36,62.04) -->
<polyline points="85.96,66.36 93.36,69.4 96.36,62.04" fill="none" stroke="#1d4ed8" stroke-width="1.8"/>
<!-- labels off their respective lines -->
<text x="54" y="102" font-size="11" font-weight="700" fill="#1d4ed8">O</text>
<text x="209" y="109" font-size="11" font-weight="700" fill="#1d4ed8">A</text>
<!-- T label: outward from O direction (0.38,-0.92)*16 from T -->
<text x="92" y="43" font-size="11" font-weight="700" fill="#10b981">T</text>
<!-- R label: midpoint OT=(79.5,82) offset perpendicular (-0.92,-0.38)*8 left side -->
<text x="66" y="82" font-size="10" fill="#2563eb" font-weight="700">R</text>
<!-- AT label: midpoint T→A=(147,82) offset perp upward (-0.38,0.92)*-12 = above line -->
<text x="143" y="69" font-size="10" fill="#10b981" font-weight="700">AT</text>
<!-- |OA| label: below midpoint of OA -->
<text x="124" y="122" 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=240,AY=110,R=55;
const MX=(OX+AX)/2, MY=(OY+AY)/2, MR=(AX-OX)/2;
const OA=Math.sqrt((AX-OX)**2+(AY-OY)**2);
const sinA=R/OA, cosA=Math.sqrt(1-sinA*sinA);
/* T_x=OX+R*sinA=OX+R²/OA, T_y=OY∓R*cosA=OY∓R*AT/OA */
const T1X=OX+R*sinA, T1Y=OY-R*cosA;
const T2X=OX+R*sinA, T2Y=OY+R*cosA;
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.toFixed(1)}" cy="${T1Y.toFixed(1)}" r="4.5" fill="#10b981"/>`;
extras+=`<circle cx="${T2X.toFixed(1)}" cy="${T2Y.toFixed(1)}" r="4.5" fill="#10b981"/>`;
/* T labels in outward radial direction */
const ur1x=(T1X-OX)/R, ur1y=(T1Y-OY)/R;
const ur2x=(T2X-OX)/R, ur2y=(T2Y-OY)/R;
extras+=`<text x="${(T1X+ur1x*15-5).toFixed(1)}" y="${(T1Y+ur1y*15+4).toFixed(1)}" font-size="11" font-weight="700" fill="#065f46">T₁</text>`;
extras+=`<text x="${(T2X+ur2x*15-5).toFixed(1)}" y="${(T2Y+ur2y*15+10).toFixed(1)}" font-size="11" font-weight="700" fill="#065f46">T₂</text>`;
/* right-angle markers: arms toward O (INSIDE △OTA) and toward A */
const ut1x=-ur1y, ut1y=ur1x; // CCW perp = toward A for upper T1
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 ut2x=ur2y, ut2y=-ur2x; // CW perp = toward A for lower T2
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)}`;
extras+=`<polyline points="${rm1}" fill="none" stroke="#1d4ed8" stroke-width="1.6"/>`;
extras+=`<polyline points="${rm2}" 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 sinT=R/OA, cosT=Math.sqrt(Math.max(0,1-sinT*sinT));
/* T_x=OX+R*sinT=OX+R²/OA, T_y=OY∓R*cosT=OY∓R*AT/OA */
const T1X=OX+R*sinT, T1Y=OY-R*cosT;
const T2X=OX+R*sinT, T2Y=OY+R*cosT;
const AT=Math.sqrt(Math.max(0,OA*OA-R*R));
const AXc=Math.min(AX,W-14);
lenEl.textContent='Длина касательной AT = √('+OA+'²−'+R+'²) = '+AT.toFixed(2);
/* T labels: outward from O */
const ur1x=(T1X-OX)/R, ur1y=(T1Y-OY)/R;
const ur2x=(T2X-OX)/R, ur2y=(T2Y-OY)/R;
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-16}" y="${OY+5}" font-size="10" font-weight="700" fill="#1d4ed8">O</text>
<circle cx="${AXc}" cy="${AY}" r="3.5" fill="#1d4ed8"/>
<text x="${AXc+4}" y="${AY+5}" font-size="10" font-weight="700" fill="#1d4ed8">A</text>
<line x1="${OX}" y1="${OY}" x2="${AXc}" 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.toFixed(1)}" cy="${T1Y.toFixed(1)}" r="4" fill="#10b981"/>
<circle cx="${T2X.toFixed(1)}" cy="${T2Y.toFixed(1)}" r="4" fill="#10b981"/>
<line x1="${AXc}" y1="${AY}" x2="${T1X.toFixed(1)}" y2="${T1Y.toFixed(1)}" stroke="#10b981" stroke-width="2"/>
<line x1="${AXc}" y1="${AY}" x2="${T2X.toFixed(1)}" y2="${T2Y.toFixed(1)}" stroke="#10b981" stroke-width="2"/>
<text x="${(T1X+ur1x*13-5).toFixed(1)}" y="${(T1Y+ur1y*13+4).toFixed(1)}" font-size="10" font-weight="700" fill="#065f46">T₁</text>
<text x="${(T2X+ur2x*13-5).toFixed(1)}" y="${(T2Y+ur2y*13+10).toFixed(1)}" 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 265 205" style="max-width:280px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- angle vertex B=(20,183), two sides: horizontal + upper-right (220,-120)/253 -->
<!-- half-angle≈14.3°, bisector dir≈(0.969,-0.247) -->
<!-- inscribed circle r=35: d=r/sin(14.3°)=141.7 -->
<!-- O=(157,148), T₁=(157,183) on horiz side, T₂=(140,117) on upper side -->
<!-- side 1: B=(20,183) rightward -->
<line x1="20" y1="183" x2="255" y2="183" stroke="#0891b2" stroke-width="2"/>
<!-- side 2: B=(20,183) to (240,63) direction (220,-120)/253 -->
<line x1="20" y1="183" x2="245" y2="63" stroke="#0891b2" stroke-width="2"/>
<!-- bisector dashed: B to ~(195,140) -->
<line x1="20" y1="183" x2="200" y2="138" stroke="#64748b" stroke-width="1.4" stroke-dasharray="5,3"/>
<!-- inscribed circle O=(157,148) r=35 -->
<circle cx="157" cy="148" r="35" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="157" cy="148" r="3" fill="#0e7490"/>
<!-- radii to tangent points -->
<line x1="157" y1="148" x2="157" y2="183" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="157" y1="148" x2="140" y2="117" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<!-- right-angle at T₁=(157,183): radius goes upward (0,-1), tangent is horizontal (1,0) s=8 -->
<polyline points="157,175 165,175 165,183" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<!-- right-angle at T₂=(140,117): u_r=(T₂-O)/r=(-17/35,-31/35)=(-0.486,-0.886) u_t=(0.886,-0.486) s=8 -->
<!-- T₂+s*ur=(140-3.9,117-7.1)=(136.1,109.9) next=(136.1+7.1,109.9-3.9)=(143.2,106.0) next=(140+7.1,117-3.9)=(147.1,113.1) -->
<polyline points="136.1,109.9 143.2,106.0 147.1,113.1" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<!-- tangent point dots -->
<circle cx="157" cy="183" r="3.5" fill="#10b981"/>
<circle cx="140" cy="117" r="3.5" fill="#10b981"/>
<!-- labels -->
<circle cx="20" cy="183" r="3" fill="#0e7490"/>
<text x="7" y="181" font-size="11" font-weight="700" fill="#0e7490">B</text>
<!-- O label: above-right of center, off the radii -->
<text x="162" y="145" font-size="11" font-weight="700" fill="#0e7490">O</text>
<!-- T₁ label: below T₁, off horizontal line -->
<text x="160" y="196" font-size="10" font-weight="700" fill="#0e7490">T₁</text>
<!-- T₂ label: upper-left of T₂, outward direction (-0.486,-0.886)*13 from T₂ -->
<text x="126" y="107" font-size="10" font-weight="700" fill="#0e7490">T₂</text>
<text x="203" y="131" 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 280 200" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- B=(15,178), full angle = 30°, half = 15°.
Lower side: horizontal y=178, to (265,178).
Upper side: direction (cos30°,-sin30°)=(0.866,-0.5). At length 280 → (15+242.5, 178-140)=(257,38).
Bisector: (cos15°,-sin15°)=(0.966,-0.259). To length 220 → (15+212.5, 178-57)=(227,121).
O₁: d=84.9, O₁=(15+82, 178-22)=(97,156), r=d·sin15°=22.
O₂: d=139, O₂=(15+134, 178-36)=(149,142), r=d·sin15°=36.
Upper tangent points: foot of perpendicular from O onto upper line.
T₁_up = B + ((O₁-B)·u) · u, where u=(0.866,-0.5).
(O₁-B)·u = 82·0.866 + (-22)·(-0.5) = 71+11 = 82.
T₁_up = (15+82·0.866, 178+82·(-0.5)) = (86,137).
T₂_up = (15+134·0.866, 178+134·(-0.5)) = (131,111). -->
<line x1="15" y1="178" x2="265" y2="178" stroke="#0891b2" stroke-width="2"/>
<line x1="15" y1="178" x2="257" y2="38" stroke="#0891b2" stroke-width="2"/>
<line x1="15" y1="178" x2="227" y2="121" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<!-- small circle O₁=(97,156) r=22 -->
<circle cx="97" cy="156" r="22" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="97" cy="156" r="2.5" fill="#0e7490"/>
<!-- large circle O₂=(149,142) r=36 -->
<circle cx="149" cy="142" r="36" fill="rgba(8,145,178,.05)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="149" cy="142" r="2.5" fill="#0e7490"/>
<!-- tangent points on lower side -->
<circle cx="97" cy="178" r="3" fill="#10b981"/>
<circle cx="149" cy="178" r="3" fill="#10b981"/>
<!-- tangent points on upper side -->
<circle cx="86" cy="137" r="3" fill="#10b981"/>
<circle cx="131" cy="111" r="3" fill="#10b981"/>
<!-- B point -->
<circle cx="15" cy="178" r="3.5" fill="#0e7490"/>
<text x="3" y="175" font-size="11" font-weight="700" fill="#0e7490">B</text>
<text x="89" y="190" font-size="9" fill="#065f46" font-weight="700">T₁</text>
<text x="141" y="190" font-size="9" fill="#065f46" font-weight="700">T₂</text>
<text x="63" y="135" font-size="9" fill="#065f46" font-weight="700">T₃</text>
<text x="108" y="110" font-size="9" fill="#065f46" font-weight="700">T₄</text>
<text x="91" y="160" font-size="10" fill="#0e7490" font-weight="700">O₁</text>
<text x="143" y="146" font-size="10" fill="#0e7490" font-weight="700">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);
/* right-angle at T₂ on side 2 */
const s2x=Math.cos(ang2*Math.PI/180), s2y=-Math.sin(ang2*Math.PI/180);
const ot2ux=(OX-T2X)/r, ot2uy=(OY-T2Y)/r;
const rs=8;
const rm2pts=`${(T2X+s2x*rs).toFixed(1)},${(T2Y+s2y*rs).toFixed(1)} ${(T2X+s2x*rs+ot2ux*rs).toFixed(1)},${(T2Y+s2y*rs+ot2uy*rs).toFixed(1)} ${(T2X+ot2ux*rs).toFixed(1)},${(T2Y+ot2uy*rs).toFixed(1)}`;
/* T₂ label: perpendicular outward from side 2 (left when going along side 2) = (-s2y, s2x) = (sin(ang2), cos(ang2)) */
const t2labX=(T2X+Math.sin(ang2*Math.PI/180)*(-14)-4).toFixed(1);
const t2labY=(T2Y+Math.cos(ang2*Math.PI/180)*(-14)+4).toFixed(1);
/* T₁ label: below T₁ (off horizontal side) */
/* O label: to the right of O, offset away from radius to T₁ */
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)).toFixed(1)}" y2="${(BY-arm*Math.sin(ang2*Math.PI/180)).toFixed(1)}" stroke="#0891b2" stroke-width="2"/>
<line x1="${BX}" y1="${BY}" x2="${(OX+50*(OX-BX)/d).toFixed(1)}" y2="${(OY+50*(OY-BY)/d).toFixed(1)}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="4,3"/>
<circle cx="${OX.toFixed(1)}" cy="${OY.toFixed(1)}" r="${r.toFixed(1)}" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="${OX.toFixed(1)}" cy="${OY.toFixed(1)}" r="3" fill="#0e7490"/>
<circle cx="${T1X.toFixed(1)}" cy="${T1Y}" r="3.5" fill="#10b981"/>
<circle cx="${T2X.toFixed(1)}" cy="${T2Y.toFixed(1)}" r="3.5" fill="#10b981"/>
<line x1="${OX.toFixed(1)}" y1="${OY.toFixed(1)}" x2="${T1X.toFixed(1)}" y2="${T1Y}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="${OX.toFixed(1)}" y1="${OY.toFixed(1)}" x2="${T2X.toFixed(1)}" y2="${T2Y.toFixed(1)}" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<polyline points="${T1X.toFixed(1)},${T1Y} ${(T1X-9).toFixed(1)},${T1Y} ${(T1X-9).toFixed(1)},${T1Y-9}" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<polyline points="${rm2pts}" 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+5).toFixed(1)}" y="${(OY+4).toFixed(1)}" font-size="11" font-weight="700" fill="#0e7490">O</text>
<text x="${t2labX}" y="${t2labY}" font-size="9" fill="#065f46" font-weight="700">T₂</text>
<text x="${(T1X+4).toFixed(1)}" y="${T1Y+13}" font-size="9" fill="#065f46" font-weight="700">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='';
/* right-angle at T₂: side2 dir=(cos60°,-sin60°), radius-toward-O dir=((OX-T2X)/r,(OY-T2Y)/r) */
const s2x=Math.cos(ang2*Math.PI/180), s2y=-Math.sin(ang2*Math.PI/180);
const ot2ux=(OX-T2X)/r, ot2uy=(OY-T2Y)/r;
const rs=8;
const rm2p=`${(T2X+s2x*rs).toFixed(1)},${(T2Y+s2y*rs).toFixed(1)} ${(T2X+s2x*rs+ot2ux*rs).toFixed(1)},${(T2Y+s2y*rs+ot2uy*rs).toFixed(1)} ${(T2X+ot2ux*rs).toFixed(1)},${(T2Y+ot2uy*rs).toFixed(1)}`;
/* T₂ label outward from angle (perpendicular left of side2 direction = (-s2y, s2x) rotated outward) */
/* outward from angle interior: perpendicular to side2 pointing away = (sin(ang2), cos(ang2)) i.e. left-perp */
const t2lx=(T2X+Math.sin(ang2*Math.PI/180)*(-13)-4).toFixed(1);
const t2ly=(T2Y+Math.cos(ang2*Math.PI/180)*(-13)+4).toFixed(1);
/* r label: midpoint of OT₂, offset perpendicular */
const rOT2mx=((OX+T2X)/2).toFixed(1), rOT2my=((OY+T2Y)/2).toFixed(1);
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.toFixed(1)}" y2="${T2Y.toFixed(1)}" 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+=`<polyline points="${rm2p}" fill="none" stroke="#0e7490" stroke-width="1.5"/>`;extras+=`<text x="${t2lx}" y="${t2ly}" font-size="9" fill="#0e7490" font-weight="700">T₂</text><text x="${T1X+4}" y="${T1Y+13}" font-size="9" fill="#0e7490" font-weight="700">T₁</text>`;}
if(step>=2){extras+=`<text x="${rOT2mx}" y="${rOT2my}" font-size="9" fill="#10b981" font-weight="700">r</text><text x="${((T1X+OX)/2-18).toFixed(1)}" y="${((T1Y+OY)/2+4).toFixed(1)}" font-size="9" fill="#10b981" font-weight="700">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.toFixed(1)},${T2Y.toFixed(1)} ${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+6}" y="${OY+4}" 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>
<!-- Внутреннее касание: большая O₁=(185,60) R₁=40, малая O₂=(200,60) R₂=25, d=15=|40-25|.
Точка касания T на правом краю обеих: O₁+(R₁,0)=O₂+(R₂,0)=(225,60). -->
<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="225" cy="60" r="3.5" fill="#dc2626"/>
<text x="178" y="58" font-size="10" font-weight="700" fill="#0e7490">O₁</text>
<text x="194" y="58" font-size="10" font-weight="700" fill="#065f46">O₂</text>
<text x="228" y="56" font-size="11" font-weight="800" 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="90" x2="65" y2="50" stroke="#0d9488" stroke-width="1.4" stroke-dasharray="3,2"/>
<line x1="215" y1="90" x2="215" y2="65" stroke="#0d9488" stroke-width="1.4" stroke-dasharray="3,2"/>
<line x1="65" y1="90" x2="65" y2="130" stroke="#0d9488" stroke-width="1.4" stroke-dasharray="3,2"/>
<line x1="215" y1="90" x2="215" y2="115" stroke="#0d9488" stroke-width="1.4" stroke-dasharray="3,2"/>
<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"/>
<!-- right-angle markers: proper L inside angle between radius (down to O) and tangent (toward other circle) -->
<polyline points="65,59 74,59 74,50" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<polyline points="215,74 206,74 206,65" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<polyline points="65,121 74,121 74,130" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<polyline points="215,106 206,106 206,115" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<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 280 140" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="60" cy="85" r="45" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<circle cx="210" cy="85" r="28" fill="rgba(13,148,136,.08)" stroke="#0d9488" stroke-width="2"/>
<!-- tangent line T₁T₂ -->
<line x1="60" y1="40" x2="210" y2="57" stroke="#dc2626" stroke-width="2.2"/>
<!-- radii to T₁ and T₂ (vertical) -->
<line x1="60" y1="85" x2="60" y2="40" stroke="#0d9488" stroke-width="1.8"/>
<line x1="210" y1="85" x2="210" y2="57" stroke="#0d9488" stroke-width="1.8"/>
<!-- O₁O₂ line + auxiliary point K (foot of perp from O₂ on O₁T₁) -->
<line x1="60" y1="85" x2="210" y2="85" stroke="#64748b" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="60" y1="57" x2="210" y2="57" stroke="#64748b" stroke-width="1.2" stroke-dasharray="2,2"/>
<circle cx="60" cy="57" r="2.5" fill="#0d9488"/>
<text x="46" y="60" font-size="10" font-weight="700" fill="#0f766e">K</text>
<!-- vertex dots -->
<circle cx="60" cy="85" r="2.5" fill="#0f766e"/>
<circle cx="210" cy="85" r="2.5" fill="#0f766e"/>
<circle cx="60" cy="40" r="3.5" fill="#dc2626"/>
<circle cx="210" cy="57" r="3.5" fill="#dc2626"/>
<!-- right-angle markers at T₁ (between OT and tangent toward T₂): u_OT=down, u_t≈(0.993,0.113) -->
<polyline points="60,49 69,49 69,40" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<!-- at T₂: u_OT=down, u_t toward T₁≈(-0.993,-0.113) -->
<polyline points="210,66 201,66 201,57" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<!-- right angle at K (between KO₁=down and KO₂=right) -->
<polyline points="60,66 69,66 69,57" fill="none" stroke="#0f766e" stroke-width="1.4"/>
<text x="48" y="83" font-size="10" font-weight="700" fill="#0f766e">O₁</text>
<text x="214" y="83" font-size="10" font-weight="700" fill="#0f766e">O₂</text>
<text x="48" y="36" font-size="11" font-weight="700" fill="#dc2626">T₁</text>
<text x="214" y="54" font-size="11" font-weight="700" fill="#dc2626">T₂</text>
<text x="125" y="42" text-anchor="middle" font-size="11" fill="#dc2626" font-weight="700"></text>
<text x="40" y="78" font-size="9" fill="#0d9488" font-weight="700">R₁</text>
<text x="215" y="76" font-size="9" fill="#0d9488" font-weight="700">R₂</text>
<text x="125" y="99" text-anchor="middle" font-size="10" fill="#64748b" font-weight="700">d = |O₁O₂|</text>
<text x="120" y="71" text-anchor="middle" font-size="9" fill="#0d9488" font-weight="700">R₁−R₂</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;
/* right-angle markers at T1 (upper-left tangent point) and T2 (upper-right) */
const s=8;
const u1x=(T1X-cx1)/R1, u1y=(T1Y-CY)/R1; // outward radial unit at T1
const t1x=(T2X-T1X), t1y=(T2Y-T1Y), t1len=Math.hypot(t1x,t1y);
const v1x=t1x/t1len, v1y=t1y/t1len; // along tangent toward T2
// marker: arms inside (toward O1 and along tangent)
const m1p1x=T1X-u1x*s, m1p1y=T1Y-u1y*s;
const m1cx=m1p1x+v1x*s, m1cy=m1p1y+v1y*s;
const m1p2x=T1X+v1x*s, m1p2y=T1Y+v1y*s;
const u2x=(T2X-cx2)/R2, u2y=(T2Y-CY)/R2;
const v2x=-v1x, v2y=-v1y; // toward T1
const m2p1x=T2X-u2x*s, m2p1y=T2Y-u2y*s;
const m2cx=m2p1x+v2x*s, m2cy=m2p1y+v2y*s;
const m2p2x=T2X+v2x*s, m2p2y=T2Y+v2y*s;
/* lower tangent T3-T4 markers */
const u3x=(T3X-cx1)/R1, u3y=(T3Y-CY)/R1;
const t3x=(T4X-T3X), t3y=(T4Y-T3Y), t3len=Math.hypot(t3x,t3y);
const v3x=t3x/t3len, v3y=t3y/t3len;
const m3p1x=T3X-u3x*s, m3p1y=T3Y-u3y*s;
const m3cx=m3p1x+v3x*s, m3cy=m3p1y+v3y*s;
const m3p2x=T3X+v3x*s, m3p2y=T3Y+v3y*s;
const u4x=(T4X-cx2)/R2, u4y=(T4Y-CY)/R2;
const v4x=-v3x, v4y=-v3y;
const m4p1x=T4X-u4x*s, m4p1y=T4Y-u4y*s;
const m4cx=m4p1x+v4x*s, m4cy=m4p1y+v4y*s;
const m4p2x=T4X+v4x*s, m4p2y=T4Y+v4y*s;
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="${cx1}" y1="${CY}" x2="${T1X.toFixed(1)}" y2="${T1Y.toFixed(1)}" stroke="#0d9488" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="${cx2}" y1="${CY}" x2="${T2X.toFixed(1)}" y2="${T2Y.toFixed(1)}" stroke="#0d9488" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="${cx1}" y1="${CY}" x2="${T3X.toFixed(1)}" y2="${T3Y.toFixed(1)}" stroke="#0d9488" stroke-width="1.3" stroke-dasharray="3,2"/>
<line x1="${cx2}" y1="${CY}" x2="${T4X.toFixed(1)}" y2="${T4Y.toFixed(1)}" stroke="#0d9488" stroke-width="1.3" 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"/>
<circle cx="${T3X}" cy="${T3Y}" r="3.5" fill="#dc2626"/>
<circle cx="${T4X}" cy="${T4Y}" r="3.5" fill="#dc2626"/>
<polyline points="${m1p1x.toFixed(1)},${m1p1y.toFixed(1)} ${m1cx.toFixed(1)},${m1cy.toFixed(1)} ${m1p2x.toFixed(1)},${m1p2y.toFixed(1)}" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<polyline points="${m2p1x.toFixed(1)},${m2p1y.toFixed(1)} ${m2cx.toFixed(1)},${m2cy.toFixed(1)} ${m2p2x.toFixed(1)},${m2p2y.toFixed(1)}" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<polyline points="${m3p1x.toFixed(1)},${m3p1y.toFixed(1)} ${m3cx.toFixed(1)},${m3cy.toFixed(1)} ${m3p2x.toFixed(1)},${m3p2y.toFixed(1)}" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<polyline points="${m4p1x.toFixed(1)},${m4p1y.toFixed(1)} ${m4cx.toFixed(1)},${m4cy.toFixed(1)} ${m4p2x.toFixed(1)},${m4p2y.toFixed(1)}" fill="none" stroke="#0f766e" stroke-width="1.6"/>
<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 280 200" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- Circle O=(120,100), R=70. A at angle -60° (top-right), C at angle 60° (bottom-right).
A=(120+70·cos(-60°), 100+70·sin(-60°))=(155, 39.4); C=(155, 160.6). -->
<!-- Sector fill (pie slice OAC, the 120° wedge facing right) -->
<path d="M 120,100 L 155,39 A 70,70 0 0,1 155,161 Z" fill="rgba(245,158,11,.20)" stroke="none"/>
<!-- Highlighted arc AC (the small arc, 120°) -->
<path d="M 155,39 A 70,70 0 0,1 155,161" fill="none" stroke="#ef4444" stroke-width="3.5"/>
<!-- Full circle outline -->
<circle cx="120" cy="100" r="70" fill="none" stroke="#0891b2" stroke-width="2"/>
<!-- Radii OA and OC -->
<line x1="120" y1="100" x2="155" y2="39" stroke="#0891b2" stroke-width="2"/>
<line x1="120" y1="100" x2="155" y2="161" stroke="#0891b2" stroke-width="2"/>
<!-- Angle marker α at center O (arc of radius 22, between OA and OC).
OA direction: (155-120, 39-100)/70=(0.5,-0.871), so start at O+22·(0.5,-0.871)=(131, 80.8).
OC direction: (155-120, 161-100)/70=(0.5, 0.871), so end at O+22·(0.5, 0.871)=(131, 119.2). -->
<path d="M 131,81 A 22,22 0 0,1 131,119" fill="none" stroke="#f59e0b" stroke-width="2.4"/>
<!-- Center dot and vertex dots -->
<circle cx="120" cy="100" r="3.5" fill="#0e7490"/>
<circle cx="155" cy="39" r="4" fill="#0284c7"/>
<circle cx="155" cy="161" r="4" fill="#0284c7"/>
<!-- Labels -->
<text x="103" y="105" font-size="13" font-weight="800" fill="#0e7490" font-family="Unbounded,sans-serif">O</text>
<text x="160" y="34" font-size="13" font-weight="800" fill="#0284c7" font-family="Unbounded,sans-serif">A</text>
<text x="160" y="174" font-size="13" font-weight="800" fill="#0284c7" font-family="Unbounded,sans-serif">C</text>
<text x="138" y="105" font-size="13" font-weight="800" fill="#b45309" font-family="JetBrains Mono,monospace">α</text>
<text x="200" y="100" font-size="12" font-weight="800" fill="#dc2626" font-family="JetBrains Mono,monospace">⌣AC = α°</text>
<text x="20" y="22" font-size="10" font-weight="700" fill="#0891b2">центральный угол ∠AOC</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 280 190" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<!-- O=(110,100) R=70. A at top (angle -90°)=(110,30). C at angle 30°: (110+70·cos30°, 100+70·sin30°)=(170.6, 135). -->
<!-- Sector fill -->
<path d="M 110,100 L 110,30 A 70,70 0 0,1 171,135 Z" fill="rgba(245,158,11,.15)" stroke="none"/>
<!-- Highlighted arc -->
<path d="M 110,30 A 70,70 0 0,1 171,135" fill="none" stroke="#ef4444" stroke-width="4"/>
<!-- Circle outline -->
<circle cx="110" cy="100" r="70" fill="none" stroke="#0891b2" stroke-width="2"/>
<!-- Radii (solid for visibility, with labels) -->
<line x1="110" y1="100" x2="110" y2="30" stroke="#0891b2" stroke-width="2"/>
<line x1="110" y1="100" x2="171" y2="135" stroke="#0891b2" stroke-width="2"/>
<!-- Angle α arc at center -->
<path d="M 110,72 A 28,28 0 0,1 134,114" fill="none" stroke="#f59e0b" stroke-width="2.4"/>
<!-- Center dot and vertex dots -->
<circle cx="110" cy="100" r="3.5" fill="#0e7490"/>
<circle cx="110" cy="30" r="4" fill="#0284c7"/>
<circle cx="171" cy="135" r="4" fill="#0284c7"/>
<!-- R label on radius OA -->
<text x="92" y="68" font-size="13" font-weight="800" fill="#0284c7" font-family="JetBrains Mono,monospace">R</text>
<!-- Labels -->
<text x="93" y="105" font-size="13" font-weight="800" fill="#0e7490" font-family="Unbounded,sans-serif">O</text>
<text x="104" y="22" font-size="13" font-weight="800" fill="#0284c7" font-family="Unbounded,sans-serif">A</text>
<text x="176" y="143" font-size="13" font-weight="800" fill="#0284c7" font-family="Unbounded,sans-serif">C</text>
<text x="124" y="103" font-size="14" font-weight="800" fill="#b45309" font-family="JetBrains Mono,monospace">α</text>
<!-- formula label, off the arc -->
<text x="182" y="78" font-size="11" fill="#dc2626" font-weight="800" font-family="JetBrains Mono,monospace"></text>
<text x="20" y="22" font-size="10" font-weight="700" fill="#dc2626">красная дуга AC = </text>
<text x="20" y="182" font-size="11" font-weight="800" fill="#0369a1" font-family="JetBrains Mono,monospace"> = (α/360°)·2π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="72" cy="43" r="4" fill="#0891b2"/>
<circle cx="169" cy="56" r="4" fill="#0891b2"/>
<circle cx="84" cy="149" r="5" fill="#dc2626"/>
<line x1="115" y1="92" x2="72" y2="43" stroke="#06b6d4" stroke-width="1.8"/>
<line x1="115" y1="92" x2="169" y2="56" stroke="#06b6d4" stroke-width="1.8"/>
<line x1="84" y1="149" x2="72" y2="43" stroke="#dc2626" stroke-width="2"/>
<line x1="84" y1="149" x2="169" y2="56" stroke="#dc2626" stroke-width="2"/>
<path d="M 72,43 A 65,65 0 0,1 169,56" 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="38" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="173" y="52" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="70" y="162" 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="110" cy="133" r="4" fill="#0284c7"/>
<circle cx="161" cy="104" r="4" fill="#0284c7"/>
<line x1="110" y1="133" x2="110" y2="17" stroke="#0284c7" stroke-width="2"/>
<line x1="161" y1="104" x2="110" y2="17" stroke="#0284c7" stroke-width="2"/>
<line x1="110" y1="75" x2="161" y2="104" 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="115" y="140" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="165" y="107" font-size="11" font-weight="700" fill="#0284c7">C</text>
<text x="64" y="72" font-size="9" fill="#b45309">O на AB</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}" 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="69" cy="47" r="4" fill="#0284c7"/>
<circle cx="178" cy="54" r="4" fill="#0284c7"/>
<circle cx="75" cy="136" r="4.5" fill="#dc2626"/>
<circle cx="120" cy="154" r="4.5" fill="#10b981"/>
<circle cx="163" cy="138" r="4.5" fill="#7c3aed"/>
<line x1="75" y1="136" x2="69" y2="47" stroke="#dc2626" stroke-width="1.8"/>
<line x1="75" y1="136" x2="178" y2="54" stroke="#dc2626" stroke-width="1.8"/>
<line x1="120" y1="154" x2="69" y2="47" stroke="#10b981" stroke-width="1.8"/>
<line x1="120" y1="154" x2="178" y2="54" stroke="#10b981" stroke-width="1.8"/>
<line x1="163" y1="138" x2="69" y2="47" stroke="#7c3aed" stroke-width="1.8"/>
<line x1="163" y1="138" x2="178" y2="54" stroke="#7c3aed" stroke-width="1.8"/>
<path d="M 69,47 A 66,66 0 0,1 178,54" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="3"/>
<text x="54" y="42" 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="58" y="148" 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="167" y="152" 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="50" cy="43" r="3.5" fill="#0284c7"/>
<circle cx="153" cy="49" r="3.5" fill="#0284c7"/>
<circle cx="65" cy="118" r="4" fill="#dc2626"/>
<circle cx="100" cy="130" r="4" fill="#10b981"/>
<circle cx="135" cy="118" r="4" fill="#7c3aed"/>
<path d="M 50,43 A 58,58 0 0,1 153,49" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="2.5"/>
<line x1="65" y1="118" x2="50" y2="43" stroke="#dc2626" stroke-width="1.6"/>
<line x1="65" y1="118" x2="153" y2="49" stroke="#dc2626" stroke-width="1.6"/>
<line x1="100" y1="130" x2="50" y2="43" stroke="#10b981" stroke-width="1.6"/>
<line x1="100" y1="130" x2="153" y2="49" stroke="#10b981" stroke-width="1.6"/>
<line x1="135" y1="118" x2="50" y2="43" stroke="#7c3aed" stroke-width="1.6"/>
<line x1="135" y1="118" x2="153" y2="49" stroke="#7c3aed" stroke-width="1.6"/>
<text x="36" y="38" font-size="10" font-weight="700" fill="#0284c7">A</text>
<text x="157" y="45" font-size="10" font-weight="700" fill="#0284c7">C</text>
<text x="49" y="130" font-size="9" fill="#dc2626">B₁=40°</text>
<text x="93" y="142" font-size="9" fill="#10b981">B₂=40°</text>
<text x="128" y="130" 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="99" cy="30" r="5" fill="#dc2626"/>
<line x1="99" y1="30" x2="53" y2="90" stroke="#dc2626" stroke-width="2.2"/>
<line x1="99" y1="30" x2="177" y2="90" stroke="#dc2626" stroke-width="2.2"/>
<polyline points="94,37 101,43 106,36" 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="84" y="26" 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="73,27 80,33 85,25" 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 buildP12(){
const box=document.getElementById('p12-body');
let html='';
html+=makeCard('rule','Угол между касательной и хордой','12.1',`
<p><b>Теорема.</b> Угол между касательной и хордой, проведённой из точки касания, равен половине дуги, заключённой между ними.</p>
$$\\angle(l,AB) = \\dfrac{1}{2}\\,\\smile AB$$
<p style="margin-top:8px">Здесь $l$ — касательная к окружности в точке $A$, $AB$ — хорда из точки касания $A$. Дуга $\\smile AB$ — та, которая лежит «внутри» угла.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 180" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="120" cy="95" r="62" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<circle cx="120" cy="95" r="3" fill="#0891b2"/>
<circle cx="58" cy="95" r="4.5" fill="#dc2626"/>
<circle cx="103" cy="36" r="4" fill="#0284c7"/>
<line x1="20" y1="95" x2="200" y2="95" stroke="#dc2626" stroke-width="2.2"/>
<line x1="58" y1="95" x2="103" y2="36" stroke="#0284c7" stroke-width="2.2"/>
<line x1="120" y1="95" x2="58" y2="95" stroke="#64748b" stroke-width="1.4" stroke-dasharray="4,3"/>
<path d="M 58,95 A 62,62 0 0,1 103,36" fill="rgba(8,145,178,.18)" stroke="#0891b2" stroke-width="2.5"/>
<path d="M 75,95 A 17,17 0 0,1 68,83" fill="none" stroke="#e11d48" stroke-width="1.8"/>
<text x="8" y="91" font-size="10" fill="#dc2626" font-weight="700">l</text>
<text x="42" y="112" font-size="11" font-weight="700" fill="#dc2626">A</text>
<text x="88" y="30" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="122" y="91" font-size="10" font-weight="700" fill="#0891b2">O</text>
<text x="68" y="79" font-size="9" fill="#e11d48">&#945;</text>
<text x="175" y="72" font-size="9" fill="#0891b2">&#8978;AB</text>
<text x="175" y="84" font-size="9" fill="#e11d48">&#945; = &#189;&#8978;AB</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство (случай: O внутри угла)','12.2',`
<p>Пусть $l$ — касательная в $A$, $AB$ — хорда. Проведём диаметр $AC$ из точки $A$.</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li><b>Шаг 1.</b> Касательная перпендикулярна радиусу $OA$: $l \\perp OA$, значит $\\angle(l,AC) = 90°$.</li>
<li><b>Шаг 2.</b> Угол между $l$ и хордой $AB$: $\\angle(l,AB) = 90° - \\angle(AB,OA) = 90° - \\angle BAC'$, где $C'$ — точка на $l$. Точнее: $\\angle(l,AB) = \\angle CAB = $ вписанный угол на дуге $BC$... нет, используем другой подход.</li>
<li><b>Шаг 3 (прямо).</b> $\\angle(l,AB) = \\dfrac{1}{2}\\smile AB$ — следует из того, что $\\angle CAB = \\dfrac{1}{2}\\smile CB$ (вписанный), и $90° = \\dfrac{1}{2}\\cdot 180°$, поэтому $\\angle(l,AB) = 90° - \\angle CAB = \\dfrac{1}{2}(180° - \\smile CB) = \\dfrac{1}{2}\\smile AB$.</li>
</ol>
<p style="margin-top:8px"><b>ч.т.д.</b></p>`);
html+=makeCard('example','Пример применения','12.3',`
<p><b>Задача 1.</b> Касательная $l$ и хорда $AB$ образуют угол $35°$. Найди дугу $\\smile AB$.</p>
<p style="margin-top:8px"><b>Решение.</b> По теореме: $35° = \\dfrac{1}{2}\\smile AB$, значит $\\smile AB = 70°$.</p>
<p style="margin-top:10px"><b>Задача 2.</b> Дуга $\\smile AB = 110°$. Найди угол между касательной и хордой $AB$.</p>
<p style="margin-top:6px"><b>Решение.</b> $\\angle = \\dfrac{1}{2}\\cdot 110° = 55°$.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 240 150" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="105" cy="80" r="55" fill="rgba(8,145,178,.07)" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="105" cy="80" r="3" fill="#0891b2"/>
<circle cx="50" cy="80" r="4" fill="#dc2626"/>
<circle cx="93" cy="27" r="4" fill="#0284c7"/>
<line x1="10" y1="80" x2="180" y2="80" stroke="#dc2626" stroke-width="2"/>
<line x1="50" y1="80" x2="93" y2="27" stroke="#0284c7" stroke-width="2"/>
<path d="M 50,80 A 55,55 0 0,1 93,27" fill="rgba(8,145,178,.18)" stroke="#0891b2" stroke-width="2.5"/>
<text x="10" y="74" font-size="10" fill="#dc2626">l</text>
<text x="36" y="96" font-size="11" font-weight="700" fill="#dc2626">A</text>
<text x="80" y="22" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="134" y="58" font-size="9" fill="#0891b2">110°</text>
<text x="60" y="72" font-size="9" fill="#e11d48">55°</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — слайдер хорды */
html+=`<div class="wg" id="p12-slider-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Касательная и хорда: угол = ½ дуги</div></div>
<div class="wg-help">Двигай слайдер — меняй положение хорды $AB$. Наблюдай: угол всегда равен половине отсекаемой дуги.</div>
<div class="sliders">
<label>Дуга $AB$ = <b id="p12-arc-val">80</b>°
<input type="range" min="10" max="170" value="80" id="p12-arc-sl">
</label>
</div>
<div id="p12-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p12-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:var(--pri-soft,#cffafe);color:var(--pri2,#0e7490)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p12-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="p12-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p12-proof-text" style="padding:10px 14px;background:var(--pri-soft,#cffafe);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="p12-proof-next">Далее</button>
<button class="btn" id="p12-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">Дуга AB (°): <input type="number" id="p12-arc-inp" class="tinp" value="80" min="1" max="359" style="width:90px"></label>
<button class="btn primary" id="p12-arc2ang">→ угол</button>
<label style="font-size:.9rem">Угол (°): <input type="number" id="p12-ang-inp" class="tinp" value="40" min="1" max="179" style="width:90px"></label>
<button class="btn primary" id="p12-ang2arc">→ дуга</button>
</div>
<div id="p12-calc-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">Тренажёр §12</div></div>
<div class="wg-help">5 задач на угол между касательной и хордой.</div>
<div class="score-display"><span>Задача <b id="p12-tr-i">1</b> / 5</span><span>Очки: <b id="p12-tr-score">0</b></span></div>
<div id="p12-tr-task" style="padding:14px;background:var(--pri-soft,#cffafe);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="p12-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p12-tr-go">Проверить</button>
<button class="btn" id="p12-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p12-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — DnD */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 5</span><div class="wg-title">Верно или неверно?</div></div>
<div class="wg-help">Рассортируй утверждения об угле между касательной и хордой.</div>
<div id="p12-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="p12-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p12-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p12-dnd-check">Проверить</button><button class="btn" id="p12-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p12-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §12 */
html+=`<div class="wg" style="border-color:var(--pri2,#0e7490)">
<div class="wg-header"><span class="wg-badge" style="background:var(--pri2,#0e7490)">БОСС §12</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p12-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p12-read');bumpProgress('p12',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §12 (+10 XP)
</button>
</div>`;
html+=secNav('p11','p13');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдер хорды === */
(function(){
const sl=document.getElementById('p12-arc-sl');
const valEl=document.getElementById('p12-arc-val');
const svgWrap=document.getElementById('p12-svg-wrap');
const info=document.getElementById('p12-info');
const R=65, cx=130, cy=100, W=260, H=200;
function draw(){
const arcDeg=+sl.value;
valEl.textContent=arcDeg;
const ang=arcDeg/2;
// A is leftmost point of circle
const aA=Math.PI; // angle for A = 180deg => A=(cx-R, cy)
const Ax=cx+R*Math.cos(aA), Ay=cy+R*Math.sin(aA);
// B is at angle (PI - arcDeg*PI/180) from positive x-axis, going CCW from A
const aB=Math.PI - arcDeg*Math.PI/180;
const Bx=cx+R*Math.cos(aB), By=cy+R*Math.sin(aB);
// tangent at A is vertical (perpendicular to radius OA which is horizontal)
const tLen=50;
const T1x=Ax, T1y=Ay-tLen;
const T2x=Ax, T2y=Ay+tLen;
// arc indicator small
const large=arcDeg>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(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<path d="M ${Ax} ${Ay} A ${R} ${R} 0 ${large} 0 ${Bx} ${By}" fill="rgba(8,145,178,.2)" stroke="#0891b2" stroke-width="3"/>
<line x1="${T1x}" y1="${T1y}" x2="${T2x}" y2="${T2y}" stroke="#dc2626" stroke-width="2.5"/>
<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2.2"/>
<line x1="${cx}" y1="${cy}" x2="${Ax}" y2="${Ay}" stroke="#64748b" stroke-width="1.2" stroke-dasharray="4,3"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0891b2"/>
<circle cx="${Ax}" cy="${Ay}" r="5" fill="#dc2626"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<text x="${Ax-20}" y="${Ay+4}" font-size="12" font-weight="700" fill="#dc2626">A</text>
<text x="${Bx+(Bx>cx?7:-18)}" y="${By+(By<cy?-6:16)}" font-size="12" font-weight="700" fill="#0284c7">B</text>
<text x="${cx+4}" y="${cy-6}" font-size="10" font-weight="700" fill="#0891b2">O</text>
<text x="${T1x+4}" y="${T1y+10}" font-size="10" fill="#dc2626">l</text>
<text x="${(Ax+Bx)/2+6}" y="${(Ay+By)/2-8}" font-size="9" fill="#0891b2">${arcDeg}°</text>
<text x="${Ax+6}" y="${Ay-18}" font-size="10" font-weight="700" fill="#e11d48">${Math.round(ang)}°</text>
</svg>`;
info.textContent='Дуга AB = '+arcDeg+'° → Угол (l, AB) = '+Math.round(ang)+'° (= '+arcDeg+'°/2)';
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=55, cx=115, cy=85, W=250, H=175;
const aA=Math.PI;
const Ax=cx+R*Math.cos(aA), Ay=cy;
const aB=Math.PI-70*Math.PI/180;
const Bx=cx+R*Math.cos(aB), By=cy+R*Math.sin(aB);
// diameter through A: C is diametrically opposite to A
const Ccx=cx+R, Ccy=cy;
const steps=[
{text:'<b>Дано:</b> $l$ — касательная в точке $A$, $AB$ — хорда. Обозначим $\\angle(l,AB)=\\alpha$. Доказать: $\\alpha = \\dfrac{1}{2}\\smile AB$.'},
{text:'<b>Шаг 1.</b> Проведём диаметр $AC$ через точку $A$. Так как касательная перпендикулярна радиусу $OA$, то $l \\perp OA$, следовательно $\\angle(l,AC) = 90°$.'},
{text:'<b>Шаг 2.</b> Угол $\\angle BAC$ — вписанный, опирается на дугу $\\smile BC$. По теореме §9: $\\angle BAC = \\dfrac{1}{2}\\smile BC$.'},
{text:'<b>Шаг 3.</b> Из рисунка: $\\alpha = \\angle(l,AB) = 90° - \\angle BAC = 90° - \\dfrac{1}{2}\\smile BC = \\dfrac{1}{2}(180° - \\smile BC) = \\dfrac{1}{2}\\smile AB$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p12-proof-svg'), txtEl=document.getElementById('p12-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<line x1="${Ax}" y1="${Ay}" x2="${Ccx}" y2="${Ccy}" stroke="#f59e0b" stroke-width="2" stroke-dasharray="5,3"/>`;
ex+=`<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#f59e0b"/>`;
ex+=`<text x="${Ccx+6}" y="${Ccy+4}" font-size="11" font-weight="700" fill="#b45309">C</text>`;
ex+=`<text x="${Ax-4}" y="${Ay-30}" font-size="9" fill="#dc2626">90°</text>`;
}
if(step>=2){
ex+=`<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2"/>`;
ex+=`<text x="${(Ax+Bx)/2-14}" y="${(Ay+By)/2-6}" font-size="9" fill="#0284c7">∠BAC</text>`;
}
if(step>=3){
ex+=`<text x="${Ax+6}" y="${Ay-18}" font-size="10" font-weight="700" fill="#e11d48">α=½⌢AB</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(8,145,178,.07)" stroke="#0891b2" stroke-width="2"/>
<line x1="${Ax}" y1="${Ay-55}" x2="${Ax}" y2="${Ay+55}" stroke="#dc2626" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0891b2"/>
<circle cx="${Ax}" cy="${Ay}" r="5" fill="#dc2626"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<text x="${Ax-18}" y="${Ay+4}" font-size="11" font-weight="700" fill="#dc2626">A</text>
<text x="${Bx+(Bx>cx?7:-18)}" y="${By-5}" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="${cx+4}" y="${cy-6}" font-size="9" fill="#0891b2">O</text>
<text x="${Ax-12}" y="${Ay-58}" font-size="9" fill="#dc2626">l</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p12-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p12-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p12-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p12-arc2ang').addEventListener('click',()=>{
const v=parseFloat(document.getElementById('p12-arc-inp').value);
const out=document.getElementById('p12-calc-out');
out.style.display='block';
if(isNaN(v)||v<=0||v>=360){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите дугу от 1 до 359°.';return;}
out.style.background='var(--pri-soft,#cffafe)';out.style.color='var(--pri2,#0e7490)';
out.textContent='Дуга '+v+'° → Угол = '+v+'°/2 = '+(v/2)+'°';
});
document.getElementById('p12-ang2arc').addEventListener('click',()=>{
const v=parseFloat(document.getElementById('p12-ang-inp').value);
const out=document.getElementById('p12-calc-out');
out.style.display='block';
if(isNaN(v)||v<=0||v>=180){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите угол от 1 до 179°.';return;}
out.style.background='var(--pri-soft,#cffafe)';out.style.color='var(--pri2,#0e7490)';
out.textContent='Угол '+v+'° → Дуга AB = 2·'+v+'° = '+(2*v)+'°';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'Угол между касательной $l$ и хордой $AB$ равен $40°$. Найди дугу $\\smile AB$.',a:80,hint:'Дуга = 2·40° = 80°'},
{q:'Дуга $\\smile AB = 130°$. Найди угол между касательной в точке $A$ и хордой $AB$.',a:65,hint:'Угол = 130°/2 = 65°'},
{q:'Угол между касательной и хордой $= 90°$. Чему равна дуга, отсекаемая хордой?',a:180,hint:'Дуга = 2·90° = 180°, значит хорда — диаметр'},
{q:'Угол между касательной и хордой $= 45°$. Найди дугу.',a:90,hint:'Дуга = 2·45° = 90°'},
{q:'Дуга $\\smile AB = 54°$. Угол между касательной в точке $A$ и хордой $AB$:',a:27,hint:'Угол = 54°/2 = 27°'},
];
let cur=0, score=0;
const iEl=document.getElementById('p12-tr-i'), scEl=document.getElementById('p12-tr-score');
const taskEl=document.getElementById('p12-tr-task'), ansEl=document.getElementById('p12-tr-ans');
const goBtn=document.getElementById('p12-tr-go'), startBtn=document.getElementById('p12-tr-start');
const fb=document.getElementById('p12-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,'p12-trainer');bumpProgress('p12',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:'Угол (касательная, хорда) = ½ дуги',cat:'true'},
{label:'Угол (касательная, хорда) = дуге целиком',cat:'false'},
{label:'Если дуга AB = 100°, угол = 50°',cat:'true'},
{label:'Угол между касательной и хордой может быть больше 90°',cat:'false'},
{label:'Если угол = 90°, то хорда — диаметр',cat:'true'},
{label:'Касательная параллельна хорде всегда',cat:'false'},
];
const pool=document.getElementById('p12-dnd-pool');
const boxes={true:document.getElementById('p12-drop-true-items'),false:document.getElementById('p12-drop-false-items')};
const fb=document.getElementById('p12-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,bx])=>{
bx.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;
bx.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p12-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,'p12-dnd');bumpProgress('p12',15);}
});
document.getElementById('p12-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §12 === */
(function(){
const tasks=[
{q:'Угол между касательной и хордой $AB = 35°$. Дуга $\\smile AB$:',
opts:['70°','35°','17,5°'],cor:0,
exp:'$\\smile AB = 2 \\cdot 35° = 70°$.'},
{q:'Дуга $\\smile AB = 160°$. Угол между касательной в $A$ и хордой $AB$:',
opts:['80°','160°','40°'],cor:0,
exp:'Угол $= \\dfrac{1}{2}\\cdot 160° = 80°$.'},
{q:'Угол между касательной и хордой $= 60°$. Дуга между ними:',
opts:['120°','60°','30°'],cor:0,
exp:'Дуга $= 2\\cdot 60° = 120°$.'},
{q:'Если хорда — диаметр, угол между касательной в точке начала диаметра и диаметром равен:',
opts:['90°','180°','45°'],cor:0,
exp:'Диаметр стягивает дугу $180°$. Угол $= \\dfrac{1}{2}\\cdot 180° = 90°$.'},
];
const cont=document.getElementById('p12-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-boss12="p12-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss12=\\'p12-${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('p12-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,'p12-boss-${i}');bumpProgress('p12',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p12-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--pri-soft,#cffafe);color:var(--pri2,#0e7490);line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP13(){
const box=document.getElementById('p13-body');
let html='';
html+=makeCard('rule','Угол между двумя хордами','13.1',`
<p><b>Теорема.</b> Угол между двумя хордами, пересекающимися внутри окружности, равен полусумме двух дуг: той, которую он «охватывает», и противоположной.</p>
$$\\angle APС = \\dfrac{1}{2}(\\smile AC + \\smile BD)$$
<p style="margin-top:8px">Хорды $AB$ и $CD$ пересекаются в точке $P$ внутри окружности. Угол $\\angle APC$ (и вертикальный ему $\\angle BPD$) равен полусумме дуг $\\smile AC$ и $\\smile BD$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 280 180" style="max-width:300px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="120" cy="90" r="65" fill="rgba(6,182,212,.07)" stroke="#06b6d4" stroke-width="2"/>
<circle cx="120" cy="90" r="3" fill="#0891b2"/>
<circle cx="59" cy="68" r="4" fill="#0284c7"/>
<circle cx="184" cy="79" r="4" fill="#0284c7"/>
<circle cx="142" cy="29" r="4" fill="#dc2626"/>
<circle cx="98" cy="151" r="4" fill="#dc2626"/>
<line x1="59" y1="68" x2="184" y2="79" stroke="#0284c7" stroke-width="2"/>
<line x1="142" y1="29" x2="98" y2="151" stroke="#dc2626" stroke-width="2"/>
<circle cx="126" cy="74" r="4.5" fill="#7c3aed"/>
<path d="M 59,68 A 65,65 0 0,0 142,29" fill="rgba(6,182,212,.2)" stroke="#06b6d4" stroke-width="2.5"/>
<path d="M 184,79 A 65,65 0 0,0 98,151" fill="rgba(220,38,38,.15)" stroke="#dc2626" stroke-width="2.5"/>
<text x="43" y="64" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="188" y="83" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="146" y="24" font-size="11" font-weight="700" fill="#dc2626">C</text>
<text x="82" y="166" font-size="11" font-weight="700" fill="#dc2626">D</text>
<text x="110" y="71" font-size="11" font-weight="700" fill="#7c3aed">P</text>
<text x="5" y="110" font-size="9" fill="#0891b2">½(⌢AC+⌢BD)</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство','13.2',`
<p>Хорды $AB$ и $CD$ пересекаются в $P$. Соединим $A$ с $D$ — получим треугольник $\\triangle APD$... нет, выберем правильно: соединим $AD$.</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li><b>Шаг 1.</b> Соединим $A$ и $D$. Рассмотрим $\\triangle APD$ (вершины $A$, $P$, $D$).</li>
<li><b>Шаг 2.</b> Угол $\\angle ADP$ — вписанный, опирается на дугу $\\smile AC$ (от $A$ до $C$ через вершины хорды $AB$). По теореме §9: $\\angle DAB = \\dfrac{1}{2}\\smile BD$.</li>
<li><b>Шаг 3.</b> Угол $\\angle DAB$ — вписанный, опирается на $\\smile DB$: $\\angle DAB = \\dfrac{1}{2}\\smile DB$. Угол $\\angle ADP$ опирается на $\\smile AC$: $\\angle ADP = \\dfrac{1}{2}\\smile AC$.</li>
<li><b>Шаг 4.</b> По теореме о внешнем угле треугольника: $\\angle APC = \\angle DAB + \\angle ADB = \\dfrac{1}{2}\\smile BD + \\dfrac{1}{2}\\smile AC = \\dfrac{1}{2}(\\smile AC + \\smile BD)$. <b>ч.т.д.</b></li>
</ol>`);
html+=makeCard('example','Примеры','13.3',`
<p><b>Задача 1.</b> Хорды пересекаются внутри окружности. Дуга $\\smile AC = 80°$, дуга $\\smile BD = 60°$. Найди угол при пересечении.</p>
<p style="margin-top:8px"><b>Решение.</b> $\\angle = \\dfrac{1}{2}(80° + 60°) = \\dfrac{140°}{2} = 70°$.</p>
<p style="margin-top:10px"><b>Задача 2.</b> Угол при пересечении хорд $= 85°$, одна из дуг $= 90°$. Найди вторую дугу.</p>
<p style="margin-top:6px"><b>Решение.</b> $85° = \\dfrac{1}{2}(90° + x)$ ⟹ $x = 2\\cdot 85° - 90° = 80°$.</p>`);
/* ИНТЕРАКТИВ 1 — слайдер дуг */
html+=`<div class="wg" id="p13-slider-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>Дуга AC = <b id="p13-arc1-val">80</b>°
<input type="range" min="10" max="160" value="80" id="p13-arc1-sl">
</label>
<label>Дуга BD = <b id="p13-arc2-val">60</b>°
<input type="range" min="10" max="160" value="60" id="p13-arc2-sl">
</label>
</div>
<div id="p13-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p13-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:var(--acc-soft,#a5f3fc);color:var(--acc2,#0891b2)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p13-proof-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Доказательство по шагам</div></div>
<div class="wg-help">Нажимай «Далее» — каждый шаг раскрывает ключевую идею.</div>
<div id="p13-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p13-proof-text" style="padding:10px 14px;background:var(--acc-soft,#a5f3fc);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="p13-proof-next">Далее</button>
<button class="btn" id="p13-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: угол между хордами</div></div>
<div class="wg-help">Введи две дуги — получи угол. Или угол и одну дугу — найди вторую дугу.</div>
<div style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px">
<label style="font-size:.9rem">Дуга 1 (°): <input type="number" id="p13-d1" class="tinp" value="80" min="1" max="350" style="width:80px"></label>
<label style="font-size:.9rem">Дуга 2 (°): <input type="number" id="p13-d2" class="tinp" value="60" min="1" max="350" style="width:80px"></label>
<button class="btn primary" id="p13-calc-ang">→ угол</button>
<label style="font-size:.9rem">Угол (°): <input type="number" id="p13-ang" class="tinp" value="70" min="1" max="179" style="width:80px"></label>
<button class="btn primary" id="p13-calc-arc">→ дуга 2</button>
</div>
<div id="p13-calc-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">Тренажёр §13</div></div>
<div class="wg-help">5 задач на угол между хордами внутри окружности.</div>
<div class="score-display"><span>Задача <b id="p13-tr-i">1</b> / 5</span><span>Очки: <b id="p13-tr-score">0</b></span></div>
<div id="p13-tr-task" style="padding:14px;background:var(--acc-soft,#a5f3fc);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="p13-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p13-tr-go">Проверить</button>
<button class="btn" id="p13-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p13-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 5 — 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="p13-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="p13-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p13-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p13-dnd-check">Проверить</button><button class="btn" id="p13-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p13-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §13 */
html+=`<div class="wg" style="border-color:var(--acc2,#0891b2)">
<div class="wg-header"><span class="wg-badge" style="background:var(--acc2,#0891b2)">БОСС §13</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p13-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p13-read');bumpProgress('p13',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §13 (+10 XP)
</button>
</div>`;
html+=secNav('p12','p14');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдеры дуг === */
(function(){
const sl1=document.getElementById('p13-arc1-sl'), sl2=document.getElementById('p13-arc2-sl');
const v1=document.getElementById('p13-arc1-val'), v2=document.getElementById('p13-arc2-val');
const svgWrap=document.getElementById('p13-svg-wrap'), info=document.getElementById('p13-info');
const R=64, cx=128, cy=95, W=256, H=192;
function draw(){
const a1=+sl1.value, a2=+sl2.value;
v1.textContent=a1; v2.textContent=a2;
const ang=Math.round((a1+a2)/2);
// Place A, C, B, D on circle such that arc AC = a1, arc BD = a2
// A at 200deg, C at 200+a1, B at 200+a1+50 (gap), D at 200+a1+50+a2
const aA=200*Math.PI/180;
const aC=(200+a1)*Math.PI/180;
const aB=(200+a1+a2+20)*Math.PI/180;
const aD=(200+a1+a2+20+a2)*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);
const Dx=cx+R*Math.cos(aD), Dy=cy+R*Math.sin(aD);
// intersection of chords AC and BD — line-line intersection
const denom=(Ax-Ccx)*(By-Dy)-(Ay-Ccy)*(Bx-Dx);
let Px=cx, Py=cy;
if(Math.abs(denom)>0.01){
const t=((Ax-Bx)*(By-Dy)-(Ay-By)*(Bx-Dx))/denom;
Px=Ax+t*(Ccx-Ax); Py=Ay+t*(Ccy-Ay);
}
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 ${a1>180?1:0} 1 ${Ccx} ${Ccy}" fill="rgba(6,182,212,.2)" stroke="#06b6d4" stroke-width="3"/>
<path d="M ${Bx} ${By} A ${R} ${R} 0 ${a2>180?1:0} 1 ${Dx} ${Dy}" fill="rgba(220,38,38,.15)" stroke="#dc2626" stroke-width="2.5"/>
<line x1="${Ax}" y1="${Ay}" x2="${Ccx}" y2="${Ccy}" stroke="#0284c7" stroke-width="2.2"/>
<line x1="${Bx}" y1="${By}" x2="${Dx}" y2="${Dy}" stroke="#dc2626" stroke-width="2.2"/>
<circle cx="${cx}" cy="${cy}" r="3" 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="4" fill="#dc2626"/>
<circle cx="${Dx}" cy="${Dy}" r="4" fill="#dc2626"/>
<circle cx="${Px}" cy="${Py}" r="5" fill="#7c3aed"/>
<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="${Bx+(Bx>cx?7:-16)}" y="${By+(By>cy?15:-4)}" font-size="11" font-weight="700" fill="#dc2626">B</text>
<text x="${Dx+(Dx>cx?7:-16)}" y="${Dy+(Dy>cy?15:-4)}" font-size="11" font-weight="700" fill="#dc2626">D</text>
<text x="${Px+6}" y="${Py-5}" font-size="10" font-weight="700" fill="#7c3aed">P</text>
<text x="${Px+8}" y="${Py+14}" font-size="10" font-weight="700" fill="#7c3aed">${ang}°</text>
<text x="${cx}" y="${cy-R-10}" text-anchor="middle" font-size="9" fill="#06b6d4">⌢AC=${a1}°</text>
<text x="${cx}" y="${cy+R+16}" text-anchor="middle" font-size="9" fill="#dc2626">⌢BD=${a2}°</text>
</svg>`;
info.textContent='⌢AC = '+a1+'°, ⌢BD = '+a2+'° → Угол = ½('+a1+'+'+a2+') = '+ang+'°';
}
sl1.addEventListener('input',draw); sl2.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=55, cx=115, cy=85, W=250, H=175;
const aA=220*Math.PI/180, aC=10*Math.PI/180;
const aB=130*Math.PI/180, aD=300*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);
const Dx=cx+R*Math.cos(aD), Dy=cy+R*Math.sin(aD);
const denom=(Ax-Ccx)*(By-Dy)-(Ay-Ccy)*(Bx-Dx);
const t=((Ax-Bx)*(By-Dy)-(Ay-By)*(Bx-Dx))/denom;
const Px=Ax+t*(Ccx-Ax), Py=Ay+t*(Ccy-Ay);
const steps=[
{text:'<b>Дано:</b> хорды $AB$ и $CD$ пересекаются в точке $P$ внутри окружности. Обозначим: $\\smile AC$ — дуга между $A$ и $C$ (со стороны угла $\\angle APC$), $\\smile BD$ — противоположная дуга.'},
{text:'<b>Шаг 1.</b> Соединим $A$ и $D$. Рассмотрим треугольник $\\triangle APD$. Угол $\\angle APC$ является внешним углом этого треугольника при вершине $P$.'},
{text:'<b>Шаг 2.</b> По теореме о внешнем угле треугольника: $\\angle APC = \\angle PAD + \\angle PDA$. Угол $\\angle PAD = \\angle BAD$ — вписанный, опирается на $\\smile BD$: $\\angle BAD = \\dfrac{1}{2}\\smile BD$.'},
{text:'<b>Шаг 3.</b> Угол $\\angle PDA = \\angle CDA$ — вписанный, опирается на $\\smile CA$: $\\angle CDA = \\dfrac{1}{2}\\smile AC$. Итого: $\\angle APC = \\dfrac{1}{2}\\smile BD + \\dfrac{1}{2}\\smile AC = \\dfrac{1}{2}(\\smile AC + \\smile BD)$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p13-proof-svg'), txtEl=document.getElementById('p13-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<line x1="${Ax}" y1="${Ay}" x2="${Dx}" y2="${Dy}" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="5,3"/>`;
}
if(step>=2){
ex+=`<text x="${(Ax+Px)/2-14}" y="${(Ay+Py)/2+6}" font-size="9" fill="#b45309">∠BAD</text>`;
}
if(step>=3){
ex+=`<text x="${(Dx+Px)/2+4}" y="${(Dy+Py)/2}" font-size="9" fill="#0891b2">∠CDA</text>`;
ex+=`<text x="${Px+6}" y="${Py-8}" font-size="10" font-weight="700" fill="#7c3aed">∠APC</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="${Ccx}" y2="${Ccy}" stroke="#0284c7" stroke-width="2"/>
<line x1="${Bx}" y1="${By}" x2="${Dx}" y2="${Dy}" stroke="#dc2626" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3" 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="4" fill="#dc2626"/>
<circle cx="${Dx}" cy="${Dy}" r="4" fill="#dc2626"/>
<circle cx="${Px}" cy="${Py}" r="4.5" fill="#7c3aed"/>
<text x="${Ax+(Ax>cx?7:-16)}" y="${Ay+(Ay>cy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">A</text>
<text x="${Ccx+(Ccx>cx?7:-16)}" y="${Ccy+(Ccy>cy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">C</text>
<text x="${Bx+(Bx>cx?7:-16)}" y="${By+(By>cy?14:-4)}" font-size="10" font-weight="700" fill="#dc2626">B</text>
<text x="${Dx+(Dx>cx?7:-16)}" y="${Dy+(Dy>cy?14:-4)}" font-size="10" font-weight="700" fill="#dc2626">D</text>
<text x="${Px+5}" y="${Py+4}" font-size="10" font-weight="700" fill="#7c3aed">P</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p13-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p13-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p13-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p13-calc-ang').addEventListener('click',()=>{
const d1=parseFloat(document.getElementById('p13-d1').value);
const d2=parseFloat(document.getElementById('p13-d2').value);
const out=document.getElementById('p13-calc-out');
out.style.display='block';
if(isNaN(d1)||isNaN(d2)||d1<=0||d2<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите положительные дуги.';return;}
out.style.background='var(--acc-soft,#a5f3fc)';out.style.color='var(--acc2,#0891b2)';
out.textContent='Угол = ½('+d1+'+'+d2+') = '+(d1+d2)/2+'°';
});
document.getElementById('p13-calc-arc').addEventListener('click',()=>{
const ang=parseFloat(document.getElementById('p13-ang').value);
const d1=parseFloat(document.getElementById('p13-d1').value);
const out=document.getElementById('p13-calc-out');
out.style.display='block';
if(isNaN(ang)||isNaN(d1)||ang<=0||d1<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите угол и дугу 1.';return;}
const d2=2*ang-d1;
if(d2<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Дуга 2 должна быть положительной.';return;}
out.style.background='var(--acc-soft,#a5f3fc)';out.style.color='var(--acc2,#0891b2)';
out.textContent='Дуга 2 = 2·'+ang+' '+d1+' = '+d2+'°';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'Хорды пересекаются внутри окружности. Дуга $\\smile AC = 70°$, дуга $\\smile BD = 50°$. Угол при пересечении:',a:60,hint:'½(70+50) = 60°'},
{q:'Угол при пересечении хорд $= 75°$, одна дуга $= 80°$. Найди вторую дугу.',a:70,hint:'2·7580 = 70°'},
{q:'Обе дуги равны $100°$. Угол при пересечении хорд:',a:100,hint:'½(100+100) = 100°'},
{q:'Дуга $\\smile AC = 120°$, дуга $\\smile BD = 40°$. Угол при пересечении хорд:',a:80,hint:'½(120+40) = 80°'},
{q:'Угол при пересечении $= 90°$, дуга $\\smile AC = \\smile BD$. Чему равна каждая дуга?',a:90,hint:'½(x+x)=90° ⟹ x=90°'},
];
let cur=0, score=0;
const iEl=document.getElementById('p13-tr-i'), scEl=document.getElementById('p13-tr-score');
const taskEl=document.getElementById('p13-tr-task'), ansEl=document.getElementById('p13-tr-ans');
const goBtn=document.getElementById('p13-tr-go'), startBtn=document.getElementById('p13-tr-start');
const fb=document.getElementById('p13-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,'p13-trainer');bumpProgress('p13',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:'Угол между хордами = ½(сумма двух дуг)',cat:'true'},
{label:'Угол между хордами = разности двух дуг',cat:'false'},
{label:'Если обе дуги по 90°, угол = 90°',cat:'true'},
{label:'Угол между хордами всегда острый',cat:'false'},
{label:'Вертикальные углы при пересечении хорд равны',cat:'true'},
{label:'Угол при пересечении = вписанному углу',cat:'false'},
];
const pool=document.getElementById('p13-dnd-pool');
const boxes={true:document.getElementById('p13-drop-true-items'),false:document.getElementById('p13-drop-false-items')};
const fb=document.getElementById('p13-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,bx])=>{
bx.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;
bx.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p13-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,'p13-dnd');bumpProgress('p13',15);}
});
document.getElementById('p13-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §13 === */
(function(){
const tasks=[
{q:'Дуги $\\smile AC = 50°$, $\\smile BD = 90°$. Угол при пересечении хорд:',
opts:['70°','140°','45°'],cor:0,
exp:'$\\angle = \\dfrac{1}{2}(50+90) = 70°$.'},
{q:'Угол при пересечении $= 100°$, одна дуга $= 120°$. Другая дуга:',
opts:['80°','60°','200°'],cor:0,
exp:'$2\\cdot100 - 120 = 80°$.'},
{q:'Две хорды пересекаются в центре окружности. Угол между ними равен:',
opts:['Центральному углу','Вписанному углу','Может быть любым'],cor:2,
exp:'Если хорды пересекаются в центре, это два диаметра. Угол определяется расположением точек.'},
{q:'Дуга $\\smile AC = \\smile BD = 80°$. Угол при пересечении хорд:',
opts:['80°','40°','160°'],cor:0,
exp:'$\\angle = \\dfrac{1}{2}(80+80) = 80°$.'},
];
const cont=document.getElementById('p13-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-boss13="p13-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss13=\\'p13-${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('p13-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,'p13-boss-${i}');bumpProgress('p13',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p13-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--acc-soft,#a5f3fc);color:var(--acc2,#0891b2);line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP14(){
const box=document.getElementById('p14-body');
let html='';
html+=makeCard('rule','Угол между двумя секущими из внешней точки','14.1',`
<p><b>Теорема.</b> Угол между двумя секущими, проведёнными из одной точки вне окружности, равен полуразности дуг, заключённых между секущими (большей минус меньшей).</p>
$$\\angle P = \\dfrac{1}{2}(\\smile AB - \\smile CD)$$
<p style="margin-top:8px">$P$ — внешняя точка; секущие пересекают окружность в точках $A$, $B$ и $C$, $D$ соответственно ($PA < PB$, $PC < PD$). Дуга $\\smile AB$ — дальняя (большая), $\\smile CD$ — ближняя (меньшая).</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 300 180" style="max-width:310px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="140" cy="90" r="60" fill="rgba(2,132,199,.07)" stroke="#0284c7" stroke-width="2"/>
<circle cx="140" cy="90" r="3" fill="#0369a1"/>
<circle cx="260" cy="90" r="4.5" fill="#0891b2"/>
<circle cx="195" cy="66" r="4" fill="#dc2626"/>
<circle cx="113" cy="36" r="4" fill="#dc2626"/>
<circle cx="199" cy="101" r="4" fill="#0284c7"/>
<circle cx="88" cy="120" r="4" fill="#0284c7"/>
<line x1="260" y1="90" x2="97" y2="22" stroke="#dc2626" stroke-width="2"/>
<line x1="260" y1="90" x2="74" y2="130" stroke="#0284c7" stroke-width="2"/>
<path d="M 113,36 A 60,60 0 0,1 88,120" fill="rgba(220,38,38,.2)" stroke="#dc2626" stroke-width="3"/>
<path d="M 195,66 A 60,60 0 0,1 199,101" fill="rgba(2,132,199,.2)" stroke="#0284c7" stroke-width="2.5"/>
<text x="258" y="108" font-size="12" font-weight="700" fill="#0891b2">P</text>
<text x="199" y="62" font-size="11" font-weight="700" fill="#dc2626">C</text>
<text x="97" y="30" font-size="11" font-weight="700" fill="#dc2626">A</text>
<text x="203" y="105" font-size="11" font-weight="700" fill="#0284c7">D</text>
<text x="72" y="136" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="6" y="90" font-size="9" fill="#0891b2">∠P = ½(⌢AB ⌢CD)</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство','14.2',`
<p>Пусть секущие из точки $P$ пересекают окружность в $C, A$ и $D, B$ ($C$ и $D$ ближе к $P$, $A$ и $B$ дальше). Соединим $A$ и $D$.</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li><b>Шаг 1.</b> В треугольнике $\\triangle PAD$ угол $\\angle P$ является внутренним. Угол $\\angle ADB$ — внешний угол треугольника $\\triangle PCD$ при вершине $D$... рассмотрим иначе.</li>
<li><b>Шаг 2.</b> $\\angle CAD$ — вписанный угол, опирается на $\\smile CD$: $\\angle CAD = \\dfrac{1}{2}\\smile CD$.</li>
<li><b>Шаг 3.</b> $\\angle ADB$ — вписанный угол (= $\\angle ADP$), опирается на $\\smile AB$: $\\angle ADB = \\dfrac{1}{2}\\smile AB$.</li>
<li><b>Шаг 4.</b> В треугольнике $\\triangle PAD$: $\\angle ADB$ — внешний угол при $D$. Поэтому $\\angle ADB = \\angle P + \\angle PAD$, откуда $\\angle P = \\angle ADB - \\angle CAD = \\dfrac{1}{2}\\smile AB - \\dfrac{1}{2}\\smile CD = \\dfrac{1}{2}(\\smile AB - \\smile CD)$. <b>ч.т.д.</b></li>
</ol>`);
html+=makeCard('example','Примеры','14.3',`
<p><b>Задача 1.</b> Угол при внешней точке $= 30°$, бо́льшая дуга $= 130°$. Найди меньшую дугу.</p>
<p style="margin-top:8px"><b>Решение.</b> $30 = \\dfrac{1}{2}(130 - x)$, $60 = 130 - x$, $x = 70°$.</p>
<p style="margin-top:10px"><b>Задача 2.</b> Дуга $\\smile AB = 150°$, дуга $\\smile CD = 50°$. Угол $P$:</p>
<p style="margin-top:6px"><b>Решение.</b> $\\angle P = \\dfrac{1}{2}(150 - 50) = 50°$.</p>`);
/* ИНТЕРАКТИВ 1 — слайдер */
html+=`<div class="wg" id="p14-slider-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>Дуга AB (большая) = <b id="p14-arcB-val">140</b>°
<input type="range" min="20" max="200" value="140" id="p14-arcB-sl">
</label>
<label>Дуга CD (меньшая) = <b id="p14-arcS-val">40</b>°
<input type="range" min="5" max="100" value="40" id="p14-arcS-sl">
</label>
</div>
<div id="p14-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p14-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:var(--pri-soft,#cffafe);color:var(--pri2,#0e7490)"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p14-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="p14-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p14-proof-text" style="padding:10px 14px;background:var(--pri-soft,#cffafe);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="p14-proof-next">Далее</button>
<button class="btn" id="p14-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="p14-big" class="tinp" value="140" min="1" max="358" style="width:80px"></label>
<label style="font-size:.9rem">Мал. дуга (°): <input type="number" id="p14-sml" class="tinp" value="40" min="1" max="179" style="width:80px"></label>
<button class="btn primary" id="p14-calc-ang">→ угол</button>
<label style="font-size:.9rem">Угол P (°): <input type="number" id="p14-ang" class="tinp" value="50" min="1" max="89" style="width:80px"></label>
<button class="btn primary" id="p14-calc-sml">→ мал. дугу</button>
</div>
<div id="p14-calc-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">Тренажёр §14</div></div>
<div class="wg-help">5 задач на угол между секущими из внешней точки.</div>
<div class="score-display"><span>Задача <b id="p14-tr-i">1</b> / 5</span><span>Очки: <b id="p14-tr-score">0</b></span></div>
<div id="p14-tr-task" style="padding:14px;background:var(--pri-soft,#cffafe);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="p14-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p14-tr-go">Проверить</button>
<button class="btn" id="p14-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p14-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 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="p14-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="p14-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p14-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p14-dnd-check">Проверить</button><button class="btn" id="p14-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p14-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §14 */
html+=`<div class="wg" style="border-color:var(--pri2,#0e7490)">
<div class="wg-header"><span class="wg-badge" style="background:var(--pri2,#0e7490)">БОСС §14</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p14-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p14-read');bumpProgress('p14',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §14 (+10 XP)
</button>
</div>`;
html+=secNav('p13','p15');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдеры дуг === */
(function(){
const slB=document.getElementById('p14-arcB-sl'), slS=document.getElementById('p14-arcS-sl');
const vB=document.getElementById('p14-arcB-val'), vS=document.getElementById('p14-arcS-val');
const svgWrap=document.getElementById('p14-svg-wrap'), info=document.getElementById('p14-info');
const R=60, cx=125, cy=90, W=300, H=184;
const Px=278, Py=90;
function draw(){
let arcB=+slB.value, arcS=+slS.value;
if(arcS>=arcB-5){arcS=arcB-5;slS.value=arcS;}
vB.textContent=arcB; vS.textContent=arcS;
const ang=Math.round((arcB-arcS)/2);
// A, B endpoints of far chord: arc AB = arcB, symmetric about horizontal from center
const halfB=arcB/2*Math.PI/180;
const Ax=cx+R*Math.cos(Math.PI+halfB), Ay=cy+R*Math.sin(Math.PI+halfB);
const Bx=cx+R*Math.cos(Math.PI-halfB), By=cy+R*Math.sin(Math.PI-halfB);
// C, D endpoints of near chord: arc CD = arcS, symmetric
const halfS=arcS/2*Math.PI/180;
const Ccx=cx+R*Math.cos(Math.PI+halfS), Ccy=cy+R*Math.sin(Math.PI+halfS);
const Dx=cx+R*Math.cos(Math.PI-halfS), Dy=cy+R*Math.sin(Math.PI-halfS);
const large=arcB>180?1:0;
const largeS=arcS>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(2,132,199,.07)" stroke="#0284c7" stroke-width="2"/>
<path d="M ${Ax} ${Ay} A ${R} ${R} 0 ${large} 1 ${Bx} ${By}" fill="rgba(220,38,38,.18)" stroke="#dc2626" stroke-width="3"/>
<path d="M ${Ccx} ${Ccy} A ${R} ${R} 0 ${largeS} 1 ${Dx} ${Dy}" fill="rgba(2,132,199,.18)" stroke="#0284c7" stroke-width="2.5"/>
<line x1="${Px}" y1="${Py}" x2="${Ax+(Ax-Px)*0.05}" y2="${Ay+(Ay-Py)*0.05}" stroke="#dc2626" stroke-width="2"/>
<line x1="${Px}" y1="${Py}" x2="${Bx+(Bx-Px)*0.05}" y2="${By+(By-Py)*0.05}" stroke="#0284c7" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0369a1"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#dc2626"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="3.5" fill="#dc2626"/>
<circle cx="${Dx}" cy="${Dy}" r="3.5" fill="#0284c7"/>
<circle cx="${Px}" cy="${Py}" r="5" fill="#0891b2"/>
<text x="${Ax+(Ax>cx?7:-16)}" y="${Ay+(Ay>cy?15:-4)}" font-size="11" font-weight="700" fill="#dc2626">A</text>
<text x="${Bx+(Bx>cx?7:-16)}" y="${By+(By>cy?15:-4)}" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="${Ccx+(Ccx>cx?4:-14)}" y="${Ccy+(Ccy>cy?13:-2)}" font-size="9" font-weight="700" fill="#dc2626">C</text>
<text x="${Dx+(Dx>cx?4:-14)}" y="${Dy+(Dy>cy?13:-2)}" font-size="9" font-weight="700" fill="#0284c7">D</text>
<text x="${Px+6}" y="${Py+4}" font-size="11" font-weight="700" fill="#0891b2">P</text>
<text x="${Px-90}" y="${Py-30}" font-size="10" font-weight="700" fill="#7c3aed">∠P = ${ang}°</text>
<text x="10" y="16" font-size="9" fill="#dc2626">⌢AB=${arcB}°</text>
<text x="10" y="28" font-size="9" fill="#0284c7">⌢CD=${arcS}°</text>
</svg>`;
info.textContent='⌢AB = '+arcB+'°, ⌢CD = '+arcS+'° → ∠P = ½('+arcB+''+arcS+') = '+ang+'°';
}
slB.addEventListener('input',draw); slS.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=52, cx=105, cy=80, W=260, H=165;
const Px=242, Py=80;
// Secants from P: computed as actual intersections with the circle
const _base=Math.atan2(cy-Py,cx-Px);
function _sec(offDeg){const a=_base+offDeg*Math.PI/180,dx=Math.cos(a),dy=Math.sin(a),b=2*((Px-cx)*dx+(Py-cy)*dy),c=(Px-cx)**2+(Py-cy)**2-R*R,d=b*b-4*c,t1=(-b-Math.sqrt(d))/2,t2=(-b+Math.sqrt(d))/2;return[{x:Px+t1*dx,y:Py+t1*dy},{x:Px+t2*dx,y:Py+t2*dy}];}
const _s1=_sec(15), _s2=_sec(-15);
// s1: near=C, far=A; s2: near=D, far=B
const Ccx=_s1[0].x, Ccy=_s1[0].y;
const Ax=_s1[1].x, Ay=_s1[1].y;
const Dx=_s2[0].x, Dy=_s2[0].y;
const Bx=_s2[1].x, By=_s2[1].y;
const steps=[
{text:'<b>Дано:</b> Из точки $P$ вне окружности проведены две секущие. Одна пересекает в $C, A$ ($C$ ближе к $P$), другая — в $D, B$ ($D$ ближе к $P$). Доказать: $\\angle P = \\dfrac{1}{2}(\\smile AB - \\smile CD)$.'},
{text:'<b>Шаг 1.</b> Соединим точки $A$ и $D$. Рассмотрим треугольник $\\triangle PAD$.'},
{text:'<b>Шаг 2.</b> Угол $\\angle ADP$ — внешний угол треугольника $\\triangle CAD$ при вершине $D$... нет. Точнее: угол $\\angle ADB$ — вписанный, опирающийся на дугу $\\smile AB$: $\\angle ADB = \\dfrac{1}{2}\\smile AB$. Угол $\\angle DAC = \\angle DAС$ — вписанный на $\\smile CD$: $\\angle DAC = \\dfrac{1}{2}\\smile CD$.'},
{text:'<b>Шаг 3.</b> Из треугольника $\\triangle PAD$: $\\angle ADB = \\angle P + \\angle DAС$ (внешний угол). Отсюда $\\angle P = \\angle ADB - \\angle DAC = \\dfrac{1}{2}\\smile AB - \\dfrac{1}{2}\\smile CD = \\dfrac{1}{2}(\\smile AB - \\smile CD)$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p14-proof-svg'), txtEl=document.getElementById('p14-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<line x1="${Ax}" y1="${Ay}" x2="${Dx}" y2="${Dy}" stroke="#f59e0b" stroke-width="1.8" stroke-dasharray="5,3"/>`;
}
if(step>=2){
ex+=`<text x="${(Ax+Dx)/2}" y="${(Ay+Dy)/2-8}" font-size="8" fill="#b45309">AD</text>`;
}
if(step>=3){
ex+=`<text x="${(Px+Ax)/2-10}" y="${(Py+Ay)/2}" font-size="8" fill="#7c3aed">∠P</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"/>
<line x1="${Px}" y1="${Py}" x2="${Ax}" y2="${Ay}" stroke="#dc2626" stroke-width="2"/>
<line x1="${Px}" y1="${Py}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#0369a1"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#dc2626"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="3.5" fill="#dc2626"/>
<circle cx="${Dx}" cy="${Dy}" r="3.5" fill="#0284c7"/>
<circle cx="${Px}" cy="${Py}" r="4.5" fill="#0891b2"/>
<text x="${Ax+(Ax>cx?6:-16)}" y="${Ay+(Ay>cy?14:-4)}" font-size="10" font-weight="700" fill="#dc2626">A</text>
<text x="${Bx+(Bx>cx?6:-16)}" y="${By+(By>cy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">B</text>
<text x="${Ccx-14}" y="${Ccy+(Ccy>cy?12:-2)}" font-size="9" fill="#dc2626">C</text>
<text x="${Dx-14}" y="${Dy+(Dy>cy?12:-2)}" font-size="9" fill="#0284c7">D</text>
<text x="${Px+5}" y="${Py+4}" font-size="10" font-weight="700" fill="#0891b2">P</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p14-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p14-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p14-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p14-calc-ang').addEventListener('click',()=>{
const big=parseFloat(document.getElementById('p14-big').value);
const sml=parseFloat(document.getElementById('p14-sml').value);
const out=document.getElementById('p14-calc-out');
out.style.display='block';
if(isNaN(big)||isNaN(sml)||big<=sml){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Бол. дуга должна быть больше мал. дуги.';return;}
out.style.background='var(--pri-soft,#cffafe)';out.style.color='var(--pri2,#0e7490)';
out.textContent='∠P = ½('+big+''+sml+') = '+((big-sml)/2)+'°';
});
document.getElementById('p14-calc-sml').addEventListener('click',()=>{
const ang=parseFloat(document.getElementById('p14-ang').value);
const big=parseFloat(document.getElementById('p14-big').value);
const out=document.getElementById('p14-calc-out');
out.style.display='block';
if(isNaN(ang)||isNaN(big)||ang<=0||big<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите угол и большую дугу.';return;}
const sml=big-2*ang;
if(sml<=0){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Мал. дуга получается неположительной — проверьте данные.';return;}
out.style.background='var(--pri-soft,#cffafe)';out.style.color='var(--pri2,#0e7490)';
out.textContent='Мал. дуга = '+big+'2·'+ang+' = '+sml+'°';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'Дуги $\\smile AB = 150°$, $\\smile CD = 50°$. Угол $P$ между секущими:',a:50,hint:'½(15050) = 50°'},
{q:'Угол $P = 40°$, бол. дуга $= 130°$. Найди меньшую дугу.',a:50,hint:'Мал. дуга = 1302·40 = 50°'},
{q:'Дуги: $\\smile AB = 200°$, $\\smile CD = 80°$. Угол $P$:',a:60,hint:'½(20080) = 60°'},
{q:'Угол $P = 35°$, мал. дуга $= 60°$. Найди бол. дугу.',a:130,hint:'Бол. дуга = 60+2·35 = 130°'},
{q:'Обе секущие совпадают (стягивают одинаковые дуги). Угол $P$:',a:0,hint:'Полуразность 0 → угол = 0°'},
];
let cur=0, score=0;
const iEl=document.getElementById('p14-tr-i'), scEl=document.getElementById('p14-tr-score');
const taskEl=document.getElementById('p14-tr-task'), ansEl=document.getElementById('p14-tr-ans');
const goBtn=document.getElementById('p14-tr-go'), startBtn=document.getElementById('p14-tr-start');
const fb=document.getElementById('p14-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,'p14-trainer');bumpProgress('p14',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:'Угол между секущими = ½|дуга1 − дуга2|',cat:'true'},
{label:'Угол между секущими = ½(дуга1 + дуга2)',cat:'false'},
{label:'Бол. дуга всегда минус мал. дуга',cat:'true'},
{label:'Угол P может быть больше 90°',cat:'false'},
{label:'Если дуги равны, угол P = 0°',cat:'true'},
{label:'Угол между секущими равен вписанному углу',cat:'false'},
];
const pool=document.getElementById('p14-dnd-pool');
const boxes={true:document.getElementById('p14-drop-true-items'),false:document.getElementById('p14-drop-false-items')};
const fb=document.getElementById('p14-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,bx])=>{
bx.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;
bx.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p14-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,'p14-dnd');bumpProgress('p14',15);}
});
document.getElementById('p14-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §14 === */
(function(){
const tasks=[
{q:'Дуги $\\smile AB = 160°$, $\\smile CD = 60°$. Угол $P$:',
opts:['50°','110°','100°'],cor:0,
exp:'$\\angle P = \\dfrac{1}{2}(160-60) = 50°$.'},
{q:'Угол $P = 45°$, мал. дуга $= 70°$. Бол. дуга:',
opts:['160°','115°','25°'],cor:0,
exp:'Бол. дуга $= 70 + 2\\cdot45 = 160°$.'},
{q:'Секущие становятся касательными (каждая касается в одной точке). Дуга $\\smile AB$ превращается в точку. Угол $P$:',
opts:['½ дуги CD','Дуге CD','Нулю'],cor:0,
exp:'Когда секущая стягивается в касательную, $\\smile AB \\to 0$, и формула даёт $\\angle P = \\dfrac{1}{2}(0 - \\smile CD)$ — ошибка. Правильно: оба становятся касательными, угол = ½ разности двух дуг между точками касания.'},
{q:'Дуга $\\smile AB = 100°$, $\\smile CD = 100°$. Угол $P$:',
opts:['0°','50°','100°'],cor:0,
exp:'$\\angle P = \\dfrac{1}{2}(100-100) = 0°$ — секущие параллельны.'},
];
const cont=document.getElementById('p14-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-boss14="p14-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss14=\\'p14-${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('p14-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,'p14-boss-${i}');bumpProgress('p14',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p14-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--pri-soft,#cffafe);color:var(--pri2,#0e7490);line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP15(){
const box=document.getElementById('p15-body');
let html='';
html+=makeCard('rule','Свойство пересекающихся хорд','15.1',`
<p><b>Теорема.</b> Если две хорды $AB$ и $CD$ окружности пересекаются в точке $P$, то произведения их отрезков равны:</p>
$$PA \\cdot PB = PC \\cdot PD$$
<p style="margin-top:8px">$P$ — точка пересечения хорд внутри окружности; $PA$, $PB$ — отрезки хорды $AB$, $PC$, $PD$ — отрезки хорды $CD$.</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 270 180" style="max-width:290px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="120" cy="90" r="65" fill="rgba(16,185,129,.07)" stroke="#10b981" stroke-width="2"/>
<circle cx="120" cy="90" r="3" fill="#059669"/>
<circle cx="59" cy="68" r="4" fill="#0284c7"/>
<circle cx="181" cy="112" r="4" fill="#0284c7"/>
<circle cx="78" cy="140" r="4" fill="#dc2626"/>
<circle cx="153" cy="34" r="4" fill="#dc2626"/>
<line x1="59" y1="68" x2="181" y2="112" stroke="#0284c7" stroke-width="2.2"/>
<line x1="78" y1="140" x2="153" y2="34" stroke="#dc2626" stroke-width="2.2"/>
<circle cx="114" cy="88" r="5" fill="#7c3aed"/>
<text x="43" y="64" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="185" y="116" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="62" y="154" font-size="11" font-weight="700" fill="#dc2626">C</text>
<text x="157" y="30" font-size="11" font-weight="700" fill="#dc2626">D</text>
<text x="98" y="85" font-size="11" font-weight="700" fill="#7c3aed">P</text>
<text x="183" y="65" font-size="9" fill="#059669">PA·PB = PC·PD</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство через подобие','15.2',`
<p>Хорды $AB$ и $CD$ пересекаются в $P$. Рассмотрим треугольники $\\triangle APC$ и $\\triangle DPB$.</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li><b>Угол при $P$:</b> $\\angle APC = \\angle DPB$ (вертикальные углы).</li>
<li><b>Вписанные углы на одной дуге:</b> $\\angle PAC = \\angle PDC$ (оба опираются на дугу $\\smile BC$).</li>
<li><b>Вывод:</b> $\\triangle APC \\sim \\triangle DPB$ (по двум углам — АА).</li>
<li><b>Пропорция сторон:</b> $\\dfrac{PA}{PD} = \\dfrac{PC}{PB}$, откуда $PA \\cdot PB = PC \\cdot PD$. <b>ч.т.д.</b></li>
</ol>`);
html+=makeCard('example','Пример применения','15.3',`
<p><b>Задача.</b> Хорды пересекаются. $PA = 4$, $PB = 9$, $PC = 6$. Найди $PD$.</p>
<p style="margin-top:8px"><b>Решение.</b> $PA \\cdot PB = PC \\cdot PD$ ⟹ $4 \\cdot 9 = 6 \\cdot PD$ ⟹ $PD = \\dfrac{36}{6} = 6$.</p>
<div style="display:flex;justify-content:center;margin-top:12px">
<svg viewBox="0 0 240 160" style="max-width:260px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="110" cy="82" r="62" fill="rgba(16,185,129,.07)" stroke="#10b981" stroke-width="1.8"/>
<circle cx="110" cy="82" r="3" fill="#059669"/>
<circle cx="50" cy="65" r="4" fill="#0284c7"/>
<circle cx="174" cy="99" r="4" fill="#0284c7"/>
<circle cx="64" cy="135" r="4" fill="#dc2626"/>
<circle cx="158" cy="38" r="4" fill="#dc2626"/>
<line x1="50" y1="65" x2="174" y2="99" stroke="#0284c7" stroke-width="2"/>
<line x1="64" y1="135" x2="158" y2="38" stroke="#dc2626" stroke-width="2"/>
<circle cx="107" cy="82" r="4.5" fill="#7c3aed"/>
<text x="34" y="61" font-size="10" font-weight="700" fill="#0284c7">A</text>
<text x="178" y="103" font-size="10" font-weight="700" fill="#0284c7">B</text>
<text x="49" y="149" font-size="10" font-weight="700" fill="#dc2626">C</text>
<text x="162" y="34" font-size="10" font-weight="700" fill="#dc2626">D</text>
<text x="92" y="79" font-size="10" font-weight="700" fill="#7c3aed">P</text>
<text x="60" y="70" font-size="9" fill="#0284c7">PA=4</text>
<text x="140" y="88" font-size="9" fill="#0284c7">PB=9</text>
<text x="72" y="112" font-size="9" fill="#dc2626">PC=6</text>
<text x="130" y="55" font-size="9" fill="#dc2626">PD=?</text>
</svg>
</div>`);
/* ИНТЕРАКТИВ 1 — draggable-стиль через слайдер положения хорд */
html+=`<div class="wg" id="p15-slider-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">PA · PB = PC · PD (живая демонстрация)</div></div>
<div class="wg-help">Меняй положение точки $P$ внутри окружности — произведения всегда равны.</div>
<div class="sliders">
<label>Положение P (угол) = <b id="p15-pos-val">40</b>°
<input type="range" min="5" max="85" value="40" id="p15-pos-sl">
</label>
<label>Наклон хорды AB = <b id="p15-rot-val">20</b>°
<input type="range" min="-60" max="60" value="20" id="p15-rot-sl">
</label>
</div>
<div id="p15-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p15-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:var(--ok-bg,#d1fae5);color:#065f46"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p15-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="p15-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p15-proof-text" style="padding:10px 14px;background:var(--ok-bg,#d1fae5);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="p15-proof-next">Далее</button>
<button class="btn" id="p15-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: PA · PB = PC · PD</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">PA: <input type="number" id="p15-pa" class="tinp" value="4" min="0.1" style="width:70px"></label>
<label style="font-size:.9rem">PB: <input type="number" id="p15-pb" class="tinp" value="9" min="0.1" style="width:70px"></label>
<label style="font-size:.9rem">PC: <input type="number" id="p15-pc" class="tinp" value="6" min="0.1" style="width:70px"></label>
<label style="font-size:.9rem">PD: <input type="number" id="p15-pd" class="tinp" placeholder="?" style="width:70px"></label>
<button class="btn primary" id="p15-calc-pd">Найти PD</button>
</div>
<div id="p15-calc-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">Тренажёр §15</div></div>
<div class="wg-help">5 задач на свойство пересекающихся хорд.</div>
<div class="score-display"><span>Задача <b id="p15-tr-i">1</b> / 5</span><span>Очки: <b id="p15-tr-score">0</b></span></div>
<div id="p15-tr-task" style="padding:14px;background:var(--ok-bg,#d1fae5);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="p15-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p15-tr-go">Проверить</button>
<button class="btn" id="p15-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p15-tr-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 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="p15-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="p15-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p15-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p15-dnd-check">Проверить</button><button class="btn" id="p15-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p15-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §15 */
html+=`<div class="wg" style="border-color:#059669">
<div class="wg-header"><span class="wg-badge" style="background:#059669">БОСС §15</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p15-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p15-read');bumpProgress('p15',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/></svg>
Я прочитал §15 (+10 XP)
</button>
</div>`;
html+=secNav('p14','p16');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдеры положения P === */
(function(){
const slPos=document.getElementById('p15-pos-sl'), slRot=document.getElementById('p15-rot-sl');
const vPos=document.getElementById('p15-pos-val'), vRot=document.getElementById('p15-rot-val');
const svgWrap=document.getElementById('p15-svg-wrap'), info=document.getElementById('p15-info');
const R=65, cx=130, cy=95, W=260, H=192;
function draw(){
const posAngle=+slPos.value, rotAngle=+slRot.value;
vPos.textContent=posAngle; vRot.textContent=rotAngle;
// P is inside circle at radius fraction, along angle posAngle
const pFrac=0.45; // P at 45% of radius
const pRad=posAngle*Math.PI/180;
const Px=cx+R*pFrac*Math.cos(pRad), Py=cy+R*pFrac*Math.sin(pRad);
// chord AB: line through P at angle rotAngle*PI/180, find intersections with circle
const theta1=(rotAngle)*Math.PI/180;
const dx1=Math.cos(theta1), dy1=Math.sin(theta1);
// parametric: (Px+t*dx1)^2 ... solve quadratic
function chordIntersect(px,py,dx,dy){
const a=dx*dx+dy*dy;
const b=2*((px-cx)*dx+(py-cy)*dy);
const c=(px-cx)*(px-cx)+(py-cy)*(py-cy)-R*R;
const disc=b*b-4*a*c;
if(disc<0)return null;
const t1=(-b-Math.sqrt(disc))/(2*a);
const t2=(-b+Math.sqrt(disc))/(2*a);
return [t1,t2];
}
const t1=chordIntersect(Px,Py,dx1,dy1);
const t2=chordIntersect(Px,Py,-dy1,dx1);
if(!t1||!t2){info.textContent='Переместите P внутрь окружности';return;}
const Ax=Px+t1[0]*dx1, Ay=Py+t1[0]*dy1;
const Bx=Px+t1[1]*dx1, By=Py+t1[1]*dy1;
const Ccx=Px+t2[0]*(-dy1), Ccy=Py+t2[0]*dx1;
const Dx=Px+t2[1]*(-dy1), Dy=Py+t2[1]*dx1;
const PA=Math.sqrt((Px-Ax)**2+(Py-Ay)**2);
const PB=Math.sqrt((Px-Bx)**2+(Py-By)**2);
const PC=Math.sqrt((Px-Ccx)**2+(Py-Ccy)**2);
const PD=Math.sqrt((Px-Dx)**2+(Py-Dy)**2);
const prod1=PA*PB, prod2=PC*PD;
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(16,185,129,.07)" stroke="#10b981" stroke-width="2"/>
<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2.2"/>
<line x1="${Ccx}" y1="${Ccy}" x2="${Dx}" y2="${Dy}" stroke="#dc2626" stroke-width="2.2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#059669"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#dc2626"/>
<circle cx="${Dx}" cy="${Dy}" r="4" fill="#dc2626"/>
<circle cx="${Px}" cy="${Py}" r="5.5" fill="#7c3aed"/>
<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="${Bx+(Bx>cx?7:-16)}" y="${By+(By>cy?15:-4)}" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="${Ccx+(Ccx>cx?7:-16)}" y="${Ccy+(Ccy>cy?15:-4)}" font-size="11" font-weight="700" fill="#dc2626">C</text>
<text x="${Dx+(Dx>cx?7:-16)}" y="${Dy+(Dy>cy?15:-4)}" font-size="11" font-weight="700" fill="#dc2626">D</text>
<text x="${Px+6}" y="${Py-5}" font-size="10" font-weight="700" fill="#7c3aed">P</text>
<text x="${(Px+Ax)/2+4}" y="${(Py+Ay)/2}" font-size="8" fill="#0284c7">${PA.toFixed(1)}</text>
<text x="${(Px+Bx)/2+4}" y="${(Py+By)/2}" font-size="8" fill="#0284c7">${PB.toFixed(1)}</text>
<text x="${(Px+Ccx)/2-18}" y="${(Py+Ccy)/2}" font-size="8" fill="#dc2626">${PC.toFixed(1)}</text>
<text x="${(Px+Dx)/2-18}" y="${(Py+Dy)/2}" font-size="8" fill="#dc2626">${PD.toFixed(1)}</text>
</svg>`;
info.textContent='PA·PB = '+PA.toFixed(2)+'·'+PB.toFixed(2)+' = '+prod1.toFixed(2)+' | PC·PD = '+PC.toFixed(2)+'·'+PD.toFixed(2)+' = '+prod2.toFixed(2)+(Math.abs(prod1-prod2)<0.1?' ✓ Равны!':' (пересчёт...)');
}
slPos.addEventListener('input',draw); slRot.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=55, cx=115, cy=85, W=250, H=175;
const Ax=cx+R*Math.cos(200*Math.PI/180), Ay=cy+R*Math.sin(200*Math.PI/180);
const Bx=cx+R*Math.cos(20*Math.PI/180), By=cy+R*Math.sin(20*Math.PI/180);
const Ccx=cx+R*Math.cos(130*Math.PI/180), Ccy=cy+R*Math.sin(130*Math.PI/180);
const Dx=cx+R*Math.cos(330*Math.PI/180), Dy=cy+R*Math.sin(330*Math.PI/180);
const denom=(Ax-Bx)*(Ccy-Dy)-(Ay-By)*(Ccx-Dx);
const t=((Ax-Ccx)*(Ccy-Dy)-(Ay-Ccy)*(Ccx-Dx))/denom;
const Px=Ax+t*(Bx-Ax), Py=Ay+t*(By-Ay);
const steps=[
{text:'<b>Дано:</b> хорды $AB$ и $CD$ пересекаются в $P$ внутри окружности. Доказать: $PA \\cdot PB = PC \\cdot PD$.'},
{text:'<b>Шаг 1.</b> Рассмотрим треугольники $\\triangle APC$ и $\\triangle DPB$. Углы $\\angle APC$ и $\\angle DPB$ — вертикальные, значит они равны.'},
{text:'<b>Шаг 2.</b> Углы $\\angle PAC$ и $\\angle PDB$ — вписанные, опираются на одну дугу $\\smile BC$, значит $\\angle PAC = \\angle PDB$.'},
{text:'<b>Шаг 3.</b> По признаку подобия AA: $\\triangle APC \\sim \\triangle DPB$. Из подобия: $\\dfrac{PA}{PD} = \\dfrac{PC}{PB}$, откуда $PA \\cdot PB = PC \\cdot PD$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p15-proof-svg'), txtEl=document.getElementById('p15-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<polygon points="${Ax},${Ay} ${Px},${Py} ${Ccx},${Ccy}" fill="rgba(8,145,178,.15)" stroke="#0891b2" stroke-width="1.5"/>`;
ex+=`<polygon points="${Dx},${Dy} ${Px},${Py} ${Bx},${By}" fill="rgba(220,38,38,.12)" stroke="#dc2626" stroke-width="1.5"/>`;
}
if(step>=2){
ex+=`<text x="${(Ax+Px)/2-4}" y="${(Ay+Py)/2+4}" font-size="8" fill="#0891b2">∠PAC</text>`;
ex+=`<text x="${(Dx+Px)/2-4}" y="${(Dy+Py)/2}" font-size="8" fill="#dc2626">∠PDB</text>`;
}
if(step>=3){
ex+=`<text x="${Px+6}" y="${Py-10}" font-size="9" font-weight="700" fill="#7c3aed">△APC~△DPB</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(16,185,129,.07)" stroke="#10b981" stroke-width="2"/>
<line x1="${Ax}" y1="${Ay}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2"/>
<line x1="${Ccx}" y1="${Ccy}" x2="${Dx}" y2="${Dy}" stroke="#dc2626" stroke-width="2"/>
<circle cx="${cx}" cy="${cy}" r="3" fill="#059669"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<circle cx="${Ccx}" cy="${Ccy}" r="4" fill="#dc2626"/>
<circle cx="${Dx}" cy="${Dy}" r="4" fill="#dc2626"/>
<circle cx="${Px}" cy="${Py}" r="4.5" fill="#7c3aed"/>
<text x="${Ax+(Ax>cx?6:-16)}" y="${Ay+(Ay>cy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">A</text>
<text x="${Bx+(Bx>cx?6:-16)}" y="${By+(By>cy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">B</text>
<text x="${Ccx+(Ccx>cx?6:-16)}" y="${Ccy+(Ccy>cy?14:-4)}" font-size="10" font-weight="700" fill="#dc2626">C</text>
<text x="${Dx+(Dx>cx?6:-16)}" y="${Dy+(Dy>cy?14:-4)}" font-size="10" font-weight="700" fill="#dc2626">D</text>
<text x="${Px+5}" y="${Py+4}" font-size="10" font-weight="700" fill="#7c3aed">P</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p15-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p15-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p15-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор === */
(function(){
document.getElementById('p15-calc-pd').addEventListener('click',()=>{
const pa=parseFloat(document.getElementById('p15-pa').value);
const pb=parseFloat(document.getElementById('p15-pb').value);
const pc=parseFloat(document.getElementById('p15-pc').value);
const out=document.getElementById('p15-calc-out');
out.style.display='block';
if([pa,pb,pc].some(v=>isNaN(v)||v<=0)){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent='Введите положительные значения PA, PB, PC.';return;}
const pd=pa*pb/pc;
out.style.background='var(--ok-bg,#d1fae5)';out.style.color='#065f46';
out.innerHTML='PD = PA·PB/PC = '+pa+'·'+pb+'/'+pc+' = <b>'+pd.toFixed(4)+'</b>';
});
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'$PA = 3$, $PB = 12$, $PC = 9$. Найди $PD$.',a:4,hint:'PD = 3·12/9 = 4'},
{q:'$PA = 4$, $PB = 9$, $PC = 6$. Найди $PD$.',a:6,hint:'PD = 4·9/6 = 6'},
{q:'$PA = 5$, $PC = 5$, $PD = 5$. Найди $PB$.',a:5,hint:'PB = PC·PD/PA = 5'},
{q:'$PA = 2$, $PB = 8$, $PD = 4$. Найди $PC$.',a:4,hint:'PC = PA·PB/PD = 16/4 = 4'},
{q:'$PA = 6$, $PB = 6$, $PC = 4$. Найди $PD$.',a:9,hint:'PD = 6·6/4 = 9'},
];
let cur=0, score=0;
const iEl=document.getElementById('p15-tr-i'), scEl=document.getElementById('p15-tr-score');
const taskEl=document.getElementById('p15-tr-task'), ansEl=document.getElementById('p15-tr-ans');
const goBtn=document.getElementById('p15-tr-go'), startBtn=document.getElementById('p15-tr-start');
const fb=document.getElementById('p15-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,'p15-trainer');bumpProgress('p15',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 5: DnD верно/неверно === */
(function(){
const items=[
{label:'PA·PB = PC·PD для любых двух хорд, пересекающихся внутри',cat:'true'},
{label:'PA + PB = PC + PD',cat:'false'},
{label:'Если PA = PC, то PB = PD',cat:'true'},
{label:'Произведение отрезков одной хорды больше произведения другой',cat:'false'},
{label:'Точка P делит хорды пропорционально: PA/PD = PC/PB',cat:'true'},
{label:'Отношение PA/PB = PC/PD',cat:'false'},
];
const pool=document.getElementById('p15-dnd-pool');
const boxes={true:document.getElementById('p15-drop-true-items'),false:document.getElementById('p15-drop-false-items')};
const fb=document.getElementById('p15-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,bx])=>{
bx.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;
bx.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p15-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,'p15-dnd');bumpProgress('p15',15);}
});
document.getElementById('p15-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §15 === */
(function(){
const tasks=[
{q:'$PA = 4, PB = 9, PC = 6$. Найди $PD$.',
opts:['6','3','12'],cor:0,
exp:'$PD = PA\\cdot PB / PC = 4\\cdot9/6 = 6$.'},
{q:'$PA = PB = 5, PC = 5$. Найди $PD$.',
opts:['5','10','25'],cor:0,
exp:'$PD = 5\\cdot5/5 = 5$. Точка $P$ — середина каждой хорды.'},
{q:'Хорды пересекаются в центре. $PA = 3$. Чему равно $PB$?',
opts:['3','6','Недостаточно данных'],cor:0,
exp:'В центре окружности хорды — диаметры, поэтому $PA = PB = R$.'},
{q:'$PA = 2, PC = 3, PD = 4$. Найди $PB$.',
opts:['6','3','2'],cor:0,
exp:'$PB = PC\\cdot PD / PA = 3\\cdot4/2 = 6$.'},
];
const cont=document.getElementById('p15-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-boss15="p15-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss15=\\'p15-${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('p15-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,'p15-boss-${i}');bumpProgress('p15',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p15-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:var(--ok-bg,#d1fae5);color:#065f46;line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildP16(){
const box=document.getElementById('p16-body');
let html='';
html+=makeCard('rule','Свойство касательной и секущей','16.1',`
<p><b>Теорема.</b> Если из внешней точки $P$ проведены касательная $PT$ (где $T$ — точка касания) и секущая, пересекающая окружность в точках $A$ и $B$ ($PA < PB$), то:</p>
$$PT^2 = PA \\cdot PB$$
<p style="margin-top:8px"><b>Следствие:</b> квадрат длины касательной равен произведению полной секущей ($PB$) на её внешнюю часть ($PA$).</p>
<div style="display:flex;justify-content:center;margin-top:14px">
<svg viewBox="0 0 300 190" style="max-width:310px;background:#fafafa;border:1px solid var(--border);border-radius:10px">
<circle cx="130" cy="95" r="65" fill="rgba(124,58,237,.07)" stroke="#7c3aed" stroke-width="2"/>
<circle cx="130" cy="95" r="3" fill="#5b21b6"/>
<circle cx="260" cy="95" r="5" fill="#0891b2"/>
<circle cx="163" cy="151" r="4.5" fill="#dc2626"/>
<circle cx="192" cy="77" r="4" fill="#0284c7"/>
<circle cx="85" cy="48" r="4" fill="#0284c7"/>
<line x1="260" y1="95" x2="153" y2="158" stroke="#dc2626" stroke-width="2.5"/>
<line x1="260" y1="95" x2="68" y2="42" stroke="#0284c7" stroke-width="2"/>
<line x1="130" y1="95" x2="163" y2="151" stroke="#5b21b6" stroke-width="1.4" stroke-dasharray="3,3"/>
<polyline points="159,144 152,148 156,155" fill="none" stroke="#5b21b6" stroke-width="1.6"/>
<text x="258" y="113" font-size="12" font-weight="700" fill="#0891b2">P</text>
<text x="154" y="168" font-size="11" font-weight="700" fill="#dc2626">T</text>
<text x="196" y="73" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="70" y="38" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="128" y="91" font-size="9" font-weight="700" fill="#5b21b6">O</text>
<text x="10" y="72" font-size="9" fill="#dc2626">PT</text>
<text x="10" y="90" font-size="9" fill="#0284c7">PA · PB</text>
<text x="10" y="108" font-size="9" fill="#7c3aed">PT² = PA·PB</text>
</svg>
</div>`);
html+=makeCard('theory','Доказательство через подобие','16.2',`
<p>Из точки $P$ вне окружности проведены: касательная $PT$ и секущая через $A$, $B$ ($PA < PB$). Докажем $PT^2 = PA \\cdot PB$.</p>
<ol style="margin-left:18px;margin-top:6px;line-height:2">
<li><b>Шаг 1.</b> Рассмотрим треугольники $\\triangle PTA$ и $\\triangle PBT$.</li>
<li><b>Шаг 2.</b> Общий угол при $P$: $\\angle TPА = \\angle BPT$ (общий угол).</li>
<li><b>Шаг 3.</b> По теореме §12: $\\angle PTA = \\angle TBA$ (угол между касательной $PT$ и хордой $TA$ равен вписанному углу $\\angle TBA$, опирающемуся на ту же дугу $\\smile TA$).</li>
<li><b>Шаг 4.</b> Значит $\\triangle PTA \\sim \\triangle PBT$ (по АА). Из подобия: $\\dfrac{PT}{PB} = \\dfrac{PA}{PT}$, откуда $PT^2 = PA \\cdot PB$. <b>ч.т.д.</b></li>
</ol>`);
html+=makeCard('example','Примеры','16.3',`
<p><b>Задача 1.</b> $PA = 4$, $PB = 9$. Найди длину касательной $PT$.</p>
<p style="margin-top:8px"><b>Решение.</b> $PT^2 = 4 \\cdot 9 = 36$, $PT = 6$.</p>
<p style="margin-top:10px"><b>Задача 2.</b> $PT = 8$, $PA = 4$. Найди $PB$.</p>
<p style="margin-top:6px"><b>Решение.</b> $PB = PT^2/PA = 64/4 = 16$.</p>
<p style="margin-top:10px"><b>Задача 3.</b> $PT = 6$, $PB = 12$. Найди $PA$.</p>
<p style="margin-top:6px"><b>Решение.</b> $PA = PT^2/PB = 36/12 = 3$.</p>`);
/* ИНТЕРАКТИВ 1 — слайдер секущей */
html+=`<div class="wg" id="p16-slider-wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">PT² = PA · PB (живая демонстрация)</div></div>
<div class="wg-help">Меняй положение секущей слайдером. PT² всегда равно PA·PB.</div>
<div class="sliders">
<label>Угол секущей = <b id="p16-sec-val">25</b>°
<input type="range" min="5" max="60" value="25" id="p16-sec-sl">
</label>
</div>
<div id="p16-svg-wrap" style="display:flex;justify-content:center"></div>
<div id="p16-info" style="margin-top:10px;padding:10px 14px;border-radius:10px;font-size:.95rem;font-weight:700;text-align:center;background:#ede9fe;color:#5b21b6"></div>
</div>`;
/* ИНТЕРАКТИВ 2 — пошаговое доказательство */
html+=`<div class="wg" id="p16-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="p16-proof-svg" style="display:flex;justify-content:center;margin-bottom:10px"></div>
<div id="p16-proof-text" style="padding:10px 14px;background:#ede9fe;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="p16-proof-next">Далее</button>
<button class="btn" id="p16-proof-reset">Сначала</button>
</div>
</div>`;
/* ИНТЕРАКТИВ 3 — калькулятор (три варианта) */
html+=`<div class="wg">
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Калькулятор: PT² = PA · PB</div></div>
<div class="wg-help">Выбери что искать: PT, PA или PB.</div>
<div style="display:flex;gap:8px;margin-bottom:12px;flex-wrap:wrap">
<button class="btn primary" id="p16-mode-pt" style="opacity:1">Найти PT</button>
<button class="btn" id="p16-mode-pa">Найти PA</button>
<button class="btn" id="p16-mode-pb">Найти PB</button>
</div>
<div id="p16-calc-fields" style="display:flex;gap:10px;flex-wrap:wrap;align-items:center;margin-bottom:10px"></div>
<button class="btn primary" id="p16-calc-go">Вычислить</button>
<div id="p16-calc-out" style="display:none;margin-top:10px;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">Тренажёр §16</div></div>
<div class="wg-help">5 задач на свойство касательной и секущей.</div>
<div class="score-display"><span>Задача <b id="p16-tr-i">1</b> / 5</span><span>Очки: <b id="p16-tr-score">0</b></span></div>
<div id="p16-tr-task" style="padding:14px;background:#ede9fe;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="p16-tr-ans" class="tinp" placeholder="Ответ" style="width:130px">
<button class="btn primary" id="p16-tr-go">Проверить</button>
<button class="btn" id="p16-tr-start">Начать заново</button>
</div>
<div class="feedback" id="p16-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="p16-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="p16-drop-true-items"></div></div>
<div class="drop-box"><h5>Неверно</h5><div class="drop-items" id="p16-drop-false-items"></div></div>
</div>
<div class="actions"><button class="btn primary" id="p16-dnd-check">Проверить</button><button class="btn" id="p16-dnd-reset">Сбросить</button></div>
<div class="feedback" id="p16-dnd-fb" style="display:none"></div>
</div>`;
/* ИНТЕРАКТИВ 6 — Босс §16 */
html+=`<div class="wg" style="border-color:#5b21b6">
<div class="wg-header"><span class="wg-badge" style="background:#5b21b6">БОСС §16</span><div class="wg-title">Итоговые задачи</div></div>
<div class="wg-help">4 задачи повышенной сложности — каждая верная даёт +5 XP.</div>
<div id="p16-boss-tasks"></div>
</div>`;
html+=`<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" onclick="addXp(10,'p16-read');bumpProgress('p16',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>
Я прочитал §16 (+10 XP)
</button>
</div>`;
html+=secNav('p15','final4');
box.innerHTML=html;
if(window.renderMathInElement) setTimeout(()=>renderMath(box),0);
/* === INIT 1: слайдер секущей === */
(function(){
const sl=document.getElementById('p16-sec-sl');
const valEl=document.getElementById('p16-sec-val');
const svgWrap=document.getElementById('p16-svg-wrap');
const info=document.getElementById('p16-info');
const R=62, ocx=115, ocy=95, W=285, H=192;
const Px=262, Py=95;
// tangent: T is where line from P is tangent to circle
// tangent length = sqrt(PO^2 - R^2)
const PO=Math.sqrt((Px-ocx)**2+(Py-ocy)**2);
const PTlen=Math.sqrt(PO*PO-R*R);
// angle of tangent from P: sin(alpha) = R/PO
const tanAngle=Math.asin(R/PO);
// main tangent angle (upper tangent)
const baseAngle=Math.atan2(ocy-Py,ocx-Px); // angle from P toward O
const Tx=Px+PTlen*Math.cos(baseAngle-tanAngle);
const Ty=Py+PTlen*Math.sin(baseAngle-tanAngle);
function draw(){
const secDeg=+sl.value;
valEl.textContent=secDeg;
// secant from P at angle (baseAngle + secDeg*PI/180)
const secAngle=baseAngle+secDeg*Math.PI/180;
const dx=Math.cos(secAngle), dy=Math.sin(secAngle);
// intersect with circle: quadratic
const a=dx*dx+dy*dy;
const b=2*((Px-ocx)*dx+(Py-ocy)*dy);
const c=(Px-ocx)**2+(Py-ocy)**2-R*R;
const disc=b*b-4*a*c;
if(disc<0){svgWrap.innerHTML='';return;}
const t1=(-b-Math.sqrt(disc))/(2*a);
const t2=(-b+Math.sqrt(disc))/(2*a);
const Ax=Px+t1*dx, Ay=Py+t1*dy;
const Bx=Px+t2*dx, By=Py+t2*dy;
const PA=Math.abs(t1), PB=Math.abs(t2);
const PT=PTlen;
const prod=PA*PB;
const pt2=PT*PT;
// right-angle marker at T (tangent perp to OT)
const OTx=(Tx-ocx)/R, OTy=(Ty-ocy)/R; // unit vector O->T
const ux=-OTy, uy=OTx; // tangent direction
const s=8;
const m1x=Tx+s*(-OTx), m1y=Ty+s*(-OTy); // toward O
const m2x=m1x+s*ux, m2y=m1y+s*uy;
const m3x=Tx+s*ux, m3y=Ty+s*uy;
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="${ocx}" cy="${ocy}" r="${R}" fill="rgba(124,58,237,.07)" stroke="#7c3aed" stroke-width="2"/>
<line x1="${ocx}" y1="${ocy}" x2="${Tx}" y2="${Ty}" stroke="#5b21b6" stroke-width="1.4" stroke-dasharray="3,3"/>
<line x1="${Px}" y1="${Py}" x2="${Tx+(Tx-Px)*0.04}" y2="${Ty+(Ty-Py)*0.04}" stroke="#dc2626" stroke-width="2.5"/>
<line x1="${Px}" y1="${Py}" x2="${Ax+(Ax-Px)*0.04}" y2="${Ay+(Ay-Py)*0.04}" stroke="#0284c7" stroke-width="2.2"/>
<polyline points="${m1x},${m1y} ${m2x},${m2y} ${m3x},${m3y}" fill="none" stroke="#5b21b6" stroke-width="1.6"/>
<circle cx="${ocx}" cy="${ocy}" r="3" fill="#5b21b6"/>
<circle cx="${Tx}" cy="${Ty}" r="4.5" fill="#dc2626"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<circle cx="${Px}" cy="${Py}" r="5" fill="#0891b2"/>
<text x="${Tx+(Tx>ocx?6:-16)}" y="${Ty+(Ty>ocy?15:-4)}" font-size="11" font-weight="700" fill="#dc2626">T</text>
<text x="${Ax+(Ax>ocx?6:-16)}" y="${Ay+(Ay>ocy?15:-4)}" font-size="11" font-weight="700" fill="#0284c7">A</text>
<text x="${Bx+(Bx>ocx?6:-16)}" y="${By+(By>ocy?15:-4)}" font-size="11" font-weight="700" fill="#0284c7">B</text>
<text x="${Px+6}" y="${Py+4}" font-size="11" font-weight="700" fill="#0891b2">P</text>
<text x="${ocx+4}" y="${ocy-6}" font-size="9" fill="#5b21b6">O</text>
<text x="${(Px+Tx)/2+4}" y="${(Py+Ty)/2-6}" font-size="8" fill="#dc2626">PT=${PT.toFixed(1)}</text>
<text x="${(Px+Ax)/2+4}" y="${(Py+Ay)/2+8}" font-size="8" fill="#0284c7">PA=${PA.toFixed(1)}</text>
<text x="${(Ax+Bx)/2+4}" y="${(Ay+By)/2}" font-size="8" fill="#0284c7">AB=${(PB-PA).toFixed(1)}</text>
</svg>`;
info.textContent='PT² = '+pt2.toFixed(2)+' | PA·PB = '+prod.toFixed(2)+(Math.abs(pt2-prod)<0.1?' ✓ Равны!':'');
}
sl.addEventListener('input',draw);
draw();
})();
/* === INIT 2: пошаговое доказательство === */
(function(){
const R=52, ocx=105, ocy=82, W=265, H=168;
const Px=248, Py=82;
const PO=Math.sqrt((Px-ocx)**2+(Py-ocy)**2);
const PTlen=Math.sqrt(PO*PO-R*R);
const baseAngle=Math.atan2(ocy-Py,ocx-Px);
const tanAngle=Math.asin(R/PO);
const Tx=Px+PTlen*Math.cos(baseAngle-tanAngle);
const Ty=Py+PTlen*Math.sin(baseAngle-tanAngle);
const secAngle=baseAngle+28*Math.PI/180;
const dx=Math.cos(secAngle), dy=Math.sin(secAngle);
const aCoef=dx*dx+dy*dy;
const bCoef=2*((Px-ocx)*dx+(Py-ocy)*dy);
const cCoef=(Px-ocx)**2+(Py-ocy)**2-R*R;
const disc=bCoef*bCoef-4*aCoef*cCoef;
const t1=(-bCoef-Math.sqrt(disc))/(2*aCoef);
const t2=(-bCoef+Math.sqrt(disc))/(2*aCoef);
const Ax=Px+t1*dx, Ay=Py+t1*dy;
const Bx=Px+t2*dx, By=Py+t2*dy;
const steps=[
{text:'<b>Дано:</b> Из точки $P$ вне окружности проведены: касательная $PT$ и секущая $PAB$ ($PA < PB$). Доказать: $PT^2 = PA \\cdot PB$.'},
{text:'<b>Шаг 1.</b> Рассмотрим треугольники $\\triangle PTA$ и $\\triangle PBT$. Угол $\\angle TPА$ — общий для обоих треугольников.'},
{text:'<b>Шаг 2.</b> По теореме §12: угол между касательной $PT$ и хордой $TA$ равен вписанному углу $\\angle TBA$, опирающемуся на ту же дугу $\\smile TA$. Значит $\\angle PTA = \\angle PBT$.'},
{text:'<b>Шаг 3.</b> $\\triangle PTA \\sim \\triangle PBT$ (по АА). Из подобия: $\\dfrac{PT}{PB} = \\dfrac{PA}{PT}$, т.е. $PT^2 = PA \\cdot PB$. <b>ч.т.д.</b>'},
];
let step=0;
const svgEl=document.getElementById('p16-proof-svg'), txtEl=document.getElementById('p16-proof-text');
function draw(){
let ex='';
if(step>=1){
ex+=`<polygon points="${Px},${Py} ${Tx},${Ty} ${Ax},${Ay}" fill="rgba(124,58,237,.15)" stroke="#7c3aed" stroke-width="1.5"/>`;
ex+=`<polygon points="${Px},${Py} ${Bx},${By} ${Tx},${Ty}" fill="rgba(16,185,129,.12)" stroke="#059669" stroke-width="1.5"/>`;
}
if(step>=2){
ex+=`<text x="${(Tx+Ax)/2-16}" y="${(Ty+Ay)/2+6}" font-size="8" fill="#7c3aed">∠PTA</text>`;
ex+=`<text x="${(Bx+Tx)/2+2}" y="${(By+Ty)/2-4}" font-size="8" fill="#059669">∠TBA</text>`;
}
if(step>=3){
ex+=`<text x="${(Px+Ax)/2-8}" y="${(Py+Ay)/2+12}" font-size="9" font-weight="700" fill="#5b21b6">PT²=PA·PB</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="${ocx}" cy="${ocy}" r="${R}" fill="rgba(124,58,237,.07)" stroke="#7c3aed" stroke-width="2"/>
<line x1="${Px}" y1="${Py}" x2="${Tx}" y2="${Ty}" stroke="#dc2626" stroke-width="2.2"/>
<line x1="${Px}" y1="${Py}" x2="${Bx}" y2="${By}" stroke="#0284c7" stroke-width="2"/>
<circle cx="${ocx}" cy="${ocy}" r="3" fill="#5b21b6"/>
<circle cx="${Tx}" cy="${Ty}" r="4.5" fill="#dc2626"/>
<circle cx="${Ax}" cy="${Ay}" r="4" fill="#0284c7"/>
<circle cx="${Bx}" cy="${By}" r="4" fill="#0284c7"/>
<circle cx="${Px}" cy="${Py}" r="4.5" fill="#0891b2"/>
<text x="${Tx+(Tx>ocx?6:-16)}" y="${Ty+(Ty>ocy?14:-4)}" font-size="10" font-weight="700" fill="#dc2626">T</text>
<text x="${Ax+(Ax>ocx?5:-15)}" y="${Ay+(Ay>ocy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">A</text>
<text x="${Bx+(Bx>ocx?5:-15)}" y="${By+(By>ocy?14:-4)}" font-size="10" font-weight="700" fill="#0284c7">B</text>
<text x="${Px+5}" y="${Py+4}" font-size="10" font-weight="700" fill="#0891b2">P</text>
${ex}
</svg>`;
txtEl.innerHTML=steps[step].text;
if(window.renderMathInElement) try{renderMath(txtEl);}catch(e){}
document.getElementById('p16-proof-next').textContent=step>=steps.length-1?'Готово':'Далее';
}
document.getElementById('p16-proof-next').addEventListener('click',()=>{if(step<steps.length-1)step++;draw();});
document.getElementById('p16-proof-reset').addEventListener('click',()=>{step=0;draw();});
draw();
})();
/* === INIT 3: калькулятор 3-в-1 === */
(function(){
let mode='pt';
const fields=document.getElementById('p16-calc-fields');
const out=document.getElementById('p16-calc-out');
const modes={
pt:{label:'Найти PT',fields:[['PA','p16-cpa','4'],['PB','p16-cpb','9']],
calc:()=>{const pa=parseFloat(document.getElementById('p16-cpa').value),pb=parseFloat(document.getElementById('p16-cpb').value);if(isNaN(pa)||isNaN(pb)||pa<=0||pb<=0||pa>=pb)return{err:'PA и PB > 0, PA < PB'};const pt=Math.sqrt(pa*pb);return{ok:'PT = \\u221a(PA\\u00b7PB) = \\u221a('+pa+'\\u00b7'+pb+') = '+pt.toFixed(4)};}},
pa:{label:'Найти PA',fields:[['PT','p16-cpt2','6'],['PB','p16-cpb2','9']],
calc:()=>{const pt=parseFloat(document.getElementById('p16-cpt2').value),pb=parseFloat(document.getElementById('p16-cpb2').value);if(isNaN(pt)||isNaN(pb)||pt<=0||pb<=0||pt*pt>=pb*pb)return{err:'PT и PB > 0, PT < PB'};const pa=pt*pt/pb;return{ok:'PA = PT²/PB = '+pt+'²/'+pb+' = '+pa.toFixed(4)};}},
pb:{label:'Найти PB',fields:[['PT','p16-cpt3','6'],['PA','p16-cpa3','4']],
calc:()=>{const pt=parseFloat(document.getElementById('p16-cpt3').value),pa=parseFloat(document.getElementById('p16-cpa3').value);if(isNaN(pt)||isNaN(pa)||pt<=0||pa<=0||pa>=pt)return{err:'PT и PA > 0, PA < PT'};const pb=pt*pt/pa;return{ok:'PB = PT²/PA = '+pt+'²/'+pa+' = '+pb.toFixed(4)};}}
};
function setMode(m){
mode=m;
['pt','pa','pb'].forEach(k=>document.getElementById('p16-mode-'+k).className='btn'+(k===m?' primary':''));
const cfg=modes[m];
fields.innerHTML=cfg.fields.map(([lab,id,def])=>`<label style="font-size:.9rem">${lab}: <input type="number" id="${id}" class="tinp" value="${def}" min="0.1" style="width:80px"></label>`).join('');
out.style.display='none';
}
document.getElementById('p16-mode-pt').addEventListener('click',()=>setMode('pt'));
document.getElementById('p16-mode-pa').addEventListener('click',()=>setMode('pa'));
document.getElementById('p16-mode-pb').addEventListener('click',()=>setMode('pb'));
document.getElementById('p16-calc-go').addEventListener('click',()=>{
const res=modes[mode].calc();
out.style.display='block';
if(res.err){out.style.background='#fee2e2';out.style.color='#7f1d1d';out.textContent=res.err;}
else{out.style.background='#ede9fe';out.style.color='#5b21b6';out.textContent=res.ok;}
});
setMode('pt');
})();
/* === INIT 4: тренажёр === */
(function(){
const tasks=[
{q:'$PA = 4$, $PB = 9$. Найди $PT$.',a:6,hint:'PT = √(4·9) = √36 = 6'},
{q:'$PT = 8$, $PA = 4$. Найди $PB$.',a:16,hint:'PB = 64/4 = 16'},
{q:'$PT = 6$, $PB = 12$. Найди $PA$.',a:3,hint:'PA = 36/12 = 3'},
{q:'$PA = 3$, $PB = 12$. Найди $PT$.',a:6,hint:'PT = √(3·12) = √36 = 6'},
{q:'$PT = 10$, $PA = 5$. Найди $PB$.',a:20,hint:'PB = 100/5 = 20'},
];
let cur=0, score=0;
const iEl=document.getElementById('p16-tr-i'), scEl=document.getElementById('p16-tr-score');
const taskEl=document.getElementById('p16-tr-task'), ansEl=document.getElementById('p16-tr-ans');
const goBtn=document.getElementById('p16-tr-go'), startBtn=document.getElementById('p16-tr-start');
const fb=document.getElementById('p16-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,'p16-trainer');bumpProgress('p16',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 5: DnD верно/неверно === */
(function(){
const items=[
{label:'PT² = PA·PB',cat:'true'},
{label:'PT = PA + PB',cat:'false'},
{label:'PT — среднее геометрическое PA и PB',cat:'true'},
{label:'PT всегда больше PA и PB',cat:'false'},
{label:'Если PA = PB, то PA = PB = PT (точка P — на окружности)',cat:'false'},
{label:'Квадрат касательной = полная секущая × внешняя часть',cat:'true'},
];
const pool=document.getElementById('p16-dnd-pool');
const boxes={true:document.getElementById('p16-drop-true-items'),false:document.getElementById('p16-drop-false-items')};
const fb=document.getElementById('p16-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,bx])=>{
bx.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;
bx.appendChild(chip);
});
});
pool.appendChild(chip);
});
}
document.getElementById('p16-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,'p16-dnd');bumpProgress('p16',15);}
});
document.getElementById('p16-dnd-reset').addEventListener('click',reset);
reset();
})();
/* === INIT 6: Босс §16 === */
(function(){
const tasks=[
{q:'$PA = 4, PB = 16$. Длина касательной $PT$:',
opts:['8','64','4'],cor:0,
exp:'$PT = \\sqrt{4\\cdot16} = \\sqrt{64} = 8$.'},
{q:'$PT = 6, PB = 9$. Найди $PA$.',
opts:['4','3','2'],cor:0,
exp:'$PA = PT^2/PB = 36/9 = 4$.'},
{q:'$PT = 5, PA = 5$. Найди $PB$.',
opts:['5','10','25'],cor:0,
exp:'$PB = PT^2/PA = 25/5 = 5$. Значит $PA = PB$ — секущая проходит через центр (диаметр).'},
{q:'$PA = 3, AB = 5$ (хорда). Найди $PT$.',
opts:['$\\sqrt{24}$','$\\sqrt{15}$','$\\sqrt{8}$'],cor:0,
exp:'$PB = PA + AB = 3+5 = 8$. $PT = \\sqrt{3\\cdot8} = \\sqrt{24} = 2\\sqrt{6}$.'},
];
const cont=document.getElementById('p16-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-boss16="p16-${i}" data-j="${j}" onclick="(function(btn){
const btns=document.querySelectorAll('[data-boss16=\\'p16-${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('p16-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,'p16-boss-${i}');bumpProgress('p16',5);}
})(this)" style="text-align:left">${o}</button>`).join('')}
</div>
<div id="p16-boss-exp-${i}" style="display:none;margin-top:8px;padding:8px 12px;border-radius:8px;font-size:.88rem;background:#ede9fe;color:#5b21b6;line-height:1.55"></div>
</div>`;
});
cont.innerHTML=bhtml;
if(window.renderMathInElement) try{renderMath(cont);}catch(e){}
})();
}
function buildFinal4(){
const box = document.getElementById('final4-body');
let html = '';
/* === ЧАСТЬ 1: Итоговая шпаргалка === */
html += `<div class="card" style="border-color:var(--sec-acc,var(--pri));background:linear-gradient(135deg,var(--card),var(--sec-acc-soft,var(--pri-soft)))">
<div class="card-header">
<div class="card-icon theory">
<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="2" x2="12" y2="12"/><line x1="12" y1="12" x2="18" y2="16"/></svg>
</div>
<div class="card-title">Итоговая шпаргалка · Вся Глава 4 «Окружности»</div>
</div>
<div class="card-body">
<div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:10px">
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§1 Признак касательной</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="28" cy="34" r="18" fill="rgba(8,145,178,.10)" stroke="#0891b2" stroke-width="2"/>
<line x1="10" y1="34" x2="66" y2="34" stroke="#0e7490" stroke-width="2"/>
<line x1="28" y1="34" x2="28" y2="16" stroke="#0891b2" stroke-width="1.8" stroke-dasharray="3 2"/>
<path d="M28,34 L34,34 L34,28" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<circle cx="28" cy="34" r="3" fill="#0891b2" stroke="#fff" stroke-width="1.2"/>
<text x="20" y="13" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">R</text>
<text x="48" y="31" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">t</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$t \\perp R \\Leftrightarrow d = R$</p>
<p style="font-size:.78rem;color:var(--muted)">касательная ⊥ радиусу</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§2 Свойство касательной</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$OT \\perp t,\\; OT = R$</p>
<p style="font-size:.82rem;margin-bottom:4px">расстояние $d(O,t) = R$</p>
<p style="font-size:.78rem;color:var(--muted)">перпендикуляр из центра</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§3 Касательные из точки</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="28" cy="30" r="16" fill="rgba(8,145,178,.10)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="60" y1="30" x2="15" y2="16" stroke="#0e7490" stroke-width="1.8"/>
<line x1="60" y1="30" x2="15" y2="44" stroke="#0e7490" stroke-width="1.8"/>
<circle cx="60" cy="30" r="3" fill="#0e7490" stroke="#fff" stroke-width="1.2"/>
<circle cx="15" cy="16" r="3" fill="#0891b2" stroke="#fff" stroke-width="1.2"/>
<circle cx="15" cy="44" r="3" fill="#0891b2" stroke="#fff" stroke-width="1.2"/>
<text x="62" y="28" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">A</text>
<text x="4" y="14" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">T1</text>
<text x="4" y="48" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">T2</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$AT_1 = AT_2$</p>
<p style="font-size:.78rem;color:var(--muted)">равны, $OA$ — биссектриса</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§4 Построение касательной</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">окружность на $OA$ как диаметре</p>
<p style="font-size:.82rem;margin-bottom:4px">точки пересечения $T_1, T_2$</p>
<p style="font-size:.78rem;color:var(--muted)">$\\angle OT_1A = 90°$ (Фалес)</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§5 Окружность в угол</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">центр на биссектрисе угла</p>
<p style="font-size:.82rem;margin-bottom:4px">$R = d(O, \\ \\ \text{стор})$</p>
<p style="font-size:.78rem;color:var(--muted)">вписана в угол</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§6 Два круга: 5 случаев</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="22" cy="30" r="16" fill="none" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="48" cy="30" r="12" fill="none" stroke="#0e7490" stroke-width="1.8"/>
<circle cx="22" cy="30" r="2.5" fill="#0891b2"/>
<circle cx="48" cy="30" r="2.5" fill="#0e7490"/>
<line x1="22" y1="30" x2="48" y2="30" stroke="#64748b" stroke-width="1" stroke-dasharray="2 2"/>
<text x="14" y="12" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">O1</text>
<text x="42" y="12" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">O2</text>
</svg>
<div>
<p style="font-size:.82rem;margin-bottom:4px">$d > R_1{+}R_2$: нет точек</p>
<p style="font-size:.82rem;margin-bottom:4px">$d = R_1{+}R_2$: вн. касание</p>
<p style="font-size:.78rem;color:var(--muted)">5 взаим. расположений</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§7 Общая касательная</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">внешняя: $\\ell = \\sqrt{d^2-(R_1-R_2)^2}$</p>
<p style="font-size:.82rem;margin-bottom:4px">внутренняя: $\\ell = \\sqrt{d^2-(R_1+R_2)^2}$</p>
<p style="font-size:.78rem;color:var(--muted)">$d$ — расст. между центрами</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§8 Центральный и дуга</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="35" cy="33" r="22" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="35" y1="33" x2="52" y2="14" stroke="#0e7490" stroke-width="1.8"/>
<line x1="35" y1="33" x2="55" y2="42" stroke="#0e7490" stroke-width="1.8"/>
<path d="M49,16 A18,18 0 0,1 54,41" stroke="#e07b00" stroke-width="2.5" fill="none"/>
<circle cx="35" cy="33" r="2.5" fill="#0891b2"/>
<text x="30" y="30" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">O</text>
<text x="53" y="12" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">A</text>
<text x="57" y="46" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">B</text>
<text x="58" y="28" font-size="7" fill="#e07b00" font-family="JetBrains Mono,monospace">&#x2322;</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle AOB$ — центр. угол</p>
<p style="font-size:.78rem;color:var(--muted)">дуга $\\smile AB = \\angle AOB$</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§9 Вписанный угол</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="35" cy="32" r="22" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="14" y1="43" x2="56" y2="14" stroke="#0e7490" stroke-width="1.8"/>
<line x1="14" y1="43" x2="56" y2="51" stroke="#0e7490" stroke-width="1.8"/>
<circle cx="14" cy="43" r="3" fill="#0e7490" stroke="#fff" stroke-width="1.2"/>
<circle cx="56" cy="14" r="3" fill="#0891b2" stroke="#fff" stroke-width="1.2"/>
<circle cx="56" cy="51" r="3" fill="#0891b2" stroke="#fff" stroke-width="1.2"/>
<text x="2" y="42" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">C</text>
<text x="59" y="12" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">A</text>
<text x="59" y="54" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">B</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle ACB = \\dfrac{1}{2}\\angle AOB$</p>
<p style="font-size:.78rem;color:var(--muted)">= ½ центрального</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§10 Углы на одну дугу</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle ACB = \\angle ADB$</p>
<p style="font-size:.82rem;margin-bottom:4px">$C, D$ на одной стороне от $AB$</p>
<p style="font-size:.78rem;color:var(--muted)">вписанные углы равны</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§11 Угол на диаметр</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="35" cy="33" r="22" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="13" y1="33" x2="57" y2="33" stroke="#0e7490" stroke-width="2"/>
<line x1="13" y1="33" x2="35" y2="11" stroke="#0891b2" stroke-width="1.8"/>
<line x1="57" y1="33" x2="35" y2="11" stroke="#0891b2" stroke-width="1.8"/>
<path d="M31,18 L35,15 L39,18" fill="none" stroke="#e07b00" stroke-width="1.5"/>
<circle cx="13" cy="33" r="3" fill="#0e7490" stroke="#fff" stroke-width="1.2"/>
<circle cx="57" cy="33" r="3" fill="#0e7490" stroke="#fff" stroke-width="1.2"/>
<circle cx="35" cy="11" r="3" fill="#0891b2" stroke="#fff" stroke-width="1.2"/>
<text x="2" y="44" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">A</text>
<text x="60" y="44" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">B</text>
<text x="32" y="8" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">C</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle ACB = 90°$</p>
<p style="font-size:.78rem;color:var(--muted)">$AB$ — диаметр</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§12 Угол касат. и хорды</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle(t, AB) = \\dfrac{1}{2}\\smile AB$</p>
<p style="font-size:.78rem;color:var(--muted)">= ½ дуга, стянутой хордой</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§13 Угол двух хорд</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle P = \\dfrac{1}{2}(\\smile AC + \\smile BD)$</p>
<p style="font-size:.78rem;color:var(--muted)">хорды пересекаются внутри</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§14 Угол двух секущих</div>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$\\angle P = \\dfrac{1}{2}|\\smile AC - \\smile BD|$</p>
<p style="font-size:.78rem;color:var(--muted)">секущие из внешней точки</p>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§15 Произведение хорд</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="35" cy="30" r="22" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="13" y1="42" x2="60" y2="20" stroke="#0e7490" stroke-width="1.8"/>
<line x1="16" y1="16" x2="57" y2="46" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="36" cy="32" r="3" fill="#e07b00" stroke="#fff" stroke-width="1.2"/>
<text x="31" y="29" font-size="7" fill="#e07b00" font-family="JetBrains Mono,monospace">P</text>
<text x="2" y="46" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">A</text>
<text x="62" y="18" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">B</text>
<text x="8" y="14" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">C</text>
<text x="59" y="50" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">D</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$PA \\cdot PB = PC \\cdot PD$</p>
<p style="font-size:.78rem;color:var(--muted)">хорды AB, CD пересеч. в P</p>
</div>
</div>
</div>
<div style="background:var(--card);border:1.5px solid var(--border);border-radius:11px;padding:12px">
<div style="font-family:'Unbounded',sans-serif;font-size:.65rem;font-weight:800;color:var(--sec-acc-d,var(--pri2));text-transform:uppercase;letter-spacing:.07em;margin-bottom:7px">§16 Касательная и секущая</div>
<div style="display:flex;align-items:center;gap:10px">
<svg viewBox="0 0 70 60" style="width:70px;height:60px;flex-shrink:0">
<circle cx="38" cy="30" r="20" fill="rgba(8,145,178,.08)" stroke="#0891b2" stroke-width="1.8"/>
<line x1="10" y1="50" x2="55" y2="12" stroke="#0e7490" stroke-width="2"/>
<line x1="10" y1="50" x2="63" y2="38" stroke="#0891b2" stroke-width="1.8"/>
<circle cx="10" cy="50" r="3" fill="#e07b00" stroke="#fff" stroke-width="1.2"/>
<circle cx="55" cy="12" r="3" fill="#0e7490" stroke="#fff" stroke-width="1.2"/>
<text x="3" y="49" font-size="7" fill="#e07b00" font-family="JetBrains Mono,monospace">P</text>
<text x="57" y="10" font-size="7" fill="#0e7490" font-family="JetBrains Mono,monospace">T</text>
<text x="50" y="56" font-size="7" fill="#0891b2" font-family="JetBrains Mono,monospace">A B</text>
</svg>
<div>
<p style="font-size:.88rem;margin-bottom:4px">$PT^2 = PA \\cdot PB$</p>
<p style="font-size:.78rem;color:var(--muted)">T — точка касания</p>
</div>
</div>
</div>
</div>
</div>
</div>`;
/* === ЧАСТЬ 2: Интерактивная карта связей === */
html += `<div class="wg" id="final4-map-wrap">
<div class="wg-header"><span class="wg-badge">КАРТА СВЯЗЕЙ</span><div class="wg-title">Окружность: касательные, углы, произведения отрезков</div></div>
<div class="wg-help">Нажми на узел, чтобы увидеть формулу и способ применения.</div>
<div id="final4-map-svg" style="display:flex;justify-content:center;overflow-x:auto"></div>
<div id="final4-map-info" style="min-height:56px;padding:12px 16px;background:var(--sec-acc-soft,var(--pri-soft));border-radius:10px;margin-top:10px;font-size:.9rem;line-height:1.65;color:var(--text)">Нажми на узел в схеме выше</div>
</div>`;
/* === ЧАСТЬ 3: 7 боссов === */
html += `<div class="wg" style="border-color:#0891b2;background:linear-gradient(135deg,var(--card),#cffafe)">
<div class="wg-header">
<span class="wg-badge" style="background:#0891b2">7 БОССОВ ГЛАВЫ 4</span>
<div class="wg-title">Интегрированные задачи</div>
</div>
<div class="wg-help">Каждая задача объединяет 2–3 темы главы. +10 XP за каждого побеждённого босса. Победи всех семерых — получишь +50 XP и достижение «Мастер окружностей Главы 4»!</div>
<div id="final4-bosses"></div>
</div>`;
/* === ЧАСТЬ 4: Финальная плашка === */
html += `<div id="final4-finish" style="display:none;margin-top:20px;padding:24px;background:linear-gradient(135deg,#cffafe,#e0f2fe);border:2px solid #0891b2;border-radius:16px;text-align:center">
<div style="font-family:'Unbounded',sans-serif;font-size:1.2rem;font-weight:900;color:#164e63;margin-bottom:10px">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:28px;height:28px;vertical-align:middle;margin-right:6px"><circle cx="12" cy="12" r="10"/><polyline points="12,6 12,12 16,14"/></svg>
Мастер окружностей Главы 4!
</div>
<p style="color:#164e63;font-size:.95rem;margin-bottom:16px">Ты победил всех 7 боссов и освоил всю Главу 4 «Окружности». Геометрия 8 завершена — превосходная работа!</p>
<a href="/textbooks" class="btn primary" style="font-size:.98rem;padding:12px 28px">
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
К списку учебников
</a>
</div>`;
html += `<div style="margin-top:18px;display:flex;justify-content:center">
<button class="btn primary" id="final4-read-btn" onclick="addXp(10,'final4-read');bumpProgress('final4',40);this.textContent='Прочитано!';this.disabled=true;">
<svg class="ic" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="2" x2="12" y2="12"/><line x1="12" y1="12" x2="18" y2="16"/></svg>
Я изучил Главу 4 (+10 XP)
</button>
</div>`;
html += secNav('p16', null);
box.innerHTML = html;
/* === JS: Карта связей SVG === */
(function(){
const W = 620, H = 360;
const nodes = [
{ id:'circ', x:310, y:30, rx:64, label:'ОКРУЖНОСТЬ',
props:'Центральная тема главы 4. Окружность радиуса $R$ с центром $O$ — множество точек, равноудалённых от $O$.' },
{ id:'tang', x:100, y:120, rx:60, label:'Касательные §1–7',
props:'§1–7: касательная $\\perp$ радиусу в точке касания; из внешней точки равны два отрезка касательных; 5 взаимных расположений окружностей; $\\ell = \\sqrt{d^2-(R_1{\\pm}R_2)^2}$.' },
{ id:'angl', x:310, y:120, rx:60, label:'Углы §814',
props:'§8–14: центральный угол = дуга; вписанный = ½ центрального; углы на одну дугу равны; угол на диаметр = 90°; угол (касательная, хорда) = ½ дуга; угол двух хорд = ½(дуга₁+дуга₂); угол двух секущих = ½|дуга₁−дуга₂|.' },
{ id:'prod', x:510, y:120, rx:60, label:'Отрезки §1516',
props:'§15: хорды $PA\\cdot PB = PC\\cdot PD$. §16: касательная и секущая $PT^2 = PA\\cdot PB$. Оба факта доказываются через подобие треугольников.' },
{ id:'t13', x:80, y:230, rx:52, label:'§3 Равные касат.',
props:'§3: из внешней точки $A$ отрезки касательных равны: $AT_1 = AT_2$. Прямая $OA$ является биссектрисой угла $T_1AT_2$.' },
{ id:'t67', x:220, y:230, rx:52, label:'§67 Два круга',
props:'§6–7: 5 случаев взаимного расположения; длина внешней общей касательной $\\ell = \\sqrt{d^2-(R_1-R_2)^2}$, внутренней $\\ell = \\sqrt{d^2-(R_1+R_2)^2}$.' },
{ id:'t911', x:380, y:230, rx:52, label:'§911 Вписанный',
props:'§9: вписанный угол = ½ центрального. §10: вписанные на одну дугу равны. §11: вписанный угол, опирающийся на диаметр, равен 90°.' },
{ id:'t1214', x:530, y:230, rx:52, label:'§1214 Угол и дуга',
props:'§12: угол между касательной и хордой = ½ дуга. §13: угол между двумя хордами = ½(дуга₁+дуга₂). §14: угол между двумя секущими из внешней точки = ½|дуга₁−дуга₂|.' },
{ id:'t15', x:200, y:320, rx:52, label:'§15 Хорды',
props:'§15: если хорды $AB$ и $CD$ пересекаются в точке $P$ внутри окружности, то $PA\\cdot PB = PC\\cdot PD$. Доказывается через подобие $\\triangle PAC\\sim\\triangle PDB$.' },
{ id:'t16', x:420, y:320, rx:52, label:'§16 Касат.+секущая',
props:'§16: если из точки $P$ проведены касательная $PT$ и секущая $PAB$, то $PT^2 = PA\\cdot PB$. Следствие подобия $\\triangle PTA\\sim\\triangle PBT$.' },
];
const edges = [
['circ','tang'],['circ','angl'],['circ','prod'],
['tang','t13'],['tang','t67'],
['angl','t911'],['angl','t1214'],
['prod','t15'],['prod','t16'],
];
let sel = null;
function draw(selId){
const colors = { circ:'#0891b2', tang:'#0e7490', angl:'#0284c7', prod:'#0369a1',
t13:'#06b6d4', t67:'#0891b2', t911:'#2563eb', t1214:'#7c3aed',
t15:'#0369a1', t16:'#0891b2' };
let s = `<svg viewBox="0 0 ${W} ${H}" style="width:100%;max-width:640px;background:var(--card);border:1.5px solid var(--border);border-radius:14px;cursor:pointer">`;
s += `<defs><marker id="f4-arr" markerWidth="7" markerHeight="7" refX="6" refY="3.5" orient="auto"><polygon points="0 0,7 3.5,0 7" fill="#94a3b8"/></marker></defs>`;
edges.forEach(([a,b])=>{
const na=nodes.find(n=>n.id===a), nb=nodes.find(n=>n.id===b);
if(!na||!nb) return;
const dx=nb.x-na.x, dy=nb.y-na.y, len=Math.sqrt(dx*dx+dy*dy);
if(len<1) return;
const sy_r=na.rx*0.50;
const sx=na.x+dx/len*na.rx, sy2=na.y+dy/len*sy_r;
const ex=nb.x-dx/len*(nb.rx+7), ey=nb.y-dy/len*(nb.rx*0.50+7);
const isAct = selId===a||selId===b;
s += `<line x1="${sx.toFixed(1)}" y1="${sy2.toFixed(1)}" x2="${ex.toFixed(1)}" y2="${ey.toFixed(1)}" stroke="${isAct?'#0891b2':'#94a3b8'}" stroke-width="${isAct?2.5:1.5}" marker-end="url(#f4-arr)"/>`;
});
nodes.forEach(n=>{
const isS = selId===n.id;
const col = colors[n.id] || '#0891b2';
const ry = n.rx * 0.50;
s += `<ellipse cx="${n.x}" cy="${n.y}" rx="${n.rx}" ry="${ry}" fill="${isS?col:'var(--card)'}" stroke="${col}" stroke-width="${isS?3:2}" data-nid="${n.id}" style="cursor:pointer"/>`;
const words = n.label.split(' ');
const line1 = words.slice(0,2).join(' '), line2 = words.slice(2).join(' ');
const tc = isS ? '#fff' : col;
if(line2){
s += `<text x="${n.x}" y="${n.y-5}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line1}</text>`;
s += `<text x="${n.x}" y="${n.y+7}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line2}</text>`;
} else {
s += `<text x="${n.x}" y="${n.y+4}" text-anchor="middle" font-size="8" font-weight="800" font-family="Unbounded,sans-serif" fill="${tc}" style="pointer-events:none">${line1}</text>`;
}
});
s += '</svg>';
document.getElementById('final4-map-svg').innerHTML = s;
document.getElementById('final4-map-svg').querySelector('svg').addEventListener('click', function(e){
const el = e.target.closest('[data-nid]');
if(!el) return;
const nid = el.dataset.nid;
sel = (sel===nid) ? null : nid;
const nd = nodes.find(n=>n.id===nid);
if(sel && nd){ document.getElementById('final4-map-info').innerHTML = '<b>' + nd.label + '</b>: ' + nd.props; renderMath(document.getElementById('final4-map-info')); }
else document.getElementById('final4-map-info').textContent = 'Нажми на узел в схеме выше';
draw(sel);
});
}
draw(null);
})();
/* === JS: 7 боссов === */
(function(){
const bosses = [
{
n: 1,
title: 'Две касательные из точки',
color: '#0891b2',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="90" cy="92" r="50" fill="rgba(8,145,178,.09)" stroke="#0891b2" stroke-width="2"/>
<circle cx="90" cy="92" r="2.5" fill="#0891b2"/>
<circle cx="240" cy="92" r="4" fill="#0e7490" stroke="#fff" stroke-width="1.5"/>
<line x1="90" y1="92" x2="48" y2="45" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="3 2"/>
<line x1="90" y1="92" x2="48" y2="139" stroke="#0891b2" stroke-width="1.5" stroke-dasharray="3 2"/>
<line x1="240" y1="92" x2="48" y2="45" stroke="#0e7490" stroke-width="2"/>
<line x1="240" y1="92" x2="48" y2="139" stroke="#0e7490" stroke-width="2"/>
<path d="M52,53 L44,50 L44,58" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<path d="M52,131 L44,134 L44,126" fill="none" stroke="#0e7490" stroke-width="1.5"/>
<circle cx="48" cy="45" r="3.5" fill="#0891b2" stroke="#fff" stroke-width="1.5"/>
<circle cx="48" cy="139" r="3.5" fill="#0891b2" stroke="#fff" stroke-width="1.5"/>
<text x="86" y="88" font-size="9" fill="#0e7490" font-family="Unbounded,sans-serif" font-weight="800">O</text>
<text x="243" y="96" font-size="10" fill="#0e7490" font-family="Unbounded,sans-serif" font-weight="800">P</text>
<text x="34" y="42" font-size="10" fill="#0891b2" font-family="Unbounded,sans-serif" font-weight="800">T1</text>
<text x="34" y="152" font-size="10" fill="#0891b2" font-family="Unbounded,sans-serif" font-weight="800">T2</text>
<text x="110" y="68" font-size="9" fill="#0e7490" font-family="JetBrains Mono,monospace">R=5</text>
<text x="155" y="80" font-size="9" fill="#0e7490" font-family="JetBrains Mono,monospace">|OP|=13</text>
</svg>`,
cond: 'Из точки $P$ к окружности с центром $O$ и радиусом $R = 5$ проведены две касательные $PT_1$ и $PT_2$. $|OP| = 13$. (§1, §3)',
parts: [
{ label: 'Найди длину касательной $PT_1$ (в единицах).', ans: 12, hint: '$OT_1 \\perp PT_1$, теорема Пифагора: $PT_1 = \\sqrt{OP^2 - R^2} = \\sqrt{169-25} = \\sqrt{144} = 12$' },
{ label: 'Найди периметр четырёхугольника $OT_1PT_2$.', ans: 34, hint: '$P = PT_1 + OT_1 + PT_2 + OT_2 = 12+5+12+5 = 34$. По §3: $PT_1=PT_2=12$.' },
],
},
{
n: 2,
title: 'Вписанный угол и диаметр',
color: '#0284c7',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="140" cy="95" r="76" fill="rgba(2,132,199,.08)" stroke="#0284c7" stroke-width="2"/>
<circle cx="140" cy="95" r="2.5" fill="#0284c7"/>
<line x1="64" y1="95" x2="216" y2="95" stroke="#0369a1" stroke-width="2.5"/>
<line x1="64" y1="95" x2="190" y2="28" stroke="#0284c7" stroke-width="1.8"/>
<line x1="216" y1="95" x2="190" y2="28" stroke="#0284c7" stroke-width="1.8"/>
<path d="M74,95 A12,12 0 0,0 68,84" fill="none" stroke="#e07b00" stroke-width="1.8"/>
<path d="M182,38 L182,28 L192,28" fill="none" stroke="#e07b00" stroke-width="1.5"/>
<circle cx="64" cy="95" r="4" fill="#0369a1" stroke="#fff" stroke-width="1.5"/>
<circle cx="216" cy="95" r="4" fill="#0369a1" stroke="#fff" stroke-width="1.5"/>
<circle cx="190" cy="28" r="4" fill="#0284c7" stroke="#fff" stroke-width="1.5"/>
<text x="48" y="110" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">A</text>
<text x="218" y="110" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">B</text>
<text x="192" y="24" font-size="11" font-weight="700" fill="#0284c7" font-family="Unbounded,sans-serif">C</text>
<text x="136" y="90" font-size="9" fill="#0369a1" font-family="Unbounded,sans-serif" font-weight="800">O</text>
<text x="67" y="82" font-size="9" fill="#e07b00" font-family="JetBrains Mono,monospace">35°</text>
<text x="103" y="175" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">AB — диаметр</text>
</svg>`,
cond: 'В окружности $AB$ — диаметр, $C$ — точка на окружности. $\\angle CAB = 35°$. (§9, §11)',
parts: [
{ label: 'Найди $\\angle ACB$ (в градусах).', ans: 90, hint: '$\\angle ACB = 90°$ — вписанный угол, опирающийся на диаметр $AB$ (§11).' },
{ label: 'Найди $\\angle ABC$ (в градусах).', ans: 55, hint: '$\\angle ACB = 90°$, $\\angle CAB = 35°$, $\\angle ABC = 180° - 90° - 35° = 55°$.' },
],
},
{
n: 3,
title: 'Вписанные углы + пересечение хорд',
color: '#7c3aed',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="140" cy="92" r="72" fill="rgba(124,58,237,.08)" stroke="#7c3aed" stroke-width="2"/>
<circle cx="140" cy="92" r="2.5" fill="#7c3aed"/>
<line x1="78" y1="52" x2="202" y2="145" stroke="#6d28d9" stroke-width="1.8"/>
<line x1="80" y1="148" x2="200" y2="48" stroke="#4f46e5" stroke-width="1.8"/>
<circle cx="142" cy="97" r="4" fill="#e07b00" stroke="#fff" stroke-width="1.5"/>
<circle cx="78" cy="52" r="4" fill="#6d28d9" stroke="#fff" stroke-width="1.5"/>
<circle cx="202" cy="145" r="4" fill="#6d28d9" stroke="#fff" stroke-width="1.5"/>
<circle cx="80" cy="148" r="4" fill="#4f46e5" stroke="#fff" stroke-width="1.5"/>
<circle cx="200" cy="48" r="4" fill="#4f46e5" stroke="#fff" stroke-width="1.5"/>
<text x="63" y="50" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">A</text>
<text x="204" y="160" font-size="11" font-weight="700" fill="#6d28d9" font-family="Unbounded,sans-serif">C</text>
<text x="65" y="162" font-size="11" font-weight="700" fill="#4f46e5" font-family="Unbounded,sans-serif">B</text>
<text x="202" y="46" font-size="11" font-weight="700" fill="#4f46e5" font-family="Unbounded,sans-serif">D</text>
<text x="148" y="94" font-size="10" font-weight="700" fill="#e07b00" font-family="Unbounded,sans-serif">P</text>
<text x="90" y="20" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">&#x2322;AC=70°</text>
<text x="172" y="175" font-size="9" fill="#4f46e5" font-family="JetBrains Mono,monospace">&#x2322;BD=50°</text>
</svg>`,
cond: 'В окружности хорды $AB$ и $CD$ пересекаются в точке $P$. Дуга $\\smile AC = 70°$, дуга $\\smile BD = 50°$. (§10, §13)',
parts: [
{ label: 'Найди угол при пересечении хорд в точке $P$ (в градусах).', ans: 60, hint: '$\\angle APD = \\dfrac{1}{2}(\\smile AC + \\smile BD) = \\dfrac{1}{2}(70+50) = 60°$ (§13).' },
{ label: 'Найди $\\angle ADC$ — вписанный угол, опирающийся на дугу $AC$ (в градусах).', ans: 35, hint: '$\\angle ADC = \\dfrac{1}{2}\\smile AC = \\dfrac{1}{2}\\cdot 70° = 35°$ (§10).' },
],
},
{
n: 4,
title: 'Две секущие из внешней точки',
color: '#0369a1',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="155" cy="90" r="62" fill="rgba(3,105,161,.08)" stroke="#0369a1" stroke-width="2"/>
<circle cx="155" cy="90" r="2.5" fill="#0369a1"/>
<line x1="20" y1="90" x2="217" y2="50" stroke="#0284c7" stroke-width="1.8"/>
<line x1="20" y1="90" x2="215" y2="132" stroke="#0369a1" stroke-width="1.8"/>
<circle cx="20" cy="90" r="4" fill="#0369a1" stroke="#fff" stroke-width="1.5"/>
<circle cx="95" cy="58" r="3.5" fill="#0284c7" stroke="#fff" stroke-width="1.5"/>
<circle cx="217" cy="50" r="3.5" fill="#0284c7" stroke="#fff" stroke-width="1.5"/>
<circle cx="97" cy="122" r="3.5" fill="#0369a1" stroke="#fff" stroke-width="1.5"/>
<circle cx="215" cy="132" r="3.5" fill="#0369a1" stroke="#fff" stroke-width="1.5"/>
<text x="4" y="103" font-size="11" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">P</text>
<text x="85" y="52" font-size="10" font-weight="700" fill="#0284c7" font-family="Unbounded,sans-serif">B</text>
<text x="220" y="48" font-size="10" font-weight="700" fill="#0284c7" font-family="Unbounded,sans-serif">A</text>
<text x="84" y="136" font-size="10" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">D</text>
<text x="218" y="146" font-size="10" font-weight="700" fill="#0369a1" font-family="Unbounded,sans-serif">C</text>
<path d="M94,66 A10,10 0 0,0 32,90" fill="none" stroke="#e07b00" stroke-width="1.5" stroke-dasharray="3 2"/>
<text x="28" y="76" font-size="9" fill="#e07b00" font-family="JetBrains Mono,monospace">?</text>
<text x="148" y="18" font-size="9" fill="#0284c7" font-family="JetBrains Mono,monospace">&#x2322;AC=100°</text>
<text x="148" y="175" font-size="9" fill="#0369a1" font-family="JetBrains Mono,monospace">&#x2322;BD=40°</text>
</svg>`,
cond: 'Из внешней точки $P$ проведены две секущие $PAC$ и $PBD$. Дуга $\\smile AC = 100°$, дуга $\\smile BD = 40°$. (§14)',
parts: [
{ label: 'Найди угол $\\angle APB$ при точке $P$ (в градусах).', ans: 30, hint: '$\\angle P = \\dfrac{1}{2}|\\smile AC - \\smile BD| = \\dfrac{1}{2}|100-40| = 30°$ (§14).' },
],
},
{
n: 5,
title: 'Произведение отрезков хорд',
color: '#059669',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="140" cy="92" r="74" fill="rgba(5,150,105,.08)" stroke="#059669" stroke-width="2"/>
<circle cx="140" cy="92" r="2.5" fill="#059669"/>
<line x1="68" y1="62" x2="212" y2="142" stroke="#047857" stroke-width="1.8"/>
<line x1="70" y1="148" x2="210" y2="44" stroke="#10b981" stroke-width="1.8"/>
<circle cx="138" cy="100" r="4" fill="#e07b00" stroke="#fff" stroke-width="1.5"/>
<circle cx="68" cy="62" r="4" fill="#047857" stroke="#fff" stroke-width="1.5"/>
<circle cx="212" cy="142" r="4" fill="#047857" stroke="#fff" stroke-width="1.5"/>
<circle cx="70" cy="148" r="4" fill="#10b981" stroke="#fff" stroke-width="1.5"/>
<circle cx="210" cy="44" r="4" fill="#10b981" stroke="#fff" stroke-width="1.5"/>
<text x="54" y="60" font-size="11" font-weight="700" fill="#047857" font-family="Unbounded,sans-serif">A</text>
<text x="214" y="158" font-size="11" font-weight="700" fill="#047857" font-family="Unbounded,sans-serif">B</text>
<text x="56" y="162" font-size="11" font-weight="700" fill="#10b981" font-family="Unbounded,sans-serif">C</text>
<text x="212" y="42" font-size="11" font-weight="700" fill="#10b981" font-family="Unbounded,sans-serif">D</text>
<text x="144" y="98" font-size="10" font-weight="700" fill="#e07b00" font-family="Unbounded,sans-serif">P</text>
<text x="88" y="74" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">PA=4</text>
<text x="162" y="140" font-size="9" fill="#047857" font-family="JetBrains Mono,monospace">PB=9</text>
<text x="78" y="138" font-size="9" fill="#10b981" font-family="JetBrains Mono,monospace">PC=6</text>
<text x="160" y="62" font-size="9" fill="#10b981" font-family="JetBrains Mono,monospace">PD=?</text>
</svg>`,
cond: 'В окружности хорды $AB$ и $CD$ пересекаются в точке $P$. $PA = 4$, $PB = 9$, $PC = 6$. (§15)',
parts: [
{ label: 'Найди $PD$.', ans: 6, hint: '$PA \\cdot PB = PC \\cdot PD \\Rightarrow PD = \\dfrac{PA \\cdot PB}{PC} = \\dfrac{4 \\cdot 9}{6} = 6$.' },
],
},
{
n: 6,
title: 'Касательная и секущая',
color: '#d97706',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="155" cy="88" r="64" fill="rgba(217,119,6,.08)" stroke="#d97706" stroke-width="2"/>
<circle cx="155" cy="88" r="2.5" fill="#d97706"/>
<line x1="20" y1="165" x2="200" y2="28" stroke="#b45309" stroke-width="2"/>
<line x1="20" y1="165" x2="220" y2="110" stroke="#d97706" stroke-width="2"/>
<circle cx="20" cy="165" r="4" fill="#b45309" stroke="#fff" stroke-width="1.5"/>
<circle cx="136" cy="44" r="3.5" fill="#b45309" stroke="#fff" stroke-width="1.5"/>
<circle cx="100" cy="148" r="3.5" fill="#d97706" stroke="#fff" stroke-width="1.5"/>
<circle cx="218" cy="108" r="3.5" fill="#d97706" stroke="#fff" stroke-width="1.5"/>
<text x="4" y="175" font-size="11" font-weight="700" fill="#92400e" font-family="Unbounded,sans-serif">P</text>
<text x="134" y="40" font-size="11" font-weight="700" fill="#b45309" font-family="Unbounded,sans-serif">T</text>
<text x="82" y="164" font-size="11" font-weight="700" fill="#d97706" font-family="Unbounded,sans-serif">A</text>
<text x="220" y="124" font-size="11" font-weight="700" fill="#d97706" font-family="Unbounded,sans-serif">B</text>
<text x="52" y="96" font-size="9" fill="#b45309" font-family="JetBrains Mono,monospace">PT=8</text>
<text x="120" y="170" font-size="9" fill="#d97706" font-family="JetBrains Mono,monospace">AB=12</text>
<text x="135" y="155" font-size="9" fill="#d97706" font-family="JetBrains Mono,monospace">PA=?</text>
</svg>`,
cond: 'Из точки $P$ проведены касательная $PT$ и секущая $PAB$. $PT = 8$, $AB = 12$. (§16)',
parts: [
{ label: 'Найди $PA$ (внешний отрезок секущей). Подсказка: $PA(PA+12) = 64$.', ans: 4, hint: '$PT^2 = PA\\cdot PB$, $PB = PA+12$. Уравнение: $PA^2+12PA-64=0$. Корень: $PA = \\dfrac{-12+\\sqrt{144+256}}{2} = \\dfrac{-12+20}{2} = 4$.' },
{ label: 'Найди $PB$.', ans: 16, hint: '$PB = PA + AB = 4+12 = 16$. Проверка: $8^2 = 4\\cdot 16 = 64$ — верно.' },
],
},
{
n: 7,
title: 'Общая касательная двух окружностей',
color: '#6d28d9',
svg: `<svg viewBox="0 0 280 185" style="width:100%;max-width:280px;background:var(--card);border:1px solid var(--border);border-radius:10px;display:block;margin:10px auto">
<circle cx="80" cy="100" r="52" fill="rgba(109,40,217,.08)" stroke="#6d28d9" stroke-width="2"/>
<circle cx="200" cy="100" r="20" fill="rgba(139,92,246,.12)" stroke="#8b5cf6" stroke-width="2"/>
<circle cx="80" cy="100" r="2.5" fill="#6d28d9"/>
<circle cx="200" cy="100" r="2.5" fill="#8b5cf6"/>
<line x1="80" y1="100" x2="200" y2="100" stroke="#64748b" stroke-width="1.2" stroke-dasharray="3 2"/>
<line x1="68" y1="49" x2="208" y2="80" stroke="#6d28d9" stroke-width="2.2"/>
<circle cx="68" cy="49" r="3.5" fill="#6d28d9" stroke="#fff" stroke-width="1.5"/>
<circle cx="208" cy="80" r="3.5" fill="#8b5cf6" stroke="#fff" stroke-width="1.5"/>
<text x="70" y="95" font-size="9" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="800">O1</text>
<text x="194" y="95" font-size="9" fill="#8b5cf6" font-family="Unbounded,sans-serif" font-weight="800">O2</text>
<text x="22" y="96" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">R1=6</text>
<text x="213" y="118" font-size="9" fill="#8b5cf6" font-family="JetBrains Mono,monospace">R2=2</text>
<text x="110" y="115" font-size="9" fill="#64748b" font-family="JetBrains Mono,monospace">d=10</text>
<text x="100" y="40" font-size="9" fill="#6d28d9" font-family="JetBrains Mono,monospace">&#x2113;=?</text>
<text x="56" y="42" font-size="9" fill="#6d28d9" font-family="Unbounded,sans-serif" font-weight="700">T1</text>
<text x="210" y="76" font-size="9" fill="#8b5cf6" font-family="Unbounded,sans-serif" font-weight="700">T2</text>
</svg>`,
cond: 'Две окружности с $R_1 = 6$, $R_2 = 2$. Расстояние между центрами $d = 10$. Найди длину общей внешней касательной. (§7)',
parts: [
{ label: 'Найди $\\ell = \\sqrt{d^2-(R_1-R_2)^2}$. Введи результат (округли до 2 знаков).', ans: 9.17, tol: 0.05, hint: '$\\ell = \\sqrt{10^2 - (6-2)^2} = \\sqrt{100-16} = \\sqrt{84} \\approx 9{,}17$.' },
],
},
];
window.final4BossSolved = new Set();
const bossBox = document.getElementById('final4-bosses');
bossBox.innerHTML = bosses.map(b => {
const partsHtml = b.parts.map((p,pi) => {
return `<div style="padding:10px 0;border-top:1px dashed var(--border)">
<div style="font-size:.9rem;margin-bottom:7px">${p.label}</div>
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap">
<input type="number" step="any" class="tinp final4-boss-inp" data-b="${b.n-1}" data-p="${pi}" placeholder="Ответ" style="width:120px">
<button class="btn primary final4-boss-check" data-b="${b.n-1}" data-p="${pi}" style="background:${b.color};border-color:${b.color}">Проверить</button>
<span class="final4-boss-ok" data-b="${b.n-1}" data-p="${pi}" style="display:none;color:var(--ok);font-weight:700">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3" style="width:16px;height:16px;vertical-align:middle"><polyline points="20 6 9 17 4 12"/></svg>
</span>
</div>
<div class="feedback final4-boss-fb" data-b="${b.n-1}" data-p="${pi}" style="display:none;margin-top:6px"></div>
</div>`;
}).join('');
const svgHtml = b.svg ? `<div style="display:flex;justify-content:center;margin:10px 0">${b.svg}</div>` : '';
return `<div style="padding:16px;background:var(--card);border-radius:12px;border:2px solid ${b.color};margin-bottom:14px" id="final4-boss-card-${b.n-1}">
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;flex-wrap:wrap">
<span style="background:${b.color};color:#fff;padding:4px 10px;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.7rem;font-weight:800">БОСС ${b.n}</span>
<span style="font-family:'Unbounded',sans-serif;font-size:.88rem;font-weight:800;color:${b.color}">${b.title}</span>
<span id="final4-boss-xp-${b.n-1}" style="margin-left:auto;display:none;background:var(--ok-bg);color:#065f46;padding:3px 10px;border-radius:99px;font-size:.78rem;font-weight:800">+10 XP</span>
</div>
<div style="padding:10px 14px;background:linear-gradient(135deg,#cffafe,#fff);border-left:4px solid ${b.color};border-radius:9px;font-size:.92rem;line-height:1.6;margin-bottom:4px">${b.cond}</div>
${svgHtml}
${partsHtml}
</div>`;
}).join('');
function checkPart(bi, pi){
const boss = bosses[bi];
const part = boss.parts[pi];
const inp = bossBox.querySelector('.final4-boss-inp[data-b="'+bi+'"][data-p="'+pi+'"]');
const fb = bossBox.querySelector('.final4-boss-fb[data-b="'+bi+'"][data-p="'+pi+'"]');
const ok = bossBox.querySelector('.final4-boss-ok[data-b="'+bi+'"][data-p="'+pi+'"]');
if(!inp) return;
const val = parseFloat(inp.value);
const tol = part.tol !== undefined ? part.tol : 0;
if(Math.abs(val - part.ans) <= tol){
feedback(fb, true, 'Верно! ' + (part.hint ? '<br><span style="font-size:.82rem;opacity:.85">' + part.hint + '</span>' : ''));
inp.disabled = true;
const btn = bossBox.querySelector('.final4-boss-check[data-b="'+bi+'"][data-p="'+pi+'"]');
if(btn) btn.disabled = true;
if(ok) ok.style.display = 'inline';
const allDone = boss.parts.every((_,pj) => {
const el = bossBox.querySelector('.final4-boss-inp[data-b="'+bi+'"][data-p="'+pj+'"]');
return el && el.disabled;
});
if(allDone && !window.final4BossSolved.has(bi)){
window.final4BossSolved.add(bi);
addXp(10, 'final4-boss-' + (bi+1));
const xpBadge = document.getElementById('final4-boss-xp-' + bi);
if(xpBadge) xpBadge.style.display = 'inline';
bumpProgress('final4', 8);
if(window.final4BossSolved.size === bosses.length){
setTimeout(function(){
confetti();
if(!STATE.achievements.has('final4-master')){
STATE.achievements.set('final4-master', 'Мастер окружностей Главы 4');
saveProgress();
const pop = document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent = 'Мастер окружностей Главы 4!'; pop.classList.add('show'); setTimeout(function(){ pop.classList.remove('show'); }, 4000); }
}
addXp(50, 'final4-all-bosses');
bumpProgress('final4', 20);
const fin = document.getElementById('final4-finish');
if(fin) fin.style.display = 'block';
}, 500);
}
}
} else {
feedback(fb, false, 'Неверно. Подсказка: ' + part.hint);
}
}
bossBox.querySelectorAll('.final4-boss-check').forEach(function(btn){
btn.addEventListener('click', function(){ checkPart(+btn.dataset.b, +btn.dataset.p); });
});
bossBox.querySelectorAll('.final4-boss-inp').forEach(function(inp){
inp.addEventListener('keydown', function(e){ if(e.key==='Enter'){ var btn=bossBox.querySelector('.final4-boss-check[data-b="'+inp.dataset.b+'"][data-p="'+inp.dataset.p+'"]'); if(btn)btn.click(); } });
});
})();
renderMath(box);
}
</script>
</body>
</html>