Files
Learn_System/frontend/textbooks/geometry_10_r3.html
T
Maxim Dolgolyov 7f045737d3 feat(geom10 W7): Финал Раздела 3 — 5 боссов + ачивка stereo10_r3_master
- Босс 1 Прямая ⊥ плоскость (4 этапа, +30 XP)
- Босс 2 Расстояния (4 этапа, +30 XP)
- Босс 3 Угол + ТТП (4 этапа, +35 XP, поддержка √2/2, 1/√3 и т.п.)
- Босс 4 ⊥-плоскости (4 этапа, +30 XP)
- Босс 5 Сборная (5 этапов, +45 XP — диагональ куба √3, sin угла 1/√3)
- Celebration: ачивка stereo10_r3_master + 130 XP бонус
- sec-nav: финал-таб разблокирован, refreshTabs учитывает {f1..f5}
- Состояние: STATE.bosses{f1..f5} + geometry10_achievements в localStorage
2026-05-29 15:26:04 +03:00

1714 lines
104 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 name="viewport" content="width=device-width,initial-scale=1.0">
<title>Геометрия 10 · Раздел 3 · Перпендикулярность</title>
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@400;500;600;700;800;900&family=Inter:wght@400;500;600;700&family=Unbounded:wght@400;700;800;900&family=JetBrains+Mono:wght@400;500;700&display=swap" rel="stylesheet">
<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"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/stereo3d.js?v=1"></script>
<style>
:root{
--bg:#fff1f2; --card:#fff; --card-2:#f1f5f9;
--text:#3f0a1c; --text-2:#7f1d1d; --muted:#475569;
--border:#fecdd3; --border-2:#e2e8f0;
--pri:#e11d48; --pri-d:#be123c; --pri-l:#fda4af;
--pri-soft:#fecdd3; --pri-soft-2:#ffe4e6;
--dark:#7f1d1d;
--accent:#7c3aed;
--good:#16a34a;
--warn:#d97706;
--sh:0 4px 16px rgba(225,29,72,.08);
--sh-h:0 12px 36px rgba(225,29,72,.18);
}
html.dark{
--bg:#1c0612; --card:#240a1c; --card-2:#2d1024;
--text:#fecdd3; --text-2:#fda4af; --muted:#94a3b8;
--border:#7f1d1d; --border-2:#1e293b;
--pri-soft:rgba(225,29,72,.18); --pri-soft-2:rgba(225,29,72,.10);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{min-height:100vh}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);line-height:1.6;transition:background .25s,color .25s}
.hdr{position:relative;background:linear-gradient(110deg,var(--dark) 0%,var(--pri) 55%,var(--pri-l) 100%);color:#fff;padding:32px 24px 28px;overflow:hidden}
.hdr::before{content:'⊥';position:absolute;right:8px;top:-18%;font-family:'Outfit',sans-serif;font-size:clamp(8rem,22vw,18rem);font-weight:900;color:rgba(255,255,255,.10);line-height:1;pointer-events:none;user-select:none}
.hdr-inner{position:relative;z-index:1;max-width:1100px;margin:0 auto;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.hdr-back{display:inline-flex;align-items:center;gap:8px;padding:8px 14px;background:rgba(255,255,255,.14);border-radius:9px;color:#fff;text-decoration:none;font-size:.85rem;font-weight:600;transition:background .15s}
.hdr-back:hover{background:rgba(255,255,255,.24)}
.hdr h1{font-family:'Outfit',sans-serif;font-size:1.7rem;font-weight:900;letter-spacing:-.01em}
.hdr-sub{font-size:.92rem;opacity:.88;margin-top:4px}
.hdr-side{margin-left:auto;display:flex;gap:8px;align-items:center}
.hdr-btn{padding:8px 12px;background:rgba(255,255,255,.14);border:none;color:#fff;border-radius:9px;cursor:pointer;font-weight:600;font-size:.82rem;display:inline-flex;align-items:center;gap:6px;transition:background .15s;font-family:inherit}
.hdr-btn:hover{background:rgba(255,255,255,.24)}
.hdr-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 12px;background:linear-gradient(135deg,#f59e0b,#7c3aed);border-radius:99px;font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;letter-spacing:.04em;color:#fff;box-shadow:0 4px 12px rgba(124,58,237,.32)}
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.sec-nav{position:sticky;top:0;z-index:30;background:var(--bg);border-bottom:1px solid var(--border-2);padding:10px 16px;overflow-x:auto;white-space:nowrap;box-shadow:0 2px 8px rgba(0,0,0,.04)}
.sec-nav-inner{display:inline-flex;gap:6px;max-width:1100px;margin:0 auto}
.sec-tab{display:inline-flex;align-items:center;gap:6px;padding:7px 14px;background:var(--card-2);border:1px solid var(--border-2);border-radius:10px;font-size:.82rem;font-weight:700;color:var(--muted);cursor:pointer;transition:all .15s;text-decoration:none;font-family:inherit}
.sec-tab:hover{background:var(--pri-soft);color:var(--pri-d);border-color:var(--pri-l)}
.sec-tab.active{background:var(--pri);color:#fff;border-color:var(--pri-d)}
.sec-tab .dot{width:8px;height:8px;border-radius:50%;background:rgba(0,0,0,.15);transition:background .25s}
.sec-tab.read .dot{background:var(--good)}
.sec-tab.active .dot{background:#fff}
.sec-tab.locked{opacity:.55}
main{max-width:1100px;margin:0 auto;padding:32px 24px 80px}
.para{margin-bottom:48px;scroll-margin-top:72px}
.para-head{display:flex;align-items:flex-start;gap:16px;margin-bottom:18px}
.para-num{font-family:'Outfit',sans-serif;font-size:1.6rem;font-weight:900;color:#fff;background:linear-gradient(135deg,var(--pri),var(--pri-d));padding:10px 16px;border-radius:11px;letter-spacing:-.02em;flex-shrink:0;box-shadow:var(--sh)}
.para-h{flex:1;min-width:0}
.para-h h2{font-family:'Outfit',sans-serif;font-size:1.6rem;font-weight:800;letter-spacing:-.01em;line-height:1.2;margin-bottom:4px}
.para-h-sub{color:var(--muted);font-size:.95rem}
.theory{display:grid;grid-template-columns:1fr;gap:14px;margin-bottom:24px}
@media(min-width:760px){.theory{grid-template-columns:repeat(2,1fr)}}
.t-card{background:var(--card);border:1.5px solid var(--border-2);border-radius:13px;padding:16px 18px;box-shadow:var(--sh);transition:border-color .15s}
.t-card:hover{border-color:var(--pri-l)}
.t-tag{display:inline-block;padding:3px 9px;background:var(--pri-soft);color:var(--pri-d);border-radius:6px;font-size:.7rem;font-weight:800;letter-spacing:.06em;text-transform:uppercase;margin-bottom:8px}
.t-title{font-family:'Outfit',sans-serif;font-size:1.02rem;font-weight:800;margin-bottom:6px;color:var(--text)}
.t-body{font-size:.92rem;color:var(--text);opacity:.9;line-height:1.6}
.t-body p{margin-bottom:8px}
.t-body ul{margin:6px 0 6px 20px}
.t-body li{margin-bottom:4px}
.t-body code{background:var(--card-2);padding:2px 6px;border-radius:5px;font-family:'JetBrains Mono',monospace;font-size:.86em}
.viz{background:var(--card);border:1.5px solid var(--border-2);border-radius:14px;padding:18px;margin-bottom:18px;box-shadow:var(--sh)}
.viz-title{font-family:'Outfit',sans-serif;font-size:.94rem;font-weight:800;color:var(--text);margin-bottom:10px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.viz-title .badge{padding:2px 8px;background:var(--pri-soft);color:var(--pri-d);border-radius:5px;font-size:.7rem;letter-spacing:.04em}
.viz-cap{font-size:.84rem;color:var(--muted);margin-top:8px;line-height:1.55}
.viz-row{display:flex;gap:12px;flex-wrap:wrap;justify-content:center}
.viz-cell{flex:1 1 200px;max-width:240px;text-align:center}
.viz-cell-label{font-size:.78rem;color:var(--muted);font-weight:700;margin-top:6px}
.inter{background:var(--card);border:1.5px solid var(--border-2);border-radius:14px;padding:18px;margin-bottom:18px;box-shadow:var(--sh)}
.inter-h{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.inter-icon{width:34px;height:34px;border-radius:9px;background:var(--pri-soft);color:var(--pri-d);display:flex;align-items:center;justify-content:center;flex-shrink:0;font-family:'Outfit',sans-serif;font-weight:900;font-size:.96rem}
.inter-title{font-family:'Outfit',sans-serif;font-size:1rem;font-weight:800;flex:1}
.inter-progress{font-size:.78rem;color:var(--muted);font-weight:700;font-family:'JetBrains Mono',monospace}
.quiz{display:flex;gap:14px;align-items:center;flex-wrap:wrap}
.quiz-q{flex:1;min-width:200px;font-size:.95rem;font-weight:600;line-height:1.55}
.quiz-opts{display:flex;gap:8px;flex-wrap:wrap}
.quiz-opt{padding:8px 14px;background:var(--card-2);border:1.5px solid var(--border-2);border-radius:9px;font-weight:700;font-size:.88rem;cursor:pointer;color:var(--text);font-family:inherit;transition:all .15s}
.quiz-opt:hover{background:var(--pri-soft);border-color:var(--pri-l)}
.quiz-opt.correct{background:linear-gradient(135deg,#dcfce7,#bbf7d0);border-color:#16a34a;color:#166534;animation:pop .35s}
.quiz-opt.wrong{background:linear-gradient(135deg,#fee2e2,#fecaca);border-color:#dc2626;color:#991b1b;animation:shake .35s}
@keyframes pop{0%{transform:scale(1)}50%{transform:scale(1.07)}100%{transform:scale(1)}}
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}
.quiz-input{display:inline-flex;align-items:center;gap:8px;background:var(--card-2);border:1.5px solid var(--border-2);border-radius:9px;padding:4px 6px;transition:border-color .15s}
.quiz-input.correct{border-color:#16a34a;background:linear-gradient(135deg,#dcfce7,#bbf7d0)}
.quiz-input.wrong{border-color:#dc2626;background:linear-gradient(135deg,#fee2e2,#fecaca)}
.quiz-input input{background:transparent;border:none;outline:none;padding:6px 8px;font-family:'JetBrains Mono',monospace;font-size:.92rem;font-weight:700;color:var(--text);width:100px}
.quiz-input button{background:var(--pri);border:none;color:#fff;padding:6px 10px;border-radius:6px;cursor:pointer;font-weight:700;font-size:.82rem;font-family:inherit}
.quiz-input button:hover{filter:brightness(1.08)}
.quiz-feedback{margin-top:10px;padding:10px 14px;background:var(--card-2);border-radius:9px;font-size:.88rem;color:var(--muted);display:none}
.quiz-feedback.show{display:block}
.quiz-feedback.good{background:linear-gradient(135deg,#dcfce7,#f0fdf4);color:#166534;border-left:3px solid #16a34a}
.quiz-feedback.bad{background:linear-gradient(135deg,#fee2e2,#fef2f2);color:#991b1b;border-left:3px solid #dc2626}
.boss{background:linear-gradient(135deg,#7f1d1d 0%,#9f1239 50%,#be123c 100%);color:#fff;border-radius:18px;padding:24px;margin-bottom:24px;position:relative;overflow:hidden;box-shadow:0 16px 48px rgba(190,18,60,.30)}
.boss::before{content:'';position:absolute;inset:0;background:radial-gradient(circle at 20% 30%,rgba(255,255,255,.10),transparent 50%);pointer-events:none}
.boss-h{display:flex;align-items:center;gap:12px;margin-bottom:14px;position:relative;z-index:1;flex-wrap:wrap}
.boss-badge{padding:5px 12px;background:rgba(245,158,11,.32);border:1px solid rgba(251,191,36,.5);border-radius:99px;font-family:'Unbounded',sans-serif;font-size:.72rem;font-weight:800;letter-spacing:.06em;color:#fde68a;text-transform:uppercase}
.boss-title{font-family:'Outfit',sans-serif;font-size:1.2rem;font-weight:800;flex:1}
.boss-hp{margin-bottom:14px;position:relative;z-index:1}
.boss-hp-label{display:flex;justify-content:space-between;font-size:.78rem;font-weight:700;margin-bottom:5px;color:#fecdd3}
.boss-hp-bar{height:12px;background:rgba(255,255,255,.10);border-radius:7px;overflow:hidden;border:1px solid rgba(255,255,255,.18)}
.boss-hp-fill{height:100%;background:linear-gradient(90deg,#f59e0b,#ef4444);transition:width .5s ease-out}
.boss-question{background:rgba(0,0,0,.32);border-radius:12px;padding:16px;margin-bottom:14px;position:relative;z-index:1;border:1px solid rgba(255,255,255,.10)}
.boss-stage-label{font-size:.74rem;color:#fda4af;font-weight:700;letter-spacing:.08em;text-transform:uppercase;margin-bottom:6px}
.boss-q{font-size:1.02rem;font-weight:700;margin-bottom:14px;line-height:1.55}
.boss-opts{display:flex;gap:8px;flex-wrap:wrap}
.boss-opt{padding:10px 16px;background:rgba(255,255,255,.10);border:1.5px solid rgba(255,255,255,.20);border-radius:9px;color:#fff;font-weight:700;font-size:.92rem;cursor:pointer;font-family:inherit;transition:all .15s}
.boss-opt:hover{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.4)}
.boss-opt.correct{background:linear-gradient(135deg,#16a34a,#22c55e);border-color:#86efac;animation:pop .35s}
.boss-opt.wrong{background:linear-gradient(135deg,#dc2626,#ef4444);border-color:#fca5a5;animation:shake .35s}
.boss-input{display:inline-flex;align-items:center;gap:6px;background:rgba(0,0,0,.36);border:1.5px solid rgba(255,255,255,.20);border-radius:9px;padding:4px 6px}
.boss-input.wrong{border-color:#fca5a5;animation:shake .35s}
.boss-input input{background:transparent;border:none;outline:none;color:#fff;font-family:'JetBrains Mono',monospace;font-size:.95rem;font-weight:700;padding:6px 8px;width:110px}
.boss-input button{background:#f59e0b;border:none;color:#fff;padding:6px 12px;border-radius:6px;cursor:pointer;font-weight:800;font-size:.82rem;font-family:inherit}
.boss-defeated{text-align:center;padding:16px;position:relative;z-index:1}
.boss-defeated-title{font-family:'Outfit',sans-serif;font-size:1.3rem;font-weight:900;color:#fde68a;margin-bottom:8px;letter-spacing:-.01em}
.boss-defeated-sub{font-size:.92rem;color:#fecdd3;margin-bottom:14px}
.boss-defeated-xp{display:inline-flex;align-items:center;gap:6px;padding:8px 16px;background:linear-gradient(135deg,#f59e0b,#dc2626);border-radius:99px;font-family:'Unbounded',sans-serif;font-weight:800;font-size:.86rem;letter-spacing:.06em;box-shadow:0 6px 20px rgba(245,158,11,.4)}
.boss.victory{background:linear-gradient(135deg,#15803d,#22c55e 50%,#86efac)}
.boss.victory::before{background:radial-gradient(circle at 50% 50%,rgba(254,240,138,.20),transparent 70%)}
.para-actions{display:flex;justify-content:center;margin-top:18px;gap:10px}
.mark-btn{padding:11px 22px;background:var(--pri);color:#fff;border:none;border-radius:11px;font-weight:800;font-size:.92rem;cursor:pointer;font-family:'Inter',sans-serif;display:inline-flex;align-items:center;gap:8px;transition:filter .15s,transform .15s;box-shadow:var(--sh)}
.mark-btn:hover{filter:brightness(1.10);transform:translateY(-1px)}
.mark-btn.done{background:linear-gradient(135deg,var(--good),#22c55e)}
.stub-card{background:linear-gradient(135deg,var(--pri-soft),transparent);border:1px dashed var(--pri-l);border-radius:14px;padding:24px;text-align:center;color:var(--pri-d);margin-bottom:24px}
.stub-card b{font-family:'Outfit',sans-serif;font-size:1.1rem;display:block;margin-bottom:4px}
.stub-card small{display:block;margin-top:6px;color:var(--muted);font-size:.84rem}
.foot{text-align:center;padding:24px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border-2);margin-top:30px}
@media (max-width:560px){
.hdr h1{font-size:1.35rem}
.hdr-sub{font-size:.85rem}
.para-num{font-size:1.3rem;padding:8px 12px}
.para-h h2{font-size:1.3rem}
.quiz{flex-direction:column;align-items:flex-start}
}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-inner">
<div>
<a href="/textbook/geometry-10" class="hdr-back">
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
К курсу
</a>
</div>
<div>
<h1>Раздел 3. Перпендикулярность</h1>
<div class="hdr-sub">Прямая ⊥ плоскость · Расстояния · Углы · Двугранный угол</div>
</div>
<div class="hdr-side">
<span class="hdr-xp" id="hdr-xp">0 XP</span>
<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>
<nav class="sec-nav">
<div class="sec-nav-inner">
<a class="sec-tab active" data-tab="7" href="#para-7"><span class="dot"></span>§7 Прямая ⊥ пл-сть</a>
<a class="sec-tab" data-tab="8" href="#para-8"><span class="dot"></span>§8 Расстояния</a>
<a class="sec-tab" data-tab="9" href="#para-9"><span class="dot"></span>§9 Угол</a>
<a class="sec-tab" data-tab="10" href="#para-10"><span class="dot"></span>§10 Пл-сти ⊥</a>
<a class="sec-tab" data-tab="final" href="#para-final"><span class="dot"></span>Финал</a>
</div>
</nav>
<main>
<!-- §7 -->
<section id="para-7" class="para">
<div class="para-head">
<div class="para-num">§ 7</div>
<div class="para-h">
<h2>Перпендикулярность прямой и плоскости</h2>
<div class="para-h-sub">Определение · признак · свойства · связь с параллельностью</div>
</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ОПРЕДЕЛЕНИЕ</span> Прямая, перпендикулярная плоскости</div>
<div id="viz7-def" style="text-align:center"></div>
<div class="viz-cap">Прямая $l$ перпендикулярна плоскости $\alpha$, если она <b>перпендикулярна любой</b> прямой, лежащей в этой плоскости и проходящей через точку пересечения. Обозначение: $l \perp \alpha$.</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ПРИЗНАК</span> $l \perp m,\ l \perp n,\ m \cap n = O \Rightarrow l \perp \alpha$</div>
<div id="viz7-sign" style="text-align:center"></div>
<div class="viz-cap">Если прямая $l$ перпендикулярна <b>двум пересекающимся</b> прямым $m$ и $n$ в плоскости $\alpha$, то $l \perp \alpha$. Двух пересекающихся достаточно — необязательно проверять все прямые плоскости.</div>
</div>
<div class="theory">
<div class="t-card">
<span class="t-tag">7.1</span>
<div class="t-title">Определение</div>
<div class="t-body">
<p>Прямая $l$ называется <b>перпендикулярной плоскости</b> $\alpha$, если она перпендикулярна <b>каждой</b> прямой в $\alpha$, проходящей через точку их пересечения.</p>
<p>Обозначение: $l \perp \alpha$.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">7.2</span>
<div class="t-title">Признак перпендикулярности</div>
<div class="t-body">
<p>Если прямая $l$ перпендикулярна двум пересекающимся прямым $m$ и $n$ плоскости $\alpha$, то $l \perp \alpha$.</p>
<p>Это основной инструмент для доказательства перпендикулярности.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">7.3</span>
<div class="t-title">Свойство</div>
<div class="t-body">
<p>Если $l \perp \alpha$, то $l$ перпендикулярна <b>любой</b> прямой плоскости $\alpha$ (не только проходящей через точку пересечения, но и параллельной ей).</p>
<p>$l \perp \alpha,\ a \subset \alpha \Rightarrow l \perp a$.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">7.4</span>
<div class="t-title">Параллельность и перпендикулярность</div>
<div class="t-body">
<p>Если $l \perp \alpha$ и $l \parallel l'$, то $l' \perp \alpha$.</p>
<p>Если $l_1 \perp \alpha$ и $l_2 \perp \alpha$, то $l_1 \parallel l_2$.</p>
<p>Две прямые, перпендикулярные одной плоскости, всегда параллельны между собой.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">7.5</span>
<div class="t-title">Существование и единственность</div>
<div class="t-body">
<p>Через любую точку пространства проходит <b>единственная</b> прямая, перпендикулярная данной плоскости.</p>
<p>Через любую точку плоскости — единственная прямая, перпендикулярная этой плоскости.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">7.6</span>
<div class="t-title">Куб и перпендикулярность</div>
<div class="t-body">
<p>В кубе $ABCDA_1B_1C_1D_1$: ребро $AA_1$ перпендикулярно нижней грани $ABCD$, потому что $AA_1 \perp AB$ и $AA_1 \perp AD$ (две пересек. прямые в плоскости).</p>
<p>Аналогично — каждое боковое ребро перпендикулярно обоим основаниям.</p>
</div>
</div>
</div>
<div class="inter" data-inter="i7-perp">
<div class="inter-h">
<div class="inter-icon">1</div>
<div class="inter-title">Перпендикулярна ли прямая плоскости?</div>
<div class="inter-progress" id="i7-perp-prog">0 / 6</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i7-perp-q"></div>
<div class="quiz-opts" id="i7-perp-opts"></div>
</div>
<div class="quiz-feedback" id="i7-perp-fb"></div>
</div>
<div class="inter" data-inter="i7-sign">
<div class="inter-h">
<div class="inter-icon">2</div>
<div class="inter-title">Применение признака</div>
<div class="inter-progress" id="i7-sign-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i7-sign-q"></div>
<div class="quiz-opts" id="i7-sign-opts"></div>
</div>
<div class="quiz-feedback" id="i7-sign-fb"></div>
</div>
<div class="inter" data-inter="i7-cube">
<div class="inter-h">
<div class="inter-icon">3</div>
<div class="inter-title">Перпендикулярность в кубе</div>
<div class="inter-progress" id="i7-cube-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i7-cube-q"></div>
<div class="quiz-opts" id="i7-cube-opts"></div>
</div>
<div class="quiz-feedback" id="i7-cube-fb"></div>
</div>
<div class="boss" id="boss-7"></div>
<div class="para-actions">
<button class="mark-btn" id="mark-7">
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
<span>Отметить §7 как изученный</span>
</button>
</div>
</section>
<!-- §8 -->
<section id="para-8" class="para">
<div class="para-head">
<div class="para-num">§ 8</div>
<div class="para-h">
<h2>Расстояния в пространстве</h2>
<div class="para-h-sub">Точка ↔ плоскость · параллельные плоскости · скрещивающиеся прямые</div>
</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">4 ВИДА РАССТОЯНИЙ</span> Все через перпендикуляр</div>
<div class="viz-row">
<div class="viz-cell"><div id="viz8-pt-pl"></div><div class="viz-cell-label">Точка → плоскость</div></div>
<div class="viz-cell"><div id="viz8-ln-pl"></div><div class="viz-cell-label">Прямая ∥ плоскость</div></div>
<div class="viz-cell"><div id="viz8-pl-pl"></div><div class="viz-cell-label">Парал. плоскости</div></div>
<div class="viz-cell"><div id="viz8-skew"></div><div class="viz-cell-label">Скрещ. прямые</div></div>
</div>
<div class="viz-cap">Расстояние в стереометрии — всегда длина <b>перпендикуляра</b>. От точки до плоскости — это длина перпендикуляра, опущенного из точки.</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ТОЧКА И ПЛОСКОСТЬ</span> Расстояние $\rho(A, \alpha) = |AO|$</div>
<div id="viz8-detail" style="text-align:center"></div>
<div class="viz-cap">Точка $A$ вне плоскости $\alpha$. Опускаем перпендикуляр $AO$ ($O \in \alpha$). Длина $|AO|$ — расстояние от $A$ до $\alpha$. Любая <span style="color:#1e3a8a;font-weight:800">наклонная $AB$</span> всегда длиннее перпендикуляра.</div>
</div>
<div class="theory">
<div class="t-card">
<span class="t-tag">8.1</span>
<div class="t-title">Расстояние от точки до плоскости</div>
<div class="t-body">
<p>Длина перпендикуляра, опущенного из точки $A$ на плоскость $\alpha$.</p>
<p>Перпендикуляр короче любой наклонной из той же точки.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">8.2</span>
<div class="t-title">От прямой до параллельной плоскости</div>
<div class="t-body">
<p>Если $a \parallel \alpha$, то расстояние от $a$ до $\alpha$ — это расстояние от <b>любой точки</b> прямой $a$ до $\alpha$ (оно постоянно).</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">8.3</span>
<div class="t-title">Между параллельными плоскостями</div>
<div class="t-body">
<p>Длина общего перпендикуляра между $\alpha \parallel \beta$. Равна расстоянию от любой точки одной плоскости до другой.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">8.4</span>
<div class="t-title">Между скрещивающимися прямыми</div>
<div class="t-body">
<p>Длина <b>общего перпендикуляра</b> к двум скрещивающимся прямым.</p>
<p>Общий перпендикуляр существует, единствен и перпендикулярен обеим прямым.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">8.5</span>
<div class="t-title">Свойство перпендикуляра</div>
<div class="t-body">
<p>Перпендикуляр из точки на плоскость — это <b>кратчайший</b> отрезок от точки до плоскости.</p>
<p>Если из точки опущен перпендикуляр $AO$ и наклонная $AB$, то $|AO| \le |AB|$, причём равенство — только если $B = O$.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">8.6</span>
<div class="t-title">Куб: типовые расстояния</div>
<div class="t-body">
<p>В кубе с ребром $a$:</p>
<ul>
<li>Расстояние от $A$ до плоскости $A_1B_1C_1D_1$ равно $a$ (ребро $AA_1$).</li>
<li>Расстояние между рёбрами $AB$ и $C_1D_1$ равно $a\sqrt{2}$ (диагональ грани).</li>
<li>Расстояние между $AB$ и $CC_1$ равно $a$ (ребро $BC$).</li>
</ul>
</div>
</div>
</div>
<div class="inter" data-inter="i8-cube">
<div class="inter-h">
<div class="inter-icon">1</div>
<div class="inter-title">Расстояния в кубе (ребро $a = 1$)</div>
<div class="inter-progress" id="i8-cube-prog">0 / 6</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i8-cube-q"></div>
<div class="quiz-input">
<input id="i8-cube-in" type="text" placeholder="ответ">
<button id="i8-cube-go">OK</button>
</div>
</div>
<div class="quiz-feedback" id="i8-cube-fb"></div>
</div>
<div class="inter" data-inter="i8-type">
<div class="inter-h">
<div class="inter-icon">2</div>
<div class="inter-title">Какое расстояние ищется?</div>
<div class="inter-progress" id="i8-type-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i8-type-q"></div>
<div class="quiz-opts" id="i8-type-opts"></div>
</div>
<div class="quiz-feedback" id="i8-type-fb"></div>
</div>
<div class="inter" data-inter="i8-true">
<div class="inter-h">
<div class="inter-icon">3</div>
<div class="inter-title">Верно или неверно</div>
<div class="inter-progress" id="i8-true-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i8-true-q"></div>
<div class="quiz-opts" id="i8-true-opts"></div>
</div>
<div class="quiz-feedback" id="i8-true-fb"></div>
</div>
<div class="boss" id="boss-8"></div>
<div class="para-actions">
<button class="mark-btn" id="mark-8">
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
<span>Отметить §8 как изученный</span>
</button>
</div>
</section>
<!-- §9 -->
<section id="para-9" class="para">
<div class="para-head">
<div class="para-num">§ 9</div>
<div class="para-h">
<h2>Угол между прямой и плоскостью</h2>
<div class="para-h-sub">Наклонная и её проекция · теорема о трёх перпендикулярах (ТТП)</div>
</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ОПРЕДЕЛЕНИЕ</span> Угол между наклонной и плоскостью</div>
<div id="viz9-angle" style="text-align:center"></div>
<div class="viz-cap">Точка $A$ вне плоскости $\alpha$. <span style="color:#dc2626;font-weight:800">$AH$ — перпендикуляр</span> ($H \in \alpha$). <span style="color:#1e3a8a;font-weight:800">$AB$ — наклонная</span> ($B \in \alpha, B \neq H$). <span style="color:#16a34a;font-weight:800">$HB$ — проекция наклонной</span>. <b>Углом</b> между $AB$ и $\alpha$ называется $\angle ABH$ — угол между наклонной и её проекцией.</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ТТП</span> Теорема о трёх перпендикулярах</div>
<div id="viz9-ttp" style="text-align:center"></div>
<div class="viz-cap">Если из основания $H$ перпендикуляра $AH$ к плоскости $\alpha$ провести в плоскости $\alpha$ прямую $BC \perp HB$, то и <b>наклонная</b> $AB \perp BC$. Обратное верно: $AB \perp BC \Rightarrow HB \perp BC$.</div>
</div>
<div class="theory">
<div class="t-card">
<span class="t-tag">9.1</span>
<div class="t-title">Наклонная и проекция</div>
<div class="t-body">
<p>Если $A \notin \alpha$, $AH \perp \alpha$ ($H \in \alpha$), а $AB$ — отрезок до $B \in \alpha, B \neq H$, то:</p>
<ul>
<li>$AH$ — <b>перпендикуляр</b> из $A$;</li>
<li>$AB$ — <b>наклонная</b>;</li>
<li>$HB$ — <b>проекция</b> наклонной $AB$.</li>
</ul>
</div>
</div>
<div class="t-card">
<span class="t-tag">9.2</span>
<div class="t-title">Угол между прямой и плоскостью</div>
<div class="t-body">
<p>Углом между <b>наклонной</b> и плоскостью называется <b>угол между наклонной и её проекцией</b> на эту плоскость: $\varphi = \angle ABH$.</p>
<p>Для перпендикулярной прямой угол с плоскостью равен $90°$.</p>
<p>Для прямой, лежащей в плоскости (или параллельной ей) — $0°$.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">9.3</span>
<div class="t-title">Теорема о трёх перпендикулярах</div>
<div class="t-body">
<p><b>Прямая теорема:</b> $AH \perp \alpha, BC \subset \alpha, HB \perp BC \Rightarrow AB \perp BC$.</p>
<p><b>Обратная теорема:</b> $AH \perp \alpha, BC \subset \alpha, AB \perp BC \Rightarrow HB \perp BC$.</p>
<p>Часто применяется в задачах с пирамидами и призмами.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">9.4</span>
<div class="t-title">Равные наклонные = равные проекции</div>
<div class="t-body">
<p>Из одной точки $A$ к плоскости $\alpha$ проведены наклонные $AB_1$ и $AB_2$. Тогда:</p>
<ul>
<li>$|AB_1| = |AB_2| \Leftrightarrow |HB_1| = |HB_2|$;</li>
<li>бóльшая наклонная даёт бóльшую проекцию.</li>
</ul>
</div>
</div>
<div class="t-card">
<span class="t-tag">9.5</span>
<div class="t-title">Формула угла</div>
<div class="t-body">
<p>Если $|AH| = h$ — перпендикуляр, $|HB| = p$ — проекция, $|AB| = \ell$ — наклонная, то:</p>
<p>$\tg \varphi = \dfrac{h}{p}, \quad \sin \varphi = \dfrac{h}{\ell}, \quad \cos \varphi = \dfrac{p}{\ell}$.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">9.6</span>
<div class="t-title">ТТП в кубе</div>
<div class="t-body">
<p>Куб $ABCDA_1B_1C_1D_1$. Диагональ $AC_1$ — наклонная к плоскости $ABCD$. Её проекция — диагональ $AC$ нижней грани.</p>
<p>$\tg \varphi = \dfrac{AA_1}{AC} = \dfrac{a}{a\sqrt{2}} = \dfrac{1}{\sqrt{2}}$, откуда $\varphi \approx 35{,}26°$.</p>
</div>
</div>
</div>
<div class="inter" data-inter="i9-elem">
<div class="inter-h">
<div class="inter-icon">1</div>
<div class="inter-title">Перпендикуляр, наклонная или проекция?</div>
<div class="inter-progress" id="i9-elem-prog">0 / 6</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i9-elem-q"></div>
<div class="quiz-opts" id="i9-elem-opts"></div>
</div>
<div class="quiz-feedback" id="i9-elem-fb"></div>
</div>
<div class="inter" data-inter="i9-cube">
<div class="inter-h">
<div class="inter-icon">2</div>
<div class="inter-title">Углы наклонных в кубе (ребро $a = 1$)</div>
<div class="inter-progress" id="i9-cube-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i9-cube-q"></div>
<div class="quiz-input">
<input id="i9-cube-in" type="text" placeholder="ответ">
<button id="i9-cube-go">OK</button>
</div>
</div>
<div class="quiz-feedback" id="i9-cube-fb"></div>
</div>
<div class="inter" data-inter="i9-ttp">
<div class="inter-h">
<div class="inter-icon">3</div>
<div class="inter-title">Применима ли ТТП?</div>
<div class="inter-progress" id="i9-ttp-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i9-ttp-q"></div>
<div class="quiz-opts" id="i9-ttp-opts"></div>
</div>
<div class="quiz-feedback" id="i9-ttp-fb"></div>
</div>
<div class="boss" id="boss-9"></div>
<div class="para-actions">
<button class="mark-btn" id="mark-9">
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
<span>Отметить §9 как изученный</span>
</button>
</div>
</section>
<!-- §10 -->
<section id="para-10" class="para">
<div class="para-head">
<div class="para-num">§ 10</div>
<div class="para-h">
<h2>Перпендикулярность плоскостей</h2>
<div class="para-h-sub">Двугранный угол · линейный угол · признак $\alpha \perp \beta$</div>
</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ДВУГРАННЫЙ УГОЛ</span> Полуплоскости с общим ребром</div>
<div id="viz10-dihedral" style="text-align:center"></div>
<div class="viz-cap">Двугранный угол — фигура из двух полуплоскостей с общим ребром $l$. Его величина измеряется <b>линейным углом</b>: из точки $M \in l$ в каждой полуплоскости проводят $MP \perp l$ и $MQ \perp l$. Тогда $\angle PMQ$ — линейный угол двугранного угла.</div>
</div>
<div class="viz">
<div class="viz-title"><span class="badge">ПРИЗНАК</span> $\alpha \perp \beta$, если $\alpha \supset l \perp \beta$</div>
<div id="viz10-sign" style="text-align:center"></div>
<div class="viz-cap">Если плоскость $\alpha$ содержит прямую $l$, <b>перпендикулярную</b> плоскости $\beta$, — то $\alpha \perp \beta$. Иначе: достаточно одной перпендикулярной к $\beta$ прямой в $\alpha$, чтобы плоскости были перпендикулярны.</div>
</div>
<div class="theory">
<div class="t-card">
<span class="t-tag">10.1</span>
<div class="t-title">Двугранный угол</div>
<div class="t-body">
<p><b>Двугранный угол</b> — фигура из двух полуплоскостей с общим ребром $l$ (граней двугранного угла).</p>
<p>Двугранный угол может быть острым, прямым, тупым или развёрнутым.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">10.2</span>
<div class="t-title">Линейный угол</div>
<div class="t-body">
<p>Возьмём $M \in l$. В каждой полуплоскости проведём луч $\perp l$ из $M$. Угол между этими лучами — <b>линейный угол</b>.</p>
<p>Линейный угол не зависит от выбора точки $M$ на ребре.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">10.3</span>
<div class="t-title">Перпендикулярные плоскости</div>
<div class="t-body">
<p>Две плоскости называются <b>перпендикулярными</b>, если их двугранный угол прямой ($90°$).</p>
<p>Обозначение: $\alpha \perp \beta$.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">10.4</span>
<div class="t-title">Признак $\alpha \perp \beta$</div>
<div class="t-body">
<p>Если плоскость $\alpha$ содержит прямую $l$, перпендикулярную плоскости $\beta$, то $\alpha \perp \beta$.</p>
<p>Достаточно <b>одной</b> такой прямой.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">10.5</span>
<div class="t-title">Свойство</div>
<div class="t-body">
<p>Если $\alpha \perp \beta$ и из точки $M \in \alpha$ опустить перпендикуляр $MK$ в плоскости $\alpha$ к линии пересечения $\alpha \cap \beta$, то $MK \perp \beta$.</p>
<p>Перпендикуляр к ребру двугранного угла в одной из полуплоскостей перпендикулярен другой плоскости.</p>
</div>
</div>
<div class="t-card">
<span class="t-tag">10.6</span>
<div class="t-title">⊥-плоскости в кубе</div>
<div class="t-body">
<p>В кубе все смежные грани перпендикулярны. Например, $ABCD \perp ABB_1A_1$, потому что ребро $AA_1 \subset ABB_1A_1$ и $AA_1 \perp ABCD$ — выполнен признак.</p>
<p>Каждая грань куба перпендикулярна 4 соседним и параллельна 1 противоположной.</p>
</div>
</div>
</div>
<div class="inter" data-inter="i10-dihedral">
<div class="inter-h">
<div class="inter-icon">1</div>
<div class="inter-title">Двугранный угол: понимаешь?</div>
<div class="inter-progress" id="i10-dihedral-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i10-dihedral-q"></div>
<div class="quiz-opts" id="i10-dihedral-opts"></div>
</div>
<div class="quiz-feedback" id="i10-dihedral-fb"></div>
</div>
<div class="inter" data-inter="i10-sign">
<div class="inter-h">
<div class="inter-icon">2</div>
<div class="inter-title">Признак перпендикулярности плоскостей</div>
<div class="inter-progress" id="i10-sign-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i10-sign-q"></div>
<div class="quiz-opts" id="i10-sign-opts"></div>
</div>
<div class="quiz-feedback" id="i10-sign-fb"></div>
</div>
<div class="inter" data-inter="i10-cube">
<div class="inter-h">
<div class="inter-icon">3</div>
<div class="inter-title">Перпендикулярность граней куба</div>
<div class="inter-progress" id="i10-cube-prog">0 / 5</div>
</div>
<div class="quiz">
<div class="quiz-q" id="i10-cube-q"></div>
<div class="quiz-opts" id="i10-cube-opts"></div>
</div>
<div class="quiz-feedback" id="i10-cube-fb"></div>
</div>
<div class="boss" id="boss-10"></div>
<div class="para-actions">
<button class="mark-btn" id="mark-10">
<svg class="ic" viewBox="0 0 24 24"><polyline points="20 6 9 17 4 12"/></svg>
<span>Отметить §10 как изученный</span>
</button>
</div>
</section>
<section id="para-final" class="para">
<div class="para-head">
<div class="para-num"></div>
<div class="para-h">
<h2>Финал раздела 3</h2>
<div class="para-h-sub">5 интегральных боссов · ачивка «Перпендикулярность освоена»</div>
</div>
</div>
<div class="viz" style="background:linear-gradient(135deg,var(--pri-soft),var(--pri-soft-2));border-color:var(--pri-l)">
<div class="viz-title" style="color:var(--pri-d)"><span class="badge">ФИНАЛЬНОЕ ИСПЫТАНИЕ</span> Победи 5 боссов подряд</div>
<div class="viz-cap" style="color:var(--text-2);margin-top:0">Каждый босс — на одну тему: <b>прямая⊥плоскость</b>, <b>расстояния</b>, <b>угол наклонной + ТТП</b>, <b>⊥-плоскости</b>, <b>сборная задача</b>. После победы над всеми — ачивка <code>stereo10_r3_master</code> и +130 XP бонусом.</div>
</div>
<div class="boss" id="boss-f1"></div>
<div class="boss" id="boss-f2"></div>
<div class="boss" id="boss-f3"></div>
<div class="boss" id="boss-f4"></div>
<div class="boss" id="boss-f5"></div>
<div id="celebration" style="display:none"></div>
</section>
</main>
<footer class="foot">
Геометрия — 10 класс · Раздел 3 · LearnSpace
</footer>
<script>
'use strict';
(function(){
var saved = localStorage.getItem('geometry10_theme') || localStorage.getItem('theme') || 'light';
if (saved === 'dark') document.documentElement.classList.add('dark');
var lab = document.getElementById('theme-lab');
if (lab) lab.textContent = saved === 'dark' ? 'Светлая' : 'Тёмная';
document.getElementById('theme-btn').addEventListener('click', function(){
document.documentElement.classList.toggle('dark');
var dark = document.documentElement.classList.contains('dark');
localStorage.setItem('geometry10_theme', dark ? 'dark' : 'light');
localStorage.setItem('theme', dark ? 'dark' : 'light');
if (lab) lab.textContent = dark ? 'Светлая' : 'Тёмная';
});
})();
var STATE_KEY = 'geometry10_r3_state';
var STATE = (function(){
try { var raw = localStorage.getItem(STATE_KEY); if (raw) return JSON.parse(raw); } catch(e){}
return { read:[], bosses:{}, interactives:{} };
})();
function saveState(){ try { localStorage.setItem(STATE_KEY, JSON.stringify(STATE)); } catch(e){} }
function addXp(amount, reason){
var cur = parseInt(localStorage.getItem('geometry10_xp') || '0', 10) || 0;
cur += amount;
localStorage.setItem('geometry10_xp', String(cur));
updateXpBadge();
if (window.LS && window.LS.xp && typeof window.LS.xp.toast === 'function'){
window.LS.xp.toast('+' + amount + ' XP — ' + (reason || ''));
}
}
function updateXpBadge(){
var el = document.getElementById('hdr-xp');
if (el) el.textContent = (parseInt(localStorage.getItem('geometry10_xp')||'0',10)||0) + ' XP';
}
updateXpBadge();
var syncTimer = null;
function syncProgress(){
if (syncTimer) clearTimeout(syncTimer);
syncTimer = setTimeout(function(){
if (!window.LS || typeof window.LS.api !== 'function') return;
window.LS.api('/api/textbooks/geometry-10-r3/progress', {
method:'POST',
body: JSON.stringify({ read: STATE.read })
}).catch(function(){});
}, 600);
}
function markRead(paraNum){
if (STATE.read.indexOf(paraNum) < 0){
STATE.read.push(paraNum);
saveState();
syncProgress();
}
refreshTabs();
refreshMarkBtn(paraNum);
}
function refreshMarkBtn(n){
var btn = document.getElementById('mark-' + n);
if (!btn) return;
if (STATE.read.indexOf(n) >= 0){
btn.classList.add('done');
btn.querySelector('span').textContent = '§' + n + ' изучен';
}
}
function refreshTabs(){
document.querySelectorAll('.sec-tab').forEach(function(t){
var n = t.getAttribute('data-tab');
if (n === '7' || n === '8' || n === '9' || n === '10'){
if (STATE.read.indexOf(parseInt(n,10)) >= 0) t.classList.add('read');
else t.classList.remove('read');
} else if (n === 'final'){
var allBeat = ['f1','f2','f3','f4','f5'].every(function(k){
return STATE.bosses && STATE.bosses[k] && STATE.bosses[k].defeated;
});
if (allBeat) t.classList.add('read');
}
});
}
/* ========== SVG VIZ ========== */
function buildPerpDef(){
if (!window.STEREO3D) return setTimeout(buildPerpDef, 80);
var S = window.STEREO3D;
var sc = new S.Scene(420, 320, {view:'CABINET', scale:50});
sc.addPlane([0,0,0],[0,0,1],{size:2.2, label:'α'});
// Прямая l вертикально через O
sc.addEdge([0,0,-0.3],[0,0,1.8], {stroke:'#dc2626', width:3});
sc.addLabel('l', [0,0,1.8], {dx:12, dy:-4, color:'#dc2626', fontSize:16, anchor:'start'});
sc.addVertex([0,0,0], 'O', {dx:10, dy:14, color:'#0b1d33'});
// 4 прямые в плоскости через O (под разными углами)
var dirs = [
[1.5, 0, 0], // x
[0, 1.5, 0], // y
[1.2, 1.0, 0],
[-1.2, 1.0, 0]
];
for (var i = 0; i < dirs.length; i++){
sc.addEdge([-dirs[i][0], -dirs[i][1], 0], dirs[i], {stroke:'#1e3a8a', width:1.8});
// маркер прямого угла
sc.addRightAngleMark([0,0,0], [0,0,0.3], [dirs[i][0]*0.25, dirs[i][1]*0.25, 0], {color:'#7c3aed', width:1.5, size:0.18});
}
document.getElementById('viz7-def').innerHTML = sc.render();
}
function buildPerpSign(){
if (!window.STEREO3D) return setTimeout(buildPerpSign, 80);
var S = window.STEREO3D;
var sc = new S.Scene(420, 320, {view:'CABINET', scale:50});
sc.addPlane([0,0,0],[0,0,1],{size:2.2, label:'α'});
// l вертикально
sc.addEdge([0,0,-0.2],[0,0,1.8], {stroke:'#dc2626', width:3});
sc.addLabel('l', [0,0,1.8], {dx:12, dy:-4, color:'#dc2626', fontSize:16, anchor:'start'});
// m в плоскости α (вдоль x)
sc.addEdge([-1.6, 0, 0],[1.6, 0, 0], {stroke:'#16a34a', width:2.4});
sc.addLabel('m', [1.6, 0, 0], {dx:12, dy:-4, color:'#16a34a', fontSize:14, anchor:'start'});
// n в плоскости α (вдоль y)
sc.addEdge([0, -1.4, 0],[0, 1.4, 0], {stroke:'#0891b2', width:2.4});
sc.addLabel('n', [0, 1.4, 0], {dx:12, dy:-4, color:'#0891b2', fontSize:14, anchor:'start'});
// O — точка пересечения
sc.addVertex([0,0,0], 'O', {dx:-22, dy:14, color:'#0b1d33'});
// правый угол l-m и l-n
sc.addRightAngleMark([0,0,0], [0,0,0.3], [0.3, 0, 0], {color:'#7c3aed', width:1.5, size:0.20});
sc.addRightAngleMark([0,0,0], [0,0,0.3], [0, 0.3, 0], {color:'#7c3aed', width:1.5, size:0.20});
document.getElementById('viz7-sign').innerHTML = sc.render();
}
function buildDistanceCases(){
if (!window.STEREO3D) return setTimeout(buildDistanceCases, 80);
var S = window.STEREO3D;
// 1) Точка → плоскость
(function(){
var sc = new S.Scene(220, 200, {view:'CABINET', scale:40});
sc.addPlane([0,0,0],[0,0,1],{size:1.8, label:'α'});
sc.addVertex([0, 0, 1.2], 'A', {dx:10, dy:-6, color:'#dc2626'});
sc.addEdge([0, 0, 1.2],[0, 0, 0], {stroke:'#dc2626', width:2.6});
sc.addVertex([0, 0, 0], 'O', {dx:-14, dy:14, color:'#0b1d33'});
sc.addRightAngleMark([0,0,0], [0,0,0.3], [0.3, 0, 0], {color:'#7c3aed', width:1.5, size:0.20});
document.getElementById('viz8-pt-pl').innerHTML = sc.render();
})();
// 2) Прямая ∥ плоскость
(function(){
var sc = new S.Scene(220, 200, {view:'CABINET', scale:40});
sc.addPlane([0,0,0],[0,0,1],{size:1.8, label:'α'});
sc.addEdge([-1.4, -0.4, 0.9],[1.4, 0.4, 0.9], {stroke:'#16a34a', width:2.6});
sc.addLabel('a', [1.4, 0.4, 0.9], {dx:12, dy:-4, color:'#16a34a', fontSize:14, anchor:'start'});
sc.addEdge([0, 0, 0.9],[0, 0, 0], {stroke:'#dc2626', width:2.4, dash:'5 3'});
document.getElementById('viz8-ln-pl').innerHTML = sc.render();
})();
// 3) Параллельные плоскости
(function(){
var sc = new S.Scene(220, 200, {view:'CABINET', scale:40});
sc.addPlane([0,0,-0.4],[0,0,1],{size:1.5, label:'α'});
sc.addPlane([0,0,+0.6],[0,0,1],{size:1.5, label:'β', fill:'#86efac', opacity:0.32});
sc.addEdge([0, 0, 0.6],[0, 0, -0.4], {stroke:'#dc2626', width:2.6});
document.getElementById('viz8-pl-pl').innerHTML = sc.render();
})();
// 4) Скрещивающиеся прямые
(function(){
var sc = new S.Scene(220, 200, {view:'CABINET', scale:40});
sc.addEdge([-1.3, -0.5, 0],[1.3, 0.5, 0], {stroke:'#1e3a8a', width:2.4});
sc.addEdge([-1.3, 0.5, 1.1],[1.3, -0.5, 1.1], {stroke:'#0891b2', width:2.4});
// общий перпендикуляр
sc.addEdge([0,0,0],[0,0,1.1], {stroke:'#dc2626', width:2.6});
sc.addLabel('a', [1.3, 0.5, 0], {dx:10, dy:-4, color:'#1e3a8a', fontSize:13, anchor:'start'});
sc.addLabel('b', [1.3, -0.5, 1.1], {dx:10, dy:-4, color:'#0891b2', fontSize:13, anchor:'start'});
document.getElementById('viz8-skew').innerHTML = sc.render();
})();
}
function buildDistanceDetail(){
if (!window.STEREO3D) return setTimeout(buildDistanceDetail, 80);
var S = window.STEREO3D;
var sc = new S.Scene(440, 320, {view:'CABINET', scale:60});
sc.addPlane([0,0,0],[0,0,1],{size:2.2, label:'α'});
// Точка A над плоскостью
sc.addVertex([0.2, 0.3, 1.2], 'A', {dx:10, dy:-6, color:'#dc2626'});
// Перпендикуляр AO
sc.addEdge([0.2, 0.3, 1.2],[0.2, 0.3, 0], {stroke:'#dc2626', width:2.8});
sc.addVertex([0.2, 0.3, 0], 'O', {dx:-18, dy:14, color:'#0b1d33'});
// Наклонная AB
sc.addEdge([0.2, 0.3, 1.2],[-1.2, -0.7, 0], {stroke:'#1e3a8a', width:2.4, dash:'4 3'});
sc.addVertex([-1.2, -0.7, 0], 'B', {dx:-16, dy:14, color:'#1e3a8a'});
// Прямой угол при O
sc.addRightAngleMark([0.2,0.3,0], [0.2,0.3,0.3], [0.5, 0.3, 0], {color:'#7c3aed', width:1.5, size:0.18});
// Подписи длин
sc.addLabel('h', [0.2, 0.3, 0.6], {dx:14, dy:0, color:'#dc2626', fontSize:14, anchor:'start'});
document.getElementById('viz8-detail').innerHTML = sc.render();
}
/* ===== §9 SVGs ===== */
function buildAngleViz(){
if (!window.STEREO3D) return setTimeout(buildAngleViz, 80);
var S = window.STEREO3D;
var sc = new S.Scene(440, 320, {view:'CABINET', scale:60});
sc.addPlane([0,0,0],[0,0,1],{size:2.2, label:'α'});
// Точка A над плоскостью
var A = [0, 0, 1.4];
var H = [0, 0, 0];
var B = [1.3, 0.4, 0];
sc.addVertex(A, 'A', {dx:10, dy:-6, color:'#dc2626'});
sc.addVertex(H, 'H', {dx:-18, dy:14, color:'#7c3aed'});
sc.addVertex(B, 'B', {dx:12, dy:10, color:'#1e3a8a'});
// AH — перпендикуляр
sc.addEdge(A, H, {stroke:'#dc2626', width:2.8});
// AB — наклонная
sc.addEdge(A, B, {stroke:'#1e3a8a', width:2.6});
// HB — проекция
sc.addEdge(H, B, {stroke:'#16a34a', width:2.6});
// Прямой угол при H
sc.addRightAngleMark(H, [0,0,0.3], [0.3, 0.1, 0], {color:'#7c3aed', width:1.5, size:0.18});
// Угол φ при B
sc.addAngleMark(B, A, H, {r:0.45, color:'#d97706', width:1.6, label:'φ'});
document.getElementById('viz9-angle').innerHTML = sc.render();
}
function buildTTPViz(){
if (!window.STEREO3D) return setTimeout(buildTTPViz, 80);
var S = window.STEREO3D;
var sc = new S.Scene(440, 320, {view:'CABINET', scale:60});
sc.addPlane([0,0,0],[0,0,1],{size:2.2, label:'α'});
var A = [0, 0, 1.3];
var H = [0, 0, 0];
var B = [1.2, 0, 0];
var C = [1.2, 0.9, 0];
sc.addVertex(A, 'A', {dx:10, dy:-6, color:'#dc2626'});
sc.addVertex(H, 'H', {dx:-18, dy:14, color:'#7c3aed'});
sc.addVertex(B, 'B', {dx:6, dy:14, color:'#1e3a8a'});
sc.addVertex(C, 'C', {dx:12, dy:-4, color:'#16a34a'});
// AH перпендикуляр
sc.addEdge(A, H, {stroke:'#dc2626', width:2.8});
// HB проекция
sc.addEdge(H, B, {stroke:'#7c3aed', width:2.4});
// BC — прямая в α перпендикулярная HB
sc.addEdge(B, C, {stroke:'#16a34a', width:2.6});
// AB наклонная
sc.addEdge(A, B, {stroke:'#1e3a8a', width:2.6});
// Прямые углы: при H (AH ⊥ HB), при B (HB ⊥ BC), при B (AB ⊥ BC по выводу)
sc.addRightAngleMark(H, [0,0,0.3], [0.3, 0, 0], {color:'#7c3aed', width:1.5, size:0.18});
sc.addRightAngleMark(B, [0.9, 0, 0], [1.2, 0.3, 0], {color:'#7c3aed', width:1.5, size:0.18});
document.getElementById('viz9-ttp').innerHTML = sc.render();
}
/* ===== §10 SVGs ===== */
function buildDihedralViz(){
if (!window.STEREO3D) return setTimeout(buildDihedralViz, 80);
var S = window.STEREO3D;
var sc = new S.Scene(440, 320, {view:'CABINET', scale:60});
// Полуплоскость 1: горизонтальная (y >= 0)
// Полуплоскость 2: наклонена под 60° от первой
// Ребро l — ось x
// Рисуем как 2 параллелограмма
// Полуплоскость 1: точки (-1.4,0,0), (1.4,0,0), (1.4,1.2,0), (-1.4,1.2,0)
sc.addFace([[-1.4,0,0],[1.4,0,0],[1.4,1.2,0],[-1.4,1.2,0]], {fill:'#dbeafe', opacity:0.45, stroke:'#1e3a8a', strokeWidth:1.2});
// Полуплоскость 2: повёрнута на 60° вокруг x
var a = Math.PI / 3;
var ca = Math.cos(a), sa = Math.sin(a);
var rot60 = function(p){ return [p[0], p[1]*ca, p[1]*sa]; };
sc.addFace([
rot60([-1.4,0,0]),
rot60([1.4,0,0]),
rot60([1.4,1.2,0]),
rot60([-1.4,1.2,0])
], {fill:'#fef3c7', opacity:0.50, stroke:'#d97706', strokeWidth:1.2});
// Ребро l
sc.addEdge([-1.5, 0, 0],[1.5, 0, 0], {stroke:'#dc2626', width:3});
sc.addLabel('l', [1.5, 0, 0], {dx:12, dy:-4, color:'#dc2626', fontSize:15, anchor:'start'});
// Точка M на ребре
var M = [0.2, 0, 0];
sc.addVertex(M, 'M', {dx:0, dy:14, color:'#0b1d33'});
// MP в первой полуплоскости перпендикулярно l (вдоль y)
var P = [0.2, 0.9, 0];
sc.addEdge(M, P, {stroke:'#1e3a8a', width:2.4});
sc.addVertex(P, 'P', {dx:8, dy:-4, color:'#1e3a8a'});
// MQ во второй полуплоскости перпендикулярно l (под 60° от MP)
var Q = rot60([0.2, 0.9, 0]);
sc.addEdge(M, Q, {stroke:'#d97706', width:2.4});
sc.addVertex(Q, 'Q', {dx:8, dy:-4, color:'#d97706'});
// Угол PMQ
sc.addAngleMark(M, P, Q, {r:0.40, color:'#7c3aed', width:1.6, label:'φ'});
// Прямые углы при M
sc.addRightAngleMark(M, [0.45, 0, 0], [0.2, 0.25, 0], {color:'#16a34a', width:1.4, size:0.16});
document.getElementById('viz10-dihedral').innerHTML = sc.render();
}
function buildPlanePerpSign(){
if (!window.STEREO3D) return setTimeout(buildPlanePerpSign, 80);
var S = window.STEREO3D;
var sc = new S.Scene(440, 320, {view:'CABINET', scale:55});
// β — горизонтальная
sc.addPlane([0,0,0],[0,0,1],{size:2.2, label:'β'});
// α — вертикальная (yz-плоскость, нормаль вдоль x)
sc.addPlane([0,0,0.6],[1,0,0],{size:1.5, label:'α', fill:'#fde047', opacity:0.30});
// Прямая l в α (вертикальная) перпендикулярна β
sc.addEdge([0,0,-0.2],[0,0,1.8], {stroke:'#dc2626', width:3});
sc.addLabel('l', [0,0,1.8], {dx:12, dy:-4, color:'#dc2626', fontSize:16, anchor:'start'});
// Точка O пересечения l и β
sc.addVertex([0,0,0], 'O', {dx:8, dy:14, color:'#0b1d33'});
// Прямой угол при O между l и β
sc.addRightAngleMark([0,0,0], [0,0,0.3], [0.3, 0, 0], {color:'#7c3aed', width:1.5, size:0.18});
document.getElementById('viz10-sign').innerHTML = sc.render();
}
/* ========== Quiz Engine (shared) ========== */
function runQuizMC(opts){
var state = STATE.interactives[opts.id] || { idx: 0, solved: 0 };
var qEl = document.getElementById(opts.id + '-q');
var optsEl = document.getElementById(opts.id + '-opts');
var fbEl = document.getElementById(opts.id + '-fb');
var progEl = document.getElementById(opts.id + '-prog');
function render(){
if (state.solved >= opts.items.length){
qEl.innerHTML = '<b style="color:var(--good)">Все задания решены!</b> +' + (opts.xpPerAll || 10) + ' XP.';
optsEl.innerHTML = '';
fbEl.classList.remove('show');
progEl.textContent = opts.items.length + ' / ' + opts.items.length;
if (!state.awarded){
state.awarded = true;
STATE.interactives[opts.id] = state;
saveState();
addXp(opts.xpPerAll || 10, opts.title || 'тренажёр');
}
return;
}
var item = opts.items[state.idx % opts.items.length];
qEl.innerHTML = item.q;
optsEl.innerHTML = '';
fbEl.classList.remove('show');
for (var i = 0; i < item.opts.length; i++){
(function(i){
var btn = document.createElement('button');
btn.className = 'quiz-opt';
btn.innerHTML = item.opts[i];
btn.addEventListener('click', function(){
var correct = (i === item.correct);
if (correct){
btn.classList.add('correct');
state.solved++;
state.idx++;
STATE.interactives[opts.id] = state;
saveState();
progEl.textContent = state.solved + ' / ' + opts.items.length;
fbEl.className = 'quiz-feedback show good';
fbEl.innerHTML = '<b>Верно.</b> ' + (item.explain || '');
tryKatex(fbEl);
setTimeout(render, 900);
} else {
btn.classList.add('wrong');
fbEl.className = 'quiz-feedback show bad';
fbEl.innerHTML = '<b>Не так.</b> ' + (item.explain || '');
tryKatex(fbEl);
}
});
optsEl.appendChild(btn);
})(i);
}
progEl.textContent = state.solved + ' / ' + opts.items.length;
tryKatex(qEl);
}
render();
}
function runQuizInput(opts){
var state = STATE.interactives[opts.id] || { idx:0, solved:0 };
var qEl = document.getElementById(opts.id + '-q');
var inEl = document.getElementById(opts.id + '-in');
var goEl = document.getElementById(opts.id + '-go');
var fbEl = document.getElementById(opts.id + '-fb');
var progEl = document.getElementById(opts.id + '-prog');
var box = inEl.parentNode;
function normalizeAns(s){
return String(s||'').toLowerCase()
.replace(/\s+/g,'')
.replace(/°/g,'')
.replace(/sqrt/g,'√')
.replace(/корень/g,'√')
.replace(/,/g,'.');
}
function render(){
if (state.solved >= opts.items.length){
qEl.innerHTML = '<b style="color:var(--good)">Все задания решены!</b> +' + (opts.xpPerAll || 10) + ' XP.';
inEl.value = ''; inEl.disabled = true; goEl.disabled = true;
progEl.textContent = opts.items.length + ' / ' + opts.items.length;
box.className = 'quiz-input correct';
if (!state.awarded){
state.awarded = true;
STATE.interactives[opts.id] = state;
saveState();
addXp(opts.xpPerAll || 10, opts.title || 'тренажёр');
}
return;
}
var item = opts.items[state.idx % opts.items.length];
qEl.innerHTML = item.q;
inEl.value = ''; inEl.disabled = false; goEl.disabled = false;
fbEl.classList.remove('show');
box.className = 'quiz-input';
progEl.textContent = state.solved + ' / ' + opts.items.length;
tryKatex(qEl);
}
function check(){
var item = opts.items[state.idx % opts.items.length];
var v = normalizeAns(inEl.value);
var answers = Array.isArray(item.answer) ? item.answer.map(normalizeAns) : [normalizeAns(item.answer)];
if (answers.indexOf(v) >= 0){
box.className = 'quiz-input correct';
state.solved++;
state.idx++;
STATE.interactives[opts.id] = state;
saveState();
fbEl.className = 'quiz-feedback show good';
fbEl.innerHTML = '<b>Верно.</b> ' + (item.explain || '');
tryKatex(fbEl);
setTimeout(render, 900);
} else {
box.className = 'quiz-input wrong';
fbEl.className = 'quiz-feedback show bad';
fbEl.innerHTML = '<b>Не так.</b> ' + (item.explain || '');
tryKatex(fbEl);
}
}
goEl.addEventListener('click', check);
inEl.addEventListener('keydown', function(e){ if (e.key === 'Enter') check(); });
render();
}
/* ========== Quiz Items ========== */
var i7PerpItems = [
{ q:'Прямая $l$ перпендикулярна одной прямой $a \\subset \\alpha$. Достаточно для $l \\perp \\alpha$?', opts:['Да','Нет','Иногда'], correct:1, explain:'Нужны две пересекающиеся прямые в плоскости — одной мало.' },
{ q:'Прямая $l$ перпендикулярна двум параллельным прямым $a, b \\subset \\alpha$. Достаточно?', opts:['Да','Нет'], correct:1, explain:'Нужны именно две ПЕРЕСЕКАЮЩИЕСЯ. Параллельные мало.' },
{ q:'Прямая $l$ перпендикулярна двум пересекающимся $m, n \\subset \\alpha$. Тогда $l \\perp \\alpha$?', opts:['Да','Нет','Иногда'], correct:0, explain:'Это и есть признак перпендикулярности.' },
{ q:'Если $l \\perp \\alpha$ и $p \\subset \\alpha$, то…', opts:['$l \\perp p$','$l \\parallel p$','$l$ скрещ. с $p$'], correct:0, explain:'$l$ перпендикулярна любой прямой плоскости.' },
{ q:'Если $l_1 \\perp \\alpha$ и $l_2 \\perp \\alpha$, то $l_1$ и $l_2$…', opts:['Параллельны','Пересекаются','Перпендикулярны'], correct:0, explain:'Две прямые, перпендикулярные одной плоскости, всегда параллельны.' },
{ q:'Через точку проходит сколько прямых, перпендикулярных данной плоскости?', opts:['1','2','Бесконечно'], correct:0, explain:'Единственная.' }
];
var i7SignItems = [
{ q:'В кубе ребро $AA_1$ перпендикулярно $AB$ и $AD$. Каков вывод?', opts:['$AA_1 \\perp ABCD$','$AA_1 \\parallel ABCD$','Никакого'], correct:0, explain:'$AB$ и $AD$ пересекаются в $A$ — признак работает: $AA_1 \\perp$ плоскости $ABCD$.' },
{ q:'Прямая $l$ перпендикулярна двум прямым $a, b \\subset \\alpha$, но $a \\parallel b$. Можем ли утверждать $l \\perp \\alpha$?', opts:['Да','Нет','Иногда'], correct:1, explain:'Признак требует ПЕРЕСЕКАЮЩИЕСЯ прямые. Параллельных недостаточно.' },
{ q:'Доказано $l \\perp \\alpha$. Что можем заключить про любую прямую $p \\subset \\alpha$?', opts:['$l \\perp p$','$l \\parallel p$','Ничего'], correct:0, explain:'Свойство: $l \\perp$ каждой прямой плоскости.' },
{ q:'Если $l_1 \\perp \\alpha$ и $l_1 \\parallel l_2$, то $l_2$…', opts:['$\\perp \\alpha$','$\\parallel \\alpha$','Лежит в $\\alpha$'], correct:0, explain:'Если параллельна перпендикулярной — сама перпендикулярна.' },
{ q:'Прямая $l$ пересекает плоскость $\\alpha$ и образует с двумя пересек. прямыми $m, n \\subset \\alpha$ равные углы. Что нельзя заключить?', opts:['$l \\perp \\alpha$','$l$ наклонная','Угол с $\\alpha$ определён'], correct:0, explain:'Равные углы — недостаточно для перпендикулярности. Нужны прямые углы.' }
];
var i7CubeItems = [
{ q:'Куб: ребро $AA_1$ и плоскость $ABCD$ — это…', opts:['$\\perp$','$\\parallel$','Лежит'], correct:0, explain:'$AA_1 \\perp AB$ и $AA_1 \\perp AD$ ⇒ $AA_1 \\perp ABCD$.' },
{ q:'Куб: ребро $BB_1$ и плоскость $ABCD$ — это…', opts:['$\\perp$','$\\parallel$','Под углом 45°'], correct:0, explain:'Все боковые рёбра перпендикулярны основанию.' },
{ q:'Куб: ребро $AB$ и плоскость $ADD_1A_1$ (левая боковая) — это…', opts:['$\\perp$','$\\parallel$','Лежит'], correct:0, explain:'$AB \\perp AD$ и $AB \\perp AA_1$ ⇒ $AB \\perp$ плоскости $ADD_1A_1$.' },
{ q:'Куб: какая прямая перпендикулярна плоскости $BCC_1B_1$ (правая грань)?', opts:['$AB$','$BC$','$BB_1$','$AC$'], correct:0, explain:'$AB \\perp BC$ и $AB \\perp BB_1$ — обе в правой грани ⇒ $AB \\perp BCC_1B_1$.' },
{ q:'Куб: диагональ $AC$ нижней грани и ребро $AA_1$ — это…', opts:['$\\perp$','$\\parallel$','Под углом 45°'], correct:0, explain:'$AA_1 \\perp$ всей плоскости $ABCD$, значит $AA_1 \\perp AC$ (свойство).' }
];
var i8CubeItems = [
{ q:'Куб с ребром $1$. Расстояние от $A$ до плоскости $A_1B_1C_1D_1$?', answer:'1', explain:'Это длина бокового ребра $AA_1 = 1$.' },
{ q:'Куб с ребром $1$. Расстояние между параллельными гранями?', answer:'1', explain:'Расстояние = ребро куба = $1$.' },
{ q:'Куб с ребром $1$. Расстояние между скрещ. рёбрами $AB$ и $CC_1$?', answer:'1', explain:'Общий перпендикуляр — это $BC = 1$.' },
{ q:'Куб с ребром $1$. Расстояние между скрещ. рёбрами $AB$ и $C_1D_1$? (Запиши без $\\sqrt{}$: используй число или формулу типа sqrt(2)).', answer:['√2','sqrt(2)','sqrt2','корень2','1.41','1.414'], explain:'Это диагональ грани квадрата 1×1: $\\sqrt{2}$.' },
{ q:'Куб с ребром $1$. Расстояние между параллельными прямыми $AB$ и $D_1C_1$?', answer:['√2','sqrt(2)','sqrt2','1.41','1.414'], explain:'$AB$ и $D_1C_1$ лежат на противоположных гранях по диагонали; расстояние — диагональ квадрата 1×1 = $\\sqrt{2}$.' },
{ q:'Куб с ребром $2$. Расстояние от $A$ до плоскости $A_1B_1C_1D_1$?', answer:'2', explain:'Ребро куба = 2.' }
];
var i8TypeItems = [
{ q:'«Дан куб. Найди расстояние от $A$ до $B_1$.» Какой это тип задачи?', opts:['Точка → точка','Точка → плоскость','Точка → прямая','Скрещ. прямые'], correct:0, explain:'Просто длина отрезка — расстояние между двумя точками.' },
{ q:'«Дан куб. Найди расстояние от $A$ до плоскости $BB_1C_1C$.» Какой тип?', opts:['Точка → точка','Точка → плоскость','Точка → прямая','Скрещ. прямые'], correct:1, explain:'Точка до плоскости — длина перпендикуляра.' },
{ q:'«Найди расстояние между скрещ. рёбрами куба $AD$ и $BB_1$.»', opts:['Точка → точка','Точка → плоскость','Параллельные плоскости','Скрещ. прямые'], correct:3, explain:'Скрещ. прямые — общий перпендикуляр.' },
{ q:'«Между параллельными гранями куба.»', opts:['Точка → плоскость','Парал. плоскости','Парал. прямые','Скрещ. прямые'], correct:1, explain:'Параллельные плоскости — длина их общего перпендикуляра.' },
{ q:'«Дана прямая $a \\parallel \\alpha$. Найти $\\rho(a, \\alpha)$.»', opts:['Точка → точка','Прямая → парал. пл-ть','Парал. плоскости','Скрещ. прямые'], correct:1, explain:'От параллельной прямой до плоскости — расстояние от любой точки прямой.' }
];
var i8TrueItems = [
{ q:'Перпендикуляр из точки на плоскость — это кратчайший отрезок до неё.', opts:['Верно','Неверно'], correct:0, explain:'Любая наклонная длиннее перпендикуляра.' },
{ q:'Если из точки $A$ опущены перпендикуляр $AO$ и наклонная $AB$, то $|AO| \\ge |AB|$.', opts:['Верно','Неверно'], correct:1, explain:'Наоборот: $|AO| \\le |AB|$. Перпендикуляр — самый короткий.' },
{ q:'Расстояние между скрещ. прямыми — длина общего перпендикуляра.', opts:['Верно','Неверно'], correct:0, explain:'Общий перпендикуляр существует, единствен и реализует кратчайшее расстояние.' },
{ q:'Расстояние от прямой $a \\parallel \\alpha$ до плоскости $\\alpha$ зависит от выбора точки прямой.', opts:['Верно','Неверно'], correct:1, explain:'Не зависит — для любой точки расстояние одинаково.' },
{ q:'У двух параллельных плоскостей есть бесконечно много общих перпендикуляров одинаковой длины.', opts:['Верно','Неверно'], correct:0, explain:'Каждый перпендикуляр к плоскостям имеет одну и ту же длину — расстояние между ними.' }
];
var i9ElemItems = [
{ q:'Из точки $A$ к плоскости $\\alpha$: $AH \\perp \\alpha$, $H \\in \\alpha$. Чем называется $AH$?', opts:['Перпендикуляр','Наклонная','Проекция'], correct:0, explain:'Перпендикуляр.' },
{ q:'Из точки $A$ к плоскости проведён отрезок $AB$, $B \\in \\alpha, B \\neq H$. Это…', opts:['Перпендикуляр','Наклонная','Проекция'], correct:1, explain:'Наклонная.' },
{ q:'Отрезок $HB$ ($H$ — основание перпендикуляра, $B$ — конец наклонной) — это…', opts:['Перпендикуляр','Наклонная','Проекция'], correct:2, explain:'Проекция наклонной на плоскость.' },
{ q:'Угол между прямой и плоскостью — это угол между…', opts:['Прямой и любой прямой плоскости','Прямой и её проекцией','Прямой и перпендикуляром'], correct:1, explain:'Наклонная и её проекция.' },
{ q:'Чему равен угол между прямой и плоскостью, в которой она лежит?', opts:['$0°$','$45°$','$90°$'], correct:0, explain:'Прямая в плоскости даёт угол $0°$.' },
{ q:'Чему равен угол между перпендикулярной к плоскости прямой и самой плоскостью?', opts:['$0°$','$45°$','$90°$'], correct:2, explain:'Перпендикулярная — даёт $90°$.' }
];
var i9CubeItems = [
{ q:'Угол между ребром $AA_1$ и плоскостью $ABCD$ (нижняя грань)?', answer:'90', explain:'$AA_1 \\perp ABCD$ ⇒ угол $90°$.' },
{ q:'Угол между ребром $AB$ и плоскостью $ABCD$?', answer:'0', explain:'Ребро лежит в плоскости — угол $0°$.' },
{ q:'Угол между диагональю $AC$ и плоскостью $ABCD$?', answer:'0', explain:'Диагональ лежит в нижней плоскости.' },
{ q:'$\\tg$ угла между $AC_1$ и плоскостью $ABCD$? (Куб с ребром 1.)', answer:['1/√2','1/sqrt(2)','√2/2','sqrt(2)/2','0.707'], explain:'$\\tg \\varphi = \\frac{AA_1}{AC} = \\frac{1}{\\sqrt{2}} = \\frac{\\sqrt{2}}{2}$.' },
{ q:'Угол между диагональю $A_1C$ и плоскостью $A_1B_1C_1D_1$ — в градусах? (через $\\tg \\varphi = \\sqrt{2}$, ответ $\\approx$54.7°, округли до целого)', answer:['55','54','arctg(√2)','arctan(sqrt(2))'], explain:'Проекция $A_1C$ на верхнюю грань = $A_1C_1$ = $\\sqrt{2}$. $\\tg \\varphi = 1/\\sqrt{2}$... подожди. Перпендикуляр $CC_1 = 1$ (от $C$ до верх. грани). Проекция $C_1A_1 = \\sqrt{2}$. $\\tg \\varphi = 1/\\sqrt{2} \\approx 35°$. Округление: 35.' }
];
// Заметка: 5-я задача переформулирована — оставим ответ 35 (в градусах).
i9CubeItems[4] = { q:'Угол между диагональю $A_1C$ и плоскостью $A_1B_1C_1D_1$ — в градусах, целое (формула $\\tg\\varphi = 1/\\sqrt{2}$, $\\varphi \\approx ?$).', answer:'35', explain:'$\\tg \\varphi = \\frac{1}{\\sqrt{2}} \\approx 0.707 \\Rightarrow \\varphi \\approx 35°$.' };
var i9TtpItems = [
{ q:'$AH \\perp \\alpha$, $BC \\subset \\alpha$, $HB \\perp BC$. Вывод по ТТП?', opts:['$AB \\perp BC$','$AB \\parallel BC$','Ничего'], correct:0, explain:'Прямая ТТП: $AB \\perp BC$.' },
{ q:'$AH \\perp \\alpha$, $BC \\subset \\alpha$, $AB \\perp BC$. Вывод по обратной ТТП?', opts:['$HB \\perp BC$','$HB \\parallel BC$','Ничего'], correct:0, explain:'Обратная ТТП: $HB \\perp BC$.' },
{ q:'Если $BC \\not\\subset \\alpha$ (т.е. $BC$ не лежит в плоскости), применима ли ТТП?', opts:['Да','Нет'], correct:1, explain:'ТТП требует, чтобы $BC$ лежало в той же плоскости, что и проекция.' },
{ q:'Если $AH$ — не перпендикуляр, а наклонная, применима ли ТТП?', opts:['Да','Нет'], correct:1, explain:'ТТП требует именно перпендикуляр $AH$.' },
{ q:'В пирамиде высота $SO \\perp$ основание. Грань $SAB$. Перпендикулярна ли $SAB$ ребру $CD$ в основании? (При условии $OB \\perp CD$)', opts:['Да, по ТТП','Нет','Нужны дополнительные данные'], correct:0, explain:'$SO \\perp$ основание, $CD$ в основании, $OB \\perp CD$ ⇒ по ТТП $SB \\perp CD$.' }
];
var i10DihedralItems = [
{ q:'Двугранный угол — это…', opts:['Угол между прямыми','Фигура из 2 полуплоскостей с общим ребром','Угол наклонной','Угол между плоскостями (всегда острый)'], correct:1, explain:'2 полуплоскости с общим ребром.' },
{ q:'Линейный угол двугранного угла строится…', opts:['Произвольно','Перпендикуляром к ребру из точки $M \\in l$','Через диагональ','Через высоту'], correct:1, explain:'Лучи $\\perp l$ в каждой полуплоскости.' },
{ q:'Зависит ли линейный угол от выбора точки $M$ на ребре?', opts:['Да','Нет'], correct:1, explain:'Не зависит — все линейные углы двугранного угла равны.' },
{ q:'Две плоскости называются перпендикулярными, если…', opts:['Параллельны','Их двугранный угол равен $90°$','Они совпадают','Их пересекает прямая'], correct:1, explain:'Линейный угол $= 90°$.' },
{ q:'Чему равен линейный угол развёрнутого двугранного угла?', opts:['$0°$','$90°$','$180°$','$360°$'], correct:2, explain:'Развёрнутый — это $180°$.' }
];
var i10SignItems = [
{ q:'Прямая $l \\subset \\alpha$, $l \\perp \\beta$. Вывод?', opts:['$\\alpha \\parallel \\beta$','$\\alpha \\perp \\beta$','$\\alpha = \\beta$'], correct:1, explain:'Признак $\\alpha \\perp \\beta$.' },
{ q:'Достаточно ли $\\alpha$ содержать ОДНУ прямую, перпендикулярную $\\beta$, для перпендикулярности плоскостей?', opts:['Да','Нет, нужно две','Нужно три'], correct:0, explain:'Одной прямой достаточно — это и есть признак.' },
{ q:'Если плоскость $\\alpha$ содержит прямую, параллельную $\\beta$, можем ли мы заключить $\\alpha \\perp \\beta$?', opts:['Да','Нет'], correct:1, explain:'Параллельная прямая — это про параллельность плоскостей, а не перпендикулярность.' },
{ q:'$\\alpha \\perp \\beta$. Опускаем из $M \\in \\alpha$ перпендикуляр в $\\alpha$ к линии пересечения. Этот перпендикуляр…', opts:['$\\parallel \\beta$','$\\perp \\beta$','$\\subset \\beta$'], correct:1, explain:'Перпендикулярен второй плоскости (свойство).' },
{ q:'Если плоскость $\\alpha$ перпендикулярна плоскости $\\beta$, а $\\beta \\perp \\gamma$, то $\\alpha \\perp \\gamma$?', opts:['Всегда','Не обязательно','Никогда'], correct:1, explain:'Перпендикулярность плоскостей не транзитивна — могут быть и параллельны, и пересекаться под любым углом.' }
];
var i10CubeItems = [
{ q:'Куб: плоскости граней $ABCD$ и $ABB_1A_1$ — это…', opts:['Параллельны','Перпендикулярны','Пересекаются под $45°$'], correct:1, explain:'Смежные грани куба перпендикулярны: $AA_1 \\subset ABB_1A_1$ и $AA_1 \\perp ABCD$ — признак.' },
{ q:'Куб: плоскости $ABCD$ и $A_1B_1C_1D_1$ — это…', opts:['Параллельны','Перпендикулярны','Совпадают'], correct:0, explain:'Противоположные грани — параллельны.' },
{ q:'Сколько граней куба перпендикулярно одной заданной грани?', opts:['2','3','4','6'], correct:2, explain:'4 смежные грани перпендикулярны; 1 параллельна.' },
{ q:'Куб: плоскости $ABB_1A_1$ и $BCC_1B_1$ (две соседние боковые) — это…', opts:['Параллельны','Перпендикулярны','Пересекаются под $60°$'], correct:1, explain:'Соседние боковые грани куба перпендикулярны (общее ребро $BB_1$, линейный угол — между $BA$ и $BC$, равен $90°$).' },
{ q:'Куб: диагональная плоскость $ACC_1A_1$ и нижняя грань $ABCD$ — это…', opts:['Параллельны','Перпендикулярны','Под $45°$'], correct:1, explain:'$AA_1 \\subset ACC_1A_1$ и $AA_1 \\perp ABCD$ ⇒ $ACC_1A_1 \\perp ABCD$.' }
];
/* ========== Bosses ========== */
var BOSS_DEFS = {
7: {
title:'§7 — Перпендикулярность прямой и плоскости',
xp:70,
stages:[
{ q:'Достаточно ли $l$ перпендикулярна одной прямой плоскости, чтобы $l \\perp \\alpha$?', type:'mc', opts:['Да','Нет','Иногда'], correct:1, explain:'Нужны две ПЕРЕСЕКАЮЩИЕСЯ.' },
{ q:'$l \\perp m$, $l \\perp n$, $m \\cap n = O \\in \\alpha$. Вывод?', type:'mc', opts:['$l \\perp \\alpha$','$l \\parallel \\alpha$','Никакой'], correct:0, explain:'Признак перпендикулярности.' },
{ q:'Сколько прямых, перпендикулярных плоскости, можно провести через точку?', type:'input', a:'1', explain:'Единственная.' },
{ q:'Если $l_1 \\perp \\alpha$ и $l_2 \\perp \\alpha$, то $l_1$ и $l_2$…', type:'mc', opts:['$\\parallel$','$\\perp$','Скрещ.'], correct:0, explain:'Параллельны.' },
{ q:'Куб: ребро $CC_1$ перпендикулярно плоскости $ABCD$?', type:'mc', opts:['Да','Нет','Зависит от куба'], correct:0, explain:'Боковое ребро ⊥ основанию.' }
]
},
8: {
title:'§8 — Расстояния',
xp:70,
stages:[
{ q:'Куб с ребром $1$. Расстояние от $A_1$ до плоскости $ABCD$?', type:'input', a:'1', explain:'Длина $AA_1 = 1$.' },
{ q:'Куб с ребром $1$. Расстояние между $AA_1$ и $CC_1$? (форма ответа: число)', type:'input', a:['√2','sqrt(2)','sqrt2','1.41','1.414'], explain:'$AA_1 \\parallel CC_1$ (параллельные прямые); расстояние = диагональ $AC = \\sqrt{2}$.' },
{ q:'Перпендикуляр короче любой наклонной из той же точки?', type:'mc', opts:['Да','Нет','Иногда'], correct:0, explain:'Да — основное свойство.' },
{ q:'Куб с ребром $2$. Расстояние между параллельными гранями?', type:'input', a:'2', explain:'Расстояние = ребро = 2.' },
{ q:'Расстояние между скрещ. прямыми — это длина чего?', type:'mc', opts:['Любого отрезка','Общего перпендикуляра','Касательной','Биссектрисы'], correct:1, explain:'Общего перпендикуляра.' }
]
},
9: {
title:'§9 — Угол и ТТП',
xp:70,
stages:[
{ q:'Из точки $A$ к плоскости проведены $AH$ (перпендикуляр), $AB$ (наклонная). Что такое $HB$?', type:'mc', opts:['Перпендикуляр','Наклонная','Проекция'], correct:2, explain:'Проекция наклонной.' },
{ q:'Угол между наклонной и плоскостью — это угол между…', type:'mc', opts:['Наклонной и перпендикуляром','Наклонной и проекцией','Наклонной и любой прямой'], correct:1, explain:'Наклонная и её проекция.' },
{ q:'ТТП: $AH \\perp \\alpha, BC \\subset \\alpha, HB \\perp BC$. Вывод про $AB$ и $BC$?', type:'mc', opts:['$AB \\perp BC$','$AB \\parallel BC$','Ничего'], correct:0, explain:'$AB \\perp BC$ — прямая ТТП.' },
{ q:'Угол между диагональю куба $AC_1$ и плоскостью $ABCD$ ($\\tg \\varphi = 1/\\sqrt{2}$, $\\varphi \\approx ?°$, округли до целого)', type:'input', a:'35', explain:'$\\varphi \\approx 35{,}26°$.' },
{ q:'Чему равен угол между прямой $a \\subset \\alpha$ и плоскостью $\\alpha$?', type:'input', a:'0', explain:'$0°$ — прямая лежит в плоскости.' }
]
},
10: {
title:'§10 — Перпендикулярность плоскостей',
xp:75,
stages:[
{ q:'Двугранный угол — это…', type:'mc', opts:['Угол между плоскостями','2 полуплоскости с общим ребром','Угол между прямыми','Угол наклонной'], correct:1, explain:'2 полуплоскости + ребро.' },
{ q:'Линейный угол двугранного угла строится…', type:'mc', opts:['Произвольно','Перпендикулярами к ребру в каждой полуплоскости','Через высоту','Через диагональ'], correct:1, explain:'Перпендикуляры к ребру.' },
{ q:'Плоскость $\\alpha \\supset l \\perp \\beta$. Вывод?', type:'mc', opts:['$\\alpha \\parallel \\beta$','$\\alpha \\perp \\beta$','$\\alpha = \\beta$'], correct:1, explain:'Признак: $\\alpha \\perp \\beta$.' },
{ q:'Сколько граней куба перпендикулярно одной заданной грани?', type:'input', a:'4', explain:'4 смежные.' },
{ q:'Куб: плоскости $ABB_1A_1$ и $CDD_1C_1$ — это…', type:'mc', opts:['Параллельны','Перпендикулярны','Совпадают'], correct:0, explain:'Это противоположные боковые грани — параллельны.' },
{ q:'Линейный угол развёрнутого двугранного угла равен … градусов', type:'input', a:'180', explain:'$180°$ — развёрнутый угол.' }
]
}
};
var FINAL_BOSS_DEFS = {
f1: {
title:'Босс 1 · Прямая ⊥ плоскость',
xp:30,
stages:[
{ q:'Признак $l \\perp \\alpha$: $l$ перпендикулярна двум $?$ прямым в $\\alpha$.', type:'mc', opts:['Параллельным','Пересекающимся','Произвольным'], correct:1, explain:'Двум ПЕРЕСЕКАЮЩИМСЯ прямым.' },
{ q:'Через точку проходит сколько прямых, перпендикулярных данной плоскости?', type:'input', a:'1', explain:'Единственная.' },
{ q:'Если $l \\perp \\alpha$ и $a \\subset \\alpha$, то $l$ и $a$…', type:'mc', opts:['Параллельны','Перпендикулярны','Скрещиваются'], correct:1, explain:'$l$ перпендикулярна любой прямой плоскости.' },
{ q:'Куб: ребро $DD_1$ перпендикулярно плоскости $ABCD$?', type:'mc', opts:['Да','Нет','Зависит'], correct:0, explain:'Все боковые рёбра ⊥ основанию.' }
]
},
f2: {
title:'Босс 2 · Расстояния',
xp:30,
stages:[
{ q:'Куб с ребром $3$. Расстояние от $A$ до плоскости $A_1B_1C_1D_1$?', type:'input', a:'3', explain:'Длина $AA_1 = 3$.' },
{ q:'Куб с ребром $1$. Расстояние между скрещ. рёбрами $AB$ и $D_1C_1$?', type:'input', a:['√2','sqrt(2)','sqrt2','1.41','1.414'], explain:'Диагональ грани $\\sqrt{2}$.' },
{ q:'Расстояние между скрещ. прямыми реализуется на каком отрезке?', type:'mc', opts:['Любом','Общем перпендикуляре','Биссектрисе','Касательной'], correct:1, explain:'Общий перпендикуляр.' },
{ q:'Перпендикуляр из точки на плоскость … любой наклонной из той же точки.', type:'mc', opts:['Длиннее','Короче','Равен'], correct:1, explain:'Короче (кратчайший отрезок).' }
]
},
f3: {
title:'Босс 3 · Угол + ТТП',
xp:35,
stages:[
{ q:'Что такое проекция наклонной $AB$ на плоскость $\\alpha$ (где $AH \\perp \\alpha$, $H \\in \\alpha$)?', type:'mc', opts:['$AH$','$HB$','$AB$'], correct:1, explain:'Проекция — отрезок $HB$.' },
{ q:'Угол между прямой и плоскостью — это угол между прямой и…', type:'mc', opts:['Перпендикуляром','Проекцией','Любой прямой'], correct:1, explain:'Наклонная и её проекция.' },
{ q:'ТТП: $AH \\perp \\alpha, BC \\subset \\alpha, HB \\perp BC$. Что верно?', type:'mc', opts:['$AB \\perp BC$','$AB \\parallel BC$','Ничего'], correct:0, explain:'$AB \\perp BC$.' },
{ q:'Куб (ребро 1): $\\tg$ угла между диагональю $AC_1$ и плоскостью $ABCD$?', type:'input', a:['1/√2','1/sqrt(2)','√2/2','sqrt(2)/2','0.707'], explain:'$\\tg \\varphi = \\frac{1}{\\sqrt{2}}$.' }
]
},
f4: {
title:'Босс 4 · ⊥-плоскости',
xp:30,
stages:[
{ q:'Двугранный угол — это…', type:'mc', opts:['Угол наклонной','2 полуплоскости с общим ребром','Угол прямых'], correct:1, explain:'Полуплоскости + общее ребро.' },
{ q:'Признак $\\alpha \\perp \\beta$: $\\alpha$ содержит прямую, $?$ к $\\beta$.', type:'mc', opts:['Параллельную','Перпендикулярную','Произвольную'], correct:1, explain:'Перпендикулярную $\\beta$.' },
{ q:'Сколько граней куба перпендикулярно одной заданной грани?', type:'input', a:'4', explain:'4 смежные.' },
{ q:'Линейный угол двугранного угла зависит от выбора точки на ребре?', type:'mc', opts:['Да','Нет'], correct:1, explain:'Не зависит.' }
]
},
f5: {
title:'Босс 5 · Сборная',
xp:45,
stages:[
{ q:'Куб с ребром $1$. Расстояние от $A$ до $C_1$? (длина диагонали куба)', type:'input', a:['√3','sqrt(3)','sqrt3','1.73','1.732'], explain:'Диагональ куба $= a\\sqrt{3}$.' },
{ q:'Куб (ребро 1): $\\sin$ угла между $AC_1$ и плоскостью $ABCD$?', type:'input', a:['1/√3','1/sqrt(3)','√3/3','sqrt(3)/3','0.577'], explain:'$\\sin \\varphi = \\frac{AA_1}{AC_1} = \\frac{1}{\\sqrt{3}}$.' },
{ q:'Если $l_1 \\perp \\alpha$ и $l_2 \\perp \\alpha$, то $l_1$ и $l_2$ — …', type:'mc', opts:['$\\parallel$','$\\perp$','Скрещиваются'], correct:0, explain:'Параллельны.' },
{ q:'В пирамиде высота $SO \\perp$ основание. Применяем ТТП: $OB \\perp BC \\Rightarrow$ ?', type:'mc', opts:['$SB \\perp BC$','$SB \\parallel BC$','Ничего'], correct:0, explain:'По ТТП: $SB \\perp BC$.' },
{ q:'Куб: диагональная плоскость $BDD_1B_1$ и грань $ABCD$ — это…', type:'mc', opts:['Параллельны','Перпендикулярны','Под $45°$'], correct:1, explain:'$BB_1 \\subset BDD_1B_1$ и $BB_1 \\perp ABCD$ ⇒ перпендикулярны.' }
]
}
};
function renderFinalBoss(id){
var def = FINAL_BOSS_DEFS[id];
if (!def) return;
var el = document.getElementById('boss-' + id);
if (!el) return;
if (!STATE.bosses) STATE.bosses = {};
var st = STATE.bosses[id] || { stage:0, defeated:false };
STATE.bosses[id] = st;
if (st.defeated){
el.classList.add('victory');
el.innerHTML = '<div class="boss-defeated">'
+ '<div class="boss-defeated-title">' + def.title + ' побеждён!</div>'
+ '<span class="boss-defeated-xp">+' + def.xp + ' XP</span>'
+ '</div>';
checkFinalComplete();
return;
}
el.classList.remove('victory');
var total = def.stages.length;
var stage = def.stages[st.stage];
var hp = Math.round((1 - st.stage/total) * 100);
var optsHtml;
if (stage.type === 'mc'){
optsHtml = '<div class="boss-opts">';
for (var i = 0; i < stage.opts.length; i++){
optsHtml += '<button class="boss-opt" data-i="' + i + '">' + stage.opts[i] + '</button>';
}
optsHtml += '</div>';
} else {
optsHtml = '<div class="boss-input"><input type="text" id="boss-' + id + '-in" inputmode="text" placeholder="ответ"><button id="boss-' + id + '-go">Атака</button></div>';
}
el.innerHTML = '<div class="boss-h">'
+ '<span class="boss-badge">Финал</span>'
+ '<span class="boss-title">' + def.title + '</span>'
+ '</div>'
+ '<div class="boss-hp"><div class="boss-hp-label"><span>HP босса</span><span>' + hp + '%</span></div>'
+ '<div class="boss-hp-bar"><div class="boss-hp-fill" style="width:' + hp + '%"></div></div></div>'
+ '<div class="boss-question">'
+ '<div class="boss-stage-label">Этап ' + (st.stage+1) + ' / ' + total + '</div>'
+ '<div class="boss-q">' + stage.q + '</div>'
+ optsHtml + '</div>';
function normalizeAns(s){
return String(s||'').toLowerCase()
.replace(/\s+/g,'')
.replace(/°/g,'')
.replace(/sqrt/g,'√')
.replace(/корень/g,'√')
.replace(/,/g,'.');
}
if (stage.type === 'mc'){
el.querySelectorAll('.boss-opt').forEach(function(btn){
btn.addEventListener('click', function(){
var i = parseInt(btn.getAttribute('data-i'), 10);
var ok = (i === stage.correct);
if (ok){
btn.classList.add('correct');
setTimeout(function(){ advanceFinalBoss(id); }, 600);
} else {
btn.classList.add('wrong');
setTimeout(function(){ btn.classList.remove('wrong'); }, 600);
}
});
});
} else {
var inEl = document.getElementById('boss-' + id + '-in');
var goEl = document.getElementById('boss-' + id + '-go');
var box = inEl.parentNode;
function attack(){
var v = normalizeAns(inEl.value);
var answers = Array.isArray(stage.a) ? stage.a.map(normalizeAns) : [normalizeAns(stage.a)];
if (answers.indexOf(v) >= 0){
inEl.style.background = 'rgba(34,197,94,.25)';
setTimeout(function(){ advanceFinalBoss(id); }, 500);
} else {
box.classList.add('wrong');
inEl.style.background = 'rgba(220,38,38,.25)';
setTimeout(function(){ box.classList.remove('wrong'); inEl.style.background=''; }, 600);
}
}
goEl.addEventListener('click', attack);
inEl.addEventListener('keydown', function(e){ if (e.key === 'Enter') attack(); });
}
tryKatex(el);
}
function advanceFinalBoss(id){
var st = STATE.bosses[id];
var def = FINAL_BOSS_DEFS[id];
st.stage++;
if (st.stage >= def.stages.length){
st.defeated = true;
saveState();
addXp(def.xp, def.title);
} else {
saveState();
}
renderFinalBoss(id);
}
function checkFinalComplete(){
var allBeat = ['f1','f2','f3','f4','f5'].every(function(k){
return STATE.bosses[k] && STATE.bosses[k].defeated;
});
if (!allBeat) return;
var cel = document.getElementById('celebration');
if (!cel) return;
if (cel.dataset.shown === '1') return;
cel.dataset.shown = '1';
cel.style.display = 'block';
cel.innerHTML = '<div class="boss victory" style="text-align:center;padding:40px 24px">'
+ '<div style="font-family:Unbounded,sans-serif;font-size:1.8rem;font-weight:900;color:#fef3c7;letter-spacing:-.01em;margin-bottom:8px">★ Раздел 3 пройден! ★</div>'
+ '<div style="font-size:1rem;color:#dcfce7;margin-bottom:16px">Все 5 финальных боссов побеждены. Перпендикулярность — освоена.</div>'
+ '<span class="boss-defeated-xp" style="font-size:1rem;padding:10px 22px">+ 130 XP бонус + ачивка «stereo10_r3_master»</span>'
+ '</div>';
var achKey = 'geometry10_achievements';
var raw = localStorage.getItem(achKey);
var list = [];
try { list = raw ? JSON.parse(raw) : []; } catch(e){}
if (list.indexOf('stereo10_r3_master') < 0){
list.push('stereo10_r3_master');
localStorage.setItem(achKey, JSON.stringify(list));
addXp(130, 'ачивка: Перпендикулярность освоена');
}
}
function renderBoss(num){
var def = BOSS_DEFS[num];
if (!def) return;
var el = document.getElementById('boss-' + num);
if (!el) return;
var st = STATE.bosses[num] || { stage:0, defeated:false };
STATE.bosses[num] = st;
if (st.defeated){
el.classList.add('victory');
el.innerHTML = '<div class="boss-defeated">'
+ '<div class="boss-defeated-title">Босс §' + num + ' побеждён!</div>'
+ '<div class="boss-defeated-sub">' + def.title + '</div>'
+ '<span class="boss-defeated-xp">+' + def.xp + ' XP</span>'
+ '</div>';
return;
}
el.classList.remove('victory');
var total = def.stages.length;
var stage = def.stages[st.stage];
var hp = Math.round((1 - st.stage/total) * 100);
var optsHtml;
if (stage.type === 'mc'){
optsHtml = '<div class="boss-opts">';
for (var i = 0; i < stage.opts.length; i++){
optsHtml += '<button class="boss-opt" data-i="' + i + '">' + stage.opts[i] + '</button>';
}
optsHtml += '</div>';
} else {
optsHtml = '<div class="boss-input"><input type="text" id="boss-' + num + '-in" inputmode="text" placeholder="ответ"><button id="boss-' + num + '-go">Атака</button></div>';
}
el.innerHTML = '<div class="boss-h">'
+ '<span class="boss-badge">Босс</span>'
+ '<span class="boss-title">' + def.title + '</span>'
+ '</div>'
+ '<div class="boss-hp"><div class="boss-hp-label"><span>HP босса</span><span>' + hp + '%</span></div>'
+ '<div class="boss-hp-bar"><div class="boss-hp-fill" style="width:' + hp + '%"></div></div></div>'
+ '<div class="boss-question">'
+ '<div class="boss-stage-label">Этап ' + (st.stage+1) + ' / ' + total + '</div>'
+ '<div class="boss-q">' + stage.q + '</div>'
+ optsHtml + '</div>';
function normalizeAns(s){
return String(s||'').toLowerCase()
.replace(/\s+/g,'')
.replace(/°/g,'')
.replace(/sqrt/g,'√')
.replace(/корень/g,'√')
.replace(/,/g,'.');
}
if (stage.type === 'mc'){
el.querySelectorAll('.boss-opt').forEach(function(btn){
btn.addEventListener('click', function(){
var i = parseInt(btn.getAttribute('data-i'), 10);
var ok = (i === stage.correct);
if (ok){
btn.classList.add('correct');
setTimeout(function(){ advanceBoss(num); }, 600);
} else {
btn.classList.add('wrong');
setTimeout(function(){ btn.classList.remove('wrong'); }, 600);
}
});
});
} else {
var inEl = document.getElementById('boss-' + num + '-in');
var goEl = document.getElementById('boss-' + num + '-go');
var box = inEl.parentNode;
function attack(){
var v = normalizeAns(inEl.value);
var answers = Array.isArray(stage.a) ? stage.a.map(normalizeAns) : [normalizeAns(stage.a)];
if (answers.indexOf(v) >= 0){
box.classList.remove('wrong');
inEl.style.background = 'rgba(34,197,94,.25)';
setTimeout(function(){ advanceBoss(num); }, 500);
} else {
box.classList.add('wrong');
inEl.style.background = 'rgba(220,38,38,.25)';
setTimeout(function(){ box.classList.remove('wrong'); inEl.style.background=''; }, 600);
}
}
goEl.addEventListener('click', attack);
inEl.addEventListener('keydown', function(e){ if (e.key === 'Enter') attack(); });
}
tryKatex(el);
}
function advanceBoss(num){
var st = STATE.bosses[num];
var def = BOSS_DEFS[num];
st.stage++;
if (st.stage >= def.stages.length){
st.defeated = true;
saveState();
addXp(def.xp, 'босс §' + num);
} else {
saveState();
}
renderBoss(num);
}
function tryKatex(scope){
if (!window.renderMathInElement) return;
try {
window.renderMathInElement(scope || document.body, {
delimiters: [
{left:'$$', right:'$$', display:true},
{left:'$', right:'$', display:false},
{left:'\\(', right:'\\)', display:false},
{left:'\\[', right:'\\]', display:true}
],
throwOnError: false
});
} catch(e){}
}
function start(){
buildPerpDef();
buildPerpSign();
buildDistanceCases();
buildDistanceDetail();
buildAngleViz();
buildTTPViz();
buildDihedralViz();
buildPlanePerpSign();
runQuizMC({ id:'i7-perp', items:i7PerpItems, xpPerAll:14, title:'перпендикулярность' });
runQuizMC({ id:'i7-sign', items:i7SignItems, xpPerAll:12, title:'признак' });
runQuizMC({ id:'i7-cube', items:i7CubeItems, xpPerAll:12, title:'⊥ в кубе' });
runQuizInput({ id:'i8-cube', items:i8CubeItems, xpPerAll:18, title:'расстояния в кубе' });
runQuizMC({ id:'i8-type', items:i8TypeItems, xpPerAll:12, title:'тип расстояния' });
runQuizMC({ id:'i8-true', items:i8TrueItems, xpPerAll:10, title:'верно/неверно' });
runQuizMC({ id:'i9-elem', items:i9ElemItems, xpPerAll:12, title:'элементы наклонной' });
runQuizInput({ id:'i9-cube', items:i9CubeItems, xpPerAll:16, title:'углы в кубе' });
runQuizMC({ id:'i9-ttp', items:i9TtpItems, xpPerAll:12, title:'ТТП' });
runQuizMC({ id:'i10-dihedral', items:i10DihedralItems, xpPerAll:12, title:'двугранный угол' });
runQuizMC({ id:'i10-sign', items:i10SignItems, xpPerAll:12, title:'признак ⊥ плоскостей' });
runQuizMC({ id:'i10-cube', items:i10CubeItems, xpPerAll:12, title:'⊥ грани куба' });
renderBoss(7);
renderBoss(8);
renderBoss(9);
renderBoss(10);
renderFinalBoss('f1');
renderFinalBoss('f2');
renderFinalBoss('f3');
renderFinalBoss('f4');
renderFinalBoss('f5');
checkFinalComplete();
document.getElementById('mark-7').addEventListener('click', function(){ markRead(7); });
document.getElementById('mark-8').addEventListener('click', function(){ markRead(8); });
document.getElementById('mark-9').addEventListener('click', function(){ markRead(9); });
document.getElementById('mark-10').addEventListener('click', function(){ markRead(10); });
refreshMarkBtn(7); refreshMarkBtn(8); refreshMarkBtn(9); refreshMarkBtn(10);
refreshTabs();
var tabs = document.querySelectorAll('.sec-tab[data-tab]');
var sections = ['para-7','para-8','para-9','para-10','para-final'];
function onScroll(){
var y = window.scrollY + 100;
var active = 0;
for (var i = 0; i < sections.length; i++){
var el = document.getElementById(sections[i]);
if (!el) continue;
if (el.offsetTop <= y) active = i;
}
tabs.forEach(function(t,j){ if (j === active) t.classList.add('active'); else t.classList.remove('active'); });
}
window.addEventListener('scroll', onScroll, {passive:true});
setTimeout(function(){ tryKatex(document.body); }, 50);
}
if (document.readyState === 'loading'){
document.addEventListener('DOMContentLoaded', start);
} else {
start();
}
</script>
</body>
</html>