Files
Learn_System/frontend/textbooks/physics_7_ch2.html

417 lines
29 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">
<title>Физика 7 · Глава 2 · Строение вещества</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<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"
onload="renderMathInElement(document.body,{delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false},{left:'\\[',right:'\\]',display:true},{left:'\\(',right:'\\)',display:false}],throwOnError:false})"></script>
<script src="/js/api.js" defer></script>
<script src="/js/xp.js" defer></script>
<script src="/js/phys.js?v=20260530" defer></script>
<script src="/js/phys7_ch2_widgets.js?v=20260530" defer></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=Manrope:wght@600;700;800;900&family=Unbounded:wght@700;800;900&family=JetBrains+Mono:wght@500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#f0f9ff; --card:#fff; --card-soft:#f8fafc; --text:#0f172a; --muted:#475569;
--border:#bae6fd; --pri:#0284c7; --pri2:#0c4a6e; --pri-soft:#e0f2fe;
--acc:#7c3aed; --acc-d:#5b21b6; --acc-soft:#ede9fe;
--ok:#10b981; --ok-bg:#d1fae5; --fail:#dc2626; --fail-bg:#fee2e2; --warn:#f59e0b; --warn-bg:#fef3c7;
--sh:0 4px 16px rgba(2,132,199,.08); --sh-h:0 12px 36px rgba(2,132,199,.16);
}
html.dark{--bg:#0c1e2e;--card:#0e2436;--card-soft:#0b1a28;--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.6;transition:background .25s,color .25s}
.hdr{position:relative;background:linear-gradient(135deg,#4c1d95,#7c3aed 60%,#c4b5fd);color:#fff;padding:24px 22px 22px;overflow:hidden;border-bottom:2px solid rgba(255,255,255,.18)}
.hdr-inner{position:relative;z-index:1;max-width:1240px;margin:0 auto;display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.hdr h1{font-family:'Unbounded',sans-serif;font-size:1.55rem;font-weight:800;letter-spacing:-.01em}
.hdr-sub{font-size:.88rem;opacity:.9;margin-top:3px}
.hdr-side{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.hdr-btn{padding:8px 12px;background:rgba(255,255,255,.16);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;text-decoration:none}
.hdr-btn:hover{background:rgba(255,255,255,.26)}
.ic{width:16px;height:16px;stroke:currentColor;fill:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}
.main{max-width:1240px;margin:0 auto;padding:22px;width:100%;display:grid;grid-template-columns:1fr 280px;gap:24px}
@media(max-width:980px){.main{grid-template-columns:1fr;padding:14px}}
.col-main{min-width:0}
.psel{background:var(--card);border:1.5px solid var(--border);border-radius:14px;padding:16px;margin-bottom:18px;box-shadow:var(--sh)}
.psel-head{font-family:'Unbounded',sans-serif;font-size:.78rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px}
.psel-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(170px,1fr));gap:10px}
.psel-card{padding:12px;background:var(--card-soft);border:1.5px solid var(--border);border-radius:10px;cursor:pointer;transition:transform .15s,border-color .15s,box-shadow .15s;text-align:left}
.psel-card:hover{border-color:var(--acc);transform:translateY(-2px);box-shadow:0 4px 14px rgba(0,0,0,.06)}
.psel-card.active{border-color:var(--acc);background:var(--acc-soft)}
.psel-num{font-size:.7rem;font-weight:800;color:var(--acc-d);letter-spacing:.04em;text-transform:uppercase;margin-bottom:3px}
.psel-title{font-size:.86rem;font-weight:700;line-height:1.35}
.psel-prog{height:4px;background:rgba(0,0,0,.07);border-radius:3px;overflow:hidden;margin-top:7px}
.psel-prog-fill{height:100%;background:linear-gradient(90deg,var(--acc),var(--acc-d));border-radius:3px;transition:width .4s}
.sec{display:none;background:var(--card);border:1.5px solid var(--border);border-radius:14px;padding:22px;box-shadow:var(--sh);position:relative}
.sec.active{display:block}
.sec[data-watermark]::before{content:attr(data-watermark);position:absolute;right:18px;top:-12px;font-family:'Unbounded',sans-serif;font-size:5.2rem;font-weight:900;color:var(--acc-soft);pointer-events:none;line-height:1;user-select:none}
.sec-header{display:flex;align-items:baseline;gap:14px;margin-bottom:18px;padding-bottom:14px;border-bottom:1.5px solid var(--border);position:relative;z-index:1}
.sec-num{background:linear-gradient(135deg,var(--acc),var(--acc-d));color:#fff;padding:5px 12px;border-radius:9px;font-family:'Unbounded',sans-serif;font-weight:800;font-size:.86rem;letter-spacing:.04em}
.sec-h{font-family:'Unbounded',sans-serif;font-size:1.35rem;font-weight:800;color:var(--text)}
.placeholder{padding:32px 20px;text-align:center;color:var(--muted);font-size:.95rem;background:var(--card-soft);border:1.5px dashed var(--border);border-radius:10px}
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
.sidecard-row{margin-bottom:8px;font-size:.86rem;line-height:1.6}
.sidecard-row b{color:var(--pri);font-weight:700}
@media(max-width:980px){.col-side{position:static;max-height:none}}
.xp-card{background:linear-gradient(135deg,var(--acc-soft),var(--pri-soft));border:1.5px solid var(--acc);border-radius:12px;padding:14px;margin-bottom:14px}
.xp-card-title{font-size:.68rem;font-weight:800;color:var(--acc-d);text-transform:uppercase;letter-spacing:.07em;margin-bottom:8px;display:flex;align-items:center;justify-content:space-between}
.xp-level{font-size:1.1rem;font-weight:900;color:var(--acc-d);font-family:'Unbounded',sans-serif}
.xp-bar{height:9px;background:rgba(245,158,11,.15);border-radius:6px;overflow:hidden;margin:7px 0}
.xp-fill{height:100%;background:linear-gradient(90deg,var(--acc),var(--pri));border-radius:6px;transition:width .5s cubic-bezier(.4,0,.2,1)}
.xp-nums{font-size:.74rem;color:var(--muted);display:flex;justify-content:space-between}
.col-side-backdrop{position:fixed;inset:0;background:rgba(0,0,0,.42);z-index:9990;display:none}
.col-side-backdrop.show{display:block}
@media(min-width:981px){#sidebar-btn{display:none}.col-side-backdrop.show{display:none}}
@media(max-width:980px){
.col-side{position:fixed;top:0;right:0;height:100vh;width:300px;max-width:88vw;background:var(--bg);box-shadow:-12px 0 24px rgba(0,0,0,.18);padding:18px 16px;overflow-y:auto;transform:translateX(100%);transition:transform .25s ease;z-index:9991;max-height:none}
.col-side.open{transform:none}
}
.ach-popup{position:fixed;top:80px;right:18px;background:linear-gradient(135deg,var(--acc-d),var(--acc));color:#fff;padding:12px 18px;border-radius:11px;font-weight:700;font-size:.9rem;box-shadow:0 8px 28px rgba(0,0,0,.25);z-index:1002;display:none;align-items:center;gap:8px;max-width:340px}
.ach-popup.show{display:flex}
.foot{text-align:center;padding:30px 16px;color:var(--muted);font-size:.78rem;border-top:1px solid var(--border);margin-top:30px}
/* Search modal */
.search-modal{position:fixed;inset:0;background:rgba(15,23,42,.55);backdrop-filter:blur(4px);z-index:9993;display:none;align-items:flex-start;justify-content:center;padding-top:80px}
.search-modal.show{display:flex}
.search-box{background:var(--card);border-radius:14px;width:520px;max-width:92vw;padding:14px;box-shadow:0 24px 64px rgba(0,0,0,.35);border:1.5px solid var(--border)}
.search-inp{width:100%;padding:11px 14px;background:var(--card-soft);border:1.5px solid var(--border);border-radius:9px;color:var(--text);font-size:.95rem;font-family:inherit;outline:0}
.search-inp:focus{border-color:var(--acc)}
.search-list{margin-top:12px;max-height:320px;overflow-y:auto}
.search-item{padding:10px 12px;border-radius:9px;cursor:pointer;border:1px solid transparent;font-size:.9rem}
.search-item:hover,.search-item.cur{background:var(--acc-soft);border-color:var(--acc)}
.search-item .num{display:inline-block;padding:2px 8px;background:var(--acc);color:#fff;border-radius:99px;font-size:.7rem;font-weight:700;margin-right:8px}
</style>
</head>
<body>
<header class="hdr">
<div class="hdr-inner">
<div>
<a href="/textbook/physics-7" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><polyline points="15 18 9 12 15 6"/></svg> К физике 7</a>
</div>
<div>
<h1>Физика 7 &middot; Глава 2</h1>
<div class="hdr-sub">Строение вещества &middot; §§813</div>
</div>
<div class="hdr-side">
<button id="search-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m21 21-4-4"/></svg> Поиск</button>
<button id="sidebar-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><line x1="4" y1="6" x2="20" y2="6"/><line x1="4" y1="12" x2="20" y2="12"/><line x1="4" y1="18" x2="14" y2="18"/></svg> Шпаргалка</button>
<button id="theme-btn" class="hdr-btn"><svg class="ic" viewBox="0 0 24 24"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg><span id="theme-lab">Тёмная</span></button>
</div>
</div>
</header>
<main class="main">
<div class="col-main">
<div class="psel">
<div class="psel-head">Параграфы главы 2</div>
<div class="psel-grid" id="psel-grid"></div>
</div>
<section id="sec-p8" class="sec" data-watermark="•">
<div class="sec-header"><span class="sec-num">§ 8</span><h2 class="sec-h">Дискретное строение вещества</h2></div>
<div id="p8-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p9" class="sec" data-watermark="~">
<div class="sec-header"><span class="sec-num">§ 9</span><h2 class="sec-h">Тепловое движение частиц</h2></div>
<div id="p9-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p10" class="sec" data-watermark="⇌">
<div class="sec-header"><span class="sec-num">§ 10</span><h2 class="sec-h">Взаимодействие частиц</h2></div>
<div id="p10-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p11" class="sec" data-watermark="△">
<div class="sec-header"><span class="sec-num">§ 11</span><h2 class="sec-h">Газ, жидкость, твёрдое</h2></div>
<div id="p11-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p12" class="sec" data-watermark="↔">
<div class="sec-header"><span class="sec-num">§ 12</span><h2 class="sec-h">Тепловое расширение</h2></div>
<div id="p12-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p13" class="sec" data-watermark="°">
<div class="sec-header"><span class="sec-num">§ 13</span><h2 class="sec-h">Температура. Термометры</h2></div>
<div id="p13-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-final2" class="sec" data-watermark="★">
<div class="sec-header"><span class="sec-num">Финал</span><h2 class="sec-h">Итоги главы 2</h2></div>
<div id="final2-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
</div>
<aside class="col-side" id="col-side"><div id="sidebar-content"></div></aside>
<div class="col-side-backdrop" id="col-side-backdrop"></div>
</main>
<div class="ach-popup" id="ach-popup"><svg class="ic" viewBox="0 0 24 24"><polygon points="12,2 15,9 22,9.3 17,14 18.5,21 12,17 5.5,21 7,14 2,9.3 9,9"/></svg><span id="ach-text"></span></div>
<div class="search-modal" id="search-modal"><div class="search-box">
<input type="text" class="search-inp" id="search-inp" placeholder="Поиск по параграфам... (Esc — закрыть, Ctrl+K)">
<div class="search-list" id="search-list"></div>
</div></div>
<footer class="foot">Интерактивный учебник «Физика 7 класс» &middot; Глава 2 &middot; LearnSpace</footer>
<script>
'use strict';
const LS_PREFIX = 'physics7_ch2';
const _TB_SLUG = 'physics-7-ch2';
const PARAS = [{id:'p8',num:'§ 8',title:"Дискретное строение вещества",wm:'•'},{id:'p9',num:'§ 9',title:"Тепловое движение частиц",wm:'~'},{id:'p10',num:'§ 10',title:"Взаимодействие частиц",wm:'⇌'},{id:'p11',num:'§ 11',title:"Газ, жидкость, твёрдое",wm:'△'},{id:'p12',num:'§ 12',title:"Тепловое расширение",wm:'↔'},{id:'p13',num:'§ 13',title:"Температура. Термометры",wm:'°'},{id:'final2',num:'Финал',title:"Итоги главы 2",wm:'★'}];
const TOTAL_PARAS = PARAS.length;
const SIDEBARS = {
p8: { title: 'Шпаргалка § 8', rows: [
['Строение', 'Вещество состоит из молекул и атомов; между ними — промежутки'],
['Молекула', 'Наименьшая частица вещества, сохраняющая его хим. свойства'],
['Размер', 'Диаметр молекулы $\\approx 10^{-10}$ м; ядра атома $\\approx 10^{-15}$ м'],
['Доказательства', 'Сжимаемость газов, растворение, расширение при нагреве'],
['Из чего молекула', 'Молекулы состоят из атомов']
]},
p9: { title: 'Шпаргалка § 9', rows: [
['Тепловое движение', 'Непрерывное хаотическое движение молекул любого тела'],
['Скорость и $T$', 'Чем выше температура, тем быстрее движутся частицы'],
['Броуновское движение', 'Видимые частицы дёргаются под ударами молекул'],
['Диффузия', 'Самопроизвольное взаимопроникновение молекул разных веществ'],
['Скорость диффузии', 'Газ $\\gg$ жидкость $\\gg$ твёрдое тело; растёт с температурой']
]},
p10: { title: 'Шпаргалка § 10', rows: [
['Два вида сил', 'Между молекулами одновременно действуют притяжение и отталкивание'],
['$r < r_0$', 'Преобладает отталкивание'],
['$r = r_0$', 'Силы уравновешиваются'],
['$r > r_0$', 'Преобладает притяжение; при $r \\gg r_0$ силы малы'],
['Приложение', 'Упругость пружины, несжимаемость жидкостей — та же природа']
]},
p11: { title: 'Шпаргалка § 11', rows: [
['Твёрдое', 'Молекулы в кристаллической решётке; сохраняет форму и объём'],
['Жидкое', 'Молекулы «перескакивают»; объём сохраняет, форму — нет'],
['Газообразное', 'Молекулы летают свободно; ни форма, ни объём не сохраняются'],
['Молекула при переходе', 'Сама молекула не меняется — меняется характер её движения'],
['Пример', 'Вода: лёд ($<0$ °C), вода ($0$$100$ °C), пар ($>100$ °C)']
]},
p12: { title: 'Шпаргалка § 12', rows: [
['Причина расширения', 'При нагреве амплитуда колебаний молекул растёт → расстояния увеличиваются'],
['Порядок расширения', 'Газы $\\gg$ жидкости $\\gg$ твёрдые тела'],
['Формула', '$\\Delta l = l_0 \\cdot \\alpha \\cdot \\Delta T$ ($\\alpha$ — коэф. линейного расширения)'],
['Примеры', 'Зазоры в рельсах, провисание проводов, биметаллическая пластина'],
['Аномалия воды', 'Макс. плотность при $+4$ °C; при $0$–$4$ °C вода сжимается при нагреве']
]},
p13: { title: 'Шпаргалка § 13', rows: [
['Температура', 'Физ. величина, характеризующая степень нагретости тела'],
['Связь с молекулами', 'Чем быстрее движутся молекулы — тем выше $t$'],
['Шкала Цельсия', '$0$ °C — таяние льда; $100$ °C — кипение воды при норм. давлении'],
['Кельвин', '$T = t + 273{,}15$; абсолютный нуль: $T = 0$ К $= -273{,}15$ °C'],
['Виды термометров', 'Жидкостный, биметаллический, электронный, инфракрасный']
]},
final2: { title: 'Шпаргалка · Итоги главы 2', rows: [
['§8 Строение', 'Молекулы $\\approx 10^{-10}$ м; между ними промежутки — отсюда сжимаемость'],
['§9 Движение', 'Тепловое (хаотическое) движение; диффузия быстрее при большем $T$'],
['§10 Силы', 'При $r < r_0$ — отталкивание; при $r > r_0$ — притяжение'],
['§1112 Агрегаты', 'Газ: нет формы/объёма; жидкость: есть объём; твёрдое: есть форма и объём; расширение: $\\Delta l = l_0 \\alpha \\Delta T$'],
['§13 Температура', '$t$ (°C) и $T$ (К): $T = t + 273{,}15$; $0$ °C — лёд, $100$ °C — кипение']
]}
};
const TIPS = [];
const ACH_LABELS = { start: 'Начало главы 2', ch_done: 'Знаток вещества' };
const STATE = { current: null, progress: {}, xp: 0, level: 1, achievements: new Map(), _built: new Set() };
function _xpForLevel(lv){ return Math.round(100 * Math.pow(lv-1, 1.6)); }
function calcLevel(xp){ let lv = 1; while(_xpForLevel(lv+1) <= xp) lv++; return lv; }
function loadProgress(){
try{
const s = localStorage.getItem(LS_PREFIX + '_progress'); if(s) Object.assign(STATE.progress, JSON.parse(s));
const a = localStorage.getItem(LS_PREFIX + '_achievements');
if(a){ const p = JSON.parse(a); if(p && typeof p === 'object'){ for(const [id,t] of Object.entries(p)) STATE.achievements.set(id, (t && t !== id) ? t : (ACH_LABELS[id] || id)); } }
STATE.xp = +(localStorage.getItem('physics7_xp') || 0); STATE.level = calcLevel(STATE.xp);
}catch(e){}
}
function saveProgress(){
try{
localStorage.setItem(LS_PREFIX + '_progress', JSON.stringify(STATE.progress));
localStorage.setItem(LS_PREFIX + '_achievements', JSON.stringify(Object.fromEntries(STATE.achievements)));
localStorage.setItem('physics7_xp', String(STATE.xp));
}catch(e){}
}
function bumpProgress(key, delta){
STATE.progress[key] = Math.max(0, Math.min(100, (STATE.progress[key]||0) + delta));
saveProgress(); refreshProgressUI();
if(STATE.progress[key] >= 100 && key === PARAS[PARAS.length-1].id) achievement('ch_done', 'Знаток вещества');
}
function addXp(n, src){
if(!n) return;
const prev = STATE.level; STATE.xp = Math.max(0, (STATE.xp||0) + n); STATE.level = calcLevel(STATE.xp);
saveProgress(); refreshProgressUI();
if(window.LS && window.LS.xp) window.LS.xp.add(n, 'physics7-ch2-' + (src||'misc'));
if(STATE.level > prev){
const pop = document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent = 'Уровень ' + STATE.level + '!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 2600); }
}
}
function achievement(id, label){
if(STATE.achievements.has(id)) return;
STATE.achievements.set(id, label || ACH_LABELS[id] || id);
saveProgress();
const pop = document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent = 'Ачивка: ' + (label || ACH_LABELS[id] || id); pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 3000); }
addXp(20, 'ach-' + id);
}
function refreshProgressUI(){
document.querySelectorAll('[data-prog-card]').forEach(el => {
const k = el.dataset.progCard;
const fl = el.querySelector('.psel-prog-fill');
if(fl) fl.style.width = (STATE.progress[k]||0) + '%';
});
if(STATE.current && document.getElementById('sidebar-content')){ try{ buildSidebar(STATE.current); }catch(e){} }
}
function buildParaSelector(){
const grid = document.getElementById('psel-grid');
if(!grid) return;
grid.innerHTML = PARAS.map(p =>
'<button class="psel-card" data-id="' + p.id + '" data-prog-card="' + p.id + '">'
+ '<div class="psel-num">' + p.num + '</div>'
+ '<div class="psel-title">' + p.title + '</div>'
+ '<div class="psel-prog"><div class="psel-prog-fill" style="width:' + (STATE.progress[p.id]||0) + '%"></div></div>'
+ '</button>'
).join('');
grid.querySelectorAll('.psel-card').forEach(c => c.addEventListener('click', () => goTo(c.dataset.id)));
}
function ensureBuilt(id){
if(STATE._built.has(id)) return;
STATE._built.add(id);
const W = window['PHYS7_CH2_WIDGETS'];
if(W && typeof W[id] === 'function'){
const body = document.getElementById(id + '-body');
if(body){
const ph = body.querySelector('.placeholder');
if(ph) ph.remove();
}
try{ W[id](); }catch(e){ console.warn('phys7 widget ' + id + ':', e.message); }
}
}
function goTo(id){
STATE.current = id; ensureBuilt(id);
document.querySelectorAll('.sec').forEach(s => s.classList.remove('active'));
const el = document.getElementById('sec-' + id); if(el) el.classList.add('active');
document.querySelectorAll('.psel-card').forEach(c => c.classList.toggle('active', c.dataset.id === id));
buildSidebar(id);
window.scrollTo({ top: 0, behavior: 'smooth' });
if((STATE.progress[id]||0) < 10) bumpProgress(id, 10);
if(window.renderMathInElement && el){
setTimeout(() => {
try{ renderMathInElement(el, { delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}], throwOnError:false }); }catch(e){}
}, 0);
}
}
function buildSidebar(id){
const box = document.getElementById('sidebar-content');
if(!box) return;
const sb = SIDEBARS[id] || SIDEBARS[PARAS[0].id];
const xpForLv = _xpForLevel(STATE.level), xpNext = _xpForLevel(STATE.level+1);
const xpInLv = STATE.xp - xpForLv, xpRange = xpNext - xpForLv;
const xpPct = xpRange > 0 ? Math.round(xpInLv / xpRange * 100) : 100;
let html = '';
html += '<div class="xp-card"><div class="xp-card-title"><span>XP-прогресс</span><span class="xp-level">Ур. ' + STATE.level + '</span></div><div class="xp-bar"><div class="xp-fill" style="width:' + xpPct + '%"></div></div><div class="xp-nums"><span>' + STATE.xp + ' XP</span><span>' + xpNext + ' XP</span></div></div>';
if(sb && sb.rows && sb.rows.length){
html += '<div class="sidecard"><h4>' + sb.title + '</h4>';
sb.rows.forEach(([k,v]) => { html += '<div class="sidecard-row"><b>' + k + '</b>' + (v ? ' &mdash; ' + v : '') + '</div>'; });
html += '</div>';
}
const tip = TIPS.find(t => t.sec === id) || TIPS[0];
if(tip){
html += '<div class="sidecard" style="background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft));border-color:var(--warn)"><h4 style="color:#92400e">Подсказка</h4><div class="sidecard-row" style="margin-bottom:0;font-size:.84rem">' + tip.html + '</div></div>';
}
if(STATE.achievements.size > 0){
html += '<div class="sidecard"><h4>Достижения <span style="color:var(--warn);float:right">' + STATE.achievements.size + '</span></h4>';
[...STATE.achievements.values()].slice(-4).forEach(t => { html += '<div class="sidecard-row" style="font-size:.78rem;color:var(--ok)">&#10003; ' + t + '</div>'; });
html += '</div>';
}
box.innerHTML = html;
if(window.renderMathInElement){
try{ renderMathInElement(box, { delimiters:[{left:'$$',right:'$$',display:true},{left:'$',right:'$',display:false}], throwOnError:false }); }catch(e){}
}
}
function initTheme(){
const t = localStorage.getItem(LS_PREFIX + '_theme') || localStorage.getItem('physics7_theme') || 'light';
if(t === 'dark') document.documentElement.classList.add('dark');
document.getElementById('theme-lab').textContent = t === 'dark' ? 'Светлая' : 'Тёмная';
document.getElementById('theme-btn').addEventListener('click', () => {
document.documentElement.classList.toggle('dark');
const dark = document.documentElement.classList.contains('dark');
localStorage.setItem(LS_PREFIX + '_theme', dark ? 'dark' : 'light');
localStorage.setItem('physics7_theme', dark ? 'dark' : 'light');
document.getElementById('theme-lab').textContent = dark ? 'Светлая' : 'Тёмная';
});
}
function initSidebarToggle(){
const side = document.getElementById('col-side'), back = document.getElementById('col-side-backdrop'), btn = document.getElementById('sidebar-btn');
if(!side || !btn) return;
function open(){ side.classList.add('open'); back.classList.add('show'); }
function close(){ side.classList.remove('open'); back.classList.remove('show'); }
btn.addEventListener('click', () => { if(side.classList.contains('open')) close(); else open(); });
back.addEventListener('click', close);
document.addEventListener('keydown', e => { if(e.key === 'Escape') close(); });
}
function initSearch(){
const btn = document.getElementById('search-btn'), modal = document.getElementById('search-modal'), inp = document.getElementById('search-inp'), list = document.getElementById('search-list');
if(!btn || !modal) return;
let cur = 0;
function render(q){
const ql = (q||'').toLowerCase().trim();
const items = PARAS.filter(p => !ql || p.title.toLowerCase().includes(ql) || p.num.toLowerCase().includes(ql));
list.innerHTML = items.map((p,i) => '<div class="search-item' + (i === cur ? ' cur' : '') + '" data-id="' + p.id + '"><span class="num">' + p.num + '</span>' + p.title + '</div>').join('');
list.querySelectorAll('.search-item').forEach(el => el.addEventListener('click', () => { goTo(el.dataset.id); close(); }));
}
function open(){ modal.classList.add('show'); inp.value = ''; cur = 0; render(''); setTimeout(() => inp.focus(), 50); }
function close(){ modal.classList.remove('show'); }
btn.addEventListener('click', open);
modal.addEventListener('click', e => { if(e.target === modal) close(); });
inp.addEventListener('input', () => { cur = 0; render(inp.value); });
inp.addEventListener('keydown', e => {
const items = list.querySelectorAll('.search-item');
if(e.key === 'ArrowDown'){ e.preventDefault(); cur = Math.min(items.length-1, cur+1); render(inp.value); }
else if(e.key === 'ArrowUp'){ e.preventDefault(); cur = Math.max(0, cur-1); render(inp.value); }
else if(e.key === 'Enter'){ e.preventDefault(); const sel = items[cur]; if(sel){ goTo(sel.dataset.id); close(); } }
else if(e.key === 'Escape'){ e.preventDefault(); close(); }
});
document.addEventListener('keydown', e => { if((e.ctrlKey || e.metaKey) && (e.key === 'k' || e.key === 'K')){ e.preventDefault(); if(modal.classList.contains('show')) close(); else open(); } });
}
function init(){
loadProgress(); initTheme(); initSidebarToggle(); initSearch();
buildParaSelector(); refreshProgressUI(); goTo(PARAS[0].id);
setTimeout(() => achievement('start'), 600);
}
document.addEventListener('DOMContentLoaded', init);
</script>
</body>
</html>