Files
Learn_System/frontend/textbooks/physics_7_ch4.html

431 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 · Глава 4 · Давление</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<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_ch4_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:#d97706; --acc-d:#92400e; --acc-soft:#fef3c7;
--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,#78350f,#d97706 60%,#fbbf24);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; Глава 4</h1>
<div class="hdr-sub">Давление &middot; §§2835</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">Параграфы главы 4</div>
<div class="psel-grid" id="psel-grid"></div>
</div>
<section id="sec-p28" class="sec" data-watermark="p">
<div class="sec-header"><span class="sec-num">§ 28</span><h2 class="sec-h">Давление. Единицы давления</h2></div>
<div id="p28-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p29" class="sec" data-watermark="∴">
<div class="sec-header"><span class="sec-num">§ 29</span><h2 class="sec-h">Давление газа</h2></div>
<div id="p29-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p30" class="sec" data-watermark="⊕">
<div class="sec-header"><span class="sec-num">§ 30</span><h2 class="sec-h">Закон Паскаля</h2></div>
<div id="p30-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p31" class="sec" data-watermark="≡">
<div class="sec-header"><span class="sec-num">§ 31</span><h2 class="sec-h">Гидростатическое давление</h2></div>
<div id="p31-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p32" class="sec" data-watermark="U">
<div class="sec-header"><span class="sec-num">§ 32</span><h2 class="sec-h">Сообщающиеся сосуды</h2></div>
<div id="p32-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p33" class="sec" data-watermark="⌒">
<div class="sec-header"><span class="sec-num">§ 33</span><h2 class="sec-h">Газы и их вес</h2></div>
<div id="p33-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p34" class="sec" data-watermark="">
<div class="sec-header"><span class="sec-num">§ 34</span><h2 class="sec-h">Атмосферное давление</h2></div>
<div id="p34-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p35" class="sec" data-watermark="⏚">
<div class="sec-header"><span class="sec-num">§ 35</span><h2 class="sec-h">Барометры и манометры</h2></div>
<div id="p35-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-final4" class="sec" data-watermark="★">
<div class="sec-header"><span class="sec-num">Финал</span><h2 class="sec-h">Итоги главы 4</h2></div>
<div id="final4-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; Глава 4 &middot; LearnSpace</footer>
<script>
'use strict';
const LS_PREFIX = 'physics7_ch4';
const _TB_SLUG = 'physics-7-ch4';
const PARAS = [{id:'p28',num:'§ 28',title:"Давление. Единицы давления",wm:'p'},{id:'p29',num:'§ 29',title:"Давление газа",wm:'∴'},{id:'p30',num:'§ 30',title:"Закон Паскаля",wm:'⊕'},{id:'p31',num:'§ 31',title:"Гидростатическое давление",wm:'≡'},{id:'p32',num:'§ 32',title:"Сообщающиеся сосуды",wm:'U'},{id:'p33',num:'§ 33',title:"Газы и их вес",wm:'⌒'},{id:'p34',num:'§ 34',title:"Атмосферное давление",wm:''},{id:'p35',num:'§ 35',title:"Барометры и манометры",wm:'⏚'},{id:'final4',num:'Финал',title:"Итоги главы 4",wm:'★'}];
const TOTAL_PARAS = PARAS.length;
const SIDEBARS = {
p28: { title: 'Шпаргалка § 28', rows: [
['$p = F / S$', 'давление = сила / площадь'],
['Единица', '1 Па = 1 Н/м²; 1 кПа = 1000 Па'],
['Увеличить $p$', 'уменьшить $S$ при той же $F$'],
['Примеры', 'гвоздь: $\\sim$ГПа; лыжник: $\\sim$2,8 кПа']
]},
p29: { title: 'Шпаргалка § 29', rows: [
['Источник $p$', 'удары молекул о стенки сосуда'],
['$p$ растёт если', 'больше молекул, выше $T$, меньше $V$'],
['Во все стороны', 'газ давит равномерно во все стороны'],
['Пример', 'шина на солнце — $T$ растёт, $p$ растёт']
]},
p30: { title: 'Шпаргалка § 30', rows: [
['Закон Паскаля', 'давление в жидкости/газе передаётся без изменения во все стороны'],
['Пресс: $F_2$', '$F_2 = F_1 \\cdot \\dfrac{S_2}{S_1}$'],
['Выигрыш', 'в силе — во столько раз, во сколько $S_2 > S_1$'],
['Применение', 'пресс, подъёмник, тормоза авто, ковш экскаватора']
]},
p31: { title: 'Шпаргалка § 31', rows: [
['$p = \\rho g h$', 'гидростатическое давление на глубине $h$'],
['Зависит от', '$\\rho$ жидкости и глубины $h$; форма сосуда — не важна'],
['Парадокс', 'в любом сосуде на одной глубине $p$ одинаково'],
['Пример', '$h = 10$ м вода $\\Rightarrow$ $p \\approx 98$ кПа $\\approx 1$ атм']
]},
p32: { title: 'Шпаргалка § 32', rows: [
['Закон', 'однородная жидкость устанавливается на одном уровне'],
['Почему', '$p = \\rho g h$ одинаково на дне — жидкость не перетекает'],
['Разные жидкости', '$\\rho_1 h_1 = \\rho_2 h_2$ (обратно пропорц. плотностям)'],
['Применение', 'чайник, шлюз, водонапорная башня, колодец']
]},
p33: { title: 'Шпаргалка § 33', rows: [
['Газ имеет массу', '$m = \\rho V$; вес $P = mg$'],
['Воздух у Земли', '$\\rho_{возд} \\approx 1{,}29$ кг/м³'],
['Пример', 'воздух в комнате 60 м³ $\\approx$ 77 кг'],
['Тяжелее воздуха', '$CO_2$, $Cl_2$, $Rn$; легче — $He$, $H_2$']
]},
p34: { title: 'Шпаргалка § 34', rows: [
['Норма', '$p_0 = 101\\,325$ Па $= 760$ мм рт. ст. $\\approx 1$ атм'],
['Торричелли', 'ртуть в трубке $\\approx 760$ мм — доказал атм. давление (1643)'],
['С высотой', 'каждые $\\approx 12$ м вверх $\\Rightarrow$ $-1$ мм рт. ст.'],
['Эльбрус 5642 м', '$p \\approx 400$ мм рт. ст. — почти вдвое меньше нормы']
]},
p35: { title: 'Шпаргалка § 35', rows: [
['Барометр', 'измеряет атмосферное давление (Торричелли, анероид)'],
['Манометр', 'измеряет давление газа/жидкости в сосуде'],
['Анероид', 'безжидкостный пружинный барометр'],
['1 мм рт. ст.', '$\\approx 133$ Па; манометр показывает $\\Delta p = p - p_0$']
]},
final4: { title: 'Шпаргалка · Итоги главы 4', rows: [
['Давление', '$p = F/S$, [Па]'],
['Паскаль', '$p$ в жидкости/газе передаётся без изменения во все стороны'],
['Гидропресс', '$F_2 = F_1 \\cdot S_2 / S_1$'],
['Гидростатика', '$p = \\rho g h$; форма сосуда не важна'],
['Атмосфера', '$p_0 = 760$ мм рт. ст. $\\approx 101$ кПа; $-1$ мм/12 м']
]}
};
const TIPS = [];
const ACH_LABELS = { start: 'Начало главы 4', 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-ch4-' + (src||'misc'));
if(STATE.level > prev){
const pop = document.getElementById('ach-popup');
if(pop){ document.getElementById('ach-text').textContent = 'Уровень ' + STATE.level + '!'; pop.classList.add('show'); setTimeout(()=>pop.classList.remove('show'), 2600); }
}
}
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_CH4_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>