Files
Learn_System/frontend/textbooks/physics_8_hub.html
T
Maxim Dolgolyov 77e4dffb43 feat(phys8): Phase 0 redesign foundation — CSS + JS infrastructure
Закладывает уникальный визуальный язык и engine'ы для редизайна Физики 8.

CSS:
- phys8-design-system.css (12 КБ): 3 темы (thermal/electric/spectrum),
  тематические hero-палитры, watermarks, animations (thermal-shift,
  electric-pulse, spectrum-drift, wm-breathe/flicker/rotate, noise overlay),
  staggered fade-in для виджетов, soft elevation на карточках,
  monospace для физ. величин, topic-aware progress bars,
  mobile responsive (≤768px), prefers-reduced-motion.
- phys8-interactives.css (10 КБ): .p8-draggable + .p8-droptarget с
  hover-effects, .p8-palette (для circuit-builder), .p8-scrubber,
  .p8-readout табло, .p8-tooltip, .p8-sandbox canvas wrapper,
  .p8-thermometer + .p8-compass-needle SVG-композиции, glow-utility.

JS:
- phys8-anim.js (6 КБ): easing-функции (quad/cubic/expo/back/elastic/
  bounce/spring), tween-engine с onUpdate/onComplete, raf-wrapper,
  oscillate, stagger, onVisible (IntersectionObserver). Экспорт P8Anim.
- phys8-drag.js (12 КБ): универсальный drag-engine. P8Drag.attach()
  для DOM/SVG, P8Drag.attachCanvas() для логических объектов с
  hit-test, P8Drag.attachPalette() для drag-from-palette-to-drop,
  constraints (lockX/Y, bounds, snap-to-grid), touch + mouse + pointer.
- phys8-helpers.js (18 КБ): тематические хелперы. P8Helpers.thermal
  (tempColor 0-1, heatFlowArrow, molecule, thermometerSVG,
  convectionCellParticles), .em (chargeSVG, circuitComponent для
  battery/resistor/lamp/ammeter/voltmeter/switch, fieldLineFrom),
  .optics (rayLine, lensSVG converging/diverging, mirrorPlane),
  .svg utils (el, create, linearGradient, radialGradient,
  gradientArrow, labeledText).

Линковка (redesign_p8_phase0.cjs):
- 2 CSS-link после katex CDN
- 3 JS-link после phys.js/xp.js
- body class p8-theme-thermal/electric/spectrum на ch1/ch2/ch3
- hub и lab — без темы (нейтральный пурпурный brand)
2026-05-30 09:55:00 +03:00

863 lines
44 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>Физика 8 класс — учебник</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 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:#faf5ff; --card:#fff;
--text:#0f172a; --muted:#475569;
--border:#e9d5ff;
--pri:#7c3aed; --pri-d:#5b21b6;
--pri-soft:#ede9fe;
--ch1:#dc2626; --ch1-d:#991b1b;
--ch2:#d97706; --ch2-d:#92400e;
--ch3:#0891b2; --ch3-d:#0e7490;
--ch4:#10b981; --ch4-d:#047857;
--sh:0 4px 16px rgba(124,58,237,.10);
--sh-h:0 12px 36px rgba(124,58,237,.18);
}
html.dark{
--bg:#15102a; --card:#1f1640;
--text:#ede9fe; --muted:#a78bfa;
--border:#3b2871;
--pri-soft:rgba(124,58,237,.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,#312e81 0%,#7c3aed 55%,#c4b5fd 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(196,181,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,#7c3aed,#c4b5fd);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(124,58,237,.14);border-radius:5px;overflow:hidden;margin-top:6px}
.po-fill{height:100%;background:linear-gradient(90deg,var(--pri),#c4b5fd);border-radius:5px;transition:width .5s}
.po-xp{display:inline-flex;align-items:center;gap:6px;padding:6px 14px;background:linear-gradient(135deg,#a78bfa,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(124,58,237,.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,#7f1d1d,#dc2626 60%,#f87171)}
.ch-cover.ch2{background:linear-gradient(135deg,#78350f,#d97706 60%,#fbbf24)}
.ch-cover.ch3{background:linear-gradient(135deg,#164e63,#0891b2 60%,#22d3ee)}
.ch-cover.ch4{background:linear-gradient(135deg,#064e3b,#10b981 60%,#6ee7b7)}
.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-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),#f87171)}
.ch-card.ch2-card .ch-action{background:linear-gradient(135deg,var(--ch2),#fbbf24)}
.ch-card.ch3-card .ch-action{background:linear-gradient(135deg,var(--ch3),#22d3ee)}
.ch-card.ch4-card .ch-action{background:linear-gradient(135deg,var(--ch4),#6ee7b7)}
/* ACHIEVEMENT STRIP */
.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:#a855f7;box-shadow:0 0 0 3px rgba(168,85,247,.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,#a78bfa,#7c3aed)}
.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:#5b21b6}
.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,#312e81 0%,#7c3aed 55%,#a78bfa 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-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-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(124,58,237,.08),rgba(196,181,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(124,58,237,.14);border-radius:5px;overflow:hidden}
.boss-overall-bar .fill{height:100%;background:linear-gradient(90deg,var(--pri),#c4b5fd,#a78bfa);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(124,58,237,.14);color:var(--pri-d);letter-spacing:.04em;text-transform:uppercase}
html.dark .boss-tag{color:#c4b5fd}
.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(124,58,237,.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),#a78bfa);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,#ede9fe,#ddd6fe);border:1.5px solid #a78bfa;display:none;align-items:center;gap:14px;flex-wrap:wrap}
.final-cta.show{display:flex}
html.dark .final-cta{background:linear-gradient(135deg,rgba(124,58,237,.22),rgba(91,33,182,.18));border-color:#7c3aed}
.final-cta-icon{width:48px;height:48px;border-radius:12px;background:linear-gradient(135deg,#a78bfa,#7c3aed);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:#5b21b6;font-size:1.05rem;font-family:'Outfit',sans-serif}
html.dark .final-cta-title{color:#ddd6fe}
.final-cta-sub{font-size:.86rem;color:#6d28d9;margin-top:2px}
html.dark .final-cta-sub{color:#c4b5fd}
.final-cta-btn{padding:10px 18px;border-radius:10px;background:linear-gradient(135deg,var(--pri),#a78bfa);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; 8 класс</h1>
<div class="hdr-sub">Полный курс физики 8 класса: тепловые явления, электромагнитные явления, световые явления, лабораторный практикум</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-8-ch1" class="ch-card ch1-card" id="ch-1">
<div class="ch-cover ch1">
<div class="ch-cover-wm">Q</div>
<div class="ch-num">Глава 1</div>
<div class="ch-title">Тепловые явления</div>
<div class="ch-range">&sect;1&ndash;&sect;11 + Финал</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-8-ch2" class="ch-card ch2-card" id="ch-2">
<div class="ch-cover ch2">
<div class="ch-cover-wm">I</div>
<div class="ch-num">Глава 2</div>
<div class="ch-title">Электромагнитные явления</div>
<div class="ch-range">&sect;12&ndash;&sect;31 + Финал</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-8-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;32&ndash;&sect;40 + Финал</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-8-lab" class="ch-card ch4-card" id="ch-4">
<div class="ch-cover ch4">
<div class="ch-cover-wm">ЛР</div>
<div class="ch-num">Лаборатория</div>
<div class="ch-title">Лабораторный практикум</div>
<div class="ch-range">7 виртуальных ЛР</div>
</div>
<div class="ch-body">
<div class="ch-desc">7 виртуальных лабораторных работ: теплообмен, удельная теплоёмкость, простейшая цепь, последовательное и параллельное соединения, работа и мощность тока, отражение света.</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>
</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 интегрированных боссов по всем 3 главам. Победи всех — получи «Магистр физики 8» и +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>$Q = cm\Delta T$ — нагрев / охлаждение</li>
<li>$Q = qm$ — сгорание топлива</li>
<li>$Q = \lambda m$ — плавление</li>
<li>$Q = L m$ — парообразование</li>
<li>Теплопередача: проводность, конвекция, излучение</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>$q = Ne$, $e = 1{,}6 \cdot 10^{-19}$ Кл</li>
<li>$A = qU$, $U = A/q$</li>
<li>$I = q/t$, $I = U/R$ — закон Ома</li>
<li>$R = \rho l / S$</li>
<li>Последов.: $R = R_1+R_2$, $U = U_1+U_2$</li>
<li>Паралл.: $1/R = 1/R_1 + 1/R_2$</li>
<li>$P = UI$, $A = UIt$, $Q = I^2 Rt$</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>$c = 3 \cdot 10^8$ м/с</li>
<li>Закон отражения: $\alpha = \beta$</li>
<li>Закон Снеллиуса: $\dfrac{\sin\alpha}{\sin\beta} = n$</li>
<li>$D = 1/F$ (дптр)</li>
<li>$\dfrac{1}{F} = \dfrac{1}{d} + \dfrac{1}{f}$ (тонкая линза)</li>
<li>Близо-: $D &lt; 0$; дально-: $D &gt; 0$</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, ачивка «Магистр физики 8» получена.</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>
<div class="ach-strip" id="ach-strip">
<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">Магистр физики 8</div>
<div class="ach-sub" id="ach-sub">Прочитайте все 40 параграфов и выполните все 7 лабораторных работ, чтобы получить достижение</div>
</div>
</div>
</main>
<footer class="foot">
Интерактивный учебник «Физика &mdash; 8 класс» &middot; LearnSpace
</footer>
<script>
'use strict';
/* THEME */
(function(){
var saved = localStorage.getItem('physics8_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('physics8_theme', dark ? 'dark' : 'light');
localStorage.setItem('theme', dark ? 'dark' : 'light');
if (lab) lab.textContent = dark ? 'Светлая' : 'Тёмная';
});
})();
/* PROGRESS */
var TOTAL = 47; // 11 + 20 + 9 + 7
var CH_PARA = {
'physics-8-ch1': 11,
'physics-8-ch2': 20,
'physics-8-ch3': 9,
'physics-8-lab': 7
};
var CH_IDX = {
'physics-8-ch1': 1,
'physics-8-ch2': 2,
'physics-8-ch3': 3,
'physics-8-lab': 4
};
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 === 4 ? 'Продолжить ЛР' : 'Продолжить');
else if (readCount >= total) btnEl.textContent = 'Открыть снова';
else btnEl.textContent = (idx === 4 ? 'Открыть практикум' : 'Открыть главу');
}
return pct;
}
var FIN_ACH_KEY = 'physics8_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('physics8_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 = 'Выполнено! Вы — Магистр физики 8.';
else sub.textContent = 'Выполнено! Вы прошли весь курс физики 8 класса.';
}
}
}
/* COURSE FINAL — lazy bosses */
var FIN_BOSS_KEY = 'physics8_course_bosses';
var FIN_BOSSES = [
{
n: 1,
title: 'Электрочайник: тепло + работа тока',
tag: 'Гл. 1 + 2',
q: 'Электрочайник нагревает $m = 1$ кг воды от $t_1 = 20$ °C до кипения ($t_2 = 100$ °C) за время $\\tau = 5$ мин. Сетевое напряжение $U = 220$ В, КПД $\\eta = 100\\%$. Найди силу тока $I$ в А (округли до сотых). ($c_{воды} = 4200$ Дж/(кг·К))',
hint: '$Q = cm\\Delta T = 4200 \\cdot 1 \\cdot 80 = 336\\,000$ Дж. Работа тока $A = UIt$, при $\\eta=100\\%$ $A=Q$: $I = \\dfrac{Q}{Ut} = \\dfrac{336\\,000}{220 \\cdot 300} = 5{,}09$ А.',
ans: 5.09,
tol: 0.05,
step: '0.01'
},
{
n: 2,
title: 'Плавление льда электроплиткой',
tag: 'Гл. 1 + 2',
q: 'Сколько энергии в кВт·ч нужно, чтобы расплавить $m = 2$ кг льда при $t = 0$ °C? ($\\lambda_{льда} = 3{,}34 \\cdot 10^5$ Дж/кг; округли до сотых).',
hint: '$Q = \\lambda m = 3{,}34 \\cdot 10^5 \\cdot 2 = 6{,}68 \\cdot 10^5$ Дж $= \\dfrac{6{,}68\\cdot10^5}{3{,}6\\cdot10^6} \\approx 0{,}19$ кВт·ч.',
ans: 0.19,
tol: 0.01,
step: '0.01'
},
{
n: 3,
title: 'Закон Джоуля — Ленца',
tag: 'Гл. 2',
q: 'По нихромовой спирали с сопротивлением $R = 50$ Ом течёт ток $I = 4$ А в течение $\\tau = 10$ мин. Сколько теплоты выделится в Дж?',
hint: '$Q = I^2 R t = 16 \\cdot 50 \\cdot 600 = 480\\,000$ Дж.',
ans: 480000,
tol: 1000,
step: '1'
},
{
n: 4,
title: 'Смешанная цепь',
tag: 'Гл. 2',
q: 'К батарейке $U = 12$ В подключены последовательно резистор $R_1 = 4$ Ом и параллельный блок из двух резисторов $R_2 = R_3 = 6$ Ом. Найди общий ток в цепи в А.',
hint: 'Паралл. блок: $R_{23} = \\dfrac{6 \\cdot 6}{6+6} = 3$ Ом. Всего: $R = R_1 + R_{23} = 7$ Ом. $I = U/R = 12/7 \\approx 1{,}71$ А.',
ans: 1.71,
tol: 0.05,
step: '0.01'
},
{
n: 5,
title: 'Сопротивление провода',
tag: 'Гл. 2',
q: 'Найди сопротивление медного провода длиной $l = 100$ м и площадью сечения $S = 0{,}5$ мм² в Ом. ($\\rho_{меди} = 0{,}017$ Ом·мм²/м; округли до десятых)',
hint: '$R = \\rho l/S = 0{,}017 \\cdot 100 / 0{,}5 = 3{,}4$ Ом.',
ans: 3.4,
tol: 0.1,
step: '0.01'
},
{
n: 6,
title: 'Преломление',
tag: 'Гл. 3',
q: 'Луч переходит из воздуха ($n_1 = 1$) в воду ($n_2 = 1{,}33$). Угол падения $\\alpha = 45°$. Найди угол преломления $\\beta$ в градусах (округли до десятых).',
hint: '$\\sin\\beta = \\dfrac{n_1 \\sin\\alpha}{n_2} = \\dfrac{\\sin 45°}{1{,}33} \\approx \\dfrac{0{,}707}{1{,}33} \\approx 0{,}532$, $\\beta \\approx 32{,}1°$.',
ans: 32.1,
tol: 0.5,
step: '0.1'
},
{
n: 7,
title: 'Тонкая линза',
tag: 'Гл. 3',
q: 'Собирающая линза с $F = 20$ см. Предмет на расстоянии $d = 30$ см от линзы. Найди расстояние от линзы до изображения $f$ в см.',
hint: '$\\dfrac{1}{F} = \\dfrac{1}{d} + \\dfrac{1}{f} \\Rightarrow f = \\dfrac{dF}{d-F} = \\dfrac{30 \\cdot 20}{30-20} = 60$ см.',
ans: 60,
tol: 1,
step: '1'
},
{
n: 8,
title: 'Очки',
tag: 'Гл. 3',
q: 'Близорукому нужны очки с фокусным расстоянием $|F| = 50$ см. Какая оптическая сила линзы в дптр? Знак учти (для рассеивающей линзы — отрицательный).',
hint: '$D = 1/F = 1/(-0{,}5) = -2$ дптр.',
ans: -2,
tol: 0.1,
step: '0.1'
},
{
n: 9,
title: 'Стоимость электроэнергии',
tag: 'Гл. 2',
q: 'В квартире лампа мощностью $P = 100$ Вт горит $6$ часов в день. Тариф $t = 0{,}20$ руб/(кВт·ч). Сколько рублей нужно заплатить за месяц (30 дней)? Округли до сотых.',
hint: 'Энергия за месяц: $W = P \\cdot \\tau = 0{,}1 \\cdot 6 \\cdot 30 = 18$ кВт·ч. Стоимость: $18 \\cdot 0{,}20 = 3{,}60$ руб.',
ans: 3.6,
tol: 0.05,
step: '0.01'
},
{
n: 10,
title: 'Магистр физики 8',
tag: 'синтез курса',
q: 'Электролампа $U=220$ В мощностью $P=60$ Вт горит на сетчатке глаза изображение нити. До лампы $d=2$ м, фокус хрусталика глаза $F=2{,}0$ см. Найди $f$ (расстояние от хрусталика до изображения) в см. Округли до сотых.',
hint: '$\\dfrac{1}{f} = \\dfrac{1}{F} - \\dfrac{1}{d} = \\dfrac{1}{0{,}02} - \\dfrac{1}{2} = 50 - 0{,}5 = 49{,}5$ м$^{-1}$. $f = 1/49{,}5 \\approx 0{,}0202$ м $= 2{,}02$ см.',
ans: 2.02,
tol: 0.02,
step: '0.01'
}
];
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('physics8_xp') || '0', 10) || 0;
localStorage.setItem('physics8_xp', String(xp + 150));
try {
if (window.LS && typeof window.LS.addXp === 'function') {
window.LS.addXp(150, 'physics8-master');
} else if (typeof window.addXp === 'function') {
window.addXp(150, 'physics8-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 = 'Выполнено! Вы — Магистр физики 8.';
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('physics8_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('physics8_xp') || '0', 10) || 0;
localStorage.setItem('physics8_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('physics8_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 = 'Выполнено! Вы — Магистр физики 8.';
}
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 = 'Выполнено! Вы — Магистр физики 8.';
}
})();
function loadProgress() {
if (typeof window.LS === 'undefined' || typeof window.LS.api !== 'function') {
renderProgress([]);
return;
}
window.LS.api('/api/textbooks/physics-8/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>