Files
Maxim Dolgolyov e4050fcaed feat(phys7): Phase 8 — финал курса. Панель 7 ачивок + confetti + завершение плана
ХАБ physics_7_hub.html:
- Подключён canvas-confetti с CDN (jsdelivr 1.6.0)
- Заменена старая ach-strip с одной ачивкой на полную панель .ach-section
  с сеткой из 7 карточек: 5 ачивок глав + лаб + master
- Master-карточка выделена (grid-column: 1/-1, фиолетовый градиент при .lit)
- Каждая карточка: иконка (★ при .lit, ? до получения), название, описание условия
- Счётчик «N / 7 ачивок получено»
- renderAchievements() читает все 7 ключей из localStorage и подсвечивает
  получённые, обновляется при focus
- При первом получении «Магистр физики 7» — confetti-залп в 3 волны (через
  sessionStorage флаг, чтобы не запускать повторно при ре-открытии хаба)
- Текст финального аккордеона: «...по всем 5 главам» вместо «3»

ПЛАН plans/textbooks-7/PLAN_PHYSICS_7.md:
- Заголовок отмечен как « ЗАВЕРШЁН» (Phase 0..8)
- Добавлена итоговая сводка реализации:
  * Таблица 9 фаз с файлами, строками и коммитами
  * Список 6 главных визуалов с указанием §
  * Таблица 7 ачивок (slug / название / условие / XP)
  * Оценка XP за полное прохождение (~3 550)
  * Список фактически использованных хелперов phys.js
  * Список уроков, учтённых с первого коммита (cache-busting, sidebar-фикс,
    delimiters, скобки в KaTeX, self-sufficient миграция, без эмоджи)

Итог: 5-й физический курс в проекте, первый учебник 7 класса по физике.
8 фаз × несколько волн каждая = ~14 100 строк кода. Все интерактивы работают.
parse-check, smoke-test и pre-commit хуки пройдены на каждом этапе.
2026-05-30 12:01:50 +03:00

1018 lines
53 KiB
HTML
Raw Permalink 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">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Физика 7 класс — учебник</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&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<link rel="stylesheet" href="/css/phys8-interactives.css">
<link rel="stylesheet" href="/css/phys8-design-system.css">
<link rel="stylesheet" href="/css/phys-textbook-widgets.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 defer src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/phys8-helpers.js" defer></script>
<script src="/js/phys8-drag.js" defer></script>
<script src="/js/phys8-anim.js" defer></script>
<style>
:root{
--bg:#f0f9ff; --card:#fff;
--text:#0f172a; --muted:#475569;
--border:#bae6fd;
--pri:#0284c7; --pri-d:#0c4a6e;
--pri-soft:#e0f2fe;
--ch1:#4f46e5; --ch1-d:#3730a3;
--ch2:#7c3aed; --ch2-d:#5b21b6;
--ch3:#dc2626; --ch3-d:#991b1b;
--ch4:#d97706; --ch4-d:#92400e;
--ch5:#10b981; --ch5-d:#047857;
--ch6:#0891b2; --ch6-d:#0e7490;
--sh:0 4px 16px rgba(2,132,199,.10);
--sh-h:0 12px 36px rgba(2,132,199,.18);
}
html.dark{
--bg:#0c1e2e; --card:#0e2436;
--text:#e0f2fe; --muted:#7dd3fc;
--border:#1e3a5f;
--pri-soft:rgba(2,132,199,.18);
}
*{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.55;transition:background .25s,color .25s}
/* HEADER */
.hdr{position:relative;background:linear-gradient(110deg,#0c4a6e 0%,#0284c7 55%,#bae6fd 100%);color:#fff;padding:32px 24px 28px;overflow:hidden;border-bottom:2px solid rgba(237,233,254,.18)}
.hdr::before{content:'ФИЗИКА';position:absolute;right:-14px;top:-18%;font-family:'Outfit',sans-serif;font-size:clamp(5rem,16vw,13rem);font-weight:900;letter-spacing:-.04em;color:transparent;-webkit-text-stroke:1.5px rgba(237,233,254,.14);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.85rem;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}
.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)}
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
main{max-width:1100px;margin:0 auto;padding:32px 24px 60px}
/* OVERALL PROGRESS */
.prog-overall{background:linear-gradient(135deg,var(--pri-soft),rgba(186,230,253,.18));border:1px solid var(--border);border-radius:14px;padding:14px 18px;margin-bottom:28px;display:flex;gap:14px;align-items:center;flex-wrap:wrap}
.po-icon{width:46px;height:46px;border-radius:12px;background:linear-gradient(135deg,#0284c7,#bae6fd);color:#fff;display:flex;align-items:center;justify-content:center;flex-shrink:0;font-family:'Outfit',sans-serif;font-size:1.4rem;font-weight:900;font-style:italic}
.po-text{flex:1;min-width:160px}
.po-label{font-size:.78rem;font-weight:700;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-bottom:4px}
.po-bar{height:8px;background:rgba(2,132,199,.14);border-radius:5px;overflow:hidden;margin-top:6px}
.po-fill{height:100%;background:linear-gradient(90deg,var(--pri),#bae6fd);border-radius:5px;transition:width .5s}
.po-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;background:linear-gradient(135deg,#7dd3fc,var(--pri));color:#fff;border-radius:99px;font-size:.8rem;font-weight:800;font-family:'Unbounded',sans-serif;letter-spacing:.02em;box-shadow:0 4px 12px rgba(2,132,199,.24)}
/* CHAPTER GRID — 4 sections: 3 chapters + lab */
.ch-grid{display:grid;grid-template-columns:1fr;gap:18px;margin-bottom:30px}
@media(min-width:680px){.ch-grid{grid-template-columns:1fr 1fr}}
.ch-card{background:var(--card);border:1.5px solid var(--border);border-radius:18px;overflow:hidden;display:flex;flex-direction:column;transition:transform .2s,box-shadow .2s,border-color .2s;cursor:pointer;text-decoration:none;color:inherit}
.ch-card:hover{transform:translateY(-4px);box-shadow:var(--sh-h)}
.ch-cover{padding:22px 22px 18px;color:#fff;position:relative;overflow:hidden}
.ch-cover-wm{position:absolute;right:-8px;top:-22px;font-size:5.2rem;font-weight:900;font-family:'Outfit',sans-serif;line-height:1;color:rgba(255,255,255,.20);pointer-events:none;letter-spacing:-.04em}
.ch-num{display:inline-block;padding:4px 10px;background:rgba(255,255,255,.22);border-radius:99px;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;margin-bottom:8px;position:relative;z-index:1}
.ch-title{font-family:'Outfit',sans-serif;font-size:1.1rem;font-weight:800;letter-spacing:-.01em;position:relative;z-index:1;line-height:1.3}
.ch-range{font-size:.84rem;opacity:.88;margin-top:4px;position:relative;z-index:1;font-weight:500}
.ch-cover.ch1{background:linear-gradient(135deg,#312e81,#4f46e5 60%,#a5b4fc)}
.ch-cover.ch2{background:linear-gradient(135deg,#4c1d95,#7c3aed 60%,#c4b5fd)}
.ch-cover.ch3{background:linear-gradient(135deg,#7f1d1d,#dc2626 60%,#f87171)}
.ch-cover.ch4{background:linear-gradient(135deg,#78350f,#d97706 60%,#fbbf24)}
.ch-cover.ch5{background:linear-gradient(135deg,#064e3b,#10b981 60%,#6ee7b7)}
.ch-cover.ch6{background:linear-gradient(135deg,#164e63,#0891b2 60%,#22d3ee)}
.ch-body{padding:16px 20px 18px;display:flex;flex-direction:column;flex:1}
.ch-desc{font-size:.88rem;color:var(--text);opacity:.84;flex:1;margin-bottom:12px;line-height:1.55}
.ch-prog{margin-bottom:12px}
.ch-prog-label{display:flex;justify-content:space-between;font-size:.74rem;color:var(--muted);font-weight:600;margin-bottom:4px}
.ch-prog-bar{height:6px;background:rgba(0,0,0,.07);border-radius:4px;overflow:hidden}
.ch-prog-fill{height:100%;border-radius:4px;transition:width .5s}
.ch-card.ch1-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch1),var(--ch1-d))}
.ch-card.ch2-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch2),var(--ch2-d))}
.ch-card.ch3-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch3),var(--ch3-d))}
.ch-card.ch4-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch4),var(--ch4-d))}
.ch-card.ch5-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch5),var(--ch5-d))}
.ch-card.ch6-card .ch-prog-fill{background:linear-gradient(90deg,var(--ch6),var(--ch6-d))}
.ch-action{display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:11px;font-weight:700;font-size:.9rem;color:#fff;transition:filter .15s}
.ch-action:hover{filter:brightness(1.08)}
.ch-card.ch1-card .ch-action{background:linear-gradient(135deg,var(--ch1),#a5b4fc)}
.ch-card.ch2-card .ch-action{background:linear-gradient(135deg,var(--ch2),#c4b5fd)}
.ch-card.ch3-card .ch-action{background:linear-gradient(135deg,var(--ch3),#f87171)}
.ch-card.ch4-card .ch-action{background:linear-gradient(135deg,var(--ch4),#fbbf24)}
.ch-card.ch5-card .ch-action{background:linear-gradient(135deg,var(--ch5),#6ee7b7)}
.ch-card.ch6-card .ch-action{background:linear-gradient(135deg,var(--ch6),#22d3ee)}
/* ACHIEVEMENT STRIP */
/* ACHIEVEMENTS PANEL — 7 cards */
.ach-section{background:var(--card);border:1.5px solid var(--border);border-radius:16px;padding:18px 22px;margin-bottom:28px;box-shadow:var(--sh)}
.ach-section-title{font-family:'Outfit',sans-serif;font-size:1.18rem;font-weight:800;color:var(--text);margin-bottom:4px}
.ach-section-sub{font-size:.86rem;color:var(--muted);margin-bottom:14px}
.ach-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(170px,1fr));gap:10px}
.ach-card{background:var(--card-soft,#f8fafc);border:1.5px solid var(--border);border-radius:12px;padding:12px 14px;display:flex;align-items:center;gap:10px;transition:all .25s;position:relative;opacity:.55}
.ach-card.lit{opacity:1;background:linear-gradient(135deg,#fef3c7,#fde68a);border-color:#f59e0b;box-shadow:0 4px 14px rgba(245,158,11,.22)}
.ach-card.master{grid-column:1/-1;background:linear-gradient(135deg,var(--pri-soft),#e0e7ff);border-color:var(--pri)}
.ach-card.master.lit{background:linear-gradient(135deg,#a78bfa,#7c3aed);border-color:#5b21b6;color:#fff;box-shadow:0 8px 28px rgba(124,58,237,.35)}
.ach-card::before{content:'?';width:36px;height:36px;border-radius:10px;background:rgba(0,0,0,.07);color:var(--muted);font-family:'Unbounded',sans-serif;font-weight:900;font-size:1.1rem;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.ach-card.lit::before{content:'\\2605';background:linear-gradient(135deg,#f59e0b,#d97706);color:#fff;text-shadow:0 1px 2px rgba(0,0,0,.2)}
.ach-card.master.lit::before{background:rgba(255,255,255,.25);color:#fff}
.ach-card-text{flex:1;min-width:0}
.ach-card-label{font-weight:800;font-size:.92rem;color:var(--text);line-height:1.2}
.ach-card.master.lit .ach-card-label{color:#fff}
.ach-card-sub{font-size:.74rem;color:var(--muted);margin-top:2px;line-height:1.4}
.ach-card.master.lit .ach-card-sub{color:rgba(255,255,255,.85)}
.ach-strip{background:var(--card);border:1.5px solid var(--border);border-radius:16px;padding:18px 22px;margin-bottom:28px;display:flex;align-items:center;gap:16px;transition:border-color .4s,box-shadow .4s}
.ach-strip.lit{border-color:#0ea5e9;box-shadow:0 0 0 3px rgba(14,165,233,.22)}
.ach-icon{width:52px;height:52px;border-radius:14px;background:rgba(0,0,0,.06);display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .4s}
.ach-strip.lit .ach-icon{background:linear-gradient(135deg,#7dd3fc,#0284c7)}
.ach-icon svg{width:28px;height:28px;stroke:var(--muted);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.ach-strip.lit .ach-icon svg{stroke:#fff}
.ach-text{flex:1}
.ach-title{font-weight:800;font-size:1.02rem;color:var(--text)}
.ach-sub{font-size:.85rem;color:var(--muted);margin-top:2px}
.ach-strip.lit .ach-title{color:#0c4a6e}
.foot{text-align:center;padding:24px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border)}
/* COURSE FINAL */
.final-wrap{margin:0 0 28px;background:var(--card);border:1.5px solid var(--border);border-radius:18px;overflow:hidden;box-shadow:var(--sh)}
.final-head{padding:18px 22px;background:linear-gradient(135deg,#0c4a6e 0%,#0284c7 55%,#7dd3fc 100%);color:#fff;cursor:pointer;display:flex;align-items:center;gap:14px;user-select:none;transition:filter .15s}
.final-head:hover{filter:brightness(1.06)}
.final-head-icon{width:46px;height:46px;border-radius:12px;background:rgba(255,255,255,.18);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.final-head-icon svg{width:26px;height:26px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.final-head-text{flex:1;min-width:0}
.final-head-tag{display:inline-block;padding:3px 9px;background:rgba(255,255,255,.22);border-radius:99px;font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.08em;margin-bottom:4px}
.final-head-title{font-family:'Outfit',sans-serif;font-size:1.18rem;font-weight:800;letter-spacing:-.01em;line-height:1.25}
.final-head-sub{font-size:.84rem;opacity:.9;margin-top:2px}
.final-chevron{flex-shrink:0;transition:transform .25s}
.final-chevron svg{width:24px;height:24px;stroke:#fff;fill:none;stroke-width:2.4;stroke-linecap:round;stroke-linejoin:round}
.final-wrap.open .final-chevron{transform:rotate(180deg)}
.final-body{display:none;padding:22px}
.final-wrap.open .final-body{display:block}
.fin-section-title{font-family:'Outfit',sans-serif;font-size:1.18rem;font-weight:800;color:var(--text);margin:8px 0 14px;letter-spacing:-.005em;display:flex;align-items:center;gap:9px}
.fin-section-title svg{width:20px;height:20px;stroke:var(--pri);fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
/* CHEAT SHEET */
.cheat-grid{display:grid;grid-template-columns:1fr;gap:14px;margin-bottom:28px}
@media(min-width:680px){.cheat-grid{grid-template-columns:1fr 1fr}}
@media(min-width:1000px){.cheat-grid{grid-template-columns:repeat(3,1fr)}}
.cheat-card{border:1.5px solid var(--border);border-radius:13px;padding:14px 16px;background:var(--card);position:relative;overflow:hidden}
.cheat-card::before{content:'';position:absolute;left:0;top:0;bottom:0;width:4px}
.cheat-card.c1::before{background:linear-gradient(180deg,var(--ch1),var(--ch1-d))}
.cheat-card.c2::before{background:linear-gradient(180deg,var(--ch2),var(--ch2-d))}
.cheat-card.c3::before{background:linear-gradient(180deg,var(--ch3),var(--ch3-d))}
.cheat-card.c4::before{background:linear-gradient(180deg,var(--ch4),var(--ch4-d))}
.cheat-card.c5::before{background:linear-gradient(180deg,var(--ch5),var(--ch5-d))}
.cheat-head{display:flex;align-items:center;gap:9px;margin-bottom:9px;padding-left:6px}
.cheat-badge{font-size:.7rem;font-weight:800;padding:2px 8px;border-radius:99px;color:#fff;letter-spacing:.05em;text-transform:uppercase}
.cheat-card.c1 .cheat-badge{background:var(--ch1)}
.cheat-card.c2 .cheat-badge{background:var(--ch2)}
.cheat-card.c3 .cheat-badge{background:var(--ch3)}
.cheat-card.c4 .cheat-badge{background:var(--ch4)}
.cheat-card.c5 .cheat-badge{background:var(--ch5)}
.cheat-title{font-weight:800;color:var(--text);font-size:.98rem}
.cheat-list{list-style:none;padding-left:6px;margin:0}
.cheat-list li{padding:6px 0;border-bottom:1px dashed var(--border);font-size:.92rem;line-height:1.5;color:var(--text)}
.cheat-list li:last-child{border-bottom:0}
/* BOSS PROGRESS */
.boss-overall-bar{background:linear-gradient(135deg,rgba(2,132,199,.08),rgba(186,230,253,.10));border:1px solid var(--border);border-radius:12px;padding:13px 16px;margin:6px 0 18px;display:flex;gap:14px;align-items:center;flex-wrap:wrap}
.boss-overall-bar .lab{font-weight:700;font-size:.95rem;color:var(--text);min-width:200px}
.boss-overall-bar .bar{flex:1;min-width:160px;height:9px;background:rgba(2,132,199,.14);border-radius:5px;overflow:hidden}
.boss-overall-bar .fill{height:100%;background:linear-gradient(90deg,var(--pri),#bae6fd,#7dd3fc);transition:width .5s;border-radius:5px}
/* BOSS CARDS */
.boss-card{background:var(--card);border:2px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;transition:border-color .35s,box-shadow .35s,transform .2s}
.boss-card.solved{border-color:#10b981;box-shadow:0 0 0 3px rgba(16,185,129,.18)}
.boss-head{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap}
.boss-tag{font-size:.7rem;font-weight:800;padding:3px 9px;border-radius:99px;background:rgba(2,132,199,.14);color:var(--pri-d);letter-spacing:.04em;text-transform:uppercase}
html.dark .boss-tag{color:#bae6fd}
.boss-title{font-family:'Outfit',sans-serif;font-weight:800;color:var(--text);font-size:1.02rem;flex:1;min-width:0}
.boss-q{padding:12px 14px;background:rgba(2,132,199,.06);border-radius:10px;font-size:.96rem;line-height:1.55;margin-bottom:10px;color:var(--text)}
.boss-row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-bottom:6px}
.boss-input{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);font-family:'JetBrains Mono',monospace;width:130px;text-align:center;font-size:.95rem;transition:border-color .15s}
.boss-input:focus{outline:0;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-soft)}
.boss-btn{padding:8px 16px;border-radius:9px;background:var(--card);color:var(--text);border:1.5px solid var(--border);font-weight:700;font-size:.88rem;cursor:pointer;font-family:inherit;transition:background .15s,border-color .15s,transform .1s}
.boss-btn:hover{background:var(--pri-soft);border-color:var(--pri)}
.boss-btn:active{transform:scale(.96)}
.boss-btn.primary{background:linear-gradient(135deg,var(--pri),#7dd3fc);color:#fff;border-color:transparent}
.boss-btn.primary:hover{filter:brightness(1.08)}
.boss-fb{padding:10px 14px;border-radius:9px;font-weight:600;font-size:.88rem;margin-top:8px;display:none;line-height:1.45}
.boss-fb.ok{display:block;background:#d1fae5;color:#065f46;border-left:4px solid #10b981}
.boss-fb.fail{display:block;background:#fee2e2;color:#7f1d1d;border-left:4px solid #dc2626}
html.dark .boss-fb.ok{background:rgba(16,185,129,.18);color:#a7f3d0}
html.dark .boss-fb.fail{background:rgba(220,38,38,.18);color:#fecaca}
.boss-hint-txt{margin-top:8px;padding:9px 13px;background:rgba(245,158,11,.12);border-left:3px solid #f59e0b;border-radius:6px;font-size:.86rem;color:var(--text);display:none;line-height:1.5}
.boss-hint-txt.show{display:block}
/* FINAL CTA */
.final-cta{margin-top:24px;padding:18px 20px;border-radius:14px;background:linear-gradient(135deg,#e0f2fe,#bae6fd);border:1.5px solid #7dd3fc;display:none;align-items:center;gap:14px;flex-wrap:wrap}
.final-cta.show{display:flex}
html.dark .final-cta{background:linear-gradient(135deg,rgba(2,132,199,.22),rgba(91,33,182,.18));border-color:#0284c7}
.final-cta-icon{width:48px;height:48px;border-radius:12px;background:linear-gradient(135deg,#7dd3fc,#0284c7);display:flex;align-items:center;justify-content:center;flex-shrink:0}
.final-cta-icon svg{width:28px;height:28px;stroke:#fff;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.final-cta-txt{flex:1;min-width:180px}
.final-cta-title{font-weight:800;color:#0c4a6e;font-size:1.05rem;font-family:'Outfit',sans-serif}
html.dark .final-cta-title{color:#bae6fd}
.final-cta-sub{font-size:.86rem;color:#0369a1;margin-top:2px}
html.dark .final-cta-sub{color:#bae6fd}
.final-cta-btn{padding:10px 18px;border-radius:10px;background:linear-gradient(135deg,var(--pri),#7dd3fc);color:#fff;text-decoration:none;font-weight:800;font-size:.9rem;display:inline-flex;align-items:center;gap:7px;transition:filter .15s}
.final-cta-btn:hover{filter:brightness(1.1)}
.final-cta-btn svg{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-inner">
<div>
<a href="/textbooks" class="hdr-back">
<svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg>
К каталогу
</a>
</div>
<div>
<h1>Физика &mdash; 7 класс</h1>
<div class="hdr-sub">Первый курс физики: методы познания природы, строение вещества, движение и силы, давление, работа и энергия, лабораторный практикум</div>
</div>
<div class="hdr-side">
<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>
<section class="prog-overall">
<div class="po-icon">f</div>
<div class="po-text">
<div class="po-label">Общий прогресс по курсу</div>
<div id="overall-text" style="font-size:1.05rem;font-weight:700">Загрузка...</div>
<div class="po-bar"><div id="overall-fill" class="po-fill" style="width:0%"></div></div>
</div>
<div id="hero-xp-badge" class="po-xp" style="display:none" data-gamified>0 XP</div>
</section>
<div class="ch-grid">
<a href="/textbook/physics-7-ch1" class="ch-card ch1-card" id="ch-1">
<div class="ch-cover ch1">
<div class="ch-cover-wm">&Sigma;</div>
<div class="ch-num">Глава 1</div>
<div class="ch-title">Методы познания природы</div>
<div class="ch-range">&sect;1&ndash;&sect;7 + Финал</div>
</div>
<div class="ch-body">
<div class="ch-desc">Физика как наука. Тело, явление, величина. Методы исследования. Прямые и косвенные измерения. СИ. Цена деления. Погрешность.</div>
<div class="ch-prog">
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-1">0%</span></div>
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-1" style="width:0%"></div></div>
</div>
<div class="ch-action">
<span id="btn-1">Открыть главу</span>
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</div>
</a>
<a href="/textbook/physics-7-ch2" class="ch-card ch2-card" id="ch-2">
<div class="ch-cover ch2">
<div class="ch-cover-wm">&deg;</div>
<div class="ch-num">Глава 2</div>
<div class="ch-title">Строение вещества</div>
<div class="ch-range">&sect;8&ndash;&sect;13 + Финал</div>
</div>
<div class="ch-body">
<div class="ch-desc">Дискретное строение. Тепловое движение. Взаимодействие частиц. Три состояния вещества. Тепловое расширение. Температура и термометры.</div>
<div class="ch-prog">
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-2">0%</span></div>
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-2" style="width:0%"></div></div>
</div>
<div class="ch-action">
<span id="btn-2">Открыть главу</span>
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</div>
</a>
<a href="/textbook/physics-7-ch3" class="ch-card ch3-card" id="ch-3">
<div class="ch-cover ch3">
<div class="ch-cover-wm">F</div>
<div class="ch-num">Глава 3</div>
<div class="ch-title">Движение и силы</div>
<div class="ch-range">&sect;14&ndash;&sect;27 + Финал</div>
</div>
<div class="ch-body">
<div class="ch-desc">Механическое движение. Равномерное и неравномерное движение. Скорость. Масса. Плотность. Силы тяжести, упругости, трения. Динамометр. Равнодействующая.</div>
<div class="ch-prog">
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-3">0%</span></div>
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-3" style="width:0%"></div></div>
</div>
<div class="ch-action">
<span id="btn-3">Открыть главу</span>
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</div>
</a>
<a href="/textbook/physics-7-ch4" class="ch-card ch4-card" id="ch-4">
<div class="ch-cover ch4">
<div class="ch-cover-wm">P</div>
<div class="ch-num">Глава 4</div>
<div class="ch-title">Давление</div>
<div class="ch-range">&sect;28&ndash;&sect;35 + Финал</div>
</div>
<div class="ch-body">
<div class="ch-desc">Давление твёрдых тел, газов, жидкостей. Закон Паскаля. Гидравлический пресс. Гидростатика. Сообщающиеся сосуды. Атмосферное давление. Барометры и манометры.</div>
<div class="ch-prog">
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-4">0%</span></div>
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-4" style="width:0%"></div></div>
</div>
<div class="ch-action">
<span id="btn-4">Открыть главу</span>
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</div>
</a>
<a href="/textbook/physics-7-ch5" class="ch-card ch5-card" id="ch-5">
<div class="ch-cover ch5">
<div class="ch-cover-wm">E</div>
<div class="ch-num">Глава 5</div>
<div class="ch-title">Работа. Мощность. Энергия</div>
<div class="ch-range">&sect;36&ndash;&sect;42 + Финал</div>
</div>
<div class="ch-body">
<div class="ch-desc">Механическая работа. КПД. Мощность. Кинетическая и потенциальная энергия. Закон сохранения механической энергии.</div>
<div class="ch-prog">
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-5">0%</span></div>
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-5" style="width:0%"></div></div>
</div>
<div class="ch-action">
<span id="btn-5">Открыть главу</span>
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</div>
</a>
<a href="/textbook/physics-7-lab" class="ch-card ch6-card" id="ch-6">
<div class="ch-cover ch6">
<div class="ch-cover-wm">ЛР</div>
<div class="ch-num">Лаборатория</div>
<div class="ch-title">Лабораторный практикум</div>
<div class="ch-range">6 виртуальных ЛР</div>
</div>
<div class="ch-body">
<div class="ch-desc">6 виртуальных лабораторных работ: цена деления, измерение длины и объёма, неравномерное движение, плотность вещества, сила трения.</div>
<div class="ch-prog">
<div class="ch-prog-label"><span>Прогресс</span><span id="prog-6">0%</span></div>
<div class="ch-prog-bar"><div class="ch-prog-fill" id="fill-6" style="width:0%"></div></div>
</div>
<div class="ch-action">
<span id="btn-6">Открыть практикум</span>
<svg class="ic" viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</div>
</div>
</a>
</div>
<section class="final-wrap" id="course-final">
<div class="final-head" id="final-head" tabindex="0" role="button" aria-expanded="false" aria-controls="final-body">
<div class="final-head-icon">
<svg viewBox="0 0 24 24"><path d="M7 4h10v6a5 5 0 0 1-10 0V4z"/><path d="M5 4h2v2H5a2 2 0 0 1 0-4M19 4h-2v2h2a2 2 0 0 0 0-4M9 20h6M12 15v5"/></svg>
</div>
<div class="final-head-text">
<div class="final-head-tag">Финал курса</div>
<div class="final-head-title">Босс-проверка по всему курсу</div>
<div class="final-head-sub">Шпаргалка курса и 10 интегрированных боссов по всем 5 главам. Победи всех — получи «Магистр физики 7» и +150 XP.</div>
</div>
<div class="final-chevron"><svg viewBox="0 0 24 24"><polyline points="6 9 12 15 18 9"/></svg></div>
</div>
<div class="final-body" id="final-body">
<div class="fin-section-title">
<svg viewBox="0 0 24 24"><path d="M4 6h16M4 12h16M4 18h10"/></svg>
Шпаргалка курса
</div>
<div class="cheat-grid">
<div class="cheat-card c1">
<div class="cheat-head">
<span class="cheat-badge">Гл. 1</span>
<span class="cheat-title">Методы познания</span>
</div>
<ul class="cheat-list">
<li>$C = (X_2 - X_1)/N$ — цена деления</li>
<li>$\Delta X = C/2$ — погрешность</li>
<li>СИ: м, кг, с, А, К, моль, кд</li>
<li>Кратные: к (10³), М (10⁶); дольные: м (10⁻³), мк (10⁻⁶)</li>
<li>$S = ab$, $V = abc$ — косвенные измерения</li>
</ul>
</div>
<div class="cheat-card c2">
<div class="cheat-head">
<span class="cheat-badge">Гл. 2</span>
<span class="cheat-title">Строение вещества</span>
</div>
<ul class="cheat-list">
<li>$d_{мол} \sim 10^{-10}$ м</li>
<li>Тверд.: фиксированная форма и объём</li>
<li>Жидк.: объём фиксирован, форма — нет</li>
<li>Газ: ни форма, ни объём не фиксированы</li>
<li>$\Delta l \sim \Delta T$ (расширение)</li>
<li>Шкала Цельсия: 0 — лёд, 100 — кипение</li>
</ul>
</div>
<div class="cheat-card c3">
<div class="cheat-head">
<span class="cheat-badge">Гл. 3</span>
<span class="cheat-title">Движение и силы</span>
</div>
<ul class="cheat-list">
<li>$v = s/t$, $[v] = $ м/с</li>
<li>$\langle v\rangle = s_{полн}/t_{полн}$</li>
<li>$\rho = m/V$, $[\rho] = $ кг/м³</li>
<li>$F_т = mg$, $g \approx 10$ Н/кг</li>
<li>$P = mg$ (вес на опоре)</li>
<li>$R = F_1 + F_2$ (сонапр.), $R = |F_1 - F_2|$ (противопол.)</li>
<li>$F_{тр} \sim N$</li>
</ul>
</div>
<div class="cheat-card c4">
<div class="cheat-head">
<span class="cheat-badge">Гл. 4</span>
<span class="cheat-title">Давление</span>
</div>
<ul class="cheat-list">
<li>$p = F/S$, $[p] = $ Па</li>
<li>Закон Паскаля: $p$ передаётся одинаково</li>
<li>Гидравлика: $F_2/F_1 = S_2/S_1$</li>
<li>$p = \rho g h$ — гидростатика</li>
<li>Сообщ. сосуды → один уровень (однородная жидкость)</li>
<li>$p_0 = 101\,325$ Па $= 760$ мм рт. ст.</li>
</ul>
</div>
<div class="cheat-card c5">
<div class="cheat-head">
<span class="cheat-badge">Гл. 5</span>
<span class="cheat-title">Работа и энергия</span>
</div>
<ul class="cheat-list">
<li>$A = Fs$ (при $\vec F \parallel \vec s$), $[A] = $ Дж</li>
<li>$\eta = A_{полез}/A_{полн} \cdot 100\%$</li>
<li>$P = A/t$, $[P] = $ Вт</li>
<li>$E_к = mv^2/2$</li>
<li>$E_п = mgh$</li>
<li>$E_к + E_п = \text{const}$ (без трения)</li>
</ul>
</div>
</div>
<div class="fin-section-title">
<svg viewBox="0 0 24 24"><path d="M14.5 3.5l-5 5L4 4l1.5 6L3 12l5 1 1 5 2.5-2.5 6 1.5-4.5-5.5 5-5"/></svg>
10 интегрированных боссов
</div>
<div class="boss-overall-bar">
<div class="lab" id="fin-boss-lab">Боссов побеждено: 0 / 10</div>
<div class="bar"><div class="fill" id="fin-boss-fill" style="width:0%"></div></div>
</div>
<div id="fin-bosses-container"></div>
<div class="final-cta" id="final-cta">
<div class="final-cta-icon">
<svg viewBox="0 0 24 24"><path d="M6 9H4l-1-3h18l-1 3h-2M6 9l1 6h10l1-6M6 9h12"/><path d="M9 21h6M12 15v6"/></svg>
</div>
<div class="final-cta-txt">
<div class="final-cta-title">Курс Физика 8 пройден!</div>
<div class="final-cta-sub">Вы прошли всю итоговую проверку курса. +150 XP, ачивка «Магистр физики 7» получена.</div>
</div>
<a href="/textbooks" class="final-cta-btn">
К каталогу учебников
<svg viewBox="0 0 24 24"><polyline points="9 18 15 12 9 6"/></svg>
</a>
</div>
</div>
</section>
<section class="ach-section" id="ach-section">
<h2 class="ach-section-title">Достижения курса</h2>
<div class="ach-section-sub" id="ach-section-sub">0 / 7 ачивок получено</div>
<div class="ach-grid" id="ach-grid">
<div class="ach-card" data-ach="physics7_ch1_yphys" data-label="Юный физик" data-sub="Все 5 боссов финала главы 1"></div>
<div class="ach-card" data-ach="physics7_ch2_master" data-label="Знаток вещества" data-sub="Все 5 боссов финала главы 2"></div>
<div class="ach-card" data-ach="physics7_ch3_master" data-label="Мастер движения" data-sub="Все 10 боссов финала главы 3"></div>
<div class="ach-card" data-ach="physics7_ch4_master" data-label="Властелин давления" data-sub="Все 7 боссов финала главы 4"></div>
<div class="ach-card" data-ach="physics7_ch5_master" data-label="Энергетик" data-sub="Все 7 боссов финала главы 5"></div>
<div class="ach-card" data-ach="physics7_lab_master" data-label="Лаборант 7 класса" data-sub="Все 6 ЛР сданы"></div>
<div class="ach-card master" data-ach="physics7_course_master" data-label="Магистр физики 7" data-sub="Все 10 интегрированных боссов курса"></div>
</div>
</section>
<div class="ach-strip" id="ach-strip" style="display:none">
<div class="ach-icon">
<svg viewBox="0 0 24 24">
<path d="M6 9H4l-1-3h18l-1 3h-2M6 9l1 6h10l1-6M6 9h12"/><path d="M9 21h6M12 15v6"/>
</svg>
</div>
<div class="ach-text">
<div class="ach-title">Магистр физики 7</div>
<div class="ach-sub" id="ach-sub">Получи достижение, победив 10 итоговых боссов курса</div>
</div>
</div>
</main>
<footer class="foot">
Интерактивный учебник «Физика &mdash; 7 класс» &middot; LearnSpace
</footer>
<script>
'use strict';
/* THEME */
(function(){
var saved = localStorage.getItem('physics7_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('physics7_theme', dark ? 'dark' : 'light');
localStorage.setItem('theme', dark ? 'dark' : 'light');
if (lab) lab.textContent = dark ? 'Светлая' : 'Тёмная';
});
})();
/* PROGRESS */
var TOTAL = 48; // 7 + 6 + 14 + 8 + 7 + 6
var CH_PARA = {
'physics-7-ch1': 7,
'physics-7-ch2': 6,
'physics-7-ch3': 14,
'physics-7-ch4': 8,
'physics-7-ch5': 7,
'physics-7-lab': 6
};
var CH_IDX = {
'physics-7-ch1': 1,
'physics-7-ch2': 2,
'physics-7-ch3': 3,
'physics-7-ch4': 4,
'physics-7-ch5': 5,
'physics-7-lab': 6
};
function setChProg(idx, readCount, total) {
var pct = total ? Math.round(readCount * 100 / total) : 0;
var labelEl = document.getElementById('prog-' + idx);
var fillEl = document.getElementById('fill-' + idx);
var btnEl = document.getElementById('btn-' + idx);
if (labelEl) labelEl.textContent = pct + '%';
if (fillEl) fillEl.style.width = pct + '%';
if (btnEl) {
if (readCount > 0 && readCount < total) btnEl.textContent = (idx === 6 ? 'Продолжить ЛР' : 'Продолжить');
else if (readCount >= total) btnEl.textContent = 'Открыть снова';
else btnEl.textContent = (idx === 6 ? 'Открыть практикум' : 'Открыть главу');
}
return pct;
}
var FIN_ACH_KEY = 'physics7_course_master';
function renderProgress(children) {
var totalRead = 0;
for (var i = 0; i < children.length; i++) {
var ch = children[i];
var idx = CH_IDX[ch.slug];
if (!idx) continue;
var read = ch.progress ? ch.progress.read.length : 0;
var total = ch.para_count || CH_PARA[ch.slug] || 1;
totalRead += read;
setChProg(idx, read, total);
}
var pct = Math.round(totalRead * 100 / TOTAL);
var overallEl = document.getElementById('overall-text');
var fillEl = document.getElementById('overall-fill');
if (overallEl) overallEl.textContent = totalRead + ' из ' + TOTAL + ' пунктов \xb7 ' + pct + '%';
if (fillEl) fillEl.style.width = pct + '%';
var xpBadge = document.getElementById('hero-xp-badge');
var xp = parseInt(localStorage.getItem('physics7_xp') || '0', 10) || 0;
if (xpBadge && xp > 0) {
xpBadge.style.display = '';
xpBadge.textContent = xp + ' XP';
}
var mastered = localStorage.getItem(FIN_ACH_KEY) === '1';
if (totalRead >= TOTAL || mastered) {
var strip = document.getElementById('ach-strip');
var sub = document.getElementById('ach-sub');
if (strip) strip.classList.add('lit');
if (sub) {
if (mastered) sub.textContent = 'Выполнено! Вы — Магистр физики 7.';
else sub.textContent = 'Выполнено! Вы прошли весь курс физики 7 класса.';
}
}
}
/* COURSE FINAL — lazy bosses */
var FIN_BOSS_KEY = 'physics7_course_bosses';
var FIN_BOSSES = [
{
n: 1,
title: 'Цена деления линейки',
tag: 'Гл. 1',
q: 'На линейке между отметками $0$ и $1$ см нанесено $10$ маленьких делений. Найди цену деления в мм.',
hint: '$C = (X_2 - X_1)/N = 10\\,\\text{мм}/10 = 1$ мм.',
ans: 1,
tol: 0.05,
step: '0.1'
},
{
n: 2,
title: 'Плотность и масса',
tag: 'Гл. 3',
q: 'Алюминиевый брусок имеет массу $m = 270$ г. Плотность алюминия $\\rho = 2700$ кг/м³. Найди объём бруска в см³.',
hint: '$m = 0{,}270$ кг. $V = m/\\rho = 0{,}270/2700 = 10^{-4}$ м³ $= 100$ см³.',
ans: 100,
tol: 1,
step: '1'
},
{
n: 3,
title: 'Сила тяжести на Луне',
tag: 'Гл. 3',
q: 'Тело массой $m = 250$ г. Что покажет динамометр на Луне, где $g_Л = 1{,}6$ Н/кг? Ответ в Н (округли до сотых).',
hint: '$F = mg = 0{,}25 \\cdot 1{,}6 = 0{,}40$ Н.',
ans: 0.40,
tol: 0.02,
step: '0.01'
},
{
n: 4,
title: 'Равнодействующая трёх сил',
tag: 'Гл. 3',
q: 'На тело действуют три силы по одной прямой: $F_1 = 30$ Н вправо, $F_2 = 20$ Н вправо, $F_3 = 40$ Н влево. Найди модуль равнодействующей в Н.',
hint: 'Вправо: $30 + 20 = 50$ Н. Влево: $40$ Н. $|R| = 50 - 40 = 10$ Н (направлена вправо).',
ans: 10,
tol: 0.5,
step: '1'
},
{
n: 5,
title: 'Давление на дне бассейна',
tag: 'Гл. 4',
q: 'Глубина бассейна $h = 3$ м. Найди гидростатическое давление воды на дно в кПа. ($g = 9{,}8$ Н/кг, $\\rho_{воды} = 1000$ кг/м³)',
hint: '$p = \\rho g h = 1000 \\cdot 9{,}8 \\cdot 3 = 29\\,400$ Па $= 29{,}4$ кПа.',
ans: 29.4,
tol: 0.5,
step: '0.1'
},
{
n: 6,
title: 'Гидравлический пресс',
tag: 'Гл. 4',
q: 'Малый поршень имеет площадь $S_1 = 2$ см², большой — $S_2 = 200$ см². На малый поршень давит сила $F_1 = 50$ Н. Какую силу в Н создаёт большой поршень?',
hint: 'По закону Паскаля $p_1 = p_2$, $F_2 = F_1 \\cdot S_2/S_1 = 50 \\cdot 200/2 = 5000$ Н.',
ans: 5000,
tol: 50,
step: '1'
},
{
n: 7,
title: 'Атмосфера на 30-м этаже',
tag: 'Гл. 4',
q: 'Высота 30-этажного дома около $H = 90$ м. На каждые $12$ м подъёма атм. давление падает на $1$ мм рт. ст. На сколько мм рт. ст. отличается давление на крыше от первого этажа?',
hint: '$\\Delta p = H/12 = 90/12 = 7{,}5$ мм рт. ст.',
ans: 7.5,
tol: 0.2,
step: '0.1'
},
{
n: 8,
title: 'Работа силы трения',
tag: 'Гл. 5',
q: 'Брусок переместили на $s = 5$ м, преодолевая силу трения $F_{тр} = 20$ Н. Какую работу совершила сила трения? Ответ в Дж со знаком (трение направлено против движения).',
hint: '$A_{тр} = -F_{тр} \\cdot s = -20 \\cdot 5 = -100$ Дж (отрицательная — энергия рассеивается в тепло).',
ans: -100,
tol: 1,
step: '1'
},
{
n: 9,
title: 'КПД наклонной плоскости',
tag: 'Гл. 5',
q: 'Груз массой $m = 50$ кг поднимают по наклону длиной $l = 4$ м на высоту $h = 1$ м, прикладывая силу $F = 150$ Н вдоль наклона. ($g = 10$ Н/кг). Найди КПД в %.',
hint: '$A_{полез} = mgh = 50 \\cdot 10 \\cdot 1 = 500$ Дж. $A_{полн} = F \\cdot l = 150 \\cdot 4 = 600$ Дж. $\\eta = 500/600 \\cdot 100\\% \\approx 83$ %.',
ans: 83,
tol: 1,
step: '1'
},
{
n: 10,
title: 'Магистр физики 7',
tag: 'синтез курса',
q: 'Тело массой $m = 0{,}5$ кг падает с высоты $h = 10$ м без сопротивления воздуха. Найди скорость $v$ у земли в м/с (округли до десятых). ($g = 9{,}8$ Н/кг)',
hint: 'По закону сохранения: $mgh = mv^2/2 \\Rightarrow v = \\sqrt{2gh} = \\sqrt{2 \\cdot 9{,}8 \\cdot 10} = \\sqrt{196} = 14{,}0$ м/с.',
ans: 14.0,
tol: 0.2,
step: '0.1'
}
];
function loadFinBossState(){
try { return JSON.parse(localStorage.getItem(FIN_BOSS_KEY) || '{}') || {}; }
catch(e) { return {}; }
}
function saveFinBossState(s){
try { localStorage.setItem(FIN_BOSS_KEY, JSON.stringify(s)); } catch(e){}
}
function finRenderKatex(root){
if (typeof window.renderMathInElement !== 'function') return;
try {
window.renderMathInElement(root, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
throwOnError: false
});
} catch(e){}
}
function updateFinBossBar(state){
var won = 0;
for (var k in state) if (state[k]) won++;
var lab = document.getElementById('fin-boss-lab');
var fill = document.getElementById('fin-boss-fill');
if (lab) lab.textContent = 'Боссов побеждено: ' + won + ' / ' + FIN_BOSSES.length;
if (fill) fill.style.width = Math.round(won * 100 / FIN_BOSSES.length) + '%';
return won;
}
function maybeUnlockMaster(state){
if (localStorage.getItem(FIN_ACH_KEY) === '1') return;
var won = 0;
for (var k in state) if (state[k]) won++;
if (won < FIN_BOSSES.length) return;
localStorage.setItem(FIN_ACH_KEY, '1');
/* +150 XP */
var xp = parseInt(localStorage.getItem('physics7_xp') || '0', 10) || 0;
localStorage.setItem('physics7_xp', String(xp + 150));
try {
if (window.LS && typeof window.LS.addXp === 'function') {
window.LS.addXp(150, 'physics7-master');
} else if (typeof window.addXp === 'function') {
window.addXp(150, 'physics7-master');
}
} catch(e){}
try { if (typeof window.confetti === 'function') window.confetti({particleCount: 220, spread: 110, origin: {y: .6}}); } catch(e){}
var strip = document.getElementById('ach-strip');
var sub = document.getElementById('ach-sub');
if (strip) strip.classList.add('lit');
if (sub) sub.textContent = 'Выполнено! Вы — Магистр физики 7.';
var cta = document.getElementById('final-cta');
if (cta) cta.classList.add('show');
var xpBadge = document.getElementById('hero-xp-badge');
if (xpBadge) {
var newXp = parseInt(localStorage.getItem('physics7_xp') || '0', 10) || 0;
xpBadge.style.display = '';
xpBadge.textContent = newXp + ' XP';
}
}
function buildFinBoss(b, state){
var solvedClass = state[b.n] ? ' solved' : '';
var step = b.step || '1';
var displayAns = (typeof b.ans === 'number' && step !== '1') ? b.ans.toFixed(2) : b.ans;
return '<div class="boss-card' + solvedClass + '" id="fin-boss-' + b.n + '-card">'
+ '<div class="boss-head">'
+ '<span class="boss-tag">' + b.tag + '</span>'
+ '<span class="boss-title">Босс ' + b.n + '. ' + b.title + '</span>'
+ '</div>'
+ '<div class="boss-q" id="fin-boss-' + b.n + '-q">' + b.q + '</div>'
+ '<div class="boss-row">'
+ '<input type="number" step="' + step + '" class="boss-input" id="fin-boss-' + b.n + '-inp" placeholder="число"' + (state[b.n] ? ' value="' + displayAns + '" disabled' : '') + '>'
+ '<button class="boss-btn primary" id="fin-boss-' + b.n + '-go"' + (state[b.n] ? ' disabled' : '') + '>Атаковать</button>'
+ '<button class="boss-btn" id="fin-boss-' + b.n + '-hint">Подсказка</button>'
+ '</div>'
+ '<div class="boss-hint-txt" id="fin-boss-' + b.n + '-hinttxt">' + b.hint + '</div>'
+ '<div class="boss-fb' + (state[b.n] ? ' ok' : '') + '" id="fin-boss-' + b.n + '-fb">' + (state[b.n] ? 'Победа! +15 XP. Босс уже повержен.' : '') + '</div>'
+ '</div>';
}
function bindFinBoss(b){
var state = loadFinBossState();
var goBtn = document.getElementById('fin-boss-' + b.n + '-go');
var hintBtn = document.getElementById('fin-boss-' + b.n + '-hint');
var inp = document.getElementById('fin-boss-' + b.n + '-inp');
var fb = document.getElementById('fin-boss-' + b.n + '-fb');
var hintTx = document.getElementById('fin-boss-' + b.n + '-hinttxt');
var card = document.getElementById('fin-boss-' + b.n + '-card');
if (!goBtn) return;
if (hintBtn) hintBtn.addEventListener('click', function(){
if (hintTx) hintTx.classList.toggle('show');
});
if (state[b.n]) return;
goBtn.addEventListener('click', function(){
var v = parseFloat((inp.value || '').replace(',', '.'));
if (isNaN(v)) {
fb.className = 'boss-fb fail';
fb.textContent = 'Введите число.';
return;
}
var tol = (typeof b.tol === 'number') ? b.tol : 1e-9;
if (Math.abs(v - b.ans) < tol) {
fb.className = 'boss-fb ok';
fb.textContent = 'Победа! +15 XP. Босс повержен.';
card.classList.add('solved');
goBtn.disabled = true;
inp.disabled = true;
var s = loadFinBossState();
if (!s[b.n]) {
s[b.n] = true;
saveFinBossState(s);
var xp = parseInt(localStorage.getItem('physics7_xp') || '0', 10) || 0;
localStorage.setItem('physics7_xp', String(xp + 15));
try {
if (window.LS && typeof window.LS.addXp === 'function') window.LS.addXp(15, 'fin-boss-' + b.n);
else if (typeof window.addXp === 'function') window.addXp(15, 'fin-boss-' + b.n);
} catch(e){}
var xpBadge = document.getElementById('hero-xp-badge');
if (xpBadge) {
var nXp = parseInt(localStorage.getItem('physics7_xp') || '0', 10) || 0;
xpBadge.style.display = '';
xpBadge.textContent = nXp + ' XP';
}
updateFinBossBar(s);
maybeUnlockMaster(s);
}
} else {
fb.className = 'boss-fb fail';
fb.textContent = 'Не то. Перепроверь решение и попробуй снова.';
}
});
inp.addEventListener('keydown', function(e){
if (e.key === 'Enter') { e.preventDefault(); goBtn.click(); }
});
}
var FIN_BOSSES_RENDERED = false;
function renderFinBosses(){
if (FIN_BOSSES_RENDERED) return;
var cont = document.getElementById('fin-bosses-container');
if (!cont) return;
var state = loadFinBossState();
var html = '';
for (var i = 0; i < FIN_BOSSES.length; i++) html += buildFinBoss(FIN_BOSSES[i], state);
cont.innerHTML = html;
for (var j = 0; j < FIN_BOSSES.length; j++) bindFinBoss(FIN_BOSSES[j]);
var wrap = document.getElementById('course-final');
finRenderKatex(wrap);
updateFinBossBar(state);
if (localStorage.getItem(FIN_ACH_KEY) === '1') {
var cta = document.getElementById('final-cta');
if (cta) cta.classList.add('show');
var strip = document.getElementById('ach-strip');
var sub = document.getElementById('ach-sub');
if (strip) strip.classList.add('lit');
if (sub) sub.textContent = 'Выполнено! Вы — Магистр физики 7.';
}
FIN_BOSSES_RENDERED = true;
}
/* FINAL ACCORDION */
(function bindFinalAccordion(){
var head = document.getElementById('final-head');
var wrap = document.getElementById('course-final');
if (!head || !wrap) return;
function toggle(){
var willOpen = !wrap.classList.contains('open');
wrap.classList.toggle('open');
head.setAttribute('aria-expanded', willOpen ? 'true' : 'false');
if (willOpen) {
renderFinBosses();
finRenderKatex(wrap);
}
}
head.addEventListener('click', toggle);
head.addEventListener('keydown', function(e){
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
});
})();
(function syncMasterOnLoad(){
if (localStorage.getItem(FIN_ACH_KEY) === '1') {
var strip = document.getElementById('ach-strip');
var sub = document.getElementById('ach-sub');
if (strip) strip.classList.add('lit');
if (sub) sub.textContent = 'Выполнено! Вы — Магистр физики 7.';
}
})();
/* ACHIEVEMENTS PANEL — render 7 cards based on localStorage keys */
function renderAchievements(){
var cards = document.querySelectorAll('.ach-card');
var lit = 0;
cards.forEach(function(c){
var key = c.dataset.ach;
var label = c.dataset.label;
var sub = c.dataset.sub;
var ok = localStorage.getItem(key) === '1';
if (ok) { c.classList.add('lit'); lit++; }
if (!c.querySelector('.ach-card-text')) {
var txt = document.createElement('div');
txt.className = 'ach-card-text';
txt.innerHTML = '<div class="ach-card-label">' + label + '</div><div class="ach-card-sub">' + (ok ? sub + ' · получено' : sub) + '</div>';
c.appendChild(txt);
}
});
var subEl = document.getElementById('ach-section-sub');
if (subEl) subEl.textContent = lit + ' / 7 ачивок получено';
return lit;
}
(function initAchievementsPanel(){
var litCount = renderAchievements();
/* Если первый раз получили «Магистр физики 7» — запустить confetti */
var fired = sessionStorage.getItem('physics7_confetti_fired') === '1';
if (!fired && localStorage.getItem(FIN_ACH_KEY) === '1' && typeof window.confetti === 'function') {
sessionStorage.setItem('physics7_confetti_fired', '1');
setTimeout(function(){
window.confetti({ particleCount: 220, spread: 110, origin: { y: 0.6 } });
setTimeout(function(){ window.confetti({ particleCount: 120, angle: 60, spread: 70, origin: { x: 0, y: 0.7 } }); }, 250);
setTimeout(function(){ window.confetti({ particleCount: 120, angle: 120, spread: 70, origin: { x: 1, y: 0.7 } }); }, 400);
}, 400);
}
/* Перерисовка при возврате на вкладку */
window.addEventListener('focus', renderAchievements);
})();
function loadProgress() {
if (typeof window.LS === 'undefined' || typeof window.LS.api !== 'function') {
renderProgress([]);
return;
}
window.LS.api('/api/textbooks/physics-7/children')
.then(function(data) {
if (data && data.children) renderProgress(data.children);
else renderProgress([]);
})
.catch(function() { renderProgress([]); });
}
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', loadProgress);
} else {
loadProgress();
}
window.addEventListener('focus', loadProgress);
</script>
</body>
</html>