Files

491 lines
35 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 · Глава 3 · Движение и силы</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_ch3_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:#dc2626; --acc-d:#991b1b; --acc-soft:#fee2e2;
--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,#7f1d1d,#dc2626 60%,#f87171);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; Глава 3</h1>
<div class="hdr-sub">Движение и силы &middot; §§1427</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">Параграфы главы 3</div>
<div class="psel-grid" id="psel-grid"></div>
</div>
<section id="sec-p14" class="sec" data-watermark="→">
<div class="sec-header"><span class="sec-num">§ 14</span><h2 class="sec-h">Механическое движение. Относительность</h2></div>
<div id="p14-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p15" class="sec" data-watermark="s">
<div class="sec-header"><span class="sec-num">§ 15</span><h2 class="sec-h">Траектория, путь, время</h2></div>
<div id="p15-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p16" class="sec" data-watermark="v">
<div class="sec-header"><span class="sec-num">§ 16</span><h2 class="sec-h">Равномерное движение. Скорость</h2></div>
<div id="p16-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p17" class="sec" data-watermark="∠">
<div class="sec-header"><span class="sec-num">§ 17</span><h2 class="sec-h">Графики s(t) и v(t)</h2></div>
<div id="p17-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p18" class="sec" data-watermark="⟨⟩">
<div class="sec-header"><span class="sec-num">§ 18</span><h2 class="sec-h">Средняя скорость</h2></div>
<div id="p18-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p19" class="sec" data-watermark="∞">
<div class="sec-header"><span class="sec-num">§ 19</span><h2 class="sec-h">Инерция</h2></div>
<div id="p19-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p20" class="sec" data-watermark="ρ">
<div class="sec-header"><span class="sec-num">§ 20</span><h2 class="sec-h">Масса. Плотность</h2></div>
<div id="p20-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p21" class="sec" data-watermark="F">
<div class="sec-header"><span class="sec-num">§ 21</span><h2 class="sec-h">Сила</h2></div>
<div id="p21-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p22" class="sec" data-watermark="↓">
<div class="sec-header"><span class="sec-num">§ 22</span><h2 class="sec-h">Сила тяжести</h2></div>
<div id="p22-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p23" class="sec" data-watermark="≈">
<div class="sec-header"><span class="sec-num">§ 23</span><h2 class="sec-h">Сила упругости</h2></div>
<div id="p23-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p24" class="sec" data-watermark="P">
<div class="sec-header"><span class="sec-num">§ 24</span><h2 class="sec-h">Вес тела</h2></div>
<div id="p24-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p25" class="sec" data-watermark="⊥">
<div class="sec-header"><span class="sec-num">§ 25</span><h2 class="sec-h">Динамометр</h2></div>
<div id="p25-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p26" class="sec" data-watermark="+">
<div class="sec-header"><span class="sec-num">§ 26</span><h2 class="sec-h">Сложение сил</h2></div>
<div id="p26-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-p27" class="sec" data-watermark="~">
<div class="sec-header"><span class="sec-num">§ 27</span><h2 class="sec-h">Сила трения</h2></div>
<div id="p27-body"><div class="placeholder">Содержимое параграфа появится в одной из ближайших фаз разработки.</div></div>
</section>
<section id="sec-final3" class="sec" data-watermark="★">
<div class="sec-header"><span class="sec-num">Финал</span><h2 class="sec-h">Итоги главы 3</h2></div>
<div id="final3-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; Глава 3 &middot; LearnSpace</footer>
<script>
'use strict';
const LS_PREFIX = 'physics7_ch3';
const _TB_SLUG = 'physics-7-ch3';
const PARAS = [{id:'p14',num:'§ 14',title:"Механическое движение. Относительность",wm:'→'},{id:'p15',num:'§ 15',title:"Траектория, путь, время",wm:'s'},{id:'p16',num:'§ 16',title:"Равномерное движение. Скорость",wm:'v'},{id:'p17',num:'§ 17',title:"Графики s(t) и v(t)",wm:'∠'},{id:'p18',num:'§ 18',title:"Средняя скорость",wm:'⟨⟩'},{id:'p19',num:'§ 19',title:"Инерция",wm:'∞'},{id:'p20',num:'§ 20',title:"Масса. Плотность",wm:'ρ'},{id:'p21',num:'§ 21',title:"Сила",wm:'F'},{id:'p22',num:'§ 22',title:"Сила тяжести",wm:'↓'},{id:'p23',num:'§ 23',title:"Сила упругости",wm:'≈'},{id:'p24',num:'§ 24',title:"Вес тела",wm:'P'},{id:'p25',num:'§ 25',title:"Динамометр",wm:'⊥'},{id:'p26',num:'§ 26',title:"Сложение сил",wm:'+'},{id:'p27',num:'§ 27',title:"Сила трения",wm:'~'},{id:'final3',num:'Финал',title:"Итоги главы 3",wm:'★'}];
const TOTAL_PARAS = PARAS.length;
const SIDEBARS = {
p14: { title: 'Шпаргалка § 14', rows: [
['Движение', 'изменение положения тела относительно других тел со временем'],
['Система отсчёта', 'тело отсчёта + оси координат + часы'],
['Относительность', 'покой и движение зависят от выбранной СО'],
['Пример', 'пассажир в вагоне: покоится относительно вагона, движется относительно Земли']
]},
p15: { title: 'Шпаргалка § 15', rows: [
['Траектория', 'линия, по которой движется тело'],
['Путь $s$', 'длина траектории; $[s] = $ м; всегда $\\ge 0$'],
['Время $t$', 'длительность движения; $[t] = $ с'],
['Виды', 'прямолинейная, криволинейная, замкнутая']
]},
p16: { title: 'Шпаргалка § 16', rows: [
['Скорость', '$v = \\dfrac{s}{t}$; $[v] = $ м/с'],
['Единицы', '$1$ м/с $= 3{,}6$ км/ч; $1$ км/ч $\\approx 0{,}28$ м/с'],
['Путь', '$s = v \\cdot t$'],
['Время', '$t = \\dfrac{s}{v}$'],
['Характер', 'равномерное: за равные промежутки — равные расстояния']
]},
p17: { title: 'Шпаргалка § 17', rows: [
['График $s(t)$', 'прямая через начало координат; наклон = $v$'],
['График $v(t)$', 'горизонтальная линия (равномерное: $v = $ const)'],
['Площадь под $v(t)$', 'равна пройденному пути $s = v \\cdot t$'],
['Два тела на $s(t)$', 'больший наклон — большая скорость']
]},
p18: { title: 'Шпаргалка § 18', rows: [
['Средняя скорость', '$\\langle v \\rangle = \\dfrac{s_{полн}}{t_{полн}}$'],
['Ловушка', '$\\langle v \\rangle \\ne \\dfrac{v_1 + v_2}{2}$ при разном времени на участках'],
['Неравномерное', 'скорость меняется со временем'],
['Пример', 'пешком $0{,}5$ км + метро $5$ км за $20$ мин $\\Rightarrow \\langle v \\rangle = 16{,}5$ км/ч']
]},
p19: { title: 'Шпаргалка § 19', rows: [
['Инерция', 'стремление тела сохранять состояние покоя или равномерного движения'],
['Закон Галилея', 'без внешнего воздействия скорость тела не изменяется'],
['Что меняет скорость', 'только воздействие другого тела'],
['Мера инертности', 'масса: тяжёлое тело сложнее разогнать и остановить']
]},
p20: { title: 'Шпаргалка § 20', rows: [
['Масса $m$', 'мера инертности и количества вещества; $[m] = $ кг'],
['Плотность', '$\\rho = \\dfrac{m}{V}$; $[\\rho] = $ кг/м³ или г/см³'],
['Выражения', '$m = \\rho V$; $V = \\dfrac{m}{\\rho}$'],
['Примеры', 'вода $1000$ кг/м³; алюминий $2700$; железо $7800$; золото $19300$']
]},
p21: { title: 'Шпаргалка § 21', rows: [
['Сила $\\vec{F}$', 'мера взаимодействия двух тел; $[F] = $ Н (ньютон)'],
['Сила — вектор', 'характеризуется модулем, направлением и точкой приложения'],
['Основные силы', '$\\vec{F}_т$ (тяжести), $\\vec{F}_{упр}$ (упругости), $\\vec{F}_{тр}$ (трения), $\\vec{N}$ (нормальная)']
]},
p22: { title: 'Шпаргалка § 22', rows: [
['Сила тяжести', '$F_т = mg$; направлена вертикально вниз'],
['$g$ на Земле', '$9{,}8$ Н/кг $\\approx 10$ Н/кг'],
['$g$ на Луне', '$\\approx 1{,}6$ Н/кг (в $\\approx 6$ раз меньше)'],
['Пример', '$m = 0{,}1$ кг $\\Rightarrow F_т \\approx 1$ Н (среднее яблоко)']
]},
p23: { title: 'Шпаргалка § 23', rows: [
['Упругая сила', 'возникает при деформации; возвращает тело в исходную форму'],
['Закон Гука', '$F_{упр} \\sim \\Delta l$ (сила пропорциональна удлинению)'],
['Пластическая деф.', 'при сильном растяжении пружина не вернётся — закон Гука нарушается'],
['Примеры', 'пружина, резинка, тетива лука, прогнутая доска']
]},
p24: { title: 'Шпаргалка § 24', rows: [
['Вес $\\vec{P}$', 'сила, с которой тело давит на опору (подвес); $[P] = $ Н'],
['Отличие от $F_т$', '$F_т$ приложена к телу, $P$ — к опоре; на покое $P = mg$'],
['Невесомость', '$P = 0$ при свободном падении (МКС, лифт в пике)'],
['Перегрузка', 'лифт ускоряется вверх — $P > mg$']
]},
p25: { title: 'Шпаргалка § 25', rows: [
['Динамометр', 'прибор для измерения силы; основан на растяжении пружины'],
['Шкала', '$[F] = $ Н; не превышай предел — пружина испортится'],
['Масса по показанию', '$m = F/g$'],
['Цена деления', 'например, $0..4$ Н с $40$ делениями $\\Rightarrow C = 0{,}1$ Н']
]},
p26: { title: 'Шпаргалка § 26', rows: [
['Равнодействующая $\\vec{R}$', 'одна сила, заменяющая совокупность всех действующих сил'],
['Сонаправленные', '$R = F_1 + F_2$; направление то же'],
['Противоположные', '$R = |F_1 - F_2|$; направление — в сторону большей силы'],
['Равновесие', '$R = 0 \\Rightarrow$ тело покоится или движется равномерно']
]},
p27: { title: 'Шпаргалка § 27', rows: [
['Сила трения', 'направлена против движения (или попытки движения)'],
['$F_{тр} = \\mu N$', '$\\mu$ — коэф. трения; $N$ — нормальная реакция опоры'],
['Виды', 'покоя $\\ge$ скольжения $\\gg$ качения'],
['Польза / вред', 'помогает ходить, тормозить; вредит: изнашивает, греет']
]},
final3: { title: 'Шпаргалка · Итоги главы 3', rows: [
['Движение', '$v = \\dfrac{s}{t}$; $\\langle v \\rangle = \\dfrac{s_{полн}}{t_{полн}}$'],
['Плотность', '$\\rho = \\dfrac{m}{V}$; $m = \\rho V$; $V = \\dfrac{m}{\\rho}$'],
['Сила тяжести', '$F_т = mg$; $g \\approx 9{,}8$ Н/кг (Земля)'],
['Закон Гука', '$F_{упр} \\sim \\Delta l$; трение: $F_{тр} = \\mu N$'],
['Равнодействующая', 'сонаправл.: $R = F_1 + F_2$; противоположн.: $R = |F_1 - F_2|$']
]}
};
const TIPS = [];
const ACH_LABELS = { start: 'Начало главы 3', 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-ch3-' + (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_CH3_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>